# HLstatsX Community Edition - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Nicholas Hastings (nshastings@gmail.com)
# http://www.hlxcommunity.com
#
# HLstatsX Community Edition is a continuation of 
# ELstatsNEO - Real-time player and clan rankings and statistics
# Copyleft (L) 2008-20XX Malte Bayer (steam@neo-soft.org)
# http://ovrsized.neo-soft.org/
# 
# ELstatsNEO is an very improved & enhanced - so called Ultra-Humongus Edition of HLstatsX
# HLstatsX - Real-time player and clan rankings and statistics for Half-Life 2
# http://www.hlstatsx.com/
# Copyright (C) 2005-2007 Tobias Oetzel (Tobi@hlstatsx.com)
#
# HLstatsX is an enhanced version of HLstats made by Simon Garner
# HLstats - Real-time player and clan rankings and statistics for Half-Life
# http://sourceforge.net/projects/hlstats/
# Copyright (C) 2001  Simon Garner
#             
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# 
# For support and installation notes visit http://www.hlxcommunity.com

sub get_fav_weapon  {

	my ($player)  = @_;
	my $p_connect_time = $player->{connect_time};
   
	my $result = &doQuery("
		SELECT
			hlstats_Events_Frags.weapon,
			COUNT(hlstats_Events_Frags.weapon) AS kills,
			SUM(hlstats_Events_Frags.headshot=1) as headshots
		FROM
			hlstats_Events_Frags,hlstats_Servers
		WHERE
			hlstats_Servers.serverId=hlstats_Events_Frags.serverId
			AND hlstats_Servers.game='".&quoteSQL($g_servers{$s_addr}->{game})."' AND hlstats_Events_Frags.killerId=".$player->{playerid}."
		GROUP BY
			hlstats_Events_Frags.weapon
		ORDER BY
			kills desc, headshots desc
		LIMIT 1	
	");
	my ($fav_weapon, $fav_weapon_kills, $fav_weapon_headshots) = $result->fetchrow_array;
	$result->finish;

	my $result = &doQuery("
		SELECT
			IFNULL(ROUND((SUM(hlstats_Events_Statsme.hits) / SUM(hlstats_Events_Statsme.shots) * 100), 0), 0) AS acc
		FROM
			hlstats_Events_Statsme, hlstats_Servers
		WHERE
			hlstats_Servers.serverId=hlstats_Events_Statsme.serverId
			AND hlstats_Servers.game='".&quoteSQL($g_servers{$s_addr}->{game})."' AND hlstats_Events_Statsme.PlayerId=".$player->{playerid}."
			AND hlstats_Events_Statsme.weapon='".&quoteSQL($fav_weapon)."'
		LIMIT 0,1	
	");
	my ($fav_weapon_sm_acc) = $result->fetchrow_array;
	$result->finish;

	my $result = &doQuery("
		SELECT
			hlstats_Events_Frags.weapon,
			COUNT(hlstats_Events_Frags.weapon) AS kills,
			SUM(hlstats_Events_Frags.headshot=1) as headshots
		FROM
			hlstats_Events_Frags,hlstats_Servers
		WHERE
			hlstats_Servers.serverId=hlstats_Events_Frags.serverId
			AND hlstats_Servers.game='".&quoteSQL($g_servers{$s_addr}->{game})."' AND hlstats_Events_Frags.killerId='".$player->{playerid}."'
			AND (hlstats_Events_Frags.eventTime > FROM_UNIXTIME(".$p_connect_time."))
		GROUP BY
			hlstats_Events_Frags.weapon
		ORDER BY
			kills desc, headshots desc
		LIMIT 0, 1	
	");

	my ($s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_headshots) = $result->fetchrow_array;
	$result->finish;
	my $s_fav_weapon_sm_acc = 0;
   
	if (($s_fav_weapon ne "") && ($s_fav_weapon_kills > 0)) {
		my $result = &doQuery("
			SELECT
				IFNULL(ROUND((SUM(hlstats_Events_Statsme.hits) / SUM(hlstats_Events_Statsme.shots) * 100), 0), 0) AS acc
			FROM
				hlstats_Events_Statsme, hlstats_Servers
			WHERE
				hlstats_Servers.serverId=hlstats_Events_Statsme.serverId
				AND hlstats_Servers.game='".&quoteSQL($g_servers{$s_addr}->{game})."' AND hlstats_Events_Statsme.PlayerId='".$player->{playerid}."'
				AND hlstats_Events_Statsme.weapon='".&quoteSQL($s_fav_weapon)."'
				AND (hlstats_Events_Statsme.eventTime > FROM_UNIXTIME(".$p_connect_time."))
			LIMIT 0,1	
		");
		($s_fav_weapon_sm_acc) = $result->fetchrow_array;
		$result->finish;
	}
   
	return ($g_games{$g_servers{$s_addr}->{game}}{weapons}{$fav_weapon}{name}, $fav_weapon_kills, $fav_weapon_sm_acc, $g_games{$g_servers{$s_addr}->{game}}{weapons}{$s_fav_weapon}{name}, $s_fav_weapon_kills, $s_fav_weapon_sm_acc);
}

sub get_next_ranks
{
	my ($player)  = @_;

	my $result = &doQuery("
		SELECT
			$g_ranktype,
			kills / IF(deaths=0,1,deaths) AS kpd
		FROM
			hlstats_Players
		WHERE
			playerId=" . $player->{playerid}
	);
	my ($base, $kpd) = $result->fetchrow_array;
	$result->finish;
	my $playerName = $player->{name};

	if (!$base) {
		$base = 0;
	}

	my $ranknumber = $player->getRank();

	my $rankword = "";
	if ($g_ranktype eq "kills") {
		$rankword = " kills";
	}
	my $osd_message = "->1 - Next Players\\n".sprintf("   %02d  %s%s        -      %s", $ranknumber, &number_format($base), $rankword, $playerName)."\\n";
   
	my $result = &doQuery("
		SELECT
			playerId,
			lastName,
			$g_ranktype,
			kills / IF(deaths=0,1,deaths) AS kpd
		FROM
			hlstats_Players
		WHERE
			game='".&quoteSQL($player->{game})."'
			AND $g_ranktype = $base
			AND hideranking = 0
			AND kills >= 1
			AND playerId <> " . $player->{playerid} . "
		HAVING
			kpd>=$kpd
		ORDER BY $g_ranktype, kpd
		LIMIT 0,10
	");

	my $player_count = 0;   
	my $i = $ranknumber;
	while (($player_count < 11) && (my ($playerId, $lastName, $p_base, $kpd) = $result->fetchrow_array)) {
		$i--;
		if (length($lastName) > 20) {
			$lastName = substr($lastName, 0, 17)."...";
		}
		$player_count++;
		$osd_message .= sprintf("   %02d  %s%s  +%04d  %s", $i, &number_format($p_base), $rankword, &number_format($p_base-$base), $lastName)."\\n";
	}
	$result->finish;

	if ($player_count < 11)  {
		my $result = &doQuery("
			SELECT
				playerId,
				lastName,
				$g_ranktype,
				kills / IF(deaths=0,1,deaths) AS kpd
			FROM
				hlstats_Players
			WHERE
				game='".&quoteSQL($player->{game})."' 
				AND hideranking = 0
				AND $g_ranktype > $base
				AND kills >= 1
			ORDER BY
				$g_ranktype,
				kpd
			LIMIT 0,10
		");
      
		while (($player_count < 11) && (my ($playerId, $lastName, $p_base, $kpd) = $result->fetchrow_array)) {
			$i--;
			if (length($lastName) > 20) {
				$lastName = substr($lastName, 0, 17)."...";
			}
			$osd_message .= sprintf("   %02d  %s%s  +%04d  %s", $i, &number_format($p_base), $rankword, ($p_base-$base), $lastName)."\\n";
			$player_count++;
		}
		$result->finish;
	}
   
	return ($ranknumber, $g_games{$player->{game}}->getTotalPlayers(), $osd_message);
}


sub get_player_rank
{
	my ($player)  = @_;
	
	my $base = 0;
	if ($g_ranktype ne "kills") {
		$base = $player->{skill};
	} else {
		$base = $player->{total_kills};
	}
   
	return ($base, $player->getRank(), $g_games{$player->{game}}->getTotalPlayers());

}

sub get_player_data
{
	my ($player, $get_rank)  = @_;

	my $result = &doQuery("
		SELECT
			skill, kills, deaths, suicides, headshots,
			IFNULL(ROUND((hits / shots * 100), 0), 0) AS acc,
			connection_time
		FROM
			hlstats_Players
		WHERE
			playerId='" . $player->{playerid} . "'
	");
    my ($skill, $kills, $deaths, $suicides, $headshots, $acc, $connection_time) = $result->fetchrow_array;
	$result->finish;
	
    my $playerName = $player->{name};
      
    if ($deaths > 0) {
		$kd = sprintf("%.2f", $kills/$deaths);
    } else {
		$kd = sprintf("%.2f", $kills);
    }
    if ($kills > 0) {
		$hpk = sprintf("%.0f", (100/$kills) * $headshots);
    } else {
		$hpk = sprintf("%.0f", $kills);
    }
    
    if ($kills > 0) {
		($fav_weapon, $fav_weapon_kills, $fav_weapon_acc, $s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_acc) = get_fav_weapon($player);
    } else {
		$fav_weapon   = "-";
		$s_fav_weapon = "-";
    }  
    
    if ($get_rank > 0) {
		my ($rang_skill, $rank_number, $total_players) = get_player_rank($player);
		return ($skill, $kills, $deaths, $kd, $suicides, $headshots, $hpk, $acc, $connection_time,$fav_weapon, $fav_weapon_kills, $fav_weapon_acc, $s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_acc, $rank_number, $total_players);
    } else {
		return ($skill, $kills, $deaths, $kd, $suicides, $headshots, $hpk, $acc, $connection_time, $fav_weapon, $fav_weapon_kills, $fav_weapon_acc, $s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_acc);
    }
    
}

sub get_menu_text
{
	my ($player, $skill, $kills, $deaths, $kd, $suicides, $headshots, $hpk, $acc, $connection_time, $fav_weapon, $fav_weapon_kills, $fav_weapon_acc, $s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_acc, $rank_number, $total_players) = @_;

	my $p_name         = $player->{name};
	my $p_connect_time = $player->{connect_time};

	my $s_pos_change = "N/A";
	if ($player->{session_start_pos} > 0)  {
		$s_pos_change   = ($player->{session_start_pos} - $rank_number);
		if ($s_pos_change > 0) {
			$s_pos_change = "+".$s_pos_change;
		}
	}

	my $s_skill_change = $player->{session_skill};
	if ($s_skill_change > 0) {
		$s_skill_change = "+".$s_skill_change;
	}
  
	my $s_kills        = $player->{session_kills};
	my $s_deaths       = $player->{session_deaths};
	my $s_headshots    = $player->{session_headshots};
	my $s_hits         = $player->{session_hits};
	my $s_shots        = $player->{session_shots};

	if ($s_deaths > 0) {
		$s_kd = sprintf("%.2f", $s_kills/$s_deaths);
	} else {
		if ($s_kills > 0) {
			$s_kd = sprintf("%.2f", $s_kills);
		} else {
			$s_kd = sprintf("%.2f", 0);
		} 
	}
  
	if ($s_kills > 0) {
		$s_hpk = sprintf("%.0f", (100/$s_kills) * $s_headshots);
	} else {
		if ($s_headshots > 0) {
			$s_hpk = sprintf("%.0f", $s_headshots);
		} else {
			$s_hpk = sprintf("%.0f", 0);
		}  
	}

	if ($s_shots > 0) {
		$s_acc = sprintf("%.0f", (100/$s_shots) * $s_hits);
	} else {
		if ($s_hits > 0) {
			$s_acc = sprintf("%.0f", $s_hits);
		} else {
			$s_acc = sprintf("%.0f", 0);
		}
	}

	my $weapon_str =  "   No Fav Weapon\\n";
	my $acc_str    =  "   $acc% Accuracy\\n";
	if ($fav_weapon_kills > 0) {
		$weapon_str = "   ".$fav_weapon_kills." kills with ".$fav_weapon."\\n";
		$acc_str    = "   $acc% Accuracy (".$fav_weapon." ".$fav_weapon_acc."%)\\n";
	}
	if ($acc == 0) {
		$acc_str = "";
	}

	$s_weapon_str =  "   No Fav Weapon\\n";
	$s_acc_str    =  "   $s_acc% Accuracy\\n";
	if ($s_fav_weapon_kills > 0) {
		$s_weapon_str = "   ".$s_fav_weapon_kills." kills with ".$s_fav_weapon."\\n";
		$s_acc_str    = "   $s_acc% Accuracy (".$s_fav_weapon." ".$s_fav_weapon_acc."%)\\n";
	}
  
	if ($s_acc == 0) {
		$s_acc_str = "";
	}
	my $cmd_text = "";
	
	if ($g_ranktype eq "kills") {
		$cmd_text = 	"->1 - Total\\n".
					"   Position ".&number_format($rank_number)." of ".&number_format($total_players)."\\n".
                    "   ".&number_format($kills).":".&number_format($deaths)." Frags ($kd)\\n".
					"   ".&number_format($headshots)." Headshots ($hpk%)\\n".
					"   ".&number_format($skill)." Points\\n".
					$weapon_str.
                    $acc_str.
                    "   Time ".&date_format($connection_time)."\\n \\n".
                    "->2 - Session\\n".
                    "   ".&number_format($s_pos_change)." Positions\\n".
                    "   ".&number_format($s_kills).":".&number_format($s_deaths)." Frags ($s_kd)\\n".
                    "   ".&number_format($s_headshots)." Headshots ($s_hpk%)\\n".
					"   ".&number_format($s_skill_change)." Points\\n".
                    $s_weapon_str.
                    $s_acc_str.
                    "   Time ".&date_format(time() - $p_connect_time)."\\n";
	} else {
		$cmd_text = 	"->1 - Total\\n".
					"   Position ".&number_format($rank_number)." of ".&number_format($total_players)."\\n".
					"   ".&number_format($skill)." Points\\n".
                    "   ".&number_format($kills).":".&number_format($deaths)." Frags ($kd)\\n".
					"   ".&number_format($headshots)." Headshots ($hpk%)\\n".
					$weapon_str.
                    $acc_str.
                    "   Time ".&date_format($connection_time)."\\n \\n".
                    "->2 - Session\\n".
                    "   ".&number_format($s_pos_change)." Positions\\n".
                    "   ".&number_format($s_skill_change)." Points\\n".
                    "   ".&number_format($s_kills).":".&number_format($s_deaths)." Frags ($s_kd)\\n".
                    "   ".&number_format($s_headshots)." Headshots ($s_hpk%)\\n".
                    $s_weapon_str.
                    $s_acc_str.
                    "   Time ".&date_format(time() - $p_connect_time)."\\n";
	}
	
		$points = "   ".&number_format($skill)." Points\\n";
	$s_points = "   ".&number_format($s_skill_change)." Points\\n";

	return $cmd_text;
}

sub endKillStreak
{
	my ($player) = @_;
	
	my $killtotal = $player->{kills_per_life};
	if ($killtotal > $player->{kill_streak}) {
		$player->{kill_streak} = $killtotal;
	}	
	if ($killtotal > 12) {
		$killtotal = 12;
	}
	# octo: I don't think suicides should count as deaths in a row
	if ($killtotal > 1) {
		&doEvent_PlayerAction(
			$player->{userid},
			$player->{uniqueid},
			"kill_streak_" . $killtotal
		);
	}
	$player->{kills_per_life} = 0;
}

#
# 001. Connect
#

sub doEvent_Connect
{	
	my ($playerId, $playerUniqueId, $ipAddr) = @_;

	my $desc;
	my $player            = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr         = &getPlayerInfoString($player, $playerId);
    my $min_players_rank  = $g_servers{$s_addr}->{min_players_rank};
	my $hostname;
	my $hostgroup;
	
	if ($player)
	{
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($player->{is_bot} == 1))
		{
			$player->set("connect_time", time());
			$player->updateDB();
			$desc = "(IGNORED) BOT: ";
		} else {
			$player->set("connect_time", time());
			my $player_rank = 0;
			$player_rank = $player->getRank();
			if ($min_players_rank > 0 || $player_rank == 0) {
				if ($player_rank > $min_players_rank) {
					my $steamid = $player->{uniqueid};
					my $p_steamid = $player->{plain_uniqueid};
					if ($g_servers{$s_addr}->is_admin($steamid) == 0) {
						if ($g_servers{$s_addr}->{game_engine} == 1) {
							$g_servers{$s_addr}->dorcon("kick #$playerId Not a Top $min_players_rank-Player");
						} else {
							$g_servers{$s_addr}->dorcon("kickid $p_steamid Not a Top $min_players_rank-Player");
						}
					}
				}
			}  
			
			if ($g_mode eq "LAN")
			{
				$player->set("uniqueid", $ipAddr);
			}
			
			&recordEvent(
				"Connects", 0,
				$player->{playerid},
				$ipAddr,
				$hostname,
				$hostgroup
			);
		}		
	}
	else
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}
	
	return $desc . $playerstr . " connected, address \"$ipAddr\","
		. " hostname \"$hostname\", hostgroup \"$hostgroup\"";
}


#
# 002. Enter Game
#

sub doEvent_EnterGame
{
	my ($playerId, $playerUniqueId) = @_;
	
	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);
	my $isbot = $player->{is_bot};
	
    my $min_players_rank  = $g_servers{$s_addr}->{min_players_rank};
    
	if ($player)
	{
		if ($g_mode eq "Normal" && $isbot == 0 && $player->{userid} > 0)
		{
			$hostname = &resolveIp($player->{address});
			$hostgroup = "";
	
			if ($hostname)
			{
				$hostgroup = &getHostGroup($hostname);
			}
			if ($g_stdin == 0 && $g_servers{$s_addr}->{connect_announce} > 0)
			{
				my $player_rank = $player->getRank();
				if ($player->{country} ne "")
				{					
					my $msg = "";
					if ($player_rank == 0)
					{
						$msg = sprintf("Player %s has connected from %s", $player->{name},$player->{country});
					}
					elsif ($player->{skill} == 1000)
					{
						$msg = sprintf("New player %s has connected from %s",$player->{name},$player->{country});
					}
					elsif ($g_ranktype ne "kills")
					{
						$msg = sprintf("%s (Pos %s with %s points) has connected from %s",$player->{name},$player_rank,$player->{skill},$player->{country});
					}
					else
					{
						$msg = sprintf("%s (Pos %s with %s kills) has connected from %s",$player->{name},$player_rank,$player->{total_kills},$player->{country});
					}
					$g_servers{$s_addr}->messageAll($msg, $player->{playerid}, 1);
				}
				else
				{
					if ($g_ranktype ne "kills")
					{
						$msg = sprintf("%s (Pos %s with %s points) has connected",$player->{name},$player_rank,$player->{skill});
					}
					else
					{
						$msg = sprintf("%s (Pos %s with %s kills) has connected",$player->{name},$player_rank,$player->{total_kills});
					}
					$g_servers{$s_addr}->messageAll($msg, $player->{playerid}, 1);
				}
			}
		}
		
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($isbot == 1))
		{
			$connect_time = $player->{connect_time};
			if ($connect_time == 0)
			{
				$player->set("connect_time", time());
			}  
			$player->updateDB();
			$desc = "(IGNORED) BOT: ";
		}
		else
		{
			$connect_time = $player->{connect_time};
			if ($connect_time == 0)
			{
				$player->set("connect_time", time());
				if (($min_players_rank > 0) && ($isbot == 0))
				{
					my $player_rank = $player->getRank();
					if ($player_rank > $min_players_rank || $player_rank == 0)
					{
						my $steamid = $player->{uniqueid};
						my $p_steamid = $player->{plain_uniqueid};
						if ($g_servers{$s_addr}->is_admin($steamid) == 0)
						{
							$g_servers{$s_addr}->dorcon("kickid $p_steamid Not a Top".$min_players_rank."-Player");
						}
					}
				}
			}
			if ($isbot == 0)
			{
				$player->updateDB();
				recordEvent(
					"Entries", 0,
					$player->{playerid}
				);
			}
		}
	}
	else
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}
	
	return $desc . $playerstr . " entered the game";
}


#
# 003. Disconnect
#

sub doEvent_Disconnect
{
	my ($pUserId, $playerUniqueId, $ev_properties) = @_;
	
	my $desc;
	my $player = lookupPlayer($s_addr, $pUserId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $pUserId);
	
	if ($player)
	{
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && (($player->{is_bot} == 1) || ($pUserId < 0)))
		{
			$player->updateDB();
			removePlayer($s_addr, $pUserId, $playerUniqueId);
			$desc = "(IGNORED) BOT: ";
		} else {
			&recordEvent(
				"Disconnects", 0,
				$player->{playerid}
			);
			
			&endKillStreak($player);
			
			if (($g_global_chat > 0)) {
				my $p_name    = $player->{name};
				my $b_message = $p_name." (".$g_servers{$s_addr}->{name}.") disconnected";
				if ($player->{is_dead} == 1) {
					$b_message  = "*DEAD* ".$p_name." (".$g_servers{$s_addr}->{name}.") disconnected";
				}
				send_global_chat($b_message);
			}
		
			my $p_steamid = $player->{plain_uniqueid};
			my $p_connect_time = $player->{connect_time};
			my $p_is_banned = $player->{is_banned};
        
			if ($p_connect_time == 0) {
				$p_connect_time = time();
			}
        
			my $auto_ban = $g_servers{$s_addr}->{auto_ban};
			# time()-$p_connect_time > 30 to avoid permanent bans changes in 5 min bans
			# $p_is_banned > 0 for not converting bans to "just" 5 minutes bans
			if (($auto_ban > 0) && ((time() - $p_connect_time) > 30) && ($p_is_banned == 0) && ($player->{is_bot} == 0))    
			{
				if ($g_servers{$s_addr}->is_admin($playerUniqueId) == 0)  {
					$g_servers{$s_addr}->dorcon("banid 5 $p_steamid");
				}
			}
			$player->updateDB();
			removePlayer($s_addr, $pUserId, $playerUniqueId);
		}
	}
	else
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
		if ($playerUniqueId ne "") {
			if ($ev_properties eq "(reason \"VAC banned from secure server\")") {
				$desc = "(IGNORED) VAC BANNED PLAYER [".$playerUniqueId."]: ";
				my $playerid = &getPlayerId($playerUniqueId);
				if ($playerid) {
					my $query = "SELECT lastName, hideranking FROM hlstats_Players WHERE playerId=$playerid";
					my $result = &doQuery($query);
					($lastName, $hideranking) = $result->fetchrow_array;
					$result->finish;
					if ($hideranking < 2)  {
						my $query = "UPDATE hlstats_Players SET last_event=UNIX_TIMESTAMP(), hideranking=2 WHERE playerId=$playerid";
						&execNonQuery($query);
						$desc = "HIDING VAC BANNED PLAYER [".$playerUniqueId.", ".$lastName."]: ";
					} else {
						$desc = "VAC BANNED PLAYER [".$playerUniqueId.", ".$lastName."] ALREADY HIDDEN: ";
					}
				}
			} elsif ($ev_properties eq "(reason \"Kicked by Console :  You have been banned, visit www.steambans.com for information.\")") {
				$desc = "(IGNORED) STEAMBANS BANNED PLAYER [".$playerUniqueId."]: ";
				my $playerid = &getPlayerId($playerUniqueId);
				if ($playerid) {
					my $query      = "SELECT lastName, hideranking FROM hlstats_Players WHERE playerId=$playerid";
					my $result     = &doQuery($query);
					($lastName, $hideranking) = $result->fetchrow_array;
					$result->finish;
					if ($hideranking < 2)  {
						my $query = "UPDATE hlstats_Players SET last_event=UNIX_TIMESTAMP(), hideranking=2 WHERE playerId=$playerid";
						&execNonQuery($query);
						$desc = "HIDING STEAMBANS BANNED PLAYER [".$playerUniqueId.", ".$lastName."]: ";
					} else {
						$desc = "STEANBANS BANNED PLAYER [".$playerUniqueId.", ".$lastName."] ALREADY HIDDEN: ";
					}
				}
			}
		}
	}

	return $desc . $playerstr . " disconnected ".$ev_properties;
}


