diff options
Diffstat (limited to 'src/game/g_utils.c')
-rw-r--r-- | src/game/g_utils.c | 1071 |
1 files changed, 0 insertions, 1071 deletions
diff --git a/src/game/g_utils.c b/src/game/g_utils.c deleted file mode 100644 index 9b163a92..00000000 --- a/src/game/g_utils.c +++ /dev/null @@ -1,1071 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// g_utils.c -- misc utility functions for game module - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "g_local.h" - -typedef struct -{ - char oldShader[ MAX_QPATH ]; - char newShader[ MAX_QPATH ]; - float timeOffset; -} shaderRemap_t; - -#define MAX_SHADER_REMAPS 128 - -int remapCount = 0; -shaderRemap_t remappedShaders[ MAX_SHADER_REMAPS ]; - -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 ) - { - // found it, just update this one - 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++; - } -} - -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 - -========================================================================= -*/ - -/* -================ -G_FindConfigstringIndex - -================ -*/ -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 ) - G_Error( "G_FindConfigstringIndex: overflow" ); - - trap_SetConfigstring( start + i, name ); - - return i; -} - -//TA: added ParticleSystemIndex -int G_ParticleSystemIndex( char *name ) -{ - return G_FindConfigstringIndex( name, CS_PARTICLE_SYSTEMS, MAX_GAME_PARTICLE_SYSTEMS, qtrue ); -} - -//TA: added ShaderIndex -int G_ShaderIndex( char *name ) -{ - return G_FindConfigstringIndex( name, CS_SHADERS, MAX_SHADERS, qtrue ); -} - -int G_ModelIndex( char *name ) -{ - return G_FindConfigstringIndex( name, CS_MODELS, MAX_MODELS, qtrue ); -} - -int G_SoundIndex( char *name ) -{ - return G_FindConfigstringIndex( name, CS_SOUNDS, MAX_SOUNDS, qtrue ); -} - -//===================================================================== - - -/* -================ -G_TeamCommand - -Broadcasts a command to only a specific team -================ -*/ -void G_TeamCommand( pTeam_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 ].ps.stats[ STAT_PTEAM ] == team ) - G_SendCommandFromServer( i, va( "%s", cmd ) ); - } - } -} - - -/* -============= -G_Find - -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. - -============= -*/ -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; -} - - -/* -============= -G_PickTarget - -Selects a random entity from among the targets -============= -*/ -#define MAXCHOICES 32 - -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; - } - - while( 1 ) - { - ent = G_Find( ent, FOFS( targetname ), targetname ); - - if( !ent ) - break; - - choice[ num_choices++ ] = ent; - - if( num_choices == MAXCHOICES ) - break; - } - - if( !num_choices ) - { - G_Printf( "G_PickTarget: target %s not found\n", targetname ); - return NULL; - } - - return choice[ rand( ) % num_choices ]; -} - - -/* -============================== -G_UseTargets - -"activator" should be set to the entity that initiated the firing. - -Search for (string)targetname in all entities that -match (string)self.target and call their .use function - -============================== -*/ -void G_UseTargets( gentity_t *ent, gentity_t *activator ) -{ - gentity_t *t; - - 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( ) ); - } - - if( !ent->target ) - return; - - t = NULL; - while( ( t = G_Find( t, FOFS( targetname ), ent->target ) ) != NULL ) - { - if( t == ent ) - G_Printf( "WARNING: Entity used itself.\n" ); - else - { - if( t->use ) - t->use( t, ent, activator ); - } - - if( !ent->inuse ) - { - G_Printf( "entity was removed while using targets\n" ); - return; - } - } -} - - -/* -============= -TempVector - -This is just a convenience function -for making temporary vectors for function calls -============= -*/ -float *tv( float x, float y, float z ) -{ - static int index; - static vec3_t vecs[ 8 ]; - float *v; - - // use an array so that multiple tempvectors won't collide - // for a while - v = vecs[ index ]; - index = ( index + 1 ) & 7; - - v[ 0 ] = x; - v[ 1 ] = y; - v[ 2 ] = z; - - return v; -} - - -/* -============= -VectorToString - -This is just a convenience function -for printing vectors -============= -*/ -char *vtos( const vec3_t v ) -{ - static int index; - static char str[ 8 ][ 32 ]; - char *s; - - // use an array so that multiple vtos won't collide - 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; -} - - -/* -=============== -G_SetMovedir - -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. -=============== -*/ -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 ); -} - - -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; -} - - -void G_InitGentity( gentity_t *e ) -{ - e->inuse = qtrue; - e->classname = "noclass"; - e->s.number = e - g_entities; - e->r.ownerNum = ENTITYNUM_NONE; -} - -/* -================= -G_Spawn - -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. -================= -*/ -gentity_t *G_Spawn( void ) -{ - int i, force; - gentity_t *e; - - e = NULL; // shut up warning - i = 0; // shut up warning - - for( force = 0; force < 2; force++ ) - { - // if we go through all entities and can't find one to free, - // override the normal minimum times before use - e = &g_entities[ MAX_CLIENTS ]; - - for( i = MAX_CLIENTS; i < level.num_entities; i++, e++ ) - { - if( e->inuse ) - continue; - - // the first couple seconds of server time can involve a lot of - // freeing and allocating, so relax the replacement policy - if( !force && e->freetime > level.startTime + 2000 && level.time - e->freetime < 1000 ) - continue; - - // reuse this slot - G_InitGentity( e ); - return e; - } - - if( i != MAX_GENTITIES ) - break; - } - - if( i == ENTITYNUM_MAX_NORMAL ) - { - for( i = 0; i < MAX_GENTITIES; i++ ) - G_Printf( "%4i: %s\n", i, g_entities[ i ].classname ); - - G_Error( "G_Spawn: no free entities" ); - } - - // open up a new slot - level.num_entities++; - - // let the server system know that there are more entities - trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ), - &level.clients[ 0 ].ps, sizeof( level.clients[ 0 ] ) ); - - G_InitGentity( e ); - return e; -} - - -/* -================= -G_EntitiesFree -================= -*/ -qboolean G_EntitiesFree( void ) -{ - int i; - gentity_t *e; - - e = &g_entities[ MAX_CLIENTS ]; - - for( i = MAX_CLIENTS; i < level.num_entities; i++, e++ ) - { - if( e->inuse ) - continue; - - // slot available - return qtrue; - } - - return qfalse; -} - - -/* -================= -G_FreeEntity - -Marks the entity as free -================= -*/ -void G_FreeEntity( gentity_t *ent ) -{ - trap_UnlinkEntity( ent ); // unlink from world - - if( ent->neverFree ) - return; - - memset( ent, 0, sizeof( *ent ) ); - ent->classname = "freent"; - ent->freetime = level.time; - ent->inuse = qfalse; -} - -/* -================= -G_TempEntity - -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) -================= -*/ -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 ); - SnapVector( snapped ); // save network bandwidth - G_SetOrigin( e, snapped ); - - // find cluster for PVS - trap_LinkEntity( e ); - - return e; -} - - - -/* -============================================================================== - -Kill box - -============================================================================== -*/ - -/* -================= -G_KillBox - -Kills all entities that would touch the proposed new positioning -of ent. Ent should be unlinked before calling this! -================= -*/ -void G_KillBox( gentity_t *ent ) -{ - int i, num; - int touch[ MAX_GENTITIES ]; - 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; - - //TA: impossible to telefrag self - if( ent == hit ) - continue; - - // nail it - G_Damage( hit, ent, ent, NULL, NULL, - 100000, DAMAGE_NO_PROTECTION, MOD_TELEFRAG ); - } - -} - -//============================================================================== - -/* -=============== -G_AddPredictableEvent - -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 -=============== -*/ -void G_AddPredictableEvent( gentity_t *ent, int event, int eventParm ) -{ - if( !ent->client ) - return; - - BG_AddPredictableEventToPlayerstate( event, eventParm, &ent->client->ps ); -} - - -/* -=============== -G_AddEvent - -Adds an event+parm and twiddles the event counter -=============== -*/ -void G_AddEvent( gentity_t *ent, int event, int eventParm ) -{ - int bits; - - if( !event ) - { - G_Printf( "G_AddEvent: zero event added for entity %i\n", ent->s.number ); - return; - } - - // clients need to add the event in playerState_t instead of entityState_t - if( ent->client ) - { - bits = ent->client->ps.externalEvent & EV_EVENT_BITS; - bits = ( bits + EV_EVENT_BIT1 ) & EV_EVENT_BITS; - ent->client->ps.externalEvent = event | bits; - ent->client->ps.externalEventParm = eventParm; - ent->client->ps.externalEventTime = level.time; - } - 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; -} - - -/* -=============== -G_BroadcastEvent - -Sends an event to every client -=============== -*/ -void G_BroadcastEvent( int event, int eventParm ) -{ - gentity_t *ent; - - ent = G_TempEntity( vec3_origin, event ); - ent->s.eventParm = eventParm; - ent->r.svFlags = SVF_BROADCAST; // send to everyone -} - - -/* -============= -G_Sound -============= -*/ -void G_Sound( gentity_t *ent, int channel, int soundIndex ) -{ - gentity_t *te; - - te = G_TempEntity( ent->r.currentOrigin, EV_GENERAL_SOUND ); - te->s.eventParm = soundIndex; -} - - -/* -============= -G_ClientIsLagging -============= -*/ -qboolean G_ClientIsLagging( gclient_t *client ) -{ - if( client ) - { - if( client->ps.ping >= 999 ) - return qtrue; - else - return qfalse; - } - - return qfalse; //is a non-existant client lagging? woooo zen -} - - -static commandQueue_t queuedCommands[ MAX_CLIENTS ]; - -/* -=============== -G_PopCommandQueue - -Return the front of a command queue -Must use immediately or copy to a buffer -=============== -*/ -static const char *G_PopCommandQueue( commandQueue_t *cq ) -{ - if( cq->front ) - { - commandQueueElement_t *cqe = cq->front; - - cq->front = cqe->next; - - // last element in the queue - if( cq->front == NULL ) - cq->back = NULL; - - cq->nextCommandTime = level.time + g_minCommandPeriod.integer; - cqe->used = qfalse; - - return cqe->command; - } - else - return NULL; -} - -/* -=============== -G_PushCommandQueue - -Put a command on a command queue -=============== -*/ -static void G_PushCommandQueue( commandQueue_t *cq, const char *cmd ) -{ - int i; - - for( i = 0; i < MAX_QUEUE_COMMANDS; i++ ) - { - commandQueueElement_t *cqe = &cq->pool[ i ]; - - if( !cqe->used ) - { - cqe->used = qtrue; - cqe->next = NULL; - Q_strncpyz( cqe->command, cmd, MAX_TOKEN_CHARS ); - - if( cq->back ) - { - cq->back->next = cqe; - cq->back = cqe; - } - else - { - cq->front = cqe; - cq->back = cqe; - } - - return; - } - } - - //drop the command -} - -/* -=============== -G_PrintCommandQueue -=============== -*/ -#if 0 //quiet compiler -static void G_PrintCommandQueue( commandQueue_t *cq ) -{ - commandQueueElement_t *cqe; - - if( cq->front ) - { - cqe = cq->front; - - do - { - G_Printf( "->\"%s\"", cqe->command ); - } while( ( cqe = cqe->next ) ); - - G_Printf( "\n" ); - } -} -#endif - -/* -=============== -G_ReadyToDequeue -=============== -*/ -static qboolean G_ReadyToDequeue( commandQueue_t *cq ) -{ - if( !cq ) - return qfalse; - - return cq->front && cq->nextCommandTime <= level.time; -} - -/* -=============== -G_ProcessCommandQueues - -Check for any outstanding commands to be sent -=============== -*/ -void G_ProcessCommandQueues( void ) -{ - int i; - - for( i = 0; i < MAX_CLIENTS; i++ ) - { - gclient_t *cl = &level.clients[ i ]; - commandQueue_t *cq = &queuedCommands[ i ]; - - if( !G_ClientIsLagging( cl ) && G_ReadyToDequeue( cq ) ) - { - const char *command = G_PopCommandQueue( cq ); - - if( command ) - trap_SendServerCommand( i, command ); - } - } -} - -/* -=============== -G_InitCommandQueue -=============== -*/ -void G_InitCommandQueue( int clientNum ) -{ - int i; - commandQueue_t *cq = &queuedCommands[ clientNum ]; - - if( clientNum >= 0 && clientNum < MAX_CLIENTS ) - { - cq->front = cq->back = NULL; - cq->nextCommandTime = 0; - - for( i = 0; i < MAX_QUEUE_COMMANDS; i++ ) - { - commandQueueElement_t *cqe = &cq->pool[ i ]; - - cqe->used = qfalse; - } - } -} - -/* -=============== -G_SendCommandFromServer - -Sends a command to a client -=============== -*/ -void G_SendCommandFromServer( int clientNum, const char *cmd ) -{ - commandQueue_t *cq = &queuedCommands[ clientNum ]; - - if( clientNum < 0 ) - cq = NULL; - - if( strlen( cmd ) > 1022 ) - { - G_LogPrintf( "G_SendCommandFromServer( %d, ... ) length exceeds 1022.\n", clientNum ); - G_LogPrintf( "cmd [%s]\n", cmd ); - return; - } - - if( cq ) - { - gclient_t *cl = &level.clients[ clientNum ]; - - if( cq->nextCommandTime > level.time || G_ClientIsLagging( cl ) ) - { - //can't send yet, so queue the command up - G_PushCommandQueue( cq, cmd ); - } - else - { - cq->nextCommandTime = level.time + g_minCommandPeriod.integer; - trap_SendServerCommand( clientNum, cmd ); - } - } - else //no queue exists for this client - trap_SendServerCommand( clientNum, cmd ); -} - -//============================================================================== - - -/* -================ -G_SetOrigin - -Sets the pos trajectory for a fixed position -================ -*/ -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 ); - VectorCopy( origin, ent->s.origin ); //TA: if shit breaks - blame this line -} - -//TA: from quakestyle.telefragged.com -// (NOBODY): Code helper function -// -gentity_t *G_FindRadius( gentity_t *from, vec3_t org, float rad ) -{ - vec3_t eorg; - int j; - - if( !from ) - from = g_entities; - else - from++; - - for( ; from < &g_entities[ level.num_entities ]; from++ ) - { - if( !from->inuse ) - continue; - - for( j = 0; j < 3; j++ ) - eorg[ j ] = org[ j ] - ( from->r.currentOrigin[ j ] + ( from->r.mins[ j ] + from->r.maxs[ j ] ) * 0.5 ); - - if( VectorLength( eorg ) > rad ) - continue; - - return from; - } - - return NULL; -} - -/* -=============== -G_Visible - -Test for a LOS between two entities -=============== -*/ -qboolean G_Visible( gentity_t *ent1, gentity_t *ent2 ) -{ - trace_t trace; - - trap_Trace( &trace, ent1->s.pos.trBase, NULL, NULL, ent2->s.pos.trBase, ent1->s.number, MASK_SHOT ); - - if( trace.contents & CONTENTS_SOLID ) - return qfalse; - - return qtrue; -} - -/* -=============== -G_ClosestEnt - -Test a list of entities for the closest to a particular point -=============== -*/ -gentity_t *G_ClosestEnt( vec3_t origin, gentity_t **entities, int numEntities ) -{ - int i; - float nd, d = 1000000.0f; - gentity_t *closestEnt = NULL; - - for( i = 0; i < numEntities; i++ ) - { - gentity_t *ent = entities[ i ]; - - if( ( nd = Distance( origin, ent->s.origin ) ) < d ) - { - d = nd; - closestEnt = ent; - } - } - - return closestEnt; -} - -/* -=============== -G_TriggerMenu - -Trigger a menu on some client -=============== -*/ -void G_TriggerMenu( int clientNum, dynMenu_t menu ) -{ - char buffer[ 32 ]; - - Com_sprintf( buffer, 32, "servermenu %d", menu ); - G_SendCommandFromServer( clientNum, buffer ); -} - - -/* -=============== -G_CloseMenus - -Close all open menus on some client -=============== -*/ -void G_CloseMenus( int clientNum ) -{ - char buffer[ 32 ]; - - Com_sprintf( buffer, 32, "serverclosemenus" ); - G_SendCommandFromServer( clientNum, buffer ); -} - - -/* -================ -DebugLine - - debug polygons only work when running a local game - with r_debugSurface set to 2 -================ -*/ -int DebugLine( vec3_t start, vec3_t end, int color ) -{ - vec3_t points[ 4 ], dir, cross, up = { 0, 0, 1 }; - float dot; - - VectorCopy( start, points[ 0 ] ); - VectorCopy( start, points[ 1 ] ); - //points[1][2] -= 2; - VectorCopy( end, points[ 2 ] ); - //points[2][2] -= 2; - VectorCopy( end, points[ 3 ] ); - - - VectorSubtract( end, start, dir ); - VectorNormalize( dir ); - dot = DotProduct( dir, up ); - - if( dot > 0.99 || dot < -0.99 ) - VectorSet( cross, 1, 0, 0 ); - else - CrossProduct( dir, up, cross ); - - VectorNormalize( cross ); - - VectorMA(points[ 0 ], 2, cross, points[ 0 ] ); - VectorMA(points[ 1 ], -2, cross, points[ 1 ] ); - VectorMA(points[ 2 ], -2, cross, points[ 2 ] ); - VectorMA(points[ 3 ], 2, cross, points[ 3 ] ); - - return trap_DebugPolygonCreate( color, 4, points ); -} - |