/* ============ 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 < ARRAY_LEN(level.numteamVotingClients); 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(); } }
/* ============ CalculateRanks Recalculates the score ranks of all players This will be called on every client connect, begin, disconnect, death, and team change. ============ */ void CalculateRanks() { theLevel.follow1_ = -1; theLevel.follow2_ = -1; theLevel.numConnectedClients_ = 0; theLevel.numNonSpectatorClients_ = 0; theLevel.numPlayingClients_ = 0; theLevel.numVotingClients_ = 0; // don't count bots for( int i = 0; i < ClientBase::TEAM_NUM_TEAMS; i++ ) theLevel.numteamVotingClients_[i] = 0; for( int i = 1 ; i <= theLevel.maxclients_ ; i++ ) { GameClient* client = theLevel.getClient(i); if( client && client->pers_.connected_ != GameClient::ClientPersistant::CON_DISCONNECTED ) { theLevel.sortedClients_[theLevel.numConnectedClients_] = i; theLevel.numConnectedClients_++; if( client->sess_.sessionTeam_ != ClientBase::TEAM_SPECTATOR ) { theLevel.numNonSpectatorClients_++; // decide if this should be auto-followed if ( client->pers_.connected_ == GameClient::ClientPersistant::CON_CONNECTED ) { theLevel.numPlayingClients_++; if( !(theLevel.getEntity(i)->r.svFlags & SVF_BOT) ) { theLevel.numVotingClients_++; if( client->sess_.sessionTeam_ == ClientBase::TEAM_RED ) theLevel.numteamVotingClients_[0]++; else if( client->sess_.sessionTeam_ == ClientBase::TEAM_BLUE ) theLevel.numteamVotingClients_[1]++; } if( theLevel.follow1_ == -1 ) theLevel.follow1_ = i; else if( theLevel.follow2_ == -1 ) theLevel.follow2_ = i; } } } } qsort( theLevel.sortedClients_, theLevel.numConnectedClients_, sizeof(theLevel.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 ( int i = 0; i < theLevel.numConnectedClients_; i++ ) { GameClient *cl = theLevel.getClient(theLevel.sortedClients_[i]); if( theLevel.teamScores_[ClientBase::TEAM_RED] == theLevel.teamScores_[ClientBase::TEAM_BLUE] ) cl->ps_.persistant[PERS_RANK] = 2; else if( theLevel.teamScores_[ClientBase::TEAM_RED] > theLevel.teamScores_[ClientBase::TEAM_BLUE] ) cl->ps_.persistant[PERS_RANK] = 0; else cl->ps_.persistant[PERS_RANK] = 1; } } else { int rank = -1; int score = 0; for( int i = 0; i < theLevel.numPlayingClients_; i++ ) { GameClient *cl = theLevel.getClient(theLevel.sortedClients_[i]); int newScore = cl->ps_.persistant[PERS_SCORE]; if( i == 0 || newScore != score ) { rank = i; // assume we aren't tied until the next client is checked theLevel.getClient(theLevel.sortedClients_[i])->ps_.persistant[PERS_RANK] = rank; } else { // we are tied with the previous client theLevel.getClient(theLevel.sortedClients_[i-1])->ps_.persistant[PERS_RANK] = rank | RANK_TIED_FLAG; theLevel.getClient(theLevel.sortedClients_[i])->ps_.persistant[PERS_RANK] = rank | RANK_TIED_FLAG; } score = newScore; if( g_gametype.integer == GT_SINGLE_PLAYER && theLevel.numPlayingClients_ == 1 ) theLevel.getClient(theLevel.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 ) { SV_SetConfigstring( CS_SCORES1, va("%i", theLevel.teamScores_[ClientBase::TEAM_RED] ) ); SV_SetConfigstring( CS_SCORES2, va("%i", theLevel.teamScores_[ClientBase::TEAM_BLUE] ) ); } else { if( theLevel.numConnectedClients_ == 0 ) { SV_SetConfigstring( CS_SCORES1, va("%i", SCORE_NOT_PRESENT) ); SV_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) ); } else if( theLevel.numConnectedClients_ == 1 ) { SV_SetConfigstring( CS_SCORES1, va("%i", theLevel.getClient(theLevel.sortedClients_[0])->ps_.persistant[PERS_SCORE] ) ); SV_SetConfigstring( CS_SCORES2, va("%i", SCORE_NOT_PRESENT) ); } else { SV_SetConfigstring( CS_SCORES1, va("%i", theLevel.getClient(theLevel.sortedClients_[0])->ps_.persistant[PERS_SCORE] ) ); SV_SetConfigstring( CS_SCORES2, va("%i", theLevel.getClient(theLevel.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( theLevel.intermissiontime_ ) SendScoreboardMessageToAllClients(); }
/* ================ G_RunFrame Advances the non-player objects in the world ================ */ void G_RunFrame( int levelTime ) { int i; gentity_t *ent; // if we are waiting for the level to restart, do nothing if ( level.restarted ) { return; } level.framenum++; level.previousTime = level.time; level.time = levelTime; // get any cvar changes G_UpdateCvars(); // // go through all allocated objects // ent = &g_entities[0]; for (i=0 ; i<level.num_entities ; i++, ent++) { if ( !ent->inuse ) { continue; } // clear events that are too old if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) { if ( ent->s.event ) { ent->s.event = 0; // &= EV_EVENT_BITS; if ( ent->client ) { ent->client->ps.externalEvent = 0; // predicted events should never be set to zero //ent->client->ps.events[0] = 0; //ent->client->ps.events[1] = 0; } } if ( ent->freeAfterEvent ) { // tempEntities or dropped items completely go away after their event G_FreeEntity( ent ); continue; } else if ( ent->unlinkAfterEvent ) { // items that will respawn will hide themselves after their pickup event ent->unlinkAfterEvent = qfalse; trap_UnlinkEntity( ent ); } } // temporary entities don't think if ( ent->freeAfterEvent ) { continue; } if ( !ent->r.linked && ent->neverFree ) { continue; } if ( ent->s.eType == ET_MISSILE ) { G_RunMissile( ent ); continue; } if ( ent->s.eType == ET_ITEM || ent->physicsObject ) { G_RunItem( ent ); continue; } if ( ent->s.eType == ET_MOVER ) { G_RunMover( ent ); continue; } if ( i < MAX_CLIENTS ) { G_RunClient( ent ); continue; } G_RunThink( ent ); } // perform final fixups on the players ent = &g_entities[0]; for (i=0 ; i < level.maxclients ; i++, ent++ ) { if ( ent->inuse ) { ClientEndFrame( ent ); } } // see if it is time to do a tournement restart CheckTournament(); // see if it is time to end the level CheckExitRules(); // update to team status? CheckTeamStatus(); // cancel vote if timed out CheckVote(); // check team votes CheckTeamVote( TEAM_RED ); CheckTeamVote( TEAM_BLUE ); // for tracking changes CheckCvars(); if (g_listEntity.integer) { for (i = 0; i < MAX_GENTITIES; i++) { G_Printf("%4i: %s\n", i, g_entities[i].classname); } trap_Cvar_Set("g_listEntity", "0"); } }
/* ================ G_RunFrame Advances the non-player objects in the world ================ */ void G_RunFrame( int levelTime ) { int i; // if we are waiting for the level to restart, do nothing if( theLevel.restarted_ ) return; theLevel.framenum_++; theLevel.previousTime_ = theLevel.time_; theLevel.time_ = levelTime; int msec = theLevel.time_ - theLevel.previousTime_; // get any cvar changes G_UpdateCvars(); // // go through all allocated objects // int start = Sys_Milliseconds(); GameEntity* ent = 0;//&g_entities[0]; for( i=0 ; i<theLevel.num_entities_ ; i++ ) { ent = theLevel.getEntity(i); if( !ent || !ent->inuse_ ) continue; // clear events that are too old if( theLevel.time_ - ent->eventTime_ > EVENT_VALID_MSEC ) { if( ent->s.event ) { ent->s.event = 0; // &= EV_EVENT_BITS; if( ent->client_ ) { ent->client_->ps_.externalEvent = 0; // predicted events should never be set to zero //ent->client->ps.events[0] = 0; //ent->client->ps.events[1] = 0; } } if( ent->freeAfterEvent_ ) { // tempEntities or dropped items completely go away after their event ent->freeUp();// former G_FreeEntity continue; } else if( ent->unlinkAfterEvent_ ) { // items that will respawn will hide themselves after their pickup event ent->unlinkAfterEvent_ = false; SV_UnlinkEntity( ent ); } } // temporary entities don't think if( ent->freeAfterEvent_ ) continue; if( ent->s.eType == ET_MISSILE || ent->s.eType == ET_BULLET ) { G_RunMissile( ent ); continue; } if( ent->s.eType == ET_ITEM || ent->physicsObject_ ) { G_RunItem( ent ); continue; } if( ent->s.eType == ET_MOVER ) { G_RunMover( ent ); continue; } if( ent->client_ ) { G_RunClient( ent ); continue; } G_RunThink( ent ); } int end = Sys_Milliseconds(); start = Sys_Milliseconds(); // perform final fixups on the players //ent = &g_entities[0]; for( i=1 ; i <= theLevel.maxclients_ ; i++ ) { ent = theLevel.getEntity(i); if( ent && ent->inuse_ ) ClientEndFrame( ent ); } end = Sys_Milliseconds(); // see if it is time to do a tournement restart CheckTournament(); // see if it is time to end the level CheckExitRules(); // update to team status? CheckTeamStatus(); // cancel vote if timed out CheckVote(); // check team votes CheckTeamVote( ClientBase::TEAM_RED ); CheckTeamVote( ClientBase::TEAM_BLUE ); // for tracking changes CheckCvars(); if( g_listEntity.integer ) { for( i = 0; i < MAX_GENTITIES; i++ ) { ent = theLevel.getEntity(i); Com_Printf("%4i: %s\n", i, ent->classname_); } Cvar_Set("g_listEntity", "0"); } }