/* ================ G_InitSessionData Called on a first-time connect ================ */ void G_InitSessionData( gclient_t *client, char *userinfo ) { clientSession_t *sess; const char *value; sess = &client->sess; // initial team determination if ( g_gametype.integer >= GT_TEAM ) { if ( g_teamAutoJoin.integer && !(g_entities[ client - level.clients ].r.svFlags & SVF_BOT) ) { sess->sessionTeam = PickTeam( -1 ); BroadcastTeamChange( client, -1 ); } else { // always spawn as spectator in team games sess->sessionTeam = TEAM_SPECTATOR; } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->sessionTeam = TEAM_SPECTATOR; } else { switch ( g_gametype.integer ) { default: case GT_FFA: case GT_SINGLE_PLAYER: if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients >= g_maxGameClients.integer ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_TOURNAMENT: // if the game is full, go into a waiting mode if ( level.numNonSpectatorClients >= 2 ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; } } } sess->spectatorState = SPECTATOR_FREE; AddTournamentQueue(client); if (crandom() > 0) client->sess.weapon = WP_RAILGUN; else client->sess.weapon = WP_ROCKET_LAUNCHER; G_WriteClientSessionData( client ); }
/* ================ G_InitSessionData Called on a first-time connect ================ */ void G_InitSessionData( gclient_t *client, char *userinfo ) { clientSession_t *sess; const char *value; sess = &client->sess; // initial team determination if ( g_gametype.integer >= GT_TEAM ) { if ( g_teamAutoJoin.integer ) { sess->sessionTeam = PickTeam( -1 ); BroadcastTeamChange( client, -1 ); } else { // always spawn as spectator in team games sess->sessionTeam = TEAM_SPECTATOR; } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->sessionTeam = TEAM_SPECTATOR; } else { switch ( g_gametype.integer ) { default: case GT_FFA: case GT_SINGLE_PLAYER: if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients >= g_maxGameClients.integer ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_TOURNAMENT: // if the game is full, go into a waiting mode if ( level.numNonSpectatorClients >= 2 ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; } } } sess->spectatorState = SPECTATOR_FREE; sess->spectatorTime = level.time; G_WriteClientSessionData( client ); }
/* ================ G_InitSessionData Called on a first-time connect ================ */ void G_InitSessionData( gclient_t *client, char *userinfo ) { clientSession_t *sess; const char *value; sess = &client->sess; // initial team determination if ( level.gametypeData->teams ) { if ( g_teamAutoJoin.integer ) { sess->team = PickTeam( -1 ); BroadcastTeamChange( client, -1 ); } else { // always spawn as spectator in team games sess->team = TEAM_SPECTATOR; } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->team = TEAM_SPECTATOR; } else { if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients >= g_maxGameClients.integer ) { sess->team = TEAM_SPECTATOR; } else { sess->team = TEAM_FREE; } } } sess->spectatorState = SPECTATOR_FREE; sess->spectatorTime = level.time; G_WriteClientSessionData( client ); }
/** LQ3A: Changed return from void to qboolean. This function initilises the session data and assigns a team to the client, if we cannot assign a team it returns qfalse and the client should be dropped from the server. @see ClientConnect(). */ qboolean G_InitSessionData( gclient_t *client, char *userinfo ) { clientSession_t *sess; /* LQ3A */ // const char *value; qboolean bCanClientSpectate; int iVacantPlayerSlots; /* LQ3A */ UNREFERENCED_PARAMETER(userinfo); sess = &client->sess; /* LQ3A */ bCanClientSpectate = LQ3A_CanClientSpectate(LQ3A_ClientToEntity(client)); iVacantPlayerSlots = LQ3A_GetVacantPlayerSlots(); // initial team determination if (g_gametype.integer >= GT_TEAM) { /* LQ3A: Added support for g_maxGameClients in team games. Force auto join when the client cannot spectate. */ if (iVacantPlayerSlots && (g_teamAutoJoin.integer || !bCanClientSpectate)) { sess->sessionTeam = PickTeam( -1 ); BroadcastTeamChange( client, -1 ); } else if (bCanClientSpectate) { sess->sessionTeam = TEAM_SPECTATOR; } else { /* No vacant player slots and we cannot spectate. */ return qfalse; } } else { /* LQ3A: Place clients into spectator mode by default where possible. */ if (bCanClientSpectate) { sess->sessionTeam = TEAM_SPECTATOR; } /* If we cannot spectate, place the client in the game when there are vacant slots. */ else if (iVacantPlayerSlots) { sess->sessionTeam = TEAM_FREE; } else { /* No vacant player slots and we cannot spectate. */ return qfalse; } } sess->spectatorState = SPECTATOR_FREE; sess->spectatorTime = level.time; /* LQ3A */ if (sess->sessionTeam == TEAM_SPECTATOR) { LQ3A_CompleteClientMoveToSpectatorTeam(LQ3A_ClientToEntity(client)); } G_WriteClientSessionData( client ); /* LQ3A */ return qtrue; }
/* =============== G_AddBot =============== */ static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) { int value; int connectionNum; int clientNum; int t; char *botinfo; char *key; char *s; char *botname; char *model; char *headmodel; char userinfo[MAX_INFO_STRING]; qboolean modelSet; // have the server allocate a client slot value = trap_BotAllocateClient(); if ( value == -1 ) { G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" ); return; } // get connection and client numbers connectionNum = value & 0xFFFF; clientNum = value >> 16; // set default team if( !team || !*team ) { if( g_gametype.integer >= GT_TEAM ) { if( PickTeam(clientNum) == TEAM_RED) { team = "red"; } else { team = "blue"; } } else { team = "free"; } } // get the botinfo from bots.txt if (Q_stricmp(name, "random") == 0) { if (Q_stricmp(team, "blue") == 0) t = TEAM_BLUE; else if (Q_stricmp(team, "red") == 0) t = TEAM_RED; else t = TEAM_FREE; // get info of a randomly selected bot botinfo = G_GetBotInfoByNumber( G_SelectRandomBotForAdd( t ) ); } else { // get info of the bot botinfo = G_GetBotInfoByName( name ); } if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); trap_BotFreeClient(clientNum); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } // check for an alternative name if (altname && altname[0]) { botname = altname; } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%.2f", skill) ); Info_SetValueForKey( userinfo, "teampref", team ); if ( skill >= 1 && skill < 2 ) { Info_SetValueForKey( userinfo, "handicap", "50" ); } else if ( skill >= 2 && skill < 3 ) { Info_SetValueForKey( userinfo, "handicap", "70" ); } else if ( skill >= 3 && skill < 4 ) { Info_SetValueForKey( userinfo, "handicap", "90" ); } key = "model"; model = Info_ValueForKey( botinfo, key ); modelSet = ( *model ); if ( !modelSet ) { model = DEFAULT_MODEL; } Info_SetValueForKey( userinfo, key, model ); key = "team_model"; Info_SetValueForKey( userinfo, key, model ); key = "headmodel"; headmodel = Info_ValueForKey( botinfo, key ); if ( !*headmodel ) { if (!modelSet) { headmodel = DEFAULT_HEAD; } else { headmodel = model; } } Info_SetValueForKey( userinfo, key, headmodel ); key = "team_headmodel"; Info_SetValueForKey( userinfo, key, headmodel ); key = "color1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = va("%d", DEFAULT_CLIENT_COLOR1); } Info_SetValueForKey( userinfo, key, s ); key = "color2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = va("%d", DEFAULT_CLIENT_COLOR2); } Info_SetValueForKey( userinfo, key, s ); s = Info_ValueForKey(botinfo, "aifile"); if (!*s ) { trap_Print( S_COLOR_RED "Error: bot has no aifile specified\n" ); trap_BotFreeClient(clientNum); return; } Info_SetValueForKey( userinfo, "characterfile", s ); // register the userinfo trap_SetUserinfo( clientNum, userinfo ); // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue, connectionNum, 0 ) ) { return; } if( delay == 0 ) { ClientBegin( clientNum ); return; } AddBotToSpawnQueue( clientNum, delay ); }
/* =========== ClientUserInfoChanged Called from ClientConnect when the player first connects and directly by the server system when the player updates a userinfo variable. The game can override any of the settings and call trap_SetUserinfo if desired. ============ */ void ClientUserinfoChanged( int clientNum ) { gentity_t *ent; int teamTask, teamLeader, team, health; char *s; char model[MAX_QPATH]; char headModel[MAX_QPATH]; char oldname[MAX_STRING_CHARS]; gclient_t *client; char c1[MAX_INFO_STRING]; char c2[MAX_INFO_STRING]; char redTeam[MAX_INFO_STRING]; char blueTeam[MAX_INFO_STRING]; char userinfo[MAX_INFO_STRING]; ent = g_entities + clientNum; client = ent->client; trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); // check for malformed or illegal info strings if ( !Info_Validate(userinfo) ) { strcpy (userinfo, "\\name\\badinfo"); } // check for local client s = Info_ValueForKey( userinfo, "ip" ); if ( !strcmp( s, "localhost" ) ) { client->pers.localClient = qtrue; } // check the item prediction s = Info_ValueForKey( userinfo, "cg_predictItems" ); if ( !atoi( s ) ) { client->pers.predictItemPickup = qfalse; } else { client->pers.predictItemPickup = qtrue; } // set name Q_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) ); s = Info_ValueForKey (userinfo, "name"); ClientCleanName( s, client->pers.netname, sizeof(client->pers.netname) ); if ( client->sess.sessionTeam == TEAM_SPECTATOR ) { if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) { Q_strncpyz( client->pers.netname, "scoreboard", sizeof(client->pers.netname) ); } } if ( client->pers.connected == CON_CONNECTED ) { if ( strcmp( oldname, client->pers.netname ) ) { trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, client->pers.netname) ); } } // set max health #ifdef MISSIONPACK if (client->ps.powerups[PW_GUARD]) { client->pers.maxHealth = 200; } else { health = atoi( Info_ValueForKey( userinfo, "handicap" ) ); client->pers.maxHealth = health; if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) { client->pers.maxHealth = 100; } } #else health = atoi( Info_ValueForKey( userinfo, "handicap" ) ); client->pers.maxHealth = health; if ( client->pers.maxHealth < 1 || client->pers.maxHealth > 100 ) { client->pers.maxHealth = 100; } #endif client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; // set model if( g_gametype.integer >= GT_TEAM ) { Q_strncpyz( model, Info_ValueForKey (userinfo, "team_model"), sizeof( model ) ); Q_strncpyz( headModel, Info_ValueForKey (userinfo, "team_headmodel"), sizeof( headModel ) ); } else { Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) ); Q_strncpyz( headModel, Info_ValueForKey (userinfo, "headmodel"), sizeof( headModel ) ); } // bots set their team a few frames later if (g_gametype.integer >= GT_TEAM && g_entities[clientNum].r.svFlags & SVF_BOT) { s = Info_ValueForKey( userinfo, "team" ); if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) { team = TEAM_RED; } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) { team = TEAM_BLUE; } else { // pick the team with the least number of players team = PickTeam( clientNum ); } } else { team = client->sess.sessionTeam; } /* NOTE: all client side now // team switch( team ) { case TEAM_RED: ForceClientSkin(client, model, "red"); // ForceClientSkin(client, headModel, "red"); break; case TEAM_BLUE: ForceClientSkin(client, model, "blue"); // ForceClientSkin(client, headModel, "blue"); break; } // don't ever use a default skin in teamplay, it would just waste memory // however bots will always join a team but they spawn in as spectator if ( g_gametype.integer >= GT_TEAM && team == TEAM_SPECTATOR) { ForceClientSkin(client, model, "red"); // ForceClientSkin(client, headModel, "red"); } */ #ifdef MISSIONPACK if (g_gametype.integer >= GT_TEAM) { client->pers.teamInfo = qtrue; } else { s = Info_ValueForKey( userinfo, "teamoverlay" ); if ( ! *s || atoi( s ) != 0 ) { client->pers.teamInfo = qtrue; } else { client->pers.teamInfo = qfalse; } } #else // teamInfo s = Info_ValueForKey( userinfo, "teamoverlay" ); if ( ! *s || atoi( s ) != 0 ) { client->pers.teamInfo = qtrue; } else { client->pers.teamInfo = qfalse; } #endif /* s = Info_ValueForKey( userinfo, "cg_pmove_fixed" ); if ( !*s || atoi( s ) == 0 ) { client->pers.pmoveFixed = qfalse; } else { client->pers.pmoveFixed = qtrue; } */ // team task (0 = none, 1 = offence, 2 = defence) teamTask = atoi(Info_ValueForKey(userinfo, "teamtask")); // team Leader (1 = leader, 0 is normal player) teamLeader = client->sess.teamLeader; // colors strcpy(c1, Info_ValueForKey( userinfo, "color1" )); strcpy(c2, Info_ValueForKey( userinfo, "color2" )); strcpy(redTeam, Info_ValueForKey( userinfo, "g_redteam" )); strcpy(blueTeam, Info_ValueForKey( userinfo, "g_blueteam" )); // send over a subset of the userinfo keys so other clients can // print scoreboards, display models, and play custom sounds if ( ent->r.svFlags & SVF_BOT ) { s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d", client->pers.netname, team, model, headModel, c1, c2, client->pers.maxHealth, client->sess.wins, client->sess.losses, Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader ); } else { s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d", client->pers.netname, client->sess.sessionTeam, model, headModel, redTeam, blueTeam, c1, c2, client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader); } trap_SetConfigstring( CS_PLAYERS+clientNum, s ); // this is not the userinfo, more like the configstring actually G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s ); }
/* LQ3A: Added bBroadcast parameter to allow the calling function to suppress the change. */ void SetTeam( gentity_t *ent, char *s, qboolean bBroadcast) { /* LQ3A */ team_t team, oldTeam; gclient_t *client; int clientNum; spectatorState_t specState; int specClient; int teamLeader; // // see what change is requested // client = ent->client; clientNum = client - level.clients; specClient = 0; specState = SPECTATOR_NOT; if ( !Q_stricmp( s, "scoreboard" ) || !Q_stricmp( s, "score" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_SCOREBOARD; } else if ( !Q_stricmp( s, "follow1" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FOLLOW; specClient = -1; } else if ( !Q_stricmp( s, "follow2" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FOLLOW; specClient = -2; } else if ( !Q_stricmp( s, "spectator" ) || !Q_stricmp( s, "s" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FREE; } else if ( g_gametype.integer >= GT_TEAM ) { // if running a team game, assign player to one of the teams specState = SPECTATOR_NOT; if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) { team = TEAM_RED; } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) { team = TEAM_BLUE; } else { // pick the team with the least number of players team = PickTeam( clientNum ); } if ( g_teamForceBalance.integer ) { int counts[TEAM_NUM_TEAMS]; counts[TEAM_BLUE] = TeamCount( ent->client->ps.clientNum, TEAM_BLUE ); counts[TEAM_RED] = TeamCount( ent->client->ps.clientNum, TEAM_RED ); // We allow a spread of two if ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) { trap_SendServerCommand( ent->client->ps.clientNum, "cp \"Red team has too many players.\n\"" ); return; // ignore the request } if ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) { trap_SendServerCommand( ent->client->ps.clientNum, "cp \"Blue team has too many players.\n\"" ); return; // ignore the request } // It's ok, the team we are switching to has less or same number of players } } else { // force them to spectators if there aren't any spots free /* LQ3A */ team = ((client->sess.sessionTeam == TEAM_FREE) || ((client->sess.sessionTeam != TEAM_FREE) && LQ3A_GetVacantPlayerSlots())) ? TEAM_FREE : TEAM_SPECTATOR; } // override decision if limiting the players if ( (g_gametype.integer == GT_TOURNAMENT) && level.numNonSpectatorClients >= 2 ) { team = TEAM_SPECTATOR; } else if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients > g_maxGameClients.integer ) { team = TEAM_SPECTATOR; } // // decide if we will allow the change // oldTeam = client->sess.sessionTeam; /* LQ3A */ if ( team == oldTeam /*&& team != TEAM_SPECTATOR*/ ) { return; } /* LQ3A: Ensure we're allowed to spectate. */ if ((team == TEAM_SPECTATOR) && !LQ3A_CanClientSpectate(ent)) { return; } // // execute the team change // // if the player was dead leave the body if ( client->ps.stats[STAT_HEALTH] <= 0 ) { CopyToBodyQue(ent); } // he starts at 'base' client->pers.teamState.state = TEAM_BEGIN; /* LQ3A*/ if (oldTeam == TEAM_SPECTATOR) { ent->r.svFlags &= ~SVF_NOCLIENT; client->pers.enterTime += (level.time - client->sess.spectatorTime); /* Restore the players score. */ client->ps.persistant[PERS_SCORE] = client->pers.iScore; } else if (ent->client->ps.stats[STAT_HEALTH] > 0) { // Kill him (makes sure he loses flags, etc) ent->flags &= ~FL_GODMODE; /* LQ3A: Kill the player if they have too little health. */ if ((g_spectatorFreePass.integer > 0) && (ent->client->ps.stats[STAT_HEALTH] < g_spectatorFreePass.integer)) { ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; player_die (ent, ent, ent, 100000, MOD_SUICIDE); } else { /* LQ3A: Drop items and return flags when we're allowed to become a spectator without commiting suicide. */ // if client is in a nodrop area, don't drop anything (but return CTF flags!) if (!(trap_PointContents(ent->r.currentOrigin, -1) & CONTENTS_NODROP)) { TossClientItems(ent); } else { if (ent->client->ps.powerups[PW_NEUTRALFLAG]) { Team_ReturnFlag(TEAM_FREE); } else if (ent->client->ps.powerups[PW_REDFLAG]) { Team_ReturnFlag(TEAM_RED); } else if (ent->client->ps.powerups[PW_BLUEFLAG]) { Team_ReturnFlag(TEAM_BLUE); } } #ifdef MISSIONPACK TossClientPersistantPowerups(ent); if(g_gametype.integer == GT_HARVESTER) { TossClientCubes(ent); } #endif } } // they go to the end of the line for tournements if ( team == TEAM_SPECTATOR ) { /* LQ3A */ LQ3A_CompleteClientMoveToSpectatorTeam(ent); } client->sess.sessionTeam = team; client->sess.spectatorState = specState; client->sess.spectatorClient = specClient; client->sess.teamLeader = qfalse; if ( team == TEAM_RED || team == TEAM_BLUE ) { teamLeader = TeamLeader( team ); // if there is no team leader or the team leader is a bot and this client is not a bot if ( teamLeader == -1 || ( !(g_entities[clientNum].r.svFlags & SVF_BOT) && (g_entities[teamLeader].r.svFlags & SVF_BOT) ) ) { SetLeader( team, clientNum ); } } // make sure there is a team leader on the team the player came from if ( oldTeam == TEAM_RED || oldTeam == TEAM_BLUE ) { CheckTeamLeader( oldTeam ); } /* LQ3A: Broadcast the change when instructed to do so. */ if (bBroadcast) { BroadcastTeamChange(client, oldTeam); } // get and distribute relevent paramters ClientUserinfoChanged( clientNum ); /* LQ3A */ if (team != TEAM_SPECTATOR) { /* Spawn the client into the game. */ ClientBegin(clientNum); } else { /* Update the cached scores. */ CalculateRanks(); } }
//[TABBot] //added bot type varible static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname, int bottype) { //static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) { //[/TABBot] int clientNum; char *botinfo; gentity_t *bot; char *key; char *s; char *botname; char *model; // char *headmodel; char userinfo[MAX_INFO_STRING]; int preTeam = 0; //[DuelGuns][EnhancedImpliment] /* char *firearm; // ** change gun model qboolean bot_dualguns = qfalse; int gunoption=0; */ //[/DuelGuns][EnhancedImpliment] // get the botinfo from bots.txt botinfo = G_GetBotInfoByName( name ); if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } // check for an alternative name if (altname && altname[0]) { botname = altname; } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) ); if ( skill >= 1 && skill < 2 ) { Info_SetValueForKey( userinfo, "handicap", "50" ); } else if ( skill >= 2 && skill < 3 ) { Info_SetValueForKey( userinfo, "handicap", "70" ); } else if ( skill >= 3 && skill < 4 ) { Info_SetValueForKey( userinfo, "handicap", "90" ); } key = "model"; model = Info_ValueForKey( botinfo, key ); if ( !*model ) { model = "kyle/default"; } Info_SetValueForKey( userinfo, key, model ); /* key = "headmodel"; headmodel = Info_ValueForKey( botinfo, key ); if ( !*headmodel ) { headmodel = model; } Info_SetValueForKey( userinfo, key, headmodel ); key = "team_headmodel"; Info_SetValueForKey( userinfo, key, headmodel ); */ key = "gender"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "male"; } Info_SetValueForKey( userinfo, "sex", s ); key = "color1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); key = "color2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); key = "saber1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "single_1"; } Info_SetValueForKey( userinfo, key, s ); key = "saber2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "none"; } Info_SetValueForKey( userinfo, key, s ); s = Info_ValueForKey(botinfo, "personality"); if (!*s ) { Info_SetValueForKey( userinfo, "personality", "botfiles/default.jkb" ); } else { Info_SetValueForKey( userinfo, "personality", s ); } //[DuelGuns][EnhancedImpliment] /* // if(1)//f_dualguns.integer) // { key = "dualgun"; s = Info_ValueForKey(botinfo, key); if (*s) { gunoption = atoi(s); } if(gunoption>0) bot_dualguns = qtrue; // } firearm = Info_ValueForKey( botinfo, "firearm"); if (!*firearm) { Info_SetValueForKey( userinfo, "firearm", botname ); } else { Info_SetValueForKey( userinfo, "firearm", firearm); } */ //[/DuelGuns][EnhancedImpliment] //[RGBSabers] key = "rgb_saber1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "255,0,0"; } Info_SetValueForKey( userinfo, key, s ); key = "rgb_saber2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "0,255,255"; } Info_SetValueForKey( userinfo, key, s ); key = "rgb_script1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "none"; } Info_SetValueForKey( userinfo, key, s ); key = "rgb_script2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "none"; } Info_SetValueForKey( userinfo, key, s ); //[/RGBSabers] //[ClientPlugInDetect] //set it so that the bots are assumed to have the OJP client plugin //this should be CURRENT_OJPENHANCED_CLIENTVERSION Info_SetValueForKey( userinfo, "ojp_clientplugin", CURRENT_OJPENHANCED_CLIENTVERSION ); //[/ClientPlugInDetect] // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if ( clientNum == -1 ) { // G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); // G_Printf( S_COLOR_RED "Start server with more 'open' slots.\n" ); trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "UNABLE_TO_ADD_BOT"))); return; } //[DuelGuns][EnhancedImpliment] /* if(bot_dualguns) { g_entities[clientNum].client->ps.dualguns = 1; } */ //[/DuelGuns][EnhancedImpliment] // initialize the bot settings if( !team || !*team ) { if( g_gametype.integer >= GT_TEAM ) { //[AdminSys] if( PickTeam(clientNum, qtrue) == TEAM_RED) { //if( PickTeam(clientNum) == TEAM_RED) { //[/AdminSys] team = "red"; } else { team = "blue"; } } else { team = "red"; } } // Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) ); Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) ); Info_SetValueForKey( userinfo, "team", team ); //[TABBot] Info_SetValueForKey( userinfo, "bottype", va( "%i", bottype) ); //[/TABBot] bot = &g_entities[ clientNum ]; bot->r.svFlags |= SVF_BOT; bot->inuse = qtrue; // register the userinfo trap_SetUserinfo( clientNum, userinfo ); //[NewGameTypes][EnhancedImpliment] //if (g_gametype.integer >= GT_TEAM && g_gametype.integer != GT_RPG) if (g_gametype.integer >= GT_TEAM) //[/NewGameTypes][EnhancedImpliment] { if (team && Q_stricmp(team, "red") == 0) { bot->client->sess.sessionTeam = TEAM_RED; } else if (team && Q_stricmp(team, "blue") == 0) { bot->client->sess.sessionTeam = TEAM_BLUE; } else { //[AdminSys] bot->client->sess.sessionTeam = PickTeam( -1, qtrue ); //bot->client->sess.sessionTeam = PickTeam( -1 ); //[/AdminSys] } } if (g_gametype.integer == GT_SIEGE) { bot->client->sess.siegeDesiredTeam = bot->client->sess.sessionTeam; bot->client->sess.sessionTeam = TEAM_SPECTATOR; } preTeam = bot->client->sess.sessionTeam; // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue ) ) { return; } if (bot->client->sess.sessionTeam != preTeam) { trap_GetUserinfo(clientNum, userinfo, MAX_INFO_STRING); if (bot->client->sess.sessionTeam == TEAM_SPECTATOR) { bot->client->sess.sessionTeam = preTeam; } if (bot->client->sess.sessionTeam == TEAM_RED) { team = "Red"; } else { if (g_gametype.integer == GT_SIEGE) { if (bot->client->sess.sessionTeam == TEAM_BLUE) { team = "Blue"; } else { team = "s"; } } else { team = "Blue"; } } Info_SetValueForKey( userinfo, "team", team ); trap_SetUserinfo( clientNum, userinfo ); bot->client->ps.persistant[ PERS_TEAM ] = bot->client->sess.sessionTeam; G_ReadSessionData( bot->client ); ClientUserinfoChanged( clientNum ); } if (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) { int loners = 0; int doubles = 0; bot->client->sess.duelTeam = 0; G_PowerDuelCount(&loners, &doubles, qtrue); if (!doubles || loners > (doubles/2)) { bot->client->sess.duelTeam = DUELTEAM_DOUBLE; } else { bot->client->sess.duelTeam = DUELTEAM_LONE; } bot->client->sess.sessionTeam = TEAM_SPECTATOR; SetTeam(bot, "s"); } else { if( delay == 0 ) { ClientBegin( clientNum, qfalse ); //UNIQUEFIX - what's the purpose of this? //ClientUserinfoChanged( clientNum ); return; } AddBotToSpawnQueue( clientNum, delay ); //UNIQUEFIX - what's the purpose of this? //ClientUserinfoChanged( clientNum ); } }
/** Called from ClientConnect when the player first connects and directly by the server system when the player updates a userinfo variable. The game can override any of the settings and call trap_SetUserinfo if desired. */ void ClientUserinfoChanged(int clientNum) { gentity_t *ent; int teamTask, teamLeader, team, health; char *s; char oldname[MAX_STRING_CHARS]; gclient_t *client; char userinfo[MAX_INFO_STRING]; char *nameError; ent = g_entities + clientNum; client = ent->client; trap_GetUserinfo(clientNum, userinfo, sizeof(userinfo)); // check for malformed or illegal info strings if (!Info_Validate(userinfo)) { strcpy (userinfo, "\\name\\badinfo"); // don't keep those clients and userinfo trap_DropClient(clientNum, "Invalid userinfo"); } // check for local client s = Info_ValueForKey(userinfo, "ip"); if (!strcmp(s, "localhost")) { client->pers.localClient = qtrue; } // check the item prediction s = Info_ValueForKey(userinfo, "cg_predictItems"); if (!atoi(s)) { client->pers.predictItemPickup = qfalse; } else { client->pers.predictItemPickup = qtrue; } // set name Q_strncpyz(oldname, client->pers.netname, sizeof(oldname)); s = Info_ValueForKey(userinfo, "name"); nameError = ClientCleanName(s, client->pers.netname, sizeof client->pers.netname); if (client->pers.connected == CON_CONNECTED && strcmp(oldname, s)) { if (client->pers.muted) { ClientPrint(ent, "You cannot change your name while you are muted."); } else if (nameError) { ClientPrint(ent, "%s", nameError); } else { G_LogPrintf("%s ^7renamed to %s\n", oldname, client->pers.netname); } if (nameError || client->pers.muted) { Q_strncpyz(client->pers.netname, oldname, sizeof client->pers.netname); } } if (client->sess.sessionTeam == TEAM_SPECTATOR) { if (client->sess.spectatorState == SPECTATOR_SCOREBOARD) { Q_strncpyz(client->pers.netname, "scoreboard", sizeof(client->pers.netname)); } } // set max health health = atoi(Info_ValueForKey(userinfo, "handicap")); client->pers.maxHealth = health; if (client->pers.maxHealth < 1 || client->pers.maxHealth > 100) { client->pers.maxHealth = 100; } client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth; // bots set their team a few frames later if (g_gametype.integer >= GT_TEAM && g_entities[clientNum].r.svFlags & SVF_BOT) { s = Info_ValueForKey(userinfo, "team"); if (!Q_stricmp(s, "red") || !Q_stricmp(s, "r")) { team = TEAM_RED; } else if (!Q_stricmp(s, "blue") || !Q_stricmp(s, "b")) { team = TEAM_BLUE; } else { // pick the team with the least number of players team = PickTeam(clientNum); } } else { team = client->sess.sessionTeam; } // team task (0 = none, 1 = offence, 2 = defence) teamTask = atoi(Info_ValueForKey(userinfo, "teamtask")); // team Leader (1 = leader, 0 is normal player) teamLeader = client->sess.teamLeader; // send over a subset of the userinfo keys so other clients can // print scoreboards, display models, and play custom sounds if (ent->r.svFlags & SVF_BOT) { s = va("n\\%s\\t\\%i\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d", client->pers.netname, team, client->pers.maxHealth, client->sess.wins, client->sess.losses, Info_ValueForKey(userinfo, "skill"), teamTask, teamLeader); } else { s = va("n\\%s\\t\\%i\\s\\%d\\r\\%i\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d", client->pers.netname, team, client->sess.specOnly, client->pers.ready, client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader); } trap_SetConfigstring(CS_PLAYERS+clientNum, s); // this is not the userinfo, more like the configstring actually G_LogPrintf("ClientUserinfoChanged: %i %s\n", clientNum, s); }
/* =============== G_AddBot =============== */ static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) { int clientNum; char *botinfo; gentity_t *bot; char *key; char *s; char *botname; char *model; char *headmodel; char *logo; char userinfo[MAX_INFO_STRING]; // get the botinfo from bots.txt botinfo = G_GetBotInfoByName( name ); if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } // check for an alternative name if (altname && altname[0]) { botname = altname; } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) ); if ( skill >= 1 && skill < 2 ) { Info_SetValueForKey( userinfo, "handicap", "50" ); } else if ( skill >= 2 && skill < 3 ) { Info_SetValueForKey( userinfo, "handicap", "70" ); } else if ( skill >= 3 && skill < 4 ) { Info_SetValueForKey( userinfo, "handicap", "90" ); } key = "spraylogo"; logo = Info_ValueForKey( botinfo, key); if ( !*logo ) { logo = "15_padlogo"; } Info_SetValueForKey( userinfo, key, logo ); key = "model"; model = Info_ValueForKey( botinfo, key ); if ( !*model ) { model = "padman/default"; } else if ( g_gametype.integer < GT_TEAM ) { // If a team is given, but we're not in a team-gametype // this is caused by the ui, so we're forcing a skin. // This is rather nasty.. // TODO: Check whether the resulting model exists if ( *team ) { char *color = NULL; if ( !Q_stricmp( team, "red" ) || !Q_stricmp( team, "r" ) || !Q_stricmp( team, "0" ) ) { color = "red"; } else if ( !Q_stricmp( team, "blue" ) || !Q_stricmp( team, "b" ) || !Q_stricmp( team, "1" ) ) { color = "blue"; } // user decided to add a skin and specify a team // use skin color (way easier to implement) // FIXME: Explicitly search for color after ('/' or) '_' if ( strstr( model, "_red" ) || strstr( model, "_blue" ) ) { color = NULL; } if ( color ) { if ( strrchr( model, '/' ) ) { // model is a skin already, append colorname to skin // fatpad/fatty _red model = va( "%s_%s", model, color ); } else { // model is a "basemodel", append skin // fatpad /red model = va( "%s/%s", model, color ); } } } } Info_SetValueForKey( userinfo, key, model ); key = "team_model"; Info_SetValueForKey( userinfo, key, model ); key = "headmodel"; headmodel = Info_ValueForKey( botinfo, key ); if ( !*headmodel ) { headmodel = model; } Info_SetValueForKey( userinfo, key, headmodel ); key = "team_headmodel"; Info_SetValueForKey( userinfo, key, headmodel ); key = "gender"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "male"; } Info_SetValueForKey( userinfo, "sex", s ); key = "color1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); key = "color2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "5"; } Info_SetValueForKey( userinfo, key, s ); s = Info_ValueForKey(botinfo, "aifile"); if (!*s ) { trap_Printf( S_COLOR_RED "Error: bot has no aifile specified\n" ); return; } // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if ( clientNum == -1 ) { G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" ); return; } // initialize the bot settings if( !team || !*team ) { if( g_gametype.integer >= GT_TEAM ) { if( PickTeam(clientNum) == TEAM_RED) { team = "red"; } else { team = "blue"; } } else { team = "red"; } } Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) ); Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) ); Info_SetValueForKey( userinfo, "team", team ); bot = &g_entities[ clientNum ]; bot->r.svFlags |= SVF_BOT; bot->inuse = qtrue; // register the userinfo trap_SetUserinfo( clientNum, userinfo ); // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue ) ) { return; } if( delay == 0 ) { ClientBegin( clientNum ); return; } AddBotToSpawnQueue( clientNum, delay ); }
/* ================== G_SpawnBot ================== */ void G_SpawnBot( const char *text ) { // bot parameters char name[MAX_TOKEN_CHARS] = "wolfBot"; //GS prevent bot health from counting down to 70 (i.e. don't set STAT_MAX_HEALTH = 70) char skill[MAX_TOKEN_CHARS] = "4"; char team[MAX_TOKEN_CHARS] = ""; char pClass[MAX_TOKEN_CHARS] = ""; char pWeapon[MAX_TOKEN_CHARS] = "0"; char spawnPoint[MAX_TOKEN_CHARS] = ""; char respawn[MAX_TOKEN_CHARS] = ""; char scriptName[MAX_TOKEN_CHARS] = "wolfBot"; char characterFile[MAX_TOKEN_CHARS] = ""; // START - Mad Doc - TDF char rank[MAX_TOKEN_CHARS] = ""; char botSkills[MAX_TOKEN_CHARS] = ""; // END Mad Doc - TDF char pow[MAX_TOKEN_CHARS] = "no"; // This is the selection meny index used in SetWolfSpawnWeapons int weaponSpawnNumber = -1; // parsing vars char *token, *pStr, *old_pStr; char cmd[MAX_TOKEN_CHARS], last_cmd[MAX_TOKEN_CHARS]; char cmd_var[MAX_TOKEN_CHARS]; char string[MAX_TOKEN_CHARS]; int j, pClassInt; int characterInt, rankNum; int skills[SK_NUM_SKILLS]; qboolean prisonerOfWar; int teamNum; // parameters spawnBotCommand_t params[] = { {"/name", name, qfalse, "[name]"}, {"/skill", skill, qfalse, "[0-4]"}, {"/team", team, qfalse, "[AXIS/ALLIES]"}, {"/class", pClass, qfalse, "[SOLDIER/MEDIC/LIEUTENANT/ENGINEER/COVERTOPS/FIELDOPS]"}, // FIXME: remove LIEUTENANT from missionpack {"/weapon", pWeapon, qfalse, "[weaponValue]"}, {"/spawnpoint", spawnPoint, qtrue, "[targetname]"}, {"/respawn", respawn, qfalse, "[ON/OFF]"}, {"/scriptName", scriptName, qfalse, "[scriptName]"}, {"/character", characterFile, qfalse, "[character]"}, // START Mad Doc - TDF {"/rank", rank, qfalse, "[rank]"}, {"/skills", botSkills, qfalse, "[botskills]"}, // not really to be exposed to script // END Mad Doc - TDF {"/pow", pow, qfalse, "[yes/no]"}, {NULL} }; // special tables typedef struct { char *weapon; int index; } spawnBotWeapons_t; // TAT 1/16/2003 - uninit'ed data here - getting crazy data for the skills memset(&skills, 0, sizeof(skills)); // // parse the vars pStr = (char *)text; token = COM_Parse( &pStr ); Q_strncpyz( cmd, token, sizeof(cmd) ); // if this is a question mark, show help info if (!Q_stricmp( cmd, "?" ) || !Q_stricmp( cmd, "/?" )) { G_Printf( "Spawns a bot into the game, with the given parameters.\n\nSPAWNBOT [/param [value]] [/param [value]] ...\n\n where [/param [value]] may consist of:\n\n" ); for (j=0; params[j].cmd; j++) { G_Printf( " %s %s\n", params[j].cmd, params[j].help ); } return; } // // intitializations for (j=0; params[j].cmd; j++) { params[j].count = 0; } memset( last_cmd, 0, sizeof(last_cmd) ); pStr = (char *)text; // // parse each command while (cmd[0]) { // // build the string up to the next parameter change token = COM_Parse( &pStr ); Q_strncpyz( cmd, token, sizeof(cmd) ); if (!cmd[0]) break; // if we find an "or", then use the last command if (!Q_stricmp( cmd, "or" )) { // use the last command Q_strncpyz( cmd, last_cmd, sizeof(cmd) ); } // // read the parameters memset( string, 0, sizeof(string) ); token = COM_Parse( &pStr ); Q_strncpyz( cmd_var, token, sizeof(cmd_var) ); if (!cmd_var[0]) break; while (qtrue) { Q_strcat( string, sizeof(string), cmd_var ); old_pStr = pStr; token = COM_Parse( &pStr ); Q_strncpyz( cmd_var, token, sizeof(cmd_var) ); if (cmd_var[0] && (cmd_var[0] == '/' || !Q_stricmp( cmd_var, "or" ))) { pStr = old_pStr; break; } if (!cmd_var[0]) break; Q_strcat( string, sizeof(string), " " ); } // // see if this command exists in the parameters table for (j=0; params[j].cmd; j++) { if (!Q_stricmp( params[j].cmd, cmd )) { // found a match, if this field already has an entry, then randomly override it if (!params[j].count || (!params[j].appendParams && ((rand()%(++params[j].count)) == 0))) { Q_strncpyz( params[j].string, string, sizeof(string) ); } else if (params[j].appendParams) { // append this token Q_strcat( params[j].string, sizeof(string), va(" %s", string) ); } params[j].count++; break; } } if (!params[j].cmd) { G_Printf( "G_SpawnBot: unknown parameter: %s\nFor usage info, use \"spawnbot /?\"\n", cmd ); return; } // Q_strncpyz( last_cmd, cmd, sizeof(last_cmd) ); Q_strncpyz( cmd, cmd_var, sizeof(cmd) ); } // if (strlen( pClass )) { pClassInt = 1 + G_ClassForString( pClass ); } else { pClassInt = 0; } if ( !Q_stricmp( team, "red" ) || !Q_stricmp( team, "r" ) || !Q_stricmp( team, "axis" ) ) { teamNum = TEAM_AXIS; } else if ( !Q_stricmp( team, "blue" ) || !Q_stricmp( team, "b" ) || !Q_stricmp( team, "allies" ) ) { teamNum = TEAM_ALLIES; } else { // pick the team with the least number of players teamNum = PickTeam( -1 ); } G_BotParseCharacterParms( characterFile, &characterInt ); // Gordon: 27/11/02 if( *pow && !Q_stricmp(pow, "yes") ) { prisonerOfWar = qtrue; } else { prisonerOfWar = qfalse; } // START Mad Doc - TDF // special case: if "NONE" is specified, treat this differently if (!Q_stricmp(pWeapon, "NONE")) { weaponSpawnNumber = -1; } // END Mad Doc - TDF // START Mad Doctor I changes, 8/17/2002. // If we have a weapon specified, and we have a class specified else if (isdigit(pWeapon[0])) { // Just convert the string to a number weaponSpawnNumber = atoi(pWeapon); } // if (isdigit(pWeapon[0]))... // If we have a weapon specified as a string, and we have a class specified else if (pClassInt > 0) { // Translate the weapon name into a proper weapon index // Get the index for the weapon weaponSpawnNumber = Bot_GetWeaponForClassAndTeam( pClassInt - 1, teamNum, pWeapon ); // Get default weapon if (weaponSpawnNumber == -1) weaponSpawnNumber = BG_GetPlayerClassInfo( teamNum, pClassInt - 1 )->classWeapons[0]; } // if (Q_stricmp(pWeapon[MAX_TOKEN_CHARS], "0")... // Otherwise, no weapon is selected else { // Just use the default weaponSpawnNumber = BG_GetPlayerClassInfo( teamNum, pClassInt - 1 )->classWeapons[0]; } // else... // START Mad Doc - TDF rankNum = atoi(rank); if( rankNum ) { rankNum--; // people like to start with 1 // Gordon: coders are people too :( } if (botSkills[0]) { // parse the skills out int i; char *pString, *token; pString = botSkills; for (i = 0; i < SK_NUM_SKILLS; i++) { token = COM_ParseExt( &pString, qfalse ); skills[i] = atoi(token); } } // {"/botskills", botSkills, qfalse, "[botskills]"}, // not really to be exposed to script // END Mad Doc - TDF G_AddBot( name, atoi(skill), team, spawnPoint, pClassInt, weaponSpawnNumber, characterInt, respawn, scriptName, rankNum, skills, prisonerOfWar ); // END Mad Doctor I changes, 8/17/2002. }
/* =============== G_AddBot =============== */ static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) { int clientNum; char *botinfo; gentity_t *bot; char *key; char *s; char *botname; char *model; // char *headmodel; char userinfo[MAX_INFO_STRING]; int preTeam = 0; // get the botinfo from bots.txt botinfo = G_GetBotInfoByName( name ); if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } // check for an alternative name if (altname && altname[0]) { botname = altname; } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) ); if ( skill >= 1 && skill < 2 ) { Info_SetValueForKey( userinfo, "handicap", "50" ); } else if ( skill >= 2 && skill < 3 ) { Info_SetValueForKey( userinfo, "handicap", "70" ); } else if ( skill >= 3 && skill < 4 ) { Info_SetValueForKey( userinfo, "handicap", "90" ); } key = "model"; model = Info_ValueForKey( botinfo, key ); if ( !*model ) { model = "kyle/default"; } Info_SetValueForKey( userinfo, key, model ); /* key = "headmodel"; headmodel = Info_ValueForKey( botinfo, key ); if ( !*headmodel ) { headmodel = model; } Info_SetValueForKey( userinfo, key, headmodel ); key = "team_headmodel"; Info_SetValueForKey( userinfo, key, headmodel ); */ key = "gender"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "male"; } Info_SetValueForKey( userinfo, "sex", s ); key = "color1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); key = "color2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); key = "saber1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "single_1"; } Info_SetValueForKey( userinfo, key, s ); key = "saber2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "none"; } Info_SetValueForKey( userinfo, key, s ); s = Info_ValueForKey(botinfo, "personality"); if (!*s ) { Info_SetValueForKey( userinfo, "personality", "botfiles/default.jkb" ); } else { Info_SetValueForKey( userinfo, "personality", s ); } // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if ( clientNum == -1 ) { // G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); // G_Printf( S_COLOR_RED "Start server with more 'open' slots.\n" ); trap_SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "UNABLE_TO_ADD_BOT"))); return; } // initialize the bot settings if( !team || !*team ) { if( g_gametype.integer >= GT_TEAM ) { if( PickTeam(clientNum) == TEAM_RED) { team = "red"; } else { team = "blue"; } } else { team = "red"; } } // Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) ); Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) ); Info_SetValueForKey( userinfo, "team", team ); bot = &g_entities[ clientNum ]; bot->r.svFlags |= SVF_BOT; bot->inuse = qtrue; // register the userinfo trap_SetUserinfo( clientNum, userinfo ); if (g_gametype.integer >= GT_TEAM) { if (team && Q_stricmp(team, "red") == 0) { bot->client->sess.sessionTeam = TEAM_RED; } else if (team && Q_stricmp(team, "blue") == 0) { bot->client->sess.sessionTeam = TEAM_BLUE; } else { bot->client->sess.sessionTeam = PickTeam( -1 ); } } if (g_gametype.integer == GT_SIEGE) { bot->client->sess.siegeDesiredTeam = bot->client->sess.sessionTeam; bot->client->sess.sessionTeam = TEAM_SPECTATOR; } preTeam = bot->client->sess.sessionTeam; // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue ) ) { return; } if (bot->client->sess.sessionTeam != preTeam) { trap_GetUserinfo(clientNum, userinfo, MAX_INFO_STRING); if (bot->client->sess.sessionTeam == TEAM_SPECTATOR) { bot->client->sess.sessionTeam = preTeam; } if (bot->client->sess.sessionTeam == TEAM_RED) { team = "Red"; } else { if (g_gametype.integer == GT_SIEGE) { if (bot->client->sess.sessionTeam == TEAM_BLUE) { team = "Blue"; } else { team = "s"; } } else { team = "Blue"; } } Info_SetValueForKey( userinfo, "team", team ); trap_SetUserinfo( clientNum, userinfo ); bot->client->ps.persistant[ PERS_TEAM ] = bot->client->sess.sessionTeam; G_ReadSessionData( bot->client ); ClientUserinfoChanged( clientNum ); } if (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) { int loners = 0; int doubles = 0; bot->client->sess.duelTeam = 0; G_PowerDuelCount(&loners, &doubles, qtrue); if (!doubles || loners > (doubles/2)) { bot->client->sess.duelTeam = DUELTEAM_DOUBLE; } else { bot->client->sess.duelTeam = DUELTEAM_LONE; } bot->client->sess.sessionTeam = TEAM_SPECTATOR; SetTeam(bot, "s"); } else { if( delay == 0 ) { ClientBegin( clientNum, qfalse ); return; } AddBotToSpawnQueue( clientNum, delay ); } }
void G_InitSessionData( gclient_t *client, char *userinfo, qboolean isBot, qboolean firstTime ) { clientSession_t *sess; const char *value; sess = &client->sess; client->sess.siegeDesiredTeam = TEAM_FREE; // initial team determination if ( g_gametype.integer >= GT_TEAM ) { if ( g_teamAutoJoin.integer ) { sess->sessionTeam = PickTeam( -1 ); } else { // always spawn as spectator in team games if (!isBot) { sess->sessionTeam = TEAM_SPECTATOR; } else { //Bots choose their team on creation value = Info_ValueForKey( userinfo, "team" ); if (value[0] == 'r' || value[0] == 'R') { sess->sessionTeam = TEAM_RED; } else if (value[0] == 'b' || value[0] == 'B') { sess->sessionTeam = TEAM_BLUE; } else { sess->sessionTeam = PickTeam( -1 ); } } } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->sessionTeam = TEAM_SPECTATOR; } else { switch ( g_gametype.integer ) { default: case GT_FFA: case GT_HOLOCRON: case GT_JEDIMASTER: case GT_SINGLE_PLAYER: if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients >= g_maxGameClients.integer ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_DUEL: // if the game is full, go into a waiting mode if ( level.numNonSpectatorClients >= 2 ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_POWERDUEL: { int loners = 0; int doubles = 0; G_PowerDuelCount(&loners, &doubles, qtrue); if (!doubles || loners > (doubles/2)) { sess->duelTeam = DUELTEAM_DOUBLE; } else { sess->duelTeam = DUELTEAM_LONE; } } sess->sessionTeam = TEAM_SPECTATOR; break; } } } if (firstTime){ Q_strncpyz(sess->ipString, Info_ValueForKey( userinfo, "ip" ) , sizeof(sess->ipString)); } if ( !getIpPortFromString( sess->ipString, &(sess->ip), &(sess->port) ) ) { sess->ip = 0; sess->port = 0; } sess->nameChangeTime = getGlobalTime(); // accounts system //if (isDBLoaded && !isBot){ // username = Info_ValueForKey(userinfo, "password"); // delimitator = strchr(username,':'); // if (delimitator){ // *delimitator = '\0'; //seperate username and password // Q_strncpyz(client->sess.username,username,sizeof(client->sess.username)); // } else { // client->sess.username[0] = '\0'; // } //} else { client->sess.username[0] = '\0'; } sess->isInkognito = qfalse; sess->ignoreFlags = 0; sess->canJoin = !sv_passwordlessSpectators.integer || PasswordMatches( Info_ValueForKey( userinfo, "password" ) ); sess->whTrustToggle = qfalse; sess->spectatorState = SPECTATOR_FREE; sess->spectatorTime = level.time; sess->inactivityTime = getGlobalTime() + 1000 * g_spectatorInactivity.integer; sess->siegeClass[0] = 0; Q_strncpyz( sess->saberType, Info_ValueForKey( userinfo, "saber1" ), sizeof( sess->saberType ) ); Q_strncpyz( sess->saber2Type, Info_ValueForKey( userinfo, "saber2" ), sizeof( sess->saber2Type ) ); sess->shadowMuted = qfalse; #ifdef NEWMOD_SUPPORT sess->cuidHash[0] = '\0'; sess->serverKeys[0] = sess->serverKeys[1] = 0; sess->auth = level.nmAuthEnabled && *Info_ValueForKey( userinfo, "nm_ver" ) ? PENDING : INVALID; #endif }
static void G_AddBot( const char *name, int skill, const char *team, const char *spawnPoint, int playerClass, int playerWeapon, int characerIndex, const char *respawn, const char *scriptName, int rank, int skills[], qboolean pow ) { #define MAX_BOTNAMES 1024 int clientNum; char *botinfo; gentity_t *bot; char *key; char *s; char *botname; // char *model; char userinfo[MAX_INFO_STRING]; // get the botinfo from bots.txt botinfo = G_GetBotInfoByName( "wolfbot" ); if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%i", skill) ); s = Info_ValueForKey(botinfo, "aifile"); if (!*s ) { trap_Printf( S_COLOR_RED "Error: bot has no aifile specified\n" ); return; } // have the server allocate a client slot clientNum = trap_BotAllocateClient( 0 ); // Arnout: 0 means no prefered clientslot if ( clientNum == -1 ) { G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" ); return; } // initialize the bot settings if( !team || !*team ) { if( PickTeam(clientNum) == TEAM_AXIS) { team = "red"; } else { team = "blue"; } } Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) ); //Info_SetValueForKey( userinfo, "skill", va( "%i", skill ) ); Info_SetValueForKey( userinfo, "team", team ); if( spawnPoint && spawnPoint[0] ) { Info_SetValueForKey( userinfo, "spawnPoint", spawnPoint ); } if (scriptName && scriptName[0]) { Info_SetValueForKey( userinfo, "scriptName", scriptName ); } /* if (playerClass > 0) { Info_SetValueForKey( userinfo, "pClass", va("%i", playerClass) ); } if (playerWeapon) { Info_SetValueForKey( userinfo, "pWeapon", va("%i", playerWeapon) ); }*/ // END Mad Doc - TDF key = "wolfbot"; if (!Q_stricmp( (char *)name, key )) { // read the botnames file, and pick a name that doesnt exist fileHandle_t f; int len, i, j, k; qboolean setname = qfalse; char botnames[8192], *pbotnames, *listbotnames[MAX_BOTNAMES], *token, *oldpbotnames; int lengthbotnames[MAX_BOTNAMES]; len = trap_FS_FOpenFile( "botfiles/botnames.txt", &f, FS_READ ); if (len >= 0) { if (len > sizeof(botnames)) { G_Error( "botfiles/botnames.txt is too big (max = %i)", (int)sizeof(botnames) ); } memset( botnames, 0, sizeof(botnames) ); trap_FS_Read( botnames, len, f ); pbotnames = botnames; // read them in i = 0; oldpbotnames = pbotnames; while ((token = COM_Parse( &pbotnames ))) { if (!token[0]) break; listbotnames[i] = strstr( oldpbotnames, token ); lengthbotnames[i] = strlen(token); listbotnames[i][lengthbotnames[i]] = 0; oldpbotnames = pbotnames; if (++i == MAX_BOTNAMES) break; } // if (i > 2) { j = rand() % (i-1); // start at a random spot inthe list for( k = j + 1; k != j; k++ ) { if( k == i ) { k = -1; // gets increased on next loop continue; } if (ClientFromName( listbotnames[k] ) == -1) { // found an unused name Info_SetValueForKey( userinfo, "name", listbotnames[k] ); setname = qtrue; break; } } } // trap_FS_FCloseFile( f ); } if (!setname) { Info_SetValueForKey( userinfo, "name", va("wolfbot_%i", clientNum+1) ); } } else { Info_SetValueForKey( userinfo, "name", name ); } // if a character was specified, put the index of that character filename in the CS_CHARACTERS table in the userinfo if( characerIndex != -1 ) { Info_SetValueForKey( userinfo, "ch", va( "%i", characerIndex ) ); } // if a rank was specified, use that /* if (rank != -1) { Info_SetValueForKey(userinfo, "rank", va("%i", rank)); }*/ // END Mad Doc - TDF bot = &g_entities[ clientNum ]; bot->r.svFlags |= SVF_BOT; if( pow ) { bot->r.svFlags |= SVF_POW; } bot->inuse = qtrue; bot->aiName = bot->client->pers.netname; // register the userinfo trap_SetUserinfo( clientNum, userinfo ); // have it connect to the game as a normal client if ((s = ClientConnect( clientNum, qtrue, qtrue ))) { G_Printf( S_COLOR_RED "Unable to add bot: %s\n", s ); return; } SetTeam( bot, (char *)team, qtrue, -1, -1, qfalse ); /* if( skills ) { int i; for( i = 0; i < SK_NUM_SKILLS; i++ ) { bot->client->sess.skill[i] = skills[i]; } }*/ return; }
/* =========== ClientBegin called when a client has finished connecting, and is ready to be placed into the level. This will happen every level load, and on transition between teams, but doesn't happen on respawns ============ */ void ClientBegin( int clientNum, qboolean allowTeamReset ) { gentity_t *ent; gclient_t *client; gentity_t *tent; int flags, i; char userinfo[MAX_INFO_VALUE], *modelname; ent = g_entities + clientNum; if ((ent->r.svFlags & SVF_BOT) && g_gametype.integer >= GT_TEAM) { if (allowTeamReset) { const char *team = "Red"; int preSess; //SetTeam(ent, ""); ent->client->sess.sessionTeam = PickTeam(-1); trap_GetUserinfo(clientNum, userinfo, MAX_INFO_STRING); if (ent->client->sess.sessionTeam == TEAM_SPECTATOR) { ent->client->sess.sessionTeam = TEAM_RED; } if (ent->client->sess.sessionTeam == TEAM_RED) { team = "Red"; } else { team = "Blue"; } Info_SetValueForKey( userinfo, "team", team ); trap_SetUserinfo( clientNum, userinfo ); ent->client->ps.persistant[ PERS_TEAM ] = ent->client->sess.sessionTeam; preSess = ent->client->sess.sessionTeam; G_ReadSessionData( ent->client ); ent->client->sess.sessionTeam = preSess; G_WriteClientSessionData(ent->client); ClientUserinfoChanged( clientNum ); ClientBegin(clientNum, qfalse); return; } } client = level.clients + clientNum; if ( ent->r.linked ) { trap_UnlinkEntity( ent ); } G_InitGentity( ent ); ent->touch = 0; ent->pain = 0; ent->client = client; client->pers.connected = CON_CONNECTED; client->pers.enterTime = level.time; client->pers.teamState.state = TEAM_BEGIN; // save eflags around this, because changing teams will // cause this to happen with a valid entity, and we // want to make sure the teleport bit is set right // so the viewpoint doesn't interpolate through the // world to the new position flags = client->ps.eFlags; i = 0; while (i < NUM_FORCE_POWERS) { if (ent->client->ps.fd.forcePowersActive & (1 << i)) { WP_ForcePowerStop(ent, i); } i++; } i = TRACK_CHANNEL_1; while (i < NUM_TRACK_CHANNELS) { if (ent->client->ps.fd.killSoundEntIndex[i-50] && ent->client->ps.fd.killSoundEntIndex[i-50] < MAX_GENTITIES && ent->client->ps.fd.killSoundEntIndex[i-50] > 0) { G_MuteSound(ent->client->ps.fd.killSoundEntIndex[i-50], CHAN_VOICE); } i++; } i = 0; memset( &client->ps, 0, sizeof( client->ps ) ); client->ps.eFlags = flags; client->ps.hasDetPackPlanted = qfalse; //first-time force power initialization WP_InitForcePowers( ent ); //init saber ent WP_SaberInitBladeData( ent ); // First time model setup for that player. trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) ); modelname = Info_ValueForKey (userinfo, "model"); SetupGameGhoul2Model(client, modelname); if (ent->client->ghoul2) { ent->bolt_Head = trap_G2API_AddBolt(ent->client->ghoul2, 0, "cranium"); ent->bolt_Waist = trap_G2API_AddBolt(ent->client->ghoul2, 0, "thoracic"); ent->bolt_LArm = trap_G2API_AddBolt(ent->client->ghoul2, 0, "lradius"); ent->bolt_RArm = trap_G2API_AddBolt(ent->client->ghoul2, 0, "rradius"); ent->bolt_LLeg = trap_G2API_AddBolt(ent->client->ghoul2, 0, "ltibia"); ent->bolt_RLeg = trap_G2API_AddBolt(ent->client->ghoul2, 0, "rtibia"); ent->bolt_Motion = trap_G2API_AddBolt(ent->client->ghoul2, 0, "Motion"); } // locate ent at a spawn point ClientSpawn( ent ); if ( client->sess.sessionTeam != TEAM_SPECTATOR ) { // send event tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN ); tent->s.clientNum = ent->s.clientNum; if ( g_gametype.integer != GT_TOURNAMENT ) { trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " %s\n\"", client->pers.netname, G_GetStripEdString("SVINGAME", "PLENTER")) ); } } G_LogPrintf( "ClientBegin: %i\n", clientNum ); // count current clients and rank for scoreboard CalculateRanks(); G_ClearClientLog(clientNum); }
void SetTeam( gentity_t *ent, char *s ) { int clientNum, specClient=0; team_t team, oldTeam; gclient_t *client = ent->client; spectatorState_t specState = SPECTATOR_NOT; // see what change is requested clientNum = ARRAY_INDEX( level.clients, client ); if ( !Q_stricmp( s, "scoreboard" ) || !Q_stricmp( s, "score" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_SCOREBOARD; } else if ( !Q_stricmp( s, "follow1" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FOLLOW; specClient = -1; } else if ( !Q_stricmp( s, "follow2" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FOLLOW; specClient = -2; } else if ( !Q_stricmp( s, "spectator" ) || !Q_stricmp( s, "s" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FREE; } // if running a team game, assign player to one of the teams else if ( level.gametype >= GT_TEAMBLOOD ) { specState = SPECTATOR_NOT; if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) team = TEAM_RED; else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) team = TEAM_BLUE; else team = PickTeam( clientNum ); // pick the team with the least number of players if ( g_teamForceBalance->integer ) { int counts[TEAM_NUM_TEAMS]; counts[TEAM_BLUE] = TeamCount( clientNum, TEAM_BLUE ); counts[TEAM_RED] = TeamCount( clientNum, TEAM_RED ); // We allow a spread of two if ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) { trap->SV_GameSendServerCommand( clientNum, "cp \"Red team has too many players.\n\"" ); return; // ignore the request } if ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) { trap->SV_GameSendServerCommand( clientNum, "cp \"Blue team has too many players.\n\"" ); return; // ignore the request } // It's ok, the team we are switching to has less or same number of players } } else team = TEAM_FREE; // force them to spectators if there aren't any spots free // override decision if limiting the players if ( (level.gametype == GT_DUEL) && level.numNonSpectatorClients >= 2 ) team = TEAM_SPECTATOR; else if ( g_maxGameClients->integer > 0 && level.numNonSpectatorClients >= g_maxGameClients->integer ) team = TEAM_SPECTATOR; // decide if we will allow the change oldTeam = client->sess.sessionTeam; if ( team == oldTeam && team != TEAM_SPECTATOR ) return; // if the player was dead leave the body if ( client->ps.stats[STAT_HEALTH] <= 0 ) { CopyToBodyQue( ent ); } // he starts at 'base' client->pers.teamState.state = TEAM_BEGIN; if ( oldTeam != TEAM_SPECTATOR ) { // Kill him (makes sure he loses flags, etc) ent->flags &= ~FL_GODMODE; ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; player_die( ent, ent, ent, 100000, MOD_SUICIDE ); } // they go to the end of the line for tournaments if ( team == TEAM_SPECTATOR && oldTeam != team ) AddTournamentQueue( client ); // exploit fix: with 3 (any odd amount?) players connected, one could /callvote map x followed by /team s to force the vote G_ClearVote( ent ); client->sess.sessionTeam = team; client->sess.spectatorState = specState; client->sess.spectatorClient = specClient; BroadcastTeamChange( client, oldTeam ); ClientUserinfoChanged( clientNum ); ClientBegin( clientNum ); }
/* ================ G_InitSessionData Called on a first-time connect ================ */ void G_InitSessionData( gclient_t *client, char *userinfo, qboolean isBot ) { clientSession_t *sess; const char *value; sess = &client->sess; client->sess.siegeDesiredTeam = TEAM_FREE; // initial team determination if ( level.gametype >= GT_TEAM ) { if ( g_teamAutoJoin.integer && !(g_entities[client-level.clients].r.svFlags & SVF_BOT) ) { sess->sessionTeam = PickTeam( -1 ); BroadcastTeamChange( client, -1 ); } else { // always spawn as spectator in team games if (!isBot) { sess->sessionTeam = TEAM_SPECTATOR; } else { //Bots choose their team on creation value = Info_ValueForKey( userinfo, "team" ); if (value[0] == 'r' || value[0] == 'R') { sess->sessionTeam = TEAM_RED; } else if (value[0] == 'b' || value[0] == 'B') { sess->sessionTeam = TEAM_BLUE; } else { sess->sessionTeam = PickTeam( -1 ); } BroadcastTeamChange( client, -1 ); } } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->sessionTeam = TEAM_SPECTATOR; } else { switch ( level.gametype ) { default: case GT_FFA: case GT_HOLOCRON: case GT_JEDIMASTER: case GT_SINGLE_PLAYER: if (!isBot && (!g_maxGameClients.integer || (g_maxGameClients.integer > 0 && //loda fixme - this should fix clients showing ingame when they really arnt , when first connect? level.numNonSpectatorClients >= g_maxGameClients.integer))) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_DUEL: // if the game is full, go into a waiting mode if ( level.numNonSpectatorClients >= 2 ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_POWERDUEL: //sess->duelTeam = DUELTEAM_LONE; //default { int loners = 0; int doubles = 0; G_PowerDuelCount(&loners, &doubles, qtrue); if (!doubles || loners > (doubles/2)) { sess->duelTeam = DUELTEAM_DOUBLE; } else { sess->duelTeam = DUELTEAM_LONE; } } sess->sessionTeam = TEAM_SPECTATOR; break; } } } sess->spectatorState = SPECTATOR_FREE; AddTournamentQueue(client); sess->siegeClass[0] = 0; sess->ignore = 0;//[JAPRO - Serverside - All - Ignore] G_WriteClientSessionData( client ); }
/** LQ3A: Changed return from void to qboolean. This function reads the session data from cvars and assigns a team to the client, if we cannot assign a team it returns qfalse and the client should be dropped from the server. @see ClientConnect(). */ qboolean G_ReadSessionData(gclient_t *client) { char s[MAX_STRING_CHARS]; const char *var; // bk001205 - format int teamLeader; int spectatorState; int sessionTeam; /* LQ3A */ qboolean bCanClientSpectate; var = va( "session%i", client - level.clients ); trap_Cvar_VariableStringBuffer( var, s, sizeof(s) ); sscanf( s, "%i %i %i %i %i %i %i", &sessionTeam, // bk010221 - format &client->sess.spectatorTime, &spectatorState, // bk010221 - format &client->sess.spectatorClient, &client->sess.wins, &client->sess.losses, &teamLeader // bk010221 - format ); /* LQ3A */ bCanClientSpectate = LQ3A_CanClientSpectate(LQ3A_ClientToEntity(client)); /* Place clients into the same teams they were in previously. */ if (g_gametype.integer >= GT_TEAM) { client->sess.sessionTeam = (team_t)sessionTeam; /* Force spectators into the game if we can no longer spectate. */ if ((client->sess.sessionTeam == TEAM_SPECTATOR) && !bCanClientSpectate) { client->sess.sessionTeam = PickTeam(-1); BroadcastTeamChange(client, -1); } } /* Always default as spectator. */ else if (bCanClientSpectate) { client->sess.sessionTeam = TEAM_SPECTATOR; } /* If we cannot spectate, can we join the game? */ else if (LQ3A_GetVacantPlayerSlots()) { client->sess.sessionTeam = TEAM_FREE; } else { /* No vacant player slots and we cannot spectate. */ return qfalse; } if (client->sess.sessionTeam == TEAM_SPECTATOR) { /* Force free floating spectator mode each level load. */ client->sess.spectatorState = SPECTATOR_FREE; client->sess.spectatorClient = 0; } client->sess.teamLeader = (qboolean)teamLeader; /* LQ3A */ return qtrue; }
// Called on a first-time connect void G_InitClientSessionData( gclient_t *client, char *userinfo, qboolean isBot ) { clientSession_t *sess = &client->sess; const char *value; client->sess.siegeDesiredTeam = TEAM_FREE; // initial team determination if ( level.gametype >= GT_TEAM ) { if ( g_teamAutoJoin.integer && !(g_entities[client-level.clients].r.svFlags & SVF_BOT) ) { sess->sessionTeam = PickTeam( -1 ); client->ps.fd.forceDoInit = 1; //every time we change teams make sure our force powers are set right } else { // always spawn as spectator in team games if (!isBot) { sess->sessionTeam = TEAM_SPECTATOR; } else { //Bots choose their team on creation value = Info_ValueForKey( userinfo, "team" ); if (value[0] == 'r' || value[0] == 'R') { sess->sessionTeam = TEAM_RED; } else if (value[0] == 'b' || value[0] == 'B') { sess->sessionTeam = TEAM_BLUE; } else { sess->sessionTeam = PickTeam( -1 ); } client->ps.fd.forceDoInit = 1; //every time we change teams make sure our force powers are set right } } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->sessionTeam = TEAM_SPECTATOR; } else { switch ( level.gametype ) { default: case GT_FFA: case GT_SINGLE_PLAYER: if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients >= g_maxGameClients.integer ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_DUEL: // if the game is full, go into a waiting mode if ( level.numNonSpectatorClients >= 2 ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_POWERDUEL: //sess->duelTeam = DUELTEAM_LONE; //default { int loners = 0; int doubles = 0; G_PowerDuelCount(&loners, &doubles, qtrue); if (!doubles || loners > (doubles/2)) { sess->duelTeam = DUELTEAM_DOUBLE; } else { sess->duelTeam = DUELTEAM_LONE; } } sess->sessionTeam = TEAM_SPECTATOR; break; } } } sess->spectatorState = SPECTATOR_FREE; AddTournamentQueue(client); G_WriteClientSessionData( client ); }
/* ================ G_InitSessionData Called on a first-time connect ================ */ void G_InitSessionData( gclient_t *client, char *userinfo, qboolean isBot ) { clientSession_t *sess; const char *value; sess = &client->sess; client->sess.siegeDesiredTeam = TEAM_FREE; // initial team determination if ( g_gametype.integer >= GT_TEAM ) { if ( g_teamAutoJoin.integer ) { sess->sessionTeam = PickTeam( -1 ); BroadcastTeamChange( client, -1 ); } else { // always spawn as spectator in team games if (!isBot) { sess->sessionTeam = TEAM_SPECTATOR; } else { //Bots choose their team on creation value = Info_ValueForKey( userinfo, "team" ); if (value[0] == 'r' || value[0] == 'R') { sess->sessionTeam = TEAM_RED; } else if (value[0] == 'b' || value[0] == 'B') { sess->sessionTeam = TEAM_BLUE; } else { sess->sessionTeam = PickTeam( -1 ); } BroadcastTeamChange( client, -1 ); } } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->sessionTeam = TEAM_SPECTATOR; } else { switch ( g_gametype.integer ) { default: case GT_FFA: case GT_HOLOCRON: case GT_JEDIMASTER: case GT_SINGLE_PLAYER: if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients >= g_maxGameClients.integer ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_DUEL: // if the game is full, go into a waiting mode if ( level.numNonSpectatorClients >= 2 ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_POWERDUEL: //sess->duelTeam = DUELTEAM_LONE; //default { int loners = 0; int doubles = 0; G_PowerDuelCount(&loners, &doubles, qtrue); if (!doubles || loners > (doubles/2)) { sess->duelTeam = DUELTEAM_DOUBLE; } else { sess->duelTeam = DUELTEAM_LONE; } } sess->sessionTeam = TEAM_SPECTATOR; break; } } } sess->spectatorState = SPECTATOR_FREE; sess->spectatorTime = level.time; sess->siegeClass[0] = 0; sess->saberType[0] = 0; sess->saber2Type[0] = 0; G_WriteClientSessionData( client ); }
/* =============== G_AddBot =============== */ static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) { int clientNum; char *botinfo; gentity_t *bot; char *key; char *s; char *botname; char *model; char *headmodel; char userinfo[MAX_INFO_STRING]; // get the botinfo from bots.txt botinfo = G_GetBotInfoByName( name ); if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } // check for an alternative name if (altname && altname[0]) { botname = altname; } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) ); if ( skill >= 1 && skill < 2 ) { Info_SetValueForKey( userinfo, "handicap", "50" ); } else if ( skill >= 2 && skill < 3 ) { Info_SetValueForKey( userinfo, "handicap", "70" ); } else if ( skill >= 3 && skill < 4 ) { Info_SetValueForKey( userinfo, "handicap", "90" ); } key = "model"; model = Info_ValueForKey( botinfo, key ); if ( !*model ) { model = "sarge/default"; } Info_SetValueForKey( userinfo, key, model ); key = "team_model"; Info_SetValueForKey( userinfo, key, model ); key = "headmodel"; headmodel = Info_ValueForKey( botinfo, key ); if ( !*headmodel ) { headmodel = model; } Info_SetValueForKey( userinfo, key, headmodel ); key = "team_headmodel"; Info_SetValueForKey( userinfo, key, headmodel ); key = "gender"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "male"; } Info_SetValueForKey( userinfo, "sex", s ); key = "color1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); key = "color2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "5"; } Info_SetValueForKey( userinfo, key, s ); s = Info_ValueForKey(botinfo, "aifile"); if (!*s ) { trap_Printf( S_COLOR_RED "Error: bot has no aifile specified\n" ); return; } // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if ( clientNum == -1 ) { G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" ); return; } // initialize the bot settings if( !team || !*team ) { if( g_gametype.integer >= GT_TEAM && g_ffa_gt!=1) { if( PickTeam(clientNum) == TEAM_RED) { team = "red"; } else { team = "blue"; } } else { team = "red"; } } Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) ); Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) ); Info_SetValueForKey( userinfo, "team", team ); bot = &g_entities[ clientNum ]; bot->r.svFlags |= SVF_BOT; bot->inuse = qtrue; // register the userinfo trap_SetUserinfo( clientNum, userinfo ); // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue ) ) { return; } if( delay == 0 ) { ClientBegin( clientNum ); return; } AddBotToSpawnQueue( clientNum, delay ); }
/* ================= SetTeam ================= */ void SetTeam( gentity_t *ent, char *s ) { int team, oldTeam; gclient_t *client; int clientNum; spectatorState_t specState; int specClient; int teamLeader; // // see what change is requested // client = ent->client; clientNum = client - level.clients; specClient = 0; specState = SPECTATOR_NOT; if ( !Q_stricmp( s, "scoreboard" ) || !Q_stricmp( s, "score" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_SCOREBOARD; } else if ( !Q_stricmp( s, "follow1" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FOLLOW; specClient = -1; } else if ( !Q_stricmp( s, "follow2" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FOLLOW; specClient = -2; } else if ( !Q_stricmp( s, "spectator" ) || !Q_stricmp( s, "s" ) ) { team = TEAM_SPECTATOR; specState = SPECTATOR_FREE; } else if ( g_gametype.integer >= GT_TEAM ) { // if running a team game, assign player to one of the teams specState = SPECTATOR_NOT; if ( !Q_stricmp( s, "red" ) || !Q_stricmp( s, "r" ) ) { team = TEAM_RED; } else if ( !Q_stricmp( s, "blue" ) || !Q_stricmp( s, "b" ) ) { team = TEAM_BLUE; } else { // pick the team with the least number of players team = PickTeam( clientNum ); } if ( g_teamForceBalance.integer ) { int counts[TEAM_NUM_TEAMS]; counts[TEAM_BLUE] = TeamCount( clientNum, TEAM_BLUE ); counts[TEAM_RED] = TeamCount( clientNum, TEAM_RED ); // We allow a spread of two if ( team == TEAM_RED && counts[TEAM_RED] - counts[TEAM_BLUE] > 1 ) { trap_SendServerCommand( clientNum, "cp \"Red team has too many players.\n\"" ); return; // ignore the request } if ( team == TEAM_BLUE && counts[TEAM_BLUE] - counts[TEAM_RED] > 1 ) { trap_SendServerCommand( clientNum, "cp \"Blue team has too many players.\n\"" ); return; // ignore the request } // It's ok, the team we are switching to has less or same number of players } } else { // force them to spectators if there aren't any spots free team = TEAM_FREE; } // override decision if limiting the players if ( (g_gametype.integer == GT_TOURNAMENT) && level.numNonSpectatorClients >= 2 ) { team = TEAM_SPECTATOR; } else if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients >= g_maxGameClients.integer ) { team = TEAM_SPECTATOR; } // // decide if we will allow the change // oldTeam = client->sess.sessionTeam; if ( team == oldTeam && team != TEAM_SPECTATOR ) { return; } // // execute the team change // // if the player was dead leave the body if ( client->ps.stats[STAT_HEALTH] <= 0 ) { CopyToBodyQue(ent); } // he starts at 'base' client->pers.teamState.state = TEAM_BEGIN; if ( oldTeam != TEAM_SPECTATOR ) { // Kill him (makes sure he loses flags, etc) ent->flags &= ~FL_GODMODE; ent->client->ps.stats[STAT_HEALTH] = ent->health = 0; player_die (ent, ent, ent, 100000, MOD_SUICIDE); } // they go to the end of the line for tournements if(team == TEAM_SPECTATOR && oldTeam != team) AddTournamentQueue(client); client->sess.sessionTeam = team; client->sess.spectatorState = specState; client->sess.spectatorClient = specClient; client->sess.teamLeader = qfalse; if ( team == TEAM_RED || team == TEAM_BLUE ) { teamLeader = TeamLeader( team ); // if there is no team leader or the team leader is a bot and this client is not a bot if ( teamLeader == -1 || ( !(g_entities[clientNum].r.svFlags & SVF_BOT) && (g_entities[teamLeader].r.svFlags & SVF_BOT) ) ) { SetLeader( team, clientNum ); } } // make sure there is a team leader on the team the player came from if ( oldTeam == TEAM_RED || oldTeam == TEAM_BLUE ) { CheckTeamLeader( oldTeam ); } BroadcastTeamChange( client, oldTeam ); // get and distribute relevent paramters ClientUserinfoChanged( clientNum ); ClientBegin( clientNum ); }
/* =============== G_AddBot =============== */ static void G_AddBot( const char *name, float skill, const char *team, int delay ) { int clientNum; char *botinfo; char *key; char *s; char *botname; char *model; char userinfo[MAX_INFO_STRING]; // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if ( clientNum == -1 ) { G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" ); return; } // get the botinfo from bots.txt botinfo = G_GetBotInfoByName( name ); if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); trap_BotFreeClient( clientNum ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if ( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%.2f", skill) ); if ( skill == 1 ) { Info_SetValueForKey( userinfo, "handicap", "50" ); } else if ( skill == 2 ) { Info_SetValueForKey( userinfo, "handicap", "70" ); } else if ( skill == 3 ) { Info_SetValueForKey( userinfo, "handicap", "90" ); } key = "model"; model = Info_ValueForKey( botinfo, key ); if ( !*model ) { model = "visor/default"; } Info_SetValueForKey( userinfo, key, model ); key = "gender"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "male"; } Info_SetValueForKey( userinfo, "sex", s ); key = "color"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); s = Info_ValueForKey( botinfo, "aifile" ); if ( !*s ) { trap_Print( S_COLOR_RED "Error: bot has no aifile specified\n" ); trap_BotFreeClient( clientNum ); return; } Info_SetValueForKey( userinfo, "characterfile", s ); if ( !team || !*team ) { if ( g_gametype.integer == GT_TEAM || g_gametype.integer == GT_CTF ) { if ( PickTeam( clientNum ) == TEAM_RED ) { team = "red"; } else { team = "blue"; } } else { team = "red"; } } Info_SetValueForKey( userinfo, "team", team ); // register the userinfo trap_SetUserinfo( clientNum, userinfo ); // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue ) ) { return; } if ( delay == 0 ) { ClientBegin( clientNum ); return; } AddBotToSpawnQueue( clientNum, delay ); }
/* =============== G_AddBot =============== */ static void G_AddBot(const char *name, float skill, const char *team, int delay, char *altname) { int clientNum; char *botinfo; gentity_t *bot; char *s; char *botname; char *model; char *headmodel; char userinfo[MAX_INFO_STRING]; weapon_t tpWeapon = WP_M4; holdable_t tpItem = HI_LASER; // get the botinfo from bots.txt botinfo = G_GetBotInfoByName(name); if (!botinfo) { G_Printf(S_COLOR_RED "Error: Bot '%s' not defined\n", name); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey(botinfo, "funname"); if (!botname[0]) { botname = Info_ValueForKey(botinfo, "name"); } // check for an alternative name if (altname && altname[0]) { botname = altname; } Info_SetValueForKey(userinfo, "name", botname); Info_SetValueForKey(userinfo, "rate", "25000"); Info_SetValueForKey(userinfo, "snaps", "20"); Info_SetValueForKey(userinfo, "skill", va("%1.2f", skill)); if (skill >= 1 && skill < 2) { Info_SetValueForKey(userinfo, "handicap", "50"); } else if (skill >= 2 && skill < 3) { Info_SetValueForKey(userinfo, "handicap", "70"); } else if (skill >= 3 && skill < 4) { Info_SetValueForKey(userinfo, "handicap", "90"); } model = Info_ValueForKey(botinfo, "model"); if (!*model) { // Elder: changed to our default model = "reactionmale/default"; } Info_SetValueForKey(userinfo, "model", model); Info_SetValueForKey(userinfo, "team_model", model); headmodel = Info_ValueForKey(botinfo, "headmodel"); if (!*headmodel) { headmodel = model; } Info_SetValueForKey(userinfo, "headmodel", headmodel); Info_SetValueForKey(userinfo, "team_headmodel", headmodel); s = Info_ValueForKey(botinfo, "gender"); if (!*s) { s = "male"; } Info_SetValueForKey(userinfo, "sex", s); s = Info_ValueForKey(botinfo, "color1"); if (!*s) { s = "4"; } Info_SetValueForKey(userinfo, "color1", s); s = Info_ValueForKey(botinfo, "color2"); if (!*s) { s = "5"; } Info_SetValueForKey(userinfo, "color2", s); s = Info_ValueForKey(botinfo, "aifile"); if (!*s) { trap_Printf(S_COLOR_RED "Error: bot has no aifile specified\n"); return; } // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if (clientNum == -1) { G_Printf(S_COLOR_RED "Unable to add bot. All player slots are in use.\n"); G_Printf(S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n"); return; } // initialize the bot settings if (!team || !*team) { if (g_gametype.integer >= GT_TEAM) { if (PickTeam(clientNum) == TEAM_RED) { team = "red"; } else { team = "blue"; } } else { team = "red"; } } Info_SetValueForKey(userinfo, "characterfile", Info_ValueForKey(botinfo, "aifile")); Info_SetValueForKey(userinfo, "skill", va("%5.2f", skill)); Info_SetValueForKey(userinfo, "team", team); if (g_gametype.integer == GT_TEAMPLAY) { //Makro - load custom weapon/item from bot file tpWeapon = CharToWeapon(Info_ValueForKey(botinfo, "weapon"), WP_M4); tpItem = CharToItem(Info_ValueForKey(botinfo, "item"), HI_LASER); } Info_SetValueForKey(userinfo, "tpw", va("%i", tpWeapon - WP_NONE)); Info_SetValueForKey(userinfo, "tpi", va("%i", tpItem - HI_NONE)); bot = &g_entities[clientNum]; bot->r.svFlags |= SVF_BOT; bot->inuse = qtrue; // register the userinfo trap_SetUserinfo(clientNum, userinfo); // have it connect to the game as a normal client if (ClientConnect(clientNum, qtrue, qtrue)) { return; } if (delay == 0) { ClientBegin(clientNum); //Makro - load custom weapon/item from bot file if (g_gametype.integer == GT_TEAMPLAY) { bot->client->teamplayWeapon = tpWeapon; bot->client->teamplayItem = tpItem; } return; } AddBotToSpawnQueue(clientNum, delay); //Makro - load custom weapon/item from bot file if (g_gametype.integer == GT_TEAMPLAY) { bot->client->teamplayWeapon = tpWeapon; bot->client->teamplayItem = tpItem; } }
/* =============== G_AddBot =============== */ static void G_AddBot( const char *name, float skill, const char *team, const char *pclass, int delay, char *altname) { int clientNum; char *botinfo; gentity_t *bot; char *key; char *s; char *botname; char *model; char userinfo[MAX_INFO_STRING]; int preTeam = 0; // get the botinfo from bots.txt botinfo = G_GetBotInfoByName( name ); if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } // check for an alternative name if (altname && altname[0]) { botname = altname; } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%1.2f", skill) ); /* if ( skill >= 1 && skill < 2 ) { Info_SetValueForKey( userinfo, "handicap", "50" ); } else if ( skill >= 2 && skill < 3 ) { Info_SetValueForKey( userinfo, "handicap", "70" ); } else if ( skill >= 3 && skill < 4 ) { Info_SetValueForKey( userinfo, "handicap", "90" ); } */ key = "model"; model = Info_ValueForKey( botinfo, key ); if ( !*model ) { model = "munro/main/default"; //RPG-X MODEL SYSTEM } Info_SetValueForKey( userinfo, key, model ); key = "gender"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "male"; } Info_SetValueForKey( userinfo, "sex", s ); key = "color"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); s = Info_ValueForKey(botinfo, "aifile"); if (!*s ) { trap_Printf( S_COLOR_RED "Error: bot has no aifile specified\n" ); return; } // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if ( clientNum == -1 ) { G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" ); return; } // initialize the bot settings if( !team || !*team ) { if( g_gametype.integer >= GT_TEAM ) { if( PickTeam(clientNum) == TEAM_RED) { team = "red"; } else { team = "blue"; } } else { team = "red"; } } Info_SetValueForKey( userinfo, "characterfile", Info_ValueForKey( botinfo, "aifile" ) ); Info_SetValueForKey( userinfo, "skill", va( "%5.2f", skill ) ); Info_SetValueForKey( userinfo, "team", team ); bot = &g_entities[ clientNum ]; bot->r.svFlags |= SVF_BOT; bot->inuse = qtrue; // register the userinfo trap_SetUserinfo( clientNum, userinfo ); if (g_gametype.integer >= GT_TEAM) { if (team && Q_stricmp(team, "red") == 0) { bot->client->sess.sessionTeam = TEAM_RED; } else if (team && Q_stricmp(team, "blue") == 0) { bot->client->sess.sessionTeam = TEAM_BLUE; } else { bot->client->sess.sessionTeam = PickTeam( -1 ); } } preTeam = bot->client->sess.sessionTeam; // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue ) ) { return; } if (bot->client->sess.sessionTeam != preTeam) { trap_GetUserinfo(clientNum, userinfo, MAX_INFO_STRING); if (bot->client->sess.sessionTeam == TEAM_SPECTATOR) { bot->client->sess.sessionTeam = preTeam; } if (bot->client->sess.sessionTeam == TEAM_RED) { team = "Red"; } else { team = "Blue"; } Info_SetValueForKey( userinfo, "team", team ); trap_SetUserinfo( clientNum, userinfo ); bot->client->ps.persistant[ PERS_TEAM ] = bot->client->sess.sessionTeam; G_ReadSessionData( bot->client ); ClientUserinfoChanged( clientNum ); } if( delay == 0 ) { ClientBegin( clientNum, qfalse, qfalse, qfalse ); return; } AddBotToSpawnQueue( clientNum, delay ); }
/* ================ G_InitSessionData Called on a first-time connect ================ */ void G_InitSessionData( gclient_t *client, char *userinfo, qboolean isBot ) { clientSession_t *sess; const char *value; int clientNum; sess = &client->sess; clientNum = client - level.clients; // initial team determination if ( GT_Team(g_gametype.integer) ) { if ( g_teamAutoJoin.integer ) { sess->sessionTeam = PickTeam( -1 ); } else { // always spawn as spectator in team games if (!isBot) { sess->sessionTeam = TEAM_SPECTATOR; } else { //Bots choose their team on creation value = Info_ValueForKey( userinfo, "team" ); if (value[0] == 'r' || value[0] == 'R') { sess->sessionTeam = ValidateTeam( -1, TEAM_RED ) ? TEAM_RED : TEAM_SPECTATOR; } else if (value[0] == 'b' || value[0] == 'B') { sess->sessionTeam = ValidateTeam( -1, TEAM_BLUE ) ? TEAM_BLUE : TEAM_SPECTATOR; } else { sess->sessionTeam = PickTeam( -1 ); } } } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->sessionTeam = TEAM_SPECTATOR; } else { switch ( g_gametype.integer ) { default: case GT_FFA: case GT_HOLOCRON: case GT_JEDIMASTER: case GT_SINGLE_PLAYER: sess->sessionTeam = ValidateTeam( clientNum, TEAM_FREE ) ? TEAM_FREE : TEAM_SPECTATOR; break; case GT_TOURNAMENT: // if the game is full, go into a waiting mode if ( level.numNonSpectatorClients >= 2 ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; } } } if ( sess->sessionTeam == TEAM_SPECTATOR ) sess->spectatorState = SPECTATOR_FREE; else if ( level.round > 0 && g_gametype.integer != GT_REDROVER ) sess->spectatorState = SPECTATOR_FREE; else sess->spectatorState = SPECTATOR_NOT; sess->spectatorTime = level.time; G_WriteClientSessionData( client ); }
/* =============== G_AddBot =============== */ static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) { gentity_t *bot = NULL; int clientNum, preTeam = TEAM_FREE; char userinfo[MAX_INFO_STRING] = {0}, *botinfo = NULL, *key = NULL, *s = NULL, *botname = NULL, *model = NULL; // have the server allocate a client slot clientNum = trap->BotAllocateClient(); if ( clientNum == -1 ) { // trap->Print( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); // trap->Print( S_COLOR_RED "Start server with more 'open' slots.\n" ); trap->SendServerCommand( -1, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "UNABLE_TO_ADD_BOT"))); return; } // get the botinfo from bots.txt botinfo = G_GetBotInfoByName( name ); if ( !botinfo ) { trap->BotFreeClient( clientNum ); trap->Print( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) botname = Info_ValueForKey( botinfo, "name" ); // check for an alternative name if ( altname && altname[0] ) botname = altname; Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "ip", "localhost" ); Info_SetValueForKey( userinfo, "skill", va("%.2f", skill) ); if ( skill >= 1 && skill < 2 ) Info_SetValueForKey( userinfo, "handicap", "50" ); else if ( skill >= 2 && skill < 3 ) Info_SetValueForKey( userinfo, "handicap", "70" ); else if ( skill >= 3 && skill < 4 ) Info_SetValueForKey( userinfo, "handicap", "90" ); else Info_SetValueForKey( userinfo, "handicap", "100" ); key = "model"; model = Info_ValueForKey( botinfo, key ); if ( !*model ) model = DEFAULT_MODEL"/default"; Info_SetValueForKey( userinfo, key, model ); key = "sex"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = Info_ValueForKey( botinfo, "gender" ); if ( !*s ) s = "male"; Info_SetValueForKey( userinfo, key, s ); key = "color1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "4"; Info_SetValueForKey( userinfo, key, s ); key = "color2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "4"; Info_SetValueForKey( userinfo, key, s ); key = "saber1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = DEFAULT_SABER; Info_SetValueForKey( userinfo, key, s ); key = "saber2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "none"; Info_SetValueForKey( userinfo, key, s ); key = "forcepowers"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = DEFAULT_FORCEPOWERS; Info_SetValueForKey( userinfo, key, s ); key = "cg_predictItems"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "1"; Info_SetValueForKey( userinfo, key, s ); key = "char_color_red"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "255"; Info_SetValueForKey( userinfo, key, s ); key = "char_color_green"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "255"; Info_SetValueForKey( userinfo, key, s ); key = "char_color_blue"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "255"; Info_SetValueForKey( userinfo, key, s ); key = "teamtask"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "0"; Info_SetValueForKey( userinfo, key, s ); key = "personality"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) s = "botfiles/default.jkb"; Info_SetValueForKey( userinfo, key, s ); // initialize the bot settings if ( !team || !*team ) { if ( level.gametype >= GT_TEAM ) { if ( PickTeam( clientNum ) == TEAM_RED) team = "red"; else team = "blue"; } else team = "red"; } Info_SetValueForKey( userinfo, "team", team ); bot = &g_entities[ clientNum ]; // bot->r.svFlags |= SVF_BOT; // bot->inuse = qtrue; // register the userinfo trap->SetUserinfo( clientNum, userinfo ); if ( level.gametype >= GT_TEAM ) { if ( team && !Q_stricmp( team, "red" ) ) bot->client->sess.sessionTeam = TEAM_RED; else if ( team && !Q_stricmp( team, "blue" ) ) bot->client->sess.sessionTeam = TEAM_BLUE; else bot->client->sess.sessionTeam = PickTeam( -1 ); } if ( level.gametype == GT_SIEGE ) { bot->client->sess.siegeDesiredTeam = bot->client->sess.sessionTeam; bot->client->sess.sessionTeam = TEAM_SPECTATOR; } preTeam = bot->client->sess.sessionTeam; // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue ) ) return; if ( bot->client->sess.sessionTeam != preTeam ) { trap->GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); if ( bot->client->sess.sessionTeam == TEAM_SPECTATOR ) bot->client->sess.sessionTeam = preTeam; if ( bot->client->sess.sessionTeam == TEAM_RED ) team = "Red"; else { if ( level.gametype == GT_SIEGE ) team = (bot->client->sess.sessionTeam == TEAM_BLUE) ? "Blue" : "s"; else team = "Blue"; } Info_SetValueForKey( userinfo, "team", team ); trap->SetUserinfo( clientNum, userinfo ); bot->client->ps.persistant[ PERS_TEAM ] = bot->client->sess.sessionTeam; G_ReadSessionData( bot->client ); if ( !ClientUserinfoChanged( clientNum ) ) return; } if (level.gametype == GT_DUEL || level.gametype == GT_POWERDUEL) { int loners = 0; int doubles = 0; bot->client->sess.duelTeam = 0; G_PowerDuelCount(&loners, &doubles, qtrue); if (!doubles || loners > (doubles/2)) { bot->client->sess.duelTeam = DUELTEAM_DOUBLE; } else { bot->client->sess.duelTeam = DUELTEAM_LONE; } bot->client->sess.sessionTeam = TEAM_SPECTATOR; SetTeam(bot, "s"); } else { if( delay == 0 ) { ClientBegin( clientNum, qfalse ); return; } AddBotToSpawnQueue( clientNum, delay ); } }
/* =============== G_AddBot =============== */ static void G_AddBot( const char *name, float skill, const char *team, int delay, char *altname) { int clientNum; int teamNum; int botinfoNum; char *botinfo; char *key; char *s; char *botname; char *model; char *headmodel; char userinfo[MAX_INFO_STRING]; // have the server allocate a client slot clientNum = trap_BotAllocateClient(); if ( clientNum == -1 ) { G_Printf( S_COLOR_RED "Unable to add bot. All player slots are in use.\n" ); G_Printf( S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n" ); return; } // set default team if( !team || !*team ) { if( g_gametype.integer >= GT_TEAM ) { if( PickTeam(clientNum) == TEAM_RED) { team = "red"; } else { team = "blue"; } } else { team = "free"; } } // get the botinfo from bots.txt if ( Q_stricmp( name, "random" ) == 0 ) { if ( Q_stricmp( team, "red" ) == 0 || Q_stricmp( team, "r" ) == 0 ) { teamNum = TEAM_RED; } else if ( Q_stricmp( team, "blue" ) == 0 || Q_stricmp( team, "b" ) == 0 ) { teamNum = TEAM_BLUE; } else if ( !Q_stricmp( team, "spectator" ) || !Q_stricmp( team, "s" ) ) { teamNum = TEAM_SPECTATOR; } else { teamNum = TEAM_FREE; } botinfoNum = G_SelectRandomBotInfo( teamNum ); if ( botinfoNum < 0 ) { G_Printf( S_COLOR_RED "Error: Cannot add random bot, no bot info available.\n" ); trap_BotFreeClient( clientNum ); return; } botinfo = G_GetBotInfoByNumber( botinfoNum ); } else { botinfo = G_GetBotInfoByName( name ); } if ( !botinfo ) { G_Printf( S_COLOR_RED "Error: Bot '%s' not defined\n", name ); trap_BotFreeClient( clientNum ); return; } // create the bot's userinfo userinfo[0] = '\0'; botname = Info_ValueForKey( botinfo, "funname" ); if( !botname[0] ) { botname = Info_ValueForKey( botinfo, "name" ); } // check for an alternative name if (altname && altname[0]) { botname = altname; } Info_SetValueForKey( userinfo, "name", botname ); Info_SetValueForKey( userinfo, "rate", "25000" ); Info_SetValueForKey( userinfo, "snaps", "20" ); Info_SetValueForKey( userinfo, "skill", va("%.2f", skill) ); Info_SetValueForKey( userinfo, "teampref", team ); key = "model"; model = Info_ValueForKey( botinfo, key ); if ( !*model ) { model = "visor/default"; } Info_SetValueForKey( userinfo, key, model ); key = "team_model"; Info_SetValueForKey( userinfo, key, model ); key = "headmodel"; headmodel = Info_ValueForKey( botinfo, key ); if ( !*headmodel ) { headmodel = model; } Info_SetValueForKey( userinfo, key, headmodel ); key = "team_headmodel"; Info_SetValueForKey( userinfo, key, headmodel ); key = "gender"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "male"; } Info_SetValueForKey( userinfo, "sex", s ); key = "color1"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "4"; } Info_SetValueForKey( userinfo, key, s ); key = "color2"; s = Info_ValueForKey( botinfo, key ); if ( !*s ) { s = "5"; } Info_SetValueForKey( userinfo, key, s ); s = Info_ValueForKey(botinfo, "aifile"); if (!*s ) { trap_Print( S_COLOR_RED "Error: bot has no aifile specified\n" ); trap_BotFreeClient( clientNum ); return; } Info_SetValueForKey( userinfo, "characterfile", s ); // don't send tinfo to bots, they don't parse it Info_SetValueForKey( userinfo, "teamoverlay", "0" ); // register the userinfo trap_SetUserinfo( clientNum, userinfo ); // have it connect to the game as a normal client if ( ClientConnect( clientNum, qtrue, qtrue ) ) { return; } if( delay == 0 ) { ClientBegin( clientNum ); return; } AddBotToSpawnQueue( clientNum, delay ); }
//[ExpSys] //added firsttime input so we'll know if we need to reset our skill point totals or not. void G_InitSessionData( gclient_t *client, char *userinfo, qboolean isBot, qboolean firstTime) { //void G_InitSessionData( gclient_t *client, char *userinfo, qboolean isBot ) { //[/ExpSys] clientSession_t *sess; const char *value; sess = &client->sess; client->sess.siegeDesiredTeam = TEAM_FREE; // initial team determination //[CoOp] //CoOp counts as a multi-team game. if ( g_gametype.integer >= GT_SINGLE_PLAYER) { //if ( g_gametype.integer >= GT_TEAM ) { //[/CoOp] if ( g_teamAutoJoin.integer ) { //[AdminSys] sess->sessionTeam = PickTeam( -1, isBot ); //sess->sessionTeam = PickTeam( -1 ); //[/AdminSys] BroadcastTeamChange( client, -1 ); } else { // always spawn as spectator in team games if (!isBot) { sess->sessionTeam = TEAM_SPECTATOR; } else { //Bots choose their team on creation value = Info_ValueForKey( userinfo, "team" ); if (value[0] == 'r' || value[0] == 'R') { sess->sessionTeam = TEAM_RED; } else if (value[0] == 'b' || value[0] == 'B') { sess->sessionTeam = TEAM_BLUE; } else { //[AdminSys] sess->sessionTeam = PickTeam( -1, isBot ); //sess->sessionTeam = PickTeam( -1 ); //[/AdminSys] } BroadcastTeamChange( client, -1 ); } } } else { value = Info_ValueForKey( userinfo, "team" ); if ( value[0] == 's' ) { // a willing spectator, not a waiting-in-line sess->sessionTeam = TEAM_SPECTATOR; } else { switch ( g_gametype.integer ) { default: case GT_FFA: case GT_HOLOCRON: case GT_JEDIMASTER: //[CoOp] //CoOp counts as a multi-team game. //case GT_SINGLE_PLAYER: //[/CoOp] if ( g_maxGameClients.integer > 0 && level.numNonSpectatorClients >= g_maxGameClients.integer ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_DUEL: // if the game is full, go into a waiting mode if ( level.numNonSpectatorClients >= 2 ) { sess->sessionTeam = TEAM_SPECTATOR; } else { sess->sessionTeam = TEAM_FREE; } break; case GT_POWERDUEL: //sess->duelTeam = DUELTEAM_LONE; //default { int loners = 0; int doubles = 0; G_PowerDuelCount(&loners, &doubles, qtrue); if (!doubles || loners > (doubles/2)) { sess->duelTeam = DUELTEAM_DOUBLE; } else { sess->duelTeam = DUELTEAM_LONE; } } sess->sessionTeam = TEAM_SPECTATOR; break; } } } sess->spectatorState = SPECTATOR_FREE; sess->spectatorTime = level.time; sess->siegeClass[0] = 0; sess->saberType[0] = 0; sess->saber2Type[0] = 0; //[ExpSys] //[OpenRP - Skillpoint System] if(firstTime) { //only reset skillpoints for new players. sess->IP[0] = 0; sess->skillPoints = 1; sess->adminLevel = 11; sess->radioOn = qtrue; } //[/OpenRP - Skillpoint System] else { //remember the data from the last time. char s[MAX_STRING_CHARS]; const char *var; int tempInt; char tempChar[64]; var = va( "session%i", client - level.clients ); trap_Cvar_VariableStringBuffer( var, s, sizeof(s) ); //[ExpSys] sscanf( s, "%i %i %i %i %i %i %i %i %i %i %i %i %s %s %s %i %i %i %i %i %i %i %s %i", //sscanf( s, "%i %i %i %i %i %i %i %i %i %i %i %i %s %s %s", //[ExpSys] &tempInt, // bk010221 - format &tempInt, &tempInt, // bk010221 - format &tempInt, &tempInt, &tempInt, &tempInt, // bk010221 - format &tempInt, &tempInt, &tempInt, &tempInt, &tempInt, &tempChar, &tempChar, &tempChar, &client->sess.skillPoints, //[OpenRP - account and character, other systems & IP] &client->sess.accountID, &client->sess.loggedinAccount, &client->sess.characterChosen, &client->sess.characterID, &client->sess.warnings, &client->sess.modelScale, &client->sess.IP, &client->sess.ojpClientPlugIn //[/OpenRP - account and character, other systems & IP] ); } //[/ExpSys] G_WriteClientSessionData( client ); }