From 6bf20c78f5b69d40bcc4931df93d29198435ab67 Mon Sep 17 00:00:00 2001 From: zakk Date: Fri, 26 Aug 2005 17:39:27 +0000 Subject: newlines fixed git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/game/g_utils.c | 1332 +++++++++++++++++++++++++-------------------------- 1 file changed, 666 insertions(+), 666 deletions(-) (limited to 'code/game/g_utils.c') 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 ; iinuse) - 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 ; iinuse ) { - 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 ; iclient ) { - 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 ; iinuse) + 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 ; iinuse ) { + 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 ; iclient ) { + 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); +} -- cgit v1.2.3