summaryrefslogtreecommitdiff
path: root/game/shared/tf/quest_objective_trackers.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/quest_objective_trackers.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/tf/quest_objective_trackers.cpp')
-rw-r--r--game/shared/tf/quest_objective_trackers.cpp550
1 files changed, 550 insertions, 0 deletions
diff --git a/game/shared/tf/quest_objective_trackers.cpp b/game/shared/tf/quest_objective_trackers.cpp
new file mode 100644
index 0000000..3f21d4e
--- /dev/null
+++ b/game/shared/tf/quest_objective_trackers.cpp
@@ -0,0 +1,550 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "quest_objective_manager.h"
+#include "gcsdk/gcclient.h"
+#include "gc_clientsystem.h"
+#include "econ_quests.h"
+#include "tf_gamerules.h"
+#include "schemainitutils.h"
+#include "econ_item_system.h"
+#ifdef CLIENT_DLL
+ #include "quest_log_panel.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#if defined( DEBUG ) || defined( STAGING_ONLY )
+ConVar tf_quests_commit_every_point( "tf_quests_commit_every_point", "0", FCVAR_REPLICATED );
+ConVar tf_quests_progress_enabled( "tf_quests_progress_enabled", "1", FCVAR_REPLICATED );
+#endif
+
+
+CQuestObjectiveManager *QuestObjectiveManager( void )
+{
+ static CQuestObjectiveManager g_QuestObjectiveManager;
+ return &g_QuestObjectiveManager;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CBaseQuestObjectiveTracker::CBaseQuestObjectiveTracker( const CTFQuestObjectiveDefinition* pObjective, CQuestItemTracker* pParent )
+ : m_nObjectiveDefIndex( pObjective->GetDefinitionIndex() )
+ , m_pParent( pParent )
+ , m_pEvaluator( NULL )
+{
+ KeyValues *pKVConditions = pObjective->GetConditionsKeyValues();
+
+ AssertMsg( !m_pEvaluator, "%s", CFmtStr( "Too many input for operator '%s'.", GetConditionName() ).Get() );
+
+ const char *pszType = pKVConditions->GetString( "type" );
+ m_pEvaluator = CreateEvaluatorByName( pszType, this );
+ AssertMsg( m_pEvaluator != NULL, "%s", CFmtStr( "Failed to create quest condition name '%s' for '%s'", pszType, GetConditionName() ).Get() );
+
+ SO_TRACKER_SPEW( CFmtStr( "Creating objective tracker def %d for quest def %d on item %llu for user %s\n",
+ pObjective->GetDefinitionIndex(),
+ pParent->GetItem()->GetItemDefinition()->GetDefinitionIndex(),
+ pParent->GetItem()->GetID(),
+ pParent->GetOwnerSteamID().Render() ),
+ SO_TRACKER_SPEW_OBJECTIVE_TRACKER_MANAGEMENT );
+
+ if ( !m_pEvaluator->BInitFromKV( pKVConditions, NULL ) )
+ {
+ AssertMsg( false, "Failed to init from KeyValues" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CBaseQuestObjectiveTracker::~CBaseQuestObjectiveTracker()
+{
+ if ( m_pEvaluator )
+ {
+ delete m_pEvaluator;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CBaseQuestObjectiveTracker::IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
+{
+ return m_pEvaluator->IsValidForPlayer( pOwner, invalidReasons );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const CTFPlayer *CBaseQuestObjectiveTracker::GetQuestOwner() const
+{
+ return GetTrackedPlayer();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseQuestObjectiveTracker::EvaluateCondition( CTFQuestEvaluator *pSender, int nScore )
+{
+#ifdef GAME_DLL
+ // tracker should be the root
+ Assert( !GetParent() );
+ IncrementCount( nScore );
+ ResetCondition();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseQuestObjectiveTracker::ResetCondition()
+{
+ m_pEvaluator->ResetCondition();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CBaseQuestObjectiveTracker::UpdateConditions()
+{
+ const CTFQuestObjectiveDefinition *pObjective = (CTFQuestObjectiveDefinition*)ItemSystem()->GetItemSchema()->GetQuestObjectiveByDefIndex( m_nObjectiveDefIndex );
+ if ( !pObjective )
+ return false;
+
+ // clean up previous evaluator
+ if ( m_pEvaluator )
+ {
+ delete m_pEvaluator;
+ m_pEvaluator = NULL;
+ }
+
+ CUtlVector< CUtlString > vecErrors;
+ return BInitFromKV( pObjective->GetConditionsKeyValues(), &vecErrors );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const CTFPlayer* CBaseQuestObjectiveTracker::GetTrackedPlayer() const
+{
+#ifdef CLIENT_DLL
+ return ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
+#else
+ return m_pParent->GetTrackedPlayer();
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseQuestObjectiveTracker::IncrementCount( int nIncrementValue )
+{
+ const CTFQuestObjectiveDefinition *pObjective = (CTFQuestObjectiveDefinition*)ItemSystem()->GetItemSchema()->GetQuestObjectiveByDefIndex( m_nObjectiveDefIndex );
+ Assert( pObjective );
+ if ( !pObjective )
+ return;
+
+ uint32 nPointsToAdd = nIncrementValue * pObjective->GetPoints();
+ m_pParent->IncrementCount( nPointsToAdd, pObjective );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CQuestItemTracker::CQuestItemTracker( const CSharedObject* pItem, CSteamID SteamIDOwner, CSOTrackerManager* pManager )
+ : CBaseSOTracker( pItem, SteamIDOwner, pManager )
+ , m_pItem( NULL )
+ , m_nStandardPoints( 0 )
+ , m_nBonusPoints( 0 )
+#ifdef GAME_DLL
+ , m_nStartingStandardPoints( 0 )
+ , m_nStartingBonusPoints( 0 )
+#endif
+{
+ m_pItem = assert_cast< const CEconItem* >( pItem );
+ // Retrieve starting numbers
+ UpdatePointsFromSOItem();
+
+ SO_TRACKER_SPEW( CFmtStr( "Creating tracker for quest %d on item %llu for user %s with %dsp and %dbp\n",
+ GetItem()->GetItemDefinition()->GetDefinitionIndex(),
+ GetItem()->GetID(),
+ GetOwnerSteamID().Render(),
+ GetEarnedStandardPoints(),
+ GetEarnedBonusPoints() ),
+ SO_TRACKER_SPEW_ITEM_TRACKER_MANAGEMENT );
+
+ // Create trackers for each objective
+ QuestObjectiveDefVec_t vecChosenObjectives;
+ m_pItem->GetItemDefinition()->GetQuestDef()->GetRolledObjectivesForItem( vecChosenObjectives, m_pItem );
+ FOR_EACH_VEC( vecChosenObjectives, i )
+ {
+ if ( !DoesObjectiveNeedToBeTracked( vecChosenObjectives[i] ) )
+ continue;
+
+ CBaseQuestObjectiveTracker* pNewTracker = new CBaseQuestObjectiveTracker( vecChosenObjectives[i], this );
+ m_vecObjectiveTrackers.AddToTail( pNewTracker );
+ }
+
+ if ( m_vecObjectiveTrackers.IsEmpty() )
+ {
+ SO_TRACKER_SPEW( CFmtStr( "Did not create any objective trackers for quest %d on item %llu for user %s with %dsp and %dbp\n",
+ GetItem()->GetItemDefinition()->GetDefinitionIndex(),
+ GetItem()->GetID(),
+ GetOwnerSteamID().Render(),
+ GetEarnedStandardPoints(),
+ GetEarnedBonusPoints() ),
+ SO_TRACKER_SPEW_OBJECTIVE_TRACKER_MANAGEMENT );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CQuestItemTracker::~CQuestItemTracker()
+{
+#ifdef CLIENT_DLL
+ SO_TRACKER_SPEW( CFmtStr( "Deleting tracker for quest %u on item %llu with %usp and %ubp\n",
+ m_pItem->GetItemDefinition()->GetDefinitionIndex(),
+ m_pItem->GetItemID(),
+ m_nStandardPoints,
+ m_nBonusPoints ),
+ SO_TRACKER_SPEW_ITEM_TRACKER_MANAGEMENT );
+#else
+ SO_TRACKER_SPEW( CFmtStr( "Deleting tracker for quest %u on item %llu with %usp %ussp %ubp %usbp\n",
+ m_pItem->GetItemDefinition()->GetDefinitionIndex(),
+ m_pItem->GetItemID(),
+ m_nStandardPoints,
+ m_nStartingStandardPoints,
+ m_nBonusPoints,
+ m_nStartingBonusPoints ),
+ SO_TRACKER_SPEW_ITEM_TRACKER_MANAGEMENT );
+#endif
+ m_vecObjectiveTrackers.PurgeAndDeleteElements();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Take a look at our item and update what we think our points are
+// based on the attributes on the item IF they are greater. We NEVER
+// want to lose progress for any reason.
+//-----------------------------------------------------------------------------
+void CQuestItemTracker::UpdatePointsFromSOItem()
+{
+ uint32 nNewPoints = 0;
+ static CSchemaAttributeDefHandle pAttribDef_EarnedStandardPoints( "quest earned standard points" );
+ m_pItem->FindAttribute( pAttribDef_EarnedStandardPoints, &nNewPoints );
+#ifdef GAME_DLL
+ m_nStartingStandardPoints = Max( nNewPoints, m_nStartingStandardPoints );
+#else
+ m_nStandardPoints = Max( nNewPoints, m_nStandardPoints );
+#endif
+
+ nNewPoints = 0;
+ static CSchemaAttributeDefHandle pAttribDef_EarnedBonusPoints( "quest earned bonus points" );
+ m_pItem->FindAttribute( pAttribDef_EarnedBonusPoints, &nNewPoints );
+#ifdef GAME_DLL
+ m_nStartingBonusPoints = Max( nNewPoints, m_nStartingBonusPoints );
+#else
+ m_nBonusPoints = Max( nNewPoints, m_nBonusPoints );
+#endif
+
+#ifdef GAME_DLL
+ SendUpdateToClient( NULL );
+
+ SO_TRACKER_SPEW( CFmtStr( "Updated points from item. CS:%d S:%d CB:%d B:%d\n", m_nStandardPoints, m_nStartingStandardPoints, m_nBonusPoints, m_nStartingBonusPoints ), SO_TRACKER_SPEW_OBJECTIVES );
+#else
+ SO_TRACKER_SPEW( CFmtStr( "Updated points from item. S:%d B:%d\n", m_nStandardPoints, m_nBonusPoints ), SO_TRACKER_SPEW_OBJECTIVES );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const CBaseQuestObjectiveTracker* CQuestItemTracker::FindTrackerForDefIndex( uint32 nDefIndex ) const
+{
+ FOR_EACH_VEC( m_vecObjectiveTrackers, i )
+ {
+ if ( m_vecObjectiveTrackers[ i ]->GetObjectiveDefIndex() == nDefIndex )
+ {
+ return m_vecObjectiveTrackers[ i ];
+ }
+ }
+
+ return NULL;
+}
+
+uint32 CQuestItemTracker::GetEarnedStandardPoints() const
+{
+#ifdef GAME_DLL
+ return m_nStartingStandardPoints + m_nStandardPoints;
+#else
+ return m_nStandardPoints;
+#endif
+}
+uint32 CQuestItemTracker::GetEarnedBonusPoints() const
+{
+#ifdef GAME_DLL
+ return m_nStartingBonusPoints + m_nBonusPoints;
+#else
+ return m_nBonusPoints;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestItemTracker::IncrementCount( uint32 nIncrementValue, const CQuestObjectiveDefinition* pObjective )
+{
+#if defined( DEBUG ) || defined( STAGING_ONLY )
+ if ( !tf_quests_progress_enabled.GetBool() )
+ return;
+#endif
+
+#ifdef GAME_DLL
+ Assert( pObjective );
+ Assert( m_pItem );
+ if ( !pObjective || !m_pItem )
+ return;
+
+ auto pQuestDef = m_pItem->GetItemDefinition()->GetQuestDef();
+ Assert( pQuestDef );
+ if ( !pQuestDef )
+ return;
+
+ if ( g_pVGuiLocalize && ( g_nQuestSpewFlags & SO_TRACKER_SPEW_OBJECTIVES ) )
+ {
+ locchar_t loc_IntermediateName[ MAX_ITEM_NAME_LENGTH ];
+ locchar_t locValue[ MAX_ITEM_NAME_LENGTH ];
+ loc_sprintf_safe( locValue, LOCCHAR( "%d" ), pObjective->GetPoints() );
+ loc_scpy_safe( loc_IntermediateName, CConstructLocalizedString( g_pVGuiLocalize->Find( pObjective->GetDescriptionToken() ), locValue ) );
+ char szTempObjectiveName[256];
+ ::ILocalize::ConvertUnicodeToANSI( loc_IntermediateName, szTempObjectiveName, sizeof( szTempObjectiveName ));
+
+ SO_TRACKER_SPEW( CFmtStr( "Increment for quest: %llu Objective: \"%s\" %d->%d (+%d)\n"
+ , m_pItem->GetItemID()
+ , szTempObjectiveName
+ , m_nStandardPoints + m_nBonusPoints
+ , m_nStandardPoints + m_nBonusPoints + nIncrementValue
+ , nIncrementValue ), SO_TRACKER_SPEW_OBJECTIVES );
+ }
+
+ // Regardless of standard or bonus, we fill the standard gauge first
+ uint32 nMaxStandardPoints = pQuestDef->GetMaxStandardPoints() - GetEarnedStandardPoints();
+ int nAmountToAdd = Min( nMaxStandardPoints, nIncrementValue );
+ m_nStandardPoints += nAmountToAdd;
+ nIncrementValue -= nAmountToAdd;
+
+ // If any bonus points left, fill in bonus points
+ if ( pObjective->IsAdvanced() && nIncrementValue > 0 )
+ {
+ uint32 nMaxBonusPoints = pQuestDef->GetMaxBonusPoints() + pQuestDef->GetMaxStandardPoints() - GetEarnedStandardPoints() - GetEarnedBonusPoints();
+ m_nBonusPoints += Min( nMaxBonusPoints, nIncrementValue );
+ }
+
+ bool bShouldCommit = IsQuestItemReadyToTurnIn( m_pItem );
+#if defined( DEBUG ) || defined( STAGING_ONLY )
+ bShouldCommit |= tf_quests_commit_every_point.GetBool();
+#endif
+
+ // Once we're over the turn-in threshhold, we need to record every point made.
+ if ( bShouldCommit )
+ {
+ CommitChangesToDB();
+ }
+
+ SendUpdateToClient( pObjective );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove and delete any objective trackers that are no longer needed.
+// One is considered not needed if it's a tracker for a "standard"
+// objective and we're done getting standard points, or if we're at
+// full bonus points, then there's no way for us to get points anymore
+//-----------------------------------------------------------------------------
+void CQuestItemTracker::OnUpdate()
+{
+ FOR_EACH_VEC_BACK( m_vecObjectiveTrackers, i )
+ {
+ const CQuestObjectiveDefinition *pObjective = GEconItemSchema().GetQuestObjectiveByDefIndex( m_vecObjectiveTrackers[ i ]->GetObjectiveDefIndex() );
+ Assert( pObjective );
+ if ( !pObjective || !DoesObjectiveNeedToBeTracked( pObjective ) )
+ {
+ delete m_vecObjectiveTrackers[ i ];
+ m_vecObjectiveTrackers.Remove( i );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestItemTracker::OnRemove()
+{
+#ifdef GAME_DLL
+ CommitRecord_t* pRecord = m_pManager->GetCommitRecord( m_pItem->GetItemID() );
+ if ( pRecord )
+ {
+ CMsgGCQuestObjective_PointsChange* pProto = assert_cast< CMsgGCQuestObjective_PointsChange* >( pRecord->m_pProtoMsg );
+ pProto->set_update_base_points( true );
+ }
+#endif
+}
+
+void CQuestItemTracker::Spew() const
+{
+ CBaseSOTracker::Spew();
+
+ FOR_EACH_VEC( m_vecObjectiveTrackers, i )
+ {
+ DevMsg( "Tracking objective: %d\n", m_vecObjectiveTrackers[ i ]->GetObjectiveDefIndex() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CQuestItemTracker::DoesObjectiveNeedToBeTracked( const CQuestObjectiveDefinition* pObjective ) const
+{
+ auto pQuestDef = m_pItem->GetItemDefinition()->GetQuestDef();
+
+ Assert( pObjective );
+ if ( pObjective && pQuestDef )
+ {
+ // If there's standard points to be earned, all objectives need to be tracked
+ if ( pQuestDef->GetMaxStandardPoints() > 0 && GetEarnedStandardPoints() < pQuestDef->GetMaxStandardPoints() )
+ {
+ return true;
+ }
+
+ // If this objective is advanced, only track it if there's bonus points to be earned
+ if ( pObjective->IsAdvanced() )
+ {
+ return pQuestDef->GetMaxBonusPoints() > 0 && GetEarnedBonusPoints() < pQuestDef->GetMaxBonusPoints();
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestItemTracker::CommitChangesToDB()
+{
+#ifdef CLIENT_DLL
+ if ( GetQuestLog() && GetTrackedPlayer() == C_TFPlayer::GetLocalTFPlayer() )
+ {
+ GetQuestLog()->MarkQuestsDirty();
+ }
+#else // GAME_DLL
+
+ // Nothing to commit? Bail
+ if ( m_nStandardPoints == 0 && m_nBonusPoints == 0 )
+ return;
+
+ SO_TRACKER_SPEW( CFmtStr( "CommitChangesToDB: %llu S:%d B:%d\n"
+ , m_pItem->GetItemID()
+ , GetEarnedStandardPoints()
+ , GetEarnedBonusPoints() ), 0 );
+
+ CSteamID ownerSteamID( m_pItem->GetAccountID(), GetUniverse(), k_EAccountTypeIndividual );
+
+ CMsgGCQuestObjective_PointsChange record;
+
+ // Cook up our message
+ record.set_owner_steamid( ownerSteamID.ConvertToUint64() );
+ record.set_quest_item_id( m_pItem->GetItemID() );
+ record.set_standard_points( GetEarnedStandardPoints() );
+ record.set_bonus_points( GetEarnedBonusPoints() ); // Here's the meat
+
+ m_pManager->AddCommitRecord( &record, record.quest_item_id(), true );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CQuestItemTracker::IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
+{
+ int nNumInvalid = 0;
+ FOR_EACH_VEC( m_vecObjectiveTrackers, i )
+ {
+ m_vecObjectiveTrackers[ i ]->IsValidForPlayer( pOwner, invalidReasons );
+
+ if ( !invalidReasons.IsValid() )
+ {
+ ++nNumInvalid;
+ }
+ }
+
+ return nNumInvalid;
+}
+
+#ifdef CLIENT_DLL
+//-----------------------------------------------------------------------------
+// Purpose: The server has changed scores. Apply those changes here
+//-----------------------------------------------------------------------------
+void CQuestItemTracker::UpdateFromServer( uint32 nStandardPoints, uint32 nBonusPoints )
+{
+ SO_TRACKER_SPEW( CFmtStr( "Updating \"%s's\" standard points: %d->%d bonus points: %d->%d\n"
+ , m_pItem->GetItemDefinition()->GetQuestDef()->GetRolledNameForItem( m_pItem )
+ , m_nStandardPoints
+ , nStandardPoints
+ , m_nBonusPoints
+ , nBonusPoints )
+ , SO_TRACKER_SPEW_OBJECTIVES );
+
+ m_nStandardPoints = nStandardPoints;
+ m_nBonusPoints = nBonusPoints;
+}
+#else
+void CQuestItemTracker::SendUpdateToClient( const CQuestObjectiveDefinition* pObjective )
+{
+ const CTFPlayer* pPlayer = GetTrackedPlayer();
+
+ // They might've disconnected, so let's check if they're still around
+ if ( pPlayer )
+ {
+ // Update the user on their progress
+ CSingleUserRecipientFilter filter( GetTrackedPlayer() );
+ filter.MakeReliable();
+ UserMessageBegin( filter, "QuestObjectiveCompleted" );
+ itemid_t nID = m_pItem->GetItemID();
+ WRITE_BITS( &nID, 64 );
+ WRITE_WORD( GetEarnedStandardPoints() );
+ WRITE_WORD( GetEarnedBonusPoints() );
+ WRITE_WORD( pObjective ? pObjective->GetDefinitionIndex() : (uint32)-1 );
+ MessageEnd();
+ }
+}
+#endif
+
+#if defined( DEBUG ) || defined( STAGING_ONLY )
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestItemTracker::DBG_CompleteQuest()
+{
+#ifdef GAME_DLL
+
+ auto pQuestDef = m_pItem->GetItemDefinition()->GetQuestDef();
+ uint32 nStandardPointsDelta = pQuestDef->GetMaxStandardPoints() - GetEarnedStandardPoints();
+
+ // Cheat!
+ if ( m_vecObjectiveTrackers.Count() )
+ {
+ const_cast< CBaseQuestObjectiveTracker* >( m_vecObjectiveTrackers[0] )->EvaluateCondition( NULL, nStandardPointsDelta );
+ }
+
+ CommitChangesToDB();
+#endif
+}
+#endif