T2 Classic Server

Instructions

  1. Copy and paste the following code into a file called "t2stats.cs" and place it in Base\Scripts\autoexec folder
  2. Restart the Tribes 2server.

Script

Warning This script is designed for your server only, please do not share this script, it has certain identifiers so that your server can send your data to this website.

//
// Instructions:
//  1. Place this file in Base/Scripts/autoexec folder
//  2. Restart Tribes 2 Server
//
// Stats Script by Erik Kristensen (aka Sfphinx)
//
// Original Stats Script by kryrand
//
// Made for tournament play in associate with TWL and Branzone
//
// License: MIT License
//
// Script is for "T2 Classic Server (0)" only. 
//
// Do not place this script on any other server!
//

$TribalOutpost::SettingsDebug = 0;

$TribalOutpost::OutputFolder = "t2stats";
$TribalOutpost::OutputType = "php";

$TribalOutpost::StatsEnabled = 1;
$TribalOutpost::StatsServer = "tribaloutpost.com:80";
$TribalOutpost::StatsScript = "/t2stats/matches/import/cb1dc5ec42be5d74e004060c684e46d8";

$TribalOutpost::EnablePlayByPlay = 1;

$XMLStats::NegativeDistance = 0;
$XMLStats::EGrabDistance = 90;

$DamageName[$DamageType::Blaster] = "Blaster";
$DamageName[$DamageType::Plasma] = "Plasma";
$DamageName[$DamageType::Bullet] = "Bullet";
$DamageName[$DamageType::Disc] = "Disc";
$DamageName[$DamageType::Grenade] = "Grenade";
$DamageName[$DamageType::Laser] = "Laser";
$DamageName[$DamageType::ELF] = "ELF";
$DamageName[$DamageType::Mortar] = "Mortar";
$DamageName[$DamageType::Missile] = "Missile";
$DamageName[$DamageType::ShockLance] = "ShockLance";
$DamageName[$DamageType::Mine] = "Mine";
$DamageName[$DamageType::Explosion] = "Explosion";
$DamageName[$DamageType::Impact] = "Impact";

$DamageName[$DamageType::Ground] = "Ground";
$DamageName[$DamageType::Turret] = "Turret";
$DamageName[$DamageType::PlasmaTurret] = "PlasmaTurret";
$DamageName[$DamageType::AATurret] = "AATurret";
$DamageName[$DamageType::ElfTurret] = "ElfTurret";
$DamageName[$DamageType::MortarTurret] = "MortarTurret";
$DamageName[$DamageType::MissileTurret] = "MissileTurret";
$DamageName[$DamageType::IndoorDepTurret] = "IndoorDepTurret";
$DamageName[$DamageType::OutdoorDepTurret] = "OutdoorDepTurret";
$DamageName[$DamageType::SentryTurret] = "SentryTurret";
$DamageName[$DamageType::OutOfBounds] = "OutOfBounds";
$DamageName[$DamageType::Lava] = "Lava";
$DamageName[$DamageType::ShrikeBlaster] = "ShrikeBlaster";
$DamageName[$DamageType::BellyTurret] = "BellyTurret";
$DamageName[$DamageType::BomberBombs] = "BomberBombs";
$DamageName[$DamageType::TankChaingun] = "TankChaingun";
$DamageName[$DamageType::TankMortar] = "TankMortar";
$DamageName[$DamageType::SatchelCharge] = "SatchelCharge";
$DamageName[$DamageType::MPBMissile] = "MPBMissile";
$DamageName[$DamageType::Lightning] = "Lightning";
$DamageName[$DamageType::VehicleSpawn] = "VehicleSpawn";
$DamageName[$DamageType::ForceFieldPowerup] = "ForceFieldPowerup";
$DamageName[$DamageType::Crash] = "Crash";
$DamageName[$DamageType::NexusCamping] = "NexusCamping";
$DamageName[$DamageType::Suicide] = "Suicide";