#
# 004. Suicide
#

sub doEvent_Suicide
{	
	my ($playerId, $playerUniqueId, $weapon, %properties) = @_;
	
	$x = undef;
	$y = undef;
	$z = undef;
	
	if (defined($properties{attacker_position})) {
		$coords = $properties{attacker_position};
		# print "\nCoords SUICIDE: ".$coords."\n\n";
		($x,$y,$z) = split(/ /,$coords);
	}

	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);
	
	if ($g_servers{$s_addr}->{num_trackable_players} < $g_servers{$s_addr}->{minplayers})
	{
		$desc = "(IGNORED) NOTMINPLAYERS: ";
	}
	elsif (checkBonusRound())
	{
		$desc = "(IGNORED) BonusRound: ";
	}
	elsif (!$player)
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}
	elsif ($player->{last_team_change}+2 > $ev_remotetime)
	{
		$desc = "(IGNORED) TEAMSWITCH: ";
	}
	else
	{
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($player->{is_bot} == 1))
		{
			$desc = "(IGNORED) BOT: ";
		} else {
			
			&endKillStreak($player);
			
			if ($g_servers{$s_addr}->{play_game} == TF() && defined($properties{customkill})) {
				if ($properties{customkill} eq "train") {
					&doEvent_PlayerAction(
						$player->{userid},
						$player->{uniqueid},
						"hit_by_train",
						$x,
						$y,
						$z
					);
				} elsif ($properties{customkill} eq "saw") {
					&doEvent_PlayerAction(
						$player->{userid},
						$player->{uniqueid},
						"death_sawblade",
						$x,
						$y,
						$z
					);
				}
			}
			
			&recordEvent(
				"Suicides", 0,
				$player->{playerid},
				$weapon,
				$x,
				$y,
				$z
			);

			my $suicide_penalty = (-1) * $g_servers{$s_addr}->{suicide_penalty};
			$player->increment("suicides");
			$player->increment("skill", $suicide_penalty);
			$player->increment("session_suicides");
			$player->increment("session_skill", $suicide_penalty);
			$player->increment("map_suicides");
			$g_servers{$s_addr}->increment("suicides");
			$g_servers{$s_addr}->increment("total_suicides");
			$player->updateDB();
		}
	}
	
	return $desc . $playerstr . " committed suicide with \"$weapon\"";
}


#
# 005. Team Selection
#

sub doEvent_TeamSelection
{
	my ($playerId, $playerUniqueId, $team) = @_;
	
	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);
	
	if ($player)
	{
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($player->{is_bot} == 1))
		{
			$player->set("team", $team);
			$desc = "(IGNORED) BOT: ";
		} else {
			$old_team = $player->{team};
			if (($old_team eq "CT") || ($old_team eq "TERRORIST"))
			{
				$g_servers{$s_addr}->increment("ba_player_switch");
			}  
			$player->set("last_team_change",$ev_remotetime);
			$player->set("team", $team);
			&recordEvent(
				"ChangeTeam", 0,
				$player->{playerid},
				$team
			);
			
			$player->updateTrackable();
			$player->updateDB();
			$g_servers{$s_addr}->updatePlayerCount();
		}
	}
	else
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}
	
	return $desc . $playerstr . " joined team \"$team\"";
}


#
# 006. Role Selection
#

sub doEvent_RoleSelection
{
	my ($playerId, $playerUniqueId, $role) = @_;
	
	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);
	
	if ($player)
	{
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($player->{is_bot} == 1))
		{
			$player->set("role", $role);
			$desc = "(IGNORED) BOT: ";
		} else {
			$player->set("role", $role);
			&recordEvent(
				"ChangeRole", 0,
				$player->{playerid},
				$role
			);
			my $query = "
				UPDATE
					hlstats_Roles
				SET
					picked=picked+1
				WHERE 
					game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
					AND code='" . &quoteSQL($role) . "'
				";                    
			&execNonQuery($query);
			$player->updateDB();
		}
	}
	else
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}
	
	return $desc . $playerstr . " changed role to \"$role\"";
}


