#!/usr/bin/php
<?php
/*
 Two Teams - Team Blue and Team Gold or as the log is concerned team_gold and team_blue
 Alternating Defenders and Attackers
*/

// How long will the round continue until all attackers are killed (seconds)
$round_time = 180;

// number of respawns for each player. ie. 2 respawns = 3 lives
$num_respawns = 2;

// colour for server messages
$server_message_colour = "0xff7700";

// bot objects
// create armagetron object
$armagetron = new player();
$armagetron->setname("armagetron"); 
$armagetron->setGridName("Armagetron"); 
// create gltron object
$gltron = new player();
$gltron->setname("gltron"); 
$gltron->setGridName("glTron"); 

function makeDeathMessage($gridname){
    global $server_message_colour;
    // ways to die
    $waystodie = array(
        " died whilst skydiving without a parachute high on crack.",
        "'s head got smashed in by two colliding trees which appeared from nowhere.",
        " was killed by a firing squad composed of friends and family.",
        " was followed home by a ninja warrior who sliced open their face with a samurai sword.",
        " got sucked into black hole. There was no parallel universe waiting.",
        " chocked on an apple and died a painful death.",
        " was frozen and preserved for museum exhibit.",
        " fell onto a sink.",
        " died from with sword through their forehead.",
        " slipped on a small dog and was eaten by a large cat.",
        " was eaten by cannibals.",
        " was stretched apart on a torture machine.",
        " had their face eaten by Hannibal Lecter.",
        " died from a fire escape ladder through the eye.",
        " was macheted in half while walking on their hands.",
        " was knocked into oblivion by a frog with a giant fist.",
        " was killed when an eagle dropped a live tortoise on him, mistaking his bald head for a stone.",
        " jumped into an active volcano.",
        " was killed when an old woman threw a roof tile at him.",
        " wasted away and starved to death.",
        " died of laughter after watching his drunk donkey attempt to eat figs.",
        " was crushed to death at the Battle of Beth-zechariah by a war elephant.",
        " was executed by the Romans.",
        " was skinned alive, his skin stuffed with dung then preserved as a trophy.",
        " was murdered by the mob.",
        " was captured and killed by the invading Mongols, who poured molten silver in his eyes, ears, and throat.",
        " was buried alive following their lapse into a coma.",
        " was fatally speared through the anus by a pikeman hiding under a bridge.",
        " was rumored to have been murdered by having a red-hot iron inserted into his anus.",
        " died from a lethal combination of indigestion and uncontrollable laughing.",
        " was executed by drowning in a barrel of wine at their own request.",
        " passed away peacefully at the age of 94.",
        " died of complications resulting from a strained bladder at a banquet.",
        " was beaten to death with their own wooden leg.",
        " died of a gangrenous abscess.",
        " died of overeating at a feast.",
        " was struck and killed by a globe of ball lightning.",
        " was crushed to death by the world's first mechanically powered passenger train.",
        " fell into a pit trap accompanied by a bull.",
        " died after a failed attempt to reach the North Pole in a balloon.",
        " fell to their death off the first deck of the Eiffel Tower.",
        " was shot in the head, shot three more times, bludgeoned, and then thrown into a frozen river.",
        " became the first person to die during a space mission.",
        " was electrocuted when they tried to change a light bulb.",
        " was the first known person to be killed by a robot.",
        " became the first known person to die while playing video games.",
        " walked into the tail rotor blade of a helicopter and was decapitated.",
        " toppled backwards off their chair fracturing their skull as they hit the ground."
    );   
    $msg=$waystodie[rand(0, (count($waystodie)-1))];
    return ("CONSOLE_MESSAGE " . $gridname . $server_message_colour . $msg . "\n");
};

// each team is an object with its own attributes
class team{   
    function team(){
        $this->name = "";
        $this->nicename = "";
        $this->role = "";
        $this->colour = "";
        $this->score = 0;
    }
    function setName($name){
        $this->name = $name;
    }
    function getName(){
        return $this->name;
    }
    function setNiceName($nicename){
        $this->nicename = $nicename;
    }
    function getNiceName(){
        return $this->nicename;
    }
    function setRole($role){
        $this->role = $role;
    }
    function getRole(){
        return $this->role;
    }
    function setColour($colour){
        $this->colour = $colour;
    }
    function getColour(){
        return $this->colour;
    }
    function setScore($score){
        $this->score = $score;
    }
    function addScore($score){
        $this->score += $score;
    }
    function getScore(){
        return $this->score;
    }
}

