void G_DestroyFireteam(int entityNum) { fireteamData_t *ft; if ((entityNum < 0 || entityNum >= MAX_CLIENTS) || !g_entities[entityNum].client) { G_Error("G_DestroyFireteam: invalid client\n"); } if (!G_IsFireteamLeader(entityNum, &ft)) { G_ClientPrint(entityNum, "You are not the leader of a fireteam\n"); return; } while (ft->joinOrder[0] != -1) { if (ft->joinOrder[0] != entityNum) { #ifdef FEATURE_OMNIBOT Bot_Event_FireTeamDestroyed(ft->joinOrder[0]); #endif trap_SendServerCommand(ft->joinOrder[0], "cpm \"The fireteam you are on has been disbanded\""); } G_RemoveClientFromFireteams(ft->joinOrder[0], qfalse, qfalse); } G_UpdateFireteamConfigString(ft); }
void G_KickFireTeamPlayer(int entityNum, int otherEntityNum) { fireteamData_t *ft, *ft2; if (entityNum == otherEntityNum) { return; // ok, stop being silly :p } if ((entityNum < 0 || entityNum >= MAX_CLIENTS) || !g_entities[entityNum].client) { G_Error("G_KickFireTeamPlayer: invalid client"); } if ((otherEntityNum < 0 || otherEntityNum >= MAX_CLIENTS) || !g_entities[otherEntityNum].client) { G_Error("G_KickFireTeamPlayer: invalid client"); } if (!G_IsFireteamLeader(entityNum, &ft)) { G_ClientPrintAndReturn(entityNum, "You are not the leader of a fireteam"); } if ((!G_IsOnFireteam(otherEntityNum, &ft2)) || ft != ft2) { G_ClientPrintAndReturn(entityNum, "You are not on the same Fireteam as the other player"); } G_RemoveClientFromFireteams(otherEntityNum, qtrue, qfalse); G_ClientPrintAndReturn(otherEntityNum, "You have been kicked from the fireteam"); }
/** * @brief Shuffle active players onto teams */ void G_shuffleTeams(void) { int i; team_t cTeam; //, cMedian = level.numNonSpectatorClients / 2; int cnt = 0; int sortClients[MAX_CLIENTS]; gclient_t *cl; G_teamReset(TEAM_AXIS, qtrue); G_teamReset(TEAM_ALLIES, qtrue); for (i = 0; i < level.numConnectedClients; i++) { cl = level.clients + level.sortedClients[i]; if (cl->sess.sessionTeam != TEAM_AXIS && cl->sess.sessionTeam != TEAM_ALLIES) { continue; } sortClients[cnt++] = level.sortedClients[i]; } qsort(sortClients, cnt, sizeof(int), G_SortPlayersByXP); for (i = 0; i < cnt; i++) { cl = level.clients + sortClients[i]; // cTeam = (i % 2) + TEAM_AXIS; cTeam = (((i + 1) % 4) - ((i + 1) % 2)) / 2 + TEAM_AXIS; if (cl->sess.sessionTeam != cTeam) { G_LeaveTank(g_entities + sortClients[i], qfalse); G_RemoveClientFromFireteams(sortClients[i], qtrue, qfalse); if (g_landminetimeout.integer) { G_ExplodeMines(g_entities + sortClients[i]); } G_FadeItems(g_entities + sortClients[i], MOD_SATCHEL); } cl->sess.sessionTeam = cTeam; G_UpdateCharacter(cl); ClientUserinfoChanged(sortClients[i]); ClientBegin(sortClients[i]); } AP("cp \"^1Teams have been shuffled!\n\""); }
// The only way a client should be removed from a fireteam void G_RemoveClientFromFireteams( int entityNum, qboolean update, qboolean print ) { fireteamData_t* ft; int i, j; if ( ( entityNum < 0 || entityNum >= MAX_CLIENTS ) || !g_entities[entityNum].client ) { G_Error( "G_RemoveClientFromFireteams: invalid client" ); } if ( G_IsOnFireteam( entityNum, &ft ) ) { for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( ft->joinOrder[i] == entityNum ) { if ( i == 0 ) { if ( ft->joinOrder[1] == -1 ) { ft->inuse = qfalse; ft->ident = -1; } else { // TODO: Inform client of promotion to leader } } for ( j = i; j < MAX_CLIENTS - 1; j++ ) { ft->joinOrder[j] = ft->joinOrder[j + 1]; } ft->joinOrder[MAX_CLIENTS - 1] = -1; break; } } } else { return; } if ( ft->joinOrder[0] != -1 ) { if ( g_entities[(int)ft->joinOrder[0]].r.svFlags & SVF_BOT ) { G_RemoveClientFromFireteams( ft->joinOrder[0], qfalse, qfalse ); } } if ( print ) { for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( ft->joinOrder[i] == -1 ) { break; } trap_SendServerCommand( ft->joinOrder[i], va( "cpm \"%s has left the Fireteam\"\n", level.clients[entityNum].pers.netname ) ); } } if ( update ) { G_UpdateFireteamConfigString( ft ); } }
void G_DestroyFireteam( int entityNum ) { fireteamData_t* ft; if ( ( entityNum < 0 || entityNum >= MAX_CLIENTS ) || !g_entities[entityNum].client ) { G_Error( "G_DestroyFireteam: invalid client" ); } if ( !G_IsFireteamLeader( entityNum, &ft ) ) { G_ClientPrintAndReturn( entityNum, "You are not the leader of a fireteam" ); } while ( ft->joinOrder[0] != -1 ) { if ( ft->joinOrder[0] != entityNum ) { trap_SendServerCommand( ft->joinOrder[0], "cpm \"The Fireteam you are on has been disbanded\"\n" ); } G_RemoveClientFromFireteams( ft->joinOrder[0], qfalse, qfalse ); } G_UpdateFireteamConfigString( ft ); }
// Command handler void Cmd_FireTeam_MP_f( gentity_t* ent ) { char command[32]; int i; if ( trap_Argc() < 2 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam <create|leave|apply|invite>" ); } trap_Argv( 1, command, 32 ); if ( !Q_stricmp( command, "create" ) ) { G_RegisterFireteam( ent - g_entities ); } else if ( !Q_stricmp( command, "disband" ) ) { G_DestroyFireteam( ent - g_entities ); } else if ( !Q_stricmp( command, "leave" ) ) { G_RemoveClientFromFireteams( ent - g_entities, qtrue, qtrue ); } else if ( !Q_stricmp( command, "apply" ) ) { char namebuffer[32]; int fireteam; if ( trap_Argc() < 3 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam apply <fireteamname|fireteamnumber>" ); } trap_Argv( 2, namebuffer, 32 ); fireteam = G_FireteamNumberForString( namebuffer, ent->client->sess.sessionTeam ); if ( fireteam <= 0 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam apply <fireteamname|fireteamnumber>" ); } G_ApplyToFireTeam( ent - g_entities, fireteam - 1 ); } else if ( !Q_stricmp( command, "invite" ) ) { char namebuffer[32]; int clientnum = 0; if ( trap_Argc() < 3 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam invite <clientname|clientnumber>" ); } trap_Argv( 2, namebuffer, 32 ); for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !g_entities[i].inuse || !g_entities[i].client ) { continue; } if ( !Q_stricmp( g_entities[i].client->pers.netname, namebuffer ) ) { clientnum = i + 1; } } if ( clientnum <= 0 ) { clientnum = atoi( namebuffer ); if ( ( clientnum <= 0 || clientnum > MAX_CLIENTS ) || !g_entities[clientnum - 1].inuse || !g_entities[clientnum - 1].client ) { G_ClientPrintAndReturn( ent - g_entities, "Invalid client selected" ); } } if ( clientnum <= 0 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam invite <clientname|clientnumber>" ); } G_InviteToFireTeam( ent - g_entities, clientnum - 1 ); } else if ( !Q_stricmp( command, "warn" ) ) { char namebuffer[32]; int clientnum = 0; if ( trap_Argc() < 3 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam warn <clientname|clientnumber>" ); } trap_Argv( 2, namebuffer, 32 ); for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !g_entities[i].inuse || !g_entities[i].client ) { continue; } if ( !Q_stricmp( g_entities[i].client->pers.netname, namebuffer ) ) { clientnum = i + 1; } } if ( clientnum <= 0 ) { clientnum = atoi( namebuffer ); if ( ( clientnum <= 0 || clientnum > MAX_CLIENTS ) || !g_entities[clientnum - 1].inuse || !g_entities[clientnum - 1].client ) { G_ClientPrintAndReturn( ent - g_entities, "Invalid client selected" ); } } if ( clientnum <= 0 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam warn <clientname|clientnumber>" ); } G_WarnFireTeamPlayer( ent - g_entities, clientnum - 1 ); } else if ( !Q_stricmp( command, "kick" ) ) { char namebuffer[32]; int clientnum = 0; if ( trap_Argc() < 3 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam kick <clientname|clientnumber>" ); } trap_Argv( 2, namebuffer, 32 ); for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !g_entities[i].inuse || !g_entities[i].client ) { continue; } if ( !Q_stricmp( g_entities[i].client->pers.netname, namebuffer ) ) { clientnum = i + 1; } } if ( clientnum <= 0 ) { clientnum = atoi( namebuffer ); if ( ( clientnum <= 0 || clientnum > MAX_CLIENTS ) || !g_entities[clientnum - 1].inuse || !g_entities[clientnum - 1].client ) { G_ClientPrintAndReturn( ent - g_entities, "Invalid client selected" ); } } if ( clientnum <= 0 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam kick <clientname|clientnumber>" ); } G_KickFireTeamPlayer( ent - g_entities, clientnum - 1 ); } else if ( !Q_stricmp( command, "propose" ) ) { char namebuffer[32]; int clientnum = 0; if ( trap_Argc() < 3 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam propose <clientname|clientnumber>" ); } trap_Argv( 2, namebuffer, 32 ); for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !g_entities[i].inuse || !g_entities[i].client ) { continue; } if ( !Q_stricmp( g_entities[i].client->pers.netname, namebuffer ) ) { clientnum = i + 1; } } if ( clientnum <= 0 ) { clientnum = atoi( namebuffer ); if ( ( clientnum <= 0 || clientnum > MAX_CLIENTS ) || !g_entities[clientnum - 1].inuse || !g_entities[clientnum - 1].client ) { G_ClientPrintAndReturn( ent - g_entities, "Invalid client selected" ); } } if ( clientnum <= 0 ) { G_ClientPrintAndReturn( ent - g_entities, "usage: fireteam propose <clientname|clientnumber>" ); } G_ProposeFireTeamPlayer( ent - g_entities, clientnum - 1 ); } }
/* =========== ClientDisconnect Called when a player drops from the server. Will not be called between levels. This should NOT be called directly by any game logic, call trap_DropClient(), which will call this and do server system housekeeping. ============ */ void ClientDisconnect(int clientNum) { gentity_t *ent; gentity_t *flag = NULL; gitem_t *item = NULL; vec3_t launchvel; int i; ent = g_entities + clientNum; if (!ent->client) { return; } G_RemoveClientFromFireteams(clientNum, qtrue, qfalse); G_RemoveFromAllIgnoreLists(clientNum); G_LeaveTank(ent, qfalse); // Nico, remove the client from all specInvited lists for (i = 0; i < level.numConnectedClients; ++i) { COM_BitClear(level.clients[level.sortedClients[i]].sess.specInvitedClients, clientNum); } // stop any following clients for (i = 0 ; i < level.numConnectedClients ; i++) { flag = g_entities + level.sortedClients[i]; if (flag->client->sess.sessionTeam == TEAM_SPECTATOR && flag->client->sess.spectatorState == SPECTATOR_FOLLOW && flag->client->sess.spectatorClient == clientNum) { StopFollowing(flag); } if (flag->client->ps.pm_flags & PMF_LIMBO && flag->client->sess.spectatorClient == clientNum) { Cmd_FollowCycle_f(flag, 1); } } G_FadeItems(ent, MOD_SATCHEL); // remove ourself from teamlists { mapEntityData_t *mEnt; mapEntityData_Team_t *teamList; for (i = 0; i < 2; i++) { teamList = &mapEntityData[i]; if ((mEnt = G_FindMapEntityData(&mapEntityData[0], ent - g_entities)) != NULL) { G_FreeMapEntityData(teamList, mEnt); } mEnt = G_FindMapEntityDataSingleClient(teamList, NULL, ent->s.number, -1); while (mEnt) { mapEntityData_t *mEntFree = mEnt; mEnt = G_FindMapEntityDataSingleClient(teamList, mEnt, ent->s.number, -1); G_FreeMapEntityData(teamList, mEntFree); } } } // send effect if they were completely connected if (ent->client->pers.connected == CON_CONNECTED && ent->client->sess.sessionTeam != TEAM_SPECTATOR && !(ent->client->ps.pm_flags & PMF_LIMBO)) { // They don't get to take powerups with them! // Especially important for stuff like CTF flags // New code for tossing flags if (ent->client->ps.powerups[PW_REDFLAG]) { item = BG_FindItem("Red Flag"); if (!item) { item = BG_FindItem("Objective"); } ent->client->ps.powerups[PW_REDFLAG] = 0; } if (ent->client->ps.powerups[PW_BLUEFLAG]) { item = BG_FindItem("Blue Flag"); if (!item) { item = BG_FindItem("Objective"); } ent->client->ps.powerups[PW_BLUEFLAG] = 0; } if (item) { // OSP - fix for suicide drop exploit through walls/gates launchvel[0] = 0; //crandom()*20; launchvel[1] = 0; //crandom()*20; launchvel[2] = 0; //10+random()*10; flag = LaunchItem(item, ent->r.currentOrigin, launchvel, ent - g_entities); flag->s.modelindex2 = ent->s.otherEntityNum2; // JPW NERVE FIXME set player->otherentitynum2 with old modelindex2 from flag and restore here flag->message = ent->message; // DHM - Nerve :: also restore item name // Clear out player's temp copies ent->s.otherEntityNum2 = 0; ent->message = NULL; } } G_LogPrintf("ClientDisconnect: %i\n", clientNum); trap_UnlinkEntity(ent); ent->s.modelindex = 0; ent->inuse = qfalse; ent->classname = "disconnected"; ent->client->pers.connected = CON_DISCONNECTED; ent->client->ps.persistant[PERS_TEAM] = TEAM_FREE; i = ent->client->sess.sessionTeam; ent->client->sess.sessionTeam = TEAM_FREE; ent->active = 0; trap_SetConfigstring(CS_PLAYERS + clientNum, ""); CalculateRanks(); }