int CallPriceForwardCSGO(int client, const char *weapon) { const char *weaponalias = GetTranslatedWeaponAlias(weapon); int weaponID = AliasToWeaponID(weaponalias); if (weaponID <= 0) { return -1; } void *info = GetWeaponInfo(weaponID); if (!info) { return -1; } const char *weapon_name = (const char *)((intptr_t)info + weaponNameOffset); int price = *(int *)((intptr_t)info + g_iPriceOffset); int changedprice = price; cell_t result = Pl_Continue; g_pPriceForward->PushCell(client); g_pPriceForward->PushString(weapon_name); g_pPriceForward->PushCellByRef(&changedprice); g_pPriceForward->Execute(&result); if (result == Pl_Continue) return -1; if (SetWeaponPrice(weaponID, changedprice)) return price; else return -1; }
/* <1ef43f> ../cstrike/dlls/career_tasks.cpp:192 */ CCareerTask::CCareerTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete) { m_isComplete = isComplete; m_event = event; m_eventsNeeded = n; m_name = taskName; m_eventsSeen = 0; m_mustLive = mustLive; m_crossRounds = crossRounds; m_diedThisRound = false; m_id = id; m_weaponId = AliasToWeaponID(weaponName); m_weaponClassId = AliasToWeaponClass(weaponName); m_rescuer = (Q_stricmp(taskName, "stoprescue") == 0); m_defuser = (Q_stricmp(taskName, "killdefuser") == 0); m_vip = (Q_stricmp(taskName, "killvip") == 0); if (event == EVENT_ALL_HOSTAGES_RESCUED) { m_mustLive = true; m_crossRounds = false; } if (m_isComplete) { MESSAGE_BEGIN(MSG_ALL, gmsgCZCareer); WRITE_STRING("TASKDONE"); WRITE_BYTE(m_id); MESSAGE_END(); } }
// Games implementing advanced bot support should override this. int CPlayerInfoManager::AliasToWeaponId(const char *weaponName) { //Tony; TF doesn't support this. Should it? #if defined ( CSTRIKE_DLL ) || defined ( DOD_DLL ) || defined ( SDK_DLL ) return AliasToWeaponID(weaponName); #endif return -1; }
/* <1f04ed> ../cstrike/dlls/career_tasks.cpp:757 */ void CCareerTaskManager::HandleEnemyKill(bool wasBlind, const char *weaponName, bool headshot, bool killerHasShield, CBasePlayer *pAttacker, CBasePlayer *pVictim) { HandleWeaponKill(AliasToWeaponID(weaponName), AliasToWeaponClass(weaponName), headshot, killerHasShield, pAttacker, pVictim); HandleEvent(EVENT_KILL, pAttacker, pVictim); if (headshot) { HandleEvent(EVENT_HEADSHOT, pAttacker, pVictim); } if (wasBlind) { HandleEvent(EVENT_KILL_FLASHBANGED, pAttacker, pVictim); } }
bool SetWeaponPrice(const char *weapon, int price) { const char *weaponalias = GetTranslatedWeaponAlias(weapon); int weaponID = AliasToWeaponID(weaponalias); if (weaponID <= 0) { return false; } void *info = GetWeaponInfo(weaponID); if (!info) { return false; } *(int *)((intptr_t)info+g_iPriceOffset) = price; return true; }
// Load the bot profile database void BotProfileManager::Init(const char *filename, unsigned int *checksum) { static const char *BotDifficultyName[] = { "EASY", "NORMAL", "HARD", "EXPERT", nullptr }; int dataLength; char *dataPointer = (char *)LOAD_FILE_FOR_ME(const_cast<char *>(filename), &dataLength); char *dataFile = dataPointer; if (!dataFile) { if (AreBotsAllowed()) { 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(token, "Model") != 0) { 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, "=") != 0) { 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(token, "End") != 0) { 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 = nullptr; // template names are separated by "+" while (true) { char *c = Q_strchr(token, '+'); if (c) *c = '\0'; // find the given template name for (auto templates : templateList) { if (!Q_stricmp(templates->GetName(), token)) { inherit = templates; break; } } if (!inherit) { 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 == nullptr) 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()); #ifdef REGAMEDLL_FIXES if (RANDOM_LONG(0, 2) == 2) #else // 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) #endif { 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, "=") != 0) { 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 } 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 = '\0'; for (int i = 0; i < NUM_DIFFICULTY_LEVELS; i++) { if (!Q_stricmp(BotDifficultyName[i], token)) profile->m_difficultyFlags |= (1<<i); } if (c == nullptr) 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 (auto templates : templateList) delete templates; templateList.clear(); }
/* <1f0815> ../cstrike/dlls/career_tasks.cpp:777 */ void CCareerTaskManager::HandleEnemyInjury(const char *weaponName, bool attackerHasShield, CBasePlayer *pAttacker) { HandleWeaponInjury(AliasToWeaponID(weaponName), AliasToWeaponClass(weaponName), attackerHasShield, pAttacker); HandleEvent(EVENT_PLAYER_TOOK_DAMAGE); }
void CSDKPlayerClassInfo::Parse( KeyValues *pKeyValuesData, const char *szWeaponName ) { BaseClass::Parse( pKeyValuesData, szWeaponName ); m_iTeam= pKeyValuesData->GetInt( "team", TEAM_UNASSIGNED ); // Figure out what team can have this player class m_iTeam = TEAM_UNASSIGNED; //Tony; don't check for teams unless we're using teams. You could do a free for all, but class / character based game if you wanted. #ifdef SDK_USE_TEAMS const char *pTeam = pKeyValuesData->GetString( "team", NULL ); if ( pTeam ) { if ( Q_stricmp( pTeam, "BLUE" ) == 0 ) { m_iTeam = SDK_TEAM_BLUE; } else if ( Q_stricmp( pTeam, "RED" ) == 0 ) { m_iTeam = SDK_TEAM_RED; } else { Assert( false ); } } else { Assert( false ); } #endif const char *pszPrimaryWeapon = pKeyValuesData->GetString( "primaryweapon", NULL ); m_iPrimaryWeapon = AliasToWeaponID( pszPrimaryWeapon ); Assert( m_iPrimaryWeapon != WEAPON_NONE ); // require player to have a primary weapon const char *pszSecondaryWeapon = pKeyValuesData->GetString( "secondaryweapon", NULL ); if ( pszSecondaryWeapon ) { m_iSecondaryWeapon = AliasToWeaponID( pszSecondaryWeapon ); // Assert( m_iSecondaryWeapon != WEAPON_NONE ); } else m_iSecondaryWeapon = WEAPON_NONE; const char *pszMeleeWeapon = pKeyValuesData->GetString( "meleeweapon", NULL ); if ( pszMeleeWeapon ) { m_iMeleeWeapon = AliasToWeaponID( pszMeleeWeapon ); // Assert( m_iMeleeWeapon != WEAPON_NONE ); } else m_iMeleeWeapon = WEAPON_NONE; m_iNumGrensType1 = pKeyValuesData->GetInt( "numgrens", 0 ); if ( m_iNumGrensType1 > 0 ) { const char *pszGrenType1 = pKeyValuesData->GetString( "grenadetype", NULL ); m_iGrenType1 = AliasToWeaponID( pszGrenType1 ); // Assert( m_iGrenType1 != WEAPON_NONE ); } m_iNumGrensType2 = pKeyValuesData->GetInt( "numgrens2", 0 ); if ( m_iNumGrensType2 > 0 ) { const char *pszGrenType2 = pKeyValuesData->GetString( "grenadetype2", NULL ); m_iGrenType2 = AliasToWeaponID( pszGrenType2 ); // Assert( m_iGrenType2 != WEAPON_NONE ); } Q_strncpy( m_szLimitCvar, pKeyValuesData->GetString( "limitcvar", "!! Missing limit cvar on Player Class" ), sizeof(m_szLimitCvar) ); Assert( Q_strlen( m_szLimitCvar ) > 0 && "Every class must specify a limitcvar" ); // HUD player status health images (when the player is hurt) Q_strncpy( m_szClassImage, pKeyValuesData->GetString( "classimage", "white" ), sizeof( m_szClassImage ) ); Q_strncpy( m_szClassImageBG, pKeyValuesData->GetString( "classimagebg", "white" ), sizeof( m_szClassImageBG ) ); m_flRunSpeed = pKeyValuesData->GetFloat( "RunSpeed", SDK_DEFAULT_PLAYER_RUNSPEED ); m_flSprintSpeed = pKeyValuesData->GetFloat( "SprintSpeed", SDK_DEFAULT_PLAYER_RUNSPEED ); m_flProneSpeed = pKeyValuesData->GetFloat( "ProneSpeed", SDK_DEFAULT_PLAYER_RUNSPEED ); m_iArmor = pKeyValuesData->GetInt( "armor", 0 ); }
void FilePlayerClassInfo_t::Parse( KeyValues *pKeyValuesData, const char *szPlayerClassName ) { // Okay, we tried at least once to look this up... m_bParsedScript = true; // Classname Q_strncpy( m_szPlayerClassName, szPlayerClassName, MAX_PLAYERCLASS_NAME_LENGTH ); // Printable name Q_strncpy( m_szPrintName, pKeyValuesData->GetString( "printname", "!! Missing printname on Player Class" ), MAX_PLAYERCLASS_NAME_LENGTH ); // Player Model Q_strncpy( m_szPlayerModel, pKeyValuesData->GetString( "playermodel", "!! Missing playermodel on Player Class" ), MAX_PLAYERCLASS_NAME_LENGTH ); // Select command Q_strncpy( m_szSelectCmd, pKeyValuesData->GetString( "selectcmd", "!! Missing selectcmd on Player Class" ), 32 ); m_iTeam = TEAM_UNASSIGNED; const char *pTeam = pKeyValuesData->GetString( "team", NULL ); if ( pTeam ) { if ( Q_stricmp( pTeam, "BLUE" ) == 0 ) { m_iTeam = SDK_TEAM_BLUE; } else if ( Q_stricmp( pTeam, "RED" ) == 0 ) { m_iTeam = SDK_TEAM_RED; } else { Assert( false ); } } else { Assert( false ); } const int keyLength = sizeof( "weapon_" ) + MAX_DIGITS; char keyName[ keyLength ]; int ammoKeyLength = sizeof( "weapon__ammo" ) + MAX_DIGITS; char ammoKeyName[ ammoKeyLength ]; for (int i = 1; i <= WEAPON_MAX; i++) { Q_snprintf( keyName, keyLength, "weapon_%d", i ); const char *pszWeapon = pKeyValuesData->GetString( keyName, NULL ); if( !pszWeapon ) { Warning( "weapon_%s: %s requested by class %s not found\n", keyName, pszWeapon, m_szPlayerClassName ); break; } int weaponId = AliasToWeaponID( pszWeapon ); m_WeaponVector.AddToTail( weaponId ); Q_snprintf( ammoKeyName, ammoKeyLength, "weapon_%d_ammo", i ); int ammoCount = pKeyValuesData->GetInt( ammoKeyName, 0 ); m_AmmoVector.AddToTail( ammoCount ); m_iWeaponCount = i; } Q_strncpy( m_szLimitCvar, pKeyValuesData->GetString( "limitcvar", "!! Missing limit cvar on Player Class" ), sizeof(m_szLimitCvar) ); Assert( Q_strlen( m_szLimitCvar ) > 0 && "Every class must specify a limitcvar" ); // HUD player status health images (when the player is hurt) Q_strncpy( m_szClassImage, pKeyValuesData->GetString( "classimage", "white" ), sizeof( m_szClassImage ) ); Q_strncpy( m_szClassImageBG, pKeyValuesData->GetString( "classimagebg", "white" ), sizeof( m_szClassImageBG ) ); m_iHealth = pKeyValuesData->GetFloat( "Health", 100 ); m_flRunSpeed = pKeyValuesData->GetFloat( "RunSpeed", 200 ); m_flSprintSpeed = pKeyValuesData->GetFloat( "SprintSpeed", 340 ); m_flProneSpeed = pKeyValuesData->GetFloat( "ProneSpeed", 160 ); m_flStaminaDrainRate = pKeyValuesData->GetFloat( "StaminaDrainRate", lf_combat_default_drainrate.GetFloat() ); m_flStaminaRestoreRate = pKeyValuesData->GetFloat( "StaminaRestoreRate", lf_combat_default_restorerate.GetFloat() ); m_iArmor = pKeyValuesData->GetInt( "armor", 0 ); }
/** * Load the bot profile database */ void BotProfileManager::Init( const char *filename, unsigned int *checksum ) { FileHandle_t file = filesystem->Open( filename, "r" ); if (!file) { if ( true ) // UTIL_IsGame( "czero" ) ) { CONSOLE_ECHO( "WARNING: Cannot access bot profile database '%s'\n", filename ); } return; } int dataLength = filesystem->Size( filename ); char *dataPointer = new char[ dataLength ]; int dataReadLength = filesystem->Read( dataPointer, dataLength, file ); filesystem->Close( file ); if ( dataReadLength > 0 ) { // NULL-terminate based on the length read in, since Read() can transform \r\n to \n and // return fewer bytes than we were expecting. dataPointer[ dataReadLength - 1 ] = 0; } const char *dataFile = dataPointer; // compute simple checksum if (checksum) { *checksum = 0; // ComputeSimpleChecksum( (const unsigned char *)dataPointer, dataLength ); } BotProfile defaultProfile; // // Parse the BotProfile.db into BotProfile instances // while( true ) { dataFile = SharedParse( dataFile ); if (!dataFile) break; char *token = SharedGetToken(); bool isDefault = (!stricmp( token, "Default" )); bool isTemplate = (!stricmp( token, "Template" )); bool isCustomSkin = (!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 ); delete [] dataPointer; return; } token = SharedGetToken(); Q_snprintf( skinName, sizeof( skinName ), "%s", token ); // get attribute name dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected 'Model'\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); if (stricmp( "Model", token )) { CONSOLE_ECHO( "Error parsing %s - expected 'Model'\n", filename ); delete [] dataPointer; return; } // eat '=' dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); if (strcmp( "=", token )) { CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename ); delete [] dataPointer; return; } // get attribute value dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected attribute value\n", filename ); delete [] 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[ strlen(token)*2 + strlen("models/player//.mdl") + 1 ]; Q_snprintf( m_skinFilenames[ m_nextSkin ], sizeof( 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 ); delete [] dataPointer; return; } token = SharedGetToken(); if (strcmp( "End", token )) { CONSOLE_ECHO( "Error parsing %s - expected 'End'\n", filename ); delete [] dataPointer; return; } continue; // it's just a custom skin - no need to do inheritance on a bot profile, etc. } // 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 = strchr( token, '+' ); if (c) *c = '\000'; // find the given template name FOR_EACH_LL( m_templateList, it ) { BotProfile *profile = m_templateList[ it ]; if (!stricmp( profile->GetName(), token )) { inherit = profile; break; } } if (inherit == NULL) { CONSOLE_ECHO( "Error parsing '%s' - invalid template reference '%s'\n", filename, token ); delete [] 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 ); delete [] 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 ); delete [] dataPointer; return; } token = SharedGetToken(); // check for End delimiter if (!stricmp( token, "End" )) break; // found attribute name - keep it char attributeName[64]; strcpy( attributeName, token ); // eat '=' dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); if (strcmp( "=", token )) { CONSOLE_ECHO( "Error parsing %s - expected '='\n", filename ); delete [] dataPointer; return; } // get attribute value dataFile = SharedParse( dataFile ); if (!dataFile) { CONSOLE_ECHO( "Error parsing %s - expected attribute value\n", filename ); delete [] dataPointer; return; } token = SharedGetToken(); // store value in appropriate attribute if (!stricmp( "Aggression", attributeName )) { profile->m_aggression = (float)atof(token) / 100.0f; } else if (!stricmp( "Skill", attributeName )) { profile->m_skill = (float)atof(token) / 100.0f; } else if (!stricmp( "Skin", attributeName )) { profile->m_skin = atoi(token); if ( profile->m_skin == 0 ) { // atoi() failed - try to look up a custom skin by name profile->m_skin = GetCustomSkinIndex( token, filename ); } } else if (!stricmp( "Teamwork", attributeName )) { profile->m_teamwork = (float)atof(token) / 100.0f; } else if (!stricmp( "Cost", attributeName )) { profile->m_cost = atoi(token); } else if (!stricmp( "VoicePitch", attributeName )) { profile->m_voicePitch = atoi(token); } else if (!stricmp( "VoiceBank", attributeName )) { profile->m_voiceBank = FindVoiceBankIndex( token ); } else if (!stricmp( "WeaponPreference", attributeName )) { // weapon preferences override parent prefs if (isFirstWeaponPref) { isFirstWeaponPref = false; profile->m_weaponPreferenceCount = 0; } if (!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 (!stricmp( "ReactionTime", attributeName )) { profile->m_reactionTime = (float)atof(token); #ifndef GAMEUI_EXPORTS // subtract off latency due to "think" update rate. // In GameUI, we don't really care. //profile->m_reactionTime -= g_BotUpdateInterval; #endif } else if (!stricmp( "AttackDelay", attributeName )) { profile->m_attackDelay = (float)atof(token); } else if (!stricmp( "Difficulty", attributeName )) { // override inheritance profile->m_difficultyFlags = 0; // parse bit flags while(true) { char *c = strchr( token, '+' ); if (c) *c = '\000'; for( int i=0; i<NUM_DIFFICULTY_LEVELS; ++i ) if (!stricmp( BotDifficultyName[i], token )) profile->m_difficultyFlags |= (1 << i); if (c == NULL) break; token = c+1; } } else if (!stricmp( "Team", attributeName )) { if ( !stricmp( token, "T" ) ) { profile->m_teams = TEAM_TERRORIST; } else if ( !stricmp( token, "CT" ) ) { profile->m_teams = TEAM_CT; } else { profile->m_teams = TEAM_UNASSIGNED; } } else { CONSOLE_ECHO( "Error parsing %s - unknown attribute '%s'\n", filename, attributeName ); } } if (!isDefault) { if (isTemplate) { // add to template list m_templateList.AddToTail( profile ); } else { // add profile to the master list m_profileList.AddToTail( profile ); } } }