// Each player is an object.
class player{
    function player(){
        $this->name = "";
        $this->gridname = "";
        $this->role = "";
        $this->team = "";
        $this->colour = "";
        $this->respawns_remaining = -1;  
    }
    // set object Attributes
    function setName($name){
        $this->name = $name;
    }
    function setGridName($gridname){
        $this->gridname = $gridname;
    }
    function setRole($role){
        $this->role = $role;
    }
    function setTeam($team){
        $this->team = $team;
    }
    function setColour($colour){
        $this->colour = $colour;
    }
    function setRespawnsRemaining($respawns_remaining){
        $this->respawns_remaining = $respawns_remaining;
    }
    
    // get object attributes
    function getName(){
        return $this->name;
    }
    function getGridName(){
        return $this->gridname;
    }
    function getRole(){
        return $this->role;
    }
    function getTeam(){
        return $this->team;
    }
    function getColour(){
        return $this->colour;
    }
    function getRespawnsRemaining(){
        return $this->respawns_remaining;
    }
    // will this player get respawned?
    function maybeRespawn($server_message_colour){
        // if the player has respawns remaining, respawn
        if ( $this->respawns_remaining > 0 ){
            // make the respawn position somewhat randomised 
            $diff = 30;
            $minX = 250 - $diff;
            $maxX = 250 + $diff;
            $minY = 450 - $diff;
            $maxY = 450 + $diff;
            //print("RESP " . $minX . " " . $maxX . " ". $minY . " " . $maxY . "\n");
            $Xcoord = rand($minX, $maxX);
            $Ycoord = rand($minY, $maxY);
            // respawn the player
            print("RESPAWN_PLAYER " . $this->getName() . " 1 " . $Xcoord . " " . $Ycoord . " 0 -1\n");
            // build and print respawn message
            $respawn_msg = "CONSOLE_MESSAGE " . $this->getColour() . $this->getGridName() . " " . $server_message_colour . "has been respawned. ";
            $this->respawns_remaining--; //remove a life
            if ( $this->respawns_remaining > 1 ){
                $respawn_msg .= $this->respawns_remaining . " respawns remaining.\n";
            } else if ( $this->respawns_remaining == 1 ){
                $respawn_msg .= "1 respawn remaining.\n";
            } else if ( $this->respawns_remaining == 0 ) {
                $respawn_msg .= "Last Life. Use it wisely.\n";
            }
            print( $respawn_msg );
        } else {
            //print("CONSOLE_MESSAGE " . $this->getColour() . $this->getGridName() . " " . $server_message_colour . "has moved on to a better place.\n");
            print(makeDeathMessage($this->getColour() . $this->getGridName()));
            $this->respawns_remaining--;
        }
    } 
    // kill the player and output a message
    function kill($server_message_colour){
        if( $this->respawns_remaining >= 0 ){
            print("KILL " . $this->name . "\n");
            print("CONSOLE_MESSAGE " . $this->getColour() . $this->getGridName() . " " . $server_message_colour . "was killed due to their poor attack skills\n");
        }
    }
}

function killAttackers(){
    global $attackers, $nice_team_attack, $team_colour_attack, $server_message_colour;
    foreach( $attackers AS $player ){
        if ( is_object($$player) ){
            print("KILL $player\n");
            print("CONSOLE_MESSAGE " . $$player->getColour() . $player  . $server_message_colour . " was killed due to their poor attack skills\n");
        }
    }
    print("CONSOLE_MESSAGE " . $server_message_colour . "       ****************************************\n");    
    print("CONSOLE_MESSAGE " . $server_message_colour . "       *************** Time's Up **************\n");
    print("CONSOLE_MESSAGE " . $server_message_colour . "       ***** " . $team_colour_attack . $nice_team_attack . " " . $server_message_colour . "have been destroyed ****\n");  
    print("CONSOLE_MESSAGE " . $server_message_colour . "       ****************************************\n");    
}

function msgTimeRemaining($time_remaining){
    global $server_message_colour;
    print("CONSOLE_MESSAGE " . $server_message_colour . "       ****************************************\n");    
    print("CONSOLE_MESSAGE " . $server_message_colour . "       ********* $time_remaining Remaining. *********\n");  
    if ($time_remaining == "2 Minutes" || $time_remaining == "1 Minute "){
        msgScore();
    }
    print("CONSOLE_MESSAGE " . $server_message_colour . "       ****************************************\n");      
}

function msgScore(){
    global $team_defend, $nice_team_defend, $team_colour_defend, $server_message_colour;
    print("ADD_SCORE_TEAM $team_defend 5 " . $server_message_colour . "       ***** 5 Points Awarded to " . $team_colour_defend . $nice_team_defend . " " . $server_message_colour . "****\n");  
}

//for getting gridnames from ladderlog messages
function build_string_from_array($array, $startval){
	$str="";
	for ( $i=$startval; $i <= sizeof($array); $i++ ){
		$str .= $array[$i];
		$str .= " ";
	}
	return(trim($str));
}

