/* * G_Teams_Invite_f */ void G_Teams_Invite_f( edict_t *ent ) { char *text; edict_t *toinvite; int team; if( ( !ent->r.inuse || !ent->r.client ) ) return; text = trap_Cmd_Argv( 1 ); if( !text || !strlen( text ) ) { int i; edict_t *e; char msg[1024]; msg[0] = 0; Q_strncatz( msg, "Usage: invite <player>\n", sizeof( msg ) ); Q_strncatz( msg, "- List of current players:\n", sizeof( msg ) ); for( i = 0, e = game.edicts+1; i < gs.maxclients; i++, e++ ) { if( !e->r.inuse ) continue; Q_strncatz( msg, va( "%3i: %s\n", PLAYERNUM( e ), e->r.client->netname ), sizeof( msg ) ); } G_PrintMsg( ent, "%s", msg ); return; } team = ent->s.team; if( !G_Teams_TeamIsLocked( team ) ) { G_PrintMsg( ent, "Your team is not locked.\n" ); return; } toinvite = G_PlayerForText( text ); if( !toinvite ) { G_PrintMsg( ent, "No such player.\n" ); return; } if( G_Teams_PlayerIsInvited( team, toinvite ) ) { G_PrintMsg( ent, "%s%s is already invited to your team.\n", toinvite->r.client->netname, S_COLOR_WHITE ); return; } G_Teams_InvitePlayer( team, toinvite ); G_PrintMsg( NULL, "%s%s invited %s%s to team %s%s.\n", ent->r.client->netname, S_COLOR_WHITE, toinvite->r.client->netname, S_COLOR_WHITE, GS_TeamName( team ), S_COLOR_WHITE ); }
/* * Cmd_ChaseCam_f */ void Cmd_ChaseCam_f( edict_t *ent ) { bool team_only; const char *arg1; if( ent->s.team != TEAM_SPECTATOR && !ent->r.client->teamstate.is_coach ) { G_Teams_JoinTeam( ent, TEAM_SPECTATOR ); if( !CheckFlood( ent, false ) ) { // prevent 'joined spectators' spam G_PrintMsg( NULL, "%s%s joined the %s%s team.\n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ), S_COLOR_WHITE ); } } // & 1 = scorelead // & 2 = powerups // & 4 = objectives // & 8 = fragger if( ent->r.client->teamstate.is_coach && GS_TeamBasedGametype() ) { team_only = true; } else { team_only = false; } arg1 = trap_Cmd_Argv( 1 ); if( trap_Cmd_Argc() < 2 ) { G_ChasePlayer( ent, NULL, team_only, 0 ); } else if( !Q_stricmp( arg1, "auto" ) ) { G_PrintMsg( ent, "Chasecam mode is 'auto'. It will follow the score leader when no powerup nor flag is carried.\n" ); G_ChasePlayer( ent, NULL, team_only, 7 ); } else if( !Q_stricmp( arg1, "carriers" ) ) { G_PrintMsg( ent, "Chasecam mode is 'carriers'. It will switch to flag or powerup carriers when any of these items is picked up.\n" ); G_ChasePlayer( ent, NULL, team_only, 6 ); } else if( !Q_stricmp( arg1, "powerups" ) ) { G_PrintMsg( ent, "Chasecam mode is 'powerups'. It will switch to powerup carriers when any of these items is picked up.\n" ); G_ChasePlayer( ent, NULL, team_only, 2 ); } else if( !Q_stricmp( arg1, "objectives" ) ) { G_PrintMsg( ent, "Chasecam mode is 'objectives'. It will switch to objectives carriers when any of these items is picked up.\n" ); G_ChasePlayer( ent, NULL, team_only, 4 ); } else if( !Q_stricmp( arg1, "score" ) ) { G_PrintMsg( ent, "Chasecam mode is 'score'. It will always follow the player with the best score.\n" ); G_ChasePlayer( ent, NULL, team_only, 1 ); } else if( !Q_stricmp( arg1, "fragger" ) ) { G_PrintMsg( ent, "Chasecam mode is 'fragger'. The last fragging player will be followed.\n" ); G_ChasePlayer( ent, NULL, team_only, 8 ); } else if( !Q_stricmp( arg1, "help" ) ) { G_PrintMsg( ent, "Chasecam modes:\n" ); G_PrintMsg( ent, "- 'auto': Chase the score leader unless there's an objective carrier or a powerup carrier.\n" ); G_PrintMsg( ent, "- 'carriers': User has pov control unless there's an objective carrier or a powerup carrier.\n" ); G_PrintMsg( ent, "- 'objectives': User has pov control unless there's an objective carrier.\n" ); G_PrintMsg( ent, "- 'powerups': User has pov control unless there's a flag carrier.\n" ); G_PrintMsg( ent, "- 'score': Always follow the score leader. User has no pov control.\n" ); G_PrintMsg( ent, "- 'none': Disable chasecam.\n" ); return; } else { G_ChasePlayer( ent, arg1, team_only, 0 ); } G_Teams_LeaveChallengersQueue( ent ); }
/* * G_Teams_JoinTeam - checks that client can join the given team and then joins it */ bool G_Teams_JoinTeam( edict_t *ent, int team ) { int error; G_Teams_UpdateMembersList(); // make sure we have up-to-date data if( !ent->r.client ) return false; if( ( error = G_GameTypes_DenyJoinTeam( ent, team ) ) ) { if( error == ER_TEAM_INVALID ) { G_PrintMsg( ent, "Can't join %s in %s\n", GS_TeamName( team ), gs.gametypeName ); } else if( error == ER_TEAM_CHALLENGERS ) { G_Teams_JoinChallengersQueue( ent ); } else if( error == ER_TEAM_FULL ) { G_PrintMsg( ent, "Team %s is FULL\n", GS_TeamName( team ) ); G_Teams_JoinChallengersQueue( ent ); } else if( error == ER_TEAM_LOCKED ) { G_PrintMsg( ent, "Team %s is LOCKED\n", GS_TeamName( team ) ); G_Teams_JoinChallengersQueue( ent ); } else if( error == ER_TEAM_MATCHSTATE ) { G_PrintMsg( ent, "Can't join %s at this moment\n", GS_TeamName( team ) ); } else if( error == ER_TEAM_UNEVEN ) { G_PrintMsg( ent, "Can't join %s because of uneven teams\n", GS_TeamName( team ) ); // FIXME: need more suitable message :P G_Teams_JoinChallengersQueue( ent ); } return false; } //ok, can join, proceed G_Teams_SetTeam( ent, team ); return true; }
void AiBaseTeamBrain::Debug( const char *format, ... ) { // Cut it early to help optimizer to eliminate AI_Debugv call #ifdef _DEBUG va_list va; va_start( va, format ); AI_Debugv( GS_TeamName( team ), format, va ); va_end( va ); #endif }
void G_Teams_Coach( edict_t *ent ) { if( GS_TeamBasedGametype() && !GS_InvidualGameType() && ent->s.team != TEAM_SPECTATOR ) { if( !teamlist[ent->s.team].has_coach ) { if( GS_MatchState() > MATCH_STATE_WARMUP && !GS_MatchPaused() ) { G_PrintMsg( ent, "Can't set coach mode with the match in progress\n" ); } else { // move to coach mode ent->r.client->teamstate.is_coach = true; G_GhostClient( ent ); ent->health = ent->max_health; ent->deadflag = DEAD_NO; G_ChasePlayer( ent, NULL, true, 0 ); //clear up his scores G_Match_Ready( ent ); // set ready and check readys memset( &ent->r.client->level.stats, 0, sizeof( ent->r.client->level.stats ) ); teamlist[ent->s.team].has_coach = true; G_PrintMsg( NULL, "%s%s is now team %s coach \n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ) ); } } else if( ent->r.client->teamstate.is_coach ) { // if you are this team coach, resign ent->r.client->teamstate.is_coach = false; G_PrintMsg( NULL, "%s%s is no longer team %s coach \n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ) ); G_Teams_SetTeam( ent, ent->s.team ); } else G_PrintMsg( ent, "Your team already has a coach.\n" ); } else G_PrintMsg( ent, "Coaching only valid while on a team in Team based Gametypes.\n" ); }
/* * G_Teams_Join_Cmd */ void G_Teams_Join_Cmd( edict_t *ent ) { char *t; int team; if( !ent->r.client || trap_GetClientState( PLAYERNUM( ent ) ) < CS_SPAWNED ) return; t = trap_Cmd_Argv( 1 ); if( !t || *t == 0 ) { G_Teams_JoinAnyTeam( ent, false ); return; } team = GS_Teams_TeamFromName( t ); if( team != -1 ) { if( team == TEAM_SPECTATOR ) { // special handling for spectator team Cmd_Spec_f( ent ); return; } if( team == ent->s.team ) { G_PrintMsg( ent, "You are already in %s team\n", GS_TeamName( team ) ); return; } if( G_Teams_JoinTeam( ent, team ) ) { G_PrintMsg( NULL, "%s%s joined the %s%s team.\n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ), S_COLOR_WHITE ); return; } } else { G_PrintMsg( ent, "No such team.\n" ); return; } }
void G_Teams_CoachUnLockTeam( edict_t *ent ) { if( ent->r.client->teamstate.is_coach ) { if( G_Teams_TeamIsLocked( ent->s.team ) ) { G_Teams_UnLockTeam( ent->s.team ); G_PrintMsg( NULL, "%s%s unlocked the %s team.\n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ) ); } } }
/* * G_SpectatorMode */ void G_SpectatorMode( edict_t *ent ) { // join spectator team if( ent->s.team != TEAM_SPECTATOR ) { G_Teams_JoinTeam( ent, TEAM_SPECTATOR ); G_PrintMsg( NULL, "%s%s joined the %s%s team.\n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ), S_COLOR_WHITE ); } // was in chasecam if( ent->r.client->resp.chase.active ) { ent->r.client->level.showscores = false; G_Chase_SetChaseActive( ent, false ); // reset movement speeds ent->r.client->ps.pmove.stats[PM_STAT_MAXSPEED] = DEFAULT_PLAYERSPEED; ent->r.client->ps.pmove.stats[PM_STAT_JUMPSPEED] = DEFAULT_JUMPSPEED; ent->r.client->ps.pmove.stats[PM_STAT_DASHSPEED] = DEFAULT_DASHSPEED; } ent->movetype = MOVETYPE_NOCLIP; }
/* * SCR_DrawTeamTab */ static int SCR_DrawTeamTab( const char **ptrptr, int *curteam, int x, int y, int panelWidth, struct qfontface_s *font, struct qfontface_s *titleFont, int pass ) { const char *token; const char *layout, *titles; char type; int team, team_score, team_ping; int yoffset = 0, xoffset = 0; int dir = 0, align, width, height; vec4_t teamcolor = { 0.0f, 0.0f, 0.0f, 1.0f }, pingcolor; // team tab is always the same. Sets the current team and draws its score if( !(*ptrptr) || !(*ptrptr[0]) || *ptrptr[0] == '&' ) return yoffset; team = CG_ParseValue( ptrptr ); if( team < TEAM_PLAYERS || team > TEAM_BETA ) CG_Error( "SCR_ParseTeamTab: Invalid team value\n" ); *curteam = team; if( *ptrptr[0] == '&' ) return yoffset; team_score = CG_ParseValue( ptrptr ); if( *ptrptr[0] == '&' ) return yoffset; team_ping = CG_ParseValue( ptrptr ); if( ( team == TEAM_ALPHA ) || ( team == TEAM_BETA ) ) CG_TeamColor( team, teamcolor ); teamcolor[3] = SCB_BACKGROUND_ALPHA; // make transparent if( GS_TeamBasedGametype() ) // we only draw the team tabs in team based gametypes { dir = ( team == TEAM_ALPHA ) ? -1 : 1; align = ( team == TEAM_ALPHA ) ? ALIGN_RIGHT_TOP : ALIGN_LEFT_TOP; // draw the tab xoffset = ( SCB_CENTERMARGIN * dir ); width = ( cgs.vidWidth * 0.5 ) - SCB_CENTERMARGIN; height = trap_SCR_FontHeight( titleFont ) + 2; if( !pass ) { CG_DrawAlignPic( x + xoffset, y + yoffset + SCB_SCORENUMBER_SIZE - height, width, height, align, teamcolor, cgs.shaderWhite ); } if( pass ) { xoffset += ( ( 16 * cgs.vidHeight / 600 ) * dir ); CG_DrawHUDNumeric( x + xoffset, y + yoffset, align, colorWhite, SCB_SCORENUMBER_SIZE, SCB_SCORENUMBER_SIZE, team_score ); xoffset += ( ( SCB_SCORENUMBER_SIZE * strlen(va("%i", team_score)) + ( 16 * cgs.vidHeight / 600 ) ) * dir ); trap_SCR_DrawStringWidth( x + xoffset + ( ( SCB_TINYFIELD_PIXELWIDTH + ( 16 * cgs.vidHeight / 600 ) ) * dir ), y + yoffset + SCB_SCORENUMBER_SIZE - (trap_SCR_FontHeight( titleFont ) + 1), align, GS_TeamName( team ), SCB_TEAMNAME_PIXELWIDTH, titleFont, colorWhite ); CG_PingColor( team_ping, pingcolor ); trap_SCR_DrawStringWidth( x + xoffset, y + yoffset + SCB_SCORENUMBER_SIZE - (trap_SCR_FontHeight( font ) + 1), align, va( "%i", team_ping ), SCB_TINYFIELD_PIXELWIDTH, font, pingcolor ); } yoffset += SCB_SCORENUMBER_SIZE; } else { dir = 0; align = ALIGN_CENTER_TOP; } // draw the player tab column titles layout = cgs.configStrings[CS_SCB_PLAYERTAB_LAYOUT]; titles = cgs.configStrings[CS_SCB_PLAYERTAB_TITLES]; height = trap_SCR_FontHeight( font ); // start from the center again xoffset = CG_HorizontalAlignForWidth( 0, align, panelWidth ); xoffset += ( SCB_CENTERMARGIN * dir ); while( ( token = SCR_GetNextColumnLayout( &layout, &titles, &type, &width, font ) ) != NULL ) { if( SCR_SkipColumn( type ) ) continue; if( width ) { if( pass ) { trap_SCR_DrawClampString( x + xoffset, y + yoffset, CG_TranslateString( token ), x + xoffset, y + yoffset, x + xoffset + width, y + yoffset + height, font, colorWhite ); } xoffset += width; } } yoffset += trap_SCR_FontHeight( font ); return yoffset; }
/* * G_Teams_JoinAnyTeam - find us a team since we are too lazy to do ourselves */ bool G_Teams_JoinAnyTeam( edict_t *ent, bool silent ) { int best_numplayers = gs.maxclients + 1, best_score = 999999; int i, team = -1; bool wasinqueue = ( ent->r.client->queueTimeStamp != 0 ); G_Teams_UpdateMembersList(); // make sure we have up-to-date data //depending on the gametype, of course if( !GS_TeamBasedGametype() ) { if( ent->s.team == TEAM_PLAYERS ) { if( !silent ) { G_PrintMsg( ent, "You are already in %s team\n", GS_TeamName( TEAM_PLAYERS ) ); } return false; } if( G_Teams_JoinTeam( ent, TEAM_PLAYERS ) ) { if( !silent ) { G_PrintMsg( NULL, "%s%s joined the %s team.\n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ) ); } } return true; } else { //team based //find the available team with smaller player count or worse score for( i = TEAM_ALPHA; i < GS_MAX_TEAMS; i++ ) { if( G_GameTypes_DenyJoinTeam( ent, i ) ) { continue; } if( team == -1 || teamlist[i].numplayers < best_numplayers || ( teamlist[i].numplayers == best_numplayers && teamlist[i].stats.score < best_score ) ) { best_numplayers = teamlist[i].numplayers; best_score = teamlist[i].stats.score; team = i; } } if( team == ent->s.team ) { // he is at the right team if( !silent ) { G_PrintMsg( ent, "%sCouldn't find a better team than team %s.\n", S_COLOR_WHITE, GS_TeamName( ent->s.team ) ); } return false; } if( team != -1 ) { if( G_Teams_JoinTeam( ent, team ) ) { if( !silent ) { G_PrintMsg( NULL, "%s%s joined the %s team.\n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ) ); } return true; } } if( GS_MatchState() <= MATCH_STATE_PLAYTIME && !silent ) G_Teams_JoinChallengersQueue( ent ); } // don't print message if we joined the queue if( !silent && ( !GS_HasChallengers() || wasinqueue || !ent->r.client->queueTimeStamp ) ) G_PrintMsg( ent, "You can't join the game now\n" ); return false; }
/* * G_UpdateServerInfo * update the cvars which show the match state at server browsers */ static void G_UpdateServerInfo( void ) { // g_match_time if( GS_MatchState() <= MATCH_STATE_WARMUP ) { trap_Cvar_ForceSet( "g_match_time", "Warmup" ); } else if( GS_MatchState() == MATCH_STATE_COUNTDOWN ) { trap_Cvar_ForceSet( "g_match_time", "Countdown" ); } else if( GS_MatchState() == MATCH_STATE_PLAYTIME ) { // partly from G_GetMatchState char extra[MAX_INFO_VALUE]; int clocktime, timelimit, mins, secs; if( GS_MatchDuration() ) timelimit = ( ( GS_MatchDuration() ) * 0.001 ) / 60; else timelimit = 0; clocktime = (float)( game.serverTime - GS_MatchStartTime() ) * 0.001f; if( clocktime <= 0 ) { mins = 0; secs = 0; } else { mins = clocktime / 60; secs = clocktime - mins * 60; } extra[0] = 0; if( GS_MatchExtended() ) { if( timelimit ) Q_strncatz( extra, " overtime", sizeof( extra ) ); else Q_strncatz( extra, " suddendeath", sizeof( extra ) ); } if( GS_MatchPaused() ) Q_strncatz( extra, " (in timeout)", sizeof( extra ) ); if( timelimit ) trap_Cvar_ForceSet( "g_match_time", va( "%02i:%02i / %02i:00%s", mins, secs, timelimit, extra ) ); else trap_Cvar_ForceSet( "g_match_time", va( "%02i:%02i%s", mins, secs, extra ) ); } else { trap_Cvar_ForceSet( "g_match_time", "Finished" ); } // g_match_score if( GS_MatchState() >= MATCH_STATE_PLAYTIME && GS_TeamBasedGametype() ) { char score[MAX_INFO_STRING]; score[0] = 0; Q_strncatz( score, va( " %s: %i", GS_TeamName( TEAM_ALPHA ), teamlist[TEAM_ALPHA].stats.score ), sizeof( score ) ); Q_strncatz( score, va( " %s: %i", GS_TeamName( TEAM_BETA ), teamlist[TEAM_BETA].stats.score ), sizeof( score ) ); if( strlen( score ) >= MAX_INFO_VALUE ) { // prevent "invalid info cvar value" flooding score[0] = '\0'; } trap_Cvar_ForceSet( "g_match_score", score ); } else { trap_Cvar_ForceSet( "g_match_score", "" ); } // g_needpass if( password->modified ) { if( password->string && strlen( password->string ) ) { trap_Cvar_ForceSet( "g_needpass", "1" ); } else { trap_Cvar_ForceSet( "g_needpass", "0" ); } password->modified = false; } // g_gametypes_available if( g_votable_gametypes->modified || g_disable_vote_gametype->modified ) { if( g_disable_vote_gametype->integer || !g_votable_gametypes->string || !strlen( g_votable_gametypes->string ) ) { trap_Cvar_ForceSet( "g_gametypes_available", "" ); } else { char *votable; char *name; size_t len; int count; len = 0; for( count = 0; ( name = G_ListNameForPosition( g_gametypes_list->string, count, CHAR_GAMETYPE_SEPARATOR ) ) != NULL; count++ ) { if( G_Gametype_IsVotable( name ) ) len += strlen( name ) + 1; } len++; votable = ( char * )G_Malloc( len ); votable[0] = 0; for( count = 0; ( name = G_ListNameForPosition( g_gametypes_list->string, count, CHAR_GAMETYPE_SEPARATOR ) ) != NULL; count++ ) { if( G_Gametype_IsVotable( name ) ) { Q_strncatz( votable, name, len ); Q_strncatz( votable, " ", len ); } } //votable[ strlen( votable )-2 ] = 0; // remove the last space trap_Cvar_ForceSet( "g_gametypes_available", votable ); G_Free( votable ); } g_votable_gametypes->modified = false; g_disable_vote_gametype->modified = false; } if( GS_RaceGametype() ) { trap_Cvar_ForceSet( "g_race_gametype", "1" ); } else { trap_Cvar_ForceSet( "g_race_gametype", "0" ); } }
/* * Cmd_ChaseCam_f */ void Cmd_ChaseCam_f( edict_t *ent ) { qboolean team_only; if( ent->s.team != TEAM_SPECTATOR && !ent->r.client->teamstate.is_coach ) { G_Teams_JoinTeam( ent, TEAM_SPECTATOR ); G_PrintMsg( NULL, "%s%s joined the %s%s team.\n", ent->r.client->netname, S_COLOR_WHITE, GS_TeamName( ent->s.team ), S_COLOR_WHITE ); } // & 1 = scorelead // & 2 = powerups // & 4 = flags if( ent->r.client->teamstate.is_coach && GS_TeamBasedGametype() ) team_only = qtrue; else team_only = qfalse; if( trap_Cmd_Argc() < 2 ) { G_ChasePlayer( ent, NULL, team_only, 0 ); } else if( !Q_stricmp( trap_Cmd_Argv( 1 ), "auto" ) ) { G_PrintMsg( ent, "Chasecam mode is 'auto'. It will follow the score leader when no powerup nor flag is carried.\n" ); G_ChasePlayer( ent, NULL, team_only, 7 ); } else if( !Q_stricmp( trap_Cmd_Argv( 1 ), "carriers" ) ) { G_PrintMsg( ent, "Chasecam mode is 'carriers'. It will switch to flag or powerup carriers when any of these items is picked up.\n" ); G_ChasePlayer( ent, NULL, team_only, 6 ); } else if( !Q_stricmp( trap_Cmd_Argv( 1 ), "powerups" ) ) { G_PrintMsg( ent, "Chasecam mode is 'powerups'. It will switch to powerup carriers when any of these items is picked up.\n" ); G_ChasePlayer( ent, NULL, team_only, 2 ); } else if( !Q_stricmp( trap_Cmd_Argv( 1 ), "objectives" ) ) { G_PrintMsg( ent, "Chasecam mode is 'objectives'. It will switch to objectives carriers when any of these items is picked up.\n" ); G_ChasePlayer( ent, NULL, team_only, 4 ); } else if( !Q_stricmp( trap_Cmd_Argv( 1 ), "score" ) ) { G_PrintMsg( ent, "Chasecam mode is 'score'. It will always follow the highest fragger.\n" ); G_ChasePlayer( ent, NULL, team_only, 1 ); } else if( !Q_stricmp( trap_Cmd_Argv( 1 ), "help" ) ) { G_PrintMsg( ent, "Chasecam modes:\n" ); G_PrintMsg( ent, "- 'auto': Chase the score leader unless there's an objective carrier or a powerup carrier.\n" ); G_PrintMsg( ent, "- 'carriers': User has pov control unless there's an objective carrier or a powerup carrier.\n" ); G_PrintMsg( ent, "- 'objectives': User has pov control unless there's an objective carrier.\n" ); G_PrintMsg( ent, "- 'powerups': User has pov control unless there's a flag carrier.\n" ); G_PrintMsg( ent, "- 'score': Always follow the score leader. User has no pov control.\n" ); G_PrintMsg( ent, "- 'none': Disable chasecam.\n" ); return; } else { G_ChasePlayer( ent, trap_Cmd_Argv( 1 ), team_only, 0 ); } G_Teams_LeaveChallengersQueue( ent ); }