2012-01-22 21:34:33 +00:00
/*
2012-08-04 10:54:37 +00:00
* Copyright ( C ) 1999 - 2000 Id Software , Inc .
*
* g_utils . c - - misc utility functions for game module
*
*/
2012-01-22 21:34:33 +00:00
# include "g_local.h"
2012-08-04 10:54:37 +00:00
/**
* \ brief Data structure for a singele shader remap .
*
* Data structure for a single shader remap
*
*/
2012-01-22 21:34:33 +00:00
typedef struct {
2012-08-04 10:54:37 +00:00
/** The original shader */
char oldShader [ MAX_QPATH ] ;
/** The replacement shader */
char newShader [ MAX_QPATH ] ;
/** time offset */
float timeOffset ;
2012-01-22 21:34:33 +00:00
} shaderRemap_t ;
2012-08-04 10:54:37 +00:00
/** The maximum count of shader remaps */
2012-01-22 21:34:33 +00:00
# define MAX_SHADER_REMAPS 128
2012-08-04 10:54:37 +00:00
/** Current count of remapped shaders */
static int remapCount = 0 ;
/** List of shader remaps */
static shaderRemap_t remappedShaders [ MAX_SHADER_REMAPS ] ;
/**
* \ brief Add a new shader remap .
*
* Remaps oldShader with newShader .
*
* @ param oldShader shader to be remapped
* @ param newShader replacement shader
* @ param timeOffset time offset
*/
2012-01-22 21:34:33 +00:00
void AddRemap ( const char * oldShader , const char * newShader , float timeOffset ) {
int i ;
for ( i = 0 ; i < remapCount ; i + + ) {
if ( Q_stricmp ( oldShader , remappedShaders [ i ] . oldShader ) = = 0 ) {
2012-08-04 10:54:37 +00:00
/* found it, just update this one */
2012-01-22 21:34:33 +00:00
strcpy ( remappedShaders [ i ] . newShader , newShader ) ;
remappedShaders [ i ] . timeOffset = timeOffset ;
return ;
}
}
if ( remapCount < MAX_SHADER_REMAPS ) {
strcpy ( remappedShaders [ remapCount ] . newShader , newShader ) ;
strcpy ( remappedShaders [ remapCount ] . oldShader , oldShader ) ;
remappedShaders [ remapCount ] . timeOffset = timeOffset ;
remapCount + + ;
}
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Builds the shader state config .
*
* Builds the shader state config .
*
* @ return the shader state config
*/
2012-01-22 21:34:33 +00:00
const char * BuildShaderStateConfig ( void ) {
static char buff [ MAX_STRING_CHARS * 4 ] ;
char out [ ( MAX_QPATH * 2 ) + 5 ] ;
int i ;
memset ( buff , 0 , MAX_STRING_CHARS ) ;
for ( i = 0 ; i < remapCount ; i + + ) {
Com_sprintf ( out , ( MAX_QPATH * 2 ) + 5 , " %s=%s:%5.2f@ " , remappedShaders [ i ] . oldShader , remappedShaders [ i ] . newShader , remappedShaders [ i ] . timeOffset ) ;
Q_strcat ( buff , sizeof ( buff ) , out ) ;
}
return buff ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
model / sound configstring indexes
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
2012-08-04 10:54:37 +00:00
* \ brief Finds the index a config string starts at .
*
* Finds the index a config string start at .
*
* @ param name name of the config string
* @ param start look from here
* @ param max look until here
* @ param create create a new config string ?
*
* @ return The config strings index
*/
2012-01-22 21:34:33 +00:00
int G_FindConfigstringIndex ( char * name , int start , int max , qboolean create ) {
int i ;
char s [ MAX_STRING_CHARS ] ;
if ( ! name | | ! name [ 0 ] ) {
return 0 ;
}
for ( i = 1 ; i < max ; i + + ) {
trap_GetConfigstring ( start + i , s , sizeof ( s ) ) ;
if ( ! s [ 0 ] ) {
break ;
}
if ( ! strcmp ( s , name ) ) {
return i ;
}
}
if ( ! create ) {
return 0 ;
}
if ( i = = max ) {
2012-08-04 10:54:37 +00:00
/*G_Error( "G_FindConfigstringIndex: overflow" );*/
G_Printf ( S_COLOR_RED " G_FindConfigstringIndex: Full!! Could not add value: %s \n " , name ) ;
2012-01-22 21:34:33 +00:00
}
trap_SetConfigstring ( start + i , name ) ;
return i ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Get the model index for a model .
*
* Get the model index for a model .
*
* @ param name the model name
*
* @ return the models index
*/
2012-01-22 21:34:33 +00:00
int G_ModelIndex ( char * name ) {
return G_FindConfigstringIndex ( name , CS_MODELS , MAX_MODELS , qtrue ) ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Get the sound index for a sound .
*
* Get the sound index for a sound .
*
* @ param name the sound name
*
* @ return the sounds index
*/
2012-01-22 21:34:33 +00:00
int G_SoundIndex ( char * name ) {
return G_FindConfigstringIndex ( name , CS_SOUNDS , MAX_SOUNDS , qtrue ) ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Get the tric string index .
*
* Get the tric string index .
*
* @ param name the tric string name
*
* @ return the tric strings index
*/
int G_TricStringIndex ( char * name ) {
return G_FindConfigstringIndex ( name , CS_TRIC_STRINGS , MAX_TRIC_STRINGS , qtrue ) ;
}
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
//=====================================================================
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
/**
* \ brief Issue a team command .
*
* Issue a team command .
*
* @ param team the team
* @ param cmd the command
*/
2012-01-22 21:34:33 +00:00
void G_TeamCommand ( team_t team , char * cmd ) {
int i ;
for ( i = 0 ; i < level . maxclients ; i + + ) {
if ( level . clients [ i ] . pers . connected = = CON_CONNECTED ) {
if ( level . clients [ i ] . sess . sessionTeam = = team ) {
trap_SendServerCommand ( i , va ( " %s " , cmd ) ) ;
}
}
}
}
2012-08-04 10:54:37 +00:00
/**
*
* \ brief Finds an entity .
*
* Searches all active entities for the next one that holds
* the matching string at fieldofs ( use the FOFS ( ) macro ) in the structure .
* Searches beginning at the entity after from , or the beginning if NULL
* NULL will be returned if the end of the list is reached .
*
* @ param from search from this entity on
* @ param fieldofs in which field to look
* @ param match string to match
*
* @ return an matching entity or NULL
*/
2012-01-22 21:34:33 +00:00
gentity_t * G_Find ( gentity_t * from , int fieldofs , const char * match )
{
char * s ;
if ( ! from )
from = g_entities ;
else
from + + ;
for ( ; from < & g_entities [ level . num_entities ] ; from + + )
{
if ( ! from - > inuse )
continue ;
s = * ( char * * ) ( ( byte * ) from + fieldofs ) ;
if ( ! s )
continue ;
if ( ! Q_stricmp ( s , match ) )
return from ;
}
return NULL ;
}
2012-08-04 10:54:37 +00:00
/** Maximum number of possible choices for G_PickTarget. */
# define MAXCHOICES 32
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
/**
* \ brief Pick a target .
*
* Selects a random entity from among the targets .
*
* @ param targetname the targets targetname
*
* @ return an entity or NULL
*/
2012-01-22 21:34:33 +00:00
gentity_t * G_PickTarget ( char * targetname )
{
gentity_t * ent = NULL ;
int num_choices = 0 ;
gentity_t * choice [ MAXCHOICES ] ;
if ( ! targetname )
{
G_Printf ( " G_PickTarget called with NULL targetname \n " ) ;
return NULL ;
}
2012-08-04 10:54:37 +00:00
/* BOOKMARK */
2012-01-22 21:34:33 +00:00
while ( 1 )
{
ent = G_Find ( ent , FOFS ( targetname ) , targetname ) ;
if ( ! ent )
break ;
choice [ num_choices + + ] = ent ;
if ( num_choices = = MAXCHOICES )
break ;
}
2012-08-04 10:54:37 +00:00
/*================
RPG - X Modification
Phenix
13 / 06 / 2004
= = = = = = = = = = = = = = = = */
if ( ! num_choices )
{
while ( 1 )
{
ent = G_Find ( ent , FOFS ( swapname ) , targetname ) ;
if ( ! ent )
break ;
choice [ num_choices + + ] = ent ;
if ( num_choices = = MAXCHOICES )
break ;
}
}
if ( ! num_choices )
{
while ( 1 )
{
ent = G_Find ( ent , FOFS ( truename ) , targetname ) ;
if ( ! ent )
break ;
choice [ num_choices + + ] = ent ;
if ( num_choices = = MAXCHOICES )
break ;
}
}
if ( ! num_choices )
{
while ( 1 )
{
ent = G_Find ( ent , FOFS ( falsename ) , targetname ) ;
if ( ! ent )
break ;
choice [ num_choices + + ] = ent ;
if ( num_choices = = MAXCHOICES )
break ;
}
}
/*================
End Modification
= = = = = = = = = = = = = = = = */
2012-01-22 21:34:33 +00:00
if ( ! num_choices )
{
G_Printf ( " G_PickTarget: target %s not found \n " , targetname ) ;
return NULL ;
}
return choice [ rand ( ) % num_choices ] ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Use all targets of the given entity .
*
* Goes through all entities and calls ther use function if their
* targetname , swapname , truename , falsename , bluename are matching
* the target . activator should be set the the inflictor of this function
* call .
*
* @ param ent the entity
* @ param activator the activator
* @ param target target to match
*/
void G_UseTargets2 ( gentity_t * ent , gentity_t * activator , char * target ) {
2012-01-22 21:34:33 +00:00
gentity_t * t ;
2012-08-04 10:54:37 +00:00
list_iter_p szIter ;
safeZone_t * sz ;
2012-01-22 21:34:33 +00:00
if ( ! ent ) {
return ;
}
if ( ent - > targetShaderName & & ent - > targetShaderNewName ) {
float f = level . time * 0.001 ;
AddRemap ( ent - > targetShaderName , ent - > targetShaderNewName , f ) ;
trap_SetConfigstring ( CS_SHADERSTATE , BuildShaderStateConfig ( ) ) ;
}
2012-08-04 10:54:37 +00:00
if ( ! target ) {
2012-01-22 21:34:33 +00:00
return ;
}
t = NULL ;
2012-08-04 10:54:37 +00:00
while ( ( t = G_Find ( t , FOFS ( targetname ) , target ) ) ! = NULL ) {
if ( t = = ent ) {
G_Printf ( va ( " WARNING: Entity %i used itself. \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
} else {
if ( t - > use ) {
t - > use ( t , ent , activator ) ;
# ifdef G_LUA
if ( t - > luaUse )
{
if ( activator )
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , activator - > s . number ) ;
}
else
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , ENTITYNUM_WORLD ) ;
}
}
# endif
}
}
if ( ! ent - > inuse ) {
G_Printf ( va ( " Entity %i was removed while using targets \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
return ;
}
}
/*================
RPG - X Modification
Phenix
13 / 06 / 2004
= = = = = = = = = = = = = = = = */
t = NULL ;
while ( ( t = G_Find ( t , FOFS ( swapname ) , target ) ) ! = NULL ) {
if ( t = = ent ) {
G_Printf ( va ( " WARNING: Entity %i used itself. \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
} else {
if ( t - > use ) {
t - > use ( t , ent , activator ) ;
# ifdef G_LUA
if ( t - > luaUse )
{
if ( activator )
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , activator - > s . number ) ;
}
else
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , ENTITYNUM_WORLD ) ;
}
}
# endif
}
}
if ( ! ent - > inuse ) {
G_Printf ( va ( " Entity %i was removed while using targets \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
return ;
}
}
t = NULL ;
while ( ( t = G_Find ( t , FOFS ( truename ) , target ) ) ! = NULL ) {
if ( t = = ent ) {
G_Printf ( va ( " WARNING: Entity %i used itself. \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
} else {
if ( t - > use ) {
t - > use ( t , ent , activator ) ;
# ifdef G_LUA
if ( t - > luaUse )
{
if ( activator )
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , activator - > s . number ) ;
}
else
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , ENTITYNUM_WORLD ) ;
}
}
# endif
}
}
if ( ! ent - > inuse ) {
G_Printf ( va ( " Entity %i was removed while using targets \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
return ;
}
}
t = NULL ;
while ( ( t = G_Find ( t , FOFS ( falsename ) , target ) ) ! = NULL ) {
2012-01-22 21:34:33 +00:00
if ( t = = ent ) {
2012-08-04 10:54:37 +00:00
G_Printf ( va ( " WARNING: Entity %i used itself. \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
2012-01-22 21:34:33 +00:00
} else {
if ( t - > use ) {
t - > use ( t , ent , activator ) ;
2012-08-04 10:54:37 +00:00
# ifdef G_LUA
if ( t - > luaUse )
{
if ( activator )
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , activator - > s . number ) ;
}
else
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , ENTITYNUM_WORLD ) ;
}
}
# endif
2012-01-22 21:34:33 +00:00
}
}
if ( ! ent - > inuse ) {
2012-08-04 10:54:37 +00:00
G_Printf ( va ( " Entity %i was removed while using targets \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
2012-01-22 21:34:33 +00:00
return ;
}
}
2012-08-04 10:54:37 +00:00
/*================
End Modification
= = = = = = = = = = = = = = = = */
/*
* RPG - X | GSIO01 | 11 / 05 / 2009 | MOD START
* target_alert
*/
t = NULL ;
while ( ( t = G_Find ( t , FOFS ( bluename ) , target ) ) ! = NULL ) {
if ( t = = ent ) {
G_Printf ( va ( " WARNING: Entity %i used itself. \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
} else {
if ( t - > use ) {
t - > use ( t , ent , ent ) ;
# ifdef G_LUA
if ( t - > luaUse )
{
if ( activator )
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , activator - > s . number ) ;
}
else
{
LuaHook_G_EntityUse ( t - > luaUse , t - > s . number , ent - > s . number , ENTITYNUM_WORLD ) ;
}
}
# endif
}
}
if ( ! ent - > inuse ) {
G_Printf ( va ( " Entity %i was removed while using targets \n " , t - > s . number ) ) ; /* RPG-X | GSIO01 | 22.10.09: a little bit more information for the mapper */
return ;
}
}
/* self destruct safe zones */
if ( selfdestructSafeZones ! = NULL & & selfdestructSafeZones - > length > 0 ) {
szIter = list_iterator ( selfdestructSafeZones , FRONT ) ;
for ( sz = ( safeZone_t * ) list_next ( szIter ) ; sz ! = NULL ; sz = ( safeZone_t * ) list_next ( szIter ) ) {
if ( ! strcmp ( sz - > name , target ) ) {
sz - > active = ( qboolean ) ! sz - > active ;
}
}
}
2012-01-22 21:34:33 +00:00
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Use all of the given entity ' s targets .
*
* Use all of the given entity ' s targets .
*
* @ param ent the entity
* @ param activator the initiator of the function call
*/
void G_UseTargets ( gentity_t * ent , gentity_t * activator ) {
if ( ! ent ) {
return ;
}
G_UseTargets2 ( ent , activator , ent - > target ) ;
}
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
/**
* \ brief Create a temporary vector .
*
* This is just a convenience function
* for making temporary vectors for function calls
*
* @ param x x - value
* @ param y y - value
* @ param z z - value
*
* @ return temporary vector
*/
2012-01-22 21:34:33 +00:00
float * tv ( float x , float y , float z ) {
static int index ;
static vec3_t vecs [ 8 ] ;
float * v ;
2012-08-04 10:54:37 +00:00
/*
* use an array so that multiple tempvectors won ' t collide
* for a while
*/
2012-01-22 21:34:33 +00:00
v = vecs [ index ] ;
index = ( index + 1 ) & 7 ;
v [ 0 ] = x ;
v [ 1 ] = y ;
v [ 2 ] = z ;
return v ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Converts a vector to a string to be printed .
*
* This is just a convenience function
* for printing vectors
*
* @ param v the vector
*
* @ return string representation of the vector
*/
2012-01-22 21:34:33 +00:00
char * vtos ( const vec3_t v ) {
static int index ;
static char str [ 8 ] [ 32 ] ;
char * s ;
2012-08-04 10:54:37 +00:00
/* use an array so that multiple vtos won't collide */
2012-01-22 21:34:33 +00:00
s = str [ index ] ;
index = ( index + 1 ) & 7 ;
Com_sprintf ( s , 32 , " (%i %i %i) " , ( int ) v [ 0 ] , ( int ) v [ 1 ] , ( int ) v [ 2 ] ) ;
return s ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Converts angles to move directions .
*
* The editor only specifies a single value for angles ( yaw ) ,
* but we have special constants to generate an up or down direction .
* Angles will be cleared , because it is being used to represent a direction
* instead of an orientation .
*
* @ param angles the angles
* @ param movedir the movedir
*/
2012-01-22 21:34:33 +00:00
void G_SetMovedir ( vec3_t angles , vec3_t movedir ) {
static vec3_t VEC_UP = { 0 , - 1 , 0 } ;
static vec3_t MOVEDIR_UP = { 0 , 0 , 1 } ;
static vec3_t VEC_DOWN = { 0 , - 2 , 0 } ;
static vec3_t MOVEDIR_DOWN = { 0 , 0 , - 1 } ;
if ( VectorCompare ( angles , VEC_UP ) ) {
VectorCopy ( MOVEDIR_UP , movedir ) ;
} else if ( VectorCompare ( angles , VEC_DOWN ) ) {
VectorCopy ( MOVEDIR_DOWN , movedir ) ;
} else {
AngleVectors ( angles , movedir , NULL , NULL ) ;
}
VectorClear ( angles ) ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Get the yaw from a vector .
*
* Get the yaw from a vector .
*
* @ param vec the vector
*
* @ return the yaw
*/
2012-01-22 21:34:33 +00:00
float vectoyaw ( const vec3_t vec ) {
float yaw ;
if ( vec [ YAW ] = = 0 & & vec [ PITCH ] = = 0 ) {
yaw = 0 ;
} else {
if ( vec [ PITCH ] ) {
yaw = ( atan2 ( vec [ YAW ] , vec [ PITCH ] ) * 180 / M_PI ) ;
} else if ( vec [ YAW ] > 0 ) {
yaw = 90 ;
} else {
yaw = 270 ;
}
if ( yaw < 0 ) {
yaw + = 360 ;
}
}
return yaw ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Init the entity .
*
* Inits a given game entity .
*
* @ param e the entity
*/
2012-01-22 21:34:33 +00:00
void G_InitGentity ( gentity_t * e ) {
e - > inuse = qtrue ;
e - > classname = " noclass " ;
e - > s . number = e - g_entities ;
e - > r . ownerNum = ENTITYNUM_NONE ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Spawns a new entity .
*
* Either finds a free entity , or allocates a new one .
* The slots from 0 to MAX_CLIENTS - 1 are always reserved for clients ,
* and will never be used by anything else .
* Try to avoid reusing an entity that was recently freed , because it
* can cause the client to think the entity morphed into something else
* instead of being removed and recreated , which can cause interpolated
* angles and bad trails .
*
* @ return a new entity or NULL
*/
2012-01-22 21:34:33 +00:00
gentity_t * G_Spawn ( void ) {
int i , force ;
gentity_t * e ;
2012-08-04 10:54:37 +00:00
/* RPG-X: RedTechie - Get rid of tripmines first */
gentity_t * tripwire = NULL ;
int foundTripWires [ MAX_GENTITIES ] = { ENTITYNUM_NONE } ;
int tripcount = 0 ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
e = NULL ; /* shut up warning */
i = 0 ; /* shut up warning */
2012-01-22 21:34:33 +00:00
for ( force = 0 ; force < 2 ; force + + ) {
2012-08-04 10:54:37 +00:00
/* if we go through all entities and can't find one to free, */
/* override the normal minimum times before use */
2012-01-22 21:34:33 +00:00
e = & g_entities [ MAX_CLIENTS ] ;
for ( i = MAX_CLIENTS ; i < level . num_entities ; i + + , e + + ) {
if ( e - > inuse ) {
continue ;
}
2012-08-04 10:54:37 +00:00
/* the first couple seconds of server time can involve a lot of */
/* freeing and allocating, so relax the replacement policy */
2012-01-22 21:34:33 +00:00
if ( ! force & & e - > freetime > level . startTime + 2000 & & level . time - e - > freetime < 1000 ) {
continue ;
}
2012-08-04 10:54:37 +00:00
/* reuse this slot */
2012-01-22 21:34:33 +00:00
G_InitGentity ( e ) ;
return e ;
}
2012-08-04 10:54:37 +00:00
if ( i ! = ENTITYNUM_MAX_NORMAL ) {
2012-01-22 21:34:33 +00:00
break ;
}
}
2012-08-04 10:54:37 +00:00
/* RPG-X: RedTechie DEBUG: SHOW HOW MANY ENT's WE HAVE LEFT */
/*trap_SendServerCommand( -1, va("print \"^1DEBUG: current:%i total:%i\n\"", i, ENTITYNUM_MAX_NORMAL));*/
2012-01-22 21:34:33 +00:00
if ( i = = ENTITYNUM_MAX_NORMAL ) {
2012-08-04 10:54:37 +00:00
/* RPG-X: RedTechie - Do some rpg-x house cleaning before we decalre the server dead */
while ( ( tripwire = G_Find ( tripwire , FOFS ( classname ) , " tripwire " ) ) ! = NULL )
{
foundTripWires [ tripcount + + ] = tripwire - > s . number ;
}
if ( tripcount ! = 0 ) {
for ( i = 0 ; i < tripcount ; i + + )
{
/* remove it... or blow it? */
if ( & g_entities [ foundTripWires [ i ] ] ! = NULL )
{
G_FreeEntity ( & g_entities [ foundTripWires [ i ] ] ) ;
foundTripWires [ i ] = ENTITYNUM_NONE ;
}
}
G_LogPrintf ( " RPG-X WARNING: Max entities hit! Removed all tripmines. Restart the server ASAP or suffer a server crash! \n " ) ;
trap_SendServerCommand ( - 1 , va ( " print \" ^1RPG-X WARNING: Max entities hit! Removed all tripmines. Restart the server ASAP or suffer a server crash! \n \" " , i , ENTITYNUM_MAX_NORMAL ) ) ;
if ( i = = ENTITYNUM_MAX_NORMAL ) {
G_Error ( " G_Spawn: no free entities " ) ;
}
} else {
G_Error ( " G_Spawn: no free entities " ) ;
2012-01-22 21:34:33 +00:00
}
}
2012-08-04 10:54:37 +00:00
/* RPG-X: RedTechie - Update global entity count */
RPGEntityCount = i ;
/* open up a new slot */
2012-01-22 21:34:33 +00:00
level . num_entities + + ;
2012-08-04 10:54:37 +00:00
/* let the server system know that there are more entities */
2012-01-22 21:34:33 +00:00
trap_LocateGameData ( level . gentities , level . num_entities , sizeof ( gentity_t ) ,
& level . clients [ 0 ] . ps , sizeof ( level . clients [ 0 ] ) ) ;
G_InitGentity ( e ) ;
return e ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Free an entity .
*
* Marks the entity as free .
*
* @ param ed entity to free
*/
2012-01-22 21:34:33 +00:00
void G_FreeEntity ( gentity_t * ed ) {
2012-08-04 10:54:37 +00:00
trap_UnlinkEntity ( ed ) ; /* unlink from world */
2012-01-22 21:34:33 +00:00
if ( ed - > neverFree ) {
return ;
}
2012-08-04 10:54:37 +00:00
# ifdef G_LUA
/* Lua API callbacks */
if ( ed - > luaFree & & ! ed - > client )
{
LuaHook_G_EntityFree ( ed - > luaFree , ed - > s . number ) ;
}
# endif
2012-01-22 21:34:33 +00:00
memset ( ed , 0 , sizeof ( * ed ) ) ;
ed - > classname = " freed " ;
ed - > freetime = level . time ;
ed - > inuse = qfalse ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Spawn an temporary entity .
*
* Spawns an event entity that will be auto - removed
* The origin will be snapped to save net bandwidth , so care
* must be taken if the origin is right on a surface ( snap towards start vector first )
*
* @ param origin the origin
* @ param event the event to use for this entity
*
* @ return the temporary entity
*/
2012-01-22 21:34:33 +00:00
gentity_t * G_TempEntity ( vec3_t origin , int event ) {
gentity_t * e ;
vec3_t snapped ;
e = G_Spawn ( ) ;
e - > s . eType = ET_EVENTS + event ;
e - > classname = " tempEntity " ;
e - > eventTime = level . time ;
e - > freeAfterEvent = qtrue ;
VectorCopy ( origin , snapped ) ;
2012-08-04 10:54:37 +00:00
SnapVector ( snapped ) ; /* save network bandwidth */
2012-01-22 21:34:33 +00:00
G_SetOrigin ( e , snapped ) ;
2012-08-04 10:54:37 +00:00
/* find cluster for PVS */
2012-01-22 21:34:33 +00:00
trap_LinkEntity ( e ) ;
return e ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Kill box
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-08-04 10:54:37 +00:00
/**
* \ brief Kill all that would be inside a new one .
*
* Kills all entities that would touch the proposed new positioning
* of ent . Ent should be unlinked before calling this !
*
* @ param ent the entity
*/
2012-01-22 21:34:33 +00:00
void G_KillBox ( gentity_t * ent ) {
2012-08-04 10:54:37 +00:00
int i , num ;
int touch [ MAX_GENTITIES ] ;
2012-01-22 21:34:33 +00:00
gentity_t * hit ;
vec3_t mins , maxs ;
VectorAdd ( ent - > client - > ps . origin , ent - > r . mins , mins ) ;
VectorAdd ( ent - > client - > ps . origin , ent - > r . maxs , maxs ) ;
num = trap_EntitiesInBox ( mins , maxs , touch , MAX_GENTITIES ) ;
for ( i = 0 ; i < num ; i + + ) {
hit = & g_entities [ touch [ i ] ] ;
if ( ! hit - > client ) {
continue ;
}
2012-08-04 10:54:37 +00:00
/* nail it */
2012-01-22 21:34:33 +00:00
G_Damage ( hit , ent , ent , NULL , NULL ,
100000 , DAMAGE_NO_PROTECTION , MOD_TELEFRAG ) ;
}
}
2012-08-04 10:54:37 +00:00
/**
* \ author J2J
* \ brief Push all entities away that are inside a new entity .
*
* Basically does teh same as G_KillBox except it will
* push players and other entities away instead of killing them .
*
* @ param ent the entity
*
* @ return was an ent moved ?
*/
qboolean G_MoveBox ( gentity_t * ent )
{
int i , num ;
int touch [ MAX_GENTITIES ] ;
gentity_t * hit ;
vec3_t mins , maxs ;
vec3_t dir ;
qboolean movedPlayer = qfalse ;
VectorAdd ( ent - > client - > ps . origin , ent - > r . mins , mins ) ;
VectorAdd ( ent - > client - > ps . origin , ent - > r . maxs , maxs ) ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
num = trap_EntitiesInBox ( mins , maxs , touch , MAX_GENTITIES ) ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
for ( i = 0 ; i < num ; i + + )
{
hit = & g_entities [ touch [ i ] ] ;
if ( ! hit - > client | | hit - > client - > ps . clientNum = = ent - > client - > ps . clientNum )
{
continue ;
}
VectorSet ( dir , 0 , hit - > client - > ps . viewangles [ YAW ] , 0 ) ;
AngleVectors ( dir , hit - > client - > ps . velocity , NULL , NULL ) ;
VectorScale ( hit - > client - > ps . velocity , - 150 , hit - > client - > ps . velocity ) ;
hit - > client - > ps . pm_time = 160 ; /* hold time */
hit - > client - > ps . pm_flags | = PMF_TIME_KNOCKBACK ;
movedPlayer = qtrue ;
}
return movedPlayer ;
}
//==============================================================================
/**
* \ brief Adds a new Predictable event .
*
* Use for non - pmove events that would also be predicted on the
* client side : jumppads and item pickups
* Adds an event + parm and twiddles the event counter
*
* @ param ent the entity
* @ param event the event
* @ param eventParm any parameters for the event
*/
2012-01-22 21:34:33 +00:00
void G_AddPredictableEvent ( gentity_t * ent , int event , int eventParm ) {
if ( ! ent - > client ) {
return ;
}
BG_AddPredictableEventToPlayerstate ( event , eventParm , & ent - > client - > ps ) ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Add a new event .
*
* Adds an event + parm and twiddles the event counter
*
* @ param ent the entity
* @ param event the event
* @ param eventParm parameter for the event
*/
2012-01-22 21:34:33 +00:00
void G_AddEvent ( gentity_t * ent , int event , int eventParm ) {
int bits ;
2012-08-04 10:54:37 +00:00
playerState_t * ps = & ent - > client - > ps ;
2012-01-22 21:34:33 +00:00
if ( ! event ) {
G_Printf ( " G_AddEvent: zero event added for entity %i \n " , ent - > s . number ) ;
return ;
}
2012-08-04 10:54:37 +00:00
/* clients need to add the event in playerState_t instead of entityState_t */
2012-01-22 21:34:33 +00:00
if ( ent - > client ) {
2012-08-04 10:54:37 +00:00
bits = ps - > externalEvent & EV_EVENT_BITS ;
2012-01-22 21:34:33 +00:00
bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS ;
2012-08-04 10:54:37 +00:00
ps - > externalEvent = event | bits ;
ps - > externalEventParm = eventParm ;
ps - > externalEventTime = level . time ;
2012-01-22 21:34:33 +00:00
} else {
bits = ent - > s . event & EV_EVENT_BITS ;
bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS ;
ent - > s . event = event | bits ;
ent - > s . eventParm = eventParm ;
}
ent - > eventTime = level . time ;
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Makes an entity to play a non looping sound .
*
* Makes an entity to play a non looping sound .
*
* @ param ent the entity
* @ param soundIndex the sounds index
*/
void G_Sound ( gentity_t * ent , int soundIndex ) {
2012-01-22 21:34:33 +00:00
gentity_t * te ;
te = G_TempEntity ( ent - > r . currentOrigin , EV_GENERAL_SOUND ) ;
te - > s . eventParm = soundIndex ;
}
//==============================================================================
2012-08-04 10:54:37 +00:00
/**
* \ brief Set the Origin of an entity .
*
* Sets the pos trajectory for a fixed position
*
* @ param ent the entity
* @ param origin the new origin
*/
2012-01-22 21:34:33 +00:00
void G_SetOrigin ( gentity_t * ent , vec3_t origin ) {
VectorCopy ( origin , ent - > s . pos . trBase ) ;
ent - > s . pos . trType = TR_STATIONARY ;
ent - > s . pos . trTime = 0 ;
ent - > s . pos . trDuration = 0 ;
VectorClear ( ent - > s . pos . trDelta ) ;
VectorCopy ( origin , ent - > r . currentOrigin ) ;
2012-08-04 10:54:37 +00:00
VectorCopy ( origin , ent - > s . origin ) ; /* RPG-X | GSIO01 | 24.08.2009 */
2012-01-22 21:34:33 +00:00
}
2012-08-04 10:54:37 +00:00
/**
* \ brief Set the angles of an entity .
*
* Sets the pos trajectory for a fixed angular position
*
* @ param ent the entity
* @ param angles the new angles
*/
void G_SetAngles ( gentity_t * ent , vec3_t angles ) {
VectorCopy ( angles , ent - > s . apos . trBase ) ;
ent - > s . apos . trType = TR_STATIONARY ;
ent - > s . apos . trTime = 0 ;
ent - > s . apos . trDuration = 0 ;
VectorClear ( ent - > s . apos . trDelta ) ;
VectorCopy ( angles , ent - > r . currentAngles ) ;
VectorCopy ( angles , ent - > s . angles ) ;
}
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
/**
* \ brief Get list of entities around a given origin ,
*
* Given an origin and a radius , return all entities that are in use that are within the list
*
* @ param origin the origin
* @ param radius the radius to look in around
* @ param ignore entity to ignore
* @ param takeDamage only list ents that may get damaged ?
* @ param ent_list the resulting list
*
* @ return the number of found entities in the list
*/
int G_RadiusList ( vec3_t origin , float radius , gentity_t * ignore , qboolean takeDamage , gentity_t * ent_list [ MAX_GENTITIES ] )
{
float dist ;
gentity_t * ent ;
int entityList [ MAX_GENTITIES ] ;
int numListedEntities ;
vec3_t mins , maxs ;
vec3_t v ;
int i , e ;
int ent_count = 0 ;
if ( radius < 1 )
{
radius = 1 ;
}
for ( i = 0 ; i < 3 ; i + + )
{
mins [ i ] = origin [ i ] - radius ;
maxs [ i ] = origin [ i ] + radius ;
}
numListedEntities = trap_EntitiesInBox ( mins , maxs , entityList , MAX_GENTITIES ) ;
for ( e = 0 ; e < numListedEntities ; e + + )
{
ent = & g_entities [ entityList [ e ] ] ;
if ( ( ent = = ignore ) | | ! ( ent - > inuse ) | | ent - > takedamage ! = takeDamage )
continue ;
/* find the distance from the edge of the bounding box */
for ( i = 0 ; i < 3 ; i + + )
{
if ( origin [ i ] < ent - > r . absmin [ i ] )
{
v [ i ] = ent - > r . absmin [ i ] - origin [ i ] ;
} else if ( origin [ i ] > ent - > r . absmax [ i ] )
{
v [ i ] = origin [ i ] - ent - > r . absmax [ i ] ;
} else
{
v [ i ] = 0 ;
}
}
dist = VectorLength ( v ) ;
if ( dist > = radius )
{
continue ;
}
/* ok, we are within the radius, add us to the incoming list */
ent_list [ ent_count ] = ent ;
ent_count + + ;
}
/* we are done, return how many we found */
return ( ent_count ) ;
}
int G_RadiusListOfType ( char * classname , vec3_t origin , float radius , gentity_t * ignore , gentity_t * ent_list [ MAX_GENTITIES ] ) {
float dist ;
gentity_t * ent ;
int entityList [ MAX_GENTITIES ] ;
int numListedEntities ;
vec3_t mins , maxs ;
vec3_t v ;
int i , e ;
int ent_count = 0 ;
if ( radius < 1 )
{
radius = 1 ;
}
for ( i = 0 ; i < 3 ; i + + )
{
mins [ i ] = origin [ i ] - radius ;
maxs [ i ] = origin [ i ] + radius ;
}
numListedEntities = trap_EntitiesInBox ( mins , maxs , entityList , MAX_GENTITIES ) ;
for ( e = 0 ; e < numListedEntities ; e + + )
{
ent = & g_entities [ entityList [ e ] ] ;
if ( ( ent = = ignore ) | | ! ( ent - > inuse ) | | strcmp ( classname , ent - > classname ) )
continue ;
/* find the distance from the edge of the bounding box */
for ( i = 0 ; i < 3 ; i + + )
{
if ( origin [ i ] < ent - > r . absmin [ i ] )
{
v [ i ] = ent - > r . absmin [ i ] - origin [ i ] ;
} else if ( origin [ i ] > ent - > r . absmax [ i ] )
{
v [ i ] = origin [ i ] - ent - > r . absmax [ i ] ;
} else
{
v [ i ] = 0 ;
}
}
dist = VectorLength ( v ) ;
if ( dist > = radius )
{
continue ;
}
/* ok, we are within the radius, add us to the incoming list */
ent_list [ ent_count ] = ent ;
ent_count + + ;
}
/* we are done, return how many we found */
return ( ent_count ) ;
}
/**
* \ brief Find the nearest entity
*
* Find the nearest entity .
*
* @ param classname filter the results by this classname
* @ param origin the origin
* @ param the radoius to look in around
* @ param ignore entity to ignore
* @ param takeDamage only return an entity that may take damage ?
*
* @ return the nearest entity
*/
gentity_t * G_GetNearestEnt ( char * classname , vec3_t origin , float radius , gentity_t * ignore , qboolean takeDamage ) {
gentity_t * entList [ MAX_GENTITIES ] , * nearest = NULL ;
int count , i ;
float distance , minDist ;
vec3_t dist ;
if ( ! radius ) { /* we don't care how far it is away */
radius = 9999999 ;
}
minDist = radius ;
count = G_RadiusList ( origin , radius , ignore , takeDamage , entList ) ;
for ( i = 0 ; i < count ; i + + ) {
if ( entList [ i ] ! = ignore ) {
if ( entList [ i ] - > s . origin [ 0 ] | | entList [ i ] - > s . origin [ 1 ] | | entList [ i ] - > s . origin [ 2 ] ) {
VectorSubtract ( origin , entList [ i ] - > s . origin , dist ) ;
} else if ( entList [ i ] - > r . currentOrigin [ 0 ] | | entList [ i ] - > r . currentOrigin [ 1 ] | | entList [ i ] - > r . currentOrigin [ 2 ] ) {
VectorSubtract ( origin , entList [ i ] - > r . currentOrigin , dist ) ;
} else if ( entList [ i ] - > s . pos . trBase [ 0 ] | | entList [ i ] - > s . pos . trBase [ 1 ] | | entList [ i ] - > s . pos . trBase [ 2 ] ) {
VectorSubtract ( origin , entList [ i ] - > s . pos . trBase , dist ) ;
} else { /* wow none of above ... well then assume it's origin is 0 0 0*/
VectorCopy ( origin , dist ) ;
}
distance = VectorLength ( dist ) ;
if ( distance < 0 ) {
distance * = - 1 ;
}
if ( distance < minDist ) {
if ( classname & & ! Q_stricmp ( classname , entList [ i ] - > classname ) ) {
minDist = distance ;
nearest = entList [ i ] ;
} else if ( ! classname ) {
minDist = distance ;
nearest = entList [ i ] ;
}
}
}
}
return nearest ;
}
/**
* \ brief Find the nearest player .
*
* Find the nearest player
*
* @ param origin the origin
* @ param radius the radius to look in around
* @ param ignore entity to ignore
*
* @ return the nearest player
*/
gentity_t * G_GetNearestPlayer ( vec3_t origin , float radius , gentity_t * ignore ) {
gentity_t * entList [ MAX_GENTITIES ] , * nearest = NULL ;
int count , i ;
float distance , minDist ;
vec3_t dist ;
if ( ! radius )
radius = 999999 ;
minDist = radius ;
count = G_RadiusList ( origin , radius , ignore , qtrue , entList ) ;
for ( i = 0 ; i < MAX_CLIENTS ; i + + ) {
if ( entList [ i ] - > client ) {
VectorSubtract ( origin , entList [ i ] - > r . currentOrigin , dist ) ;
distance = VectorLength ( dist ) ;
if ( distance < 0 )
distance * = - 1 ;
if ( distance < minDist ) {
minDist = distance ;
nearest = entList [ i ] ;
}
}
}
return nearest ;
}
/**
* \ author GSIO01
* \ brief Get all entities with the specified targetname .
*
* Get all entities with the specified targetname .
*
* @ param targetname the targetname
* @ param entities the result
*
* @ return number of entities found
*/
int G_GetEntityByTargetname ( const char * targetname , gentity_t * entities [ MAX_GENTITIES ] ) {
int i ;
int cnt = 0 ;
gentity_t * t ;
for ( i = MAX_GENTITIES - 1 ; i > - 1 ; i - - ) {
if ( ! & g_entities [ i ] ) continue ;
t = & g_entities [ i ] ;
if ( t - > targetname & & ! Q_strncmp ( t - > targetname , targetname , strlen ( targetname ) ) ) {
entities [ cnt ] = t ;
cnt + + ;
}
}
return cnt ;
}
/**
* \ author GSIO01
* \ brief Get all entities with specified target .
*
* Get all entities matching the specifie target .
*
* @ param target target the entities should have
* @ param entities the result
*
* @ return number of matches found
*/
int G_GetEntityByTarget ( const char * target , gentity_t * entities [ MAX_GENTITIES ] ) {
int i ;
int cnt = 0 ;
gentity_t * t ;
for ( i = MAX_GENTITIES - 1 ; i > - 1 ; i - - ) {
if ( ! & g_entities [ i ] ) continue ;
t = & g_entities [ i ] ;
if ( t - > target & & ! Q_strncmp ( t - > target , target , strlen ( target ) ) ) {
entities [ cnt ] = t ;
cnt + + ;
}
}
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
return cnt ;
}
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
/**
* \ author GSIO01
* \ brief Get all entities with specified brush model
*
* Get all entities matching the specified brush model .
* Normally this only shoud be one entity .
*
* @ param bmodel brush model to match
* @ param entities the result
*
* @ return number of matches found
*/
int G_GetEntityByBmodel ( char * bmodel , gentity_t * entities [ MAX_GENTITIES ] ) {
int i ;
int cnt = 0 ;
gentity_t * t ;
for ( i = MAX_GENTITIES - 1 ; i > - 1 ; i - - ) {
if ( ! & g_entities [ i ] ) continue ;
t = & g_entities [ i ] ;
if ( t - > model & & ! Q_strncmp ( t - > model , bmodel , strlen ( bmodel ) ) ) {
entities [ cnt ] = t ;
cnt + + ;
}
}
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
return cnt ;
}
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
/**
* Checks if the line of sight between two entities is blocked .
*
* \ author Ubergames - Phenix
* \ date 2 / 8 / 2004
*
* @ param ent1 entity one
* @ param ent2 entity two
*
* @ return is line of sight blocked ?
*/
qboolean LineOfSight ( gentity_t * ent1 , gentity_t * ent2 ) {
trace_t trace ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
trap_Trace ( & trace , ent1 - > s . pos . trBase , NULL , NULL , ent2 - > s . pos . trBase , ent1 - > s . number , MASK_SHOT ) ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
if ( trace . contents & CONTENTS_SOLID ) {
return qfalse ;
}
return qtrue ;
2012-01-22 21:34:33 +00:00
}
2012-08-04 10:54:37 +00:00