summaryrefslogtreecommitdiff
path: root/game/shared/tf/tf_quest_editor_panel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/tf/tf_quest_editor_panel.cpp')
-rw-r--r--game/shared/tf/tf_quest_editor_panel.cpp2455
1 files changed, 2455 insertions, 0 deletions
diff --git a/game/shared/tf/tf_quest_editor_panel.cpp b/game/shared/tf/tf_quest_editor_panel.cpp
new file mode 100644
index 0000000..9cc2276
--- /dev/null
+++ b/game/shared/tf/tf_quest_editor_panel.cpp
@@ -0,0 +1,2455 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "tf_quest_editor_panel.h"
+#include "econ_item_tools.h"
+#include "tier2/p4helpers.h"
+#include "tier2/fileutils.h"
+#include "vgui/IInput.h"
+
+#ifdef STAGING_ONLY
+
+using namespace vgui;
+
+ConVar tf_quest_editor_element_height( "tf_quest_editor_element_height", "20", FCVAR_ARCHIVE );
+ConVar tf_quest_editor_indent_width( "tf_quest_editor_indent_width", "20", FCVAR_ARCHIVE );
+ConVar tf_quest_editor_entry_inset( "tf_quest_editor_entry_inset", "120" );
+
+static const char *g_skItemNameFormat = "quest%d";
+static const char *g_skNameTokenFormat = "#quest%dname%d";
+static const char *g_skDescTokenFormat = "#quest%ddesc%d";
+static const char *g_skObjectiveDescTokenFormat = "#quest%dobjectivedesc%d";
+static const char *g_skLocalizationFile = "resource/tf_quests_english.txt";
+static const char *g_skQuestDefFile = "tf/scripts/items/unencrypted/_items_quests.txt";
+static const char *g_skQuestObjectivesConditionsDefFile = "tf/scripts/items/unencrypted/_items_quest_objective_definitions.txt";
+static const char *g_skQuestObjectivesHouseKeepingFile = "items_quest_objective_housekeeping.csv";
+static const int g_nkFirstQuestDef = 25000;
+
+static const char* g_skQuestPrefabs[] = { "quest_prefab_1st_operation_pauling"
+ , "quest_prefab_halloween_2015"
+ , "quest_prefab_2nd_operation_pauling" };
+
+#define FLAGS_NONE 0
+#define FLAG_HIDDEN 1<<0
+#define FLAG_COLLAPSED 1<<1
+#define FLAG_COLLAPSABLE 1<<2
+#define FLAG_MUST_BE_LAST 1<<3
+#define FLAG_NOT_DELETABLE 1<<4
+#define FLAG_OUTPUT_LAST 1<<5
+#define FLAG_DELETED 1<<6
+#define FLAG_HIGHLIGHT_MOUSEOVER 1<<7
+#define FLAG_DONT_EXPORT 1<<8
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+static CQuestEditorPanel* g_pQuestEditor = NULL;
+static void cc_tf_quest_editor()
+{
+ g_pQuestEditor = new CQuestEditorPanel( NULL, "QuestEditor" );
+ g_pQuestEditor->MakeReadyForUse();
+ g_pQuestEditor->Deploy();
+}
+ConCommand tf_quest_editor( "tf_quest_editor", cc_tf_quest_editor );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes out all of the localization data for each quest intro "resource/tf_quests_english.txt"
+//-----------------------------------------------------------------------------
+void WriteLocalizationData()
+{
+ char szQuestEnglishFile[MAX_PATH];
+ if ( !GenerateFullPath( g_skLocalizationFile, "MOD", szQuestEnglishFile, ARRAYSIZE( szQuestEnglishFile ) ) )
+ {
+ Warning( "Failed to GenerateFullPath %s\n", g_skLocalizationFile );
+ return;
+ }
+
+ FOR_EACH_VEC( ILocalizationEditorParamAutoList::AutoList(), i )
+ {
+ CLocalizationEditorParam* pLocalizationEntry = static_cast< CLocalizationEditorParam* >( ILocalizationEditorParamAutoList::AutoList()[i] );
+ // We set the filename to "deleted" for deleted entries so that they don't get written out
+ // into tf_quests_english.txt
+ const char* pszFile = pLocalizationEntry->IsFlagSet( FLAG_DELETED, true ) ? "deleted" : szQuestEnglishFile;
+
+ wchar_t wszLocalizedValue[MAX_QUEST_DESC_LENGTH];
+ g_pVGuiLocalize->ConvertANSIToUnicode( pLocalizationEntry->GetLocalizationValue(), wszLocalizedValue, sizeof( wszLocalizedValue ) );
+
+ const char *pszTokenName = pLocalizationEntry->GetValue();
+ if ( pszTokenName[0] == '#' )
+ {
+ pszTokenName++;
+ }
+ g_pVGuiLocalize->AddString( pszTokenName, wszLocalizedValue, pszFile );
+ }
+
+ // Get the name of the file and p4 check it out
+ char szCorrectCaseFilePath[MAX_PATH];
+ g_pFullFileSystem->GetCaseCorrectFullPath( szQuestEnglishFile, szCorrectCaseFilePath );
+ CP4AutoEditFile a( szCorrectCaseFilePath );
+
+ g_pVGuiLocalize->SaveToFile( szQuestEnglishFile );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IEditorObject::IEditorObject( EditorObjectInitStruct init )
+ : EditablePanel( init.pParent, init.m_pszKeyName )
+ , m_Flags( init.nFlags )
+ , m_pOwningEditable( NULL )
+ , m_bHasChanges( false )
+{
+ memset( m_szKeyName, 0, sizeof( m_szKeyName ) );
+ if ( init.m_pszKeyName )
+ {
+ V_sprintf_safe( m_szKeyName, "%s", init.m_pszKeyName );
+ }
+
+ SetWide( init.pParent->GetWide() );
+
+ SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_RIGHT, 6, 6, -6, -6 );
+}
+
+void IEditorObject::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ SetTall( GetContentTall() );
+}
+
+void IEditorObject::OnSizeChanged( int newWide, int newTall )
+{
+ BaseClass::OnSizeChanged( newWide, newTall );
+
+ GetParent()->InvalidateLayout();
+}
+
+
+bool IEditorObject::IsFlagSet( int nFlag, bool bCheckUpTree ) const
+{
+ bool bIsFlagSet = m_Flags & nFlag;
+ if ( !bIsFlagSet && bCheckUpTree )
+ {
+ IEditorObject* pParent = dynamic_cast< IEditorObject* >( const_cast<IEditorObject*>(this)->GetParent() );
+ if ( pParent )
+ {
+ bIsFlagSet |= pParent->IsFlagSet( nFlag, bCheckUpTree );
+ }
+ }
+ return bIsFlagSet;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IEditorObject::ESerializeAction IEditorObject::ShouldWrite( const IEditableDataType* pCallingEditable ) const
+{
+ if ( IsFlagSet( FLAG_DONT_EXPORT ) )
+ return SKIP_THIS_AND_CHILDREN;
+
+ if ( IsFlagSet( FLAG_DELETED ) )
+ return SKIP_THIS_AND_CHILDREN;
+
+ if ( GetOwningEditable() != pCallingEditable )
+ return SKIP_THIS_AND_CONTINUE;
+
+ return WRITE_THIS_AND_CONTINUE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: If we're set to highlight on mouseover, do so!
+//-----------------------------------------------------------------------------
+void IEditorObject::OnThink()
+{
+ if ( IsFlagSet( FLAG_HIGHLIGHT_MOUSEOVER, false ) )
+ {
+ if ( IsCursorOver() )
+ {
+ SetBgColor( Color( 100, 150, 100, 30 ) );
+ }
+ else
+ {
+ SetBgColor( Color( 235, 226, 202, 2 ) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CEditorObjectNode::CEditorObjectNode( EditorObjectInitStruct init )
+ : BaseClass( init )
+{
+ m_pToggleCollapseButton = new Button( this, "togglecollapse", "-", this, "togglecollapse" );
+ m_pToggleCollapseButton->SetVisible( false );
+ m_pToggleCollapseButton->SetWide( 20 );
+ m_pToggleCollapseButton->SetZPos( 100 );
+
+ m_pDeleteButton = new Button( this, "deletebutton", "x", this, "delete" );
+ m_pDeleteButton->SetWide( 20 );
+ m_pDeleteButton->SetTall( 20 );
+
+ CEditorObjectNode* pNode = dynamic_cast< CEditorObjectNode* >( init.pParent );
+ if ( pNode )
+ {
+ pNode->AddChild( this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CEditorObjectNode::~CEditorObjectNode()
+{
+ CEditorObjectNode* pEditorPanel = dynamic_cast<CEditorObjectNode*>( GetParent() );
+ if ( pEditorPanel )
+ {
+ pEditorPanel->RemoveChild( this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const IEditableDataType* IEditorObject::GetOwningEditable() const
+{
+ const IEditableDataType* pOwningEditable = NULL;
+ const IEditorObject* pPanel = this;
+
+ do
+ {
+ pOwningEditable = pPanel->m_pOwningEditable;
+ pPanel = dynamic_cast< const IEditorObject* >( const_cast< IEditorObject* >( pPanel )->GetParent() ); // Good lord, VGUI. GetParent() isn't const? Really?
+ }
+ while ( pOwningEditable == NULL && pPanel != NULL );
+
+ Assert( pOwningEditable != NULL );
+
+ return pOwningEditable;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void IEditorObject::InvalidateChain()
+{
+ InvalidateLayout();
+
+ Panel* pParent = this;
+
+ do
+ {
+ pParent = pParent->GetParent();
+ pParent->InvalidateLayout();
+ }
+ while( dynamic_cast< IEditorObject* >( pParent ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void IEditorObject::ClearPendingChangesFlag()
+{
+ m_bHasChanges = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEditorObjectNode::AddChild( IEditorObject* pChild )
+{
+ m_bHasChanges = true;
+ m_vecChildren.AddToTail( pChild );
+ if ( !IsFlagSet( FLAG_HIDDEN ) && IsFlagSet( FLAG_COLLAPSABLE ) )
+ {
+ m_pToggleCollapseButton->SetVisible( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEditorObjectNode::RemoveChild( IEditorObject* pChild )
+{
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ if ( m_vecChildren[i] == pChild )
+ {
+ m_vecChildren.Remove( i );
+ if ( m_vecChildren.Count() == 0 )
+ {
+ m_pToggleCollapseButton->SetVisible( false );
+ }
+
+ m_bHasChanges = true;
+
+ return;
+ }
+ }
+
+ Assert( !"Couldn't find child to remove!" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CEditorObjectNode::GetNextAvailableKeyNumber() const
+{
+ int nNextAvailable = 0;
+
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ if ( !m_vecChildren[i]->IsFlagSet( FLAG_DONT_EXPORT ) )
+ {
+ nNextAvailable = Max( nNextAvailable, atoi( m_vecChildren[i]->GetName() ) );
+ }
+ }
+
+ return nNextAvailable;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CEditorObjectNode::HasChanges( bool bCheckChildren ) const
+{
+ bool bHasChanges = m_bHasChanges;
+
+ if ( bCheckChildren )
+ {
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ bHasChanges |= m_vecChildren[i]->HasChanges( bCheckChildren );
+ }
+ }
+
+ return bHasChanges;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CEditorObjectNode::GetContentTall() const
+{
+ // Hidden panels have 0 height
+ int nTall = IsFlagSet( FLAG_HIDDEN ) ? 0 : tf_quest_editor_element_height.GetInt();
+
+ // Collapsed panels just return their height.
+ if ( IsFlagSet( FLAG_COLLAPSED ) )
+ return nTall;
+
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ nTall += m_vecChildren[i]->GetContentTall();
+ }
+
+ return nTall;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEditorObjectNode::SerializeToKVs( KeyValues* pKV, const IEditableDataType* pCallingEditable ) const
+{
+ m_bHasChanges = false;
+
+ // End of the Line if deleted
+ if ( IsFlagSet( FLAG_DELETED ) )
+ return;
+
+ ESerializeAction action = ShouldWrite( pCallingEditable );
+ if ( action == SKIP_THIS_AND_CHILDREN )
+ return;
+
+ if ( action != SKIP_THIS_AND_CONTINUE )
+ {
+ pKV = pKV->CreateNewKey();
+ pKV->SetName( GetKeyName() );
+ }
+
+ CUtlVector< IEditorObject* > vecLastOutputs;
+
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ if ( m_vecChildren[ i ]->IsFlagSet( FLAG_OUTPUT_LAST ) )
+ {
+ vecLastOutputs.AddToTail( m_vecChildren[i] );
+ continue;
+ }
+
+ m_vecChildren[i]->SerializeToKVs( pKV, pCallingEditable );
+
+ }
+
+ FOR_EACH_VEC( vecLastOutputs, i )
+ {
+ vecLastOutputs[ i ]->SerializeToKVs( pKV, pCallingEditable );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEditorObjectNode::PerformLayout()
+{
+ m_pDeleteButton->SetVisible( m_vecChildren.Count() > 0 && !IsFlagSet( FLAG_HIDDEN ) && !IsFlagSet( FLAG_NOT_DELETABLE ) );
+ m_pDeleteButton->SetPos( 470, 0 );
+
+ BaseClass::PerformLayout();
+
+ int nTall = IsFlagSet( FLAG_HIDDEN ) ? 0 : tf_quest_editor_element_height.GetInt();
+
+ CUtlVector< IEditorObject* > vecLastParams;
+
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ if ( IsFlagSet( FLAG_MUST_BE_LAST ) )
+ {
+ vecLastParams.AddToTail( m_vecChildren[i] );
+ continue;
+ }
+
+ m_vecChildren[i]->SetPos( IsFlagSet( FLAG_HIDDEN ) ? 0 : tf_quest_editor_indent_width.GetInt(), nTall );
+ nTall += m_vecChildren[i]->GetContentTall();
+ }
+
+ FOR_EACH_VEC( vecLastParams, i )
+ {
+ vecLastParams[i]->SetPos( IsFlagSet( FLAG_HIDDEN ) ? 0 : tf_quest_editor_indent_width.GetInt(), nTall );
+ nTall += vecLastParams[i]->GetContentTall();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CEditorObjectNode::OnCommand( const char *command )
+{
+ if ( V_stricmp( "togglecollapse", command ) == 0 )
+ {
+ if ( IsFlagSet( FLAG_COLLAPSED ) )
+ {
+ m_pToggleCollapseButton->SetText( "-" );
+ }
+ else
+ {
+ m_pToggleCollapseButton->SetText( "+" );
+ }
+
+ SetFlag( FLAG_COLLAPSED, !IsFlagSet( FLAG_COLLAPSED ) );
+ InvalidateChain();
+
+ return;
+ }
+ if ( V_stricmp( command, "delete" ) == 0 )
+ {
+ RemoveNode();
+ return;
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+void CEditorObjectNode::MarkForDeletion()
+{
+ BaseClass::MarkForDeletion();
+
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ m_vecChildren[i]->MarkForDeletion();
+ }
+}
+
+void CEditorObjectNode::RemoveNode()
+{
+ MarkForDeletion();
+
+ InvalidateChain();
+}
+
+void CEditorObjectNode::ClearPendingChangesFlag()
+{
+ BaseClass::ClearPendingChangesFlag();
+
+ FOR_EACH_VEC( m_vecChildren, i )
+ {
+ m_vecChildren[ i ]->ClearPendingChangesFlag();
+ }
+}
+
+IEditorObjectParameter::IEditorObjectParameter( EditorObjectInitStruct init, const char *pszLabelText )
+ : BaseClass( init )
+{
+ memset( m_szSavedValueBuff, 0, sizeof( m_szSavedValueBuff ) );
+
+ SetTall( tf_quest_editor_element_height.GetInt() );
+
+ m_pLabel = new Label( this, "paramlabel", pszLabelText );
+ m_pLabel->SetWide( 100 );
+ m_pLabel->SetPos( 20, 0 );
+ m_pLabel->SetVisible( pszLabelText != NULL );
+
+ CEditorObjectNode* pNode = dynamic_cast< CEditorObjectNode* >( init.pParent );
+ if ( pNode )
+ {
+ pNode->AddChild( this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IEditorObjectParameter::~IEditorObjectParameter()
+{
+ CEditorObjectNode* pEditorPanel = dynamic_cast<CEditorObjectNode*>( GetParent() );
+ if ( pEditorPanel )
+ {
+ pEditorPanel->RemoveChild( this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void IEditorObjectParameter::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pLabel->SetPos( 20, 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void IEditorObjectParameter::SerializeToKVs( KeyValues* pKV, const IEditableDataType* pCallingEditable ) const
+{
+ m_bHasChanges = false;
+
+ if ( ShouldWrite( pCallingEditable ) == WRITE_THIS_AND_CONTINUE )
+ {
+ KeyValues* pKVStomp = pKV->FindKey( GetKeyName() );
+ if ( pKVStomp )
+ {
+ AssertMsg2( false, "STOMPING existing key: %s with %s\n", pKVStomp->GetName(), GetValue() );
+ KeyValuesDumpAsDevMsg( pKVStomp );
+ }
+
+ pKV->SetString( GetKeyName(), GetValue() );
+
+ UpdateSavedValue( GetValue() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void IEditorObjectParameter::UpdateSavedValue( const char* pszNewValue ) const
+{
+ // Update saved string
+ memset( m_szSavedValueBuff, 0, sizeof( m_szSavedValueBuff ) );
+ V_sprintf_safe( m_szSavedValueBuff, "%s", pszNewValue );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void IEditorObjectParameter::OnTextChanged( KeyValues *data )
+{
+ m_bHasChanges = CheckForChanges();
+
+ IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
+ Color labelNormalFGColor = GetSchemeColor("Label.TextColor", Color(0, 0, 0, 255), pScheme);
+ Color labelChangesFGColor = GetSchemeColor("RichText.SelectedBgColor", Color(0, 0, 0, 255), pScheme);
+
+ m_pLabel->SetFgColor( m_bHasChanges ? labelChangesFGColor : labelNormalFGColor );
+
+ g_pQuestEditor->CheckForChanges();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool IEditorObjectParameter::CheckForChanges() const
+{
+ return !FStrEq( GetValue(), m_szSavedValueBuff );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTextEntryEditorParam::CTextEntryEditorParam( EditorObjectInitStruct init, const char *pszLabelText, const char *pszValue )
+ : BaseClass( init, pszLabelText )
+{
+ UpdateSavedValue( pszValue );
+
+ SetTall( tf_quest_editor_element_height.GetInt() );
+ m_pTextEntry = new TextEntry( this, "entry" );
+ m_pTextEntry->SetPos( tf_quest_editor_entry_inset.GetInt(), 0 );
+ m_pTextEntry->SetWide( 400 );
+ m_pTextEntry->SetTall( tf_quest_editor_element_height.GetInt() );
+ m_pTextEntry->SetMultiline( true );
+ m_pTextEntry->SetCatchEnterKey( true );
+ SetTextEntryValue( pszValue );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTextEntryEditorParam::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pTextEntry->SetPos( tf_quest_editor_entry_inset.GetInt(), 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CTextEntryEditorParam::GetContentTall() const
+{
+ return IsFlagSet( FLAG_HIDDEN ) ? 0 : m_pTextEntry->GetTall();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTextEntryEditorParam::SetTextEntryValue( const char* pszValue )
+{
+ m_pTextEntry->SetText( pszValue );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char* CTextEntryEditorParam::GetValue() const
+{
+ m_pTextEntry->GetText( m_szValueBuff, sizeof( m_szValueBuff ) );
+ return m_szValueBuff;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IMPLEMENT_AUTO_LIST( ILocalizationEditorParamAutoList );
+CLocalizationEditorParam::CLocalizationEditorParam( EditorObjectInitStruct init, const char *pszLabelText, const char *pszLocalizationToken )
+ : BaseClass( init, pszLabelText, NULL )
+{
+ char szBuff[MAX_QUEST_DESC_LENGTH];
+ memset( szBuff, 0, sizeof( szBuff ) );
+ g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pszLocalizationToken ), szBuff, sizeof( szBuff ) );
+ SetTextEntryValue( szBuff );
+ UpdateSavedValue( szBuff );
+
+ V_sprintf_safe( m_szLocalizationToken, "%s", pszLocalizationToken );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CLocalizationEditorParam::GetValue() const
+{
+ // Always return the localization token
+ return m_szLocalizationToken;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char* CLocalizationEditorParam::GetLocalizationValue() const
+{
+ return BaseClass::GetValue();
+}
+
+bool CLocalizationEditorParam::CheckForChanges() const
+{
+ return !FStrEq( m_szSavedValueBuff, GetLocalizationValue() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CComboBoxEditorParam::CComboBoxEditorParam( EditorObjectInitStruct init, const char *pszLabelText )
+ : BaseClass( init, pszLabelText )
+ , m_pComboBox( NULL )
+{
+ m_pComboBox = new ComboBox( this, "combobox", 10, false );
+ m_pComboBox->AddActionSignalTarget( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CComboBoxEditorParam::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pComboBox->SetWide( 350 );
+ m_pComboBox->SetPos( tf_quest_editor_entry_inset.GetInt(), 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CComboBoxEditorParam::GetContentTall() const
+{
+ return IsFlagSet( FLAG_HIDDEN ) ? 0 : m_pComboBox->GetTall();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char* CComboBoxEditorParam::GetValue() const
+{
+ return m_pComboBox->GetActiveItemUserData()->GetString( "write" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CComboBoxEditorParam::AddComboBoxEntry( const char* pszText, bool bSelected, const char* pszWriteValue, const char* pszCommand )
+{
+ KeyValues *pKVData = new KeyValues( "data" );
+ pKVData->SetString( "write", pszWriteValue );
+ pKVData->SetString( "command", pszCommand );
+
+ int nIndex = m_pComboBox->AddItem( pszText, pKVData );
+
+ if ( bSelected )
+ {
+ m_pComboBox->SilentActivateItemByRow( nIndex );
+ UpdateSavedValue( pszWriteValue );
+ }
+
+ if ( pszWriteValue == NULL )
+ {
+ pszWriteValue = pszText;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CComboBoxEditorParam::OnTextChanged( KeyValues *data )
+{
+ Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
+ vgui::ComboBox *pComboBox = dynamic_cast<vgui::ComboBox *>( pPanel );
+
+ if ( pComboBox == m_pComboBox )
+ {
+ CQuestObjectiveRestrictionNode* pParent = dynamic_cast< CQuestObjectiveRestrictionNode* >( GetParent() );
+ if ( pParent )
+ {
+ // What to do
+ const char* pszCommand = m_pComboBox->GetActiveItemUserData()->GetString( "command" );
+ // What to write
+ const char* pszWriteValue = m_pComboBox->GetActiveItemUserData()->GetString( "write" );
+ if ( V_stricmp( pszCommand, "changetype" ) == 0 )
+ {
+ pParent->SetNewType( pszWriteValue );
+ }
+ else if ( V_stricmp( pszCommand, "changeevent" ) == 0 )
+ {
+ pParent->SetNewEvent( pszWriteValue );
+ }
+ }
+ }
+
+ BaseClass::OnTextChanged( data );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CNewQuestObjectiveParam::CNewQuestObjectiveParam( EditorObjectInitStruct init, const char *pszLabelText )
+ : BaseClass( init, NULL )
+{
+ SetFlag( FLAG_DONT_EXPORT, true );
+
+ m_pAddButton = new Button( this, "add", "Add New Filter", this, "add" );
+ m_pAddButton->SetTall( 20 );
+ m_pComboBox->SetVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNewQuestObjectiveParam::PerformLayout()
+{
+ BaseClass::PerformLayout();
+ m_pAddButton->SetWide( 200 );
+ m_pAddButton->SetPos( tf_quest_editor_indent_width.GetInt(), 0 );
+ m_pAddButton->SetContentAlignment( Label::a_center );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNewQuestObjectiveParam::OnCommand( const char *command )
+{
+ if ( FStrEq( command, "add" ) )
+ {
+ CQuestObjectiveRestrictionNode *pObjectiveParent = dynamic_cast< CQuestObjectiveRestrictionNode* >( GetParent() );
+ Assert( pObjectiveParent );
+ if ( pObjectiveParent )
+ {
+ const char *pszWriteValue = m_pComboBox->GetActiveItemUserData()->GetString( "write" );
+ CTFQuestCondition *pNewCondition = pObjectiveParent->GetCondition()->AddChildByName( pszWriteValue );
+ if ( pNewCondition )
+ {
+ new CQuestObjectiveRestrictionNode( { GetParent(), CFmtStr( "%d", pObjectiveParent->GetNextAvailableKeyNumber() ), FLAGS_NONE }, pNewCondition );
+ InvalidateChain();
+ }
+ }
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IOptionalExpandableBlock::IOptionalExpandableBlock( EditorObjectInitStruct init, const char* pszButtonText )
+ : BaseClass( init )
+{
+ m_pAddButton = new Button( this, "add", pszButtonText, this, "add" );
+}
+
+void IOptionalExpandableBlock::InitControls( KeyValues* pKVBlock )
+{
+ int nNumControlsCreated = 0;
+ if ( pKVBlock )
+ {
+ FOR_EACH_TRUE_SUBKEY( pKVBlock, pKVKey )
+ {
+ CreateNewControl( pKVKey );
+ ++nNumControlsCreated;
+ }
+ }
+
+ while( nNumControlsCreated < GetMinCount() )
+ {
+ CreateNewDefaultControl();
+ ++nNumControlsCreated;
+ }
+
+ InvalidateChain();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void IOptionalExpandableBlock::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pAddButton->SetPos( 0, 0 );
+ m_pAddButton->SetWide( 200 );
+ m_pAddButton->SetContentAlignment(Label::a_center);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void IOptionalExpandableBlock::OnCommand( const char *command )
+{
+ if ( FStrEq( "add", command ) )
+ {
+ CreateNewDefaultControl();
+ InvalidateChain();
+ return;
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+void IOptionalExpandableBlock::CreateNewControl( KeyValues* pKV )
+{
+ SetFlag( FLAG_DONT_EXPORT, false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CQuestObjectiveNode::CQuestObjectiveNode( CEditorObjectNode* pParentNode, KeyValues* pKVObjective )
+ : BaseClass( { pParentNode, pKVObjective->GetName(), FLAG_COLLAPSABLE } )
+ , m_pDefIndexComboBox( NULL )
+ , m_pSelectObjectiveButton( NULL )
+{
+ // Create the description field
+ new CLocalizationEditorParam( { this, "description_string", FLAGS_NONE }, "Objective Desc:", pKVObjective->GetString( "description_string" ) );
+ new CTextEntryEditorParam( { this, "defindex", FLAG_HIDDEN }, "Defindex", pKVObjective->GetString( "defindex" ) );
+
+ CComboBoxEditorParam * pOptionalComboBox = new CComboBoxEditorParam( { this, "optional", FLAGS_NONE }, "Optional:" );
+ pOptionalComboBox->AddComboBoxEntry( "False", !pKVObjective->GetBool( "optional", false ), "0", NULL );
+ pOptionalComboBox->AddComboBoxEntry( "True", pKVObjective->GetBool( "optional", false ), "1", NULL );
+
+ CComboBoxEditorParam * pAdvancedComboBox = new CComboBoxEditorParam( { this, "advanced", FLAGS_NONE }, "Advanced:" );
+ pAdvancedComboBox->AddComboBoxEntry( "False", !pKVObjective->GetBool( "advanced", false ), "0", NULL );
+ pAdvancedComboBox->AddComboBoxEntry( "True", pKVObjective->GetBool( "advanced", false ), "1", NULL );
+
+ CTextEntryEditorParam *pPointsNode = new CTextEntryEditorParam( { this, "points", FLAGS_NONE }, "Points:", CFmtStr( "%d", pKVObjective->GetInt( "points", 1 ) ) );
+ pPointsNode->GetTextEntry()->SetAllowNumericInputOnly( true );
+
+ // The condition def index this objective wants to use
+ ObjectiveConditionDefIndex_t nConditionsDefIndex = pKVObjective->GetInt( "conditions_def_index", INVALID_QUEST_OBJECTIVE_CONDITIONS_INDEX );
+ Assert( nConditionsDefIndex != INVALID_QUEST_OBJECTIVE_CONDITIONS_INDEX );
+
+ m_pDefIndexComboBox = new CComboBoxEditorParam( { this, "conditions_def_index", FLAGS_NONE }, "Conditions:" );
+ m_pDefIndexComboBox->GetComboBox()->AddActionSignalTarget( this );
+
+
+ m_pSelectObjectiveButton = new Button( m_pDefIndexComboBox, "selectobjective", "Pick", this, "selectobjective" );
+ m_pSelectObjectiveButton->AddActionSignalTarget( this );
+
+
+ PopulateAndSelectConditionsCombobox( nConditionsDefIndex );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveNode::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pSelectObjectiveButton->SetPos( m_pDefIndexComboBox->GetComboBox()->GetXPos() + m_pDefIndexComboBox->GetComboBox()->GetWide(), 0 );
+ m_pSelectObjectiveButton->SetWide( 36 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveNode::PopulateAndSelectConditionsCombobox( int nSelectedDefIndex )
+{
+ // Clean out oldies
+ m_pDefIndexComboBox->GetComboBox()->RemoveAll();
+
+ // Go through all of the current data and fill out our combo box with all of the objective conditions
+ const CUtlVector< IEditableDataType* >& vecEditableData = g_pQuestEditor->GetEditableData();
+ FOR_EACH_VEC( vecEditableData, i )
+ {
+ IEditableDataType* pEditable = vecEditableData[i];
+ if ( pEditable->GetType() == IEditableDataType::TYPE_OBJECTIVE_CONDITIONS && !g_pQuestEditor->IsOpenForEdit( pEditable ) )
+ {
+ KeyValues* pKVData = pEditable->GetLiveData();
+ bool bSelected = atoi( pKVData->GetName() ) == nSelectedDefIndex;
+ m_pDefIndexComboBox->AddComboBoxEntry( CFmtStr( "\t%s", pKVData->GetString( "name", "ERROR" ) ), bSelected, pKVData->GetName(), NULL );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveNode::OnCommand( const char *command )
+{
+ if ( FStrEq( "selectobjective", command ) )
+ {
+ KeyValues* pKV = new KeyValues( "SelectQuestObjective" );
+ pKV->SetPtr( "panel", this );
+
+ PostMessage( g_pQuestEditor, pKV );
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Pump the command from the menu panel into us as a command
+//-----------------------------------------------------------------------------
+void CQuestObjectiveNode::OnTextChanged( KeyValues *data )
+{
+ Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
+
+ ComboBox *pComboBox = dynamic_cast<ComboBox*>( pPanel );
+ if ( pComboBox )
+ {
+ if ( pComboBox == m_pDefIndexComboBox->GetComboBox() )
+ {
+ KeyValues* pKVUserData = pComboBox->GetActiveItemUserData();
+ OnCommand( pKVUserData->GetString( "command" ) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveNode::OnObjectiveSelected( KeyValues *data )
+{
+ int nDesiredDefIndex = data->GetInt( "defindex", INVALID_ITEM_DEF_INDEX );
+ Assert( nDesiredDefIndex != INVALID_ITEM_DEF_INDEX );
+
+ ComboBox* pComboBox = m_pDefIndexComboBox->GetComboBox();
+ if ( pComboBox )
+ {
+ for( int i=0; i < pComboBox->GetItemCount(); ++i )
+ {
+ KeyValues* pKVUserData = pComboBox->GetItemUserData( i );
+ int nDefIndex = pKVUserData->GetInt( "write", INVALID_ITEM_DEF_INDEX );
+
+ if ( nDefIndex == nDesiredDefIndex )
+ {
+ pComboBox->ActivateItemByRow( i );
+ return;
+ }
+ }
+ }
+
+ // Didn't find the matching defindex!
+ Assert( false );
+}
+
+void CQuestDescriptionNode::CreateNewControl( KeyValues* pKV )
+{
+ CEditorObjectNode* pNode = new CEditorObjectNode( EditorObjectInitStruct{ this, pKV->GetName(), FLAGS_NONE } );
+ CLocalizationEditorParam *pLocParam = new CLocalizationEditorParam( { pNode, "token", FLAGS_NONE }, "Description:", pKV->GetString( "token" ) );
+ pLocParam->GetTextEntry()->SetTall( 200 );
+ pLocParam->SetTall( 200 );
+ pLocParam->GetTextEntry()->SetVerticalScrollbar( true );
+
+ BaseClass::CreateNewControl( pKV );
+}
+
+void CQuestDescriptionNode::CreateNewDefaultControl()
+{
+ int nDefindex = GetNextAvailableKeyNumber() + 1;
+ int nObjectDefIndex = atoi( GetOwningEditable()->GetLiveData()->GetName() );
+
+ KeyValuesAD pKVDesc( CFmtStr( "%d", nDefindex ) );
+ pKVDesc->SetString( "token", CFmtStr( g_skDescTokenFormat, nObjectDefIndex, nDefindex ) );
+
+ CreateNewControl( pKVDesc );
+}
+
+void CQuestNameNode::CreateNewControl( KeyValues* pKV )
+{
+ CEditorObjectNode* pNode = new CEditorObjectNode( EditorObjectInitStruct{ this, pKV->GetName(), FLAGS_NONE } );
+ new CLocalizationEditorParam( { pNode, "token", FLAGS_NONE }, "Name:", pKV->GetString( "token" ) );
+
+ BaseClass::CreateNewControl( pKV );
+}
+
+void CQuestNameNode::CreateNewDefaultControl()
+{
+ int nDefindex = GetNextAvailableKeyNumber() + 1;
+ int nObjectDefIndex = atoi( GetOwningEditable()->GetLiveData()->GetName() );
+
+ KeyValuesAD pKVName( CFmtStr( "%d", nDefindex ) );
+ pKVName->SetString( "token", CFmtStr( g_skNameTokenFormat, nObjectDefIndex, nDefindex ) );
+
+ CreateNewControl( pKVName );
+}
+
+
+CComboBoxEditorParam* CreateWeaponComboBox( EditorObjectInitStruct init, const char* pszLabelText, item_definition_index_t defIndexSelect )
+{
+ CComboBoxEditorParam* pCombo = new CComboBoxEditorParam( init, pszLabelText );
+ pCombo->GetComboBox()->SetEditable( true ); // Allow for typing in the combo box. There's a lot of stuff
+
+ CUtlDict< item_definition_index_t > weaponDict;
+ const CEconItemSchema::SortedItemDefinitionMap_t& mapItemDefs = GetItemSchema()->GetSortedItemDefinitionMap();
+ FOR_EACH_MAP( mapItemDefs, i )
+ {
+ CTFItemDefinition* pDef = (CTFItemDefinition*)mapItemDefs[i];
+
+ int iSlot = pDef->GetDefaultLoadoutSlot();
+ if ( pDef->GetEquipType() == EEquipType_t::EQUIP_TYPE_ACCOUNT )
+ continue;
+
+ if ( !( iSlot == LOADOUT_POSITION_PRIMARY
+ || iSlot == LOADOUT_POSITION_SECONDARY
+ || iSlot == LOADOUT_POSITION_MELEE
+ || iSlot == LOADOUT_POSITION_PDA
+ || iSlot == LOADOUT_POSITION_PDA2
+ || iSlot == LOADOUT_POSITION_BUILDING ) )
+ continue;
+
+ // sort weapon by name by adding to weaponDict
+ weaponDict.Insert( pDef->GetDefinitionName(), pDef->GetDefinitionIndex() );
+ }
+
+ // add sorted weapon to the combobox
+ FOR_EACH_DICT( weaponDict, i )
+ {
+ item_definition_index_t weaponDefIndex = weaponDict.Element( i );
+ bool bSelect = defIndexSelect == weaponDefIndex;
+ pCombo->AddComboBoxEntry( weaponDict.GetElementName( i ), bSelect, CFmtStr( "%d", weaponDefIndex ), NULL );
+ }
+
+ return pCombo;
+}
+
+void CRequiredItemsParam::CreateNewControl( KeyValues* pKV )
+{
+ CEditorObjectNode* pRoot = new CEditorObjectNode( EditorObjectInitStruct{ this, pKV->GetName(), FLAGS_NONE } );
+
+ item_definition_index_t defIndexCurrent = (item_definition_index_t)pKV->GetInt( "loaner_defindex", INVALID_ITEM_DEF_INDEX );
+ CreateWeaponComboBox( { pRoot, "loaner_defindex", FLAG_NOT_DELETABLE }, "Loaner Item:", defIndexCurrent );
+
+ CQualifyingItemsParam* pQualifying = new CQualifyingItemsParam( EditorObjectInitStruct{ pRoot, "qualifying_items", FLAG_NOT_DELETABLE } );
+ pQualifying->InitControls( pKV->FindKey( "qualifying_items" ) );
+
+ BaseClass::CreateNewControl( pKV );
+}
+
+void CRequiredItemsParam::CreateNewDefaultControl()
+{
+ int nDefindex = GetNextAvailableKeyNumber() + 1;
+ int nObjectDefIndex = atoi( GetOwningEditable()->GetLiveData()->GetName() );
+
+ KeyValuesAD pKVName( CFmtStr( "%d", nDefindex ) );
+ pKVName->SetString( "token", CFmtStr( g_skNameTokenFormat, nObjectDefIndex, nDefindex ) );
+ CreateNewControl( pKVName );
+}
+
+
+void CQualifyingItemsParam::CreateNewControl( KeyValues* pKV )
+{
+ CEditorObjectNode* pNode = new CEditorObjectNode( EditorObjectInitStruct{ this, pKV->GetName(), FLAGS_NONE } );
+
+ item_definition_index_t defIndexCurrent = (item_definition_index_t)pKV->GetInt( "defindex", INVALID_ITEM_DEF_INDEX );
+ CreateWeaponComboBox( { pNode, "defindex", FLAGS_NONE }, "Qualifying Item:", defIndexCurrent );
+
+ BaseClass::CreateNewControl( pKV );
+}
+
+void CQualifyingItemsParam::CreateNewDefaultControl()
+{
+ int nDefindex = GetNextAvailableKeyNumber() + 1;
+
+ KeyValuesAD pKVQualifying( CFmtStr( "%d", nDefindex ) );
+ pKVQualifying->SetInt( "defindex", 0 );
+
+ CreateNewControl( pKVQualifying );
+}
+
+void CObjectiveExpandable::CreateNewControl( KeyValues* pKV )
+{
+ new CQuestObjectiveNode( this, pKV );
+}
+
+void CObjectiveExpandable::CreateNewDefaultControl()
+{
+ int nDefindex = GetNextAvailableKeyNumber() + 1;
+
+ KeyValuesAD pKVObjective( CFmtStr( "%d", nDefindex ) );
+ pKVObjective->SetInt( "description_string", 0 );
+
+ const int nQuestDefIndex = atoi( GetOwningEditable()->GetLiveData()->GetName() );
+ const int nObjDefIndex = ( ( nQuestDefIndex - g_nkFirstQuestDef ) + 1 ) * 100 + nDefindex;
+ pKVObjective->SetInt( "defindex", nObjDefIndex );
+ pKVObjective->SetString( "description_string", CFmtStr( g_skObjectiveDescTokenFormat, nQuestDefIndex, nDefindex ) );
+ pKVObjective->SetBool( "optional", false );
+ pKVObjective->SetInt( "conditions_def_index", INVALID_QUEST_OBJECTIVE_CONDITIONS_INDEX );
+ pKVObjective->SetInt( "advanced", 0 );
+
+ CreateNewControl( pKVObjective );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CQuestObjectiveRestrictionNode::CQuestObjectiveRestrictionNode( EditorObjectInitStruct init, CTFQuestCondition *pCondition )
+ : BaseClass( { init.pParent, init.m_pszKeyName, init.nFlags | FLAG_HIGHLIGHT_MOUSEOVER } )
+ , m_pCondition( pCondition )
+ , m_pNewCondition( NULL )
+{
+ CreateControlsForCondition();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveRestrictionNode::CreateControlsForCondition()
+{
+ CComboBoxEditorParam* pTypeParam = new CComboBoxEditorParam( { this, "type", FLAGS_NONE }, "Type:" );
+
+ CUtlVector< const char* > vecValidChildren;
+ m_pCondition->GetValidTypes( vecValidChildren );
+ FOR_EACH_VEC( vecValidChildren, i )
+ {
+ bool bSelected = FStrEq( m_pCondition->GetConditionName(), vecValidChildren[ i ] );
+ pTypeParam->AddComboBoxEntry( vecValidChildren[ i ], bSelected, vecValidChildren[ i ], "changetype" );
+ }
+
+ // Parameters for this node
+ KeyValuesAD KVParams( "params" );
+ m_pCondition->GetRequiredParamKeys( KVParams );
+
+ KeyValuesAD outputKey( "output" );
+ m_pCondition->GetOutputKeyValues( outputKey );
+
+ FOR_EACH_TRUE_SUBKEY( KVParams, params )
+ {
+ const char *pszParamEnglishName = params->GetString( "english_name", NULL );
+ const char *pszParamName = params->GetName();
+ const char *pszLabelText = pszParamEnglishName ? pszParamEnglishName : pszParamName;
+ const char *pszAction = FStrEq( pszParamName, "event_name" ) ? "changeevent" : NULL;
+
+ const char* pszControlType = params->GetString( "control_type", "combo_box" ); // Default to combobox
+
+ if ( FStrEq( "text_entry", pszControlType ) )
+ {
+ const char *pszOutput = outputKey->GetString( pszParamName, "" );
+ new CTextEntryEditorParam( { this, params->GetName(), FLAGS_NONE }, pszLabelText, pszOutput );
+ }
+ else if ( FStrEq( "combo_box", pszControlType ) )
+ {
+ CComboBoxEditorParam* pNewParam = new CComboBoxEditorParam( { this, params->GetName(), FLAGS_NONE }, pszLabelText );
+
+ const char *pszOutput = outputKey->GetString( pszParamName, "" );
+
+ pNewParam->ClearComboBoxEntries();
+
+ FOR_EACH_TRUE_SUBKEY( params, pChoiceKey )
+ {
+ const char *pszChoiceName = pChoiceKey->GetName();
+ const char *pszChoiceEnglishName = pChoiceKey->GetString( "english_name", NULL );
+
+ bool bSelect = FStrEq( pszOutput, pszChoiceName ) || pChoiceKey == params->GetFirstTrueSubKey();
+
+ pNewParam->AddComboBoxEntry( pszChoiceEnglishName ? pszChoiceEnglishName : pszChoiceName, bSelect, pszChoiceName, pszAction );
+ }
+
+ // Hide parameters where there's only 1 option
+ pNewParam->SetFlag( FLAG_HIDDEN, pNewParam->GetComboBox()->GetItemCount() <= 1 );
+ }
+ }
+
+ // Children of this node
+ CUtlVector< CTFQuestCondition* > vecChildConditions;
+ m_pCondition->GetChildren( vecChildConditions );
+ FOR_EACH_VEC( vecChildConditions, iChild )
+ {
+ CTFQuestCondition* pChildCondition = vecChildConditions[ iChild ];
+ new CQuestObjectiveRestrictionNode( { this, CFmtStr( "%d", iChild ), FLAGS_NONE }, pChildCondition );
+ }
+
+ CreateAddOpportunityParam();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveRestrictionNode::CreateAddOpportunityParam()
+{
+ int nChildCount = 0;
+ FOR_EACH_VEC( GetChildren(), i )
+ {
+ if ( dynamic_cast< CQuestObjectiveRestrictionNode* >( GetChildren()[i] ) )
+ {
+ ++nChildCount;
+ }
+ }
+
+ bool bShowAddOpportunity = m_pCondition && nChildCount < m_pCondition->GetMaxInputCount() ;
+ if ( m_pNewCondition && !bShowAddOpportunity )
+ {
+ delete m_pNewCondition;
+ m_pNewCondition = NULL;
+ }
+ else if ( !m_pNewCondition && bShowAddOpportunity )
+ {
+ // Add empty potential node
+ CUtlVector< const char* > vecValidChildren;
+ m_pCondition->GetValidChildren( vecValidChildren );
+ if ( vecValidChildren.Count() )
+ {
+ m_pNewCondition = new CNewQuestObjectiveParam( { this, NULL, FLAGS_NONE }, NULL );
+ FOR_EACH_VEC( vecValidChildren, i )
+ {
+ m_pNewCondition->AddComboBoxEntry( vecValidChildren[ i ], false, vecValidChildren [ i ], NULL );
+ }
+ }
+ }
+}
+
+void CQuestObjectiveRestrictionNode::RemoveNode()
+{
+ // tell parent to remove me and my children
+ if ( m_pCondition )
+ {
+ CTFQuestCondition *pParentCondition = m_pCondition->GetParent();
+ if ( pParentCondition )
+ {
+ pParentCondition->RemoveAndDeleteChild( m_pCondition );
+ }
+ }
+
+ m_pCondition = NULL;
+
+ BaseClass::RemoveNode();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveRestrictionNode::SetNewType( const char *pszType )
+{
+ // Delete all children
+ FOR_EACH_VEC_BACK( m_vecChildren, i )
+ {
+ m_vecChildren[i]->MarkForDeletion();
+ }
+
+ m_pNewCondition = NULL;
+
+
+ // Create new restriction
+ CTFQuestCondition* pParent = m_pCondition->GetParent();
+ if ( pParent && pParent->RemoveAndDeleteChild( m_pCondition ) )
+ {
+ m_pCondition = pParent->AddChildByName( pszType );
+ }
+ else
+ {
+ delete m_pCondition;
+ m_pCondition = CreateEvaluatorByName( pszType, NULL );
+ }
+
+ CreateControlsForCondition();
+ InvalidateChain();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveRestrictionNode::SetNewEvent( const char *pszEvent )
+{
+ // We only have to blow up everything if we're an evaluator
+ if ( !m_pCondition->IsEvaluator() )
+ {
+ return;
+ }
+
+ // Delete all children
+ FOR_EACH_VEC_BACK( m_vecChildren, i )
+ {
+ m_vecChildren[i]->MarkForDeletion();
+ }
+
+ m_pNewCondition = NULL;
+
+ char szType[256];
+ V_sprintf_safe( szType, "%s", m_pCondition->GetConditionName() );
+
+ // Create new restriction
+ CTFQuestCondition* pParent = m_pCondition->GetParent();
+ if ( pParent && pParent->RemoveAndDeleteChild( m_pCondition ) )
+ {
+ m_pCondition = pParent->AddChildByName( szType );
+ }
+ else
+ {
+ delete m_pCondition;
+ m_pCondition = CreateEvaluatorByName( szType, NULL );
+ }
+
+ V_sprintf_safe( m_szEventName, "%s", pszEvent );
+
+ m_pCondition->SetEventName( m_szEventName );
+ CreateControlsForCondition();
+ InvalidateChain();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestObjectiveRestrictionNode::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ CreateAddOpportunityParam();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CEditorQuest::CEditorQuest( KeyValues *pKV, Panel* pParent, const IEditableDataType* pEditable )
+ : CEditorObjectNode( EditorObjectInitStruct{ pParent, pKV->GetName(), FLAGS_NONE } )
+{
+ SetOwningEditable( pEditable );
+
+ new CTextEntryEditorParam( { this, "name", FLAG_HIDDEN }, "Item Def Name:", pKV->GetString( "name" ) );
+ new CLocalizationEditorParam( { this, "item_name", FLAGS_NONE }, "Item Name:", pKV->GetString( "item_name" ) );
+
+ CComboBoxEditorParam *pPrefabParam = new CComboBoxEditorParam( { this, "prefab", FLAGS_NONE }, "Prefab:" );
+ int nChosenIndex = -1;
+ for( int i=0; i < ARRAYSIZE( g_skQuestPrefabs ); ++i )
+ {
+ if ( FStrEq( g_skQuestPrefabs[i], pKV->GetString( "prefab" ) ) )
+ {
+ nChosenIndex = i;
+ }
+
+ bool bSelect = nChosenIndex == i || ( nChosenIndex == -1 && i == 0 );
+ pPrefabParam->AddComboBoxEntry( g_skQuestPrefabs[i], bSelect, g_skQuestPrefabs[i], NULL );
+ }
+
+ // Get the quest keys
+ KeyValues *pKVQuest = pKV->FindKey( "quest" );
+
+ // Create the panels to hold the quest def
+ CEditorObjectNode *pQuestNode = new CEditorObjectNode( EditorObjectInitStruct{ this, "quest", FLAG_HIDDEN } );
+
+ CQuestNameNode* pNameNode = new CQuestNameNode( EditorObjectInitStruct{ pQuestNode, "names", FLAG_NOT_DELETABLE | FLAG_COLLAPSABLE } );
+ pNameNode->InitControls( pKVQuest->FindKey( "names" ) );
+
+ new CTextEntryEditorParam( { pQuestNode, "max_standard_points", FLAGS_NONE }, "Max Standard Points:", pKVQuest->GetString( "max_standard_points" ) );
+ new CTextEntryEditorParam( { pQuestNode, "max_bonus_points", FLAGS_NONE }, "Max Bonus Points:", pKVQuest->GetString( "max_bonus_points" ) );
+ new CTextEntryEditorParam( { pQuestNode, "reward", FLAGS_NONE }, "Reward:", pKVQuest->GetString( "reward" ) );
+ new CTextEntryEditorParam( { pQuestNode, "objectives_to_roll", FLAGS_NONE }, "Objectives to roll:", pKVQuest->GetString( "objectives_to_roll" ) );
+ new CTextEntryEditorParam( { pQuestNode, "mm_map", FLAGS_NONE }, "Casual MM Map:", pKVQuest->GetString( "mm_map" ) );
+ CComboBoxEditorParam *pThemeParam = new CComboBoxEditorParam( { pQuestNode, "theme", FLAGS_NONE }, "Theming:" );
+ nChosenIndex = -1;
+ {
+ const auto& mapThemes = GetItemSchema()->GetQuestThemes();
+ FOR_EACH_MAP( mapThemes, i )
+ {
+ if ( FStrEq( mapThemes[i]->GetName(), pKVQuest->GetString( "theme" ) ) )
+ {
+ nChosenIndex = i;
+ }
+
+ bool bSelect = nChosenIndex == i || ( nChosenIndex == -1 && i == 0 );
+ pThemeParam->AddComboBoxEntry( mapThemes[i]->GetName(), bSelect, mapThemes[i]->GetName(), NULL );
+ }
+ }
+
+ CComboBoxEditorParam *pCorrespondingOperation = new CComboBoxEditorParam( { pQuestNode, "operation", FLAGS_NONE }, "Operation:" );
+ nChosenIndex = -1;
+ {
+ const auto& mapOperations = GetItemSchema()->GetOperationDefinitions();
+ FOR_EACH_MAP( mapOperations, i )
+ {
+ if ( FStrEq( mapOperations[i]->GetName(), pKVQuest->GetString( "operation" ) ) )
+ {
+ nChosenIndex = i;
+ }
+
+ bool bSelect = nChosenIndex == i || ( nChosenIndex == -1 && i == 0 );
+ pCorrespondingOperation->AddComboBoxEntry( mapOperations[i]->GetName(), bSelect, mapOperations[i]->GetName(), NULL );
+ }
+ }
+
+ CQuestDescriptionNode* pDescNode = new CQuestDescriptionNode( EditorObjectInitStruct{ pQuestNode, "descriptions", FLAG_NOT_DELETABLE | FLAG_COLLAPSABLE | FLAG_COLLAPSED } );
+ pDescNode->InitControls( pKVQuest->FindKey( "descriptions" ) );
+
+ CRequiredItemsParam* pRequiredExpandable = new CRequiredItemsParam( EditorObjectInitStruct{ pQuestNode, "required_items", FLAG_NOT_DELETABLE | FLAG_COLLAPSABLE | FLAG_DONT_EXPORT } );
+ pRequiredExpandable->InitControls( pKVQuest->FindKey( "required_items" ) );
+
+ CObjectiveExpandable* pObjectiveExpandable = new CObjectiveExpandable( EditorObjectInitStruct{ pQuestNode, "objectives", FLAG_NOT_DELETABLE | FLAG_COLLAPSABLE } );
+ pObjectiveExpandable->InitControls( pKVQuest->FindKey( "objectives" ) );
+
+ // Gets the scrollbar to be the right height
+ pParent->InvalidateLayout();
+}
+
+
+CEditorQuest::~CEditorQuest()
+{}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IEditableDataType::IEditableDataType( KeyValues* pKVData )
+ : m_pKVLiveData( pKVData->MakeCopy() )
+ , m_pKVSavedData( pKVData->MakeCopy() )
+ , m_pCurrentObject( NULL )
+ , m_bHasUnsavedChanges( false )
+{}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+IEditableDataType::~IEditableDataType()
+{
+ // We own the keys
+ if ( m_pKVLiveData )
+ {
+ m_pKVLiveData->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create the panels and store a pointer to them
+//-----------------------------------------------------------------------------
+void IEditableDataType::CreatePanels( Panel* pParent )
+{
+ Assert( m_pCurrentObject == NULL );
+ m_pCurrentObject = CreateEditableObject_Internal( pParent );
+ m_pCurrentObject->ClearPendingChangesFlag();
+
+ UpdateButton();
+}
+
+void IEditableDataType::DestroyPanels()
+{
+ if ( m_pCurrentObject )
+ {
+ m_pCurrentObject->MarkForDeletion();
+ m_pCurrentObject = NULL;
+ }
+
+ UpdateButton();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Given a type and a name, see if we match
+//-----------------------------------------------------------------------------
+bool IEditableDataType::MatchesCriteria( EType type, const char* pszName ) const
+{
+ return GetType() == type && FStrEq( pszName, m_pKVLiveData->GetName() );
+}
+
+class CKeyValuesDumpToString : public IKeyValuesDumpContextAsText
+{
+public:
+ // Overrides developer level to dump in DevMsg, zero to dump as Msg
+ CKeyValuesDumpToString() {}
+
+public:
+
+ virtual bool KvWriteValue( KeyValues *val, int nIndentLevel ) OVERRIDE
+ {
+ if ( !val )
+ {
+ return
+ KvWriteIndent( nIndentLevel ) &&
+ KvWriteText( "<< NULL >>\n" );
+ }
+
+ if ( !KvWriteIndent( nIndentLevel ) )
+ return false;
+
+ if ( !KvWriteText( val->GetName() ) )
+ return false;
+
+ if ( !KvWriteText( " " ) )
+ return false;
+
+ if ( !KvWriteText( val->GetString() ) )
+ return false;
+
+ return KvWriteText( "\n" );
+ }
+
+ virtual bool KvWriteText( char const *szText ) OVERRIDE
+ {
+ m_strDump.Append( szText );
+ return true;
+ }
+
+ CUtlString m_strDump;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Saves any changes that have been made with the controls. Does NOT write to disk.
+//-----------------------------------------------------------------------------
+void IEditableDataType::SaveEdits()
+{
+ // Get the new keys
+ KeyValues* tempKV = new KeyValues( "edits" );
+ tempKV->AddSubKey( m_pKVLiveData->MakeCopy() );
+
+ WriteObjectToKeyValues( false, tempKV );
+
+ // Update the live keys
+ m_pKVLiveData->deleteThis();
+ m_pKVLiveData = tempKV->GetFirstTrueSubKey()->MakeCopy();
+
+ CKeyValuesDumpToString dumpOrig;
+ CKeyValuesDumpToString dumpNew;
+
+ // Dump into strings
+ m_pKVLiveData->Dump( &dumpNew, 0, true );
+ m_pKVSavedData->Dump( &dumpOrig, 0, true );
+
+ // Compare the strings to check for a difference
+ m_bHasUnsavedChanges = !FStrEq( dumpOrig.m_strDump, dumpNew.m_strDump );
+
+ if ( m_bHasUnsavedChanges )
+ {
+ ConColorMsg( Color( 0, 173, 53, 255 ), "Old:\n%s", dumpOrig.m_strDump.String() );
+ ConColorMsg( Color( 218, 128, 56, 255 ), "New:\n%s", dumpNew.m_strDump.String() );
+ }
+
+ tempKV->deleteThis();
+
+ UpdateButton();
+}
+
+void IEditableDataType::UpdateButton()
+{
+ Button* pButton = g_pQuestEditor->GetButtonForEditable( this );
+ if ( pButton )
+ {
+ IScheme *pScheme = vgui::scheme()->GetIScheme( pButton->GetScheme() );
+ Color buttonBGColor = pButton->GetSchemeColor("Button.BgColor", Color(0, 0, 0, 255), pScheme);
+ Color buttonFGColor = pButton->GetSchemeColor("Button.FGColor", Color(0, 0, 0, 255), pScheme);
+
+ if ( m_pCurrentObject )
+ {
+ buttonBGColor[0] = Min( buttonBGColor[0] + 70, 255 );
+ buttonBGColor[1] = Min( buttonBGColor[1] + 70, 255 );
+ buttonBGColor[2] = Min( buttonBGColor[2] + 70, 255 );
+ }
+
+ if ( m_bHasUnsavedChanges )
+ {
+ buttonFGColor[0] = Min( buttonFGColor[0] + 150, 255 ); // Lil more red
+ }
+
+ pButton->SetDefaultColor( buttonFGColor, buttonBGColor );
+ pButton->SetArmedColor( buttonFGColor, pButton->GetButtonArmedBgColor() );
+
+ if ( GetType() == IEditableDataType::TYPE_QUEST )
+ {
+ char szItemName[256];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( m_pKVLiveData->GetString( "item_name" ) ), szItemName, sizeof( szItemName ) );
+ pButton->SetText( CFmtStr( "%s: %s", m_pKVLiveData->GetName(), szItemName ) );
+ }
+ else
+ {
+ pButton->SetText( CFmtStr( "%s: %s", m_pKVLiveData->GetName(), m_pKVLiveData->GetString( "name" ) ) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Serialize our object and save changes to disk
+//-----------------------------------------------------------------------------
+void IEditableDataType::SaveChangesToDisk()
+{
+ SaveEdits();
+
+ WriteDataToDisk( false );
+
+ // Clean out old save data and copy the new keys
+ if ( m_pKVSavedData )
+ {
+ m_pKVSavedData->deleteThis();
+ }
+
+ m_pKVSavedData = m_pKVLiveData->MakeCopy();
+
+ UpdateButton();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove our entry from any file we exist in. Remove our panels.
+// Delete our button that activates us.
+//-----------------------------------------------------------------------------
+void IEditableDataType::DeleteEntry()
+{
+ WriteDataToDisk( true );
+
+ if ( m_pCurrentObject )
+ {
+ m_pCurrentObject->SetFlag( FLAG_DELETED, true );
+ WriteLocalizationData();
+ }
+
+ UpdateButton();
+}
+
+void IEditableDataType::RevertChanges()
+{
+ Assert( m_pCurrentObject );
+ if ( !m_pCurrentObject )
+ return;
+
+ // Delete old panels
+ Panel* pCurrentParent = m_pCurrentObject->GetParent();
+ m_pCurrentObject->MarkForDeletion();
+ m_pCurrentObject = NULL;
+
+ // Delete live keys, and copy over the saved ones to live
+ m_pKVLiveData->deleteThis();
+ m_pKVLiveData = m_pKVSavedData->MakeCopy();
+
+ // Recreate panels
+ CreatePanels( pCurrentParent );
+ CheckForChanges();
+}
+
+void IEditableDataType::CheckForChanges()
+{
+ if ( m_pCurrentObject )
+ {
+ m_bHasUnsavedChanges = m_pCurrentObject->HasChanges( true );
+ UpdateButton();
+ }
+}
+
+void IEditableDataType::WriteObjectToKeyValues( bool bDelete, KeyValues* pKVExistingFileData )
+{
+ KeyValuesAD tempKV( "temp" );
+ m_pCurrentObject->SerializeToKVs( tempKV, this );
+
+ FOR_EACH_SUBKEY( tempKV, pNewObjectKey )
+ {
+ KeyValues *pCurrentObjectKey = pKVExistingFileData->FindKey( pNewObjectKey->GetName() );
+ if ( pCurrentObjectKey )
+ {
+ if ( bDelete )
+ {
+ pCurrentObjectKey->deleteThis();
+ }
+ else
+ {
+ // copy all elems
+ pCurrentObjectKey->Clear();
+ FOR_EACH_SUBKEY( pNewObjectKey, pElem )
+ {
+ pCurrentObjectKey->AddSubKey( pElem->MakeCopy() );
+ }
+ }
+ }
+ else
+ {
+ pKVExistingFileData->AddSubKey( pNewObjectKey->MakeCopy() );
+ }
+ }
+}
+
+
+int Sort_DefIndex( KeyValues* const* p1, KeyValues* const* p2 )
+{
+ int n1 = atoi( (*p1)->GetName() );
+ int n2 = atoi( (*p2)->GetName() );
+
+ return n1 - n2;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Write quest data to "tf/scripts/items/unencrypted/_items_quests.txt"
+//-----------------------------------------------------------------------------
+void CEditableQuestDataType::WriteDataToDisk( bool bDelete )
+{
+ // Wrap all of the quest in a "quests" keyvalue
+ CUtlBuffer bufRawData;
+ bufRawData.SetBufferType( true, true );
+ bufRawData.PutString( CFmtStr( "\"%s\"\n{\n", "quests") );
+
+ bool bReadFileOK = g_pFullFileSystem->ReadFile( g_skQuestDefFile, NULL, bufRawData );
+ if ( !bReadFileOK )
+ {
+ AssertMsg1( false, "Couldn't load file %s for saving!", g_skQuestDefFile );
+ return;
+ }
+
+ bufRawData.PutString( "\n}" );
+
+ // Load the buffer into keyvalues
+ KeyValuesAD pKVQuestItemData( "quests" );
+ pKVQuestItemData->LoadFromBuffer( NULL, bufRawData );
+
+ WriteObjectToKeyValues( bDelete, pKVQuestItemData );
+
+ // Sort by defindex
+ CUtlVector< KeyValues* > vecQuests;
+ FOR_EACH_SUBKEY( pKVQuestItemData, pItemKey )
+ {
+ vecQuests.AddToTail( pItemKey );
+ }
+ vecQuests.Sort( &Sort_DefIndex );
+
+
+ // Write housekeeping CSV file
+ FileHandle_t fileHandle = g_pFullFileSystem->Open( g_skQuestObjectivesHouseKeepingFile, "wt" );
+
+ // Write them out in order
+ CUtlBuffer buffer;
+ FOR_EACH_VEC( vecQuests, i )
+ {
+ // Write a row as we go through each quest item
+ KeyValues* pKVQuestBlock = vecQuests[i]->FindKey( "quest" );
+ if ( pKVQuestBlock )
+ {
+ KeyValues* pKVObjectives = pKVQuestBlock->FindKey( "objectives" );
+ if ( pKVObjectives )
+ {
+ FOR_EACH_TRUE_SUBKEY( pKVObjectives, pKVEntry )
+ {
+ char szDesc[256];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pKVEntry->GetString( "description_string" ) ), szDesc, sizeof( szDesc ) );
+ g_pFullFileSystem->FPrintf( fileHandle, "%d,%d,%d,%s,\n", pKVEntry->GetInt( "DefIndex" ), pKVEntry->GetInt( "points" ), pKVEntry->GetInt( "advanced" ), szDesc );
+ }
+ }
+ }
+
+ vecQuests[i]->RecursiveSaveToFile( buffer, 0, false, true );
+ }
+
+ g_pFullFileSystem->Close( fileHandle );
+
+ char szCorrectCaseFilePath[MAX_PATH];
+ g_pFullFileSystem->GetCaseCorrectFullPath( g_skQuestDefFile, szCorrectCaseFilePath );
+ CP4AutoEditFile a( szCorrectCaseFilePath );
+
+ if ( !g_pFullFileSystem->WriteFile( szCorrectCaseFilePath, NULL, buffer ) )
+ {
+ Warning( "Failed to write data to %s", g_skQuestDefFile );
+ }
+}
+
+IEditorObject* CEditableQuestDataType::CreateEditableObject_Internal( Panel* pParent ) const
+{
+ CEditorQuest* pNewQuest = new CEditorQuest( m_pKVLiveData, pParent, this );
+ return pNewQuest;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Write quest data to "tf/scripts/items/unencrypted/_items_quest_objective_definitions.txt"
+//-----------------------------------------------------------------------------
+void CEditableObjectiveConditionDataType::WriteDataToDisk( bool bDelete )
+{
+ // Wrap all of the quest in a "quests" keyvalue
+ CUtlBuffer bufRawData;
+ bufRawData.SetBufferType( true, true );
+
+ bool bReadFileOK = g_pFullFileSystem->ReadFile( g_skQuestObjectivesConditionsDefFile, NULL, bufRawData );
+ if ( !bReadFileOK )
+ {
+ AssertMsg1( false, "Couldn't load file %s for saving!", g_skQuestObjectivesConditionsDefFile );
+ return;
+ }
+
+ // Load the buffer into keyvalues
+ KeyValuesAD pKVQuestObjectivesData( "quest_objective_conditions" );
+ pKVQuestObjectivesData->LoadFromBuffer( NULL, bufRawData );
+
+ WriteObjectToKeyValues( bDelete, pKVQuestObjectivesData );
+
+ // Sort by defindex
+ CUtlVector< KeyValues* > vecQuestObjectives;
+ FOR_EACH_SUBKEY( pKVQuestObjectivesData, pItemKey )
+ {
+ vecQuestObjectives.AddToTail( pItemKey );
+ }
+ vecQuestObjectives.Sort( &Sort_DefIndex );
+
+ KeyValuesAD pKVSorted( "quest_objective_conditions" );
+
+ // Write them out in order
+ FOR_EACH_VEC( vecQuestObjectives, i )
+ {
+ pKVSorted->AddSubKey( vecQuestObjectives[i]->MakeCopy() );
+ }
+
+ // Write the definitions
+ {
+ CUtlBuffer buffer;
+ pKVSorted->RecursiveSaveToFile( buffer, 0, false, true );
+
+ char szCorrectCaseFilePath[MAX_PATH];
+ g_pFullFileSystem->GetCaseCorrectFullPath( g_skQuestObjectivesConditionsDefFile, szCorrectCaseFilePath );
+ CP4AutoEditFile a( szCorrectCaseFilePath );
+
+ if ( !g_pFullFileSystem->WriteFile( szCorrectCaseFilePath, NULL, buffer ) )
+ {
+ Warning( "Failed to write data to %s", g_skQuestObjectivesConditionsDefFile );
+ }
+ }
+}
+
+IEditorObject* CEditableObjectiveConditionDataType::CreateEditableObject_Internal( Panel* pParent ) const
+{
+ CEditorObjectNode *pConditionDef = new CEditorObjectNode( EditorObjectInitStruct{ pParent, m_pKVLiveData->GetName(), FLAG_HIDDEN } );
+ pConditionDef->SetOwningEditable( this );
+
+ new CTextEntryEditorParam( { pConditionDef, "name", FLAGS_NONE }, "Conditions name:", m_pKVLiveData->GetString( "name" ) );
+
+ CRequiredItemsParam* pRequiredExpandable = new CRequiredItemsParam( EditorObjectInitStruct{ pConditionDef, "required_items", FLAG_NOT_DELETABLE | FLAG_COLLAPSABLE | FLAG_DONT_EXPORT } );
+ pRequiredExpandable->InitControls( m_pKVLiveData->FindKey( "required_items" ) );
+
+ KeyValues* pKVConditionLogic = m_pKVLiveData->FindKey( "condition_logic" );
+
+ const char *pszType = pKVConditionLogic->GetString( "type" );
+ CTFQuestCondition *pCondition = CreateEvaluatorByName( pszType, NULL );
+
+ if ( !pCondition->BInitFromKV( pKVConditionLogic, NULL ) )
+ {
+ Assert( false );
+ }
+
+ new CQuestObjectiveRestrictionNode( { pConditionDef, "condition_logic", FLAGS_NONE }, pCondition );
+
+ return pConditionDef;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CQuestEditorPanel::CQuestEditorPanel( Panel *pParent, const char *pszName )
+ : Frame( pParent, pszName )
+ , m_pCurrentOpenEdit( NULL )
+ , m_eCurrentSelectionMode( SELECTION_MODE_NONE )
+{
+ SetTitle( "Quest Editor", true );
+
+ memset( m_pButtonsFilterTextEntry, NULL, sizeof( m_pButtonsFilterTextEntry ) );
+ m_pEditingPanel = new CExScrollingEditablePanel( this, "EditingPanel" );
+ m_pButtonsContainers[ IEditableDataType::TYPE_QUEST ] = new CExScrollingEditablePanel( this, "QuestListContainer" );
+ m_pButtonsContainers[ IEditableDataType::TYPE_OBJECTIVE_CONDITIONS ] = new CExScrollingEditablePanel( this, "QuestObjectiveConditionsContainer" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::Deploy()
+{
+ PopulateExistingQuests();
+
+ SetVisible( true );
+ MakePopup();
+ MoveToFront();
+ SetKeyBoardInputEnabled(true);
+ SetMouseInputEnabled(true);
+ InvalidateLayout( true, true );
+
+ // Center it, keeping requested size
+ int x, y, ww, wt, wide, tall;
+ vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
+ GetSize(wide, tall);
+ SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings( "Resource/UI/econ/QuestEditor.res" );
+
+ m_pButtonsFilterTextEntry[ IEditableDataType::TYPE_QUEST ] = FindControl< TextEntry >( "QuestsFilter" );
+ if ( m_pButtonsFilterTextEntry[ IEditableDataType::TYPE_QUEST ] )
+ {
+ m_pButtonsFilterTextEntry[ IEditableDataType::TYPE_QUEST ]->AddActionSignalTarget( this );
+ }
+ m_pButtonsFilterTextEntry[ IEditableDataType::TYPE_OBJECTIVE_CONDITIONS ] = FindControl< TextEntry >( "ConditionsFilter" );
+ if ( m_pButtonsFilterTextEntry[ IEditableDataType::TYPE_OBJECTIVE_CONDITIONS ] )
+ {
+ m_pButtonsFilterTextEntry[ IEditableDataType::TYPE_OBJECTIVE_CONDITIONS ]->AddActionSignalTarget( this );
+ }
+
+ Label *pP4Warning = FindControl< Label >( "P4Warning" );
+ if ( pP4Warning )
+ {
+ pP4Warning->SetVisible( p4 == NULL );
+ }
+
+ Button* pSaveButton = FindControl< Button >( "SaveButton" );
+ if ( pSaveButton )
+ {
+ pSaveButton->SetEnabled( p4 != NULL );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ for ( int nType = 0; nType < IEditableDataType::NUM_TYPES; ++nType )
+ {
+ UpdateButtons( (IEditableDataType::EType)nType );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::UpdateButtons( IEditableDataType::EType eType )
+{
+ m_pButtonsContainers[ eType ]->ResetScrollAmount();
+
+ // Get the text out of the text entry
+ char szFilterText[256];
+ m_pButtonsFilterTextEntry[ eType ]->GetText( szFilterText, sizeof( szFilterText ) );
+ Q_strlower( szFilterText );
+
+ int yPos = 5;
+ FOR_EACH_VEC( m_vecEditableButtons[ eType ], i )
+ {
+ Button* pButton = m_vecEditableButtons[ eType ][ i ];
+
+ // Get the text out of the button
+ char szButtonText[256];
+ pButton->GetText( szButtonText, sizeof( szButtonText ) );
+ Q_strlower( szButtonText );
+
+ // Substring search for the text entry text in the button text
+ if ( V_strstr( szButtonText, szFilterText ) == NULL )
+ {
+ pButton->SetVisible( false );
+ continue;
+ }
+
+ pButton->SetVisible( true );
+
+ float flWideScale = 1.f;
+ pButton->SetWide( pButton->GetParent()->GetWide() * flWideScale );
+ pButton->SetTall( 20 );
+ pButton->SetPos( 0, yPos );
+ yPos += pButton->GetTall() + 5 ;
+ }
+
+ m_pButtonsContainers[ eType ]->InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::OnCommand( const char *command )
+{
+ if ( Q_strnicmp( "select", command, 6 ) == 0 )
+ {
+ // comes in the form "select(type) (name)"
+ const char* pszType = command + 6;
+ IEditableDataType::EType eType = (IEditableDataType::EType)atoi( pszType );
+ // Jump past the first ' ' and grab whatever is left as the name
+ const char* pszName = strchr( pszType, ' ' ) + 1;
+
+ if ( m_eCurrentSelectionMode == SELECTION_MODE_QUEST_OBJECTIVE && eType == IEditableDataType::TYPE_OBJECTIVE_CONDITIONS )
+ {
+ m_eCurrentSelectionMode = SELECTION_MODE_NONE;
+
+ Panel* pSelectionpanel = m_hSelectionPanel.Get();
+ if ( pSelectionpanel )
+ {
+ PostMessage( pSelectionpanel, new KeyValues( "ObjectiveSelected", "defindex", pszName ) );
+ }
+ }
+ else
+ {
+ if ( m_pCurrentOpenEdit )
+ {
+ // This the one that's already open? Don't do anything
+ if ( FStrEq( pszName, m_pCurrentOpenEdit->GetLiveData()->GetName() ) )
+ {
+ return;
+ }
+
+ // We have something open. Close it down, saving live edits
+ CloseEdit( m_pCurrentOpenEdit );
+ m_pCurrentOpenEdit = NULL;
+ }
+
+ m_pEditingPanel->ResetScrollAmount();
+ m_pCurrentOpenEdit = OpenForEdit( eType, pszName, m_pEditingPanel );
+ m_pEditingPanel->InvalidateLayout();
+ }
+
+ return;
+ }
+ else if ( Q_stricmp( "revert", command ) == 0 )
+ {
+ if ( m_pCurrentOpenEdit )
+ {
+ m_pCurrentOpenEdit->RevertChanges();
+ }
+
+ ResetQuestSelectionState();
+ }
+ else if ( Q_stricmp( "save", command ) == 0 )
+ {
+ WriteLocalizationData();
+
+ FOR_EACH_VEC( m_vecOpenEdits, i )
+ {
+ m_vecOpenEdits[ i ]->SaveChangesToDisk();
+ }
+
+ ResetQuestSelectionState();
+
+ return;
+ }
+ else if ( Q_stricmp( "newquest", command ) == 0 )
+ {
+ CloseEdit( m_pCurrentOpenEdit );
+ m_pEditingPanel->ResetScrollAmount();
+ IEditableDataType* pNewEditable = CreateNewQuest();
+ m_pCurrentOpenEdit = OpenForEdit( IEditableDataType::TYPE_QUEST, CFmtStr( "%s", pNewEditable->GetLiveData()->GetName() ), m_pEditingPanel );
+ ResetQuestSelectionState();
+ }
+ else if ( Q_stricmp( "newobjcond", command ) == 0 )
+ {
+ CloseEdit( m_pCurrentOpenEdit );
+ m_pEditingPanel->ResetScrollAmount();
+ IEditableDataType* pNewEditable = CreateNewObjectiveCondition();
+ m_pCurrentOpenEdit = OpenForEdit( IEditableDataType::TYPE_OBJECTIVE_CONDITIONS, CFmtStr( "%s", pNewEditable->GetLiveData()->GetName() ), m_pEditingPanel );
+ ResetQuestSelectionState();
+ }
+ else if ( Q_stricmp( "delete", command ) == 0 )
+ {
+ if ( m_pCurrentOpenEdit )
+ {
+ m_pCurrentOpenEdit->DeleteEntry();
+ CloseEdit( m_pCurrentOpenEdit );
+
+ Button* pButton = GetButtonForEditable( m_pCurrentOpenEdit );
+ Assert( pButton );
+ // Delete the button associated with this editable
+ if( pButton )
+ {
+ if ( !m_vecEditableButtons[ m_pCurrentOpenEdit->GetType() ].FindAndRemove( pButton ) )
+ {
+ AssertMsg( false, "Could not find button to remove when deleting editable!" );
+ }
+ pButton->MarkForDeletion();
+ InvalidateLayout();
+ }
+
+ // Remove this editable from the list
+ if ( !m_vecEditableData.FindAndRemove( m_pCurrentOpenEdit ) )
+ {
+ AssertMsg( false, "Could not find editable to remove when deleting editable!" );
+ }
+
+ delete m_pCurrentOpenEdit;
+ m_pCurrentOpenEdit = NULL;
+ }
+ ResetQuestSelectionState();
+ }
+ else if ( Q_stricmp( "open_edit_context", command ) == 0 )
+ {
+ OpenEditContextMenu();
+ ResetQuestSelectionState();
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+void CQuestEditorPanel::OnThink()
+{
+ FOR_EACH_VEC( m_vecOpenEdits, i )
+ {
+ engine->Con_NPrintf( i, CFmtStr( "%s %s", m_vecOpenEdits[i]->GetType() == IEditableDataType::TYPE_OBJECTIVE_CONDITIONS ? "Condition" : "Quest", m_vecOpenEdits[i]->GetLiveData()->GetName() ) );
+ }
+
+ BaseClass::OnThink();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Try to find the right editable to open
+//-----------------------------------------------------------------------------
+IEditableDataType* CQuestEditorPanel::OpenForEdit( IEditableDataType::EType type, const char* pszName, Panel* pParent )
+{
+ FOR_EACH_VEC( m_vecEditableData, i )
+ {
+ if ( m_vecEditableData[i]->MatchesCriteria( type, pszName ) )
+ {
+ m_vecEditableData[i]->CreatePanels( pParent );
+
+ FOR_EACH_VEC( m_vecOpenEdits, j )
+ {
+ if ( m_vecOpenEdits[j] == m_vecEditableData[i] )
+ {
+ AssertMsg1( false, "Editable with name %s was already open for edit!", m_vecEditableData[i]->GetLiveData()->GetName() );
+ m_vecOpenEdits.Remove( j );
+ }
+ }
+
+ m_vecOpenEdits.AddToTail( m_vecEditableData[i] );
+ return m_vecEditableData[i];
+ }
+ }
+
+ Assert( !"Failed to find editable for edit!" );
+ return NULL;
+}
+
+void CQuestEditorPanel::CloseEdit( IEditableDataType* pEditable )
+{
+ if ( !pEditable )
+ return;
+
+ FOR_EACH_VEC( m_vecOpenEdits, i )
+ {
+ if ( m_vecOpenEdits[i] == pEditable )
+ {
+ m_vecOpenEdits.Remove( i );
+ pEditable->SaveEdits();
+ pEditable->DestroyPanels();
+ return;
+ }
+ }
+
+ AssertMsg1( false, "Editable with name %s wasn't open for edit!", pEditable->GetLiveData()->GetName() );
+}
+
+bool CQuestEditorPanel::IsOpenForEdit( const IEditableDataType* pEditable ) const
+{
+ Assert( pEditable );
+ if ( !pEditable )
+ return false;
+
+ FOR_EACH_VEC( m_vecOpenEdits, i )
+ {
+ if ( m_vecOpenEdits[i] == pEditable )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Button* CQuestEditorPanel::GetButtonForEditable( const IEditableDataType* pEditable ) const
+{
+ IEditableDataType::EType eType = pEditable->GetType();
+
+ auto& vecButtons = m_vecEditableButtons[ eType ];
+ FOR_EACH_VEC( vecButtons, i )
+ {
+ if ( vecButtons[i] == pEditable->GetButton() )
+ {
+ return vecButtons[i];
+ }
+ }
+
+ return NULL;
+}
+
+template< typename T >
+IEditableDataType* CQuestEditorPanel::AddNewEditableKVData( KeyValues* pKVData, const char* pszName )
+{
+ IEditableDataType* pNewEditable = new T( pKVData );
+ IEditableDataType::EType eType = pNewEditable->GetType();
+ m_vecEditableData.AddToTail( pNewEditable );
+
+ Button *pButton = new Button( m_pButtonsContainers[ eType ]
+ , "objectivebutton"
+ , CFmtStr( "%s: %s", pKVData->GetName(), pszName )
+ , this
+ , CFmtStr( "select%d %s", eType, pKVData->GetName() ) );
+
+ pNewEditable->SetButton( pButton );
+ m_vecEditableButtons[ eType ].AddToTail( pButton );
+
+ InvalidateLayout();
+
+ return pNewEditable;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::PopulateExistingQuests()
+{
+ m_vecEditableData.PurgeAndDeleteElements();
+
+ // Quest data
+ {
+ // Quests are a little strange. In the quest file, there is no root key because quests
+ // are items and are spliced right into the middle of all the other items. To handle this
+ // We add "quests"
+ // {
+ // << all the stuff from the file >>
+ // }
+ // To make parsing easier
+ CUtlBuffer bufRawData;
+ bufRawData.SetBufferType( true, true );
+ bufRawData.PutString( "\"quests\"\n{\n" );
+ bool bReadFileOK = g_pFullFileSystem->ReadFile( g_skQuestDefFile, NULL, bufRawData );
+ if ( !bReadFileOK )
+ {
+ AssertMsg1( false, "Couldn't load quest file %s for saving!", g_skQuestDefFile );
+ return;
+ }
+ bufRawData.PutString( "\n}" );
+
+ // Load quest data from file
+ KeyValuesAD pKVQuestDefinitions( "quests" );
+ pKVQuestDefinitions->LoadFromBuffer( NULL, bufRawData );
+
+ // Create editable objects and buttons for each
+ FOR_EACH_TRUE_SUBKEY( pKVQuestDefinitions, pKVQuest )
+ {
+ char szItemName[256];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pKVQuest->GetString( "item_name" ) ), szItemName, sizeof( szItemName ) );
+
+ AddNewEditableKVData< CEditableQuestDataType >( pKVQuest, szItemName );
+ }
+ }
+
+ // Objective data
+ {
+ CUtlBuffer bufRawData;
+ bufRawData.SetBufferType( true, true );
+
+ // Now go read the objective conditions file
+ bool bReadFileOK = g_pFullFileSystem->ReadFile( g_skQuestObjectivesConditionsDefFile, NULL, bufRawData );
+ if ( !bReadFileOK )
+ {
+ AssertMsg1( false, "Couldn't load quest file %s for saving!", g_skQuestObjectivesConditionsDefFile );
+ return;
+ }
+
+ // Load objective data from file
+ KeyValuesAD pKVObjectiveConditions( "objectives" );
+ pKVObjectiveConditions->LoadFromBuffer( NULL, bufRawData );
+
+ // Create editable objects and buttons for each
+ FOR_EACH_TRUE_SUBKEY( pKVObjectiveConditions, pKVCondition )
+ {
+ AddNewEditableKVData< CEditableObjectiveConditionDataType >( pKVCondition, pKVCondition->GetString( "name" ) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a new quest with the next available itemdefindex
+//-----------------------------------------------------------------------------
+IEditableDataType* CQuestEditorPanel::CreateNewQuest()
+{
+ // Find the next item def to use
+ int nNextQuestDefIndex = 0;
+ FOR_EACH_VEC( m_vecEditableData, i )
+ {
+ IEditableDataType* pData = m_vecEditableData[ i ];
+ if ( pData->GetType() == IEditableDataType::TYPE_QUEST )
+ {
+ nNextQuestDefIndex = Max( nNextQuestDefIndex, atoi( pData->GetLiveData()->GetName() ) );
+ }
+ }
+
+ ++nNextQuestDefIndex;
+
+ // Create keyvalues to describe a default quest
+ KeyValuesAD pKVNewQuest( CFmtStr( "%d", nNextQuestDefIndex ) );
+ pKVNewQuest->SetString( "name", CFmtStr( g_skItemNameFormat, nNextQuestDefIndex ) );
+ pKVNewQuest->SetString( "item_name", CFmtStr( g_skNameTokenFormat, nNextQuestDefIndex ) );
+ pKVNewQuest->SetString( "prefab", g_skQuestPrefabs[0] );
+
+ // Tool keys
+ KeyValues *pKeyQuestBlock = pKVNewQuest->CreateNewKey(); pKeyQuestBlock->SetName( "quest" );
+ pKeyQuestBlock->SetInt( "max_standard_points", 100 );
+ pKeyQuestBlock->SetInt( "max_bonus_points", 30 );
+ pKeyQuestBlock->SetInt( "objectives_to_roll", 1 );
+ pKeyQuestBlock->SetString( "reward", "contract_lootlist_1" );
+ pKeyQuestBlock->SetString( "theme", GetItemSchema()->GetQuestThemes()[0]->GetName() );
+ KeyValues *pKeyObjectiveBlock = pKeyQuestBlock->CreateNewKey(); pKeyObjectiveBlock->SetName( "objectives" );
+
+ return AddNewEditableKVData< CEditableQuestDataType >( pKVNewQuest, pKVNewQuest->GetString( "name" ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a new conditions with the next available defindex
+//-----------------------------------------------------------------------------
+IEditableDataType* CQuestEditorPanel::CreateNewObjectiveCondition()
+{
+ int nNextDefIndex = 0;
+ FOR_EACH_VEC( m_vecEditableData, i )
+ {
+ IEditableDataType* pData = m_vecEditableData[ i ];
+ if ( pData->GetType() == IEditableDataType::TYPE_OBJECTIVE_CONDITIONS )
+ {
+ nNextDefIndex = Max( nNextDefIndex, atoi( pData->GetLiveData()->GetName() ) );
+ }
+ }
+
+ ++nNextDefIndex;
+
+ KeyValuesAD pKVNewObjCond( CFmtStr( "%d", nNextDefIndex ) );
+ pKVNewObjCond->SetString( "name", "*** New Objective ***" );
+
+ KeyValues* pKVConditionsBlock = pKVNewObjCond->CreateNewKey();
+ pKVConditionsBlock->SetName( "condition_logic" );
+ pKVConditionsBlock->SetString( "event_name", "player_score_changed" );
+ pKVConditionsBlock->SetString( "score_key_name", "delta" );
+ pKVConditionsBlock->SetString( "type", "event_listener" );
+
+ return AddNewEditableKVData< CEditableObjectiveConditionDataType >( pKVNewObjCond, pKVNewObjCond->GetString( "name" ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Open up a context menu with actions for the editing item
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::OpenEditContextMenu()
+{
+ Menu *pContextMenu = new Menu( this, "ContextMenu" );
+
+ pContextMenu->AddMenuItem( "Save", this, new KeyValues( "save" ) );
+ pContextMenu->AddMenuItem( "Revert", this, new KeyValues( "revert" ) );
+ pContextMenu->AddSeparator();
+ pContextMenu->AddMenuItem( "Delete", this, new KeyValues( "delete" ) );
+
+ // Position to the cursor's position
+ int nX, nY;
+ g_pVGuiInput->GetCursorPosition( nX, nY );
+ pContextMenu->SetPos( nX - 1, nY - 1 );
+
+ pContextMenu->SetVisible(true);
+ pContextMenu->AddActionSignalTarget(this);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::OnTextChanged( KeyValues *data )
+{
+ Panel *pPanel = reinterpret_cast< vgui::Panel* >( data->GetPtr( "panel" ) );
+
+ for ( int nType = 0; nType < IEditableDataType::NUM_TYPES; ++nType )
+ {
+ if ( pPanel == m_pButtonsFilterTextEntry[ nType ] )
+ {
+ UpdateButtons( (IEditableDataType::EType)nType );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::OnSelectQuestObjective( KeyValues *data )
+{
+ m_hSelectionPanel = reinterpret_cast< vgui::Panel* >( data->GetPtr( "panel" ) );
+ m_eCurrentSelectionMode = SELECTION_MODE_QUEST_OBJECTIVE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CQuestEditorPanel::CheckForChanges()
+{
+ FOR_EACH_VEC( m_vecEditableData, i )
+ {
+ m_vecEditableData[i]->CheckForChanges();
+ }
+}
+
+#endif // STAGING_ONLY