#
# 007. Change Name
#

sub doEvent_ChangeName
{
	my ($playerId, $playerUniqueId, $newname) = @_;
	
	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);
	
	if ($player)
	{
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($player->{is_bot} == 1))
		{
			$player->updateDB();
			removePlayer($s_addr, $playerId, $playerUniqueId);
			$desc = "(IGNORED) BOT: ";
		} else {
			my $name = $player->{name};
			&recordEvent(
				"ChangeName", 0,
				$player->{playerid},
				$name,
				$newname
			);

			if (($g_mode eq "NameTrack") || ($player->{is_bot} == 1))
			{
				$player->updateDB();
				removePlayer($s_addr, $playerId, $playerUniqueId);
			} else {
				$player->set("name", $newname);
				$player->updateDB();
			}
		}
	}
	else
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}
	
	return $desc . $playerstr . " changed name to \"$newname\"";
}


#
# E008. Frag
#

sub doEvent_Frag
{
	$rcmd = $g_servers{$s_addr}->{broadcasting_command};

	my ($killerId, $killerUniqueId, $victimId, $victimUniqueId, $weapon, $headshot, $x, $y, $z, $vx, $vy, $vz, %properties) = @_;

	# if killer coords were on kill line, use them
	if (defined($properties{attacker_position})) {
		$coords = $properties{attacker_position};
		($x,$y,$z) = split(/ /,$coords);
	} elsif (defined($properties{killerpos})) { #pvkii
		$coords = $properties{killerpos};
		($x,$y,$z) = split(/ /,$coords);
	} elsif ($g_servers{$s_addr}->{nextkillx} ne "") {
	# else use coords stored from plugin if available
		$x = $g_servers{$s_addr}->{nextkillx};
		$y = $g_servers{$s_addr}->{nextkilly};
		$z = $g_servers{$s_addr}->{nextkillz};
	}
	# reset last kill coords
	$g_servers{$s_addr}->{nextkillx} = "";
	$g_servers{$s_addr}->{nextkilly} = "";
	$g_servers{$s_addr}->{nextkillz} = "";
	
		# if killer coords were on kill line, use them
	if (defined($properties{victim_position})) {
		$coords = $properties{victim_position};
		($vx,$vy,$vz) = split(/ /,$coords);
	} elsif (defined($properties{victimpos})) { #pvkii
		$coords = $properties{victimpos};
		($vx,$vy,$vz) = split(/ /,$coords);
	} elsif ($g_servers{$s_addr}->{nextkillvicx} ne "") {
	# else use coords stored from plugin if available
		$vx = $g_servers{$s_addr}->{nextkillvicx};
		$vy = $g_servers{$s_addr}->{nextkillvicy};
		$vz = $g_servers{$s_addr}->{nextkillvicz};
	}
	# reset last kill coords
	$g_servers{$s_addr}->{nextkillvicx} = "";
	$g_servers{$s_addr}->{nextkillvicy} = "";
	$g_servers{$s_addr}->{nextkillzvic} = "";

	# determine if kill was fake
	# currently only applicable to TF2's "Dead Ringer"
	my $isfake = (defined($properties{customkill}) && $properties{customkill} eq "feign_death")?1:0;
	
	my $desc;
	my $killer = lookupPlayer($s_addr, $killerId, $killerUniqueId);
	my $victim = lookupPlayer($s_addr, $victimId, $victimUniqueId);
	my $killerstr = &getPlayerInfoString($killer, $killerId);
	my $victimstr = &getPlayerInfoString($victim, $victimId);
	
	my $headshotFromAction = 0;

	if (($g_servers{$s_addr}->{num_trackable_players} < $g_servers{$s_addr}->{minplayers}) && $g_servers{$s_addr}->{play_game} != L4D()) {
		$desc = "(IGNORED) NOTMINPLAYERS: ";
	} elsif (checkBonusRound()) {
		$desc = "(IGNORED) BonusRound: ";
	} elsif ($killer && $victim) {
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && (($killer->{is_bot} == 1) || ($victim->{is_bot} == 1))) {
			$desc = "(IGNORED) BOT: ";
		} elsif ($g_servers{$s_addr}->{play_game} == L4D() && $killer->{team} eq "Infected" && $victim->{team} eq "Infected") {
			$desc = "(IGNORED) L4D Infected TK: ";
		} else {
		
			# weapon fixes
			if ($weapon eq "") {
				if ($killer->{role} ne "") {
					$weapon = $killer->{role};
				} else {
					$weapon = "world";
				}
			} elsif ($g_servers{$s_addr}->{play_game} == ZPS()) {
				# strip off the 2 at the end of some weapon names in FoF so weapon is right hand is counted the same as same weapon in the left hand
				if ($weapon eq "broom") {
					$weapon = "crowbar";
				}
			} elsif ($g_servers{$s_addr}->{play_game} == FF()) {
				if ($weapon eq "BOOM_HEADSHOT") {
					$weapon = "weapon_sniperrifle";
					$headshot = 1;
				} elsif ($weapon eq "grenade_napalmlet") {
					$weapon = "grenade_napalm";
				}
			} elsif ($g_servers{$s_addr}->{play_game} == TFC() && $weapon eq "headshot") {
				$weapon = "sniperrifle";
				$headshot = 1;
			} elsif ($g_servers{$s_addr}->{play_game} == FOF()) {
				# strip off the 2 at the end of some weapon names in FoF so weapon is right hand is counted the same as same weapon in the left hand
				$weapon =~ s/2$//;
				if ($weapon eq "bow") {
					$weapon = "arrow";
				}
			} elsif ($g_servers{$s_addr}->{play_game} == PVKII()) {
				if (defined($properties{killerclass})) {
					my $krole = $properties{killerclass};
					if ($krole ne "" && $krole ne $killer->{role})
					{
						&doEvent_RoleSelection(
							$killer->{"userid"},
							$killer->{"uniqueid"},
							$krole
						);
					}
				} 
				if (defined($properties{victimclass})) {
					my $vrole = $properties{victimclass};
					if ($vrole ne "" && $vrole ne $victim->{role})
					{
						&doEvent_RoleSelection(
							$victim->{"userid"},
							$victim->{"uniqueid"},
							$vrole
						);
					}
				}
			} elsif ($g_servers{$s_addr}->{play_game} == TF()) {
				# Change weapon code for player_penetration to machina and log an action
				if ($weapon eq "player_penetration") {
					$weapon = "machina";
					&doEvent_PlayerAction(
						$killer->{userid},
						$killer->{uniqueid},
						"player_penetration",
						$x,
						$y,
						$z
					);
				}
			}
			
			# if plugin marked next kill as headshot for this player, headshot
			if ($g_servers{$s_addr}->{nextkillheadshot} == $killer->{playerid}) {
				$headshot = 1;
				$headshotFromAction = 1;
			}
			# reset nextkillheadshot flag at end of sub
			
			my $was_tk = &sameTeam($killer->{team}, $victim->{team});

			# This is a fix for TF2 - they report player death after reporting team switch
			# I don't know how soon after a team switch in other games that you can actually attempt to kill someone
			if((($was_tk == 1) && ($victim->{last_team_change}+2 > $ev_remotetime)) && ($g_servers{$s_addr}->{play_game} == TF())) {
				# print "NOT A TEAM KILL - RECENT TEAM SWITCH by " . $victim->{name} . "(Now:" . $ev_remotetime . ") Changed(" . $victim->{last_team_change} .")";
				$desc = "NOT A TEAM KILL - RECENT TEAM SWITCH";
				$was_tk=0;
			}
			if (($was_tk==0) || ($g_servers{$s_addr}->{game_type} == 1)) {
				# Frag
				
				if($isfake == 0) {
					#kill streak code by octo
					
					$killer->{"kills_per_life"}+=1;
					$victim->{"deaths_in_a_row"}+=1;	
					if ($victim->{"deaths_in_a_row"} > $victim->{"death_streak"}) {
						$victim->set("death_streak", $victim->{"deaths_in_a_row"});
					}

					# we don't need to update the killer's death_streak since it was done when he is a victim	
					$killer->{"deaths_in_a_row"} = 0;
					
					&endKillStreak($victim);

					&recordEvent(
						"Frags", 0,
						$killer->{playerid},
						$victim->{playerid},
						$weapon,
						$headshot,
						$killer->{role},
						$victim->{role},
						$x,
						$y,
						$z,
						$vx,
						$vy,
						$vz
					);

					if ($killer->{role} ne "") {
						my $query = "
							UPDATE
								hlstats_Roles
							SET
								kills=kills+1
							WHERE 
								game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
								AND code='" . &quoteSQL($killer->{role}) . "'
							";
						&execNonQuery($query);
					}

					if ($victim->{role} ne "") {
						my $query = "
							UPDATE
								hlstats_Roles
							SET
								deaths=deaths+1
							WHERE 
								game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
								AND code='" . &quoteSQL($victim->{role}) . "'
							";
						&execNonQuery($query);
					}

					$killer->increment("total_kills");
				} else {
					$desc = "FEIGN DEATH: ";
				}
				
				my $killerskill = $killer->{skill};
				my $victimskill = $victim->{skill};
				
				if ($g_servers{$s_addr}->{play_game} == L4D())
				{
					$killerskill = &calcL4DSkill(
						$killer->{skill}, 
						$weapon, 
						$g_servers{$s_addr}->{difficulty}
					);
				}
				else
				{
					($killerskill, $victimskill) = &calcSkill(
						$g_servers{$s_addr}->{"skill_mode"},
						$killer->{"skill"}, $killer->{"total_kills"},
						$victim->{"skill"}, $victim->{"total_kills"},
						$weapon,
						$killer->{team}
					);
				}
				
				$k_name    = $killer->{name};
				$k_skill   = $killerskill - $killer->{skill};
				$v_name    = $victim->{name};
				$v_skill   = $victimskill - $victim->{skill};
				
				if ($g_servers{$s_addr}->{broadcasting_events} == 1) {
					my $killer_add_text = "";
					if ($killer->{"total_kills"} < $g_player_minkills) {
						$killer_add_text = " [".$killer->{"total_kills"}."/".$g_player_minkills."]";
					}
					my $victim_add_text = "";
					if ($victim->{"total_kills"} < $g_player_minkills) {
						$victim_add_text = " [".$victim->{"total_kills"}."/".$g_player_minkills."]";
					}
					my $v_skill_text = "";
					if ($k_skill != ((-1) * $v_skill)) {
						$v_skill_text = " [".$v_skill."]";
					}
					my $k_userid  = $g_servers{$s_addr}->format_userid($killer->{"userid"});
					my $v_userid  = $g_servers{$s_addr}->format_userid($victim->{"userid"});
					my $colorparam = $g_servers{$s_addr}->{format_color};
					my $msg = "";
					if ($g_servers{$s_addr}->{play_game} == L4D()) {
						$msg = sprintf("%s (%s)%s got %s points for killing %s",$k_name,&number_format($killerskill),$killer_add_text,$k_skill,$v_name);
					} else {
						$msg = sprintf("%s (%s)%s got %s points%s for killing %s (%s)%s",$k_name,&number_format($killerskill),$killer_add_text,$k_skill,$v_skill_text,$v_name,&number_format($victimskill),$victim_add_text);
					}
					my @rcmds;
					if (($killer->{is_bot} == 0) && ($killer->{"display_events"} == 1) && ($killer->{userid} > 0)) {
						my $cmd_str = sprintf("%s %s%s %s",$rcmd,$k_userid,$colorparam,$g_servers{$s_addr}->quoteparam($msg));
						push(@rcmds, $cmd_str);
						if (($g_player_minkills > 20) && (($killer->{"total_kills"} < ($g_player_minkills / 4)) || (($killer->{"total_kills"} < $g_player_minkills) && (($killer->{"total_kills"} % 5) == 0)))) {
							my $cmd_str = sprintf("%s %s %s",$rcmd,$k_userid,$g_servers{$s_addr}->quoteparam("You need ".&number_format($g_player_minkills-$killer->{"total_kills"})." kills to get regular points"));
							push(@rcmds, $cmd_str);
							
						}
					}  
					if (($victim->{is_bot} == 0) && ($victim->{"display_events"} == 1) && ($g_servers{$s_addr}->{play_game} != L4D()) && ($victim->{userid} > 0) && $isfake == 0) {
						push(@rcmds, sprintf("%s %s%s %s",$rcmd,$v_userid,$colorparam,$g_servers{$s_addr}->quoteparam($msg)));
					}
					if (@rcmds) {
						$g_servers{$s_addr}->dorcon_multi(@rcmds);
					}
				}  
				if($isfake == 0) {
					$killer->set("skill", $killerskill);
					$victim->set("skill", $victimskill);
					
					$killer->increment("session_skill", $k_skill);
					$killer->increment("kills");
					$killer->increment("session_kills");
					$g_servers{$s_addr}->increment("kills");
					$g_servers{$s_addr}->increment("total_kills");
					
					$update_data = "kills=kills+1";
					
					if ($headshot == 1) {
						$killer->increment("headshots");
						$killer->increment("session_headshots");
						$g_servers{$s_addr}->increment("headshots");
						$g_servers{$s_addr}->increment("total_headshots");
						$update_data .= ", headshots=headshots+1";
						
						if ($headshotFromAction == 0) {
							&doEvent_PlayerAction(
									$killer->{"userid"},
									$killer->{"uniqueid"},
									"headshot"
							);
						}
					}
					$victim->increment("deaths");
					$victim->increment("session_deaths");
					$victim->increment("session_skill", $v_skill);

					my $query = "
						UPDATE
							hlstats_Weapons
						SET	
							$update_data 
						WHERE
							game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
							AND code='" . &quoteSQL($weapon) . "'
					";
					&execNonQuery($query);
					
					$query = "
						INSERT INTO hlstats_Maps_Counts (game, map, kills, headshots)
						VALUES ('".&quoteSQL($g_servers{$s_addr}->{game})."', '".&quoteSQL($g_servers{$s_addr}->get_map())."', 1, $headshot)
						ON DUPLICATE KEY UPDATE kills=kills+1".(($headshot)?", headshots=headshots+1":"");
					&execNonQuery($query);
					
					if ($g_servers{$s_addr}->{play_game} == L4D()) {
						if ($victim->{team} eq "Infected" && $victim->{role} ne "infected" && $victim->{role} ne "") {
								&doEvent_PlayerAction(
									$killer->{userid},
									$killer->{uniqueid},
									"killed_".lc($victim->{role}),
									$x,
									$y,
									$z
								);
						} elsif ($victim->{team} eq "Survivor") {
								&doEvent_PlayerPlayerAction(
									$killer->{"userid"},
									$killer->{"uniqueid"},
									$victim->{"userid"},
									$victim->{"uniqueid"},
									"killed_survivor",
									$x,
									$y,
									$z,
									$vx,
									$vy,
									$vz
								);
						}
					}
				}
			} else {
				# print "was TK";
				if ($weapon eq "dod_bomb_target") {
					$desc = "IGNORED BOMBED TEAMKILL DODS ";
					return $desc . $killerstr . " killed " . $victimstr . " with \"".$weapon."\"";
				}
		      
				# Teamkill
				&recordEvent(
					"Teamkills", 0,
					$killer->{playerid},
					$victim->{playerid},
					$weapon,
					$x,
					$y,
					$z,
					$vx,
					$vy,
					$vz
				);
				
				my $tk_penalty = (-1) * $g_servers{$s_addr}->{"tk_penalty"};

				$killer->increment("skill", $tk_penalty);
				$killer->increment("session_skill", $tk_penalty);
				$killer->increment('teamkills');

				$k_name = $killer->{name};
				$k_skill = $killer->{skill};
				
				if ($g_servers{$s_addr}->{broadcasting_events} == 1) {
					my $k_userid  = $g_servers{$s_addr}->format_userid($killer->{userid});
					my $v_userid  = $g_servers{$s_addr}->format_userid($victim->{userid});
					my $colorparam = $g_servers{$s_addr}->{format_color};
					my $msg = sprintf("%s lost %s points (%s) for team-killing",$k_name,$tk_penalty,&number_format($k_skill));
					
					my @rcmds;
					if (($killer->{is_bot} == 0) && ($killer->{display_events} == 1) && ($killer->{userid} > 0)) {
						my $cmd_str = sprintf("%s %s%s %s",$rcmd,$k_userid, $colorparam, $g_servers{$s_addr}->quoteparam($msg));
						push (@rcmds, $cmd_str);
					}
					if (($victim->{is_bot} == 0) && ($victim->{display_events} == 1) && ($victim->{userid} > 0)) {
						my $cmd_str = sprintf("%s %s%s %s",$rcmd,$v_userid, $colorparam, $g_servers{$s_addr}->quoteparam($msg));
						push (@rcmds, $cmd_str);
					}
					if (@rcmds) {
						$g_servers{$s_addr}->dorcon_multi(@rcmds);
					}					
				}

				$update_data = "kills=kills+1";
				if ($headshot == 1) {
					$update_data .= ", headshots=headshots+1";
				}
				my $query = "
					UPDATE
						hlstats_Weapons
					SET	
						$update_data 
					WHERE
						game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
						AND code='" . &quoteSQL($weapon) . "'
				";
				&execNonQuery($query);
				$desc = "TEAMKILL: ";
			}
		}
		if($isfake == 0) {
			$killer->increment("map_kills");
			if ($headshot == 1) {
				$killer->increment("map_headshots");
			}
			$killer->updateDB();
			$victim->increment("map_deaths");
			$victim->set("is_dead", "1");
			if ($victim->{auto_type} eq "kill") {
				&doEvent_Chat("say",
					$victim->{"userid"},
					$victim->{"uniqueid"},
					$victim->{auto_command}
				);
				$victim->updateDB();
			}
		}
	} else {
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}
	
	# reset next kill headshot flag
	$g_servers{$s_addr}->{nextkillheadshot} = 0;

	return $desc . $killerstr . " killed " . $victimstr . " with \"".$weapon."\"";
}



