2008-12-15 22:00:00 +01:00
|
|
|
|
//=======================================================================
|
|
|
|
|
// Copyright XashXT Group 2008 <20>
|
|
|
|
|
// sv_game.c - server dlls interaction
|
|
|
|
|
//=======================================================================
|
|
|
|
|
|
|
|
|
|
#include "common.h"
|
|
|
|
|
#include "server.h"
|
2010-08-04 22:00:00 +02:00
|
|
|
|
#include "protocol.h"
|
2009-09-29 22:00:00 +02:00
|
|
|
|
#include "net_sound.h"
|
2010-08-04 22:00:00 +02:00
|
|
|
|
#include "net_encode.h"
|
2008-12-15 22:00:00 +01:00
|
|
|
|
#include "byteorder.h"
|
|
|
|
|
#include "matrix_lib.h"
|
2010-08-07 22:00:00 +02:00
|
|
|
|
#include "event_flags.h"
|
2009-11-10 22:00:00 +01:00
|
|
|
|
#include "pm_defs.h"
|
2008-12-15 22:00:00 +01:00
|
|
|
|
#include "const.h"
|
|
|
|
|
|
2010-06-28 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
EntvarsDescription
|
|
|
|
|
|
|
|
|
|
entavrs table for FindEntityByString
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
#define ENTVARS_COUNT ( sizeof( gEntvarsDescription ) / sizeof( gEntvarsDescription[0] ))
|
|
|
|
|
|
|
|
|
|
static TYPEDESCRIPTION gEntvarsDescription[] =
|
|
|
|
|
{
|
|
|
|
|
DEFINE_ENTITY_FIELD( classname, FIELD_STRING ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( globalname, FIELD_STRING ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( model, FIELD_MODELNAME ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( viewmodel, FIELD_MODELNAME ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( weaponmodel, FIELD_MODELNAME ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( target, FIELD_STRING ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( targetname, FIELD_STRING ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( netname, FIELD_STRING ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( message, FIELD_STRING ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( noise, FIELD_SOUNDNAME ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( noise1, FIELD_SOUNDNAME ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( noise2, FIELD_SOUNDNAME ),
|
|
|
|
|
DEFINE_ENTITY_FIELD( noise3, FIELD_SOUNDNAME ),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
SV_GetEntvarsDescription
|
|
|
|
|
|
|
|
|
|
entavrs table for FindEntityByString
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
TYPEDESCRIPTION *SV_GetEntvarsDescirption( int number )
|
|
|
|
|
{
|
|
|
|
|
if( number < 0 && number >= ENTVARS_COUNT )
|
|
|
|
|
return NULL;
|
|
|
|
|
return &gEntvarsDescription[number];
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-23 22:00:00 +02:00
|
|
|
|
void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-09-23 22:00:00 +02:00
|
|
|
|
int i;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-04-07 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( e ) || !min || !max )
|
|
|
|
|
return;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
for( i = 0; i < 3; i++ )
|
2010-04-13 22:00:00 +02:00
|
|
|
|
{
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( min[i] > max[i] )
|
2010-04-13 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_SetMinMaxSize: %s backwards mins/maxs\n", SV_ClassName( e ));
|
|
|
|
|
SV_LinkEdict( e, false ); // just relink edict and exit
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-09-23 22:00:00 +02:00
|
|
|
|
VectorCopy( min, e->v.mins );
|
|
|
|
|
VectorCopy( max, e->v.maxs );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorSubtract( max, min, e->v.size );
|
|
|
|
|
|
2009-11-02 22:00:00 +01:00
|
|
|
|
SV_LinkEdict( e, false );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-02 22:00:00 +01:00
|
|
|
|
void SV_CopyTraceToGlobal( trace_t *trace )
|
2009-10-28 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
svgame.globals->trace_allsolid = trace->fAllSolid;
|
|
|
|
|
svgame.globals->trace_startsolid = trace->fStartSolid;
|
|
|
|
|
svgame.globals->trace_fraction = trace->flFraction;
|
|
|
|
|
svgame.globals->trace_plane_dist = trace->flPlaneDist;
|
|
|
|
|
svgame.globals->trace_ent = trace->pHit;
|
2009-11-02 22:00:00 +01:00
|
|
|
|
svgame.globals->trace_flags = 0;
|
|
|
|
|
svgame.globals->trace_inopen = trace->fInOpen;
|
|
|
|
|
svgame.globals->trace_inwater = trace->fInWater;
|
2009-10-28 22:00:00 +01:00
|
|
|
|
VectorCopy( trace->vecEndPos, svgame.globals->trace_endpos );
|
|
|
|
|
VectorCopy( trace->vecPlaneNormal, svgame.globals->trace_plane_normal );
|
|
|
|
|
svgame.globals->trace_hitgroup = trace->iHitgroup;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SV_SetModel( edict_t *ent, const char *name )
|
|
|
|
|
{
|
2010-05-31 22:00:00 +02:00
|
|
|
|
vec3_t mins = { 0.0f, 0.0f, 0.0f };
|
|
|
|
|
vec3_t maxs = { 0.0f, 0.0f, 0.0f };
|
2009-10-28 22:00:00 +01:00
|
|
|
|
int i;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
i = SV_ModelIndex( name );
|
|
|
|
|
if( i == 0 ) return;
|
2009-01-02 22:00:00 +01:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.model = MAKE_STRING( sv.configstrings[CS_MODELS+i] );
|
|
|
|
|
ent->v.modelindex = i;
|
|
|
|
|
|
2010-05-27 22:00:00 +02:00
|
|
|
|
// set sizes only for brush models
|
|
|
|
|
if( CM_GetModelType( ent->v.modelindex ) == mod_brush )
|
|
|
|
|
Mod_GetBounds( ent->v.modelindex, mins, maxs );
|
2010-05-31 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
SV_SetMinMaxSize( ent, mins, maxs );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float SV_AngleMod( float ideal, float current, float speed )
|
|
|
|
|
{
|
|
|
|
|
float move;
|
|
|
|
|
|
2010-04-01 22:00:00 +02:00
|
|
|
|
if( anglemod( current ) == ideal ) // already there?
|
|
|
|
|
return current;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
move = ideal - current;
|
2009-09-23 22:00:00 +02:00
|
|
|
|
if( ideal > current )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-04-01 22:00:00 +02:00
|
|
|
|
if( move >= 180 )
|
|
|
|
|
move = move - 360;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-01 22:00:00 +02:00
|
|
|
|
if( move <= -180 )
|
|
|
|
|
move = move + 360;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2009-09-23 22:00:00 +02:00
|
|
|
|
if( move > 0 )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-04-01 22:00:00 +02:00
|
|
|
|
if( move > speed )
|
|
|
|
|
move = speed;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-01 22:00:00 +02:00
|
|
|
|
if( move < -speed )
|
|
|
|
|
move = -speed;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2009-09-23 22:00:00 +02:00
|
|
|
|
return anglemod( current + move );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SV_ConfigString( int index, const char *val )
|
|
|
|
|
{
|
2009-09-23 22:00:00 +02:00
|
|
|
|
if( index < 0 || index >= MAX_CONFIGSTRINGS )
|
|
|
|
|
Host_Error( "SV_ConfigString: bad index %i value %s\n", index, val );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-09-23 22:00:00 +02:00
|
|
|
|
if( !val || !*val ) val = "";
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// change the string in sv
|
|
|
|
|
com.strcpy( sv.configstrings[index], val );
|
|
|
|
|
|
|
|
|
|
if( sv.state != ss_loading )
|
|
|
|
|
{
|
|
|
|
|
// send the update to everyone
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_Clear( &sv.multicast );
|
|
|
|
|
BF_WriteByte( &sv.multicast, svc_configstring );
|
|
|
|
|
BF_WriteShort( &sv.multicast, index );
|
|
|
|
|
BF_WriteString( &sv.multicast, val );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_ALL, vec3_origin, NULL );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-01 22:00:00 +02:00
|
|
|
|
void SV_CreateDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags )
|
|
|
|
|
{
|
2010-07-29 22:00:00 +02:00
|
|
|
|
ASSERT( origin );
|
2010-07-01 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// static decals are posters, it's always reliable
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_bspdecal );
|
|
|
|
|
BF_WriteBitVec3Coord( &sv.multicast, origin );
|
|
|
|
|
BF_WriteWord( &sv.multicast, decalIndex );
|
|
|
|
|
BF_WriteShort( &sv.multicast, entityIndex );
|
2010-07-02 22:00:00 +02:00
|
|
|
|
if( entityIndex > 0 )
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteWord( &sv.multicast, modelIndex );
|
|
|
|
|
BF_WriteByte( &sv.multicast, flags );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_INIT, NULL, NULL );
|
2010-07-01 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
static bool SV_OriginIn( int mode, const vec3_t v1, const vec3_t v2 )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
int leafnum;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
byte *mask;
|
|
|
|
|
|
2009-11-03 22:00:00 +01:00
|
|
|
|
leafnum = CM_PointLeafnum( v1 );
|
2010-04-13 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
switch( mode )
|
|
|
|
|
{
|
|
|
|
|
case DVIS_PVS:
|
2010-05-22 22:00:00 +02:00
|
|
|
|
mask = CM_LeafPVS( leafnum );
|
2010-04-13 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
case DVIS_PHS:
|
2010-05-22 22:00:00 +02:00
|
|
|
|
mask = CM_LeafPHS( leafnum );
|
2010-04-13 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2010-05-22 22:00:00 +02:00
|
|
|
|
mask = NULL; // skip any checks
|
2010-04-13 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2009-11-03 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
leafnum = CM_PointLeafnum( v2 );
|
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
if( mask && (!( mask[leafnum>>3] & (1<<( leafnum & 7 )))))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-13 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
SV_BoxInPVS
|
2010-04-12 22:00:00 +02:00
|
|
|
|
|
2010-04-13 22:00:00 +02:00
|
|
|
|
check brush boxes in fat pvs
|
|
|
|
|
==============
|
|
|
|
|
*/
|
2010-05-27 22:00:00 +02:00
|
|
|
|
static bool SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax )
|
2010-04-13 22:00:00 +02:00
|
|
|
|
{
|
2010-05-27 22:00:00 +02:00
|
|
|
|
// if( pe && !pe->BoxVisible( absmin, absmax, CM_FatPVS( org, false )))
|
|
|
|
|
if( pe && !pe->BoxVisible( absmin, absmax, CM_LeafPVS( CM_PointLeafnum( org ))))
|
2010-04-12 22:00:00 +02:00
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-07 22:00:00 +02:00
|
|
|
|
void SV_WriteEntityPatch( const char *filename )
|
|
|
|
|
{
|
|
|
|
|
file_t *f;
|
|
|
|
|
dheader_t *header;
|
|
|
|
|
int ver = -1, lumpofs = 0, lumplen = 0;
|
|
|
|
|
byte buf[MAX_SYSPATH]; // 1 kb
|
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
|
|
f = FS_Open( va( "maps/%s.bsp", filename ), "rb" );
|
|
|
|
|
if( !f ) return;
|
|
|
|
|
|
|
|
|
|
Mem_Set( buf, 0, MAX_SYSPATH );
|
|
|
|
|
FS_Read( f, buf, MAX_SYSPATH );
|
2010-05-22 22:00:00 +02:00
|
|
|
|
ver = LittleLong(*(uint *)buf);
|
2010-04-07 22:00:00 +02:00
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
switch( ver )
|
2010-04-07 22:00:00 +02:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
case Q1BSP_VERSION:
|
|
|
|
|
case HLBSP_VERSION:
|
2010-04-07 22:00:00 +02:00
|
|
|
|
header = (dheader_t *)buf;
|
2010-05-31 22:00:00 +02:00
|
|
|
|
if( LittleLong( header->lumps[LUMP_PLANES].filelen ) % sizeof( dplane_t ))
|
|
|
|
|
{
|
|
|
|
|
lumpofs = LittleLong( header->lumps[LUMP_PLANES].fileofs );
|
|
|
|
|
lumplen = LittleLong( header->lumps[LUMP_PLANES].filelen );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lumpofs = LittleLong( header->lumps[LUMP_ENTITIES].fileofs );
|
|
|
|
|
lumplen = LittleLong( header->lumps[LUMP_ENTITIES].filelen );
|
|
|
|
|
}
|
2010-04-07 22:00:00 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
FS_Close( f );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( lumplen >= 10 )
|
|
|
|
|
{
|
|
|
|
|
char *entities = NULL;
|
|
|
|
|
|
|
|
|
|
FS_Seek( f, lumpofs, SEEK_SET );
|
|
|
|
|
entities = (char *)Z_Malloc( lumplen + 1 );
|
|
|
|
|
FS_Read( f, entities, lumplen );
|
|
|
|
|
FS_WriteFile( va( "maps/%s.ent", filename ), entities, lumplen );
|
|
|
|
|
Msg( "Write 'maps/%s.ent'\n", filename );
|
|
|
|
|
Mem_Free( entities );
|
|
|
|
|
}
|
|
|
|
|
FS_Close( f );
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-03 22:00:00 +01:00
|
|
|
|
script_t *SV_GetEntityScript( const char *filename )
|
2009-09-28 22:00:00 +02:00
|
|
|
|
{
|
2009-11-03 22:00:00 +01:00
|
|
|
|
file_t *f;
|
|
|
|
|
dheader_t *header;
|
|
|
|
|
string entfilename;
|
|
|
|
|
script_t *ents = NULL;
|
|
|
|
|
int ver = -1, lumpofs = 0, lumplen = 0;
|
|
|
|
|
byte buf[MAX_SYSPATH]; // 1 kb
|
|
|
|
|
bool result = false;
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
f = FS_Open( va( "maps/%s.bsp", filename ), "rb" );
|
2009-11-03 22:00:00 +01:00
|
|
|
|
if( !f ) return NULL;
|
|
|
|
|
|
|
|
|
|
Mem_Set( buf, 0, MAX_SYSPATH );
|
|
|
|
|
FS_Read( f, buf, MAX_SYSPATH );
|
2010-05-22 22:00:00 +02:00
|
|
|
|
ver = LittleLong(*(uint *)buf);
|
2009-11-03 22:00:00 +01:00
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
switch( ver )
|
2009-11-03 22:00:00 +01:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
case Q1BSP_VERSION:
|
|
|
|
|
case HLBSP_VERSION:
|
2009-11-03 22:00:00 +01:00
|
|
|
|
header = (dheader_t *)buf;
|
2010-05-31 22:00:00 +02:00
|
|
|
|
if( LittleLong( header->lumps[LUMP_PLANES].filelen ) % sizeof( dplane_t ))
|
|
|
|
|
{
|
|
|
|
|
lumpofs = LittleLong( header->lumps[LUMP_PLANES].fileofs );
|
|
|
|
|
lumplen = LittleLong( header->lumps[LUMP_PLANES].filelen );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
lumpofs = LittleLong( header->lumps[LUMP_ENTITIES].fileofs );
|
|
|
|
|
lumplen = LittleLong( header->lumps[LUMP_ENTITIES].filelen );
|
|
|
|
|
}
|
2009-11-03 22:00:00 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
FS_Close( f );
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
2009-11-03 22:00:00 +01:00
|
|
|
|
// check for entfile too
|
|
|
|
|
com.strncpy( entfilename, va( "maps/%s.ent", filename ), sizeof( entfilename ));
|
|
|
|
|
ents = Com_OpenScript( entfilename, NULL, 0 );
|
|
|
|
|
|
|
|
|
|
if( !ents && lumplen >= 10 )
|
2009-09-28 22:00:00 +02:00
|
|
|
|
{
|
2009-11-03 22:00:00 +01:00
|
|
|
|
char *entities = NULL;
|
|
|
|
|
|
|
|
|
|
FS_Seek( f, lumpofs, SEEK_SET );
|
|
|
|
|
entities = (char *)Z_Malloc( lumplen + 1 );
|
|
|
|
|
FS_Read( f, entities, lumplen );
|
|
|
|
|
ents = Com_OpenScript( "ents", entities, lumplen + 1 );
|
|
|
|
|
Mem_Free( entities ); // no reason to keep it
|
|
|
|
|
}
|
|
|
|
|
FS_Close( f ); // all done
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
2009-11-03 22:00:00 +01:00
|
|
|
|
return ents;
|
|
|
|
|
}
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
2010-04-02 22:00:00 +02:00
|
|
|
|
int SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name )
|
2009-11-03 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
script_t *ents = NULL;
|
2010-04-02 22:00:00 +02:00
|
|
|
|
int flags = 0;
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
2009-11-03 22:00:00 +01:00
|
|
|
|
ents = SV_GetEntityScript( filename );
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
2009-11-03 22:00:00 +01:00
|
|
|
|
if( ents )
|
|
|
|
|
{
|
|
|
|
|
// if there are entities to parse, a missing message key just
|
|
|
|
|
// means there is no title, so clear the message string now
|
|
|
|
|
token_t token;
|
2010-04-02 22:00:00 +02:00
|
|
|
|
string check_name;
|
|
|
|
|
bool need_landmark = com.strlen( landmark_name ) > 0 ? true : false;
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
2010-04-02 22:00:00 +02:00
|
|
|
|
if( !need_landmark && host.developer >= 2 )
|
2009-09-28 22:00:00 +02:00
|
|
|
|
{
|
2010-04-02 22:00:00 +02:00
|
|
|
|
// not transition,
|
2009-11-03 22:00:00 +01:00
|
|
|
|
Com_CloseScript( ents );
|
2010-04-02 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// skip spawnpoint checks in devmode
|
|
|
|
|
return (MAP_IS_EXIST|MAP_HAS_SPAWNPOINT);
|
2009-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-02 22:00:00 +02:00
|
|
|
|
flags |= MAP_IS_EXIST; // map is exist
|
|
|
|
|
|
2010-06-08 22:00:00 +02:00
|
|
|
|
while( Com_ReadToken( ents, SC_ALLOW_NEWLINES|SC_ALLOW_PATHNAMES2, &token ))
|
2009-09-28 22:00:00 +02:00
|
|
|
|
{
|
2009-11-03 22:00:00 +01:00
|
|
|
|
if( !com.strcmp( token.string, "classname" ))
|
2009-09-28 22:00:00 +02:00
|
|
|
|
{
|
2009-11-03 22:00:00 +01:00
|
|
|
|
// check classname for spawn entity
|
2010-06-08 22:00:00 +02:00
|
|
|
|
Com_ReadString( ents, SC_ALLOW_PATHNAMES2, check_name );
|
2010-04-02 22:00:00 +02:00
|
|
|
|
if( !com.strcmp( spawn_entity, check_name ))
|
|
|
|
|
{
|
|
|
|
|
flags |= MAP_HAS_SPAWNPOINT;
|
|
|
|
|
|
|
|
|
|
// we already find landmark, stop the parsing
|
|
|
|
|
if( need_landmark && flags & MAP_HAS_LANDMARK )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( need_landmark && !com.strcmp( token.string, "targetname" ))
|
|
|
|
|
{
|
|
|
|
|
// check targetname for landmark entity
|
2010-06-08 22:00:00 +02:00
|
|
|
|
Com_ReadString( ents, SC_ALLOW_PATHNAMES2, check_name );
|
2010-04-02 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( !com.strcmp( landmark_name, check_name ))
|
2009-09-28 22:00:00 +02:00
|
|
|
|
{
|
2010-04-02 22:00:00 +02:00
|
|
|
|
flags |= MAP_HAS_LANDMARK;
|
|
|
|
|
|
|
|
|
|
// we already find spawnpoint, stop the parsing
|
|
|
|
|
if( flags & MAP_HAS_SPAWNPOINT )
|
|
|
|
|
break;
|
2009-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-11-03 22:00:00 +01:00
|
|
|
|
Com_CloseScript( ents );
|
2009-09-28 22:00:00 +02:00
|
|
|
|
}
|
2010-04-02 22:00:00 +02:00
|
|
|
|
return flags;
|
2009-09-28 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-24 22:00:00 +02:00
|
|
|
|
void SV_InitEdict( edict_t *pEdict )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-07-29 22:00:00 +02:00
|
|
|
|
ASSERT( pEdict );
|
|
|
|
|
ASSERT( pEdict->pvPrivateData == NULL );
|
|
|
|
|
ASSERT( pEdict->pvServerData == NULL );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2008-12-16 22:00:00 +01:00
|
|
|
|
pEdict->v.pContainingEntity = pEdict; // make cross-links for consistency
|
2009-09-24 22:00:00 +02:00
|
|
|
|
pEdict->pvServerData = (sv_priv_t *)Mem_Alloc( svgame.mempool, sizeof( sv_priv_t ));
|
2008-12-26 22:00:00 +01:00
|
|
|
|
pEdict->pvPrivateData = NULL; // will be alloced later by pfnAllocPrivateData
|
2009-01-04 22:00:00 +01:00
|
|
|
|
pEdict->serialnumber = NUM_FOR_EDICT( pEdict );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pEdict->free = false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-16 22:00:00 +01:00
|
|
|
|
void SV_FreeEdict( edict_t *pEdict )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-07-29 22:00:00 +02:00
|
|
|
|
ASSERT( pEdict );
|
|
|
|
|
ASSERT( pEdict->free == false );
|
2008-12-17 22:00:00 +01:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// unlink from world
|
2008-12-16 22:00:00 +01:00
|
|
|
|
SV_UnlinkEdict( pEdict );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2008-12-16 22:00:00 +01:00
|
|
|
|
if( pEdict->pvServerData ) Mem_Free( pEdict->pvServerData );
|
2009-09-24 22:00:00 +02:00
|
|
|
|
if( pEdict->pvPrivateData )
|
|
|
|
|
{
|
|
|
|
|
svgame.dllFuncs.pfnOnFreeEntPrivateData( pEdict );
|
|
|
|
|
Mem_Free( pEdict->pvPrivateData );
|
|
|
|
|
}
|
|
|
|
|
Mem_Set( pEdict, 0, sizeof( *pEdict ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// mark edict as freed
|
2010-07-23 22:00:00 +02:00
|
|
|
|
pEdict->freetime = sv_time();
|
2008-12-16 22:00:00 +01:00
|
|
|
|
pEdict->v.nextthink = -1;
|
|
|
|
|
pEdict->free = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
edict_t *SV_AllocEdict( void )
|
|
|
|
|
{
|
|
|
|
|
edict_t *pEdict;
|
|
|
|
|
int i;
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
for( i = svgame.globals->maxClients + 1; i < svgame.globals->numEntities; i++ )
|
2008-12-16 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
pEdict = EDICT_NUM( i );
|
|
|
|
|
// the first couple seconds of server time can involve a lot of
|
|
|
|
|
// freeing and allocating, so relax the replacement policy
|
2010-07-23 22:00:00 +02:00
|
|
|
|
if( pEdict->free && ( pEdict->freetime < 2.0 || sv_time() - pEdict->freetime > 0.5 ))
|
2008-12-16 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
SV_InitEdict( pEdict );
|
|
|
|
|
return pEdict;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-13 22:00:00 +02:00
|
|
|
|
if( i >= svgame.globals->maxEntities )
|
|
|
|
|
Host_Error( "ED_AllocEdict: no free edicts\n" );
|
2008-12-16 22:00:00 +01:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->numEntities++;
|
2008-12-16 22:00:00 +01:00
|
|
|
|
pEdict = EDICT_NUM( i );
|
|
|
|
|
SV_InitEdict( pEdict );
|
|
|
|
|
|
|
|
|
|
return pEdict;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-01-10 22:00:00 +01:00
|
|
|
|
edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
|
|
|
|
|
{
|
|
|
|
|
const char *pszClassName;
|
|
|
|
|
LINK_ENTITY_FUNC SpawnEdict;
|
|
|
|
|
|
|
|
|
|
pszClassName = STRING( className );
|
2010-03-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( !ent )
|
|
|
|
|
{
|
|
|
|
|
// allocate new one
|
|
|
|
|
ent = SV_AllocEdict();
|
|
|
|
|
}
|
2009-09-24 22:00:00 +02:00
|
|
|
|
else if( ent->free )
|
|
|
|
|
{
|
2010-02-16 22:00:00 +01:00
|
|
|
|
SV_InitEdict( ent ); // re-init edict
|
|
|
|
|
MsgDev( D_WARN, "SV_AllocPrivateData: entity %s is freed!\n", STRING( className ));
|
2009-09-24 22:00:00 +02:00
|
|
|
|
}
|
2010-02-16 22:00:00 +01:00
|
|
|
|
|
2009-01-10 22:00:00 +01:00
|
|
|
|
ent->v.classname = className;
|
|
|
|
|
ent->v.pContainingEntity = ent; // re-link
|
2010-08-07 22:00:00 +02:00
|
|
|
|
|
2010-03-20 22:00:00 +01:00
|
|
|
|
VectorSet( ent->v.rendercolor, 255, 255, 255 ); // assume default color
|
2010-08-07 22:00:00 +02:00
|
|
|
|
ent->v.scale = 1.0f; // set default scale
|
2010-03-20 22:00:00 +01:00
|
|
|
|
|
2009-01-10 22:00:00 +01:00
|
|
|
|
// allocate edict private memory (passed by dlls)
|
2010-03-27 22:00:00 +01:00
|
|
|
|
SpawnEdict = (LINK_ENTITY_FUNC)FS_GetProcAddress( svgame.hInstance, pszClassName );
|
2009-01-10 22:00:00 +01:00
|
|
|
|
if( !SpawnEdict )
|
|
|
|
|
{
|
|
|
|
|
// attempt to create custom entity
|
|
|
|
|
if( svgame.dllFuncs.pfnCreate( ent, pszClassName ) == -1 )
|
|
|
|
|
{
|
|
|
|
|
ent->v.flags |= FL_KILLME;
|
2009-09-24 22:00:00 +02:00
|
|
|
|
MsgDev( D_ERROR, "No spawn function for %s\n", STRING( className ));
|
2009-01-10 22:00:00 +01:00
|
|
|
|
return ent; // this edict will be removed from map
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else SpawnEdict( &ent->v );
|
|
|
|
|
|
2010-07-29 22:00:00 +02:00
|
|
|
|
ASSERT( ent->pvServerData )
|
2009-01-10 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// also register classname to send for client
|
|
|
|
|
ent->pvServerData->s.classname = SV_ClassIndex( pszClassName );
|
|
|
|
|
|
|
|
|
|
return ent;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
void SV_FreeEdicts( void )
|
|
|
|
|
{
|
2009-09-28 22:00:00 +02:00
|
|
|
|
int i = 0;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
edict_t *ent;
|
|
|
|
|
|
|
|
|
|
for( i = 0; i < svgame.globals->numEntities; i++ )
|
|
|
|
|
{
|
|
|
|
|
ent = EDICT_NUM( i );
|
|
|
|
|
if( ent->free ) continue;
|
|
|
|
|
SV_FreeEdict( ent );
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2010-08-06 22:00:00 +02:00
|
|
|
|
void SV_PlaybackEvent( sizebuf_t *msg, event_info_t *info )
|
2009-12-02 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
event_args_t nullargs;
|
|
|
|
|
|
2010-07-29 22:00:00 +02:00
|
|
|
|
ASSERT( msg );
|
|
|
|
|
ASSERT( info );
|
2009-12-02 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
Mem_Set( &nullargs, 0, sizeof( nullargs ));
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteWord( msg, info->index ); // send event index
|
|
|
|
|
BF_WriteWord( msg, (int)( info->fire_time * 100.0f )); // send event delay
|
2009-12-02 22:00:00 +01:00
|
|
|
|
MSG_WriteDeltaEvent( msg, &nullargs, &info->args ); // FIXME: zero-compressing
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
bool SV_IsValidEdict( const edict_t *e )
|
|
|
|
|
{
|
|
|
|
|
if( !e ) return false;
|
|
|
|
|
if( e->free ) return false;
|
|
|
|
|
if( !e->pvServerData ) return false;
|
|
|
|
|
// edict without pvPrivateData is valid edict
|
|
|
|
|
// server.dll know how allocate it
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *SV_ClassName( const edict_t *e )
|
|
|
|
|
{
|
|
|
|
|
if( !e ) return "(null)";
|
|
|
|
|
if( e->free ) return "freed";
|
|
|
|
|
return STRING( e->v.classname );
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
static bool SV_IsValidCmd( const char *pCmd )
|
|
|
|
|
{
|
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
|
|
len = com.strlen( pCmd );
|
|
|
|
|
|
|
|
|
|
// valid commands all have a ';' or newline '\n' as their last character
|
|
|
|
|
if( len && ( pCmd[len-1] == '\n' || pCmd[len-1] == ';' ))
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, bool spawned_only )
|
|
|
|
|
{
|
|
|
|
|
sv_client_t *client;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if( !SV_IsValidEdict( pEdict ))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
i = NUM_FOR_EDICT( pEdict ) - 1;
|
|
|
|
|
if( i < 0 || i >= sv_maxclients->integer )
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if( spawned_only )
|
|
|
|
|
{
|
|
|
|
|
if( svs.clients[i].state != cs_spawned )
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-03-20 22:00:00 +01:00
|
|
|
|
#if 0
|
2009-11-23 22:00:00 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( svs.clients[i].state < cs_connected )
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-03-20 22:00:00 +01:00
|
|
|
|
#endif
|
2009-11-23 22:00:00 +01:00
|
|
|
|
client = svs.clients + i;
|
|
|
|
|
|
|
|
|
|
return client;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-28 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
SV_BaselineForEntity
|
|
|
|
|
|
|
|
|
|
assume pEdict is valid
|
|
|
|
|
=========
|
|
|
|
|
*/
|
2010-06-28 22:00:00 +02:00
|
|
|
|
void SV_BaselineForEntity( edict_t *pEdict )
|
2009-11-28 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
sv_priv_t *sv_ent;
|
|
|
|
|
|
|
|
|
|
sv_ent = pEdict->pvServerData;
|
|
|
|
|
if( !sv_ent ) return;
|
|
|
|
|
|
|
|
|
|
// update baseline for new entity
|
|
|
|
|
if( !sv_ent->s.number )
|
|
|
|
|
{
|
2010-06-28 22:00:00 +02:00
|
|
|
|
int modelindex;
|
|
|
|
|
sv_client_t *cl;
|
2009-11-28 22:00:00 +01:00
|
|
|
|
|
2010-06-28 22:00:00 +02:00
|
|
|
|
sv_ent->s.classname = SV_ClassIndex( STRING( pEdict->v.classname ));
|
|
|
|
|
sv_ent->s.number = pEdict->serialnumber;
|
|
|
|
|
|
|
|
|
|
if( pEdict->v.flags & FL_CLIENT && ( cl = SV_ClientFromEdict( pEdict, false )))
|
|
|
|
|
modelindex = cl->modelindex ? cl->modelindex : pEdict->v.modelindex;
|
|
|
|
|
else modelindex = pEdict->v.modelindex;
|
2009-11-28 22:00:00 +01:00
|
|
|
|
|
2010-04-24 22:00:00 +02:00
|
|
|
|
if( pEdict->v.modelindex || pEdict->v.effects )
|
2009-11-28 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
// take current state as baseline
|
2010-06-28 22:00:00 +02:00
|
|
|
|
svgame.dllFuncs.pfnCreateBaseline( &sv_ent->s, pEdict, modelindex );
|
|
|
|
|
svs.baselines[pEdict->serialnumber] = sv_ent->s;
|
2009-11-28 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-28 22:00:00 +02:00
|
|
|
|
if( sv.state == ss_active && ( sv_ent->s.modelindex || sv_ent->s.effects ))
|
2009-11-28 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
entity_state_t nullstate;
|
|
|
|
|
|
|
|
|
|
Mem_Set( &nullstate, 0, sizeof( nullstate ));
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_spawnbaseline );
|
|
|
|
|
MSG_WriteDeltaEntity( &nullstate, &sv_ent->s, &sv.multicast, true, sv.time );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_DirectSend( MSG_ALL, vec3_origin, NULL );
|
2009-11-28 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
SV_ClassifyEdict
|
|
|
|
|
|
|
|
|
|
sorting edict by type
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
void SV_ClassifyEdict( edict_t *ent, int m_iNewClass )
|
|
|
|
|
{
|
|
|
|
|
sv_priv_t *sv_ent;
|
|
|
|
|
|
|
|
|
|
sv_ent = ent->pvServerData;
|
|
|
|
|
if( !sv_ent ) return;
|
|
|
|
|
|
|
|
|
|
// take baseline
|
|
|
|
|
SV_BaselineForEntity( ent );
|
|
|
|
|
|
|
|
|
|
if( m_iNewClass != ED_SPAWNED )
|
|
|
|
|
{
|
|
|
|
|
sv_ent->s.ed_type = m_iNewClass;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( sv_ent->s.ed_type != ED_SPAWNED )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// auto-classify
|
|
|
|
|
sv_ent->s.ed_type = svgame.dllFuncs.pfnClassifyEdict( ent );
|
|
|
|
|
|
|
|
|
|
if( sv_ent->s.ed_type != ED_SPAWNED )
|
|
|
|
|
{
|
2010-04-09 22:00:00 +02:00
|
|
|
|
MsgDev( D_NOTE, "AutoClass: %s: <%s>\n", STRING( ent->v.classname ), ed_name[sv_ent->s.ed_type] );
|
2009-11-28 22:00:00 +01:00
|
|
|
|
}
|
2010-04-09 22:00:00 +02:00
|
|
|
|
// else leave unclassified, wait for next SV_LinkEdict...
|
2009-11-28 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
void SV_SetClientMaxspeed( sv_client_t *cl, float fNewMaxspeed )
|
|
|
|
|
{
|
|
|
|
|
// fakeclients must be changed speed too
|
|
|
|
|
fNewMaxspeed = bound( -svgame.movevars.maxspeed, fNewMaxspeed, svgame.movevars.maxspeed );
|
|
|
|
|
|
|
|
|
|
cl->edict->v.maxspeed = fNewMaxspeed;
|
2010-08-05 22:00:00 +02:00
|
|
|
|
Info_SetValueForKey( cl->physinfo, "maxspd", va( "%.f", fNewMaxspeed ));
|
2009-11-23 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
===============================================================================
|
2009-09-23 22:00:00 +02:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
Game Builtin Functions
|
|
|
|
|
|
|
|
|
|
===============================================================================
|
|
|
|
|
*/
|
2008-12-25 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
pfnMemAlloc
|
|
|
|
|
|
|
|
|
|
=========
|
|
|
|
|
*/
|
|
|
|
|
static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline )
|
2008-12-20 22:00:00 +01:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
return com.malloc( svgame.private, cb, filename, fileline );
|
2008-12-20 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-25 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
pfnMemFree
|
|
|
|
|
|
|
|
|
|
=========
|
|
|
|
|
*/
|
|
|
|
|
static void pfnMemFree( void *mem, const char *filename, const int fileline )
|
2008-12-20 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
com.free( mem, filename, fileline );
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
pfnPrecacheModel
|
|
|
|
|
|
|
|
|
|
=========
|
|
|
|
|
*/
|
|
|
|
|
int pfnPrecacheModel( const char *s )
|
|
|
|
|
{
|
2009-10-29 22:00:00 +01:00
|
|
|
|
int modelIndex = SV_ModelIndex( s );
|
|
|
|
|
|
|
|
|
|
CM_RegisterModel( s, modelIndex );
|
|
|
|
|
|
|
|
|
|
return modelIndex;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
pfnPrecacheSound
|
|
|
|
|
|
|
|
|
|
=========
|
|
|
|
|
*/
|
|
|
|
|
int pfnPrecacheSound( const char *s )
|
|
|
|
|
{
|
|
|
|
|
return SV_SoundIndex( s );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnSetModel
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
void pfnSetModel( edict_t *e, const char *m )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( e ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_SetModel: invalid entity %s\n", SV_ClassName( e ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !m || m[0] <= ' ' )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_SetModel: null name\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
SV_SetModel( e, m );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnModelIndex
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
int pfnModelIndex( const char *m )
|
|
|
|
|
{
|
|
|
|
|
int index;
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
if( !m || !m[0] ) return 0;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
index = SV_FindIndex( m, CS_MODELS, MAX_MODELS, false );
|
|
|
|
|
if( !index ) MsgDev( D_WARN, "SV_ModelIndex: %s not precached\n", m );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnModelFrames
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
int pfnModelFrames( int modelIndex )
|
|
|
|
|
{
|
2009-10-28 22:00:00 +01:00
|
|
|
|
int numFrames = 0;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-10-28 22:00:00 +01:00
|
|
|
|
Mod_GetFrames( modelIndex, &numFrames );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-10-28 22:00:00 +01:00
|
|
|
|
return numFrames;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnSetSize
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
void pfnSetSize( edict_t *e, const float *rgflMin, const float *rgflMax )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( e ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_SetSize: invalid entity %s\n", SV_ClassName( e ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// ignore world silently
|
|
|
|
|
if( e == EDICT_NUM( 0 ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
2009-09-23 22:00:00 +02:00
|
|
|
|
SV_SetMinMaxSize( e, rgflMin, rgflMax );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnChangeLevel
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
void pfnChangeLevel( const char* s1, const char* s2 )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !s1 || s1[0] <= ' ' ) return;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-03-24 22:00:00 +01:00
|
|
|
|
// make sure we don't issue two changelevels
|
2010-06-20 22:00:00 +02:00
|
|
|
|
if( svs.changelevel_next_time > sv.time )
|
2010-04-02 22:00:00 +02:00
|
|
|
|
return;
|
2010-03-24 22:00:00 +01:00
|
|
|
|
|
2010-07-23 22:00:00 +02:00
|
|
|
|
svs.changelevel_next_time = sv.time + 1000; // rest 1 secs if failed
|
2010-03-24 22:00:00 +01:00
|
|
|
|
|
2009-09-28 22:00:00 +02:00
|
|
|
|
if( !s2 ) Cbuf_AddText( va( "changelevel %s\n", s1 )); // Quake changlevel
|
|
|
|
|
else Cbuf_AddText( va( "changelevel %s %s\n", s1, s2 )); // Half-Life changelevel
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnVecToYaw
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
float pfnVecToYaw( const float *rgflVector )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !rgflVector ) return 0;
|
|
|
|
|
return SV_VecToYaw( rgflVector );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnVecToAngles
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
void pfnVecToAngles( const float *rgflVectorIn, float *rgflVectorOut )
|
|
|
|
|
{
|
|
|
|
|
float forward;
|
|
|
|
|
float yaw, pitch;
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !rgflVectorIn )
|
|
|
|
|
{
|
|
|
|
|
if( rgflVectorOut ) VectorClear( rgflVectorOut );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( rgflVectorIn[1] == 0 && rgflVectorIn[0] == 0 )
|
|
|
|
|
{
|
|
|
|
|
yaw = 0;
|
|
|
|
|
if( rgflVectorIn[2] > 0 )
|
|
|
|
|
pitch = 90;
|
|
|
|
|
else pitch = 270;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( rgflVectorIn[0] )
|
|
|
|
|
{
|
|
|
|
|
yaw = (int)( com.atan2( rgflVectorIn[1], rgflVectorIn[0] ) * 180 / M_PI );
|
|
|
|
|
if( yaw < 0 ) yaw += 360;
|
|
|
|
|
}
|
|
|
|
|
else if( rgflVectorIn[1] > 0 )
|
|
|
|
|
yaw = 90;
|
|
|
|
|
else yaw = 270;
|
|
|
|
|
|
|
|
|
|
forward = com.sqrt( rgflVectorIn[0] * rgflVectorIn[0] + rgflVectorIn[1] * rgflVectorIn[1] );
|
|
|
|
|
pitch = (int)( com.atan2( rgflVectorIn[2], forward ) * 180 / M_PI );
|
|
|
|
|
if( pitch < 0 ) pitch += 360;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( rgflVectorOut ) VectorSet( rgflVectorOut, pitch, yaw, 0 );
|
|
|
|
|
else MsgDev( D_ERROR, "SV_VecToAngles: no output vector specified\n" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnMoveToOrigin
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
void pfnMoveToOrigin( edict_t *ent, const float *pflGoal, float dist, int iMoveType )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( ent ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_MoveToOrigin: invalid entity %s\n", SV_ClassName( ent ));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-04-01 22:00:00 +02:00
|
|
|
|
if( !pflGoal )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_MoveToOrigin: invalid goal pos\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
SV_MoveToOrigin( ent, pflGoal, dist, iMoveType );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
pfnChangeYaw
|
|
|
|
|
|
|
|
|
|
==============
|
|
|
|
|
*/
|
|
|
|
|
void pfnChangeYaw( edict_t* ent )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( ent ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_ChangeYaw: invalid entity %s\n", SV_ClassName( ent ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-01 22:00:00 +02:00
|
|
|
|
ent->v.angles[YAW] = SV_AngleMod( ent->v.ideal_yaw, ent->v.angles[YAW], ent->v.yaw_speed );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
pfnChangePitch
|
|
|
|
|
|
|
|
|
|
==============
|
|
|
|
|
*/
|
|
|
|
|
void pfnChangePitch( edict_t* ent )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( ent ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_ChangePitch: invalid entity %s\n", SV_ClassName( ent ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
ent->v.angles[PITCH] = SV_AngleMod( ent->v.idealpitch, ent->v.angles[PITCH], ent->v.pitch_speed );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
pfnFindEntityByString
|
|
|
|
|
|
|
|
|
|
=========
|
|
|
|
|
*/
|
|
|
|
|
edict_t* pfnFindEntityByString( edict_t *pStartEdict, const char *pszField, const char *pszValue )
|
|
|
|
|
{
|
2009-09-23 22:00:00 +02:00
|
|
|
|
int index = 0, e = 0;
|
|
|
|
|
TYPEDESCRIPTION *desc = NULL;
|
2010-06-28 22:00:00 +02:00
|
|
|
|
edict_t *ed;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
const char *t;
|
2008-12-20 22:00:00 +01:00
|
|
|
|
|
2009-01-04 22:00:00 +01:00
|
|
|
|
if( pStartEdict ) e = NUM_FOR_EDICT( pStartEdict );
|
2010-05-28 22:00:00 +02:00
|
|
|
|
if( !pszValue || !*pszValue ) return svgame.edicts;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-06-28 22:00:00 +02:00
|
|
|
|
while(( desc = SV_GetEntvarsDescirption( index++ )) != NULL )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-09-23 22:00:00 +02:00
|
|
|
|
if( !com.strcmp( pszField, desc->fieldName ))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( desc == NULL )
|
|
|
|
|
{
|
2010-06-28 22:00:00 +02:00
|
|
|
|
MsgDev( D_ERROR, "SV_FindEntityByString: field %s not a string\n", pszField );
|
2010-05-28 22:00:00 +02:00
|
|
|
|
return svgame.edicts;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
for( e++; e < svgame.globals->numEntities; e++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
ed = EDICT_NUM( e );
|
2010-07-26 22:00:00 +02:00
|
|
|
|
|
2010-03-30 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( ed )) continue;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-09-23 22:00:00 +02:00
|
|
|
|
switch( desc->fieldType )
|
|
|
|
|
{
|
|
|
|
|
case FIELD_STRING:
|
|
|
|
|
case FIELD_MODELNAME:
|
|
|
|
|
case FIELD_SOUNDNAME:
|
|
|
|
|
t = STRING( *(string_t *)&((byte *)&ed->v)[desc->fieldOffset] );
|
|
|
|
|
if( !t ) t = "";
|
|
|
|
|
if( !com.strcmp( t, pszValue ))
|
|
|
|
|
return ed;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2010-05-28 22:00:00 +02:00
|
|
|
|
return svgame.edicts;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
pfnGetEntityIllum
|
|
|
|
|
|
2010-07-01 22:00:00 +02:00
|
|
|
|
returns weighted lightvalue for entity position
|
2008-12-15 22:00:00 +01:00
|
|
|
|
==============
|
|
|
|
|
*/
|
|
|
|
|
int pfnGetEntityIllum( edict_t* pEnt )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( pEnt ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_GetEntityIllum: invalid entity %s\n", SV_ClassName( pEnt ));
|
2010-07-01 22:00:00 +02:00
|
|
|
|
return 0;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2010-07-01 22:00:00 +02:00
|
|
|
|
return CM_LightEntity( pEnt );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnFindEntityInSphere
|
|
|
|
|
|
|
|
|
|
return NULL instead of world
|
|
|
|
|
=================
|
|
|
|
|
*/
|
2009-11-16 22:00:00 +01:00
|
|
|
|
edict_t* pfnFindEntityInSphere( edict_t *pStartEdict, const float *org, float flRadius )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2008-12-18 22:00:00 +01:00
|
|
|
|
edict_t *ent;
|
2009-11-16 22:00:00 +01:00
|
|
|
|
float distSquared;
|
|
|
|
|
float eorg;
|
|
|
|
|
int j, e = 0;
|
|
|
|
|
|
|
|
|
|
flRadius *= flRadius;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-03-30 22:00:00 +02:00
|
|
|
|
if( SV_IsValidEdict( pStartEdict ))
|
2008-12-17 22:00:00 +01:00
|
|
|
|
e = NUM_FOR_EDICT( pStartEdict );
|
2009-11-16 22:00:00 +01:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
for( e++; e < svgame.globals->numEntities; e++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
ent = EDICT_NUM( e );
|
2010-03-30 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( ent )) continue;
|
2010-07-26 22:00:00 +02:00
|
|
|
|
if( !ent->pvPrivateData ) continue;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-11-16 22:00:00 +01:00
|
|
|
|
distSquared = 0;
|
|
|
|
|
for( j = 0; j < 3 && distSquared <= flRadius; j++ )
|
|
|
|
|
{
|
|
|
|
|
if( org[j] < ent->v.absmin[j] )
|
|
|
|
|
eorg = org[j] - ent->v.absmin[j];
|
|
|
|
|
else if( org[j] > ent->v.absmax[j] )
|
|
|
|
|
eorg = org[j] - ent->v.absmax[j];
|
|
|
|
|
else eorg = 0;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-11-16 22:00:00 +01:00
|
|
|
|
distSquared += eorg * eorg;
|
|
|
|
|
}
|
|
|
|
|
if( distSquared > flRadius )
|
|
|
|
|
continue;
|
|
|
|
|
return ent;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2010-07-26 22:00:00 +02:00
|
|
|
|
return svgame.edicts;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnFindClientInPVS
|
|
|
|
|
|
|
|
|
|
return NULL instead of world
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
edict_t* pfnFindClientInPVS( edict_t *pEdict )
|
|
|
|
|
{
|
2010-03-30 22:00:00 +02:00
|
|
|
|
edict_t *pClient;
|
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
const float *org;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if( !SV_IsValidEdict( pEdict ))
|
|
|
|
|
return NULL;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-01-31 22:00:00 +01:00
|
|
|
|
for( i = 0; i < svgame.globals->maxClients; i++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-01-31 22:00:00 +01:00
|
|
|
|
pClient = EDICT_NUM( i + 1 );
|
2010-03-30 22:00:00 +02:00
|
|
|
|
if(( cl = SV_ClientFromEdict( pClient, true )) == NULL )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// check for SET_VIEW
|
|
|
|
|
if( SV_IsValidEdict( cl->pViewEntity ))
|
|
|
|
|
org = cl->pViewEntity->v.origin;
|
|
|
|
|
else org = pClient->v.origin;
|
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
if( SV_OriginIn( DVIS_PVS, pEdict->v.origin, org ))
|
2010-03-30 22:00:00 +02:00
|
|
|
|
return pClient;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2008-12-18 22:00:00 +01:00
|
|
|
|
return NULL;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnFindClientInPHS
|
|
|
|
|
|
|
|
|
|
return NULL instead of world
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
edict_t* pfnFindClientInPHS( edict_t *pEdict )
|
|
|
|
|
{
|
2010-03-30 22:00:00 +02:00
|
|
|
|
edict_t *pClient;
|
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
const float *org;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if( !SV_IsValidEdict( pEdict ))
|
|
|
|
|
return NULL;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-01-31 22:00:00 +01:00
|
|
|
|
for( i = 0; i < svgame.globals->maxClients; i++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-01-31 22:00:00 +01:00
|
|
|
|
pClient = EDICT_NUM( i + 1 );
|
2010-03-30 22:00:00 +02:00
|
|
|
|
if(( cl = SV_ClientFromEdict( pClient, true )) == NULL )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// check for SET_VIEW
|
|
|
|
|
if( SV_IsValidEdict( cl->pViewEntity ))
|
|
|
|
|
org = cl->pViewEntity->v.origin;
|
|
|
|
|
else org = pClient->v.origin;
|
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
if( SV_OriginIn( DVIS_PHS, pEdict->v.origin, org ))
|
2010-03-30 22:00:00 +02:00
|
|
|
|
return pClient;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2008-12-18 22:00:00 +01:00
|
|
|
|
return NULL;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnEntitiesInPVS
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
2010-04-12 22:00:00 +02:00
|
|
|
|
edict_t *pfnEntitiesInPVS( edict_t *pplayer )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
edict_t *pEdict, *chain;
|
2010-04-12 22:00:00 +02:00
|
|
|
|
int i, result;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( pplayer ))
|
|
|
|
|
return NULL;
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
for( chain = NULL, i = svgame.globals->maxClients + 1; i < svgame.globals->numEntities; i++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
pEdict = EDICT_NUM( i );
|
2010-03-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( !SV_IsValidEdict( pEdict )) continue;
|
|
|
|
|
|
|
|
|
|
if( CM_GetModelType( pEdict->v.modelindex ) == mod_brush )
|
2010-04-13 22:00:00 +02:00
|
|
|
|
result = SV_BoxInPVS( pplayer->v.origin, pEdict->v.absmin, pEdict->v.absmax );
|
2010-04-12 22:00:00 +02:00
|
|
|
|
else result = SV_OriginIn( DVIS_PVS, pplayer->v.origin, pEdict->v.origin );
|
2010-03-30 22:00:00 +02:00
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
if( result )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
pEdict->v.chain = chain;
|
|
|
|
|
chain = pEdict;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-06 22:00:00 +01:00
|
|
|
|
return chain;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnEntitiesInPHS
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
2010-04-12 22:00:00 +02:00
|
|
|
|
edict_t *pfnEntitiesInPHS( edict_t *pplayer )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
edict_t *pEdict, *chain;
|
2010-04-13 22:00:00 +02:00
|
|
|
|
vec3_t checkPos;
|
|
|
|
|
int i;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( pplayer ))
|
|
|
|
|
return NULL;
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
for( chain = NULL, i = svgame.globals->maxClients + 1; i < svgame.globals->numEntities; i++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
pEdict = EDICT_NUM( i );
|
2010-03-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( !SV_IsValidEdict( pEdict )) continue;
|
|
|
|
|
|
|
|
|
|
if( CM_GetModelType( pEdict->v.modelindex ) == mod_brush )
|
2010-04-13 22:00:00 +02:00
|
|
|
|
VectorAverage( pEdict->v.absmin, pEdict->v.absmax, checkPos );
|
|
|
|
|
else VectorCopy( pEdict->v.origin, checkPos );
|
2010-03-30 22:00:00 +02:00
|
|
|
|
|
2010-04-13 22:00:00 +02:00
|
|
|
|
if( SV_OriginIn( DVIS_PHS, pplayer->v.origin, checkPos ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
pEdict->v.chain = chain;
|
|
|
|
|
chain = pEdict;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-01-06 22:00:00 +01:00
|
|
|
|
return chain;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
pfnMakeVectors
|
|
|
|
|
|
|
|
|
|
==============
|
|
|
|
|
*/
|
|
|
|
|
void pfnMakeVectors( const float *rgflVector )
|
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
AngleVectors( rgflVector, svgame.globals->v_forward, svgame.globals->v_right, svgame.globals->v_up );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
pfnCreateEntity
|
|
|
|
|
|
|
|
|
|
just allocate new one
|
|
|
|
|
==============
|
|
|
|
|
*/
|
|
|
|
|
edict_t* pfnCreateEntity( void )
|
|
|
|
|
{
|
|
|
|
|
return SV_AllocEdict();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
pfnRemoveEntity
|
|
|
|
|
|
|
|
|
|
free edict private mem, unlink physics etc
|
|
|
|
|
==============
|
|
|
|
|
*/
|
|
|
|
|
void pfnRemoveEntity( edict_t* e )
|
|
|
|
|
{
|
2010-04-03 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( e ))
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_RemoveEntity: entity already freed\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// never free client or world entity
|
2010-04-03 22:00:00 +02:00
|
|
|
|
if( e->serialnumber < ( svgame.globals->maxClients + 1 ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "SV_RemoveEntity: can't delete %s\n", (e == EDICT_NUM( 0 )) ? "world" : "client" );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
SV_FreeEdict( e );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
pfnCreateNamedEntity
|
|
|
|
|
|
|
|
|
|
==============
|
|
|
|
|
*/
|
|
|
|
|
edict_t* pfnCreateNamedEntity( string_t className )
|
|
|
|
|
{
|
2009-01-10 22:00:00 +01:00
|
|
|
|
return SV_AllocPrivateData( NULL, className );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnMakeStatic
|
|
|
|
|
|
|
|
|
|
disable entity updates to client
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
static void pfnMakeStatic( edict_t *ent )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( ent ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_MakeStatic: invalid entity %s\n", SV_ClassName( ent ));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2008-12-26 22:00:00 +01:00
|
|
|
|
ent->pvServerData->s.ed_type = ED_STATIC;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2009-01-11 22:00:00 +01:00
|
|
|
|
pfnLinkEntity
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-01-11 22:00:00 +01:00
|
|
|
|
Xash3D extension
|
2008-12-15 22:00:00 +01:00
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
static void pfnLinkEntity( edict_t *e, int touch_triggers )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( e ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_LinkEntity: invalid entity %s\n", SV_ClassName( e ));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
SV_LinkEdict( e, touch_triggers );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
===============
|
|
|
|
|
pfnDropToFloor
|
|
|
|
|
|
|
|
|
|
===============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
int pfnDropToFloor( edict_t* e )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-02 22:00:00 +01:00
|
|
|
|
vec3_t end;
|
|
|
|
|
trace_t trace;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-04-12 22:00:00 +02:00
|
|
|
|
if( sv.loadgame )
|
|
|
|
|
return 0;
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( e ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-01-31 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "SV_DropToFloor: invalid entity %s\n", SV_ClassName( e ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
VectorCopy( e->v.origin, end );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
end[2] -= 256;
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
trace = SV_Move( e->v.origin, e->v.mins, e->v.maxs, end, MOVE_NORMAL, e );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-06-27 22:00:00 +02:00
|
|
|
|
if( trace.flFraction == 1.0f || trace.fAllSolid )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-06-27 22:00:00 +02:00
|
|
|
|
return false;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2010-04-09 22:00:00 +02:00
|
|
|
|
|
2010-06-27 22:00:00 +02:00
|
|
|
|
VectorCopy( trace.vecEndPos, e->v.origin );
|
|
|
|
|
SV_LinkEdict( e, false );
|
|
|
|
|
e->v.flags |= FL_ONGROUND;
|
|
|
|
|
e->v.groundentity = trace.pHit;
|
2010-04-09 22:00:00 +02:00
|
|
|
|
|
2010-06-27 22:00:00 +02:00
|
|
|
|
return true;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
===============
|
|
|
|
|
pfnWalkMove
|
|
|
|
|
|
|
|
|
|
===============
|
|
|
|
|
*/
|
|
|
|
|
int pfnWalkMove( edict_t *ent, float yaw, float dist, int iMode )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
vec3_t move;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( ent ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_WalkMove: invalid entity %s\n", SV_ClassName( ent ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-01 22:00:00 +02:00
|
|
|
|
if(!( ent->v.flags & ( FL_FLY|FL_SWIM|FL_ONGROUND )))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
yaw = yaw * M_PI * 2 / 360;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorSet( move, com.cos( yaw ) * dist, com.sin( yaw ) * dist, 0.0f );
|
2010-04-01 22:00:00 +02:00
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return SV_WalkMove( ent, move, iMode );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnSetOrigin
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
void pfnSetOrigin( edict_t *e, const float *rgflOrigin )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( e ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_SetOrigin: invalid entity %s\n", SV_ClassName( e ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VectorCopy( rgflOrigin, e->v.origin );
|
2009-11-02 22:00:00 +01:00
|
|
|
|
SV_LinkEdict( e, false );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
2009-01-25 22:00:00 +01:00
|
|
|
|
SV_StartSound
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
2009-01-25 22:00:00 +01:00
|
|
|
|
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-04-13 22:00:00 +02:00
|
|
|
|
int sound_idx;
|
2010-07-01 22:00:00 +02:00
|
|
|
|
int entityIndex;
|
2010-04-24 22:00:00 +02:00
|
|
|
|
int msg_dest;
|
2009-11-25 22:00:00 +01:00
|
|
|
|
vec3_t origin;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if( attn < ATTN_NONE || attn > ATTN_IDLE )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_StartSound: attenuation must be in range 0-2\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( chan < 0 || chan > 7 )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_StartSound: channel must be in range 0-7\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( ent ))
|
2008-12-21 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_StartSound: edict == NULL\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-29 22:00:00 +02:00
|
|
|
|
if( vol != VOL_NORM ) flags |= SND_VOLUME;
|
2010-04-24 22:00:00 +02:00
|
|
|
|
if( attn != ATTN_NONE ) flags |= SND_ATTENUATION;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
if( pitch != PITCH_NORM ) flags |= SND_PITCH;
|
|
|
|
|
|
2010-07-01 22:00:00 +02:00
|
|
|
|
// can't track this entity on the client.
|
|
|
|
|
// write static sound
|
|
|
|
|
if( !ent->pvServerData->linked ) flags |= SND_FIXED_ORIGIN;
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
// ultimate method for detect bsp models with invalid solidity (e.g. func_pushable)
|
|
|
|
|
if( CM_GetModelType( ent->v.modelindex ) == mod_brush )
|
2008-12-21 22:00:00 +01:00
|
|
|
|
{
|
2010-04-13 22:00:00 +02:00
|
|
|
|
VectorAverage( ent->v.absmin, ent->v.absmax, origin );
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if( flags & SND_SPAWNING )
|
2010-06-27 22:00:00 +02:00
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
msg_dest = MSG_INIT;
|
2010-06-27 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if( chan == CHAN_STATIC )
|
|
|
|
|
msg_dest = MSG_ALL;
|
2010-06-28 22:00:00 +02:00
|
|
|
|
else msg_dest = MSG_PAS_R;
|
2010-06-27 22:00:00 +02:00
|
|
|
|
}
|
2008-12-21 22:00:00 +01:00
|
|
|
|
}
|
2009-09-29 22:00:00 +02:00
|
|
|
|
else
|
2008-12-21 22:00:00 +01:00
|
|
|
|
{
|
2010-04-13 22:00:00 +02:00
|
|
|
|
VectorAverage( ent->v.mins, ent->v.maxs, origin );
|
|
|
|
|
VectorAdd( origin, ent->v.origin, origin );
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if( flags & SND_SPAWNING )
|
|
|
|
|
msg_dest = MSG_INIT;
|
2010-06-28 22:00:00 +02:00
|
|
|
|
else msg_dest = MSG_PAS_R;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// always sending stop sound command
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( flags & SND_STOP ) msg_dest = MSG_ALL;
|
2008-12-21 22:00:00 +01:00
|
|
|
|
|
2010-06-27 22:00:00 +02:00
|
|
|
|
if( sample[0] == '!' && com.is_digit( sample + 1 ))
|
|
|
|
|
{
|
|
|
|
|
flags |= SND_SENTENCE;
|
|
|
|
|
sound_idx = com.atoi( sample + 1 );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// precache_sound can be used twice: cache sounds when loading
|
|
|
|
|
// and return sound index when server is active
|
|
|
|
|
sound_idx = SV_SoundIndex( sample );
|
|
|
|
|
}
|
2008-12-21 22:00:00 +01:00
|
|
|
|
|
2010-07-01 22:00:00 +02:00
|
|
|
|
if( !ent->pvServerData->linked )
|
|
|
|
|
entityIndex = 0;
|
|
|
|
|
else if( SV_IsValidEdict( ent->v.aiment ))
|
|
|
|
|
entityIndex = ent->v.aiment->serialnumber;
|
|
|
|
|
else entityIndex = ent->serialnumber;
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_sound );
|
|
|
|
|
BF_WriteWord( &sv.multicast, flags );
|
|
|
|
|
BF_WriteWord( &sv.multicast, sound_idx );
|
|
|
|
|
BF_WriteByte( &sv.multicast, chan );
|
2008-12-21 22:00:00 +01:00
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
if( flags & SND_VOLUME ) BF_WriteByte( &sv.multicast, vol * 255 );
|
|
|
|
|
if( flags & SND_ATTENUATION ) BF_WriteByte( &sv.multicast, attn * 64 );
|
|
|
|
|
if( flags & SND_PITCH ) BF_WriteByte( &sv.multicast, pitch );
|
2009-09-29 22:00:00 +02:00
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteWord( &sv.multicast, entityIndex );
|
|
|
|
|
if( flags & SND_FIXED_ORIGIN ) BF_WriteBitVec3Coord( &sv.multicast, origin );
|
2009-09-29 22:00:00 +02:00
|
|
|
|
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( msg_dest, origin, NULL );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnEmitAmbientSound
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
2010-06-28 22:00:00 +02:00
|
|
|
|
void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vol, float attn, int flags, int pitch )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-04-18 22:00:00 +02:00
|
|
|
|
int number = 0, sound_idx;
|
2009-11-25 22:00:00 +01:00
|
|
|
|
int msg_dest = MSG_PAS_R;
|
|
|
|
|
vec3_t origin;
|
2009-10-11 22:00:00 +02:00
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( attn < ATTN_NONE || attn > ATTN_IDLE )
|
2009-10-11 22:00:00 +02:00
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "SV_AmbientSound: attenuation must be in range 0-2\n" );
|
|
|
|
|
return;
|
2009-10-11 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( !pos )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_AmbientSound: pos == NULL!\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-10-11 22:00:00 +02:00
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( sv.state == ss_loading ) flags |= SND_SPAWNING;
|
|
|
|
|
if( vol != VOL_NORM ) flags |= SND_VOLUME;
|
2010-04-24 22:00:00 +02:00
|
|
|
|
if( attn != ATTN_NONE ) flags |= SND_ATTENUATION;
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( pitch != PITCH_NORM ) flags |= SND_PITCH;
|
2009-10-11 22:00:00 +02:00
|
|
|
|
|
2010-04-18 22:00:00 +02:00
|
|
|
|
if( flags & SND_SPAWNING )
|
|
|
|
|
msg_dest = MSG_INIT;
|
2010-06-28 22:00:00 +02:00
|
|
|
|
else msg_dest = MSG_ALL;
|
2010-04-18 22:00:00 +02:00
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
// ultimate method for detect bsp models with invalid solidity (e.g. func_pushable)
|
2010-04-18 22:00:00 +02:00
|
|
|
|
if( SV_IsValidEdict( ent ))
|
2009-10-11 22:00:00 +02:00
|
|
|
|
{
|
2010-04-18 22:00:00 +02:00
|
|
|
|
if( CM_GetModelType( ent->v.modelindex ) == mod_brush )
|
|
|
|
|
{
|
|
|
|
|
VectorAverage( ent->v.absmin, ent->v.absmax, origin );
|
|
|
|
|
number = ent->serialnumber;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
VectorAverage( ent->v.mins, ent->v.maxs, origin );
|
|
|
|
|
VectorAdd( origin, ent->v.origin, origin );
|
|
|
|
|
}
|
2009-10-11 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-04-18 22:00:00 +02:00
|
|
|
|
VectorCopy( pos, origin );
|
2009-10-11 22:00:00 +02:00
|
|
|
|
}
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// always sending stop sound command
|
|
|
|
|
if( flags & SND_STOP ) msg_dest = MSG_ALL;
|
|
|
|
|
flags |= SND_FIXED_ORIGIN;
|
|
|
|
|
|
2010-06-28 22:00:00 +02:00
|
|
|
|
if( sample[0] == '!' && com.is_digit( sample + 1 ))
|
|
|
|
|
{
|
|
|
|
|
flags |= SND_SENTENCE;
|
|
|
|
|
sound_idx = com.atoi( sample + 1 );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// precache_sound can be used twice: cache sounds when loading
|
|
|
|
|
// and return sound index when server is active
|
|
|
|
|
sound_idx = SV_SoundIndex( sample );
|
|
|
|
|
}
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_ambientsound );
|
|
|
|
|
BF_WriteWord( &sv.multicast, flags );
|
|
|
|
|
BF_WriteWord( &sv.multicast, sound_idx );
|
|
|
|
|
BF_WriteByte( &sv.multicast, CHAN_AUTO );
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
if( flags & SND_VOLUME ) BF_WriteByte( &sv.multicast, vol * 255 );
|
|
|
|
|
if( flags & SND_ATTENUATION ) BF_WriteByte( &sv.multicast, attn * 64 );
|
|
|
|
|
if( flags & SND_PITCH ) BF_WriteByte( &sv.multicast, pitch );
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// plays from fixed position
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteWord( &sv.multicast, number );
|
|
|
|
|
BF_WriteBitVec3Coord( &sv.multicast, pos );
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( msg_dest, origin, NULL );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnTraceLine
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
2008-12-25 22:00:00 +01:00
|
|
|
|
static void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-02 22:00:00 +01:00
|
|
|
|
trace_t result;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-12-17 22:00:00 +01:00
|
|
|
|
if( svgame.globals->trace_flags & 1 )
|
2010-05-04 22:00:00 +02:00
|
|
|
|
fNoMonsters |= FMOVE_SIMPLEBOX;
|
2009-12-17 22:00:00 +01:00
|
|
|
|
svgame.globals->trace_flags = 0;
|
|
|
|
|
|
2009-11-15 22:00:00 +01:00
|
|
|
|
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
|
2009-11-23 22:00:00 +01:00
|
|
|
|
Host_Error( "TraceLine: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
|
|
|
|
|
result = SV_Move( v1, vec3_origin, vec3_origin, v2, fNoMonsters, pentToSkip );
|
2010-05-31 22:00:00 +02:00
|
|
|
|
if( ptr ) *ptr = result;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnTraceToss
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
2009-01-11 22:00:00 +01:00
|
|
|
|
static void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-02 22:00:00 +01:00
|
|
|
|
trace_t result;
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( pent ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_MoveToss: invalid entity %s\n", SV_ClassName( pent ));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-02 22:00:00 +01:00
|
|
|
|
result = SV_MoveToss( pent, pentToIgnore );
|
2010-05-31 22:00:00 +02:00
|
|
|
|
if( ptr ) *ptr = result;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnTraceHull
|
|
|
|
|
|
|
|
|
|
=================
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
static void pfnTraceHull( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-02 22:00:00 +01:00
|
|
|
|
trace_t result;
|
2009-11-23 22:00:00 +01:00
|
|
|
|
float *mins, *maxs;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
hullNumber = bound( 0, hullNumber, 3 );
|
|
|
|
|
mins = GI->client_mins[hullNumber];
|
|
|
|
|
maxs = GI->client_maxs[hullNumber];
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-12-17 22:00:00 +01:00
|
|
|
|
if( svgame.globals->trace_flags & 1 )
|
2010-05-04 22:00:00 +02:00
|
|
|
|
fNoMonsters |= FMOVE_SIMPLEBOX;
|
2009-12-17 22:00:00 +01:00
|
|
|
|
svgame.globals->trace_flags = 0;
|
|
|
|
|
|
2009-11-15 22:00:00 +01:00
|
|
|
|
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
|
2009-11-23 22:00:00 +01:00
|
|
|
|
Host_Error( "TraceHull: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
|
|
|
|
|
result = SV_Move( v1, mins, maxs, v2, fNoMonsters, pentToSkip );
|
|
|
|
|
if( ptr ) Mem_Copy( ptr, &result, sizeof( *ptr ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnTraceMonsterHull
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
trace_t result;
|
|
|
|
|
float *mins, *maxs;
|
|
|
|
|
|
|
|
|
|
if( !SV_IsValidEdict( pEdict ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_TraceMonsterHull: invalid entity %s\n", SV_ClassName( pEdict ));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-17 22:00:00 +01:00
|
|
|
|
if( svgame.globals->trace_flags & 1 )
|
2010-05-04 22:00:00 +02:00
|
|
|
|
fNoMonsters |= FMOVE_SIMPLEBOX;
|
2009-12-17 22:00:00 +01:00
|
|
|
|
svgame.globals->trace_flags = 0;
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
mins = pEdict->v.mins;
|
|
|
|
|
maxs = pEdict->v.maxs;
|
|
|
|
|
|
|
|
|
|
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
|
|
|
|
|
Host_Error( "TraceMonsterHull: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
|
|
|
|
|
result = SV_Move( v1, mins, maxs, v2, fNoMonsters, pentToSkip );
|
|
|
|
|
if( ptr ) Mem_Copy( ptr, &result, sizeof( *ptr ));
|
|
|
|
|
|
|
|
|
|
return ptr->fAllSolid;
|
2009-09-22 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnTraceModel
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-01-11 22:00:00 +01:00
|
|
|
|
static void pfnTraceModel( const float *v1, const float *v2, edict_t *pent, TraceResult *ptr )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( pent ))
|
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
MsgDev( D_WARN, "TraceModel: invalid entity %s\n", SV_ClassName( pent ));
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
|
|
|
|
|
Host_Error( "TraceModel: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
|
2010-05-22 22:00:00 +02:00
|
|
|
|
if( ptr ) *ptr = CM_ClipMove( pent, v1, pent->v.mins, pent->v.maxs, v2, 0 );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2009-10-28 22:00:00 +01:00
|
|
|
|
pfnTraceTexture
|
2009-09-22 22:00:00 +02:00
|
|
|
|
|
2009-10-28 22:00:00 +01:00
|
|
|
|
returns texture basename
|
2009-09-22 22:00:00 +02:00
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-01-11 22:00:00 +01:00
|
|
|
|
static const char *pfnTraceTexture( edict_t *pTextureEntity, const float *v1, const float *v2 )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( pTextureEntity ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "TraceTexture: invalid entity %s\n", SV_ClassName( pTextureEntity ));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-15 22:00:00 +01:00
|
|
|
|
if( VectorIsNAN( v1 ) || VectorIsNAN( v2 ))
|
2009-11-23 22:00:00 +01:00
|
|
|
|
Host_Error( "TraceTexture: NAN errors detected '%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] );
|
2010-05-22 22:00:00 +02:00
|
|
|
|
|
2010-07-13 22:00:00 +02:00
|
|
|
|
return CM_TraceTexture( pTextureEntity, v1, v2 );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2010-04-01 22:00:00 +02:00
|
|
|
|
pfnTestEntityPosition
|
2009-09-22 22:00:00 +02:00
|
|
|
|
|
2010-04-01 22:00:00 +02:00
|
|
|
|
returns true if the entity is in solid currently
|
2009-09-22 22:00:00 +02:00
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-06-16 22:00:00 +02:00
|
|
|
|
static int pfnTestEntityPosition( edict_t *pTestEdict )
|
2009-09-22 22:00:00 +02:00
|
|
|
|
{
|
2010-04-01 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( pTestEdict ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_TestEntity: invalid entity %s\n", SV_ClassName( pTestEdict ));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-16 22:00:00 +02:00
|
|
|
|
return SV_TestEntityPosition( pTestEdict );
|
2009-09-22 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetAimVector
|
|
|
|
|
|
|
|
|
|
FIXME: use speed for reduce aiming accuracy
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnGetAimVector( edict_t* ent, float speed, float *rgflReturn )
|
|
|
|
|
{
|
2009-10-28 22:00:00 +01:00
|
|
|
|
edict_t *check, *bestent;
|
|
|
|
|
vec3_t start, dir, end, bestdir;
|
|
|
|
|
float dist, bestdist;
|
|
|
|
|
bool fNoFriendlyFire;
|
|
|
|
|
int i, j;
|
2009-11-02 22:00:00 +01:00
|
|
|
|
trace_t tr;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// these vairable defined in server.dll
|
|
|
|
|
fNoFriendlyFire = Cvar_VariableValue( "mp_friendlyfire" );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
VectorCopy( svgame.globals->v_forward, rgflReturn ); // assume failure if it returns early
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( ent ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_GetAimVector: invalid entity %s\n", SV_ClassName( ent ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VectorCopy( ent->v.origin, start );
|
|
|
|
|
start[2] += 20;
|
|
|
|
|
|
|
|
|
|
// try sending a trace straight
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorCopy( svgame.globals->v_forward, dir );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorMA( start, 2048, dir, end );
|
2009-11-02 22:00:00 +01:00
|
|
|
|
tr = SV_Move( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-10-28 22:00:00 +01:00
|
|
|
|
if( tr.pHit && (tr.pHit->v.takedamage == DAMAGE_AIM && fNoFriendlyFire || ent->v.team <= 0 || ent->v.team != tr.pHit->v.team ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
VectorCopy( svgame.globals->v_forward, rgflReturn );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// try all possible entities
|
|
|
|
|
VectorCopy( dir, bestdir );
|
|
|
|
|
bestdist = 0.5f;
|
|
|
|
|
bestent = NULL;
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
check = EDICT_NUM( 1 ); // start at first client
|
|
|
|
|
for( i = 1; i < svgame.globals->numEntities; i++, check++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
if( check->v.takedamage != DAMAGE_AIM ) continue;
|
|
|
|
|
if( check == ent ) continue;
|
|
|
|
|
if( fNoFriendlyFire && ent->v.team > 0 && ent->v.team == check->v.team )
|
|
|
|
|
continue; // don't aim at teammate
|
|
|
|
|
for( j = 0; j < 3; j++ )
|
2010-03-30 22:00:00 +02:00
|
|
|
|
end[j] = check->v.origin[j] + 0.5f * (check->v.mins[j] + check->v.maxs[j]);
|
2008-12-15 22:00:00 +01:00
|
|
|
|
VectorSubtract( end, start, dir );
|
|
|
|
|
VectorNormalize( dir );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
dist = DotProduct( dir, svgame.globals->v_forward );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( dist < bestdist ) continue; // to far to turn
|
2009-11-02 22:00:00 +01:00
|
|
|
|
tr = SV_Move( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent );
|
2009-10-28 22:00:00 +01:00
|
|
|
|
if( tr.pHit == check )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
// can shoot at this one
|
|
|
|
|
bestdist = dist;
|
|
|
|
|
bestent = check;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( bestent )
|
|
|
|
|
{
|
|
|
|
|
VectorSubtract( bestent->v.origin, ent->v.origin, dir );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
dist = DotProduct( dir, svgame.globals->v_forward );
|
|
|
|
|
VectorScale( svgame.globals->v_forward, dist, end );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
end[2] = dir[2];
|
|
|
|
|
VectorNormalize( end );
|
|
|
|
|
VectorCopy( end, rgflReturn );
|
|
|
|
|
}
|
|
|
|
|
else VectorCopy( bestdir, rgflReturn );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
pfnServerCommand
|
|
|
|
|
|
|
|
|
|
=========
|
|
|
|
|
*/
|
|
|
|
|
void pfnServerCommand( const char* str )
|
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( SV_IsValidCmd( str )) Cbuf_AddText( str );
|
|
|
|
|
else MsgDev( D_ERROR, "bad server command %s\n", str );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
pfnServerExecute
|
|
|
|
|
|
|
|
|
|
=========
|
|
|
|
|
*/
|
|
|
|
|
void pfnServerExecute( void )
|
|
|
|
|
{
|
|
|
|
|
Cbuf_Execute();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=========
|
|
|
|
|
pfnClientCommand
|
|
|
|
|
|
|
|
|
|
=========
|
|
|
|
|
*/
|
|
|
|
|
void pfnClientCommand( edict_t* pEdict, char* szFmt, ... )
|
|
|
|
|
{
|
|
|
|
|
sv_client_t *client;
|
|
|
|
|
string buffer;
|
|
|
|
|
va_list args;
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( sv.state != ss_active )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_ClientCommand: server is not active!\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client = SV_ClientFromEdict( pEdict, true );
|
|
|
|
|
if( client == NULL )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "SV_ClientCommand: client is not spawned!\n" );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-24 22:00:00 +02:00
|
|
|
|
if( pEdict->v.flags & FL_FAKECLIENT )
|
|
|
|
|
return;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
va_start( args, szFmt );
|
|
|
|
|
com.vsnprintf( buffer, MAX_STRING, szFmt, args );
|
|
|
|
|
va_end( args );
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( SV_IsValidCmd( buffer ))
|
|
|
|
|
{
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_stufftext );
|
|
|
|
|
BF_WriteString( &sv.multicast, buffer );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_ONE, NULL, client->edict );
|
2009-11-25 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else MsgDev( D_ERROR, "Tried to stuff bad command %s\n", buffer );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnParticleEffect
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
Make sure the event gets sent to all clients
|
2008-12-15 22:00:00 +01:00
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
void pfnParticleEffect( const float *org, const float *dir, float color, float count )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
int i, v;
|
|
|
|
|
|
|
|
|
|
if( !org || !dir )
|
|
|
|
|
{
|
|
|
|
|
if( !org ) MsgDev( D_ERROR, "SV_StartParticle: NULL origin. Ignored\n" );
|
|
|
|
|
if( !dir ) MsgDev( D_ERROR, "SV_StartParticle: NULL dir. Ignored\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_particle );
|
|
|
|
|
BF_WriteBitVec3Coord( &sv.multicast, org );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
for( i = 0; i < 3; i++ )
|
|
|
|
|
{
|
|
|
|
|
v = bound( -128, dir[i] * 16, 127 );
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteChar( &sv.multicast, v );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
}
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, count );
|
|
|
|
|
BF_WriteByte( &sv.multicast, color );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_ALL, org, NULL );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
===============
|
|
|
|
|
pfnLightStyle
|
|
|
|
|
|
|
|
|
|
===============
|
|
|
|
|
*/
|
2009-11-25 22:00:00 +01:00
|
|
|
|
void pfnLightStyle( int style, const char* val )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( style < 0 ) style = 0;
|
|
|
|
|
if( style >= MAX_LIGHTSTYLES )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
Host_Error( "SV_LightStyle: style: %i >= %d", style, MAX_LIGHTSTYLES );
|
2010-07-01 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
CM_SetLightStyle( style, val ); // update info for SV_LightPoint
|
2008-12-15 22:00:00 +01:00
|
|
|
|
SV_ConfigString( CS_LIGHTSTYLES + style, val );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=================
|
|
|
|
|
pfnDecalIndex
|
|
|
|
|
|
|
|
|
|
register decal shader on client
|
|
|
|
|
=================
|
|
|
|
|
*/
|
|
|
|
|
int pfnDecalIndex( const char *m )
|
|
|
|
|
{
|
|
|
|
|
return SV_DecalIndex( m );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPointContents
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2008-12-25 22:00:00 +01:00
|
|
|
|
static int pfnPointContents( const float *rgflVector )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
return SV_PointContents( rgflVector );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnMessageBegin
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-09-28 22:00:00 +02:00
|
|
|
|
void pfnMessageBegin( int msg_dest, int msg_num, const float *pOrigin, edict_t *ed )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-09-29 22:00:00 +02:00
|
|
|
|
if( svgame.msg_started )
|
|
|
|
|
Host_Error( "MessageBegin: New message started when msg '%s' has not been sent yet\n", svgame.msg_name );
|
|
|
|
|
svgame.msg_started = true;
|
|
|
|
|
|
2010-06-22 22:00:00 +02:00
|
|
|
|
// some malicious users trying send message with engine index
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// reduce number to avoid overflow problems or cheating
|
2009-09-28 22:00:00 +02:00
|
|
|
|
svgame.msg_index = bound( svc_bad, msg_num, svc_nop );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-01-02 22:00:00 +01:00
|
|
|
|
if( svgame.msg_index >= 0 && svgame.msg_index < MAX_USER_MESSAGES )
|
2010-06-22 22:00:00 +02:00
|
|
|
|
svgame.msg_name = svgame.msg[svgame.msg_index].name;
|
2009-01-02 22:00:00 +01:00
|
|
|
|
else svgame.msg_name = NULL;
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svgame.msg_index );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// save message destination
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( pOrigin ) VectorCopy( pOrigin, svgame.msg_org );
|
|
|
|
|
else VectorClear( svgame.msg_org );
|
|
|
|
|
|
2010-06-22 22:00:00 +02:00
|
|
|
|
if( svgame.msg[svgame.msg_index].size == -1 )
|
2008-12-26 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
// variable sized messages sent size as first byte
|
2010-08-04 22:00:00 +02:00
|
|
|
|
svgame.msg_size_index = BF_GetNumBytesWritten( &sv.multicast );
|
|
|
|
|
BF_WriteByte( &sv.multicast, 0 ); // reserve space for now
|
2008-12-26 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else svgame.msg_size_index = -1;
|
|
|
|
|
|
|
|
|
|
svgame.msg_realsize = 0;
|
|
|
|
|
svgame.msg_dest = msg_dest;
|
|
|
|
|
svgame.msg_ent = ed;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnMessageEnd
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnMessageEnd( void )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
const char *name = "Unknown";
|
|
|
|
|
float *org = NULL;
|
2009-01-02 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if( svgame.msg_name ) name = svgame.msg_name;
|
2010-04-13 22:00:00 +02:00
|
|
|
|
if( !svgame.msg_started ) Host_Error( "MessageEnd: called with no active message\n" );
|
2009-09-29 22:00:00 +02:00
|
|
|
|
svgame.msg_started = false;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
|
2010-06-22 22:00:00 +02:00
|
|
|
|
if( svgame.msg[svgame.msg_index].size != -1 )
|
2008-12-26 22:00:00 +01:00
|
|
|
|
{
|
2010-06-22 22:00:00 +02:00
|
|
|
|
int expsize = svgame.msg[svgame.msg_index].size;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
int realsize = svgame.msg_realsize;
|
2008-12-17 22:00:00 +01:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
// compare bounds
|
|
|
|
|
if( expsize != realsize )
|
|
|
|
|
{
|
2010-06-22 22:00:00 +02:00
|
|
|
|
MsgDev( D_ERROR, "SV_Message: %s expected %i bytes, it written %i. Ignored.\n", name, expsize, realsize );
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_Clear( &sv.multicast );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if( svgame.msg_size_index != -1 )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
// variable sized message
|
2009-09-28 22:00:00 +02:00
|
|
|
|
if( svgame.msg_realsize > 255 )
|
2008-12-26 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_Message: %s too long (more than 255 bytes)\n", name );
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_Clear( &sv.multicast );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2009-09-28 22:00:00 +02:00
|
|
|
|
else if( svgame.msg_realsize <= 0 )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_Message: %s writes NULL message\n", name );
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_Clear( &sv.multicast );
|
2009-09-28 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
2010-08-04 22:00:00 +02:00
|
|
|
|
sv.multicast.pData[svgame.msg_size_index] = svgame.msg_realsize;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2009-09-28 22:00:00 +02:00
|
|
|
|
// this should never happen
|
2008-12-26 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "SV_Message: %s have encountered error\n", name );
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_Clear( &sv.multicast );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !VectorIsNull( svgame.msg_org )) org = svgame.msg_org;
|
2009-11-25 22:00:00 +01:00
|
|
|
|
svgame.msg_dest = bound( MSG_BROADCAST, svgame.msg_dest, MSG_SPEC );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( svgame.msg_dest, org, svgame.msg_ent );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnWriteByte
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnWriteByte( int iValue )
|
|
|
|
|
{
|
2009-01-02 22:00:00 +01:00
|
|
|
|
if( iValue == -1 ) iValue = 0xFF; // convert char to byte
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, iValue );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.msg_realsize++;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnWriteChar
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnWriteChar( int iValue )
|
|
|
|
|
{
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteChar( &sv.multicast, iValue );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.msg_realsize++;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnWriteShort
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnWriteShort( int iValue )
|
|
|
|
|
{
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteShort( &sv.multicast, iValue );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.msg_realsize += 2;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnWriteLong
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnWriteLong( int iValue )
|
|
|
|
|
{
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteLong( &sv.multicast, iValue );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.msg_realsize += 4;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnWriteAngle
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnWriteAngle( float flValue )
|
|
|
|
|
{
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteBitAngle( &sv.multicast, flValue, 16 );
|
2009-01-04 22:00:00 +01:00
|
|
|
|
svgame.msg_realsize += 2;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnWriteCoord
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnWriteCoord( float flValue )
|
|
|
|
|
{
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteFloat( &sv.multicast, flValue );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.msg_realsize += 4;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnWriteString
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-08-06 22:00:00 +02:00
|
|
|
|
void pfnWriteString( const char *src )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-08-06 22:00:00 +02:00
|
|
|
|
char *dst, string[MAX_SYSPATH];
|
|
|
|
|
int len = com.strlen( src ) + 1;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-08-06 22:00:00 +02:00
|
|
|
|
if( len >= MAX_SYSPATH )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "pfnWriteString: exceeds %i symbols\n", MAX_SYSPATH );
|
|
|
|
|
BF_WriteChar( &sv.multicast, 0 );
|
|
|
|
|
svgame.msg_realsize += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// prepare string to sending
|
|
|
|
|
dst = string;
|
|
|
|
|
|
|
|
|
|
while( 1 )
|
|
|
|
|
{
|
|
|
|
|
// some escaped chars parsed as two symbols - merge it here
|
|
|
|
|
if( src[0] == '\\' && src[1] == 'n' )
|
|
|
|
|
{
|
|
|
|
|
*dst++ = '\n';
|
|
|
|
|
src += 2;
|
|
|
|
|
len -= 1;
|
|
|
|
|
}
|
|
|
|
|
else if( src[0] == '\\' && src[1] == 'r' )
|
|
|
|
|
{
|
|
|
|
|
*dst++ = '\r';
|
|
|
|
|
src += 2;
|
|
|
|
|
len -= 1;
|
|
|
|
|
}
|
|
|
|
|
else if( src[0] == '\\' && src[1] == 't' )
|
|
|
|
|
{
|
|
|
|
|
*dst++ = '\t';
|
|
|
|
|
src += 2;
|
|
|
|
|
len -= 1;
|
|
|
|
|
}
|
|
|
|
|
else if(( *dst++ = *src++ ) == 0 )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*dst = '\0'; // string end (not included in count)
|
|
|
|
|
BF_WriteString( &sv.multicast, string );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-09-28 22:00:00 +02:00
|
|
|
|
// NOTE: some messages with constant string length can be marked as known sized
|
2010-08-06 22:00:00 +02:00
|
|
|
|
svgame.msg_realsize += len;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnWriteEntity
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnWriteEntity( int iValue )
|
|
|
|
|
{
|
2010-07-02 22:00:00 +02:00
|
|
|
|
if( iValue < 0 || iValue >= svgame.globals->numEntities )
|
2010-08-04 22:00:00 +02:00
|
|
|
|
Host_Error( "BF_WriteEntity: invalid entnumber %i\n", iValue );
|
|
|
|
|
BF_WriteShort( &sv.multicast, iValue );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.msg_realsize += 2;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPvAllocEntPrivateData
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void *pfnPvAllocEntPrivateData( edict_t *pEdict, long cb )
|
|
|
|
|
{
|
2010-07-29 22:00:00 +02:00
|
|
|
|
ASSERT( pEdict );
|
|
|
|
|
ASSERT( pEdict->free == false );
|
|
|
|
|
ASSERT( pEdict->pvServerData );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// to avoid multiple alloc
|
2008-12-26 22:00:00 +01:00
|
|
|
|
pEdict->pvPrivateData = (void *)Mem_Realloc( svgame.private, pEdict->pvPrivateData, cb );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
return pEdict->pvPrivateData;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPvEntPrivateData
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void *pfnPvEntPrivateData( edict_t *pEdict )
|
|
|
|
|
{
|
|
|
|
|
if( pEdict )
|
|
|
|
|
return pEdict->pvPrivateData;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-12-15 22:00:00 +01:00
|
|
|
|
=============
|
|
|
|
|
pfnFreeEntPrivateData
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnFreeEntPrivateData( edict_t *pEdict )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !pEdict ) return;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( pEdict->pvPrivateData )
|
|
|
|
|
Mem_Free( pEdict->pvPrivateData );
|
|
|
|
|
pEdict->pvPrivateData = NULL; // freed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
SV_AllocString
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
string_t SV_AllocString( const char *szValue )
|
|
|
|
|
{
|
2010-03-30 22:00:00 +02:00
|
|
|
|
if( sys_sharedstrings->integer )
|
|
|
|
|
{
|
|
|
|
|
const char *newString;
|
|
|
|
|
newString = com.stralloc( svgame.stringspool, szValue, __FILE__, __LINE__ );
|
|
|
|
|
return newString - svgame.globals->pStringBase;
|
|
|
|
|
}
|
2008-12-26 22:00:00 +01:00
|
|
|
|
return StringTable_SetString( svgame.hStringTable, szValue );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
SV_GetString
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
const char *SV_GetString( string_t iString )
|
|
|
|
|
{
|
2010-03-30 22:00:00 +02:00
|
|
|
|
if( sys_sharedstrings->integer )
|
|
|
|
|
return (svgame.globals->pStringBase + iString);
|
2008-12-26 22:00:00 +01:00
|
|
|
|
return StringTable_GetString( svgame.hStringTable, iString );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetVarsOfEnt
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
entvars_t *pfnGetVarsOfEnt( edict_t *pEdict )
|
|
|
|
|
{
|
|
|
|
|
if( pEdict )
|
|
|
|
|
return &pEdict->v;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPEntityOfEntOffset
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
edict_t* pfnPEntityOfEntOffset( int iEntOffset )
|
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
return (&((edict_t*)svgame.vp)[iEntOffset]);
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnEntOffsetOfPEntity
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnEntOffsetOfPEntity( const edict_t *pEdict )
|
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
return ((byte *)pEdict - (byte *)svgame.vp);
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnIndexOfEdict
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnIndexOfEdict( const edict_t *pEdict )
|
|
|
|
|
{
|
2010-03-30 22:00:00 +02:00
|
|
|
|
if( !SV_IsValidEdict( pEdict ))
|
2010-07-02 22:00:00 +02:00
|
|
|
|
return 0;
|
2008-12-17 22:00:00 +01:00
|
|
|
|
return NUM_FOR_EDICT( pEdict );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPEntityOfEntIndex
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
edict_t* pfnPEntityOfEntIndex( int iEntIndex )
|
|
|
|
|
{
|
2009-09-28 22:00:00 +02:00
|
|
|
|
if( iEntIndex < 0 || iEntIndex >= svgame.globals->numEntities )
|
|
|
|
|
return NULL; // out of range
|
2008-12-17 22:00:00 +01:00
|
|
|
|
return EDICT_NUM( iEntIndex );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnFindEntityByVars
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
debug routine
|
2008-12-15 22:00:00 +01:00
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
edict_t* pfnFindEntityByVars( entvars_t *pvars )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-03-30 22:00:00 +02:00
|
|
|
|
edict_t *e;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
int i;
|
|
|
|
|
|
2010-03-30 22:00:00 +02:00
|
|
|
|
// don't pass invalid arguments
|
|
|
|
|
if( !pvars ) return NULL;
|
|
|
|
|
|
|
|
|
|
for( i = 0; i < svgame.globals->numEntities; i++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-03-30 22:00:00 +02:00
|
|
|
|
e = EDICT_NUM( i );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( !memcmp( &e->v, pvars, sizeof( entvars_t )))
|
2010-03-30 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
Msg( "FindEntityByVars: %s\n", SV_ClassName( e ));
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return e; // found it
|
2010-03-30 22:00:00 +02:00
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetModelPtr
|
|
|
|
|
|
|
|
|
|
returns pointer to a studiomodel
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-01-22 22:00:00 +01:00
|
|
|
|
static void *pfnGetModelPtr( edict_t* pEdict )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-10-28 22:00:00 +01:00
|
|
|
|
if( !pEdict || pEdict->free )
|
|
|
|
|
return NULL;
|
|
|
|
|
return Mod_Extradata( pEdict->v.modelindex );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnRegUserMsg
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnRegUserMsg( const char *pszName, int iSize )
|
|
|
|
|
{
|
2010-06-22 22:00:00 +02:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if( !pszName || !pszName[0] )
|
|
|
|
|
return svc_bad;
|
|
|
|
|
|
|
|
|
|
if( com.strlen( pszName ) >= sizeof( svgame.msg[0].name ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "REG_USER_MSG: too long name %s\n", pszName );
|
|
|
|
|
return svc_bad; // force error
|
|
|
|
|
}
|
2008-12-25 22:00:00 +01:00
|
|
|
|
|
2010-06-22 22:00:00 +02:00
|
|
|
|
if( iSize > 255 )
|
2008-12-25 22:00:00 +01:00
|
|
|
|
{
|
2010-06-22 22:00:00 +02:00
|
|
|
|
MsgDev( D_ERROR, "REG_USER_MSG: %s has too big size %i\n", pszName, iSize );
|
2008-12-25 22:00:00 +01:00
|
|
|
|
return svc_bad; // force error
|
|
|
|
|
}
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-06-22 22:00:00 +02:00
|
|
|
|
// make sure what size inrange
|
|
|
|
|
iSize = bound( -1, iSize, 255 );
|
|
|
|
|
|
|
|
|
|
// message 0 is reserved for svc_bad
|
|
|
|
|
for( i = 0; i < MAX_USER_MESSAGES && svgame.msg[i].name[0]; i++ )
|
|
|
|
|
{
|
|
|
|
|
// see if already registered
|
|
|
|
|
if( !com.strcmp( svgame.msg[i].name, pszName ))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( i == MAX_USER_MESSAGES )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "REG_USER_MSG: user messages limit exceeded\n" );
|
|
|
|
|
return svc_bad;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// register new message
|
|
|
|
|
com.strncpy( svgame.msg[i].name, pszName, sizeof( svgame.msg[i].name ));
|
|
|
|
|
svgame.msg[i].size = iSize;
|
|
|
|
|
svgame.msg[i].number = i; // paranoid mode :-)
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-07-19 22:00:00 +02:00
|
|
|
|
// catch some user messages
|
|
|
|
|
if( !com.strcmp( pszName, "HudText" ))
|
|
|
|
|
svgame.gmsgHudText = i;
|
|
|
|
|
|
2010-07-08 22:00:00 +02:00
|
|
|
|
if( sv.state == ss_active )
|
|
|
|
|
{
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_usermessage );
|
|
|
|
|
BF_WriteString( &sv.multicast, pszName );
|
|
|
|
|
BF_WriteByte( &sv.multicast, i );
|
|
|
|
|
BF_WriteByte( &sv.multicast, (byte)iSize );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_ALL, vec3_origin, NULL );
|
2010-07-08 22:00:00 +02:00
|
|
|
|
}
|
2010-06-22 22:00:00 +02:00
|
|
|
|
return i;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2010-05-22 22:00:00 +02:00
|
|
|
|
pfnAnimationAutomove
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
animating studiomodel
|
2008-12-15 22:00:00 +01:00
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-05-22 22:00:00 +02:00
|
|
|
|
void pfnAnimationAutomove( const edict_t* pEdict, float flTime )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
// FIXME: implement
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetBonePosition
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-12-05 22:00:00 +01:00
|
|
|
|
static void pfnGetBonePosition( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( pEdict ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_GetBonePos: invalid entity %s\n", SV_ClassName( pEdict ));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CM_GetBonePosition( (edict_t *)pEdict, iBone, rgflOrigin, rgflAngles );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnFunctionFromName
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
dword pfnFunctionFromName( const char *pName )
|
|
|
|
|
{
|
2010-03-27 22:00:00 +01:00
|
|
|
|
return FS_FunctionFromName( svgame.hInstance, pName );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnNameForFunction
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
const char *pfnNameForFunction( dword function )
|
|
|
|
|
{
|
2010-03-27 22:00:00 +01:00
|
|
|
|
return FS_NameForFunction( svgame.hInstance, function );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnClientPrintf
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
sv_client_t *client;
|
|
|
|
|
bool fake;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( sv.state != ss_active )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
// send message into console during loading
|
|
|
|
|
MsgDev( D_INFO, szMsg );
|
|
|
|
|
return;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
client = SV_ClientFromEdict( pEdict, true );
|
|
|
|
|
if( client == NULL )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "SV_ClientPrintf: client is not spawned!\n" );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
fake = ( pEdict->v.flags & FL_FAKECLIENT ) ? true : false;
|
2009-01-02 22:00:00 +01:00
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
switch( ptype )
|
2009-01-02 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
case print_console:
|
|
|
|
|
if( fake ) MsgDev( D_INFO, szMsg );
|
|
|
|
|
else SV_ClientPrintf( client, PRINT_HIGH, "%s", szMsg );
|
|
|
|
|
break;
|
|
|
|
|
case print_chat:
|
|
|
|
|
if( fake ) return;
|
|
|
|
|
SV_ClientPrintf( client, PRINT_CHAT, "%s", szMsg );
|
|
|
|
|
break;
|
|
|
|
|
case print_center:
|
|
|
|
|
if( fake ) return;
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_centerprint );
|
|
|
|
|
BF_WriteString( &sv.multicast, szMsg );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_ONE, NULL, client->edict );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
break;
|
2009-01-02 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnServerPrint
|
2009-09-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
void pfnServerPrint( const char *szMsg )
|
2009-09-22 22:00:00 +02:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
// while loading in-progress we can sending message only for local client
|
2010-07-17 22:00:00 +02:00
|
|
|
|
if( sv.state == ss_loading ) MsgDev( D_INFO, szMsg );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
else SV_BroadcastPrintf( PRINT_HIGH, "%s", szMsg );
|
2009-09-22 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetAttachment
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-10-15 22:00:00 +02:00
|
|
|
|
static void pfnGetAttachment( const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( pEdict ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_GetAttachment: invalid entity %s\n", SV_ClassName( pEdict ));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-25 22:00:00 +01:00
|
|
|
|
CM_GetAttachment(( edict_t *)pEdict, iAttachment, rgflOrigin, rgflAngles );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnCRC32_Init
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
void pfnCRC32_Init( CRC32_t *pulCRC )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
CRC32_Init( pulCRC );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnCRC32_ProcessBuffer
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
void pfnCRC32_ProcessBuffer( CRC32_t *pulCRC, void *p, int len )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
CRC32_ProcessBuffer( pulCRC, p, len );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnCRC32_ProcessByte
|
2009-09-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
void pfnCRC32_ProcessByte( CRC32_t *pulCRC, byte ch )
|
2009-09-22 22:00:00 +02:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
CRC32_ProcessByte( pulCRC, ch );
|
2009-09-22 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnCRC32_Final
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
CRC32_t pfnCRC32_Final( CRC32_t pulCRC )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
CRC32_Final( &pulCRC );
|
|
|
|
|
|
|
|
|
|
return pulCRC;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnCrosshairAngle
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnCrosshairAngle( const edict_t *pClient, float pitch, float yaw )
|
|
|
|
|
{
|
2009-09-29 22:00:00 +02:00
|
|
|
|
sv_client_t *client;
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
client = SV_ClientFromEdict( pClient, true );
|
|
|
|
|
if( client == NULL )
|
2009-09-29 22:00:00 +02:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "SV_SetCrosshairAngle: invalid client!\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fakeclients ignore it silently
|
|
|
|
|
if( pClient->v.flags & FL_FAKECLIENT ) return;
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_crosshairangle );
|
|
|
|
|
BF_WriteBitAngle( &sv.multicast, pitch, 8 );
|
|
|
|
|
BF_WriteBitAngle( &sv.multicast, yaw, 8 );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_ONE, vec3_origin, pClient );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnSetView
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnSetView( const edict_t *pClient, const edict_t *pViewent )
|
|
|
|
|
{
|
|
|
|
|
sv_client_t *client;
|
|
|
|
|
|
|
|
|
|
if( pClient == NULL || pClient->free )
|
|
|
|
|
{
|
2010-03-21 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "PF_SetView: invalid client!\n" );
|
2009-09-29 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client = pClient->pvServerData->client;
|
|
|
|
|
if( !client )
|
|
|
|
|
{
|
2010-03-21 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "PF_SetView: not a client!\n" );
|
2009-09-29 22:00:00 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( pViewent == NULL || pViewent->free )
|
|
|
|
|
{
|
2010-03-21 22:00:00 +01:00
|
|
|
|
MsgDev( D_ERROR, "PF_SetView: invalid viewent!\n" );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
if( pClient == pViewent ) client->pViewEntity = NULL;
|
|
|
|
|
else client->pViewEntity = (edict_t *)pViewent;
|
|
|
|
|
|
|
|
|
|
// fakeclients ignore to send client message
|
|
|
|
|
if( pClient->v.flags & FL_FAKECLIENT ) return;
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &client->netchan.message, svc_setview );
|
|
|
|
|
BF_WriteWord( &client->netchan.message, NUM_FOR_EDICT( pViewent ));
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_ONE, NULL, client->edict );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnCompareFileTime
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnCompareFileTime( const char *filename1, const char *filename2, int *iCompare )
|
|
|
|
|
{
|
2009-09-28 22:00:00 +02:00
|
|
|
|
int bRet = 0;
|
|
|
|
|
|
|
|
|
|
*iCompare = 0;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-09-28 22:00:00 +02:00
|
|
|
|
if( filename1 && filename2 )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-03-27 22:00:00 +01:00
|
|
|
|
long ft1 = FS_FileTime( filename1 );
|
|
|
|
|
long ft2 = FS_FileTime( filename2 );
|
2009-09-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
*iCompare = Host_CompareFileTime( ft1, ft2 );
|
|
|
|
|
bRet = 1;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
2009-09-28 22:00:00 +02:00
|
|
|
|
return bRet;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2008-12-25 22:00:00 +01:00
|
|
|
|
pfnStaticDecal
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnStaticDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
if( !origin )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_StaticDecal: NULL origin. Ignored\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-01 22:00:00 +02:00
|
|
|
|
SV_CreateDecal( origin, decalIndex, entityIndex, modelIndex, FDECAL_PERMANENT );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPrecacheGeneric
|
|
|
|
|
|
|
|
|
|
can be used for precache scripts
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
int pfnPrecacheGeneric( const char *s )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return SV_GenericIndex( s );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnIsDedicatedServer
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnIsDedicatedServer( void )
|
|
|
|
|
{
|
|
|
|
|
return (host.type == HOST_DEDICATED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnIsMapValid
|
|
|
|
|
|
|
|
|
|
vaild map must contain one info_player_deatchmatch
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnIsMapValid( char *filename )
|
|
|
|
|
{
|
2009-09-28 22:00:00 +02:00
|
|
|
|
char *spawn_entity;
|
2010-04-02 22:00:00 +02:00
|
|
|
|
int flags;
|
2009-07-12 22:00:00 +02:00
|
|
|
|
|
2009-09-28 22:00:00 +02:00
|
|
|
|
// determine spawn entity classname
|
|
|
|
|
if( Cvar_VariableInteger( "deathmatch" ))
|
|
|
|
|
spawn_entity = GI->dm_entity;
|
|
|
|
|
else if( Cvar_VariableInteger( "coop" ))
|
|
|
|
|
spawn_entity = GI->coop_entity;
|
|
|
|
|
else if( Cvar_VariableInteger( "teamplay" ))
|
|
|
|
|
spawn_entity = GI->team_entity;
|
|
|
|
|
else spawn_entity = GI->sp_entity;
|
2009-07-12 22:00:00 +02:00
|
|
|
|
|
2010-04-02 22:00:00 +02:00
|
|
|
|
flags = SV_MapIsValid( filename, spawn_entity, NULL );
|
|
|
|
|
|
|
|
|
|
if(( flags & MAP_IS_EXIST ) && ( flags & MAP_HAS_SPAWNPOINT ))
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnClassifyEdict
|
|
|
|
|
|
|
|
|
|
classify edict for render and network usage
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnClassifyEdict( edict_t *pEdict, int class )
|
|
|
|
|
{
|
2009-11-28 22:00:00 +01:00
|
|
|
|
if( !SV_IsValidEdict( pEdict ))
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
2009-11-28 22:00:00 +01:00
|
|
|
|
MsgDev( D_WARN, "SV_ClassifyEdict: invalid entity %s\n", SV_ClassName( pEdict ));
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-28 22:00:00 +01:00
|
|
|
|
SV_ClassifyEdict( pEdict, class );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnFadeClientVolume
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-25 22:00:00 +01:00
|
|
|
|
void pfnFadeClientVolume( const edict_t *pEdict, float fadePercent, float fadeOutSeconds, float holdTime, float fadeInSeconds )
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
|
|
|
|
|
cl = SV_ClientFromEdict( pEdict, true );
|
|
|
|
|
if( !cl )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_FadeClientVolume: client is not spawned!\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &sv.multicast, svc_soundfade );
|
|
|
|
|
BF_WriteFloat( &sv.multicast, fadePercent );
|
|
|
|
|
BF_WriteFloat( &sv.multicast, fadeOutSeconds );
|
|
|
|
|
BF_WriteFloat( &sv.multicast, holdTime );
|
|
|
|
|
BF_WriteFloat( &sv.multicast, fadeInSeconds );
|
2010-08-06 22:00:00 +02:00
|
|
|
|
SV_Send( MSG_ONE, NULL, cl->edict );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnSetClientMaxspeed
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnSetClientMaxspeed( const edict_t *pEdict, float fNewMaxspeed )
|
|
|
|
|
{
|
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
|
|
|
|
|
cl = SV_ClientFromEdict( pEdict, false ); // connected clients allowed
|
|
|
|
|
if( !cl )
|
|
|
|
|
{
|
2010-04-09 22:00:00 +02:00
|
|
|
|
MsgDev( D_ERROR, "SV_SetClientMaxspeed: client is not active!\n" );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SV_SetClientMaxspeed( cl, fNewMaxspeed );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnCreateFakeClient
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
edict_t *pfnCreateFakeClient( const char *netname )
|
|
|
|
|
{
|
|
|
|
|
return SV_FakeConnect( netname );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnRunPlayerMove
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-06-23 22:00:00 +02:00
|
|
|
|
void pfnRunPlayerMove( edict_t *pClient, const float *v_angle, float fmove, float smove, float upmove, word buttons, byte impulse, byte msec )
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
sv_client_t *cl;
|
2010-06-23 22:00:00 +02:00
|
|
|
|
usercmd_t cmd;
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if( sv.paused ) return;
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
if(( cl = SV_ClientFromEdict( pClient, true )) == NULL )
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
2010-06-23 22:00:00 +02:00
|
|
|
|
MsgDev( D_ERROR, "SV_ClientThink: fakeclient is not spawned!\n" );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!( pClient->v.flags & FL_FAKECLIENT ))
|
|
|
|
|
return; // only fakeclients allows
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
Mem_Set( &cmd, 0, sizeof( cmd ));
|
|
|
|
|
if( v_angle ) VectorCopy( v_angle, cmd.viewangles );
|
|
|
|
|
cmd.forwardmove = fmove;
|
|
|
|
|
cmd.sidemove = smove;
|
|
|
|
|
cmd.upmove = upmove;
|
|
|
|
|
cmd.buttons = buttons;
|
|
|
|
|
cmd.impulse = impulse;
|
|
|
|
|
cmd.msec = msec;
|
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
cl->random_seed = Com_RandomLong( 0, 0x7fffffff ); // full range
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
SV_PreRunCmd( cl, &cmd );
|
|
|
|
|
SV_RunCmd( cl, &cmd );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
SV_PostRunCmd( cl );
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
cl->lastcmd = cmd;
|
2009-11-23 22:00:00 +01:00
|
|
|
|
cl->lastcmd.buttons = 0; // avoid multiple fires on lag
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnInfo_RemoveKey
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnInfo_RemoveKey( char *s, char *key )
|
|
|
|
|
{
|
|
|
|
|
Info_RemoveKey( s, key );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnInfoKeyValue
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
char *pfnInfoKeyValue( char *infobuffer, char *key )
|
|
|
|
|
{
|
|
|
|
|
return Info_ValueForKey( infobuffer, key );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnSetKeyValue
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnSetKeyValue( char *infobuffer, char *key, char *value )
|
|
|
|
|
{
|
|
|
|
|
Info_SetValueForKey( infobuffer, key, value );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetInfoKeyBuffer
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
char *pfnGetInfoKeyBuffer( edict_t *e )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
cl = SV_ClientFromEdict( e, false ); // pfnUserInfoChanged passed
|
|
|
|
|
if( cl == NULL )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_GetClientUserinfo: client is not connected!\n" );
|
|
|
|
|
return Cvar_Serverinfo(); // otherwise return ServerInfo
|
|
|
|
|
}
|
|
|
|
|
return cl->userinfo;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnSetClientKeyValue
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnSetClientKeyValue( int clientIndex, char *infobuffer, char *key, char *value )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
|
|
|
|
|
if( clientIndex < 0 || clientIndex >= sv_maxclients->integer )
|
|
|
|
|
return;
|
|
|
|
|
if( svs.clients[clientIndex].state < cs_spawned )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
cl = svs.clients + clientIndex;
|
|
|
|
|
Info_SetValueForKey( cl->userinfo, key, value );
|
2009-12-04 22:00:00 +01:00
|
|
|
|
cl->sendinfo = true;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-10 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetPhysicsKeyValue
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
const char *pfnGetPhysicsKeyValue( const edict_t *pClient, const char *key )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
|
|
|
|
|
cl = SV_ClientFromEdict( pClient, false ); // pfnUserInfoChanged passed
|
|
|
|
|
if( cl == NULL )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_GetClientPhysKey: client is not connected!\n" );
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
return Info_ValueForKey( cl->physinfo, key );
|
2009-11-10 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnSetPhysicsKeyValue
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnSetPhysicsKeyValue( const edict_t *pClient, const char *key, const char *value )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
|
|
|
|
|
cl = SV_ClientFromEdict( pClient, false ); // pfnUserInfoChanged passed
|
|
|
|
|
if( cl == NULL )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_SetClientPhysinfo: client is not connected!\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-08-05 22:00:00 +02:00
|
|
|
|
Info_SetValueForKey( cl->physinfo, key, value );
|
2009-11-10 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetPhysicsInfoString
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
const char *pfnGetPhysicsInfoString( const edict_t *pClient )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
|
|
|
|
|
cl = SV_ClientFromEdict( pClient, false ); // pfnUserInfoChanged passed
|
|
|
|
|
if( cl == NULL )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_GetClientPhysinfo: client is not connected!\n" );
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
return cl->physinfo;
|
2009-11-10 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-01-11 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPrecacheEvent
|
|
|
|
|
|
2009-11-23 22:00:00 +01:00
|
|
|
|
register or returns already registered event id
|
2009-01-11 22:00:00 +01:00
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
word pfnPrecacheEvent( int type, const char *psz )
|
|
|
|
|
{
|
2009-11-23 22:00:00 +01:00
|
|
|
|
return SV_FindIndex( psz, CS_EVENTS, MAX_EVENTS, type );
|
2009-01-11 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPlaybackEvent
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-06-23 22:00:00 +02:00
|
|
|
|
static void pfnPlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, float delay,
|
|
|
|
|
float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 )
|
2009-01-11 22:00:00 +01:00
|
|
|
|
{
|
2009-12-02 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
event_state_t *es;
|
2010-06-23 22:00:00 +02:00
|
|
|
|
event_args_t args;
|
2009-12-02 22:00:00 +01:00
|
|
|
|
event_info_t *ei = NULL;
|
2010-05-22 22:00:00 +02:00
|
|
|
|
int j, leafnum, slot, bestslot;
|
|
|
|
|
int invokerIndex = 0;
|
2009-12-02 22:00:00 +01:00
|
|
|
|
byte *mask = NULL;
|
|
|
|
|
vec3_t pvspoint;
|
|
|
|
|
|
|
|
|
|
// first check event for out of bounds
|
|
|
|
|
if( eventindex < 1 || eventindex > MAX_EVENTS )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_PlaybackEvent: invalid eventindex %i\n", eventindex );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check event for precached
|
|
|
|
|
if( !SV_FindIndex( sv.configstrings[CS_EVENTS+eventindex], CS_EVENTS, MAX_EVENTS, false ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_PlaybackEvent: event %i was not precached\n", eventindex );
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
args.flags = 0;
|
|
|
|
|
if( SV_IsValidEdict( pInvoker ))
|
|
|
|
|
args.entindex = NUM_FOR_EDICT( pInvoker );
|
|
|
|
|
else args.entindex = 0;
|
|
|
|
|
VectorCopy( origin, args.origin );
|
|
|
|
|
VectorCopy( angles, args.angles );
|
|
|
|
|
|
|
|
|
|
args.fparam1 = fparam1;
|
|
|
|
|
args.fparam2 = fparam2;
|
|
|
|
|
args.iparam1 = iparam1;
|
|
|
|
|
args.iparam2 = iparam2;
|
|
|
|
|
args.bparam1 = bparam1;
|
|
|
|
|
args.bparam2 = bparam2;
|
|
|
|
|
|
2009-12-02 22:00:00 +01:00
|
|
|
|
if(!( flags & FEV_GLOBAL ))
|
|
|
|
|
{
|
|
|
|
|
// PVS message - trying to get a pvspoint
|
2010-06-23 22:00:00 +02:00
|
|
|
|
// args.origin always have higher priority than invoker->origin
|
|
|
|
|
if( !VectorIsNull( args.origin ))
|
2009-12-02 22:00:00 +01:00
|
|
|
|
{
|
2010-06-23 22:00:00 +02:00
|
|
|
|
VectorCopy( args.origin, pvspoint );
|
2009-12-02 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else if( SV_IsValidEdict( pInvoker ))
|
|
|
|
|
{
|
|
|
|
|
VectorCopy( pInvoker->v.origin, pvspoint );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char *ev_name = sv.configstrings[CS_EVENTS+eventindex];
|
|
|
|
|
MsgDev( D_ERROR, "%s: not a FEV_GLOBAL event missing origin. Ignored.\n", ev_name );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check event for some user errors
|
|
|
|
|
if( flags & (FEV_NOTHOST|FEV_HOSTONLY))
|
|
|
|
|
{
|
|
|
|
|
if( !SV_ClientFromEdict( pInvoker, true ))
|
|
|
|
|
{
|
|
|
|
|
const char *ev_name = sv.configstrings[CS_EVENTS+eventindex];
|
|
|
|
|
if( flags & FEV_NOTHOST )
|
|
|
|
|
MsgDev( D_WARN, "%s: specified FEV_NOTHOST when invoker not a client\n", ev_name );
|
|
|
|
|
if( flags & FEV_HOSTONLY )
|
|
|
|
|
MsgDev( D_WARN, "%s: specified FEV_HOSTONLY when invoker not a client\n", ev_name );
|
|
|
|
|
// pInvoker isn't a client
|
|
|
|
|
flags &= ~(FEV_NOTHOST|FEV_HOSTONLY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flags |= FEV_SERVER; // it's a server event
|
|
|
|
|
|
|
|
|
|
if( delay < 0.0f )
|
|
|
|
|
delay = 0.0f; // fixup negative delays
|
|
|
|
|
|
|
|
|
|
if( SV_IsValidEdict( pInvoker ))
|
|
|
|
|
invokerIndex = NUM_FOR_EDICT( pInvoker );
|
|
|
|
|
|
|
|
|
|
if( flags & FEV_RELIABLE )
|
|
|
|
|
{
|
2010-06-23 22:00:00 +02:00
|
|
|
|
args.ducking = 0;
|
|
|
|
|
VectorClear( args.velocity );
|
2009-12-02 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else if( invokerIndex )
|
|
|
|
|
{
|
|
|
|
|
// get up some info from invoker
|
2010-06-23 22:00:00 +02:00
|
|
|
|
if( VectorIsNull( args.origin ))
|
|
|
|
|
VectorCopy( pInvoker->v.origin, args.origin );
|
|
|
|
|
if( VectorIsNull( args.angles ))
|
2010-02-26 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
if( SV_ClientFromEdict( pInvoker, true ))
|
2010-06-23 22:00:00 +02:00
|
|
|
|
VectorCopy( pInvoker->v.v_angle, args.angles );
|
|
|
|
|
else VectorCopy( pInvoker->v.angles, args.angles );
|
2010-02-26 22:00:00 +01:00
|
|
|
|
}
|
2010-06-23 22:00:00 +02:00
|
|
|
|
else if( SV_ClientFromEdict( pInvoker, true ) && VectorCompare( pInvoker->v.angles, args.angles ))
|
2010-03-14 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
// NOTE: if user specified pPlayer->pev->angles
|
|
|
|
|
// silently replace it with viewangles, client expected this
|
2010-06-23 22:00:00 +02:00
|
|
|
|
VectorCopy( pInvoker->v.v_angle, args.angles );
|
2010-03-14 22:00:00 +01:00
|
|
|
|
}
|
2010-06-23 22:00:00 +02:00
|
|
|
|
VectorCopy( pInvoker->v.velocity, args.velocity );
|
|
|
|
|
args.ducking = (pInvoker->v.flags & FL_DUCKING) ? true : false;
|
2009-12-02 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!( flags & FEV_GLOBAL ))
|
|
|
|
|
{
|
|
|
|
|
// setup pvs cluster for invoker
|
|
|
|
|
leafnum = CM_PointLeafnum( pvspoint );
|
2010-05-22 22:00:00 +02:00
|
|
|
|
mask = CM_LeafPVS( leafnum );
|
2009-12-02 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// process all the clients
|
|
|
|
|
for( slot = 0, cl = svs.clients; slot < sv_maxclients->integer; slot++, cl++ )
|
|
|
|
|
{
|
|
|
|
|
if( cl->state != cs_spawned || !cl->edict || ( cl->edict->v.flags & FL_FAKECLIENT ))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if( flags & FEV_NOTHOST && cl->edict == pInvoker )
|
|
|
|
|
continue; // will be played on client side
|
|
|
|
|
|
|
|
|
|
if( flags & FEV_HOSTONLY && cl->edict != pInvoker )
|
|
|
|
|
continue; // sending only to invoker
|
|
|
|
|
|
|
|
|
|
if(!( flags & FEV_GLOBAL ))
|
|
|
|
|
{
|
|
|
|
|
leafnum = CM_PointLeafnum( cl->edict->v.origin );
|
2010-05-22 22:00:00 +02:00
|
|
|
|
if( mask && (!(mask[leafnum>>3] & (1<<(leafnum & 7)))))
|
2009-12-02 22:00:00 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// all checks passed, send the event
|
|
|
|
|
|
|
|
|
|
// reliable event
|
|
|
|
|
if( flags & FEV_RELIABLE )
|
|
|
|
|
{
|
|
|
|
|
event_info_t info;
|
|
|
|
|
|
|
|
|
|
info.index = eventindex;
|
|
|
|
|
info.fire_time = delay;
|
2010-06-23 22:00:00 +02:00
|
|
|
|
info.args = args;
|
2009-12-02 22:00:00 +01:00
|
|
|
|
info.entity_index = invokerIndex;
|
|
|
|
|
info.packet_index = -1;
|
|
|
|
|
info.flags = 0; // server ignore flags
|
|
|
|
|
|
|
|
|
|
// skipping queue, write in reliable datagram
|
2010-08-04 22:00:00 +02:00
|
|
|
|
BF_WriteByte( &cl->reliable, svc_event_reliable );
|
2009-12-02 22:00:00 +01:00
|
|
|
|
SV_PlaybackEvent( &cl->reliable, &info );
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// unreliable event (stores in queue)
|
|
|
|
|
es = &cl->events;
|
|
|
|
|
bestslot = -1;
|
|
|
|
|
|
|
|
|
|
for( j = 0; j < MAX_EVENT_QUEUE; j++ )
|
|
|
|
|
{
|
|
|
|
|
ei = &es->ei[j];
|
|
|
|
|
|
|
|
|
|
if( ei->index == 0 )
|
|
|
|
|
{
|
|
|
|
|
// found an empty slot
|
|
|
|
|
bestslot = j;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// no slot found for this player, oh well
|
|
|
|
|
if( bestslot == -1 ) continue;
|
|
|
|
|
|
|
|
|
|
ei->index = eventindex;
|
|
|
|
|
ei->fire_time = delay;
|
2010-06-23 22:00:00 +02:00
|
|
|
|
ei->args = args;
|
2009-12-02 22:00:00 +01:00
|
|
|
|
ei->entity_index = invokerIndex;
|
|
|
|
|
ei->packet_index = -1;
|
|
|
|
|
ei->flags = 0; // server ignore flags
|
|
|
|
|
}
|
2009-11-23 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2010-05-22 22:00:00 +02:00
|
|
|
|
pfnSetFatPVS
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
set fat PVS
|
2009-11-25 22:00:00 +01:00
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-05-22 22:00:00 +02:00
|
|
|
|
byte *pfnSetFatPVS( const float *org, int portal )
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
if( !org ) return NULL;
|
|
|
|
|
return CM_FatPVS( org, portal );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2010-05-22 22:00:00 +02:00
|
|
|
|
pfnSetFatPHS
|
2009-11-25 22:00:00 +01:00
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
set fat PHS
|
2009-11-25 22:00:00 +01:00
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-05-22 22:00:00 +02:00
|
|
|
|
byte *pfnSetFatPAS( const float *org, int portal )
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
if( !org ) return NULL;
|
|
|
|
|
return CM_FatPHS( org, portal );
|
2009-01-11 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnCheckVisibility
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnCheckVisibility( const edict_t *entity, byte *pset )
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
int i, l;
|
|
|
|
|
|
|
|
|
|
if( !SV_IsValidEdict( entity ))
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_WARN, "SV_CheckVisibility: invalid entity %s\n", SV_ClassName( entity ));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !pset ) return 1; // vis not set - fullvis enabled
|
|
|
|
|
|
|
|
|
|
// never send entities that aren't linked in
|
|
|
|
|
if( !entity->pvServerData->linked ) return 0;
|
|
|
|
|
|
|
|
|
|
// check individual leafs
|
2010-05-22 22:00:00 +02:00
|
|
|
|
if( !entity->pvServerData->num_leafs )
|
2009-11-25 22:00:00 +01:00
|
|
|
|
return 0; // not a linked in
|
|
|
|
|
|
2010-05-22 22:00:00 +02:00
|
|
|
|
if( entity->pvServerData->num_leafs == -1 )
|
|
|
|
|
{
|
|
|
|
|
// too many leafs for individual check, go by headnode
|
|
|
|
|
if( !CM_HeadnodeVisible( entity->pvServerData->headnode, pset ))
|
|
|
|
|
return 0;
|
2009-11-25 22:00:00 +01:00
|
|
|
|
}
|
2010-05-22 22:00:00 +02:00
|
|
|
|
else
|
2009-11-25 22:00:00 +01:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
// check individual leafs
|
|
|
|
|
for( i = 0; i < entity->pvServerData->num_leafs; i++ )
|
2009-11-25 22:00:00 +01:00
|
|
|
|
{
|
2010-05-22 22:00:00 +02:00
|
|
|
|
l = entity->pvServerData->leafnums[i];
|
|
|
|
|
|
|
|
|
|
if( pset[l>>3] & (1<<( l & 7 )))
|
|
|
|
|
break;
|
2009-11-25 22:00:00 +01:00
|
|
|
|
}
|
2010-05-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( i == entity->pvServerData->num_leafs )
|
|
|
|
|
return 0; // not visible
|
2009-11-25 22:00:00 +01:00
|
|
|
|
}
|
2010-05-28 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// run additional check for BoxVisible
|
|
|
|
|
if( pe && CM_GetModelType( entity->v.modelindex ) == mod_brush )
|
|
|
|
|
{
|
|
|
|
|
if( !pe->BoxVisible( entity->v.absmin, entity->v.absmax, pset ))
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-11 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnCanSkipPlayer
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnCanSkipPlayer( const edict_t *player )
|
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
|
|
|
|
|
cl = SV_ClientFromEdict( player, true );
|
|
|
|
|
if( cl == NULL )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_CanSkip: client is not connected!\n" );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-14 22:00:00 +01:00
|
|
|
|
if( com.atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )) == 1 )
|
2009-11-25 22:00:00 +01:00
|
|
|
|
return true;
|
2009-01-11 22:00:00 +01:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetCurrentPlayer
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnGetCurrentPlayer( void )
|
|
|
|
|
{
|
|
|
|
|
if( svs.currentPlayer )
|
|
|
|
|
return svs.currentPlayer - svs.clients;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-18 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnSetGroupMask
|
2009-09-18 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
void pfnSetGroupMask( int mask, int op )
|
2009-09-18 22:00:00 +02:00
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
svs.groupmask = mask;
|
|
|
|
|
svs.groupop = op;
|
2009-09-18 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 22:00:00 +02:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnEndSection
|
2009-09-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-06-23 22:00:00 +02:00
|
|
|
|
void pfnEndSection( const char *pszSection )
|
2009-09-22 22:00:00 +02:00
|
|
|
|
{
|
2010-06-23 22:00:00 +02:00
|
|
|
|
if( !com.stricmp( "credits", pszSection ))
|
2009-11-25 22:00:00 +01:00
|
|
|
|
Host_Credits ();
|
2010-06-23 22:00:00 +02:00
|
|
|
|
else Host_EndGame( pszSection );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetPlayerUserId
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
int pfnGetPlayerUserId( edict_t *e )
|
|
|
|
|
{
|
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if( !svs.initialized )
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
if( !SV_ClientFromEdict( e, false ))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
|
|
|
|
|
{
|
|
|
|
|
if( cl->edict == e )
|
|
|
|
|
{
|
|
|
|
|
return cl->userid;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// couldn't find it
|
|
|
|
|
return -1;
|
2009-09-22 22:00:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnGetPlayerAuthId
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
These function must returns cd-key hashed value
|
|
|
|
|
but Xash3D currently doesn't have any security checks
|
|
|
|
|
return nullstring for now
|
2008-12-15 22:00:00 +01:00
|
|
|
|
=============
|
|
|
|
|
*/
|
2010-06-23 22:00:00 +02:00
|
|
|
|
const char *pfnGetPlayerAuthId( edict_t *e )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-06-23 22:00:00 +02:00
|
|
|
|
return "";
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnPlayMusic
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnPlayMusic( const char *trackname, int flags )
|
|
|
|
|
{
|
|
|
|
|
SV_ConfigString( CS_BACKGROUND_TRACK, trackname );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnDropClient
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnDropClient( int clientIndex )
|
|
|
|
|
{
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( clientIndex < 0 || clientIndex >= svgame.globals->maxClients )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_DropClient: not a client\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if( svs.clients[clientIndex].state != cs_spawned )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_DropClient: that client slot is not connected\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
SV_DropClient( svs.clients + clientIndex );
|
|
|
|
|
}
|
2009-09-22 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnGetPlayerPing
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
2009-11-23 22:00:00 +01:00
|
|
|
|
void pfnGetPlayerStats( const edict_t *pClient, int *ping, int *packet_loss )
|
2009-09-22 22:00:00 +02:00
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
sv_client_t *cl;
|
|
|
|
|
|
|
|
|
|
cl = SV_ClientFromEdict( pClient, false );
|
|
|
|
|
if( cl == NULL )
|
|
|
|
|
{
|
|
|
|
|
MsgDev( D_ERROR, "SV_GetPlayerStats: client is not connected!\n" );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( ping ) *ping = cl->ping;
|
|
|
|
|
if( packet_loss ) *packet_loss = cl->packet_loss;
|
2009-09-22 22:00:00 +02:00
|
|
|
|
}
|
2009-11-23 22:00:00 +01:00
|
|
|
|
|
2009-11-25 22:00:00 +01:00
|
|
|
|
/*
|
|
|
|
|
=============
|
|
|
|
|
pfnAddServerCommand
|
|
|
|
|
|
|
|
|
|
=============
|
|
|
|
|
*/
|
|
|
|
|
void pfnAddServerCommand( const char *cmd_name, void (*function)(void), const char *cmd_desc )
|
2009-11-23 22:00:00 +01:00
|
|
|
|
{
|
2009-11-25 22:00:00 +01:00
|
|
|
|
Cmd_AddCommand( cmd_name, function, cmd_desc );
|
2009-11-23 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// engine callbacks
|
|
|
|
|
static enginefuncs_t gEngfuncs =
|
|
|
|
|
{
|
|
|
|
|
pfnPrecacheModel,
|
|
|
|
|
pfnPrecacheSound,
|
|
|
|
|
pfnSetModel,
|
|
|
|
|
pfnModelIndex,
|
|
|
|
|
pfnModelFrames,
|
|
|
|
|
pfnSetSize,
|
|
|
|
|
pfnChangeLevel,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnFindClientInPHS,
|
|
|
|
|
pfnEntitiesInPHS,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnVecToYaw,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnVecToAngles,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnMoveToOrigin,
|
|
|
|
|
pfnChangeYaw,
|
|
|
|
|
pfnChangePitch,
|
|
|
|
|
pfnFindEntityByString,
|
|
|
|
|
pfnGetEntityIllum,
|
|
|
|
|
pfnFindEntityInSphere,
|
|
|
|
|
pfnFindClientInPVS,
|
|
|
|
|
pfnEntitiesInPVS,
|
|
|
|
|
pfnMakeVectors,
|
2008-12-25 22:00:00 +01:00
|
|
|
|
AngleVectors,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnCreateEntity,
|
|
|
|
|
pfnRemoveEntity,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnCreateNamedEntity,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnMakeStatic,
|
2009-01-11 22:00:00 +01:00
|
|
|
|
pfnLinkEntity,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnDropToFloor,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnWalkMove,
|
|
|
|
|
pfnSetOrigin,
|
2009-01-25 22:00:00 +01:00
|
|
|
|
SV_StartSound,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnEmitAmbientSound,
|
|
|
|
|
pfnTraceLine,
|
|
|
|
|
pfnTraceToss,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnTraceMonsterHull,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnTraceHull,
|
|
|
|
|
pfnTraceModel,
|
|
|
|
|
pfnTraceTexture,
|
2010-04-01 22:00:00 +02:00
|
|
|
|
pfnTestEntityPosition,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnGetAimVector,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnServerCommand,
|
|
|
|
|
pfnServerExecute,
|
|
|
|
|
pfnClientCommand,
|
|
|
|
|
pfnParticleEffect,
|
|
|
|
|
pfnLightStyle,
|
|
|
|
|
pfnDecalIndex,
|
|
|
|
|
pfnPointContents,
|
|
|
|
|
pfnMessageBegin,
|
|
|
|
|
pfnMessageEnd,
|
|
|
|
|
pfnWriteByte,
|
|
|
|
|
pfnWriteChar,
|
|
|
|
|
pfnWriteShort,
|
|
|
|
|
pfnWriteLong,
|
|
|
|
|
pfnWriteAngle,
|
|
|
|
|
pfnWriteCoord,
|
|
|
|
|
pfnWriteString,
|
|
|
|
|
pfnWriteEntity,
|
|
|
|
|
pfnCVarRegister,
|
2009-12-04 22:00:00 +01:00
|
|
|
|
pfnCVarGetValue,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnCVarGetString,
|
2009-12-04 22:00:00 +01:00
|
|
|
|
pfnCVarSetValue,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnCVarSetString,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnAlertMessage,
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnGetProcAddress,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnPvAllocEntPrivateData,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnPvEntPrivateData,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnFreeEntPrivateData,
|
2008-12-26 22:00:00 +01:00
|
|
|
|
SV_GetString,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
SV_AllocString,
|
|
|
|
|
pfnGetVarsOfEnt,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnPEntityOfEntOffset,
|
|
|
|
|
pfnEntOffsetOfPEntity,
|
|
|
|
|
pfnIndexOfEdict,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnPEntityOfEntIndex,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnFindEntityByVars,
|
|
|
|
|
pfnGetModelPtr,
|
|
|
|
|
pfnRegUserMsg,
|
2010-05-22 22:00:00 +02:00
|
|
|
|
pfnAnimationAutomove,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnGetBonePosition,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnFunctionFromName,
|
|
|
|
|
pfnNameForFunction,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnClientPrintf,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnServerPrint,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnCmd_Args,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnCmd_Argv,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnCmd_Argc,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnGetAttachment,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnCRC32_Init,
|
|
|
|
|
pfnCRC32_ProcessBuffer,
|
|
|
|
|
pfnCRC32_ProcessByte,
|
|
|
|
|
pfnCRC32_Final,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnRandomLong,
|
|
|
|
|
pfnRandomFloat,
|
2009-09-18 22:00:00 +02:00
|
|
|
|
pfnSetView,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnTime,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnCrosshairAngle,
|
|
|
|
|
pfnLoadFile,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnFreeFile,
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnEndSection,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnCompareFileTime,
|
2010-04-09 22:00:00 +02:00
|
|
|
|
pfnGetGameDir,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnClassifyEdict,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnFadeClientVolume,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnSetClientMaxspeed,
|
|
|
|
|
pfnCreateFakeClient,
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnRunPlayerMove,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnFileExists,
|
|
|
|
|
pfnGetInfoKeyBuffer,
|
|
|
|
|
pfnInfoKeyValue,
|
|
|
|
|
pfnSetKeyValue,
|
|
|
|
|
pfnSetClientKeyValue,
|
|
|
|
|
pfnIsMapValid,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnStaticDecal,
|
|
|
|
|
pfnPrecacheGeneric,
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnGetPlayerUserId,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnPlayMusic,
|
|
|
|
|
pfnIsDedicatedServer,
|
|
|
|
|
pfnMemAlloc,
|
|
|
|
|
pfnMemFree,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pfnInfo_RemoveKey,
|
2009-11-10 22:00:00 +01:00
|
|
|
|
pfnGetPhysicsKeyValue,
|
|
|
|
|
pfnSetPhysicsKeyValue,
|
|
|
|
|
pfnGetPhysicsInfoString,
|
2009-01-11 22:00:00 +01:00
|
|
|
|
pfnPrecacheEvent,
|
|
|
|
|
pfnPlaybackEvent,
|
2010-05-22 22:00:00 +02:00
|
|
|
|
pfnSetFatPVS,
|
|
|
|
|
pfnSetFatPAS,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnCheckVisibility,
|
2010-08-06 22:00:00 +02:00
|
|
|
|
Delta_SetField,
|
|
|
|
|
Delta_UnsetField,
|
|
|
|
|
Delta_AddEncoder,
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnGetCurrentPlayer,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnCanSkipPlayer,
|
2010-08-06 22:00:00 +02:00
|
|
|
|
Delta_FindField,
|
|
|
|
|
Delta_SetFieldByIndex,
|
|
|
|
|
Delta_UnsetFieldByIndex,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnSetGroupMask,
|
2009-09-22 22:00:00 +02:00
|
|
|
|
pfnDropClient,
|
|
|
|
|
Host_Error,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnParseToken,
|
|
|
|
|
pfnGetPlayerStats,
|
2009-11-25 22:00:00 +01:00
|
|
|
|
pfnAddServerCommand,
|
2009-11-23 22:00:00 +01:00
|
|
|
|
pfnLoadLibrary,
|
|
|
|
|
pfnFreeLibrary,
|
2010-06-23 22:00:00 +02:00
|
|
|
|
pfnGetPlayerAuthId,
|
2008-12-15 22:00:00 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
====================
|
|
|
|
|
SV_ParseEdict
|
|
|
|
|
|
|
|
|
|
Parses an edict out of the given string, returning the new position
|
|
|
|
|
ed should be a properly initialized empty edict.
|
|
|
|
|
====================
|
|
|
|
|
*/
|
|
|
|
|
bool SV_ParseEdict( script_t *script, edict_t *ent )
|
|
|
|
|
{
|
|
|
|
|
KeyValueData pkvd[256]; // per one entity
|
|
|
|
|
int i, numpairs = 0;
|
|
|
|
|
const char *classname = NULL;
|
2010-03-09 22:00:00 +01:00
|
|
|
|
bool anglehack;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
token_t token;
|
|
|
|
|
|
|
|
|
|
// go through all the dictionary pairs
|
|
|
|
|
while( 1 )
|
|
|
|
|
{
|
|
|
|
|
string keyname;
|
|
|
|
|
|
|
|
|
|
// parse key
|
2010-06-08 22:00:00 +02:00
|
|
|
|
if( !Com_ReadToken( script, SC_ALLOW_NEWLINES|SC_ALLOW_PATHNAMES2, &token ))
|
2010-04-13 22:00:00 +02:00
|
|
|
|
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( token.string[0] == '}' ) break; // end of desc
|
2010-03-09 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// anglehack is to allow QuakeEd to write single scalar angles
|
2010-03-30 22:00:00 +02:00
|
|
|
|
// and allow them to be turned into vectors.
|
2010-03-09 22:00:00 +01:00
|
|
|
|
if( !com.strcmp( token.string, "angle" ))
|
|
|
|
|
{
|
|
|
|
|
com.strncpy( token.string, "angles", sizeof( token.string ));
|
|
|
|
|
anglehack = true;
|
|
|
|
|
}
|
|
|
|
|
else anglehack = false;
|
|
|
|
|
|
|
|
|
|
com.strncpy( keyname, token.string, sizeof( keyname ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// parse value
|
|
|
|
|
if( !Com_ReadToken( script, SC_ALLOW_PATHNAMES2, &token ))
|
2010-04-13 22:00:00 +02:00
|
|
|
|
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
if( token.string[0] == '}' )
|
2010-04-13 22:00:00 +02:00
|
|
|
|
Host_Error( "ED_ParseEdict: closing brace without data\n" );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-03-09 22:00:00 +01:00
|
|
|
|
// ignore attempts to set key ""
|
|
|
|
|
if( !keyname[0] ) continue;
|
|
|
|
|
|
2010-06-08 22:00:00 +02:00
|
|
|
|
// "wad" field is completely ignored
|
2010-03-28 22:00:00 +02:00
|
|
|
|
if( !com.strcmp( keyname, "wad" ))
|
|
|
|
|
continue;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// keynames with a leading underscore are used for utility comments,
|
|
|
|
|
// and are immediately discarded by engine
|
|
|
|
|
if( keyname[0] == '_' ) continue;
|
|
|
|
|
|
2010-03-09 22:00:00 +01:00
|
|
|
|
if( anglehack )
|
|
|
|
|
{
|
|
|
|
|
string temp;
|
|
|
|
|
com.strncpy( temp, token.string, sizeof( temp ));
|
|
|
|
|
com.snprintf( token.string, sizeof( token.string ), "0 %s 0", temp );
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
// create keyvalue strings
|
|
|
|
|
pkvd[numpairs].szClassName = (char *)classname; // unknown at this moment
|
2010-03-28 22:00:00 +02:00
|
|
|
|
pkvd[numpairs].szKeyName = copystring( keyname );
|
|
|
|
|
pkvd[numpairs].szValue = copystring( token.string );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
pkvd[numpairs].fHandled = false;
|
|
|
|
|
|
|
|
|
|
if( !com.strcmp( keyname, "classname" ) && classname == NULL )
|
|
|
|
|
classname = pkvd[numpairs].szValue;
|
|
|
|
|
if( ++numpairs >= 256 ) break;
|
|
|
|
|
}
|
2009-01-02 22:00:00 +01:00
|
|
|
|
|
2009-01-10 22:00:00 +01:00
|
|
|
|
ent = SV_AllocPrivateData( ent, MAKE_STRING( classname ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2009-01-18 22:00:00 +01:00
|
|
|
|
if( ent->v.flags & FL_KILLME )
|
|
|
|
|
return false;
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
for( i = 0; i < numpairs; i++ )
|
|
|
|
|
{
|
2010-03-28 22:00:00 +02:00
|
|
|
|
if( !pkvd[i].fHandled )
|
|
|
|
|
{
|
|
|
|
|
pkvd[i].szClassName = (char *)classname;
|
|
|
|
|
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// no reason to keep this data
|
|
|
|
|
Mem_Free( pkvd[i].szKeyName );
|
|
|
|
|
Mem_Free( pkvd[i].szValue );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
================
|
|
|
|
|
SV_LoadFromFile
|
|
|
|
|
|
|
|
|
|
The entities are directly placed in the array, rather than allocated with
|
|
|
|
|
ED_Alloc, because otherwise an error loading the map would have entity
|
|
|
|
|
number references out of order.
|
|
|
|
|
|
|
|
|
|
Creates a server's entity / program execution context by
|
|
|
|
|
parsing textual entity definitions out of an ent file.
|
|
|
|
|
================
|
|
|
|
|
*/
|
|
|
|
|
void SV_LoadFromFile( script_t *entities )
|
|
|
|
|
{
|
|
|
|
|
token_t token;
|
|
|
|
|
int inhibited, spawned, died;
|
2009-09-24 22:00:00 +02:00
|
|
|
|
int current_skill = Cvar_VariableInteger( "skill" ); // lock skill level
|
|
|
|
|
bool deathmatch = Cvar_VariableInteger( "deathmatch" );
|
2008-12-16 22:00:00 +01:00
|
|
|
|
bool create_world = true;
|
|
|
|
|
edict_t *ent;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
inhibited = 0;
|
|
|
|
|
spawned = 0;
|
|
|
|
|
died = 0;
|
|
|
|
|
|
|
|
|
|
// parse ents
|
2010-06-08 22:00:00 +02:00
|
|
|
|
while( Com_ReadToken( entities, SC_ALLOW_NEWLINES|SC_ALLOW_PATHNAMES2, &token ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
|
|
|
|
if( token.string[0] != '{' )
|
2010-04-13 22:00:00 +02:00
|
|
|
|
Host_Error( "ED_LoadFromFile: found %s when expecting {\n", token.string );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2008-12-16 22:00:00 +01:00
|
|
|
|
if( create_world )
|
|
|
|
|
{
|
|
|
|
|
create_world = false;
|
2009-09-24 22:00:00 +02:00
|
|
|
|
ent = EDICT_NUM( 0 ); // already initialized
|
2008-12-16 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
else ent = SV_AllocEdict();
|
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( !SV_ParseEdict( entities, ent ))
|
|
|
|
|
continue;
|
2008-12-16 22:00:00 +01:00
|
|
|
|
|
2009-09-24 22:00:00 +02:00
|
|
|
|
// remove things from different skill levels or deathmatch
|
|
|
|
|
if( deathmatch )
|
|
|
|
|
{
|
|
|
|
|
if( ent->v.spawnflags & SF_NOT_DEATHMATCH )
|
|
|
|
|
{
|
|
|
|
|
SV_FreeEdict( ent );
|
|
|
|
|
inhibited++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-03-07 22:00:00 +01:00
|
|
|
|
else if( GI->sp_inhibite_ents && current_skill == 0 && ent->v.spawnflags & SF_NOT_EASY )
|
2009-09-24 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
SV_FreeEdict( ent );
|
|
|
|
|
inhibited++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2010-03-07 22:00:00 +01:00
|
|
|
|
else if( GI->sp_inhibite_ents && current_skill == 1 && ent->v.spawnflags & SF_NOT_MEDIUM )
|
2009-09-24 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
SV_FreeEdict( ent );
|
|
|
|
|
inhibited++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2010-03-07 22:00:00 +01:00
|
|
|
|
else if( GI->sp_inhibite_ents && current_skill >= 2 && ent->v.spawnflags & SF_NOT_HARD )
|
2009-09-24 22:00:00 +02:00
|
|
|
|
{
|
|
|
|
|
SV_FreeEdict( ent );
|
|
|
|
|
inhibited++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( svgame.dllFuncs.pfnSpawn( ent ) == -1 )
|
2008-12-16 22:00:00 +01:00
|
|
|
|
died++;
|
|
|
|
|
else spawned++;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
MsgDev( D_INFO, "%i entities inhibited\n", inhibited );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
==============
|
|
|
|
|
SpawnEntities
|
|
|
|
|
|
|
|
|
|
Creates a server's entity / program execution context by
|
|
|
|
|
parsing textual entity definitions out of an ent file.
|
|
|
|
|
==============
|
|
|
|
|
*/
|
|
|
|
|
void SV_SpawnEntities( const char *mapname, script_t *entities )
|
|
|
|
|
{
|
|
|
|
|
edict_t *ent;
|
|
|
|
|
|
|
|
|
|
MsgDev( D_NOTE, "SV_SpawnEntities()\n" );
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
// reset misc parms
|
2010-06-16 22:00:00 +02:00
|
|
|
|
Cvar_Reset( "sv_zmax" );
|
|
|
|
|
Cvar_Reset( "sv_wateramp" );
|
2010-06-23 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
// reset sky parms
|
2010-06-16 22:00:00 +02:00
|
|
|
|
Cvar_Reset( "sv_skycolor_r" );
|
|
|
|
|
Cvar_Reset( "sv_skycolor_g" );
|
|
|
|
|
Cvar_Reset( "sv_skycolor_b" );
|
|
|
|
|
Cvar_Reset( "sv_skyvec_x" );
|
|
|
|
|
Cvar_Reset( "sv_skyvec_y" );
|
|
|
|
|
Cvar_Reset( "sv_skyvec_z" );
|
2010-06-23 22:00:00 +02:00
|
|
|
|
Cvar_Reset( "sv_skyname" );
|
2010-06-16 22:00:00 +02:00
|
|
|
|
|
2008-12-17 22:00:00 +01:00
|
|
|
|
ent = EDICT_NUM( 0 );
|
2009-09-28 22:00:00 +02:00
|
|
|
|
if( ent->free ) SV_InitEdict( ent );
|
|
|
|
|
ent->v.model = MAKE_STRING( sv.configstrings[CS_MODELS+1] );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
ent->v.modelindex = 1; // world model
|
|
|
|
|
ent->v.solid = SOLID_BSP;
|
|
|
|
|
ent->v.movetype = MOVETYPE_PUSH;
|
2009-01-11 22:00:00 +01:00
|
|
|
|
|
2009-11-27 22:00:00 +01:00
|
|
|
|
svgame.globals->maxEntities = GI->max_edicts;
|
|
|
|
|
svgame.globals->maxClients = sv_maxclients->integer;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals->mapname = MAKE_STRING( sv.name );
|
2009-09-28 22:00:00 +02:00
|
|
|
|
svgame.globals->startspot = MAKE_STRING( sv.startspot );
|
2010-07-23 22:00:00 +02:00
|
|
|
|
svgame.globals->time = sv_time();
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// spawn the rest of the entities on the map
|
|
|
|
|
SV_LoadFromFile( entities );
|
2010-04-09 22:00:00 +02:00
|
|
|
|
if( !pe ) Com_CloseScript( entities );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-03-28 22:00:00 +02:00
|
|
|
|
MsgDev( D_NOTE, "Total %i entities spawned\n", svgame.globals->numEntities );
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SV_UnloadProgs( void )
|
|
|
|
|
{
|
2009-09-28 22:00:00 +02:00
|
|
|
|
SV_DeactivateServer ();
|
2008-12-26 22:00:00 +01:00
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
Delta_Shutdown ();
|
|
|
|
|
|
2009-09-28 22:00:00 +02:00
|
|
|
|
svgame.dllFuncs.pfnGameShutdown ();
|
2010-03-30 22:00:00 +02:00
|
|
|
|
|
|
|
|
|
if( sys_sharedstrings->integer )
|
|
|
|
|
Mem_FreePool( &svgame.stringspool );
|
|
|
|
|
else StringTable_Delete( svgame.hStringTable );
|
2009-01-22 22:00:00 +01:00
|
|
|
|
|
2010-03-27 22:00:00 +01:00
|
|
|
|
FS_FreeLibrary( svgame.hInstance );
|
2008-12-26 22:00:00 +01:00
|
|
|
|
Mem_FreePool( &svgame.mempool );
|
|
|
|
|
Mem_FreePool( &svgame.private );
|
2009-09-28 22:00:00 +02:00
|
|
|
|
Mem_Set( &svgame, 0, sizeof( svgame ));
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2010-03-25 22:00:00 +01:00
|
|
|
|
bool SV_LoadProgs( const char *name )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-06-23 22:00:00 +02:00
|
|
|
|
static APIFUNCTION GetEntityAPI;
|
|
|
|
|
static GIVEFNPTRSTODLL GiveFnptrsToDll;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
static globalvars_t gpGlobals;
|
2009-11-10 22:00:00 +01:00
|
|
|
|
static playermove_t gpMove;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
edict_t *e;
|
|
|
|
|
int i;
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
if( svgame.hInstance ) SV_UnloadProgs();
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// fill it in
|
2009-11-10 22:00:00 +01:00
|
|
|
|
svgame.pmove = &gpMove;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.globals = &gpGlobals;
|
|
|
|
|
svgame.mempool = Mem_AllocPool( "Server Edicts Zone" );
|
|
|
|
|
svgame.private = Mem_AllocPool( "Server Private Zone" );
|
2010-03-27 22:00:00 +01:00
|
|
|
|
svgame.hInstance = FS_LoadLibrary( name, true );
|
2010-03-28 22:00:00 +02:00
|
|
|
|
if( !svgame.hInstance ) return false;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
GetEntityAPI = (APIFUNCTION)FS_GetProcAddress( svgame.hInstance, "GetEntityAPI" );
|
2010-03-27 22:00:00 +01:00
|
|
|
|
|
2008-12-15 22:00:00 +01:00
|
|
|
|
if( !GetEntityAPI )
|
|
|
|
|
{
|
2010-03-28 22:00:00 +02:00
|
|
|
|
FS_FreeLibrary( svgame.hInstance );
|
2010-06-23 22:00:00 +02:00
|
|
|
|
MsgDev( D_NOTE, "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" );
|
|
|
|
|
svgame.hInstance = NULL;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GiveFnptrsToDll = (GIVEFNPTRSTODLL)FS_GetProcAddress( svgame.hInstance, "GiveFnptrsToDll" );
|
|
|
|
|
|
|
|
|
|
if( !GiveFnptrsToDll )
|
|
|
|
|
{
|
|
|
|
|
FS_FreeLibrary( svgame.hInstance );
|
|
|
|
|
MsgDev( D_NOTE, "SV_LoadProgs: failed to get address of GiveFnptrsToDll proc\n" );
|
2010-03-28 22:00:00 +02:00
|
|
|
|
svgame.hInstance = NULL;
|
2010-03-25 22:00:00 +01:00
|
|
|
|
return false;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
if( !GetEntityAPI( &svgame.dllFuncs, SV_INTERFACE_VERSION ))
|
2008-12-15 22:00:00 +01:00
|
|
|
|
{
|
2010-03-28 22:00:00 +02:00
|
|
|
|
FS_FreeLibrary( svgame.hInstance );
|
2010-06-23 22:00:00 +02:00
|
|
|
|
MsgDev( D_ERROR, "SV_LoadProgs: couldn't get entity API\n" );
|
2010-03-28 22:00:00 +02:00
|
|
|
|
svgame.hInstance = NULL;
|
2010-03-25 22:00:00 +01:00
|
|
|
|
return false;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2010-06-23 22:00:00 +02:00
|
|
|
|
GiveFnptrsToDll( &gEngfuncs, svgame.globals );
|
|
|
|
|
|
2010-03-30 22:00:00 +02:00
|
|
|
|
svgame.globals->pStringBase = ""; // setup string base
|
|
|
|
|
|
|
|
|
|
if( sys_sharedstrings->integer )
|
|
|
|
|
{
|
|
|
|
|
// just use Half-Life system - base pointer and malloc
|
|
|
|
|
svgame.stringspool = Mem_AllocPool( "Server Strings" );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 65535 unique strings should be enough ...
|
|
|
|
|
svgame.hStringTable = StringTable_Create( "Server", 0x10000 );
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-24 22:00:00 +02:00
|
|
|
|
svgame.globals->maxEntities = GI->max_edicts;
|
2009-09-25 22:00:00 +02:00
|
|
|
|
svgame.globals->maxClients = sv_maxclients->integer;
|
2008-12-26 22:00:00 +01:00
|
|
|
|
svgame.edicts = Mem_Alloc( svgame.mempool, sizeof( edict_t ) * svgame.globals->maxEntities );
|
|
|
|
|
svgame.globals->numEntities = svgame.globals->maxClients + 1; // clients + world
|
|
|
|
|
for( i = 0, e = svgame.edicts; i < svgame.globals->maxEntities; i++, e++ )
|
2008-12-15 22:00:00 +01:00
|
|
|
|
e->free = true; // mark all edicts as freed
|
|
|
|
|
|
2010-07-19 22:00:00 +02:00
|
|
|
|
// clear user messages
|
|
|
|
|
svgame.gmsgHudText = -1;
|
|
|
|
|
|
2008-12-26 22:00:00 +01:00
|
|
|
|
// all done, initialize game
|
|
|
|
|
svgame.dllFuncs.pfnGameInit();
|
2010-06-22 22:00:00 +02:00
|
|
|
|
pfnRegUserMsg( "svc_bad", 0 ); // register svc_bad message
|
2009-11-10 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
// initialize pm_shared
|
|
|
|
|
SV_InitClientMove();
|
2009-12-10 22:00:00 +01:00
|
|
|
|
|
2010-08-04 22:00:00 +02:00
|
|
|
|
Delta_Init ();
|
|
|
|
|
|
2010-08-05 22:00:00 +02:00
|
|
|
|
// register custom encoders
|
|
|
|
|
svgame.dllFuncs.pfnRegisterEncoders();
|
|
|
|
|
|
2009-12-10 22:00:00 +01:00
|
|
|
|
// fire once
|
|
|
|
|
MsgDev( D_INFO, "Dll loaded for mod %s\n", svgame.dllFuncs.pfnGetGameDescription() );
|
2010-03-25 22:00:00 +01:00
|
|
|
|
|
|
|
|
|
return true;
|
2008-12-15 22:00:00 +01:00
|
|
|
|
}
|