The 1.1.0.0 version of Half-Life includes a stat tracking program called TFStats for Team Fortress 1.5. This document will explain how it works.

What is TFStats?

TFStats is a program that generates an HTML report of a Team Fortress 1.5 match.




Who runs TFStats?

TFStats is a server-side application. The server op must run the program with the logfiles his server generates and make the report available via the web. If the server op has done so, a player can point his browser to the report on the web and view how well he did against the others, and how useful he was to his team, etc.


How do I install TFStats?

TFStats is installed along with the Half-Life patch it accompanies. TFStats was written to be easy to install and use, the only file required to use it is TFStatsRT.exe itself. However, to use custom rules (see custom rules below) you must also have the custom rule files (also explained below). All other files necessary for correct operation such as gifs and javascript source files are embedded in the program and will be automatically generated when TFStats is run. Thus TFStats can be relocated/reinstalled by copying TFStatsRT.exe and any rule files you may use to which ever directory you want.


Running TFStats

How do I run TFStats on my server that is running Windows?

Basic (Recommended) Method: Run the windows front end (TFStats.exe) and run through the tabs, changing the directories and checkboxes to your tastes, then add some logs in the first panel, and click OK. TFStats will generate reports for each of the logs you requested.

Advanced Method: Open a windows command prompt, and change directories to the directory in which TFStats resides. Run TFStatsRT.exe file with the name of a logfile specified as a command line parameter. For example, after changing to the right directory, you'd type something similar to this (though with a different log file) at the command line:
TFStatsRT.exe  logs\L0726012.log
If you use this method, you can also specify an output folder to tell the program where to put all the files it generates. For example:
TFStatsRT.exe  logs\L0726012.log  outputDir=c:\TFStatsReports\L0726012\
If you don't specify a folder, it will output files into the directory that it is running from. It is recommended that you always specify an output directory so you don't clutter up your current directory with html files and things.

What is the outputdir?

OutputDir is a switch to tell TFStats to put the files in the location specified after the = sign

What is a switch?

Switches are ways to get TFStats to do different stuff depending on what you want.
OutputDir which is explained above.

DisplayMM2: (yes/no) This switch tells TFStats whether or not to display team_messages in the dialog readout. Setting this switch to "yes" will make TFStats display team messages, setting it to no will ensure that team_messages are omitted from the readout. Here is an example of how to use it:
TFStatsRT.exe  logs\L0726012.log  outputDir=ReportOutput\L0726012  DisplayMM2=no
or
TFStatsRT.exe  L0726012.log  outputDir=ReportOutput\L0726012  DisplayMM2=yes


ruleDir: This switch tells TFStats where to look for rule files. TFStats will look for rules in the directory specified after the = sign.

persistPlayerStats: (yes/no) This switch tells TFStats to save player statistics so that they can be ranked across several matches. If you use this switch you must include the next two switches as well. The two switches after those are optional (Note: player stats will not be saved for lan games)
playerDir: This tells TFStats to store the player files in the directory specified after the = sign. If TFStats encounters any player files already in that directory, it will determine if any of the players it is storing are the same as any players that are already there, and if so, it will merge their statistics. Since player files are meant to be shared by all reports, it is recommended that you specify this directory to be somewhere in "common ground", rather than putting it with one report. The recommended value for this switch is the ouput directory (explained above) with "\..\players" appended. For example, if your outputDir is "c:\TFStatsReportOutput\L090105" then the recommended playerDir is "c:\TFStatsReportOutput\L090105\..\players" or just "c:\TFStatsReportOutput\players".
playerHTTPPath: This is the path from the output directory to the player directory. It will be inserted into the HTML that TFStats generates. Since several reports will be accessing the same player report and that player report can be , this switch will have to be customized to your particular setup. The value of this switch depends on how you make your reports available on your web server, and what the value for the playerDir switch is. If you use the recommended value of the playerDir, then the value for this switch needs to be "../player". Note that the forward slash needs to be there even if you are using Windows. HTTP paths use forward slashes.
eliminateOldPlayers: (yes/no) This switch tells TFStats to not report players who have not played for a certain amount of time from the persistent player stats. Note that this does not delete their data files, it just omits them from the report. So if they return to your server and play, they will have not lost their old stats.
oldPlayerCutoff: The value of this switch is how many days a player can be absent from the server before his stats are eliminated from the persistent stats. For example if the value of this switch is 7. Then a player has to play at least once a week for their stats to continue to be reported. If they are absent for longer than a week, their stats will be omitted from the report until they return.

