⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tf_playerclass.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/***
*
*	Copyright (c) 1999, Valve LLC. All rights reserved.
*	
*	This product contains software technology licensed from Id 
*	Software, Inc. ("Id Technology").  Id Technology (c) 1996 Id Software, Inc. 
*	All Rights Reserved.
*
*   Use, distribution, and modification of this source code and/or resulting
*   object code is restricted to non-commercial enhancements to products from
*   Valve LLC.  All other use, distribution, or modification is prohibited
*   without written permission from Valve LLC.
*
****/
/*

===== tf_playerclass.cpp ========================================================

  functions dealing with the TF playerclasses

*/
#include "cbase.h"
#include "player.h"
#include "basecombatweapon.h"
#include "tf_player.h"
#include "tf_obj.h"
#include "weapon_builder.h"
#include "tf_team.h"
#include "tf_func_resource.h"
#include "orders.h"
#include "order_repair.h"
#include "engine/IEngineSound.h"
#include "vstdlib/strtools.h"
#include "textstatsmgr.h"
#include "ammodef.h"
#include "weapon_objectselection.h"
#include "vcollide_parse.h"
#include "weapon_combatshield.h"
#include "tf_vehicle_tank.h"
#include "tf_obj_manned_plasmagun.h"
#include "tf_obj_manned_missilelauncher.h"

extern char *g_pszEMPPulseStart;
extern ConVar tf_fastbuild;


// Stat groupings
enum
{
	STATS_TANK = TFCLASS_CLASS_COUNT,
	STATS_MANNEDGUN_PLASMA,
	STATS_MANNEDGUN_ROCKET,

	STATS_NUM_GROUPS,
};

char *sNonClassStatNames[] =
{
	"Tanks",
	"Manned Plasmaguns",
	"Manned Rocket launchers",
};

// Stats between player classes (like how many snipers killed recons).
class CInterClassStats
{
public:
	
			CInterClassStats()
			{
				m_flTotalDamageInflicted = 0;
				m_nKills = 0;

				m_flTotalEngagementDist = 0;
				m_nEngagements = 0;

				m_flTotalNormalizedEngagementDist = 0;
				m_nNormalizedEngagements = 0;
			}

public:
	//
	// Note: "containing class" refers to the class in the CPlayerClassStats that owns this CInterClassStats.
	// So if there's a CPlayerClassStats for a recon, and it has a CInterClassStats for a sniper,
	// then "containing class" refers to the recon. In this example, m_flTotalDamageInflicted representss
	// how much damage the recon players inflicted on the snipers.
	//
	double	m_flTotalDamageInflicted;	// Total damage inflicted on this class by the containing class.
	double	m_flTotalEngagementDist;	// Used to get the average engagement distance.
	int		m_nEngagements;

	double m_flTotalNormalizedEngagementDist;
	int m_nNormalizedEngagements;

	int		m_nKills;					// Now many times the containing class killed this one.
};

class CPlayerClassStats
{
public:
	CPlayerClassStats()
	{
		m_flPlayerTime = 0;
	}

public:
			
	CInterClassStats	m_InterClassStats[STATS_NUM_GROUPS];
	double				m_flPlayerTime;	// How much player time was spent in this class.
};

		
ConVar	tf2_object_hard_limits( "tf2_object_hard_limits","0", FCVAR_NONE, "If true, use hard object limits instead of resource costs" ); 

CPlayerClassStats g_PlayerClassStats[STATS_NUM_GROUPS];

void AddPlayerClassTime( int classnum, float seconds )
{
	g_PlayerClassStats[ classnum ].m_flPlayerTime += seconds;
}

int GetStatGroupFor( CBaseTFPlayer *pPlayer )
{
	// In a vehicle?
	if ( pPlayer->IsInAVehicle() )
	{
		if ( dynamic_cast<CVehicleTank*>( pPlayer->GetVehicle() ) )
			return STATS_TANK;
		if ( dynamic_cast<CObjectMannedMissileLauncher*>( pPlayer->GetVehicle() ) )
			return STATS_MANNEDGUN_ROCKET;
		if ( dynamic_cast<CObjectMannedPlasmagun*>( pPlayer->GetVehicle() ) )
			return STATS_MANNEDGUN_PLASMA;
	}

	// Otherwise, use the playerclass
	return pPlayer->GetPlayerClass()->GetTFClass();
}

const char* GetGroupNameFor( int iStatGroup )
{
	Assert( iStatGroup > TFCLASS_UNDECIDED && iStatGroup < STATS_NUM_GROUPS );
	if ( iStatGroup < TFCLASS_CLASS_COUNT )
		return GetTFClassInfo( iStatGroup )->m_pClassName;
	else
		return sNonClassStatNames[ iStatGroup - TFCLASS_CLASS_COUNT ];
}


