Server Script

Last updated 1 June 2012

<?php /* Race Script Includes highscores per map, finish timers, map/cfg rotator, and more Requires a TargetZone as a finish line, winzones will not work If you are not using Rx Hosting your directory needs write permission Made by dukevin (dukevinjduke@gmail.com)
 * 1) !/usr/bin/php

$save_directory_location = "/home/duke/aa/servers/smart/var/logs/";  //The directory to save files. Must end with trailing slash

$countdown_secs_after_finish = 30;	//After someone finishes, how many seconds on the timer before the round ends?

$countdown_if_last_player = true; //If only 1 player remaining, start the timer?

$max_time_limit = -1; //start the timer after this many seconds, -1 to disable time limits

$points = array(10, 7, 5, 4, 3, 2, 1, 1, 1, 1); //points awarded for 1st, 2nd, 3rd, 4th, 5th, etc...

$display_mode = 2; //If set to "1" display a center_message of the map name, 2 for console_message, 3 for both, 0 for no message

$display_prefix = "Current race: 0xffff00"; //When showing the map name, this is appended before it, if $display_mode is 0, this is disabled

$smart_time = true; //If true, the game will determine how many seconds to put on the timer based on previous records instead of using $countdown_secs_after_finish which will be used as the minimum amount of time instead.

$countdown_last_player_extra_time = 0; //If only 1 player remaining, give the last racer this many seconds of extra time to finish. Not needed if $smart_time is true

//Below, inbetween quotes, if you are including maps, put something like: "/path/to/map.aamap.xml". If you are using cfgs, put "mycfg.cfg" $includes = array("Default.cfg","100Watts.cfg","Aflac.cfg","AnimusonConfusion.cfg","Aoi.cfg","ApplePie.cfg","AQuickExplosion.cfg","Arco.cfg","AroundandAround.cfg","AroundTheHorn.cfg","Arsenal.cfg","AtlanticCharter.cfg","Axe.cfg","BatPigBear.cfg","BenignRevolution.cfg","Berlin.cfg","BlazingParadise.cfg","BloodyHell.cfg","Broken.cfg","Buffalo.cfg","CandyBar.cfg","Cell.cfg","Charriot.cfg","Cherrio.cfg","Chicken.cfg","Chihuahua.cfg","Claw.cfg","Colombo.cfg","Compact.cfg","Croma.cfg","DeathOctagon.cfg","DeathTrap.cfg","Disastro.cfg","Divided.cfg","Dizzy.cfg","DontFlinch.cfg","Dragrace.cfg","Eighty.cfg","FirePalace.cfg","Fobia.cfg","Four.cfg","Flex.cfg","FrizzleFraz.cfg","Glacier.cfg","Guitar.cfg","Handgrip.cfg","Holiday.cfg","Hurricania.cfg","Hyperpod.cfg","Illusion.cfg","Insanity.cfg","ItsABug.cfg","JailBreak.cfg","Jelly.cfg","Jester.cfg","KirbyDance.cfg","LetsDance.cfg","Lava.cfg","lol.cfg","Luigi.cfg","Marathon.cfg","Margarita.cfg","Mario.cfg","Mint.cfg","Moon.cfg","MovinOnUp.cfg","MrRoboto.cfg","Mutant.cfg","Nebraska.cfg","Nova.cfg","OctaGone2Death.cfg","Octarace.cfg","One.cfg","OnePathv2.cfg","Organius.cfg","Paura.cfg","PewPew.cfg","PillsburyDrummerboy.cfg","Pirata.cfg","PointOfNoReturn.cfg","Pow.cfg","PureRacingTorture.cfg","RacersOnYourMark.cfg","RatTunnels.cfg","Resurrection.cfg","RoadLessTraveled.cfg","Roundabout.cfg","Seven.cfg","Shield.cfg","ShoppingMall.cfg","SidebySide.cfg","Six.cfg","SmallSpaces.cfg","Spiral.cfg","SpiralHam.cfg","SquareRoot.cfg","Stardome.cfg","Sun.cfg","Symmetry.cfg","TannersBigTronDaddy.cfg","TheMachine.cfg","TheRoadNotTaken.cfg","Three.cfg","TikiTime.cfg","TortureChamber.cfg","Trijecture.cfg","Trucco.cfg","TurnAround.cfg","Two.cfg","Unfortunate.cfg","Verta.cfg","Verta2.cfg","Voltrobe.cfg","What.cfg","WhatTheHECK.cfg","Wrapper.cfg","XploderPro.cfg","Zero.cfg","ZigZag.cfg","ZigZagZaney.cfg","Zipper.cfg","Zone4.cfg");

$rotate_mode = 2; //Set to 1 for simple random, 2 to play each map in order, 3 to randomly pick a map that hasn't been picked yet.

$num_map_plays = 2; //play each map how many times before switching to next map

$zombie_win = false; //Does the winner get a zombie? (adjust zombie_zone_speed to fit your liking)

$precision = 3; //How many decimal places to show times? A value of 3 shows X.xxx, 2 shows X.xx. 5 is max.

/*===================== End of customization options =============================*/

