📄 g_utils.cpp
字号:
//-----------------------------------------------------------------------------
//
// $Logfile:: /Quake 2 Engine/Sin/code/game/g_utils.cpp $
// $Revision:: 68 $
// $Author:: Jimdose $
// $Date:: 12/15/98 6:17p $
//
// Copyright (C) 1998 by Ritual Entertainment, Inc.
// All rights reserved.
//
// This source is may not be distributed and/or modified without
// expressly written permission by Ritual Entertainment, Inc.
//
// $Log:: /Quake 2 Engine/Sin/code/game/g_utils.cpp $
//
// 68 12/15/98 6:17p Jimdose
// made SelectSpawnPoint handle progressive starts
//
// 67 11/19/98 9:28p Jimdose
// Made killbox work better
//
// 66 11/15/98 7:51p Markd
// Made location based stuff case insensitive
//
// 65 11/06/98 10:04p Jimdose
// Added G_AllocDebugLines
// Added g_numdebuglines
//
// 64 11/06/98 5:47p Markd
// got rid of edict event archiving
//
// 63 10/28/98 4:46p Jimdose
// G_ArchiveEdict was accessing edict->owner->entity, which may be cleared out
// when called.
//
// 62 10/27/98 9:46p Aldie
// Changed training cvar to level.training
//
// 61 10/26/98 3:50a Markd
// put in prediction
//
// 60 10/26/98 2:41a Aldie
// Training startpoint
//
// 59 10/24/98 12:42a Markd
// changed origins to worldorigins where appropriate
//
// 58 10/21/98 6:42p Markd
// Added sv_drawtrace
//
// 57 10/18/98 3:23a Jimdose
// Added G_Milliseconds and G_DebugPrintf
//
// 56 10/16/98 7:18p Markd
// Changed ExecuteThread a little bit
//
// 55 10/10/98 1:27a Jimdose
// Added G_LoadAndExecScript
// added edict archiving functions
//
// 54 10/09/98 4:53p Markd
// Added ExecuteThread code
//
// 53 10/09/98 4:33p Aldie
// Added some team functions
//
// 52 10/09/98 2:05a Aldie
// Updated DMFLAGS
//
// 51 10/07/98 11:48p Jimdose
// changed game.spawnpoint to a str
//
// 50 10/03/98 1:09p Aldie
// Added findclientsinradius
//
// 49 9/28/98 5:50p Markd
// Changed Swamp to Duct
//
// 48 9/22/98 4:23p Markd
// Fixed some targetname stuff for lights, doors and scriptobjects
//
// 47 9/14/98 5:41p Jimdose
// Added G_CalcBoundsOfMove
//
// 46 9/01/98 7:49p Markd
// Put code into findradius that will return NULL if world is NULL
//
// 45 9/01/98 7:45p Aldie
// Updated location string stuff
//
// 44 8/31/98 7:49p Jimdose
// Made M_CheckBottom allow greater falls
//
// 43 8/31/98 7:45p Aldie
// Updated surface data structure and removed surfinfo field
//
// 42 8/29/98 9:43p Jimdose
// Made all function names consistantly begin with G_
// Added call info to G_Trace
// Added G_ShowTrace
// Moved all of DebugLines functions into g_utils
//
// 41 8/29/98 2:53p Aldie
// Added status meter for loading levels.
//
// 40 8/28/98 3:46p Markd
// Put in centroid support for find radius
//
// 39 8/27/98 9:05p Jimdose
// Moved several short functions to g_utils.h as inline
//
// 38 8/25/98 7:47p Jimdose
// Added gravaxis to SelectSpawnPoint
//
// 37 8/24/98 4:56p Markd
// Added G_CalculateImpulse
//
// 36 8/18/98 11:51p Jimdose
// Changed G_TouchTriggers to check for the entity touching itself
//
// 35 8/14/98 4:21p Aldie
// Changed rad to rad2 in findradius
//
// 34 8/13/98 4:57p Jimdose
// Made findradius not do a squareroot calculation.
//
// 33 8/08/98 7:50p Jimdose
// changed realWorld to world
//
// 32 8/03/98 7:55p Jimdose
// Added G_DrawDebugNumber
//
// 31 7/23/98 6:17p Aldie
// Updated damage system and fixed some damage related bugs. Also put tracers
// back to the way they were, and added gib event to funcscriptmodels
//
// 30 7/21/98 1:10p Aldie
// Added meansofdeath to obituaries
//
// 29 7/17/98 7:57p Markd
// Added radius to FullTrace
//
// 28 6/15/98 10:07p Jimdose
// Added G_FullTrace
//
// 27 6/10/98 2:10p Aldie
// Updated damage function.
//
// 26 5/26/98 4:22p Markd
// Rewrote G_GetTarget
//
// 25 5/24/98 8:55p Jimdose
// Removed the char * cast from Q_stricmp call
//
// 24 5/24/98 8:46p Jimdose
// Made a lot of functions more str-friendly.
// Got rid of a lot of char * based strings
// Cleaned up get spawn arg functions and sound functions
// sound functions now use consistant syntax
//
// 23 5/24/98 4:48p Jimdose
// Made char *'s const
//
// 22 5/20/98 7:17p Markd
// Added G_DebugBBox
//
// 21 5/20/98 11:11a Markd
// removed char * dependency
//
// 20 5/14/98 10:12p Jimdose
// Added G_NextEntity
//
// 19 5/03/98 4:44p Jimdose
// changed Vector class
// added line drawing utility functions similar to OpenGL
//
// 18 5/02/98 12:01a Jimdose
// added groundplane, groundsurface, groundcontents
//
//
// 17 4/29/98 5:05p Jimdose
// SelectSpawnPoint was using the world as the spawnspot when no spawn spot
// existed
//
// 16 4/16/98 2:04p Jimdose
// G_InitEdict inits frame and prevframe
// Working on M_CheckBottom
//
// 15 4/10/98 4:56p Jimdose
// Set spawntime in G_InitEdict
//
// 14 4/06/98 5:43p Jimdose
// G_InitEdict sets RF_FRAMELERP on new ents
//
// 13 4/04/98 6:04p Jimdose
// Added G_GetNameForSurface
//
// 12 3/28/98 4:36p Jimdose
// Added deathmatch starts
//
// 11 3/26/98 8:19p Jimdose
// Changed groundentity to an edict_t *
// Fixed killbox
//
// 10 3/24/98 4:55p Jimdose
// Fixed G_GetMovedir to return a vector properly (points to bug with Vector.h)
//
// 9 3/23/98 1:31p Jimdose
// Revamped event and command system
//
// 8 3/11/98 2:27p Jimdose
// G_GetMovedir had a bug where the result was rotated 90 degrees
//
// 7 3/05/98 7:18p Markd
// Added default scale to InitEdict
//
// 6 3/02/98 5:45p Jimdose
// Added findradius
// Removed unused Q2 code
//
// 5 2/19/98 5:02p Jimdose
// Moved G_Entity, G_Random, and G_CRandom to g_utils
//
// 4 2/18/98 8:07p Jimdose
// Added IsNumeric
//
// 3 2/06/98 5:51p Jimdose
// Added KillBox
// Changed G_TouchTriggers and M_CheckBottom to be .cpp compatible
//
// 2 2/03/98 10:50a Jimdose
// Created file.
// Merged with pre-Q2 dlls
//
// DESCRIPTION:
//
#include "g_local.h"
#include "g_utils.h"
#include "ctype.h"
#include "worldspawn.h"
#include "scriptmaster.h"
#include "windows.h"
cvar_t *g_numdebuglines;
debugline_t *DebugLines = NULL;
Vector currentVertex( 0, 0, 0 );
Vector vertColor( 1, 1, 1 );
float vertAlpha = 1;
float vertexIndex = 0;
/*
============
G_TouchTriggers
============
*/
void G_TouchTriggers
(
Entity *ent
)
{
int i;
int num;
edict_t *touch[ MAX_EDICTS ];
edict_t *hit;
Event *ev;
// dead things don't activate triggers!
if ( ( ent->client || ( ent->edict->svflags & SVF_MONSTER ) ) && ( ent->health <= 0 ) )
{
return;
}
num = gi.BoxEdicts( ent->absmin.vec3(), ent->absmax.vec3(), touch, MAX_EDICTS, AREA_TRIGGERS );
// be careful, it is possible to have an entity in this
// list removed before we get to it (killtriggered)
for( i = 0; i < num; i++ )
{
hit = touch[ i ];
if ( !hit->inuse || ( hit->entity == ent ) )
{
continue;
}
assert( hit->entity );
// FIXME
// should we post the events on the list with zero time
ev = new Event( EV_Touch );
ev->AddEntity( ent );
hit->entity->ProcessEvent( ev );
}
}
/*
============
G_TouchSolids
Call after linking a new trigger in during gameplay
to force all entities it covers to immediately touch it
============
*/
void G_TouchSolids
(
Entity *ent
)
{
int i;
int num;
edict_t *touch[ MAX_EDICTS ];
edict_t *hit;
Event *ev;
num = gi.BoxEdicts( ent->absmin.vec3(), ent->absmax.vec3(), touch, MAX_EDICTS, AREA_SOLID );
// be careful, it is possible to have an entity in this
// list removed before we get to it (killtriggered)
for( i = 0; i < num; i++ )
{
hit = touch[ i ];
if ( !hit->inuse )
{
continue;
}
assert( hit->entity );
//FIXME
// should we post the events so that we don't have to worry about any entities going away
ev = new Event( EV_Touch );
ev->AddEntity( ent );
hit->entity->ProcessEvent( ev );
}
}
EXPORT_FROM_DLL void G_ShowTrace
(
trace_t *trace,
edict_t *passent,
const char *reason
)
{
str text;
str pass;
str hit;
assert( reason );
assert( trace );
if ( passent )
{
pass = va( "'%s'(%d)", passent->entname, passent->s.number );
}
else
{
pass = "NULL";
}
if ( trace->ent )
{
hit = va( "'%s'(%d)", trace->ent->entname, trace->ent->s.number );
}
else
{
hit = "NULL";
}
text = va( "%0.1f : Pass %s Frac %f Hit %s : '%s'\n",
level.time, pass.c_str(), trace->fraction, hit.c_str(), reason ? reason : "" );
if ( sv_traceinfo->value == 3 )
{
G_DebugPrintf( text.c_str() );
}
else
{
gi.dprintf( "%s", text.c_str() );
}
}
EXPORT_FROM_DLL void G_CalcBoundsOfMove
(
Vector &start,
Vector &end,
Vector &mins,
Vector &maxs,
Vector *minbounds,
Vector *maxbounds
)
{
Vector bmin;
Vector bmax;
ClearBounds( bmin.vec3(), bmax.vec3() );
AddPointToBounds( start.vec3(), bmin.vec3(), bmax.vec3() );
AddPointToBounds( end.vec3(), bmin.vec3(), bmax.vec3() );
bmin += mins;
bmax += maxs;
if ( minbounds )
{
*minbounds = bmin;
}
if ( maxbounds )
{
*maxbounds = bmax;
}
}
EXPORT_FROM_DLL trace_t G_Trace
(
vec3_t start,
vec3_t mins,
vec3_t maxs,
vec3_t end,
edict_t *passent,
int contentmask,
const char *reason
)
{
trace_t trace;
trace = gi.trace( start, mins, maxs, end, passent, contentmask );
assert( !trace.ent || trace.ent->entity );
if ( sv_traceinfo->value > 1 )
{
G_ShowTrace( &trace, passent, reason );
}
sv_numtraces++;
if ( sv_drawtrace->value )
{
G_DebugLine( Vector( start ), Vector( end ), 1, 1, 0, 1 );
}
return trace;
}
EXPORT_FROM_DLL trace_t G_Trace
(
Vector &start,
Vector &mins,
Vector &maxs,
Vector &end,
Entity *passent,
int contentmask,
const char *reason
)
{
edict_t *ent;
trace_t trace;
assert( reason );
if ( passent == NULL )
{
ent = NULL;
}
else
{
ent = passent->edict;
}
trace = gi.trace( start.vec3(), mins.vec3(), maxs.vec3(), end.vec3(), ent, contentmask );
assert( !trace.ent || trace.ent->entity );
if ( sv_traceinfo->value > 1 )
{
G_ShowTrace( &trace, ent, reason );
}
sv_numtraces++;
if ( sv_drawtrace->value )
{
G_DebugLine( start, end, 1, 1, 0, 1 );
}
return trace;
}
EXPORT_FROM_DLL trace_t G_FullTrace
(
Vector &start,
Vector &mins,
Vector &maxs,
Vector &end,
float radius,
Entity *passent,
int contentmask,
const char *reason
)
{
edict_t *ent;
trace_t trace;
if ( passent == NULL )
{
ent = NULL;
}
else
{
ent = passent->edict;
}
trace = gi.fulltrace( start.vec3(), mins.vec3(), maxs.vec3(), end.vec3(), radius, ent, contentmask );
assert( !trace.ent || trace.ent->entity );
if ( sv_traceinfo->value > 1 )
{
G_ShowTrace( &trace, ent, reason );
}
sv_numtraces++;
if ( sv_drawtrace->value )
{
G_DebugLine( start, end, 0, 1, 1, 1 );
}
return trace;
}
EXPORT_FROM_DLL trace_t G_FullTrace
(
vec3_t start,
vec3_t mins,
vec3_t maxs,
vec3_t end,
float radius,
edict_t *passent,
int contentmask,
const char *reason
)
{
trace_t trace;
trace = gi.fulltrace( start, mins, maxs, end, radius, passent, contentmask );
assert( !trace.ent || trace.ent->entity );
if ( sv_traceinfo->value > 1 )
{
G_ShowTrace( &trace, passent, reason );
}
sv_numtraces++;
if ( sv_drawtrace->value )
{
G_DebugLine( Vector( start ), Vector( end ), 0, 1, 1, 1 );
}
return trace;
}
/*
=======================================================================
SelectSpawnPoint
=======================================================================
*/
/*
================
PlayersRangeFromSpot
Returns the distance to the nearest player from the given spot
================
*/
float PlayersRangeFromSpot
(
Entity *spot
)
{
Entity *player;
float bestplayerdistance;
Vector v;
int n;
float playerdistance;
bestplayerdistance = 9999999;
for( n = 1; n <= maxclients->value; n++ )
{
if ( !g_edicts[ n ].inuse || !g_edicts[ n ].entity )
{
continue;
}
player = g_edicts[ n ].entity;
if ( player->health <= 0 )
{
continue;
}
v = spot->worldorigin - player->worldorigin;
playerdistance = v.length();
if ( playerdistance < bestplayerdistance )
{
bestplayerdistance = playerdistance;
}
}
return bestplayerdistance;
}
/*
================
SelectRandomDeathmatchSpawnPoint
go to a random point, but NOT the two points closest
to other players
================
*/
Entity *SelectRandomDeathmatchSpawnPoint
(
void
)
{
Entity *spot, *spot1, *spot2;
int count = 0;
int selection;
int num;
float range, range1, range2;
spot = NULL;
range1 = range2 = 99999;
spot1 = spot2 = NULL;
num = 0;
while( ( num = G_FindClass( num, "info_player_deathmatch" ) ) != 0 )
{
spot = G_GetEntity( num );
count++;
range = PlayersRangeFromSpot( spot );
if ( range < range1 )
{
range1 = range;
spot1 = spot;
}
else if (range < range2)
{
range2 = range;
spot2 = spot;
}
}
if ( !count )
{
return NULL;
}
if ( count <= 2 )
{
spot1 = spot2 = NULL;
}
else
{
count -= 2;
}
selection = rand() % count;
spot = NULL;
num = 0;
do
{
num = G_FindClass( num, "info_player_deathmatch" );
spot = G_GetEntity( num );
if ( spot == spot1 || spot == spot2 )
{
selection++;
}
}
while( selection-- );
return spot;
}
/*
================
SelectFarthestDeathmatchSpawnPoint
================
*/
Entity *SelectFarthestDeathmatchSpawnPoint
(
void
)
{
Entity *bestspot;
float bestdistance;
float bestplayerdistance;
Entity *spot;
int num;
spot = NULL;
bestspot = NULL;
bestdistance = 0;
num = 0;
while( ( num = G_FindClass( num, "info_player_deathmatch" ) ) != NULL )
{
spot = G_GetEntity( num );
bestplayerdistance = PlayersRangeFromSpot( spot );
if ( bestplayerdistance > bestdistance )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -