<?php
/********************************************************
 *     Name: idlekick.php
 *     Date: 19/09/2008
 * Modified: 20/10/2008
 *   Author: DedDerek (www.dedderek.org)
 *  Version: 0.2
REQUIREMENT: Requires TMGery Plugin Manager by DedDerek
             http://www.tm-forum.com/viewforum.php?f=131
 *  Purpose: Provides idlekick functionality for the
 *           TM gery server controller software.
 *    Usage: Follow instructions in readme.txt
*********************************************************/

//configuration variables for idlekick script
//see line 26-40

class idlekick{
	var $idlecount=array();
	var $isidlethisround=array();
	var $kickplaycounter=0;
	var $kickspeccounter=0;
	var $starttime;
	var $kickedppl=array();
	var $client;

	var $idlekickenable = true;		// Enable idlekick function? (can always be enabled/disabled on the flay with "/idlekick toggle" for admin users)
	var $kickPlayAfter = 2;         // Player idle this number of challenges and get kicked
	var $kickSpecAfter = 4;         // Spectator idle this number of challenges and get kicked
	var $kickadmins = true;			// Allow admin users to be kicked?
	var $kickSpecToo = true;        // Kick spectators too
	
	var $resetOnChat = true;        // Reset idle counter on chat use
	var $resetOnCheckpoint = true;  // Reset idle counter when passing a checkpoint (this includes finish)
	var $resetOnFinish = false;     // Reset idle counter when reaching the finish (do not use this in time-attack, rounds or team mode as everyone will always 'finish')
	
	
	//the following settings are for debugging or enabling further verbosity for the idlekick function
	var $idlekick_debug = false;	// Set to true to see debugging events to the console
	var $idlekick_advdebug = false;	// Set to true to show array debugging when an idlekick change occurs (checkpoints,chats,finish)
	/* !!! END CONFIGURATION !!!!!!!!!!!!!!!! */

	/* Called on Gery Startup */
	function idlekickinit(){
		global $client;
		$this->client = $client;
		
		//check the admin hasn't set a threshold to 0
		if($this->kickPlayAfter == 0 || $this->kickSpecAfter == 0){
			echo '[IDLEWARN] !WARNING!!! An idlekick variable is set to 0 rounds kick! This system will not kick players or spectators who have been idle for 0 rounds. The setting will be ignored and kick for that play type disabled.'."\n";
		}
		
		$this->starttime=time();
		if($this->idlekickenable == true){
			$this->client->query('ChatSendServerMessage','$f00>> $0a0Idlekick by DedDerek enabled and starting!');
			if($this->kickSpecToo){ $msgspec = '$ff0 & spectators after $f00'.$this->kickSpecAfter; }else{ $msgspec = ''; }
			$this->client->query('ChatSendServerMessage','$f00>>$ff0 Kicking players after $f00'.$this->kickPlayAfter.$msgspec.'$ff0 rounds!');
				
			//create the base arrays for users already in the server
			if(!@$client->query("GetPlayerList", 255, 0)){
				Error($client->getErrorMessage(), $client->getErrorCode());
			}else{
				$PlayerList = $client->getResponse();
			}
			for($i=0;$i<count($PlayerList);$i++){
				$player=$PlayerList[$i]['Login'];
				$this->isidlethisround[$player] = false;
				$this->idlecount[$player] = 0;
				if ($this->idlekick_debug == true){
					echo "[IdleStartup] Creating base array for player " . $player . "\n";
				}
			}			
			$this->debugvars();
		}		
	} // end idlekickinit

