📄 g_main.c
字号:
// set client fields on player ents
for ( i=0 ; i<level.maxclients ; i++ ) {
g_entities[i].client = level.clients + i;
}
// always leave room for the max number of clients,
// even if they aren't all used, so numbers inside that
// range are NEVER anything but clients
level.num_entities = MAX_CLIENTS;
// let the server system know where the entites are
trap_LocateGameData( level.gentities, level.num_entities, sizeof( gentity_t ),
&level.clients[0].ps, sizeof( level.clients[0] ) );
// reserve some spots for dead player bodies
InitBodyQue();
ClearRegisteredItems();
// parse the key/value pairs and spawn gentities
G_SpawnEntitiesFromString();
// general initialization
G_FindTeams();
// make sure we have flags for CTF, etc
if( g_gametype.integer >= GT_TEAM ) {
G_CheckTeamItems();
}
SaveRegisteredItems();
G_Printf ("-----------------------------------\n");
if( g_gametype.integer == GT_SINGLE_PLAYER || trap_Cvar_VariableIntegerValue( "com_buildScript" ) ) {
G_ModelIndex( SP_PODIUM_MODEL );
G_SoundIndex( "sound/player/gurp1.wav" );
G_SoundIndex( "sound/player/gurp2.wav" );
}
if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
BotAISetup( restart );
BotAILoadMap( restart );
G_InitBots( restart );
}
G_RemapTeamShaders();
}
/*
=================
G_ShutdownGame
=================
*/
void G_ShutdownGame( int restart ) {
G_Printf ("==== ShutdownGame ====\n");
if ( level.logFile ) {
G_LogPrintf("ShutdownGame:\n" );
G_LogPrintf("------------------------------------------------------------\n" );
trap_FS_FCloseFile( level.logFile );
}
// write all the client session data so we can get it back
G_WriteSessionData();
if ( trap_Cvar_VariableIntegerValue( "bot_enable" ) ) {
BotAIShutdown( restart );
}
}
//===================================================================
#ifndef GAME_HARD_LINKED
// this is only here so the functions in q_shared.c and bg_*.c can link
void QDECL Com_Error ( int level, const char *error, ... ) {
va_list argptr;
char text[1024];
va_start (argptr, error);
vsprintf (text, error, argptr);
va_end (argptr);
G_Error( "%s", text);
}
void QDECL Com_Printf( const char *msg, ... ) {
va_list argptr;
char text[1024];
va_start (argptr, msg);
vsprintf (text, msg, argptr);
va_end (argptr);
G_Printf ("%s", text);
}
#endif
/*
========================================================================
PLAYER COUNTING / SCORE SORTING
========================================================================
*/
/*
=============
AddTournamentPlayer
If there are less than two tournament players, put a
spectator in the game and restart
=============
*/
void AddTournamentPlayer( void ) {
int i;
gclient_t *client;
gclient_t *nextInLine;
if ( level.numPlayingClients >= 2 ) {
return;
}
// never change during intermission
if ( level.intermissiontime ) {
return;
}
nextInLine = NULL;
for ( i = 0 ; i < level.maxclients ; i++ ) {
client = &level.clients[i];
if ( client->pers.connected != CON_CONNECTED ) {
continue;
}
if ( client->sess.sessionTeam != TEAM_SPECTATOR ) {
continue;
}
// never select the dedicated follow or scoreboard clients
if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ||
client->sess.spectatorClient < 0 ) {
continue;
}
if ( !nextInLine || client->sess.spectatorTime < nextInLine->sess.spectatorTime ) {
nextInLine = client;
}
}
if ( !nextInLine ) {
return;
}
level.warmupTime = -1;
// set them to free-for-all team
SetTeam( &g_entities[ nextInLine - level.clients ], "f" );
}
/*
=======================
RemoveTournamentLoser
Make the loser a spectator at the back of the line
=======================
*/
void RemoveTournamentLoser( void ) {
int clientNum;
if ( level.numPlayingClients != 2 ) {
return;
}
clientNum = level.sortedClients[1];
if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
return;
}
// make them a spectator
SetTeam( &g_entities[ clientNum ], "s" );
}
/*
=======================
RemoveTournamentWinner
=======================
*/
void RemoveTournamentWinner( void ) {
int clientNum;
if ( level.numPlayingClients != 2 ) {
return;
}
clientNum = level.sortedClients[0];
if ( level.clients[ clientNum ].pers.connected != CON_CONNECTED ) {
return;
}
// make them a spectator
SetTeam( &g_entities[ clientNum ], "s" );
}
/*
=======================
AdjustTournamentScores
=======================
*/
void AdjustTournamentScores( void ) {
int clientNum;
clientNum = level.sortedClients[0];
if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
level.clients[ clientNum ].sess.wins++;
ClientUserinfoChanged( clientNum );
}
clientNum = level.sortedClients[1];
if ( level.clients[ clientNum ].pers.connected == CON_CONNECTED ) {
level.clients[ clientNum ].sess.losses++;
ClientUserinfoChanged( clientNum );
}
}
/*
=============
SortRanks
=============
*/
int QDECL SortRanks( const void *a, const void *b ) {
gclient_t *ca, *cb;
ca = &level.clients[*(int *)a];
cb = &level.clients[*(int *)b];
// sort special clients last
if ( ca->sess.spectatorState == SPECTATOR_SCOREBOARD || ca->sess.spectatorClient < 0 ) {
return 1;
}
if ( cb->sess.spectatorState == SPECTATOR_SCOREBOARD || cb->sess.spectatorClient < 0 ) {
return -1;
}
// then connecting clients
if ( ca->pers.connected == CON_CONNECTING ) {
return 1;
}
if ( cb->pers.connected == CON_CONNECTING ) {
return -1;
}
// then spectators
if ( ca->sess.sessionTeam == TEAM_SPECTATOR && cb->sess.sessionTeam == TEAM_SPECTATOR ) {
if ( ca->sess.spectatorTime < cb->sess.spectatorTime ) {
return -1;
}
if ( ca->sess.spectatorTime > cb->sess.spectatorTime ) {
return 1;
}
return 0;
}
if ( ca->sess.sessionTeam == TEAM_SPECTATOR ) {
return 1;
}
if ( cb->sess.sessionTeam == TEAM_SPECTATOR ) {
return -1;
}
// then sort by score
if ( ca->ps.persistant[PERS_SCORE]
> cb->ps.persistant[PERS_SCORE] ) {
return -1;
}
if ( ca->ps.persistant[PERS_SCORE]
< cb->ps.persistant[PERS_SCORE] ) {
return 1;
}
return 0;
}
/*
============
CalculateRanks
Recalculates the score ranks of all players
This will be called on every client connect, begin, disconnect, death,
and team change.
============
*/
void CalculateRanks( void ) {
int i;
int rank;
int score;
int newScore;
gclient_t *cl;
level.follow1 = -1;
level.follow2 = -1;
level.numConnectedClients = 0;
level.numNonSpectatorClients = 0;
level.numPlayingClients = 0;
level.numVotingClients = 0; // don't count bots
for ( i = 0; i < TEAM_NUM_TEAMS; i++ ) {
level.numteamVotingClients[i] = 0;
}
for ( i = 0 ; i < level.maxclients ; i++ ) {
if ( level.clients[i].pers.connected != CON_DISCONNECTED ) {
level.sortedClients[level.numConnectedClients] = i;
level.numConnectedClients++;
if ( level.clients[i].sess.sessionTeam != TEAM_SPECTATOR ) {
level.numNonSpectatorClients++;
// decide if this should be auto-followed
if ( level.clients[i].pers.connected == CON_CONNECTED ) {
level.numPlayingClients++;
if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
level.numVotingClients++;
if ( level.clients[i].sess.sessionTeam == TEAM_RED )
level.numteamVotingClients[0]++;
else if ( level.clients[i].sess.sessionTeam == TEAM_BLUE )
level.numteamVotingClients[1]++;
}
if ( level.follow1 == -1 ) {
level.follow1 = i;
} else if ( level.follow2 == -1 ) {
level.follow2 = i;
}
}
}
}
}
qsort( level.sortedClients, level.numConnectedClients,
sizeof(level.sortedClients[0]), SortRanks );
// set the rank value for all clients that are connected and not spectators
if ( g_gametype.integer >= GT_TEAM ) {
// in team games, rank is just the order of the teams, 0=red, 1=blue, 2=tied
for ( i = 0; i < level.numConnectedClients; i++ ) {
cl = &level.clients[ level.sortedClients[i] ];
if ( level.teamScores[TEAM_RED] == level.teamScores[TEAM_BLUE] ) {
cl->ps.persistant[PERS_RANK] = 2;
} else if ( level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE] ) {
cl->ps.persistant[PERS_RANK] = 0;
} else {
cl->ps.persistant[PERS_RANK] = 1;
}
}
} else {
rank = -1;
score = 0;
for ( i = 0; i < level.numPlayingClients; i++ ) {
cl = &level.clients[ level.sortedClients[i] ];
newScore = cl->ps.persistant[PERS_SCORE];
if ( i == 0 || newScore != score ) {
rank = i;
// assume we aren't tied until the next client is checked
level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank;
} else {
// we are tied with the previous client
level.clients[ level.sortedClients[i-1] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
}
score = newScore;
if ( g_gametype.integer == GT_SINGLE_PLAYER && level.numPlayingClients == 1 ) {
level.clients[ level.sortedClients[i] ].ps.persistant[PERS_RANK] = rank | RANK_TIED_FLAG;
}
}
}
// set the CS_SCORES1/2 configstrings, which will be visible to everyone
if ( g_gametype.integer >= GT_TEAM ) {
trap_SetConfigstring( CS_SCORES1, va("%i", level.teamScores[TEAM_RED] ) );
trap_SetConfigstring( CS_SCORES2, va("%i", level.teamScores[TEAM_BLUE] ) );
} else {
if ( level.numConnectedClients == 0 ) {
trap_SetConfigstring( CS_SCORES1, va("%i", SCORE_NOT_PRESENT) );
trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
} else if ( level.numConnectedClients == 1 ) {
trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
trap_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) );
} else {
trap_SetConfigstring( CS_SCORES1, va("%i", level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE] ) );
trap_SetConfigstring( CS_SCORES2, va("%i", level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE] ) );
}
}
// see if it is time to end the level
CheckExitRules();
// if we are at the intermission, send the new info to everyone
if ( level.intermissiontime ) {
SendScoreboardMessageToAllClients();
}
}
/*
========================================================================
MAP CHANGING
========================================================================
*/
/*
========================
SendScoreboardMessageToAllClients
Do this at BeginIntermission time and whenever ranks are recalculated
due to enters/exits/forced team changes
========================
*/
void SendScoreboardMessageToAllClients( void ) {
int i;
for ( i = 0 ; i < level.maxclients ; i++ ) {
if ( level.clients[ i ].pers.connected == CON_CONNECTED ) {
DeathmatchScoreboardMessage( g_entities + i );
}
}
}
/*
========================
MoveClientToIntermission
When the intermission starts, this will be called for all players.
If a new client connects, this will be called after the spawn function.
========================
*/
void MoveClientToIntermission( gentity_t *ent ) {
// take out of follow mode if needed
if ( ent->client->sess.spectatorState == SPECTATOR_FOLLOW ) {
StopFollowing( ent );
}
// move to the spot
VectorCopy( level.intermission_origin, ent->s.origin );
VectorCopy( level.intermission_origin, ent->client->ps.origin );
VectorCopy (level.intermission_angle, ent->client->ps.viewangles);
ent->client->ps.pm_type = PM_INTERMISSION;
// clean up powerup info
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -