diff options
| author | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 | 
|---|---|---|
| committer | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 | 
| commit | 6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch) | |
| tree | e3eda937a05d7db42de725b7013bd0344b987f34 /code/game/g_utils.c | |
| parent | 872d4d7f55af706737ffb361bb76ad13e7496770 (diff) | |
| download | ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip  | |
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/game/g_utils.c')
| -rwxr-xr-x | code/game/g_utils.c | 1332 | 
1 files changed, 666 insertions, 666 deletions
diff --git a/code/game/g_utils.c b/code/game/g_utils.c index adef5d1..8c6f35b 100755 --- a/code/game/g_utils.c +++ b/code/game/g_utils.c @@ -1,666 +1,666 @@ -/*
 -===========================================================================
 -Copyright (C) 1999-2005 Id Software, Inc.
 -
 -This file is part of Quake III Arena source code.
 -
 -Quake III Arena source code is free software; you can redistribute it
 -and/or modify it under the terms of the GNU General Public License as
 -published by the Free Software Foundation; either version 2 of the License,
 -or (at your option) any later version.
 -
 -Quake III Arena source code 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.  See the
 -GNU General Public License for more details.
 -
 -You should have received a copy of the GNU General Public License
 -along with Foobar; if not, write to the Free Software
 -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 -===========================================================================
 -*/
 -//
 -// g_utils.c -- misc utility functions for game module
 -
 -#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() {
 -	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;
 -}
 -
 -
 -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( 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 ));
 -			}
 -		}
 -	}
 -}
 -
 -
 -/*
 -=============
 -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 *ed ) {
 -	trap_UnlinkEntity (ed);		// unlink from world
 -
 -	if ( ed->neverFree ) {
 -		return;
 -	}
 -
 -	memset (ed, 0, sizeof(*ed));
 -	ed->classname = "freed";
 -	ed->freetime = level.time;
 -	ed->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;
 -		}
 -
 -		// 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_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_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 );
 -}
 -
 -/*
 -================
 -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);
 -}
 +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code 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.  See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +=========================================================================== +*/ +// +// g_utils.c -- misc utility functions for game module + +#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() { +	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; +} + + +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( 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 )); +			} +		} +	} +} + + +/* +============= +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 *ed ) { +	trap_UnlinkEntity (ed);		// unlink from world + +	if ( ed->neverFree ) { +		return; +	} + +	memset (ed, 0, sizeof(*ed)); +	ed->classname = "freed"; +	ed->freetime = level.time; +	ed->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; +		} + +		// 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_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_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 ); +} + +/* +================ +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); +}  | 