package TribalOutpost
{
	function CTFGame::missionLoadDone(%game)
	{
		if ($TribalOutpost::SettingsDebug)
			echo("+++TribalOutpost::CTFGame::missionLoadDone+++");

		// -- Make sure the pickupxml directory gets created
		export("$TribalOutpost::Settings*", $TribalOutpost::OutputFolder @ "/empty", false);

		if ($TribalOutpost::EnablePlayByPlay)
		{
			deleteVariables("$TribalOutpost::PlayByPlay*");

			$TribalOutpost::PlayByPlayCount = 0;

			$TribalOutpost::PlayByPlayCount++;
			$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "MissionStart," @ getSimTime();
		}

		Parent::missionLoadDone(%game);

		$CurrentMissionDistance = vectorDist($TeamFlag[1].getTransform(), $TeamFlag[2].getTransform());
	}

	function GameConnection::onConnect(%client, %name, %raceGender, %skin, %voice, %voicePitch)
	{
		Parent::onConnect(%client, %name, %raceGender, %skin, %voice, %voicePitch);
		%client.jointime = getSimTime();

		if ($TribalOutpost::EnablePlayByPlay)
		{
			$TribalOutpost::PlayByPlayCount++;
			$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "PlayerConnect," @ %client.jointime @","@ %client;
		}
	}

	function GameConnection::onDrop(%client, %reason)
	{
		if ($TribalOutpost::EnablePlayByPlay)
		{
			$TribalOutpost::PlayByPlayCount++;
			$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "PlayerDisconnect," @ getSimTime() @","@ %client @","@ %reason;
		}

		Parent::onDrop(%client, %reason);
	}

	function CTFGame::gameOver(%game)
	{
		if ($TribalOutpost::SettingsDebug)
			echo("+++TribalOutpost::CTFGame::gameOver - Called");

		if ($TribalOutpost::EnablePlayByPlay)
		{
			$TribalOutpost::PlayByPlayCount++;
			$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "MissionEnd," @ getSimTime();

			$TribalOutpost::PlayByPlayFilename = "playbyplay/" @ statsGetFilename();
			export("$TribalOutpost::PlayByPlay*", $TribalOutpost::PlayByPlayFilename, false);
		}

		%game.saveStats(%game);

		Parent::gameOver(%game);

		if ($TribalOutpost::StatsEnabled)
		{
			%http = new HTTPObject();
			%http.get($TribalOutpost::StatsServer, $TribalOutpost::StatsScript @ "/" @ $TribalOutpost::CurrentStatsFileName, "file=" @ $TribalOutpost::CurrentStatsFileName @ "&rand=" @ getSimTime());
		}
	}

	function CTFGame::playerGotFlagTarget(%game, %player)
	{
		if ($TribalOutpost::SettingsDebug)
			echo("+++TribalOutpost::CTFGame::playerGotFlagTarget+++");

		if ($TribalOutpost::EnablePlayByPlay)
		{
			$TribalOutpost::PlayByPlayCount++;
			$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "FlagGrab," @ getSimTime() @","@ %player.client @","@ %player.position;
		}

		Parent::playerGotFlagTarget(%game, %player);
	}

	function CTFGame::playerDroppedFlag(%game, %player)
	{
		if ($TribalOutpost::SettingsDebug)
			echo("+++TribalOutpost::CTFGame::playerDroppedFlag+++");

		%flag = %player.holdingFlag;
		%homeflag = $TeamFlag[%player.client.team];
		%pickDistFromHome = vectorDist(%game.statFlagPos[%flag], %homeflag.originalPosition);
		%dropDistFromHome = vectorDist(%player.getTransform(), %homeflag.originalPosition);
		%distance = %pickDistFromHome - %dropDistFromHome;
		%distance = (%distance>0 ? %distance : ($XMLStats::NegativeDistance ? %distance : 0));
		%player.client.flagTime += getSimTime() - %game.statFlagTime[%flag];
		%player.client.flagDist += %distance;
		%player.client.flagPercentDist += %distance/$CurrentMissionDistance;
		%player.client.tempFlagTime += getSimTime() - %game.statFlagTime[%flag];
		%player.client.tempFlagDist += %distance;
		%player.client.tempFlagPercentDist += %distance/$CurrentMissionDistance;

		if ($TribalOutpost::EnablePlayByPlay)
		{
			$TribalOutpost::PlayByPlayCount++;
			$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "FlagDrop," @ getSimTime() @","@ %player.client @","@ %player.position;
		}

		Parent::playerDroppedFlag(%game, %player);
	}

	function CTFGame::flagCap(%game, %player)
	{
		if ($TribalOutpost::SettingsDebug)
			echo("+++TribalOutpost::CTFGame::flagCap+++");

		%flag = %player.holdingFlag;
		%homeflag = $TeamFlag[%player.client.team];
		%pickDistFromHome = vectorDist(%game.statFlagPos[%flag], %homeflag.originalPosition);
		%dropDistFromHome = vectorDist(%player.getTransform(), %homeflag.originalPosition);
		%distance = %pickDistFromHome - %dropDistFromHome;
		%distance = (%distance>0 ? %distance : ($XMLStats::NegativeDistance ? %distance : 0));
		%player.client.flagTime += getSimTime() - %game.statFlagTime[%flag];
		%player.client.flagDist += %distance;
		%player.client.flagPercentDist += %distance/$CurrentMissionDistance;
		%player.client.tempFlagTime += getSimTime() - %game.statFlagTime[%flag];
		%player.client.tempFlagDist += %distance;
		%player.client.tempFlagPercentDist += %distance/$CurrentMissionDistance;

		if ($TribalOutpost::EnablePlayByPlay)
		{
			$TribalOutpost::PlayByPlayCount++;
			$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "FlagCap," @ getSimTime() @","@ %player.client @","@ %player.position;
		}

		Parent::flagCap(%game, %player);

		%count = ClientGroup.getCount();
		for(%i = 0; %i < ClientGroup.getCount(); %i++)
		{
			%client = ClientGroup.getObject(%i);
			if(%client.team == %player.client.team)
				%game.awardTempFlagStats(%client);
		}
	}

	function CTFGame::flagReturn(%game, %flag, %player)
	{
		if ($TribalOutpost::SettingsDebug)
			echo("+++TribalOutpost::CTFGame::flagReturn+++");

		if ($TribalOutpost::EnablePlayByPlay)
		{
			$TribalOutpost::PlayByPlayCount++;
			$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "FlagReturn," @ getSimTime() @","@ %player.client @","@ %player.position;
		}

		Parent::flagReturn(%game, %flag, %player);

		%count = ClientGroup.getCount();
		for(%i = 0; %i < ClientGroup.getCount(); %i++)
		{
			%client = ClientGroup.getObject(%i);
			if(%client.team == %player.client.team)
				%game.resetTempFlagStats(%client);
		}
	}


	function CTFGame::onClientKilled(%game, %clVictim, %clKiller, %damageType, %implement, %damageLocation)
	{
		if ($TribalOutpost::EnablePlayByPlay)
			tribaloutpost_handleKillStat(%game, %clVictim, %clKiller, %damageType, %implement, %damageLocation);

		Parent::onClientKilled(%game, %clVictim, %clKiller, %damageType, %implement, %damageLocation);
	}



	function statsGetFilename()
	{
		%filename = formatTimeString("yy-mm-dd-") @ $CurrentMission;
		%append = "";
		%i = 1;
		while(isFile($TribalOutpost::OutputFolder @ "/" @ %filename @ %append @ "." @ $TribalOutpost::OutputType))
		{
			%i++;
			%append = "_"@%i;
		}
		return %filename @ %append @ "." @ $TribalOutpost::OutputType;
	}

	function statsGetWinner(%game)
	{
		if(%game.numTeams > 1)
		{
			%topScore = "";
			for(%team = 1; %team <= %game.numTeams; %team++)
			{
				if ( %topScore $= "" || $TeamScore[%team] > %topScore )
				{
					%topScore = $TeamScore[%team];
					%firstTeam = %team;
					%otherTeams = "";
				}
				else if ( $TeamScore[%team] == %topScore )
				{
					%otherTeams = %otherTeams TAB %team;
				}
			}
			return %firstTeam @ %otherTeams;
		}
		return "";
	}

	function statsSetCaptains(%game)
	{
		if(%game.numTeams > 1)
		{
			for(%team = 1; %team <= %game.numTeams; %team++)
				%captain[%team] = 0;

			for(%i = 0; %i < ClientGroup.getCount(); %i++)
			{
				%cl = ClientGroup.getObject(%i);
				if(%cl.team != 0 && %cl.playersTeamed > 0 && (%captain[%cl.team] == 0 || %captain[%cl.team].playersTeamed < %cl.playersTeamed))
				{
					%captain[%cl.team] = %cl;
				}
			}

			for(%team = 1; %team <= %game.numTeams; %team++)
				%captain[%team].wasCaptain = 1;
		}
	}

	function statsDefaultPlayerOutput(%file, %game, %format, %cl)
	{
		%elapsedTime = mFloor((getSimTime()-$missionStartTime) / 1000);
		%timeHere = mFloor((getSimTime()-%cl.jointime)/1000);
		%file.writeLine(%format.line("name", %cl.nameBase));
		%file.writeLine(%format.line("fullname", stripTaggedVar(%cl.name)));
		%file.writeLine(%format.line("ip", %cl.getAddress()));
		%file.writeLine(%format.line("guid", %cl.guid));
		%file.writeLine(%format.line("clid", %cl));
		if(%cl.team > 0)
			%file.writeLine(%format.line("team", getTaggedString(%game.getTeamName(%cl.team))));
		%file.writeLine(%format.line("captain", (%cl.wasCaptain$="" ? 0 : %cl.wasCaptain)));
		%file.writeLine(%format.line("time", ((%elapsedTime<%timeHere) ? %elapsedTime : %timeHere)));
		%file.writeLine(%format.line("score", (%cl.score$="" ? 0 : %cl.score)));
		%file.writeLine(%format.line("kills", (%cl.kills$="" ? 0 : %cl.kills)));
		%file.writeLine(%format.line("deaths", (%cl.deaths$="" ? 0 : %cl.deaths)));
		%file.writeLine(%format.line("suicides", (%cl.suicides$="" ? 0 : %cl.suicides)));
		%file.writeLine(%format.line("teamkills", (%cl.teamKills$="" ? 0 : %cl.teamKills)));
	}

	function statsMapServerOutput(%file, %game, %format)
	{
		%elapsedTime = mFloor((getSimTime()-$missionStartTime) / 1000);

		%file.writeLine(%format.line("server", $Host::GameName));
		%file.writeLine(%format.line("tournament", $Host::TournamentMode));
		%file.writeLine(%format.line("map", $CurrentMission));
		%file.writeLine(%format.line("gametype", $CurrentMissionType));

		if(%game.class $= "CTFGame")
			%file.writeLine(%format.line("distance", $CurrentMissionDistance));

		%file.writeLine(%format.line("day", formatTimeString("DD")));
		%file.writeLine(%format.line("month", formatTimeString("MM")));
		%file.writeLine(%format.line("monthnum", formatTimeString("m")));
		%file.writeLine(%format.line("date", formatTimeString("d")));
		%file.writeLine(%format.line("year", formatTimeString("yy")));
		%file.writeLine(%format.line("hour", formatTimeString("H")));
		%file.writeLine(%format.line("minute", formatTimeString("nn")));
		%file.writeLine(%format.line("second", formatTimeString("ss")));
		%file.writeLine(%format.line("length", %elapsedTime));
	}

	function statsTeamOutput(%file, %game, %format, %winner)
	{
		if(%game.numTeams > 1)
		{
			if(getFieldCount(%winner) == 1)
			{
				%file.writeLine(%format.line("winner", getTaggedString(%game.getTeamName(getField(%winner, 0)))));
			}

			for(%team = 1; %team-1 < %game.numTeams; %team++)
			{
				if ( %topScore $= "" || $TeamScore[%team] > %topScore )
				{
					%topScore = $TeamScore[%team];
					%firstTeam = %team;
					%topCount = 1;
				}
				else if ( $TeamScore[%team] == %topScore )
				{
					%secondTeam = %team;
					%topCount++;
				}

				if ($TeamScore[%team] $= "")
					%score = 0;
				else
					%score = $TeamScore[%team];

				%file.writeLine(%format.start("team"));
				%file.writeLine(%format.line("name", getTaggedString(%game.getTeamName(%team))));
				%file.writeLine(%format.line("score", %score));
				%file.writeLine(%format.end("team"));
			}
		}
	}

	function statsPlayByPlayOutput(%file, %format)
	{
		%fobject = new FileObject();

		if (!%fobject.openForRead($TribalOutpost::PlayByPlayFilename))
		{
			error(%file SPC "is unreadable");
			continue;
		}

		%file.writeLine(%format.start("playbyplay"));
		while (!%fobject.isEOF())
		{
			%line = %fobject.readLine();
			%file.writeLine(fixExportVariables(%line));
		}
		%file.writeLine(%format.end("playbyplay"));

		%fobject.close();
	}

	function fixExportVariables(%str)
	{
		%str = strreplace(%str, "TribalOutpost::PlayByPlay", "playbyplay[");
		%str = strreplace(%str, " = ", "] = ");
		%str = strreplace(%str, "Count", "'Count'");
		%str = strreplace(%str, "Filename", "'Filename'");
		return %str;
	}

	function DefaultGame::resetCustomStats(%game, %client)
	{
		%client.wasCaptain = 0;
		%client.playersTeamed = 0;
	}

	function CTFGame::resetCustomStats(%game, %client)
	{
		%client.eGrabs = 0;
		%client.flagTime = 0;
		%client.flagDist = 0;
		%client.flagPercentDist = 0;
		%client.cappedFlagTime = 0;
		%client.cappedFlagDist = 0;
		%client.cappedFlagPercentDist = 0;
		%game.resetTempFlagStats(%client);
		DefaultGame::resetCustomStats(%game, %client);
	}

	function CTFGame::awardTempFlagStats(%game, %client)
	{
		%client.cappedFlagTime += %client.tempFlagTime;
		%client.cappedFlagDist += %client.tempFlagDist;
		%client.cappedFlagPercentDist += %client.tempFlagPercentDist;
		%game.resetTempFlagStats(%client);
	}

	function CTFGame::resetTempFlagStats(%game, %client)
	{
		%client.tempFlagTime = 0;
		%client.tempFlagDist = 0;
		%client.tempFlagPercentDist = 0;
	}

	function CTFGame::saveStats(%game)
	{
		%filename = statsGetFilename();
		$TribalOutpost::CurrentStatsFileName = %filename;
		new FileObject("outfile");
		outfile.openForWrite($TribalOutpost::OutputFolder @ "/" @ %filename);

		%format = new ScriptObject() {
			class = "OutputFormat";
			type = $TribalOutpost::OutputType;
		};

		%winner = statsGetWinner(%game);
		statsMapServerOutput(outfile, %game, %format);
		statsTeamOutput(outfile, %game, %format, %winner);
		statsSetCaptains(%game);

		%count = ClientGroup.getCount();
		for (%i = 0; %i < %count; %i++)
		{
			%cl = ClientGroup.getObject(%i);
			outfile.writeLine(%format.start("player"));
			statsDefaultPlayerOutput(outfile, %game, %format, %cl);
			outfile.writeLine(%format.line("flagtime", (%cl.flagTime$="" ? 0 : mFloor(%cl.flagTime/1000))));
			outfile.writeLine(%format.line("flagdist", (%cl.flagDist$="" ? 0 : %cl.flagDist)));
			outfile.writeLine(%format.line("flagpercentdist", (%cl.flagPercentDist$="" ? 0 : %cl.flagPercentDist)));
			outfile.writeLine(%format.line("cappedflagtime", (%cl.cappedFlagTime$="" ? 0 : mFloor(%cl.cappedFlagTime/1000))));
			outfile.writeLine(%format.line("cappedflagdist", (%cl.cappedFlagDist$="" ? 0 : %cl.cappedFlagDist)));
			outfile.writeLine(%format.line("cappedflagpercentdist", (%cl.cappedFlagPercentDist$="" ? 0 : %cl.cappedFlagPercentDist)));
			outfile.writeLine(%format.line("caps", (%cl.flagCaps$="" ? 0 : %cl.flagCaps)));
			outfile.writeLine(%format.line("grabs", (%cl.flagGrabs$="" ? 0 : %cl.flagGrabs)));
			outfile.writeLine(%format.line("egrabs", (%cl.eGrabs$="" ? 0 : %cl.eGrabs)));
			outfile.writeLine(%format.line("gendestroys", (%cl.genDestroys$="" ? 0 : %cl.genDestroys)));
			outfile.writeLine(%format.line("sensordestroys", (%cl.sensorDestroys$="" ? 0 : %cl.sensorDestroys)));
			outfile.writeLine(%format.line("turretdestroys", (%cl.turretDestroys$="" ? 0 : %cl.turretDestroys)));
			outfile.writeLine(%format.line("invdestroys", (%cl.iStationDestroys$="" ? 0 : %cl.iStationDestroys)));
			outfile.writeLine(%format.line("vpaddestroys", (%cl.vstationDestroys$="" ? 0 : %cl.vstationDestroys)));
			outfile.writeLine(%format.line("solardestroys", (%cl.solarDestroys$="" ? 0 : %cl.solarDestroys)));
			outfile.writeLine(%format.line("sentrydestroys", (%cl.sentryDestroys$="" ? 0 : %cl.sentryDestroys)));
			outfile.writeLine(%format.line("depsensordestroys", (%cl.depSensorDestroys$="" ? 0 : %cl.depSensorDestroys)));
			outfile.writeLine(%format.line("depturretdestroys", (%cl.depTurretDestroys$="" ? 0 : %cl.depTurretDestroys)));
			outfile.writeLine(%format.line("depinvdestroys", (%cl.depStationDestroys$="" ? 0 : %cl.depStationDestroys)));
			// Defense scores
			outfile.writeLine(%format.line("flagdefends", (%cl.flagDefends$="" ? 0 : %cl.flagDefends)));
			outfile.writeLine(%format.line("gendefends", (%cl.genDefends$="" ? 0 : %cl.genDefends)));
			outfile.writeLine(%format.line("flagkills", (%cl.carrierKills$="" ? 0 : %cl.carrierKills)));
			outfile.writeLine(%format.line("escorts", (%cl.escortAssists$="" ? 0 : %cl.escortAssists)));
			outfile.writeLine(%format.line("farmkills", (%cl.turretKills$="" ? 0 : %cl.turretKills)));
			outfile.writeLine(%format.line("returnpoints", (%cl.returnPts$="" ? 0 : %cl.returnPts)));
			outfile.writeLine(%format.end("player"));
			%game.resetCustomStats(%cl);
		}

		if ($TribalOutpost::EnablePlayByPlay)
			statsPlayByPlayOutput(outfile, %format);

		outfile.close();
	}

	function OutputFormat::line(%this, %key, %val)
	{
		switch$(%this.type)
		{
			case "xml":
				return (%this.block$=""?"":"	") @"<"@ %key @">"@ XMLString(%val) @"</"@ %key @">";
			case "php":
				if(%this.block !$= "")
					%key = %this.block @"["@ %this.count[%this.block] @"]['"@ %key @"']";
				return "$"@ %key @" = \""@ escapeQuotes(%val) @"\";";
		}
	}

	function OutputFormat::start(%this, %block)
	{
		%this.block = %block;
		if(%this.count[%block] $= "")
			%this.count[%block] = 0;
		else
			%this.count[%block]++;
		switch$(%this.type)
		{
			case "xml":
				return "<"@ %block @">";
			case "php":
				if(%this.count[%block] == 0)
					return "$"@ %block @" = array();";
				return "";
		}
	}

	function OutputFormat::end(%this, %block)
	{
		%this.block = "";
		switch$(%this.type)
		{
			case "xml":
				return "</"@ %block @">";
			case "php":
				return "";
		}
	}

	function XMLString(%str)
	{
	   %str = strreplace(%str, "&", "&amp;");
	   %str = strreplace(%str, ">", "&gt;");
	   %str = strreplace(%str, "<", "&lt;");
	   return %str;
	}

	function escapeQuotes(%str)
	{
	   %str = strreplace(%str, "\"", "\\\"");
	   %str = strreplace(%str, "\\", "\\\\");
	   return %str;
	}

	function addUniqueField(%blob, %field)
	{
	   if(%blob $= "")
	      return %field;
	   %c = getFieldCount(%blob);
	   for(%i = 0; %i < %c; %i++)
	   {
	      if(%field $= getField(%blob, %i))
	         return %blob;
	   }
	   return %blob TAB %field;
	}


	function tribaloutpost_handleKillStat(%game, %victim, %killer, %damageType, %implement, %damageLocation)
	{
		if (%damageType == $DamageType::Impact) // run down by vehicle
		{
			if ((%controller = %implement.getControllingClient()) > 0)
			{
				// ... controlled by someone
				%killer = %controller;
			}
			else
			{
				// ... unmanned
				%killer = 0;
			}
		}
		else if (isObject(%implement) && (%implement.getClassName() $= "Turret" || %implement.getClassName() $= "VehicleTurret" || %implement.getClassName() $= "FlyingVehicle" || %implement.getClassName() $= "HoverVehicle"))
		{
			if (%implement.getControllingClient() != 0)
			{
				// turret is being controlled
				%killer = %implement.getControllingClient();
			}
			// use the handle associated with the deployed object to verify valid owner
			else if (isObject(%implement.owner))
			{
				%killer = %implement.owner;
			}
			else
			{
				// turret is not a placed (owned) turret (or owner is no longer on it's team),
				// and is not being controlled
				%killer = 0;
			}
		}

		if (isObject(%killer))
		{
			if (%game.numTeams > 1 && %killer.team == %victim.team && %killer != %victim)
			{
				// a teamkill
				//$atfstats::teamkills[%killer]++;
				//$TribalOutpost::PlayByPlay[TeamKill, getSimTime()] = "TeamKill" SPC %killer SPC %victim;
				//$TribalOutpost::PlayByPlay[TeamKill, getSimTime()] = %killer @","@ %victim @","@ %victim.player.position;
				$TribalOutpost::PlayByPlayCount++;
				$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "TeamKill," @ getSimTime() @","@ %killer @","@ %victim @","@ $DamageName[%damageType] @","@ %victim.player.position;
			}
			else if (%killer == %victim)
			{
				// self-kill
				//$atfstats::selfkills[%killer]++;
				//$TribalOutpost::PlayByPlay[SelfKill, getSimTime()] = %killer @","@ %killer.player.position;
				$TribalOutpost::PlayByPlayCount++;
				$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "SelfKill," @ getSimTime() @","@ %killer @","@ $DamageName[%damageType];
			}
			else
			{
				// normal kill
				//$atfstats::kills[%killer, $DamageName[%damageType]]++;
				//$TribalOutpost::PlayByPlay[Kill, getSimTime()] = "Kill" SPC %killer SPC %victim;
				//$TribalOutpost::PlayByPlay[Kill, getSimTime()] = %killer @","@ %victim @","@ %victim.player.position;
				$TribalOutpost::PlayByPlayCount++;
				$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "Kill," @ getSimTime() @","@ %killer @","@ %victim @","@ $DamageName[%damageType] @","@ %victim.player.position;
			}
		}

		if (isObject(%victim))
		{
			$TribalOutpost::PlayByPlayCount++;

			if (%killer == 0)
			{
				$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "Death," @ getSimTime() @","@ %victim @","@ %killer @","@ %implement.getClassName() @","@ %victim.player.position;
			}
			else
			{
				$TribalOutpost::PlayByPlay[$TribalOutpost::PlayByPlayCount] = "Death," @ getSimTime() @","@ %victim @","@ %killer @","@ $DamageName[%damageType] @","@ %victim.player.position;
			}
		}
	}

	function getDATA::onLine(%this, %line)
	{
		echo("++ONLINE++");
		echo(%line);
	}

	function getDATA::onDisconnect(%this)
	{
		echo("++DISCONNECT++");
		%this.delete();
	}

	function getDATA::connectionTerminated( %this )
	{
		echo("++TERMINATED++");
	}

	function getDATA::connectionDied( %this )
	{
		echo("++DIED++");
	}

};

activatePackage(TribalOutpost);