	/* Called when the user types "/idlekick" */
	function idlekickmsgs($command,$playerlogin){
		$command = $command[0];
		$playerlogin = $playerlogin[0];
		if($command == '' || $command == 'info'){ //information messages
			//setup the info
			if($this->idlekickenable == false){ $status='$f00DISABLED'; }else{ $status = '$fffEnabled'; }
			if($this->kickSpecToo == false){ $speckickstatus = 'DISABLED'; }else{ $speckickstatus = 'Enabled'; }
			
			$resettypes='';
			if($this->resetOnChat){ $resettypes .= 'Chat'; }
			if($this->resetOnCheckpoint){ $resettypes .= ', Checkpoint'; }
			if($this->resetOnFinish){ $resettypes .= ', Finish'; }
			if($this->kickadmins == false){ $admkick = 'can not'; }else{ $admkick = '$f00CAN'; }
			
			if($this->idlekick_debug == false){ $basedebug = 'DISABLED'; }else{ $basedebug = 'ENABLED'; }
			if($this->idlekick_advdebug == false){ $advdebug = 'DISABLED'; }else{ $advdebug = 'ENABLED'; }
			
			//create the message
			$msg  = '$ff0> Idlekick is '.$status.'$ff0: Kicks after $fff'.$this->kickPlayAfter.' '.$this->kickSpecAfter.'$ff0. Spectator kick is $fff'.$speckickstatus."\n";
			$msg .= '$ff0> Idle reset on:$fff '.$resettypes.'$ff0. Admin\'s $fff'.$admkick.'$ff0 be kicked!'."\n";
			$msg .= '$ff0> Basic Debugging: $fff'.$basedebug.'$ff0 Advanced Debugging: $fff'.$advdebug."\n";
			$msg .= '$ff0> Other Commands: $fff/idlekick stats, /idlekick kicks, /idlekick toggle';
			
		}elseif($command == 'stats'){ //stats (how many have been kicked)
			$msg  = '$ff0> $fff'.$this->kickplaycounter.'$ff0 players & $fff'.$this->kickspeccounter.'$ff0 spectators kicked!'."\n";
			$msg .= '$ff0> $fff'.($this->kickplaycounter+$this->kickspeccounter).'$ff0 kicks since '.date('l d/m/Y, h:i:s A',$this->starttime);
			
		}elseif($command == 'kicks'){ //kicks (last 5 kicks)
			$arrcnt = count($this->kickedppl);
			$msg = '$ff0> Last 10 idlekicks:';
			$count=1;
			for($i=0;$i<$arrcnt;$i++){
				$msg .= "\n".'$ff0> '.$count.': '.$this->kickedppl[$i][1].' '.$this->kickedppl[$i][0].'$z$ff0 at $fff'.date('d/m/Y, h:i:s A',$this->kickedppl[$i][2]);
				$count++;
			}
			if($arrcnt == 0){
				$msg .= "\n".'$ff0> $f00No kicks recorded!';
			}
			
		}elseif($command == 'toggle'){
			//is the player an admin?
			if(isadmin($playerlogin)){
				//if enabled then disable and notify the admin of this
				if($this->idlekickenable == true){
					$this->idlekickenable = false;
					$msg = '$ff0>> $f00Idlekick Disabled Temporarily by an admin!!!';
					$this->client->query('ChatSendServerMessage',$msg);
					return;
				}else{
					//if disabled then enable and notify the admin of this
					$this->idlekickenable = true;
					$msg = '$ff0>> $0a0Idlekick Enabled!!!';
					$this->client->query('ChatSendServerMessage',$msg);
					return;
				}
			}else{ //not an admin, deny this message
				$msg = '$ff0> $f00SORRY!$ff0 This command is admin only!';
			}
		}else{
			//send a generic message listing the available commands
			$msg = '$ff0> Allowed Commands: $fff/idlekick info, /idlekick stats, /idlekick kicks, /idlekick toggle';
		}
		
		//send the message to the client
		$this->client->query('ChatSendServerMessageToLogin',$msg,$playerlogin);
	} // end infomsg

