/* * G_EndServerFrames_UpdateChaseCam */ void G_EndServerFrames_UpdateChaseCam( void ) { int i, team; edict_t *ent; // do it by teams, so spectators can copy the chasecam information from players for( team = TEAM_PLAYERS; team < GS_MAX_TEAMS; team++ ) { for( i = 0; i < teamlist[team].numplayers; i++ ) { ent = game.edicts + teamlist[team].playerIndices[i]; if( trap_GetClientState( PLAYERNUM(ent) ) < CS_SPAWNED ) { G_Chase_SetChaseActive( ent, false ); continue; } G_EndFrame_UpdateChaseCam( ent ); } } // Do spectators last team = TEAM_SPECTATOR; for( i = 0; i < teamlist[team].numplayers; i++ ) { ent = game.edicts + teamlist[team].playerIndices[i]; if( trap_GetClientState( PLAYERNUM(ent) ) < CS_SPAWNED ) { G_Chase_SetChaseActive( ent, false ); continue; } G_EndFrame_UpdateChaseCam( ent ); } }
/* ================= UI_ResetMenu ================= */ void UI_ResetMenu(void) { uiClientState_t cstate; int n1, n2, n3; int l1, l2, l3; // zero set all our globals memset( &s_reset, 0, sizeof(s_reset) ); Reset_Cache(); n1 = UI_ProportionalStringWidth( "YES/NO" ); n2 = UI_ProportionalStringWidth( "YES" ) + PROP_GAP_WIDTH; n3 = UI_ProportionalStringWidth( "/" ) + PROP_GAP_WIDTH; l1 = 320 - ( n1 / 2 ); l2 = l1 + n2; l3 = l2 + n3; s_reset.slashX = l2; s_reset.menu.draw = Reset_MenuDraw; s_reset.menu.key = Reset_MenuKey; s_reset.menu.wrapAround = qtrue; trap_GetClientState( &cstate ); if ( cstate.connState >= CA_CONNECTED ) { // float on top of running game s_reset.menu.fullscreen = qfalse; } else { // game not running s_reset.menu.fullscreen = qtrue; } s_reset.yes.generic.type = MTYPE_PTEXT; s_reset.yes.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; s_reset.yes.generic.callback = Reset_MenuEvent; s_reset.yes.generic.id = ID_YES; s_reset.yes.generic.x = l1; s_reset.yes.generic.y = 264; s_reset.yes.string = "YES"; s_reset.yes.color = color_red; s_reset.yes.style = UI_LEFT; s_reset.no.generic.type = MTYPE_PTEXT; s_reset.no.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; s_reset.no.generic.callback = Reset_MenuEvent; s_reset.no.generic.id = ID_NO; s_reset.no.generic.x = l3; s_reset.no.generic.y = 264; s_reset.no.string = "NO"; s_reset.no.color = color_red; s_reset.no.style = UI_LEFT; Menu_AddItem( &s_reset.menu, &s_reset.yes ); Menu_AddItem( &s_reset.menu, &s_reset.no ); UI_PushMenu( &s_reset.menu ); Menu_SetCursorToItem( &s_reset.menu, &s_reset.no ); }
/* * G_Chase_IsValidTarget */ static bool G_Chase_IsValidTarget( edict_t *ent, edict_t *target, bool teamonly ) { if( !ent || !target ) { return false; } if( !target->r.inuse || !target->r.client || trap_GetClientState( PLAYERNUM( target ) ) < CS_SPAWNED ) { return false; } if( target->s.team < TEAM_PLAYERS || target->s.team >= GS_MAX_TEAMS || target == ent ) { return false; } if( teamonly && !ent->r.client->teamstate.is_coach && G_ISGHOSTING( target ) ) { return false; } if( teamonly && target->s.team != ent->s.team ) { return false; } if( G_ISGHOSTING( target ) && !target->deadflag && target->s.team != TEAM_SPECTATOR ) { return false; // ghosts that are neither dead, nor speccing (probably originating from gt-specific rules) } return true; }
void G_ScoreboardMessage_AddChasers( int entnum, int entnum_self ) { char entry[MAX_TOKEN_CHARS]; int i; edict_t *e; size_t len; len = strlen( scoreboardString ); if( !len ) return; // add personal spectators Q_strncpyz( entry, "&y ", sizeof( entry ) ); ADD_SCOREBOARD_ENTRY( scoreboardString, len, entry ); for( i = 0; i < teamlist[TEAM_SPECTATOR].numplayers; i++ ) { e = game.edicts + teamlist[TEAM_SPECTATOR].playerIndices[i]; if( ENTNUM( e ) == entnum_self ) continue; if( e->r.client->connecting || trap_GetClientState( PLAYERNUM( e ) ) < CS_SPAWNED ) continue; if( !e->r.client->resp.chase.active || e->r.client->resp.chase.target != entnum ) continue; Q_snprintfz( entry, sizeof( entry ), "%i ", PLAYERNUM( e ) ); ADD_SCOREBOARD_ENTRY( scoreboardString, len, entry ); } }
/* * G_Teams_JoinChallengersQueue */ void G_Teams_JoinChallengersQueue( edict_t *ent ) { int pos = 0; edict_t *e; if( !GS_HasChallengers() ) { ent->r.client->queueTimeStamp = 0; return; } if( ent->s.team != TEAM_SPECTATOR ) return; // enter the challengers queue if( !ent->r.client->queueTimeStamp ) { // enter the line ent->r.client->queueTimeStamp = game.realtime; for( e = game.edicts + 1; PLAYERNUM( e ) < gs.maxclients; e++ ) { if( !e->r.inuse || !e->r.client || trap_GetClientState( PLAYERNUM(e) ) < CS_SPAWNED ) continue; if( !e->r.client->queueTimeStamp || e->s.team != TEAM_SPECTATOR ) continue; // if there are other players with the same timestamp, increase ours if( e->r.client->queueTimeStamp >= ent->r.client->queueTimeStamp ) ent->r.client->queueTimeStamp = e->r.client->queueTimeStamp+1; if( e->r.client->queueTimeStamp < ent->r.client->queueTimeStamp ) pos++; } G_PrintMsg( ent, "%sYou entered the challengers queue in position %i\n", S_COLOR_CYAN, pos+1 ); G_UpdatePlayerMatchMsg( ent ); } }
/* =============== UI_TeamOrdersMenu_f =============== */ void UI_TeamOrdersMenu_f(void) { uiClientState_t cs; char info[MAX_INFO_STRING]; int team; // make sure it's a team game trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); teamOrdersMenuInfo.gametype = atoi(Info_ValueForKey(info, "g_gametype")); if (teamOrdersMenuInfo.gametype < GT_TEAM) { return; } // not available to spectators trap_GetClientState(&cs); trap_GetConfigString(CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING); team = atoi(Info_ValueForKey(info, "t")); if (team == TEAM_SPECTATOR) { return; } UI_TeamOrdersMenu(); }
/* * ClientCommand */ void ClientCommand( edict_t *ent ) { char *cmd; int i; if( !ent->r.client || trap_GetClientState( PLAYERNUM( ent ) ) < CS_SPAWNED ) return; // not fully in game yet cmd = trap_Cmd_Argv( 0 ); if( Q_stricmp( cmd, "cvarinfo" ) ) // skip cvarinfo cmds because they are automatic responses G_Client_UpdateActivity( ent->r.client ); // activity detected for( i = 0; i < MAX_GAMECOMMANDS; i++ ) { if( !g_Commands[i].name[0] ) break; if( !Q_stricmp( g_Commands[i].name, cmd ) ) { if( g_Commands[i].func ) g_Commands[i].func( ent ); else GT_asCallGameCommand( ent->r.client, cmd, trap_Cmd_Args(), trap_Cmd_Argc() - 1 ); return; } } G_PrintMsg( ent, "Bad user command: %s\n", cmd ); }
/* * TVM_ClientBegin * * called when a client has finished connecting, and is ready * to be placed into the game. This will happen every level load. */ void TVM_ClientBegin( tvm_relay_t *relay, edict_t *ent ) { edict_t *spot, *other; int i, specs; char hostname[MAX_CONFIGSTRING_CHARS]; assert( ent && ent->local && ent->r.client ); //TVM_Printf( "Begin: %s\n", ent->r.client->pers.netname ); ent->r.client->pers.connecting = false; spot = TVM_SelectSpawnPoint( ent ); if( spot ) { VectorCopy( spot->s.origin, ent->s.origin ); VectorCopy( spot->s.origin, ent->s.old_origin ); VectorCopy( spot->s.angles, ent->s.angles ); VectorCopy( spot->s.origin, ent->r.client->ps.pmove.origin ); VectorCopy( spot->s.angles, ent->r.client->ps.viewangles ); } else { VectorClear( ent->s.origin ); VectorClear( ent->s.old_origin ); VectorClear( ent->s.angles ); VectorClear( ent->r.client->ps.pmove.origin ); VectorClear( ent->r.client->ps.viewangles ); } ent->s.teleported = true; // set the delta angle for( i = 0; i < 3; i++ ) ent->r.client->ps.pmove.delta_angles[i] = ANGLE2SHORT( ent->s.angles[i] ) - ent->r.client->pers.cmd_angles[i]; specs = 0; for( i = 0; i < relay->local_maxclients; i++ ) { other = relay->local_edicts + i; if( other == ent ) continue; if( !other->r.inuse || !other->r.client ) continue; if( trap_GetClientState( relay, PLAYERNUM( other ) ) != CS_SPAWNED ) continue; specs++; } Q_strncpyz( hostname, relay->configStrings[CS_HOSTNAME], sizeof( hostname ) ); TVM_PrintMsg( relay, ent, S_COLOR_ORANGE "Welcome to %s! There %s currently %i spectator%s on this channel.\n", COM_RemoveColorTokens( hostname ), (specs == 1 ? "is" : "are"), specs, (specs == 1 ? "" : "s") ); TVM_PrintMsg( relay, ent, S_COLOR_ORANGE "For more information about chase camera modes type 'chase help' at console.\n" ); if( ent->r.client->chase.active ) TVM_ChaseClientEndSnapFrame( ent ); else TVM_ClientEndSnapFrame( ent ); }
/* * G_ClientEndSnapFrame * * Called for each player at the end of the server frame * and right after spawning */ void G_ClientEndSnapFrame( edict_t *ent ) { gclient_t *client; int i; if( trap_GetClientState( PLAYERNUM( ent ) ) < CS_SPAWNED ) return; client = ent->r.client; // set fov if( !client->ps.pmove.stats[PM_STAT_ZOOMTIME] ) client->ps.fov = ent->r.client->fov; else { float frac = (float)client->ps.pmove.stats[PM_STAT_ZOOMTIME] / (float)ZOOMTIME; client->ps.fov = client->fov - ( (float)( client->fov - client->zoomfov ) * frac ); } // If the end of unit layout is displayed, don't give // the player any normal movement attributes if( GS_MatchState() >= MATCH_STATE_POSTMATCH ) { G_SetClientStats( ent ); } else { if( G_IsDead( ent ) && !level.gametype.customDeadBodyCam ) { G_Client_DeadView( ent ); } G_PlayerWorldEffects( ent ); // burn from lava, etc G_ClientDamageFeedback( ent ); // show damage taken along the snap G_SetClientStats( ent ); G_SetClientEffects( ent ); G_SetClientSound( ent ); G_SetClientFrame( ent ); client->ps.plrkeys = client->resp.snap.plrkeys; } G_ReleaseClientPSEvent( client ); // set the delta angle for( i = 0; i < 3; i++ ) client->ps.pmove.delta_angles[i] = ANGLE2SHORT( client->ps.viewangles[i] ) - client->ucmd.angles[i]; // this is pretty hackish. We exploit the fact that servers *do not* transmit // origin2/old_origin for ET_PLAYER/ET_CORPSE entities, and we use it for sending the player velocity if( !G_ISGHOSTING( ent ) ) { ent->r.svflags |= SVF_TRANSMITORIGIN2; VectorCopy( ent->velocity, ent->s.origin2 ); } else ent->r.svflags &= ~SVF_TRANSMITORIGIN2; }
/* * G_ClearSnap * We just run G_SnapFrame, the server just sent the snap to the clients, * it's now time to clean up snap specific data to start the next snap from clean. */ void G_ClearSnap( void ) { edict_t *ent; game.realtime = trap_Milliseconds(); // level.time etc. might not be real time // clear gametype's clock override gs.gameState.longstats[GAMELONG_CLOCKOVERRIDE] = 0; // clear all events in the snap for( ent = &game.edicts[0]; ENTNUM( ent ) < game.numentities; ent++ ) { if( ISEVENTENTITY( &ent->s ) ) // events do not persist after a snapshot { G_FreeEdict( ent ); continue; } // events only last for a single message ent->s.events[0] = ent->s.events[1] = 0; ent->s.eventParms[0] = ent->s.eventParms[1] = 0; ent->numEvents = 0; ent->eventPriority[0] = ent->eventPriority[1] = false; ent->s.teleported = qfalse; // remove teleported bit. // remove effect bits that are (most likely) added from gametypes ent->s.effects = ( ent->s.effects & (EF_TAKEDAMAGE|EF_CARRIER|EF_FLAG_TRAIL|EF_ROTATE_AND_BOB|EF_STRONG_WEAPON|EF_GHOST) ); } // recover some info, let players respawn and finally clear the snap structures for( ent = &game.edicts[0]; ENTNUM( ent ) < game.numentities; ent++ ) { if( !GS_MatchPaused() ) { // copy origin to old origin ( this old_origin is for snaps ) if( !( ent->r.svflags & SVF_TRANSMITORIGIN2 ) ) VectorCopy( ent->s.origin, ent->s.old_origin ); G_CheckClientRespawnClick( ent ); } if( GS_MatchPaused() ) ent->s.sound = entity_sound_backup[ENTNUM( ent )]; // clear the snap temp info memset( &ent->snap, 0, sizeof( ent->snap ) ); if( ent->r.client && trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED ) { memset( &ent->r.client->resp.snap, 0, sizeof( ent->r.client->resp.snap ) ); // set race stats to invisible RS_clearHUDStats( ent->r.client ); // racesow - clear with our function } } g_snapStarted = false; }
/* =============== UI_TeamOrdersMenu_BuildBotList =============== */ static void UI_TeamOrdersMenu_BuildBotList(void) { uiClientState_t cs; int numPlayers; int isBot; int n; char playerTeam; char botTeam; char info[MAX_INFO_STRING]; for (n = 0; n < 9; n++) { teamOrdersMenuInfo.bots[n] = teamOrdersMenuInfo.botNames[n]; } trap_GetClientState(&cs); Q_strncpyz(teamOrdersMenuInfo.botNames[0], "Everyone", 16); teamOrdersMenuInfo.numBots = 1; trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); numPlayers = atoi(Info_ValueForKey(info, "sv_maxclients")); teamOrdersMenuInfo.gametype = atoi(Info_ValueForKey(info, "g_gametype")); //Too: get the player team before the loop, so If player enter after bots in game, the menu still works ! trap_GetConfigString(CS_PLAYERS + cs.clientNum, info, MAX_INFO_STRING); playerTeam = *Info_ValueForKey(info, "t"); for (n = 0; n < numPlayers && teamOrdersMenuInfo.numBots < 9; n++) { trap_GetConfigString(CS_PLAYERS + n, info, MAX_INFO_STRING); //playerTeam = TEAM_SPECTATOR; // bk001204 = possible uninit use /*if (n == cs.clientNum) { playerTeam = *Info_ValueForKey(info, "t"); continue; }*/ isBot = atoi(Info_ValueForKey(info, "skill")); if (!isBot) { continue; } botTeam = *Info_ValueForKey(info, "t"); if (botTeam != playerTeam) { continue; } Q_strncpyz(teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots], Info_ValueForKey(info, "n"), 16); Q_CleanStr(teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots]); teamOrdersMenuInfo.numBots++; } }
/* * Cmd_PlayersExt_f */ static void Cmd_PlayersExt_f( edict_t *ent, bool onlyspecs ) { int i; int count = 0; int start = 0; char line[64]; char msg[1024]; if( trap_Cmd_Argc() > 1 ) start = atoi( trap_Cmd_Argv( 1 ) ); clamp( start, 0, gs.maxclients - 1 ); // print information msg[0] = 0; for( i = start; i < gs.maxclients; i++ ) { if( trap_GetClientState( i ) >= CS_SPAWNED ) { if( onlyspecs && game.edicts[i+1].s.team != TEAM_SPECTATOR ) continue; Q_snprintfz( line, sizeof( line ), "%3i %s%s\n", i, game.clients[i].netname, game.clients[i].isoperator ? " op" : "" ); if( strlen( line ) + strlen( msg ) > sizeof( msg ) - 100 ) { // can't print all of them in one packet Q_strncatz( msg, "...\n", sizeof( msg ) ); break; } if( count == 0 ) { Q_strncatz( msg, "num name\n", sizeof( msg ) ); Q_strncatz( msg, "--- ---------------\n", sizeof( msg ) ); } Q_strncatz( msg, line, sizeof( msg ) ); count++; } } if( count ) Q_strncatz( msg, "--- ---------------\n", sizeof( msg ) ); Q_strncatz( msg, va( "%3i %s\n", count, trap_Cmd_Argv( 0 ) ), sizeof( msg ) ); G_PrintMsg( ent, "%s", msg ); if( i < gs.maxclients ) G_PrintMsg( ent, "Type '%s %i' for more %s\n", trap_Cmd_Argv( 0 ), i, trap_Cmd_Argv( 0 ) ); }
//========================================== // AITools_Frame // Gives think time to the debug tools found // in this archive (those witch need it) //========================================== void AITools_Frame( void ) { edict_t *ent; for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients; ent++ ) { if( !ent->r.inuse ) continue; if( trap_GetClientState( PLAYERNUM( ent ) ) < CS_SPAWNED ) continue; AITools_DropNodes( ent ); AITools_ShowPlinks( ent ); } }
/* ================= UI_TogglePlayerIngame ================= */ void UI_TogglePlayerIngame(int localClientNum) { uiClientState_t cs; trap_GetClientState( &cs ); if (cs.clientNums[localClientNum] == -1) { trap_Cmd_ExecuteText( EXEC_APPEND, va("%s\n", Com_LocalClientCvarName(localClientNum, "dropin")) ); } else { trap_Cmd_ExecuteText( EXEC_APPEND, va("%s\n", Com_LocalClientCvarName(localClientNum, "dropout")) ); } UI_ForceMenuOff (); }
/* ================= InSelectPlayerMenu ================= */ void InSelectPlayerMenu( void (*playerfunc)(int), const char *banner, qboolean disableMissingPlayers ) { uiClientState_t cs; trap_GetClientState( &cs ); // If there is only one local client skip this menu. if (UI_NumLocalClients(&cs) <= 1 && disableMissingPlayers) { playerfunc(0); return; } InSelectPlayer_MenuInit( &cs, banner, disableMissingPlayers ); s_setupplayers.playerfunc = playerfunc; UI_PushMenu( &s_setupplayers.menu ); }
void UI_LoadPanel_RenderHeaderText( panel_button_t* button ) { uiClientState_t cstate; char downloadName[MAX_INFO_VALUE]; trap_GetClientState( &cstate ); trap_Cvar_VariableStringBuffer( "cl_downloadName", downloadName, sizeof( downloadName ) ); if ( ( cstate.connState == CA_DISCONNECTED || cstate.connState == CA_CONNECTED ) && *downloadName ) { button->text = "DOWNLOADING..."; } else { button->text = "CONNECTING..."; } BG_PanelButtonsRender_Text( button ); }
void G_Gametype_GENERIC_SetUpEndMatch( void ) { edict_t *ent; level.gametype.readyAnnouncementEnabled = false; level.gametype.scoreAnnouncementEnabled = false; level.gametype.pickableItemsMask = 0; // disallow item pickup level.gametype.countdownEnabled = false; for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients; ent++ ) { if( ent->r.inuse && trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED ) G_ClientRespawn( ent, true ); } G_AnnouncerSound( NULL, trap_SoundIndex( va( S_ANNOUNCER_POSTMATCH_GAMEOVER_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); }
/* =============== UI_TeamOrdersMenu_BuildBotList =============== */ static void UI_TeamOrdersMenu_BuildBotList(void) { uiClientState_t cs; int numPlayers; int isBot; int n; char playerTeam = '3'; char botTeam; char info[MAX_INFO_STRING]; for (n = 0; n < 9; n++) { teamOrdersMenuInfo.bots[n] = teamOrdersMenuInfo.botNames[n]; } trap_GetClientState(&cs); Q_strncpyz(teamOrdersMenuInfo.botNames[0], "Everyone", 16); teamOrdersMenuInfo.numBots = 1; trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); numPlayers = atoi(Info_ValueForKey(info, "sv_maxclients")); teamOrdersMenuInfo.gametype = atoi(Info_ValueForKey(info, "g_gametype")); for (n = 0; n < numPlayers && teamOrdersMenuInfo.numBots < 9; n++) { trap_GetConfigString(CS_PLAYERS + n, info, MAX_INFO_STRING); if (n == cs.clientNum) { playerTeam = *Info_ValueForKey(info, "t"); continue; } isBot = atoi(Info_ValueForKey(info, "skill")); if (!isBot) { continue; } botTeam = *Info_ValueForKey(info, "t"); if (botTeam != playerTeam) { continue; } Q_strncpyz(teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots], Info_ValueForKey(info, "n"), 16); Q_CleanStr(teamOrdersMenuInfo.botNames[teamOrdersMenuInfo.numBots]); teamOrdersMenuInfo.numBots++; } }
/* * G_CheckNumBots */ static void G_CheckNumBots( void ) { edict_t *ent; int desiredNumBots; if( level.spawnedTimeStamp + 5000 > game.realtime ) return; // check sanity of g_numbots if( g_numbots->integer < 0 ) trap_Cvar_Set( "g_numbots", "0" ); if( g_numbots->integer > gs.maxclients ) trap_Cvar_Set( "g_numbots", va( "%i", gs.maxclients ) ); if( level.gametype.numBots > gs.maxclients ) level.gametype.numBots = gs.maxclients; desiredNumBots = level.gametype.numBots ? level.gametype.numBots : g_numbots->integer; if( desiredNumBots < game.numBots ) { // kick one bot for( ent = game.edicts + gs.maxclients; PLAYERNUM( ent ) >= 0; ent-- ) { if( !ent->r.inuse || !( ent->r.svflags & SVF_FAKECLIENT ) ) continue; if( AI_GetType( ent->ai ) == AI_ISBOT ) { trap_DropClient( ent, DROP_TYPE_GENERAL, NULL ); break; } } return; } if( desiredNumBots > game.numBots ) { // add a bot if there is room for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients && game.numBots < desiredNumBots; ent++ ) { if( !ent->r.inuse && trap_GetClientState( PLAYERNUM( ent ) ) == CS_FREE ) BOT_SpawnBot( NULL ); } } }
/* ================ Con_ToggleConsole_f ================ */ void Con_ToggleConsole_f (void) { uiClientState_t cls; trap_GetClientState( &cls ); // Can't toggle the console when it's the only thing available if ( cls.connState == CA_DISCONNECTED && trap_Key_GetCatcher( ) == KEYCATCH_CONSOLE ) { return; } if ( con_autoclear.integer ) { MField_Clear( &g_consoleField ); } g_consoleField.widthInChars = g_console_field_width; trap_Key_SetCatcher( trap_Key_GetCatcher( ) ^ KEYCATCH_CONSOLE ); }
/* * G_Chase_IsValidTarget */ static bool G_Chase_IsValidTarget( edict_t *ent, edict_t *target, bool teamonly ) { if( !ent || !target ) return false; if( !target->r.inuse || !target->r.client || trap_GetClientState( PLAYERNUM( target ) ) < CS_SPAWNED ) return false; if( target->s.team < TEAM_PLAYERS || target->s.team >= GS_MAX_TEAMS || target == ent ) return false; if( teamonly && !ent->r.client->teamstate.is_coach && G_ISGHOSTING( target ) ) return false; if( teamonly && target->s.team != ent->s.team ) return false; return true; }
/* ================= UI_Message hacked over from Confirm stuff ================= */ void UI_Message( const char **lines ) { uiClientState_t cstate; int n1, l1; // zero set all our globals memset( &s_confirm, 0, sizeof(s_confirm) ); ConfirmMenu_Cache(); n1 = UI_ProportionalStringWidth( "OK" ); l1 = 320 - ( n1 / 2 ); s_confirm.lines = lines; s_confirm.style = UI_CENTER|UI_INVERSE|UI_SMALLFONT; s_confirm.menu.draw = MessageMenu_Draw; s_confirm.menu.key = ConfirmMenu_Key; s_confirm.menu.wrapAround = qtrue; trap_GetClientState( &cstate ); if ( cstate.connState >= CA_CONNECTED ) { s_confirm.menu.fullscreen = qfalse; } else { s_confirm.menu.fullscreen = qtrue; } s_confirm.yes.generic.type = MTYPE_PTEXT; s_confirm.yes.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS; s_confirm.yes.generic.callback = ConfirmMenu_Event; s_confirm.yes.generic.id = ID_CONFIRM_YES; s_confirm.yes.generic.x = l1; s_confirm.yes.generic.y = 280; s_confirm.yes.string = "OK"; s_confirm.yes.color = color_red; s_confirm.yes.style = UI_LEFT; Menu_AddItem( &s_confirm.menu, &s_confirm.yes ); UI_PushMenu( &s_confirm.menu ); Menu_SetCursorToItem( &s_confirm.menu, &s_confirm.yes ); }
/* * G_Client_InactivityRemove */ void G_Client_InactivityRemove( gclient_t *client ) { if( !client ) return; if( trap_GetClientState( client - game.clients ) < CS_SPAWNED ) return; if( client->ps.pmove.pm_type != PM_NORMAL ) return; if( g_inactivity_maxtime->modified ) { if( g_inactivity_maxtime->value <= 0.0f ) trap_Cvar_ForceSet( "g_inactivity_maxtime", "0.0" ); else if( g_inactivity_maxtime->value < 15.0f ) trap_Cvar_ForceSet( "g_inactivity_maxtime", "15.0" ); g_inactivity_maxtime->modified = false; } if( g_inactivity_maxtime->value == 0.0f ) return; if( ( GS_MatchState() != MATCH_STATE_PLAYTIME ) || !level.gametype.removeInactivePlayers ) return; // inactive for too long if( client->level.last_activity && client->level.last_activity + ( g_inactivity_maxtime->value * 1000 ) < level.time ) { if( client->team >= TEAM_PLAYERS && client->team < GS_MAX_TEAMS ) { edict_t *ent = &game.edicts[ client - game.clients + 1 ]; // move to spectators and reset the queue time, effectively removing from the challengers queue G_Teams_SetTeam( ent, TEAM_SPECTATOR ); client->queueTimeStamp = 0; G_PrintMsg( NULL, "%s" S_COLOR_YELLOW " has been moved to spectator after %.1f seconds of inactivity\n", client->netname, g_inactivity_maxtime->value ); } } }
/* * G_Laser_Think */ static void G_Laser_Think( edict_t *ent ) { edict_t *owner; if( ent->s.ownerNum < 1 || ent->s.ownerNum > gs.maxclients ) { G_FreeEdict( ent ); return; } owner = &game.edicts[ent->s.ownerNum]; if( G_ISGHOSTING( owner ) || owner->s.weapon != WEAP_LASERGUN || trap_GetClientState( PLAYERNUM( owner ) ) < CS_SPAWNED || ( owner->r.client->ps.weaponState != WEAPON_STATE_REFIRESTRONG && owner->r.client->ps.weaponState != WEAPON_STATE_REFIRE ) ) { G_HideLaser( ent ); return; } ent->nextThink = level.time + 1; }
/* * G_TickOutPowerUps */ static void G_TickOutPowerUps( void ) { edict_t *ent; gsitem_t *item; int i; for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients; ent++ ) { if( ent->r.inuse && trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED ) { for( i = POWERUP_QUAD; i < POWERUP_TOTAL; i++ ) { item = GS_FindItemByTag( i ); if( item && item->quantity && ent->r.client->ps.inventory[item->tag] > 0 ) { ent->r.client->ps.inventory[item->tag]--; } } } } // also tick out dropped powerups for( ent = game.edicts + gs.maxclients + BODY_QUEUE_SIZE; ENTNUM( ent ) < game.numentities; ent++ ) { if( !ent->r.inuse || !ent->item ) continue; if( !( ent->item->type & IT_POWERUP ) ) continue; if( ent->spawnflags & DROPPED_ITEM ) { ent->count--; if( ent->count <= 0 ) { G_FreeEdict( ent ); continue; } } } }
/* * 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; } }
/* * G_ClientThink * Client frame think, and call to execute its usercommands thinking */ void G_ClientThink( edict_t *ent ) { if( !ent || !ent->r.client ) return; if( trap_GetClientState( PLAYERNUM( ent ) ) < CS_SPAWNED ) return; ent->r.client->ps.POVnum = ENTNUM( ent ); // set self // load instashield if( GS_Instagib() && g_instashield->integer ) { if( ent->s.team >= TEAM_PLAYERS && ent->s.team < GS_MAX_TEAMS ) { if( ent->r.client->ps.inventory[POWERUP_SHELL] > 0 ) { ent->r.client->resp.instashieldCharge -= ( game.frametime * 0.001f ) * 60.0f; clamp( ent->r.client->resp.instashieldCharge, 0, INSTA_SHIELD_MAX ); if( ent->r.client->resp.instashieldCharge == 0 ) ent->r.client->ps.inventory[POWERUP_SHELL] = 0; } else { ent->r.client->resp.instashieldCharge += ( game.frametime * 0.001f ) * 20.0f; clamp( ent->r.client->resp.instashieldCharge, 0, INSTA_SHIELD_MAX ); } } } // run bots thinking with the rest of clients if( ent->r.svflags & SVF_FAKECLIENT ) { if( !ent->think && AI_GetType( ent->ai ) == AI_ISBOT ) AI_Think( ent ); } trap_ExecuteClientThinks( PLAYERNUM( ent ) ); }
/* * G_CheckClientRespawnClick */ void G_CheckClientRespawnClick( edict_t *ent ) { if( !ent->r.inuse || !ent->r.client || !G_IsDead( ent ) ) return; if( GS_MatchState() >= MATCH_STATE_POSTMATCH ) return; if( trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED ) { // if the spawnsystem doesn't require to click if( G_SpawnQueue_GetSystem( ent->s.team ) != SPAWNSYSTEM_INSTANT ) { int minDelay = g_respawn_delay_min->integer; // waves system must wait for at least 500 msecs (to see the death, but very short for selfkilling tactics). if( G_SpawnQueue_GetSystem( ent->s.team ) == SPAWNSYSTEM_WAVES ) minDelay = ( g_respawn_delay_min->integer < 500 ) ? 500 : g_respawn_delay_min->integer; // hold system must wait for at least 1000 msecs (to see the death properly) if( G_SpawnQueue_GetSystem( ent->s.team ) == SPAWNSYSTEM_HOLD ) minDelay = ( g_respawn_delay_min->integer < 1300 ) ? 1300 : g_respawn_delay_min->integer; if( level.time >= ent->deathTimeStamp + minDelay ) G_SpawnQueue_AddClient( ent ); } // clicked else if( ent->r.client->resp.snap.buttons & BUTTON_ATTACK ) { if( level.time > ent->deathTimeStamp + g_respawn_delay_min->integer ) G_SpawnQueue_AddClient( ent ); } // didn't click, but too much time passed else if( g_respawn_delay_max->integer && ( level.time > ent->deathTimeStamp + g_respawn_delay_max->integer ) ) { G_SpawnQueue_AddClient( ent ); } } }
/* * G_Teams_UpdateMembersList * It's better to count the list in detail once per fame, than * creating a quick list each time we need it. */ void G_Teams_UpdateMembersList( void ) { edict_t *ent; int i, team; for( team = TEAM_SPECTATOR; team < GS_MAX_TEAMS; team++ ) { teamlist[team].numplayers = 0; teamlist[team].ping = 0; teamlist[team].has_coach = false; //create a temp list with the clients inside this team for( i = 0, ent = game.edicts + 1; i < gs.maxclients; i++, ent++ ) { if( !ent->r.client || ( trap_GetClientState( PLAYERNUM( ent ) ) < CS_CONNECTED ) ) continue; if( ent->s.team == team ) { teamlist[team].playerIndices[teamlist[team].numplayers++] = ENTNUM( ent ); if( ent->r.client->teamstate.is_coach ) teamlist[team].has_coach = true; } } qsort( teamlist[team].playerIndices, teamlist[team].numplayers, sizeof( teamlist[team].playerIndices[0] ), G_Teams_CompareMembers ); if( teamlist[team].numplayers ) { for( i = 0; i < teamlist[team].numplayers; i++ ) teamlist[team].ping += game.edicts[teamlist[team].playerIndices[i]].r.client->r.ping; teamlist[team].ping /= teamlist[team].numplayers; } } }
/* * G_Match_ScoreAnnouncement */ static void G_Match_ScoreAnnouncement( void ) { int i; edict_t *e, *chased; int num_leaders, team; if( !level.gametype.scoreAnnouncementEnabled ) return; num_leaders = 0; memset( leaders, 0, sizeof( leaders ) ); if( GS_TeamBasedGametype() ) { int score_max = -999999999; for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ ) { if( !teamlist[team].numplayers ) continue; if( teamlist[team].stats.score > score_max ) { score_max = teamlist[team].stats.score; leaders[0] = team; num_leaders = 1; } else if( teamlist[team].stats.score == score_max ) { leaders[num_leaders++] = team; } } leaders[num_leaders] = 0; } else { int score_max = -999999999; for( i = 0; i < MAX_CLIENTS && i < teamlist[TEAM_PLAYERS].numplayers; i++ ) { if( game.clients[teamlist[TEAM_PLAYERS].playerIndices[i]-1].level.stats.score > score_max ) { score_max = game.clients[teamlist[TEAM_PLAYERS].playerIndices[i]-1].level.stats.score; leaders[0] = teamlist[TEAM_PLAYERS].playerIndices[i]; num_leaders = 1; } else if( game.clients[teamlist[TEAM_PLAYERS].playerIndices[i]-1].level.stats.score == score_max ) { leaders[num_leaders++] = teamlist[TEAM_PLAYERS].playerIndices[i]; } } leaders[num_leaders] = 0; } if( !score_announcement_init ) { // copy over to last_leaders memcpy( last_leaders, leaders, sizeof( leaders ) ); score_announcement_init = true; return; } for( e = game.edicts + 1; PLAYERNUM( e ) < gs.maxclients; e++ ) { if( !e->r.client || trap_GetClientState( PLAYERNUM( e ) ) < CS_SPAWNED ) continue; if( e->r.client->resp.chase.active ) chased = &game.edicts[e->r.client->resp.chase.target]; else chased = e; // floating spectator if( chased->s.team == TEAM_SPECTATOR ) { if( !GS_TeamBasedGametype() ) continue; if( last_leaders[1] == 0 && leaders[1] != 0 ) { G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TIED_LEAD_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); } else if( leaders[1] == 0 && ( last_leaders[0] != leaders[0] || last_leaders[1] != 0 ) ) { //G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_1_to_4_TAKEN_LEAD_1_to_2, // leaders[0]-1, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); } continue; } // in the game or chasing someone who is if( G_WasLeading( chased ) && !G_IsLeading( chased ) ) { if( GS_TeamBasedGametype() && !GS_InvidualGameType() ) G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_LOST_LEAD_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); else G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_LOST_LEAD_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); } else if( ( !G_WasLeading( chased ) || ( last_leaders[1] != 0 ) ) && G_IsLeading( chased ) && ( leaders[1] == 0 ) ) { if( GS_TeamBasedGametype() && !GS_InvidualGameType() ) G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TAKEN_LEAD_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); else G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TAKEN_LEAD_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); } else if( ( !G_WasLeading( chased ) || ( last_leaders[1] == 0 ) ) && G_IsLeading( chased ) && ( leaders[1] != 0 ) ) { if( GS_TeamBasedGametype() && !GS_InvidualGameType() ) G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TEAM_TIED_LEAD_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); else G_AnnouncerSound( e, trap_SoundIndex( va( S_ANNOUNCER_SCORE_TIED_LEAD_1_to_2, ( rand()&1 )+1 ) ), GS_MAX_TEAMS, true, NULL ); } } // copy over to last_leaders memcpy( last_leaders, leaders, sizeof( leaders ) ); }