useSupportDir: (yes/no) This switch tells TFStats to share images, style sheets and javascripts between all reports, thus saving disk space. If you use this switch you must include the next two switches as well...
supportDir: This tells TFStats where the resources will be located on your hard drive. The recommended value for this switch is the ouput directory (explained above) with "\..\support" appended. For example, if your outputDir is "c:\TFStatsReportOutput\L090105" then the recommended supportDir is "c:\TFStatsReportOutput\L090105\..\support" or just "c:\TFStatsReportOutput\support".
supportHTTPPath: This is the path from the output directory to the support directory. It will be inserted into the HTML that TFStats generates. Much like the playerHTTPPath, the value of this switch will be highly subjective, depending on your web-setup. The recommended value of this switch is "../support"

displayStartupInfo: (yes/no) This switch tells TFStats to display the all the switches that you are passing it as it runs. This will help if you think you are entering the switches correctly, but it is not working for some reason.




TFStats Output



What does TFStats produce?

After TFStats has done it's thing, you'll find several new files in the directory you specified. The HTML files make up report itself, and the rest of the files are support files to make the report look and work better. The files in the \img directory are all the images that the report uses. The CSS file and JS file are support files, containing style parameters and javascript source code respectively.


How do I look at the report?

index.html is the starting page of the report. Just load up index.html in your favorite browser (see below for browser compatibility issues) and you will be able to view the report. You can navigate through the report like any web page. The links on the left control what section you are viewing. On the top, info about the match itself is displayed.


How do I let players on my server look at the report?

The easiest way to do this is to post it to your webpage. How you do this varies from person to person. If you do not have a webpage, you can e-mail the files to players who request them.

What browsers are compatible with the report?

TFStats was developed and tested primarily on Microsoft Internet Explorer 5 thus it looks best on IE5, however, IE4 and Netscape 4 were both tested and both are supported as well. In general, for a browser to work with TFStats, it needs to support HTML 4.0 with Cascading Style Sheets and it needs to be able to execute Javascript 1.2 scripts. So, in conclusion, the recommended browser is IE5. If you have IE5, you will be getting the full TFStats experience. However, the other browsers mentioned above work too.

The Report


What is rank?

A player's rank is the number kills they got, minus the number of deaths, divided by the amount of time he was playing. Ranks below 0 signify that the player had more deaths than kills. The team's average rank is just that, the average rank of the team. More specifically the formula for calculating rank is as follows:
((Kills - Deaths) * 1000) / secondsPlaying
This amounts to the player's kills-deaths per 1000 seconds.

What do the awards mean?

Awards are given out to players who showed exemplary service in certain areas. There is one or two awards for each class, and several awards that aren't specific to one class.
Here is each award described in full:
Class Awards:
Scout:
Survivalist Award: This award is given to the scout who dies the least.
Sniper:
Sharpshooter Award: This award is given to the best sniper. All of a sniper's snipe-shot kills are totaled, with Headshots being worth 3 normal shots, and the highest total wins the award.

Soldier:
Rocketry Award: The soldier who gets the most kills with his trusty rocket launcher wins this award.

Demoman:
Grenadier Award: This is given to the demoman who killed the most people with the grenade launcher.
Demolitions Award: This is given to the demoman who gets the most kills with the detpack.

