📄 g_main.cpp
字号:
G_InitClientPersistant( ent->client );
}
}
G_ClientUserinfoChanged( ent, userinfo );
if ( game.maxclients > 1 )
{
gi.printf( "%s connected\n", ent->client->pers.netname );
}
LoadingServer = false;
return true;
}
/*
===========
G_ClientDisconnect
called when a player drops from the server
============
*/
void G_ClientDisconnect
(
edict_t *ent
)
{
// If we get an error, call the server's error function
if ( setjmp( G_AbortGame ) )
{
G_ExitWithError();
}
if ( ( !ent->client ) || ( !ent->entity ) )
{
return;
}
delete ent->entity;
ent->entity = NULL;
}
/*
==================
Cmd_Say_f
==================
*/
void G_Say
(
edict_t *ent,
qboolean team,
qboolean arg0
)
{
int j;
edict_t *other;
const char *p;
char text[ 2048 ];
if ( gi.argc() < 2 && !arg0 )
{
return;
}
if ( !DM_FLAG( DF_MODELTEAMS | DF_SKINTEAMS ) )
{
team = false;
}
if ( team )
{
Com_sprintf( text, sizeof( text ), "(%s): ", ent->client->pers.netname );
}
else
{
Com_sprintf( text, sizeof( text ), "%s: ", ent->client->pers.netname );
}
if ( arg0 )
{
strcat( text, gi.argv( 0 ) );
strcat( text, " " );
strcat( text, gi.args() );
}
else
{
p = gi.args();
if ( *p == '"' )
{
p++;
strcat( text, p );
text[ strlen( text ) - 1 ] = 0;
}
else
{
strcat( text, p );
}
}
// don't let text be too long for malicious reasons
if ( strlen( text ) > 150 )
{
text[ 150 ] = 0;
}
strcat( text, "\n" );
if ( dedicated->value )
{
gi.cprintf( NULL, PRINT_CHAT, "%s", text );
}
for( j = 1; j <= game.maxclients; j++ )
{
other = &g_edicts[ j ];
if ( !other->inuse || !other->client )
{
continue;
}
#if 0
if ( team )
{
if ( !OnSameTeam( ent, other ) )
{
continue;
}
}
#endif
gi.cprintf( other, PRINT_CHAT, "%s", text );
}
}
void ClientCommand
(
edict_t *ent
)
{
const char *cmd;
int i;
int n;
Event *ev;
qboolean found;
cvar_t *cvar;
float t;
if ( !ent->client || !ent->entity )
{
// not fully in game yet
return;
}
cmd = gi.argv( 0 );
n = gi.argc();
if ( !Q_strcasecmp( cmd, "say" ) )
{
G_Say( ent, false, false );
return;
}
else if ( game.maxclients == 1 )
{
// only allow these commands when we only have one client (most likely only a local game)
if ( !Q_strcasecmp( cmd, "add" ) )
{
if ( n < 3 )
{
gi.cprintf( ent, PRINT_HIGH, "Syntax: add [var name] [amount].\n" );
return;
}
cvar = gi.cvar( gi.argv( 1 ), "0", 0 );
t = cvar->value + atof( gi.argv( 2 ) );
gi.cvar_set( gi.argv( 1 ), va( "%f", t ) );
gi.dprintf( "%s = %f\n", gi.argv( 1 ), cvar->value );
return;
}
else if ( !Q_strcasecmp( cmd, "eventlist" ) )
{
const char *mask;
mask = NULL;
if ( n > 1 )
{
mask = gi.argv( 1 );
}
Event::ListCommands( mask );
return;
}
else if ( !Q_strcasecmp( cmd, "classlist" ) )
{
listAllClasses();
return;
}
else if ( !Q_strcasecmp( cmd, "classtree" ) )
{
if ( n > 1 )
{
listInheritanceOrder( gi.argv( 1 ) );
}
else
{
gi.cprintf( ent, PRINT_HIGH, "Syntax: classtree [classname].\n" );
}
return;
}
else if ( !Q_strcasecmp( cmd, "showvar" ) )
{
ScriptVariable *var;
var = Director.GetExistingVariable( gi.argv( 1 ) );
if ( var )
{
gi.cprintf( ent, PRINT_HIGH, "%s = '%s'\n", gi.argv( 1 ), var->stringValue() );
}
else
{
gi.cprintf( ent, PRINT_HIGH, "Variable '%s' does not exist.\n", gi.argv( 1 ) );
}
return;
}
}
found = false;
if ( Event::Exists( cmd ) )
{
ev = new Event( cmd );
ev->SetSource( EV_FROM_CONSOLE );
ev->SetConsoleEdict( ent );
for( i = 1; i < n; i++ )
{
ev->AddToken( gi.argv( i ) );
}
if ( !Q_strncasecmp( cmd, "view", 4 ) )
{
found = Viewmodel.ProcessEvent( ev );
}
else if ( !Q_strncasecmp( cmd, "ai_", 2 ) )
{
found = PathManager.ProcessEvent( ev );
}
else if ( !Q_strncasecmp( cmd, "console", 7 ) )
{
found = consoleManager.ProcessEvent( ev );
}
else
{
found = ent->entity->ProcessEvent( ev );
}
}
if ( !found )
{
// anything that doesn't match a command will be a chat
G_Say( ent, false, true );
}
}
void G_ClientCommand
(
edict_t *ent
)
{
// If we get an error, call the server's error function
if ( setjmp( G_AbortGame ) )
{
G_ExitWithError();
}
//FIXME
// setjmp doesn't seem to like to work inside the above function, so I've broken it out,
// which makes it happy. Wierd.
ClientCommand( ent );
}
/*
==================
G_DeathmatchScoreboardMessage
==================
*/
void G_DeathmatchScoreboardMessage
(
Entity *ent,
Entity *killer
)
{
char entry[ 1024 ];
char string[ 1400 ];
int stringlength;
int i, j, k;
int sorted[ MAX_CLIENTS ];
int sortedscores[ MAX_CLIENTS ];
int score, total;
int x,y;
gclient_t *cl;
edict_t *cl_ent, *killeredict, *entedict;
const char *tag;
killeredict = NULL;
entedict = NULL;
if ( killer )
{
killeredict = killer->edict;
}
if ( ent )
{
entedict = ent->edict;
}
// sort the clients by score
total = 0;
for( i = 0; i < game.maxclients; i++ )
{
cl_ent = g_edicts + 1 + i;
if ( !cl_ent->inuse )
{
continue;
}
score = game.clients[ i ].resp.score;
for( j = 0; j < total; j++ )
{
if ( score > sortedscores[ j ] )
break;
}
for( k = total; k > j; k-- )
{
sorted[ k ] = sorted[ k - 1 ];
sortedscores[ k ] = sortedscores[ k - 1 ];
}
sorted[ j ] = i;
sortedscores[ j ] = score;
total++;
}
// print level name and exit rules
string[ 0 ] = 0;
stringlength = strlen( string );
// add the clients in sorted order
if ( total > 12 )
{
total = 12;
}
for( i = 0; i < total; i++ )
{
cl = &game.clients[ sorted[ i ] ];
cl_ent = g_edicts + 1 + sorted[ i ];
x = (i>=6) ? 160 : 0;
y = 32 + 32 * (i%6);
// Add a tag to the player and the killer
if (cl_ent == entedict)
tag = "tag1";
else if (cl_ent == killeredict)
tag = "tag2";
else
tag = NULL;
// send the layout
Com_sprintf( entry, sizeof( entry ),
"client %i %i %i %i %i %i ",
x, y, sorted[ i ], cl->resp.score, cl->ping, ( level.framenum - cl->resp.enterframe ) / 600 );
// Put the tag on the end of the client command
if ( tag )
strcat( entry, va( "1 %s ",tag ) );
else
strcat( entry, va( "0 " ) );
j = strlen( entry );
if ( stringlength + j > 1024 )
{
break;
}
strcpy( string + stringlength, entry );
stringlength += j;
}
gi.WriteByte( svc_layout );
gi.WriteString( string );
}
/*
==================
G_DeathmatchScoreboard
Draw instead of help message.
Note that it isn't that hard to overflow the 1400 byte message limit!
==================
*/
void G_DeathmatchScoreboard
(
Entity *ent
)
{
G_DeathmatchScoreboardMessage( ent, ent->enemy );
gi.unicast( ent->edict, true );
}
/*
=================
G_ClientDrawBoundingBoxes
=================
*/
void G_ClientDrawBoundingBoxes
(
void
)
{
edict_t *edict;
Entity *ent;
Vector eye;
// don't show bboxes during deathmatch
if ( !sv_showbboxes->value || ( deathmatch->value && !sv_cheats->value ) )
{
return;
}
edict = g_edicts + 1 + 0;
ent = edict->entity;
if ( ent )
{
eye = ent->worldorigin;
ent = findradius( NULL, eye, 1000 );
while( ent )
{
switch ((int)sv_showbboxes->value)
{
case 1:
if ( ent->edict != edict && ent->edict->s.solid)
{
if (ent->bindmaster)
G_DebugBBox( ent->worldorigin, ent->mins, ent->maxs, 0, 1, 0, 1 );
else
G_DebugBBox( ent->worldorigin, ent->mins, ent->maxs, 1, 1, 0, 1 );
}
break;
case 2:
if ( ent->edict != edict && ent->edict->s.solid)
{
if (ent->bindmaster)
G_DebugBBox( "0 0 0", ent->edict->absmin, ent->edict->absmax, 0, 0, 1, 1 );
else
G_DebugBBox( "0 0 0", ent->edict->absmin, ent->edict->absmax, 1, 0, 1, 1 );
}
break;
case 3:
if ( ent->edict->s.modelindex && !(ent->edict->s.renderfx & RF_DONTDRAW) )
G_DebugBBox( ent->worldorigin, ent->mins, ent->maxs, 1, 1, 0, 1 );
break;
case 4:
default:
G_DebugBBox( ent->worldorigin, ent->mins, ent->maxs, 1, 1, 0, 1 );
break;
case 5:
if ( ent->edict->s.solid )
{
G_DebugBBox( ent->worldorigin, ent->edict->fullmins, ent->edict->fullmaxs, 1, 1, 1, 1 );
}
break;
}
ent = findradius( ent, eye, 1000 );
}
}
}
CLASS_DECLARATION( Class, game_locals_t, NULL );
ResponseDef game_locals_t::Responses[] =
{
{ NULL, NULL }
};
game_locals_t::game_locals_t()
{
clients = NULL;
autosaved = false;
spawnpoint = "";
maxentities = 0;
maxclients = 0;
maxconsoles = 0;
maxsurfaces = 0;
force_entnum = false;
spawn_entnum = 0;
ValidPlayerModels.FreeObjectList();
}
EXPORT_FROM_DLL void game_locals_t::Archive
(
Archiver &arc
)
{
int i;
int num;
Class::Archive( arc );
arc.WriteBoolean( autosaved );
arc.WriteString( spawnpoint );
arc.WriteBoolean( force_entnum );
arc.WriteInteger( spawn_entnum );
// List of valid player models loaded from players global scriptfile
num = ValidPlayerModels.NumObjects();
arc.WriteInteger( num );
for( i = 1; i <= num; i++ )
{
arc.WriteString( ValidPlayerModels.ObjectAt( i ) );
}
arc.WriteInteger( maxentities );
arc.WriteInteger( maxclients );
arc.WriteInteger( maxconsoles );
arc.WriteInteger( maxsurfaces );
for( i = 0; i < maxclients; i++ )
{
G_WriteClient( arc, &clients[ i ] );
}
}
EXPORT_FROM_DLL void game_locals_t::Unarchive
(
Archiver &arc
)
{
int i;
int num;
str modelname;
Class::Unarchive( arc );
arc.ReadBoolean( &autosaved );
arc.ReadString( &spawnpoint );
arc.ReadBoolean( &force_entnum );
arc.ReadInteger( &spawn_entnum );
// Load list of valid player models
arc.ReadInteger( &num );
for( i = 1; i <= num; i++ )
{
arc.ReadString( &modelname );
ValidPlayerModels.AddObject( modelname );
}
arc.ReadInteger( &maxentities );
arc.ReadInteger( &maxclients
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -