📄 g_utils.cpp
字号:
bestspot = spot;
bestdistance = bestplayerdistance;
}
}
if ( bestspot )
{
return bestspot;
}
// if there is a player just spawned on each and every start spot
// we have no choice to turn one into a telefrag meltdown
num = G_FindClass( 0, "info_player_deathmatch" );
spot = G_GetEntity( num );
return spot;
}
Entity *SelectDeathmatchSpawnPoint
(
void
)
{
if ( DM_FLAG( DF_SPAWN_FARTHEST ) )
{
return SelectFarthestDeathmatchSpawnPoint();
}
else
{
return SelectRandomDeathmatchSpawnPoint();
}
}
Entity *SelectCoopSpawnPoint
(
void
)
{
const char *tname;
Entity *spot = NULL;
int num;
num = 0;
while( ( num = G_FindClass( num, "info_player_coop" ) ) != 0 )
{
spot = G_GetEntity( num );
tname = spot->TargetName();
if ( !game.spawnpoint.length() || !tname || !tname[ 0 ] )
{
break;
}
if ( Q_stricmp( game.spawnpoint.c_str(), spot->TargetName() ) == 0 )
{
break;
}
}
return spot;
}
/*
===========
SelectSpawnPoint
Chooses a player start, deathmatch start, coop start, etc
============
*/
void SelectSpawnPoint
(
Vector &origin,
Vector &angles,
int *gravaxis
)
{
const char * tname;
Entity *spot = NULL;
Entity *spot2 = NULL;
int num;
if ( ( level.training == 2 ) && game.spawnpoint.length() )
{
num = 0;
while( ( num = G_FindClass( num, "info_player_progressivestart" ) ) != 0 )
{
spot2 = G_GetEntity( num );
tname = spot2->TargetName();
if ( !tname || !tname[ 0 ] )
{
break;
}
if ( Q_stricmp( game.spawnpoint.c_str(), spot2->TargetName() ) == 0 )
{
spot = spot2;
break;
}
}
}
else if ( deathmatch->value || level.training == 1 )
{
spot = SelectDeathmatchSpawnPoint();
}
else if ( coop->value )
{
spot = SelectCoopSpawnPoint();
}
// find a single player start spot
if ( !spot )
{
num = 0;
while( ( num = G_FindClass( num, "info_player_start" ) ) != 0 )
{
spot = G_GetEntity( num );
tname = spot->TargetName();
if ( !game.spawnpoint.length() || !tname || !tname[ 0 ] )
{
break;
}
if ( Q_stricmp( game.spawnpoint.c_str(), spot->TargetName() ) == 0 )
{
break;
}
}
if ( !spot )
{
if ( !game.spawnpoint.length() )
{
// there wasn't a spawnpoint without a target, so use any
num = G_FindClass( 0, "info_player_start" );
spot = G_GetEntity( num );
}
if ( !spot || !spot->entnum )
{
gi.error( "Couldn't find spawn point %s\n", game.spawnpoint.c_str() );
}
}
}
origin = spot->worldorigin + "0 0 9";
angles = spot->angles;
if ( gravaxis )
{
*gravaxis = spot->gravaxis;
}
}
/*
=============
M_CheckBottom
Returns false if any part of the bottom of the entity is off an edge that
is not a staircase.
=============
*/
int c_yes, c_no;
qboolean M_CheckBottom
(
Entity *ent
)
{
Vector mins, maxs, start, stop;
trace_t trace;
int x, y;
float mid, bottom;
mins = ent->worldorigin + ent->mins * 0.5;
maxs = ent->worldorigin + ent->maxs * 0.5;
// if all of the points under the corners are solid world, don't bother
// with the tougher checks
// the corners must be within 16 of the midpoint
start[ 2 ] = mins[ 2 ] - 1;
for( x = 0; x <= 1; x++ )
{
for( y = 0; y <= 1; y++ )
{
start[ 0 ] = x ? maxs[ 0 ] : mins[ 0 ];
start[ 1 ] = y ? maxs[ 1 ] : mins[ 1 ];
if ( gi.pointcontents( start.vec3() ) != CONTENTS_SOLID )
{
goto realcheck;
}
}
}
c_yes++;
return true; // we got out easy
realcheck:
c_no++;
//
// check it for real...
//
start[ 2 ] = mins[ 2 ];
// the midpoint must be within 16 of the bottom
start[ 0 ] = stop[ 0 ] = ( mins[ 0 ] + maxs[ 0 ] ) * 0.5;
start[ 1 ] = stop[ 1 ] = ( mins[ 1 ] + maxs[ 1 ] ) * 0.5;
stop[ 2 ] = start[ 2 ] - 3 * STEPSIZE;//2 * STEPSIZE;
trace = G_Trace( start, vec_zero, vec_zero, stop, ent, MASK_MONSTERSOLID, "M_CheckBottom 1" );
if ( trace.fraction == 1.0 )
{
return false;
}
mid = bottom = trace.endpos[ 2 ];
// the corners must be within 16 of the midpoint
for( x = 0; x <= 1; x++ )
{
for( y = 0; y <= 1; y++ )
{
start[ 0 ] = stop[ 0 ] = x ? maxs[ 0 ] : mins[ 0 ];
start[ 1 ] = stop[ 1 ] = y ? maxs[ 1 ] : mins[ 1 ];
trace = G_Trace( start, vec_zero, vec_zero, stop, ent, MASK_MONSTERSOLID, "M_CheckBottom 2" );
if ( trace.fraction != 1.0 && trace.endpos[ 2 ] > bottom )
{
bottom = trace.endpos[ 2 ];
}
if ( trace.fraction == 1.0 || mid - trace.endpos[ 2 ] > STEPSIZE )
{
return false;
}
}
}
c_yes++;
return true;
}
char *G_CopyString
(
const char *in
)
{
char *newb;
char *new_p;
int i,l;
assert( in );
l = strlen( in ) + 1;
newb = ( char * )gi.TagMalloc( l, TAG_LEVEL );
new_p = newb;
for( i = 0; i < l; i++ )
{
if ( ( in[ i ] == '\\' ) && ( i < l - 1 ) )
{
i++;
if ( in[ i ] == 'n' )
{
*new_p++ = '\n';
}
else
{
*new_p++ = '\\';
}
}
else
{
*new_p++ = in[ i ];
}
}
return newb;
}
int G_FindClass
(
int entnum,
const char *classname
)
{
edict_t *from;
for ( from = &g_edicts[ entnum + 1 ]; from < &g_edicts[ globals.num_edicts ] ; from++ )
{
if ( !from->inuse )
{
continue;
}
if ( !Q_stricmp ( from->entity->getClassID(), classname ) )
{
return from->s.number;
}
}
return 0;
}
int G_FindTarget
(
int entnum,
const char *name
)
{
edict_t *from;
Entity *next;
if ( name && name[ 0 ] )
{
from = &g_edicts[ entnum ];
next = world->GetNextEntity( str( name ), from->entity );
if ( next )
{
return next->entnum;
}
}
return 0;
}
EXPORT_FROM_DLL Entity *G_NextEntity
(
Entity *ent
)
{
edict_t *from;
if ( !g_edicts )
{
return NULL;
}
if ( !ent )
{
ent = world;
}
if ( !ent )
{
return NULL;
}
for ( from = ent->edict + 1; from < &g_edicts[ globals.num_edicts ] ; from++ )
{
if ( !from->inuse || !from->entity )
{
continue;
}
return from->entity;
}
return NULL;
}
//
// QuakeEd only writes a single float for angles (bad idea), so up and down are
// just constant angles.
//
Vector G_GetMovedir
(
void
)
{
float angle;
angle = G_GetFloatArg( "angle" );
if ( angle == -1 )
{
return Vector( 0, 0, 1 );
}
else if ( angle == -2 )
{
return Vector( 0, 0, -1 );
}
angle *= ( M_PI * 2 / 360 );
return Vector( cos( angle ), sin( angle ), 0 );
}
/*
=================
KillBox
Kills all entities that would touch the proposed new positioning
of ent. Ent should be unlinked before calling this!
=================
*/
qboolean KillBox
(
Entity *ent
)
{
int i;
int num;
edict_t *touch[ MAX_EDICTS ];
edict_t *hit;
Vector min;
Vector max;
int fail;
fail = 0;
min = ent->worldorigin + ent->mins;
max = ent->worldorigin + ent->maxs;
num = gi.BoxEdicts( min.vec3(), max.vec3(), touch, MAX_EDICTS, AREA_SOLID );
for( i = 0; i < num; i++ )
{
hit = touch[ i ];
if ( !hit->inuse || ( hit->entity == ent ) || !hit->entity || ( hit->entity == world ) )
{
continue;
}
hit->entity->Damage( ent, ent, hit->entity->health + 100000, ent->worldorigin, vec_zero, vec_zero,
0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG, -1, -1, 1.0f );
//
// if we didn't kill it, fail
//
if ( hit->entity->getSolidType() != SOLID_NOT )
{
fail++;
}
}
//
// all clear
//
return !fail;
}
qboolean IsNumeric
(
const char *str
)
{
int len;
int i;
qboolean dot;
if ( *str == '-' )
{
str++;
}
dot = false;
len = strlen( str );
for( i = 0; i < len; i++ )
{
if ( !isdigit( str[ i ] ) )
{
if ( ( str[ i ] == '.' ) && !dot )
{
dot = true;
continue;
}
return false;
}
}
return true;
}
void G_InitEdict
(
edict_t *e
)
{
e->inuse = true;
e->s.number = e - g_edicts;
// make sure a default scale gets set
e->s.scale = 1.0f;
e->s.renderfx |= RF_FRAMELERP;
e->spawntime = level.time;
e->s.frame = 0;
e->s.prevframe = -1;
}
/*
=================
findradius
Returns entities that have origins within a spherical area
findradius (origin, radius)
=================
*/
Entity *findradius
(
Entity *startent,
Vector org,
float rad
)
{
Vector eorg;
edict_t *from;
float r2;
if ( !startent )
{
startent = world;
}
if ( !startent )
{
return NULL;
}
// square the radius so that we don't have to do a square root
r2 = rad * rad;
assert( startent->edict );
for ( from = startent->edict + 1; from < &g_edicts[ globals.num_edicts ]; from++ )
{
if ( !from->inuse )
{
continue;
}
assert( from->entity );
eorg = org - from->entity->centroid;
// dot product returns length squared
if ( ( eorg * eorg ) <= r2 )
{
return from->entity;
}
}
return NULL;
}
/*
=================
findclientinradius
Returns clients that have origins within a spherical area
findclientinradius (origin, radius)
=================
*/
Entity *findclientsinradius
(
Entity *startent,
Vector org,
float rad
)
{
Vector eorg;
edict_t *ed;
float r2;
int i;
// square the radius so that we don't have to do a square root
r2 = rad * rad;
for( i = startent->entnum; i < game.maxclients; i++ )
{
ed = &g_edicts[ 1 + i ];
if ( !ed->inuse || !ed->entity )
{
continue;
}
eorg = org - ed->entity->centroid;
// dot product returns length squared
if ( ( eorg * eorg ) <= r2 )
{
return ed->entity;
}
}
return NULL;
}
const char *G_GetNameForSurface
(
csurface_t *s
)
{
switch( s->flags & MASK_SURF_TYPE )
{
case SURF_TYPE_WOOD :
return "wood";
case SURF_TYPE_METAL :
return "metal";
case SURF_TYPE_STONE :
return "stone";
case SURF_TYPE_CONCRETE :
return "concrete";
case SURF_TYPE_DIRT :
return "dirt";
case SURF_TYPE_FLESH :
return "flesh";
case SURF_TYPE_GRILL :
return "grill";
case SURF_TYPE_GLASS :
return "glass";
case SURF_TYPE_FABRIC :
return "fabric";
case SURF_TYPE_MONITOR :
return "monitor";
case SURF_TYPE_GRAVEL :
return "gravel";
case SURF_TYPE_VEGETATION :
return "vegetation";
case SURF_TYPE_PAPER :
return "paper";
case SURF_TYPE_DUCT :
return "duct";
case SURF_TYPE_WATER :
return "water";
}
return "";
}
void G_InitDebugLines
(
void
)
{
*gi.DebugLines = DebugLines;
*gi.numDebugLines = 0;
currentVertex = vec_zero;
vertColor = Vector( 1, 1, 1 );
vertAlpha = 1;
vertexIndex = 0;
}
void G_AllocDebugLines
(
void
)
{
g_numdebuglines = gi.cvar( "g_numdebuglines", "4096", CVAR_LATCH );
DebugLines = ( debugline_t * )gi.TagMalloc( ( int )g_numdebuglines->value * sizeof( debugline_t ), TAG_GAME );
G_InitDebugLines();
}
void G_DebugLine
(
Vector start,
Vector end,
float r,
float g,
float b,
float alpha
)
{
debugline_t *line;
if ( !g_numdebuglines )
{
return;
}
if ( *gi.numDebugLines >= g_numdebuglines->value )
{
gi.dprintf( "G_DebugLine: Exceeded MAX_DEBUG_LINES\n" );
return;
}
line = &DebugLines[ *gi.numDebugLines ];
( *gi.numDebugLines )++;
VectorCopy( start.vec3(), line->start );
VectorCopy( end.vec3(), line->end );
VectorSet( line->color, r, g, b );
line->alpha = alpha;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -