/* ============== ReloadMapCycleFile Parses mapcycle.txt file into mapcycle_t structure ============== */ int ReloadMapCycleFile( char *filename, mapcycle_t *cycle ) { char szBuffer[ MAX_RULE_BUFFER ]; char szMap[ 32 ]; int length; char *pFileList; char *aFileList = pFileList = (char*)LOAD_FILE_FOR_ME( filename, &length ); int hasbuffer; mapcycle_item_s *item, *newlist = NULL, *next; if ( pFileList && length ) { // the first map name in the file becomes the default while ( 1 ) { hasbuffer = 0; memset( szBuffer, 0, MAX_RULE_BUFFER ); pFileList = COM_Parse( pFileList ); if ( strlen( com_token ) <= 0 ) break; strcpy( szMap, com_token ); // Any more tokens on this line? if ( COM_TokenWaiting( pFileList ) ) { pFileList = COM_Parse( pFileList ); if ( strlen( com_token ) > 0 ) { hasbuffer = 1; strcpy( szBuffer, com_token ); } } // Check map if ( IS_MAP_VALID( szMap ) ) { // Create entry char *s; item = new mapcycle_item_s; strcpy( item->mapname, szMap ); item->minplayers = 0; item->maxplayers = 0; memset( item->rulebuffer, 0, MAX_RULE_BUFFER ); if ( hasbuffer ) { s = g_engfuncs.pfnInfoKeyValue( szBuffer, "minplayers" ); if ( s && s[0] ) { item->minplayers = atoi( s ); item->minplayers = max( item->minplayers, 0 ); item->minplayers = min( item->minplayers, gpGlobals->maxClients ); } s = g_engfuncs.pfnInfoKeyValue( szBuffer, "maxplayers" ); if ( s && s[0] ) { item->maxplayers = atoi( s ); item->maxplayers = max( item->maxplayers, 0 ); item->maxplayers = min( item->maxplayers, gpGlobals->maxClients ); } // Remove keys // g_engfuncs.pfnInfo_RemoveKey( szBuffer, "minplayers" ); g_engfuncs.pfnInfo_RemoveKey( szBuffer, "maxplayers" ); strcpy( item->rulebuffer, szBuffer ); } item->next = cycle->items; cycle->items = item; } else { ALERT( at_console, "Skipping %s from mapcycle, not a valid map\n", szMap ); } } FREE_FILE( aFileList ); } // Fixup circular list pointer item = cycle->items; // Reverse it to get original order while ( item ) { next = item->next; item->next = newlist; newlist = item; item = next; } cycle->items = newlist; item = cycle->items; // Didn't parse anything if ( !item ) { return 0; } while ( item->next ) { item = item->next; } item->next = cycle->items; cycle->next_item = item->next; return 1; }
/* <4a8acb> ../game_shared/bot/bot_profile.cpp:137 */ void BotProfileManager::Init(const char *filename, unsigned int *checksum) { int dataLength; char *dataPointer = (char *)LOAD_FILE_FOR_ME(const_cast<char *>(filename), &dataLength); const char *dataFile = dataPointer; if (dataFile == NULL) { if (UTIL_IsGame("czero")) { CONSOLE_ECHO("WARNING: Cannot access bot profile database '%s'\n", filename); } return; } // compute simple checksum if (checksum) { *checksum = ComputeSimpleChecksum((const unsigned char *)dataPointer, dataLength); } // keep list of templates used for inheritance BotProfileList templateList; BotProfile defaultProfile; // Parse the BotProfile.db into BotProfile instances while (true) { dataFile = SharedParse(dataFile); if (!dataFile) break; char *token = SharedGetToken(); bool isDefault = (!Q_stricmp(token, "Default")); bool isTemplate = (!Q_stricmp(token, "Template")); bool isCustomSkin = (!Q_stricmp(token, "Skin")); if (isCustomSkin) { const int BufLen = 64; char skinName[BufLen]; // get skin name dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected skin name\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); Q_snprintf(skinName, BufLen, "%s", token); // get attribute name dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected 'Model'\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); if (Q_stricmp("Model", token)) { CONSOLE_ECHO("Error parsing %s - expected 'Model'\n", filename); FREE_FILE(dataPointer); return; } // eat '=' dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected '='\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); if (Q_strcmp("=", token)) { CONSOLE_ECHO("Error parsing %s - expected '='\n", filename); FREE_FILE(dataPointer); return; } // get attribute value dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected attribute value\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); const char *decoratedName = GetDecoratedSkinName(skinName, filename); bool skinExists = GetCustomSkinIndex(decoratedName) > 0; if (m_nextSkin < NumCustomSkins && !skinExists) { // decorate the name m_skins[ m_nextSkin ] = CloneString(decoratedName); // construct the model filename m_skinModelnames[ m_nextSkin ] = CloneString(token); m_skinFilenames[ m_nextSkin ] = new char[ Q_strlen(token) * 2 + Q_strlen("models/player//.mdl") + 1 ]; Q_sprintf(m_skinFilenames[ m_nextSkin ], "models/player/%s/%s.mdl", token, token); ++m_nextSkin; } // eat 'End' dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); if (Q_strcmp("End", token)) { CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename); FREE_FILE(dataPointer); return; } // it's just a custom skin - no need to do inheritance on a bot profile, etc. continue; } // encountered a new profile BotProfile *profile; if (isDefault) { profile = &defaultProfile; } else { profile = new BotProfile; // always inherit from Default *profile = defaultProfile; } // do inheritance in order of appearance if (!isTemplate && !isDefault) { const BotProfile *inherit = NULL; // template names are separated by "+" while (true) { char *c = Q_strchr(token, '+'); if (c) *c = '\000'; // find the given template name for (BotProfileList::iterator iter = templateList.begin(); iter != templateList.end(); ++iter) { if (!Q_stricmp((*iter)->GetName(), token)) { inherit = *iter; break; } } if (inherit == NULL) { CONSOLE_ECHO("Error parsing '%s' - invalid template reference '%s'\n", filename, token); FREE_FILE(dataPointer); return; } // inherit the data profile->Inherit(inherit, &defaultProfile); if (c == NULL) break; token = c + 1; } } // get name of this profile if (!isDefault) { dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing '%s' - expected name\n", filename); FREE_FILE(dataPointer); return; } profile->m_name = CloneString(SharedGetToken()); // HACK HACK // Until we have a generalized means of storing bot preferences, we're going to hardcode the bot's // preference towards silencers based on his name. if (profile->m_name[0] % 2) { profile->m_prefersSilencer = true; } } // read attributes for this profile bool isFirstWeaponPref = true; while (true) { // get next token dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected 'End'\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); // check for End delimiter if (!Q_stricmp(token, "End")) break; // found attribute name - keep it char attributeName[64]; Q_strcpy(attributeName, token); // eat '=' dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected '='\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); if (Q_strcmp("=", token)) { CONSOLE_ECHO("Error parsing %s - expected '='\n", filename); FREE_FILE(dataPointer); return; } // get attribute value dataFile = SharedParse(dataFile); if (!dataFile) { CONSOLE_ECHO("Error parsing %s - expected attribute value\n", filename); FREE_FILE(dataPointer); return; } token = SharedGetToken(); // store value in appropriate attribute if (!Q_stricmp("Aggression", attributeName)) { profile->m_aggression = Q_atof(token) / 100.0f; } else if (!Q_stricmp("Skill", attributeName)) { profile->m_skill = Q_atof(token) / 100.0f; } else if (!Q_stricmp("Skin", attributeName)) { profile->m_skin = Q_atoi(token); if (profile->m_skin == 0) { // Q_atoi() failed - try to look up a custom skin by name profile->m_skin = GetCustomSkinIndex(token, filename); } } else if (!Q_stricmp("Teamwork", attributeName)) { profile->m_teamwork = Q_atof(token) / 100.0f; } else if (!Q_stricmp("Cost", attributeName)) { profile->m_cost = Q_atoi(token); } else if (!Q_stricmp("VoicePitch", attributeName)) { profile->m_voicePitch = Q_atoi(token); } else if (!Q_stricmp("VoiceBank", attributeName)) { profile->m_voiceBank = FindVoiceBankIndex(token); } else if (!Q_stricmp("WeaponPreference", attributeName)) { // weapon preferences override parent prefs if (isFirstWeaponPref) { isFirstWeaponPref = false; profile->m_weaponPreferenceCount = 0; } if (!Q_stricmp(token, "none")) { profile->m_weaponPreferenceCount = 0; } else { if (profile->m_weaponPreferenceCount < BotProfile::MAX_WEAPON_PREFS) { profile->m_weaponPreference[ profile->m_weaponPreferenceCount++ ] = AliasToWeaponID(token); } } } else if (!Q_stricmp("ReactionTime", attributeName)) { profile->m_reactionTime = Q_atof(token); #ifndef GAMEUI_EXPORTS // subtract off latency due to "think" update rate. // In GameUI, we don't really care. profile->m_reactionTime -= g_flBotFullThinkInterval; #endif // GAMEUI_EXPORTS } else if (!Q_stricmp("AttackDelay", attributeName)) { profile->m_attackDelay = Q_atof(token); } else if (!Q_stricmp("Difficulty", attributeName)) { // override inheritance profile->m_difficultyFlags = 0; // parse bit flags while (true) { char *c = Q_strchr(token, '+'); if (c) *c = '\000'; for (int i = 0; i < NUM_DIFFICULTY_LEVELS; ++i) { if (!Q_stricmp(BotDifficultyName[i], token)) profile->m_difficultyFlags |= (1 << i); } if (c == NULL) break; token = c + 1; } } else if (!Q_stricmp("Team", attributeName)) { if (!Q_stricmp(token, "T")) { profile->m_teams = BOT_TEAM_T; } else if (!Q_stricmp(token, "CT")) { profile->m_teams = BOT_TEAM_CT; } else { profile->m_teams = BOT_TEAM_ANY; } } else { CONSOLE_ECHO("Error parsing %s - unknown attribute '%s'\n", filename, attributeName); } } if (!isDefault) { if (isTemplate) { // add to template list templateList.push_back(profile); } else { // add profile to the master list m_profileList.push_back(profile); } } } FREE_FILE(dataPointer); // free the templates for (BotProfileList::iterator iter = templateList.begin(); iter != templateList.end(); ++iter) delete *iter; }