#
# 010. Player-Player Actions
#

sub doEvent_PlayerPlayerAction
{
	my ($playerId, $playerUniqueId, $victimId, $victimUniqueId, $action, $x, $y, $z, $vx, $vy, $vz, %properties) = @_;
	$rcmd = $g_servers{$s_addr}->{broadcasting_command};
	
	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $victim = lookupPlayer($s_addr, $victimId, $victimUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);
	my $victimstr = &getPlayerInfoString($victim, $victimId);
	if ($playerId == $victimId) {
		$desc = "(IGNORED) PLAYER SAME AS VICTIM: ";
	} elsif ($g_servers{$s_addr}->{num_trackable_players} < $g_servers{$s_addr}->{minplayers}) {
		$desc = "(IGNORED) NOTMINPLAYERS: ";
	} elsif (checkBonusRound()) {
		$desc = "(IGNORED) BonusRound: ";
	} elsif ($player && $victim) {
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && (($killer->{is_bot} == 1) || ($victim->{is_bot} == 1))) {
			$desc = "(IGNORED) BOT: ";
		} else {
			if ($g_servers{$s_addr}->{play_game} == TF() && $action eq "medic_death") {
				#do heal points
				
				if (defined($properties{ubercharge}) && $properties{ubercharge} == 1) {
					&doEvent_PlayerAction(
						$playerId,
						$playerUniqueId,
						"killed_charged_medic",
						$x,
						$y,
						$z
					);
					&doEvent_PlayerPlayerAction(
						$playerId,
						$playerUniqueId,
						$victimId,
						$victimUniqueId,
						"killed_charged_medic",
						$x,
						$y,
						$z,
						$vx,
						$vy,
						$vz
					);
				}
			}
			
			my $map = $g_servers{$s_addr}->get_map();
			if (defined($g_games{$g_servers{$s_addr}->{game}}{actions}{$map."_$action"}) && $g_games{$g_servers{$s_addr}->{game}}{actions}{$map."_$action"}{ppaction}) {
				&doEvent_PlayerPlayerAction(
						$playerId,
						$playerUniqueId,
						$victimId,
						$victimUniqueId,
						$map."_$action",
						$x,
						$y,
						$z,
						$vx,
						$vy,
						$vz
					);
			}
			if (defined($g_games{$g_servers{$s_addr}->{game}}{actions}{$action}) && $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{ppaction}) {
				my $actionname = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{descr};
				my $actionid = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{id};
				my $reward_player = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{reward_player};
				my $reward_team = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{reward_team};
				my $team = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{team};
				
				if (defined($properties{assister_position})) {
					$coords = $properties{assister_position};
					($x,$y,$z) = split(/ /,$coords);
				} elsif (defined($properties{position})) {
					$coords = $properties{position};
					($x,$y,$z) = split(/ /,$coords);
				} elsif (defined($properties{attacker_position})) {
					$coords = $properties{attacker_position};
					($x,$y,$z) = split(/ /,$coords);
				}
				
				if (defined($properties{victim_position})) {
					$coords = $properties{victim_position};
					($vx,$vy,$vz) = split(/ /,$coords);
				}
				
				&recordEvent(
					"PlayerPlayerActions", 0,
					$player->{playerid},
					$victim->{playerid},
					$actionid,
					$reward_player,
					$x,
					$y,
					$z,
					$vx,
					$vy,
					$vz
				);
				
				my $query = "
					UPDATE
						hlstats_Actions
					SET
						count=count+1 
					WHERE
						game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
						AND code = '".&quoteSQL($action)."'
				";
				&execNonQuery($query);
				if ($reward_player != 0) {
					my $victimreward = $reward_player * -1;
					$player->increment("skill", $reward_player, 1);
					$player->increment("session_skill", $reward_player, 1);
					$victim->increment("skill", $victimreward, 1);
					$victim->increment("session_skill", $victimreward, 1);
					
					if ($g_servers{$s_addr}->{broadcasting_events} == 1) {
						if ($g_servers{$s_addr}->{broadcasting_player_actions} == 1) {
							my $verb = "";
							if ($reward_player < 0) {
								$verb = "lost";
							} else {
								$verb = "got";
							}
							my $colorparam = $g_servers{$s_addr}->{format_color};
							my $coloraction = $g_servers{$s_addr}->{format_action};
							my $colorend = $g_servers{$s_addr}->{format_actionend};
							my $p_name    = $player->{name};
							my $p_skill   = $player->{skill};
							my $v_name    = $victim->{name};
							my $v_skill   = $victim->{skill};
							my $msg = sprintf("%s %s %s points (%s) for %s%s%s against %s (%s)",$p_name,$verb,abs($reward_player), &number_format($p_skill),$coloraction,$actionname,$colorend, $v_name, &number_format($v_skill));
							my @rcmds;
							if (($player->{is_bot} == 0) && ($player->{display_events} == 1) && ($player->{userid} > 0)) {
								my $p_userid  = $g_servers{$s_addr}->format_userid($player->{userid});
								my $cmd_str = sprintf("%s %s%s %s",$rcmd,$p_userid,$colorparam,$g_servers{$s_addr}->quoteparam($msg));
								push(@rcmds, $cmd_str);
							}
							if (($victim->{is_bot} == 0) && ($victim->{display_events} == 1) && ($victim->{userid} > 0)) {
								my $v_userid  = $g_servers{$s_addr}->format_userid($victim->{userid});
								my $cmd_str = sprintf("%s %s%s %s",$rcmd,$v_userid,$colorparam,$g_servers{$s_addr}->quoteparam($msg));
								push(@rcmds, $cmd_str);
							}
							if (@rcmds) {
								$g_servers{$s_addr}->dorcon_multi(@rcmds);
							}
						}
					}
				}
				if ($team && $reward_team != 0) {
					&rewardTeam($team, $reward_team, $actionid, $actionname, $action);
				}
				
			} else {
				$desc = "(IGNORED) ";
			}
		}
	} else {
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}

	return $desc . $playerstr . " triggered \"".$action."\" against " . $victimstr;
}


#
# E011. Player Objectives/Actions
#

