2001-12-31 16:16:59 +00:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//
|
2001-12-31 16:28:42 +00:00
|
|
|
// $Log$
|
2002-05-11 19:18:20 +00:00
|
|
|
// Revision 1.73 2002/05/11 19:18:20 makro
|
|
|
|
// Sand surfaceparm
|
|
|
|
//
|
2002-05-11 18:47:09 +00:00
|
|
|
// Revision 1.72 2002/05/11 18:47:09 niceass
|
|
|
|
// last fire animation fixed
|
|
|
|
//
|
2002-05-08 07:24:33 +00:00
|
|
|
// Revision 1.71 2002/05/08 07:24:33 niceass
|
|
|
|
// Double jumping added. Everything feels very good.
|
|
|
|
//
|
2002-05-07 05:07:32 +00:00
|
|
|
// Revision 1.70 2002/05/07 05:07:32 niceass
|
|
|
|
// several physics fixes
|
|
|
|
//
|
2002-05-01 21:14:59 +00:00
|
|
|
// Revision 1.69 2002/05/01 21:14:59 jbravo
|
|
|
|
// Misc fixes
|
|
|
|
//
|
2002-04-26 05:29:38 +00:00
|
|
|
// Revision 1.68 2002/04/26 05:29:38 niceass
|
|
|
|
// PHYSICS, Take 2
|
|
|
|
//
|
2002-04-20 15:05:08 +00:00
|
|
|
// Revision 1.67 2002/04/20 15:03:47 makro
|
|
|
|
// More footstep sounds, a few other things
|
|
|
|
//
|
2002-04-06 21:42:20 +00:00
|
|
|
// Revision 1.66 2002/04/06 21:42:20 makro
|
|
|
|
// Changes to bot code. New surfaceparm system.
|
|
|
|
//
|
2002-03-31 03:31:24 +00:00
|
|
|
// Revision 1.65 2002/03/31 03:31:24 jbravo
|
|
|
|
// Compiler warning cleanups
|
|
|
|
//
|
2002-03-27 17:20:38 +00:00
|
|
|
// Revision 1.64 2002/03/27 17:20:38 jbravo
|
|
|
|
// Workaround to the bandage bug :)
|
|
|
|
//
|
2002-03-23 05:17:43 +00:00
|
|
|
// Revision 1.63 2002/03/23 05:17:42 jbravo
|
|
|
|
// Major cleanup of game -> cgame communication with LCA vars.
|
|
|
|
//
|
2002-03-18 19:19:08 +00:00
|
|
|
// Revision 1.62 2002/03/18 19:18:39 slicer
|
|
|
|
// Fixed bandage bugs ( i hope )
|
|
|
|
//
|
2002-03-11 01:45:46 +00:00
|
|
|
// Revision 1.61 2002/03/11 01:45:46 jbravo
|
|
|
|
// Bye bye backflips! :)
|
|
|
|
//
|
2002-03-11 01:29:54 +00:00
|
|
|
// Revision 1.60 2002/03/11 01:29:54 slicer
|
|
|
|
// Fixed Sniper zooming during LCA
|
|
|
|
//
|
2002-03-02 22:02:09 +00:00
|
|
|
// Revision 1.59 2002/03/02 22:02:09 niceass
|
|
|
|
// mk23 and akimbo last fire animation fixed
|
|
|
|
//
|
2002-03-02 08:03:14 +00:00
|
|
|
// Revision 1.58 2002/03/02 08:03:14 niceass
|
|
|
|
// look down movement bug fixed
|
|
|
|
//
|
2002-02-27 01:54:29 +00:00
|
|
|
// Revision 1.57 2002/02/27 01:54:28 jbravo
|
|
|
|
// More spectatorfixes and finally stopped all fallingdamage anims and
|
|
|
|
// sounds during LCA.
|
|
|
|
//
|
2002-02-04 00:30:35 +00:00
|
|
|
// Revision 1.56 2002/02/04 00:30:35 niceass
|
|
|
|
// New physics
|
|
|
|
//
|
2002-01-24 14:20:53 +00:00
|
|
|
// Revision 1.55 2002/01/24 14:20:53 jbravo
|
|
|
|
// Adding func_explosive and a few new surfaceparms
|
|
|
|
//
|
2002-01-11 20:20:58 +00:00
|
|
|
// Revision 1.54 2002/01/11 20:20:58 jbravo
|
|
|
|
// Adding TP to main branch
|
|
|
|
//
|
2002-01-11 19:48:33 +00:00
|
|
|
// Revision 1.53 2002/01/11 19:48:29 jbravo
|
|
|
|
// Formatted the source in non DOS format.
|
|
|
|
//
|
2001-12-31 16:28:42 +00:00
|
|
|
// Revision 1.52 2001/12/31 16:28:42 jbravo
|
|
|
|
// I made a Booboo with the Log tag.
|
|
|
|
//
|
2001-12-31 16:16:59 +00:00
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
2001-05-06 20:50:27 +00:00
|
|
|
// 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
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
#include "q_shared.h"
|
|
|
|
#include "bg_public.h"
|
|
|
|
#include "bg_local.h"
|
|
|
|
|
2002-04-06 21:42:20 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
pmove_t *pm;
|
|
|
|
pml_t pml;
|
|
|
|
|
2001-07-24 01:50:01 +00:00
|
|
|
//Elder: reduce x-y speed on ladders by this factor so it 'feels' more like Q2
|
|
|
|
#define PM_LADDER_MOVE_REDUCTION 10
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// movement parameters
|
|
|
|
float pm_stopspeed = 100.0f;
|
|
|
|
float pm_duckScale = 0.25f;
|
|
|
|
float pm_swimScale = 0.50f;
|
|
|
|
float pm_wadeScale = 0.70f;
|
|
|
|
float pm_ladderScale = 0.75f; // more c3a ladders
|
2002-02-04 00:30:35 +00:00
|
|
|
float pm_maxspeed = 300;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
float pm_accelerate = 10.0f;
|
|
|
|
float pm_airaccelerate = 1.0f;
|
|
|
|
float pm_wateraccelerate = 4.0f;
|
|
|
|
float pm_flyaccelerate = 8.0f;
|
|
|
|
float pm_ladderAccelerate = 3000; // same as ladder friction.
|
|
|
|
|
|
|
|
float pm_friction = 6.0f;
|
|
|
|
float pm_waterfriction = 1.0f;
|
|
|
|
float pm_flightfriction = 3.0f;
|
|
|
|
float pm_spectatorfriction = 5.0f;
|
2001-11-12 07:59:19 +00:00
|
|
|
float pm_ladderfriction = 3000;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
2001-06-13 01:14:31 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
int c_pmove = 0;
|
|
|
|
|
2001-07-28 02:24:11 +00:00
|
|
|
/* [QUARANTINE] - Weapon Animations
|
|
|
|
===================
|
|
|
|
PM_StartWeaponAnim, PM_ContinueWeaponAnim
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
static void PM_StartWeaponAnim( int anim ) {
|
|
|
|
if ( pm->ps->pm_type >= PM_DEAD ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pm->ps->generic1 = ( ( pm->ps->generic1 & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PM_ContinueWeaponAnim( int anim ) {
|
|
|
|
if ( ( pm->ps->generic1 & ~ANIM_TOGGLEBIT ) == anim ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PM_StartWeaponAnim( anim );
|
|
|
|
}
|
|
|
|
// END
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
PM_AddEvent
|
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void PM_AddEvent( int newEvent ) {
|
|
|
|
BG_AddPredictableEventToPlayerstate( newEvent, 0, pm->ps );
|
|
|
|
}
|
|
|
|
|
2001-07-28 14:12:11 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
PM_AddEvent
|
|
|
|
|
|
|
|
Elder: stuffs event parameters
|
2001-08-30 09:47:39 +00:00
|
|
|
Be careful because you are stuffing the player
|
2001-07-28 14:12:11 +00:00
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void PM_AddEvent2( int newEvent, int eventParm ) {
|
|
|
|
BG_AddPredictableEventToPlayerstate( newEvent, eventParm, pm->ps );
|
|
|
|
}
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
static void PM_StartLegsAnim( int anim ) {
|
|
|
|
if ( pm->ps->pm_type >= PM_DEAD ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( pm->ps->legsTimer > 0 ) {
|
|
|
|
return; // a high priority animation is running
|
|
|
|
}
|
|
|
|
pm->ps->legsAnim = ( ( pm->ps->legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT )
|
|
|
|
| anim;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PM_ContinueLegsAnim( int anim ) {
|
|
|
|
if ( ( pm->ps->legsAnim & ~ANIM_TOGGLEBIT ) == anim ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( pm->ps->legsTimer > 0 ) {
|
|
|
|
return; // a high priority animation is running
|
|
|
|
}
|
|
|
|
PM_StartLegsAnim( anim );
|
|
|
|
}
|
|
|
|
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void PM_ForceLegsAnim( int anim ) {
|
|
|
|
pm->ps->legsTimer = 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;
|
2001-08-01 19:52:17 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
backoff = DotProduct (in, normal);
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( backoff < 0 ) {
|
|
|
|
backoff *= overbounce;
|
|
|
|
} else {
|
|
|
|
backoff /= overbounce;
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( i=0 ; i<3 ; i++ ) {
|
|
|
|
change = normal[i]*backoff;
|
|
|
|
out[i] = in[i] - change;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==================
|
|
|
|
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;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
vel = pm->ps->velocity;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
VectorCopy( vel, vec );
|
2002-05-08 07:24:33 +00:00
|
|
|
/*if ( pml.walking ) {
|
2001-05-06 20:50:27 +00:00
|
|
|
vec[2] = 0; // ignore slope movement
|
2002-05-08 07:24:33 +00:00
|
|
|
}*/
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
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 ) {
|
2002-04-26 05:29:38 +00:00
|
|
|
if ( pml.walking && !(pml.groundTrace.surfaceFlags & SURF_SLICK) && pm->ps->groundEntityNum) {
|
2001-05-06 20:50:27 +00:00
|
|
|
// if getting knocked back, no friction
|
|
|
|
if ( ! (pm->ps->pm_flags & PMF_TIME_KNOCKBACK) ) {
|
|
|
|
control = speed < pm_stopspeed ? pm_stopspeed : speed;
|
|
|
|
drop += control*pm_friction*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->powerups[PW_FLIGHT]) {
|
|
|
|
drop += speed*pm_flightfriction*pml.frametime;
|
|
|
|
}
|
|
|
|
|
2001-11-12 07:59:19 +00:00
|
|
|
if ( pml.ladder ) // If they're on a ladder...
|
2001-05-06 20:50:27 +00:00
|
|
|
{
|
2001-11-12 07:59:19 +00:00
|
|
|
drop += speed*pm_ladderfriction*pml.frametime; // Add ladder friction!
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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 ) {
|
|
|
|
int i;
|
|
|
|
float addspeed, accelspeed, currentspeed;
|
2002-02-04 00:30:35 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
currentspeed = DotProduct (pm->ps->velocity, wishdir);
|
|
|
|
addspeed = wishspeed - currentspeed;
|
|
|
|
if (addspeed <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
accelspeed = accel*pml.frametime*wishspeed;
|
|
|
|
if (accelspeed > addspeed) {
|
|
|
|
accelspeed = addspeed;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
for (i=0 ; i<3 ; i++) {
|
2001-11-12 07:59:19 +00:00
|
|
|
pm->ps->velocity[i] += accelspeed*wishdir[i];
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
============
|
|
|
|
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;
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
|
|
|
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;
|
2001-11-12 07:59:19 +00:00
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
PM_CheckJump
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
static qboolean PM_CheckJump( void ) {
|
|
|
|
if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
|
|
|
|
return qfalse; // don't allow jump until all buttons are up
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pm->cmd.upmove < 10 ) {
|
|
|
|
// not holding jump
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2002-05-08 07:24:33 +00:00
|
|
|
if (!pml.groundPlane && !pml.walking) return qfalse;
|
|
|
|
|
|
|
|
if ( pm->debugLevel ) {
|
|
|
|
Com_Printf("%i:jump\n", c_pmove);
|
|
|
|
}
|
2002-04-26 05:29:38 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
pml.groundPlane = qfalse; // jumping away
|
|
|
|
pml.walking = qfalse;
|
|
|
|
pm->ps->pm_flags |= PMF_JUMP_HELD;
|
|
|
|
|
|
|
|
pm->ps->groundEntityNum = ENTITYNUM_NONE;
|
2002-04-26 05:29:38 +00:00
|
|
|
pm->ps->velocity[2] += JUMP_VELOCITY;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
if (pm->ps->velocity[2] < JUMP_VELOCITY)
|
|
|
|
pm->ps->velocity[2] = JUMP_VELOCITY;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
PM_AddEvent( EV_JUMP );
|
|
|
|
|
2002-03-11 01:45:46 +00:00
|
|
|
PM_ForceLegsAnim( LEGS_JUMP );
|
|
|
|
pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
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 );
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2002-04-26 05:29:38 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
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
|
2002-04-26 05:29:38 +00:00
|
|
|
PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
|
|
|
|
pm->ps->velocity, OVERCLIP );
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
VectorNormalize(pm->ps->velocity);
|
|
|
|
VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
|
|
|
|
}
|
|
|
|
|
2002-02-04 00:30:35 +00:00
|
|
|
PM_StepSlideMove( qfalse );
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
PM_AirMove
|
|
|
|
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
static void PM_AirMove( void ) {
|
|
|
|
int i;
|
|
|
|
vec3_t wishvel;
|
|
|
|
float fmove, smove;
|
|
|
|
vec3_t wishdir;
|
|
|
|
float wishspeed;
|
|
|
|
float scale;
|
2002-04-26 05:29:38 +00:00
|
|
|
usercmd_t cmd;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
PM_CheckJump();
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_Friction();
|
|
|
|
|
|
|
|
fmove = pm->cmd.forwardmove;
|
|
|
|
smove = pm->cmd.rightmove;
|
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
cmd = pm->cmd;
|
|
|
|
scale = PM_CmdScale( &cmd );
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
// set the movementDir so clients can rotate the legs for strafing
|
|
|
|
PM_SetMovementDir();
|
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
// project moves down to flat plane
|
|
|
|
|
|
|
|
pml.forward[2] = 0;
|
|
|
|
pml.right[2] = 0;
|
|
|
|
VectorNormalize (pml.forward);
|
|
|
|
VectorNormalize (pml.right);
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
for ( i = 0 ; i < 2 ; i++ ) {
|
2002-04-26 05:29:38 +00:00
|
|
|
wishvel[i] = pml.forward[i]*fmove*scale + pml.right[i]*smove*scale;
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
wishvel[2] = 0;
|
|
|
|
|
|
|
|
VectorCopy (wishvel, wishdir);
|
|
|
|
wishspeed = VectorNormalize(wishdir);
|
2002-04-26 05:29:38 +00:00
|
|
|
//wishspeed *= scale;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
2002-02-04 00:30:35 +00:00
|
|
|
// not on ground, so little effect on velocity
|
|
|
|
PM_Accelerate (wishdir, wishspeed, pm_airaccelerate);
|
2001-05-06 20:50:27 +00:00
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
// 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 );
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
PM_GrappleMove
|
|
|
|
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
static void PM_GrappleMove( void ) {
|
|
|
|
vec3_t vel, v;
|
|
|
|
float vlen;
|
|
|
|
|
|
|
|
VectorScale(pml.forward, -16, v);
|
|
|
|
VectorAdd(pm->ps->grapplePoint, v, v);
|
|
|
|
VectorSubtract(v, pm->ps->origin, vel);
|
|
|
|
vlen = VectorLength(vel);
|
|
|
|
VectorNormalize( vel );
|
|
|
|
|
|
|
|
if (vlen <= 100)
|
|
|
|
VectorScale(vel, 10 * vlen, vel);
|
|
|
|
else
|
|
|
|
VectorScale(vel, 800, vel);
|
|
|
|
|
|
|
|
VectorCopy(vel, pm->ps->velocity);
|
|
|
|
|
|
|
|
pml.groundPlane = 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;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( pm->waterlevel > 2 && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) {
|
|
|
|
// begin swimming
|
|
|
|
PM_WaterMove();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-06-18 01:59:58 +00:00
|
|
|
//Blaze: Cant jump while someone has leg damage
|
2001-06-18 00:28:47 +00:00
|
|
|
if ( !((pm->ps->stats[STAT_RQ3] & RQ3_LEGDAMAGE) == RQ3_LEGDAMAGE) && PM_CheckJump () ) {
|
2001-05-06 20:50:27 +00:00
|
|
|
// jumped away
|
|
|
|
if ( pm->waterlevel > 1 ) {
|
|
|
|
PM_WaterMove();
|
|
|
|
} else {
|
|
|
|
PM_AirMove();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
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();
|
|
|
|
|
2002-03-02 08:03:14 +00:00
|
|
|
// project the forward and right directions onto the ground plane
|
|
|
|
pml.forward[2] = 0;
|
|
|
|
pml.right[2] = 0;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
for ( i = 0 ; i < 3 ; i++ ) {
|
2002-03-02 08:03:14 +00:00
|
|
|
wishvel[i] = pml.forward[i]*fmove + pml.right[i]*smove;
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
2002-03-02 08:03:14 +00:00
|
|
|
// when going up or down slopes the wish velocity should Not be zero
|
|
|
|
// wishvel[2] = 0;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
VectorCopy (wishvel, wishdir);
|
|
|
|
wishspeed = VectorNormalize(wishdir);
|
2002-03-02 08:03:14 +00:00
|
|
|
wishspeed *= scale;
|
2001-07-30 17:09:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// 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 = pm_airaccelerate;
|
|
|
|
} else {
|
|
|
|
accelerate = pm_accelerate;
|
|
|
|
}
|
|
|
|
|
|
|
|
PM_Accelerate (wishdir, wishspeed, accelerate);
|
|
|
|
|
2002-05-07 05:07:32 +00:00
|
|
|
if (pm->ps->velocity[2] < 0) pm->ps->velocity[2] = 0;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
2002-05-07 05:07:32 +00:00
|
|
|
if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) {
|
|
|
|
pm->ps->velocity[2] -= pm->ps->gravity * pml.frametime;
|
|
|
|
}
|
2002-04-26 05:29:38 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// don't do anything if standing still
|
|
|
|
if (!pm->ps->velocity[0] && !pm->ps->velocity[1]) {
|
|
|
|
return;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_StepSlideMove( qfalse );
|
2002-05-07 05:07:32 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
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;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
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 ) {
|
2002-04-06 21:42:20 +00:00
|
|
|
int Material = GetMaterialFromFlag(pml.groundTrace.surfaceFlags);
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( pml.groundTrace.surfaceFlags & SURF_NOSTEPS ) {
|
|
|
|
return 0;
|
|
|
|
}
|
2002-04-06 21:42:20 +00:00
|
|
|
//Makro - new surfaceparm system
|
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_METALSTEPS ) {
|
|
|
|
if ( Material == MAT_METALSTEPS ) {
|
2001-05-06 20:50:27 +00:00
|
|
|
return EV_FOOTSTEP_METAL;
|
|
|
|
}
|
2001-08-06 19:15:00 +00:00
|
|
|
//Elder: added for footstep support
|
2002-04-06 21:42:20 +00:00
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_GRASS ) {
|
|
|
|
if ( Material == MAT_GRASS ) {
|
2001-08-06 19:15:00 +00:00
|
|
|
return EV_FOOTSTEP_GRASS;
|
|
|
|
}
|
2001-11-14 06:57:40 +00:00
|
|
|
|
2002-01-24 14:20:53 +00:00
|
|
|
// JBravo: re-enables Gravel.
|
2002-04-06 21:42:20 +00:00
|
|
|
//Makro - new surfaceparm system
|
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_GRAVEL ) {
|
|
|
|
if ( Material == MAT_GRAVEL ) {
|
2002-01-24 14:20:53 +00:00
|
|
|
return EV_FOOTSTEP_GRAVEL;
|
|
|
|
}
|
2001-08-17 20:48:18 +00:00
|
|
|
|
2002-04-06 21:42:20 +00:00
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_WOOD ) {
|
|
|
|
if ( Material == MAT_WOOD ) {
|
2001-08-17 20:48:18 +00:00
|
|
|
return EV_FOOTSTEP_WOOD;
|
|
|
|
}
|
|
|
|
|
2002-04-06 21:42:20 +00:00
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_CARPET ) {
|
|
|
|
if ( Material == MAT_CARPET ) {
|
2001-08-17 20:48:18 +00:00
|
|
|
return EV_FOOTSTEP_CARPET;
|
|
|
|
}
|
|
|
|
|
2002-04-06 21:42:20 +00:00
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_METAL2 ) {
|
|
|
|
if ( Material == MAT_METAL2 ) {
|
2001-08-17 20:48:18 +00:00
|
|
|
return EV_FOOTSTEP_METAL2;
|
|
|
|
}
|
|
|
|
|
2002-01-24 14:20:53 +00:00
|
|
|
// JBravo: Begin adding new sounds
|
2002-04-06 21:42:20 +00:00
|
|
|
//Makro - new surfaceparm system
|
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_SNOW ) {
|
|
|
|
if ( Material == MAT_SNOW ) {
|
2002-01-24 14:20:53 +00:00
|
|
|
return EV_FOOTSTEP_SNOW;
|
|
|
|
}
|
|
|
|
|
2002-04-06 21:42:20 +00:00
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_MUD ) {
|
|
|
|
if ( Material == MAT_MUD ) {
|
2002-01-24 14:20:53 +00:00
|
|
|
return EV_FOOTSTEP_MUD;
|
|
|
|
}
|
|
|
|
|
2002-04-06 21:42:20 +00:00
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_WOOD2 ) {
|
|
|
|
if ( Material == MAT_WOOD2 ) {
|
2002-01-24 14:20:53 +00:00
|
|
|
return EV_FOOTSTEP_WOOD2;
|
|
|
|
}
|
|
|
|
|
2002-04-06 21:42:20 +00:00
|
|
|
//if ( pml.groundTrace.surfaceFlags & SURF_HARDMETAL ) {
|
|
|
|
if ( Material == MAT_HARDMETAL ) {
|
2002-01-24 14:20:53 +00:00
|
|
|
return EV_FOOTSTEP_HARDMETAL;
|
|
|
|
}
|
|
|
|
// JBravo: end adding new sounds
|
2002-04-20 15:05:08 +00:00
|
|
|
// Makro - 5 new sounds
|
|
|
|
if ( Material == MAT_LEAVES ) {
|
|
|
|
return EV_FOOTSTEP_LEAVES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Material == MAT_CEMENT ) {
|
|
|
|
return EV_FOOTSTEP_CEMENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Material == MAT_MARBLE ) {
|
|
|
|
return EV_FOOTSTEP_MARBLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Material == MAT_SNOW2 ) {
|
|
|
|
return EV_FOOTSTEP_SNOW2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( Material == MAT_HARDSTEPS ) {
|
|
|
|
return EV_FOOTSTEP_HARDSTEPS;
|
|
|
|
}
|
2002-05-11 19:18:20 +00:00
|
|
|
|
|
|
|
if ( Material == MAT_SAND ) {
|
|
|
|
return EV_FOOTSTEP_SAND;
|
|
|
|
}
|
2002-04-20 15:05:08 +00:00
|
|
|
// Makro - end new sounds
|
2002-01-24 14:20:53 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
return EV_FOOTSTEP;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
PM_CrashLand
|
|
|
|
|
|
|
|
Check for hard landings that generate sound events
|
|
|
|
=================
|
|
|
|
*/
|
|
|
|
static void PM_CrashLand( void ) {
|
|
|
|
float delta;
|
2001-07-16 01:40:33 +00:00
|
|
|
//float dist;
|
|
|
|
//float vel, acc;
|
|
|
|
//float t;
|
|
|
|
//float a, b, c, den;
|
2001-05-06 20:50:27 +00:00
|
|
|
int damage;
|
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
// JBravo: no falling at all during LCA in Teamplay
|
2002-03-23 05:17:43 +00:00
|
|
|
if (pm->lca) {
|
2002-02-27 01:54:29 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-03-11 01:45:46 +00:00
|
|
|
PM_ForceLegsAnim( LEGS_LAND );
|
2001-05-06 20:50:27 +00:00
|
|
|
|
2001-10-11 22:52:43 +00:00
|
|
|
// Elder: 300/320 factor included
|
|
|
|
delta = 0.9375f * (pm->ps->velocity[2] - pml.previous_velocity[2]);
|
2001-05-06 20:50:27 +00:00
|
|
|
delta = delta*delta * 0.0001;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2001-07-10 01:26:35 +00:00
|
|
|
if (delta > 30)
|
|
|
|
{
|
|
|
|
damage = (int)(((delta-30)/2));
|
|
|
|
if (damage < 1) damage = 1;
|
|
|
|
damage *= 10;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
|
|
|
|
2001-07-10 01:26:35 +00:00
|
|
|
if ( !(pml.groundTrace.surfaceFlags & SURF_NODAMAGE) ) {
|
2002-04-26 05:29:38 +00:00
|
|
|
//Blaze lots of changes to make it more like aq2
|
|
|
|
// this is a pain grunt, so don't play it if dead
|
2001-07-10 01:26:35 +00:00
|
|
|
if ( pm->ps->stats[STAT_HEALTH] > 0 && damage > 0) {
|
2001-07-27 00:21:23 +00:00
|
|
|
if (bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_SLIPPERS)
|
|
|
|
PM_AddEvent( EV_FALL_FAR_NOSOUND );
|
|
|
|
else
|
|
|
|
PM_AddEvent( EV_FALL_FAR );
|
2001-11-12 07:59:19 +00:00
|
|
|
|
|
|
|
|
2001-07-10 01:26:35 +00:00
|
|
|
pm->ps->stats[STAT_FALLDAMAGE] = damage;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
else
|
2001-07-10 01:26:35 +00:00
|
|
|
{
|
|
|
|
PM_AddEvent( PM_FootstepForSurface() );
|
2001-11-12 07:59:19 +00:00
|
|
|
//Elder: added? useful?
|
2001-07-10 01:26:35 +00:00
|
|
|
pm->ps->stats[STAT_FALLDAMAGE] = 0;
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
else if (delta > 20)
|
2001-07-27 00:21:23 +00:00
|
|
|
{ if (bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_SLIPPERS)
|
2001-11-12 07:59:19 +00:00
|
|
|
{
|
2001-10-11 22:52:43 +00:00
|
|
|
PM_AddEvent( EV_FALL_SHORT_NOSOUND );
|
2001-11-12 07:59:19 +00:00
|
|
|
//Elder: added? useful?
|
2001-07-27 00:21:23 +00:00
|
|
|
pm->ps->stats[STAT_FALLDAMAGE] = 0;
|
|
|
|
}
|
|
|
|
else
|
2001-11-12 07:59:19 +00:00
|
|
|
{
|
2001-10-11 22:52:43 +00:00
|
|
|
PM_AddEvent( EV_FALL_SHORT );
|
2001-11-12 07:59:19 +00:00
|
|
|
//Elder: added? useful?
|
2001-07-27 00:21:23 +00:00
|
|
|
pm->ps->stats[STAT_FALLDAMAGE] = 0;
|
|
|
|
}
|
2001-07-16 01:40:33 +00:00
|
|
|
}
|
2001-07-27 00:21:23 +00:00
|
|
|
else if (!(bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_SLIPPERS))
|
2001-07-16 01:40:33 +00:00
|
|
|
{
|
2001-10-11 22:52:43 +00:00
|
|
|
// Elder: don't spam sound events going up -- more like Q2 ladders as well
|
|
|
|
if (!pml.ladder || pm->ps->velocity[2] < 0)
|
|
|
|
PM_AddEvent( PM_FootstepForSurface() );
|
2001-11-12 07:59:19 +00:00
|
|
|
//Elder: added? useful?
|
2001-07-16 01:40:33 +00:00
|
|
|
pm->ps->stats[STAT_FALLDAMAGE] = 0;
|
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask);
|
|
|
|
if ( trace.fraction == 1.0 ) {
|
2002-03-11 01:45:46 +00:00
|
|
|
PM_ForceLegsAnim( LEGS_JUMP );
|
|
|
|
pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pm->ps->groundEntityNum = ENTITYNUM_NONE;
|
|
|
|
pml.groundPlane = qfalse;
|
|
|
|
pml.walking = qfalse;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
PM_GroundTrace
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
static void PM_GroundTrace( void ) {
|
|
|
|
vec3_t point;
|
|
|
|
trace_t trace;
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
// do something corrective if the trace starts in a solid...
|
|
|
|
if ( trace.allsolid ) {
|
|
|
|
if ( !PM_CorrectAllSolid(&trace) )
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
// if the trace didn't hit anything and not on ladder, we are in free fall
|
2001-10-11 22:52:43 +00:00
|
|
|
if ( trace.fraction == 1.0 && !pml.ladder) {
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_GroundTraceMissed();
|
|
|
|
pml.groundPlane = qfalse;
|
|
|
|
pml.walking = qfalse;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if getting thrown off the ground
|
2002-05-08 07:24:33 +00:00
|
|
|
/*
|
|
|
|
// NiceAss: Comment out and you get double jumping =D
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( pm->ps->velocity[2] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) {
|
|
|
|
if ( pm->debugLevel ) {
|
|
|
|
Com_Printf("%i:kickoff\n", c_pmove);
|
|
|
|
}
|
2002-04-26 05:29:38 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// go into jump animation
|
2002-03-11 01:45:46 +00:00
|
|
|
PM_ForceLegsAnim( LEGS_JUMP );
|
|
|
|
pm->ps->pm_flags &= ~PMF_BACKWARDS_JUMP;
|
2002-04-26 05:29:38 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
pm->ps->groundEntityNum = ENTITYNUM_NONE;
|
|
|
|
pml.groundPlane = qfalse;
|
|
|
|
pml.walking = qfalse;
|
|
|
|
return;
|
|
|
|
}
|
2002-05-08 07:24:33 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (pm->ps->velocity[2] > 180)
|
|
|
|
{ // NiceAss: This is here for slope acceleration!
|
|
|
|
if ( pm->debugLevel ) {
|
|
|
|
Com_Printf("%i:slopeslide\n", c_pmove);
|
|
|
|
}
|
|
|
|
|
|
|
|
pml.groundPlane = qfalse;
|
|
|
|
pm->ps->groundEntityNum = ENTITYNUM_NONE;
|
|
|
|
//pml.walking = qfalse; // Maybe not needed?
|
|
|
|
return;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// slopes that are too steep will not be considered onground
|
2001-10-11 22:52:43 +00:00
|
|
|
// Elder: added ladder check
|
|
|
|
if ( trace.plane.normal[2] < MIN_WALK_NORMAL && !pml.ladder) {
|
2001-05-06 20:50:27 +00:00
|
|
|
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;
|
2002-05-07 05:07:32 +00:00
|
|
|
pml.groundPlane = qfalse; //qtrue;
|
2001-05-06 20:50:27 +00:00
|
|
|
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);
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_CrashLand();
|
|
|
|
|
2001-10-11 22:52:43 +00:00
|
|
|
if (pml.ladder)
|
|
|
|
{
|
|
|
|
pml.groundPlane = qfalse;
|
|
|
|
pml.walking = qfalse;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// 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;
|
|
|
|
|
|
|
|
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];
|
2001-11-12 07:59:19 +00:00
|
|
|
point[2] = pm->ps->origin[2] + MINS_Z + 1;
|
2001-05-06 20:50:27 +00:00
|
|
|
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;
|
2001-11-12 07:59:19 +00:00
|
|
|
vec3_t point; // NiceAss: Added for FUNKY CODE ALERT section
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
|
|
|
|
if ( pm->ps->pm_flags & PMF_INVULEXPAND ) {
|
|
|
|
// invulnerability sphere has a 42 units radius
|
|
|
|
VectorSet( pm->mins, -42, -42, -42 );
|
|
|
|
VectorSet( pm->maxs, 42, 42, 42 );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VectorSet( pm->mins, -15, -15, MINS_Z );
|
|
|
|
VectorSet( pm->maxs, 15, 15, 16 );
|
|
|
|
}
|
|
|
|
pm->ps->pm_flags |= PMF_DUCKED;
|
|
|
|
pm->ps->viewheight = CROUCH_VIEWHEIGHT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pm->ps->pm_flags &= ~PMF_INVULEXPAND;
|
|
|
|
|
|
|
|
pm->mins[0] = -15;
|
|
|
|
pm->mins[1] = -15;
|
|
|
|
|
|
|
|
pm->maxs[0] = 15;
|
|
|
|
pm->maxs[1] = 15;
|
|
|
|
|
|
|
|
pm->mins[2] = MINS_Z;
|
|
|
|
|
|
|
|
if (pm->ps->pm_type == PM_DEAD)
|
|
|
|
{
|
|
|
|
pm->maxs[2] = -8;
|
|
|
|
pm->ps->viewheight = DEAD_VIEWHEIGHT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-11-12 07:59:19 +00:00
|
|
|
// NiceAss: FUNKY CODE ALERT!
|
|
|
|
// Check to see if there is ground below. No? then you can't duck...
|
|
|
|
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);
|
|
|
|
|
2001-11-25 23:04:08 +00:00
|
|
|
if ( trace.fraction == 1.0 && !pml.ladder && !(pm->ps->pm_flags & PMF_DUCKED)) {
|
2001-11-12 07:59:19 +00:00
|
|
|
pm->maxs[2] = 32;
|
|
|
|
pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// End of funky code alert
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
if (pm->cmd.upmove < 0)
|
|
|
|
{ // 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] = 32;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
if (pm->ps->pm_flags & PMF_DUCKED )
|
2001-05-06 20:50:27 +00:00
|
|
|
{
|
|
|
|
pm->maxs[2] = 16;
|
|
|
|
pm->ps->viewheight = CROUCH_VIEWHEIGHT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pm->maxs[2] = 32;
|
|
|
|
pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//===================================================================
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
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
|
|
|
|
//
|
|
|
|
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 ) {
|
|
|
|
|
|
|
|
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
|
|
|
|
PM_ContinueLegsAnim( LEGS_IDLECR );
|
|
|
|
}
|
|
|
|
// airborne leaves position in cycle intact, but doesn't advance
|
|
|
|
if ( pm->waterlevel > 1 ) {
|
|
|
|
PM_ContinueLegsAnim( LEGS_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 ) {
|
|
|
|
PM_ContinueLegsAnim( LEGS_IDLECR );
|
|
|
|
} else {
|
|
|
|
PM_ContinueLegsAnim( LEGS_IDLE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
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 ) {
|
|
|
|
PM_ContinueLegsAnim( LEGS_BACKCR );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PM_ContinueLegsAnim( LEGS_WALKCR );
|
|
|
|
}
|
|
|
|
// ducked characters never play footsteps
|
|
|
|
/*
|
|
|
|
} else if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
|
|
|
|
if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
|
|
|
|
bobmove = 0.4; // faster speeds bob faster
|
|
|
|
footstep = qtrue;
|
|
|
|
} else {
|
|
|
|
bobmove = 0.3;
|
|
|
|
}
|
|
|
|
PM_ContinueLegsAnim( LEGS_BACK );
|
|
|
|
*/
|
|
|
|
} else {
|
|
|
|
if ( !( pm->cmd.buttons & BUTTON_WALKING ) ) {
|
|
|
|
bobmove = 0.4f; // faster speeds bob faster
|
|
|
|
if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
|
|
|
|
PM_ContinueLegsAnim( LEGS_BACK );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PM_ContinueLegsAnim( LEGS_RUN );
|
|
|
|
}
|
|
|
|
footstep = qtrue;
|
|
|
|
} else {
|
|
|
|
bobmove = 0.3f; // walking bobs slow
|
|
|
|
if ( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) {
|
|
|
|
PM_ContinueLegsAnim( LEGS_BACKWALK );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
PM_ContinueLegsAnim( LEGS_WALK );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 ) {
|
2001-07-01 05:11:12 +00:00
|
|
|
//Elder: we can check for slippers here!
|
2001-05-06 20:50:27 +00:00
|
|
|
// on ground will only play sounds if running
|
2001-07-27 00:21:23 +00:00
|
|
|
if (( footstep && !pm->noFootsteps ) && !(bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_SLIPPERS)) {
|
2001-05-06 20:50:27 +00:00
|
|
|
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 ) {
|
2002-01-11 20:20:58 +00:00
|
|
|
//G_Printf("CHANGING WEAP TO: %i\n", weapon);
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( weapon <= WP_NONE || weapon >= WP_NUM_WEAPONS ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
|
|
|
|
return;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PM_AddEvent( EV_CHANGE_WEAPON );
|
2001-08-17 20:48:18 +00:00
|
|
|
|
|
|
|
//Elder: ignore disarm delays when throwing a weapon
|
|
|
|
if (pm->ps->stats[STAT_RQ3] & RQ3_THROWWEAPON)
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_THROWWEAPON;
|
|
|
|
pm->ps->weaponTime = 0;
|
2001-06-24 02:08:15 +00:00
|
|
|
}
|
2001-08-17 20:48:18 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
//pm->ps->weaponTime += 200;
|
|
|
|
//Elder: dependent time for each weapon
|
|
|
|
switch (pm->ps->weapon) {
|
|
|
|
case WP_PISTOL:
|
|
|
|
pm->ps->weaponTime += RQ3_PISTOL_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_M3:
|
|
|
|
pm->ps->weaponTime += RQ3_M3_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_M4:
|
|
|
|
pm->ps->weaponTime += RQ3_M4_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_MP5:
|
|
|
|
pm->ps->weaponTime += RQ3_MP5_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_HANDCANNON:
|
|
|
|
pm->ps->weaponTime += RQ3_HANDCANNON_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_SSG3000:
|
|
|
|
pm->ps->weaponTime += RQ3_SSG3000_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_AKIMBO:
|
|
|
|
pm->ps->weaponTime += RQ3_AKIMBO_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_KNIFE:
|
|
|
|
pm->ps->weaponTime += RQ3_KNIFE_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_GRENADE:
|
|
|
|
pm->ps->weaponTime += RQ3_GRENADE_DISARM_DELAY;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//Elder: shouldn't be here
|
|
|
|
//G_Printf("PM_BeginWeaponChange: received bad weapon %d\n", pm->ps->weapon);
|
|
|
|
pm->ps->weaponTime += 600;
|
|
|
|
break;
|
|
|
|
}
|
2001-06-24 02:08:15 +00:00
|
|
|
|
2002-04-26 05:29:38 +00:00
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
if ( pm->ps->weapon == WP_KNIFE && !(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) )
|
2001-09-11 00:12:29 +00:00
|
|
|
PM_StartWeaponAnim(WP_ANIM_THROWDISARM);
|
2001-11-25 23:04:08 +00:00
|
|
|
else {
|
2001-10-30 23:26:03 +00:00
|
|
|
PM_StartWeaponAnim(WP_ANIM_DISARM);
|
2001-11-25 23:04:08 +00:00
|
|
|
}
|
2001-08-17 20:48:18 +00:00
|
|
|
}
|
2001-08-30 09:47:39 +00:00
|
|
|
|
|
|
|
// Elder: cancel reload stuff here
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = 0;
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
|
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_FASTRELOADS;
|
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_LOCKRELOADS;
|
2001-10-11 22:52:43 +00:00
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_QUEUERELOAD;
|
2001-08-30 09:47:39 +00:00
|
|
|
|
2001-11-11 07:24:27 +00:00
|
|
|
// Elder: cancel burst shots
|
|
|
|
pm->ps->stats[STAT_BURST] = 0;
|
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
// NiceAss: Added this as a fix for knifes and grenades when you throw the last one.
|
|
|
|
if ( ( (pm->ps->weapon == WP_GRENADE || pm->ps->weapon == WP_KNIFE) && pm->ps->ammo[pm->ps->weapon] == 0) &&
|
|
|
|
pm->ps->weaponstate != WEAPON_FIRING )
|
|
|
|
{
|
|
|
|
pm->ps->weaponstate = WEAPON_DROPPING;
|
2001-11-25 23:04:08 +00:00
|
|
|
pm->ps->weaponTime = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
pm->ps->weaponstate = WEAPON_DROPPING;
|
|
|
|
|
2001-10-30 23:26:03 +00:00
|
|
|
if (pm->ps->weapon == WP_KNIFE && !(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE))
|
2001-09-11 00:12:29 +00:00
|
|
|
PM_StartWeaponAnim(WP_ANIM_THROWDISARM);
|
2001-11-25 23:04:08 +00:00
|
|
|
else {
|
2001-10-30 23:26:03 +00:00
|
|
|
PM_StartWeaponAnim(WP_ANIM_DISARM);
|
2001-11-25 23:04:08 +00:00
|
|
|
}
|
2001-06-24 02:08:15 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_StartTorsoAnim( TORSO_DROP );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
PM_FinishWeaponChange
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
static void PM_FinishWeaponChange( void ) {
|
2002-03-27 17:20:38 +00:00
|
|
|
int weapon, savedWeap;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
weapon = pm->cmd.weapon;
|
2001-06-10 06:46:06 +00:00
|
|
|
|
2002-03-27 17:20:38 +00:00
|
|
|
// JBravo: debug for the bandage bug
|
|
|
|
savedWeap = pm->ps->weapon;
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( weapon < WP_NONE || weapon >= WP_NUM_WEAPONS ) {
|
2002-05-01 21:14:59 +00:00
|
|
|
// Com_Printf("BANDAGEBUG: (1) weapon is %d and cmd.weapon is %d. Reverting to previous weapon\n", pm->ps->weapon,
|
|
|
|
// weapon);
|
2002-03-27 17:20:38 +00:00
|
|
|
weapon = savedWeap;
|
|
|
|
// weapon = WP_NONE;
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( !( pm->ps->stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) {
|
2002-05-01 21:14:59 +00:00
|
|
|
// Com_Printf("BANDAGEBUG: (2) weapon is %d and cmd.weapon is %d. Reverting to previous weapon\n", pm->ps->weapon,
|
|
|
|
// weapon);
|
2002-03-27 17:20:38 +00:00
|
|
|
weapon = savedWeap;
|
|
|
|
// weapon = WP_NONE;
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
//Remove grenade/knife if out of ammo
|
|
|
|
if ( (weapon == WP_GRENADE || weapon == WP_KNIFE) && pm->ps->ammo[weapon] == 0)
|
2001-07-16 01:40:33 +00:00
|
|
|
{
|
2001-12-17 15:08:34 +00:00
|
|
|
if (weapon == WP_GRENADE) pm->ps->stats[STAT_WEAPONS] &= ~(1 << WP_GRENADE);
|
|
|
|
if (weapon == WP_KNIFE) pm->ps->stats[STAT_WEAPONS] &= ~(1 << WP_KNIFE);
|
2001-07-16 01:40:33 +00:00
|
|
|
weapon = WP_PISTOL;
|
|
|
|
}
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
pm->ps->weapon = weapon;
|
|
|
|
pm->ps->weaponstate = WEAPON_RAISING;
|
2001-06-24 02:08:15 +00:00
|
|
|
//Elder: weapon-dependent timing
|
2001-08-06 19:15:00 +00:00
|
|
|
switch (pm->ps->weapon) {
|
2001-06-24 02:08:15 +00:00
|
|
|
case WP_PISTOL:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_PISTOL_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
case WP_M3:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_M3_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
case WP_M4:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_M4_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
case WP_MP5:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_MP5_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
case WP_HANDCANNON:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_HANDCANNON_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
case WP_SSG3000:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_SSG3000_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
case WP_AKIMBO:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_AKIMBO_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
case WP_KNIFE:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_KNIFE_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
case WP_GRENADE:
|
2001-08-06 19:15:00 +00:00
|
|
|
pm->ps->weaponTime += RQ3_GRENADE_ACTIVATE_DELAY;
|
2001-06-24 02:08:15 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//Elder: shouldn't be here
|
|
|
|
//G_Printf("PM_FinishWeaponChange: received bad weapon %d\n", pm->ps->weapon);
|
|
|
|
pm->ps->weaponTime += 750;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-10-30 23:26:03 +00:00
|
|
|
if (pm->ps->weapon == WP_KNIFE && !(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE))
|
2001-09-11 00:12:29 +00:00
|
|
|
PM_StartWeaponAnim(WP_ANIM_THROWACTIVATE);
|
2001-10-30 23:26:03 +00:00
|
|
|
else
|
|
|
|
PM_StartWeaponAnim(WP_ANIM_ACTIVATE);
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_StartTorsoAnim( TORSO_RAISE );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
==============
|
|
|
|
PM_TorsoAnimation
|
|
|
|
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static void PM_TorsoAnimation( void ) {
|
|
|
|
if ( pm->ps->weaponstate == WEAPON_READY ) {
|
|
|
|
if ( pm->ps->weapon == WP_KNIFE ) {
|
|
|
|
PM_ContinueTorsoAnim( TORSO_STAND2 );
|
|
|
|
} else {
|
|
|
|
PM_ContinueTorsoAnim( TORSO_STAND );
|
|
|
|
}
|
2001-07-28 02:24:11 +00:00
|
|
|
// QUARANTINE - Weapon Animation
|
|
|
|
// Should always draw the weapon when it is just ready
|
2001-09-11 00:12:29 +00:00
|
|
|
if (pm->ps->ammo[pm->ps->weapon] == 0)
|
|
|
|
PM_ContinueWeaponAnim( WP_ANIM_EMPTY );
|
|
|
|
else if (pm->ps->weapon == WP_KNIFE && !(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE))
|
|
|
|
PM_ContinueWeaponAnim(WP_ANIM_THROWIDLE);
|
2001-10-30 23:26:03 +00:00
|
|
|
else
|
|
|
|
PM_ContinueWeaponAnim(WP_ANIM_IDLE);
|
2001-09-11 00:12:29 +00:00
|
|
|
|
2001-07-28 02:24:11 +00:00
|
|
|
// PM_ContinueWeaponAnim( WP_ANIM_READY );
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
PM_Reload
|
|
|
|
|
|
|
|
Added by Elder
|
|
|
|
What a mess this is :/
|
|
|
|
FIXME: This is poorly implemented
|
|
|
|
|
|
|
|
Does reload stuff like fast-reloads, sound events,
|
|
|
|
some ammo synchronization, etc.
|
|
|
|
Clip management is handled on the server (ReloadWeapon)
|
|
|
|
because we can't store all the clips in a playerstate (nor should we)
|
|
|
|
It is triggered by BUTTON_AFFIRMATIVE (bind +button5)
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static void PM_Reload( void )
|
|
|
|
{
|
|
|
|
// int weapon = pm->ps->weapon;
|
2001-10-11 22:52:43 +00:00
|
|
|
int truePress = 0;
|
2001-08-30 09:47:39 +00:00
|
|
|
|
|
|
|
// only normal/noclip players can reload
|
|
|
|
if (pm->ps->pm_type > PM_NOCLIP)
|
|
|
|
{
|
|
|
|
pm->ps->pm_flags &= ~PMF_RELOAD_HELD;
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = 0;
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
|
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_FASTRELOADS;
|
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_LOCKRELOADS;
|
2001-10-11 22:52:43 +00:00
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_QUEUERELOAD;
|
2001-08-30 09:47:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-10-11 22:52:43 +00:00
|
|
|
// try to reload since it's queued
|
|
|
|
if ( pm->ps->stats[STAT_RQ3] & RQ3_QUEUERELOAD )
|
|
|
|
{
|
|
|
|
if ( (pm->cmd.buttons & BUTTON_AFFIRMATIVE) && !(pm->ps->pm_flags & PMF_RELOAD_HELD))
|
|
|
|
truePress = 1;
|
|
|
|
|
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_QUEUERELOAD;
|
|
|
|
pm->ps->pm_flags &= ~PMF_RELOAD_HELD;
|
|
|
|
pm->cmd.buttons |= BUTTON_AFFIRMATIVE;
|
|
|
|
}
|
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) {
|
|
|
|
if ( !(pm->ps->pm_flags & PMF_RELOAD_HELD) )
|
|
|
|
{
|
|
|
|
// prevent throttling
|
|
|
|
pm->ps->pm_flags |= PMF_RELOAD_HELD;
|
|
|
|
|
|
|
|
// check for bursting or weapon delay
|
|
|
|
if (pm->ps->stats[STAT_BURST] > 0 || pm->ps->weaponTime > 0)
|
2001-10-11 22:52:43 +00:00
|
|
|
{
|
|
|
|
if (truePress && (pm->ps->weapon == WP_SSG3000 || pm->ps->weapon == WP_M3))
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_RQ3] |= RQ3_FASTRELOADS;
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pm->ps->stats[STAT_RQ3] |= RQ3_QUEUERELOAD;
|
2001-08-30 09:47:39 +00:00
|
|
|
return;
|
2001-10-11 22:52:43 +00:00
|
|
|
}
|
2001-08-30 09:47:39 +00:00
|
|
|
|
|
|
|
// check for bandaging
|
2002-03-18 19:19:08 +00:00
|
|
|
/* if (pm->ps->stats[STAT_RQ3] & RQ3_BANDAGE_WORK)
|
|
|
|
return;
|
|
|
|
*/
|
|
|
|
//Slicer
|
|
|
|
if(pm->ps->weaponstate == WEAPON_BANDAGING)
|
2001-08-30 09:47:39 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// check for full clip or non-reloadable weapons
|
|
|
|
if (pm->ps->ammo[pm->ps->weapon] == ClipAmountForAmmo(pm->ps->weapon) ||
|
|
|
|
pm->ps->weapon == WP_KNIFE ||
|
|
|
|
pm->ps->weapon == WP_GRENADE)
|
|
|
|
{
|
|
|
|
//Com_Printf("No need to reload.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for insufficient ammo
|
|
|
|
if (pm->ps->stats[STAT_CLIPS] <= 0)
|
|
|
|
{
|
|
|
|
//Com_Printf("Out of ammo.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (pm->ps->weapon == WP_HANDCANNON ||
|
|
|
|
pm->ps->weapon == WP_AKIMBO)
|
|
|
|
{
|
|
|
|
if (pm->ps->stats[STAT_CLIPS] < 2)
|
|
|
|
{
|
|
|
|
//Com_Printf("Not enough ammo.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for fast-reload interrupt
|
|
|
|
if (pm->ps->weapon == WP_M3 || pm->ps->weapon == WP_SSG3000)
|
|
|
|
{
|
|
|
|
if (pm->ps->stats[STAT_RELOADTIME] > 0) {
|
|
|
|
if ( pm->ps->stats[STAT_RQ3] & RQ3_LOCKRELOADS )
|
|
|
|
{
|
2001-09-11 00:12:29 +00:00
|
|
|
//Com_Printf("============= Locked out in fast-reload interrupt\n");
|
2001-08-30 09:47:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//if (pm->ps->ammo[pm->ps->weapon] + pm->ps->stats[STAT_RELOADATTEMPTS] < ClipAmountForAmmo(pm->ps->weapon) &&
|
|
|
|
//pm->ps->stats[STAT_RELOADATTEMPTS] < pm->ps->stats[STAT_CLIPS])
|
|
|
|
if (pm->ps->stats[STAT_RELOADATTEMPTS] < ClipAmountForAmmo(pm->ps->weapon))
|
|
|
|
{
|
|
|
|
//Com_Printf("Hit fast-reload entrance\n");
|
|
|
|
// add to reload queue and enable fast-reloads flag
|
|
|
|
pm->ps->stats[STAT_RQ3] |= RQ3_FASTRELOADS;
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS]++;
|
2001-09-11 00:12:29 +00:00
|
|
|
//Com_Printf("======== Reload attempts: %i ========\n", pm->ps->stats[STAT_RELOADATTEMPTS]);
|
2001-08-30 09:47:39 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fresh reload
|
|
|
|
if (pm->ps->stats[STAT_RELOADTIME] == 0)
|
|
|
|
{
|
|
|
|
// set reload time according to weapon
|
|
|
|
switch (pm->ps->weapon)
|
|
|
|
{
|
|
|
|
case WP_PISTOL:
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_PISTOL_RELOAD_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_AKIMBO:
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_AKIMBO_RELOAD_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_M3:
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_M3_RELOAD_DELAY;
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS]++;
|
|
|
|
break;
|
|
|
|
case WP_M4:
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_M4_RELOAD_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_MP5:
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_MP5_RELOAD_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_HANDCANNON:
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_HANDCANNON_RELOAD_DELAY;
|
|
|
|
break;
|
|
|
|
case WP_SSG3000:
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_SSG3000_RELOAD_DELAY;
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS]++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-10-11 22:52:43 +00:00
|
|
|
// start the animation off
|
|
|
|
if (pm->ps->weaponstate != WEAPON_RELOADING)
|
|
|
|
PM_StartWeaponAnim(WP_ANIM_RELOAD);
|
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
pm->ps->weaponstate = WEAPON_RELOADING;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
PM_AddEvent(EV_RELOAD_WEAPON0);
|
|
|
|
//Com_Printf("Starting reload\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pm->ps->pm_flags &= ~PMF_RELOAD_HELD;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
// in-progress reload
|
|
|
|
if (pm->ps->stats[STAT_RELOADTIME] > 0)
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] -= pml.msec;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
// process any fast-reload stuff here
|
|
|
|
if (pm->ps->weapon == WP_M3 || pm->ps->weapon == WP_SSG3000) {
|
|
|
|
if ((pm->ps->stats[STAT_RQ3] & RQ3_FASTRELOADS) && pm->ps->stats[STAT_RELOADATTEMPTS] > 0)
|
|
|
|
{
|
|
|
|
if (pm->ps->weapon == WP_M3)
|
|
|
|
{
|
|
|
|
// knock down reload time if doing fast-reloads
|
|
|
|
if (pm->ps->stats[STAT_RELOADTIME] > RQ3_M3_FAST_RELOAD_DELAY)
|
|
|
|
{
|
|
|
|
//Com_Printf("Reducing reload time\n");
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_M3_FAST_RELOAD_DELAY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// knock down reload time if doing fast-reloads
|
|
|
|
if (pm->ps->stats[STAT_RELOADTIME] > RQ3_SSG3000_FAST_RELOAD_DELAY)
|
|
|
|
{
|
|
|
|
//Com_Printf("Reducing reload time\n");
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = RQ3_SSG3000_FAST_RELOAD_DELAY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// insert stage 1 sound events here; check against the reload time
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-11-11 07:24:27 +00:00
|
|
|
// Special handcannon shell ejection hack
|
|
|
|
if ( pm->ps->weapon == WP_HANDCANNON &&
|
|
|
|
!(pm->ps->stats[STAT_RQ3] & RQ3_RELOADWEAPON1) &&
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] < 1400 )
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_RQ3] |= RQ3_RELOADWEAPON1;
|
|
|
|
PM_AddEvent(EV_RELOAD_WEAPON1);
|
|
|
|
}
|
2001-08-30 09:47:39 +00:00
|
|
|
|
|
|
|
// finished reload
|
|
|
|
if (pm->ps->stats[STAT_RELOADTIME] <= 0)
|
|
|
|
{
|
|
|
|
int ammotoadd;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
ammotoadd = ClipAmountForReload(pm->ps->weapon);
|
|
|
|
if (pm->ps->weapon == WP_M3 || pm->ps->weapon == WP_SSG3000)
|
|
|
|
{
|
|
|
|
// need to also check here because of fast-reloads
|
|
|
|
if (ammotoadd + pm->ps->ammo[pm->ps->weapon] > ClipAmountForAmmo(pm->ps->weapon) ||
|
|
|
|
pm->ps->stats[STAT_CLIPS] <= 0)
|
|
|
|
{
|
|
|
|
ammotoadd = pm->ps->ammo[pm->ps->weapon];
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ammotoadd += pm->ps->ammo[pm->ps->weapon];
|
|
|
|
}
|
|
|
|
|
|
|
|
// akimbo and MK23 synchronization
|
|
|
|
if (pm->ps->weapon == WP_AKIMBO)
|
|
|
|
{
|
|
|
|
pm->ps->ammo[WP_PISTOL] = RQ3_PISTOL_AMMO;
|
|
|
|
}
|
|
|
|
else if (pm->ps->weapon == WP_PISTOL &&
|
|
|
|
(pm->ps->stats[STAT_WEAPONS] & (1 << WP_AKIMBO)))
|
|
|
|
{
|
|
|
|
// weird? That's because we gave one pistol a full clip
|
|
|
|
pm->ps->ammo[WP_AKIMBO] = pm->ps->ammo[WP_AKIMBO] - pm->ps->ammo[WP_PISTOL] + ammotoadd;
|
|
|
|
if (pm->ps->ammo[WP_AKIMBO] > RQ3_AKIMBO_AMMO)
|
|
|
|
pm->ps->ammo[WP_AKIMBO] = RQ3_AKIMBO_AMMO;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
if ( !(pm->ps->stats[STAT_RQ3] & RQ3_LOCKRELOADS) ) {
|
2001-08-30 09:47:39 +00:00
|
|
|
pm->ps->ammo[pm->ps->weapon] = ammotoadd;
|
2001-12-17 15:08:34 +00:00
|
|
|
}
|
2001-08-30 09:47:39 +00:00
|
|
|
|
2001-11-12 07:59:19 +00:00
|
|
|
// handle continuous fast-reloads
|
|
|
|
if ((pm->ps->weapon == WP_M3 || pm->ps->weapon == WP_SSG3000) &&
|
2001-08-30 09:47:39 +00:00
|
|
|
(pm->ps->stats[STAT_RQ3] & RQ3_FASTRELOADS) )//&&
|
|
|
|
//pm->ps->stats[STAT_RELOADATTEMPTS] > 0)
|
|
|
|
{
|
|
|
|
if ( !(pm->ps->stats[STAT_RQ3] & RQ3_LOCKRELOADS) &&
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS] > 0)
|
|
|
|
{
|
|
|
|
//Com_Printf("Fast-reload cycle repeating\n");
|
|
|
|
if (pm->ps->weapon == WP_M3)
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] += RQ3_M3_FAST_RELOAD_DELAY;
|
|
|
|
else
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] += RQ3_SSG3000_FAST_RELOAD_DELAY;
|
|
|
|
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS]--;
|
2001-11-12 07:59:19 +00:00
|
|
|
|
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
if (pm->ps->stats[STAT_RELOADATTEMPTS] > 0)
|
2001-10-11 22:52:43 +00:00
|
|
|
{
|
|
|
|
PM_StartWeaponAnim(WP_ANIM_EXTRA1);
|
|
|
|
//PM_StartWeaponAnim(WP_ANIM_RELOAD);
|
|
|
|
}
|
2001-11-11 07:24:27 +00:00
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
if (pm->ps->stats[STAT_CLIPS] > 0)
|
|
|
|
{
|
2001-09-11 00:12:29 +00:00
|
|
|
//Com_Printf("Sending event from continuous fast-reloads\n");
|
2001-11-11 07:24:27 +00:00
|
|
|
PM_AddEvent(EV_RELOAD_WEAPON1);
|
|
|
|
//PM_AddEvent(EV_RELOAD_WEAPON0);
|
2001-08-30 09:47:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-09-11 00:12:29 +00:00
|
|
|
//Com_Printf("Negative event prevented\n");
|
2001-08-30 09:47:39 +00:00
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-09-11 00:12:29 +00:00
|
|
|
//Com_Printf("============= Locked out in continuous fast-reloads\n");
|
2001-08-30 09:47:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// finishing up fast reloads
|
|
|
|
if ((pm->ps->stats[STAT_RQ3] & RQ3_FASTRELOADS) &&
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS] == 0)
|
|
|
|
{
|
|
|
|
//Com_Printf("Fast-reload cycle ending\n");
|
|
|
|
if (pm->ps->weapon == WP_M3)
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] += RQ3_M3_FINISH_RELOAD_DELAY;
|
|
|
|
else
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] += RQ3_SSG3000_FINISH_RELOAD_DELAY;
|
|
|
|
|
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_FASTRELOADS;
|
|
|
|
// lock fast-reloads during finish delay
|
|
|
|
pm->ps->stats[STAT_RQ3] |= RQ3_LOCKRELOADS;
|
2001-09-11 00:12:29 +00:00
|
|
|
//Com_Printf("<<<<<<<<<<<<< Locking\n");
|
2001-10-11 22:52:43 +00:00
|
|
|
PM_StartWeaponAnim( WP_ANIM_EXTRA2 );
|
2001-08-30 09:47:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
// normal reload case
|
|
|
|
//else
|
|
|
|
//{
|
|
|
|
// unlock
|
|
|
|
if (pm->ps->stats[STAT_RQ3] & RQ3_LOCKRELOADS)
|
|
|
|
{
|
2001-09-11 00:12:29 +00:00
|
|
|
//Com_Printf(">>>>>>>>>>>>> Unlocking\n");
|
2001-08-30 09:47:39 +00:00
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_LOCKRELOADS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-09-11 00:12:29 +00:00
|
|
|
//Com_Printf("Sending event from normal reload\n");
|
2001-08-30 09:47:39 +00:00
|
|
|
PM_AddEvent(EV_RELOAD_WEAPON2);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Com_Printf("Finished reload\n");
|
|
|
|
pm->ps->stats[STAT_RELOADTIME] = 0;
|
|
|
|
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
|
2001-11-11 07:24:27 +00:00
|
|
|
pm->ps->stats[STAT_RQ3] &= ~RQ3_RELOADWEAPON1;
|
2001-08-30 09:47:39 +00:00
|
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
//}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
} // end finish reload
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
} // end in-progress reload
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
/*
|
|
|
|
==============
|
|
|
|
PM_Weapon
|
|
|
|
|
|
|
|
Generates weapon events and modifes the weapon counter
|
|
|
|
==============
|
|
|
|
*/
|
|
|
|
static void PM_Weapon( void ) {
|
|
|
|
int addTime;
|
|
|
|
|
2001-06-08 04:47:30 +00:00
|
|
|
//Elder: PISTOL always gets set to 12 if akimbos have >11 based on AQ2 observation
|
|
|
|
if (pm->ps->weapon == WP_AKIMBO && pm->ps->ammo[WP_AKIMBO] > 11) {
|
|
|
|
pm->ps->ammo[WP_PISTOL] = 12;
|
|
|
|
}
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for dead player
|
|
|
|
if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
|
|
|
|
pm->ps->weapon = WP_NONE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-08-13 17:26:53 +00:00
|
|
|
//Elder: New 3rb Code
|
|
|
|
//force fire button down if STAT_BURST is < proper amount
|
2001-11-12 07:59:19 +00:00
|
|
|
//Otherwise release the button
|
2001-08-13 17:26:53 +00:00
|
|
|
if ( (pm->ps->weapon == WP_M4 &&
|
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE) ||
|
|
|
|
(pm->ps->weapon == WP_MP5 &&
|
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_MP5MODE) == RQ3_MP5MODE))
|
|
|
|
{
|
|
|
|
int weaponNum = pm->ps->weapon;
|
|
|
|
|
|
|
|
if (pm->ps->ammo[weaponNum] == 0)
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_BURST] = 0;
|
|
|
|
}
|
|
|
|
else if (pm->cmd.buttons & BUTTON_ATTACK)// && client->ps.stats[STAT_BURST] > 0)
|
|
|
|
{
|
|
|
|
if ( pm->ps->stats[STAT_BURST] >= 0 && pm->ps->stats[STAT_BURST] < 3)
|
|
|
|
pm->cmd.buttons |= BUTTON_ATTACK;
|
|
|
|
else
|
|
|
|
pm->cmd.buttons &= ~BUTTON_ATTACK;
|
|
|
|
}
|
|
|
|
else if (pm->ps->stats[STAT_BURST] > 2)
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_BURST] = 0;
|
|
|
|
pm->ps->weaponTime += 300;
|
|
|
|
}
|
|
|
|
//Don't need?
|
|
|
|
else if (pm->ps->stats[STAT_BURST] > 0)
|
|
|
|
pm->cmd.buttons |= BUTTON_ATTACK;
|
|
|
|
}
|
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
//agt: Knife stupidity
|
|
|
|
//I'll hijack STAT_BURST for this one
|
|
|
|
if( pm->ps->weapon == WP_KNIFE && (pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) ) {
|
|
|
|
if (pm->cmd.buttons & BUTTON_ATTACK &&
|
|
|
|
pm->ps->stats[STAT_BURST] >= 0 && pm->ps->stats[STAT_BURST] < 5)
|
|
|
|
{
|
|
|
|
pm->cmd.buttons |= BUTTON_ATTACK;
|
|
|
|
}
|
|
|
|
else if (pm->ps->stats[STAT_BURST] > 4) {
|
|
|
|
pm->ps->stats[STAT_BURST] = 0;
|
|
|
|
pm->ps->weaponTime += 650; // NiceAss note: 30ms * 5 attacks = 150 ms + 650ms = 800ms.
|
|
|
|
}
|
|
|
|
else if (pm->ps->stats[STAT_BURST] > 0) {
|
|
|
|
pm->cmd.buttons |= BUTTON_ATTACK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-08-13 17:26:53 +00:00
|
|
|
//Elder: New semi-auto code
|
2001-11-12 07:59:19 +00:00
|
|
|
if ( pm->ps->weapon == WP_PISTOL &&
|
2001-08-13 17:26:53 +00:00
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_MK23MODE) == RQ3_MK23MODE)
|
|
|
|
{
|
|
|
|
if (pm->ps->ammo[WP_PISTOL] == 0)
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_BURST] = 0;
|
|
|
|
}
|
2001-11-11 07:24:27 +00:00
|
|
|
else if ( (pm->cmd.buttons & BUTTON_ATTACK) && pm->ps->stats[STAT_BURST] )
|
2001-08-13 17:26:53 +00:00
|
|
|
{
|
|
|
|
pm->cmd.buttons &= ~BUTTON_ATTACK;
|
|
|
|
}
|
|
|
|
else if (pm->ps->stats[STAT_BURST])
|
|
|
|
{
|
2001-11-25 23:04:08 +00:00
|
|
|
pm->ps->weaponTime += 100; // lowered again to 100 from 150 from 200
|
2001-08-13 17:26:53 +00:00
|
|
|
pm->ps->stats[STAT_BURST] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-09-01 16:14:14 +00:00
|
|
|
// Elder: new akimbo code
|
|
|
|
if ( pm->ps->weapon == WP_AKIMBO )
|
|
|
|
{
|
|
|
|
if (pm->ps->ammo[WP_AKIMBO] == 0 && pm->ps->stats[STAT_BURST])
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_BURST] = 0;
|
|
|
|
pm->cmd.buttons &= ~BUTTON_ATTACK;
|
|
|
|
}
|
|
|
|
else if (pm->ps->stats[STAT_BURST])
|
|
|
|
{
|
|
|
|
pm->cmd.buttons |= BUTTON_ATTACK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-11-25 23:04:08 +00:00
|
|
|
//NiceAss: I added this smoother M4 rise. Should this be used?
|
|
|
|
/*
|
|
|
|
if ( ( pm->cmd.buttons & 1 || pm->ps->stats[STAT_BURST] ) && pm->ps->ammo[pm->ps->weapon]) {
|
|
|
|
if ( pm->ps->weapon == WP_M4)
|
|
|
|
{
|
|
|
|
pm->ps->delta_angles[0] = ANGLE2SHORT(SHORT2ANGLE(pm->ps->delta_angles[0]) - 0.08);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
// make weapon function
|
|
|
|
if ( pm->ps->weaponTime > 0 ) {
|
|
|
|
pm->ps->weaponTime -= pml.msec;
|
|
|
|
}
|
|
|
|
|
2001-11-08 02:37:32 +00:00
|
|
|
// Elder: make stall decrease
|
|
|
|
if ( pm->ps->stats[STAT_WEAPONSTALLTIME] > 0 ) {
|
|
|
|
pm->ps->stats[STAT_WEAPONSTALLTIME] -= pml.msec;
|
|
|
|
}
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// check for weapon change
|
|
|
|
// can't change if weapon is firing, but can change
|
|
|
|
// again if lowering or raising
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-11-11 07:24:27 +00:00
|
|
|
// Elder: modified so that a dropweapon command is high precedence
|
|
|
|
|
2001-11-08 02:37:32 +00:00
|
|
|
//if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING) {
|
2001-11-11 07:24:27 +00:00
|
|
|
if ( (pm->ps->stats[STAT_RQ3] & RQ3_THROWWEAPON) || (pm->ps->weaponTime <= 0 &&
|
|
|
|
!(pm->ps->weaponstate == WEAPON_FIRING || pm->ps->weaponstate == WEAPON_STALL))) {
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( pm->ps->weapon != pm->cmd.weapon ) {
|
2001-11-11 07:24:27 +00:00
|
|
|
//Elder: if switching weapons, fire off the grenade "instantly"
|
2001-07-01 05:11:12 +00:00
|
|
|
if ( pm->ps->weapon == WP_GRENADE && pm->ps->weaponstate == WEAPON_COCKED) {
|
|
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
|
|
pm->cmd.buttons &= ~BUTTON_ATTACK;
|
2001-12-17 15:08:34 +00:00
|
|
|
PM_AddEvent2( EV_FIRE_WEAPON, RQ3_WPMOD_GRENADEDROP );
|
2001-07-01 05:11:12 +00:00
|
|
|
pm->ps->ammo[WP_GRENADE]--;
|
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_BeginWeaponChange( pm->cmd.weapon );
|
|
|
|
}
|
2001-08-06 19:15:00 +00:00
|
|
|
else
|
|
|
|
{
|
2001-08-17 20:48:18 +00:00
|
|
|
//Elder: temp hack
|
2001-09-11 00:12:29 +00:00
|
|
|
if (pm->ps->weaponstate == WEAPON_READY)
|
|
|
|
{
|
2001-11-25 23:04:08 +00:00
|
|
|
if (pm->ps->ammo[pm->ps->weapon] == 0) {
|
2001-09-11 00:12:29 +00:00
|
|
|
PM_ContinueWeaponAnim( WP_ANIM_EMPTY );
|
2001-11-25 23:04:08 +00:00
|
|
|
}
|
2001-09-11 00:12:29 +00:00
|
|
|
else if (pm->ps->weapon == WP_KNIFE &&
|
2001-11-25 23:04:08 +00:00
|
|
|
!(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE)) {
|
2001-09-11 00:12:29 +00:00
|
|
|
PM_ContinueWeaponAnim(WP_ANIM_THROWIDLE);
|
2001-11-25 23:04:08 +00:00
|
|
|
}
|
2001-10-30 23:26:03 +00:00
|
|
|
else
|
|
|
|
PM_ContinueWeaponAnim(WP_ANIM_IDLE);
|
2001-09-11 00:12:29 +00:00
|
|
|
}
|
2001-08-06 19:15:00 +00:00
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
2001-11-08 02:37:32 +00:00
|
|
|
// Elder: added STAT_RELOADTIME and STAT_WEAPONSTALLTIME check
|
|
|
|
if ( pm->ps->weaponTime > 0 || pm->ps->stats[STAT_RELOADTIME] > 0 ||
|
|
|
|
pm->ps->stats[STAT_WEAPONSTALLTIME] > 0) {
|
2001-05-06 20:50:27 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// change weapon if time
|
2002-03-18 19:19:08 +00:00
|
|
|
if ( pm->ps->weaponstate == WEAPON_DROPPING || pm->ps->weaponstate == WEAPON_BANDAGING ) {
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_FinishWeaponChange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
//NiceAss: Attempt to have the knife/grenade "activate" after a throw if you have another one of them
|
|
|
|
if ( pm->ps->weaponstate == WEAPON_FIRING && pm->ps->ammo[pm->ps->weapon] > 0 &&
|
|
|
|
(pm->ps->weapon == WP_KNIFE || pm->ps->weapon == WP_GRENADE) ) {
|
|
|
|
|
|
|
|
if (pm->ps->weapon == WP_KNIFE && !(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE))
|
|
|
|
{
|
|
|
|
pm->ps->weaponTime = RQ3_KNIFE_ACTIVATE_DELAY;
|
|
|
|
PM_StartWeaponAnim(WP_ANIM_THROWACTIVATE);
|
|
|
|
pm->ps->weaponstate = WEAPON_RAISING;
|
|
|
|
PM_StartTorsoAnim( TORSO_RAISE );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (pm->ps->weapon == WP_GRENADE)
|
|
|
|
{
|
|
|
|
pm->ps->weaponTime = RQ3_GRENADE_DELAY;
|
|
|
|
PM_StartWeaponAnim(WP_ANIM_ACTIVATE);
|
|
|
|
pm->ps->weaponstate = WEAPON_RAISING;
|
|
|
|
PM_StartTorsoAnim( TORSO_RAISE );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pm->ps->weaponstate == WEAPON_RAISING &&
|
|
|
|
!( ( pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) && pm->ps->stats[STAT_BURST]) ) {
|
2001-05-06 20:50:27 +00:00
|
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
if ( pm->ps->weapon == WP_KNIFE ) {
|
|
|
|
PM_StartTorsoAnim( TORSO_STAND2 );
|
|
|
|
} else {
|
|
|
|
PM_StartTorsoAnim( TORSO_STAND );
|
|
|
|
}
|
2001-08-17 20:48:18 +00:00
|
|
|
// temp hack
|
2001-11-25 23:04:08 +00:00
|
|
|
if (pm->ps->ammo[pm->ps->weapon] == 0) {
|
2001-09-11 00:12:29 +00:00
|
|
|
PM_ContinueWeaponAnim( WP_ANIM_EMPTY );
|
2001-11-25 23:04:08 +00:00
|
|
|
}
|
2002-04-26 05:29:38 +00:00
|
|
|
|
2001-09-11 00:12:29 +00:00
|
|
|
else if (pm->ps->weapon == WP_KNIFE && !(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE))
|
|
|
|
PM_StartWeaponAnim( WP_ANIM_THROWIDLE );
|
2001-10-30 23:26:03 +00:00
|
|
|
else
|
|
|
|
PM_StartWeaponAnim( WP_ANIM_IDLE );
|
2001-12-17 15:08:34 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
// NiceAss: Added for knife animation switch.
|
|
|
|
// At the moment, this is only used for changing knife-throw modes.
|
|
|
|
if ( pm->ps->weaponstate == WEAPON_MODECHANGE ) {
|
|
|
|
if ( pm->ps->weapon == WP_KNIFE) pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2002-03-11 01:29:54 +00:00
|
|
|
// JBravo: no shooting during LCA
|
2002-03-23 05:17:43 +00:00
|
|
|
if (pm->lca) {
|
2002-03-11 01:29:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-07-01 05:11:12 +00:00
|
|
|
// Elder: fire on release - based on code from inolen
|
2001-05-06 20:50:27 +00:00
|
|
|
// check for fire
|
2001-07-03 10:26:42 +00:00
|
|
|
// if they are pressing attack and their current weapon is the grenade
|
2001-11-08 02:37:32 +00:00
|
|
|
if ( pm->cmd.buttons & 1 )
|
|
|
|
{
|
|
|
|
if ( pm->ps->weapon == WP_GRENADE )
|
|
|
|
{
|
2001-11-15 04:20:18 +00:00
|
|
|
if ( pm->ps->weaponstate == WEAPON_READY )
|
|
|
|
{
|
|
|
|
// NiceAss: Add a delay so the pin-pull animation can complete.
|
2001-11-14 06:57:40 +00:00
|
|
|
pm->ps->weaponTime = 800;
|
2001-11-15 04:20:18 +00:00
|
|
|
// put it in the "cocked" position and play the pin-pull animation
|
|
|
|
pm->ps->weaponstate = WEAPON_COCKED;
|
|
|
|
PM_ContinueWeaponAnim(WP_ANIM_EXTRA1);
|
|
|
|
return;
|
2001-11-14 06:57:40 +00:00
|
|
|
}
|
2001-12-17 15:08:34 +00:00
|
|
|
else if ( pm->ps->weaponstate == WEAPON_COCKED )
|
2001-11-15 04:20:18 +00:00
|
|
|
return;
|
2001-11-08 02:37:32 +00:00
|
|
|
}
|
|
|
|
// Elder: stall the thrown knife action
|
2001-11-15 07:06:33 +00:00
|
|
|
|
2001-11-08 02:37:32 +00:00
|
|
|
else if ( pm->ps->weapon == WP_KNIFE && pm->ps->weaponstate != WEAPON_STALL &&
|
|
|
|
pm->ps->stats[STAT_WEAPONSTALLTIME] <= 0 &&
|
2001-12-17 15:08:34 +00:00
|
|
|
!(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) &&
|
|
|
|
pm->ps->ammo[pm->ps->weapon])
|
2001-11-08 02:37:32 +00:00
|
|
|
{
|
|
|
|
pm->ps->weaponstate = WEAPON_STALL;
|
|
|
|
pm->ps->stats[STAT_WEAPONSTALLTIME] = 200;
|
|
|
|
PM_StartWeaponAnim( WP_ANIM_THROWFIRE );
|
|
|
|
return;
|
|
|
|
}
|
2001-07-01 05:11:12 +00:00
|
|
|
}
|
|
|
|
|
2001-11-14 06:57:40 +00:00
|
|
|
// check for fireA release
|
2001-07-01 05:11:12 +00:00
|
|
|
// if they aren't pressing attack
|
2001-11-15 04:20:18 +00:00
|
|
|
if ( !(pm->cmd.buttons & 1) ) {
|
2001-07-01 05:11:12 +00:00
|
|
|
// if we had them cocked and then they aren't pressing it then
|
|
|
|
// that means they released it
|
2001-11-15 04:20:18 +00:00
|
|
|
if ( pm->ps->weapon == WP_GRENADE )
|
|
|
|
{
|
|
|
|
if ( pm->ps->weaponstate == WEAPON_COCKED )
|
|
|
|
{
|
|
|
|
// Stall for the toss motion
|
|
|
|
pm->ps->weaponstate = WEAPON_STALL;
|
|
|
|
pm->ps->stats[STAT_WEAPONSTALLTIME] = 300;
|
|
|
|
PM_StartWeaponAnim( WP_ANIM_FIRE );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if ( pm->ps->weaponstate == WEAPON_STALL )
|
|
|
|
{
|
|
|
|
// set to be able to fire
|
|
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// else if they arn't pressing attack, then they just are running around
|
|
|
|
pm->ps->weaponTime = 0;
|
|
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
return;
|
|
|
|
}
|
2001-07-01 05:11:12 +00:00
|
|
|
}
|
2001-11-15 07:06:33 +00:00
|
|
|
|
2001-11-15 04:20:18 +00:00
|
|
|
else if ( pm->ps->weapon == WP_KNIFE &&
|
|
|
|
!(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE))
|
|
|
|
{
|
|
|
|
if ( pm->ps->weaponstate == WEAPON_STALL )
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_WEAPONSTALLTIME] = 0;
|
|
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// else if they arn't pressing attack, then they just are running around
|
|
|
|
pm->ps->weaponTime = 0;
|
|
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
return;
|
|
|
|
}
|
2001-11-08 02:37:32 +00:00
|
|
|
}
|
2001-11-15 07:06:33 +00:00
|
|
|
|
2001-07-01 05:11:12 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// else if they arn't pressing attack, then they just are running around
|
|
|
|
pm->ps->weaponTime = 0;
|
|
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-08-06 19:15:00 +00:00
|
|
|
// check for out of ammo
|
|
|
|
if ( ! pm->ps->ammo[ pm->ps->weapon ]) {
|
|
|
|
PM_AddEvent( EV_NOAMMO );
|
2001-12-17 15:08:34 +00:00
|
|
|
//NiceAss: Dirty hack:
|
|
|
|
if (pm->ps->weapon == WP_KNIFE || pm->ps->weapon == WP_GRENADE)
|
|
|
|
//PM_FinishWeaponChange();
|
|
|
|
pm->ps->weaponstate = WEAPON_DROPPING;
|
|
|
|
else
|
|
|
|
pm->ps->weaponTime += 500;
|
|
|
|
|
2001-08-06 19:15:00 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-11-08 02:37:32 +00:00
|
|
|
|
|
|
|
|
2001-08-06 19:15:00 +00:00
|
|
|
//Elder: custom player model fire animations go here
|
|
|
|
// start the animation even if out of ammo -- Elder: NO WAY
|
2001-10-30 23:26:03 +00:00
|
|
|
if ( pm->ps->weapon == WP_KNIFE || pm->ps->weapon == WP_GRENADE ) {
|
2001-11-08 02:37:32 +00:00
|
|
|
if ( pm->ps->weapon == WP_KNIFE &&
|
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) )
|
2001-12-17 15:08:34 +00:00
|
|
|
// Modified by agt for slash "bursting"
|
|
|
|
if(!pm->ps->stats[STAT_BURST]) PM_StartWeaponAnim( WP_ANIM_FIRE );
|
2001-09-11 00:12:29 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_StartTorsoAnim( TORSO_ATTACK2 );
|
|
|
|
} else {
|
2001-08-06 19:15:00 +00:00
|
|
|
// Elder: don't repeat if semi-auto
|
2002-03-31 03:31:24 +00:00
|
|
|
if (!(pm->ps->weapon == WP_PISTOL && pm->ps->stats[STAT_BURST]) ||
|
|
|
|
!(pm->ps->weapon == WP_M4 && pm->ps->stats[STAT_BURST] > 2) ||
|
|
|
|
!(pm->ps->weapon == WP_MP5 && pm->ps->stats[STAT_BURST] > 2)) {
|
2001-08-06 19:15:00 +00:00
|
|
|
PM_StartTorsoAnim( TORSO_ATTACK );
|
|
|
|
|
|
|
|
// QUARANTINE - Weapon animations
|
|
|
|
// This should change pm->ps->generic1 so we can animate
|
|
|
|
// Elder: don't repeat if on semi-auto
|
2001-08-30 09:47:39 +00:00
|
|
|
// temp hack
|
2002-05-11 18:47:09 +00:00
|
|
|
|
2001-09-11 00:12:29 +00:00
|
|
|
if (pm->ps->weapon == WP_AKIMBO)
|
|
|
|
{
|
|
|
|
// don't repeat animation if on second akimbo shot
|
2002-03-02 22:02:09 +00:00
|
|
|
if ( !pm->ps->stats[STAT_BURST] ) {
|
|
|
|
if ( pm->ps->ammo[pm->ps->weapon] > 2 )
|
|
|
|
PM_StartWeaponAnim( WP_ANIM_FIRE );
|
|
|
|
else
|
|
|
|
PM_StartWeaponAnim( WP_ANIM_EXTRA1 );
|
|
|
|
}
|
2001-09-11 00:12:29 +00:00
|
|
|
}
|
2002-03-02 22:02:09 +00:00
|
|
|
else {
|
2002-05-11 18:47:09 +00:00
|
|
|
if ( pm->ps->ammo[pm->ps->weapon] > 1 || pm->ps->weapon != WP_PISTOL )
|
2001-12-17 15:08:34 +00:00
|
|
|
PM_StartWeaponAnim( WP_ANIM_FIRE );
|
2002-05-11 18:47:09 +00:00
|
|
|
else
|
2002-03-02 22:02:09 +00:00
|
|
|
PM_StartWeaponAnim( WP_ANIM_EXTRA1 ); // Fix for last round fired
|
|
|
|
}
|
2001-08-06 19:15:00 +00:00
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-12-17 15:08:34 +00:00
|
|
|
//NiceAss: Hack of the week!!!!
|
|
|
|
if (pm->ps->weaponstate == WEAPON_FIRING && pm->ps->weapon == WP_GRENADE) return;
|
2001-11-25 23:04:08 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
|
|
|
2001-09-01 16:14:14 +00:00
|
|
|
// Elder: akimbo check to auto-fire the second bullet
|
|
|
|
//if ( pm->ps->weapon == WP_AKIMBO && pm->ps->stats[STAT_BURST] == 0)
|
|
|
|
//pm->ps->stats[STAT_BURST] = 1;
|
|
|
|
|
2001-08-13 17:26:53 +00:00
|
|
|
// Elder: increment stat if alt-fire mode --needs to be predicted as well
|
|
|
|
if ( (pm->ps->weapon == WP_M4 &&
|
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE) ||
|
|
|
|
(pm->ps->weapon == WP_MP5 &&
|
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_MP5MODE) == RQ3_MP5MODE) ||
|
|
|
|
(pm->ps->weapon == WP_PISTOL &&
|
2001-12-17 15:08:34 +00:00
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_MK23MODE) == RQ3_MK23MODE) ||
|
|
|
|
(pm->ps->weapon == WP_KNIFE &&
|
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) == RQ3_KNIFEMODE) )
|
2001-08-13 17:26:53 +00:00
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_BURST]++;
|
|
|
|
}
|
|
|
|
|
2001-07-03 10:26:42 +00:00
|
|
|
//Elder: M4 kick code
|
|
|
|
//ent->client->ps.delta_angles[0] = ANGLE2SHORT(SHORT2ANGLE(ent->client->ps.delta_angles[0]) - 0.7);
|
|
|
|
if ( pm->ps->weapon == WP_M4 && ((pm->ps->persistant[PERS_WEAPONMODES] & RQ3_M4MODE) != RQ3_M4MODE) )
|
|
|
|
{
|
|
|
|
pm->ps->delta_angles[0] = ANGLE2SHORT(SHORT2ANGLE(pm->ps->delta_angles[0]) - 0.7);
|
|
|
|
}
|
|
|
|
|
2001-06-26 02:06:50 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// take an ammo away if not infinite
|
|
|
|
if ( pm->ps->ammo[ pm->ps->weapon ] != -1 ) {
|
|
|
|
//Blaze: Dont remove ammo for knife
|
2001-06-10 06:46:06 +00:00
|
|
|
//Elder: don't remove ammo if slashing knife
|
2001-06-11 06:12:32 +00:00
|
|
|
if ( !(pm->ps->weapon == WP_KNIFE && (pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) == RQ3_KNIFEMODE) ) {
|
2001-06-10 06:46:06 +00:00
|
|
|
//G_Printf("Taking away ammo\n");
|
2001-06-08 04:47:30 +00:00
|
|
|
pm->ps->ammo[ pm->ps->weapon ]--;
|
2001-06-10 06:46:06 +00:00
|
|
|
}
|
2001-07-09 00:32:10 +00:00
|
|
|
|
|
|
|
//Elder: special weapon case handling
|
|
|
|
|
|
|
|
//Elder: remove knives from inventory if out of ammo
|
|
|
|
if (pm->ps->weapon == WP_KNIFE && pm->ps->ammo[ WP_KNIFE ] == 0)
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_WEAPONS] &= ~( 1 << WP_KNIFE);
|
|
|
|
}
|
|
|
|
//Elder: remove grenade from inventory if out of ammo
|
|
|
|
else if (pm->ps->weapon == WP_GRENADE && pm->ps->ammo[ WP_GRENADE ] == 0)
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_WEAPONS] &= ~( 1 << WP_GRENADE);
|
|
|
|
}
|
2001-09-01 16:14:14 +00:00
|
|
|
//Elder: remove one more bullet/shell if handcannon
|
2001-07-09 00:32:10 +00:00
|
|
|
else if (pm->ps->weapon == WP_HANDCANNON)
|
|
|
|
{
|
2001-08-30 09:47:39 +00:00
|
|
|
pm->ps->ammo[ WP_HANDCANNON ]--;
|
2001-06-08 04:47:30 +00:00
|
|
|
}
|
2001-06-26 02:06:50 +00:00
|
|
|
//Elder: take away an extra bullet if available - handled in g_weapon.c as well
|
2001-09-01 16:14:14 +00:00
|
|
|
//else if (pm->ps->weapon == WP_AKIMBO && pm->ps->ammo[ WP_AKIMBO ] > 0) {
|
|
|
|
//pm->ps->ammo[ WP_AKIMBO ] --;
|
|
|
|
//}
|
2001-06-26 02:06:50 +00:00
|
|
|
|
2001-06-08 04:47:30 +00:00
|
|
|
//Elder: sync bullets a la AQ2 style
|
2001-08-30 09:47:39 +00:00
|
|
|
if (pm->ps->weapon == WP_AKIMBO && pm->ps->ammo[WP_AKIMBO] < 12) {
|
2001-06-08 04:47:30 +00:00
|
|
|
pm->ps->ammo[WP_PISTOL] = pm->ps->ammo[WP_AKIMBO];
|
|
|
|
}
|
|
|
|
else if (pm->ps->weapon == WP_PISTOL && pm->ps->ammo[WP_AKIMBO] > 0) {
|
|
|
|
pm->ps->ammo[WP_AKIMBO]--;
|
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
2001-06-26 02:06:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
// fire weapon
|
2001-07-28 14:12:11 +00:00
|
|
|
//Elder: check for silencer
|
|
|
|
if (bg_itemlist[pm->ps->stats[STAT_HOLDABLE_ITEM]].giTag == HI_SILENCER &&
|
|
|
|
(pm->ps->weapon == WP_PISTOL ||
|
|
|
|
pm->ps->weapon == WP_MP5 ||
|
2001-12-17 15:08:34 +00:00
|
|
|
pm->ps->weapon == WP_SSG3000)) {
|
2001-07-28 14:12:11 +00:00
|
|
|
PM_AddEvent2( EV_FIRE_WEAPON, RQ3_WPMOD_SILENCER );
|
|
|
|
}
|
2001-12-17 15:08:34 +00:00
|
|
|
else if (pm->ps->stats[STAT_BURST] > 1 && pm->ps->weapon == WP_KNIFE &&
|
|
|
|
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) == RQ3_KNIFEMODE)
|
|
|
|
{
|
|
|
|
// NiceAss: Prevent the client from doing stuff after the first "slash".
|
|
|
|
PM_AddEvent2( EV_FIRE_WEAPON, RQ3_WPMOD_KNIFENOMARK);
|
|
|
|
}
|
2001-07-28 14:12:11 +00:00
|
|
|
else
|
|
|
|
PM_AddEvent( EV_FIRE_WEAPON );
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
switch( pm->ps->weapon ) {
|
|
|
|
default:
|
2001-06-18 01:59:58 +00:00
|
|
|
//Elder: weapon delay times using constants
|
2001-05-06 20:50:27 +00:00
|
|
|
case WP_SSG3000:
|
2001-06-18 01:59:58 +00:00
|
|
|
addTime = RQ3_SSG3000_DELAY;
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
case WP_PISTOL:
|
2001-06-18 01:59:58 +00:00
|
|
|
addTime = RQ3_PISTOL_DELAY;
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
case WP_M4:
|
2001-06-18 01:59:58 +00:00
|
|
|
addTime = RQ3_M4_DELAY;
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
case WP_MP5:
|
2001-06-18 01:59:58 +00:00
|
|
|
addTime = RQ3_MP5_DELAY;
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
case WP_KNIFE:
|
2001-06-18 01:59:58 +00:00
|
|
|
if ( (pm->ps->persistant[PERS_WEAPONMODES] & RQ3_KNIFEMODE) == RQ3_KNIFEMODE) {
|
|
|
|
//knife slash
|
2001-12-17 15:08:34 +00:00
|
|
|
//agt: hacking it up a little. The alternate time value should be
|
|
|
|
//a constant, but I have a headache and I'm tired of screwing around
|
|
|
|
//with the knives. [NiceAss: I'll do it for you!]
|
|
|
|
if(pm->ps->stats[STAT_BURST]) {
|
|
|
|
addTime = RQ3_KNIFE_SLASH_BURST; //NiceAss: Not really a burst, but it fits with everything else =D
|
|
|
|
} else {
|
|
|
|
addTime = RQ3_KNIFE_DELAY;
|
|
|
|
}
|
2001-06-18 01:59:58 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
//knife throw
|
|
|
|
addTime = RQ3_THROW_DELAY;
|
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
case WP_HANDCANNON:
|
2001-06-18 01:59:58 +00:00
|
|
|
addTime = RQ3_HANDCANNON_DELAY;
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
case WP_M3:
|
2001-06-18 01:59:58 +00:00
|
|
|
addTime = RQ3_M3_DELAY;
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
case WP_AKIMBO:
|
2001-09-01 16:14:14 +00:00
|
|
|
if (pm->ps->stats[STAT_BURST])
|
|
|
|
{
|
|
|
|
addTime = RQ3_AKIMBO_DELAY2;
|
|
|
|
pm->ps->stats[STAT_BURST] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pm->ps->stats[STAT_BURST] = 1;
|
|
|
|
addTime = RQ3_AKIMBO_DELAY;
|
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
case WP_GRENADE:
|
2001-06-18 01:59:58 +00:00
|
|
|
addTime = RQ3_GRENADE_DELAY;
|
2001-05-06 20:50:27 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pm->ps->powerups[PW_HASTE] ) {
|
|
|
|
addTime /= 1.3;
|
|
|
|
}
|
|
|
|
|
|
|
|
pm->ps->weaponTime += addTime;
|
2001-06-26 02:06:50 +00:00
|
|
|
|
|
|
|
//Auto-switch when out of ammo with grenade or knife
|
|
|
|
if ( (pm->ps->weapon == WP_KNIFE || pm->ps->weapon == WP_GRENADE) &&
|
|
|
|
!pm->ps->ammo[ pm->ps->weapon ]) {
|
|
|
|
PM_AddEvent( EV_NOAMMO );
|
|
|
|
pm->ps->weaponTime += 150;
|
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
PM_Animate
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void PM_Animate( void ) {
|
|
|
|
if ( pm->cmd.buttons & BUTTON_GESTURE ) {
|
|
|
|
if ( pm->ps->torsoTimer == 0 ) {
|
|
|
|
PM_StartTorsoAnim( TORSO_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 isntead of a full move
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) {
|
|
|
|
short temp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
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 = 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 > 16000 ) {
|
|
|
|
ps->delta_angles[i] = 16000 - cmd->angles[i];
|
|
|
|
temp = 16000;
|
|
|
|
} else if ( temp < -16000 ) {
|
|
|
|
ps->delta_angles[i] = -16000 - cmd->angles[i];
|
|
|
|
temp = -16000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ps->viewangles[i] = SHORT2ANGLE(temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
===================
|
|
|
|
PM_LadderMove()
|
|
|
|
by: Calrathan [Arthur Tomlin]
|
|
|
|
|
2001-11-12 07:59:19 +00:00
|
|
|
Right now all I know is that this works for VERTICAL ladders.
|
2001-05-06 20:50:27 +00:00
|
|
|
Ladders with angles on them (urban2 for AQ2) haven't been tested.
|
|
|
|
===================
|
|
|
|
*/
|
|
|
|
static void PM_LadderMove( void ) {
|
|
|
|
int i;
|
|
|
|
vec3_t wishvel;
|
|
|
|
float wishspeed;
|
|
|
|
vec3_t wishdir;
|
|
|
|
float scale;
|
|
|
|
float vel;
|
|
|
|
|
2001-08-18 19:59:25 +00:00
|
|
|
// Elder: ladder jump crap
|
|
|
|
trace_t tr;
|
|
|
|
vec3_t lookAhead;
|
|
|
|
vec3_t trEndTest;
|
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
// New experimental jump code -- not too good
|
|
|
|
#if 0
|
|
|
|
// Elder: ladder jump crap
|
|
|
|
lookAhead[0] = pml.forward[0];
|
|
|
|
lookAhead[1] = pml.forward[1];
|
|
|
|
lookAhead[2] = 0;
|
|
|
|
VectorNormalize (lookAhead);
|
|
|
|
// Calculate end point
|
|
|
|
VectorMA (pm->ps->origin, 1, lookAhead, trEndTest);
|
|
|
|
//trEndTest[2] += 20;
|
|
|
|
trEndTest[2] += 6;
|
|
|
|
// Calculate start point
|
|
|
|
VectorCopy(pm->ps->origin, lookAhead);
|
|
|
|
//lookAhead[2] += 16;
|
|
|
|
lookAhead[2] += 2;
|
|
|
|
|
|
|
|
pm->trace (&tr, lookAhead, pm->mins, pm->maxs, trEndTest,
|
|
|
|
pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
|
|
|
|
if (tr.fraction == 1 || !(tr.surfaceFlags & SURF_LADDER))
|
|
|
|
{
|
|
|
|
// good conditions -- now we can set up a double jump on the ladder
|
|
|
|
if (pm->debugLevel)
|
|
|
|
Com_Printf("Ladder jump conditions met...\n");
|
|
|
|
if (pm->ps->stats[STAT_JUMPTIME] > 0 && PM_CheckJump())
|
|
|
|
{
|
|
|
|
if (pm->debugLevel)
|
|
|
|
Com_Printf("Trying ladder jump...\n");
|
|
|
|
pml.ladder = qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// End ladder jump crap
|
|
|
|
#endif
|
2001-08-18 19:59:25 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_Friction ();
|
2001-08-30 09:47:39 +00:00
|
|
|
//pml.ladder = qtrue;
|
2001-05-06 20:50:27 +00:00
|
|
|
|
|
|
|
scale = PM_CmdScale( &pm->cmd );
|
|
|
|
|
|
|
|
// user intentions [what the user is attempting to do]
|
2001-11-12 07:59:19 +00:00
|
|
|
if ( !scale ) {
|
2001-05-06 20:50:27 +00:00
|
|
|
wishvel[0] = 0;
|
|
|
|
wishvel[1] = 0;
|
|
|
|
wishvel[2] = 0;
|
|
|
|
}
|
|
|
|
else { // if they're trying to move... lets calculate it
|
|
|
|
for (i=0 ; i<3 ; i++)
|
|
|
|
wishvel[i] = scale * pml.forward[i]*pm->cmd.forwardmove +
|
2001-11-12 07:59:19 +00:00
|
|
|
scale * pml.right[i]*pm->cmd.rightmove;
|
2001-07-16 01:40:33 +00:00
|
|
|
//Elder: changed from a factor of 2 to 10
|
2001-07-24 01:50:01 +00:00
|
|
|
wishvel[0] /= PM_LADDER_MOVE_REDUCTION;
|
|
|
|
wishvel[1] /= PM_LADDER_MOVE_REDUCTION;
|
2001-05-06 20:50:27 +00:00
|
|
|
wishvel[2] += scale * pm->cmd.upmove;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy (wishvel, wishdir);
|
|
|
|
wishspeed = VectorNormalize(wishdir);
|
|
|
|
|
|
|
|
if ( wishspeed > pm->ps->speed * pm_ladderScale ) {
|
|
|
|
wishspeed = pm->ps->speed * pm_ladderScale;
|
|
|
|
}
|
|
|
|
|
2001-08-30 09:47:39 +00:00
|
|
|
// Old ladder jump code -- right now it works better
|
|
|
|
#if 1
|
2001-08-18 19:59:25 +00:00
|
|
|
// Elder: ladder jump crap
|
|
|
|
lookAhead[0] = pml.forward[0];
|
|
|
|
lookAhead[1] = pml.forward[1];
|
|
|
|
lookAhead[2] = 0;
|
|
|
|
VectorNormalize (lookAhead);
|
|
|
|
// Calculate end point
|
|
|
|
VectorMA (pm->ps->origin, 1, lookAhead, trEndTest);
|
|
|
|
trEndTest[2] += 20;
|
|
|
|
// Calculate start point
|
|
|
|
VectorCopy(pm->ps->origin, lookAhead);
|
|
|
|
lookAhead[2] += 16;
|
|
|
|
|
|
|
|
pm->trace (&tr, lookAhead, pm->mins, pm->maxs, trEndTest,
|
|
|
|
pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
|
|
|
|
if (tr.fraction == 1 || !(tr.surfaceFlags & SURF_LADDER))
|
|
|
|
{
|
|
|
|
// good conditions -- now we can set up a double jump on the ladder
|
|
|
|
if (pm->debugLevel)
|
|
|
|
Com_Printf("Ladder jump conditions met...\n");
|
|
|
|
if (PM_CheckJump())
|
|
|
|
{
|
|
|
|
if (pm->debugLevel)
|
2001-08-30 09:47:39 +00:00
|
|
|
Com_Printf("Trying ladder jump...\n");
|
2001-08-18 19:59:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// End ladder jump crap
|
2001-08-30 09:47:39 +00:00
|
|
|
#endif
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_Accelerate (wishdir, wishspeed, pm_ladderAccelerate);
|
|
|
|
|
|
|
|
// This SHOULD help us with sloped ladders, but it remains untested.
|
|
|
|
if ( pml.groundPlane && DotProduct( pm->ps->velocity,
|
|
|
|
pml.groundTrace.plane.normal ) < 0 ) {
|
|
|
|
vel = VectorLength(pm->ps->velocity);
|
2001-11-12 07:59:19 +00:00
|
|
|
// slide along the ground plane [the ladder section under our feet]
|
|
|
|
PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal,
|
2001-05-06 20:50:27 +00:00
|
|
|
pm->ps->velocity, OVERCLIP );
|
|
|
|
|
|
|
|
VectorNormalize(pm->ps->velocity);
|
|
|
|
VectorScale(pm->ps->velocity, vel, pm->ps->velocity);
|
|
|
|
}
|
|
|
|
|
2002-02-04 00:30:35 +00:00
|
|
|
PM_StepSlideMove( qfalse ); // move without gravity
|
2001-08-18 19:59:25 +00:00
|
|
|
// Elder: stop legs from animating
|
2001-08-30 09:47:39 +00:00
|
|
|
PM_ForceLegsAnim( LEGS_JUMP );
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
=============
|
|
|
|
CheckLadder [ ARTHUR TOMLIN ]
|
|
|
|
=============
|
|
|
|
*/
|
|
|
|
void CheckLadder( void )
|
|
|
|
{
|
|
|
|
vec3_t flatforward,spot;
|
|
|
|
trace_t trace;
|
2001-08-18 19:59:25 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
pml.ladder = qfalse;
|
2001-08-18 19:59:25 +00:00
|
|
|
pml.previous_ladder = qfalse;
|
2001-05-06 20:50:27 +00:00
|
|
|
// check for ladder
|
|
|
|
flatforward[0] = pml.forward[0];
|
|
|
|
flatforward[1] = pml.forward[1];
|
|
|
|
flatforward[2] = 0;
|
|
|
|
VectorNormalize (flatforward);
|
2001-08-18 19:59:25 +00:00
|
|
|
|
|
|
|
// Elder: Previously on ladder? Does this work?
|
|
|
|
VectorMA (pml.previous_origin, 1, flatforward, spot);
|
|
|
|
pm->trace (&trace, pml.previous_origin, pm->mins, pm->maxs, spot,
|
|
|
|
pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
|
|
|
|
if ((trace.fraction < 1) && (trace.surfaceFlags & SURF_LADDER))
|
|
|
|
pml.previous_ladder = qtrue;
|
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
VectorMA (pm->ps->origin, 1, flatforward, spot);
|
|
|
|
pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, spot,
|
|
|
|
pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
|
|
|
|
if ((trace.fraction < 1) && (trace.surfaceFlags & SURF_LADDER))
|
|
|
|
pml.ladder = qtrue;
|
|
|
|
|
2001-08-18 19:59:25 +00:00
|
|
|
// Elder: does this work?
|
2001-10-11 22:52:43 +00:00
|
|
|
/*
|
2001-08-30 09:47:39 +00:00
|
|
|
if (pml.ladder && pml.previous_ladder == qfalse)
|
|
|
|
{
|
|
|
|
if (pm->debugLevel)
|
|
|
|
Com_Printf("Hit ladder hard\n");
|
2001-08-18 19:59:25 +00:00
|
|
|
PM_CrashLand();
|
2001-08-30 09:47:39 +00:00
|
|
|
}
|
2001-10-11 22:52:43 +00:00
|
|
|
*/
|
2001-05-06 20:50:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
================
|
|
|
|
PmoveSingle
|
|
|
|
|
|
|
|
================
|
|
|
|
*/
|
|
|
|
void trap_SnapVector( float *v );
|
|
|
|
|
|
|
|
void PmoveSingle (pmove_t *pmove) {
|
|
|
|
pm = pmove;
|
|
|
|
|
|
|
|
// 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 ) && pm->ps->ammo[ pm->ps->weapon ] ) {
|
|
|
|
pm->ps->eFlags |= EF_FIRING;
|
|
|
|
} else {
|
|
|
|
pm->ps->eFlags &= ~EF_FIRING;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear the respawned flag if attack and use are cleared
|
2001-11-12 07:59:19 +00:00
|
|
|
if ( pm->ps->stats[STAT_HEALTH] > 0 &&
|
2001-05-06 20:50:27 +00:00
|
|
|
!( 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 ) {
|
|
|
|
// keep the talk button set tho for when the cmd.serverTime > 66 msec
|
|
|
|
// and the same cmd is used multiple times in Pmove
|
|
|
|
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;
|
|
|
|
|
|
|
|
// update the viewangles
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_UpdateViewAngles( pm->ps, &pm->cmd );
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( pm->ps->pm_type == PM_SPECTATOR ) {
|
|
|
|
PM_CheckDuck ();
|
|
|
|
PM_FlyMove ();
|
|
|
|
PM_DropTimers ();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pm->ps->pm_type == PM_NOCLIP ) {
|
|
|
|
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 ();
|
|
|
|
|
|
|
|
// set groundentity
|
|
|
|
PM_GroundTrace();
|
|
|
|
|
|
|
|
if ( pm->ps->pm_type == PM_DEAD ) {
|
|
|
|
PM_DeadMove ();
|
|
|
|
}
|
|
|
|
|
|
|
|
PM_DropTimers();
|
|
|
|
CheckLadder(); // ARTHUR TOMLIN check and see if they're on a ladder
|
|
|
|
|
|
|
|
#ifdef MISSIONPACK
|
|
|
|
if ( pm->ps->powerups[PW_INVULNERABILITY] ) {
|
|
|
|
PM_InvulnerabilityMove();
|
|
|
|
} else
|
|
|
|
#endif
|
2002-04-26 05:29:38 +00:00
|
|
|
|
2001-05-06 20:50:27 +00:00
|
|
|
if ( pm->ps->powerups[PW_FLIGHT] ) {
|
|
|
|
// flight powerup doesn't allow jump and has different friction
|
|
|
|
PM_FlyMove();
|
|
|
|
} else if (pm->ps->pm_flags & PMF_GRAPPLE_PULL) {
|
|
|
|
PM_GrappleMove();
|
|
|
|
// We can wiggle a bit
|
|
|
|
PM_AirMove();
|
|
|
|
} else if (pm->ps->pm_flags & PMF_TIME_WATERJUMP) {
|
|
|
|
PM_WaterJumpMove();
|
2001-06-15 13:43:54 +00:00
|
|
|
} else if ( pm->waterlevel > 1 && !pml.ladder) { //Blaze: wtf, need to add a comment to make it a big enough change for cvs to notice
|
2001-05-06 20:50:27 +00:00
|
|
|
// swimming
|
|
|
|
PM_WaterMove();
|
2001-10-11 22:52:43 +00:00
|
|
|
// Elder: Added !(...) check below to prevent crouch spasms at bottom of ladders
|
2001-11-12 07:59:19 +00:00
|
|
|
} else if (pml.ladder && !(pm->ps->viewheight == CROUCH_VIEWHEIGHT && pm->ps->groundEntityNum != ENTITYNUM_NONE)) {
|
2001-05-06 20:50:27 +00:00
|
|
|
PM_LadderMove();
|
|
|
|
} else if ( pml.walking ) {
|
|
|
|
// walking on ground
|
|
|
|
PM_WalkMove();
|
2001-06-13 01:14:31 +00:00
|
|
|
if ( (pm->cmd.serverTime % 1000 > 333) && ((pm->ps->stats[STAT_RQ3] & RQ3_LEGDAMAGE) == RQ3_LEGDAMAGE))
|
|
|
|
{
|
|
|
|
pm->ps->velocity[0] = (int)((float)pm->ps->velocity[0] * 0.66);
|
|
|
|
pm->ps->velocity[1] = (int)((float)pm->ps->velocity[1] * 0.66);
|
|
|
|
pm->ps->velocity[2] = (int)((float)pm->ps->velocity[2] * 0.66);
|
2001-11-12 07:59:19 +00:00
|
|
|
|
2001-06-13 01:14:31 +00:00
|
|
|
// pm->ps->speed = 0; //Dosent work
|
|
|
|
}
|
2001-05-06 20:50:27 +00:00
|
|
|
} else {
|
|
|
|
// airborne
|
|
|
|
PM_AirMove();
|
|
|
|
}
|
|
|
|
|
|
|
|
PM_Animate();
|
|
|
|
|
|
|
|
// set groundentity, watertype, and waterlevel
|
|
|
|
PM_GroundTrace();
|
|
|
|
PM_SetWaterLevel();
|
|
|
|
|
|
|
|
// weapons
|
2001-08-30 09:47:39 +00:00
|
|
|
PM_Reload();
|
2001-05-06 20:50:27 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//PM_CheckStuck();
|
|
|
|
|
|
|
|
}
|
|
|
|
|