void PrintPlayerClassStats()
{
	IFileSystem *pFileSys = filesystem;

	FileHandle_t hFile = pFileSys->Open( "class_stats.txt", "wt", "LOGDIR" );
	if ( hFile == FILESYSTEM_INVALID_HANDLE )
		return;


	pFileSys->FPrintf( hFile, "Class\tPlayer Time (minutes)\tAvg Engagement Dist\t(OLD) Engagement Dist\n" );
	for ( int i=TFCLASS_UNDECIDED+1; i < STATS_NUM_GROUPS; i++ )
	{
		CPlayerClassStats *pStats = &g_PlayerClassStats[i];


		// Figure out the average engagement distance across all classes.
		int j;
		double flAvgEngagementDist = 0;
		int nTotalEngagements = 0;
		double flTotalEngagementDist = 0;

		double flTotalNormalizedEngagementDist = 0;
		int nTotalNormalizedEngagements = 0;

		for ( j=TFCLASS_UNDECIDED+1; j < STATS_NUM_GROUPS; j++ )
		{
			CInterClassStats *pInter = &g_PlayerClassStats[i].m_InterClassStats[j];
			
			nTotalEngagements += pInter->m_nEngagements;
			flTotalEngagementDist += pInter->m_flTotalEngagementDist;

			nTotalNormalizedEngagements += pInter->m_nNormalizedEngagements;
			flTotalNormalizedEngagementDist += pInter->m_flTotalNormalizedEngagementDist;
		}
		flAvgEngagementDist = nTotalEngagements ? ( flTotalEngagementDist / nTotalEngagements ) : 0;
		double flAvgNormalizedEngagementDist = nTotalNormalizedEngagements ? (flTotalNormalizedEngagementDist / nTotalNormalizedEngagements) : 0;
		
		
		pFileSys->FPrintf( hFile, "%s",		GetGroupNameFor( i ) );
		pFileSys->FPrintf( hFile, "\t%.1f", (pStats->m_flPlayerTime / 60.0f) );
		pFileSys->FPrintf( hFile, "\t%d",	(int)flAvgNormalizedEngagementDist );
		pFileSys->FPrintf( hFile, "\t%d",	(int)flAvgEngagementDist );
		pFileSys->FPrintf( hFile, "\n" );
	}

	pFileSys->FPrintf( hFile, "\n" );
	pFileSys->FPrintf( hFile, "\n" );


	pFileSys->FPrintf( hFile, "Class\tTarget Class\tTotal Damage\tKills\tAvg Engagement Dist\t(OLD) Engagement Dist\n" );
	
	for ( i=TFCLASS_UNDECIDED+1; i < STATS_NUM_GROUPS; i++ )
	{
		CPlayerClassStats *pStats = &g_PlayerClassStats[i];

		// Print the inter-class stats.
		for ( int j=TFCLASS_UNDECIDED+1; j < STATS_NUM_GROUPS; j++ )
		{
			CInterClassStats *pInter = &pStats->m_InterClassStats[j];

			pFileSys->FPrintf( hFile, "%s", GetGroupNameFor( i ) );
			pFileSys->FPrintf( hFile, "\t%s", GetGroupNameFor( j ) );
			pFileSys->FPrintf( hFile, "\t%d", (int)pInter->m_flTotalDamageInflicted );
			pFileSys->FPrintf( hFile, "\t%d", pInter->m_nKills );
			pFileSys->FPrintf( hFile, "\t%d", (int)(pInter->m_nNormalizedEngagements ? (pInter->m_flTotalNormalizedEngagementDist / pInter->m_nNormalizedEngagements) : 0) );
			pFileSys->FPrintf( hFile, "\t%d", (int)(pInter->m_nEngagements ? (pInter->m_flTotalEngagementDist / pInter->m_nEngagements) : 0) );
			pFileSys->FPrintf( hFile, "\n" );
		}
	}

	pFileSys->Close( hFile );
}

CTextStatFile g_PlayerClassStatsOutput( PrintPlayerClassStats );


// ---------------------------------------------------------------------------------------------------------------- //
// Detailed stats output.
// ---------------------------------------------------------------------------------------------------------------- //

ConVar tf_DetailedStats( "tf_DetailedStats", "1", 0, "Prints extensive detailed gameplay stats into detailed_stats.txt" );

class CShotInfo
{
public:
	float m_flDistance;
	int m_nDamage;
};