sub doEvent_PlayerAction
{
	$rcmd = $g_servers{$s_addr}->{broadcasting_command};
	my ($playerId, $playerUniqueId, $action, $x, $y, $z, %properties) = @_;	
	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);
	
	if ($g_servers{$s_addr}->{num_trackable_players} < $g_servers{$s_addr}->{minplayers}) {
		$desc = "(IGNORED) NOTMINPLAYERS: ";
	} elsif (checkBonusRound()) {
		$desc = "(IGNORED) BonusRound: ";
	} elsif ($player) {
		if ($action eq "kill assist") {
			if ($player->{"role"} eq "medic") {
				$action = "kill_assist_medic";
			}
		}
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($player->{is_bot} == 1)) {
			$desc = "(IGNORED) BOT: ";
			if ($action eq "Got_The_Bomb") {
				$player->set("has_bomb", "1", 1);
			} elsif ($action eq "Dropped_The_Bomb") {
				$player->set("has_bomb", "0", 1);
			}
			$player->updateDB();
		} else {
			if ($g_servers{$s_addr}->{play_game} == TF())
			{
				my $objectstring = "";
				if (defined($properties{object})) {
					$objectstring = "_".lc($properties{object});
					$objectstring =~ s/\s/_/g;
				}
				my $eventstring = "";
				if (defined($properties{event})) {
					$eventstring = "_".lc($properties{event});
					$eventstring =~ s/\s/_/g;
				}
				my $ownerstring = "";
				if (defined($properties{objectowner})) {
					my $owner = $properties{objectowner};
					$owner =~ /.+?<STEAM_[0-9]+:([0-9]+:[0-9]+)>.*/;
					$owner = $1;
					if ($owner eq $player->{uniqueid}) {
						$ownerstring = "owner_";
					}
				}
				$action = $ownerstring.$action.$objectstring.$eventstring;
				
				if ($action eq "builtobject_obj_sentrygun")
				{
					$player->{last_sg_build}=$ev_remotetime;
				}
				elsif ($action eq "builtobject_obj_dispenser")
				{
					$player->{last_disp_build}=$ev_remotetime;
				}
				elsif ($action eq "builtobject_obj_teleporter_entrance")
				{
					$player->{last_entrance_build}=$ev_remotetime;
				}
				elsif ($action eq "builtobject_obj_teleporter_exit")
				{
					$player->{last_exit_build}=$ev_remotetime;
				}
				elsif ($action eq "flagevent_defended")
				{
					if ($player->{team} eq "Red") {
						$g_servers{$s_addr}->{lastredflagdefend} = $ev_remotetime;
					} else {
						$g_servers{$s_addr}->{lastblueflagdefend} = $ev_remotetime;
					}
				}
				elsif ($action eq "flagevent_dropped")
				{
					if ($player->{team} eq "Red" && ($ev_remotetime - $g_servers{$s_addr}->{lastblueflagdefend}) <= 1) {
						$g_servers{$s_addr}->{lastblueflagdefend} = 0;
						$action="flagevent_dropped_death";
					} elsif ($player->{team} eq "Blue" && ($ev_remotetime - $g_servers{$s_addr}->{lastredflagdefend}) <= 1) {
						$g_servers{$s_addr}->{lastredflagdefend} = 0;
						$action="flagevent_dropped_death";
					}
				}
				elsif ($action eq "player_extinguished")
				{
					$action = $player->{role}."_extinguish";
				}
				else
				{
					if (($action eq "owner_killedobject_obj_sentrygun" && ($ev_remotetime - $player->{last_sg_build}) > 120) ||
						($action eq "owner_killedobject_obj_dispenser" && ($ev_remotetime - $player->{last_disp_build}) > 120) ||
						($action eq "owner_killedobject_obj_teleporter_entrance" && ($ev_remotetime - $player->{last_entrance_build}) > 120) ||
						($action eq "owner_killedobject_obj_teleporter_exit" && ($ev_remotetime - $player->{last_exit_build}) > 120))
					{
						return "(IGNORED) OBJECT MOVED: $playerstr triggered \"$action\"";
					}
				}
			}
			elsif ($g_servers{$s_addr}->{play_game} == TFC())
			{
				if ($action eq "Sentry_Built_Level_1")
				{
					$player->{last_sg_build}=$ev_remotetime;
				}
				elsif ($action eq "Built_Dispenser")
				{
					$player->{last_disp_build}=$ev_remotetime;
				}
				elsif ($action eq "Teleporter_Entrance_Finished")
				{
					$player->{last_entrance_build}=$ev_remotetime;
				}
				elsif ($action eq "Teleporter_Exit_Finished")
				{
					$player->{last_exit_build}=$ev_remotetime;
				}
				else
				{
					if (($action eq "Sentry_Dismantle" && ($ev_remotetime - $player->{last_sg_build}) > 120) ||
						($action eq "Dispenser_Dismantle" && ($ev_remotetime - $player->{last_disp_build}) > 120) ||
						($action eq "Teleporter_Entrance_Dismantle" && ($ev_remotetime - $player->{last_entrance_build}) > 120) ||
						($action eq "Teleporter_Exit_Dismantle" && ($ev_remotetime - $player->{last_exit_build}) > 120))
					{
						return "(IGNORED) OBJECT MOVED: " . $playerstr . " triggered \"$action\"";
					}
				}
			}
			elsif ($g_servers{$s_addr}->{play_game} == FF())
			{
				if ($action eq "build_sentrygun")
				{
					$player->{last_sg_build}=$ev_remotetime;
				}
				elsif ($action eq "build_dispenser")
				{
					$player->{last_disp_build}=$ev_remotetime;
				}
				else
				{
					if (($action eq "sentry_dismantled" && ($ev_remotetime - $player->{last_sg_build}) > 120) ||
						($action eq "dispenser_dismantled" && ($ev_remotetime - $player->{last_disp_build}) > 120))
					{
						return "(IGNORED) OBJECT MOVED: " . $playerstr . " triggered \"$action\"";
					}
				}
			}
			elsif ($g_servers{$s_addr}->{play_game} == NS())
			{
				my $typestring = "";
				if (defined($properties{type})) {
					$typestring = "_".lc($properties{type});
					$typestring =~ s/\s/_/g;
				}
				$action .= $typestring;
			}
			
			if (defined($properties{position})) {
				$coords = $properties{position};
				($x,$y,$z) = split(/ /,$coords);
			} elsif (defined($properties{assister_position})) {
				$coords = $properties{assister_position};
				($x,$y,$z) = split(/ /,$coords);
			} elsif (defined($properties{attacker_position})) {
				$coords = $properties{attacker_position};
				($x,$y,$z) = split(/ /,$coords);
			}
			if ($action eq "headshot") {
				$g_servers{$s_addr}->{nextkillheadshot} = $player->{playerid}
			}

			my $map = $g_servers{$s_addr}->get_map();
			if (defined($g_games{$g_servers{$s_addr}->{game}}{actions}{$map."_$action"}) && $g_games{$g_servers{$s_addr}->{game}}{actions}{$map."_$action"}{paction}) {
				&doEvent_PlayerAction(
						$playerId,
						$playerUniqueId,
						$map."_$action",
						$x,
						$y,
						$z
					);
			}
			if (defined($g_games{$g_servers{$s_addr}->{game}}{actions}{$action}) && $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{paction}) {
				my $actionname = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{descr};
				my $actionid = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{id};
				my $reward_player = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{reward_player};
				my $reward_team = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{reward_team};
				my $team = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{team};
				
				&recordEvent(
					"PlayerActions", 0,
					$player->{playerid},
					$actionid,
					$reward_player,
					$x,
					$y,
					$z
				);
				my $query = "
					UPDATE
						hlstats_Actions
					SET	
						count=count+1 
					WHERE
						game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
						AND code = '".&quoteSQL($action)."'
				";
				&execNonQuery($query);
				$player->increment("skill", $reward_player);
				$player->increment("session_skill", $reward_player);
				$p_name = $player->{name};
				$p_skill = $player->{skill};
				
				
				if (($g_servers{$s_addr}->{broadcasting_events} == 1) && ($reward_player != 0)) {
					if ($g_servers{$s_addr}->{broadcasting_player_actions} == 1) {
						my $p_userid  = $g_servers{$s_addr}->format_userid($player->{userid});
						if (($player->{is_bot} == 0) && ($player->{display_events} == 1) && ($player->{userid} > 0)) {
							my $colorparam = $g_servers{$s_addr}->{format_color};
							my $coloraction = $g_servers{$s_addr}->{format_action};
							if ($reward_player !=0) {
								my $verb = "got";
								if ($reward_player < 0) {
									$verb = "lost";
								}
								my $msg = sprintf("%s %s %s points (%s) for %s%s", $p_name, $verb, abs($reward_player),&number_format($p_skill),$coloraction,$actionname);
								my $cmd_str = sprintf("%s %s%s %s",$rcmd,$p_userid,$colorparam,$g_servers{$s_addr}->quoteparam($msg));
								$g_servers{$s_addr}->dorcon($cmd_str);
							}
						}
					}
				} 
				if ($action eq "Got_The_Bomb") {
					$player->set("has_bomb", "1", 1);
				} elsif ($action eq "Dropped_The_Bomb") {
					$player->set("has_bomb", "0", 1);
				}
				$player->updateDB();
				
				if ($reward_team != 0 && $action ne "pointcaptured") {
					if (!$team) {
						$team = $player->{team};
					}
					# print "Reward Team ($team) giving ($reward_team) for $actionname\n";
					&rewardTeam($team, $reward_team, $actionid, $actionname, $action);
				}
			} else {
				$desc = "(IGNORED) ";
			}
		}
	} else {
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}
	
	return $desc . $playerstr . " triggered \"$action\"";
}


#
# 012. Team Objectives/Actions
#

sub doEvent_TeamAction
{
	$rcmd = $g_servers{$s_addr}->{broadcasting_command};
	my ($team, $action) = @_;
	my $desc;
	if ($g_servers{$s_addr}->{num_trackable_players} < $g_servers{$s_addr}->{minplayers}) {
		$desc = "(IGNORED) NOTMINPLAYERS: ";

# Team events, such as Round_Win can still occur during Bonus Round		
#	} elsif (checkBonusRound()) {
#		$desc = "(IGNORED) BonusRound: ";

	} else {
		my $map = $g_servers{$s_addr}->get_map();
		if ((defined($g_games{$g_servers{$s_addr}->{game}}{actions}{$action}) && $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{taction}) || (defined($g_games{$g_servers{$s_addr}->{game}}{actions}{$map."_$action"}) && $g_games{$g_servers{$s_addr}->{game}}{actions}{$map."_$action"}{taction})) {
			my $actionname = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{descr};
			my $actionid = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{id};
			my $reward_team = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{reward_team};
			my $actionteam = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{team};
			if ($actionteam eq "") {
				$actionteam = $team;
			}
			#print "T: ".$actionid." - ".$actionname." - ".$actionteam." - ".$reward_player." - ".$reward_team." - ".$team."\n";
			my $query = "
				UPDATE
					hlstats_Actions
				SET	
					count=count+1 
				WHERE
					game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
					AND code IN ('" . &quoteSQL($g_servers{$s_addr}->get_map() . "_$action") . "', '" . &quoteSQL($action) . "')
			";
			&execNonQuery($query);
			
			if ($g_servers{$s_addr}->{round_status} == 0) {
				if ($reward_team != 0) {
					&rewardTeam($actionteam, $reward_team, $actionid, $actionname, $action);
				}
			}
		} else {
			$desc = "(IGNORED) ";
		}
	}
	if ($g_servers{$s_addr}->{round_status} == 0) {
		if (($action eq "CTs_Win")  || ($action eq "Bomb_Defused")) {
			$g_servers{$s_addr}->increment("round_status");
			$g_servers{$s_addr}->increment("ct_wins");
			$g_servers{$s_addr}->increment("map_ct_wins");
			$g_servers{$s_addr}->add_round_winner("ct");
			if ($action eq "Bomb_Defused") {
				$g_servers{$s_addr}->increment("bombs_defused");
			}  
		} elsif (($action eq "Terrorists_Win") || ($action eq "Target_Bombed")) {
			$g_servers{$s_addr}->increment("round_status");
			$g_servers{$s_addr}->increment("ts_wins");
			$g_servers{$s_addr}->increment("map_ts_wins");
			$g_servers{$s_addr}->add_round_winner("ts");
			if ($action eq "Target_Bombed") {
				$g_servers{$s_addr}->increment("bombs_planted");
			}  
		}
	}
	$g_servers{$s_addr}->updateDB();
	return $desc . "Team \"$team\" triggered \"$action\"";
}

#
# 013. World Objectives/Actions
#

sub doEvent_WorldAction
{
	my $rcmd = $g_servers{$s_addr}->{broadcasting_command};
	my ($action) = @_;
	my $desc;
	my $act_players = $g_servers{$s_addr}->{num_trackable_players};
	my $min_players = $g_servers{$s_addr}->{minplayers};
	
	if ($act_players < $min_players) {
		$desc = "(IGNORED) NOTMINPLAYERS: ";
		if ($action eq "Round_Start") {
			$g_servers{$s_addr}->messageAll(sprintf("HLstatsX:CE disabled! Need at least %s active players (%s/%s)", $min_players, $act_players, $min_players),0,1);
		}
	} else {
		my $map = $g_servers{$s_addr}->get_map();
		if ((defined($g_games{$g_servers{$s_addr}->{game}}{actions}{$action}) && $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{waction}) || (defined($g_games{$g_servers{$s_addr}->{game}}{actions}{$map."_$action"}) && $g_games{$g_servers{$s_addr}->{game}}{actions}{$map."_$action"}{waction})) {
			my $actionname = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{descr};
			my $actionid = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{id};
			my $reward_team = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{reward_team};
			my $team = $g_games{$g_servers{$s_addr}->{game}}{actions}{$action}{team};
			my $query = "
				UPDATE
					hlstats_Actions
				SET	
					count=count+1 
				WHERE
					game='" . &quoteSQL($g_servers{$s_addr}->{game}) . "'
					AND code IN ('".&quoteSQL($map."_$action")."', '".&quoteSQL($action)."')
			";
			&execNonQuery($query);
			if ($team && $reward_team != 0) {
				&rewardTeam($team, $reward_team, $actionid, $actionname);
			}
		} else {
			$desc = "(IGNORED) ";
		}
	}
	if ($action eq "Round_End" || $action eq "Round_Win" || $action eq "Mini_Round_Win") {
		if ($action eq "Round_End") {
			$g_servers{$s_addr}->analyze_teams();
		}
		
		if (($g_servers{$s_addr}->{lastdisabledbonus}+5) < $ev_remotetime && $g_servers{$s_addr}->{bonusroundignore} > 0) {
			$g_servers{$s_addr}->set("bonusroundtime_ts", $ev_remotetime);
			$g_servers{$s_addr}->set("lastdisabledbonus", $ev_remotetime);
			$g_servers{$s_addr}->set("bonusroundtime_state", 1);
			if ($act_players >= $min_players) {
				$g_servers{$s_addr}->messageAll("Round Over - All actions/frags are ignored by HLstatsX:CE until the next round starts",0,1);
			}
		}

		while (my($pl, $player) = each(%g_players) ) {
			if ($player->{connect_time} == 0) {
				$player->set("connect_time", time());
			}
		
			&endKillStreak($player);
			
			if ($player->{auto_type} eq "end") {
				&doEvent_Chat("say",
					$player->{"userid"},
					$player->{"uniqueid"},
					$player->{auto_command}
				);
			}
			$player->updateDB();
		}
	} 

	
	if ($action eq "Round_Start" || $action eq "Mini_Round_Start") {
		$g_servers{$s_addr}->set("bonusroundtime_state", 0);
		if ($action eq "Round_Start") {
			$g_servers{$s_addr}->set("round_status", 0);
			$g_servers{$s_addr}->set("ba_player_switch", 0);
		}
		
		while (my($pl, $player) = each(%g_players) )
		{
			if ($player->{connect_time} == 0) {
				$player->set("connect_time", time());
			}  
			if ($action eq "Round_Start") {
				$player->set("is_dead", "0", 1);
				if ($player->{auto_type} eq "start") {
					&doEvent_Chat("say",
						$player->{"userid"},
						$player->{"uniqueid"},
						$player->{auto_command}
					);
				}
			}
			$player->updateDB();
		}
	}
	if ($action eq "Game_Commencing") {
		$g_servers{$s_addr}->set("round_status", 0);
		$g_servers{$s_addr}->set("map_started", time());
		$g_servers{$s_addr}->set("map_rounds", 0);
		$g_servers{$s_addr}->set("map_ct_wins", 0);
		$g_servers{$s_addr}->set("map_ts_wins", 0);
	}
	$g_servers{$s_addr}->updateDB();
	return $desc . "World triggered \"$action\" ($act_players/$min_players)";
}


#
# E014. Chat
#

