summaryrefslogtreecommitdiff
path: root/utils/tf_monoculus_stats
diff options
context:
space:
mode:
Diffstat (limited to 'utils/tf_monoculus_stats')
-rw-r--r--utils/tf_monoculus_stats/tf_monoculus_stats.cpp723
-rw-r--r--utils/tf_monoculus_stats/tf_monoculus_stats.vcproj179
2 files changed, 902 insertions, 0 deletions
diff --git a/utils/tf_monoculus_stats/tf_monoculus_stats.cpp b/utils/tf_monoculus_stats/tf_monoculus_stats.cpp
new file mode 100644
index 0000000..be093b8
--- /dev/null
+++ b/utils/tf_monoculus_stats/tf_monoculus_stats.cpp
@@ -0,0 +1,723 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// Parse Halloween 2011 server logs and mine Eyeball Boss (Monoculus) data
+
+#define _CRT_SECURE_NO_WARNINGS // STFU
+
+#include <tchar.h>
+
+#include "stdio.h"
+#include <math.h>
+#include <vector>
+
+#define MAX_BUFFER_SIZE 256
+#define MAX_NAME_SIZE 64
+
+enum EventType
+{
+ EYEBALL_SPAWN, // eyeball_spawn (max_health 11200) (player_count 18)
+ EYEBALL_ESCAPE, // eyeball_escaped (max_dps 220.00) (health 3071)
+ EYEBALL_DEATH, // eyeball_death (max_dps 467.63) (max_health 12000) (player_count 23)
+ EYEBALL_STUN, // "Aque0us<174><STEAM_0:0:212532><Red>" eyeball_stunned with "NoWeapon" (attacker_position "-1033 872 143")
+ PURGATORY_ENTER, // "I_DONT_KNOW<181><STEAM_0:1:34210475><Red>" purgatory_teleport "spawn_purgatory"
+ PURGATORY_ESCAPE, // "I_DONT_KNOW<181><STEAM_0:1:34210475><Red>" purgatory_escaped
+ LOOT_ISLAND_ENTER, // "I_DONT_KNOW<181><STEAM_0:1:34210475><Red>" purgatory_teleport "spawn_loot"
+ EYEBALL_KILLER, // "Spaghetti Western<192><STEAM_0:1:41812531><Red>" eyeball_killer with "liberty_launcher" (attacker_position "-1629 -293 213")
+
+ EVENT_COUNT
+};
+
+#define TEAM_NONE 0
+#define TEAM_RED 1
+#define TEAM_BLUE 2
+
+struct EventInfo
+{
+ EventType m_type;
+ char m_date[ MAX_NAME_SIZE ];
+ int m_timestamp; // seconds since log start
+ int m_health;
+ int m_maxHealth;
+ int m_playerCount;
+ int m_maxDPS;
+ int m_attackerPosX;
+ int m_attackerPosY;
+ int m_attackerPosZ;
+ char m_weaponName[ MAX_NAME_SIZE ];
+ char m_playerName[ MAX_NAME_SIZE ];
+ int m_playerID;
+ int m_team;
+};
+
+std::vector< EventInfo > TheData;
+
+
+//----------------------------------------------------------------------------------
+bool ParseEvent( FILE *fp, EventInfo *event )
+{
+ return false;
+}
+
+
+//----------------------------------------------------------------------------------
+char *ParsePlayer( EventInfo *event, char *data )
+{
+ // "TheSauce<17><STEAM_0:1:19333174><Red>"
+ // ARGH! Player names can contain '<' and '>'
+
+ // skip the "
+ ++data;
+
+ char *restOfData = NULL;
+
+ char *c = &data[ strlen(data)-1 ];
+
+ // backup until we find '>'
+ while( c != data )
+ {
+ --c;
+ if ( *c == '>' )
+ {
+ restOfData = c+2;
+
+ // terminate the team name
+ *c = '\000';
+ break;
+ }
+ }
+
+ // backup until we find '<'
+ char *teamName = NULL;
+
+ while( c != data )
+ {
+ --c;
+ if ( *c == '<' )
+ {
+ teamName = c+1;
+
+ // back up and terminate the Steam ID
+ --c;
+ *c = '\000';
+ break;
+ }
+ }
+
+ if ( !teamName )
+ {
+ return NULL;
+ }
+
+ if ( !strcmp( "Red", teamName ) )
+ {
+ event->m_team = TEAM_RED;
+ }
+ else if ( !strcmp( "Blue", teamName ) )
+ {
+ event->m_team = TEAM_BLUE;
+ }
+ else
+ {
+ return NULL;
+ }
+
+ // "TheSauce<17><STEAM_0:1:19333174><Red>"
+
+ // backup until we find '<'
+ char *steamID = NULL;
+
+ while( c != data )
+ {
+ --c;
+ if ( *c == '<' )
+ {
+ steamID = c+1;
+
+ // back up and terminate the player ID
+ --c;
+ *c = '\000';
+ break;
+ }
+ }
+
+ if ( !steamID )
+ {
+ return NULL;
+ }
+
+ // backup until we find '<'
+ char *playerID = NULL;
+
+ while( c != data )
+ {
+ --c;
+ if ( *c == '<' )
+ {
+ playerID = c+1;
+
+ // terminate the player name
+ *c = '\000';
+ break;
+ }
+ }
+
+ if ( !playerID )
+ {
+ return NULL;
+ }
+
+ event->m_playerID = atoi( playerID );
+
+ strcpy( event->m_playerName, data );
+
+ return restOfData;
+
+#ifdef OLDWAY
+ // skip the "
+ ++data;
+
+ char *token = strtok( data, "<" );
+ if ( !token )
+ return NULL;
+
+ strcpy( event->m_playerName, token );
+
+ token = strtok( NULL, ">" );
+ if ( !token )
+ return NULL;
+
+ event->m_playerID = atoi( token );
+
+ // steam ID
+ token = strtok( NULL, "<>" );
+ if ( !token )
+ return NULL;
+
+ // team
+ token = strtok( NULL, "<>" );
+ if ( !token )
+ return NULL;
+
+ if ( !strcmp( "Red", token ) )
+ {
+ event->m_team = TEAM_RED;
+ }
+ else if ( !strcmp( "Blue", token ) )
+ {
+ event->m_team = TEAM_BLUE;
+ }
+
+ // get rest of line after closing quote
+ token = strtok( NULL, "" );
+ token += 2;
+
+ return token;
+#endif
+}
+
+
+//----------------------------------------------------------------------------------
+// Parse and return int value from "(name value)"
+bool parse_strtok_int( const char *name, int *value )
+{
+ char *token = strtok( NULL, "( " );
+ if ( !token )
+ return false;
+
+ if ( _stricmp( name, token ) )
+ return false;
+
+ // get value
+ token = strtok( NULL, ") " );
+ if ( !token )
+ return false;
+
+ *value = atoi( token );
+ return true;
+}
+
+
+//----------------------------------------------------------------------------------
+bool ProcessData( const char *filename )
+{
+ FILE *fp = fopen( filename, "r" );
+ if ( !fp )
+ {
+ printf( "ERROR: Cannot access file '%s'\n", filename );
+ return false;
+ }
+
+ FILE *errorFP = fopen( "cooked_stats_error.txt", "w" );
+ if ( !errorFP )
+ {
+ printf( "ERROR: Can't open output file\n" );
+ return false;
+ }
+
+ char buffer[ MAX_BUFFER_SIZE ];
+
+ bool isFirstLine = true;
+ int initialTimestamp = 0;
+
+ int line = 0;
+
+ EventInfo info;
+
+ while( true )
+ {
+ memset( &info, 0, sizeof( EventInfo ) );
+
+ fgets( buffer, MAX_BUFFER_SIZE, fp );
+ ++line;
+
+ // eat filename
+ char *token = buffer;
+ while( *token != 'L' )
+ {
+ ++token;
+ }
+
+ if ( !token )
+ break;
+
+ // read date
+ token = strtok( token, "L " );
+ if ( !token )
+ break;
+
+ strcpy( info.m_date, token );
+
+ // read time
+ token = strtok( NULL, "- " );
+ if ( !token )
+ break;
+
+ token[2] = '\000';
+ int hour = atoi( token );
+
+ token[5] = '\000';
+ int minute = atoi( &token[3] );
+
+ token[8] = '\000';
+ int second = atoi( &token[6] );
+
+ int timestamp = hour * 3600 + minute * 60 + second;
+
+ if ( isFirstLine )
+ {
+ isFirstLine = false;
+ initialTimestamp = timestamp;
+ }
+
+ info.m_timestamp = timestamp - initialTimestamp;
+
+ int fullDay = 24 * 3600;
+ if ( info.m_timestamp > fullDay )
+ {
+ // wrapped past midnight
+ info.m_timestamp -= fullDay;
+ }
+
+ // eat "HALLOWEEN"
+ token = strtok( NULL, ": " );
+ if ( !token )
+ break;
+
+ // get the rest of the line
+ token = strtok( NULL, "" );
+ if ( !token )
+ break;
+
+ // skip trailing space
+ ++token;
+
+ if ( !strncmp( "eyeball_spawn", token, 13 ) )
+ {
+ // eyeball_spawn (max_health 8000) (player_count 10)
+ info.m_type = EYEBALL_SPAWN;
+
+ // eat 'eyeball_spawn'
+ token = strtok( token, " " );
+ if ( !token )
+ break;
+
+ if ( !parse_strtok_int( "max_health", &info.m_maxHealth ) )
+ break;
+
+ if ( !parse_strtok_int( "player_count", &info.m_playerCount ) )
+ break;
+ }
+ else if ( !strncmp( "eyeball_escaped", token, 15 ) )
+ {
+ // eyeball_escaped (max_dps 143.64) (health 1525)
+ info.m_type = EYEBALL_ESCAPE;
+
+ // eat 'eyeball_escape'
+ token = strtok( token, " " );
+ if ( !token )
+ break;
+
+ if ( !parse_strtok_int( "max_dps", &info.m_maxDPS ) )
+ break;
+
+ if ( !parse_strtok_int( "health", &info.m_health ) )
+ break;
+ }
+ else if ( !strncmp( "eyeball_death", token, 13 ) )
+ {
+ // eyeball_death (max_dps 285.54) (max_health 13200) (player_count 24)
+ info.m_type = EYEBALL_DEATH;
+
+ // eat 'eyeball_death'
+ token = strtok( token, " " );
+ if ( !token )
+ break;
+
+ if ( !parse_strtok_int( "max_dps", &info.m_maxDPS ) )
+ break;
+
+ if ( !parse_strtok_int( "max_health", &info.m_maxHealth ) )
+ break;
+
+ if ( !parse_strtok_int( "player_count", &info.m_playerCount ) )
+ break;
+ }
+ else if ( token[0] == '"' )
+ {
+ char *data = ParsePlayer( &info, token );
+
+ if ( data )
+ {
+ token = strtok( data, " " );
+ if ( !token )
+ continue;
+
+ if ( !strncmp( "purgatory_escaped", token, 17 ) )
+ {
+ info.m_type = PURGATORY_ESCAPE;
+ }
+ else if ( !strcmp( "purgatory_teleport", token ) )
+ {
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ if ( !strcmp( "spawn_purgatory", token ) )
+ {
+ info.m_type = PURGATORY_ENTER;
+ }
+ else if ( !strcmp( "spawn_loot", token ) )
+ {
+ info.m_type = LOOT_ISLAND_ENTER;
+ }
+ else
+ {
+ fprintf( errorFP, "ERROR @ Line %d: Unknown purgatory teleport '%s'\n", line, token );
+ continue;
+ }
+ }
+ else if ( !strcmp( "eyeball_stunned", token ) )
+ {
+ // eyeball_stunned with "short_stop" (attacker_position "-1951 -166 256")
+ info.m_type = EYEBALL_STUN;
+
+ // eat 'with'
+ token = strtok( NULL, " " );
+
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ strcpy( info.m_weaponName, token );
+
+ // eat (attacker_position
+ token = strtok( NULL, " " );
+
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ info.m_attackerPosX = atoi( token );
+
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ info.m_attackerPosY = atoi( token );
+
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ info.m_attackerPosZ = atoi( token );
+ }
+ else if ( !strcmp( "eyeball_killer", token ) )
+ {
+ // eyeball_killer with "short_stop" (attacker_position "-1213 271 236")
+ info.m_type = EYEBALL_KILLER;
+
+ // eat 'with'
+ token = strtok( NULL, " " );
+
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ strcpy( info.m_weaponName, token );
+
+ // eat (attacker_position
+ token = strtok( NULL, " " );
+
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ info.m_attackerPosX = atoi( token );
+
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ info.m_attackerPosY = atoi( token );
+
+ token = strtok( NULL, "\" " );
+ if ( !token )
+ continue;
+
+ info.m_attackerPosZ = atoi( token );
+ }
+ else
+ {
+ fprintf( errorFP, "ERROR at Line %d: Unknown player event '%s'\n", line, token );
+ }
+ }
+ }
+ else
+ {
+ fprintf( errorFP, "ERROR at Line %d: Unknown data '%s'\n", line, token );
+ continue;
+ }
+
+ TheData.push_back( info );
+ }
+
+ fclose( fp );
+
+
+ //----------------------------------------
+ unsigned int bossSpawnCount = 0;
+ unsigned int bossEscapedCount = 0;
+ unsigned int bossDeathCount = 0;
+ unsigned int bossSpawnTimestamp = 0;
+ unsigned int bossDroppedCount = 0;
+
+ std::vector< int > bossLifetime;
+ std::vector< int > bossEscapeLifetime;
+ std::vector< int > bossDeathLifetime;
+ std::vector< int > bossStunCount;
+
+ bool isBossAlive = false;
+
+ for( unsigned int i=0; i<TheData.size(); ++i )
+ {
+ switch( TheData[i].m_type )
+ {
+ case EYEBALL_SPAWN:
+ if ( isBossAlive )
+ {
+ // we didn't get an ESCAPE or DEATH - map change?
+ // timestamp can go backwards on map change, so just don't count these lifetimes
+ bossLifetime.pop_back();
+ bossEscapeLifetime.pop_back();
+ bossDeathLifetime.pop_back();
+ bossStunCount.pop_back();
+ --bossSpawnCount;
+ ++bossDroppedCount;
+ }
+
+ isBossAlive = true;
+ bossSpawnTimestamp = TheData[i].m_timestamp;
+ ++bossSpawnCount;
+
+ bossLifetime.push_back(0);
+ bossEscapeLifetime.push_back(0);
+ bossDeathLifetime.push_back(0);
+ bossStunCount.push_back(0);
+
+ break;
+
+ case EYEBALL_ESCAPE:
+ if ( !isBossAlive )
+ {
+ fprintf( errorFP, "%d: Got ESCAPE when not spawned\n", i );
+ }
+ else
+ {
+ isBossAlive = false;
+ bossLifetime[ bossSpawnCount-1 ] = TheData[i].m_timestamp - bossSpawnTimestamp;
+ bossEscapeLifetime[ bossSpawnCount-1 ] = TheData[i].m_timestamp - bossSpawnTimestamp;
+ ++bossEscapedCount;
+ }
+ break;
+
+ case EYEBALL_DEATH:
+ if ( !isBossAlive )
+ {
+ int lifetime = TheData[i].m_timestamp - bossSpawnTimestamp;
+
+ // using large time delta to account for stuns while escaping followed by a death
+ if ( lifetime - bossEscapeLifetime[ bossSpawnCount-1 ] < 60.0f )
+ {
+ // killed while escaping - he didn't actually escape!
+ bossEscapeLifetime[ bossSpawnCount-1 ] = 0;
+ --bossEscapedCount;
+ }
+ else
+ {
+ fprintf( errorFP, "%d: Got DEATH when not spawned\n", i );
+ }
+ }
+ else
+ {
+ isBossAlive = false;
+ bossLifetime[ bossSpawnCount-1 ] = TheData[i].m_timestamp - bossSpawnTimestamp;
+ bossDeathLifetime[ bossSpawnCount-1 ] = TheData[i].m_timestamp - bossSpawnTimestamp;
+ ++bossDeathCount;
+ }
+
+ break;
+
+ case EYEBALL_STUN:
+ // skip alive check to collect stuns that happen just after escape starts
+ bossStunCount[ bossSpawnCount-1 ] = bossStunCount[ bossSpawnCount-1 ] + 1;
+
+ break;
+
+ case PURGATORY_ENTER:
+ break;
+ case PURGATORY_ESCAPE:
+ break;
+ case LOOT_ISLAND_ENTER:
+ break;
+ case EYEBALL_KILLER:
+ break;
+ }
+ }
+
+ fclose( errorFP );
+
+
+ //----------------------------------------
+ sprintf( buffer, "%s_cooked.txt", filename );
+
+ fp = fopen( buffer, "w" );
+ if ( !fp )
+ {
+ printf( "ERROR: Can't open output file '%s'\n", buffer );
+ return false;
+ }
+
+ if ( bossSpawnCount )
+ {
+ int minTime = 99999, maxTime = 0, avgTime = 0;
+
+#define USE_COLUMNS
+#ifdef USE_COLUMNS
+ fprintf( fp, "Lifetime, EscapeLifetime, DeathLifetime, StunCount\n" );
+
+ for( unsigned int i=0; i<bossSpawnCount; ++i )
+ {
+ fprintf( fp, "%d, %d, %d, %d\n", bossLifetime[i], bossEscapeLifetime[i], bossDeathLifetime[i], bossStunCount[i] );
+
+ if ( bossLifetime[i] < minTime )
+ {
+ minTime = bossLifetime[i];
+ }
+
+ if ( bossLifetime[i] > maxTime )
+ {
+ maxTime = bossLifetime[i];
+ }
+
+ avgTime += bossLifetime[i];
+ }
+ fprintf( fp, "\n" );
+#else
+ fprintf( fp, "Lifetime, " );
+ for( unsigned int i=0; i<bossSpawnCount; ++i )
+ {
+ fprintf( fp, "%d, ", bossLifetime[i] );
+
+ if ( bossLifetime[i] < minTime )
+ {
+ minTime = bossLifetime[i];
+ }
+
+ if ( bossLifetime[i] > maxTime )
+ {
+ maxTime = bossLifetime[i];
+ }
+
+ avgTime += bossLifetime[i];
+ }
+ fprintf( fp, "\n" );
+
+ fprintf( fp, "EscapeLifetime, " );
+ for( unsigned int i=0; i<bossSpawnCount; ++i )
+ {
+ if ( bossEscapeLifetime[i] > 0 )
+ fprintf( fp, "%d, ", bossEscapeLifetime[i] );
+ }
+ fprintf( fp, "\n" );
+
+ fprintf( fp, "DeathLifetime, " );
+ for( unsigned int i=0; i<bossSpawnCount; ++i )
+ {
+ if ( bossDeathLifetime[i] > 0 )
+ fprintf( fp, "%d, ", bossDeathLifetime[i] );
+ }
+ fprintf( fp, "\n" );
+
+ fprintf( fp, "StunCount, " );
+ for( unsigned int i=0; i<bossSpawnCount; ++i )
+ {
+ fprintf( fp, "%d, ", bossStunCount[i] );
+ }
+ fprintf( fp, "\n\n" );
+#endif
+
+ fprintf( fp, "Boss spawn count = %d\n", bossSpawnCount );
+ fprintf( fp, "Boss escape count = %d\n", bossEscapedCount );
+ fprintf( fp, "Boss escape ratio = %d%%\n", 100 * bossEscapedCount / bossSpawnCount );
+ fprintf( fp, "Boss killed count = %d\n", bossDeathCount );
+ fprintf( fp, "Boss killed ratio = %d%%\n", 100 * bossDeathCount / bossSpawnCount );
+ fprintf( fp, "Boss dropped count = %d\n", bossDroppedCount );
+ fprintf( fp, "Boss dropped ratio = %d%%\n", 100 * bossDroppedCount / bossSpawnCount );
+ fprintf( fp, "Boss MinLifetime %d, AvgLifeTime %d, MaxLifetime %d\n", minTime, avgTime / bossSpawnCount, maxTime );
+ }
+ else
+ {
+ fprintf( fp, "No Halloween data found.\n" );
+ }
+
+ fclose( fp );
+
+ return true;
+}
+
+
+//----------------------------------------------------------------------------------
+int _tmain(int argc, _TCHAR* argv[])
+{
+ if ( argc < 2 )
+ {
+ printf( "USAGE: %s <server log .txt file>\n", argv[0] );
+ return -1;
+ }
+
+ for( int i=1; i<argc; ++i )
+ {
+ ProcessData( argv[i] );
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/utils/tf_monoculus_stats/tf_monoculus_stats.vcproj b/utils/tf_monoculus_stats/tf_monoculus_stats.vcproj
new file mode 100644
index 0000000..815e73d
--- /dev/null
+++ b/utils/tf_monoculus_stats/tf_monoculus_stats.vcproj
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="tf_monoculus_stats"
+ ProjectGUID="{66C2AEC4-23AD-4B0B-BF49-5BF1465DBC3F}"
+ RootNamespace="tf_monoculus_stats"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\tf_monoculus_stats.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>