mirror of
https://github.com/YGGverse/xash3d-fwgs.git
synced 2025-01-17 18:40:02 +00:00
engine: server: backported enttools from old engine
This commit is contained in:
parent
afa1d429fe
commit
5d73c6cb84
@ -435,6 +435,8 @@ extern convar_t sv_consistency;
|
|||||||
extern convar_t sv_password;
|
extern convar_t sv_password;
|
||||||
extern convar_t sv_uploadmax;
|
extern convar_t sv_uploadmax;
|
||||||
extern convar_t sv_trace_messages;
|
extern convar_t sv_trace_messages;
|
||||||
|
extern convar_t sv_enttools_enable;
|
||||||
|
extern convar_t sv_enttools_maxfire;
|
||||||
extern convar_t deathmatch;
|
extern convar_t deathmatch;
|
||||||
extern convar_t hostname;
|
extern convar_t hostname;
|
||||||
extern convar_t skill;
|
extern convar_t skill;
|
||||||
@ -642,8 +644,11 @@ void SV_RestartAmbientSounds( void );
|
|||||||
void SV_RestartDecals( void );
|
void SV_RestartDecals( void );
|
||||||
void SV_RestartStaticEnts( void );
|
void SV_RestartStaticEnts( void );
|
||||||
int pfnGetCurrentPlayer( void );
|
int pfnGetCurrentPlayer( void );
|
||||||
|
int pfnDropToFloor( edict_t* e );
|
||||||
edict_t *SV_EdictNum( int n );
|
edict_t *SV_EdictNum( int n );
|
||||||
char *SV_Localinfo( void );
|
char *SV_Localinfo( void );
|
||||||
|
void SV_SetModel( edict_t *ent, const char *name );
|
||||||
|
|
||||||
//
|
//
|
||||||
// sv_log.c
|
// sv_log.c
|
||||||
//
|
//
|
||||||
|
@ -2119,6 +2119,780 @@ static qboolean SV_SendBuildInfo_f( sv_client_t *cl )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
SV_GetCrossEnt
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
static edict_t *SV_GetCrossEnt( edict_t *player )
|
||||||
|
{
|
||||||
|
edict_t *ent = EDICT_NUM(1);
|
||||||
|
edict_t *closest = NULL;
|
||||||
|
float flMaxDot = 0.94;
|
||||||
|
vec3_t forward;
|
||||||
|
vec3_t viewPos;
|
||||||
|
int i;
|
||||||
|
float maxLen = 1000;
|
||||||
|
|
||||||
|
AngleVectors( player->v.v_angle, forward, NULL, NULL );
|
||||||
|
VectorAdd( player->v.origin, player->v.view_ofs, viewPos );
|
||||||
|
|
||||||
|
// find bmodels by trace
|
||||||
|
{
|
||||||
|
trace_t trace;
|
||||||
|
vec3_t target;
|
||||||
|
|
||||||
|
VectorMA( viewPos, 1000, forward, target );
|
||||||
|
trace = SV_Move( viewPos, vec3_origin, vec3_origin, target, 0, player, false );
|
||||||
|
closest = trace.ent;
|
||||||
|
VectorSubtract( viewPos, trace.endpos, target );
|
||||||
|
maxLen = VectorLength(target) + 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check untraceable entities
|
||||||
|
for ( i = 1; i < svgame.numEntities; i++, ent++ )
|
||||||
|
{
|
||||||
|
vec3_t vecLOS;
|
||||||
|
vec3_t vecOrigin;
|
||||||
|
float flDot, traceLen;
|
||||||
|
vec3_t boxSize;
|
||||||
|
trace_t trace;
|
||||||
|
vec3_t vecTrace;
|
||||||
|
|
||||||
|
if( ent->free )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( ent->v.solid == SOLID_BSP || ent->v.movetype == MOVETYPE_PUSHSTEP )
|
||||||
|
continue; // bsp models will be found by trace later
|
||||||
|
|
||||||
|
// do not touch following weapons
|
||||||
|
if( ent->v.movetype == MOVETYPE_FOLLOW )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( ent == player )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
VectorAdd( ent->v.absmin, ent->v.absmax, vecOrigin );
|
||||||
|
VectorScale( vecOrigin, 0.5, vecOrigin );
|
||||||
|
|
||||||
|
VectorSubtract( vecOrigin, viewPos, vecLOS );
|
||||||
|
traceLen = VectorLength(vecLOS);
|
||||||
|
|
||||||
|
if( traceLen > maxLen )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
VectorCopy( ent->v.size, boxSize);
|
||||||
|
VectorScale( boxSize, 0.5, boxSize );
|
||||||
|
|
||||||
|
if ( vecLOS[0] > boxSize[0] )
|
||||||
|
vecLOS[0] -= boxSize[0];
|
||||||
|
else if ( vecLOS[0] < -boxSize[0] )
|
||||||
|
vecLOS[0] += boxSize[0];
|
||||||
|
else
|
||||||
|
vecLOS[0] = 0;
|
||||||
|
|
||||||
|
if ( vecLOS[1] > boxSize[1] )
|
||||||
|
vecLOS[1] -= boxSize[1];
|
||||||
|
else if ( vecLOS[1] < -boxSize[1] )
|
||||||
|
vecLOS[1] += boxSize[1];
|
||||||
|
else
|
||||||
|
vecLOS[1] = 0;
|
||||||
|
|
||||||
|
if ( vecLOS[2] > boxSize[2] )
|
||||||
|
vecLOS[2] -= boxSize[2];
|
||||||
|
else if ( vecLOS[2] < -boxSize[2] )
|
||||||
|
vecLOS[2] += boxSize[2];
|
||||||
|
else
|
||||||
|
vecLOS[2] = 0;
|
||||||
|
VectorNormalize( vecLOS );
|
||||||
|
|
||||||
|
flDot = DotProduct (vecLOS , forward);
|
||||||
|
if ( flDot <= flMaxDot )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
trace = SV_Move( viewPos, vec3_origin, vec3_origin, vecOrigin, 0, player, false );
|
||||||
|
VectorSubtract( trace.endpos, viewPos, vecTrace );
|
||||||
|
if( VectorLength( vecTrace ) + 30 < traceLen )
|
||||||
|
continue;
|
||||||
|
closest = ent, flMaxDot = flDot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==================
|
||||||
|
SV_EntFindSingle
|
||||||
|
==================
|
||||||
|
*/
|
||||||
|
static edict_t *SV_EntFindSingle( sv_client_t *cl, const char *pattern )
|
||||||
|
{
|
||||||
|
edict_t *ent = NULL;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if( Q_isdigit( pattern ) )
|
||||||
|
{
|
||||||
|
i = Q_atoi( pattern );
|
||||||
|
|
||||||
|
if( i >= svgame.numEntities )
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( pattern, "!cross" ) )
|
||||||
|
{
|
||||||
|
ent = SV_GetCrossEnt( cl->edict );
|
||||||
|
|
||||||
|
if( !SV_IsValidEdict( ent ) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
i = NUM_FOR_EDICT( ent );
|
||||||
|
}
|
||||||
|
else if( pattern[0] == '!' ) // check for correct instance with !(num)_(serial)
|
||||||
|
{
|
||||||
|
const char *p = pattern + 1;
|
||||||
|
i = Q_atoi( p );
|
||||||
|
|
||||||
|
while( Q_isdigit( p )) p++;
|
||||||
|
|
||||||
|
if( *p++ != '_' )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if( i >= svgame.numEntities )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ent = EDICT_NUM( i );
|
||||||
|
|
||||||
|
if( ent->serialnumber != Q_atoi( p ) )
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( i = svgame.globals->maxClients + 1; i < svgame.numEntities; i++ )
|
||||||
|
{
|
||||||
|
ent = EDICT_NUM( i );
|
||||||
|
|
||||||
|
if( !SV_IsValidEdict( ent ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( Q_stricmpext( pattern, STRING( ent->v.targetname ) ) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ent = EDICT_NUM( i );
|
||||||
|
|
||||||
|
if( !SV_IsValidEdict( ent ) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
SV_EntList_f
|
||||||
|
|
||||||
|
Print list of entities to client
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static qboolean SV_EntList_f( sv_client_t *cl )
|
||||||
|
{
|
||||||
|
vec3_t borigin;
|
||||||
|
edict_t *ent = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < svgame.numEntities; i++ )
|
||||||
|
{
|
||||||
|
ent = EDICT_NUM( i );
|
||||||
|
if( !SV_IsValidEdict( ent ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// filter by string
|
||||||
|
if( Cmd_Argc() > 1 )
|
||||||
|
{
|
||||||
|
if( !Q_stricmpext( Cmd_Argv( 1 ), STRING( ent->v.classname ) ) && !Q_stricmpext( Cmd_Argv( 1 ), STRING( ent->v.targetname ) ) )
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
VectorAdd( ent->v.absmin, ent->v.absmax, borigin );
|
||||||
|
VectorScale( borigin, 0.5, borigin );
|
||||||
|
|
||||||
|
SV_ClientPrintf( cl, "%5i origin: %.f %.f %.f", i, ent->v.origin[0], ent->v.origin[1], ent->v.origin[2] );
|
||||||
|
SV_ClientPrintf( cl, "%5i borigin: %.f %.f %.f", i, borigin[0], borigin[1], borigin[2] );
|
||||||
|
|
||||||
|
if( ent->v.classname )
|
||||||
|
SV_ClientPrintf( cl, ", class: %s", STRING( ent->v.classname ));
|
||||||
|
|
||||||
|
if( ent->v.globalname )
|
||||||
|
SV_ClientPrintf( cl, ", global: %s", STRING( ent->v.globalname ));
|
||||||
|
|
||||||
|
if( ent->v.targetname )
|
||||||
|
SV_ClientPrintf( cl, ", name: %s", STRING( ent->v.targetname ));
|
||||||
|
|
||||||
|
if( ent->v.target )
|
||||||
|
SV_ClientPrintf( cl, ", target: %s", STRING( ent->v.target ));
|
||||||
|
|
||||||
|
if( ent->v.model )
|
||||||
|
SV_ClientPrintf( cl, ", model: %s", STRING( ent->v.model ));
|
||||||
|
|
||||||
|
SV_ClientPrintf( cl, "\n" );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
SV_EntInfo_f
|
||||||
|
|
||||||
|
Print specified entity information to client
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static qboolean SV_EntInfo_f( sv_client_t *cl )
|
||||||
|
{
|
||||||
|
edict_t *ent = NULL;
|
||||||
|
vec3_t borigin;
|
||||||
|
|
||||||
|
if( Cmd_Argc() != 2 )
|
||||||
|
{
|
||||||
|
SV_ClientPrintf( cl, "Use ent_info <index|name|inst>\n" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ent = SV_EntFindSingle( cl, Cmd_Argv( 1 ) );
|
||||||
|
|
||||||
|
if( !SV_IsValidEdict( ent ))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
VectorAdd( ent->v.absmin, ent->v.absmax, borigin );
|
||||||
|
VectorScale( borigin, 0.5, borigin );
|
||||||
|
|
||||||
|
SV_ClientPrintf( cl, "origin: %.f %.f %.f\n", ent->v.origin[0], ent->v.origin[1], ent->v.origin[2] );
|
||||||
|
SV_ClientPrintf( cl, "angles: %.f %.f %.f\n", ent->v.angles[0], ent->v.angles[1], ent->v.angles[2] );
|
||||||
|
SV_ClientPrintf( cl, "borigin: %.f %.f %.f\n", borigin[0], borigin[1], borigin[2] );
|
||||||
|
|
||||||
|
if( ent->v.classname )
|
||||||
|
SV_ClientPrintf( cl, "class: %s\n", STRING( ent->v.classname ));
|
||||||
|
|
||||||
|
if( ent->v.globalname )
|
||||||
|
SV_ClientPrintf( cl, "global: %s\n", STRING( ent->v.globalname ));
|
||||||
|
|
||||||
|
if( ent->v.targetname )
|
||||||
|
SV_ClientPrintf( cl, "name: %s\n", STRING( ent->v.targetname ));
|
||||||
|
|
||||||
|
if( ent->v.target )
|
||||||
|
SV_ClientPrintf( cl, "target: %s\n", STRING( ent->v.target ));
|
||||||
|
|
||||||
|
if( ent->v.model )
|
||||||
|
SV_ClientPrintf( cl, "model: %s\n", STRING( ent->v.model ));
|
||||||
|
|
||||||
|
SV_ClientPrintf( cl, "health: %.f\n", ent->v.health );
|
||||||
|
|
||||||
|
if( ent->v.gravity != 1.0f )
|
||||||
|
SV_ClientPrintf( cl, "gravity: %.2f\n", ent->v.gravity );
|
||||||
|
|
||||||
|
SV_ClientPrintf( cl, "movetype: %d\n", ent->v.movetype );
|
||||||
|
SV_ClientPrintf( cl, "rendermode: %d\n", ent->v.rendermode );
|
||||||
|
SV_ClientPrintf( cl, "renderfx: %d\n", ent->v.renderfx );
|
||||||
|
SV_ClientPrintf( cl, "renderamt: %f\n", ent->v.renderamt );
|
||||||
|
SV_ClientPrintf( cl, "rendercolor: %f %f %f\n", ent->v.rendercolor[0], ent->v.rendercolor[1], ent->v.rendercolor[2] );
|
||||||
|
SV_ClientPrintf( cl, "maxspeed: %f\n", ent->v.maxspeed );
|
||||||
|
|
||||||
|
if( ent->v.solid )
|
||||||
|
SV_ClientPrintf( cl, "solid: %d\n", ent->v.solid );
|
||||||
|
|
||||||
|
SV_ClientPrintf( cl, "flags: 0x%x\n", ent->v.flags );
|
||||||
|
SV_ClientPrintf( cl, "spawnflags: 0x%x\n", ent->v.spawnflags );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
SV_EntFire_f
|
||||||
|
|
||||||
|
Perform some actions
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static qboolean SV_EntFire_f( sv_client_t *cl )
|
||||||
|
{
|
||||||
|
edict_t *ent = NULL;
|
||||||
|
int i = 1, count = 0;
|
||||||
|
qboolean single; // true if user specified something that match single entity
|
||||||
|
|
||||||
|
if( Cmd_Argc() < 3 )
|
||||||
|
{
|
||||||
|
SV_ClientPrintf( cl, "Use ent_fire <index||pattern> <command> [<values>]\n"
|
||||||
|
"Use ent_fire 0 help to get command list\n" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ( single = Q_isdigit( Cmd_Argv( 1 ) ) ) )
|
||||||
|
{
|
||||||
|
i = Q_atoi( Cmd_Argv( 1 ) );
|
||||||
|
|
||||||
|
if( i < 0 || i >= svgame.numEntities )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ent = EDICT_NUM( i );
|
||||||
|
}
|
||||||
|
else if( ( single = !Q_stricmp( Cmd_Argv( 1 ), "!cross" ) ) )
|
||||||
|
{
|
||||||
|
ent = SV_GetCrossEnt( cl->edict );
|
||||||
|
|
||||||
|
if (!SV_IsValidEdict(ent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
i = NUM_FOR_EDICT( ent );
|
||||||
|
}
|
||||||
|
else if( ( single = ( Cmd_Argv( 1 )[0] == '!') ) ) // check for correct instance with !(num)_(serial)
|
||||||
|
{
|
||||||
|
const char *cmd = Cmd_Argv( 1 ) + 1;
|
||||||
|
i = Q_atoi( cmd );
|
||||||
|
|
||||||
|
while( Q_isdigit( cmd )) cmd++;
|
||||||
|
|
||||||
|
if( *cmd++ != '_' )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( i < 0 || i >= svgame.numEntities )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ent = EDICT_NUM( i );
|
||||||
|
if( ent->serialnumber != Q_atoi( cmd ) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = svgame.globals->maxClients + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( ; ( i < svgame.numEntities ) && ( count < sv_enttools_maxfire.value ); i++ )
|
||||||
|
{
|
||||||
|
ent = EDICT_NUM( i );
|
||||||
|
if( !SV_IsValidEdict( ent ))
|
||||||
|
{
|
||||||
|
// SV_ClientPrintf( cl, PRINT_LOW, "Got invalid entity\n" );
|
||||||
|
if( single )
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if user specified not a number, try find such entity
|
||||||
|
if( !single )
|
||||||
|
{
|
||||||
|
if( !Q_stricmpext( Cmd_Argv( 1 ), STRING( ent->v.targetname ) ) && !Q_stricmpext( Cmd_Argv( 1 ), STRING( ent->v.classname ) ))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SV_ClientPrintf( cl, "entity %i\n", i );
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if( !Q_stricmp( Cmd_Argv( 2 ), "health" ) )
|
||||||
|
ent->v.health = Q_atoi( Cmd_Argv ( 3 ) );
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "gravity" ) )
|
||||||
|
ent->v.gravity = Q_atof( Cmd_Argv ( 3 ) );
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "movetype" ) )
|
||||||
|
ent->v.movetype = Q_atoi( Cmd_Argv ( 3 ) );
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "solid" ) )
|
||||||
|
ent->v.solid = Q_atoi( Cmd_Argv ( 3 ) );
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "rename" ) )
|
||||||
|
ent->v.targetname = ALLOC_STRING( Cmd_Argv ( 3 ) );
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "settarget" ) )
|
||||||
|
ent->v.target = ALLOC_STRING( Cmd_Argv ( 3 ) );
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "setmodel" ) )
|
||||||
|
SV_SetModel( ent, Cmd_Argv( 3 ) );
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "set" ) )
|
||||||
|
{
|
||||||
|
string keyname;
|
||||||
|
string value;
|
||||||
|
KeyValueData pkvd;
|
||||||
|
if( Cmd_Argc() != 5 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pkvd.szClassName = (char*)STRING( ent->v.classname );
|
||||||
|
Q_strncpy( keyname, Cmd_Argv( 3 ), sizeof( keyname ));
|
||||||
|
Q_strncpy( value, Cmd_Argv( 4 ), sizeof( value ));
|
||||||
|
pkvd.szKeyName = keyname;
|
||||||
|
pkvd.szValue = value;
|
||||||
|
pkvd.fHandled = false;
|
||||||
|
svgame.dllFuncs.pfnKeyValue( ent, &pkvd );
|
||||||
|
|
||||||
|
if( pkvd.fHandled )
|
||||||
|
SV_ClientPrintf( cl, "value set successfully!\n" );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "touch" ) )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() == 4 )
|
||||||
|
{
|
||||||
|
edict_t *other = SV_EntFindSingle( cl, Cmd_Argv( 3 ) );
|
||||||
|
if( other && other->pvPrivateData )
|
||||||
|
svgame.dllFuncs.pfnTouch( ent, other );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
svgame.dllFuncs.pfnTouch( ent, cl->edict );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "use" ) )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() == 4 )
|
||||||
|
{
|
||||||
|
edict_t *other = SV_EntFindSingle( cl, Cmd_Argv( 3 ) );
|
||||||
|
if( other && other->pvPrivateData )
|
||||||
|
svgame.dllFuncs.pfnUse( ent, other );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
svgame.dllFuncs.pfnUse( ent, cl->edict );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "movehere" ) )
|
||||||
|
{
|
||||||
|
ent->v.origin[2] = cl->edict->v.origin[2] + 25;
|
||||||
|
ent->v.origin[1] = cl->edict->v.origin[1] + 100 * sin( DEG2RAD( cl->edict->v.angles[1] ) );
|
||||||
|
ent->v.origin[0] = cl->edict->v.origin[0] + 100 * cos( DEG2RAD( cl->edict->v.angles[1] ) );
|
||||||
|
SV_LinkEdict( ent, true );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "drop2floor" ) )
|
||||||
|
{
|
||||||
|
pfnDropToFloor( ent );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "moveup" ) )
|
||||||
|
{
|
||||||
|
float dist = 25;
|
||||||
|
if( Cmd_Argc() >= 4 )
|
||||||
|
dist = Q_atof( Cmd_Argv( 3 ) );
|
||||||
|
ent->v.origin[2] += dist;
|
||||||
|
if( Cmd_Argc() >= 5 )
|
||||||
|
{
|
||||||
|
dist = Q_atof( Cmd_Argv( 4 ) );
|
||||||
|
ent->v.origin[0] += dist * cos( DEG2RAD( cl->edict->v.angles[1] ) );
|
||||||
|
ent->v.origin[1] += dist * sin( DEG2RAD( cl->edict->v.angles[1] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "becomeowner" ) )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() == 4 )
|
||||||
|
ent->v.owner = SV_EntFindSingle( cl, Cmd_Argv( 3 ) );
|
||||||
|
else
|
||||||
|
ent->v.owner = cl->edict;
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "becomeenemy" ) )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() == 4 )
|
||||||
|
ent->v.enemy = SV_EntFindSingle( cl, Cmd_Argv( 3 ) );
|
||||||
|
else
|
||||||
|
ent->v.enemy = cl->edict;
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "becomeaiment" ) )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() == 4 )
|
||||||
|
ent->v.aiment= SV_EntFindSingle( cl, Cmd_Argv( 3 ) );
|
||||||
|
else
|
||||||
|
ent->v.aiment = cl->edict;
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "hullmin" ) )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() != 6 )
|
||||||
|
return false;
|
||||||
|
ent->v.mins[0] = Q_atof( Cmd_Argv( 3 ) );
|
||||||
|
ent->v.mins[1] = Q_atof( Cmd_Argv( 4 ) );
|
||||||
|
ent->v.mins[2] = Q_atof( Cmd_Argv( 5 ) );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "hullmax" ) )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() != 6 )
|
||||||
|
return false;
|
||||||
|
ent->v.maxs[0] = Q_atof( Cmd_Argv( 3 ) );
|
||||||
|
ent->v.maxs[1] = Q_atof( Cmd_Argv( 4 ) );
|
||||||
|
ent->v.maxs[2] = Q_atof( Cmd_Argv( 5 ) );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "rendercolor" ) )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() != 6 )
|
||||||
|
return false;
|
||||||
|
ent->v.rendercolor[0] = Q_atof( Cmd_Argv( 3 ) );
|
||||||
|
ent->v.rendercolor[1] = Q_atof( Cmd_Argv( 4 ) );
|
||||||
|
ent->v.rendercolor[2] = Q_atof( Cmd_Argv( 5 ) );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "renderamt" ) )
|
||||||
|
{
|
||||||
|
ent->v.renderamt = Q_atof( Cmd_Argv( 3 ) );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "renderfx" ) )
|
||||||
|
{
|
||||||
|
ent->v.renderfx = Q_atoi( Cmd_Argv( 3 ) );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "rendermode" ) )
|
||||||
|
{
|
||||||
|
ent->v.rendermode = Q_atoi( Cmd_Argv( 3 ) );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "angles" ) )
|
||||||
|
{
|
||||||
|
ent->v.angles[0] = Q_atof( Cmd_Argv( 3 ) );
|
||||||
|
ent->v.angles[1] = Q_atof( Cmd_Argv( 4 ) );
|
||||||
|
ent->v.angles[2] = Q_atof( Cmd_Argv( 5 ) );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "setflag" ) )
|
||||||
|
{
|
||||||
|
ent->v.flags |= 1U << Q_atoi( Cmd_Argv ( 3 ) );
|
||||||
|
SV_ClientPrintf( cl, "flags set to 0x%x\n", ent->v.flags );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "clearflag" ) )
|
||||||
|
{
|
||||||
|
ent->v.flags &= ~( 1U << Q_atoi( Cmd_Argv ( 3 ) ) );
|
||||||
|
SV_ClientPrintf( cl, "flags set to 0x%x\n", ent->v.flags );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "setspawnflag" ) )
|
||||||
|
{
|
||||||
|
ent->v.spawnflags |= 1U << Q_atoi( Cmd_Argv ( 3 ) );
|
||||||
|
SV_ClientPrintf( cl, "spawnflags set to 0x%x\n", ent->v.spawnflags );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "clearspawnflag" ) )
|
||||||
|
{
|
||||||
|
ent->v.spawnflags &= ~( 1U << Q_atoi( Cmd_Argv ( 3 ) ) );
|
||||||
|
SV_ClientPrintf( cl, "spawnflags set to 0x%x\n", ent->v.flags );
|
||||||
|
}
|
||||||
|
else if( !Q_stricmp( Cmd_Argv( 2 ), "help" ) )
|
||||||
|
{
|
||||||
|
SV_ClientPrintf( cl, "Available commands:\n"
|
||||||
|
"Set fields:\n"
|
||||||
|
" (Only set entity field, does not call any functions)\n"
|
||||||
|
" health\n"
|
||||||
|
" gravity\n"
|
||||||
|
" movetype\n"
|
||||||
|
" solid\n"
|
||||||
|
" rendermode\n"
|
||||||
|
" rendercolor (vector)\n"
|
||||||
|
" renderfx\n"
|
||||||
|
" renderamt\n"
|
||||||
|
" hullmin (vector)\n"
|
||||||
|
" hullmax (vector)\n"
|
||||||
|
"Actions\n"
|
||||||
|
" rename: set entity targetname\n"
|
||||||
|
" settarget: set entity target (only targetnames)\n"
|
||||||
|
" setmodel: set entity model\n"
|
||||||
|
" set: set <key> <value> by server library\n"
|
||||||
|
" See game FGD to get list.\n"
|
||||||
|
" command takes two arguments\n"
|
||||||
|
" touch: touch entity by current player.\n"
|
||||||
|
" use: use entity by current player.\n"
|
||||||
|
" movehere: place entity in player fov.\n"
|
||||||
|
" drop2floor: place entity to nearest floor surface\n"
|
||||||
|
" moveup: move entity to 25 units up\n"
|
||||||
|
"Flags:\n"
|
||||||
|
" (Set/clear specified flag bit, arg is bit number)\n"
|
||||||
|
" setflag\n"
|
||||||
|
" clearflag\n"
|
||||||
|
" setspawnflag\n"
|
||||||
|
" clearspawnflag\n"
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SV_ClientPrintf( cl, "Unknown command %s!\nUse \"ent_fire 0 help\" to list commands.\n", Cmd_Argv( 2 ) );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if( single )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
SV_EntSendVars
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static void SV_EntSendVars( sv_client_t *cl, edict_t *ent )
|
||||||
|
{
|
||||||
|
if( !ent )
|
||||||
|
return;
|
||||||
|
|
||||||
|
MSG_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||||
|
MSG_WriteString( &cl->netchan.message, va( "set ent_last_name \"%s\"\n", STRING( ent->v.targetname ) ));
|
||||||
|
MSG_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||||
|
MSG_WriteString( &cl->netchan.message, va( "set ent_last_num %i\n", NUM_FOR_EDICT( ent ) ));
|
||||||
|
MSG_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||||
|
MSG_WriteString( &cl->netchan.message, va( "set ent_last_inst !%i_%i\n", NUM_FOR_EDICT( ent ), ent->serialnumber ));
|
||||||
|
MSG_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||||
|
MSG_WriteString( &cl->netchan.message, va( "set ent_last_origin \"%f %f %f\"\n", ent->v.origin[0], ent->v.origin[1], ent->v.origin[2]));
|
||||||
|
MSG_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||||
|
MSG_WriteString( &cl->netchan.message, va( "set ent_last_class \"%s\"\n", STRING( ent->v.classname )));
|
||||||
|
MSG_WriteByte( &cl->netchan.message, svc_stufftext );
|
||||||
|
MSG_WriteString( &cl->netchan.message, "ent_getvars_cb\n" ); // why do we need this?
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
SV_EntCreate_f
|
||||||
|
|
||||||
|
Create new entity with specified name.
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static qboolean SV_EntCreate_f( sv_client_t *cl )
|
||||||
|
{
|
||||||
|
edict_t *ent = NULL;
|
||||||
|
int i = 0;
|
||||||
|
string_t classname;
|
||||||
|
|
||||||
|
if( Cmd_Argc() < 2 )
|
||||||
|
{
|
||||||
|
SV_ClientPrintf( cl, "Use ent_create <classname> <key1> <value1> <key2> <value2> ...\n" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
classname = ALLOC_STRING( Cmd_Argv( 1 ) );
|
||||||
|
|
||||||
|
ent = SV_AllocPrivateData( 0, classname );
|
||||||
|
|
||||||
|
// Xash3D extension
|
||||||
|
if( !ent && svgame.physFuncs.SV_CreateEntity )
|
||||||
|
{
|
||||||
|
ent = SV_AllocEdict();
|
||||||
|
ent->v.classname = classname;
|
||||||
|
if( svgame.physFuncs.SV_CreateEntity( ent, (char*)STRING( classname ) ) == -1 )
|
||||||
|
{
|
||||||
|
if( ent && !ent->free )
|
||||||
|
SV_FreeEdict( ent );
|
||||||
|
ent = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XashXT does not implement SV_CreateEntity, use saverestore export
|
||||||
|
if( !ent && svgame.physFuncs.pfnCreateEntitiesInRestoreList )
|
||||||
|
{
|
||||||
|
SAVERESTOREDATA data = { 0 };
|
||||||
|
ENTITYTABLE table = { 0 };
|
||||||
|
data.tableCount = 1;
|
||||||
|
data.pTable = &table;
|
||||||
|
table.classname = classname;
|
||||||
|
table.id = -1;
|
||||||
|
table.size = 1;
|
||||||
|
svgame.physFuncs.pfnCreateEntitiesInRestoreList( &data, 0, false );
|
||||||
|
ent = table.pent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !ent )
|
||||||
|
{
|
||||||
|
SV_ClientPrintf( cl, "Invalid entity!\n" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// choose default origin
|
||||||
|
ent->v.origin[2] = cl->edict->v.origin[2] + 25;
|
||||||
|
ent->v.origin[1] = cl->edict->v.origin[1] + 100 * sin( DEG2RAD( cl->edict->v.angles[1] ) );
|
||||||
|
ent->v.origin[0] = cl->edict->v.origin[0] + 100 * cos( DEG2RAD( cl->edict->v.angles[1] ) );
|
||||||
|
|
||||||
|
SV_LinkEdict( ent, false );
|
||||||
|
|
||||||
|
// apply keyvalues if supported
|
||||||
|
if( svgame.dllFuncs.pfnKeyValue )
|
||||||
|
{
|
||||||
|
for( i = 2; i < Cmd_Argc() - 1; i++ )
|
||||||
|
{
|
||||||
|
string keyname;
|
||||||
|
string value;
|
||||||
|
KeyValueData pkvd;
|
||||||
|
|
||||||
|
// allow split keyvalues to prespawn and postspawn
|
||||||
|
if( !Q_strcmp( Cmd_Argv( i ), "|" ) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
Q_strncpy( keyname, Cmd_Argv( i++ ), sizeof( keyname ));
|
||||||
|
Q_strncpy( value, Cmd_Argv( i ), sizeof( value ));
|
||||||
|
pkvd.fHandled = false;
|
||||||
|
pkvd.szClassName = (char*)STRING( ent->v.classname );
|
||||||
|
pkvd.szKeyName = keyname;
|
||||||
|
pkvd.szValue = value;
|
||||||
|
svgame.dllFuncs.pfnKeyValue( ent, &pkvd );
|
||||||
|
|
||||||
|
if( pkvd.fHandled )
|
||||||
|
SV_ClientPrintf( cl, "value \"%s\" set to \"%s\"!\n", pkvd.szKeyName, pkvd.szValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default targetname
|
||||||
|
if( !ent->v.targetname )
|
||||||
|
{
|
||||||
|
string newname, clientname;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for( j = 0; j < sizeof( cl->name ); j++ )
|
||||||
|
{
|
||||||
|
char c = Q_tolower( cl->name[j] );
|
||||||
|
if( c < 'a' || c > 'z' )
|
||||||
|
c = '_';
|
||||||
|
if( !cl->name[j] )
|
||||||
|
{
|
||||||
|
clientname[j] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
clientname[j] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate name based on nick name and index
|
||||||
|
Q_snprintf( newname, sizeof( newname ), "%s_%i_e%i", clientname, cl->userid, NUM_FOR_EDICT( ent ));
|
||||||
|
|
||||||
|
// i know, it may break strict aliasing rules
|
||||||
|
// but we will not lose anything in this case.
|
||||||
|
Q_strnlwr( newname, newname, sizeof( newname ));
|
||||||
|
ent->v.targetname = ALLOC_STRING( newname );
|
||||||
|
SV_EntSendVars( cl, ent );
|
||||||
|
}
|
||||||
|
|
||||||
|
SV_ClientPrintf( cl, "Created %i: %s, targetname %s\n", NUM_FOR_EDICT( ent ), Cmd_Argv( 1 ), STRING( ent->v.targetname ) );
|
||||||
|
|
||||||
|
if( svgame.dllFuncs.pfnSpawn )
|
||||||
|
svgame.dllFuncs.pfnSpawn( ent );
|
||||||
|
|
||||||
|
// now drop entity to floor.
|
||||||
|
pfnDropToFloor( ent );
|
||||||
|
|
||||||
|
// force think. Otherwise given weapon may crash server if player touch it before.
|
||||||
|
svgame.dllFuncs.pfnThink( ent );
|
||||||
|
pfnDropToFloor( ent );
|
||||||
|
|
||||||
|
// apply postspawn keyvales if supported
|
||||||
|
if( svgame.dllFuncs.pfnKeyValue )
|
||||||
|
{
|
||||||
|
for( i = i + 1; i < Cmd_Argc() - 1; i++ )
|
||||||
|
{
|
||||||
|
string keyname;
|
||||||
|
string value;
|
||||||
|
KeyValueData pkvd;
|
||||||
|
|
||||||
|
Q_strncpy( keyname, Cmd_Argv( i++ ), sizeof( keyname ));
|
||||||
|
Q_strncpy( value, Cmd_Argv( i ), sizeof( value ));
|
||||||
|
pkvd.fHandled = false;
|
||||||
|
pkvd.szClassName = (char*)STRING( ent->v.classname );
|
||||||
|
pkvd.szKeyName = keyname;
|
||||||
|
pkvd.szValue = value;
|
||||||
|
svgame.dllFuncs.pfnKeyValue( ent, &pkvd );
|
||||||
|
|
||||||
|
if( pkvd.fHandled )
|
||||||
|
SV_ClientPrintf( cl, "value \"%s\" set to \"%s\"!\n", pkvd.szKeyName, pkvd.szValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean SV_EntGetVars_f( sv_client_t *cl )
|
||||||
|
{
|
||||||
|
edict_t *ent = NULL;
|
||||||
|
|
||||||
|
if( Cmd_Argc() != 2 )
|
||||||
|
{
|
||||||
|
SV_ClientPrintf( cl, "Use ent_getvars <index|name|inst>\n" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ent = SV_EntFindSingle( cl, Cmd_Argv( 1 ) );
|
||||||
|
if( Cmd_Argc() )
|
||||||
|
{
|
||||||
|
if( !SV_IsValidEdict( ent ))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SV_EntSendVars( cl, ent );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
ucmd_t ucmds[] =
|
ucmd_t ucmds[] =
|
||||||
{
|
{
|
||||||
@ -2140,6 +2914,16 @@ ucmd_t ucmds[] =
|
|||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ucmd_t enttoolscmds[] =
|
||||||
|
{
|
||||||
|
{ "ent_list", SV_EntList_f },
|
||||||
|
{ "ent_info", SV_EntInfo_f },
|
||||||
|
{ "ent_fire", SV_EntFire_f },
|
||||||
|
{ "ent_create", SV_EntCreate_f },
|
||||||
|
{ "ent_getvars", SV_EntGetVars_f },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
SV_ExecuteUserCommand
|
SV_ExecuteUserCommand
|
||||||
@ -2162,6 +2946,24 @@ void SV_ExecuteClientCommand( sv_client_t *cl, const char *s )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !u->name && sv_enttools_enable.value > 0.0f && !sv.background )
|
||||||
|
{
|
||||||
|
for( u = enttoolscmds; u->name; u++ )
|
||||||
|
{
|
||||||
|
if( !Q_strcmp( Cmd_Argv( 0 ), u->name ))
|
||||||
|
{
|
||||||
|
Con_Reportf( "enttools->%s(): %s\n", u->name, s );
|
||||||
|
Log_Printf( "\"%s<%i><%s><>\" performed: %s\n", Info_ValueForKey( cl->userinfo, "name" ),
|
||||||
|
cl->userid, SV_GetClientIDString( cl ), NET_AdrToString( cl->netchan.remote_address ), s );
|
||||||
|
|
||||||
|
if( u->func )
|
||||||
|
u->func( cl );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( !u->name && sv.state == ss_active )
|
if( !u->name && sv.state == ss_active )
|
||||||
{
|
{
|
||||||
// custom client commands
|
// custom client commands
|
||||||
|
@ -257,6 +257,63 @@ void SV_CopyTraceToGlobal( trace_t *trace )
|
|||||||
else svgame.globals->trace_ent = svgame.edicts;
|
else svgame.globals->trace_ent = svgame.edicts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
SV_SetModel
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void SV_SetModel( edict_t *ent, const char *modelname )
|
||||||
|
{
|
||||||
|
char name[MAX_QPATH];
|
||||||
|
qboolean found = false;
|
||||||
|
model_t *mod;
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
if( !SV_IsValidEdict( ent ))
|
||||||
|
{
|
||||||
|
Con_Printf( S_WARN "SV_SetModel: invalid entity %s\n", SV_ClassName( ent ));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !modelname || modelname[0] <= ' ' )
|
||||||
|
{
|
||||||
|
Con_Printf( S_WARN "SV_SetModel: null name\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( *modelname == '\\' || *modelname == '/' )
|
||||||
|
modelname++;
|
||||||
|
|
||||||
|
Q_strncpy( name, modelname, sizeof( name ));
|
||||||
|
COM_FixSlashes( name );
|
||||||
|
|
||||||
|
i = SV_ModelIndex( name );
|
||||||
|
if( i == 0 )
|
||||||
|
{
|
||||||
|
if( sv.state == ss_active )
|
||||||
|
Con_Printf( S_ERROR "SV_SetModel: failed to set model %s: world model cannot be changed\n", name );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( COM_CheckString( name ))
|
||||||
|
{
|
||||||
|
ent->v.model = MAKE_STRING( sv.model_precache[i] );
|
||||||
|
ent->v.modelindex = i;
|
||||||
|
mod = sv.models[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// model will be cleared
|
||||||
|
ent->v.model = ent->v.modelindex = 0;
|
||||||
|
mod = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the model size
|
||||||
|
if( mod && mod->type != mod_studio )
|
||||||
|
SV_SetMinMaxSize( ent, mod->mins, mod->maxs, true );
|
||||||
|
else SV_SetMinMaxSize( ent, vec3_origin, vec3_origin, true );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
SV_ConvertTrace
|
SV_ConvertTrace
|
||||||
@ -1319,61 +1376,7 @@ pfnSetModel
|
|||||||
*/
|
*/
|
||||||
void GAME_EXPORT pfnSetModel( edict_t *e, const char *m )
|
void GAME_EXPORT pfnSetModel( edict_t *e, const char *m )
|
||||||
{
|
{
|
||||||
char name[MAX_QPATH];
|
SV_SetModel( e, m );
|
||||||
qboolean found = false;
|
|
||||||
model_t *mod;
|
|
||||||
int i = 1;
|
|
||||||
|
|
||||||
if( !SV_IsValidEdict( e ))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( *m == '\\' || *m == '/' ) m++;
|
|
||||||
Q_strncpy( name, m, sizeof( name ));
|
|
||||||
COM_FixSlashes( name );
|
|
||||||
|
|
||||||
if( COM_CheckString( name ))
|
|
||||||
{
|
|
||||||
// check to see if model was properly precached
|
|
||||||
for( ; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
|
|
||||||
{
|
|
||||||
if( !Q_stricmp( sv.model_precache[i], name ))
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !found )
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "Failed to set model %s: was not precached\n", name );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( e == svgame.edicts )
|
|
||||||
{
|
|
||||||
if( sv.state == ss_active )
|
|
||||||
Con_Printf( S_ERROR "Failed to set model %s: world model cannot be changed\n", name );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( COM_CheckString( name ))
|
|
||||||
{
|
|
||||||
e->v.model = MAKE_STRING( sv.model_precache[i] );
|
|
||||||
e->v.modelindex = i;
|
|
||||||
mod = sv.models[i];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// model will be cleared
|
|
||||||
e->v.model = e->v.modelindex = 0;
|
|
||||||
mod = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the model size
|
|
||||||
if( mod && mod->type != mod_studio )
|
|
||||||
SV_SetMinMaxSize( e, mod->mins, mod->maxs, true );
|
|
||||||
else SV_SetMinMaxSize( e, vec3_origin, vec3_origin, true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -116,6 +116,10 @@ CVAR_DEFINE_AUTO( violence_agibs, "1", 0, "show alien gib entities" );
|
|||||||
CVAR_DEFINE_AUTO( sv_voiceenable, "1", FCVAR_ARCHIVE|FCVAR_SERVER, "enable voice support" );
|
CVAR_DEFINE_AUTO( sv_voiceenable, "1", FCVAR_ARCHIVE|FCVAR_SERVER, "enable voice support" );
|
||||||
CVAR_DEFINE_AUTO( sv_voicequality, "3", FCVAR_ARCHIVE|FCVAR_SERVER, "voice chat quality level, from 0 to 5, higher is better" );
|
CVAR_DEFINE_AUTO( sv_voicequality, "3", FCVAR_ARCHIVE|FCVAR_SERVER, "voice chat quality level, from 0 to 5, higher is better" );
|
||||||
|
|
||||||
|
// enttools
|
||||||
|
CVAR_DEFINE_AUTO( sv_enttools_enable, "0", FCVAR_ARCHIVE|FCVAR_PROTECTED, "enable powerful and dangerous entity tools" );
|
||||||
|
CVAR_DEFINE_AUTO( sv_enttools_maxfire, "5", FCVAR_ARCHIVE|FCVAR_PROTECTED, "limit ent_fire actions count to prevent flooding" );
|
||||||
|
|
||||||
convar_t *sv_novis; // disable server culling entities by vis
|
convar_t *sv_novis; // disable server culling entities by vis
|
||||||
convar_t *sv_pausable;
|
convar_t *sv_pausable;
|
||||||
convar_t *timeout; // seconds without any message
|
convar_t *timeout; // seconds without any message
|
||||||
@ -981,6 +985,8 @@ void SV_Init( void )
|
|||||||
Cvar_RegisterVariable( &sv_voiceenable );
|
Cvar_RegisterVariable( &sv_voiceenable );
|
||||||
Cvar_RegisterVariable( &sv_voicequality );
|
Cvar_RegisterVariable( &sv_voicequality );
|
||||||
Cvar_RegisterVariable( &sv_trace_messages );
|
Cvar_RegisterVariable( &sv_trace_messages );
|
||||||
|
Cvar_RegisterVariable( &sv_enttools_enable );
|
||||||
|
Cvar_RegisterVariable( &sv_enttools_maxfire );
|
||||||
|
|
||||||
sv_allow_joystick = Cvar_Get( "sv_allow_joystick", "1", FCVAR_ARCHIVE, "allow connect with joystick enabled" );
|
sv_allow_joystick = Cvar_Get( "sv_allow_joystick", "1", FCVAR_ARCHIVE, "allow connect with joystick enabled" );
|
||||||
sv_allow_mouse = Cvar_Get( "sv_allow_mouse", "1", FCVAR_ARCHIVE, "allow connect with mouse" );
|
sv_allow_mouse = Cvar_Get( "sv_allow_mouse", "1", FCVAR_ARCHIVE, "allow connect with mouse" );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user