Medic:
LifeSaver Award: This is given to the medic who cured the most infections, healed the most people, etc.
Biological Warfare Award: This is given to the medic who got the most kills from infections (his bioweapon)
Heavy Weapons Guy:
Assault Cannon Award (Swiss cheese award): This award is given to the HWGuy who killed the most people with his assault cannon.
Pyro:
Blaze of Glory Award: This is given to the pyro who killed the most people with flames.
Spy:
Assassin Award: This is given to the spy who killed the most people with his knife.
Engineer:
Best Placement Award: This is given to the Engineer who has the most kills from any sentry gun he has built.
Worst Placement Award: This is given to the Engineer who has to rebuild his buildings the most. In other words, to the engineer who built the most buildings.
Non-Class-Specific Awards:
Kevorkian Award: This "award" is given to the player who kills the most teammates.
Kamikaze Award: This "award" is given to the player who kills themselves the most times.
BigMouth Award: This is given to the player who talks the most.



Using Custom Rules

Custom rules are considered an "advanced" topic. They are not required for TFStats to function, but they can enhance the generated report.

What is a custom rule?

TF is a flexible game and supports more than just Capture The Flag style maps. Take Canalzone or Rock for example, neither of them have anything to do with capturing a flag. Therefore, hardcoding flag capture support into TFStats would be silly. Custom rules are in TFStats to allow more than just flag caps to be recognized and awarded in the final report. For example, if a map-maker created a map in which the goal was to rescue a cat from a tree, then he could also create a custom rule that awarded the player who rescued the cat the most often in the final report.


Where do I put custom rules?

Custom rules are contained in custom rule files which need to be placed in the same directory as TFStatsRT.exe. If they are not, you need to specify their location using the ruleDir command line switch. The files will have the name "tfc.<mapname>.rul". For example, 2fort's custom rule file is called tfc.2fort.rul. Also the file TFC.RUL will be parsed no matter which map the match was in. Use this file for custom rules that you would like to run for all maps.


How do I write a custom rule?

The best way to learn would be by example. Here is an example custom rule that awards the person who captured command points 1 and 2 for the blue team the most often in Canalzone 2:
Award
{
name = "Command Point 1 Capture";
noWinnerMessage = "Command point 1 remained neutral throughout the match";
extraInfo = "%player captured CP 1 %number times!";
trigger
{
key= "%s[blue team] captured command point 1";
}
}

What does THAT mean?

Award:
The first line of the rule specifies what type it is. Unfortunately,TFStats only supports one type currently; Award. "Award" tells TFStats that this rule will be defining a custom award to be displayed in the awards section of the report.
name:
This defines the name of the award. This is what is displayed in the awards section.
noWinnerMessage:
If no one wins the award, then this message will be displayed in lieu of giving out an award.
extraInfo:
This is displayed with the award. The two %words represent variables that are available. %player evaluates to the winning player's name and %number evaluates to how many times the player triggered this rule. Also available are %winner which does the same as %player and %score which is almost the same as %number. While %number represents how many times a player triggered the award, %score represents his score. These are not necessarily the same, see the trigger property "value" below for details.
trigger:
This defines a trigger for this rule. A trigger is how you actually define who wins the award. triggers consist of keys and several other values that are described below.
key:
This is a string to search for in any broadcasts that are triggered by players. In Canalzone when a player captures a command point, the server broadcasts a message to all clients saying "%s[blue team] captured command point 1" (if it was CP 1). With the player's name attached. So when TFStats encounters that in the log file, it will the player whose name is attached to that message, and increment their counter for this award. You can have more than 1 key, just define as many as you like.


Why does that look different than the tfc.cz2.rul that is provided?

This is due to the interference of Titles.txt. See below for details.

What's the deal with Titles.txt, or why do the provided rul files have keys like #cz_bcap1?

Titles.txt is a text file provided by Valve to help making translation between english and non-english versions of half-life easier. However, it is of concern because it changes what is actually broadcasted to the client in broadcasts. For example, when a command point is captured in Canalzone the above message (in the custom rules section) is not transmitted. Canalzone uses the Titles.txt file, and so only transmits the ID of the message. In the case of Canalzone, the ID is something like #cz_bcap1. That ID stands for blue team captured CP1. others are #cz_bcap2 #cz_rcap4, #cz_bcap3 and so on. The reason this is being documented here is to explain why the rul files provided with TFStats have keys that don't look like strings.

What are the other properties of a trigger?

