void G_PlayerAward( edict_t *ent, const char *awardMsg ) { edict_t *other; char cmd[MAX_STRING_CHARS]; gameaward_t *ga; int i, size; score_stats_t *stats; if( !awardMsg || !awardMsg[0] || !ent->r.client ) return; Q_snprintfz( cmd, sizeof( cmd ), "aw \"%s\"", awardMsg ); trap_GameCmd( ent, cmd ); if( dedicated->integer ) G_Printf( "%s", COM_RemoveColorTokens( va( "%s receives a '%s' award.\n", ent->r.client->netname, awardMsg ) ) ); ent->r.client->level.stats.awards++; teamlist[ent->s.team].stats.awards++; G_Gametype_ScoreEvent( ent->r.client, "award", awardMsg ); stats = &ent->r.client->level.stats; if( !stats->awardAllocator ) stats->awardAllocator = LinearAllocator( sizeof( gameaward_t ), 0, _G_LevelMalloc, _G_LevelFree ); // ch : this doesnt work for race right? if( GS_MatchState() == MATCH_STATE_PLAYTIME || GS_MatchState() == MATCH_STATE_POSTMATCH ) { // ch : we store this locally to send to MM // first check if we already have this one on the clients list size = LA_Size( stats->awardAllocator ); ga = NULL; for( i = 0; i < size; i++ ) { ga = ( gameaward_t * )LA_Pointer( stats->awardAllocator, i ); if( !strncmp( ga->name, awardMsg, sizeof(ga->name)-1 ) ) break; } if( i >= size ) { ga = ( gameaward_t * )LA_Alloc( stats->awardAllocator ); memset( ga, 0, sizeof(*ga) ); ga->name = G_RegisterLevelString( awardMsg ); } if( ga ) ga->count++; } // add it to every player who's chasing this player for( other = game.edicts + 1; PLAYERNUM( other ) < gs.maxclients; other++ ) { if( !other->r.client || !other->r.inuse || !other->r.client->resp.chase.active ) continue; if( other->r.client->resp.chase.target == ENTNUM( ent ) ) trap_GameCmd( other, cmd ); } }
/* * Cmd_ShowStats_f */ static void Cmd_ShowStats_f( edict_t *ent ) { edict_t *target; if( trap_Cmd_Argc() > 2 ) { G_PrintMsg( ent, "Usage: stats [player]\n" ); return; } if( trap_Cmd_Argc() == 2 ) { target = G_PlayerForText( trap_Cmd_Argv( 1 ) ); if( target == NULL ) { G_PrintMsg( ent, "No such player\n" ); return; } } else { if( ent->r.client->resp.chase.active && game.edicts[ent->r.client->resp.chase.target].r.client ) target = &game.edicts[ent->r.client->resp.chase.target]; else target = ent; } if( target->s.team == TEAM_SPECTATOR ) { G_PrintMsg( ent, "No stats for spectators\n" ); return; } trap_GameCmd( ent, va( "plstats 1 \"%s\"", G_StatsMessage( target ) ) ); }
/* * G_Match_Autorecord_Stats */ void G_Match_Autorecord_Stats( void ) { edict_t *ent; for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients; ent++ ) { if( !ent->r.inuse || ent->s.team == TEAM_SPECTATOR || ( ent->r.svflags & SVF_FAKECLIENT ) ) continue; trap_GameCmd( ent, va( "plstats 2 \"%s\"", G_StatsMessage( ent ) ) ); } }
void G_PlayerAward( edict_t *ent, const char *awardMsg ) { edict_t *other, *third; if( !awardMsg || !awardMsg[0] || !ent->r.client ) return; trap_GameCmd( ent, va( "aw \"%s\"", awardMsg ) ); if( dedicated->integer ) G_Printf( "%s", COM_RemoveColorTokens( va( "%s receives a '%s' award.\n", ent->r.client->netname, awardMsg ) ) ); ent->r.client->level.stats.awards++; teamlist[ent->s.team].stats.awards++; G_Gametype_ScoreEvent( ent->r.client, "award", awardMsg ); // add it to every player who's chasing this player for( other = game.edicts + 1; PLAYERNUM( other ) < gs.maxclients; other++ ) { if( !other->r.client || !other->r.inuse || !other->r.client->resp.chase.active ) continue; if( other->r.client->resp.chase.target == ent->s.number ) { trap_GameCmd( other, va( "aw \"%s\"", awardMsg ) ); // someone could also be chase-caming the guy in the chasecam for( third = game.edicts + 1; PLAYERNUM( third ) < gs.maxclients; third++ ) { if( !third->r.client || !third->r.inuse || !third->r.client->resp.chase.active ) continue; if( third->r.client->resp.chase.target == other->s.number ) trap_GameCmd( third, va( "aw \"%s\"", awardMsg ) ); } } } }
/* * G_Teams_TDM_UpdateTeamInfoMessages */ void G_Teams_UpdateTeamInfoMessages( void ) { static int nexttime = 0; static char teammessage[MAX_STRING_CHARS]; edict_t *ent, *e; size_t len; int i, j, team; char entry[MAX_TOKEN_CHARS]; int locationTag; nexttime -= game.snapFrameTime; if( nexttime > 0 ) return; while( nexttime <= 0 ) nexttime += 2000; // time for a new update for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ ) { *teammessage = 0; Q_snprintfz( teammessage, sizeof( teammessage ), "ti \"" ); len = strlen( teammessage ); // add our team info to the string for( i = 0; i < teamlist[team].numplayers; i++ ) { ent = game.edicts + teamlist[team].playerIndices[i]; if( G_IsDead( ent ) ) // don't show dead players continue; if( ent->r.client->teamstate.is_coach ) // don't show coachs continue; // get location name locationTag = G_MapLocationTAGForOrigin( ent->s.origin ); if( locationTag == -1 ) continue; *entry = 0; Q_snprintfz( entry, sizeof( entry ), "%i %i %i %i ", PLAYERNUM( ent ), locationTag, HEALTH_TO_INT( ent->health ), ARMOR_TO_INT( ent->r.client->resp.armor ) ); if( MAX_STRING_CHARS - len > strlen( entry ) ) { Q_strncatz( teammessage, entry, sizeof( teammessage ) ); len = strlen( teammessage ); } } // add closing quote *entry = 0; Q_snprintfz( entry, sizeof( entry ), "\"" ); if( MAX_STRING_CHARS - len > strlen( entry ) ) { Q_strncatz( teammessage, entry, sizeof( teammessage ) ); len = strlen( teammessage ); } for( i = 0; i < teamlist[team].numplayers; i++ ) { ent = game.edicts + teamlist[team].playerIndices[i]; if( !ent->r.inuse || !ent->r.client ) continue; trap_GameCmd( ent, teammessage ); // see if there are spectators chasing this player and send them the layout too for( j = 0; j < teamlist[TEAM_SPECTATOR].numplayers; j++ ) { e = game.edicts + teamlist[TEAM_SPECTATOR].playerIndices[j]; if( !e->r.inuse || !e->r.client ) continue; if( e->r.client->resp.chase.active && e->r.client->resp.chase.target == ENTNUM( ent ) ) trap_GameCmd( e, teammessage ); } } } }
/* * G_MoveClientToTV * * Sends cmd to connect to a non-full TV server with round robin balancing */ void G_MoveClientToTV( edict_t *ent ) { int i; gclient_t *client, *best; static int last_tv = 0; bool isIPv6; char ip[MAX_INFO_VALUE]; int port; const char *p; if( !ent->r.client ) { return; } if( ent->r.svflags & SVF_FAKECLIENT ) { return; } if( ent->r.client->isTV ) { return; } best = NULL; for( i = 0; i < gs.maxclients; i++ ) { client = &game.clients[(last_tv + 1 + i) % gs.maxclients]; if( !client->isTV || client->connecting ) { // not a TV or not ready yet continue; } if( client->tv.numclients == client->tv.maxclients ) { // full continue; } if( !client->tv.channel ) { // invalid userinfo/channel number continue; } best = client; break; } if( !best ) { G_PrintMsg( ent, "Could not find a free TV server\n" ); return; } Q_strncpyz( ip, best->ip, sizeof( ip ) ); // check IP type p = strstr( ip, "::" ); isIPv6 = p != NULL; // strip port number from address string p = strrchr( ip, ':' ); if( p != NULL ) { ip[p - ip] = '\0'; } port = isIPv6 ? best->tv.port6 : best->tv.port; last_tv = best - game.clients; trap_GameCmd( ent, va( "memo tv_moveto \"%s\" %s:%hu#%i", COM_RemoveColorTokens( best->netname ), ip, port, best->tv.channel ) ); }
/* * Cmd_Upstate_f * * Update client on the state of things */ static void Cmd_Upstate_f( edict_t *ent ) { G_UpdatePlayerMatchMsg( ent, true ); G_SetPlayerHelpMessage( ent, ent->r.client->level.helpmessage, true ); trap_GameCmd( ent, va( "qm %s", ent->r.client->level.quickMenuItems ) ); }
/* * G_ClientUpdateScoreBoardMessage * * Show the scoreboard messages if the scoreboards are active */ void G_UpdateScoreBoardMessages( void ) { static int nexttime = 0; int i; edict_t *ent; gclient_t *client; bool forcedUpdate = false; char command[MAX_STRING_CHARS]; size_t maxlen, staticlen; // fixme : mess of copying maxlen = MAX_STRING_CHARS - ( strlen( "scb \"\"" + 4 ) ); if( game.asEngine != NULL ) GT_asCallScoreboardMessage( maxlen ); else G_Gametype_GENERIC_ScoreboardMessage(); G_ScoreboardMessage_AddSpectators(); staticlen = strlen( scoreboardString ); update: // send to players who have scoreboard visible for( i = 0; i < gs.maxclients; i++ ) { ent = game.edicts + 1 + i; if( !ent->r.inuse || !ent->r.client ) continue; client = ent->r.client; if( game.realtime <= client->level.scoreboard_time + scoreboardInterval ) continue; if( forcedUpdate || ( client->ps.stats[STAT_LAYOUTS] & STAT_LAYOUT_SCOREBOARD ) ) { scoreboardString[staticlen] = '\0'; if( client->resp.chase.active ) G_ScoreboardMessage_AddChasers( client->resp.chase.target, ENTNUM( ent ) ); else G_ScoreboardMessage_AddChasers( ENTNUM( ent ), ENTNUM( ent ) ); Q_snprintfz( command, sizeof( command ), "scb \"%s\"", scoreboardString ); client->level.scoreboard_time = game.realtime + scoreboardInterval - ( game.realtime%scoreboardInterval ); trap_GameCmd( ent, command ); trap_GameCmd( ent, G_PlayerStatsMessage( ent ) ); } } if( !forcedUpdate ) { // every 10 seconds, send everyone the scoreboard nexttime -= game.snapFrameTime; if( nexttime > 0 ) return; do { nexttime += 10000; } while( nexttime <= 0 ); forcedUpdate = true; goto update; } }
/* * G_ClientUpdateScoreBoardMessage * * Show the scoreboard messages if the scoreboards are active */ void G_UpdateScoreBoardMessages( void ) { static int nexttime = 0; int i; edict_t *ent; gclient_t *client; char *scoreBoardMessage = ""; qboolean forcedUpdate = qfalse; char string[MAX_STRING_CHARS]; size_t maxlen; // fixme : mess of copying maxlen = MAX_STRING_CHARS - ( strlen( "scb \"\"" + 4 ) ); if( level.gametype.asEngineHandle >= 0 ) scoreBoardMessage = G_asCallScoreboardMessage( maxlen ); else scoreBoardMessage = G_Gametype_GENERIC_ScoreboardMessage(); G_ScoreboardMessage_AddSpectators(); Q_strncpyz( string, scoreBoardMessage ? scoreBoardMessage : "", maxlen ); Q_snprintfz( scoreboardString, sizeof( scoreboardString ), "scb \"%s\"", string ); scoreBoardMessage = scoreboardString; update: // send to players who have scoreboard visible for( i = 0; i < gs.maxclients; i++ ) { ent = game.edicts + 1 + i; if( !ent->r.inuse || !ent->r.client ) continue; client = ent->r.client; if( game.realtime <= client->level.scoreboard_time + scoreboardInterval ) continue; if( forcedUpdate || ( client->ps.stats[STAT_LAYOUTS] & STAT_LAYOUT_SCOREBOARD ) ) { client->level.scoreboard_time = game.realtime + scoreboardInterval - ( game.realtime%scoreboardInterval ); trap_GameCmd( ent, scoreBoardMessage ); trap_GameCmd( ent, G_PlayerStatsMessage( ent ) ); } } if( !forcedUpdate ) { // every 10 seconds, send everyone the scoreboard nexttime -= game.snapFrameTime; if( nexttime > 0 ) return; do { nexttime += 10000; } while( nexttime <= 0 ); forcedUpdate = qtrue; goto update; } }