sub doEvent_Chat
{
	my ($msg_type, $playerId, $playerUniqueId, $message) = @_;
	$rcmd = $g_servers{$s_addr}->{player_command};
	
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);
	
	if (($player) && ($player->{is_bot} == 0)) {
		$player->updateDB();
		my $p_userid = $g_servers{$s_addr}->format_userid($player->{userid});
		my $messagelen = length($message);
		
		if ($g_global_chat > 0 || $g_log_chat > 0) {
			$hlx_command = 0;
			my $cmd = $message;
			if (($cmd =~ /^\/?skill$/i) || ($cmd =~ /^\/?rank$/i) || ($cmd =~ /^\/?points$/i) || ($cmd =~ /^\/?place$/i) ||
				($cmd =~ /^\/?kdratio$/i) || ($cmd =~ /^\/?kdeath$/i) || ($cmd =~ /^\/?kpd$/i) ||
				($cmd =~ /^\/?session$/i) || ($cmd =~ /^\/?session_data$/i) ||
				($cmd =~ /^\/?top\d{1,2}?$/i) ||
				($cmd =~ /^\/?statsme$/i) ||
				($cmd =~ /^\/?next$/i) ||
				($cmd =~ /^\/?knife$/i) || ($cmd =~ /^\/?usp$/i)       || ($cmd =~ /^\/?glock$/i)     || ($cmd =~ /^\/?deagle$/i)  || 
				($cmd =~ /^\/?p228$/i)  || ($cmd =~ /^\/?m3$/i)        || ($cmd =~ /^\/?xm1014$/i)    || ($cmd =~ /^\/?mp5navy$/i)     ||
				($cmd =~ /^\/?tmp$/i)   || ($cmd =~ /^\/?p90$/i)       || ($cmd =~ /^\/?m4a1$/i)      || ($cmd =~ /^\/?ak47$/i)    ||
				($cmd =~ /^\/?sg552$/i) || ($cmd =~ /^\/?scout$/i)     || ($cmd =~ /^\/?awp$/i)       || ($cmd =~ /^\/?g3sg1$/i)   ||
				($cmd =~ /^\/?m249$/i)  || ($cmd =~ /^\/?hegrenade$/i) || ($cmd =~ /^\/?flashbang$/i) || ($cmd =~ /^\/?elite$/i)   ||
				($cmd =~ /^\/?aug$/i)   || ($cmd =~ /^\/?mac10$/i)     || ($cmd =~ /^\/?fiveseven$/i) || ($cmd =~ /^\/?ump45$/i)   ||
				($cmd =~ /^\/?sg550$/i) || ($cmd =~ /^\/?famas$/i)     || ($cmd =~ /^\/?galil$/i) ||
				($cmd =~ /^\/?maps$/i) || ($cmd =~ /^\/?map_stats$/i) || ($cmd =~ /^\/?map$/i) ||
				($cmd =~ /^\/?kill$/i) || ($cmd =~ /^\/?kills$/i) || ($cmd =~ /^\/?player_kills$/i) ||
				($cmd =~ /^\/?weapon$/i) || ($cmd =~ /^\/?weapons$/i) || ($cmd =~ /^\/?weapon_usage$/i) ||
				($cmd =~ /^\/?action$/i) || ($cmd =~ /^\/?actions$/i) || ($cmd =~ /^\/?hlx_menu$/i) ||
				($cmd =~ /^\/?status$/i) || ($cmd =~ /^\/?load$/i) || ($cmd =~ /^\/?pro$/i) || ($cmd =~ /^\/?servers$/i) ||
				($cmd =~ /^\/?clans$/i) || ($cmd =~ /^\/?cheaters$/i) || ($cmd =~ /^\/?bans$/i) || ($cmd =~ /^\/?statsme$/i) ||
				($cmd =~ /^\/?help$/i) || ($cmd =~ /^\/?timeleft$/i) || ($cmd =~ /^\/?nextmap$/i) || ($cmd =~ /^\/?thetime$/i) ||
				($cmd =~ /^\/?hlx_display/i) || ($cmd =~ /^\/?hlx_teams/i) || 
				($cmd =~ /^\/?hlx_set/i) || ($cmd =~ /^\/?hlx_chat/i) || ($cmd =~ /^\/?hlx_auto/i)) {
				
				$hlx_command++;
			}

			if (($messagelen > 3) && ($messagelen < 15)) { # filter buy scripts

				if (($cmd =~ /ak47/i) || ($cmd =~ /ak/i) || ($cmd =~ /m4/i) || ($cmd =~ /m4a1/i) ||
					($cmd =~ /deagle/i) || ($cmd =~ /famas/i) || ($cmd =~ /galil/i) ||
					($cmd =~ /scout/i) || ($cmd =~ /awp/i) || ($cmd =~ /awm/i) ||
					($cmd =~ /aug/i) || ($cmd =~ /m249/i) || ($cmd =~ /para/i) ||
					($cmd =~ /sig/i) || ($cmd =~ /tmp/i) || ($cmd =~ /ak47/i) ||
					($cmd =~ /grenade/i) || ($cmd =~ /usp/i) || ($cmd =~ /glock/i)) {
					
					$hlx_command++;
				}
			}

			if ($g_log_chat > 0) {
				my $log = 1;
				if ($g_log_chat_admins == 0)  {
					my $steamid      = $player->{uniqueid};
					if ($g_servers{$s_addr}->is_admin($steamid) == 1) {
						$log = 0;
					}
				}
				
				if (($hlx_command == 0) && ($log == 1)) {
					my $saytype = 1;
					if ($msg_type eq "say_team") {
						$saytype = 2;
					} elsif ($msg_type eq "say_squad") {
						$saytype = 3;
					}
					&recordEvent(
						"Chat", 
						0,
						$player->{playerid},
						$saytype,
						$message
					);
				}
			}

			if (($g_global_chat > 0) && ($hlx_command == 0)) {
				my $p_name    = $player->{name};
				my $dead = "";
				if ($player->{is_dead} == 1) {
					$dead = "*DEAD* ";
				}
				my $b_message = $dead.$p_name." (".$g_servers{$s_addr}->{name}."): ".$message;
				send_global_chat($b_message);
			}
		}

		if ($message =~ /^\/?hlx_set ([^ ]+) (.+)$/i) {
			my $set_field = lc($1);
			my $set_value = $2;
			
			if ($set_field eq "name" || $set_field eq "realname") {
				&updatePlayerProfile($player, "fullName", $set_value);
			} elsif ($set_field eq "email" || $set_field eq "e-mail") {
				&updatePlayerProfile($player, "email", $set_value);
			} elsif ($set_field eq "homepage" || $set_field eq "url") {
				&updatePlayerProfile($player, "homepage", $set_value);
			} elsif ($set_field eq "icq" || $set_field eq "uin") {
				&updatePlayerProfile($player, "icq", $set_value);
			} elsif ($set_field eq "geo") {
				# string parsen aus $set_value
				my $flag = substr($set_value,0,2);
				my $cstr = substr($set_value,3,200);
				$cstr =~ /\'([^\']+)\' /;
				my $city = $1;
				$cstr = substr($set_value,index($set_value,"'",4)+1,200);
				$cstr =~ /([^ ]+) ([^ ]+)/;
				my $lat  = $1;
				my $lng  = $2;
				my $region = "";
			}
		} elsif ($message =~ /^\/?hlx_hideranking$/i) {
			my $result = &doQuery("
				SELECT
					hideranking
				FROM
					hlstats_Players
				WHERE
					playerId = " . $player->{playerid}
			);
			my ($hideranking) = $result->fetchrow_array;
			$result->finish;
			
			my $hidedesc = "";
			
			if ($hideranking == 0) {
				$hideranking = 1;
				$hidedesc = "HIDDEN from";
			} else {
				$hideranking = 0;
				$hidedesc = "VISIBLE on";
			}
			my $playerName = &abbreviate($player->{name});
			&execNonQuery("
				UPDATE
					hlstats_Players
				SET
					hideranking='$hideranking'
				WHERE
					playerId=" . $player->{playerid}
			);
			
			if ($player->{display_events} == 1) {
				$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam("'$playerName' is now $hidedesc the rankings");
			}  
			$g_servers{$s_addr}->dorcon($cmd_str);
		}
		
		if (($message =~ /^\/?hlx_auto ([^ ]+) ([^ ]+)$/i) || ($message =~ /^\/?hlx_auto_cmd ([^ ]+) ([^ ]+)$/i)) {
			my $type = lc($1);
			my $cmd  = lc($2);
			
			if (($type =~ /^start$/i) || ($type =~ /^end$/i) || ($type =~ /^kill$/i)) {
				$time = 0;
				if (($cmd =~ /^\/?skill$/i) || ($cmd =~ /^\/?rank$/i) || ($cmd =~ /^\/?points$/i) || ($cmd =~ /^\/?place$/i) ||
					($cmd =~ /^\/?kdratio$/i) || ($cmd =~ /^\/?kdeath$/i) || ($cmd =~ /^\/?kpd$/i) ||
					($cmd =~ /^\/?session$/i) || ($cmd =~ /^\/?session_data$/i) ||
					($cmd =~ /^\/?top\d{1,2}?$/i) ||
					($cmd =~ /^\/?statsme$/i) ||
					($cmd =~ /^\/?next$/i) ||
					($cmd =~ /^\/?knife$/i) || ($cmd =~ /^\/?usp$/i)       || ($cmd =~ /^\/?glock$/i)     || ($cmd =~ /^\/?deagle$/i)  || 
					($cmd =~ /^\/?p228$/i)  || ($cmd =~ /^\/?m3$/i)        || ($cmd =~ /^\/?xm1014$/i)    || ($cmd =~ /^\/?mp5navy$/i)     ||
					($cmd =~ /^\/?tmp$/i)   || ($cmd =~ /^\/?p90$/i)       || ($cmd =~ /^\/?m4a1$/i)      || ($cmd =~ /^\/?ak47$/i)    ||
					($cmd =~ /^\/?sg552$/i) || ($cmd =~ /^\/?scout$/i)     || ($cmd =~ /^\/?awp$/i)       || ($cmd =~ /^\/?g3sg1$/i)   ||
					($cmd =~ /^\/?m249$/i)  || ($cmd =~ /^\/?hegrenade$/i) || ($cmd =~ /^\/?flashbang$/i) || ($cmd =~ /^\/?elite$/i)   ||
					($cmd =~ /^\/?aug$/i)   || ($cmd =~ /^\/?mac10$/i)     || ($cmd =~ /^\/?fiveseven$/i) || ($cmd =~ /^\/?ump45$/i)   ||
					($cmd =~ /^\/?sg550$/i) || ($cmd =~ /^\/?famas$/i)     || ($cmd =~ /^\/?galil$/i) ||
					($cmd =~ /^\/?maps$/i) || ($cmd =~ /^\/?map_stats$/i) || ($cmd =~ /^\/?map$/i) ||
					($cmd =~ /^\/?kill$/i) || ($cmd =~ /^\/?kills$/i) || ($cmd =~ /^\/?player_kills$/i) ||
					($cmd =~ /^\/?weapon$/i) || ($cmd =~ /^\/?weapons$/i) || ($cmd =~ /^\/?weapon_usage$/i) ||
					($cmd =~ /^\/?action$/i) || ($cmd =~ /^\/?actions$/i)) {
					
					$player->{"auto_type"}       = $type;
					$player->{"auto_command"}    = $cmd;
					$player->{"auto_time"}       = $time;
					$player->{"auto_time_count"} = 0;

					if ($player->{display_events} == 1) {
						$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam("Set auto command to ".$player->{"auto_command"}." on ".$player->{"auto_type"}."!");
					}  
					$g_servers{$s_addr}->dorcon($cmd_str);
				}
			}
		}
		if ($message =~ /^\/?hlx_auto clear$/i) {
			$player->{"auto_type"}    = "";
			$player->{"auto_command"} = "";

			if ($player->{display_events} == 1) {
				$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam("Auto command is disabled!");
			}  
			$g_servers{$s_addr}->dorcon($cmd_str);
		}

		### Begin switching team balance
		elsif ($message =~ /^\/?hlx_teams([ ][0-9])?$/i) {
			my $steamid  = $player->{uniqueid};
			my $mode = -1;
			if (($1 eq " 0") || ($1 eq " 1")) {
				$mode = substr($1, 1, length($1)-1);
			}
			if (($mode > -1) && ($g_servers{$s_addr}->is_admin($steamid) == 1)) {
				if ($mode == 0) {
					$g_servers{$s_addr}->set("ba_enabled", 0);
					$admin_msg = "AUTO-TEAM BALANCER disabled";
					if ($g_servers{$s_addr}->{player_admin_command} ne "")  {
						$cmd_str = $g_servers{$s_addr}->{player_admin_command}." ".$g_servers{$s_addr}->quoteparam($admin_msg);
					} else {
						if ($player->{display_events} == 1) {
							$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam($admin_msg);
						}
					}
					$g_servers{$s_addr}->dorcon($cmd_str);
				} elsif ($mode == 1)  {
					$g_servers{$s_addr}->set("ba_enabled", 1);
					$admin_msg = "AUTO-TEAM BALANCER enabled";
					if ($g_servers{$s_addr}->{player_admin_command} ne "") {
						$cmd_str = $g_servers{$s_addr}->{player_admin_command}." ".$g_servers{$s_addr}->quoteparam($admin_msg);
					} else {
						if ($player->{display_events} == 1) {
							$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam($admin_msg);
						}
					}
					$g_servers{$s_addr}->dorcon($cmd_str);
				}
			}
		}

		### Disabling hlx output
		elsif ($message =~ /^\/?hlx_display\s?([01])$/i) {
			my $mode = 0;
			$mode = $1;
			
			if ($mode == 0) {
				$msg = "All console events are disabled!";
			} else {
				$msg = "All console events are enabled!";
			}
			$player->set("display_events", $mode);
			&updatePlayerProfile($player, "displayEvents", $mode);
			$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam($msg);
			$g_servers{$s_addr}->dorcon($cmd_str);
		}

		### Disabling hlx global chat output
		elsif ($message =~ /^\/?hlx_chat\s?([01])$/i) {
			my $mode = 0;
			$mode = $1;
			
			if ($mode == 0) {
				$msg = "Global chat output is disabled!";
			} else {
				$msg = "Global chat output is enabled!";
			}
			$player->set("display_chat", $mode);
			$cmd_str = $rcmd." $p_userid ".$g_servers{$s_addr}->quoteparam($msg);
			$g_servers{$s_addr}->dorcon($cmd_str);
		}

		### Skill Addon
		elsif (($message =~ /^\/?skill([ ][0-9]+)?$/i) || ($message =~ /^\/?rank([ ][0-9]+)?$/i) || ($message =~ /^\/?points([ ][0-9]+)?$/i) || ($message =~ /^\/?place([ ][0-9]+)?$/i)) {
			my $error = 0;
			if ($1 ne "") {
				$userid   = substr($1, 1, length($1)-1);
				my $found = 0;
				while (my($pl, $s_player) = each(%g_players) ) {
					if ($userid == $s_player->{userid}) {
						$player = $s_player;
						$found++;
					}
				}
				if ($found == 0) {
					$error++;
				}
			}
			my $playerName = $player->{name};
			my ($skill, $ranknumber, $totalplayers) = get_player_rank($player);
			if ($ranknumber==0) {
				$ranknumber = "(HIDDEN)";
			}

			if ($error == 0) {
				if ($message !~ /^\/?place([ ][0-9]+)?$/i) {
					$rcmd = $g_servers{$s_addr}->{player_command_osd};
					
					if ($rcmd ne "") {
						my ($skill, $kills, $deaths, $kd, $suicides, $headshots, $hpk, $acc, $connection_time, $fav_weapon, $fav_weapon_kills, $fav_weapon_acc, $s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_acc) = get_player_data($player, 0);
						my $osd_string = get_menu_text($player, $skill, $kills, $deaths, $kd, $suicides, $headshots, $hpk, $acc, $connection_time, $fav_weapon, $fav_weapon_kills, $fav_weapon_acc, $s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_acc, $ranknumber, $totalplayers);
						$cmd_str = sprintf("%s \"15\" %s %s", $rcmd, $p_userid, $g_servers{$s_addr}->quoteparam($osd_string));
					} else {
						$rcmd = $g_servers{$s_addr}->{player_command};
						my $msg = "";
						if ($g_ranktype eq "kills") {
							my $kills = $player->{total_kills};
							$msg = sprintf("%s is on rank %d of %d with %d kills!", $playerName, $ranknumber, $totalplayers, $kills);
						} else {
							$msg = sprintf("%s is on rank %d of %d with %d points!", $playerName, $ranknumber, $totalplayers, $skill);
						}
						$cmd_str = sprintf("%s %s %s", $rcmd, $p_userid, $g_servers{$s_addr}->quoteparam($msg));
					}  
				} elsif ($g_servers{$s_addr}->{"public_commands"} == 1) {
					if ($g_ranktype eq "kills") {
						my $kills = $player->{total_kills};
						$cmd_str = "";
						$g_servers{$s_addr}->messageAll(sprintf("%s is on rank %d of %d with %d kills!", $playerName, $ranknumber, $totalplayers, $kills));
					} else {
						$cmd_str = "";
						$g_servers{$s_addr}->messageAll(sprintf("%s is on rank %d of %d with %d points!", $playerName, $ranknumber, $totalplayers, $skill));
					}
				}
			} else {
				$rcmd = $g_servers{$s_addr}->{player_command};
				if ($player->{display_events} == 1) {
					$cmd_str = "$rcmd $p_userid ".$g_servers{$s_addr}->quoteparam("No player found with this userid. Type status in console to get players userid!");
				}  
			}
			if ($cmd_str ne "")
			{
				$g_servers{$s_addr}->dorcon($cmd_str);
			}
		}
		### End of Skill Addon

		### Begin of Kill-Death Ratio
		elsif (($message =~ /^\/?kdratio([ ][0-9]+)?$/i) || ($message =~ /^\/?kdeath([ ][0-9]+)?$/i) || ($message =~ /^\/?kpd([ ][0-9]+)?$/i)) {
			my $userid = 0;
			my $found = 0;
			if ($1 eq "") {
				$found++;
			} else {
				$userid = $1;
				while (my($pl, $s_player) = each(%g_players) ) {
					if ($userid == $s_player->{userid}) {
						$player = $s_player;
						$found++;
					}
				}
			}

			if ($found > 0 ) {
				my ($skill, $kills, $deaths, $kd, $suicides, $headshots, $hpk, $acc, $connection_time, $fav_weapon, $fav_weapon_kills, $fav_weapon_acc, $s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_acc, $ranknumber, $totalplayers) = get_player_data($player, 1);
				my $playerName = $player->{name};

				my $accstring = "";
				if ($acc != "0.0") {
					$accstring = $acc."% accuracy,";
				}

				if ($message !~ /^\/?kdeath([ ][0-9]+)?$/i) {
					if ($g_servers{$s_addr}->{player_command_osd} ne "") {
						my $osd_string = get_menu_text($player, $skill, $kills, $deaths, $kd, $suicides, $headshots, $hpk, $acc, $connection_time, $fav_weapon, $fav_weapon_kills, $fav_weapon_acc, $s_fav_weapon, $s_fav_weapon_kills, $s_fav_weapon_acc, $ranknumber, $totalplayers);
						$osd_string = $g_servers{$s_addr}->quoteparam($osd_string);
						$cmd_str = sprintf("%s \"10\" %s %s", $g_servers{$s_addr}->{"player_command_osd"}, $p_userid, $osd_string);
					} else {  
						if ($player->{display_events} == 1) {
							$cmd_str = $g_servers{$s_addr}->{player_command}." ".$p_userid." ".$g_servers{$s_addr}->quoteparam(sprintf("%s has %d:%d frags, %d headshots (%s%%),%s and a KD-Radio of %s", $playerName, $kills, $deaths, $headshots, $hpk, $accstring, $kd));
						}  
					}
				} else {					
					if ($g_servers{$s_addr}->{"public_commands"} == 1) {
						$cmd_str = "";
						$g_servers{$s_addr}->messageAll(sprintf("%s has %d:%d frags, %d headshots (%s%%),%s and a KD-Ratio of %s", $playerName, $kills, $deaths, $headshots, $hpk, $accstring, $kd));
					} else {
						$cmd_str = $g_servers{$s_addr}->{player_command}." ".$p_userid." ".$g_servers{$s_addr}->quoteparam(sprintf("%s has %d:%d frags, %d headshots (%s%%),%s and a KD-Ratio of %s", $playerName, $kills, $deaths, $headshots, $hpk, $accstring, $kd));
					}
				}
			} else {
				if ($player->{display_events} == 1) {
					$cmd_str = $g_servers{$s_addr}->{player_command}." ".$p_userid." ".$g_servers{$s_addr}->quoteparam("No player found with this userid. Type status in console to get players userid!");
				}
			}
			if ($cmd_str ne "")
			{
				$g_servers{$s_addr}->dorcon($cmd_str);
			}

		}
		### End of Kill-Death Ratio

		### Begin of Session stats
		elsif (($message =~ /^\/?session([ ][0-9]+)?$/i) || ($message =~ /^\/?session_data([ ][0-9]+)?$/i)) {
			my $error = 0;
			if ($1 ne "") {
				$userid   = substr($1, 1, length($1)-1);
				my $found = 0;
				while (my($pl, $s_player) = each(%g_players) ) {
					if ($userid == $s_player->{userid}) {
						$player = $s_player;
						$found++;
					}
				}
				if ($found == 0) {
					$error++;
				}
			}
			my $playerName = $player->{name};
			my $kills      = $player->{session_kills};
			my $deaths     = $player->{session_deaths};
			my $headshots  = $player->{session_headshots};
			my $suicides   = $player->{session_suicides};
			my $skill      = $player->{session_skill};
			my $shots      = $player->{session_shots};
			my $hits       = $player->{session_hits};
			my $kdstring = "";
			
			if ($deaths > 0) {
				$kd = sprintf("%.3f", $kills/$deaths);
				$kdstring = sprintf(" (%.2f%%)", $kills/$deaths)
			} else {
				$kd = sprintf("%.3f", $kills);
			}
			if ($kills > 0) {
				$hpk = sprintf("%.0f", (100/$kills) * $headshots);
			} else {
				$hpk = sprintf("%.0f", $kills);
			}
			if ($shots > 0) {
				$acc = sprintf("%.1f", (100/$shots) * $hits);
			} else {
				$acc = sprintf("%.1f", $shots);
			}
			my $accstring = "";
			if ($acc != "0.0") {
				$accstring = $acc." accuracy,";
			}
			
			if ($error == 0) {
				my $pointstr="";
				if ($g_ranktype ne "kills") {
					$pointstr = sprintf(" and a skill change of %d points", $skill);
				}
				my $msg = sprintf("%s has %d:%d frags%s, %d headshots (%s%%),%s%s", $playerName, $kills, $deaths, $kdstring, $headshots, $hpk, $accstring, $pointstr);
				if ($message !~ /^\/?session_data([ ][0-9]+)?$/i) {
					if ($g_servers{$s_addr}->{player_command_osd} ne "") {
						my ($se_skill, $se_kills, $se_deaths, $se_kd, $se_suicides, $se_headshots, $se_hpk, $se_acc, $se_connection_time, $se_fav_weapon, $se_fav_weapon_kills, $se_fav_weapon_acc, $se_s_fav_weapon, $se_s_fav_weapon_kills, $se_s_fav_weapon_acc, $se_ranknumber, $se_totalplayers) = get_player_data($player, 1);
						my $osd_string = get_menu_text($player, $se_skill, $se_kills, $se_deaths, $se_kd, $se_suicides, $se_headshots, $se_hpk, $se_acc, $se_connection_time, $se_fav_weapon, $se_fav_weapon_kills, $se_fav_weapon_acc, $se_s_fav_weapon, $se_s_fav_weapon_kills, $se_s_fav_weapon_acc, $se_ranknumber, $se_totalplayers);
						$osd_string = $g_servers{$s_addr}->quoteparam($osd_string);
						$cmd_str = sprintf("%s \"10\" %s %s", $g_servers{$s_addr}->{player_command_osd}, $p_userid, $osd_string);
					} else {
						if ($player->{display_events} == 1) {
							$cmd_str = sprintf("%s %s %s", $g_servers{$s_addr}->{player_command}, $p_userid, $g_servers{$s_addr}->quoteparam($msg));
						}  
					}  
				} else {
					if ($g_servers{$s_addr}->{"public_commands"} == 1) {
						$cmd_str = "";
						$g_servers{$s_addr}->messageAll($msg);
					} else {
						$cmd_str = sprintf("%s %s %s", $g_servers{$s_addr}->{player_command}, $p_userid, $g_servers{$s_addr}->quoteparam($msg));
					}
				}
			} else {
				if ($player->{display_events} == 1) {
					$cmd_str = $g_servers{$s_addr}->{player_command}." ".$p_userid." ".$g_servers{$s_addr}->quoteparam("No player found with this userid. Type status in console to get players userid!");
				}
			}
			if ($cmd_str ne "")
			{
				$g_servers{$s_addr}->dorcon($cmd_str);
			}
		}
		### End of Session stats
		
		### status Addon
		elsif ($message =~ /^\/?status([ ][0-9]+)?$/i) {
			if ($g_servers{$s_addr}->{use_browser} > 0) {
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $server_id  = $g_servers{$s_addr}->{id};
				my $game       = $g_servers{$s_addr}->{game};
				if ($1 ne "") {
					$server_id = substr($1, 1, length($1)-1);
				}
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=status&server_id=%s", $url, $game, $server_id));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if (($g_servers{$s_addr}->{"mod"} eq "BEETLE")) {
					$cmd_status = sprintf("%s %s say %s %s" , $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_status = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
			$g_servers{$s_addr}->dorcon($cmd_status);
			} 
		}

		### load Addon
		elsif ($message =~ /^\/?load$/i) {
		if ($g_servers{$s_addr}->{use_browser} > 0) {
			my $url        = $g_servers{$s_addr}->{ingame_url};
			my $server_id  = $g_servers{$s_addr}->{id};
			my $game       = $g_servers{$s_addr}->{game};
			my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?mode=status&server_id=%s&mode=load", $url, $server_id));
			my $browsecmd = $g_servers{$s_addr}->{browse_command};
			if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
				$cmd_load = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
			} else {
				$cmd_load = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
			}
			$g_servers{$s_addr}->dorcon($cmd_load);
			}
		}

		### servers Addon
		elsif ($message =~ /^\/?servers$/i) {
			if ($g_servers{$s_addr}->{use_browser} > 0) {
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=servers", $url, $game));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_servers = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_servers = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_servers);
			} 
		}   

		### cheaters Addon
		elsif ($message =~ /^\/?cheaters$/i || $message =~ /^\/?bans$/i) {
			if ($g_servers{$s_addr}->{use_browser} > 0)  {
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=bans", $url, $game));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_cheaters = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_cheaters = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_cheaters);
			}
		}

		### Actions Addon
		elsif (($message =~ /^\/?action$/i) || ($message =~ /^\/?actions$/i)) {
			if ($g_servers{$s_addr}->{use_browser} > 0)  {
				my $p_playerid = $player->{playerid};
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=actions&player=%s", $url, $game, $p_playerid));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};

				if ($g_servers{$s_addr}->{mod} eq "BEETLE") {
					$cmd_actions = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_actions = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_actions);		
			}
		}

		### Accuracy Addon
		elsif ($message =~ /^\/?accuracy$/i) {
			if ($g_servers{$s_addr}->{use_browser} > 0) {
				my $p_playerid = $player->{playerid};
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=accuracy&player=%s", $url, $game, $p_playerid));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_accuracy = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_accuracy = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_accuracy);	 
			}
		}

		### Targets Addon
		elsif (($message =~ /^\/?targets$/i) || ($message =~ /^\/?target$/i)) {
			if ($g_servers{$s_addr}->{use_browser} > 0)  {
				my $p_playerid = $player->{playerid};
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=targets&player=%s", $url, $game, $p_playerid));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_targets = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_targets = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_targets);
			}
		}

		### Clans Addon
		elsif ($message =~ /^\/?clans$/i) {
			if ($g_servers{$s_addr}->{use_browser} > 0)  {
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=clans", $url, $game));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_clans = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_clans = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_clans);	
			}
		}

		### Begin of next Addon
		elsif ($message =~ /^\/?next$/i) {
			if ($g_servers{$s_addr}->{player_command_osd} ne "") {
				my $playerName = $player->{name};
				my ($ranknumber, $totalplayers, $osd_message) = get_next_ranks($player);
				$osd_string = $g_servers{$s_addr}->quoteparam($osd_message);
				$cmd_str    = sprintf("%s \"10\" %s %s", $g_servers{$s_addr}->{"player_command_osd"}, $p_userid, $osd_string);
				$g_servers{$s_addr}->dorcon($cmd_str);
			}
		} 

		### Begin of Top-Players Addon
		elsif ($message =~ /^\/?top\d{1,2}?$/i) {
			my $limit = 10;
			$message =~ /top(\d*)/i;
			if ($1 > 12) {
				$limit = 12;
			} else {
				$limit = $1;
			}
			if ($g_servers{$s_addr}->{player_command_osd} ne "") {
				my $result = &doQuery("
					SELECT
						$g_ranktype, lastName, 
						kills / IF(deaths=0,1,deaths) AS kpd
					FROM
						hlstats_Players
					WHERE
						game='".&quoteSQL($player->{game})."' 
						AND hideranking = 0        
						AND kills >= 1
					ORDER BY
						$g_ranktype DESC, kpd DESC
					LIMIT 0, ".$limit);
					
				my $rankword = "";
				if ($g_ranktype eq "kills") {
					$rankword = " kills";
				}
				
				my $osd_message = "->1 - Top Players\\n";
				my $i           = 0;
				my $last_base  = "";
				while (my($base, $lastName) = $result->fetchrow_array) {
					$i++;
					if (length($lastName) > 20) {
						$lastName = substr($lastName, 0, 17)."...";
					}
					if ($last_base eq "") {
						$osd_message .= sprintf("   %02d  %s%s       -      %s", $i, &number_format($base), $rankword, $lastName)."\\n";
						$last_base   =  $base;
					} else {
						$osd_message .= sprintf("   %02d  %s%s  -%04d  %s", $i, &number_format($base), $rankword, ($last_base-$base), $lastName)."\\n";
					}
				}
				$result->finish;
				$osd_string = $g_servers{$s_addr}->quoteparam($osd_message);
				$cmd_str    = sprintf("%s \"15\" %s %s", $g_servers{$s_addr}->{player_command_osd}, $p_userid, $osd_string);
				$g_servers{$s_addr}->dorcon($cmd_str);

			} elsif ($g_servers{$s_addr}->{use_browser} > 0) {
				my $url = $g_servers{$s_addr}->{ingame_url};
				my $game = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=players", $url, $game));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_players = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_players = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_players);	
			} 
		}
		### End of Top10 Addon

		### Begin of statsme Addon
		elsif ($message =~ /^\/?statsme$/i) {
			if ($g_servers{$s_addr}->{use_browser} > 0) {
				my $p_playerid = $player->{playerid};
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=statsme&player=%s", $url, $game, $p_playerid));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_statsme = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_statsme = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_statsme);	
			}
		}
		### End of statsme Addon

		### Begin Player-Weapons Addon
		elsif (($message =~ /^\/?weapon$/i) || ($message =~ /^\/?weapons$/i)) {
			if ($g_servers{$s_addr}->{use_browser} > 0)  {
				my $p_playerid = $player->{playerid};
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=weapons&player=%s", $url, $game, $p_playerid));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_weapons = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_weapons = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_weapons); 
			}
		}
		### End of Player-Weapons Addon

		### Begin Player-Kills Addon
		elsif (($message =~ /^\/?kill$/i) || ($message =~ /^\/?kills$/i) || ($message =~ /^\/?player_kills$/i)) {
			if ($g_servers{$s_addr}->{use_browser} > 0) {
				my $p_playerid = $player->{playerid};
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=kills&player=%s", $url, $game, $p_playerid));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_kills = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_kills = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_kills);  
			}
		}
		### End of Player-Kills Addon

		### Begin Player-Map Performance Addon
		elsif (($message =~ /^\/?maps$/i) || ($message =~ /^\/?map_stats$/i) || ($message =~ /^\/?map$/i)) {
			if ($g_servers{$s_addr}->{use_browser} > 0) {
				my $p_playerid = $player->{playerid};
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=maps&player=%s", $url, $game, $p_playerid));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_maps = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_maps = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_maps);  
			}
		}
		### End of Player-Map Performance Addon

		### Begin Help Addon
		elsif (($message =~ /^\/?help$/i) || ($message =~ /^\/?cmd$/i) || ($message =~ /^\/?cmds$/i) || ($message =~ /^\/?commands$/i)) {
			if ($g_servers{$s_addr}->{use_browser} > 0)  {
				my $url        = $g_servers{$s_addr}->{ingame_url};
				my $game       = $g_servers{$s_addr}->{game};
				my $fullurl = $g_servers{$s_addr}->quoteparam(sprintf("%s/ingame.php?game=%s&mode=help", $url, $game));
				my $browsecmd = $g_servers{$s_addr}->{browse_command};
			
				if ($g_servers{$s_addr}->{"mod"} eq "BEETLE") {
					$cmd_help = sprintf("%s %s say %s %s", $g_servers{$s_addr}->{exec_command}, $p_userid, $browsecmd, $fullurl);
				} else {
					$cmd_help = sprintf("%s %s %s", $browsecmd, $p_userid, $fullurl);
				}
				$g_servers{$s_addr}->dorcon($cmd_help);  
			}
		}
		### End of Help Addon

	} # end if player  
    

	return $playerstr . " $msg_type \"$message\"";
}