The value property is described the previous section. It determines a trigger's relative value with respect to the other triggers of that rule. Thus value has no effect unless there are two triggers in a rule. There is also property called type.

What does the Type property do?

Trigger's type property controls which events are scanned for the key matches. There are 3 possible values for type. FullSearch ( the default) which is the most useful type, Broadcast and Goal. Fullsearch means that every event is scanned to see if it matches the key string. See below for a description of how to use fullsearch and other advanced matching techniques. Broadcast means that broadcasts will be scanned for the key string(s). Goal means that the key string(s) specify names of goals, instead of broadcast text. If any goal named by a key is activated, this rule is triggered. For example in Well, when team 2 captures the enemy's flag, a goal called "team 2 dropoff" is activated. Therefore, if you want to give an award for the most flag caps in Well, you'd use a rule that looked like this:
Award
{
name = "Flag Cap";
noWinnerMessage = "No one captured any flags!";
extraInfo = "%player captured the enemy flag %number times!";

trigger
{
type = goal;
key = "team one dropoff";
key = "team two dropoff";
}
}
Whenever either of the goals, "team one dropoff" or "team two dropoff" are activated the player who activated them (the one who captured the flag) has his counter incremented by the trigger's value. If value is not specified (as it isn't above), the default value of value is 1.

Why would I want multiple triggers?

If you wanted to have two distinct events affect the outcome of one award. For example, if I wanted to make a blue biased Award, I could do the following:
Award
{
name = "Flag Cap";
noWinnerMessage = "No one captured any flags!";
extraInfo = "%player captured the enemy flag %number times!";

trigger
{
type = goal;
value=2;
key = "team one dropoff";
}
trigger
{
type = goal;
value=1;
key = "team two dropoff";
}
}
Notice that team one gets twice as many "points" for each flag capture as does team two. This would make it twice as easy for a blue player to win the award for most captures because a red player would have to capture twice as many flags to win it.

Why don't Custom Rules work with Hunted?

They don't because of the way hunted was constructed, the player who killed the hunted is not mentioned anywhere in the broadcast or in any sort of goal activation, therefore there is no way to write a custom award for that.

Can I search for other things, other than goal activations and/or broadcasts? or What is the FullSearch type?

The FullSearch trigger type will search every event for the specified key string. If using the full search trigger type, you can use regular expressions in your key string. See below for more info. the full search type also allows you to match event arguments to custom variables. Also, you can specify match strings for each variable itself. Here is an example. In this example, the award will be given to the WEAPON that kills the most players. (Yes, weapons can now get awards too!)
Award
{
name = "Most Used Weapon";
noWinnerMessage = "No weapons were used during this match!";
extraInfo = "%score people were killed by %winners";

trigger
{
type = fullsearch;
key = "%killer killed %killee with %weapon";
winnerVar="%weapon";
}
}

What are regular expressions and how do I use them?

Regular expressions are a powerful tool for pattern matching. Using regular expressions you can define an expression that describes a pattern you'd like to match and a regular expression searching tool will use that expression and attempt to match it against strings. For the syntax of the regular expressions that TFStats uses, go here. To tell TFStats to use regular expression matching prefix the match pattern with !! . Here is an example illustrating the use of regular expressions AND specifying match patterns for certain variables:
Award
{
name = "Pak Grabber";
noWinnerMessage = "no one grabbed any paks!";
extraInfo = "%winner grabbed %score paks!";

trigger
{
type= fullsearch;
winnerVar="%plr_grabber";
key = "%plr_grabber activated the goal %goal";
%goal="!!(spawn_pak|i_p_t)"; // this is a match pattern for %goal. this trigger will only fire if %goal matches this pattern.
}
}
This trigger will match whenever a player activates EITHER "spawn_pak" or "i_p_t". Note that regular expressions cannot be used in the key string, only in the match patterns for variables. This is quite a simple use of regular expressions. You could set %goal to "!!.*pak.*", and that would match any goal with the word pak in it. For a reference of the regular expression syntax that TFStats uses, go here.

I don't understand at all, what is going on?

See below for Help.

Help

Please do not contact Sierra's technical support with TFStats questions.