	// called @ onChat
	function idlekickchat($chat) {
		$this->debugvars();

		// if it was not a player then bail
		if (empty($chat[1])){ return; }
		// if not enabled then bail out
		if ($this->idlekickenable == false){ return; }
		// if no check on chat use, bail out too
		if ($this->resetOnChat == false){ return; }
	
		$login = $chat[1]; //player login
		$this->isidlethisround[$login] = false;
		if ($this->idlekick_debug == true){
			echo "[Idlereset] Player " . $login . " idlecount set to 0 because of chat.\n";
		}
		
		$this->debugvars();
	}  // end kickIdleChat
	
	// called @ onCheckpoint
	function idlekickcps($info) {
		$this->debugvars();
	
		// if not enabled then bail out
		if ($this->idlekickenable == false){ return; }
		// if no check on checkpoints, bail out
		if ($this->resetOnCheckpoint == false){ return; }
	
		$login = $info[1]; //player login
		$this->isidlethisround[$login] = false;
		if ($this->idlekick_debug == true){
			echo "[Idlereset] Player " . $login . " idlecount set to 0 because of checkpoint.\n";
		}
		
		$this->debugvars();
	}  // end kickIdleCheckpoint
	
	// called @ onPlayerFinish
	function idlekickfinish($item) {
		$this->debugvars();
	
		// if not enabled then bail out
		if ($this->idlekickenable == false){ return; }
		// if no check on finishes, bail out
		if ($this->resetOnFinish == false) return;
	
		$login = $item[1]; //player login
		$this->isidlethisround[$login] = false;
		if ($this->idlekick_debug == true){
			echo "[Idlereset] Player " . $login . " idlecount set to 0 because of finish.\n";
		}
		
		$this->debugvars();
	}  // end kickIdleFinish
		
	// called @ onPlayerConnect
	function idlekickconnect($data) {
		$this->debugvars();
	
		$login = $data[0]; //player login
		$this->isidlethisround[$login] = false;
		$this->idlecount[$login] = 0;
		if ($this->idlekick_debug == true){
			echo "[IdleStart] Player " . $login . " idlecount initialised to 0.\n";
		}
		
		$this->debugvars();
	}  // end kickIdleInit
	
	// called @ onPlayerDisconnect
	function idlekickdisconnect($data) {
		$login = $data[0];
		//remove their idle count (saves on useless memory usage)
		unset($this->idlecount[$login]);
		unset($this->isidlethisround[$login]);
		
		$this->debugvars();
	} // end playerDisconnect
	
	// called @ onBeginRace (setup the isidlethisround = true for all users
	function idlekickbeginrace() {
		global $PlayerList;
		$this->debugvars();
		
		// if not enabled then bail out
		if ($this->idlekickenable == false){ return; }

		$this->isidlethisround=array();
		foreach ($PlayerList as $player) {
			$login = $player['Login'];
			$this->isidlethisround[$login] = true;
		}
		
		$this->debugvars();
	} // end startround
	