#
# 019. Map
#

sub doEvent_ChangeMap
{
	my ($type, $newmap) = @_;
	
	$g_servers{$s_addr}->set("map", $newmap);
	$g_servers{$s_addr}->clear_winner();

	if ($type eq "loading")
	{
		while (my($pl, $player) = each(%g_players) )
		{
			if ($player->{is_bot} == 1)
			{
				$player->updateDB();
				removePlayer($s_addr, $player->{userid}, $player->{uniqueid}, 1);
			}
			else
			{
				endKillStreak($player);
			}
		}
		$g_servers{$s_addr}->setHlxCvars();
		return "Loading map \"$newmap\"";
	}
	elsif ($type eq "started")
	{
		$g_servers{$s_addr}->increment("map_changes");
		$g_servers{$s_addr}->set("map_started", time());
		$g_servers{$s_addr}->set("map_rounds", 0);
		$g_servers{$s_addr}->set("map_ct_wins", 0);
		$g_servers{$s_addr}->set("map_ts_wins", 0);
		$g_servers{$s_addr}->set("map_ct_shots", 0);
		$g_servers{$s_addr}->set("map_ct_hits", 0);
		$g_servers{$s_addr}->set("map_ts_shots", 0);
		$g_servers{$s_addr}->set("map_ts_hits", 0);
		$g_servers{$s_addr}->updateDB();
		while (my($pl, $player) = each(%g_players) )
		{
			$player->set("team", "");
			$player->set("map_kills", "0");
			$player->set("map_deaths", "0");
			$player->set("map_headshots", "0");
			$player->set("map_shots", "0");
			$player->set("map_hits", "0");
			$player->{trackable} = 0;
		}
		$g_servers{$s_addr}->updatePlayerCount();
		$g_servers{$s_addr}->{map} = $newmap;
		&printNotice("Current map for server \"$s_addr\" is now \"" . $newmap . "\"");
		
		return "Started map \"$newmap\"";
	}
	else
	{
		return "Map \"$newmap\": $type";
	}
}


