2007-09-17 22:00:00 +02:00
|
|
|
|
//=======================================================================
|
|
|
|
|
// Copyright XashXT Group 2007 <20>
|
|
|
|
|
// sv_physics.c - server physic
|
|
|
|
|
//=======================================================================
|
|
|
|
|
|
2008-06-09 22:00:00 +02:00
|
|
|
|
#include "common.h"
|
2007-09-17 22:00:00 +02:00
|
|
|
|
#include "server.h"
|
2008-11-25 22:00:00 +01:00
|
|
|
|
#include "matrix_lib.h"
|
2008-08-30 22:00:00 +02:00
|
|
|
|
#include "const.h"
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2007-09-17 22:00:00 +02:00
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
|
|
|
|
|
|
|
|
|
|
doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
|
|
|
|
|
bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
|
|
|
|
|
corpses are SOLID_NOT and MOVETYPE_TOSS
|
|
|
|
|
crates are SOLID_BBOX and MOVETYPE_TOSS
|
|
|
|
|
walking monsters are SOLID_BBOX and MOVETYPE_STEP
|
|
|
|
|
flying/floating monsters are SOLID_BBOX and MOVETYPE_FLY
|
|
|
|
|
|
|
|
|
|
solid_edge items only clip against bsp models.
|
2007-09-17 22:00:00 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
#define MOVE_EPSILON 0.01
|
|
|
|
|
#define MAX_CLIP_PLANES 32
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2007-09-28 22:00:00 +02:00
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
===============================================================================
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
LINE TESTING IN HULLS
|
|
|
|
|
|
|
|
|
|
===============================================================================
|
2007-09-28 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
int SV_ContentsMask( const edict_t *passedict )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( passedict )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( passedict->v.flags & FL_MONSTER )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return MASK_MONSTERSOLID;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
else if( passedict->v.flags & FL_CLIENT )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return MASK_PLAYERSOLID;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
else if( passedict->v.solid == SOLID_TRIGGER )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return CONTENTS_SOLID|CONTENTS_BODY;
|
|
|
|
|
return MASK_SOLID;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return MASK_SOLID;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
==================
|
|
|
|
|
SV_Trace
|
|
|
|
|
==================
|
2007-09-28 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, edict_t *passedict, int contentsmask )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
vec3_t hullmins, hullmaxs;
|
|
|
|
|
int i, bodycontents;
|
|
|
|
|
bool pointtrace;
|
|
|
|
|
edict_t *traceowner, *touch;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
trace_t trace;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
vec3_t clipboxmins, clipboxmaxs;// bounding box of entire move area
|
|
|
|
|
vec3_t clipmins, clipmaxs;// size of the moving object
|
|
|
|
|
vec3_t clipmins2, clipmaxs2;// size when clipping against monsters
|
|
|
|
|
vec3_t clipstart, clipend;// start and end origin of move
|
|
|
|
|
trace_t cliptrace;// trace results
|
|
|
|
|
matrix4x4 matrix, imatrix;// matrices to transform into/out of other entity's space
|
|
|
|
|
cmodel_t *model;// model of other entity
|
|
|
|
|
int numtouchedicts;// list of entities to test for collisions
|
|
|
|
|
edict_t *touchedicts[MAX_EDICTS];
|
|
|
|
|
|
|
|
|
|
VectorCopy( start, clipstart );
|
|
|
|
|
VectorCopy( end, clipend );
|
|
|
|
|
VectorCopy( mins, clipmins );
|
|
|
|
|
VectorCopy( maxs, clipmaxs );
|
|
|
|
|
VectorCopy( mins, clipmins2 );
|
|
|
|
|
VectorCopy( maxs, clipmaxs2 );
|
|
|
|
|
|
|
|
|
|
// clip to world
|
|
|
|
|
pe->ClipToWorld( &cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, contentsmask );
|
|
|
|
|
cliptrace.startstuck = cliptrace.startsolid;
|
|
|
|
|
if( cliptrace.startsolid || cliptrace.fraction < 1 )
|
2008-12-20 22:00:00 +01:00
|
|
|
|
cliptrace.ent = EDICT_NUM( 0 );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( type == MOVE_WORLDONLY )
|
|
|
|
|
return cliptrace;
|
|
|
|
|
|
|
|
|
|
if( type == MOVE_MISSILE )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// LordHavoc: modified this, was = -15, now -= 15
|
|
|
|
|
for( i = 0; i < 3; i++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
clipmins2[i] -= 15;
|
|
|
|
|
clipmaxs2[i] += 15;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( clipmins, hullmins );
|
|
|
|
|
VectorCopy( clipmaxs, hullmaxs );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// create the bounding box of the entire move
|
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
|
|
|
{
|
|
|
|
|
clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1;
|
|
|
|
|
clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1;
|
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-20 22:00:00 +01:00
|
|
|
|
// if the passedict is world, make it NULL (to avoid two checks each time)
|
|
|
|
|
if( passedict == EDICT_NUM( 0 )) passedict = NULL;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// figure out whether this is a point trace for comparisons
|
|
|
|
|
pointtrace = VectorCompare(clipmins, clipmaxs);
|
|
|
|
|
// precalculate passedict's owner edict pointer for comparisons
|
2008-12-17 22:00:00 +01:00
|
|
|
|
if( passedict && passedict->v.owner )
|
|
|
|
|
traceowner = passedict->v.owner;
|
|
|
|
|
else traceowner = NULL;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// clip to entities
|
2008-07-31 22:00:00 +02:00
|
|
|
|
// because this uses SV_AreaEdicts, we know all entity boxes overlap
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// the clip region, so we can skip culling checks in the loop below
|
2008-11-14 22:00:00 +01:00
|
|
|
|
numtouchedicts = SV_AreaEdicts( clipboxmins, clipboxmaxs, touchedicts, host.max_edicts, AREA_SOLID );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( numtouchedicts > host.max_edicts )
|
|
|
|
|
{
|
|
|
|
|
// this never happens
|
|
|
|
|
MsgDev( D_WARN, "SV_AreaEdicts returned %i edicts, max was %i\n", numtouchedicts, host.max_edicts );
|
|
|
|
|
numtouchedicts = host.max_edicts;
|
|
|
|
|
}
|
|
|
|
|
for( i = 0; i < numtouchedicts; i++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
touch = touchedicts[i];
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( touch->v.solid < SOLID_BBOX ) continue;
|
|
|
|
|
if( type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if( passedict )
|
|
|
|
|
{
|
|
|
|
|
// don't clip against self
|
|
|
|
|
if( passedict == touch ) continue;
|
|
|
|
|
// don't clip owned entities against owner
|
|
|
|
|
if( traceowner == touch ) continue;
|
|
|
|
|
// don't clip owner against owned entities
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( passedict == touch->v.owner ) continue;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// don't clip points against points (they can't collide)
|
2008-12-17 22:00:00 +01:00
|
|
|
|
if( pointtrace && VectorCompare( touch->v.mins, touch->v.maxs ) && (type != MOVE_MISSILE || !(touch->v.flags & FL_MONSTER)))
|
2008-07-30 22:00:00 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bodycontents = CONTENTS_BODY;
|
|
|
|
|
|
|
|
|
|
// might interact, so do an exact clip
|
|
|
|
|
model = NULL;
|
2008-12-17 22:00:00 +01:00
|
|
|
|
if( touch->v.solid == SOLID_BSP || type == MOVE_HITMODEL )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
uint modelindex = (uint)touch->v.modelindex;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// if the modelindex is 0, it shouldn't be SOLID_BSP!
|
|
|
|
|
if( modelindex > 0 && modelindex < MAX_MODELS )
|
2008-12-25 22:00:00 +01:00
|
|
|
|
model = sv.models[touch->v.modelindex];
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( model ) Matrix4x4_CreateFromEntity( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2], touch->v.angles[0], touch->v.angles[1], touch->v.angles[2], 1 );
|
|
|
|
|
else Matrix4x4_CreateTranslate( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2] );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
Matrix4x4_Invert_Simple( imatrix, matrix );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if((int)touch->v.flags & FL_MONSTER)
|
|
|
|
|
pe->ClipToGenericEntity(&trace, model, touch->v.mins, touch->v.maxs, bodycontents, matrix, imatrix, clipstart, clipmins2, clipmaxs2, clipend, contentsmask );
|
|
|
|
|
else pe->ClipToGenericEntity(&trace, model, touch->v.mins, touch->v.maxs, bodycontents, matrix, imatrix, clipstart, clipmins, clipmaxs, clipend, contentsmask );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pe->CombineTraces( &cliptrace, &trace, touch, touch->v.solid == SOLID_BSP );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return cliptrace;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int SV_PointContents( const vec3_t point )
|
|
|
|
|
{
|
|
|
|
|
int i, contents = 0;
|
|
|
|
|
edict_t *touch;
|
|
|
|
|
vec3_t transformed;
|
|
|
|
|
matrix4x4 matrix, imatrix; // matrices to transform into/out of other entity's space
|
|
|
|
|
cmodel_t *model; // model of other entity
|
|
|
|
|
uint modelindex;
|
|
|
|
|
int numtouchedicts; // list of entities to test for collisions
|
|
|
|
|
edict_t *touchedicts[MAX_EDICTS];
|
|
|
|
|
|
|
|
|
|
// get world supercontents at this point
|
|
|
|
|
if( sv.worldmodel && sv.worldmodel->PointContents )
|
|
|
|
|
contents = sv.worldmodel->PointContents( point, sv.worldmodel );
|
|
|
|
|
|
|
|
|
|
// get list of entities at this point
|
2008-11-14 22:00:00 +01:00
|
|
|
|
numtouchedicts = SV_AreaEdicts( point, point, touchedicts, host.max_edicts, AREA_SOLID );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( numtouchedicts > host.max_edicts )
|
|
|
|
|
{
|
|
|
|
|
// this never happens
|
|
|
|
|
MsgDev( D_WARN, "SV_AreaEdicts returned %i edicts, max was %i\n", numtouchedicts, host.max_edicts );
|
|
|
|
|
numtouchedicts = host.max_edicts;
|
|
|
|
|
}
|
|
|
|
|
for( i = 0; i < numtouchedicts; i++ )
|
|
|
|
|
{
|
|
|
|
|
touch = touchedicts[i];
|
|
|
|
|
|
|
|
|
|
// we only care about SOLID_BSP for pointcontents
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( touch->v.solid != SOLID_BSP ) continue;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// might interact, so do an exact clip
|
2008-12-15 22:00:00 +01:00
|
|
|
|
modelindex = (uint)touch->v.modelindex;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( modelindex >= MAX_MODELS ) continue;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
model = sv.models[(int)touch->v.modelindex];
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( !model || !model->PointContents ) continue;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
Matrix4x4_CreateFromEntity( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2], touch->v.angles[0], touch->v.angles[1], touch->v.angles[2], 1 );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
Matrix4x4_Invert_Simple( imatrix, matrix );
|
|
|
|
|
Matrix4x4_Transform( imatrix, point, transformed);
|
|
|
|
|
contents |= model->PointContents( transformed, model );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return contents;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
===============================================================================
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
Utility functions
|
|
|
|
|
|
|
|
|
|
===============================================================================
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
============
|
|
|
|
|
SV_TestEntityPosition
|
|
|
|
|
|
|
|
|
|
returns true if the entity is in solid currently
|
|
|
|
|
============
|
2007-09-28 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
static int SV_TestEntityPosition( edict_t *ent, vec3_t offset )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
vec3_t org;
|
|
|
|
|
trace_t trace;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorAdd( ent->v.origin, offset, org );
|
|
|
|
|
trace = SV_Trace( org, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NOMONSTERS, ent, CONTENTS_SOLID );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.startcontents & CONTENTS_SOLID )
|
|
|
|
|
return true;
|
|
|
|
|
// if the trace found a better position for the entity, move it there
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( VectorDistance2( trace.endpos, ent->v.origin ) >= 0.0001 )
|
|
|
|
|
VectorCopy( trace.endpos, ent->v.origin );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return false;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
SV_CheckAllEnts
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void SV_CheckAllEnts( void )
|
|
|
|
|
{
|
|
|
|
|
int e;
|
|
|
|
|
edict_t *check;
|
|
|
|
|
|
|
|
|
|
// see if any solid entities are inside the final position
|
2008-12-17 22:00:00 +01:00
|
|
|
|
check = EDICT_NUM( 1 );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
for( e = 1; e < svgame.globals->numEntities; e++, check++ )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( check->free ) continue;
|
|
|
|
|
switch( check->v.movetype )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
case MOVETYPE_PUSH:
|
|
|
|
|
case MOVETYPE_NONE:
|
|
|
|
|
case MOVETYPE_FOLLOW:
|
|
|
|
|
case MOVETYPE_NOCLIP:
|
|
|
|
|
continue;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(SV_TestEntityPosition( check, vec3_origin ))
|
|
|
|
|
MsgDev( D_INFO, "entity in invalid position\n" );
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
SV_CheckVelocity
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void SV_CheckVelocity( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
float wishspeed;
|
|
|
|
|
|
|
|
|
|
// bound velocity
|
2008-07-30 22:00:00 +02:00
|
|
|
|
for( i = 0; i < 3; i++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if(IS_NAN(ent->v.velocity[i]))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
MsgDev( D_INFO, "Got a NaN velocity on entity #%i (%s)\n", NUM_FOR_EDICT( ent ), STRING( ent->v.classname ));
|
|
|
|
|
ent->v.velocity[i] = 0;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if (IS_NAN(ent->v.origin[i]))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
MsgDev( D_INFO, "Got a NaN origin on entity #%i (%s)\n", NUM_FOR_EDICT( ent ), STRING( ent->v.classname ));
|
|
|
|
|
ent->v.origin[i] = 0;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
|
2008-12-15 22:00:00 +01:00
|
|
|
|
wishspeed = DotProduct( ent->v.velocity, ent->v.velocity );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( wishspeed > sv_maxvelocity->value * sv_maxvelocity->value )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
wishspeed = sv_maxvelocity->value / sqrt(wishspeed);
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.velocity[0] *= wishspeed;
|
|
|
|
|
ent->v.velocity[1] *= wishspeed;
|
|
|
|
|
ent->v.velocity[2] *= wishspeed;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
=============
|
|
|
|
|
SV_RunThink
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
Runs thinking code if time. There is some play in the exact time the think
|
|
|
|
|
function will be called, because it is called before any movement is done
|
|
|
|
|
in a frame. Not used for pushmove objects, because they must be exact.
|
|
|
|
|
Returns false if the entity removed itself.
|
|
|
|
|
=============
|
2007-09-28 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
bool SV_RunThink( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
int iterations;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// don't let things stay in the past.
|
|
|
|
|
// it is possible to start that way by a trigger with a local time.
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( ent->v.nextthink <= 0 || ent->v.nextthink > sv.time + svgame.globals->frametime )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return true;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
for( iterations = 0; iterations < 128 && !ent->free; iterations++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = max( sv.time, ent->v.nextthink );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.nextthink = 0;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.dllFuncs.pfnThink( ent );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// mods often set nextthink to time to cause a think every frame,
|
|
|
|
|
// we don't want to loop in that case, so exit if the new nextthink is
|
2008-12-03 22:00:00 +01:00
|
|
|
|
// <= the time the qc was told, also exit if it is past the end of the frame
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( ent->v.nextthink <= svgame.globals->time || ent->v.nextthink > sv.time + svgame.globals->frametime )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
break;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return !ent->free;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==================
|
|
|
|
|
SV_Impact
|
|
|
|
|
|
|
|
|
|
Two entities have touched, so run their touch functions
|
|
|
|
|
==================
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_Impact( edict_t *e1, trace_t *trace )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
edict_t *e2 = trace->ent;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
SV_CopyTraceToGlobal( trace );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( !e1->free && !e2->free && e1->v.solid != SOLID_NOT )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.dllFuncs.pfnTouch( e1, e2 );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( !e1->free && !e2->free && e2->v.solid != SOLID_NOT )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorCopy( e2->v.origin, svgame.globals->trace_endpos );
|
|
|
|
|
VectorNegate( trace->plane.normal, svgame.globals->trace_plane_normal );
|
|
|
|
|
svgame.globals->trace_plane_dist = -trace->plane.dist;
|
|
|
|
|
svgame.globals->trace_ent = e1;
|
|
|
|
|
svgame.dllFuncs.pfnTouch( e2, e1 );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
============
|
2008-07-31 22:00:00 +02:00
|
|
|
|
SV_TouchTriggers
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-31 22:00:00 +02:00
|
|
|
|
called by player or monster
|
2007-09-28 22:00:00 +02:00
|
|
|
|
============
|
|
|
|
|
*/
|
2008-07-31 22:00:00 +02:00
|
|
|
|
void SV_TouchTriggers( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-31 22:00:00 +02:00
|
|
|
|
int i, num;
|
|
|
|
|
edict_t *touch[MAX_EDICTS];
|
|
|
|
|
|
|
|
|
|
// dead things don't activate triggers!
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if(!(ent->v.flags & FL_CLIENT) && (ent->v.health <= 0))
|
2008-07-31 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
num = SV_AreaEdicts( ent->v.absmin, ent->v.absmax, touch, host.max_edicts, AREA_TRIGGERS );
|
2008-07-31 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// be careful, it is possible to have an entity in this
|
|
|
|
|
// list removed before we get to it (killtriggered)
|
|
|
|
|
for( i = 0; i < num; i++ )
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( touch[i]->free ) continue;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
|
|
|
|
svgame.dllFuncs.pfnTouch( touch[i], ent );
|
2008-07-31 22:00:00 +02:00
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-31 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
============
|
|
|
|
|
SV_ClampMove
|
|
|
|
|
|
|
|
|
|
clamp the move to 1/8 units, so the position will
|
|
|
|
|
be accurate for client side prediction
|
|
|
|
|
============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_ClampAngle( vec3_t angle )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-31 22:00:00 +02:00
|
|
|
|
angle[0] -= 360.0 * floor(angle[0] * (1.0 / 360.0));
|
|
|
|
|
angle[1] -= 360.0 * floor(angle[1] * (1.0 / 360.0));
|
|
|
|
|
angle[2] -= 360.0 * floor(angle[2] * (1.0 / 360.0));
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
==================
|
|
|
|
|
SV_ClipVelocity
|
|
|
|
|
|
|
|
|
|
Slide off of the impacting object
|
|
|
|
|
returns the blocked flags (1 = floor, 2 = step / wall)
|
|
|
|
|
==================
|
2007-09-28 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
int i;
|
|
|
|
|
float backoff;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
backoff = -DotProduct (in, normal) * overbounce;
|
|
|
|
|
VectorMA( in, backoff, normal, out );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
for( i = 0; i < 3; i++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON )
|
|
|
|
|
out[i] = 0;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
============
|
|
|
|
|
SV_FlyMove
|
|
|
|
|
|
|
|
|
|
The basic solid body movement clip that slides along multiple planes
|
|
|
|
|
Returns the clipflags if the velocity was modified (hit something solid)
|
|
|
|
|
1 = floor
|
|
|
|
|
2 = wall / step
|
|
|
|
|
4 = dead stop
|
|
|
|
|
If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
|
|
|
|
|
============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
int SV_FlyMove( edict_t *ent, float time, float *stepnormal, int contentsmask )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
int blocked = 0, bumpcount;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
int i, j, impact, numplanes;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
float d, time_left;
|
|
|
|
|
vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
|
|
|
|
|
trace_t trace;
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( time <= 0 ) return 0;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
VectorCopy( ent->v.velocity, original_velocity );
|
|
|
|
|
VectorCopy( ent->v.velocity, primal_velocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
numplanes = 0;
|
|
|
|
|
time_left = time;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
for( bumpcount = 0; bumpcount < MAX_CLIP_PLANES; bumpcount++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if(!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorMA( ent->v.origin, time_left, ent->v.velocity, end );
|
|
|
|
|
trace = SV_Trace( ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, contentsmask );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// break if it moved the entire distance
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.fraction == 1 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( trace.endpos, ent->v.origin );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( !trace.ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
MsgDev( D_WARN, "SV_FlyMove: trace.ent == NULL\n" );
|
2008-12-17 22:00:00 +01:00
|
|
|
|
trace.ent = EDICT_NUM( 0 );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
impact = !(ent->v.flags & FL_ONGROUND) || ent->v.groundentity != trace.ent;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.plane.normal[2] )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.plane.normal[2] > 0.7 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// floor
|
|
|
|
|
blocked |= 1;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.flags |= FL_ONGROUND;
|
|
|
|
|
ent->v.groundentity = trace.ent;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// step
|
|
|
|
|
blocked |= 2;
|
|
|
|
|
// save the trace for player extrafriction
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( stepnormal ) VectorCopy( trace.plane.normal, stepnormal );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.fraction >= 0.001 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// actually covered some distance
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( trace.endpos, ent->v.origin );
|
|
|
|
|
VectorCopy( ent->v.velocity, original_velocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
numplanes = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// run the impact function
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( impact )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Impact( ent, &trace );
|
|
|
|
|
|
2007-09-28 22:00:00 +02:00
|
|
|
|
// break if removed by the impact function
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->free ) break;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time_left *= 1 - trace.fraction;
|
|
|
|
|
|
|
|
|
|
// clipped to another plane
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( numplanes >= MAX_CLIP_PLANES )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// this shouldn't really happen
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorClear( ent->v.velocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
blocked = 3;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( trace.plane.normal, planes[numplanes] );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
numplanes++;
|
|
|
|
|
|
|
|
|
|
// modify original_velocity so it parallels all of the clip planes
|
2008-07-30 22:00:00 +02:00
|
|
|
|
for( i = 0; i < numplanes; i++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_ClipVelocity( original_velocity, planes[i], new_velocity, 1 );
|
|
|
|
|
for( j = 0; j < numplanes; j++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( j != i )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// not ok
|
|
|
|
|
if(DotProduct( new_velocity, planes[j] ) < 0 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( j == numplanes ) break;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( i != numplanes )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// go along this plane
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy(new_velocity, ent->v.velocity);
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// go along the crease
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( numplanes != 2 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorClear( ent->v.velocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
blocked = 7;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
CrossProduct( planes[0], planes[1], dir );
|
|
|
|
|
VectorNormalize( dir );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
d = DotProduct( dir, ent->v.velocity );
|
|
|
|
|
VectorScale( dir, d, ent->v.velocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if current velocity is against the original velocity,
|
|
|
|
|
// stop dead to avoid tiny occilations in sloping corners
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( DotProduct(ent->v.velocity, primal_velocity ) <= 0 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorClear( ent->v.velocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// this came from QW and allows you to get out of water more easily
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( ent->v.flags & FL_WATERJUMP )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( primal_velocity, ent->v.velocity );
|
2008-07-31 22:00:00 +02:00
|
|
|
|
|
2007-09-28 22:00:00 +02:00
|
|
|
|
return blocked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
============
|
|
|
|
|
SV_AddGravity
|
|
|
|
|
|
|
|
|
|
============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_AddGravity( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( ent->pvServerData->stuck )
|
|
|
|
|
{
|
|
|
|
|
VectorClear( ent->v.velocity );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( ent->v.gravity ) // gravity modifier
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->v.velocity[2] -= sv_gravity->value * ent->v.gravity * svgame.globals->frametime;
|
|
|
|
|
else ent->v.velocity[2] -= sv_gravity->value * svgame.globals->frametime;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
===============================================================================
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
PUSHMOVE
|
|
|
|
|
|
|
|
|
|
===============================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
============
|
|
|
|
|
SV_PushEntity
|
|
|
|
|
|
|
|
|
|
Does not change the entities velocity at all
|
|
|
|
|
============
|
2007-09-28 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
static trace_t SV_PushEntity( edict_t *ent, vec3_t push, bool failonstartstuck )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
int type;
|
|
|
|
|
trace_t trace;
|
|
|
|
|
vec3_t end;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorAdd( ent->v.origin, push, end );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
type = MOVE_NOMONSTERS; // only clip against bmodels
|
|
|
|
|
else type = MOVE_NORMAL;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
trace = SV_Trace( ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent, SV_ContentsMask( ent ));
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.startstuck && failonstartstuck )
|
|
|
|
|
return trace;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( trace.endpos, ent->v.origin );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.solid >= SOLID_TRIGGER && ent->v.solid < SOLID_BOX && trace.ent && (!(ent->v.flags & FL_ONGROUND) || ent->v.groundentity != trace.ent ))
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Impact( ent, &trace );
|
|
|
|
|
return trace;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
============
|
|
|
|
|
SV_PushMove
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
============
|
2007-09-28 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_PushMove( edict_t *pusher, float movetime )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
int i, e, index;
|
|
|
|
|
int checkcontents;
|
|
|
|
|
bool rotated;
|
|
|
|
|
float savesolid, movetime2, pushltime;
|
|
|
|
|
vec3_t mins, maxs, move, move1, moveangle;
|
|
|
|
|
vec3_t pushorig, pushang, a, forward, left, up, org;
|
|
|
|
|
int num_moved, numcheckentities;
|
|
|
|
|
static edict_t *checkentities[MAX_EDICTS];
|
|
|
|
|
cmodel_t *pushermodel;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
trace_t trace;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
matrix4x4 pusherfinalmatrix, pusherfinalimatrix;
|
|
|
|
|
word moved_edicts[MAX_EDICTS];
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2] && !pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pusher->v.ltime += movetime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
switch((int) pusher->v.solid )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
case SOLID_BSP:
|
|
|
|
|
case SOLID_BBOX:
|
|
|
|
|
break;
|
|
|
|
|
case SOLID_NOT:
|
|
|
|
|
case SOLID_TRIGGER:
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
|
|
|
|
|
VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
|
|
|
|
|
SV_ClampAngle( pusher->v.angles );
|
|
|
|
|
pusher->v.ltime += movetime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( pusher );
|
|
|
|
|
return;
|
|
|
|
|
default:
|
2008-12-15 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_PushMove: entity #%i, unrecognized solid type %f\n", NUM_FOR_EDICT( pusher ), pusher->v.solid );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
index = (int)pusher->v.modelindex;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( index < 1 || index >= MAX_MODELS )
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_PushMove: entity #%i has an invalid modelindex %f\n", NUM_FOR_EDICT( pusher ), pusher->v.modelindex );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pushermodel = sv.models[index];
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
rotated = VectorLength2(pusher->v.angles) + VectorLength2(pusher->v.avelocity) > 0;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
movetime2 = movetime;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorScale( pusher->v.velocity, movetime2, move1 );
|
|
|
|
|
VectorScale( pusher->v.avelocity, movetime2, moveangle );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( moveangle[0] || moveangle[2] )
|
|
|
|
|
{
|
|
|
|
|
for( i = 0; i < 3; i++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( move1[i] > 0 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
mins[i] = pushermodel->rotatedmins[i] + pusher->v.origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
else
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v.origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v.origin[i] + 1;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
else if( moveangle[1] )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
|
|
|
{
|
|
|
|
|
if( move1[i] > 0 )
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
mins[i] = pushermodel->yawmins[i] + pusher->v.origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v.origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->yawmaxs[i] + pusher->v.origin[i] + 1;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
else
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
for( i = 0; i < 3; i++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( move1[i] > 0 )
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
mins[i] = pushermodel->normalmins[i] + pusher->v.origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v.origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->normalmaxs[i] + pusher->v.origin[i] + 1;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorNegate( moveangle, a );
|
|
|
|
|
AngleVectorsFLU( a, forward, left, up );
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( pusher->v.origin, pushorig );
|
|
|
|
|
VectorCopy( pusher->v.angles, pushang );
|
|
|
|
|
pushltime = pusher->v.ltime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// move the pusher to its final position
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorMA( pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin );
|
|
|
|
|
VectorMA( pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles );
|
|
|
|
|
pusher->v.ltime += movetime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( pusher );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
pushermodel = NULL;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( pusher->v.modelindex >= 1 && pusher->v.modelindex < MAX_MODELS )
|
|
|
|
|
pushermodel = sv.models[(int)pusher->v.modelindex];
|
|
|
|
|
Matrix4x4_CreateFromEntity( pusherfinalmatrix, pusher->v.origin[0], pusher->v.origin[1], pusher->v.origin[2], pusher->v.angles[0], pusher->v.angles[1], pusher->v.angles[2], 1 );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
Matrix4x4_Invert_Simple( pusherfinalimatrix, pusherfinalmatrix );
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
savesolid = pusher->v.solid;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// see if any solid entities are inside the final position
|
|
|
|
|
num_moved = 0;
|
|
|
|
|
|
2008-11-14 22:00:00 +01:00
|
|
|
|
numcheckentities = SV_AreaEdicts( mins, maxs, checkentities, MAX_EDICTS, AREA_SOLID );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
for( e = 0; e < numcheckentities; e++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
edict_t *check = checkentities[e];
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
switch( check->v.movetype )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
case MOVETYPE_NONE:
|
|
|
|
|
case MOVETYPE_PUSH:
|
|
|
|
|
case MOVETYPE_FOLLOW:
|
|
|
|
|
case MOVETYPE_NOCLIP:
|
|
|
|
|
continue;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// tell any MOVETYPE_STEP entity that it may need to check for water transitions
|
2008-12-26 22:00:00 +01:00
|
|
|
|
check->pvServerData->forceupdate = true;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
checkcontents = SV_ContentsMask( check );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// if the entity is standing on the pusher, it will definitely be moved
|
|
|
|
|
// if the entity is not standing on the pusher, but is in the pusher's
|
|
|
|
|
// final position, move it
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if(!( check->v.flags & FL_ONGROUND) || check->v.groundentity != pusher )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pe->ClipToGenericEntity( &trace, pushermodel, pusher->v.mins, pusher->v.maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, checkcontents );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( !trace.startsolid ) continue;
|
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( rotated )
|
|
|
|
|
{
|
|
|
|
|
vec3_t org2;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorSubtract( check->v.origin, pusher->v.origin, org );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
org2[0] = DotProduct( org, forward );
|
|
|
|
|
org2[1] = DotProduct( org, left );
|
|
|
|
|
org2[2] = DotProduct( org, up );
|
|
|
|
|
VectorSubtract( org2, org, move );
|
|
|
|
|
VectorAdd( move, move1, move );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
VectorCopy( move1, move );
|
|
|
|
|
}
|
|
|
|
|
//Msg("- pushing %f %f %f\n", move[0], move[1], move[2]);
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorCopy (check->v.origin, check->pvServerData->moved_origin );
|
|
|
|
|
VectorCopy (check->v.angles, check->pvServerData->moved_angles );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
moved_edicts[num_moved++] = NUM_FOR_EDICT( check );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// try moving the contacted entity
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pusher->v.solid = SOLID_NOT;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
trace = SV_PushEntity( check, move, true );
|
|
|
|
|
// FIXME: turn players specially
|
2008-12-15 22:00:00 +01:00
|
|
|
|
check->v.angles[1] += trace.fraction * moveangle[1];
|
|
|
|
|
pusher->v.solid = savesolid; // was SOLID_BSP
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// this trace.fraction < 1 check causes items to fall off of pushers
|
|
|
|
|
// if they pass under or through a wall
|
|
|
|
|
// the groundentity check causes items to fall off of ledges
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( check->v.movetype != MOVETYPE_WALK && (trace.fraction < 1 || check->v.groundentity != pusher ))
|
|
|
|
|
check->v.flags &= ~FL_ONGROUND;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// if it is still inside the pusher, block
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pe->ClipToGenericEntity( &trace, pushermodel, pusher->v.mins, pusher->v.maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, checkcontents );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if (trace.startsolid)
|
|
|
|
|
{
|
|
|
|
|
// try moving the contacted entity a tiny bit further to account for precision errors
|
|
|
|
|
vec3_t move2;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pusher->v.solid = SOLID_NOT;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorScale( move, 1.1f, move2 );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorCopy( check->pvServerData->moved_origin, check->v.origin );
|
|
|
|
|
VectorCopy( check->pvServerData->moved_angles, check->v.angles );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_PushEntity( check, move2, true );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pusher->v.solid = savesolid;
|
|
|
|
|
pe->ClipToGenericEntity( &trace, pushermodel, pusher->v.mins, pusher->v.maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, checkcontents );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.startsolid )
|
|
|
|
|
{
|
|
|
|
|
// try moving the contacted entity a tiny bit less to account for precision errors
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pusher->v.solid = SOLID_NOT;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorScale( move, 0.9, move2 );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorCopy( check->pvServerData->moved_origin, check->v.origin );
|
|
|
|
|
VectorCopy( check->pvServerData->moved_angles, check->v.angles );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_PushEntity( check, move2, true );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pusher->v.solid = savesolid;
|
|
|
|
|
pe->ClipToGenericEntity( &trace, pushermodel, pusher->v.mins, pusher->v.maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, checkcontents );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.startsolid )
|
|
|
|
|
{
|
|
|
|
|
// still inside pusher, so it's really blocked
|
|
|
|
|
|
|
|
|
|
// fail the move
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( check->v.mins[0] == check->v.maxs[0] ) continue;
|
|
|
|
|
if( check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// corpse
|
2008-12-15 22:00:00 +01:00
|
|
|
|
check->v.mins[0] = check->v.mins[1] = 0;
|
|
|
|
|
VectorCopy( check->v.mins, check->v.maxs );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( pushorig, pusher->v.origin );
|
|
|
|
|
VectorCopy( pushang, pusher->v.angles );
|
|
|
|
|
pusher->v.ltime = pushltime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( pusher );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// move back any entities we already moved
|
|
|
|
|
for( i = 0; i < num_moved; i++ )
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
edict_t *ed = EDICT_NUM( moved_edicts[i] );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorCopy( ed->pvServerData->moved_origin, ed->v.origin );
|
|
|
|
|
VectorCopy( ed->pvServerData->moved_angles, ed->v.angles );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ed );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.dllFuncs.pfnBlocked( pusher, check );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
SV_ClampAngle( pusher->v.angles );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2007-09-17 22:00:00 +02:00
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
================
|
|
|
|
|
SV_Physics_Pusher
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
================
|
2007-09-17 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_Physics_Pusher( edict_t *ent )
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
float thinktime, oldltime, movetime;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
oldltime = ent->v.ltime;
|
|
|
|
|
thinktime = ent->v.nextthink;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( thinktime < ent->v.ltime + svgame.globals->frametime )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
movetime = thinktime - ent->v.ltime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( movetime < 0 ) movetime = 0;
|
|
|
|
|
}
|
2008-12-26 22:00:00 +01:00
|
|
|
|
else movetime = svgame.globals->frametime;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// advances ent->v.ltime if not blocked
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( movetime ) SV_PushMove( ent, movetime );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( thinktime > oldltime && thinktime <= ent->v.ltime )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.nextthink = 0;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
|
|
|
|
svgame.dllFuncs.pfnThink( ent );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-07-30 22:00:00 +02:00
|
|
|
|
===============================================================================
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
CLIENT MOVEMENT
|
|
|
|
|
|
|
|
|
|
===============================================================================
|
2007-09-17 22:00:00 +02:00
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
static float unstickoffsets[] =
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
-1, 0, 0, 1, 0, 0, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, -1, 0, -1, 1,
|
|
|
|
|
0, 1, 1, 0, 0, 0, -1, 0, 0, 1, 0, 0, -2, 0, 0, 2, 0, 0, -3, 0, 0, 3,
|
|
|
|
|
0, 0, -4, 0, 0, 4, 0, 0, -5, 0, 0, 5, 0, 0, -6, 0, 0, 6, 0, 0, -7,
|
|
|
|
|
0, 0, 7, 0, 0, -8, 0, 0, 8, 0, 0, -9, 0, 0, 9, 0, 0, -10, 0, 0, 10,
|
|
|
|
|
0, 0, -11, 0, 0, 11, 0, 0, -12, 0, 0, 12, 0, 0, -13, 0, 0, 13, 0, 0,
|
|
|
|
|
-14, 0, 0, 14, 0, 0, -15, 0, 0, 15, 0, 0, -16, 0, 0, 16, 0, 0, -17,
|
|
|
|
|
0, 0, 17,
|
|
|
|
|
};
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
SV_CheckStuck
|
|
|
|
|
|
|
|
|
|
This is a big hack to try and fix the rare case of getting stuck in the world
|
|
|
|
|
clipping hull.
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void SV_CheckStuck( edict_t *ent )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
vec3_t offset;
|
|
|
|
|
|
2008-08-10 22:00:00 +02:00
|
|
|
|
VectorClear( offset );
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( ent->v.flags & FL_DUCKING )
|
2008-08-10 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
offset[0] += 1;
|
|
|
|
|
offset[1] += 1;
|
|
|
|
|
offset[2] += 1;
|
|
|
|
|
}
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( !SV_TestEntityPosition( ent, offset ))
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( ent->v.origin, ent->v.oldorigin );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->stuck = false;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
for( i = 0; i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0])); i += 3 )
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if(!SV_TestEntityPosition( ent, unstickoffsets + i))
|
|
|
|
|
{
|
2008-12-20 22:00:00 +01:00
|
|
|
|
MsgDev( D_NOTE, "Unstuck player with offset %g %g %g.\n", unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]);
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->stuck = false;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorSubtract( ent->v.oldorigin, ent->v.origin, offset );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if(!SV_TestEntityPosition( ent, offset ))
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-12-20 22:00:00 +01:00
|
|
|
|
MsgDev( D_NOTE, "Unstuck player by restoring oldorigin.\n" );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->stuck = false;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
2007-09-17 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2008-12-26 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if( !ent->pvServerData->stuck )
|
|
|
|
|
MsgDev( D_ERROR, "Stuck player\n" ); // fire once
|
|
|
|
|
ent->pvServerData->stuck = true;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
bool SV_UnstickEntity( edict_t *ent )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// if not stuck in a bmodel, just return
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( !SV_TestEntityPosition( ent, vec3_origin ))
|
|
|
|
|
{
|
|
|
|
|
ent->pvServerData->stuck = false;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return true;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
for( i = 0; i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0])); i += 3 )
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if(!SV_TestEntityPosition( ent, unstickoffsets + i ))
|
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
MsgDev( D_NOTE, "Unstuck entity \"%s\" with offset %g %g %g.\n", STRING( ent->v.classname ), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2] );
|
|
|
|
|
ent->pvServerData->stuck = false;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( !ent->pvServerData->stuck )
|
|
|
|
|
MsgDev( D_ERROR, "Stuck entity \"%s\".\n", STRING( ent->v.classname ));
|
|
|
|
|
ent->pvServerData->stuck = true;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
SV_CheckWater
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
bool SV_CheckWater( edict_t *ent )
|
|
|
|
|
{
|
|
|
|
|
int cont;
|
|
|
|
|
vec3_t point;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
point[0] = ent->v.origin[0];
|
|
|
|
|
point[1] = ent->v.origin[1];
|
|
|
|
|
point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.waterlevel = 0;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
ent->v.watertype = CONTENTS_NONE;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
cont = SV_PointContents( point );
|
2008-12-21 22:00:00 +01:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( cont & (MASK_WATER))
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.watertype = cont;
|
|
|
|
|
ent->v.waterlevel = 1;
|
|
|
|
|
point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( SV_PointContents( point ) & MASK_WATER )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.waterlevel = 2;
|
|
|
|
|
point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( SV_PointContents( point ) & MASK_WATER )
|
2008-12-06 22:00:00 +01:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.waterlevel = 3;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( ent->pvServerData->s.ed_type == ED_CLIENT )
|
2008-12-21 22:00:00 +01:00
|
|
|
|
ent->v.renderfx |= RDF_UNDERWATER;
|
2008-12-06 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( ent->pvServerData->s.ed_type == ED_CLIENT )
|
2008-12-21 22:00:00 +01:00
|
|
|
|
ent->v.renderfx &= ~RDF_UNDERWATER;
|
2008-12-06 22:00:00 +01:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return ent->v.waterlevel > 1;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
============
|
|
|
|
|
SV_WallFriction
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
============
|
|
|
|
|
*/
|
|
|
|
|
void SV_WallFriction( edict_t *ent, float *stepnormal )
|
|
|
|
|
{
|
|
|
|
|
float d, i;
|
|
|
|
|
vec3_t forward, into, side;
|
|
|
|
|
|
2009-01-06 22:00:00 +01:00
|
|
|
|
AngleVectors( ent->v.viewangles, forward, NULL, NULL );
|
|
|
|
|
if(( d = DotProduct( stepnormal, forward ) + 0.5 ) < 0 )
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// cut the tangential velocity
|
2009-01-06 22:00:00 +01:00
|
|
|
|
i = DotProduct( stepnormal, ent->v.velocity );
|
|
|
|
|
VectorScale( stepnormal, i, into );
|
|
|
|
|
VectorSubtract( ent->v.velocity, into, side );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.velocity[0] = side[0] * (1 + d);
|
|
|
|
|
ent->v.velocity[1] = side[1] * (1 + d);
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=====================
|
|
|
|
|
SV_WalkMove
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
Only used by players
|
|
|
|
|
======================
|
|
|
|
|
*/
|
|
|
|
|
void SV_WalkMove( edict_t *ent )
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
int contentsmask;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
int clip, oldonground, originalmove_clip, originalmove_flags;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
vec3_t upmove, downmove, start_origin, start_velocity, stepnormal;
|
|
|
|
|
vec3_t originalmove_origin, originalmove_velocity;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
edict_t *originalmove_groundentity;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
trace_t downtrace;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// if frametime is 0 (due to client sending the same timestamp twice), don't move
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( svgame.globals->frametime <= 0 ) return;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
contentsmask = SV_ContentsMask( ent );
|
2008-07-31 22:00:00 +02:00
|
|
|
|
SV_CheckVelocity( ent );
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// do a regular slide move unless it looks like you ran into a step
|
2008-12-15 22:00:00 +01:00
|
|
|
|
oldonground = (ent->v.flags & FL_ONGROUND);
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( ent->v.origin, start_origin );
|
|
|
|
|
VectorCopy( ent->v.velocity, start_velocity );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
clip = SV_FlyMove( ent, svgame.globals->frametime, NULL, contentsmask );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// if the move did not hit the ground at any point, we're not on ground
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if(!(clip & 1)) ent->v.flags &= ~FL_ONGROUND;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( ent->v.origin, originalmove_origin );
|
|
|
|
|
VectorCopy( ent->v.velocity, originalmove_velocity );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
originalmove_clip = clip;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
originalmove_flags = ent->v.flags;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
originalmove_groundentity = ent->v.groundentity;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( ent->v.flags & FL_WATERJUMP )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// if move didn't block on a step, return
|
|
|
|
|
if( clip & 2 )
|
|
|
|
|
{
|
|
|
|
|
// if move was not trying to move into the step, return
|
|
|
|
|
if(fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
|
|
|
|
|
return;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.movetype != MOVETYPE_FLY )
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// return if gibbed by a trigger
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.movetype != MOVETYPE_WALK )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// only step up while jumping if that is enabled
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( !oldonground && ent->v.waterlevel == 0 )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// try moving up and forward to go up a step
|
|
|
|
|
// back to start pos
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( start_origin, ent->v.origin );
|
|
|
|
|
VectorCopy( start_velocity, ent->v.velocity );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// move up
|
|
|
|
|
VectorClear( upmove );
|
|
|
|
|
upmove[2] = sv_stepheight->value;
|
|
|
|
|
|
|
|
|
|
SV_PushEntity( ent, upmove, false ); // FIXME: don't link?
|
|
|
|
|
|
|
|
|
|
// move forward
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.velocity[2] = 0;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
clip = SV_FlyMove( ent, svgame.globals->frametime, stepnormal, contentsmask );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.velocity[2] += start_velocity[2];
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_CheckVelocity( ent );
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// check for stuckness, possibly due to the limited precision of floats
|
|
|
|
|
// in the clipping hulls
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( clip && fabs(originalmove_origin[1] - ent->v.origin[1]) < 0.03125 && fabs(originalmove_origin[0] - ent->v.origin[0]) < 0.03125 )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// stepping up didn't make any progress, revert to original move
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( originalmove_origin, ent->v.origin );
|
|
|
|
|
VectorCopy( originalmove_velocity, ent->v.velocity );
|
2008-12-21 22:00:00 +01:00
|
|
|
|
ent->v.flags = originalmove_flags;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.groundentity = originalmove_groundentity;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// extra friction based on view angle
|
|
|
|
|
if( clip & 2 ) SV_WallFriction( ent, stepnormal );
|
|
|
|
|
}
|
|
|
|
|
// don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
|
2008-12-15 22:00:00 +01:00
|
|
|
|
else if( ent->v.waterlevel >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || (ent->v.flags & FL_ONGROUND))
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// move down
|
|
|
|
|
VectorClear( downmove );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
downmove[2] = -sv_stepheight->value + start_velocity[2] * svgame.globals->frametime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
downtrace = SV_PushEntity( ent, downmove, false ); // FIXME: don't link?
|
|
|
|
|
|
|
|
|
|
if( downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7 )
|
|
|
|
|
{
|
|
|
|
|
// this has been disabled so that you can't jump when you are stepping
|
|
|
|
|
// up while already jumping (also known as the Quake2 double jump bug)
|
|
|
|
|
#if 0
|
|
|
|
|
// LordHavoc: disabled this check so you can walk on monsters/players
|
2008-12-15 22:00:00 +01:00
|
|
|
|
//if (ent->v.solid == SOLID_BSP)
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
//Con_Printf("onground\n");
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.flags |= FL_ONGROUND;
|
|
|
|
|
ent->v.groundentity = downtrace.ent;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
#endif
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// if the push down didn't end up on good ground, use the move without
|
|
|
|
|
// the step up. This happens near wall / slope combinations, and can
|
|
|
|
|
// cause the player to hop up higher on a slope too steep to climb
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( originalmove_origin, ent->v.origin );
|
|
|
|
|
VectorCopy( originalmove_velocity, ent->v.velocity );
|
2008-12-21 22:00:00 +01:00
|
|
|
|
ent->v.flags = originalmove_flags;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.groundentity = originalmove_groundentity;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
SV_CheckVelocity( ent );
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
//============================================================================
|
|
|
|
|
|
2007-09-28 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Physics_Follow
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
Entities that are "stuck" to another entity
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_Physics_Follow( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
vec3_t vf, vr, vu, angles, v;
|
|
|
|
|
edict_t *e;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// regular thinking
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if(!SV_RunThink( ent )) return;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
e = ent->v.aiment;
|
|
|
|
|
if(VectorCompare( e->v.angles, ent->v.punchangle ))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// quick case for no rotation
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorAdd( e->v.origin, ent->v.view_ofs, ent->v.origin );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
angles[0] = -ent->v.punchangle[0];
|
|
|
|
|
angles[1] = ent->v.punchangle[1];
|
|
|
|
|
angles[2] = ent->v.punchangle[2];
|
2008-07-30 22:00:00 +02:00
|
|
|
|
AngleVectors( angles, vf, vr, vu );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
|
|
|
|
|
v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
|
|
|
|
|
v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
|
|
|
|
|
angles[0] = -e->v.angles[0];
|
|
|
|
|
angles[1] = e->v.angles[1];
|
|
|
|
|
angles[2] = e->v.angles[2];
|
2008-07-30 22:00:00 +02:00
|
|
|
|
AngleVectors( angles, vf, vr, vu );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
|
|
|
|
|
ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
|
|
|
|
|
ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2009-01-06 22:00:00 +01:00
|
|
|
|
VectorAdd( e->v.angles, ent->v.viewangles, ent->v.angles );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============================================================================
|
|
|
|
|
|
|
|
|
|
TOSS / BOUNCE
|
|
|
|
|
|
|
|
|
|
==============================================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
SV_CheckWaterTransition
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_CheckWaterTransition( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
int cont = SV_PointContents( ent->v.origin );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( !ent->v.watertype )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// just spawned here
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.watertype = cont;
|
|
|
|
|
ent->v.waterlevel = 1;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if the entity crossed into or out of water
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.watertype & MASK_WATER )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-21 22:00:00 +01:00
|
|
|
|
//Msg( "water splash!\n" );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
//SV_StartSound (ent, 0, "", 255, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( cont <= CONTENTS_WATER )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.watertype = cont;
|
|
|
|
|
ent->v.waterlevel = 1;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.watertype = 0;
|
|
|
|
|
ent->v.waterlevel = 0;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Physics_Toss
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
Toss, bounce, and fly movement. When onground, do nothing.
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_Physics_Toss( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
trace_t trace;
|
|
|
|
|
vec3_t move;
|
|
|
|
|
|
|
|
|
|
// if onground, return without moving
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.flags & FL_ONGROUND )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.velocity[2] >= (1.0 / 32.0))
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// don't stick to ground if onground and moving upward
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.flags &= FL_ONGROUND;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
else if( !ent->v.groundentity )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// we can trust FL_ONGROUND if groundentity is world because it never moves
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2008-12-26 22:00:00 +01:00
|
|
|
|
else if( ent->pvServerData->suspended && ent->v.groundentity->free )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// if ent was supported by a brush model on previous frame,
|
|
|
|
|
// and groundentity is now freed, set groundentity to 0 (world)
|
|
|
|
|
// which leaves it suspended in the air
|
2008-12-17 22:00:00 +01:00
|
|
|
|
ent->v.groundentity = EDICT_NUM( 0 );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->suspended = false;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_CheckVelocity( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// add gravity
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.movetype == MOVETYPE_TOSS || ent->v.movetype == MOVETYPE_BOUNCE )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_AddGravity( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// move angles
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorMA( ent->v.angles, svgame.globals->frametime, ent->v.avelocity, ent->v.angles );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// move origin
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorScale( ent->v.velocity, svgame.globals->frametime, move );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
trace = SV_PushEntity( ent, move, true );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->free ) return;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.startstuck )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// try to unstick the entity
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_UnstickEntity( ent );
|
|
|
|
|
trace = SV_PushEntity( ent, move, false );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->free )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.fraction < 1 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.movetype == MOVETYPE_BOUNCE )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
float d;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.5 );
|
|
|
|
|
d = DotProduct( trace.plane.normal, ent->v.velocity );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.plane.normal[2] > 0.7 && fabs(d) < 60 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.flags |= FL_ONGROUND;
|
|
|
|
|
ent->v.groundentity = trace.ent;
|
|
|
|
|
VectorClear( ent->v.velocity );
|
|
|
|
|
VectorClear( ent->v.avelocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
else ent->v.flags &= ~FL_ONGROUND;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.0 );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.plane.normal[2] > 0.7 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.flags |= FL_ONGROUND;
|
|
|
|
|
ent->v.groundentity = trace.ent;
|
2008-12-17 22:00:00 +01:00
|
|
|
|
if( trace.ent && trace.ent->v.solid == SOLID_BSP )
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->suspended = true;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorClear( ent->v.velocity );
|
|
|
|
|
VectorClear( ent->v.avelocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
else ent->v.flags &= ~FL_ONGROUND;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check for in water
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_CheckWaterTransition( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
===============================================================================
|
|
|
|
|
|
|
|
|
|
STEPPING MOVEMENT
|
|
|
|
|
|
|
|
|
|
===============================================================================
|
|
|
|
|
*/
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Physics_Step
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
Monsters freefall when they don't have a ground entity, otherwise
|
|
|
|
|
all movement is done with discrete steps.
|
|
|
|
|
|
|
|
|
|
This is also used for objects that have become still on the ground, but
|
|
|
|
|
will fall if the floor is pulled out from under them.
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_Physics_Step( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-21 22:00:00 +01:00
|
|
|
|
int flags = ent->v.flags;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if(!(flags & (FL_FLY|FL_SWIM)))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.flags & FL_ONGROUND )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// freefall if onground and moving upward
|
|
|
|
|
// freefall if not standing on a world surface (it may be a lift or trap door)
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if(ent->v.velocity[2] >= (1.0 / 32.0) || ent->v.groundentity)
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.flags &= ~FL_ONGROUND;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_AddGravity( ent );
|
|
|
|
|
SV_CheckVelocity( ent );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
SV_FlyMove( ent, svgame.globals->frametime, NULL, SV_ContentsMask( ent ));
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->forceupdate = true;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// freefall if not onground
|
2008-12-15 22:00:00 +01:00
|
|
|
|
int hitsound = ent->v.velocity[2] < sv_gravity->value * -0.1;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_AddGravity( ent );
|
|
|
|
|
SV_CheckVelocity( ent );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
SV_FlyMove( ent, svgame.globals->frametime, NULL, SV_ContentsMask( ent ));
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// just hit ground
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( hitsound && ent->v.flags & FL_ONGROUND )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
Msg("Landing crash\n");
|
2007-09-28 22:00:00 +02:00
|
|
|
|
//SV_StartSound(ent, 0, sv_sound_land.string, 255, 1);
|
|
|
|
|
}
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->forceupdate = true;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// regular thinking
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if(!SV_RunThink( ent )) return;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( ent->pvServerData->forceupdate || !VectorCompare( ent->v.origin, ent->pvServerData->water_origin))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->forceupdate = false;
|
|
|
|
|
VectorCopy( ent->v.origin, ent->pvServerData->water_origin );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_CheckWaterTransition( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
====================
|
|
|
|
|
SV_Physics_Conveyor
|
|
|
|
|
|
|
|
|
|
REAL simple - all we do is check for player riders and adjust their position.
|
|
|
|
|
Only gotcha here is we have to make sure we don't end up embedding player in
|
|
|
|
|
*another* object that's being moved by the conveyor.
|
|
|
|
|
|
|
|
|
|
====================
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_Physics_Conveyor( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
edict_t *player;
|
|
|
|
|
int i;
|
|
|
|
|
trace_t tr;
|
|
|
|
|
vec3_t v, move;
|
|
|
|
|
vec3_t point, end;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorScale( ent->v.movedir, ent->v.speed, v );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorScale( v, 0.1f, move );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-31 22:00:00 +02:00
|
|
|
|
for( i = 0; i < Host_MaxClients(); i++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
player = EDICT_NUM(i) + 1;
|
|
|
|
|
if( player->free ) continue;
|
|
|
|
|
if( !player->v.groundentity ) continue;
|
|
|
|
|
if( player->v.groundentity != ent )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
continue;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// Look below player; make sure he's on a conveyor
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( player->v.origin, point );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
point[2] += 1;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( point, end );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
end[2] -= 256;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
tr = SV_Trace( point, player->v.mins, player->v.maxs, end, MOVE_NORMAL, player, MASK_SOLID );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
// tr.ent HAS to be conveyor, but just in case we screwed something up:
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( tr.ent == ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( tr.plane.normal[2] > 0 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
v[2] = ent->v.speed * com.sqrt( 1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2];
|
|
|
|
|
if(DotProduct( ent->v.movedir, tr.plane.normal) > 0)
|
2008-07-30 22:00:00 +02:00
|
|
|
|
v[2] = -v[2]; // then we're moving down
|
2007-09-28 22:00:00 +02:00
|
|
|
|
move[2] = v[2] * 0.1f;
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorAdd( player->v.origin, move, end );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
tr = SV_Trace( player->v.origin, player->v.mins, player->v.maxs, end, MOVE_NORMAL, player, player->pvServerData->clipmask );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( tr.endpos, player->v.origin );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( player );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
SV_PhysicsNoclip
|
|
|
|
|
|
|
|
|
|
A moving object that doesn't obey physics
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_Physics_Noclip( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// regular thinking
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if(SV_RunThink( ent ))
|
|
|
|
|
{
|
|
|
|
|
SV_CheckWater( ent );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorMA( ent->v.angles, svgame.globals->frametime, ent->v.avelocity, ent->v.angles );
|
|
|
|
|
VectorMA( ent->v.origin, svgame.globals->frametime, ent->v.velocity, ent->v.origin );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
2008-07-31 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
SV_PhysicsNone
|
|
|
|
|
|
|
|
|
|
Non moving objects can only think
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2008-07-30 22:00:00 +02:00
|
|
|
|
void SV_Physics_None( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + svgame.globals->frametime)
|
2007-09-28 22:00:00 +02:00
|
|
|
|
SV_RunThink (ent);
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
|
|
static void SV_Physics_Entity( edict_t *ent )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-17 22:00:00 +01:00
|
|
|
|
switch( ent->v.movetype )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
case MOVETYPE_PUSH:
|
|
|
|
|
SV_Physics_Pusher( ent );
|
|
|
|
|
break;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
case MOVETYPE_NONE:
|
2007-11-28 22:00:00 +01:00
|
|
|
|
case MOVETYPE_PHYSIC:
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Physics_None( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
case MOVETYPE_FOLLOW:
|
|
|
|
|
SV_Physics_Follow( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_NOCLIP:
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Physics_Noclip( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_STEP:
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Physics_Step( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_WALK:
|
2008-07-16 22:00:00 +02:00
|
|
|
|
if(SV_RunThink( ent ))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if(!SV_CheckWater( ent ) && !( ent->v.flags & FL_WATERJUMP ))
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_AddGravity( ent );
|
2008-07-16 22:00:00 +02:00
|
|
|
|
SV_CheckStuck( ent );
|
|
|
|
|
SV_WalkMove( ent );
|
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
case MOVETYPE_TOSS:
|
|
|
|
|
case MOVETYPE_BOUNCE:
|
|
|
|
|
case MOVETYPE_FLY:
|
|
|
|
|
if(SV_RunThink( ent )) SV_Physics_Toss( ent );
|
|
|
|
|
break;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
case MOVETYPE_CONVEYOR:
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_Physics_Conveyor( ent );
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.dllFuncs.pfnFrame( ent );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SV_Physics_ClientEntity( edict_t *ent )
|
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
sv_client_t *client = ent->pvServerData->client;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( !client ) return;//Host_Error( "SV_Physics_ClientEntity: tired to apply physic to a non-client entity\n" );
|
|
|
|
|
|
|
|
|
|
// don't do physics on disconnected clients, FrikBot relies on this
|
|
|
|
|
if( client->state != cs_spawned )
|
|
|
|
|
{
|
|
|
|
|
memset( &client->cmd, 0, sizeof(client->cmd));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// don't run physics here if running asynchronously
|
|
|
|
|
if( client->skipframes <= 0 ) SV_ClientThink( client, &client->cmd );
|
|
|
|
|
|
|
|
|
|
// make sure the velocity is sane (not a NaN)
|
|
|
|
|
SV_CheckVelocity( ent );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( DotProduct( ent->v.velocity, ent->v.velocity ) < 0.0001 )
|
|
|
|
|
VectorClear( ent->v.velocity );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// call standard client pre-think
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
|
|
|
|
svgame.dllFuncs.pfnPlayerPreThink( ent );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
switch((int)ent->v.movetype )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
case MOVETYPE_PUSH:
|
|
|
|
|
SV_Physics_Pusher( ent );
|
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_NONE:
|
|
|
|
|
case MOVETYPE_PHYSIC:
|
|
|
|
|
SV_Physics_None( ent );
|
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_FOLLOW:
|
|
|
|
|
SV_Physics_Follow( ent );
|
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_NOCLIP:
|
|
|
|
|
SV_RunThink( ent );
|
|
|
|
|
SV_CheckWater( ent );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorMA( ent->v.origin, svgame.globals->frametime, ent->v.velocity, ent->v.origin );
|
|
|
|
|
VectorMA( ent->v.angles, svgame.globals->frametime, ent->v.avelocity, ent->v.angles );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_STEP:
|
|
|
|
|
SV_Physics_Step( ent );
|
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_WALK:
|
|
|
|
|
SV_RunThink( ent );
|
|
|
|
|
// don't run physics here if running asynchronously
|
|
|
|
|
if( client->skipframes <= 0 )
|
|
|
|
|
{
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if(!SV_CheckWater( ent ) && !( ent->v.flags & FL_WATERJUMP) )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_AddGravity (ent);
|
|
|
|
|
SV_CheckStuck (ent);
|
|
|
|
|
SV_WalkMove (ent);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_TOSS:
|
|
|
|
|
case MOVETYPE_BOUNCE:
|
|
|
|
|
// regular thinking
|
|
|
|
|
SV_RunThink( ent );
|
|
|
|
|
SV_Physics_Toss( ent );
|
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_FLY:
|
|
|
|
|
SV_RunThink( ent );
|
|
|
|
|
SV_CheckWater( ent );
|
|
|
|
|
SV_WalkMove( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2008-12-21 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "SV_Physics_ClientEntity: bad movetype %i\n", ent->v.movetype );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// decrement the countdown variable used to decide when to go back to synchronous physics
|
|
|
|
|
if( client->skipframes > 0 ) client->skipframes--;
|
|
|
|
|
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.movetype != MOVETYPE_NOCLIP )
|
2008-07-31 22:00:00 +02:00
|
|
|
|
SV_TouchTriggers( ent );
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// call standard player post-think
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
|
|
|
|
svgame.dllFuncs.pfnPlayerPostThink( ent );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SV_Physics_ClientMove( sv_client_t *client, usercmd_t *cmd )
|
|
|
|
|
{
|
|
|
|
|
edict_t *ent = client->edict;
|
|
|
|
|
|
|
|
|
|
// call player physics, this needs the proper frametime
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->frametime = sv.frametime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_ClientThink( client, cmd );
|
|
|
|
|
|
|
|
|
|
// call standard client pre-think, with frametime = 0
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
|
|
|
|
svgame.globals->frametime = 0;
|
|
|
|
|
svgame.dllFuncs.pfnPlayerPreThink( ent );
|
|
|
|
|
svgame.globals->frametime = sv.frametime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
2008-11-28 22:00:00 +01:00
|
|
|
|
if( !sv_physics->integer )
|
|
|
|
|
{
|
|
|
|
|
// make sure the velocity is sane (not a NaN)
|
|
|
|
|
SV_CheckVelocity( ent );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( DotProduct(ent->v.velocity, ent->v.velocity) < 0.0001)
|
|
|
|
|
VectorClear( ent->v.velocity );
|
2008-12-03 22:00:00 +01:00
|
|
|
|
|
2008-12-20 22:00:00 +01:00
|
|
|
|
switch( ent->v.movetype )
|
2008-12-03 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
case MOVETYPE_WALK:
|
|
|
|
|
// perform MOVETYPE_WALK behavior
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if(!SV_CheckWater( ent ) && !( ent->v.flags & FL_WATERJUMP ))
|
2008-12-03 22:00:00 +01:00
|
|
|
|
SV_AddGravity( ent );
|
|
|
|
|
SV_CheckStuck( ent );
|
|
|
|
|
SV_WalkMove( ent );
|
|
|
|
|
break;
|
|
|
|
|
case MOVETYPE_NOCLIP:
|
|
|
|
|
SV_CheckWater( ent );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorMA( ent->v.origin, svgame.globals->frametime, ent->v.velocity, ent->v.origin );
|
|
|
|
|
VectorMA( ent->v.angles, svgame.globals->frametime, ent->v.avelocity, ent->v.angles );
|
2008-12-03 22:00:00 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
2008-11-28 22:00:00 +01:00
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
}
|
|
|
|
|
else SV_LinkEdict( ent );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.movetype != MOVETYPE_NOCLIP )
|
2008-07-31 22:00:00 +02:00
|
|
|
|
SV_TouchTriggers( ent );
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// call standard player post-think, with frametime = 0
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
|
|
|
|
svgame.globals->frametime = 0;
|
|
|
|
|
svgame.dllFuncs.pfnPlayerPostThink( ent );
|
|
|
|
|
svgame.globals->frametime = sv.frametime;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
SV_Physics
|
|
|
|
|
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void SV_Physics( void )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
edict_t *ent;
|
|
|
|
|
|
|
|
|
|
// let the progs know that a new frame has started
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
|
|
|
|
svgame.globals->frametime = sv.frametime;
|
|
|
|
|
svgame.dllFuncs.pfnStartFrame();
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// treat each object in turn
|
2008-12-26 22:00:00 +01:00
|
|
|
|
for( i = 1; i < svgame.globals->numEntities; i++ )
|
2008-07-30 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent = EDICT_NUM( i );
|
|
|
|
|
if( ent->free ) continue;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorCopy( ent->v.origin, ent->v.oldorigin );
|
2008-08-11 22:00:00 +02:00
|
|
|
|
if(i <= Host_MaxClients());// SV_Physics_ClientEntity( ent );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
else if( !sv_playersonly->integer ) SV_Physics_Entity( ent );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-08-01 22:00:00 +02:00
|
|
|
|
// let everything in the world think and move
|
2009-01-05 22:00:00 +01:00
|
|
|
|
pe->Frame( svgame.globals->frametime );
|
2008-12-20 22:00:00 +01:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->time = sv.time;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// at end of frame kill all entities which supposed to it
|
2008-12-26 22:00:00 +01:00
|
|
|
|
for( i = svgame.globals->maxClients + 1; i < svgame.globals->numEntities; i++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2008-12-17 22:00:00 +01:00
|
|
|
|
ent = EDICT_NUM( i );
|
|
|
|
|
if( ent->free ) continue;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( ent->v.flags & FL_KILLME )
|
|
|
|
|
SV_FreeEdict( EDICT_NUM( i ));
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.dllFuncs.pfnEndFrame();
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
// decrement svgame.globals->numEntities if the highest number entities died
|
|
|
|
|
for( ; EDICT_NUM( svgame.globals->numEntities - 1)->free; svgame.globals->numEntities-- );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( !sv_playersonly->integer ) sv.time += sv.frametime;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|