function maybeSpawnZones($status){
    global $team_colour_defend, $nice_team_defend, $team_colour_attack, $nice_team_attack;
    if ( $status == false ){ //the zones have not yet been spawned
        print("spawn_zone fortress no_team 250 50 40 0 0 0 false\n");
        print("spawn_zone fortress no_team 250 600 1 0 0 0 false\n");
        print("CONSOLE_MESSAGE $team_colour_defend       ****************************************\n");    
        print("CONSOLE_MESSAGE $team_colour_defend       ********** $nice_team_defend Defend! ***********\n");
        print("CONSOLE_MESSAGE $team_colour_attack       ********** $nice_team_attack Attack! ***********\n");
        print("CONSOLE_MESSAGE $team_colour_attack       ****************************************\n");
        $status = true;
    } 
    return $status;
}

//set up some teams and basic attributes

$team_gold = new team();
$team_gold->setName("team_gold");
$team_gold->setNicename("Team Gold");
$team_gold->setColour("0xffff44");

$team_blue = new team();
$team_blue->setName("team_blue");
$team_blue->setNicename("Team Blue");
$team_blue->setColour("0x4488ff");

// Game loop
while (1)  {
    $line = rtrim(fgets(STDIN, 1024));   
    /* We need to keep an array of all players and their gridname. And remove them if they leave. Save on memory I guess.
    The gridname will be used for respawn messages
    entering:   
                PLAYER_ENTERED  sk33t_on_f33t   1.2.3.4  SK33T 0n F33t
                PLAYER_ENTERED  name            ip       gridname  
    Login, can happen at any time during round:    
                PLAYER_RENAMED  ct_kyle         kyle@ct     1.2.3.4     1           ct¤kyle
                PLAYER_RENAMED  oldname         newname     ip          authflag    gridname  
    Logout, anytime:
                PLAYER_RENAMED  Mkay1@forums    d;{d        1.2.3.4     0           d;{D
                PLAYER_RENAMED  oldname         newname     ip          authflag    gridname  
    Changing Gridname, only happens between rounds:
                PLAYER_RENAMED  passion         shoutless   1.2.3.4     0           Shoutless
                PLAYER_RENAMED  oldname         newname     ip          authflag    gridname
    Leaving the Arena:
                PLAYER_LEFT     Mkay1@forums    1.2.3.4
                PLAYER_LEFT     gridname        ip
    */
    if (preg_match("/^PLAYER_ENTERED /", $line)){
        $keywords = preg_split("/ /", $line);
        //create a new object for this player
        $$keywords[1] = new player();
        $$keywords[1]->setName($keywords[1]);       
        $$keywords[1]->setGridName(build_string_from_array($keywords, 3));       
    } else if (preg_match("/^PLAYER_RENAMED /", $line)){
        $keywords = preg_split("/ /", $line);
        //if new name is the same as old name just update the gridname. eg "Eddie" renamed to "eddie"
        if( $keywords[2] == $keywords[1] ){
            $$keywords[1]->setGridName(build_string_from_array($keywords, 5));
        } else {
            // create new player object based on the old object with the new names
            $$keywords[2] = new player();
            $$keywords[2]->setName($keywords[2]); 
            $$keywords[2]->setGridName(build_string_from_array($keywords, 5));
            $$keywords[2]->setRole($$keywords[1]->getRole());
            $$keywords[2]->setTeam($$keywords[1]->getTeam());
            $$keywords[2]->setColour($$keywords[1]->getColour());
            $$keywords[2]->setRespawnsRemaining($$keywords[1]->getRespawnsRemaining());           
            // if the person was an attacker, update array for end of time killing
            if ( $$keywords[2]->getRole() == "Attacker" ){
                $attackers[] = $keywords[2];
            }
            //destroy the old object
            unset($$keywords[1]);
        }
        
    } else if (preg_match("/^PLAYER_LEFT /", $line)){
        $keywords = preg_split("/ /", $line);
        //destroy the object
        unset($$keywords[1]);
    } 
 
    // reset match scores
    if (preg_match("/^NEW_MATCH /", $line)){
        $team_gold->setScore(0);
        $team_blue->setScore(0);
    } 
    
    //keep a record of teams' scores
    //ROUND_SCORE_TEAM 10 team_gold
    if (preg_match("/^ROUND_SCORE_TEAM /", $line)){
        $keywords = preg_split("/ /", $line);
        //print($line . " " . $keywords[2] . "\n");
        $$keywords[2]->addScore($keywords[1]);
    }
 
    if (preg_match("/^NEXT_ROUND/", $line)){
        //reset array of all attackers so they can be killed if they are unsucessful
        $attackers=array();
        // only kill attackers if this remains false
        $basezone_conquered = false;
        //let's set start positions
        //by default the losing team will be spawned first
        $spawn_status = false; //the zones have not yet been spawned
    }

    //SPAWN_POSITION_TEAM team_blue 0
    //SPAWN_POSITION_TEAM team_gold 1
    if (preg_match("/^SPAWN_POSITION_TEAM /", $line)){
        $keywords = preg_split("/ /", $line);
        //print($line . "\n");
        if ( $keywords[2] == 0 ){
            $$keywords[1]->setRole("Defence");
            $nice_team_defend = $$keywords[1]->getNicename();
            $team_colour_defend = $$keywords[1]->getColour();
            $team_defend = $keywords[1];
        } else {
            $$keywords[1]->setRole("Attack");
            $nice_team_attack = $$keywords[1]->getNicename();
            $team_colour_attack = $$keywords[1]->getColour();
            $team_attack = $keywords[1];
        }
    }

    // PLAYER_GRIDPOS ed@forums 240 550 0 -1 purple_persian
    // PLAYER_GRIDPOS armagetron 240 50 0 1 yellow_siamese	
	if (preg_match("/^PLAYER_GRIDPOS/", $line) && $game_time < 0 ){
        $keywords = preg_split("/ /", $line);
        //if this player is on the attacking team we will have to shrink their zone
        //also keep a record of their name so we can respawn them if they die      
        // set number of respawns remaining for each player
        //$respawns[$keywords[1]] = $num_respawns;
        //$gridplayer[$keywords[1]]['respawns_remaining'] = $num_respawns;
        $$keywords[1]->setRespawnsRemaining($num_respawns);
        
        if ( $keywords[6] == $team_attack ) {
            $attackers[] = $keywords[1];
            $$keywords[1]->setRole("Attacker");
            $$keywords[1]->setTeam($nice_team_attack);
            $$keywords[1]->setColour($team_colour_attack);           
        } else {
            $$keywords[1]->setRole("Defender");
            $$keywords[1]->setTeam($nice_team_defend);
            $$keywords[1]->setColour($team_colour_defend);
        }
    }

    if ( preg_match("/^GAME_TIME/", $line) ){
        $keywords = preg_split("/ /", $line);
        $game_time=$keywords[1];
        if ( $game_time  < 0 ) {
            //spawn zones as early as possible
            // zones could easily be included in the map, but when spawned from script they are spawned earlier
            // let helps let people know their role quicker and plan their actions
            $spawn_status = maybeSpawnZones($spawn_status);
        } else if ( $game_time  == 0 ) {
            msgTimeRemaining("3 Minutes");
        } else if ( $game_time  == ($round_time - 120) && !$basezone_conquered ) {
            msgTimeRemaining("2 Minutes");
        } else if ( $game_time  == ($round_time - 60) && !$basezone_conquered ) {
            msgTimeRemaining("1 Minute ");
        } else if ( $game_time  == ($round_time - 30) && !$basezone_conquered ) {
            msgTimeRemaining("30 Seconds");
        } else if ( $game_time  == ($round_time - 10) && !$basezone_conquered ) {
            msgTimeRemaining("10 Seconds");
        } else if ( $game_time  == ($round_time - 5) && !$basezone_conquered ) {
            msgTimeRemaining("5 Seconds");
        } else if ( $game_time  == $round_time && !$basezone_conquered ) {    
            //killAttackers();
            foreach( $attackers AS $player ){
                if ( is_object($$player) ){
                    $$player->kill($server_message_colour);
                }
            }
            print("CONSOLE_MESSAGE " . $server_message_colour . "       ****************************************\n");    
            print("CONSOLE_MESSAGE " . $server_message_colour . "       *************** Time's Up **************\n");
            print("CONSOLE_MESSAGE " . $server_message_colour . "       ***** " . $team_colour_attack . $nice_team_attack . " " . $server_message_colour . "have been destroyed ****\n");  
            print("CONSOLE_MESSAGE " . $server_message_colour . "       ****************************************\n");   
        }       
    }

    // Capture deaths and respawn if on attacking team
	//// DEATH_FRAG dumped dumper ///////////////////////////////////////
	////////////////////////////////////////////////////////////////////////
	if (preg_match("/^DEATH_FRAG/", $line) || preg_match("/^DEATH_TEAMKILL/", $line) || preg_match("/^DEATH_SUICIDE/", $line)){
		$keywords = preg_split("/ /", $line);
        $$keywords[1]->maybeRespawn($server_message_colour);
    }
   
    ////BASEZONE_CONQUERED
	if (preg_match("/^BASEZONE_CONQUERED/", $line)){
        $basezone_conquered = true; //stops the server killing the winning team
    }
}
?>