#
# 020. Rcon
#

sub doEvent_Rcon
{
	my ($type, $command, $password, $ipAddr) = @_;
	
	if ($g_rcon_record)
	{
		&recordEvent(
			"Rcon", 0,
			$type,
			$ipAddr,
			$password,
			$command
		);
	}
	else
	{
		$desc = "(IGNORED) ";
	}
	
	return $desc . "$type Rcon from \"$ipAddr\": \"$command\"";
}


#
# 500. Admin
#

sub doEvent_Admin
{
	my ($type, $message, $playerName) = @_;
	
	&recordEvent(
		"Admin", 0,
		$type,
		$message,
		$playerName
	);
	
	return "\"$type\" (\"$playerName\") \"$message\"";
}

#
# 501. Statsme (weapon)
#

sub doEvent_Statsme
{
	my ($playerId, $playerUniqueId, $weapon, $shots, $hits, $headshots, $damage, $kills, $deaths) = @_;
	my $desc;
	my $player    = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);

	if ($g_servers{$s_addr}->{num_trackable_players} < $g_servers{$s_addr}->{minplayers})
	{
		$desc = "(IGNORED) NOTMINPLAYERS: ";
	}
	elsif ($player)
	{
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($player->{is_bot} == 1))
		{
			$desc = "(IGNORED) BOT: ";
		} else {
		
			if ($weapon eq "bow") {
				$weapon = "arrow";
			}

			if ($shots>0) 
			{
				$player->increment("shots",         $shots);
				$player->increment("map_shots",     $shots);
				$player->increment("session_shots", $shots);
				$g_servers{$s_addr}->increment("total_shots", $shots);
			}  
			if ($hits>0)
			{
				$player->increment("hits",          $hits);
				$player->increment("map_hits",      $hits);
				$player->increment("session_hits",  $hits);
				$g_servers{$s_addr}->increment("total_hits", $hits);
			}  
			$player->updateDB();
               
			my $player_team = $player->{team};
			if ($player_team eq "CT")
			{
				if ($shots>0) 
				{
					$g_servers{$s_addr}->increment("ct_shots", $shots);
					$g_servers{$s_addr}->increment("map_ct_shots", $shots);
				}  
				if ($hits>0) 
				{
					$g_servers{$s_addr}->increment("ct_hits", $hits);
					$g_servers{$s_addr}->increment("map_ct_hits", $hits);
				}  
			} elsif ($player_team eq "TERRORIST") {
				if ($shots>0) 
				{
					$g_servers{$s_addr}->increment("ts_shots", $shots);
					$g_servers{$s_addr}->increment("map_ts_shots", $shots);
				}
				if ($hits>0) 
				{
					$g_servers{$s_addr}->increment("ts_hits", $hits);
					$g_servers{$s_addr}->increment("map_ts_hits", $hits);
				}  
			}
			$g_servers{$s_addr}->updateDB();
                
			&recordEvent("Statsme", 0,
				$player->{playerid},
				$weapon,
				$shots,
				$hits,
				$headshots,
				$damage,
				$kills,
				$deaths
			);
		}          
	} else
    {
		$desc = "(IGNORED) NOPLAYERINFO: ";
    }
    return $desc . $playerstr . " STATSME weaponstats (weapon \"$weapon\") (shots \"$shots\") (hits \"$hits\") (headshots \"$headshots\") (damage \"$damage\") (kills \"$kills\") (deaths \"$deaths\")";
}

#
# 502. Statsme (weapon2)
#

sub doEvent_Statsme2
{
    my ($playerId, $playerUniqueId, $weapon, $head, $chest, $stomach, $leftarm, $rightarm, $leftleg, $rightleg) = @_;

    my $desc;
    my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
    my $playerstr = &getPlayerInfoString($player, $playerId);

	if ($g_servers{$s_addr}->{num_trackable_players} < $g_servers{$s_addr}->{minplayers})
	{
		$desc = "(IGNORED) NOTMINPLAYERS: ";
	}
	elsif ($player)
	{
		if (($g_servers{$s_addr}->{ignore_bots} == 1) && ($player->{is_bot} == 1))
		{
			$desc = "(IGNORED) BOT: ";
		} else {
			if ($g_servers{$s_addr}->{play_game} == FOF()) {
				$weapon =~ s/2$//;
				if ($weapon eq "bow") {
					$weapon = "arrow";
				}
			}
			&recordEvent("Statsme2", 0,
				$player->{playerid},
				$weapon,
				$head,
				$chest,
				$stomach,
				$leftarm,
				$rightarm,
				$leftleg,
				$rightleg
			);
			$player->updateDB();
		}
     }
     else
     {
		$desc = "(IGNORED) NOPLAYERINFO: ";
     }
     return $desc . $playerstr . " STATSME weaponstats2 (weapon \"$weapon\") (head \"$head\") (chest \"$chest\") (stomach \"$stomach\") (leftarm \"$leftarm\") (rightarm \"$rightarm\") (leftleg \"$leftleg\") (rightleg \"$rightleg\")";
}

#
# 503. Statsme (latency)
#

sub doEvent_Statsme_Latency
{
	my ($playerId, $playerUniqueId, $ping) = @_;

	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);

	if (($player) && ($player->{is_bot} == 0))
	{
		&recordEvent(
			"StatsmeLatency", 0,
			$player->{playerid},
			$ping
		);
	}
	else
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}

	return $desc . $playerstr . " STATSME average latency \"$ping\"";
}

#
# 504. Statsme (time)
#

sub doEvent_Statsme_Time
{
	my ($playerId, $playerUniqueId, $time) = @_;

	my $desc;
	my $player = lookupPlayer($s_addr, $playerId, $playerUniqueId);
	my $playerstr = &getPlayerInfoString($player, $playerId);

	if (($player) && ($player->{is_bot} == 0))
	{
		&recordEvent(
			"StatsmeTime", 0,
			$player->{playerid},
			$time
		);
	}
	else
	{
		$desc = "(IGNORED) NOPLAYERINFO: ";
	}

	return $desc . $playerstr . " STATSME connection time \"$time\"";
}

#
# 505. Kill Location
#

sub doEvent_Kill_Loc
{
	my (%properties) = @_;
	
	if (defined($properties{attacker_position})) {
		my $coords = $properties{attacker_position};
		($g_servers{$s_addr}->{nextkillx}, $g_servers{$s_addr}->{nextkilly}, $g_servers{$s_addr}->{nextkillz}) = split(/ /,$coords);
	}
	
	if (defined($properties{victim_position})) {
		my $coords = $properties{victim_position};
		($g_servers{$s_addr}->{nextkillvicx}, $g_servers{$s_addr}->{nextkillvicy}, $g_servers{$s_addr}->{nextkillvicz}) = split(/ /,$coords);
	}

	return sprintf("KILL LOCATION x=>%s, y=>%s, z=>%s stored for next kill", $g_servers{$s_addr}->{nextkillx}, $g_servers{$s_addr}->{nextkilly}, $g_servers{$s_addr}->{nextkillz});
}

1;
