/* ============ Com_Filter ============ */ int Com_Filter(char *filter, char *name, int casesensitive) { char buf[MAX_TOKEN_CHARS]; char *ptr; int i; while(*filter) { if (*filter == '*') { filter++; for (i = 0; *filter; i++) { if (*filter == '*' || *filter == '?') { break; } buf[i] = *filter; filter++; } buf[i] = '\0'; if (strlen(buf)) { ptr = Com_StringContains(name, buf, casesensitive); if (!ptr) { return qfalse; } name = ptr + strlen(buf); } } else if (*filter == '?') { filter++; name++; } else { if (casesensitive) { if (*filter != *name) { return qfalse; } } else { if (toupper(*filter) != toupper(*name)) { return qfalse; } } filter++; name++; } } return qtrue; }
/* ============ Com_Filter ============ */ int Com_Filter(const char *filter, const char *name, int casesensitive) { char buf[MAX_TOKEN_CHARS]; const char *ptr; int i, found; while(*filter) { if (*filter == '*') { filter++; for (i = 0; *filter; i++) { if (*filter == '*' || *filter == '?') break; buf[i] = *filter; filter++; } buf[i] = '\0'; if (strlen(buf)) { ptr = Com_StringContains(name, buf, casesensitive); if (!ptr) return qfalse; name = ptr + strlen(buf); } } else if (*filter == '?') { filter++; name++; } else if (*filter == '[' && *(filter+1) == '[') { filter++; } else if (*filter == '[') { filter++; found = qfalse; while(*filter && !found) { if (*filter == ']' && *(filter+1) != ']') break; if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) { if (casesensitive) { if (*name >= *filter && *name <= *(filter+2)) found = qtrue; } else { if (toupper(*name) >= toupper(*filter) && toupper(*name) <= toupper(*(filter+2))) found = qtrue; } filter += 3; } else { if (casesensitive) { if (*filter == *name) found = qtrue; } else { if (toupper(*filter) == toupper(*name)) found = qtrue; } filter++; } } if (!found) return qfalse; while(*filter) { if (*filter == ']' && *(filter+1) != ']') break; filter++; } filter++; name++; } else { if (casesensitive) { if (*filter != *name) return qfalse; } else { if (toupper(*filter) != toupper(*name)) return qfalse; } filter++; name++; } } return qtrue; }
/* =========== 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. ============ */ char *ClientUserinfoChanged( int clientNum, qboolean forceName ) { gentity_t *ent; char *s; char model[ MAX_QPATH ]; char buffer[ MAX_QPATH ]; char filename[ MAX_QPATH ]; char oldname[ MAX_NAME_LENGTH ]; char newname[ MAX_NAME_LENGTH ]; char s_newname[ MAX_NAME_LENGTH ]; char err[ MAX_STRING_CHARS ]; qboolean revertName = qfalse; qboolean hasbotinname= qfalse; gclient_t *client; 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) ) { trap_SendServerCommand( ent - g_entities, "disconnect \"illegal or malformed userinfo\n\"" ); trap_DropClient( ent - g_entities, "dropped: illegal or malformed userinfo"); return "Illegal or malformed userinfo"; } // If their userinfo overflowed, tremded is in the process of disconnecting them. // If we send our own disconnect, it won't work, so just return to prevent crashes later // in this function. This check must come after the Info_Validate call. else if( !userinfo[ 0 ] ) return "Empty (overflowed) userinfo"; // stickyspec toggle s = Info_ValueForKey( userinfo, "cg_stickySpec" ); client->pers.stickySpec = atoi( s ) != 0; // set name Q_strncpyz( oldname, client->pers.netname, sizeof( oldname ) ); s = Info_ValueForKey( userinfo, "name" ); G_ClientCleanName( s, newname, sizeof( newname ) ); // check if the name contains [BOT] G_DecolorString(newname, s_newname, sizeof(newname)); hasbotinname = Com_StringContains(s_newname, "[BOT]", 0) ? qtrue : qfalse; if( strcmp( oldname, newname ) ) { if( !forceName && client->pers.namelog->nameChangeTime && level.time - client->pers.namelog->nameChangeTime <= g_minNameChangePeriod.value * 1000 ) { trap_SendServerCommand( ent - g_entities, va( "print \"Name change spam protection (g_minNameChangePeriod = %d)\n\"", g_minNameChangePeriod.integer ) ); revertName = qtrue; } else if( !forceName && g_maxNameChanges.integer > 0 && client->pers.namelog->nameChanges >= g_maxNameChanges.integer ) { trap_SendServerCommand( ent - g_entities, va( "print \"Maximum name changes reached (g_maxNameChanges = %d)\n\"", g_maxNameChanges.integer ) ); revertName = qtrue; } else if( !forceName && client->pers.namelog->muted ) { trap_SendServerCommand( ent - g_entities, "print \"You cannot change your name while you are muted\n\"" ); revertName = qtrue; } else if( !G_admin_name_check( ent, newname, err, sizeof( err ) ) ) { trap_SendServerCommand( ent - g_entities, va( "print \"%s\n\"", err ) ); revertName = qtrue; } //LEPE: Players are not allowed to have [BOT] or [bot] in names if(!(ent->r.svFlags & SVF_BOT) && g_bot_tagname.integer == 1) { if (hasbotinname) { trap_SendServerCommand( ent - g_entities, "print \"You cannot use [BOT] in your name\n\"" ); revertName = qtrue; hasbotinname = qfalse; } } if( revertName ) { Q_strncpyz( client->pers.netname, *oldname ? oldname : "UnnamedPlayer", sizeof( client->pers.netname ) ); Info_SetValueForKey( userinfo, "name", oldname ); trap_SetUserinfo( clientNum, userinfo ); } else { G_CensorString( client->pers.netname, newname, sizeof( client->pers.netname ), ent ); if( !forceName && client->pers.connected == CON_CONNECTED ) { client->pers.namelog->nameChangeTime = level.time; client->pers.namelog->nameChanges++; } if( *oldname ) { G_LogPrintf( "ClientRename: %i [%s] (%s) \"%s^7\" -> \"%s^7\" \"%c%s%c^7\"\n", clientNum, client->pers.ip.str, client->pers.guid, oldname, client->pers.netname, DECOLOR_OFF, client->pers.netname, DECOLOR_ON ); } } G_namelog_update_name( client ); } if( client->pers.classSelection == PCL_NONE ) { //This looks hacky and frankly it is. The clientInfo string needs to hold different //model details to that of the spawning class or the info change will not be //registered and an axis appears instead of the player model. There is zero chance //the player can spawn with the battlesuit, hence this choice. Com_sprintf( buffer, MAX_QPATH, "%s/%s", BG_ClassConfig( PCL_HUMAN_BSUIT )->modelName, BG_ClassConfig( PCL_HUMAN_BSUIT )->skinName ); } else { Com_sprintf( buffer, MAX_QPATH, "%s/%s%s", BG_ClassConfig( client->pers.classSelection )->modelName, BG_ClassConfig( client->pers.classSelection )->skinName, g_bot_skins.integer && hasbotinname == qtrue ? "_bot" : ""); //model segmentation Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", BG_ClassConfig( client->pers.classSelection )->modelName ); if( G_NonSegModel( filename ) ) client->ps.persistant[ PERS_STATE ] |= PS_NONSEGMODEL; else client->ps.persistant[ PERS_STATE ] &= ~PS_NONSEGMODEL; } Q_strncpyz( model, buffer, sizeof( model ) ); // wallwalk follow s = Info_ValueForKey( userinfo, "cg_wwFollow" ); if( atoi( s ) ) client->ps.persistant[ PERS_STATE ] |= PS_WALLCLIMBINGFOLLOW; else client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGFOLLOW; // wallwalk toggle s = Info_ValueForKey( userinfo, "cg_wwToggle" ); if( atoi( s ) ) client->ps.persistant[ PERS_STATE ] |= PS_WALLCLIMBINGTOGGLE; else client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGTOGGLE; // always sprint s = Info_ValueForKey( userinfo, "cg_sprintToggle" ); if( atoi( s ) ) client->ps.persistant[ PERS_STATE ] |= PS_SPRINTTOGGLE; else client->ps.persistant[ PERS_STATE ] &= ~PS_SPRINTTOGGLE; // fly speed s = Info_ValueForKey( userinfo, "cg_flySpeed" ); if( *s ) client->pers.flySpeed = atoi( s ); else client->pers.flySpeed = BG_Class( PCL_NONE )->speed; // disable blueprint errors s = Info_ValueForKey( userinfo, "cg_disableBlueprintErrors" ); if( atoi( s ) ) client->pers.disableBlueprintErrors = qtrue; else client->pers.disableBlueprintErrors = qfalse; // teamInfo s = Info_ValueForKey( userinfo, "teamoverlay" ); if( atoi( s ) != 0 ) client->pers.teamInfo = qtrue; else client->pers.teamInfo = qfalse; s = Info_ValueForKey( userinfo, "cg_unlagged" ); if( !s[0] || atoi( s ) != 0 ) client->pers.useUnlagged = qtrue; else client->pers.useUnlagged = qfalse; Q_strncpyz( client->pers.voice, Info_ValueForKey( userinfo, "voice" ), sizeof( client->pers.voice ) ); // send over a subset of the userinfo keys so other clients can // print scoreboards, display models, and play custom sounds Com_sprintf( userinfo, sizeof( userinfo ), "n\\%s\\t\\%i\\model\\%s\\ig\\%16s\\v\\%s", client->pers.netname, client->pers.teamSelection, model, Com_ClientListString( &client->sess.ignoreList ), client->pers.voice ); trap_SetConfigstring( CS_PLAYERS + clientNum, userinfo ); /*G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, userinfo );*/ return NULL; }
/** * Add one bot into a team * @param name [string] bot's name * @param team [team_t] alien or human */ qboolean G_BotAdd( char *name, team_t team ) { int i; int clientNum; char userinfo[MAX_INFO_STRING]; int reservedSlots = 0; gentity_t *ent; namelog_t *namelog; char name_s[ MAX_NAME_LENGTH ]; char name_tmp_s[ MAX_NAME_LENGTH ] = ""; reservedSlots = trap_Cvar_VariableIntegerValue( "sv_privateclients" ); //If bot name does not contains [BOT], prepend it. if(g_bot_tagname.integer == 1) { G_DecolorString(name, name_s, MAX_NAME_LENGTH); if (! (Com_StringContains(name_s, "[BOT]", 0))) { if(team == TEAM_HUMANS) { strcat(name_tmp_s, "^4[BOT] "); } else if(team == TEAM_ALIENS) { strcat(name_tmp_s, "^1[BOT] "); } strcat(name_tmp_s, name); strcpy(name, name_tmp_s); } } // LEPE: check if no player/bot exists with that name G_SanitiseString(name, name_s, sizeof(name_s) ); for( namelog = level.namelogs; namelog; namelog = namelog->next ) { if( namelog->slot >= 0 ) { for( i = 0; i < MAX_NAMELOG_NAMES && namelog->name[ i ][ 0 ]; i++ ) { G_SanitiseString(namelog->name[ i ], name_tmp_s, sizeof(name_tmp_s) ); if( i == namelog->nameOffset && namelog->slot > -1 && !strcmp( name_s, name_tmp_s ) ) { trap_Print("Nick already exists\n"); return qfalse; } } } } // find what clientNum to use for bot // LEPE: clientNum calculation was modified to prevent player hijacking // We will assign slots from maxclients - 1 to maxclients - reservedSlots - 1 clientNum = -1; for( i = level.maxclients - 1; i > level.maxclients - reservedSlots - 1; i-- ) { if( !g_entities[i].inuse ) { clientNum = i; break; } } if(clientNum == -1) { trap_Print("Error: Bots were not assigned correctly\n"); //LEPE return qfalse; } if(clientNum < level.maxclients - reservedSlots - 1) { trap_Print("no more slots for bot\n"); return qfalse; } ent = &g_entities[ clientNum ]; ent->inuse = qtrue; ent->bot = (bot_t *)BG_Alloc( sizeof(bot_t) ); // ent->bot->path.crumb = BG_Alloc( sizeof(level.paths) ); ent->r.svFlags |= SVF_BOT; // register user information userinfo[0] = '\0'; Info_SetValueForKey( userinfo, "name", name ); Info_SetValueForKey( userinfo, "rate", "25000" ); //25000 Info_SetValueForKey( userinfo, "snaps", "40" ); //so we can connect if server is password protected if(g_needpass.integer == 1) { Info_SetValueForKey( userinfo, "password", g_password.string); } trap_SetUserinfo( clientNum, userinfo ); // have it connect to the game as a normal client if(ClientConnect(clientNum, qtrue) != NULL ) { G_Printf("Something weird happened. Bot was not added."); // won't let us join return qfalse; } ClientBegin( clientNum ); G_BotDebug(ent, BOT_VERB_IMPORTANT, BOT_DEBUG_GENERAL, "Bot Added\n"); G_ChangeTeam( ent, team ); BotInit( ent ); if(team == TEAM_HUMANS) { BotInitHuman( ent ); level.humanBots++; } else if(team == TEAM_ALIENS) { BotInitAlien( ent ); level.alienBots++; } //TODO: load profile return qtrue; }