#include "cbase.h" #ifdef CLIENT_DLL #define CASW_Equip_Req C_ASW_Equip_Req #include "c_asw_player.h" #include "c_asw_marine.h" #include "c_asw_game_resource.h" #include "c_asw_marine_resource.h" #include "asw_input.h" #include "c_asw_weapon.h" #include "c_asw_game_resource.h" #include "clientmode_asw.h" #include "c_asw_objective.h" #include "c_asw_debrief_stats.h" #include "asw_hud_objective.h" #include "asw_equip_req.h" #include "achievementmgr.h" #include "asw_achievements.h" #include "asw_medal_store.h" #include "asw_equipment_list.h" #include "asw_marine_profile.h" #include "clientmode_asw.h" #ifndef _X360 #include "steam/isteamuserstats.h" #include "steam/isteamfriends.h" #include "steam/isteamutils.h" #include "steam/steam_api.h" #include "c_asw_steamstats.h" #endif #define CASW_Marine C_ASW_Marine #define CASW_Marine_Resource C_ASW_Marine_Resource #define CASW_Weapon C_ASW_Weapon #define CASW_Debrief_Stats C_ASW_Debrief_Stats #define CASW_Objective C_ASW_Objective #else #include "player.h" #include "asw_player.h" #include "asw_marine.h" #include "asw_marine_resource.h" #include "asw_weapon.h" #include "asw_objective.h" #include "asw_debrief_stats.h" #include "asw_achievements.h" #ifndef _X360 #include "steam/isteamgameserverstats.h" #include "gameinterface.h" #endif #endif #include "asw_gamerules.h" #include "asw_shareddefs.h" #include "asw_weapon_parse.h" #include "asw_medals_shared.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" extern ConVar asw_skill; ConVar asw_show_xp_details( "asw_show_xp_details", "0", FCVAR_REPLICATED, "Output XP rewards to the console" ); // Experience levels. NOTE: Level shown in the UI is one higher than used in code int g_iLevelExperience[ ASW_NUM_EXPERIENCE_LEVELS ]= { 1000, // XP under this = 1evel 1 in UI 2050, 3150, 4300, 5500, // XP under this = 1evel 5 in UI 6750, 8050, 9400, 10800, 12250, // XP under this = 1evel 10 in UI 13750, 15300, 16900, 18550, 20250, // XP under this = 1evel 15 in UI 22000, 23800, 25650, 27550, 29500, // XP under this = 1evel 20 in UI 31500, 33550, 35650, 37800, 40000, // XP under this = 1evel 25 in UI 42250, // XP under this = level 26 in UI, XP equal to this = level 27 in the UI }; int g_iXPAward[ ASW_NUM_XP_TYPES ]= { 1000, // ASW_XP_MISSION, 100, // ASW_XP_KILLS, 100, // ASW_XP_TIME, 100, // ASW_XP_FRIENDLY_FIRE, 100, // ASW_XP_DAMAGE_TAKEN, 50, // ASW_XP_HEALING, 50, // ASW_XP_HACKING }; // scalar applied to XP required to level, based on your current promotion float g_flPromotionXPScale[ ASW_PROMOTION_CAP + 1 ]= { 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 4.0f, 6.0f, }; #define ASW_MISSION_XP_AWARD_ON_FAILURE 750 // XP award divided up between objectives // NOTE: If you change this, update the labels in CExperienceReport::OnThink too float g_flXPDifficultyScale[5]= { 0.5f, // easy 1.0f, // normal 1.2f, // hard 1.4f, // insane 1.5f, // imba }; // Weapon unlocks struct ASW_Weapon_Unlock { ASW_Weapon_Unlock( const char *szWeaponClass, int iLevel ) { m_pszWeaponClass = szWeaponClass; m_iLevel = iLevel; } const char *m_pszWeaponClass; int m_iLevel; // player level needed to unlock }; // Keep Equipment.res in the same order as this ASW_Weapon_Unlock g_WeaponUnlocks[]= { ASW_Weapon_Unlock( "asw_weapon_normal_armor", 1 ),// ASW_Weapon_Unlock( "asw_weapon_shotgun", 2 ), ASW_Weapon_Unlock( "asw_weapon_buff_grenade", 3 ),// ASW_Weapon_Unlock( "asw_weapon_tesla_gun", 4 ), ASW_Weapon_Unlock( "asw_weapon_hornet_barrage", 5 ),// ASW_Weapon_Unlock( "asw_weapon_railgun", 6 ), ASW_Weapon_Unlock( "asw_weapon_freeze_grenades", 7 ),// ASW_Weapon_Unlock( "asw_weapon_heal_gun", 8 ), ASW_Weapon_Unlock( "asw_weapon_stim", 9 ),// ASW_Weapon_Unlock( "asw_weapon_pdw", 10 ), ASW_Weapon_Unlock( "asw_weapon_tesla_trap", 11 ),// ASW_Weapon_Unlock( "asw_weapon_flamer", 12 ), ASW_Weapon_Unlock( "asw_weapon_electrified_armor", 13 ),// ASW_Weapon_Unlock( "asw_weapon_sentry_freeze", 14 ), ASW_Weapon_Unlock( "asw_weapon_mines", 15 ),// ASW_Weapon_Unlock( "asw_weapon_minigun", 16 ), ASW_Weapon_Unlock( "asw_weapon_flashlight", 17 ),// ASW_Weapon_Unlock( "asw_weapon_sniper_rifle", 18 ), ASW_Weapon_Unlock( "asw_weapon_fist", 19 ),// ASW_Weapon_Unlock( "asw_weapon_sentry_flamer", 20 ), ASW_Weapon_Unlock( "asw_weapon_grenades", 21 ),// ASW_Weapon_Unlock( "asw_weapon_chainsaw", 22 ), ASW_Weapon_Unlock( "asw_weapon_night_vision", 23 ),// ASW_Weapon_Unlock( "asw_weapon_sentry_cannon", 24 ), ASW_Weapon_Unlock( "asw_weapon_smart_bomb", 25 ),// ASW_Weapon_Unlock( "asw_weapon_grenade_launcher", 26 ), // ASW_NUM_EXPERIENCE_LEVELS }; // given an Experience total, this tells you the player's level int LevelFromXP( int iExperience, int iPromotion ) { iExperience = MIN( iExperience, ASW_XP_CAP * g_flPromotionXPScale[ iPromotion ] ); for ( int i = 0; i < NELEMS( g_iLevelExperience ); i++ ) { int iRequiredXP = (int) ( g_flPromotionXPScale[ iPromotion ] * g_iLevelExperience[ i ] ); if ( iExperience < iRequiredXP ) { return i; } } return NELEMS( g_iLevelExperience ); } void CASW_Player::CalculateEarnedXP() { for ( int i = 0; i < ASW_NUM_XP_TYPES; i++ ) { m_iEarnedXP[ i ] = 0; m_iStatNumXP[ i ] = 0; } // no XP if you don't have a marine resource if ( !ASWGameResource() || !ASWGameResource()->GetFirstMarineResourceForPlayer( this ) ) return; // no earning XP in singleplayer if ( gpGlobals->maxClients <= 1 ) return; if ( ASWGameRules() && ASWGameRules()->m_bCheated.Get() ) return; #ifdef CLIENT_DLL if ( engine->IsPlayingDemo() ) return; //if ( GetClientModeASW() && !GetClientModeASW()->IsOfficialMap() ) //return; #endif int iNumObjectives = 0; float flNumObjectivesComplete = 0; float flPartialScale = 1.0f; // this is used to scale XP rewards that should be small if you've only completed part of the mission if ( ASWGameRules()->GetMissionSuccess() ) { // XP for completing the mission m_iEarnedXP[ ASW_XP_MISSION ] = g_iXPAward[ ASW_XP_MISSION ]; m_iStatNumXP[ ASW_XP_MISSION ] = 100; } else { // if failed the mission, award XP per completed objective for ( int i = 0; i < ASW_MAX_OBJECTIVES; i++ ) { CASW_Objective *pObjective = ASWGameResource()->GetObjective( i ); if ( pObjective ) { iNumObjectives++; flNumObjectivesComplete += pObjective->GetObjectiveProgress(); } } if ( iNumObjectives > 0 ) { flPartialScale = ( flNumObjectivesComplete / (float) iNumObjectives ); m_iEarnedXP[ ASW_XP_MISSION ] += g_iXPAward[ ASW_XP_MISSION ] * flPartialScale; m_iStatNumXP[ ASW_XP_MISSION ] = flPartialScale * 100.0f; } else { flPartialScale = 0.0f; } } // query debrief stats to see how much XP we should award based on performance CASW_Debrief_Stats *pDebrief = GetDebriefStats(); if ( pDebrief ) { CASW_Marine_Resource *pMR = ASWGameResource()->GetFirstMarineResourceForPlayer( this ); if ( pMR ) { int iMarineIndex = ASWGameResource()->GetMarineResourceIndex( pMR ); if ( iMarineIndex != -1 ) { // XP per kill, capped m_iEarnedXP[ ASW_XP_KILLS ] = clamp( pDebrief->GetKills( iMarineIndex ), 0, g_iXPAward[ ASW_XP_KILLS ] ); m_iStatNumXP[ ASW_XP_KILLS ] = pDebrief->GetKills( iMarineIndex ); if ( ASWGameRules()->GetMissionSuccess() ) { // FF m_iEarnedXP[ ASW_XP_FRIENDLY_FIRE ] = clamp( g_iXPAward[ ASW_XP_FRIENDLY_FIRE ] - pDebrief->GetFriendlyFire( iMarineIndex ), 0, g_iXPAward[ ASW_XP_FRIENDLY_FIRE ] ); m_iStatNumXP[ ASW_XP_FRIENDLY_FIRE ] = pDebrief->GetFriendlyFire( iMarineIndex ); } if ( ASWGameRules()->GetMissionSuccess() ) { // damage taken m_iEarnedXP[ ASW_XP_DAMAGE_TAKEN ] = clamp( g_iXPAward[ ASW_XP_DAMAGE_TAKEN ] - pDebrief->GetDamageTaken( iMarineIndex ), 0, g_iXPAward[ ASW_XP_DAMAGE_TAKEN ] ); m_iStatNumXP[ ASW_XP_DAMAGE_TAKEN ] = pDebrief->GetDamageTaken( iMarineIndex ); } // healing m_iEarnedXP[ ASW_XP_HEALING ] = clamp( pDebrief->GetHealthHealed( iMarineIndex ) / 10, 0, g_iXPAward[ ASW_XP_HEALING ] ); m_iStatNumXP[ ASW_XP_HEALING ] = pDebrief->GetHealthHealed( iMarineIndex ); // hacking if ( pDebrief->GetFastHacks( iMarineIndex ) >= 2 ) { m_iEarnedXP[ ASW_XP_HACKING ] = g_iXPAward[ ASW_XP_HACKING ]; } else if ( pDebrief->GetFastHacks( iMarineIndex ) >= 1 ) { m_iEarnedXP[ ASW_XP_HACKING ] = g_iXPAward[ ASW_XP_HACKING ] / 2; } else { m_iEarnedXP[ ASW_XP_HACKING ] = 0; } m_iStatNumXP[ ASW_XP_HACKING ] = pDebrief->GetFastHacks( iMarineIndex ); } if ( ASWGameRules()->GetMissionSuccess() ) { // time int speedrun_time = pDebrief->GetSpeedrunTime(); int nTimeTaken = pDebrief->GetTimeTaken(); // award full XP if you get less than the speedrun_time const float flMaxTime = 5.0f * 60.0f; // max of 5 minutes over if ( nTimeTaken <= speedrun_time ) { m_iEarnedXP[ ASW_XP_TIME ] = g_iXPAward[ ASW_XP_TIME ]; m_iStatNumXP[ ASW_XP_TIME ] = nTimeTaken; } else { float flReduction = 1.0f - clamp( static_cast( nTimeTaken - speedrun_time ) / flMaxTime, 0.0f, 1.0f ); m_iEarnedXP[ ASW_XP_TIME ] = g_iXPAward[ ASW_XP_TIME ] * flReduction; m_iStatNumXP[ ASW_XP_TIME ] = nTimeTaken; } } // medals XP #ifdef GAME_DLL const char *szMedalString = pMR->m_MedalsAwarded.Get(); #else const char *szMedalString = pMR->m_MedalsAwarded; #endif const char *p = szMedalString; char token[128]; p = nexttoken( token, p, ' ' ); while ( Q_strlen( token ) > 0 ) { int iMedalIndex = atoi(token); m_iEarnedXP[ ASW_XP_MEDALS ] += GetXPForMedal( iMedalIndex ); if (p) p = nexttoken( token, p, ' ' ); else token[0] = '\0'; } // achievement XP #ifdef GAME_DLL CUtlVector *pAchievementsEarned = &pMR->m_aAchievementsEarned; #else CUtlVector *pAchievementsEarned = &m_aNonLocalPlayerAchievementsEarned; if ( IsLocalPlayer() ) { pAchievementsEarned = &GetClientModeASW()->m_aAchievementsEarned; } #endif for ( int i = 0; i < pAchievementsEarned->Count(); i++ ) { m_iEarnedXP[ ASW_XP_MEDALS ] += GetXPForMedal( -(*pAchievementsEarned)[i] ); } } } for ( int i = 0; i < ASW_XP_TOTAL; i++ ) { m_iEarnedXP[ ASW_XP_TOTAL ] += m_iEarnedXP[ i ]; } // apply difficulty bonus if ( ASWGameRules() ) { m_iEarnedXP[ ASW_XP_TOTAL ] *= g_flXPDifficultyScale[ ASWGameRules()->GetSkillLevel() - 1 ]; } if ( asw_show_xp_details.GetBool() ) { Msg( "[%s] Awarding XP to player %s:\n", IsServerDll() ? "Server" : "Client", GetPlayerName() ); Msg( " EarnedXP[ ASW_XP_MISSION ] = %d\n", m_iEarnedXP[ ASW_XP_MISSION ] ); Msg( " EarnedXP[ ASW_XP_KILLS ] = %d\n", m_iEarnedXP[ ASW_XP_KILLS ] ); Msg( " EarnedXP[ ASW_XP_TIME ] = %d\n", m_iEarnedXP[ ASW_XP_TIME ] ); Msg( " EarnedXP[ ASW_XP_FRIENDLY_FIRE ] = %d\n", m_iEarnedXP[ ASW_XP_FRIENDLY_FIRE ] ); Msg( " EarnedXP[ ASW_XP_DAMAGE_TAKEN ] = %d\n", m_iEarnedXP[ ASW_XP_DAMAGE_TAKEN ] ); Msg( " EarnedXP[ ASW_XP_HEALING ] = %d\n", m_iEarnedXP[ ASW_XP_HEALING ] ); Msg( " EarnedXP[ ASW_XP_HACKING ] = %d\n", m_iEarnedXP[ ASW_XP_HACKING ] ); Msg( " EarnedXP[ ASW_XP_MEDALS ] = %d\n", m_iEarnedXP[ ASW_XP_MEDALS ] ); Msg( " EarnedXP[ ASW_XP_TOTAL ] = %d (Difficulty scale = %f)\n", m_iEarnedXP[ ASW_XP_TOTAL ], ASWGameRules() ? ( ASWGameRules()->GetSkillLevel() - 1 ) : 1.0f ); } } int CASW_Player::GetLevel() { return LevelFromXP( GetExperience(), GetPromotion() ); } int CASW_Player::GetLevelBeforeDebrief() { return LevelFromXP( GetExperienceBeforeDebrief(), GetPromotion() ); } void CASW_Player::RequestExperience() { #ifdef CLIENT_DLL // pull XP/level out of the medal store. Steam stats will overwrite these numbers if stat get is successful and USE_XP_FROM_STEAM is defined if ( IsLocalPlayer() && GetMedalStore() ) { m_iExperience = GetMedalStore()->GetExperience(); m_iPromotion = GetMedalStore()->GetPromotion(); } #endif #if !defined(NO_STEAM) #ifdef CLIENT_DLL #if !defined(USE_XP_FROM_STEAM) // if we're not pulling XP from Steam stats, then we don't request it for other players // (instead we wait for the server to network their XP) if ( !IsLocalPlayer() ) return; #endif Assert( steamapicontext->SteamUserStats() ); if ( steamapicontext->SteamUserStats() ) { if ( IsLocalPlayer( this ) ) { steamapicontext->SteamUserStats()->RequestCurrentStats(); } else { player_info_t pi; if ( engine->GetPlayerInfo( entindex(), &pi ) && pi.friendsID ) { CSteamID steamID( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual ); Msg( "Requesting Steam stats for %s (%s)\n", pi.name ? pi.name : "NULL", pi.friendsName ? pi.friendsName : "NULL" ); steamapicontext->SteamUserStats()->RequestUserStats( steamID ); } } m_bPendingSteamStats = true; m_flPendingSteamStatsStart = gpGlobals->curtime; } #else Assert( Steam3Server().SteamGameServerStats() ); if ( Steam3Server().SteamGameServerStats() ) { CSteamID steamID; if ( GetSteamID( &steamID ) ) { SteamAPICall_t hSteamAPICall = Steam3Server().SteamGameServerStats()->RequestUserStats( steamID ); if ( hSteamAPICall != 0 ) { m_CallbackGSStatsReceived.Set( hSteamAPICall, this, &CASW_Player::Steam_OnGSStatsReceived ); } } m_bPendingSteamStats = true; m_flPendingSteamStatsStart = gpGlobals->curtime; } #endif #endif } void CASW_Player::AwardExperience() { #ifdef CLIENT_DLL if ( !GetClientModeASW() || GetClientModeASW()->HasAwardedExperience( this ) || !ASWGameRules() || !ASWGameResource() ) return; #else if ( m_bHasAwardedXP || !ASWGameRules() || !ASWGameResource() ) return; #endif if ( IsX360() ) return; m_iExperience = GetExperience(); // make sure m_iExperience has the correct number (no change if local player, otherwise using networked value) m_iExperienceBeforeDebrief = m_iExperience; CalculateEarnedXP(); Msg( "%s: AwardExperience: Pre XP is %d\n", IsServerDll() ? "S" : "C", m_iExperience ); m_iExperience += m_iEarnedXP[ ASW_XP_TOTAL ]; m_iExperience = MIN( m_iExperience, ASW_XP_CAP * g_flPromotionXPScale[ GetPromotion() ] ); #ifdef CLIENT_DLL if ( IsLocalPlayer() ) { #if !defined(NO_STEAM) // only upload if Steam is running if ( steamapicontext->SteamUserStats() ) { if( GetLocalASWPlayer() == this ) g_ASW_Steamstats.PrepStatsForSend( this ); steamapicontext->SteamUserStats()->SetStat( "experience", m_iExperience ); g_ASW_AchievementMgr.UploadUserData( GetSplitScreenPlayerSlot() ); if ( GetMedalStore() ) { GetMedalStore()->SetExperience( m_iExperience ); GetMedalStore()->SetPromotion( m_iPromotion ); GetMedalStore()->SaveMedalStore(); } } #endif // NO_STEAM GetClientModeASW()->SetAwardedExperience( this ); } #else m_bHasAwardedXP = true; #endif Msg( "%s: Awarded %d XP for player %s (total is now %d)\n", IsServerDll() ? "S" : "C", m_iEarnedXP[ ASW_XP_TOTAL ], GetPlayerName(), m_iExperience ); } #ifdef CLIENT_DLL #ifdef _DEBUG ConVar asw_unlock_all_weapons( "asw_unlock_all_weapons", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "If enabled, all weapons will be available in the briefing" ); #endif int CASW_Player::GetWeaponLevelRequirement( const char *szWeaponClass ) { for ( int i = 0; i < NELEMS( g_WeaponUnlocks ); i++ ) { if ( !Q_stricmp( szWeaponClass, g_WeaponUnlocks[ i ].m_pszWeaponClass ) ) { return g_WeaponUnlocks[ i ].m_iLevel; } } return -1; } bool CASW_Player::IsWeaponUnlocked( const char *szWeaponClass ) { #ifdef _DEBUG if ( asw_unlock_all_weapons.GetBool() ) return true; #endif if ( C_ASW_Equip_Req::ForceWeaponUnlocked( szWeaponClass ) ) return true; int iPlayerLevel = GetLevel(); int iWeaponReq = GetWeaponLevelRequirement( szWeaponClass ); if ( iWeaponReq == -1 ) { // if it's not in the list of unlocked weapons, assume it's unlocked by default return true; } return iWeaponReq <= iPlayerLevel; } const char* CASW_Player::GetNextWeaponClassUnlocked() { int iPlayerLevel = GetLevel(); for ( int i = 0; i < NELEMS( g_WeaponUnlocks ); i++ ) { //Msg( "GetNextWeaponClassUnlocked: player level = %d weapon %s level = %d\n", iPlayerLevel, g_WeaponUnlocks[ i ].m_pszWeaponClass, g_WeaponUnlocks[ i ].m_iLevel ); if ( g_WeaponUnlocks[ i ].m_iLevel > iPlayerLevel ) { return g_WeaponUnlocks[ i ].m_pszWeaponClass; } } return ""; } const char *CASW_Player::GetWeaponUnlockedAtLevel( int nLevel ) { for ( int i = 0; i < NELEMS( g_WeaponUnlocks ); i++ ) { if ( g_WeaponUnlocks[ i ].m_iLevel == nLevel ) { return g_WeaponUnlocks[ i ].m_pszWeaponClass; } } return ""; } #if !defined(NO_STEAM) //----------------------------------------------------------------------------- // Purpose: called when stat download is complete //----------------------------------------------------------------------------- void CASW_Player::Steam_OnUserStatsReceived( UserStatsReceived_t *pUserStatsReceived ) { Assert( steamapicontext->SteamUserStats() ); if ( !steamapicontext->SteamUserStats() ) return; if ( pUserStatsReceived->m_eResult != k_EResultOK ) { //Msg( "CASW_Player: failed to download stats from Steam, EResult %d\n", pUserStatsReceived->m_eResult ); //Msg( " m_nGameID = %I64u\n", pUserStatsReceived->m_nGameID ); //Msg( " SteamID = %I64u\n", pUserStatsReceived->m_steamIDUser.ConvertToUint64() ); m_bPendingSteamStats = false; return; } CSteamID steamID; if ( IsLocalPlayer() ) { steamID = steamapicontext->SteamUser()->GetSteamID(); } else { player_info_t pi; if ( !engine->GetPlayerInfo( entindex(), &pi ) ) return; if ( !pi.friendsID ) return; CSteamID steamIDForPlayer( pi.friendsID, 1, steamapicontext->SteamUtils()->GetConnectedUniverse(), k_EAccountTypeIndividual ); steamID = steamIDForPlayer; Msg( "Steam_OnUserStatsReceived for non local player %s (%s)\n", pi.name ? pi.name : "NULL", pi.friendsName ? pi.friendsName : "NULL" ); } if ( steamID != pUserStatsReceived->m_steamIDUser ) return; #ifdef USE_XP_FROM_STEAM if ( steamapicontext->SteamUserStats()->GetUserStat( steamID, "experience", &m_iExperience ) ) { m_bPendingSteamStats = false; } else { Msg( "Error retrieving experience stat for player %s.\n", GetPlayerName() ); } if ( !steamapicontext->SteamUserStats()->GetUserStat( steamID, "promotion", &m_iPromotion ) ) { Msg( "Error retrieving promotion stat for player %s.\n", GetPlayerName() ); } #else if ( IsLocalPlayer( this ) ) { if ( GetMedalStore() ) { if ( !GetMedalStore()->m_bFoundNewClientDat ) // if we failed to find the new client dat, then take steam numbers { if ( steamapicontext->SteamUserStats()->GetUserStat( steamID, "experience", &m_iExperience ) ) { m_bPendingSteamStats = false; } else { Msg( "Error retrieving experience stat for player %s.\n", GetPlayerName() ); } if ( !steamapicontext->SteamUserStats()->GetUserStat( steamID, "promotion", &m_iPromotion ) ) { Msg( "Error retrieving promotion stat for player %s.\n", GetPlayerName() ); } KeyValues *kv = new KeyValues( "XPUpdate" ); kv->SetInt( "xp", m_iExperience ); kv->SetInt( "pro", m_iPromotion ); engine->ServerCmdKeyValues( kv ); // kv gets deleted in here } } } m_bPendingSteamStats = false; #endif // Fetch the rest of the steam stats here if( GetLocalASWPlayer() == this ) g_ASW_Steamstats.FetchStats( steamID, this ); if ( IsLocalPlayer() && GetLevel() >= ASW_NUM_EXPERIENCE_LEVELS ) { CAchievementMgr *pAchievementMgr = dynamic_cast( engine->GetAchievementMgr() ); if ( !pAchievementMgr ) return; pAchievementMgr->OnAchievementEvent( ACHIEVEMENT_ASW_UNLOCK_ALL_WEAPONS, STEAM_PLAYER_SLOT ); } } void CASW_Player::Steam_OnUserStatsStored( UserStatsStored_t *pUserStatsStored ) { if ( !IsLocalPlayer( this ) ) return; CSteamID steamID = steamapicontext->SteamUser()->GetSteamID(); if ( k_EResultOK != pUserStatsStored->m_eResult ) { DevMsg( "CASW_Player: failed to upload stats to Steam, EResult %d\n", pUserStatsStored->m_eResult ); #ifdef USE_XP_FROM_STEAM steamapicontext->SteamUserStats()->GetStat( "experience", &m_iExperience ); steamapicontext->SteamUserStats()->GetStat( "promotion", &m_iPromotion ); #endif // Set stats to whatever is stored on steam if( GetLocalASWPlayer() == this ) g_ASW_Steamstats.FetchStats( steamID, this ); } } #endif void asw_debug_xp_f() { C_ASW_Player *pPlayer = C_ASW_Player::GetLocalASWPlayer(); if ( pPlayer ) { Msg( "Local player Level = %d\n", pPlayer->GetLevel() ); Msg( "Local player XP = %d\n", pPlayer->GetExperience() ); Msg( "Local player earned XP = %d\n", pPlayer->GetEarnedXP( ASW_XP_TOTAL ) ); Msg( "Local player promotion level = %d\n", pPlayer->GetPromotion() ); } } ConCommand asw_debug_xp( "asw_debug_xp", asw_debug_xp_f, "Lists XP details for local player", FCVAR_NONE ); void CASW_Player::AcceptPromotion() { if ( GetExperience() < ASW_XP_CAP * g_flPromotionXPScale[ GetPromotion() ] ) return; if ( GetPromotion() >= ASW_PROMOTION_CAP ) return; m_iExperience = 0; m_iPromotion++; #if !defined(NO_STEAM) // only upload if Steam is running if ( steamapicontext->SteamUserStats() ) { steamapicontext->SteamUserStats()->SetStat( "experience", m_iExperience ); steamapicontext->SteamUserStats()->SetStat( "promotion", m_iPromotion ); steamapicontext->SteamUserStats()->SetStat( "level", 1 ); steamapicontext->SteamUserStats()->SetStat( "level.xprequired", 0 ); g_ASW_AchievementMgr.UploadUserData( GetSplitScreenPlayerSlot() ); if ( GetMedalStore() ) { GetMedalStore()->ClearNewWeapons(); GetMedalStore()->SetExperience( m_iExperience ); GetMedalStore()->SetPromotion( m_iPromotion ); GetMedalStore()->SaveMedalStore(); } KeyValues *kv = new KeyValues( "XPUpdate" ); kv->SetInt( "xp", m_iExperience ); kv->SetInt( "pro", m_iPromotion ); engine->ServerCmdKeyValues( kv ); // kv gets deleted in here } #endif // NO_STEAM CLocalPlayerFilter filter; C_BaseEntity::EmitSound( filter, -1 /*SOUND_FROM_LOCAL_PLAYER*/, "ASW_XP.LevelUp" ); engine->ClientCmd( VarArgs( "cl_promoted %d", m_iPromotion ) ); // reset the player's selected equipment if ( !ASWGameResource() || !ASWEquipmentList() ) return; C_ASW_Marine_Resource *pMR = ASWGameResource()->GetFirstMarineResourceForPlayer( this ); if ( !pMR ) return; CASW_Marine_Profile *pProfile = pMR->GetProfile(); if ( !pProfile ) return; for ( int i = 0; i < ASW_NUM_INVENTORY_SLOTS; i++ ) { const char *szWeaponClass = pProfile->m_DefaultWeaponsInSlots[ i ]; int nWeaponIndex = ASWEquipmentList()->GetIndexForSlot( i, szWeaponClass ); engine->ClientCmd( VarArgs( "cl_loadout %d %d %d", pProfile->m_ProfileIndex, i, nWeaponIndex ) ); } } #else // SERVER #if !defined(NO_STEAM) void CASW_Player::Steam_OnGSStatsReceived( GSStatsReceived_t *pGSStatsReceived, bool bError ) { Assert( Steam3Server().SteamGameServerStats() ); if ( !Steam3Server().SteamGameServerStats() ) return; if ( pGSStatsReceived->m_eResult != k_EResultOK ) { Msg( "CASW_Player: Server failed to download stats from Steam, EResult %d\n", pGSStatsReceived->m_eResult ); //Msg( " SteamID = %I64u\n", pGSStatsReceived->m_steamIDUser.ConvertToUint64() ); m_bPendingSteamStats = false; return; } CSteamID steamIDForPlayer; if ( !GetSteamID( &steamIDForPlayer ) ) return; if ( steamIDForPlayer != pGSStatsReceived->m_steamIDUser ) return; #ifdef USE_XP_FROM_STEAM if ( Steam3Server().SteamGameServerStats()->GetUserStat( steamIDForPlayer, "experience", &m_iExperience ) ) { m_bPendingSteamStats = false; } else { Msg( "Server error retrieving experience stat for player %s.\n", GetPlayerName() ); } Steam3Server().SteamGameServerStats()->GetUserStat( steamIDForPlayer, "promotion", &m_iPromotion ) #endif } #endif // NO_STEAM #endif int GetXPForMedal( int nMedal ) { return 50; // TODO: Different XP for different medal types? } int CASW_Player::GetExperience() { #ifdef USE_XP_FROM_STEAM return m_iExperience; // stat taken from steam stats #else #ifdef CLIENT_DLL if ( IsLocalPlayer() ) { return m_iExperience; // XP read from medal store } #endif return m_iNetworkedXP.Get(); // XP networked down from the server #endif } int CASW_Player::GetPromotion() { #ifdef USE_XP_FROM_STEAM return m_iPromotion; // stat taken from steam stats #else #ifdef CLIENT_DLL if ( IsLocalPlayer() ) { return m_iPromotion; // XP read from medal store } #endif return m_iNetworkedPromotion.Get(); // XP networked down from the server #endif }