2004-08-21 01:25:48 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
2005-02-06 02:47:36 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-08-21 01:25:48 +00:00
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
# include "quakedef.h"
movevars_t movevars ;
playermove_t pmove ;
2019-06-17 04:21:41 +00:00
extern cvar_t pm_noround ; //evile.
2004-08-21 01:25:48 +00:00
2017-08-16 02:14:07 +00:00
# define movevars_dpflags MOVEFLAG_QWCOMPAT
# define movevars_maxairspeed 30
# define movevars_jumpspeed 270
2004-08-21 01:25:48 +00:00
float frametime ;
vec3_t forward , right , up ;
void PM_Init ( void )
{
PM_InitBoxHull ( ) ;
}
# define MIN_STEP_NORMAL 0.7 // roughly 45 degrees
# define STOP_EPSILON 0.1
# define BLOCKED_FLOOR 1
# define BLOCKED_STEP 2
# define BLOCKED_OTHER 4
# define BLOCKED_ANY 7
2006-05-25 23:08:37 +00:00
/*
* * Add an entity to touch list , discarding duplicates
*/
static void PM_AddTouchedEnt ( int num )
{
2006-05-28 21:56:04 +00:00
if ( pmove . numtouch = = MAX_PHYSENTS )
2006-05-25 23:08:37 +00:00
return ;
2006-05-28 21:56:04 +00:00
if ( pmove . numtouch )
if ( pmove . touchindex [ pmove . numtouch - 1 ] = = num )
return ; // already added
2006-05-25 23:08:37 +00:00
pmove . touchindex [ pmove . numtouch ] = num ;
2012-01-17 07:57:46 +00:00
VectorCopy ( pmove . velocity , pmove . touchvel [ pmove . numtouch ] ) ;
2006-05-25 23:08:37 +00:00
pmove . numtouch + + ;
}
2004-08-21 01:25:48 +00:00
/*
= = = = = = = = = = = = = = = = = =
PM_ClipVelocity
Slide off of the impacting object
= = = = = = = = = = = = = = = = = =
*/
2006-05-25 23:08:37 +00:00
void PM_ClipVelocity ( vec3_t in , vec3_t normal , vec3_t out , float overbounce )
2004-08-21 01:25:48 +00:00
{
float backoff ;
float change ;
2006-05-25 23:08:37 +00:00
int i ;
2004-08-21 01:25:48 +00:00
backoff = DotProduct ( in , normal ) * overbounce ;
for ( i = 0 ; i < 3 ; i + + )
{
change = normal [ i ] * backoff ;
out [ i ] = in [ i ] - change ;
if ( out [ i ] > - STOP_EPSILON & & out [ i ] < STOP_EPSILON )
out [ i ] = 0 ;
}
}
2014-01-13 02:42:25 +00:00
# include "pr_common.h"
2014-07-12 06:56:17 +00:00
static qboolean PM_PortalTransform ( world_t * w , int portalnum , vec3_t org , vec3_t move , vec3_t newang , vec3_t newvel )
2014-01-13 02:42:25 +00:00
{
2014-07-12 06:56:17 +00:00
vec3_t rounded ;
2014-01-13 02:42:25 +00:00
qboolean okay = true ;
2018-04-06 17:21:15 +00:00
wedict_t * portal = WEDICT_NUM_UB ( w - > progs , portalnum ) ;
2014-01-13 02:42:25 +00:00
int oself = * w - > g . self ;
void * pr_globals = PR_globals ( w - > progs , PR_CURRENT ) ;
2014-07-12 06:56:17 +00:00
int i ;
int tmp ;
2015-12-28 17:41:39 +00:00
float f ;
2014-01-13 02:42:25 +00:00
* w - > g . self = EDICT_TO_PROG ( w - > progs , portal ) ;
//transform origin+velocity etc
VectorCopy ( org , G_VECTOR ( OFS_PARM0 ) ) ;
VectorCopy ( pmove . angles , G_VECTOR ( OFS_PARM1 ) ) ;
VectorCopy ( pmove . velocity , w - > g . v_forward ) ;
VectorCopy ( move , w - > g . v_right ) ;
VectorCopy ( pmove . gravitydir , w - > g . v_up ) ;
if ( ! DotProduct ( w - > g . v_up , w - > g . v_up ) )
w - > g . v_up [ 2 ] = - 1 ;
PR_ExecuteProgram ( w - > progs , portal - > xv - > camera_transform ) ;
2014-07-12 06:56:17 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
tmp = floor ( G_VECTOR ( OFS_RETURN ) [ i ] * 8 + 0.5 ) ;
rounded [ i ] = tmp / 8.0 ;
}
2014-01-13 02:42:25 +00:00
//make sure the new origin is okay for the player. back out if its invalid.
2014-07-12 06:56:17 +00:00
if ( ! PM_TestPlayerPosition ( rounded , true ) )
2014-01-13 02:42:25 +00:00
okay = false ;
else
{
2014-07-12 06:56:17 +00:00
VectorCopy ( rounded , org ) ;
VectorCopy ( w - > g . v_forward , newvel ) ;
2014-01-13 02:42:25 +00:00
VectorCopy ( w - > g . v_right , move ) ;
2014-07-12 06:56:17 +00:00
// VectorCopy(w->g.v_up, pmove.gravitydir);
2014-01-13 02:42:25 +00:00
2015-12-28 17:41:39 +00:00
//floor+floor, ish
if ( DotProduct ( w - > g . v_up , pmove . gravitydir ) < 0.7 )
{
f = DotProduct ( newvel , newvel ) ;
if ( f < 200 * 200 )
{
VectorScale ( newvel , 200 / sqrt ( f ) , newvel ) ;
}
}
2014-01-13 02:42:25 +00:00
//transform the angles too
VectorCopy ( org , G_VECTOR ( OFS_PARM0 ) ) ;
VectorCopy ( pmove . angles , G_VECTOR ( OFS_PARM1 ) ) ;
AngleVectors ( pmove . angles , w - > g . v_forward , w - > g . v_right , w - > g . v_up ) ;
PR_ExecuteProgram ( w - > progs , portal - > xv - > camera_transform ) ;
added r_meshpitch cvar that allows for fixing the unfixable mesh pitch bug from vanilla... needs a better name... do note that this will break pretty much any mod, so this is really only for TCs designed to use it. Its likely that I missed places.
nqsv: added support for spectators with nq clients. the angles are a bit rough, but hey. need to do something about frags so nq clients know who's a spectator. use 'cmd observe' to get an nq client to spectate on an fte server (then attack/jump behave the same as in qw clients).
nqsv: rewrote EF_MUZZLEFLASH handling, so svc_muzzleflash is now translated properly to EF_MUZZLEFLASH, and vice versa. No more missing muzzleflashes!
added screenshot_cubemap, so you can actually pre-generate cubemaps with fte (which can be used for reflections or whatever).
misc fixes (server crash, a couple of other less important ones).
external files based on a model's name will now obey r_replacemodels properly, instead of needing to use foo.mdl_0.skin for foo.md3.
identify <playernum> should now use the correct masked ip, instead of abrubtly failing (reported by kt)
vid_toggle console command should now obey vid_width and vid_height when switching to fullscreen, but only if vid_fullscreen is actually set, which should make it seem better behaved (reported by kt).
qcc: cleaned up sym->symboldata[sym->ofs] to be more consistent at all stages.
qcc: typedef float vec4[4]; now works to define a float array with 4 elements (however, it will be passed by-value rather than by-reference).
qcc: cleaned up optional vs __out ordering issues.
qccgui: shift+f3 searches backwards
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5064 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-02-27 09:34:35 +00:00
VectorAngles ( w - > g . v_forward , w - > g . v_up , newang , false ) ;
2014-01-13 02:42:25 +00:00
}
* w - > g . self = oself ;
return okay ;
}
2004-08-21 01:25:48 +00:00
2014-06-21 17:58:17 +00:00
static trace_t PM_PlayerTracePortals ( vec3_t start , vec3_t end , unsigned int solidmask , float * tookportal )
{
trace_t trace = PM_PlayerTrace ( start , end , MASK_PLAYERSOLID ) ;
if ( tookportal )
* tookportal = 0 ;
if ( trace . entnum > = 0 & & pmove . world )
{
physent_t * impact = & pmove . physents [ trace . entnum ] ;
if ( impact - > isportal )
{
vec3_t move ;
vec3_t from ;
2019-03-04 19:24:51 +00:00
vec3_t newang , newvel = { 0 , 0 , 0 } ;
2014-06-21 17:58:17 +00:00
VectorCopy ( trace . endpos , from ) ; //just in case
VectorSubtract ( end , trace . endpos , move ) ;
2014-07-12 06:56:17 +00:00
if ( PM_PortalTransform ( pmove . world , impact - > info , from , move , newang , newvel ) )
2014-06-21 17:58:17 +00:00
{
2014-07-12 06:56:17 +00:00
trace_t exit ;
int i , tmp ;
2014-06-21 17:58:17 +00:00
VectorAdd ( from , move , end ) ;
//if we follow the portal, then we basically need to restart from the other side.
2014-07-12 06:56:17 +00:00
exit = PM_PlayerTrace ( from , end , MASK_PLAYERSOLID ) ;
for ( i = 0 ; i < 3 ; i + + )
{
tmp = floor ( exit . endpos [ i ] * 8 + 0.5 ) ;
exit . endpos [ i ] = tmp / 8.0 ;
}
if ( PM_TestPlayerPosition ( exit . endpos , false ) )
{
if ( tookportal )
* tookportal = trace . fraction ;
VectorCopy ( newang , pmove . angles ) ;
VectorCopy ( newvel , pmove . velocity ) ;
return exit ;
}
2014-06-21 17:58:17 +00:00
}
}
}
return trace ;
}
2004-08-21 01:25:48 +00:00
/*
= = = = = = = = = = = =
PM_SlideMove
The basic solid body movement clip that slides along multiple planes
= = = = = = = = = = = =
*/
# define MAX_CLIP_PLANES 5
int PM_SlideMove ( void )
{
int bumpcount , numbumps ;
vec3_t dir ;
float d ;
int numplanes ;
vec3_t planes [ MAX_CLIP_PLANES ] ;
vec3_t primal_velocity , original_velocity ;
int i , j ;
trace_t trace ;
vec3_t end ;
float time_left ;
int blocked ;
2014-06-21 17:58:17 +00:00
float tookportal ;
2014-07-02 03:20:40 +00:00
vec3_t start ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
numbumps = 4 ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
blocked = 0 ;
VectorCopy ( pmove . velocity , original_velocity ) ;
VectorCopy ( pmove . velocity , primal_velocity ) ;
numplanes = 0 ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
time_left = frametime ;
2009-03-03 01:52:30 +00:00
// VectorAdd(pmove.velocity, pmove.basevelocity, pmove.velocity);
2004-08-21 01:25:48 +00:00
for ( bumpcount = 0 ; bumpcount < numbumps ; bumpcount + + )
{
for ( i = 0 ; i < 3 ; i + + )
end [ i ] = pmove . origin [ i ] + time_left * pmove . velocity [ i ] ;
2014-07-02 03:20:40 +00:00
VectorCopy ( pmove . origin , start ) ;
trace = PM_PlayerTracePortals ( start , end , MASK_PLAYERSOLID , & tookportal ) ;
2014-06-21 17:58:17 +00:00
if ( tookportal )
2014-01-13 02:42:25 +00:00
{
2014-06-21 17:58:17 +00:00
//made progress, but hit a portal
time_left - = time_left * tookportal ;
VectorCopy ( pmove . velocity , primal_velocity ) ;
VectorCopy ( pmove . velocity , original_velocity ) ;
numplanes = 0 ;
2014-01-13 02:42:25 +00:00
}
2004-08-21 01:25:48 +00:00
if ( trace . startsolid | | trace . allsolid )
{ // entity is trapped in another solid
VectorClear ( pmove . velocity ) ;
return 3 ;
}
if ( trace . fraction > 0 )
{ // actually covered some distance
VectorCopy ( trace . endpos , pmove . origin ) ;
numplanes = 0 ;
}
if ( trace . fraction = = 1 )
break ; // moved the entire distance
// save entity for contact
2006-05-25 23:08:37 +00:00
PM_AddTouchedEnt ( trace . entnum ) ;
2004-08-21 01:25:48 +00:00
if ( trace . plane . normal [ 2 ] > = MIN_STEP_NORMAL )
blocked | = BLOCKED_FLOOR ;
else if ( ! trace . plane . normal [ 2 ] )
blocked | = BLOCKED_STEP ;
else
blocked | = BLOCKED_OTHER ;
time_left - = time_left * trace . fraction ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
// cliped to another plane
if ( numplanes > = MAX_CLIP_PLANES )
{ // this shouldn't really happen
VectorClear ( pmove . velocity ) ;
break ;
}
VectorCopy ( trace . plane . normal , planes [ numplanes ] ) ;
numplanes + + ;
//
// modify original_velocity so it parallels all of the clip planes
//
for ( i = 0 ; i < numplanes ; i + + )
{
2005-01-13 16:50:37 +00:00
if ( movevars . walljump = = 2 ) //just bounce off!
{ //pinball
PM_ClipVelocity ( original_velocity , planes [ i ] , pmove . velocity , 2 ) ;
2006-01-02 22:59:05 +00:00
return blocked ;
2005-01-13 16:50:37 +00:00
}
//regular run at a wall and jump off
2005-01-04 08:04:42 +00:00
if ( movevars . walljump & & planes [ i ] [ 2 ] ! = 1 //not on floors
2005-01-13 16:50:37 +00:00
& & Length ( pmove . velocity ) > 200 & & pmove . cmd . buttons & 2 & & ! pmove . jump_held & & ! pmove . waterjumptime )
2005-01-04 08:04:42 +00:00
{
PM_ClipVelocity ( original_velocity , planes [ i ] , pmove . velocity , 2 ) ;
2017-08-16 02:14:07 +00:00
if ( pmove . velocity [ 2 ] < movevars_jumpspeed )
pmove . velocity [ 2 ] = movevars_jumpspeed ;
2005-01-04 08:04:42 +00:00
pmove . jump_msec = pmove . cmd . msec ;
pmove . jump_held = true ;
2005-01-13 16:50:37 +00:00
pmove . waterjumptime = 0 ;
2006-01-02 22:59:05 +00:00
return blocked ;
2005-01-04 08:04:42 +00:00
}
2004-08-21 01:25:48 +00:00
PM_ClipVelocity ( original_velocity , planes [ i ] , pmove . velocity , 1 ) ;
for ( j = 0 ; j < numplanes ; j + + )
if ( j ! = i )
{
if ( DotProduct ( pmove . velocity , planes [ j ] ) < 0 )
break ; // not ok
}
if ( j = = numplanes )
break ;
}
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
if ( i ! = numplanes )
{ // go along this plane
}
else
{ // go along the crease
if ( numplanes ! = 2 )
{
VectorClear ( pmove . velocity ) ;
break ;
}
CrossProduct ( planes [ 0 ] , planes [ 1 ] , dir ) ;
d = DotProduct ( dir , pmove . velocity ) ;
VectorScale ( dir , d , pmove . velocity ) ;
}
//
// if velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
if ( DotProduct ( pmove . velocity , primal_velocity ) < = 0 )
{
VectorClear ( pmove . velocity ) ;
break ;
}
}
if ( pmove . waterjumptime )
{
VectorCopy ( primal_velocity , pmove . velocity ) ;
}
return blocked ;
}
/*
= = = = = = = = = = = = =
PM_StepSlideMove
Each intersection will try to step over the obstruction instead of
sliding along it .
= = = = = = = = = = = = =
*/
2006-05-25 23:08:37 +00:00
int PM_StepSlideMove ( qboolean in_air )
2004-08-21 01:25:48 +00:00
{
vec3_t dest ;
trace_t trace ;
vec3_t original , originalvel , down , up , downvel ;
float downdist , updist ;
int blocked ;
2006-06-27 22:35:11 +00:00
float stepsize ;
2004-08-21 01:25:48 +00:00
// try sliding forward both on ground and up 16 pixels
// take the move that goes farthest
VectorCopy ( pmove . origin , original ) ;
VectorCopy ( pmove . velocity , originalvel ) ;
blocked = PM_SlideMove ( ) ;
if ( ! blocked )
2018-01-22 19:18:04 +00:00
{
if ( ! in_air & & movevars . stepdown )
{ //if we were onground, try stepping down after the move to try to stay on said ground.
VectorMA ( pmove . origin , movevars . stepheight , pmove . gravitydir , dest ) ;
trace = PM_PlayerTracePortals ( pmove . origin , dest , MASK_PLAYERSOLID , NULL ) ;
if ( trace . fraction ! = 1 & & - DotProduct ( pmove . gravitydir , trace . plane . normal ) > MIN_STEP_NORMAL )
{
if ( ! trace . startsolid & & ! trace . allsolid )
VectorCopy ( trace . endpos , pmove . origin ) ;
}
}
2006-05-25 23:08:37 +00:00
return blocked ; // moved the entire distance
2018-01-22 19:18:04 +00:00
}
2006-05-25 23:08:37 +00:00
2015-08-20 03:17:47 +00:00
if ( in_air )
2006-05-25 23:08:37 +00:00
{
// don't let us step up unless it's indeed a step we bumped in
// (that is, there's solid ground below)
float * org ;
if ( ! ( blocked & BLOCKED_STEP ) )
return blocked ;
2012-02-14 15:50:34 +00:00
org = ( - DotProduct ( pmove . gravitydir , originalvel ) < 0 ) ? pmove . origin : original ;
VectorMA ( org , movevars . stepheight , pmove . gravitydir , dest ) ;
2013-10-29 17:38:22 +00:00
trace = PM_PlayerTrace ( org , dest , MASK_PLAYERSOLID ) ;
2012-02-14 15:50:34 +00:00
if ( trace . fraction = = 1 | | - DotProduct ( pmove . gravitydir , trace . plane . normal ) < MIN_STEP_NORMAL )
2006-05-25 23:08:37 +00:00
return blocked ;
// adjust stepsize, otherwise it would be possible to walk up a
// a step higher than STEPSIZE
2014-06-21 17:58:17 +00:00
//FIXME gravitydir, portals
2007-06-20 00:02:54 +00:00
stepsize = movevars . stepheight - ( org [ 2 ] - trace . endpos [ 2 ] ) ;
2006-05-25 23:08:37 +00:00
}
else
2007-06-20 00:02:54 +00:00
stepsize = movevars . stepheight ;
2004-08-21 01:25:48 +00:00
VectorCopy ( pmove . origin , down ) ;
VectorCopy ( pmove . velocity , downvel ) ;
VectorCopy ( original , pmove . origin ) ;
VectorCopy ( originalvel , pmove . velocity ) ;
// move up a stair height
2012-02-14 15:50:34 +00:00
VectorMA ( pmove . origin , - stepsize , pmove . gravitydir , dest ) ;
2014-06-21 17:58:17 +00:00
trace = PM_PlayerTracePortals ( pmove . origin , dest , MASK_PLAYERSOLID , NULL ) ;
2004-08-21 01:25:48 +00:00
if ( ! trace . startsolid & & ! trace . allsolid )
{
VectorCopy ( trace . endpos , pmove . origin ) ;
}
2019-05-10 09:31:21 +00:00
if ( in_air & & - DotProduct ( pmove . gravitydir , original ) < 0 )
2012-02-14 15:50:34 +00:00
VectorMA ( pmove . velocity , - DotProduct ( pmove . velocity , pmove . gravitydir ) , pmove . gravitydir , pmove . velocity ) ; //z=0
2006-07-01 11:57:24 +00:00
2004-08-21 01:25:48 +00:00
PM_SlideMove ( ) ;
// press down the stepheight
2012-02-14 15:50:34 +00:00
VectorMA ( pmove . origin , stepsize , pmove . gravitydir , dest ) ;
2014-06-21 17:58:17 +00:00
trace = PM_PlayerTracePortals ( pmove . origin , dest , MASK_PLAYERSOLID , NULL ) ;
2012-02-14 15:50:34 +00:00
if ( trace . fraction ! = 1 & & - DotProduct ( pmove . gravitydir , trace . plane . normal ) < MIN_STEP_NORMAL )
2004-08-21 01:25:48 +00:00
goto usedown ;
if ( ! trace . startsolid & & ! trace . allsolid )
{
VectorCopy ( trace . endpos , pmove . origin ) ;
}
2012-02-14 15:50:34 +00:00
if ( - DotProduct ( pmove . gravitydir , pmove . origin ) < - DotProduct ( pmove . gravitydir , original ) )
2004-08-21 01:25:48 +00:00
goto usedown ;
VectorCopy ( pmove . origin , up ) ;
2012-02-14 15:50:34 +00:00
// decide which one went farther (in the forwards direction regardless of step values)
VectorSubtract ( down , original , dest ) ;
VectorMA ( dest , - DotProduct ( dest , pmove . gravitydir ) , pmove . gravitydir , dest ) ; //z=0
downdist = DotProduct ( dest , dest ) ;
VectorSubtract ( up , original , dest ) ;
VectorMA ( dest , - DotProduct ( dest , pmove . gravitydir ) , pmove . gravitydir , dest ) ; //z=0
updist = DotProduct ( dest , dest ) ;
2004-08-21 01:25:48 +00:00
if ( downdist > = updist )
{
usedown :
VectorCopy ( down , pmove . origin ) ;
VectorCopy ( downvel , pmove . velocity ) ;
2006-05-25 23:08:37 +00:00
return blocked ;
2004-08-21 01:25:48 +00:00
}
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
// copy z value from slide move
2012-02-14 15:50:34 +00:00
VectorMA ( pmove . velocity , DotProduct ( downvel , pmove . gravitydir ) - DotProduct ( pmove . velocity , pmove . gravitydir ) , pmove . gravitydir , pmove . velocity ) ; //z=downvel
2004-08-21 01:25:48 +00:00
if ( ! pmove . onground & & pmove . waterlevel < 2 & & ( blocked & BLOCKED_STEP ) ) {
float scale ;
// in pm_airstep mode, walking up a 16 unit high step
// will kill 16% of horizontal velocity
scale = 1 - 0.01 * ( pmove . origin [ 2 ] - original [ 2 ] ) ;
2012-02-14 15:50:34 +00:00
//FIXME gravitydir
2004-08-21 01:25:48 +00:00
pmove . velocity [ 0 ] * = scale ;
pmove . velocity [ 1 ] * = scale ;
}
2006-05-25 23:08:37 +00:00
return blocked ;
2004-08-21 01:25:48 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
PM_Friction
Handles both ground friction and water friction
= = = = = = = = = = = = = = = = = =
*/
void PM_Friction ( void )
{
float speed , newspeed , control ;
float friction ;
float drop ;
vec3_t start , stop ;
trace_t trace ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
if ( pmove . waterjumptime )
return ;
speed = Length ( pmove . velocity ) ;
if ( speed < 1 )
{
2012-07-05 19:42:36 +00:00
//fixme: gravitydir fix needed
2004-08-21 01:25:48 +00:00
pmove . velocity [ 0 ] = 0 ;
pmove . velocity [ 1 ] = 0 ;
2014-06-21 17:58:17 +00:00
if ( pmove . pm_type = = PM_FLY | | pmove . pm_type = = PM_6DOF )
2004-08-21 01:25:48 +00:00
pmove . velocity [ 2 ] = 0 ;
return ;
}
if ( pmove . waterlevel > = 2 )
// apply water friction, even if in fly mode
drop = speed * movevars . waterfriction * pmove . waterlevel * frametime ;
2014-06-21 17:58:17 +00:00
else if ( pmove . pm_type = = PM_FLY | | pmove . pm_type = = PM_6DOF ) {
2004-08-21 01:25:48 +00:00
// apply flymode friction
2014-06-21 17:58:17 +00:00
drop = speed * movevars . flyfriction * frametime ;
2004-08-21 01:25:48 +00:00
}
else if ( pmove . onground ) {
// apply ground friction
friction = movevars . friction ;
2018-12-11 00:20:59 +00:00
if ( movevars . edgefriction ! = 1.0 )
2017-08-16 02:14:07 +00:00
{
// if the leading edge is over a dropoff, increase friction
start [ 0 ] = stop [ 0 ] = pmove . origin [ 0 ] + pmove . velocity [ 0 ] / speed * 16 ;
start [ 1 ] = stop [ 1 ] = pmove . origin [ 1 ] + pmove . velocity [ 1 ] / speed * 16 ;
//FIXME: gravitydir.
//id quirk: this is a tracebox, NOT a traceline, yet still starts BELOW the player.
start [ 2 ] = pmove . origin [ 2 ] + pmove . player_mins [ 2 ] ;
stop [ 2 ] = start [ 2 ] - 34 ;
2019-03-23 07:06:37 +00:00
if ( movevars . flags & MOVEFLAG_QWEDGEBOX ) //vanilla qw behaviour is to use a tracebox, which makes edge friction almost unnoticable.
2017-08-16 02:14:07 +00:00
trace = PM_PlayerTrace ( start , stop , MASK_PLAYERSOLID ) ;
else
2019-03-23 07:06:37 +00:00
{ //traceline instead.
2017-08-16 02:14:07 +00:00
vec3_t min , max ;
VectorCopy ( pmove . player_mins , min ) ;
VectorCopy ( pmove . player_maxs , max ) ;
VectorClear ( pmove . player_mins ) ;
VectorClear ( pmove . player_maxs ) ;
trace = PM_PlayerTrace ( start , stop , MASK_PLAYERSOLID ) ;
VectorCopy ( min , pmove . player_mins ) ;
VectorCopy ( max , pmove . player_maxs ) ;
}
if ( trace . fraction = = 1 & & ! trace . startsolid )
2018-12-11 00:20:59 +00:00
friction * = movevars . edgefriction ;
2017-08-16 02:14:07 +00:00
}
2004-08-21 01:25:48 +00:00
control = speed < movevars . stopspeed ? movevars . stopspeed : speed ;
drop = control * friction * frametime ;
}
else if ( pmove . onladder )
{
control = speed < movevars . stopspeed ? movevars . stopspeed : speed ;
drop = control * movevars . friction * frametime * 6 ;
}
else
return ; // in air, no friction
// scale the velocity
newspeed = speed - drop ;
if ( newspeed < 0 )
newspeed = 0 ;
VectorScale ( pmove . velocity , newspeed / speed , pmove . velocity ) ;
}
/*
= = = = = = = = = = = = = =
PM_Accelerate
= = = = = = = = = = = = = =
*/
void PM_Accelerate ( vec3_t wishdir , float wishspeed , float accel )
{
int i ;
float addspeed , accelspeed , currentspeed ;
if ( pmove . pm_type = = PM_DEAD )
return ;
if ( pmove . waterjumptime )
return ;
currentspeed = DotProduct ( pmove . velocity , wishdir ) ;
addspeed = wishspeed - currentspeed ;
if ( addspeed < = 0 )
return ;
accelspeed = accel * frametime * wishspeed ;
if ( accelspeed > addspeed )
accelspeed = addspeed ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
for ( i = 0 ; i < 3 ; i + + )
pmove . velocity [ i ] + = accelspeed * wishdir [ i ] ;
}
void PM_AirAccelerate ( vec3_t wishdir , float wishspeed , float accel )
{
int i ;
float addspeed , accelspeed , currentspeed , wishspd = wishspeed ;
float originalspeed , newspeed , speedcap ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
if ( pmove . pm_type = = PM_DEAD )
return ;
if ( pmove . waterjumptime )
return ;
if ( movevars . bunnyspeedcap > 0 )
{
originalspeed = sqrt ( pmove . velocity [ 0 ] * pmove . velocity [ 0 ] +
pmove . velocity [ 1 ] * pmove . velocity [ 1 ] ) ;
}
else
originalspeed = 0 ; //shh compiler.
2017-08-16 02:14:07 +00:00
if ( wishspd > movevars_maxairspeed )
wishspd = movevars_maxairspeed ;
2004-08-21 01:25:48 +00:00
currentspeed = DotProduct ( pmove . velocity , wishdir ) ;
addspeed = wishspd - currentspeed ;
if ( addspeed < = 0 )
return ;
accelspeed = accel * wishspeed * frametime ;
if ( accelspeed > addspeed )
accelspeed = addspeed ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
for ( i = 0 ; i < 3 ; i + + )
pmove . velocity [ i ] + = accelspeed * wishdir [ i ] ;
if ( movevars . bunnyspeedcap > 0 )
{
newspeed = sqrt ( pmove . velocity [ 0 ] * pmove . velocity [ 0 ] +
pmove . velocity [ 1 ] * pmove . velocity [ 1 ] ) ;
if ( newspeed > originalspeed )
{
speedcap = movevars . maxspeed * movevars . bunnyspeedcap ;
if ( newspeed > speedcap )
{
if ( originalspeed < speedcap )
originalspeed = speedcap ;
pmove . velocity [ 0 ] * = originalspeed / newspeed ;
pmove . velocity [ 1 ] * = originalspeed / newspeed ;
}
}
}
}
/*
= = = = = = = = = = = = = = = = = = =
PM_WaterMove
= = = = = = = = = = = = = = = = = = =
*/
void PM_WaterMove ( void )
{
int i ;
vec3_t wishvel ;
float wishspeed ;
vec3_t wishdir ;
//
// user intentions
//
for ( i = 0 ; i < 3 ; i + + )
wishvel [ i ] = forward [ i ] * pmove . cmd . forwardmove + right [ i ] * pmove . cmd . sidemove ;
2012-02-12 05:18:31 +00:00
if ( pmove . pm_type ! = PM_FLY & & ! pmove . cmd . forwardmove & & ! pmove . cmd . sidemove & & ! pmove . cmd . upmove & & ! pmove . onladder )
2012-02-14 15:50:34 +00:00
{
2014-04-12 02:37:18 +00:00
VectorMA ( wishvel , movevars . watersinkspeed , pmove . gravitydir , wishvel ) ;
2012-02-14 15:50:34 +00:00
}
2004-08-21 01:25:48 +00:00
else
2012-02-14 15:50:34 +00:00
{
VectorMA ( wishvel , - pmove . cmd . upmove , pmove . gravitydir , wishvel ) ;
}
2004-08-21 01:25:48 +00:00
VectorCopy ( wishvel , wishdir ) ;
wishspeed = VectorNormalize ( wishdir ) ;
if ( wishspeed > movevars . maxspeed ) {
VectorScale ( wishvel , movevars . maxspeed / wishspeed , wishvel ) ;
wishspeed = movevars . maxspeed ;
}
wishspeed * = 0.7 ;
//
// water acceleration
//
PM_Accelerate ( wishdir , wishspeed , movevars . wateraccelerate ) ;
2006-05-25 23:08:37 +00:00
PM_StepSlideMove ( false ) ;
2004-08-21 01:25:48 +00:00
}
/*
*/
2009-03-03 01:52:30 +00:00
void PM_FlyMove ( void )
2004-08-21 01:25:48 +00:00
{
int i ;
vec3_t wishvel ;
float wishspeed ;
vec3_t wishdir ;
2014-06-21 17:58:17 +00:00
if ( pmove . pm_type = = PM_6DOF )
{
for ( i = 0 ; i < 3 ; i + + )
wishvel [ i ] = forward [ i ] * pmove . cmd . forwardmove + right [ i ] * pmove . cmd . sidemove + up [ i ] * pmove . cmd . upmove ;
}
else
{
for ( i = 0 ; i < 3 ; i + + )
wishvel [ i ] = forward [ i ] * pmove . cmd . forwardmove + right [ i ] * pmove . cmd . sidemove ;
2005-02-06 02:47:36 +00:00
2014-06-21 17:58:17 +00:00
VectorMA ( wishvel , - pmove . cmd . upmove , pmove . gravitydir , wishvel ) ;
}
2004-08-21 01:25:48 +00:00
VectorCopy ( wishvel , wishdir ) ;
wishspeed = VectorNormalize ( wishdir ) ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
if ( wishspeed > movevars . maxspeed ) {
VectorScale ( wishvel , movevars . maxspeed / wishspeed , wishvel ) ;
wishspeed = movevars . maxspeed ;
}
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
PM_Accelerate ( wishdir , wishspeed , movevars . accelerate ) ;
2024-04-25 05:57:34 +00:00
2006-05-25 23:08:37 +00:00
PM_StepSlideMove ( false ) ;
2004-08-21 01:25:48 +00:00
}
void PM_LadderMove ( void )
{
int i ;
vec3_t wishvel ;
float wishspeed ;
vec3_t wishdir ;
vec3_t start , dest ;
trace_t trace ;
//
// user intentions
2005-02-06 02:47:36 +00:00
//
2004-08-21 01:25:48 +00:00
for ( i = 0 ; i < 3 ; i + + )
wishvel [ i ] = forward [ i ] * pmove . cmd . forwardmove + right [ i ] * pmove . cmd . sidemove + up [ i ] * pmove . cmd . upmove ;
2009-03-03 01:52:30 +00:00
if ( wishvel [ 2 ] > = 100 | | wishvel [ 2 ] < = - 100 ) //large up/down move
2004-08-21 01:25:48 +00:00
wishvel [ 2 ] * = 10 ;
if ( pmove . cmd . buttons & 2 )
2012-02-14 15:50:34 +00:00
{
VectorMA ( wishvel , - movevars . maxspeed , pmove . gravitydir , wishvel ) ;
}
2004-08-21 01:25:48 +00:00
VectorCopy ( wishvel , wishdir ) ;
wishspeed = VectorNormalize ( wishdir ) ;
if ( wishspeed > movevars . maxspeed )
{
VectorScale ( wishvel , movevars . maxspeed / wishspeed , wishvel ) ;
wishspeed = movevars . maxspeed ;
}
PM_Accelerate ( wishdir , wishspeed , movevars . wateraccelerate ) ;
// assume it is a stair or a slope, so press down from stepheight above
VectorMA ( pmove . origin , frametime , pmove . velocity , dest ) ;
2012-02-14 15:50:34 +00:00
VectorMA ( dest , - ( movevars . stepheight + 1 ) , pmove . gravitydir , start ) ;
2013-10-29 17:38:22 +00:00
trace = PM_PlayerTrace ( start , dest , MASK_PLAYERSOLID ) ;
2004-08-21 01:25:48 +00:00
if ( ! trace . startsolid & & ! trace . allsolid ) // FIXME: check steep slope?
{ // walked up the step
VectorCopy ( trace . endpos , pmove . origin ) ;
return ;
}
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
PM_FlyMove ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = =
PM_AirMove
= = = = = = = = = = = = = = = = = = =
*/
void PM_AirMove ( void )
{
int i ;
float fmove , smove ;
vec3_t wishdir ;
float wishspeed ;
2017-12-28 16:24:50 +00:00
if ( pmove . gravitydir [ 2 ] = = - 1 & & ( pmove . angles [ 0 ] = = 90 | | pmove . angles [ 0 ] = = - 90 ) )
{ //HACK: attempt to avoid a stupid numerical precision issue.
//You know its a hack because I'm comparing exact angles.
vec3_t tmp ;
VectorSet ( tmp , pmove . angles [ 0 ] * 0.99 , pmove . angles [ 1 ] , pmove . angles [ 2 ] ) ;
AngleVectors ( tmp , forward , right , up ) ;
}
2004-08-21 01:25:48 +00:00
fmove = pmove . cmd . forwardmove ;
smove = pmove . cmd . sidemove ;
2012-02-14 15:50:34 +00:00
VectorMA ( forward , - DotProduct ( forward , pmove . gravitydir ) , pmove . gravitydir , forward ) ; //z=0
VectorMA ( right , - DotProduct ( right , pmove . gravitydir ) , pmove . gravitydir , right ) ; //z=0
2004-08-21 01:25:48 +00:00
VectorNormalize ( forward ) ;
VectorNormalize ( right ) ;
2012-02-14 15:50:34 +00:00
for ( i = 0 ; i < 3 ; i + + )
2009-04-19 00:50:42 +00:00
wishdir [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
2012-02-14 15:50:34 +00:00
VectorMA ( wishdir , - DotProduct ( wishdir , pmove . gravitydir ) , pmove . gravitydir , wishdir ) ; //z=0
2004-08-21 01:25:48 +00:00
wishspeed = VectorNormalize ( wishdir ) ;
//
// clamp to server defined max speed
//
if ( wishspeed > movevars . maxspeed )
{
wishspeed = movevars . maxspeed ;
}
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
if ( pmove . onground )
{
2006-05-25 23:08:37 +00:00
if ( movevars . slidefix )
{
2015-05-03 19:57:46 +00:00
if ( DotProduct ( pmove . velocity , pmove . gravitydir ) < 0 )
{
VectorMA ( pmove . velocity , - DotProduct ( pmove . velocity , pmove . gravitydir ) , pmove . gravitydir , pmove . velocity ) ; //z=0
//pmove.velocity[2] = min(pmove.velocity[2], 0); // bound above by 0
}
2006-05-25 23:08:37 +00:00
PM_Accelerate ( wishdir , wishspeed , movevars . accelerate ) ;
// add gravity
2012-02-14 15:50:34 +00:00
VectorMA ( pmove . velocity , movevars . entgravity * movevars . gravity * frametime , pmove . gravitydir , pmove . velocity ) ;
2006-05-25 23:08:37 +00:00
}
else
{
2012-02-14 15:50:34 +00:00
VectorMA ( pmove . velocity , - DotProduct ( pmove . velocity , pmove . gravitydir ) , pmove . gravitydir , pmove . velocity ) ; //z=0
2006-05-25 23:08:37 +00:00
PM_Accelerate ( wishdir , wishspeed , movevars . accelerate ) ;
}
2004-08-21 01:25:48 +00:00
2012-02-14 15:50:34 +00:00
//clear the z out, so we can test if we're moving horizontally relative to gravity
VectorMA ( pmove . velocity , - DotProduct ( pmove . velocity , pmove . gravitydir ) , pmove . gravitydir , wishdir ) ;
if ( ! DotProduct ( wishdir , wishdir ) & & ! movevars . slidyslopes )
2004-08-21 01:25:48 +00:00
{
2012-02-14 15:50:34 +00:00
//clear z if we're not moving
VectorClear ( pmove . velocity ) ;
2004-08-21 01:25:48 +00:00
return ;
}
2005-05-17 02:36:54 +00:00
else if ( ! movevars . slidefix & & ! movevars . slidyslopes )
2012-02-14 15:50:34 +00:00
VectorMA ( pmove . velocity , - DotProduct ( pmove . velocity , pmove . gravitydir ) , pmove . gravitydir , pmove . velocity ) ; //z=0
2004-08-21 01:25:48 +00:00
2006-05-25 23:08:37 +00:00
PM_StepSlideMove ( false ) ;
2004-08-21 01:25:48 +00:00
}
else
2006-05-25 23:08:37 +00:00
{
int blocked ;
2024-04-25 05:57:34 +00:00
2006-05-25 23:08:37 +00:00
// not on ground, so little effect on velocity
2004-08-21 01:25:48 +00:00
PM_AirAccelerate ( wishdir , wishspeed , movevars . accelerate ) ;
// add gravity
2012-02-14 15:50:34 +00:00
VectorMA ( pmove . velocity , movevars . entgravity * movevars . gravity * frametime , pmove . gravitydir , pmove . velocity ) ;
2004-08-21 01:25:48 +00:00
2015-08-20 03:17:47 +00:00
if ( DotProduct ( pmove . velocity , pmove . velocity ) > 1000 * 1000 )
{
//when in a windtunnel, step up from where we are rather than the actual ground in order to more closely match nq.
//this is needed for r1m5 (770 800 192), just beyond the silver key door.
blocked = PM_StepSlideMove ( false ) ;
}
else if ( movevars . airstep )
2006-05-25 23:08:37 +00:00
blocked = PM_StepSlideMove ( true ) ;
2004-08-21 01:25:48 +00:00
else
2006-05-25 23:08:37 +00:00
blocked = PM_SlideMove ( ) ;
2013-03-12 22:53:23 +00:00
2019-03-01 22:39:30 +00:00
if ( movevars . pground & & ( blocked & BLOCKED_FLOOR ) )
2013-03-12 22:53:23 +00:00
pmove . onground = true ;
2004-08-21 01:25:48 +00:00
}
}
cplane_t groundplane ;
/*
= = = = = = = = = = = = =
PM_CategorizePosition
= = = = = = = = = = = = =
*/
2012-02-14 15:50:34 +00:00
trace_t PM_TraceLine ( vec3_t start , vec3_t end ) ;
2004-08-21 01:25:48 +00:00
void PM_CategorizePosition ( void )
{
vec3_t point ;
int cont ;
trace_t trace ;
2012-02-17 01:12:37 +00:00
if ( pmove . gravitydir [ 0 ] = = 0 & & pmove . gravitydir [ 1 ] = = 0 & & pmove . gravitydir [ 2 ] = = 0 )
{
pmove . gravitydir [ 0 ] = 0 ;
pmove . gravitydir [ 1 ] = 0 ;
pmove . gravitydir [ 2 ] = - 1 ;
}
2012-02-14 15:50:34 +00:00
if ( pmove . pm_type = = PM_WALLWALK )
{
vec3_t tmin , tmax ;
2014-01-13 02:42:25 +00:00
VectorCopy ( pmove . player_mins , tmin ) ;
VectorCopy ( pmove . player_maxs , tmax ) ;
2015-01-21 18:18:37 +00:00
// //try tracing forwards+down
// VectorMA(pmove.origin, -48, up, point);
// VectorMA(point, 48, forward, point);
// trace = PM_TraceLine(pmove.origin, point);
// trace.fraction = 1;
2016-08-25 00:12:14 +00:00
// if (1)//trace.fraction == 1)
2015-01-21 18:18:37 +00:00
{ //getting desparate
VectorMA ( pmove . origin , - 48 , up , point ) ;
VectorMA ( point , 48 , forward , point ) ;
trace = PM_TraceLine ( pmove . origin , point ) ;
}
if ( trace . fraction = = 1 )
{
//try tracing directly down only (we may be stepping off a cliff)
VectorMA ( pmove . origin , - 48 , up , point ) ;
trace = PM_TraceLine ( pmove . origin , point ) ;
}
if ( trace . fraction = = 1 )
{
vec3_t point2 ;
//try tracing back from the cliff to see if we can find the ground beyond
VectorMA ( point , 48 , forward , point2 ) ;
VectorMA ( point2 , 48 , forward , point ) ;
trace = PM_TraceLine ( point2 , point ) ;
}
if ( trace . fraction = = 1 )
{ //getting desparate
VectorMA ( pmove . origin , - 48 , up , point ) ;
VectorMA ( point , - 48 , forward , point ) ;
trace = PM_TraceLine ( pmove . origin , point ) ;
}
2014-01-13 02:42:25 +00:00
VectorCopy ( tmin , pmove . player_mins ) ;
VectorCopy ( tmax , pmove . player_maxs ) ;
2012-02-14 15:50:34 +00:00
if ( trace . fraction < 1 )
VectorNegate ( trace . plane . normal , pmove . gravitydir ) ;
}
2004-08-21 01:25:48 +00:00
// if the player hull point one unit down is solid, the player
// is on ground
// see if standing on something solid
2012-02-14 15:50:34 +00:00
VectorAdd ( pmove . origin , pmove . gravitydir , point ) ;
2004-08-21 01:25:48 +00:00
trace . startsolid = trace . allsolid = true ;
VectorClear ( trace . endpos ) ;
2012-04-23 18:40:10 +00:00
if ( - DotProduct ( pmove . gravitydir , pmove . velocity ) > 180 )
2004-08-21 01:25:48 +00:00
{
pmove . onground = false ;
}
2019-03-01 22:39:30 +00:00
else if ( ! movevars . pground | | pmove . onground )
2004-08-21 01:25:48 +00:00
{
2014-06-21 17:58:17 +00:00
trace = PM_PlayerTracePortals ( pmove . origin , point , MASK_PLAYERSOLID , NULL ) ;
2019-03-01 22:39:30 +00:00
if ( ! trace . startsolid & & trace . fraction < 1 & & - DotProduct ( pmove . gravitydir , trace . plane . normal ) < MIN_STEP_NORMAL )
{ //if the trace hit a slope, slide down the slope to see if we can find ground below. this should fix the 'base-of-slope-is-slide' bug.
vec3_t bounce ;
PM_ClipVelocity ( pmove . gravitydir , trace . plane . normal , bounce , 2 ) ;
VectorMA ( trace . endpos , 1 - trace . fraction , bounce , point ) ;
trace = PM_PlayerTracePortals ( trace . endpos , point , MASK_PLAYERSOLID , NULL ) ;
}
2014-10-29 05:03:03 +00:00
if ( ! trace . startsolid & & ( trace . fraction = = 1 | | - DotProduct ( pmove . gravitydir , trace . plane . normal ) < MIN_STEP_NORMAL ) )
2004-08-21 01:25:48 +00:00
pmove . onground = false ;
else
{
2015-06-04 06:15:14 +00:00
pmove . onground = ! trace . startsolid ;
2004-08-21 01:25:48 +00:00
pmove . groundent = trace . entnum ;
groundplane = trace . plane ;
pmove . waterjumptime = 0 ;
}
// standing on an entity other than the world
if ( trace . entnum > 0 )
2006-05-25 23:08:37 +00:00
PM_AddTouchedEnt ( trace . entnum ) ;
2004-08-21 01:25:48 +00:00
}
//
// get waterlevel
//
pmove . waterlevel = 0 ;
pmove . watertype = FTECONTENTS_EMPTY ;
2014-06-21 17:58:17 +00:00
//FIXME: gravitydir
2018-10-11 10:31:23 +00:00
VectorCopy ( pmove . origin , point ) ;
2014-01-13 02:42:25 +00:00
point [ 2 ] = pmove . origin [ 2 ] + pmove . player_mins [ 2 ] + 1 ;
2004-08-21 01:25:48 +00:00
cont = PM_PointContents ( point ) ;
if ( cont & FTECONTENTS_FLUID )
{
pmove . watertype = cont ;
pmove . waterlevel = 1 ;
2014-01-13 02:42:25 +00:00
point [ 2 ] = pmove . origin [ 2 ] + ( pmove . player_mins [ 2 ] + pmove . player_maxs [ 2 ] ) * 0.5 ;
2004-08-21 01:25:48 +00:00
cont = PM_PointContents ( point ) ;
if ( cont & FTECONTENTS_FLUID )
{
pmove . waterlevel = 2 ;
2014-01-13 02:42:25 +00:00
point [ 2 ] = pmove . origin [ 2 ] + pmove . player_mins [ 2 ] + 24 + DEFAULT_VIEWHEIGHT ;
2004-08-21 01:25:48 +00:00
cont = PM_PointContents ( point ) ;
if ( cont & FTECONTENTS_FLUID )
pmove . waterlevel = 3 ;
}
}
2012-02-12 05:18:31 +00:00
//bsp objects marked as ladders mark regions to stand in to be classed as on a ladder.
cont = PM_ExtraBoxContents ( pmove . origin ) ;
2009-03-03 01:52:30 +00:00
2015-05-03 19:57:46 +00:00
if ( pmove . physents [ 0 ] . model )
2006-02-12 04:47:10 +00:00
{
2015-05-03 19:57:46 +00:00
# ifdef Q3BSPS
//q3 has surfaceflag-based ladders
if ( pmove . physents [ 0 ] . model - > fromgame = = fg_quake3 )
{
trace_t t ;
vec3_t flatforward , fwd1 ;
2006-02-12 04:47:10 +00:00
2015-05-03 19:57:46 +00:00
flatforward [ 0 ] = forward [ 0 ] ;
flatforward [ 1 ] = forward [ 1 ] ;
flatforward [ 2 ] = 0 ;
VectorNormalize ( flatforward ) ;
2006-02-12 04:47:10 +00:00
2015-05-03 19:57:46 +00:00
VectorMA ( pmove . origin , 24 , flatforward , fwd1 ) ;
2006-02-12 04:47:10 +00:00
2017-01-29 13:10:53 +00:00
pmove . physents [ 0 ] . model - > funcs . NativeTrace ( pmove . physents [ 0 ] . model , 0 , PE_FRAMESTATE , NULL , pmove . origin , fwd1 , pmove . player_mins , pmove . player_maxs , pmove . capsule , MASK_PLAYERSOLID , & t ) ;
2020-09-08 05:11:09 +00:00
if ( t . surface & & t . surface - > flags & Q3SURFACEFLAG_LADDER )
2015-05-03 19:57:46 +00:00
{
pmove . onladder = true ;
pmove . onground = false ; // too steep
}
2006-02-12 04:47:10 +00:00
}
2012-02-12 05:18:31 +00:00
# endif
2015-05-03 19:57:46 +00:00
//q2 has contents-based ladders
if ( ( cont & FTECONTENTS_LADDER ) | | ( ( cont & Q2CONTENTS_LADDER ) & & pmove . physents [ 0 ] . model - > fromgame = = fg_quake2 ) )
{
trace_t t ;
vec3_t flatforward , fwd1 ;
2005-02-06 02:47:36 +00:00
2015-05-03 19:57:46 +00:00
flatforward [ 0 ] = forward [ 0 ] ;
flatforward [ 1 ] = forward [ 1 ] ;
flatforward [ 2 ] = 0 ;
VectorNormalize ( flatforward ) ;
2004-08-21 01:25:48 +00:00
2015-05-03 19:57:46 +00:00
VectorMA ( pmove . origin , 24 , flatforward , fwd1 ) ;
2004-08-21 01:25:48 +00:00
2015-05-03 19:57:46 +00:00
//if we hit a wall when going forwards and we are in a ladder region, then we are on a ladder.
t = PM_PlayerTrace ( pmove . origin , fwd1 , MASK_PLAYERSOLID ) ;
if ( t . fraction < 1 )
{
pmove . onladder = true ;
pmove . onground = false ; // too steep
}
2004-08-21 01:25:48 +00:00
}
}
2009-03-03 01:52:30 +00:00
2019-03-01 22:39:30 +00:00
if ( ! movevars . pground & & pmove . onground & & pmove . pm_type ! = PM_FLY & & pmove . waterlevel < 2 )
2004-08-21 01:25:48 +00:00
{
// snap to ground so that we can't jump higher than we're supposed to
if ( ! trace . startsolid & & ! trace . allsolid )
VectorCopy ( trace . endpos , pmove . origin ) ;
}
}
/*
= = = = = = = = = = = = =
PM_CheckJump
= = = = = = = = = = = = =
*/
2018-10-11 10:31:23 +00:00
static void PM_CheckJump ( void )
2004-08-21 01:25:48 +00:00
{
if ( pmove . pm_type = = PM_FLY )
return ;
if ( pmove . pm_type = = PM_DEAD )
{
pmove . jump_held = true ; // don't jump on respawn
return ;
}
if ( ! ( pmove . cmd . buttons & BUTTON_JUMP ) )
{
pmove . jump_held = false ;
return ;
}
if ( pmove . waterjumptime )
return ;
if ( pmove . waterlevel > = 2 )
{ // swimming, not jumping
2012-02-14 15:50:34 +00:00
float speed ;
2004-08-21 01:25:48 +00:00
pmove . onground = false ;
if ( pmove . watertype = = FTECONTENTS_WATER )
2012-02-14 15:50:34 +00:00
speed = 100 ;
2004-08-21 01:25:48 +00:00
else if ( pmove . watertype = = FTECONTENTS_SLIME )
2012-02-14 15:50:34 +00:00
speed = 80 ;
2004-08-21 01:25:48 +00:00
else
2012-02-14 15:50:34 +00:00
speed = 50 ;
VectorMA ( pmove . velocity , - speed - DotProduct ( pmove . velocity , pmove . gravitydir ) , pmove . gravitydir , pmove . velocity ) ;
2004-08-21 01:25:48 +00:00
return ;
}
if ( ! pmove . onground )
return ; // in air, so no effect
if ( pmove . jump_held & & ! pmove . jump_msec )
return ; // don't pogo stick
// check for jump bug
// groundplane normal was set in the call to PM_CategorizePosition
2019-03-01 22:39:30 +00:00
if ( ! movevars . pground & & - DotProduct ( pmove . gravitydir , pmove . velocity ) < 0 & & DotProduct ( pmove . velocity , groundplane . normal ) < - 0.1 )
2004-08-21 01:25:48 +00:00
{
// pmove.velocity is pointing into the ground, clip it
PM_ClipVelocity ( pmove . velocity , groundplane . normal , pmove . velocity , 1 ) ;
}
pmove . onground = false ;
2017-08-16 02:14:07 +00:00
VectorMA ( pmove . velocity , - movevars_jumpspeed , pmove . gravitydir , pmove . velocity ) ;
2004-08-21 01:25:48 +00:00
2012-02-14 15:50:34 +00:00
if ( movevars . ktjump > 0 & & pmove . pm_type ! = PM_WALLWALK )
2004-08-21 01:25:48 +00:00
{
if ( movevars . ktjump > 1 )
movevars . ktjump = 1 ;
2017-08-16 02:14:07 +00:00
if ( pmove . velocity [ 2 ] < movevars_jumpspeed )
2004-08-21 01:25:48 +00:00
pmove . velocity [ 2 ] = pmove . velocity [ 2 ] * ( 1 - movevars . ktjump )
2017-08-16 02:14:07 +00:00
+ movevars_jumpspeed * movevars . ktjump ;
2004-08-21 01:25:48 +00:00
}
pmove . jump_held = true ; // don't jump again until released
pmove . jump_msec = pmove . cmd . msec ;
}
/*
= = = = = = = = = = = = =
PM_CheckWaterJump
= = = = = = = = = = = = =
*/
2018-10-11 10:31:23 +00:00
static void PM_CheckWaterJump ( void )
2004-08-21 01:25:48 +00:00
{
2018-04-15 02:48:23 +00:00
vec3_t spot , spot2 ;
// int cont;
2004-08-21 01:25:48 +00:00
vec3_t flatforward ;
2018-04-15 02:48:23 +00:00
trace_t tr ;
vec3_t oldmin , oldmax ;
2004-08-21 01:25:48 +00:00
2006-10-14 02:04:24 +00:00
if ( pmove . waterjumptime > 0 )
2004-08-21 01:25:48 +00:00
return ;
2012-02-27 12:23:15 +00:00
if ( pmove . pm_type = = PM_DEAD )
return ;
2004-08-21 01:25:48 +00:00
// don't hop out if we just jumped in
if ( pmove . velocity [ 2 ] < - 180 )
return ;
// see if near an edge
flatforward [ 0 ] = forward [ 0 ] ;
flatforward [ 1 ] = forward [ 1 ] ;
flatforward [ 2 ] = 0 ;
VectorNormalize ( flatforward ) ;
2018-04-15 02:48:23 +00:00
# if 1 //NQ does a traceline, which gives more permissive results. This is required for various maps that have awkward water jumps.
VectorCopy ( pmove . player_mins , oldmin ) ;
VectorCopy ( pmove . player_maxs , oldmax ) ;
VectorCopy ( pmove . origin , spot ) ;
spot [ 2 ] + = 8 + 24 + pmove . player_mins [ 2 ] ; //hexen2 fix. calculated from the normal bottom of bbox
VectorMA ( spot , 24 , flatforward , spot2 ) ;
tr = PM_TraceLine ( spot , spot2 ) ;
VectorCopy ( oldmin , pmove . player_mins ) ;
VectorCopy ( oldmax , pmove . player_maxs ) ;
if ( tr . fraction = = 1 ) //(possibly) give up if open at waist
{ //NQ bug workaround: NQ does waterjump checks inside prethink, and THEN sets waterlevel after.
//The player then moves to where waterlevel SHOULD be 3, except you're still allowed to waterjump because of last frame.
//Which is horrible buggy framerate-dependant behaviour...
//so lets just try again 2qu up.
//This'll cause slight prediction issues with other qw engines, and maybe some newly bugged maps, but those maps were probably already buggy with a low enough nq framerate.
spot [ 2 ] + = 2 ;
spot2 [ 2 ] + = 2 ;
tr = PM_TraceLine ( spot , spot2 ) ;
VectorCopy ( oldmin , pmove . player_mins ) ;
VectorCopy ( oldmax , pmove . player_maxs ) ;
if ( tr . fraction = = 1 ) //give up if open at waist
return ;
}
spot [ 2 ] + = 24 ;
spot2 [ 2 ] + = 24 ;
tr = PM_TraceLine ( spot , spot2 ) ;
VectorCopy ( oldmin , pmove . player_mins ) ;
VectorCopy ( oldmax , pmove . player_maxs ) ;
if ( tr . fraction < 1 ) //give up if blocked at eye
return ;
# else
2004-08-21 01:25:48 +00:00
VectorMA ( pmove . origin , 24 , flatforward , spot ) ;
2014-01-13 02:42:25 +00:00
spot [ 2 ] + = 8 + 24 + pmove . player_mins [ 2 ] ; //hexen2 fix. calculated from the normal bottom of bbox
2004-08-21 01:25:48 +00:00
cont = PM_PointContents ( spot ) ;
if ( ! ( cont & FTECONTENTS_SOLID ) )
return ;
spot [ 2 ] + = 24 ;
cont = PM_PointContents ( spot ) ;
if ( cont ! = FTECONTENTS_EMPTY )
return ;
2018-04-15 02:48:23 +00:00
# endif
2004-08-21 01:25:48 +00:00
// jump out of water
VectorScale ( flatforward , 50 , pmove . velocity ) ;
pmove . velocity [ 2 ] = 310 ;
pmove . waterjumptime = 2 ; // safety net
pmove . jump_held = true ; // don't jump again until released
}
/*
= = = = = = = = = = = = = = = = =
PM_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
= = = = = = = = = = = = = = = = =
*/
2018-10-11 10:31:23 +00:00
static void PM_NudgePosition ( void )
2004-08-21 01:25:48 +00:00
{
2021-07-17 15:09:54 +00:00
vec3_t base , nudged ;
2004-08-21 01:25:48 +00:00
int x , y , z ;
int i ;
2021-04-14 05:21:04 +00:00
static float sign [ ] = { 0 , - 1 / 8.0 , 1 / 8.0 } ;
2004-08-21 01:25:48 +00:00
2021-07-17 15:09:54 +00:00
VectorCopy ( pmove . origin , base ) ;
2019-04-20 15:46:35 +00:00
//really we want to just use this here
//base[i] = MSG_FromCoord(MSG_ToCoord(pmove.origin[i], movevars.coordsize), movevars.coordsize);
//but it has overflow issues, so do things the painful way instead.
//this stuff is so annoying because we're trying to avoid biasing the position towards 0. you'll see the effects of that if you use a low forwardspeed or low sv_gamespeed etc, but its also noticable with default settings too.
2019-06-17 04:21:41 +00:00
if (
# ifdef HAVE_LEGACY
pm_noround . ival | |
# endif
2019-10-14 02:36:57 +00:00
movevars . coordtype = = COORDTYPE_FLOAT_32 ) //float precision on the network. no need to truncate.
2019-06-17 04:21:41 +00:00
{
2021-07-17 15:09:54 +00:00
VectorCopy ( base , nudged ) ;
2019-06-17 04:21:41 +00:00
}
2019-10-14 02:36:57 +00:00
else if ( movevars . coordtype = = COORDTYPE_FIXED_13_3 ) //1/8th precision, but don't truncate because that screws everything up.
2019-04-20 15:46:35 +00:00
{
for ( i = 0 ; i < 3 ; i + + )
{
2021-08-04 21:16:57 +00:00
/*if (pmove.velocity[i])
2021-04-14 05:21:04 +00:00
{ //round in the direction of velocity, which means we're less likely to get stuck.
if ( pmove . velocity [ i ] > = 0 )
2021-07-17 15:09:54 +00:00
nudged [ i ] = ( qintptr_t ) ( base [ i ] * 8 + 0.5f ) / 8.0 ;
2021-04-14 05:21:04 +00:00
else
2021-07-17 15:09:54 +00:00
nudged [ i ] = ( qintptr_t ) ( base [ i ] * 8 - 0.5f ) / 8.0 ;
2021-04-14 05:21:04 +00:00
}
2021-08-04 21:16:57 +00:00
else */
2021-04-14 05:21:04 +00:00
{
2021-07-17 15:09:54 +00:00
if ( base [ i ] > = 0 )
nudged [ i ] = ( qintptr_t ) ( base [ i ] * 8 + 0.5f ) / 8.0 ;
2021-04-14 05:21:04 +00:00
else
2021-07-17 15:09:54 +00:00
nudged [ i ] = ( qintptr_t ) ( base [ i ] * 8 - 0.5f ) / 8.0 ;
2021-04-14 05:21:04 +00:00
}
2019-04-20 15:46:35 +00:00
}
}
2019-03-01 22:39:30 +00:00
else for ( i = 0 ; i < 3 ; i + + )
2021-07-17 15:09:54 +00:00
nudged [ i ] = ( ( qintptr_t ) ( pmove . origin [ i ] * 8 ) ) * 0.125 ; //legacy compat, which biases towards the origin.
playdemo accepts https urls now. will start playing before the file has finished downloading, to avoid unnecessary delays.
reworked network addresses to separate address family and connection type. this should make banning people more reliable, as well as simplifying a whole load of logic (no need to check for ipv4 AND ipv6).
tcpconnect will keep trying to connect even if the connection wasn't instant, instead of giving up instantly.
rewrote tcp connections quite a bit. sv_port_tcp now handles qtv+qizmo+http+ws+rtcbroker+tls equivalents.
qtv_streamport is now a legacy cvar and now acts equivalently to sv_port_tcp (but still separate).
rewrote screenshot and video capture code to use strides. this solves image-is-upside down issues with vulkan.
ignore alt key in browser port. oh no! no more red text! oh no! no more alt-being-wrongly-down-and-being-unable-to-type-anything-without-forcing-alt-released!
reworked audio decoder interface. now has clearly defined success/unavailable/end-of-file results. this should solve a whole load of issues with audio streaming.
fixed various openal audio streaming issues too. openal also got some workarounds for emscripten's poor emulation.
fixed ogg decoder to retain sync properly if seeked.
updated menu_media a bit. now reads vorbis comments/id3v1 tags to get proper track names. also saves the playlist so you don't have to manually repopulate the list so it might actually be usable now (after how many years?)
r_stains now defaults to 0, and is no longer enabled by presets. use decals if you want that sort of thing.
added fs_noreexec cvar, so configs will not be reexeced on gamedir change. this also means defaults won't be reapplied, etc.
added 'nvvk' renderer on windows, using nvidia's vulkan-inside-opengl gl extension. mostly just to see how much slower it is.
fixed up the ftp server quite a lot. more complete, more compliant, and should do ipv6 properly to-boot. file transfers also threaded.
fixed potential crash inside runclientphys.
experimental sv_antilag=3 setting. totally untested. the aim is to avoid missing due to lagged knockbacks. may be expensive for the server.
browser port's websockets support fixed. experimental support for webrtc ('works for me', requires a broker server).
updated avplug(renamed to ffmpeg so people know what it is) to use ffmpeg 3.2.4 properly, with its new encoder api. should be much more robust... also added experimental audio decoder for game music etc (currently doesn't resample, so playback rates are screwed, disabled by cvar).
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5097 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-10 02:08:58 +00:00
// VectorCopy (base, pmove.origin);
2004-08-21 01:25:48 +00:00
2014-07-12 06:56:17 +00:00
//if we're moving, allow that spot without snapping to any grid
2015-05-03 19:57:46 +00:00
// if (pmove.velocity[0] || pmove.velocity[1] || pmove.velocity[2])
2019-03-01 22:39:30 +00:00
// if (PM_TestPlayerPosition (pmove.origin, false))
// return;
2013-03-12 22:53:23 +00:00
2021-04-14 05:21:04 +00:00
//this is potentially 27 tests, and required for qw compat...
//with unquantized floors it often succeeds only after 19 checks. which sucks.
added r_meshpitch cvar that allows for fixing the unfixable mesh pitch bug from vanilla... needs a better name... do note that this will break pretty much any mod, so this is really only for TCs designed to use it. Its likely that I missed places.
nqsv: added support for spectators with nq clients. the angles are a bit rough, but hey. need to do something about frags so nq clients know who's a spectator. use 'cmd observe' to get an nq client to spectate on an fte server (then attack/jump behave the same as in qw clients).
nqsv: rewrote EF_MUZZLEFLASH handling, so svc_muzzleflash is now translated properly to EF_MUZZLEFLASH, and vice versa. No more missing muzzleflashes!
added screenshot_cubemap, so you can actually pre-generate cubemaps with fte (which can be used for reflections or whatever).
misc fixes (server crash, a couple of other less important ones).
external files based on a model's name will now obey r_replacemodels properly, instead of needing to use foo.mdl_0.skin for foo.md3.
identify <playernum> should now use the correct masked ip, instead of abrubtly failing (reported by kt)
vid_toggle console command should now obey vid_width and vid_height when switching to fullscreen, but only if vid_fullscreen is actually set, which should make it seem better behaved (reported by kt).
qcc: cleaned up sym->symboldata[sym->ofs] to be more consistent at all stages.
qcc: typedef float vec4[4]; now works to define a float array with 4 elements (however, it will be passed by-value rather than by-reference).
qcc: cleaned up optional vs __out ordering issues.
qccgui: shift+f3 searches backwards
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5064 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-02-27 09:34:35 +00:00
for ( z = 0 ; z < countof ( sign ) ; z + + )
2004-08-21 01:25:48 +00:00
{
added r_meshpitch cvar that allows for fixing the unfixable mesh pitch bug from vanilla... needs a better name... do note that this will break pretty much any mod, so this is really only for TCs designed to use it. Its likely that I missed places.
nqsv: added support for spectators with nq clients. the angles are a bit rough, but hey. need to do something about frags so nq clients know who's a spectator. use 'cmd observe' to get an nq client to spectate on an fte server (then attack/jump behave the same as in qw clients).
nqsv: rewrote EF_MUZZLEFLASH handling, so svc_muzzleflash is now translated properly to EF_MUZZLEFLASH, and vice versa. No more missing muzzleflashes!
added screenshot_cubemap, so you can actually pre-generate cubemaps with fte (which can be used for reflections or whatever).
misc fixes (server crash, a couple of other less important ones).
external files based on a model's name will now obey r_replacemodels properly, instead of needing to use foo.mdl_0.skin for foo.md3.
identify <playernum> should now use the correct masked ip, instead of abrubtly failing (reported by kt)
vid_toggle console command should now obey vid_width and vid_height when switching to fullscreen, but only if vid_fullscreen is actually set, which should make it seem better behaved (reported by kt).
qcc: cleaned up sym->symboldata[sym->ofs] to be more consistent at all stages.
qcc: typedef float vec4[4]; now works to define a float array with 4 elements (however, it will be passed by-value rather than by-reference).
qcc: cleaned up optional vs __out ordering issues.
qccgui: shift+f3 searches backwards
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5064 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-02-27 09:34:35 +00:00
for ( x = 0 ; x < countof ( sign ) ; x + + )
2004-08-21 01:25:48 +00:00
{
added r_meshpitch cvar that allows for fixing the unfixable mesh pitch bug from vanilla... needs a better name... do note that this will break pretty much any mod, so this is really only for TCs designed to use it. Its likely that I missed places.
nqsv: added support for spectators with nq clients. the angles are a bit rough, but hey. need to do something about frags so nq clients know who's a spectator. use 'cmd observe' to get an nq client to spectate on an fte server (then attack/jump behave the same as in qw clients).
nqsv: rewrote EF_MUZZLEFLASH handling, so svc_muzzleflash is now translated properly to EF_MUZZLEFLASH, and vice versa. No more missing muzzleflashes!
added screenshot_cubemap, so you can actually pre-generate cubemaps with fte (which can be used for reflections or whatever).
misc fixes (server crash, a couple of other less important ones).
external files based on a model's name will now obey r_replacemodels properly, instead of needing to use foo.mdl_0.skin for foo.md3.
identify <playernum> should now use the correct masked ip, instead of abrubtly failing (reported by kt)
vid_toggle console command should now obey vid_width and vid_height when switching to fullscreen, but only if vid_fullscreen is actually set, which should make it seem better behaved (reported by kt).
qcc: cleaned up sym->symboldata[sym->ofs] to be more consistent at all stages.
qcc: typedef float vec4[4]; now works to define a float array with 4 elements (however, it will be passed by-value rather than by-reference).
qcc: cleaned up optional vs __out ordering issues.
qccgui: shift+f3 searches backwards
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5064 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-02-27 09:34:35 +00:00
for ( y = 0 ; y < countof ( sign ) ; y + + )
2004-08-21 01:25:48 +00:00
{
2021-07-17 15:09:54 +00:00
pmove . origin [ 0 ] = nudged [ 0 ] + sign [ x ] ;
pmove . origin [ 1 ] = nudged [ 1 ] + sign [ y ] ;
pmove . origin [ 2 ] = nudged [ 2 ] + sign [ z ] ;
2014-07-02 03:20:40 +00:00
if ( PM_TestPlayerPosition ( pmove . origin , false ) )
2004-08-21 01:25:48 +00:00
return ;
}
}
}
2014-08-17 03:32:48 +00:00
2021-04-14 05:21:04 +00:00
//still not managed it... be more agressive axially.
for ( z = 0 ; z < 3 ; z + + )
{
VectorCopy ( base , pmove . origin ) ;
2021-07-17 15:09:54 +00:00
pmove . origin [ z ] = nudged [ z ] + ( 2 / 8.0 ) ;
2021-04-14 05:21:04 +00:00
if ( PM_TestPlayerPosition ( pmove . origin , false ) )
return ;
VectorCopy ( base , pmove . origin ) ;
2021-07-17 15:09:54 +00:00
pmove . origin [ z ] = nudged [ z ] - ( 2 / 8.0 ) ;
2021-04-14 05:21:04 +00:00
if ( PM_TestPlayerPosition ( pmove . origin , false ) )
return ;
}
2014-08-17 03:32:48 +00:00
//be more aggresssive at moving up, to match NQ
2014-08-17 03:33:31 +00:00
for ( z = 1 ; z < movevars . stepheight ; z + + )
2014-08-17 03:32:48 +00:00
{
for ( x = 0 ; x < 3 ; x + + )
{
for ( y = 0 ; y < 3 ; y + + )
{
2021-07-17 15:09:54 +00:00
pmove . origin [ 0 ] = nudged [ 0 ] + sign [ x ] ;
pmove . origin [ 1 ] = nudged [ 1 ] + sign [ y ] ;
pmove . origin [ 2 ] = nudged [ 2 ] + z ;
2014-08-17 03:32:48 +00:00
if ( PM_TestPlayerPosition ( pmove . origin , false ) )
return ;
}
}
}
2021-06-25 18:50:42 +00:00
if ( pmove . safeorigin_known & & PM_TestPlayerPosition ( pmove . safeorigin , false ) )
2014-07-12 06:56:17 +00:00
VectorCopy ( pmove . safeorigin , pmove . origin ) ;
else
VectorCopy ( base , pmove . origin ) ;
2019-07-02 04:12:20 +00:00
// Con_DPrintf ("NudgePosition: stuck\n");
2004-08-21 01:25:48 +00:00
}
/*
= = = = = = = = = = = = = = =
PM_SpectatorMove
= = = = = = = = = = = = = = =
*/
void PM_SpectatorMove ( void )
{
float speed , drop , friction , control , newspeed ;
float currentspeed , addspeed , accelspeed ;
int i ;
vec3_t wishvel ;
float fmove , smove ;
vec3_t wishdir ;
float wishspeed ;
// friction
speed = Length ( pmove . velocity ) ;
if ( speed < 1 )
{
VectorClear ( pmove . velocity ) ;
}
else
{
drop = 0 ;
friction = movevars . friction * 1.5 ; // extra friction
control = speed < movevars . stopspeed ? movevars . stopspeed : speed ;
drop + = control * friction * frametime ;
// scale the velocity
newspeed = speed - drop ;
if ( newspeed < 0 )
newspeed = 0 ;
newspeed / = speed ;
VectorScale ( pmove . velocity , newspeed , pmove . velocity ) ;
}
// accelerate
fmove = pmove . cmd . forwardmove ;
smove = pmove . cmd . sidemove ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
VectorNormalize ( forward ) ;
VectorNormalize ( right ) ;
for ( i = 0 ; i < 3 ; i + + )
wishvel [ i ] = forward [ i ] * fmove + right [ i ] * smove ;
wishvel [ 2 ] + = pmove . cmd . upmove ;
VectorCopy ( wishvel , wishdir ) ;
wishspeed = VectorNormalize ( wishdir ) ;
//
// clamp to server defined max speed
//
if ( wishspeed > movevars . spectatormaxspeed )
{
VectorScale ( wishvel , movevars . spectatormaxspeed / wishspeed , wishvel ) ;
wishspeed = movevars . spectatormaxspeed ;
}
currentspeed = DotProduct ( pmove . velocity , wishdir ) ;
addspeed = wishspeed - currentspeed ;
// Buggy QW spectator mode, kept for compatibility
if ( pmove . pm_type = = PM_OLD_SPECTATOR )
{
if ( addspeed < = 0 )
return ;
}
if ( addspeed > 0 ) {
accelspeed = movevars . accelerate * frametime * wishspeed ;
if ( accelspeed > addspeed )
accelspeed = addspeed ;
2005-02-06 02:47:36 +00:00
2004-08-21 01:25:48 +00:00
for ( i = 0 ; i < 3 ; i + + )
2005-02-06 02:47:36 +00:00
pmove . velocity [ i ] + = accelspeed * wishdir [ i ] ;
2004-08-21 01:25:48 +00:00
}
// move
VectorMA ( pmove . origin , frametime , pmove . velocity , pmove . origin ) ;
}
/*
= = = = = = = = = = = = =
PM_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 .
= = = = = = = = = = = = =
*/
2005-03-20 02:57:11 +00:00
void PM_PlayerMove ( float gamespeed )
2004-08-21 01:25:48 +00:00
{
2015-06-04 06:15:14 +00:00
// int i;
// int tmp; //for rounding
2014-07-02 03:20:40 +00:00
2005-03-20 02:57:11 +00:00
frametime = pmove . cmd . msec * 0.001 * gamespeed ;
2004-08-21 01:25:48 +00:00
pmove . numtouch = 0 ;
2013-03-12 22:53:23 +00:00
if ( pmove . pm_type = = PM_NONE | | pmove . pm_type = = PM_FREEZE )
{
2004-08-21 01:25:48 +00:00
PM_CategorizePosition ( ) ;
return ;
}
// take angles directly from command
pmove . angles [ 0 ] = SHORT2ANGLE ( pmove . cmd . angles [ 0 ] ) ;
pmove . angles [ 1 ] = SHORT2ANGLE ( pmove . cmd . angles [ 1 ] ) ;
pmove . angles [ 2 ] = SHORT2ANGLE ( pmove . cmd . angles [ 2 ] ) ;
AngleVectors ( pmove . angles , forward , right , up ) ;
if ( pmove . pm_type = = PM_SPECTATOR | | pmove . pm_type = = PM_OLD_SPECTATOR )
{
PM_SpectatorMove ( ) ;
pmove . onground = false ;
return ;
}
PM_NudgePosition ( ) ;
// set onground, watertype, and waterlevel
PM_CategorizePosition ( ) ;
2021-05-09 13:00:30 +00:00
if ( movevars . autobunny & & ! pmove . onground )
pmove . jump_held = false ;
2004-08-21 01:25:48 +00:00
if ( pmove . waterlevel = = 2 & & pmove . pm_type ! = PM_FLY )
PM_CheckWaterJump ( ) ;
2012-07-05 19:42:36 +00:00
if ( - DotProduct ( pmove . gravitydir , pmove . velocity ) < 0 | | pmove . pm_type = = PM_DEAD )
2004-08-21 01:25:48 +00:00
pmove . waterjumptime = 0 ;
if ( pmove . waterjumptime )
{
pmove . waterjumptime - = frametime ;
if ( pmove . waterjumptime < 0 )
pmove . waterjumptime = 0 ;
}
if ( pmove . jump_msec )
{
pmove . jump_msec + = pmove . cmd . msec ;
if ( pmove . jump_msec > 50 )
pmove . jump_msec = 0 ;
}
2023-01-25 23:14:13 +00:00
if ( ! movevars . bunnyfriction )
PM_CheckJump ( ) ; //qw-style bunny
2004-08-21 01:25:48 +00:00
PM_Friction ( ) ;
if ( pmove . waterlevel > = 2 )
PM_WaterMove ( ) ;
2014-06-21 17:58:17 +00:00
else if ( pmove . pm_type = = PM_FLY | | pmove . pm_type = = PM_6DOF )
2004-08-21 01:25:48 +00:00
PM_FlyMove ( ) ;
else if ( pmove . onladder )
PM_LadderMove ( ) ;
else
PM_AirMove ( ) ;
2023-01-25 23:14:13 +00:00
if ( movevars . bunnyfriction )
PM_CheckJump ( ) ; //nq-style bunny. note tick rate differences too.
2015-06-04 06:15:14 +00:00
/* //round to network precision
2015-05-03 19:57:46 +00:00
for ( i = 0 ; i < 3 ; i + + )
{
tmp = floor ( pmove . velocity [ i ] * 8 + 0.5 ) ;
pmove . velocity [ i ] = tmp / 8.0 ;
tmp = floor ( pmove . origin [ i ] * 8 + 0.5 ) ;
pmove . origin [ i ] = tmp / 8.0 ;
}
PM_NudgePosition ( ) ;
2015-06-04 06:15:14 +00:00
*/
2004-08-21 01:25:48 +00:00
// set onground, watertype, and waterlevel for final spot
PM_CategorizePosition ( ) ;
2007-09-06 23:18:52 +00:00
// this is to make sure landing sound is not played twice
// and falling damage is calculated correctly
2019-03-01 22:39:30 +00:00
if ( ! movevars . pground & & pmove . onground & & - DotProduct ( pmove . gravitydir , pmove . velocity ) < - 300
2007-09-06 23:18:52 +00:00
& & DotProduct ( pmove . velocity , groundplane . normal ) < - 0.1 )
2004-08-21 01:25:48 +00:00
{
2007-09-06 23:18:52 +00:00
PM_ClipVelocity ( pmove . velocity , groundplane . normal , pmove . velocity , 1 ) ;
2004-08-21 01:25:48 +00:00
}
}