	// called @ onEndRace (controls the idlekicking and adding to idle times)
	function idlekickendrace() {
		global $PlayerList;
		$this->debugvars();
		
		// if not enabled then bail out
		if ($this->idlekickenable == false){ return; }
		//end round calcing message to debug (if enabled)
		if($this->idlekick_debug == true){
			echo "[IdleKick] Round End! Calculating Idlekick users...\n";
		}
	
		foreach ($PlayerList as $player) {
			$spec = $player['IsSpectator'];
			$login = $player['Login'];
			$nickname = $player['NickName'];
		
			//allow admins to be kicked?
			if($this->kickadmins == false){
				//don't kick an admin!
				$isadmin = isadmin($login);
			}else{
				$isadmin = false;
			}
			

			//was the player completely idle this round? ($this->isidlethisround[$login] == true)
			if($this->isidlethisround[$login] == true && $isadmin == false){
				$this->idlecount[$login]++;
				
				//is the player a spectator?
				if($spec == '1' && $this->kickSpecToo == true){ //Spectator
					//if the players idleroundcount is more or equal to the limit then kick them and notify the server
					if($this->idlecount[$login] >= $this->kickSpecAfter && $this->kickSpecAfter > 0){
						//console message stating the kick
						echo "[Idlekick spectator] " . $login . " after " . $this->kickSpecAfter . " challenge(s) without action.";
						//send a message to the server window for all to see
						$message = '$ff0>> Idlekicking spectator $0f3'.$nickname.'$z$s$ff0 after $fff'.$this->kickSpecAfter.'$ff0 rounds inactive!';
						$this->client->query('ChatSendServerMessage',$message);
						//kick the spectator
						$this->client->query('Kick', $login);
						$this->modkickarr($login,'Spec');
						$this->kickspeccounter++;
					}elseif($this->kickSpecAfter == 0){
						echo '[IDLEERR] Cannot kick spectators as the threshold is set to 0! Increase the idle round count and restart gery.'."\n";
					}else{
						//notify of their idlecount/maxallowableidle
						if($this->idlekick_debug == true){
							echo "[IdleKick] Spectator ".$login." was idle and now has an idlekick count of: ".$this->idlecount[$login]."/".$this->kickSpecAfter."!\n";
						}
					}
				}else{ //Racer (not a specator)
					//if the players idleroundcount is more or equal to the limit then kick them and notify the server
					if($this->idlecount[$login] >= $this->kickPlayAfter && $this->kickPlayAfter > 0){
						//console message stating the kick
						echo "[Idlekick player] " . $login . " after " . $this->kickPlayAfter . " challenge(s) without action.\n";
						//send a message to the server window for all to see
						$message = '$ff0>> Idlekicking player $0f3'.$nickname.'$z$s$ff0 after $fff'.$this->kickPlayAfter.'$ff0 rounds inactive!';
						$this->client->query('ChatSendServerMessage',$message);
						//kick the spectator
						$this->client->query('Kick', $login);
						$this->modkickarr($login,'Player');
						$this->kickplaycounter++;
					}elseif($this->kickPlayAfter == 0){
						echo '[IDLEERR] Cannot kick player as the threshold is set to 0! Increase the idle round count and restart gery.'."\n";
					}else{
						//notify of their idlecount/maxallowableidle
						if($this->idlekick_debug == true){
							echo "[IdleKick] Player ".$login." was idle and now has an idlekick count of: ".$this->idlecount[$login]."/".$this->kickPlayAfter."!\n";
						}
					}
				}
			}else{ //user was not idle, reset their count
				if($this->idlekick_debug == true && $this->idlecount[$login] > 0){
					echo "[IdleKick] ".$login." idlecount reset to 0 (was ".$this->idlecount[$login].") due to activity!\n";
				}
				$this->idlecount[$login] = 0;
			}
		}
		//clear the isidlethisround variable completely
		unset($this->isidlethisround);
		
		$this->debugvars();
	}  // end kickIdlePlayers
	
	
	//debug the script by showing some array outputs
	function debugvars() {
		if($this->idlekick_advdebug == false){ return; }
		echo "[idlecount]";
		print_r($this->idlecount);
		echo "[isidlethisround]";
		print_r($this->isidlethisround);
	}
	
	//keep the kicked array to 5 values
	function modkickarr($login,$type){
		$arr = $this->kickedppl;
		//if the array if 5 long then shift it then add again to it
		if(count($arr) == 10){
			array_shift($arr);
		}
		$arr[] = array($login,$type,time());
		$this->kickedppl = $arr;
	}
}

$this->addPlugin(new idlekick());
$this->AddEvent('onStartup', 'idlekickinit');
$this->AddEvent('PlayerConnect', 'idlekickconnect');
$this->AddEvent('PlayerDisconnect', 'idlekickdisconnect');
$this->AddEvent('PlayerCheckpoint', 'idlekickcps');
$this->AddEvent('PlayerFinish', 'idlekickfinish');
$this->AddEvent('PlayerChat', 'idlekickchat');
$this->AddEvent('BeginRace', 'idlekickbeginrace');
$this->AddEvent('EndRace', 'idlekickendrace');

$this->addChatCommand('idlekick', false, 'idlekickmsgs');
?>