//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Shared interface to the tech tree & individual technologies // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #ifndef CLIENT_DLL #include "tf_player.h" #include "tf_team.h" #include "info_customtech.h" #endif #include "techtree.h" bool ParseTechnologyFile( CUtlVector< CBaseTechnology* > &pTechnologyList, IFileSystem* pFileSystem, int nTeamNumber, char *sFileName ); // Color codes for resources rescolor sResourceColor = { 64, 255, 64 }; // Prototype names for resources char sResourceName[] = "Jojierium"; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CBaseTechnology::CBaseTechnology( void ) { m_nTechLevel = 0; ZeroPreferences(); SetAvailable( false ); SetActive( false ); SetPreferred( false ); SetVoters( 0 ); SetCost( 0 ); SetDirty( false ); m_fResourceLevel = 0; memset( m_ClassResults, 0, sizeof( m_ClassResults ) ); memset( m_pszName, 0, sizeof( m_pszName ) ); memset( m_pszPrintName, 0, sizeof( m_pszPrintName ) ); memset( m_pszDescription, 0, sizeof( m_pszDescription ) ); memset( m_pszTeamSoundFile, 0, sizeof( m_pszTeamSoundFile ) ); memset( m_apszContainedTechs, 0, sizeof( m_apszContainedTechs ) ); memset( m_pContainedTechs, 0, sizeof(m_pContainedTechs) ); memset( m_apszDependentTechs, 0, sizeof( m_apszDependentTechs ) ); memset( m_pDependentTechs, 0, sizeof(m_pDependentTechs) ); m_iContainedTechs = 0; m_iDependentTechs = 0; m_iTeamSound = 0; m_bGoalTechnology = false; m_bClassUpgrade = false; m_bVehicle = false; m_bTechLevelUpgrade = false; m_bResourceTech = false; memset( m_szTextureName, 0, sizeof( m_szTextureName ) ); m_nTextureID = 0; memset( m_szButtonName, 0, sizeof( m_szButtonName ) ); m_nNumWeaponAssociations = 0; memset( m_rgszWeaponAssociation, 0, sizeof( m_rgszWeaponAssociation ) ); SetHidden( false ); ResetHintsGiven(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CBaseTechnology::~CBaseTechnology( void ) { } static bool NameStartsWith( const char *name, const char *prefix ) { if ( !name || !name[ 0 ] || !prefix || !prefix[ 0 ] ) return false; if ( !strnicmp( name, prefix, strlen( prefix ) ) ) return true; return false; } //----------------------------------------------------------------------------- // Purpose: Set the technology name //----------------------------------------------------------------------------- void CBaseTechnology::SetName( const char *pName ) { Q_strncpy( m_pszName, pName, sizeof(m_pszName) ); // Determine special information about this technology m_bClassUpgrade = NameStartsWith( pName, "class_" ); m_bVehicle = NameStartsWith( pName, "vehicle_" ); m_bTechLevelUpgrade = NameStartsWith( pName, "tech_level_" ); // HACK: Assume global techs relate to resources for now m_bResourceTech = NameStartsWith( pName, "g_" ); } //----------------------------------------------------------------------------- // Purpose: Set the technology print name //----------------------------------------------------------------------------- void CBaseTechnology::SetPrintName( const char *pName ) { Q_strncpy( m_pszPrintName, pName, sizeof(m_pszPrintName) ); } //----------------------------------------------------------------------------- // Purpose: Set the technology description //----------------------------------------------------------------------------- void CBaseTechnology::SetDescription( const char *pDesc ) { Q_strncpy( m_pszDescription, pDesc, sizeof(m_pszDescription) ); } //----------------------------------------------------------------------------- // Purpose: // Input : *pName - //----------------------------------------------------------------------------- void CBaseTechnology::SetButtonName( const char *pName ) { Q_strncpy( m_szButtonName, pName, sizeof(m_szButtonName) ); } //----------------------------------------------------------------------------- // Purpose: Set the technology level //----------------------------------------------------------------------------- void CBaseTechnology::SetLevel( int iLevel ) { m_nTechLevel = iLevel; } //----------------------------------------------------------------------------- // Purpose: // Input : *texture - //----------------------------------------------------------------------------- void CBaseTechnology::SetTextureName( const char *texture ) { Q_strncpy( m_szTextureName, texture, sizeof( m_szTextureName ) ); } //----------------------------------------------------------------------------- // Purpose: // Input : id - //----------------------------------------------------------------------------- void CBaseTechnology::SetTextureId( int id ) { m_nTextureID = id; } //----------------------------------------------------------------------------- // Purpose: Set the technologies resource costs //----------------------------------------------------------------------------- void CBaseTechnology::SetCost( float fResourceCost ) { m_fResourceCost = fResourceCost; RecalculateOverallLevel(); } //----------------------------------------------------------------------------- // Purpose: Set a specific class's sound //----------------------------------------------------------------------------- void CBaseTechnology::SetClassResultSound( int iClass, const char *pSound ) { if (!pSound) return; Assert( iClass >= 0 && iClass < TFCLASS_CLASS_COUNT ); // Class of 0 is the team's sound file if ( iClass == 0 ) { Q_strncpy( m_pszTeamSoundFile, pSound, sizeof(m_pszTeamSoundFile) ); } else { m_ClassResults[iClass].bClassTouched = true; Q_strncpy( m_ClassResults[iClass].pszSoundFile, pSound, sizeof(m_ClassResults[iClass].pszSoundFile) ); } } //----------------------------------------------------------------------------- // Purpose: // Input : associate - //----------------------------------------------------------------------------- void CBaseTechnology::SetClassResultAssociateWeapons( int iClass, bool associate ) { Assert( iClass >= 0 && iClass < TFCLASS_CLASS_COUNT ); m_ClassResults[iClass].m_bAssociateWeaponsForClass = associate; } //----------------------------------------------------------------------------- // Purpose: Set a specific class's precached sound //----------------------------------------------------------------------------- void CBaseTechnology::SetClassResultSound( int iClass, int iSound ) { Assert( iClass >= 0 && iClass < TFCLASS_CLASS_COUNT ); // Class of 0 is the team's sound file if ( iClass == 0 ) { m_iTeamSound = iSound; } else { m_ClassResults[iClass].iSound = iSound; } } //----------------------------------------------------------------------------- // Purpose: Set a specific class's description //----------------------------------------------------------------------------- void CBaseTechnology::SetClassResultDescription( int iClass, const char *pDesc ) { if (!pDesc) return; Assert( iClass > 0 && iClass < TFCLASS_CLASS_COUNT ); m_ClassResults[iClass].bClassTouched = true; Q_strncpy( m_ClassResults[iClass].pszDescription, pDesc, sizeof(m_ClassResults[iClass].pszDescription) ); } //----------------------------------------------------------------------------- // Purpose: Add a technology contained within this one //----------------------------------------------------------------------------- void CBaseTechnology::AddContainedTechnology( const char *pszTech ) { Q_strncpy( m_apszContainedTechs[ m_iContainedTechs ], pszTech, sizeof(m_apszContainedTechs[0]) ); m_iContainedTechs++; } //----------------------------------------------------------------------------- // Purpose: Add a technology dependency within this one //----------------------------------------------------------------------------- void CBaseTechnology::AddDependentTechnology( const char *pszTech ) { Q_strncpy( m_apszDependentTechs[ m_iDependentTechs ], pszTech, sizeof(m_apszDependentTechs[0]) ); m_iDependentTechs++; } //----------------------------------------------------------------------------- // Purpose: Returns true if this technology affects the specified class //----------------------------------------------------------------------------- bool CBaseTechnology::AffectsClass( int iClass ) { // If this technology directly affects this class, return true if ( m_ClassResults[ iClass ].bClassTouched ) return true; // If not, do any of our contained techs affect the specified class for (int i = 0; i < m_iContainedTechs; i++ ) { if ( m_pContainedTechs[i] ) { if ( m_pContainedTechs[i]->AffectsClass( iClass ) ) return true; } } return false; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBaseTechnology::IsClassUpgrade( void ) { return m_bClassUpgrade; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBaseTechnology::IsVehicle( void ) { return m_bVehicle; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBaseTechnology::IsResourceTech( void ) { return m_bResourceTech; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBaseTechnology::IsTechLevelUpgrade( void ) { return m_bTechLevelUpgrade; } //----------------------------------------------------------------------------- // Purpose: Returns the level to which this technology belongs // Output : int //----------------------------------------------------------------------------- int CBaseTechnology::GetLevel( void ) { return m_nTechLevel; } //----------------------------------------------------------------------------- // Purpose: Cost of technology in resource specified //----------------------------------------------------------------------------- float CBaseTechnology::GetResourceCost( void ) { return m_fResourceCost; } //----------------------------------------------------------------------------- // Purpose: Retrieves the current amount of resources spent on the technology //----------------------------------------------------------------------------- float CBaseTechnology::GetResourceLevel( void ) { return m_fResourceLevel; } //----------------------------------------------------------------------------- // Purpose: Sets a resource level to an amount //----------------------------------------------------------------------------- void CBaseTechnology::SetResourceLevel( float flResourceLevel ) { if ( m_fResourceLevel == flResourceLevel ) return; m_fResourceLevel = flResourceLevel; // Update my level & watchers RecalculateOverallLevel(); UpdateWatchers(); // Force me to be resent to clients SetDirty( true ); } //----------------------------------------------------------------------------- // Purpose: Increase the level of the specified resource spent on this technology // Output : Returns true if the technology's had enough resources to be bought //----------------------------------------------------------------------------- bool CBaseTechnology::IncreaseResourceLevel( float flResourcesToSpend ) { SetResourceLevel( m_fResourceLevel + flResourcesToSpend ); // Have my costs been met? if ( GetResourceLevel() < GetResourceCost() ) return false; return true; } //----------------------------------------------------------------------------- // Purpose: Figure out my overall owned percentage //----------------------------------------------------------------------------- void CBaseTechnology::RecalculateOverallLevel( void ) { if ( !GetResourceCost() ) { m_flOverallOwnedPercentage = 0; } else { m_flOverallOwnedPercentage = GetResourceLevel() / GetResourceCost(); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- float CBaseTechnology::GetOverallLevel( void ) { return m_flOverallOwnedPercentage; } //----------------------------------------------------------------------------- // Purpose: Force this technology to complete itself //----------------------------------------------------------------------------- void CBaseTechnology::ForceComplete( void ) { SetResourceLevel( GetResourceCost() ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CBaseTechnology::IsAGoalTechnology( void ) { return m_bGoalTechnology; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTechnology::SetGoalTechnology( bool bGoal ) { m_bGoalTechnology = bGoal; } //----------------------------------------------------------------------------- // Purpose: Returns the name of this technology // Output : const //----------------------------------------------------------------------------- const char *CBaseTechnology::GetName( void ) { return m_pszName; } //----------------------------------------------------------------------------- // Purpose: Returns printable name of this technology // Output : const //----------------------------------------------------------------------------- const char *CBaseTechnology::GetPrintName( void ) { return m_pszPrintName; } //----------------------------------------------------------------------------- // Purpose: // Output : const char //----------------------------------------------------------------------------- const char *CBaseTechnology::GetButtonName( void ) { return m_szButtonName; } //----------------------------------------------------------------------------- // Purpose: // Output : const char //----------------------------------------------------------------------------- const char *CBaseTechnology::GetTextureName(void ) { return m_szTextureName; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CBaseTechnology::GetTextureId( void ) { return m_nTextureID; } //----------------------------------------------------------------------------- // Purpose: Returns description for item // Output : const char //----------------------------------------------------------------------------- const char *CBaseTechnology::GetDescription( int iPlayerClass ) { // If we have a custom description for the local player's class, return that instead if ( AffectsClass( iPlayerClass ) ) { if ( m_ClassResults[iPlayerClass].pszDescription ) return m_ClassResults[iPlayerClass].pszDescription; } // Otherwise, return the general description return m_pszDescription; } //----------------------------------------------------------------------------- // Purpose: Returns sound filename to play for this technology //----------------------------------------------------------------------------- const char *CBaseTechnology::GetSoundFile( int iClass ) { // Class of 0 is the team sound if ( !iClass ) return m_pszTeamSoundFile; Assert(iClass > 0 && iClass < TFCLASS_CLASS_COUNT ); return m_ClassResults[iClass].pszSoundFile; } //----------------------------------------------------------------------------- // Purpose: Returns sound to play for this technology //----------------------------------------------------------------------------- int CBaseTechnology::GetSound( int iClass ) { // Class of 0 is the team sound if ( !iClass ) return m_iTeamSound; Assert(iClass > 0 && iClass < TFCLASS_CLASS_COUNT ); return m_ClassResults[iClass].iSound; } //----------------------------------------------------------------------------- // Purpose: // Input : iClass - // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBaseTechnology::GetAssociateWeaponsForClass( int iClass ) { if ( !iClass ) return false; Assert(iClass > 0 && iClass < TFCLASS_CLASS_COUNT ); return m_ClassResults[iClass].m_bAssociateWeaponsForClass; } //----------------------------------------------------------------------------- // Purpose: Returns whether the technology is available to the team // Input : state - //----------------------------------------------------------------------------- void CBaseTechnology::SetAvailable( bool state ) { if ( state != m_bAvailable ) { SetDirty( true ); } m_bAvailable = state; } //----------------------------------------------------------------------------- // Purpose: Determine whether team posses the technology // Output : Returns 1 if available, 0 otherwise //----------------------------------------------------------------------------- int CBaseTechnology::GetAvailable( void ) { return m_bAvailable; } //----------------------------------------------------------------------------- // Purpose: Zero out team preference counters //----------------------------------------------------------------------------- void CBaseTechnology::ZeroPreferences( void ) { if ( m_nPreferenceCount ) { SetDirty( true ); } m_nPreferenceCount = 0; } //----------------------------------------------------------------------------- // Purpose: Increment preference counter //----------------------------------------------------------------------------- void CBaseTechnology::IncrementPreferences( void ) { m_nPreferenceCount++; SetDirty( true ); } //----------------------------------------------------------------------------- // Purpose: Retrieve preference count //----------------------------------------------------------------------------- int CBaseTechnology::GetPreferenceCount( void ) { return m_nPreferenceCount; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- int CBaseTechnology::GetNumWeaponAssociations( void ) { return m_nNumWeaponAssociations; } //----------------------------------------------------------------------------- // Purpose: // Output : char const //----------------------------------------------------------------------------- const char *CBaseTechnology::GetAssociatedWeapon( int index ) { if ( index < 0 || index >= m_nNumWeaponAssociations ) { return ""; } return m_rgszWeaponAssociation[ index ]; } //----------------------------------------------------------------------------- // Purpose: // Input : *weaponname - //----------------------------------------------------------------------------- void CBaseTechnology::AddAssociatedWeapon( const char *weaponname ) { if ( m_nNumWeaponAssociations >= MAX_ASSOCIATED_WEAPONS ) { Assert( !"CBaseTechnology::AddAssociatedWeapon: m_nNumWeaponAssociations >= MAX_ASSOCIATED_WEAPONS" ); return; } Q_strncpy( m_rgszWeaponAssociation[ m_nNumWeaponAssociations++ ], weaponname, TECHNOLOGY_WEAPONNAME_LENGTH ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CBaseTechnology::GetNumberContainedTechs( void ) { return m_iContainedTechs; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *CBaseTechnology::GetContainedTechName( int iTech ) { Assert( iTech >= 0 && iTech < m_iContainedTechs ); return m_apszContainedTechs[ iTech ]; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTechnology::SetContainedTech( int iTech, CBaseTechnology *pTech ) { Assert( iTech >= 0 && iTech < m_iContainedTechs ); m_pContainedTechs[iTech] = pTech; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CBaseTechnology::GetNumberDependentTechs( void ) { return m_iDependentTechs; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char *CBaseTechnology::GetDependentTechName( int iTech ) { Assert( iTech >= 0 && iTech < m_iDependentTechs ); return m_apszDependentTechs[ iTech ]; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTechnology::SetDependentTech( int iTech, CBaseTechnology *pTech ) { Assert( iTech >= 0 && iTech < m_iDependentTechs ); Assert( pTech ); m_pDependentTechs[iTech] = pTech; } //----------------------------------------------------------------------------- // Purpose: Return true if this tech depends on the specified tech //----------------------------------------------------------------------------- bool CBaseTechnology::DependsOn( CBaseTechnology *pTech ) { for ( int i = 0; i < GetNumberDependentTechs(); i++ ) { if ( m_pDependentTechs[i] == pTech ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: Return true if this tech has a dependent tech that's not been completed yet //----------------------------------------------------------------------------- bool CBaseTechnology::HasInactiveDependencies( void ) { for ( int i = 0; i < GetNumberDependentTechs(); i++ ) { // This condition can occur if there's a bug in the .txt file // where a tech is told to depend on a non-existent tech if (!m_pDependentTechs[i]) continue; // Client uses m_bActive, Server uses m_bAvailable (?) if ( m_pDependentTechs[i]->GetAvailable() == false && m_pDependentTechs[i]->GetActive() == false ) return true; } return false; } //----------------------------------------------------------------------------- // Purpose: Dirty bit, used for fast knowledge of when to resend techs //----------------------------------------------------------------------------- bool CBaseTechnology::IsDirty( void ) { return m_bDirty; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTechnology::SetDirty( bool bDirty ) { m_bDirty = bDirty; } //----------------------------------------------------------------------------- // Purpose: Set availability state for item // Input : state - //----------------------------------------------------------------------------- void CBaseTechnology::SetActive( bool state ) { m_bActive = state; } //----------------------------------------------------------------------------- // Purpose: Retrieve availability state //----------------------------------------------------------------------------- bool CBaseTechnology::GetActive( void ) { return m_bActive; } //----------------------------------------------------------------------------- // Purpose: Set whether this is our local preferred item // Input : state - //----------------------------------------------------------------------------- void CBaseTechnology::SetPreferred( bool state ) { m_bPreferred = state; } //----------------------------------------------------------------------------- // Purpose: Retrieve local preferred state // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBaseTechnology::GetPreferred( void ) { return m_bPreferred; } //----------------------------------------------------------------------------- // Purpose: Set the number of players preferring this tech // Input : voters - //----------------------------------------------------------------------------- void CBaseTechnology::SetVoters( int voters ) { m_nVoters = voters; } //----------------------------------------------------------------------------- // Purpose: Get the number of players preferring this tech // Output : int //----------------------------------------------------------------------------- int CBaseTechnology::GetVoters( void ) { return m_nVoters; } //----------------------------------------------------------------------------- // Purpose: // Input : hide - //----------------------------------------------------------------------------- void CBaseTechnology::SetHidden( bool hide ) { m_bHidden = hide; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBaseTechnology::IsHidden( void ) { return m_bHidden; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTechnology::ResetHintsGiven( void ) { m_HintsGiven.RemoveAll(); } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CBaseTechnology::GetHintsGiven( int type ) { if ( m_HintsGiven.Find( type ) != m_HintsGiven.InvalidIndex() ) { return true; } return false; } //----------------------------------------------------------------------------- // Purpose: // Input : given - //----------------------------------------------------------------------------- void CBaseTechnology::SetHintsGiven( int type, bool given ) { if ( given ) { if ( m_HintsGiven.Find( type ) != m_HintsGiven.InvalidIndex() ) return; m_HintsGiven.AddToTail( type ); } else { int idx = m_HintsGiven.Find( type ); if ( idx == m_HintsGiven.InvalidIndex() ) return; m_HintsGiven.Remove( idx ); } } //==================================================================================================================== // EVIL GAME DLL ONLY CODE FOR TECHNOLOGIES //==================================================================================================================== #ifndef CLIENT_DLL //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTechnology::AddTechnologyToPlayer( CBaseTFPlayer *pPlayer ) { // Tell playerclasses listed to recalculate their technologies, only if they're listed in the class results if ( pPlayer->PlayerClass() ) { if ( m_ClassResults[ pPlayer->PlayerClass() ].bClassTouched ) { CPlayerClass *pPlayerClass = pPlayer->GetPlayerClass(); pPlayerClass->GainedNewTechnology( this ); } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTechnology::AddTechnologyToTeam( CTFTeam *pTeam ) { SetAvailable( true ); // Enable all the technologies this group contains if ( m_iContainedTechs ) { for (int i = 0; i < m_iContainedTechs; i++ ) { if ( m_pContainedTechs[i] ) { pTeam->EnableTechnology( m_pContainedTechs[i] ); } } } } //----------------------------------------------------------------------------- // Purpose: A technology watcher entity wants to register as a watcher for this technology //----------------------------------------------------------------------------- void CBaseTechnology::RegisterWatcher( CInfoCustomTechnology *pWatcher ) { m_aWatchers.AddToTail( pWatcher ); pWatcher->UpdateTechPercentage( 0 ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseTechnology::UpdateWatchers( void ) { // Tell all my watchers for (int i = 0; i < m_aWatchers.Size(); i++ ) { m_aWatchers[i]->UpdateTechPercentage( GetOverallLevel() ); } } #else //----------------------------------------------------------------------------- // Purpose: Client DLL UpdateWatchers does nothing //----------------------------------------------------------------------------- void CBaseTechnology::UpdateWatchers( void ) { } #endif //==================================================================================================================== // SHARED TECHNOLOGY TREE //==================================================================================================================== //----------------------------------------------------------------------------- // Purpose: Construct raw technology tree // Output : //----------------------------------------------------------------------------- CTechnologyTree::CTechnologyTree( IFileSystem* pFileSystem, int nTeamNumber ) { // Reset preference counter ClearPreferenceCount(); // Parse the list from the data file if ( ParseTechnologyFile( m_Technologies, pFileSystem, nTeamNumber, "scripts/technologytree.txt" ) == false ) { Assert(0); return; } LinkContainedTechnologies(); LinkDependentTechnologies(); } //----------------------------------------------------------------------------- // Purpose: Link all the contained technologies //----------------------------------------------------------------------------- void CTechnologyTree::LinkContainedTechnologies( void ) { for ( int i=0; i < m_Technologies.Size(); i++) { for ( int j = 0; j < m_Technologies[i]->GetNumberContainedTechs(); j++ ) { const char *pName = m_Technologies[i]->GetContainedTechName( j ); CBaseTechnology *pTech = GetTechnology( pName ); if ( pTech ) { m_Technologies[i]->SetContainedTech( j, pTech ); } } } } //----------------------------------------------------------------------------- // Purpose: Link all the dependent technologies //----------------------------------------------------------------------------- void CTechnologyTree::LinkDependentTechnologies( void ) { for ( int i=0; i < m_Technologies.Size(); i++) { for ( int j = 0; j < m_Technologies[i]->GetNumberDependentTechs(); j++ ) { const char *pName = m_Technologies[i]->GetDependentTechName( j ); CBaseTechnology *pTech = GetTechnology( pName ); if ( pTech ) { m_Technologies[i]->SetDependentTech( j, pTech ); } else { Warning("Unable to find dependent technology %s!\n", pName ); } } } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTechnologyTree::~CTechnologyTree( void ) { Shutdown(); } //----------------------------------------------------------------------------- // Purpose: Delete all items in the tree //----------------------------------------------------------------------------- void CTechnologyTree::Shutdown( void ) { // Loop through all used items int iSize = m_Technologies.Size(); for ( int i = iSize-1; i >= 0; i-- ) { CBaseTechnology *pItem = m_Technologies[ i ]; delete pItem; } m_Technologies.Purge(); } //----------------------------------------------------------------------------- // Purpose: Add a new technology to the tree //----------------------------------------------------------------------------- void CTechnologyTree::AddTechnologyFile( IFileSystem* pFileSystem, int nTeamNumber, char *sFileName ) { ParseTechnologyFile( m_Technologies, pFileSystem, nTeamNumber, sFileName ); } //----------------------------------------------------------------------------- // Purpose: Get the index of the specified item //----------------------------------------------------------------------------- int CTechnologyTree::GetIndex( CBaseTechnology *pItem ) { for ( int i=0; i < m_Technologies.Size(); i++) { if ( m_Technologies[i] == pItem ) return i; } return -1; } //----------------------------------------------------------------------------- // Purpose: Retrieve item by index //----------------------------------------------------------------------------- CBaseTechnology *CTechnologyTree::GetTechnology( int index ) { if ( index < 0 || index >= m_Technologies.Size() ) return NULL; return m_Technologies[ index ]; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CBaseTechnology* CTechnologyTree::GetTechnology( const char *pName ) { for ( int i=0; i < m_Technologies.Size(); i++) { if( stricmp( pName, m_Technologies[i]->GetName() ) == 0 ) return m_Technologies[i]; } return NULL; } //----------------------------------------------------------------------------- // Purpose: Return current number of objects // Output : int //----------------------------------------------------------------------------- int CTechnologyTree::GetNumberTechnologies( void ) { return m_Technologies.Size(); } //----------------------------------------------------------------------------- // Purpose: Set preferred item ( turns off all other preferences first ) //----------------------------------------------------------------------------- void CTechnologyTree::SetPreferredTechnology( CBaseTechnology *pItem ) { // Turn all of the others off for ( int i = 0; i < m_Technologies.Size(); i++ ) { CBaseTechnology *item = m_Technologies[ i ]; item->SetPreferred( false ); } // Turn this one on if ( pItem ) { pItem->SetPreferred( true ); } } //----------------------------------------------------------------------------- // Purpose: Get the technology preferred by this client //----------------------------------------------------------------------------- CBaseTechnology* CTechnologyTree::GetPreferredTechnology( void ) { // Turn all of the others off for ( int i = 0; i < m_Technologies.Size(); i++ ) { CBaseTechnology *item = m_Technologies[ i ]; if ( item->GetPreferred() ) return item; } return NULL; } //----------------------------------------------------------------------------- // Purpose: Get the number of players who've voted on techs //----------------------------------------------------------------------------- int CTechnologyTree::GetPreferenceCount( void ) { return m_nPreferenceCount; } //----------------------------------------------------------------------------- // Purpose: Zero global preference counters //----------------------------------------------------------------------------- void CTechnologyTree::ClearPreferenceCount( void ) { m_nPreferenceCount = 0; } //----------------------------------------------------------------------------- // Purpose: Increment preference counter //----------------------------------------------------------------------------- void CTechnologyTree::IncrementPreferences( void ) { m_nPreferenceCount++; } //----------------------------------------------------------------------------- // Purpose: Return the most voted-for technologies // Input : iDesireLevel: 1 = Most voted for, 2 = 2nd most voted for, etc //----------------------------------------------------------------------------- CBaseTechnology *CTechnologyTree::GetDesiredTechnology( int iDesireLevel ) { Assert( iDesireLevel > 0 && iDesireLevel < m_Technologies.Size() ); // Dump the techs into a temporary array CBaseTechnology *pSortedTechs[ MAX_TECHNOLOGIES ]; int iMaxTech = 0; for ( int i = 0; i < m_Technologies.Size(); i++ ) { // Skip Techs that are already available CBaseTechnology *technology = m_Technologies[i]; if(!technology) continue; if ( technology->GetAvailable() == false ) { pSortedTechs[iMaxTech] = m_Technologies[i]; iMaxTech++; } } // Not enough unresearched techs? if ( iMaxTech < iDesireLevel ) return NULL; // Bubble sort the tech array into order of desire int swapped = 1; while ( swapped ) { swapped = 0; for ( int i = 1; i < iMaxTech; i++ ) { if ( pSortedTechs[i]->GetPreferenceCount() > pSortedTechs[i-1]->GetPreferenceCount() ) { CBaseTechnology *pTemp = pSortedTechs[i]; pSortedTechs[i] = pSortedTechs[i-1]; pSortedTechs[i-1] = pTemp; swapped = 1; } } } return pSortedTechs[ iDesireLevel - 1 ]; } //----------------------------------------------------------------------------- // Purpose: Find out what percentage of techs in a given level this team owns //----------------------------------------------------------------------------- float CTechnologyTree::GetPercentageOfTechLevelOwned( int iTechLevel ) { float fTotalTechs = 0; float fTechsOwned = 0; for ( int i = 0; i < m_Technologies.Size(); i++ ) { CBaseTechnology *technology = m_Technologies[i]; if ( !technology ) continue; if ( technology->GetLevel() != iTechLevel ) continue; fTotalTechs++; // Do we have it? if ( technology->GetAvailable() ) { fTechsOwned++; } } if ( !fTotalTechs ) return 0.0; return ( fTechsOwned / fTotalTechs ); }