Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3369 lines
79 KiB

9 years ago
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include <assert.h>
//#include <stdio.h> // NULL
#include <math.h> // sqrt
#include <string.h> // strcpy
#include <stdlib.h> // atoi
#include <ctype.h> // isspace
9 years ago
#include "mathlib.h"
4 years ago
#if HAVE_TGMATH_H
#include <tgmath.h>
#endif
9 years ago
#include "const.h"
#include "usercmd.h"
#include "pm_defs.h"
#include "pm_shared.h"
#include "pm_movevars.h"
#include "pm_debug.h"
int g_bhopcap = 1;
4 years ago
#if CLIENT_DLL
// Spectator Mode
int iJumpSpectator;
extern float vJumpOrigin[3];
extern float vJumpAngles[3];
9 years ago
#endif
static int pm_shared_initialized = 0;
4 years ago
#if _MSC_VER
9 years ago
#pragma warning( disable : 4305 )
#endif
9 years ago
playermove_t *pmove = NULL;
// Ducking time
#define TIME_TO_DUCK 0.4f
9 years ago
#define VEC_DUCK_HULL_MIN -18
#define VEC_DUCK_HULL_MAX 18
#define VEC_DUCK_VIEW 12
#define PM_DEAD_VIEWHEIGHT -8
8 years ago
#define MAX_CLIMB_SPEED 200
#define STUCK_MOVEUP 1
#define STUCK_MOVEDOWN -1
9 years ago
#define VEC_HULL_MIN -36
#define VEC_HULL_MAX 36
8 years ago
#define VEC_VIEW 28
#define STOP_EPSILON 0.1f
9 years ago
#define CTEXTURESMAX 512 // max number of textures loaded
#include "pm_materials.h"
9 years ago
8 years ago
#define STEP_CONCRETE 0 // default step sound
9 years ago
#define STEP_METAL 1 // metal floor
#define STEP_DIRT 2 // dirt, sand, rock
#define STEP_VENT 3 // ventillation duct
#define STEP_GRATE 4 // metal grating
#define STEP_TILE 5 // floor tiles
#define STEP_SLOSH 6 // shallow liquid puddle
#define STEP_WADE 7 // wading in liquid
#define STEP_LADDER 8 // climbing ladder
#define STEP_SNOW 9
9 years ago
#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet
#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet
#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second.
#define PLAYER_MIN_BOUNCE_SPEED 200
8 years ago
#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast.
9 years ago
8 years ago
#define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump
9 years ago
#define PLAYER_DUCKING_MULTIPLIER 0.333f
9 years ago
// double to float warning
4 years ago
#if _MSC_VER
9 years ago
#pragma warning(disable : 4244)
#endif
9 years ago
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
// up / down
8 years ago
#define PITCH 0
9 years ago
// left / right
#define YAW 1
// fall over
8 years ago
#define ROLL 2
9 years ago
8 years ago
#define MAX_CLIENTS 32
9 years ago
#define CONTENTS_CURRENT_0 -9
#define CONTENTS_CURRENT_90 -10
8 years ago
#define CONTENTS_CURRENT_180 -11
#define CONTENTS_CURRENT_270 -12
9 years ago
#define CONTENTS_CURRENT_UP -13
8 years ago
#define CONTENTS_CURRENT_DOWN -14
9 years ago
8 years ago
#define CONTENTS_TRANSLUCENT -15
9 years ago
static vec3_t rgv3tStuckTable[54];
static int rgStuckLast[MAX_CLIENTS][2];
// Texture names
static int gcTextures = 0;
static char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX];
static char grgchTextureType[CTEXTURESMAX];
int g_onladder = 0;
void PM_SwapTextures( int i, int j )
{
char chTemp;
8 years ago
char szTemp[CBTEXTURENAMEMAX];
9 years ago
8 years ago
strcpy( szTemp, grgszTextureName[i] );
chTemp = grgchTextureType[i];
9 years ago
8 years ago
strcpy( grgszTextureName[i], grgszTextureName[j] );
grgchTextureType[i] = grgchTextureType[j];
9 years ago
8 years ago
strcpy( grgszTextureName[j], szTemp );
grgchTextureType[j] = chTemp;
9 years ago
}
void PM_SortTextures( void )
{
// Bubble sort, yuck, but this only occurs at startup and it's only 512 elements...
//
int i, j;
8 years ago
for( i = 0; i < gcTextures; i++ )
9 years ago
{
8 years ago
for( j = i + 1; j < gcTextures; j++ )
9 years ago
{
8 years ago
if( stricmp( grgszTextureName[i], grgszTextureName[j] ) > 0 )
9 years ago
{
// Swap
//
PM_SwapTextures( i, j );
}
}
}
}
void PM_InitTextureTypes()
{
char buffer[512];
int i, j;
byte *pMemFile;
int fileSize, filePos = 0;
9 years ago
static qboolean bTextureTypeInit = false;
8 years ago
if( bTextureTypeInit )
9 years ago
return;
memset(&( grgszTextureName[0][0] ), 0, sizeof( grgszTextureName ) );
memset( grgchTextureType, 0, sizeof( grgchTextureType ) );
9 years ago
gcTextures = 0;
pMemFile = pmove->COM_LoadFile( "sound/materials.txt", 5, &fileSize );
8 years ago
if( !pMemFile )
9 years ago
return;
memset( buffer, 0, sizeof( buffer ) );
9 years ago
// for each line in the file...
8 years ago
while( pmove->memfgets( pMemFile, fileSize, &filePos, buffer, 511 ) != NULL && (gcTextures < CTEXTURESMAX ) )
9 years ago
{
// skip whitespace
i = 0;
8 years ago
while( buffer[i] && isspace( buffer[i] ) )
9 years ago
i++;
8 years ago
if( !buffer[i] )
9 years ago
continue;
// skip comment lines
8 years ago
if( buffer[i] == '/' || !isalpha( buffer[i] ) )
9 years ago
continue;
// get texture type
8 years ago
grgchTextureType[gcTextures] = toupper( buffer[i++] );
9 years ago
// skip whitespace
8 years ago
while( buffer[i] && isspace( buffer[i] ) )
9 years ago
i++;
8 years ago
if( !buffer[i] )
9 years ago
continue;
// get sentence name
j = i;
8 years ago
while( buffer[j] && !isspace( buffer[j] ) )
9 years ago
j++;
8 years ago
if( !buffer[j] )
9 years ago
continue;
// null-terminate name and save in sentences array
8 years ago
j = min( j, CBTEXTURENAMEMAX - 1 + i );
9 years ago
buffer[j] = 0;
8 years ago
strcpy( &( grgszTextureName[gcTextures++][0] ), &( buffer[i] ) );
9 years ago
}
// Must use engine to free since we are in a .dll
8 years ago
pmove->COM_FreeFile( pMemFile );
9 years ago
PM_SortTextures();
bTextureTypeInit = true;
}
char PM_FindTextureType( char *name )
{
int left, right, pivot;
int val;
assert( pm_shared_initialized );
left = 0;
right = gcTextures - 1;
8 years ago
while( left <= right )
9 years ago
{
pivot = ( left + right ) / 2;
8 years ago
val = strnicmp( name, grgszTextureName[pivot], CBTEXTURENAMEMAX - 1 );
if( val == 0 )
9 years ago
{
8 years ago
return grgchTextureType[pivot];
9 years ago
}
8 years ago
else if( val > 0 )
9 years ago
{
left = pivot + 1;
}
8 years ago
else if( val < 0 )
9 years ago
{
right = pivot - 1;
}
}
return CHAR_TEX_CONCRETE;
}
void PM_PlayStepSound( int step, float fvol )
{
static int iSkipStep = 0;
int irand;
vec3_t hvel;
pmove->iStepLeft = !pmove->iStepLeft;
8 years ago
if( !pmove->runfuncs )
9 years ago
{
return;
}
8 years ago
irand = pmove->RandomLong( 0, 1 ) + ( pmove->iStepLeft * 2 );
9 years ago
// FIXME mp_footsteps needs to be a movevar
8 years ago
if( pmove->multiplayer && !pmove->movevars->footsteps )
9 years ago
return;
VectorCopy( pmove->velocity, hvel );
hvel[2] = 0.0f;
9 years ago
8 years ago
if( pmove->multiplayer && ( !g_onladder && Length( hvel ) <= 220 ) )
9 years ago
return;
// irand - 0,1 for right foot, 2,3 for left foot
// used to alternate left and right foot
// FIXME, move to player state
8 years ago
switch( step )
9 years ago
{
default:
case STEP_CONCRETE:
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_step1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_step3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_step2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_step4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_METAL:
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_DIRT:
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_VENT:
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_GRATE:
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_TILE:
8 years ago
if( !pmove->RandomLong( 0, 4 ) )
9 years ago
irand = 4;
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 4:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile5.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_SLOSH:
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_WADE:
8 years ago
if( iSkipStep == 0 )
9 years ago
{
iSkipStep++;
break;
}
8 years ago
if( iSkipStep++ == 3 )
9 years ago
{
iSkipStep = 0;
}
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_LADDER:
if (pmove->flags & FL_IMMUNE_SLIME) {
break;
}
8 years ago
switch( irand )
9 years ago
{
// right foot
8 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
// left foot
8 years ago
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
9 years ago
}
break;
case STEP_SNOW:
switch( irand )
{
// right foot
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_snow1.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_snow3.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
// left foot
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_snow2.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_snow4.wav", fvol, ATTN_NORM, 0, PITCH_NORM );
break;
}
break;
9 years ago
}
}
8 years ago
int PM_MapTextureTypeStepType( char chTextureType )
9 years ago
{
8 years ago
switch( chTextureType )
9 years ago
{
default:
8 years ago
case CHAR_TEX_CONCRETE:
return STEP_CONCRETE;
case CHAR_TEX_METAL:
return STEP_METAL;
case CHAR_TEX_DIRT:
return STEP_DIRT;
case CHAR_TEX_VENT:
return STEP_VENT;
case CHAR_TEX_GRATE:
return STEP_GRATE;
case CHAR_TEX_TILE:
return STEP_TILE;
case CHAR_TEX_SLOSH:
return STEP_SLOSH;
case CHAR_TEX_SNOW_OPFOR:
return STEP_SNOW;
9 years ago
}
}
/*
====================
PM_CatagorizeTextureType
Determine texture info for the texture we are standing on.
====================
*/
void PM_CatagorizeTextureType( void )
{
vec3_t start, end;
const char *pTextureName;
VectorCopy( pmove->origin, start );
VectorCopy( pmove->origin, end );
// Straight down
end[2] -= 64;
// Fill in default values, just in case.
pmove->sztexturename[0] = '\0';
pmove->chtexturetype = CHAR_TEX_CONCRETE;
pTextureName = pmove->PM_TraceTexture( pmove->onground, start, end );
8 years ago
if( !pTextureName )
9 years ago
return;
// strip leading '-0' or '+0~' or '{' or '!'
8 years ago
if( *pTextureName == '-' || *pTextureName == '+' )
9 years ago
pTextureName += 2;
8 years ago
if( *pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ' )
9 years ago
pTextureName++;
// '}}'
strcpy( pmove->sztexturename, pTextureName);
8 years ago
pmove->sztexturename[CBTEXTURENAMEMAX - 1] = 0;
9 years ago
// get texture type
pmove->chtexturetype = PM_FindTextureType( pmove->sztexturename );
}
void PM_UpdateStepSound( void )
{
8 years ago
int fWalking;
9 years ago
float fvol;
vec3_t knee;
vec3_t feet;
//vec3_t center;
9 years ago
float height;
float speed;
float velrun;
float velwalk;
float flduck;
8 years ago
int fLadder;
9 years ago
int step;
8 years ago
if( pmove->flTimeStepSound > 0 )
9 years ago
return;
8 years ago
if( pmove->flags & FL_FROZEN )
9 years ago
return;
PM_CatagorizeTextureType();
speed = Length( pmove->velocity );
// determine if we are on a ladder
fLadder = ( pmove->movetype == MOVETYPE_FLY );// IsOnLadder();
// UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!!
8 years ago
if( ( pmove->flags & FL_DUCKING) || fLadder )
9 years ago
{
velwalk = 60; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow
velrun = 80; // UNDONE: Move walking to server
flduck = 100;
}
else
{
velwalk = 120;
velrun = 210;
flduck = 0;
}
// If we're on a ladder or on the ground, and we're moving fast enough,
// play step sound. Also, if pmove->flTimeStepSound is zero, get the new
// sound right away - we just started moving in new level.
if( ( fLadder || ( pmove->onground != -1 ) ) && ( Length( pmove->velocity ) > 0.0f ) && ( speed >= velwalk || !pmove->flTimeStepSound ) )
9 years ago
{
fWalking = speed < velrun;
//VectorCopy( pmove->origin, center );
9 years ago
VectorCopy( pmove->origin, knee );
VectorCopy( pmove->origin, feet );
8 years ago
height = pmove->player_maxs[pmove->usehull][2] - pmove->player_mins[pmove->usehull][2];
9 years ago
knee[2] = pmove->origin[2] - 0.3f * height;
feet[2] = pmove->origin[2] - 0.5f * height;
9 years ago
// find out what we're stepping in or on...
8 years ago
if( fLadder )
9 years ago
{
step = STEP_LADDER;
fvol = 0.35f;
9 years ago
pmove->flTimeStepSound = 350;
}
8 years ago
else if( pmove->PM_PointContents( knee, NULL ) == CONTENTS_WATER )
9 years ago
{
step = STEP_WADE;
fvol = 0.65f;
9 years ago
pmove->flTimeStepSound = 600;
}
8 years ago
else if( pmove->PM_PointContents( feet, NULL ) == CONTENTS_WATER )
9 years ago
{
step = STEP_SLOSH;
fvol = fWalking ? 0.2f : 0.5f;
9 years ago
pmove->flTimeStepSound = fWalking ? 400 : 300;
}
else
{
// find texture under player, if different from current texture,
// get material type
step = PM_MapTextureTypeStepType( pmove->chtexturetype );
8 years ago
switch( pmove->chtexturetype )
9 years ago
{
default:
case CHAR_TEX_CONCRETE:
fvol = fWalking ? 0.2f : 0.5f;
9 years ago
pmove->flTimeStepSound = fWalking ? 400 : 300;
break;
case CHAR_TEX_METAL:
fvol = fWalking ? 0.2f : 0.5f;
9 years ago
pmove->flTimeStepSound = fWalking ? 400 : 300;
break;
case CHAR_TEX_DIRT:
case CHAR_TEX_SNOW_OPFOR:
fvol = fWalking ? 0.25f : 0.55f;
9 years ago
pmove->flTimeStepSound = fWalking ? 400 : 300;
break;
case CHAR_TEX_VENT:
fvol = fWalking ? 0.4f : 0.7f;
9 years ago
pmove->flTimeStepSound = fWalking ? 400 : 300;
break;
case CHAR_TEX_GRATE:
fvol = fWalking ? 0.2f : 0.5f;
9 years ago
pmove->flTimeStepSound = fWalking ? 400 : 300;
break;
case CHAR_TEX_TILE:
fvol = fWalking ? 0.2f : 0.5f;
9 years ago
pmove->flTimeStepSound = fWalking ? 400 : 300;
break;
case CHAR_TEX_SLOSH:
fvol = fWalking ? 0.2f : 0.5f;
9 years ago
pmove->flTimeStepSound = fWalking ? 400 : 300;
break;
}
}
8 years ago
9 years ago
pmove->flTimeStepSound += flduck; // slower step time if ducking
// play the sound
// 35% volume if ducking
8 years ago
if( pmove->flags & FL_DUCKING )
9 years ago
{
fvol *= 0.35f;
9 years ago
}
PM_PlayStepSound( step, fvol );
}
}
/*
================
PM_AddToTouched
Add's the trace result to touch list, if contact is not already in list.
================
*/
8 years ago
qboolean PM_AddToTouched( pmtrace_t tr, vec3_t impactvelocity )
9 years ago
{
int i;
8 years ago
for( i = 0; i < pmove->numtouch; i++ )
9 years ago
{
8 years ago
if( pmove->touchindex[i].ent == tr.ent )
9 years ago
break;
}
8 years ago
if( i != pmove->numtouch ) // Already in list.
9 years ago
return false;
VectorCopy( impactvelocity, tr.deltavelocity );
8 years ago
if( pmove->numtouch >= MAX_PHYSENTS )
pmove->Con_DPrintf( "Too many entities were touched!\n" );
9 years ago
pmove->touchindex[pmove->numtouch++] = tr;
return true;
}
/*
================
PM_CheckVelocity
See if the player has a bogus velocity value.
================
*/
8 years ago
void PM_CheckVelocity()
9 years ago
{
8 years ago
int i;
9 years ago
//
// bound velocity
//
8 years ago
for( i = 0; i < 3; i++ )
9 years ago
{
// See if it's bogus.
8 years ago
if( IS_NAN( pmove->velocity[i] ) )
9 years ago
{
8 years ago
pmove->Con_Printf( "PM Got a NaN velocity %i\n", i );
9 years ago
pmove->velocity[i] = 0;
}
8 years ago
if( IS_NAN( pmove->origin[i] ) )
9 years ago
{
8 years ago
pmove->Con_Printf( "PM Got a NaN origin on %i\n", i );
9 years ago
pmove->origin[i] = 0;
}
// Bound it.
8 years ago
if( pmove->velocity[i] > pmove->movevars->maxvelocity )
9 years ago
{
8 years ago
pmove->Con_DPrintf( "PM Got a velocity too high on %i\n", i );
9 years ago
pmove->velocity[i] = pmove->movevars->maxvelocity;
}
8 years ago
else if( pmove->velocity[i] < -pmove->movevars->maxvelocity )
9 years ago
{
8 years ago
pmove->Con_DPrintf( "PM Got a velocity too low on %i\n", i );
9 years ago
pmove->velocity[i] = -pmove->movevars->maxvelocity;
}
}
}
/*
==================
PM_ClipVelocity
Slide off of the impacting object
returns the blocked flags:
0x01 == floor
0x02 == step / wall
==================
*/
8 years ago
int PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce )
9 years ago
{
8 years ago
float backoff;
float change;
9 years ago
float angle;
8 years ago
int i, blocked;
9 years ago
8 years ago
angle = normal[2];
9 years ago
blocked = 0x00; // Assume unblocked.
8 years ago
if( angle > 0 ) // If the plane that is blocking us has a positive z component, then assume it's a floor.
blocked |= 0x01;
if( !angle ) // If the plane has no Z, it is vertical (wall/step)
blocked |= 0x02;
9 years ago
// Determine how far along plane to slide based on incoming direction.
// Scale by overbounce factor.
8 years ago
backoff = DotProduct( in, normal ) * overbounce;
9 years ago
8 years ago
for( i = 0; i < 3; i++ )
9 years ago
{
8 years ago
change = normal[i] * backoff;
9 years ago
out[i] = in[i] - change;
// If out velocity is too small, zero it out.
8 years ago
if( out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON )
9 years ago
out[i] = 0;
}
8 years ago
9 years ago
// Return blocking flags.
return blocked;
}
8 years ago
void PM_AddCorrectGravity()
9 years ago
{
8 years ago
float ent_gravity;
9 years ago
8 years ago
if( pmove->waterjumptime )
9 years ago
return;
8 years ago
if( pmove->gravity )
9 years ago
ent_gravity = pmove->gravity;
else
ent_gravity = 1.0f;
9 years ago
// Add gravity so they'll be in the correct position during movement
// yes, this 0.5 looks wrong, but it's not.
pmove->velocity[2] -= ( ent_gravity * pmove->movevars->gravity * 0.5f * pmove->frametime );
9 years ago
pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime;
pmove->basevelocity[2] = 0;
PM_CheckVelocity();
}
8 years ago
void PM_FixupGravityVelocity()
9 years ago
{
8 years ago
float ent_gravity;
9 years ago
8 years ago
if( pmove->waterjumptime )
9 years ago
return;
8 years ago
if( pmove->gravity )
9 years ago
ent_gravity = pmove->gravity;
else
ent_gravity = 1.0f;
9 years ago
// Get the correct velocity for the end of the dt
pmove->velocity[2] -= ( ent_gravity * pmove->movevars->gravity * pmove->frametime * 0.5f );
9 years ago
PM_CheckVelocity();
}
/*
============
PM_FlyMove
The basic solid body movement clip that slides along multiple planes
============
*/
8 years ago
int PM_FlyMove( void )
9 years ago
{
8 years ago
int bumpcount, numbumps;
vec3_t dir;
float d;
int numplanes;
vec3_t planes[MAX_CLIP_PLANES];
vec3_t primal_velocity, original_velocity;
vec3_t new_velocity;
int i, j;
pmtrace_t trace;
vec3_t end;
float time_left, allFraction;
int blocked;
numbumps = 4; // Bump up to four times
blocked = 0; // Assume not blocked
9 years ago
numplanes = 0; // and not sliding along any planes
8 years ago
VectorCopy( pmove->velocity, original_velocity ); // Store original velocity
VectorCopy( pmove->velocity, primal_velocity );
9 years ago
allFraction = 0;
time_left = pmove->frametime; // Total time for this movement operation.
8 years ago
for( bumpcount = 0; bumpcount < numbumps; bumpcount++ )
9 years ago
{
8 years ago
if( !pmove->velocity[0] && !pmove->velocity[1] && !pmove->velocity[2] )
9 years ago
break;
// Assume we can move all the way from the current origin to the
// end point.
8 years ago
for( i = 0;i < 3; i++ )
9 years ago
end[i] = pmove->origin[i] + time_left * pmove->velocity[i];
// See if we can make it from origin to end point.
8 years ago
trace = pmove->PM_PlayerTrace( pmove->origin, end, PM_NORMAL, -1 );
9 years ago
allFraction += trace.fraction;
// If we started in a solid object, or we were in solid space
// the whole way, zero out our velocity and return that we
// are blocked by floor and wall.
8 years ago
if( trace.allsolid )
9 years ago
{ // entity is trapped in another solid
8 years ago
VectorCopy( vec3_origin, pmove->velocity );
//Con_DPrintf( "Trapped 4\n" );
9 years ago
return 4;
}
// If we moved some portion of the total distance, then
// copy the end position into the pmove->origin and
// zero the plane counter.
8 years ago
if( trace.fraction > 0 )
9 years ago
{ // actually covered some distance
8 years ago
VectorCopy( trace.endpos, pmove->origin );
VectorCopy( pmove->velocity, original_velocity );
9 years ago
numplanes = 0;
}
// If we covered the entire distance, we are done
// and can return.
8 years ago
if( trace.fraction == 1 )
9 years ago
break; // moved the entire distance
8 years ago
//if( !trace.ent )
// Sys_Error( "PM_PlayerTrace: !trace.ent" );
9 years ago
// Save entity that blocked us (since fraction was < 1.0)
// for contact
// Add it if it's not already in the list!!!
8 years ago
PM_AddToTouched( trace, pmove->velocity );
9 years ago
// If the plane we hit has a high z component in the normal, then
// it's probably a floor
if( trace.plane.normal[2] > 0.7f )
9 years ago
{
8 years ago
blocked |= 1; // floor
9 years ago
}
// If the plane has a zero z component in the normal, then it's a
// step or wall
8 years ago
if( !trace.plane.normal[2] )
9 years ago
{
8 years ago
blocked |= 2; // step / wall
//Con_DPrintf( "Blocked by %i\n", trace.ent );
9 years ago
}
// Reduce amount of pmove->frametime left by total time left * fraction
// that we covered.
time_left -= time_left * trace.fraction;
// Did we run out of planes to clip against?
8 years ago
if( numplanes >= MAX_CLIP_PLANES )
9 years ago
{ // this shouldn't really happen
// Stop our movement if so.
8 years ago
VectorCopy( vec3_origin, pmove->velocity );
//Con_DPrintf( "Too many planes 4\n" );
9 years ago
break;
}
// Set up next clipping plane
8 years ago
VectorCopy( trace.plane.normal, planes[numplanes] );
9 years ago
numplanes++;
8 years ago
// modify original_velocity so it parallels all of the clip planes
//
if( pmove->movetype == MOVETYPE_WALK && ( ( pmove->onground == -1 ) || ( pmove->friction != 1 ) ) ) // relfect player velocity
9 years ago
{
8 years ago
for( i = 0; i < numplanes; i++ )
9 years ago
{
if( planes[i][2] > 0.7f )
8 years ago
{
// floor or slope
9 years ago
PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1 );
VectorCopy( new_velocity, original_velocity );
}
8 years ago
else
PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0f + pmove->movevars->bounce * ( 1 - pmove->friction ) );
9 years ago
}
VectorCopy( new_velocity, pmove->velocity );
VectorCopy( new_velocity, original_velocity );
}
else
{
8 years ago
for( i = 0; i < numplanes; i++ )
9 years ago
{
8 years ago
PM_ClipVelocity( original_velocity, planes[i], pmove->velocity, 1 );
for( j = 0; j < numplanes; j++ )
if( j != i )
9 years ago
{
// Are we now moving against this plane?
8 years ago
if( DotProduct( pmove->velocity, planes[j] ) < 0 )
9 years ago
break; // not ok
}
8 years ago
if( j == numplanes ) // Didn't have to clip, so we're ok
9 years ago
break;
}
// Did we go all the way through plane set
8 years ago
if( i != numplanes )
{
// go along this plane
// pmove->velocity is set in clipping call, no need to set again.
9 years ago
}
else
{ // go along the crease
8 years ago
if( numplanes != 2 )
9 years ago
{
8 years ago
//Con_Printf( "clip velocity, numplanes == %i\n",numplanes );
VectorCopy( vec3_origin, pmove->velocity );
//Con_DPrintf( "Trapped 4\n" );
9 years ago
break;
}
8 years ago
CrossProduct( planes[0], planes[1], dir );
d = DotProduct( dir, pmove->velocity );
VectorScale( dir, d, pmove->velocity );
9 years ago
}
8 years ago
//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
if( DotProduct( pmove->velocity, primal_velocity ) <= 0 )
9 years ago
{
8 years ago
//Con_DPrintf( "Back\n" );
VectorCopy( vec3_origin, pmove->velocity );
9 years ago
break;
}
}
}
8 years ago
if( allFraction == 0 )
9 years ago
{
8 years ago
VectorCopy( vec3_origin, pmove->velocity );
9 years ago
//Con_DPrintf( "Don't stick\n" );
}
return blocked;
}
/*
==============
PM_Accelerate
==============
*/
8 years ago
void PM_Accelerate( vec3_t wishdir, float wishspeed, float accel )
9 years ago
{
8 years ago
int i;
float addspeed, accelspeed, currentspeed;
9 years ago
// Dead player's don't accelerate
8 years ago
if( pmove->dead )
9 years ago
return;
// If waterjumping, don't accelerate
8 years ago
if( pmove->waterjumptime )
9 years ago
return;
// See if we are changing direction a bit
8 years ago
currentspeed = DotProduct( pmove->velocity, wishdir );
9 years ago
// Reduce wishspeed by the amount of veer.
addspeed = wishspeed - currentspeed;
// If not going to add any speed, done.
8 years ago
if( addspeed <= 0 )
9 years ago
return;
// Determine amount of accleration.
accelspeed = accel * pmove->frametime * wishspeed * pmove->friction;
// Cap at addspeed
8 years ago
if( accelspeed > addspeed )
9 years ago
accelspeed = addspeed;
// Adjust velocity.
8 years ago
for( i = 0; i < 3; i++ )
9 years ago
{
pmove->velocity[i] += accelspeed * wishdir[i];
}
}
/*
=====================
PM_WalkMove
Only used by players. Moves along the ground when player is a MOVETYPE_WALK.
======================
*/
8 years ago
void PM_WalkMove()
9 years ago
{
//int clip;
8 years ago
int oldonground;
9 years ago
int i;
8 years ago
vec3_t wishvel;
float spd;
float fmove, smove;
vec3_t wishdir;
float wishspeed;
9 years ago
vec3_t dest; //, start;
9 years ago
vec3_t original, originalvel;
vec3_t down, downvel;
float downdist, updist;
pmtrace_t trace;
8 years ago
9 years ago
// Copy movement amounts
fmove = pmove->cmd.forwardmove;
smove = pmove->cmd.sidemove;
8 years ago
9 years ago
// Zero out z components of movement vectors
pmove->forward[2] = 0;
8 years ago
pmove->right[2] = 0;
VectorNormalize( pmove->forward ); // Normalize remainder of vectors.
VectorNormalize( pmove->right ); //
for( i = 0; i < 2; i++ ) // Determine x and y parts of velocity
wishvel[i] = pmove->forward[i] * fmove + pmove->right[i] * smove;
9 years ago
wishvel[2] = 0; // Zero out z part of velocity
8 years ago
VectorCopy( wishvel, wishdir ); // Determine maginitude of speed of move
wishspeed = VectorNormalize( wishdir );
9 years ago
8 years ago
//
// Clamp to server defined max speed
//
if( wishspeed > pmove->maxspeed )
9 years ago
{
8 years ago
VectorScale( wishvel, pmove->maxspeed / wishspeed, wishvel );
9 years ago
wishspeed = pmove->maxspeed;
}
// Set pmove velocity
pmove->velocity[2] = 0;
8 years ago
PM_Accelerate( wishdir, wishspeed, pmove->movevars->accelerate );
9 years ago
pmove->velocity[2] = 0;
// Add in any base velocity to the current velocity.
8 years ago
VectorAdd( pmove->velocity, pmove->basevelocity, pmove->velocity );
9 years ago
spd = Length( pmove->velocity );
8 years ago
if( spd < 1.0f )
9 years ago
{
VectorClear( pmove->velocity );
return;
}
// If we are not moving, do nothing
8 years ago
//if( !pmove->velocity[0] && !pmove->velocity[1] && !pmove->velocity[2] )
9 years ago
// return;
oldonground = pmove->onground;
8 years ago
// first try just moving to the destination
dest[0] = pmove->origin[0] + pmove->velocity[0] * pmove->frametime;
dest[1] = pmove->origin[1] + pmove->velocity[1] * pmove->frametime;
9 years ago
dest[2] = pmove->origin[2];
// first try moving directly to the next spot
//VectorCopy( dest, start );
8 years ago
trace = pmove->PM_PlayerTrace( pmove->origin, dest, PM_NORMAL, -1 );
9 years ago
// If we made it all the way, then copy trace end
// as new player position.
8 years ago
if( trace.fraction == 1 )
9 years ago
{
8 years ago
VectorCopy( trace.endpos, pmove->origin );
9 years ago
return;
}
8 years ago
// Don't walk up stairs if not on ground.
if( oldonground == -1 && pmove->waterlevel == 0 )
9 years ago
return;
8 years ago
if( pmove->waterjumptime ) // If we are jumping out of water, don't do anything more.
9 years ago
return;
// Try sliding forward both on ground and up 16 pixels
// take the move that goes farthest
8 years ago
VectorCopy( pmove->origin, original ); // Save out original pos &
VectorCopy( pmove->velocity, originalvel ); // velocity.
9 years ago
// Slide move
//clip = PM_FlyMove();
PM_FlyMove();
9 years ago
// Copy the results out
8 years ago
VectorCopy( pmove->origin, down );
VectorCopy( pmove->velocity, downvel );
9 years ago
// Reset original values.
8 years ago
VectorCopy( original, pmove->origin );
9 years ago
8 years ago
VectorCopy( originalvel, pmove->velocity );
9 years ago
// Start out up one stair height
8 years ago
VectorCopy( pmove->origin, dest );
9 years ago
dest[2] += pmove->movevars->stepsize;
8 years ago
trace = pmove->PM_PlayerTrace( pmove->origin, dest, PM_NORMAL, -1 );
9 years ago
// If we started okay and made it part of the way at least,
// copy the results to the movement start position and then
// run another move try.
8 years ago
if( !trace.startsolid && !trace.allsolid )
9 years ago
{
8 years ago
VectorCopy( trace.endpos, pmove->origin );
9 years ago
}
8 years ago
// slide move the rest of the way.
//clip = PM_FlyMove();
PM_FlyMove();
9 years ago
8 years ago
// Now try going back down from the end point
// press down the stepheight
VectorCopy( pmove->origin, dest );
9 years ago
dest[2] -= pmove->movevars->stepsize;
8 years ago
trace = pmove->PM_PlayerTrace( pmove->origin, dest, PM_NORMAL, -1 );
9 years ago
// If we are not on the ground any more then
// use the original movement attempt
if( trace.plane.normal[2] < 0.7f )
9 years ago
goto usedown;
9 years ago
// If the trace ended up in empty space, copy the end
// over to the origin.
8 years ago
if( !trace.startsolid && !trace.allsolid )
9 years ago
{
8 years ago
VectorCopy( trace.endpos, pmove->origin );
9 years ago
}
// Copy this origion to up.
8 years ago
VectorCopy( pmove->origin, pmove->up );
9 years ago
// decide which one went farther
8 years ago
downdist = ( down[0] - original[0] ) * ( down[0] - original[0] )
+ ( down[1] - original[1] ) * ( down[1] - original[1] );
updist = ( pmove->up[0] - original[0] ) * ( pmove->up[0] - original[0] )
+ ( pmove->up[1] - original[1] ) * ( pmove->up[1] - original[1] );
9 years ago
8 years ago
if( downdist > updist )
9 years ago
{
usedown:
8 years ago
VectorCopy( down, pmove->origin );
VectorCopy( downvel, pmove->velocity );
9 years ago
} else // copy z value from slide move
pmove->velocity[2] = downvel[2];
}
/*
==================
PM_Friction
Handles both ground friction and water friction
==================
*/
8 years ago
void PM_Friction( void )
9 years ago
{
8 years ago
float *vel;
float speed, newspeed, control;
float friction;
float drop;
9 years ago
vec3_t newvel;
8 years ago
9 years ago
// If we are in water jump cycle, don't apply friction
8 years ago
if( pmove->waterjumptime )
9 years ago
return;
// Get velocity
vel = pmove->velocity;
// Calculate speed
8 years ago
speed = sqrt( vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2] );
9 years ago
// If too slow, return
8 years ago
if( speed < 0.1f )
9 years ago
{
return;
}
drop = 0;
8 years ago
// apply ground friction
if( pmove->onground != -1 ) // On an entity that is the ground
9 years ago
{
vec3_t start, stop;
pmtrace_t trace;
8 years ago
start[0] = stop[0] = pmove->origin[0] + vel[0] / speed * 16;
start[1] = stop[1] = pmove->origin[1] + vel[1] / speed * 16;
9 years ago
start[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2];
stop[2] = start[2] - 34;
8 years ago
trace = pmove->PM_PlayerTrace( start, stop, PM_NORMAL, -1 );
9 years ago
if( trace.fraction == 1.0f )
9 years ago
friction = pmove->movevars->friction*pmove->movevars->edgefriction;
else
friction = pmove->movevars->friction;
// Grab friction value.
//friction = pmove->movevars->friction;
friction *= pmove->friction; // player friction?
// Bleed off some speed, but if we have less than the bleed
// threshhold, bleed the theshold amount.
8 years ago
control = ( speed < pmove->movevars->stopspeed ) ? pmove->movevars->stopspeed : speed;
9 years ago
// Add the amount to t'he drop amount.
8 years ago
drop += control * friction * pmove->frametime;
9 years ago
}
8 years ago
// apply water friction
//if( pmove->waterlevel )
// drop += speed * pmove->movevars->waterfriction * waterlevel * pmove->frametime;
9 years ago
8 years ago
// scale the velocity
9 years ago
newspeed = speed - drop;
8 years ago
if( newspeed < 0 )
9 years ago
newspeed = 0;
// Determine proportion of old speed we are using.
newspeed /= speed;
// Adjust velocity according to proportion.
newvel[0] = vel[0] * newspeed;
newvel[1] = vel[1] * newspeed;
newvel[2] = vel[2] * newspeed;
VectorCopy( newvel, pmove->velocity );
}
8 years ago
void PM_AirAccelerate( vec3_t wishdir, float wishspeed, float accel )
9 years ago
{
8 years ago
int i;
float addspeed, accelspeed, currentspeed, wishspd = wishspeed;
if( pmove->dead )
9 years ago
return;
8 years ago
if( pmove->waterjumptime )
9 years ago
return;
// Cap speed
8 years ago
//wishspd = VectorNormalize( pmove->wishveloc );
if( wishspd > 30 )
9 years ago
wishspd = 30;
// Determine veer amount
8 years ago
currentspeed = DotProduct( pmove->velocity, wishdir );
9 years ago
// See how much to add
addspeed = wishspd - currentspeed;
// If not adding any, done.
8 years ago
if( addspeed <= 0 )
9 years ago
return;
// Determine acceleration speed after acceleration
accelspeed = accel * wishspeed * pmove->frametime * pmove->friction;
// Cap it
8 years ago
if( accelspeed > addspeed )
9 years ago
accelspeed = addspeed;
8 years ago
9 years ago
// Adjust pmove vel.
8 years ago
for( i = 0; i < 3; i++ )
9 years ago
{
8 years ago
pmove->velocity[i] += accelspeed * wishdir[i];
9 years ago
}
}
/*
===================
PM_WaterMove
===================
*/
8 years ago
void PM_WaterMove( void )
9 years ago
{
8 years ago
int i;
vec3_t wishvel;
float wishspeed;
vec3_t wishdir;
vec3_t start, dest;
vec3_t temp;
pmtrace_t trace;
9 years ago
float speed, newspeed, addspeed, accelspeed;
//
// user intentions
//
8 years ago
for( i = 0; i < 3; i++ )
wishvel[i] = pmove->forward[i] * pmove->cmd.forwardmove + pmove->right[i] * pmove->cmd.sidemove;
9 years ago
// Sinking after no other movement occurs
8 years ago
if( !pmove->cmd.forwardmove && !pmove->cmd.sidemove && !pmove->cmd.upmove )
9 years ago
wishvel[2] -= 60; // drift towards bottom
else // Go straight up by upmove amount.
wishvel[2] += pmove->cmd.upmove;
// Copy it over and determine speed
8 years ago
VectorCopy( wishvel, wishdir );
wishspeed = VectorNormalize( wishdir );
9 years ago
// Cap speed.
8 years ago
if( wishspeed > pmove->maxspeed )
9 years ago
{
8 years ago
VectorScale( wishvel, pmove->maxspeed / wishspeed, wishvel );
9 years ago
wishspeed = pmove->maxspeed;
}
// Slow us down a bit.
wishspeed *= 0.8f;
9 years ago
8 years ago
VectorAdd( pmove->velocity, pmove->basevelocity, pmove->velocity );
// Water friction
VectorCopy( pmove->velocity, temp );
speed = VectorNormalize( temp );
if( speed )
9 years ago
{
newspeed = speed - pmove->frametime * speed * pmove->movevars->friction * pmove->friction;
8 years ago
if( newspeed < 0 )
9 years ago
newspeed = 0;
8 years ago
VectorScale( pmove->velocity, newspeed / speed, pmove->velocity );
9 years ago
}
else
newspeed = 0;
//
// water acceleration
//
8 years ago
if( wishspeed < 0.1f )
9 years ago
{
return;
}
addspeed = wishspeed - newspeed;
8 years ago
if( addspeed > 0 )
9 years ago
{
8 years ago
VectorNormalize( wishvel );
9 years ago
accelspeed = pmove->movevars->accelerate * wishspeed * pmove->frametime * pmove->friction;
8 years ago
if( accelspeed > addspeed )
9 years ago
accelspeed = addspeed;
8 years ago
for( i = 0; i < 3; i++ )
9 years ago
pmove->velocity[i] += accelspeed * wishvel[i];
}
// Now move
// assume it is a stair or a slope, so press down from stepheight above
8 years ago
VectorMA( pmove->origin, pmove->frametime, pmove->velocity, dest );
VectorCopy( dest, start );
9 years ago
start[2] += pmove->movevars->stepsize + 1;
8 years ago
trace = pmove->PM_PlayerTrace( start, dest, PM_NORMAL, -1 );
if( !trace.startsolid && !trace.allsolid ) // FIXME: check steep slope?
9 years ago
{ // walked up the step, so just keep result and exit
8 years ago
VectorCopy( trace.endpos, pmove->origin );
9 years ago
return;
}
8 years ago
9 years ago
// Try moving straight along out normal path.
8 years ago
PM_FlyMove();
9 years ago
}
/*
===================
PM_AirMove
===================
*/
8 years ago
void PM_AirMove( void )
9 years ago
{
8 years ago
int i;
vec3_t wishvel;
float fmove, smove;
vec3_t wishdir;
float wishspeed;
9 years ago
// Copy movement amounts
fmove = pmove->cmd.forwardmove;
smove = pmove->cmd.sidemove;
8 years ago
9 years ago
// Zero out z components of movement vectors
pmove->forward[2] = 0;
8 years ago
pmove->right[2] = 0;
9 years ago
// Renormalize
8 years ago
VectorNormalize( pmove->forward );
VectorNormalize( pmove->right );
9 years ago
// Determine x and y parts of velocity
8 years ago
for( i = 0; i < 2; i++ )
9 years ago
{
8 years ago
wishvel[i] = pmove->forward[i] * fmove + pmove->right[i] * smove;
9 years ago
}
// Zero out z part of velocity
8 years ago
wishvel[2] = 0;
9 years ago
// Determine maginitude of speed of move
8 years ago
VectorCopy( wishvel, wishdir );
wishspeed = VectorNormalize( wishdir );
9 years ago
// Clamp to server defined max speed
8 years ago
if( wishspeed > pmove->maxspeed )
9 years ago
{
8 years ago
VectorScale( wishvel, pmove->maxspeed/wishspeed, wishvel );
9 years ago
wishspeed = pmove->maxspeed;
}
8 years ago
PM_AirAccelerate( wishdir, wishspeed, pmove->movevars->airaccelerate );
9 years ago
// Add in any base velocity to the current velocity.
8 years ago
VectorAdd( pmove->velocity, pmove->basevelocity, pmove->velocity );
9 years ago
8 years ago
PM_FlyMove();
9 years ago
}
qboolean PM_InWater( void )
{
return ( pmove->waterlevel > 1 );
}
/*
=============
PM_CheckWater
Sets pmove->waterlevel and pmove->watertype values.
=============
*/
8 years ago
qboolean PM_CheckWater()
9 years ago
{
8 years ago
vec3_t point;
int cont;
int truecont;
float height;
float heightover2;
9 years ago
// Pick a spot just above the players feet.
point[0] = pmove->origin[0] + ( pmove->player_mins[pmove->usehull][0] + pmove->player_maxs[pmove->usehull][0] ) * 0.5f;
point[1] = pmove->origin[1] + ( pmove->player_mins[pmove->usehull][1] + pmove->player_maxs[pmove->usehull][1] ) * 0.5f;
9 years ago
point[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2] + 1;
8 years ago
9 years ago
// Assume that we are not in water at all.
pmove->waterlevel = 0;
pmove->watertype = CONTENTS_EMPTY;
// Grab point contents.
cont = pmove->PM_PointContents (point, &truecont );
// Are we under water? (not solid and not empty?)
8 years ago
if( cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT )
9 years ago
{
// Set water type
pmove->watertype = cont;
// We are at least at level one
pmove->waterlevel = 1;
8 years ago
height = ( pmove->player_mins[pmove->usehull][2] + pmove->player_maxs[pmove->usehull][2] );
heightover2 = height * 0.5f;
9 years ago
// Now check a point that is at the player hull midpoint.
point[2] = pmove->origin[2] + heightover2;
8 years ago
cont = pmove->PM_PointContents( point, NULL );
9 years ago
// If that point is also under water...
8 years ago
if( cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT )
9 years ago
{
// Set a higher water level.
pmove->waterlevel = 2;
// Now check the eye position. (view_ofs is relative to the origin)
point[2] = pmove->origin[2] + pmove->view_ofs[2];
8 years ago
cont = pmove->PM_PointContents( point, NULL );
if( cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT )
9 years ago
pmove->waterlevel = 3; // In over our eyes
}
// Adjust velocity based on water current, if any.
8 years ago
if( ( truecont <= CONTENTS_CURRENT_0 ) && ( truecont >= CONTENTS_CURRENT_DOWN ) )
9 years ago
{
// The deeper we are, the stronger the current.
static vec3_t current_table[] =
{
8 years ago
{1, 0, 0},
{0, 1, 0},
{-1, 0, 0},
{0, -1, 0},
{0, 0, 1},
{0, 0, -1}
9 years ago
};
8 years ago
VectorMA( pmove->basevelocity, 50.0*pmove->waterlevel, current_table[CONTENTS_CURRENT_0 - truecont], pmove->basevelocity );
9 years ago
}
}
return pmove->waterlevel > 1;
}
/*
=============
PM_CatagorizePosition
=============
*/
8 years ago
void PM_CatagorizePosition( void )
9 years ago
{
8 years ago
vec3_t point;
pmtrace_t tr;
9 years ago
// if the player hull point one unit down is solid, the player
// is on ground
// see if standing on something solid
// Doing this before we move may introduce a potential latency in water detection, but
// doing it after can get us stuck on the bottom in water if the amount we move up
// is less than the 1 pixel 'threshold' we're about to snap to. Also, we'll call
// this several times per frame, so we really need to avoid sticking to the bottom of
// water on each call, and the converse case will correct itself if called twice.
PM_CheckWater();
point[0] = pmove->origin[0];
point[1] = pmove->origin[1];
point[2] = pmove->origin[2] - 2;
8 years ago
if( pmove->velocity[2] > 180 ) // Shooting up really fast. Definitely not on ground.
9 years ago
{
pmove->onground = -1;
}
else
{
// Try and move down.
8 years ago
tr = pmove->PM_PlayerTrace( pmove->origin, point, PM_NORMAL, -1 );
9 years ago
// If we hit a steep plane, we are not on ground
if( tr.plane.normal[2] < 0.7f )
9 years ago
pmove->onground = -1; // too steep
else
pmove->onground = tr.ent; // Otherwise, point to index of ent under us.
// If we are on something...
8 years ago
if( pmove->onground != -1 )
9 years ago
{
// Then we are not in water jump sequence
pmove->waterjumptime = 0;
// If we could make the move, drop us down that 1 pixel
8 years ago
if( pmove->waterlevel < 2 && !tr.startsolid && !tr.allsolid )
VectorCopy( tr.endpos, pmove->origin );
9 years ago
}
// Standing on an entity other than the world
8 years ago
if( tr.ent > 0 ) // So signal that we are touching something.
9 years ago
{
8 years ago
PM_AddToTouched( tr, pmove->velocity );
9 years ago
}
}
}
/*
=================
PM_GetRandomStuckOffsets
When a player is stuck, it's costly to try and unstick them
Grab a test offset for the player based on a passed in index
=================
*/
8 years ago
int PM_GetRandomStuckOffsets( int nIndex, int server, vec3_t offset )
9 years ago
{
8 years ago
// Last time we did a full
9 years ago
int idx;
idx = rgStuckLast[nIndex][server]++;
8 years ago
VectorCopy( rgv3tStuckTable[idx % 54], offset );
9 years ago
8 years ago
return ( idx % 54 );
9 years ago
}
8 years ago
void PM_ResetStuckOffsets( int nIndex, int server )
9 years ago
{
rgStuckLast[nIndex][server] = 0;
}
/*
=================
NudgePosition
If pmove->origin is in a solid position,
try nudging slightly on all axis to
allow for the cut precision of the net coordinates
=================
*/
#define PM_CHECKSTUCK_MINTIME 0.05f // Don't check again too quickly.
9 years ago
8 years ago
int PM_CheckStuck( void )
9 years ago
{
8 years ago
vec3_t base;
vec3_t offset;
vec3_t test;
int hitent;
int idx;
float fTime;
9 years ago
int i;
pmtrace_t traceresult;
static float rgStuckCheckTime[MAX_CLIENTS][2]; // Last time we did a full
// If position is okay, exit
8 years ago
hitent = pmove->PM_TestPlayerPosition( pmove->origin, &traceresult );
if( hitent == -1 )
9 years ago
{
PM_ResetStuckOffsets( pmove->player_index, pmove->server );
return 0;
}
8 years ago
VectorCopy( pmove->origin, base );
9 years ago
8 years ago
//
9 years ago
// Deal with precision error in network.
8 years ago
//
if( !pmove->server )
9 years ago
{
// World or BSP model
8 years ago
if( ( hitent == 0 ) || ( pmove->physents[hitent].model != NULL ) )
9 years ago
{
int nReps = 0;
PM_ResetStuckOffsets( pmove->player_index, pmove->server );
do
{
8 years ago
i = PM_GetRandomStuckOffsets( pmove->player_index, pmove->server, offset );
9 years ago
8 years ago
VectorAdd( base, offset, test );
if( pmove->PM_TestPlayerPosition( test, &traceresult ) == -1 )
9 years ago
{
PM_ResetStuckOffsets( pmove->player_index, pmove->server );
8 years ago
VectorCopy( test, pmove->origin );
9 years ago
return 0;
}
nReps++;
8 years ago
} while( nReps < 54 );
9 years ago
}
}
// Only an issue on the client.
8 years ago
if( pmove->server )
9 years ago
idx = 0;
else
idx = 1;
fTime = pmove->Sys_FloatTime();
// Too soon?
8 years ago
if( rgStuckCheckTime[pmove->player_index][idx] >= ( fTime - PM_CHECKSTUCK_MINTIME ) )
9 years ago
{
return 1;
}
rgStuckCheckTime[pmove->player_index][idx] = fTime;
pmove->PM_StuckTouch( hitent, &traceresult );
8 years ago
i = PM_GetRandomStuckOffsets( pmove->player_index, pmove->server, offset );
9 years ago
8 years ago
VectorAdd( base, offset, test );
if( ( hitent = pmove->PM_TestPlayerPosition( test, NULL ) ) == -1 )
9 years ago
{
8 years ago
//Con_DPrintf( "Nudged\n" );
9 years ago
PM_ResetStuckOffsets( pmove->player_index, pmove->server );
8 years ago
VectorCopy( test, pmove->origin );
9 years ago
return 0;
}
// If player is flailing while stuck in another player ( should never happen ), then see
// if we can't "unstick" them forceably.
8 years ago
if( pmove->cmd.buttons & ( IN_JUMP | IN_DUCK | IN_ATTACK ) && ( pmove->physents[hitent].player != 0 ) )
9 years ago
{
float x, y, z;
float xystep = 8.0f;
float zstep = 18.0f;
9 years ago
float xyminmax = xystep;
float zminmax = 4 * zstep;
8 years ago
for( z = 0; z <= zminmax; z += zstep )
9 years ago
{
8 years ago
for( x = -xyminmax; x <= xyminmax; x += xystep )
9 years ago
{
8 years ago
for( y = -xyminmax; y <= xyminmax; y += xystep )
9 years ago
{
VectorCopy( base, test );
test[0] += x;
test[1] += y;
test[2] += z;
8 years ago
if( pmove->PM_TestPlayerPosition( test, NULL ) == -1 )
9 years ago
{
VectorCopy( test, pmove->origin );
return 0;
}
}
}
}
}
8 years ago
//VectorCopy( base, pmove->origin );
9 years ago
return 1;
}
/*
===============
PM_SpectatorMove
===============
*/
8 years ago
void PM_SpectatorMove( void )
9 years ago
{
8 years ago
float speed, drop, friction, control, newspeed;
//float accel;
float currentspeed, addspeed, accelspeed;
int i;
vec3_t wishvel;
float fmove, smove;
vec3_t wishdir;
float wishspeed;
9 years ago
// this routine keeps track of the spectators psoition
// there a two different main move types : track player or moce freely (OBS_ROAMING)
// doesn't need excate track position, only to generate PVS, so just copy
// targets position and real view position is calculated on client (saves server CPU)
8 years ago
if( pmove->iuser1 == OBS_ROAMING )
9 years ago
{
4 years ago
#if CLIENT_DLL
9 years ago
// jump only in roaming mode
8 years ago
if( iJumpSpectator )
9 years ago
{
VectorCopy( vJumpOrigin, pmove->origin );
VectorCopy( vJumpAngles, pmove->angles );
VectorCopy( vec3_origin, pmove->velocity );
iJumpSpectator = 0;
return;
}
8 years ago
#endif
9 years ago
// Move around in normal spectator method
8 years ago
speed = Length( pmove->velocity );
if( speed < 1 )
9 years ago
{
8 years ago
VectorCopy( vec3_origin, pmove->velocity )
9 years ago
}
else
{
drop = 0;
friction = pmove->movevars->friction * 1.5f; // extra friction
9 years ago
control = speed < pmove->movevars->stopspeed ? pmove->movevars->stopspeed : speed;
8 years ago
drop += control * friction*pmove->frametime;
9 years ago
// scale the velocity
newspeed = speed - drop;
8 years ago
if( newspeed < 0 )
9 years ago
newspeed = 0;
newspeed /= speed;
8 years ago
VectorScale( pmove->velocity, newspeed, pmove->velocity );
9 years ago
}
// accelerate
fmove = pmove->cmd.forwardmove;
smove = pmove->cmd.sidemove;
8 years ago
VectorNormalize( pmove->forward );
VectorNormalize( pmove->right );
for( i = 0; i < 3; i++ )
9 years ago
{
8 years ago
wishvel[i] = pmove->forward[i] * fmove + pmove->right[i] * smove;
9 years ago
}
wishvel[2] += pmove->cmd.upmove;
8 years ago
VectorCopy( wishvel, wishdir );
wishspeed = VectorNormalize( wishdir );
9 years ago
//
// clamp to server defined max speed
//
8 years ago
if( wishspeed > pmove->movevars->spectatormaxspeed )
9 years ago
{
8 years ago
VectorScale( wishvel, pmove->movevars->spectatormaxspeed/wishspeed, wishvel );
9 years ago
wishspeed = pmove->movevars->spectatormaxspeed;
}
8 years ago
currentspeed = DotProduct( pmove->velocity, wishdir );
9 years ago
addspeed = wishspeed - currentspeed;
8 years ago
if( addspeed <= 0 )
9 years ago
return;
8 years ago
accelspeed = pmove->movevars->accelerate * pmove->frametime * wishspeed;
if( accelspeed > addspeed )
9 years ago
accelspeed = addspeed;
8 years ago
for( i = 0; i < 3; i++ )
pmove->velocity[i] += accelspeed*wishdir[i];
9 years ago
// move
8 years ago
VectorMA( pmove->origin, pmove->frametime, pmove->velocity, pmove->origin );
9 years ago
}
else
{
// all other modes just track some kind of target, so spectator PVS = target PVS
int target;
// no valid target ?
8 years ago
if( pmove->iuser2 <= 0 )
9 years ago
return;
// Find the client this player's targeting
8 years ago
for( target = 0; target < pmove->numphysent; target++ )
9 years ago
{
8 years ago
if( pmove->physents[target].info == pmove->iuser2 )
9 years ago
break;
}
8 years ago
if( target == pmove->numphysent )
9 years ago
return;
// use targets position as own origin for PVS
VectorCopy( pmove->physents[target].angles, pmove->angles );
VectorCopy( pmove->physents[target].origin, pmove->origin );
// no velocity
VectorCopy( vec3_origin, pmove->velocity );
}
}
/*
==================
PM_SplineFraction
Use for ease-in, ease-out style interpolation (accel/decel)
Used by ducking code.
==================
*/
float PM_SplineFraction( float value, float scale )
{
float valueSquared;
value = scale * value;
valueSquared = value * value;
// Nice little ease-in, ease-out spline-like curve
return 3 * valueSquared - 2 * valueSquared * value;
}
void PM_FixPlayerCrouchStuck( int direction )
{
8 years ago
int hitent;
9 years ago
int i;
vec3_t test;
8 years ago
hitent = pmove->PM_TestPlayerPosition( pmove->origin, NULL );
if( hitent == -1 )
9 years ago
return;
8 years ago
VectorCopy( pmove->origin, test );
for( i = 0; i < 36; i++ )
9 years ago
{
pmove->origin[2] += direction;
8 years ago
hitent = pmove->PM_TestPlayerPosition( pmove->origin, NULL );
if( hitent == -1 )
9 years ago
return;
}
VectorCopy( test, pmove->origin ); // Failed
}
void PM_UnDuck( void )
{
int i;
pmtrace_t trace;
vec3_t newOrigin;
VectorCopy( pmove->origin, newOrigin );
8 years ago
if( pmove->onground != -1 )
9 years ago
{
8 years ago
for( i = 0; i < 3; i++ )
9 years ago
{
newOrigin[i] += ( pmove->player_mins[1][i] - pmove->player_mins[0][i] );
}
}
8 years ago
9 years ago
trace = pmove->PM_PlayerTrace( newOrigin, newOrigin, PM_NORMAL, -1 );
8 years ago
if( !trace.startsolid )
9 years ago
{
pmove->usehull = 0;
// Oh, no, changing hulls stuck us into something, try unsticking downward first.
8 years ago
trace = pmove->PM_PlayerTrace( newOrigin, newOrigin, PM_NORMAL, -1 );
if( trace.startsolid )
9 years ago
{
// See if we are stuck? If so, stay ducked with the duck hull until we have a clear spot
//Con_Printf( "unstick got stuck\n" );
pmove->usehull = 1;
return;
}
pmove->flags &= ~FL_DUCKING;
pmove->bInDuck = false;
pmove->view_ofs[2] = VEC_VIEW;
pmove->flDuckTime = 0;
8 years ago
9 years ago
VectorCopy( newOrigin, pmove->origin );
// Recatagorize position since ducking can change origin
PM_CatagorizePosition();
}
}
void PM_Duck( void )
{
int i;
float time;
float duckFraction;
8 years ago
int buttonsChanged = ( pmove->oldbuttons ^ pmove->cmd.buttons ); // These buttons have changed this frame
int nButtonPressed = buttonsChanged & pmove->cmd.buttons; // The changed ones still down are "pressed"
9 years ago
//int duckchange = buttonsChanged & IN_DUCK ? 1 : 0;
//int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0;
9 years ago
8 years ago
if( pmove->cmd.buttons & IN_DUCK )
9 years ago
{
pmove->oldbuttons |= IN_DUCK;
}
else
{
pmove->oldbuttons &= ~IN_DUCK;
}
// Prevent ducking if the iuser3 variable is set
8 years ago
if( pmove->iuser3 || pmove->dead )
9 years ago
{
// Try to unduck
8 years ago
if( pmove->flags & FL_DUCKING )
9 years ago
{
PM_UnDuck();
}
return;
}
8 years ago
if( pmove->flags & FL_DUCKING )
9 years ago
{
pmove->cmd.forwardmove *= PLAYER_DUCKING_MULTIPLIER;
pmove->cmd.sidemove *= PLAYER_DUCKING_MULTIPLIER;
pmove->cmd.upmove *= PLAYER_DUCKING_MULTIPLIER;
9 years ago
}
8 years ago
if( ( pmove->cmd.buttons & IN_DUCK ) || ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) )
9 years ago
{
8 years ago
if( pmove->cmd.buttons & IN_DUCK )
9 years ago
{
8 years ago
if( (nButtonPressed & IN_DUCK ) && !( pmove->flags & FL_DUCKING ) )
9 years ago
{
// Use 1 second so super long jump will work
pmove->flDuckTime = 1000;
8 years ago
pmove->bInDuck = true;
9 years ago
}
time = max( 0.0f, ( 1.0f - (float)pmove->flDuckTime / 1000.0f ) );
8 years ago
if( pmove->bInDuck )
9 years ago
{
// Finish ducking immediately if duck time is over or not on ground
if( ( (float)pmove->flDuckTime / 1000.0f <= ( 1.0f - TIME_TO_DUCK ) ) || ( pmove->onground == -1 ) )
9 years ago
{
pmove->usehull = 1;
pmove->view_ofs[2] = VEC_DUCK_VIEW;
pmove->flags |= FL_DUCKING;
pmove->bInDuck = false;
// HACKHACK - Fudge for collision bug - no time to fix this properly
8 years ago
if( pmove->onground != -1 )
9 years ago
{
8 years ago
for( i = 0; i < 3; i++ )
9 years ago
{
pmove->origin[i] -= ( pmove->player_mins[1][i] - pmove->player_mins[0][i] );
}
// See if we are stuck?
PM_FixPlayerCrouchStuck( STUCK_MOVEUP );
// Recatagorize position since ducking can change origin
PM_CatagorizePosition();
}
}
else
{
8 years ago
float fMore = VEC_DUCK_HULL_MIN - VEC_HULL_MIN;
9 years ago
// Calc parametric time
duckFraction = PM_SplineFraction( time, ( 1.0f / TIME_TO_DUCK ) );
8 years ago
pmove->view_ofs[2] = ( ( VEC_DUCK_VIEW - fMore ) * duckFraction ) + ( VEC_VIEW * ( 1 - duckFraction ) );
9 years ago
}
}
}
else
{
// Try to unduck
PM_UnDuck();
}
}
}
void PM_LadderMove( physent_t *pLadder )
{
8 years ago
vec3_t ladderCenter;
trace_t trace;
qboolean onFloor;
vec3_t floor;
vec3_t modelmins, modelmaxs;
9 years ago
8 years ago
if( pmove->movetype == MOVETYPE_NOCLIP )
9 years ago
return;
pmove->PM_GetModelBounds( pLadder->model, modelmins, modelmaxs );
VectorAdd( modelmins, modelmaxs, ladderCenter );
VectorScale( ladderCenter, 0.5, ladderCenter );
pmove->movetype = MOVETYPE_FLY;
// On ladder, convert movement to be relative to the ladder
VectorCopy( pmove->origin, floor );
floor[2] += pmove->player_mins[pmove->usehull][2] - 1;
8 years ago
if( pmove->PM_PointContents( floor, NULL ) == CONTENTS_SOLID )
9 years ago
onFloor = true;
else
onFloor = false;
pmove->gravity = 0;
pmove->PM_TraceModel( pLadder, pmove->origin, ladderCenter, &trace );
if( trace.fraction != 1.0f )
9 years ago
{
float forward = 0, right = 0;
vec3_t vpn, v_right;
float flSpeed = MAX_CLIMB_SPEED;
// they shouldn't be able to move faster than their maxspeed
if( flSpeed > pmove->maxspeed )
flSpeed = pmove->maxspeed;
9 years ago
AngleVectors( pmove->angles, vpn, v_right, NULL );
if( pmove->flags & FL_DUCKING )
flSpeed *= PLAYER_DUCKING_MULTIPLIER;
8 years ago
if( pmove->cmd.buttons & IN_BACK )
forward -= flSpeed;
8 years ago
if( pmove->cmd.buttons & IN_FORWARD )
forward += flSpeed;
8 years ago
if( pmove->cmd.buttons & IN_MOVELEFT )
right -= flSpeed;
8 years ago
if( pmove->cmd.buttons & IN_MOVERIGHT )
right += flSpeed;
9 years ago
8 years ago
if( pmove->cmd.buttons & IN_JUMP )
9 years ago
{
pmove->movetype = MOVETYPE_WALK;
VectorScale( trace.plane.normal, 270, pmove->velocity );
}
else
{
8 years ago
if( forward != 0 || right != 0 )
9 years ago
{
vec3_t velocity, perp, cross, lateral, tmp;
float normal;
8 years ago
//ALERT( at_console, "pev %.2f %.2f %.2f - ",
// pev->velocity.x, pev->velocity.y, pev->velocity.z );
9 years ago
// Calculate player's intended velocity
8 years ago
//Vector velocity = ( forward * gpGlobals->v_forward ) + ( right * gpGlobals->v_right );
9 years ago
VectorScale( vpn, forward, velocity );
VectorMA( velocity, right, v_right, velocity );
// Perpendicular in the ladder plane
8 years ago
// Vector perp = CrossProduct( Vector( 0, 0, 1 ), trace.vecPlaneNormal );
// perp = perp.Normalize();
9 years ago
VectorClear( tmp );
tmp[2] = 1;
CrossProduct( tmp, trace.plane.normal, perp );
VectorNormalize( perp );
// decompose velocity into ladder plane
normal = DotProduct( velocity, trace.plane.normal );
// This is the velocity into the face of the ladder
VectorScale( trace.plane.normal, normal, cross );
// This is the player's additional velocity
VectorSubtract( velocity, cross, lateral );
// This turns the velocity into the face of the ladder into velocity that
// is roughly vertically perpendicular to the face of the ladder.
// NOTE: It IS possible to face up and move down or face down and move up
// because the velocity is a sum of the directional velocity and the converted
// velocity through the face of the ladder -- by design.
CrossProduct( trace.plane.normal, perp, tmp );
VectorMA( lateral, -normal, tmp, pmove->velocity );
8 years ago
if( onFloor && normal > 0 ) // On ground moving away from the ladder
9 years ago
{
VectorMA( pmove->velocity, MAX_CLIMB_SPEED, trace.plane.normal, pmove->velocity );
}
8 years ago
//pev->velocity = lateral - ( CrossProduct( trace.vecPlaneNormal, perp ) * normal );
9 years ago
}
else
{
VectorClear( pmove->velocity );
}
}
}
}
physent_t *PM_Ladder( void )
{
8 years ago
int i;
physent_t *pe;
hull_t *hull;
int num;
vec3_t test;
9 years ago
8 years ago
for( i = 0; i < pmove->nummoveent; i++ )
9 years ago
{
pe = &pmove->moveents[i];
8 years ago
if( pe->model && (modtype_t)pmove->PM_GetModelType( pe->model ) == mod_brush && pe->skin == CONTENTS_LADDER )
9 years ago
{
hull = (hull_t *)pmove->PM_HullForBsp( pe, test );
num = hull->firstclipnode;
// Offset the test point appropriately for this hull.
8 years ago
VectorSubtract( pmove->origin, test, test );
9 years ago
// Test the player's hull for intersection with this model
8 years ago
if( pmove->PM_HullPointContents( hull, num, test ) == CONTENTS_EMPTY )
9 years ago
continue;
8 years ago
9 years ago
return pe;
}
}
return NULL;
}
8 years ago
void PM_WaterJump( void )
9 years ago
{
8 years ago
if( pmove->waterjumptime > 10000 )
9 years ago
{
pmove->waterjumptime = 10000;
}
8 years ago
if( !pmove->waterjumptime )
9 years ago
return;
pmove->waterjumptime -= pmove->cmd.msec;
8 years ago
if( pmove->waterjumptime < 0 || !pmove->waterlevel )
9 years ago
{
pmove->waterjumptime = 0;
pmove->flags &= ~FL_WATERJUMP;
}
pmove->velocity[0] = pmove->movedir[0];
pmove->velocity[1] = pmove->movedir[1];
}
/*
============
PM_AddGravity
============
*/
8 years ago
void PM_AddGravity()
9 years ago
{
8 years ago
float ent_gravity;
9 years ago
8 years ago
if( pmove->gravity )
9 years ago
ent_gravity = pmove->gravity;
else
ent_gravity = 1.0f;
9 years ago
// Add gravity incorrectly
8 years ago
pmove->velocity[2] -= ( ent_gravity * pmove->movevars->gravity * pmove->frametime );
9 years ago
pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime;
pmove->basevelocity[2] = 0;
PM_CheckVelocity();
}
9 years ago
/*
============
PM_PushEntity
Does not change the entities velocity at all
============
*/
8 years ago
pmtrace_t PM_PushEntity( vec3_t push )
9 years ago
{
8 years ago
pmtrace_t trace;
vec3_t end;
9 years ago
8 years ago
VectorAdd( pmove->origin, push, end );
trace = pmove->PM_PlayerTrace( pmove->origin, end, PM_NORMAL, -1 );
VectorCopy( trace.endpos, pmove->origin );
9 years ago
// So we can run impact function afterwards.
if( trace.fraction < 1.0f && !trace.allsolid )
9 years ago
{
8 years ago
PM_AddToTouched( trace, pmove->velocity );
9 years ago
}
return trace;
}
/*
============
PM_Physics_Toss()
Dead player flying through air., e.g.
============
*/
void PM_Physics_Toss()
{
pmtrace_t trace;
8 years ago
vec3_t move;
float backoff;
9 years ago
PM_CheckWater();
8 years ago
if( pmove->velocity[2] > 0 )
9 years ago
pmove->onground = -1;
// If on ground and not moving, return.
8 years ago
if( pmove->onground != -1 )
9 years ago
{
8 years ago
if( VectorCompare( pmove->basevelocity, vec3_origin ) && VectorCompare( pmove->velocity, vec3_origin ) )
9 years ago
return;
}
8 years ago
PM_CheckVelocity();
9 years ago
8 years ago
// add gravity
if( pmove->movetype != MOVETYPE_FLY && pmove->movetype != MOVETYPE_BOUNCEMISSILE && pmove->movetype != MOVETYPE_FLYMISSILE )
9 years ago
PM_AddGravity ();
8 years ago
// move origin
9 years ago
// Base velocity is not properly accounted for since this entity will move again after the bounce without
// taking it into account
8 years ago
VectorAdd( pmove->velocity, pmove->basevelocity, pmove->velocity );
9 years ago
PM_CheckVelocity();
8 years ago
VectorScale( pmove->velocity, pmove->frametime, move );
VectorSubtract( pmove->velocity, pmove->basevelocity, pmove->velocity );
9 years ago
8 years ago
trace = PM_PushEntity( move ); // Should this clear basevelocity
9 years ago
PM_CheckVelocity();
8 years ago
if( trace.allsolid )
9 years ago
{
// entity is trapped in another solid
pmove->onground = trace.ent;
8 years ago
VectorCopy( vec3_origin, pmove->velocity );
9 years ago
return;
}
8 years ago
if( trace.fraction == 1 )
9 years ago
{
PM_CheckWater();
return;
}
8 years ago
if( pmove->movetype == MOVETYPE_BOUNCE )
backoff = 2.0f - pmove->friction;
8 years ago
else if( pmove->movetype == MOVETYPE_BOUNCEMISSILE )
backoff = 2.0f;
9 years ago
else
backoff = 1.0f;
9 years ago
8 years ago
PM_ClipVelocity( pmove->velocity, trace.plane.normal, pmove->velocity, backoff );
9 years ago
// stop if on ground
if( trace.plane.normal[2] > 0.7f )
8 years ago
{
9 years ago
float vel;
vec3_t base;
VectorClear( base );
8 years ago
if( pmove->velocity[2] < pmove->movevars->gravity * pmove->frametime )
9 years ago
{
// we're rolling on the ground, add static friction.
pmove->onground = trace.ent;
pmove->velocity[2] = 0;
}
vel = DotProduct( pmove->velocity, pmove->velocity );
8 years ago
// Con_DPrintf( "%f %f: %.0f %.0f %.0f\n", vel, trace.fraction, ent->velocity[0], ent->velocity[1], ent->velocity[2] );
9 years ago
8 years ago
if( vel < ( 30 * 30 ) || ( pmove->movetype != MOVETYPE_BOUNCE && pmove->movetype != MOVETYPE_BOUNCEMISSILE ) )
9 years ago
{
pmove->onground = trace.ent;
8 years ago
VectorCopy( vec3_origin, pmove->velocity );
9 years ago
}
else
{
VectorScale( pmove->velocity, ( 1.0f - trace.fraction) * pmove->frametime * 0.9f, move );
8 years ago
trace = PM_PushEntity( move );
9 years ago
}
VectorSubtract( pmove->velocity, base, pmove->velocity )
}
8 years ago
// check for in water
9 years ago
PM_CheckWater();
}
/*
====================
PM_NoClip
====================
*/
void PM_NoClip()
{
8 years ago
int i;
vec3_t wishvel;
float fmove, smove;
//float currentspeed, addspeed, accelspeed;
9 years ago
// Copy movement amounts
fmove = pmove->cmd.forwardmove;
smove = pmove->cmd.sidemove;
8 years ago
VectorNormalize( pmove->forward );
VectorNormalize( pmove->right );
for( i = 0; i < 3; i++ ) // Determine x and y parts of velocity
9 years ago
{
8 years ago
wishvel[i] = pmove->forward[i] * fmove + pmove->right[i] * smove;
9 years ago
}
wishvel[2] += pmove->cmd.upmove;
8 years ago
VectorMA (pmove->origin, pmove->frametime, wishvel, pmove->origin );
9 years ago
// Zero out the velocity so that we don't accumulate a huge downward velocity from
8 years ago
// gravity, etc.
9 years ago
VectorClear( pmove->velocity );
}
// Only allow bunny jumping up to 1.7x server / player maxspeed setting
#define BUNNYJUMP_MAX_SPEED_FACTOR 1.7f
//-----------------------------------------------------------------------------
// Purpose: Corrects bunny jumping ( where player initiates a bunny jump before other
// movement logic runs, thus making onground == -1 thus making PM_Friction get skipped and
// running PM_AirMove, which doesn't crop velocity to maxspeed like the ground / other
// movement logic does.
//-----------------------------------------------------------------------------
void PM_PreventMegaBunnyJumping( void )
{
// Current player speed
float spd;
// If we have to crop, apply this cropping fraction to velocity
float fraction;
// Speed at which bunny jumping is limited
float maxscaledspeed;
maxscaledspeed = BUNNYJUMP_MAX_SPEED_FACTOR * pmove->maxspeed;
// Don't divide by zero
8 years ago
if( maxscaledspeed <= 0.0f )
9 years ago
return;
spd = Length( pmove->velocity );
8 years ago
if( spd <= maxscaledspeed )
9 years ago
return;
fraction = ( maxscaledspeed / spd ) * 0.65f; //Returns the modifier for the velocity
9 years ago
VectorScale( pmove->velocity, fraction, pmove->velocity ); //Crop it down!.
}
/*
=============
PM_Jump
=============
*/
8 years ago
void PM_Jump( void )
9 years ago
{
int i;
qboolean tfc = false;
qboolean cansuperjump = false;
8 years ago
if( pmove->dead )
9 years ago
{
8 years ago
pmove->oldbuttons |= IN_JUMP; // don't jump again until released
9 years ago
return;
}
tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false;
// Spy that's feigning death cannot jump
8 years ago
if( tfc && ( pmove->deadflag == ( DEAD_DISCARDBODY + 1 ) ) )
9 years ago
{
return;
}
// See if we are waterjumping. If so, decrement count and return.
8 years ago
if( pmove->waterjumptime )
9 years ago
{
pmove->waterjumptime -= pmove->cmd.msec;
8 years ago
if( pmove->waterjumptime < 0 )
9 years ago
{
pmove->waterjumptime = 0;
}
return;
}
// If we are in the water most of the way...
8 years ago
if( pmove->waterlevel >= 2 )
{
// swimming, not jumping
9 years ago
pmove->onground = -1;
8 years ago
if( pmove->watertype == CONTENTS_WATER ) // We move up a certain amount
9 years ago
pmove->velocity[2] = 100;
8 years ago
else if( pmove->watertype == CONTENTS_SLIME )
9 years ago
pmove->velocity[2] = 80;
8 years ago
else // LAVA
9 years ago
pmove->velocity[2] = 50;
// play swiming sound
8 years ago
if( pmove->flSwimTime <= 0 )
9 years ago
{
// Don't play sound again for 1 second
pmove->flSwimTime = 1000;
8 years ago
switch( pmove->RandomLong( 0, 3 ) )
{
9 years ago
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
}
}
return;
}
// No more effect
8 years ago
if( pmove->onground == -1 )
9 years ago
{
// Flag that we jumped.
// HACK HACK HACK
// Remove this when the game .dll no longer does physics code!!!!
pmove->oldbuttons |= IN_JUMP; // don't jump again until released
return; // in air, so no effect
}
8 years ago
if( pmove->oldbuttons & IN_JUMP )
9 years ago
return; // don't pogo stick
// In the air now.
8 years ago
pmove->onground = -1;
9 years ago
if( g_bhopcap )
PM_PreventMegaBunnyJumping();
9 years ago
8 years ago
if( tfc )
9 years ago
{
pmove->PM_PlaySound( CHAN_BODY, "player/plyrjmp8.wav", 0.5, ATTN_NORM, 0, PITCH_NORM );
}
else
{
PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), 1.0f );
9 years ago
}
// See if user can super long jump?
cansuperjump = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "slj" ) ) == 1 ? true : false;
// Acclerate upward
// If we are ducking...
8 years ago
if( ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) )
9 years ago
{
// Adjust for super long jump module
// UNDONE -- note this should be based on forward angles, not current velocity.
8 years ago
if( cansuperjump && ( pmove->cmd.buttons & IN_DUCK ) && ( pmove->flDuckTime > 0 ) &&
9 years ago
Length( pmove->velocity ) > 50 )
{
pmove->punchangle[0] = -5;
8 years ago
for( i = 0; i < 2; i++ )
9 years ago
{
pmove->velocity[i] = pmove->forward[i] * PLAYER_LONGJUMP_SPEED * 1.6f;
9 years ago
}
8 years ago
pmove->velocity[2] = sqrt( 2.0f * 800.0f * 56.0f );
9 years ago
}
else
{
pmove->velocity[2] = sqrt( 2.0f * 800.0f * 45.0f );
9 years ago
}
}
else
{
pmove->velocity[2] = sqrt( 2.0f * 800.0f * 45.0f );
9 years ago
}
// Decay it for simulation
PM_FixupGravityVelocity();
// Flag that we jumped.
pmove->oldbuttons |= IN_JUMP; // don't jump again until released
}
/*
=============
PM_CheckWaterJump
=============
*/
#define WJ_HEIGHT 8
8 years ago
void PM_CheckWaterJump( void )
9 years ago
{
8 years ago
vec3_t vecStart, vecEnd;
vec3_t flatforward;
vec3_t flatvelocity;
9 years ago
float curspeed;
pmtrace_t tr;
8 years ago
int savehull;
9 years ago
// Already water jumping.
8 years ago
if( pmove->waterjumptime )
9 years ago
return;
// Don't hop out if we just jumped in
8 years ago
if( pmove->velocity[2] < -180 )
9 years ago
return; // only hop out if we are moving up
// See if we are backing up
flatvelocity[0] = pmove->velocity[0];
flatvelocity[1] = pmove->velocity[1];
flatvelocity[2] = 0;
// Must be moving
curspeed = VectorNormalize( flatvelocity );
8 years ago
9 years ago
// see if near an edge
flatforward[0] = pmove->forward[0];
flatforward[1] = pmove->forward[1];
flatforward[2] = 0;
8 years ago
VectorNormalize( flatforward );
9 years ago
// Are we backing into water from steps or something? If so, don't pop forward
if( curspeed != 0.0f && ( DotProduct( flatvelocity, flatforward ) < 0.0f ) )
9 years ago
return;
VectorCopy( pmove->origin, vecStart );
vecStart[2] += WJ_HEIGHT;
8 years ago
VectorMA( vecStart, 24, flatforward, vecEnd );
9 years ago
// Trace, this trace should use the point sized collision hull
savehull = pmove->usehull;
pmove->usehull = 2;
tr = pmove->PM_PlayerTrace( vecStart, vecEnd, PM_NORMAL, -1 );
if( tr.fraction < 1.0f && fabs( tr.plane.normal[2] ) < 0.1f ) // Facing a near vertical wall?
9 years ago
{
8 years ago
vecStart[2] += pmove->player_maxs[savehull][2] - WJ_HEIGHT;
9 years ago
VectorMA( vecStart, 24, flatforward, vecEnd );
VectorMA( vec3_origin, -50, tr.plane.normal, pmove->movedir );
tr = pmove->PM_PlayerTrace( vecStart, vecEnd, PM_NORMAL, -1 );
if( tr.fraction == 1.0f )
9 years ago
{
pmove->waterjumptime = 2000;
pmove->velocity[2] = 225;
pmove->oldbuttons |= IN_JUMP;
pmove->flags |= FL_WATERJUMP;
}
}
// Reset the collision hull
pmove->usehull = savehull;
}
void PM_CheckFalling( void )
{
8 years ago
if( pmove->onground != -1 && !pmove->dead && pmove->flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD )
9 years ago
{
float fvol = 0.5f;
9 years ago
8 years ago
if( pmove->waterlevel > 0 )
9 years ago
{
}
8 years ago
else if( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED )
9 years ago
{
8 years ago
// NOTE: In the original game dll, there were no breaks after these cases, causing the first one to
9 years ago
// cascade into the second
8 years ago
//switch( RandomLong( 0, 1 ) )
9 years ago
//{
//case 0:
//pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
//break;
//case 1:
pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM );
// break;
//}
fvol = 1.0f;
9 years ago
}
8 years ago
else if( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 )
9 years ago
{
qboolean tfc = false;
tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? true : false;
8 years ago
if( tfc )
9 years ago
{
pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM );
}
fvol = 0.85;
}
8 years ago
else if( pmove->flFallVelocity < PLAYER_MIN_BOUNCE_SPEED )
9 years ago
{
fvol = 0;
}
if( fvol > 0.0f )
9 years ago
{
// Play landing step right away
pmove->flTimeStepSound = 0;
8 years ago
9 years ago
PM_UpdateStepSound();
8 years ago
9 years ago
// play step sound for current texture
PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), fvol );
// Knock the screen around a little bit, temporary effect
pmove->punchangle[2] = pmove->flFallVelocity * 0.013f; // punch z axis
9 years ago
8 years ago
if( pmove->punchangle[0] > 8 )
9 years ago
{
8 years ago
pmove->punchangle[0] = 8;
9 years ago
}
}
}
8 years ago
if( pmove->onground != -1 )
{
9 years ago
pmove->flFallVelocity = 0;
}
}
/*
=================
PM_PlayWaterSounds
=================
*/
void PM_PlayWaterSounds( void )
{
// Did we enter or leave water?
8 years ago
if( ( pmove->oldwaterlevel == 0 && pmove->waterlevel != 0 ) || ( pmove->oldwaterlevel != 0 && pmove->waterlevel == 0 ) )
9 years ago
{
8 years ago
switch( pmove->RandomLong( 0, 3 ) )
9 years ago
{
case 0:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
case 1:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
case 2:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
case 3:
pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM, 0, PITCH_NORM );
break;
}
}
}
/*
===============
PM_CalcRoll
===============
*/
8 years ago
float PM_CalcRoll( vec3_t angles, vec3_t velocity, float rollangle, float rollspeed )
9 years ago
{
8 years ago
float sign;
float side;
float value;
vec3_t forward, right, up;
AngleVectors( angles, forward, right, up );
side = DotProduct( velocity, right );
9 years ago
sign = side < 0 ? -1 : 1;
8 years ago
side = fabs( side );
9 years ago
value = rollangle;
8 years ago
if( side < rollspeed )
9 years ago
{
side = side * value / rollspeed;
}
8 years ago
else
9 years ago
{
side = value;
}
8 years ago
9 years ago
return side * sign;
}
/*
=============
PM_DropPunchAngle
=============
*/
8 years ago
void PM_DropPunchAngle( vec3_t punchangle )
9 years ago
{
8 years ago
float len;
9 years ago
8 years ago
len = VectorNormalize( punchangle );
len -= ( 10.0f + len * 0.5f ) * pmove->frametime;
len = max( len, 0.0f );
8 years ago
VectorScale( punchangle, len, punchangle );
9 years ago
}
/*
==============
PM_CheckParamters
==============
*/
void PM_CheckParamters( void )
{
float spd;
float maxspeed;
8 years ago
vec3_t v_angle;
9 years ago
8 years ago
spd = ( pmove->cmd.forwardmove * pmove->cmd.forwardmove ) + ( pmove->cmd.sidemove * pmove->cmd.sidemove ) +
( pmove->cmd.upmove * pmove->cmd.upmove );
9 years ago
spd = sqrt( spd );
maxspeed = pmove->clientmaxspeed; //atof( pmove->PM_Info_ValueForKey( pmove->physinfo, "maxspd" ) );
if( maxspeed != 0.0f )
9 years ago
{
pmove->maxspeed = min( maxspeed, pmove->maxspeed );
}
if( ( spd != 0.0f ) && ( spd > pmove->maxspeed ) )
9 years ago
{
float fRatio = pmove->maxspeed / spd;
pmove->cmd.forwardmove *= fRatio;
8 years ago
pmove->cmd.sidemove *= fRatio;
pmove->cmd.upmove *= fRatio;
9 years ago
}
8 years ago
if( pmove->flags & FL_FROZEN || pmove->flags & FL_ONTRAIN || pmove->dead )
9 years ago
{
pmove->cmd.forwardmove = 0;
8 years ago
pmove->cmd.sidemove = 0;
pmove->cmd.upmove = 0;
9 years ago
}
PM_DropPunchAngle( pmove->punchangle );
// Take angles from command.
8 years ago
if( !pmove->dead )
9 years ago
{
8 years ago
VectorCopy( pmove->cmd.viewangles, v_angle );
9 years ago
VectorAdd( v_angle, pmove->punchangle, v_angle );
// Set up view angles.
8 years ago
pmove->angles[ROLL] = PM_CalcRoll( v_angle, pmove->velocity, pmove->movevars->rollangle, pmove->movevars->rollspeed ) * 4;
pmove->angles[PITCH] = v_angle[PITCH];
pmove->angles[YAW] = v_angle[YAW];
9 years ago
}
else
{
VectorCopy( pmove->oldangles, pmove->angles );
}
// Set dead player view_offset
8 years ago
if( pmove->dead )
9 years ago
{
pmove->view_ofs[2] = PM_DEAD_VIEWHEIGHT;
}
// Adjust client view angles to match values used on server.
8 years ago
if( pmove->angles[YAW] > 180.0f )
9 years ago
{
pmove->angles[YAW] -= 360.0f;
}
}
void PM_ReduceTimers( void )
{
8 years ago
if( pmove->flTimeStepSound > 0 )
9 years ago
{
pmove->flTimeStepSound -= pmove->cmd.msec;
8 years ago
if( pmove->flTimeStepSound < 0 )
9 years ago
{
pmove->flTimeStepSound = 0;
}
}
8 years ago
if( pmove->flDuckTime > 0 )
9 years ago
{
pmove->flDuckTime -= pmove->cmd.msec;
8 years ago
if( pmove->flDuckTime < 0 )
9 years ago
{
pmove->flDuckTime = 0;
}
}
8 years ago
if( pmove->flSwimTime > 0 )
9 years ago
{
pmove->flSwimTime -= pmove->cmd.msec;
8 years ago
if( pmove->flSwimTime < 0 )
9 years ago
{
pmove->flSwimTime = 0;
}
}
}
/*
=============
PlayerMove
Returns with origin, angles, and velocity modified in place.
Numtouch and touchindex[] will be set if any of the physents
were contacted during the move.
=============
*/
8 years ago
void PM_PlayerMove( qboolean server )
9 years ago
{
physent_t *pLadder = NULL;
// Are we running server code?
pmove->server = server;
// Adjust speeds etc.
PM_CheckParamters();
// Assume we don't touch anything
pmove->numtouch = 0;
// # of msec to apply movement
pmove->frametime = pmove->cmd.msec * 0.001f;
9 years ago
PM_ReduceTimers();
// Convert view angles to vectors
8 years ago
AngleVectors( pmove->angles, pmove->forward, pmove->right, pmove->up );
9 years ago
// PM_ShowClipBox();
// Special handling for spectator and observers. (iuser1 is set if the player's in observer mode)
8 years ago
if( pmove->spectator || pmove->iuser1 > 0 )
9 years ago
{
PM_SpectatorMove();
PM_CatagorizePosition();
return;
}
// Always try and unstick us unless we are in NOCLIP mode
8 years ago
if( pmove->movetype != MOVETYPE_NOCLIP && pmove->movetype != MOVETYPE_NONE )
9 years ago
{
8 years ago
if( PM_CheckStuck() )
9 years ago
{
return; // Can't move, we're stuck
}
}
// Now that we are "unstuck", see where we are ( waterlevel and type, pmove->onground ).
PM_CatagorizePosition();
// Store off the starting water level
pmove->oldwaterlevel = pmove->waterlevel;
// If we are not on ground, store off how fast we are moving down
8 years ago
if( pmove->onground == -1 )
9 years ago
{
pmove->flFallVelocity = -pmove->velocity[2];
}
g_onladder = 0;
// Don't run ladder code if dead or on a train
8 years ago
if( !pmove->dead && !( pmove->flags & FL_ONTRAIN ) )
9 years ago
{
pLadder = PM_Ladder();
8 years ago
if( pLadder )
9 years ago
{
g_onladder = 1;
}
}
PM_UpdateStepSound();
PM_Duck();
// Don't run ladder code if dead or on a train
8 years ago
if( !pmove->dead && !( pmove->flags & FL_ONTRAIN ) )
9 years ago
{
8 years ago
if( pLadder )
9 years ago
{
PM_LadderMove( pLadder );
}
8 years ago
else if( pmove->movetype != MOVETYPE_WALK && pmove->movetype != MOVETYPE_NOCLIP )
9 years ago
{
// Clear ladder stuff unless player is noclipping
// it will be set immediately again next frame if necessary
pmove->movetype = MOVETYPE_WALK;
}
}
// Slow down, I'm pulling it! (a box maybe) but only when I'm standing on ground
8 years ago
if( ( pmove->onground != -1 ) && ( pmove->cmd.buttons & IN_USE ) )
9 years ago
{
VectorScale( pmove->velocity, 0.3, pmove->velocity );
}
// Handle movement
8 years ago
switch( pmove->movetype )
9 years ago
{
default:
8 years ago
pmove->Con_DPrintf( "Bogus pmove player movetype %i on (%i) 0=cl 1=sv\n", pmove->movetype, pmove->server );
9 years ago
break;
case MOVETYPE_NONE:
break;
case MOVETYPE_NOCLIP:
PM_NoClip();
break;
case MOVETYPE_TOSS:
case MOVETYPE_BOUNCE:
PM_Physics_Toss();
break;
case MOVETYPE_FLY:
PM_CheckWater();
// Was jump button pressed?
// If so, set velocity to 270 away from ladder. This is currently wrong.
// Also, set MOVE_TYPE to walk, too.
8 years ago
if( pmove->cmd.buttons & IN_JUMP )
9 years ago
{
8 years ago
if( !pLadder )
9 years ago
{
8 years ago
PM_Jump();
9 years ago
}
}
else
{
pmove->oldbuttons &= ~IN_JUMP;
}
8 years ago
9 years ago
// Perform the move accounting for any base velocity.
8 years ago
VectorAdd( pmove->velocity, pmove->basevelocity, pmove->velocity );
PM_FlyMove();
VectorSubtract( pmove->velocity, pmove->basevelocity, pmove->velocity );
9 years ago
break;
case MOVETYPE_WALK:
8 years ago
if( !PM_InWater() )
9 years ago
{
PM_AddCorrectGravity();
}
// If we are leaping out of the water, just update the counters.
8 years ago
if( pmove->waterjumptime )
9 years ago
{
PM_WaterJump();
PM_FlyMove();
// Make sure waterlevel is set correctly
PM_CheckWater();
return;
}
// If we are swimming in the water, see if we are nudging against a place we can jump up out
// of, and, if so, start out jump. Otherwise, if we are not moving up, then reset jump timer to 0
8 years ago
if( pmove->waterlevel >= 2 )
9 years ago
{
8 years ago
if( pmove->waterlevel == 2 )
9 years ago
{
PM_CheckWaterJump();
}
// If we are falling again, then we must not trying to jump out of water any more.
8 years ago
if( pmove->velocity[2] < 0 && pmove->waterjumptime )
9 years ago
{
pmove->waterjumptime = 0;
}
// Was jump button pressed?
8 years ago
if( pmove->cmd.buttons & IN_JUMP )
9 years ago
{
8 years ago
PM_Jump();
9 years ago
}
else
{
pmove->oldbuttons &= ~IN_JUMP;
}
// Perform regular water movement
PM_WaterMove();
8 years ago
VectorSubtract( pmove->velocity, pmove->basevelocity, pmove->velocity );
9 years ago
// Get a final position
PM_CatagorizePosition();
}
else
// Not underwater
{
// Was jump button pressed?
8 years ago
if( pmove->cmd.buttons & IN_JUMP )
9 years ago
{
8 years ago
if( !pLadder )
9 years ago
{
8 years ago
PM_Jump();
9 years ago
}
}
else
{
pmove->oldbuttons &= ~IN_JUMP;
}
// Fricion is handled before we add in any base velocity. That way, if we are on a conveyor,
// we don't slow when standing still, relative to the conveyor.
8 years ago
if( pmove->onground != -1 )
9 years ago
{
pmove->velocity[2] = 0.0f;
9 years ago
PM_Friction();
}
// Make sure velocity is valid.
PM_CheckVelocity();
// Are we on ground now
8 years ago
if( pmove->onground != -1 )
9 years ago
{
PM_WalkMove();
}
else
{
PM_AirMove(); // Take into account movement when in air.
}
// Set final flags.
PM_CatagorizePosition();
// Now pull the base velocity back out.
// Base velocity is set if you are on a moving object, like
// a conveyor (or maybe another monster?)
8 years ago
VectorSubtract( pmove->velocity, pmove->basevelocity, pmove->velocity );
9 years ago
// Make sure velocity is valid.
PM_CheckVelocity();
// Add any remaining gravitational component.
8 years ago
if( !PM_InWater() )
9 years ago
{
PM_FixupGravityVelocity();
}
// If we are on ground, no downward velocity.
8 years ago
if( pmove->onground != -1 )
9 years ago
{
pmove->velocity[2] = 0;
}
// See if we landed on the ground with enough force to play
// a landing sound.
PM_CheckFalling();
}
// Did we enter or leave the water?
PM_PlayWaterSounds();
break;
}
}
void PM_CreateStuckTable( void )
{
float x, y, z;
int idx;
int i;
float zi[3];
8 years ago
memset( rgv3tStuckTable, 0, 54 * sizeof(vec3_t) );
9 years ago
idx = 0;
// Little Moves.
x = y = 0;
// Z moves
for( z = -0.125f; z <= 0.125f; z += 0.125f )
9 years ago
{
rgv3tStuckTable[idx][0] = x;
rgv3tStuckTable[idx][1] = y;
rgv3tStuckTable[idx][2] = z;
idx++;
}
x = z = 0;
// Y moves
for( y = -0.125f; y <= 0.125f; y += 0.125f )
9 years ago
{
rgv3tStuckTable[idx][0] = x;
rgv3tStuckTable[idx][1] = y;
rgv3tStuckTable[idx][2] = z;
idx++;
}
y = z = 0;
// X moves
for( x = -0.125f; x <= 0.125f; x += 0.125f )
9 years ago
{
rgv3tStuckTable[idx][0] = x;
rgv3tStuckTable[idx][1] = y;
rgv3tStuckTable[idx][2] = z;
idx++;
}
// Remaining multi axis nudges.
for( x = - 0.125f; x <= 0.125f; x += 0.250f )
9 years ago
{
for( y = - 0.125f; y <= 0.125f; y += 0.250f )
9 years ago
{
for( z = - 0.125f; z <= 0.125f; z += 0.250f )
9 years ago
{
rgv3tStuckTable[idx][0] = x;
rgv3tStuckTable[idx][1] = y;
rgv3tStuckTable[idx][2] = z;
idx++;
}
}
}
// Big Moves.
x = y = 0;
zi[0] = 0.0f;
zi[1] = 1.0f;
zi[2] = 6.0f;
8 years ago
for( i = 0; i < 3; i++ )
9 years ago
{
// Z moves
z = zi[i];
rgv3tStuckTable[idx][0] = x;
rgv3tStuckTable[idx][1] = y;
rgv3tStuckTable[idx][2] = z;
idx++;
}
x = z = 0;
// Y moves
for( y = -2.0f; y <= 2.0f; y += 2.0f )
9 years ago
{
rgv3tStuckTable[idx][0] = x;
rgv3tStuckTable[idx][1] = y;
rgv3tStuckTable[idx][2] = z;
idx++;
}
y = z = 0;
// X moves
for( x = -2.0f; x <= 2.0f; x += 2.0f )
9 years ago
{
rgv3tStuckTable[idx][0] = x;
rgv3tStuckTable[idx][1] = y;
rgv3tStuckTable[idx][2] = z;
idx++;
}
// Remaining multi axis nudges.
8 years ago
for( i = 0 ; i < 3; i++ )
9 years ago
{
z = zi[i];
8 years ago
for( x = -2.0f; x <= 2.0f; x += 2.0f )
9 years ago
{
for( y = -2.0f; y <= 2.0f; y += 2.0f )
9 years ago
{
rgv3tStuckTable[idx][0] = x;
rgv3tStuckTable[idx][1] = y;
rgv3tStuckTable[idx][2] = z;
idx++;
}
}
}
}
/*
This modume implements the shared player physics code between any particular game and
the engine. The same PM_Move routine is built into the game .dll and the client .dll and is
invoked by each side as appropriate. There should be no distinction, internally, between server
and client. This will ensure that prediction behaves appropriately.
*/
8 years ago
void PM_Move( struct playermove_s *ppmove, int server )
9 years ago
{
assert( pm_shared_initialized );
pmove = ppmove;
8 years ago
//pmove->Con_Printf( "PM_Move: %g, frametime %g, onground %i\n", pmove->time, pmove->frametime, pmove->onground );
9 years ago
PM_PlayerMove( ( server != 0 ) ? true : false );
8 years ago
if( pmove->onground != -1 )
9 years ago
{
pmove->flags |= FL_ONGROUND;
}
else
{
pmove->flags &= ~FL_ONGROUND;
}
// Reset friction after each movement to FrictionModifier Triggers work still.
if( pmove->movetype == MOVETYPE_WALK )
9 years ago
{
pmove->friction = 1.0f;
}
}
int PM_GetVisEntInfo( int ent )
{
8 years ago
if( ent >= 0 && ent <= pmove->numvisent )
9 years ago
{
8 years ago
return pmove->visents[ent].info;
9 years ago
}
return -1;
}
int PM_GetPhysEntInfo( int ent )
{
8 years ago
if( ent >= 0 && ent <= pmove->numphysent )
9 years ago
{
8 years ago
return pmove->physents[ent].info;
9 years ago
}
return -1;
}
void PM_Init( struct playermove_s *ppmove )
{
assert( !pm_shared_initialized );
pmove = ppmove;
PM_CreateStuckTable();
PM_InitTextureTypes();
pm_shared_initialized = 1;
}