$reccomended_settings = array("target_initial_score 0", "sp_game_type 0", "game_type 0", "sp_finish_type 0", "finish_type 0", "sp_num_ais 0", "num_ais 0", "shot_seek_update_time 0.1", "ladderlog_write_all 1|1"); //these settings should be set for racing mode and is run every round

class Player {	var $name; var $pname; var $place; var $finish_time; var $best_time; var $num_plays; function __construct($name) {		$this->name = $name; $this->read; if(empty($this->num_plays)) $this->num_plays = 0; }	function read {		global $file, $precision; $lines = file($file); foreach($lines as $line) {			$pieces = explode(" ", $line); //time name num_plays if($pieces[1] == $this->name) {				$this->best_time = round($pieces[0], $precision); $this->num_plays = $pieces[2]; break; }		}	}	function write {		global $file, $current_inc; $found = false; $lines = file($file); if(!file_exists($file)) {			c("0xff7777Warning: 0xffffffFile '$current_inc.txt' not found, file creation may have failed. Retrying..."); $fp = fopen($file, 'w'); }		foreach($lines as $i => $line) {			$pieces = explode(" ", $line); $pieces[1] = trim($pieces[1]); if($pieces[1] == $this->name) {				$lines[$i] = "$this->finish_time $this->name $this->num_plays \n"; $found = true; break; }		}		if(!$found) {			$lines[] = "$this->finish_time $this->name $this->num_plays \n"; }		sort(&$lines, SORT_NUMERIC); file_put_contents($file, $lines); fclose($fp); }	function finished($time, $place) {		global $points, $players, $current_inc, $precision, $file; $this->num_plays++; $time = round($time,$precision); $this->finish_time = $time; $this->place = $place; $sufx = suffix($place); $score = $points[$place-1]; if(empty($score)) $score = 0; if($place > 1) {			foreach($players as $p) {				if($p->place == 1) {					$first = $p->finish_time; $difference = " 0xffffff(" . round($this->finish_time - $p->finish_time,$precision) . " s behind 1st)"; break; }			}		}		else $difference = ""; c("0x55ccff > 0xffff99$this->pname 0x55ccfffinished $place$sufx in 0xffff99$time 0x55ccffseconds.$difference 0x808080+{$score} pts"); if($this->finish_time >= $this->best_time && !empty($this->best_time)) //took longer than alltime best {			pm($this->name, "   0xaaaaffYour all-time best on 0xddddff{$current_inc}0xaaaaff is 0xffffff{$this->best_time} 0xaaaaffs, you are 0xffffff". round($this->finish_time - $this->best_time, $precision)." 0xaaaaffs 0xff7777slower0xaaaaff."); }		if($this->finish_time < $this->best_time || empty($this->best_time)) {			if(!empty($this->best_time)) $oldrank = filetee($this->name, $this->name, 1, false, true) + 1; $this->write; $newrank = filetee($this->name, $this->name, 1, false, true) + 1; if(empty($this->best_time)) pm($this->name, "   0xaaaaffThis is your first time finishing 0xddddff{$current_inc}0xaaaaff!"); else pm($this->name, " 0x3388ff* 0x55ff88New personal record! You improved 0xffffff" . round($this->best_time - $this->finish_time,$precision) . "0x55ff88 s raising 0xffffff". ($oldrank - $newrank) ." 0x55ff88ranks!"); if($newrank == 1) c("0xff3333*0xffff33*0x33ff33*0x3366ff*0xffd700Congratulate 0xffffff$this->name 0xffd700for setting a new record on 0xffddaa$current_inc 0xffd700as the fastest time ever!0xff3333*0xffff33*0x33ff33*0x3366ff*"); else if($newrank == 2) c("0xff3333*0xffff33*0x33ff33*0x3366ff*0xffffff$this->name 0xc0c0c0just ranked as the 0xffffff2nd 0xc0c0c0fastest time for $current_inc!0xff3333*0xffff33*0x33ff33*0x3366ff*\n"); else if($newrank == 3) c("0xff3333*0xffff33*0x33ff33*0x3366ff*0xffffff$this->name 0xcd7f32just ranked as the 0xffcc003rd 0xcd7f32fastest time for $current_inc!0xff3333*0xffff33*0x33ff33*0x3366ff*"); else pm($this->name, "    0xaaaaaaYou are now rank 0xffffff$newrank 0xaaaaaaof ".(count(file($file)))." as the fastest time for 0xcccccc{$current_inc}0xaaaaaa!"); }		echo "add_score_player $this->name ". $score. "\n"; } } $players = array; $finished = 0; $i=0; while(true) {	$line = rtrim(fgets(STDIN, 1024)); if(preg_match("/^CYCLE_CREATED/", $line)) {		$split = explode(" ",$line); $name = $split[1]; if(getObject($name) !== false) {			$num_racers++; goto end; }		if(strstr($name,"\""))		{				c("0x000000 ! 0xffff00 $name is not allowed to use the characters 0xffffff« or \" 0xffff00 in their name."); $clean = str_replace("\"","_",$name);			$wo = str_replace("\"","",$name); echo "rename $wo $clean \n"; echo "rename $name $clean \n"; }		$players[$i] = new Player($split[1]); if(isset($pretty)) {			for($x = 0; $x < sizeof($pretty); $x++) {				$crack = explode("*%$", $pretty[$x]); if($crack[0] == $players[$i]->name) $players[$i]->pname = trim($crack[1]); }		}		if(!isset($players[$i]->pname)) $players[$i]->pname = $players[$i]->name; if($i == 0) {			$xPos = $split[2]; $yPos = $split[3]; }		if(!empty($players[$i]->best_time)) $rank = filetee($players[$i]->name, $players[$i]->name, 1, false, true) + 1; $sufx = suffix($rank); pm($players[$i]->name, "0x808080Top 3 times for $current_inc:"); filetee($players[$i]->name, $players[$i]->name, 3, true); if(!(strstr($players[$i]->name, '@'))) $remind = "0x808080(Maybe because you're logged out?)"; else $remind = null; if(!empty($players[$i]->best_time)) pm($players[$i]->name, "0x99ddffYour best time for $current_inc is 0xffffff{$players[$i]->best_time}0x99ddff s ranking 0xffffff$rank{$sufx}0x99ddff of ".count(file($file))."."); if(empty($players[$i]->best_time)) pm($players[$i]->name, "0x99ddffYou have never won 0xcccccc$current_inc 0x99ddffbefore. $remind"); $i++; $num_racers = $i; }	if(preg_match("/^PLAYER_ENTERED/", $line)) {  		//PLAYER_ENTERED rx"dukevin 76.174.69.46 Rx«dukevin		$split = explode(" ", $line);		$pretty[] = $split[1] . "*%$" . $split[3] . " " . $split[4] . " " . $split[5];		$pretty = array_slice($pretty,sizeof($pretty)-40,40);	}	if(preg_match("/^PLAYER_RENAMED/", $line))	{		$split = explode(" ", $line);		$pretty[] = $split[2] . "*%$" . $split[5] . " " . $split[6] . " " . $split[7];	}	if(preg_match("/^ROUND_COMMENCING/", $line))	{		foreach($reccomended_settings as $s)			echo "$s \n";		unset($players);		$finished = 0;		$num_racers = 0;		$a_player_finished = false;		$i = 0;		if(empty($num_plays)) $num_plays = 0;		$num_plays++;		if($num_plays >= $num_map_plays)		{			$pick = pickmap($includes, $rotate_mode);			$num_plays = 0;		}		$current_inc = retrieve($pick);		c("Reading $current_inc.txt...");		switch($display_mode)		{			case 3:				c("$display_prefix$current_inc");			case 2:				echo "center_message $display_prefix$current_inc\n"; break; case 1: c("$display_prefix$current_inc"); }		$file = "$save_directory_location". "$current_inc". ".txt"; if(!file_exists($file)) {			c("0xffff77Warning: 0xffffff$current_inc.txt not found, creating it..."); fopen($file, 'w'); sleep(1); if(!file_exists($file)) c("0xff7777Warning: 0xffffffFile creation failed, scores cannot be saved! Does your directory have write permission?"); }		if($smart_time) $countdown_secs_after_finish = smart_time($countdown_secs_after_finish); echo "target_survive_time ". ($countdown_secs_after_finish+1) ."\n"; if(mt_rand(0,7)==7) c("0x808080You can type /stats to view high scores for maps."); @clock("stop"); }	if(preg_match("/^TARGETZONE_CONQUERED/", $line) || preg_match("/^ROUND_SCORE/",$line)) {		if($finished == 0 || $a_player_finished == true) goto end; @clock("stop"); $split = explode(" ", $line); if(preg_match("/^TARGETZONE_CONQUERED/", $line)) {			echo "spawn_zone win $split[3] $split[4] 1000000 10000 0 0 false 0 0 0\n"; foreach($players as $p) filetee($p->name, $p->name, 3); }		sleep(1); if(!empty($split[6])) echo "center_message Winner: {$split[6]}\n"; echo "collapse_zone\n"; if(empty($split[6])) echo "spawn_zone win $xPos $yPos 1000000 10000 0 0 false 0 0 0\n"; $a_player_finished = true; }	if(preg_match("/^INVALID_COMMAND/", $line)) {		$split = explode(" ", $line); //INVALID_COMMAND /cast rx"dukevin 76.174.69.46 accesslevel argument 50		if($split[1] == "/stats" || $split[1] == "/s"|| $split[1] == "/search")		{			$obj = getObject($split[2]);			if(empty($split[6]) || !isset($split[6])) $split[6] = 3;			if(empty($split[5]) || !isset($split[5]))				$split[5] = $split[2];			search($obj, $split[5], $split[6]);		}		elseif($split[1] == "/version" || $split[1] == "/v" || $split[1] == "/ver" || $split[1] == "/vers")		{			$obj = getObject($split[2]);			version($obj);		}		elseif($split[1] == "/debug")		{			pm($split[2], "Number of maps rotating: " . count($includes));			pm($split[2], "Number pnames in memory: " . count($pretty));			pm($split[2], "Player Objects:");			foreach($players as $p)				pm($split[2], "$p->name");					}		else		{			pm($split[2], "0xff7777Invalid command, try 0xffffff/stats ");		}	}	if(preg_match("/^TARGETZONE_PLAYER_ENTER/", $line))	{		//TARGETZONE_PLAYER_ENTER 2 zonename 100 100 dukevin 90.8824 103.506 1 0 37.6366 $split = explode(" ", $line); $name = $split[5]; $time = $split[10]; $obj = getObject($name); if(!method_exists($obj,'finished')) {				c("0xffff77Warning: 0xffffffNo object to operate on, perhaps you just loaded scripts?"); echo "admin_kill_message 0\n"; echo "kill $name\n"; echo "admin_kill_message 1\n"; goto end; }		if($obj->finish_time > 0) //already hit the finish line goto end; $finished++; $obj->finished($time, $finished); $num_racers--; if($zombie_win) zombieplz($split[5], $split[6], $split[7]); @clock("start", $countdown_secs_after_finish); if($num_racers <= 0) echo "target_survive_time ". 1 ."\n"; }	if(preg_match("/^GAME_TIME/", $line)) {		@clock("tick"); if($max_time_limit <= 0) goto end; else {			$split = explode(" ", $line); if($split[1] == $max_time_limit) clock("start", $countdown_secs_after_finish, "kill"); }	}	if(preg_match("/^DEATH_FRAG|DEATH_SUICIDE|PLAYER_KILLED|DEATH_SHOT_FRAG|DEATH_DEATHZONE|DEATH_SHOT_SUICIDE|DEATH_TEAMKILL|DEATH_SHOT_TEAMKILL|DEATH_ZOMBIEZONE|DEATH_DEATHSHOT|DEATH_SELF_DESTRUCT/", $line)) {		$split = explode(" ", $line); if(empty(getObject($split[1])->finish_time)) $num_racers--; if(sizeof($players) <= 1) //if only 1 player, don't start the timer goto end; if($countdown_if_last_player == false) //don't start the timer if user doesn't want it			goto end; if($num_racers <= 1) {			if(@clock("getState") == "active" && (empty(getObject($split[1])->finish_time))) //only winner alive, last racer died &&racer not finish {				echo "spawn_zone win $xPos $yPos 1000000 100000 0 0 false 0 0 0\n"; foreach($players as $p) filetee($p->name, $p->name, 3); @clock("stop"); goto end; }			if($num_racers != 0) clock("start", $countdown_secs_after_finish + $countdown_last_player_extra_time, "kill"); }	}	if(preg_match("/^ROUND_WINNER/", $line)) foreach($players as $p) {			if(!(strstr($p->name, '@'))) pm($p->name, "0xffddaaYou should /login to protect your times!"); } end: }

function clock($action, $duration, $options) {	static $state, $time, $options; if($action == "start") {		if($state == "active") return; $state = "active"; $time = $duration; echo("center_message 0xff7777$time              \n"); }	if($action == "stop" || $state == "stopped") {		$state = "stopped"; $options = null; return; }	if($action == "tick") {		if($state == "stopped") return; $time--; echo("center_message 0xff7777$time              \n"); if(empty($time) || $time < 0) {			if($options = "kill") {				global $players; echo "admin_kill_message 0\n"; foreach($players as $p) echo "kill $p->name \n"; echo "admin_kill_message 1\n"; }			sleep(1); foreach($players as $p) filetee($p->name, $p->name, 3); $state = "stopped"; return; }	}	if($action == "getState") {		return $state; } } function filetee($search, $requester, $amount = 3, $display_top = false, $onlyrank = false) {	global $file; $found = false; $lines = file($file); foreach($lines as $i => $line) {		$pieces = explode(" ", $line); $pieces[1] = trim($pieces[1]); if($pieces[1] == $search) {				$found = true; if($onlyrank) return $i; break; }	}	if($display_top) $i = 0; if($amount > 150) $amount = 150; if($amount %2 == 0) $amount += 1; $amount = floor($amount/2); if($i == 0 || $i == sizeof($lines)-1) //display an extra entry for 1st and last place $amount += 1; if($found == false && $display_top == false) return false; for($x = $i-$amount; $x <= $i+$amount; $x++) {		$cut = explode(" ", $lines[$x]); $color = ($cut[1] == $search) ? '0xffff88' : '0xcccccc'; if(!empty($cut[0])) pm($requester, $color . ($x+1) . ") $cut[0] - $cut[1]");		usleep(20000);	} } function suffix($number) {	$n = (string)$number;   $n = $n[strlen($n)-1];	if($n == 1) $sufx = "st";	elseif($n == 2) $sufx = "nd";	elseif($n == 3) $sufx = "rd";	else $sufx = "th";	if($number == 11 || $number == 12 || $number == 13) //english is weird		$sufx = "th";	return $sufx; } function retrieve($mapname) {	$type = explode(".", $mapname);	if($type[sizeof($type)-1] == "xml") $head = "MAP_FILE";	elseif($type[sizeof($type)-1] == "cfg") $head = "INCLUDE";	$tail = $mapname;	echo $head . " " . $tail . "\n";	$cut = explode("/", $tail);	$split = explode(".", $cut[sizeof($cut)-1]);	foreach($split as $element)	{		if($element == "aamap" || $element == "xml" || $element == "cfg")			unset($element);		$current_inc .= $element;	}	$cut = explode("-", $current_inc);	$current_inc = trim($cut[0]);	if(empty($current_inc)) c("0xff7777Warning: 0xffffffUnable to retrieve current map name."); return empty($current_inc) ? "null" : $current_inc; }

function zombieplz($name, $x, $y) {	echo "spawn_zone zombieOwner $name $name $x $y 1 0 0 0 false\n"; } function c($string){ echo "console_message $string \n"; } function pm($name, $string){ echo "player_message {$name} \"{$string}\"\n"; } function getObject($name) {	global $players; foreach($players as $p) {		if($p->name == $name) return $p; }	foreach($players as $p) {		if($p->pname == $name) return $p; }	return false; } function pickmap($includes, $rotate_mode) {	static $i; if($rotate_mode == 1) return $includes[mt_rand(0, sizeof($includes)-1)]; if($rotate_mode == 2) {		if($i > sizeof($includes)-1 || empty($i)) $i = 0; $x = $i; $i++; return $includes[$x]; }	if($rotate_mode == 3) {		if($i > sizeof($includes)-1 || empty($i)) $i = 0; if($i == 0) shuffle($includes); $x = $i; $i++; return $includes[$x]; } } function smart_time($countdown_secs_after_finish) {	global $file, $current_inc; static $initial_countdown_secs; if(empty($initial_countdown_secs)) $initial_countdown_secs = $countdown_secs_after_finish; if($initial_countdown_secs < 100) $MAX_TIME = 75; //smart time will not allow more than 75 secs else $MAX_TIME = $initial_countdown_secs * 1.3; $lines = file($file); if(!file_exists($file))	return $initial_countdown_secs; $split = explode(" ", $lines[0]); $hs = $split[0]; $split = explode(" ", $lines[1]); $hs2nd = $split[0]; if(empty($hs)) return 60; if($hs*1.3 < $initial_countdown_secs) return $initial_countdown_secs; if(empty($hs2nd)) return $hs * 2 > $MAX_TIME ? $MAX_TIME : round($hs*2); if(($hs2nd - $hs) > 8) $hs = $hs2nd; return $hs * 1.3 > $MAX_TIME ? $MAX_TIME : round($hs*1.3); } function search($me, $search, $amount = 3) {	global $players; $count = 0; foreach($players as $p) {		if($p->pname == $search || $p->name == $search) {			$found = $p->name; $count = 1; break; }		if(stripos("{$p->pname}","$search") !== false || stripos("{$p->name}","$search") !== false) {			$count++; $found = $p->name; }	}	if($count > 1) pm($me->name, "More than one player containing '$search', using $found."); if(empty($count)) {		if(filetee($search, $me->name, $amount, false, false) == false) {			global $file; $lines = file($file); foreach($lines as $line) {				$pieces = explode(" ", $line); if(stripos("$pieces[1]","$search") !== false) {					$found = $pieces[1]; $count++; break; }			}		}	}	if(empty($found) || empty($count) || filetee($found, $me->name, -2, false, false) === false) {		pm($me->name, "No times found for player: $search"); return; }	filetee($found, $me->name, $amount, false, false); }

function version($me) {	pm($me->name, "0xffff00Script programming by 0xffffffdukevin"); pm($me->name, "0xffff00Email at 0xffffffdukevinjduke@gmail.com0xffff00 for suggestions, comments"); pm($me->name, "0xffff00Made for smart's server"); } /* known bugs: -/stats on rank 1 display twise -respawn breaks script +fixed: you should login to protect your times not showing -times showed twise if time run out -> instead make all score things shown before round_Commencing? - $me->num_plays doesn't incriment unless you beat your time //because it doesn't write + fixed x of y

?>