CUtlLinkedList<CShotInfo,int> g_ClassShotInfos[STATS_NUM_GROUPS];

void PrintDetailedPlayerClassStats()
{
	if ( !tf_DetailedStats.GetInt() )
		return;

	IFileSystem *pFileSys = filesystem;

	FileHandle_t hFile = pFileSys->Open( "class_stats_detailed.txt", "wt", "LOGDIR" );
	if ( hFile != FILESYSTEM_INVALID_HANDLE )
	{
		// Print the header.
		for ( int i=TFCLASS_UNDECIDED+1; i < STATS_NUM_GROUPS; i++ )
		{
			pFileSys->FPrintf( hFile, "%s dist\t%s dmg\t", GetGroupNameFor( i ), GetGroupNameFor( i ) );
		}
		pFileSys->FPrintf( hFile, "\n" );

		// Write out each column.
		int iterators[STATS_NUM_GROUPS];
		for ( i=TFCLASS_UNDECIDED+1; i < STATS_NUM_GROUPS; i++ )
			iterators[i] = g_ClassShotInfos[i].Head();

		bool bWroteAnything;
		do
		{
			bWroteAnything = false;
			for ( int i=TFCLASS_UNDECIDED+1; i < STATS_NUM_GROUPS; i++ )
			{
				if ( iterators[i] == g_ClassShotInfos[i].InvalidIndex() )
				{
					pFileSys->FPrintf( hFile, "\t\t" );
				}
				else
				{
					CShotInfo *pInfo = &g_ClassShotInfos[i][iterators[i]];
					iterators[i] = g_ClassShotInfos[i].Next( iterators[i] );

					pFileSys->FPrintf( hFile, "%.2f\t%d\t", pInfo->m_flDistance, pInfo->m_nDamage );
					bWroteAnything = true;
				}
			}
			pFileSys->FPrintf( hFile, "\n" );

		} while ( bWroteAnything );


		pFileSys->Close( hFile );
	}
}

CTextStatFile g_PlayerClassStatsDetailedOutput( PrintDetailedPlayerClassStats );



//=====================================================================
// PLAYER CLASS HANDLING
//=====================================================================
// Base PlayerClass
CPlayerClass::CPlayerClass( CBaseTFPlayer *pPlayer, TFClass iClass )
: m_TFClass( iClass )
{
	m_pPlayer = pPlayer;
	
	for (int i = 0; i <= MAX_TF_TEAMS; ++i)
	{
		m_sClassModel[i] = NULL_STRING;
	}
	m_iNumWeaponTechAssociations = 0;

	m_bTechAssociationsSet = false;

	m_flNormalizedEngagementNextTime = -1;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CPlayerClass::~CPlayerClass()
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CPlayerClass::ClassActivate( void )
{
	// Setup the default player movement variables.
	SetupMoveData();

	AddWeaponTechAssociations();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CPlayerClass::ClassDeactivate( void )
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CPlayerClass::AddWeaponTechAssociations( void )
{
	ClearAllWeaponTechAssoc();

	// Iterate tech tree for this class and find
	Assert( m_pPlayer );
	CTechnologyTree *tree = m_pPlayer->GetTechTree();
	Assert( tree );

	// Loop through all of the techs to see if any of them say yes to being applicable to 
	//  this class specifically
	for ( int i = 0 ; i < tree->GetNumberTechnologies(); i++ )
	{
		CBaseTechnology *tech = tree->GetTechnology( i );
		if ( !tech )
			continue;

		if ( !tech->GetAssociateWeaponsForClass( GetTFClass() ) )
			continue;

		// Associate weapon tech name with class
		AddWeaponTechAssoc( (char *)tech->GetName() );
	}
}


void CPlayerClass::NetworkStateChanged()
{
	if ( m_pPlayer )
		m_pPlayer->NetworkStateChanged();
}


//-----------------------------------------------------------------------------
// Purpose: Setup the default movement parameters, quite a few of these will be
//          overridden with class specific values.
//-----------------------------------------------------------------------------
void CPlayerClass::SetupMoveData( void )
{
	// Set the default walking and sprinting speeds.
	m_flMaxWalkingSpeed = 120;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CPlayerClass::SetupSizeData( void )
{
	// Initially set the player to the base player class standing hull size.
	m_pPlayer->SetCollisionBounds( PLAYERCLASS_HULL_STAND_MIN, PLAYERCLASS_HULL_STAND_MAX );
	m_pPlayer->SetViewOffset( PLAYERCLASS_VIEWOFFSET_STAND );
	m_pPlayer->m_Local.m_flStepSize = PLAYERCLASS_STEPSIZE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -