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-07-30 22:00:00 +02:00
|
|
|
|
#include "matrixlib.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-07-30 22:00:00 +02:00
|
|
|
|
if((int)passedict->progs.sv->flags & FL_MONSTER)
|
|
|
|
|
return MASK_MONSTERSOLID;
|
|
|
|
|
else if((int)passedict->progs.sv->flags & FL_CLIENT)
|
|
|
|
|
return MASK_PLAYERSOLID;
|
|
|
|
|
else if( passedict->progs.sv->solid == SOLID_TRIGGER )
|
|
|
|
|
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;
|
|
|
|
|
int passedictprog;
|
|
|
|
|
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 )
|
|
|
|
|
cliptrace.ent = prog->edicts;
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
// if the passedict is world, make it NULL (to avoid two checks each time)
|
|
|
|
|
if( passedict == prog->edicts ) passedict = NULL;
|
|
|
|
|
// precalculate prog value for passedict for comparisons
|
|
|
|
|
passedictprog = PRVM_EDICT_TO_PROG(passedict);
|
|
|
|
|
// figure out whether this is a point trace for comparisons
|
|
|
|
|
pointtrace = VectorCompare(clipmins, clipmaxs);
|
|
|
|
|
// precalculate passedict's owner edict pointer for comparisons
|
|
|
|
|
traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->progs.sv->owner) : 0;
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
numtouchedicts = SV_AreaEdicts( clipboxmins, clipboxmaxs, touchedicts, host.max_edicts );
|
|
|
|
|
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];
|
|
|
|
|
if( touch->progs.sv->solid < SOLID_BBOX ) continue;
|
|
|
|
|
if( type == MOVE_NOMONSTERS && touch->progs.sv->solid != SOLID_BSP )
|
|
|
|
|
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
|
|
|
|
|
if( passedictprog == touch->progs.sv->owner ) continue;
|
|
|
|
|
// don't clip points against points (they can't collide)
|
|
|
|
|
if( pointtrace && VectorCompare( touch->progs.sv->mins, touch->progs.sv->maxs ) && (type != MOVE_MISSILE || !((int)touch->progs.sv->flags & FL_MONSTER)))
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bodycontents = CONTENTS_BODY;
|
|
|
|
|
|
|
|
|
|
// might interact, so do an exact clip
|
|
|
|
|
model = NULL;
|
|
|
|
|
if((int)touch->progs.sv->solid == SOLID_BSP || type == MOVE_HITMODEL )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
uint modelindex = (uint)touch->progs.sv->modelindex;
|
|
|
|
|
// if the modelindex is 0, it shouldn't be SOLID_BSP!
|
|
|
|
|
if( modelindex > 0 && modelindex < MAX_MODELS )
|
|
|
|
|
model = sv.models[(int)touch->progs.sv->modelindex];
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( model ) Matrix4x4_CreateFromEntity( matrix, touch->progs.sv->origin[0], touch->progs.sv->origin[1], touch->progs.sv->origin[2], touch->progs.sv->angles[0], touch->progs.sv->angles[1], touch->progs.sv->angles[2], 1 );
|
|
|
|
|
else Matrix4x4_CreateTranslate( matrix, touch->progs.sv->origin[0], touch->progs.sv->origin[1], touch->progs.sv->origin[2] );
|
|
|
|
|
Matrix4x4_Invert_Simple( imatrix, matrix );
|
|
|
|
|
if((int)touch->progs.sv->flags & FL_MONSTER)
|
|
|
|
|
pe->ClipToGenericEntity(&trace, model, touch->progs.sv->mins, touch->progs.sv->maxs, bodycontents, matrix, imatrix, clipstart, clipmins2, clipmaxs2, clipend, contentsmask );
|
|
|
|
|
else pe->ClipToGenericEntity(&trace, model, touch->progs.sv->mins, touch->progs.sv->maxs, bodycontents, matrix, imatrix, clipstart, clipmins, clipmaxs, clipend, contentsmask );
|
|
|
|
|
|
|
|
|
|
pe->CombineTraces( &cliptrace, &trace, touch, touch->progs.sv->solid == SOLID_BSP );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
numtouchedicts = SV_AreaEdicts( point, point, touchedicts, host.max_edicts );
|
|
|
|
|
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
|
|
|
|
|
if( touch->progs.sv->solid != SOLID_BSP ) continue;
|
|
|
|
|
|
|
|
|
|
// might interact, so do an exact clip
|
|
|
|
|
modelindex = (uint)touch->progs.sv->modelindex;
|
|
|
|
|
if( modelindex >= MAX_MODELS ) continue;
|
|
|
|
|
model = sv.models[(int)touch->progs.sv->modelindex];
|
|
|
|
|
if( !model || !model->PointContents ) continue;
|
|
|
|
|
Matrix4x4_CreateFromEntity( matrix, touch->progs.sv->origin[0], touch->progs.sv->origin[1], touch->progs.sv->origin[2], touch->progs.sv->angles[0], touch->progs.sv->angles[1], touch->progs.sv->angles[2], 1 );
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
VectorAdd( ent->progs.sv->origin, offset, org );
|
|
|
|
|
trace = SV_Trace( org, ent->progs.sv->mins, ent->progs.sv->maxs, ent->progs.sv->origin, MOVE_NOMONSTERS, ent, CONTENTS_SOLID );
|
|
|
|
|
if( trace.startcontents & CONTENTS_SOLID )
|
|
|
|
|
return true;
|
|
|
|
|
// if the trace found a better position for the entity, move it there
|
|
|
|
|
if( VectorDistance2( trace.endpos, ent->progs.sv->origin ) >= 0.0001 )
|
|
|
|
|
VectorCopy( trace.endpos, ent->progs.sv->origin );
|
|
|
|
|
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
|
|
|
|
|
check = PRVM_NEXT_EDICT( prog->edicts );
|
|
|
|
|
for( e = 1; e < prog->num_edicts; e++, check = PRVM_NEXT_EDICT(check))
|
|
|
|
|
{
|
|
|
|
|
if( check->priv.sv->free ) continue;
|
|
|
|
|
switch((int)check->progs.sv->movetype )
|
|
|
|
|
{
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
if(IS_NAN(ent->progs.sv->velocity[i]))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
MsgDev( D_INFO, "Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(ent->progs.sv->classname));
|
2007-09-28 22:00:00 +02:00
|
|
|
|
ent->progs.sv->velocity[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
if (IS_NAN(ent->progs.sv->origin[i]))
|
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
MsgDev( D_INFO, "Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(ent->progs.sv->classname));
|
2007-09-28 22:00:00 +02:00
|
|
|
|
ent->progs.sv->origin[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
|
2008-07-30 22:00:00 +02:00
|
|
|
|
wishspeed = DotProduct( ent->progs.sv->velocity, ent->progs.sv->velocity );
|
|
|
|
|
if( wishspeed > sv_maxvelocity->value * sv_maxvelocity->value )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
wishspeed = sv_maxvelocity->value / sqrt(wishspeed);
|
|
|
|
|
ent->progs.sv->velocity[0] *= wishspeed;
|
|
|
|
|
ent->progs.sv->velocity[1] *= wishspeed;
|
|
|
|
|
ent->progs.sv->velocity[2] *= wishspeed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
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.
|
|
|
|
|
if( ent->progs.sv->nextthink <= 0 || ent->progs.sv->nextthink > sv.time + sv.frametime )
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
for( iterations = 0; iterations < 128 && !ent->priv.sv->free; iterations++ )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
prog->globals.sv->time = max( sv.time, ent->progs.sv->nextthink );
|
|
|
|
|
ent->progs.sv->nextthink = 0;
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent);
|
|
|
|
|
prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts);
|
|
|
|
|
PRVM_ExecuteProgram( ent->progs.sv->think, "pev->think" );
|
|
|
|
|
// 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
|
|
|
|
|
// <= the time the qc was told, also exit if it is past the end of the
|
|
|
|
|
// frame
|
|
|
|
|
if( ent->progs.sv->nextthink <= prog->globals.sv->time || ent->progs.sv->nextthink > sv.time + sv.frametime )
|
|
|
|
|
break;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
return !ent->priv.sv->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-07-30 22:00:00 +02:00
|
|
|
|
edict_t *e2 = (edict_t *)trace->ent;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
PRVM_PUSH_GLOBALS;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VM_SetTraceGlobals( trace );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2007-09-30 22:00:00 +02:00
|
|
|
|
prog->globals.sv->time = sv.time;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( !e1->priv.sv->free && !e2->priv.sv->free && e1->progs.sv->touch && e1->progs.sv->solid != SOLID_NOT )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2007-09-30 22:00:00 +02:00
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(e1);
|
|
|
|
|
prog->globals.sv->other = PRVM_EDICT_TO_PROG(e2);
|
2008-07-12 22:00:00 +02:00
|
|
|
|
PRVM_ExecuteProgram( e1->progs.sv->touch, "pev->touch" );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( !e1->priv.sv->free && !e2->priv.sv->free && e2->progs.sv->touch && e2->progs.sv->solid != SOLID_NOT )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2007-09-30 22:00:00 +02:00
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(e2);
|
|
|
|
|
prog->globals.sv->other = PRVM_EDICT_TO_PROG(e1);
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( e2->progs.sv->origin, prog->globals.sv->trace_endpos );
|
|
|
|
|
VectorNegate( trace->plane.normal, prog->globals.sv->trace_plane_normal );
|
|
|
|
|
prog->globals.sv->trace_plane_dist = -trace->plane.dist;
|
2007-09-30 22:00:00 +02:00
|
|
|
|
prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG(e1);
|
2008-07-30 22:00:00 +02:00
|
|
|
|
PRVM_ExecuteProgram( e2->progs.sv->touch, "pev->touch" );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
PRVM_POP_GLOBALS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
============
|
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!
|
|
|
|
|
if(!((int)ent->progs.sv->flags & FL_CLIENT) && (ent->progs.sv->health <= 0))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
num = SV_AreaEdicts( ent->progs.sv->absmin, ent->progs.sv->absmax, touch, host.max_edicts );
|
|
|
|
|
|
|
|
|
|
PRVM_PUSH_GLOBALS;
|
|
|
|
|
|
|
|
|
|
// 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++ )
|
|
|
|
|
{
|
|
|
|
|
if( touch[i]->priv.sv->free ) continue;
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(touch[i]);
|
|
|
|
|
prog->globals.sv->other = PRVM_EDICT_TO_PROG(ent);
|
|
|
|
|
prog->globals.sv->time = sv.time;
|
|
|
|
|
if(touch[i]->progs.sv->touch)
|
|
|
|
|
PRVM_ExecuteProgram( touch[i]->progs.sv->touch, "pev->touch");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// restore state
|
|
|
|
|
PRVM_POP_GLOBALS;
|
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;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
VectorCopy(ent->progs.sv->velocity, original_velocity);
|
|
|
|
|
VectorCopy(ent->progs.sv->velocity, primal_velocity);
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
if(!ent->progs.sv->velocity[0] && !ent->progs.sv->velocity[1] && !ent->progs.sv->velocity[2])
|
2007-09-28 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorMA( ent->progs.sv->origin, time_left, ent->progs.sv->velocity, end );
|
|
|
|
|
trace = SV_Trace( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->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-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( trace.endpos, ent->progs.sv->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" );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
trace.ent = prog->edicts;
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
impact = !((int)ent->progs.sv->aiflags & AI_ONGROUND) || ent->progs.sv->groundentity != PRVM_EDICT_TO_PROG(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-07-31 22:00:00 +02:00
|
|
|
|
ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( trace.endpos, ent->progs.sv->origin );
|
|
|
|
|
VectorCopy( ent->progs.sv->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-07-30 22:00:00 +02:00
|
|
|
|
if( ent->priv.sv->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-07-30 22:00:00 +02:00
|
|
|
|
VectorClear( ent->progs.sv->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
|
|
|
|
|
VectorCopy(new_velocity, ent->progs.sv->velocity);
|
|
|
|
|
}
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
VectorClear( ent->progs.sv->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 );
|
|
|
|
|
d = DotProduct( dir, ent->progs.sv->velocity );
|
|
|
|
|
VectorScale( dir, d, ent->progs.sv->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-07-30 22:00:00 +02:00
|
|
|
|
if( DotProduct(ent->progs.sv->velocity, primal_velocity ) <= 0 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorClear( ent->progs.sv->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
|
|
|
|
|
if(((int)ent->progs.sv->aiflags & AI_WATERJUMP))
|
|
|
|
|
VectorCopy( primal_velocity, ent->progs.sv->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-07-31 22:00:00 +02:00
|
|
|
|
if( ent->progs.sv->gravity )
|
|
|
|
|
ent->progs.sv->velocity[2] -= ent->progs.sv->gravity * sv.frametime;
|
|
|
|
|
else ent->progs.sv->velocity[2] -= sv_gravity->value * sv.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-07-30 22:00:00 +02:00
|
|
|
|
VectorAdd( ent->progs.sv->origin, push, end );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( ent->progs.sv->solid == SOLID_TRIGGER || ent->progs.sv->solid == SOLID_NOT )
|
|
|
|
|
type = MOVE_NOMONSTERS; // only clip against bmodels
|
|
|
|
|
else type = MOVE_NORMAL;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
trace = SV_Trace( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, end, type, ent, SV_ContentsMask( ent ));
|
|
|
|
|
if( trace.startstuck && failonstartstuck )
|
|
|
|
|
return trace;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( trace.endpos, ent->progs.sv->origin );
|
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
|
|
|
|
|
if( ent->progs.sv->solid >= SOLID_TRIGGER && ent->progs.sv->solid < SOLID_BOX && trace.ent && (!((int)ent->progs.sv->aiflags & AI_ONGROUND) || ent->progs.sv->groundentity != PRVM_EDICT_TO_PROG(trace.ent)))
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
if (!pusher->progs.sv->velocity[0] && !pusher->progs.sv->velocity[1] && !pusher->progs.sv->velocity[2] && !pusher->progs.sv->avelocity[0] && !pusher->progs.sv->avelocity[1] && !pusher->progs.sv->avelocity[2])
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
pusher->progs.sv->ltime += movetime;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch((int) pusher->progs.sv->solid )
|
|
|
|
|
{
|
|
|
|
|
case SOLID_BSP:
|
|
|
|
|
case SOLID_BBOX:
|
|
|
|
|
break;
|
|
|
|
|
case SOLID_NOT:
|
|
|
|
|
case SOLID_TRIGGER:
|
|
|
|
|
VectorMA (pusher->progs.sv->origin, movetime, pusher->progs.sv->velocity, pusher->progs.sv->origin);
|
|
|
|
|
VectorMA (pusher->progs.sv->angles, movetime, pusher->progs.sv->avelocity, pusher->progs.sv->angles);
|
|
|
|
|
SV_ClampAngle( pusher->progs.sv->angles );
|
|
|
|
|
pusher->progs.sv->ltime += movetime;
|
|
|
|
|
SV_LinkEdict( pusher );
|
|
|
|
|
return;
|
|
|
|
|
default:
|
|
|
|
|
MsgDev( D_WARN, "SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->progs.sv->solid );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
index = (int)pusher->progs.sv->modelindex;
|
|
|
|
|
if( index < 1 || index >= MAX_MODELS )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->progs.sv->modelindex );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pushermodel = sv.models[index];
|
|
|
|
|
|
|
|
|
|
rotated = VectorLength2(pusher->progs.sv->angles) + VectorLength2(pusher->progs.sv->avelocity) > 0;
|
|
|
|
|
|
|
|
|
|
movetime2 = movetime;
|
|
|
|
|
VectorScale( pusher->progs.sv->velocity, movetime2, move1 );
|
|
|
|
|
VectorScale( pusher->progs.sv->avelocity, movetime2, moveangle );
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
mins[i] = pushermodel->rotatedmins[i] + pusher->progs.sv->origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->progs.sv->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-07-30 22:00:00 +02:00
|
|
|
|
mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->progs.sv->origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->rotatedmaxs[i] + pusher->progs.sv->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 )
|
|
|
|
|
{
|
|
|
|
|
mins[i] = pushermodel->yawmins[i] + pusher->progs.sv->origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->progs.sv->origin[i] + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->progs.sv->origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->yawmaxs[i] + pusher->progs.sv->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-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 )
|
|
|
|
|
{
|
|
|
|
|
mins[i] = pushermodel->normalmins[i] + pusher->progs.sv->origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->progs.sv->origin[i] + 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->progs.sv->origin[i] - 1;
|
|
|
|
|
maxs[i] = pushermodel->normalmaxs[i] + pusher->progs.sv->origin[i] + 1;
|
|
|
|
|
}
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorNegate( moveangle, a );
|
|
|
|
|
AngleVectorsFLU( a, forward, left, up );
|
|
|
|
|
|
|
|
|
|
VectorCopy( pusher->progs.sv->origin, pushorig );
|
|
|
|
|
VectorCopy( pusher->progs.sv->angles, pushang );
|
|
|
|
|
pushltime = pusher->progs.sv->ltime;
|
|
|
|
|
|
|
|
|
|
// move the pusher to its final position
|
|
|
|
|
VectorMA( pusher->progs.sv->origin, movetime, pusher->progs.sv->velocity, pusher->progs.sv->origin );
|
|
|
|
|
VectorMA( pusher->progs.sv->angles, movetime, pusher->progs.sv->avelocity, pusher->progs.sv->angles );
|
|
|
|
|
pusher->progs.sv->ltime += movetime;
|
|
|
|
|
SV_LinkEdict( pusher );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
pushermodel = NULL;
|
|
|
|
|
if( pusher->progs.sv->modelindex >= 1 && pusher->progs.sv->modelindex < MAX_MODELS )
|
|
|
|
|
pushermodel = sv.models[(int)pusher->progs.sv->modelindex];
|
|
|
|
|
Matrix4x4_CreateFromEntity( pusherfinalmatrix, pusher->progs.sv->origin[0], pusher->progs.sv->origin[1], pusher->progs.sv->origin[2], pusher->progs.sv->angles[0], pusher->progs.sv->angles[1], pusher->progs.sv->angles[2], 1 );
|
|
|
|
|
Matrix4x4_Invert_Simple( pusherfinalimatrix, pusherfinalmatrix );
|
|
|
|
|
|
|
|
|
|
savesolid = pusher->progs.sv->solid;
|
|
|
|
|
|
|
|
|
|
// see if any solid entities are inside the final position
|
|
|
|
|
num_moved = 0;
|
|
|
|
|
|
|
|
|
|
numcheckentities = SV_AreaEdicts( mins, maxs, checkentities, MAX_EDICTS );
|
|
|
|
|
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];
|
|
|
|
|
|
|
|
|
|
switch((int)check->progs.sv->movetype)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
check->priv.sv->forceupdate = true;
|
|
|
|
|
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
|
|
|
|
|
if(!((int)check->progs.sv->aiflags & AI_ONGROUND) || PRVM_PROG_TO_EDICT(check->progs.sv->groundentity) != pusher )
|
|
|
|
|
{
|
|
|
|
|
pe->ClipToGenericEntity( &trace, pushermodel, pusher->progs.sv->mins, pusher->progs.sv->maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->progs.sv->origin, check->progs.sv->mins, check->progs.sv->maxs, check->progs.sv->origin, checkcontents );
|
|
|
|
|
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;
|
|
|
|
|
VectorSubtract( check->progs.sv->origin, pusher->progs.sv->origin, org );
|
|
|
|
|
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]);
|
|
|
|
|
|
|
|
|
|
VectorCopy (check->progs.sv->origin, check->priv.sv->moved_origin );
|
|
|
|
|
VectorCopy (check->progs.sv->angles, check->priv.sv->moved_angles );
|
|
|
|
|
moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
|
|
|
|
|
|
|
|
|
|
// try moving the contacted entity
|
|
|
|
|
pusher->progs.sv->solid = SOLID_NOT;
|
|
|
|
|
trace = SV_PushEntity( check, move, true );
|
|
|
|
|
// FIXME: turn players specially
|
|
|
|
|
check->progs.sv->angles[1] += trace.fraction * moveangle[1];
|
|
|
|
|
pusher->progs.sv->solid = savesolid; // was SOLID_BSP
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
if( check->progs.sv->movetype != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(check->progs.sv->groundentity) != pusher))
|
|
|
|
|
check->progs.sv->aiflags = (int)check->progs.sv->aiflags & ~AI_ONGROUND;
|
|
|
|
|
|
|
|
|
|
// if it is still inside the pusher, block
|
|
|
|
|
pe->ClipToGenericEntity( &trace, pushermodel, pusher->progs.sv->mins, pusher->progs.sv->maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->progs.sv->origin, check->progs.sv->mins, check->progs.sv->maxs, check->progs.sv->origin, checkcontents );
|
|
|
|
|
if (trace.startsolid)
|
|
|
|
|
{
|
|
|
|
|
// try moving the contacted entity a tiny bit further to account for precision errors
|
|
|
|
|
vec3_t move2;
|
|
|
|
|
pusher->progs.sv->solid = SOLID_NOT;
|
|
|
|
|
VectorScale( move, 1.1f, move2 );
|
|
|
|
|
VectorCopy( check->priv.sv->moved_origin, check->progs.sv->origin );
|
|
|
|
|
VectorCopy( check->priv.sv->moved_angles, check->progs.sv->angles );
|
|
|
|
|
SV_PushEntity( check, move2, true );
|
|
|
|
|
pusher->progs.sv->solid = savesolid;
|
|
|
|
|
pe->ClipToGenericEntity( &trace, pushermodel, pusher->progs.sv->mins, pusher->progs.sv->maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->progs.sv->origin, check->progs.sv->mins, check->progs.sv->maxs, check->progs.sv->origin, checkcontents );
|
|
|
|
|
if( trace.startsolid )
|
|
|
|
|
{
|
|
|
|
|
// try moving the contacted entity a tiny bit less to account for precision errors
|
|
|
|
|
pusher->progs.sv->solid = SOLID_NOT;
|
|
|
|
|
VectorScale( move, 0.9, move2 );
|
|
|
|
|
VectorCopy( check->priv.sv->moved_origin, check->progs.sv->origin );
|
|
|
|
|
VectorCopy( check->priv.sv->moved_angles, check->progs.sv->angles );
|
|
|
|
|
SV_PushEntity( check, move2, true );
|
|
|
|
|
pusher->progs.sv->solid = savesolid;
|
|
|
|
|
pe->ClipToGenericEntity( &trace, pushermodel, pusher->progs.sv->mins, pusher->progs.sv->maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->progs.sv->origin, check->progs.sv->mins, check->progs.sv->maxs, check->progs.sv->origin, checkcontents );
|
|
|
|
|
if( trace.startsolid )
|
|
|
|
|
{
|
|
|
|
|
// still inside pusher, so it's really blocked
|
|
|
|
|
|
|
|
|
|
// fail the move
|
|
|
|
|
if( check->progs.sv->mins[0] == check->progs.sv->maxs[0] ) continue;
|
|
|
|
|
if( check->progs.sv->solid == SOLID_NOT || check->progs.sv->solid == SOLID_TRIGGER )
|
|
|
|
|
{
|
|
|
|
|
// corpse
|
|
|
|
|
check->progs.sv->mins[0] = check->progs.sv->mins[1] = 0;
|
|
|
|
|
VectorCopy( check->progs.sv->mins, check->progs.sv->maxs );
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VectorCopy( pushorig, pusher->progs.sv->origin );
|
|
|
|
|
VectorCopy( pushang, pusher->progs.sv->angles );
|
|
|
|
|
pusher->progs.sv->ltime = pushltime;
|
|
|
|
|
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++ )
|
|
|
|
|
{
|
|
|
|
|
edict_t *ed = PRVM_EDICT_NUM( moved_edicts[i] );
|
|
|
|
|
VectorCopy( ed->priv.sv->moved_origin, ed->progs.sv->origin );
|
|
|
|
|
VectorCopy( ed->priv.sv->moved_angles, ed->progs.sv->angles );
|
|
|
|
|
SV_LinkEdict( ed );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
|
|
|
|
|
if( pusher->progs.sv->blocked )
|
|
|
|
|
{
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG( pusher );
|
|
|
|
|
prog->globals.sv->other = PRVM_EDICT_TO_PROG( check );
|
|
|
|
|
PRVM_ExecuteProgram( pusher->progs.sv->blocked, "pev->blocked" );
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SV_ClampAngle( pusher->progs.sv->angles );
|
|
|
|
|
}
|
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-07-30 22:00:00 +02:00
|
|
|
|
oldltime = ent->progs.sv->ltime;
|
|
|
|
|
thinktime = ent->progs.sv->nextthink;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( thinktime < ent->progs.sv->ltime + sv.frametime)
|
|
|
|
|
{
|
|
|
|
|
movetime = thinktime - ent->progs.sv->ltime;
|
|
|
|
|
if( movetime < 0 ) movetime = 0;
|
|
|
|
|
}
|
|
|
|
|
else movetime = sv.frametime;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// advances ent->progs.sv->ltime if not blocked
|
|
|
|
|
if( movetime ) SV_PushMove( ent, movetime );
|
|
|
|
|
if( thinktime > oldltime && thinktime <= ent->progs.sv->ltime )
|
|
|
|
|
{
|
|
|
|
|
ent->progs.sv->nextthink = 0;
|
|
|
|
|
prog->globals.sv->time = sv.time;
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent);
|
|
|
|
|
prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts);
|
|
|
|
|
PRVM_ExecuteProgram( ent->progs.sv->think, "pev->think" );
|
|
|
|
|
}
|
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 );
|
|
|
|
|
if((int)ent->progs.sv->aiflags & AI_DUCKED )
|
|
|
|
|
{
|
|
|
|
|
offset[0] += 1;
|
|
|
|
|
offset[1] += 1;
|
|
|
|
|
offset[2] += 1;
|
|
|
|
|
}
|
|
|
|
|
if(!SV_TestEntityPosition( ent, offset ))
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( ent->progs.sv->origin, ent->progs.sv->old_origin );
|
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-08-02 22:00:00 +02:00
|
|
|
|
MsgDev( D_INFO, "Unstuck player with offset %g %g %g.\n", unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]);
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorSubtract( ent->progs.sv->old_origin, ent->progs.sv->origin, offset );
|
|
|
|
|
if(!SV_TestEntityPosition( ent, offset ))
|
2007-09-17 22:00:00 +02:00
|
|
|
|
{
|
2008-08-02 22:00:00 +02:00
|
|
|
|
MsgDev( D_INFO, "Unstuck player by restoring oldorigin.\n" );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_LinkEdict( ent );
|
2007-09-17 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2008-08-02 22:00:00 +02:00
|
|
|
|
MsgDev( D_INFO, "Stuck player\n" );
|
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
|
|
|
|
|
if(!SV_TestEntityPosition( ent, vec3_origin ))
|
|
|
|
|
return true;
|
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 ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_INFO, "Unstuck entity \"%s\" with offset %g %g %g.\n", PRVM_GetString(ent->progs.sv->classname), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]);
|
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
MsgDev( D_INFO, "Stuck entity \"%s\".\n", PRVM_GetString(ent->progs.sv->classname));
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
point[0] = ent->progs.sv->origin[0];
|
|
|
|
|
point[1] = ent->progs.sv->origin[1];
|
|
|
|
|
point[2] = ent->progs.sv->origin[2] + ent->progs.sv->mins[2] + 1;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
ent->progs.sv->waterlevel = 0;
|
2008-08-30 22:00:00 +02:00
|
|
|
|
ent->progs.sv->watertype = 0;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
cont = SV_PointContents( point );
|
|
|
|
|
if( cont & (MASK_WATER))
|
|
|
|
|
{
|
|
|
|
|
ent->progs.sv->watertype = cont;
|
|
|
|
|
ent->progs.sv->waterlevel = 1;
|
|
|
|
|
point[2] = ent->progs.sv->origin[2] + (ent->progs.sv->mins[2] + ent->progs.sv->maxs[2])*0.5;
|
|
|
|
|
if(SV_PointContents( point ) & (MASK_WATER))
|
|
|
|
|
{
|
|
|
|
|
ent->progs.sv->waterlevel = 2;
|
|
|
|
|
point[2] = ent->progs.sv->origin[2] + ent->progs.sv->view_ofs[2];
|
|
|
|
|
if(SV_PointContents(point) & (MASK_WATER))
|
|
|
|
|
ent->progs.sv->waterlevel = 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ent->progs.sv->waterlevel > 1;
|
|
|
|
|
}
|
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;
|
|
|
|
|
|
|
|
|
|
AngleVectors (ent->progs.sv->v_angle, 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
|
|
|
|
|
i = DotProduct (stepnormal, ent->progs.sv->velocity);
|
|
|
|
|
VectorScale (stepnormal, i, into);
|
|
|
|
|
VectorSubtract (ent->progs.sv->velocity, into, side);
|
|
|
|
|
ent->progs.sv->velocity[0] = side[0] * (1 + d);
|
|
|
|
|
ent->progs.sv->velocity[1] = side[1] * (1 + d);
|
|
|
|
|
}
|
|
|
|
|
}
|
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-07-31 22:00:00 +02:00
|
|
|
|
int clip, oldonground, originalmove_clip, originalmove_aiflags;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
int originalmove_groundentity, contentsmask;
|
|
|
|
|
vec3_t upmove, downmove, start_origin, start_velocity, stepnormal;
|
|
|
|
|
vec3_t originalmove_origin, originalmove_velocity;
|
|
|
|
|
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
|
|
|
|
|
if( sv.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
|
|
|
|
|
oldonground = (int)ent->progs.sv->aiflags & AI_ONGROUND;
|
|
|
|
|
|
|
|
|
|
VectorCopy( ent->progs.sv->origin, start_origin );
|
|
|
|
|
VectorCopy( ent->progs.sv->velocity, start_velocity );
|
|
|
|
|
clip = SV_FlyMove( ent, sv.frametime, NULL, contentsmask );
|
|
|
|
|
|
|
|
|
|
// if the move did not hit the ground at any point, we're not on ground
|
|
|
|
|
if(!(clip & 1)) ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags & ~AI_ONGROUND;
|
|
|
|
|
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
|
|
|
|
|
VectorCopy( ent->progs.sv->origin, originalmove_origin );
|
|
|
|
|
VectorCopy( ent->progs.sv->velocity, originalmove_velocity );
|
|
|
|
|
originalmove_clip = clip;
|
2008-07-31 22:00:00 +02:00
|
|
|
|
originalmove_aiflags = (int)ent->progs.sv->aiflags;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
originalmove_groundentity = ent->progs.sv->groundentity;
|
|
|
|
|
|
|
|
|
|
if((int)ent->progs.sv->aiflags & AI_WATERJUMP)
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if( ent->progs.sv->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
|
|
|
|
|
if( ent->progs.sv->movetype != MOVETYPE_WALK )
|
|
|
|
|
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
|
|
|
|
|
if( !oldonground && ent->progs.sv->waterlevel == 0 )
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// try moving up and forward to go up a step
|
|
|
|
|
// back to start pos
|
|
|
|
|
VectorCopy( start_origin, ent->progs.sv->origin );
|
|
|
|
|
VectorCopy( start_velocity, ent->progs.sv->velocity );
|
|
|
|
|
|
|
|
|
|
// move up
|
|
|
|
|
VectorClear( upmove );
|
|
|
|
|
upmove[2] = sv_stepheight->value;
|
|
|
|
|
|
|
|
|
|
SV_PushEntity( ent, upmove, false ); // FIXME: don't link?
|
|
|
|
|
|
|
|
|
|
// move forward
|
|
|
|
|
ent->progs.sv->velocity[2] = 0;
|
|
|
|
|
clip = SV_FlyMove( ent, sv.frametime, stepnormal, contentsmask );
|
|
|
|
|
ent->progs.sv->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
|
|
|
|
|
if( clip && fabs(originalmove_origin[1] - ent->progs.sv->origin[1]) < 0.03125 && fabs(originalmove_origin[0] - ent->progs.sv->origin[0]) < 0.03125 )
|
|
|
|
|
{
|
|
|
|
|
// stepping up didn't make any progress, revert to original move
|
|
|
|
|
VectorCopy( originalmove_origin, ent->progs.sv->origin );
|
|
|
|
|
VectorCopy( originalmove_velocity, ent->progs.sv->velocity );
|
2008-07-31 22:00:00 +02:00
|
|
|
|
ent->progs.sv->aiflags = originalmove_aiflags;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
ent->progs.sv->groundentity = originalmove_groundentity;
|
|
|
|
|
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
|
|
|
|
|
else if( ent->progs.sv->waterlevel >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || ((int)ent->progs.sv->aiflags & AI_ONGROUND))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// move down
|
|
|
|
|
VectorClear( downmove );
|
|
|
|
|
downmove[2] = -sv_stepheight->value + start_velocity[2] * sv.frametime;
|
|
|
|
|
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
|
|
|
|
|
//if (ent->progs.sv->solid == SOLID_BSP)
|
|
|
|
|
{
|
|
|
|
|
//Con_Printf("onground\n");
|
2008-07-31 22:00:00 +02:00
|
|
|
|
ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(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
|
|
|
|
|
VectorCopy( originalmove_origin, ent->progs.sv->origin );
|
|
|
|
|
VectorCopy( originalmove_velocity, ent->progs.sv->velocity );
|
2008-07-31 22:00:00 +02:00
|
|
|
|
ent->progs.sv->aiflags = originalmove_aiflags;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
ent->progs.sv->groundentity = originalmove_groundentity;
|
|
|
|
|
}
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
e = PRVM_PROG_TO_EDICT( ent->progs.sv->aiment );
|
|
|
|
|
if(VectorCompare( e->progs.sv->angles, ent->progs.sv->punchangle ))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// quick case for no rotation
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorAdd( e->progs.sv->origin, ent->progs.sv->view_ofs, ent->progs.sv->origin );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
angles[0] = -ent->progs.sv->punchangle[0];
|
|
|
|
|
angles[1] = ent->progs.sv->punchangle[1];
|
|
|
|
|
angles[2] = ent->progs.sv->punchangle[2];
|
2008-07-30 22:00:00 +02:00
|
|
|
|
AngleVectors( angles, vf, vr, vu );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
v[0] = ent->progs.sv->view_ofs[0] * vf[0] + ent->progs.sv->view_ofs[1] * vr[0] + ent->progs.sv->view_ofs[2] * vu[0];
|
|
|
|
|
v[1] = ent->progs.sv->view_ofs[0] * vf[1] + ent->progs.sv->view_ofs[1] * vr[1] + ent->progs.sv->view_ofs[2] * vu[1];
|
|
|
|
|
v[2] = ent->progs.sv->view_ofs[0] * vf[2] + ent->progs.sv->view_ofs[1] * vr[2] + ent->progs.sv->view_ofs[2] * vu[2];
|
|
|
|
|
angles[0] = -e->progs.sv->angles[0];
|
|
|
|
|
angles[1] = e->progs.sv->angles[1];
|
|
|
|
|
angles[2] = e->progs.sv->angles[2];
|
2008-07-30 22:00:00 +02:00
|
|
|
|
AngleVectors( angles, vf, vr, vu );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
ent->progs.sv->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->progs.sv->origin[0];
|
|
|
|
|
ent->progs.sv->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->progs.sv->origin[1];
|
|
|
|
|
ent->progs.sv->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->progs.sv->origin[2];
|
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorAdd( e->progs.sv->angles, ent->progs.sv->v_angle, ent->progs.sv->angles );
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
int cont = SV_PointContents( ent->progs.sv->origin );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( !ent->progs.sv->watertype )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
// just spawned here
|
|
|
|
|
ent->progs.sv->watertype = cont;
|
|
|
|
|
ent->progs.sv->waterlevel = 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check if the entity crossed into or out of water
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if((int)ent->progs.sv->watertype & MASK_WATER )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02: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
|
|
|
|
{
|
|
|
|
|
ent->progs.sv->watertype = cont;
|
|
|
|
|
ent->progs.sv->waterlevel = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-08-30 22:00:00 +02:00
|
|
|
|
ent->progs.sv->watertype = 0;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
ent->progs.sv->waterlevel = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
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
|
|
|
|
|
if((int)ent->progs.sv->aiflags & AI_ONGROUND)
|
|
|
|
|
{
|
|
|
|
|
if( ent->progs.sv->velocity[2] >= (1.0 / 32.0))
|
|
|
|
|
{
|
|
|
|
|
// don't stick to ground if onground and moving upward
|
|
|
|
|
ent->progs.sv->aiflags -= AI_ONGROUND;
|
|
|
|
|
}
|
|
|
|
|
else if( !ent->progs.sv->groundentity )
|
|
|
|
|
{
|
|
|
|
|
// we can trust AI_ONGROUND if groundentity is world because it never moves
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if( ent->priv.sv->suspended && PRVM_PROG_TO_EDICT(ent->progs.sv->groundentity)->priv.sv->free )
|
|
|
|
|
{
|
|
|
|
|
// 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
|
|
|
|
|
ent->progs.sv->groundentity = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ent->priv.sv->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-07-30 22:00:00 +02:00
|
|
|
|
if( ent->progs.sv->movetype == MOVETYPE_TOSS || ent->progs.sv->movetype == MOVETYPE_BOUNCE )
|
|
|
|
|
SV_AddGravity( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// move angles
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorMA( ent->progs.sv->angles, sv.frametime, ent->progs.sv->avelocity, ent->progs.sv->angles );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// move origin
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorScale( ent->progs.sv->velocity, sv.frametime, move );
|
|
|
|
|
trace = SV_PushEntity( ent, move, true );
|
|
|
|
|
if( ent->priv.sv->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 );
|
|
|
|
|
if( ent->priv.sv->free )
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
if( ent->progs.sv->movetype == MOVETYPE_BOUNCE )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
float d;
|
|
|
|
|
SV_ClipVelocity( ent->progs.sv->velocity, trace.plane.normal, ent->progs.sv->velocity, 1.5 );
|
|
|
|
|
d = DotProduct( trace.plane.normal, ent->progs.sv->velocity );
|
|
|
|
|
if( trace.plane.normal[2] > 0.7 && fabs(d) < 60 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND;
|
|
|
|
|
ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorClear( ent->progs.sv->velocity );
|
|
|
|
|
VectorClear( ent->progs.sv->avelocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
2008-07-31 22:00:00 +02:00
|
|
|
|
else ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags & ~AI_ONGROUND;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_ClipVelocity( ent->progs.sv->velocity, trace.plane.normal, ent->progs.sv->velocity, 1.0 );
|
|
|
|
|
if( trace.plane.normal[2] > 0.7 )
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND;
|
|
|
|
|
ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( trace.ent->progs.sv->solid == SOLID_BSP )
|
|
|
|
|
ent->priv.sv->suspended = true;
|
|
|
|
|
VectorClear( ent->progs.sv->velocity );
|
|
|
|
|
VectorClear( ent->progs.sv->avelocity );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags & ~AI_ONGROUND;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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-07-30 22:00:00 +02:00
|
|
|
|
int flags = (int)ent->progs.sv->aiflags;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if(!(flags & (AI_FLY | AI_SWIM)))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( flags & AI_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-07-30 22:00:00 +02:00
|
|
|
|
if(ent->progs.sv->velocity[2] >= (1.0 / 32.0) || ent->progs.sv->groundentity)
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
ent->progs.sv->aiflags -= AI_ONGROUND;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_AddGravity( ent );
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
SV_FlyMove( ent, sv.frametime, NULL, SV_ContentsMask( ent ));
|
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
ent->priv.sv->forceupdate = true;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// freefall if not onground
|
|
|
|
|
int hitsound = ent->progs.sv->velocity[2] < sv_gravity->value * -0.1;
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
SV_AddGravity( ent );
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
SV_FlyMove( ent, sv.frametime, NULL, SV_ContentsMask( ent ));
|
|
|
|
|
SV_LinkEdict( ent );
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// just hit ground
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( hitsound && (int)ent->progs.sv->aiflags & AI_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-07-30 22:00:00 +02:00
|
|
|
|
ent->priv.sv->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-07-30 22:00:00 +02:00
|
|
|
|
if( ent->priv.sv->forceupdate || !VectorCompare( ent->progs.sv->origin, ent->priv.sv->water_origin))
|
2007-09-28 22:00:00 +02:00
|
|
|
|
{
|
2008-07-30 22:00:00 +02:00
|
|
|
|
ent->priv.sv->forceupdate = false;
|
|
|
|
|
VectorCopy( ent->progs.sv->origin, ent->priv.sv->water_origin );
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
VectorScale( ent->progs.sv->movedir, ent->progs.sv->speed, v );
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
|
player = PRVM_EDICT_NUM(i) + 1;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if( player->priv.sv->free ) continue;
|
|
|
|
|
if( !player->progs.sv->groundentity ) continue;
|
|
|
|
|
if( player->progs.sv->groundentity != PRVM_EDICT_TO_PROG(ent))
|
|
|
|
|
continue;
|
2007-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// Look below player; make sure he's on a conveyor
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorCopy( player->progs.sv->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-07-30 22:00:00 +02:00
|
|
|
|
tr = SV_Trace( point, player->progs.sv->mins, player->progs.sv->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
|
|
|
|
{
|
|
|
|
|
v[2] = ent->progs.sv->speed * sqrt(1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2];
|
2008-07-30 22:00:00 +02:00
|
|
|
|
if(DotProduct( ent->progs.sv->movedir, tr.plane.normal) > 0)
|
|
|
|
|
v[2] = -v[2]; // then we're moving down
|
2007-09-28 22:00:00 +02:00
|
|
|
|
move[2] = v[2] * 0.1f;
|
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
VectorAdd( player->progs.sv->origin, move, end );
|
|
|
|
|
tr = SV_Trace( player->progs.sv->origin, player->progs.sv->mins, player->progs.sv->maxs, end, MOVE_NORMAL, player, player->priv.sv->clipmask );
|
|
|
|
|
VectorCopy( tr.endpos, player->progs.sv->origin );
|
|
|
|
|
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 );
|
|
|
|
|
VectorMA( ent->progs.sv->angles, sv.frametime, ent->progs.sv->avelocity, ent->progs.sv->angles );
|
|
|
|
|
VectorMA( ent->progs.sv->origin, sv.frametime, ent->progs.sv->velocity, ent->progs.sv->origin );
|
|
|
|
|
}
|
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
|
|
|
|
{
|
|
|
|
|
if (ent->progs.sv->nextthink > 0 && ent->progs.sv->nextthink <= sv.time + sv.frametime)
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
switch((int)ent->progs.sv->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-07-30 22:00:00 +02:00
|
|
|
|
if(!SV_CheckWater( ent ) && !((int)ent->progs.sv->aiflags & AI_WATERJUMP ))
|
|
|
|
|
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:
|
|
|
|
|
MsgDev( D_ERROR, "SV_Physics: bad movetype %i\n", (int)ent->progs.sv->movetype );
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SV_Physics_ClientEntity( edict_t *ent )
|
|
|
|
|
{
|
|
|
|
|
sv_client_t *client = ent->priv.sv->client;
|
|
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
if( DotProduct( ent->progs.sv->velocity, ent->progs.sv->velocity ) < 0.0001 )
|
|
|
|
|
VectorClear( ent->progs.sv->velocity );
|
|
|
|
|
|
|
|
|
|
// call standard client pre-think
|
|
|
|
|
prog->globals.sv->time = sv.time;
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG( ent );
|
|
|
|
|
PRVM_ExecuteProgram (prog->globals.sv->PlayerPreThink, "PlayerPreThink" );
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
|
|
|
|
|
switch((int)ent->progs.sv->movetype )
|
|
|
|
|
{
|
|
|
|
|
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 );
|
|
|
|
|
VectorMA( ent->progs.sv->origin, sv.frametime, ent->progs.sv->velocity, ent->progs.sv->origin );
|
|
|
|
|
VectorMA( ent->progs.sv->angles, sv.frametime, ent->progs.sv->avelocity, ent->progs.sv->angles );
|
|
|
|
|
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 )
|
|
|
|
|
{
|
|
|
|
|
if(!SV_CheckWater( ent ) && !((int)ent->progs.sv->aiflags & AI_WATERJUMP) )
|
|
|
|
|
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-07-30 22:00:00 +02:00
|
|
|
|
MsgDev( D_ERROR, "SV_Physics_ClientEntity: bad movetype %i\n", (int)ent->progs.sv->movetype);
|
|
|
|
|
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-07-31 22:00:00 +02:00
|
|
|
|
if( ent->progs.sv->movetype != MOVETYPE_NOCLIP )
|
|
|
|
|
SV_TouchTriggers( ent );
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// call standard player post-think
|
|
|
|
|
prog->globals.sv->time = sv.time;
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent);
|
|
|
|
|
PRVM_ExecuteProgram( prog->globals.sv->PlayerPostThink, "PlayerPostThink" );
|
|
|
|
|
|
|
|
|
|
if( ent->progs.sv->fixangle )
|
|
|
|
|
{
|
|
|
|
|
// angle fixing was requested by physics code...
|
|
|
|
|
// so store the current angles for later use
|
|
|
|
|
VectorCopy( ent->progs.sv->angles, client->fix_angles );
|
|
|
|
|
ent->progs.sv->fixangle = false;// and clear fixangle for the next frame
|
|
|
|
|
client->fixangle = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SV_Physics_ClientMove( sv_client_t *client, usercmd_t *cmd )
|
|
|
|
|
{
|
|
|
|
|
edict_t *ent = client->edict;
|
|
|
|
|
|
|
|
|
|
// call player physics, this needs the proper frametime
|
|
|
|
|
prog->globals.sv->frametime = sv.frametime;
|
|
|
|
|
SV_ClientThink( client, cmd );
|
|
|
|
|
|
|
|
|
|
// call standard client pre-think, with frametime = 0
|
|
|
|
|
prog->globals.sv->time = sv.time;
|
|
|
|
|
prog->globals.sv->frametime = 0;
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent);
|
|
|
|
|
PRVM_ExecuteProgram( prog->globals.sv->PlayerPreThink, "PlayerPreThink" );
|
|
|
|
|
prog->globals.sv->frametime = sv.frametime;
|
|
|
|
|
|
|
|
|
|
// make sure the velocity is sane (not a NaN)
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
if(DotProduct(ent->progs.sv->velocity, ent->progs.sv->velocity) < 0.0001)
|
|
|
|
|
VectorClear( ent->progs.sv->velocity );
|
|
|
|
|
|
|
|
|
|
// perform MOVETYPE_WALK behavior
|
|
|
|
|
if(!SV_CheckWater (ent) && !((int)ent->progs.sv->aiflags & AI_WATERJUMP))
|
|
|
|
|
SV_AddGravity( ent );
|
|
|
|
|
SV_CheckStuck( ent );
|
|
|
|
|
SV_WalkMove( ent );
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
SV_LinkEdict( ent );
|
|
|
|
|
SV_CheckVelocity( ent );
|
|
|
|
|
|
2008-07-31 22:00:00 +02:00
|
|
|
|
if( ent->progs.sv->movetype != MOVETYPE_NOCLIP )
|
|
|
|
|
SV_TouchTriggers( ent );
|
|
|
|
|
|
2008-07-30 22:00:00 +02:00
|
|
|
|
// call standard player post-think, with frametime = 0
|
|
|
|
|
prog->globals.sv->time = sv.time;
|
|
|
|
|
prog->globals.sv->frametime = 0;
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG( ent );
|
|
|
|
|
PRVM_ExecuteProgram( prog->globals.sv->PlayerPostThink, "PlayerPostThink" );
|
|
|
|
|
prog->globals.sv->frametime = sv.frametime;
|
|
|
|
|
|
|
|
|
|
if( ent->progs.sv->fixangle )
|
|
|
|
|
{
|
|
|
|
|
// angle fixing was requested by physics code...
|
|
|
|
|
// so store the current angles for later use
|
|
|
|
|
VectorCopy( ent->progs.sv->angles, client->fix_angles );
|
|
|
|
|
ent->progs.sv->fixangle = false;// and clear fixangle for the next frame
|
|
|
|
|
client->fixangle = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
SV_Physics
|
|
|
|
|
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void SV_Physics( void )
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
edict_t *ent;
|
2008-08-01 22:00:00 +02:00
|
|
|
|
int frametime = 1000 / sv_fps->integer;
|
|
|
|
|
int num_physframes = 0;
|
2008-07-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// let the progs know that a new frame has started
|
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(prog->edicts);
|
|
|
|
|
prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts);
|
|
|
|
|
prog->globals.sv->time = sv.time;
|
|
|
|
|
prog->globals.sv->frametime = sv.frametime;
|
|
|
|
|
PRVM_ExecuteProgram( prog->globals.sv->StartFrame, "StartFrame" );
|
|
|
|
|
|
|
|
|
|
// treat each object in turn
|
|
|
|
|
for( i = 1; i < prog->num_edicts; i++ )
|
|
|
|
|
{
|
|
|
|
|
ent = PRVM_EDICT_NUM(i);
|
|
|
|
|
if( ent->priv.sv->free ) continue;
|
|
|
|
|
|
|
|
|
|
VectorCopy( ent->progs.sv->origin, ent->progs.sv->old_origin );
|
2008-08-11 22:00:00 +02:00
|
|
|
|
if(i <= Host_MaxClients());// SV_Physics_ClientEntity( ent );
|
2008-07-30 22:00:00 +02:00
|
|
|
|
else if(!sv_playersonly->integer)SV_Physics_Entity( ent );
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-01 22:00:00 +02:00
|
|
|
|
// let everything in the world think and move
|
|
|
|
|
while( svs.timeleft >= frametime )
|
|
|
|
|
{
|
|
|
|
|
svs.timeleft -= frametime;
|
|
|
|
|
pe->Frame( frametime * 0.001f );
|
|
|
|
|
num_physframes++;
|
|
|
|
|
}
|
2008-07-30 22:00:00 +02:00
|
|
|
|
prog->globals.sv->pev = PRVM_EDICT_TO_PROG(prog->edicts);
|
|
|
|
|
prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts);
|
|
|
|
|
prog->globals.sv->time = sv.time;
|
|
|
|
|
PRVM_ExecuteProgram( prog->globals.sv->EndFrame, "EndFrame" );
|
|
|
|
|
|
|
|
|
|
// decrement prog->num_edicts if the highest number entities died
|
|
|
|
|
for( ;PRVM_EDICT_NUM(prog->num_edicts - 1)->priv.sv->free; prog->num_edicts-- );
|
|
|
|
|
|
|
|
|
|
if( !sv_playersonly->integer ) sv.time += sv.frametime;
|
2007-09-17 22:00:00 +02:00
|
|
|
|
}
|