////////////////////////////////////////////////////////////////////////////////////
//
// Team Rabbit for Tribes 1
// (c) 2001, Michael Johnston
// This code may not be re-distributed without the written permission of the author.
// Inspired by Rabbit (Eric Lanz) and Imperial Elite practices
//
// CODE, DESIGN
// Michael Johnston (KineticPoet)
//
// DESIGN, CO-ORDINATION
// Eric Chu (Special)
//
// MAPS
// true, Special, daunt
//
// http://www.kineticpoet.com/trabbit/
// info@kineticpoet.com
//
/////////////////////////////////////////////////////////////////////////////////////
$TRabbit::versionString = "v0.72 beta";

exec("game.cs");  
exec("trinit.cs");
exec("trstatics.cs");
exec("trhudinterface.cs");

// All bonus info can be found in the following file...it is the heart and soul of TR
exec("trbonuses.cs");

// Fundamental game settings
$TRabbit::potatoTimeLimit = 20;		// Time until hot potato
$TRabbit::teamTimeLimit = 90;		// Anti-hog time
$TRabbit::updateTimeSlice = 1;		// Dynamic info update frequency
$TRabbit::minFlagMove = 5;		// Anti-camp minimum movement
$TRabbit::bonusFlagTimeout = 22;	// Crazy flag timeout
$TRabbit::shuffleScoreDifference = 25;	// Don't shuffle if last game was close
$TRabbit::pointsPerTimeSlice = 1;	// Points to award for each scoreTimer slice
$TRabbit::scoreTimer = 5;  		// Length of scoreTimer slice
$TRabbit::repeatedGrabRestriction = 6;  // Seconds between successive grabs by single player
$flagReturnTime = 9;  			// Flag return time
$TRabbit::minimumClientsForRecords = 8; // Need this many players for world records
$TRabbit::rulesDelay = 10;		// Seconds to display rules when player joins

// Not used:
$TRabbit::roughnessDistance = 200;	// Unnecessary roughness (distance from flag)
$TRabbit::roughnessThreshold = 5.0;	// Amount of damage before action is taken


$TRabbit::rules = "<jc><f1>You get <f2>POINTS<f1> for <f2>PASSING<f1> the flag\n-\n"
		@ "<f1>Go for <f2>HIGH<f1> and <f2>FAST<f1> passes\n-\n"
		@ "<f1>Don't allow <f2>INTERCEPTIONS<f1>\n-\n"
		@ "<f1>Only <f2>SHOOT<f1> when necessary\n\n\n"
		@ "<f0>Please be patient.  You will spawn soon.";

// Init some globals (not strictly necessary, mostly for reference)
$TRabbit::banListCount = 0;  //used to create list of disallowed items
$TRabbit::LongestFlagHeld = 0;  //used to hold longest time flag held consecutively
$TRabbit::PlayerHoldingLongest ="";  //player who held flag longest consecutive time
$TRabbit::Carrier = -1;  //used to hold ID of current flag carrier
$TRabbit::lastToPassThrough = "";  //used to see who got last point for holding flag
$TRabbit::flagDropper ="";
$TRabbit::flagGrabber ="";
$TRabbit::lastPassID = "";
$TRabbit::lastDropTime = "";
$TRabbit::thisDropTime = "";
$TRabbit::lastGrabTime = "";
$TRabbit::currentSequenceCount = 0;
$TRabbit::flagDropVelocity ="";
$TRabbit::flagDropSpeed ="";
$TRabbit::flagDropPosition ="";
$TRabbit::flagPickupVelocity ="";
$TRabbit::flagPickupPosition ="";
$TRabbit::flagPosition ="";
$TRabbit::dropperVelocity ="";
$TRabbit::grabberVelocity ="";
$TRabbit::teamGrabTime = "";
$TRabbit::performDynamicUpdate = False;
$flaggerSpeed = 0;

// Scoring
$teamScoreLimit = 1500;
$TRabbit::TimeScore[0] = 0;
$TRabbit::TimeScore[1] = 0;
$TRabbit::StyleScore[0] = 0;
$TRabbit::StyleScore[1] = 0;

// Miscellaneous fun bonus thresholds
$TRabbit::bonusBeaconStopSpeed = 34;
$TRabbit::bonusBeaconStopThreshold = 7;
$TRabbit::midairDiscDamageThreshold = 0.35;

// Pass IDs
$deadPassID = 0;
$normalPassID = 1;
$midairPassID = 2;

// Award IDs
$bestPlayerAwardID = 0;
$bestPasserAwardID = 1;
$bestReceiverAwardID = 2;
$bestInterceptorAwardID = 3;
$bestDiscsKILLzAwardID = 4;
$bestFlaggerFraggerAwardID = 5;
$speedAwardID = 6;
$heightAwardID = 7;
$numAwards = 8;

// Awards
$TRabbit::awardPlayerName = "";
$TRabbit::awardValue = "";
$TRabbit::recordPlayerName = "";
$TRabbit::recordValue = "";
$TRabbit::awardDescription[$bestPlayerAwardID] = "Best Player";
$TRabbit::awardDescription[$bestPasserAwardID] = "Best Passer";
$TRabbit::awardDescription[$bestReceiverAwardID] = "Best Receiver";
$TRabbit::awardDescription[$bestInterceptorAwardID] = "Best Interceptor";
$TRabbit::awardDescription[$bestDiscsKILLzAwardID] = "Best Disc sKILLz";
$TRabbit::awardDescription[$bestFlaggerFraggerAwardID] = "Best Flagger Fragger";
$TRabbit::awardDescription[$speedAwardID] = "Speed Record";
$TRabbit::awardDescription[$heightAwardID] = "Height Record";
$TRabbit::awardValueType[$bestPlayerAwardID] = "pts";
$TRabbit::awardValueType[$bestPasserAwardID] = "pts";
$TRabbit::awardValueType[$bestReceiverAwardID] = "pts";
$TRabbit::awardValueType[$bestInterceptorAwardID] = "pts";
$TRabbit::awardValueType[$bestDiscsKILLzAwardID] = "MA's";
$TRabbit::awardValueType[$bestFlaggerFraggerAwardID] = "pts";
$TRabbit::awardValueType[$speedAwardID] = "km/h";
$TRabbit::awardValueType[$heightAwardID] = "m";

// Miscellaneous IDs
$PotatoDamageType = -100;


// Remember original MOTD
function TRabbit::rememberSettings() {
	if ($TRabbit::origJoinMOTD == "")
		$TRabbit::origJoinMOTD = $Server::JoinMOTD;
	for (%i = 0; %i <= 7; %i++) {
		if ($TRabbit::origTeamName[%i] == "")
			$TRabbit::origTeamName[%i] = $Server::teamName[%i];
		if ($TRabbit::origTeamSkin[%i] == "")
			$TRabbit::origTeamSkin[%i] = $Server::teamSkin[%i];
	}
}

TRabbit::rememberSettings();

$Server::teamName0 = "Bunnies";           
$Server::teamName1 = "Wabbits";  

///////////////////////////////////////////////////////////////////////////////////////////////
// Initialization functions
///////////////////////////////////////////////////////////////////////////////////
function TRabbit::setJoinMOTD(){
   %line1 = "<Jc><f2>Team Rabbit " @ $TRabbit::versionString @ "<f1>\n";
   %line2 = "\n";
   %line3 = "<Jc><f0>Code, Design\n<f1>Michael Johnston (KineticPoet)\n\n";
   %line4 = "<Jc><f0>Design, Co-ordination\n<f1>Eric Chu (Special)\n\n";
   %line5 = "<Jc><f0>Inspirations\n<f1>[IE], Eric Lanz, Ben Steidl\n\n";
   %line6 = "<jc><f0>Maps\n<f1>true, Special, daunt\n\n";   
   //%line7 = "<Jc><f0>Press 'O' for game objectives & rules<f1>";
   //%line7 = "\n";
   //%line8 = "<Jc><f2>Press fire!\n";

   $Server::JoinMOTD = ""; //clear old message out
   for (%i = 1; %i <= 6; %i++){
      $Server::JoinMOTD = $Server::JoinMOTD @ %line[%i];
   }
}

function Mission::init(){
   //  echo("DEBUG : MissionInit called");
   setClientScoreHeading ("Player Name\t\x6FTeam\t\xA6Score\t\xCFPing\t\xEFPL");
   $firstTeamLine = 7;
   setTeamScoreHeading("Team Name\t\xD6Score");
   $firstObjectiveLine = $firstTeamLine + 2 + 1;
   for(%i = -1; %i < 2; %i++)
   {
      $teamScore[%i] = 0;
      newObject("TeamDrops" @ %i, SimSet);
      addToSet(MissionCleanup, "TeamDrops" @ %i);
      %dropSet = nameToID("MissionGroup/Teams/Team" @ %i @ "/DropPoints/Random");
      for(%j = 0; (%dropPoint = Group::getObject(%dropSet, %j)) != -1; %j++)
         addToSet("MissionCleanup/TeamDrops" @ %i, %dropPoint);
   }
   $numObjectives = 0;
   newObject(ObjectivesSet, SimSet);
   addToSet(MissionCleanup, ObjectivesSet);
   
   Group::iterateRecursive(MissionGroup, ObjectiveMission::initCheck);
   %group = nameToID("MissionCleanup/ObjectivesSet");
 
   for(%i = 0; (%obj = Group::getObject(%group, %i)) != -1; %i++)
   {
      %obj.objectiveLine = %i + $firstObjectiveLine;
   }

  $CorpseTimeoutValue = 3;

   // Borrowed from arena
   $TeamItemCount[0,HeavyArmor] = 0;
   $TeamItemCount[1,HeavyArmor] = 0;
   $TeamItemCount[0,LaserRifle] = 0;
   $TeamItemCount[1,LaserRifle] = 0;
   $TeamItemMax[HeavyArmor] = 0; 
   $TeamItemMax[LaserRifle] = 1;

   $Server::teamName0 = "Bunnies";           
   $Server::teamName1 = "Wabbits";     

   ObjectiveMission::refreshTeamScores();

   $TRabbit::Carrier.potatoTime = 0;
   $TRabbit::Carrier.isHot = False;
   $TRabbit::Carrier.speed = 0;
   $TRabbit::lastPassID = "";
   $TRabbit::lastDropTime = "";
   $TRabbit::thisDropTime = "";
   $TRabbit::lastGrabTime = "";
   $TRabbit::currentSequenceCount = 0;
   $TRabbit::SpecialGrab = "";
   $TRabbit::SpecialTime = 0;
   $TRabbit::flagAtHome = true;
   $TRabbit::teamThatGrabbed = "";
   $TRabbit::teamGrabTime = "";
   $TRabbit::killPenalty = True;



   // Award initialization
   for (%i = 0; %i < $numAwards; %i++) {
	$TRabbit::awardPlayerName[%i] = "n/a";
  	$TRabbit::awardValue[%i] = 0;
   }

   for(%cl = Client::getFirst(); %cl != -1; %cl = Client::getNext(%cl))
   {
      %cl.score = 0;
      Game::refreshClientScore(%cl);
   }

   AI::setupAI();
   TRabbit::setJoinMOTD();
   TRabbit::invalidateItems();
   //TRabbit::objectivesScreen();   

   $TRabbit::performDynamicUpdate = True;
   updateDynamicInfo();
}

// Called when a player joins the game
function TRabbit::JoinInit(%clientId){
   $TRabbit::PlyrNumGrabs[%clientId] = 0;
   $TRabbit::PlyrNumInterceptions[%clientId] = 0;
   $TRabbit::PlyrNumKTS[%clientId] = 0;
   $TRabbit::PlyrTtlFlagHeld[%clientId] = 0;
   $TRabbit::PlyrNumBeaconStops[%clientId] = 0;
   $TRabbit::PlyrAvgVelocity[%clientId] = 0;
   $TRabbit::PlyrNumMidairDiscs[%clientId] = 0;
   $TRabbit::PlyrNumFlaggerKills[%clientId] = 0;
   $TRabbit::PlyrNumFlagDrops[%clientId] = 0;
   $TRabbit::PlyrNumCompletions[%clientId] = 0;
   $TRabbit::PlyrNumTeamKills[%clientId] = 0;
   $TRabbit::PlyrNumGeorgesonBackstabs[%clientId] = 0;
   $TRabbit::PlyrNumReceptions[%clientId] = 0;
   $TRabbit::PlyrScoreContribution[%clientId] = 0;
   $TRabbit::PlyrPassPoints[%clientId] = 0;
   $TRabbit::PlyrReceivePoints[%clientId] = 0;
   $TRabbit::PlyrInterceptionPoints[%clientId] = 0;
   $TRabbit::PlyrShootingPoints[%clientId] = 0;
   $TRabbit::PlyrUnnecessaryRoughness[%clientId] = 0;
   //$TRabbit::ObserverZoom[%clientId] = out;
   //$TRabbit::ObserverRotation[%clientId] = "";
   //$TRabbit::ObserverZoomDir[%clientId] = 14;
   //$TRabbit::ObserverZoomFlag[%clientId] = false;
   $TRabbit::ObserverFirstPerson[%clientId] = false;

   Game::refreshClientScore(%clientId);
}


///////////////////////////////////////////////////////////////////////////////////////////////
// Display functions (scoring and objectives)
///////////////////////////////////////////////////////////////////////////////////
function remoteObjectivesMode(%clientId)
{
   if(!%clientId.guiLock || (Client::getTeam(%clientId) < 0))
   {
      TRabbit::displayFinalScores();
      remoteSCOM(%clientId, -1);
      Client::setGuiMode(%clientId, $GuiModeObjectives);
   }
}

function TRabbit::objectivesScreen(){                                                           
   if ($timeLimitReached)
      TRabbit::displayFinalScores(true);
   else
      TRabbit::displayFinalScores(false);
}

function TRabbit::displayFinalScores(%showWinningTeam){
   //TRabbit::FlagHeldCheck(); //see if a player still holding flag
   TRabbit::getAvgHolds();	 //get players' avg times
   TRabbit::getLongestFlag();	//get name and time of longest holder
   
   %numClients = getNumClients();                                  
   for(%i = 0 ; %i < %numClients ; %i++)                           
      %clientList[%i] = getClientByIndex(%i);                      
   %doIt = 1;                                                      
   while(%doIt == 1){                                              
      %doIt = "";                                                  
      for(%i= 0 ; %i < %numClients; %i++) {                        
         if((%clientList[%i]).score < (%clientList[%i+1]).score) { 
            %hold = %clientList[%i];                               
            %clientList[%i] = %clientList[%i+1];                   
            %clientList[%i+1]= %hold;                              
            %doIt=1;                                               
         }                                                         
      }                                                            
   }

   if ($teamScore[0] == $teamScore[1]) {
	%winningTeam = 0;
	%losingTeam = 1;
	%tie = True;
   }
   else if ($teamScore[0] > $teamScore[1]) {
	%winningTeam = 0;
	%losingTeam = 1;
   } else {
	%winningTeam = 1;
	%losingTeam = 0;
   }

   // Determine awards
   for(%i = 0 ; %i < %numClients ; %i++) {                           
	%plyr = %clientList[%i];
	evaluateAward($bestPlayerAwardID, %plyr, $TRabbit::PlyrScoreContribution[%plyr]); 
	evaluateAward($bestPasserAwardID, %plyr, $TRabbit::PlyrPassPoints[%plyr]); 
	evaluateAward($bestReceiverAwardID, %plyr, $TRabbit::PlyrReceivePoints[%plyr]); 
	evaluateAward($bestInterceptorAwardID, %plyr, $TRabbit::PlyrInterceptionPoints[%plyr]);
	%discValue = $TRabbit::PlyrNumMidairDiscs[%plyr] + ($TRabbit::PlyrNumGeorgesonBackstabs[%plyr] / 100); 
	evaluateAward($bestDiscsKILLzAwardID, %plyr, %discValue); 
	evaluateAward($bestFlaggerFraggerAwardID, %plyr, $TRabbit::PlyrShootingPoints[%plyr]);
   }

   %winningTeamName = getTeamName(%winningTeam);
   %winningTeamScore = $teamScore[%winningTeam];

   for(%l = -1; %l < 2 ; %l++) {
      %lineNum = 0;
  	if (%showWinningTeam && %tie)
        	Team::setObjective(%l, %lineNum++, "<f5>Tie game!");
	else if (%showWinningTeam) {
		
      Team::setObjective(%l, %lineNum++, "<f5>Team " @ %winningTeamName @ " wins!");
      Team::setObjective(%l, %lineNum++, " " );
     }
      Team::setObjective(%l, %lineNum++, "<f5>" @ getTeamName(%winningTeam) @ "<L27>Score:  " @ $teamScore[%winningTeam]);
      Team::setObjective(%l, %lineNum++, "<f5>" @ getTeamName(%losingTeam) @ "<L27>Score:  " @ $teamScore[%losingTeam]);
   
      Team::setObjective(%l, %lineNum++, " " );
      Team::setObjective(%l, %lineNum++, "<f3>Player Name<L27>Team<L40>Style<L51>Passes<L62>Pass%<L73>Rcptn's<L84>Intcp's<L95>fcKills<L105>MA's<L113>KTS");
      for(%i = 0; %i < %numClients; %i++){
         %plyr = %clientList[%i];
	 %plyrTeam = GameBase::getTeam(%plyr);
	 %numCompletions = $TRabbit::PlyrNumCompletions[%plyr];
	 %numFlagDrops = $TRabbit::PlyrNumFlagDrops[%plyr];
	 if ($TRabbit::PlyrNumFlagDrops[%plyr] == 0)
		%completionPercentage = 0;
	 else
	 	%completionPercentage = floor((%numCompletions / %numFlagDrops) * 100);
	if (%plyrTeam >= 0) {
         Team::setObjective(%l, %lineNum++, "<f1> - " 
		@ Client::getName(%plyr)
		@ "<L27>" @ getTeamName(%plyrTeam)
		@ "<L40>" @ $TRabbit::PlyrScoreContribution[%plyr]
		@ "<L51>" @ %numCompletions @ " (" @ $TRabbit::PlyrPassPoints[%plyr] @ ")"
		@ "<L62>" @ %completionPercentage @ "%"
		@ "<L73>" @ $TRabbit::PlyrNumReceptions[%plyr] @ " (" @ $TRabbit::PlyrReceivePoints[%plyr] @ ")"
		@ "<L84>" @ $TRabbit::PlyrNumInterceptions[%plyr] @ " (" @ $TRabbit::PlyrInterceptionPoints[%plyr] @ ")"
		@ "<L95>" @ $TRabbit::PlyrNumFlaggerKills[%plyr] @ " (" @ $TRabbit::PlyrShootingPoints[%plyr] @ ")"
		@ "<L105>" @ $TRabbit::PlyrNumMidairDiscs[%plyr] 
		@ "<L113>" @ $TRabbit::PlyrNumKTS[%plyr]);
	}
      }     

      Team::setObjective(%l, %lineNum++, " " );

      Team::setObjective(%l, %lineNum++, " " );
      Team::setObjective(%l, %lineNum++, "<L34><f3>THIS MATCH<L87><f0>SERVER RECORD");
      Team::setObjective(%l, %lineNum++, "<f3>Award<L34>Name<L65>Value<L87><f0>Name<L118>Value");

      // Display awards
      for (%i = 0; %i < $numAwards; %i++) {
      	Team::setObjective(%l, %lineNum++, "<f1> - " @ $TRabbit::awardDescription[%i] @
		"<L34>" @ $TRabbit::awardPlayerName[%i] @
		"<L65>" @ floor($TRabbit::awardValue[%i]) @ " " @ $TRabbit::awardValueType[%i] @
		"<L87>" @ $TRabbit::recordPlayerName[%i] @
		"<L118>" @ floor($TRabbit::recordValue[%i]) @ " " @ $TRabbit::awardValueType[%i]);
      }
 
      for(%s = %lineNum+1; %s < 30 ;%s++)	 //clear any remaining text
         Team::setObjective(%l, %s, " ");
   }
   $timeLimitReached = "";

   // Shuffle the teams based on Style points 
   %teamSwitcher = 0;
   %scoreDiff = $teamScore[%winningTeam] - $teamScore[%losingTeam];
   if (%showWinningTeam && !$Server::TourneyMode && (%scoreDiff >= $TRabbit::shuffleScoreDifference)) {
   	for(%i = 0; %i < %numClients; %i++){
		%plyr = %clientList[%i];
		%plyrTeam = GameBase::getTeam(%plyr);
		if (%plyrTeam >= 0) {
			GameBase::setTeam(%plyr, %teamSwitcher);
			if (%teamSwitcher == 0)
				%teamSwitcher = 1;
			else
				%teamSwitcher = 0;
		}			
	}
    }
   if (%showWinningTeam)
	TRabbit::restoreServerDefaults();
}

// Scores and stats here
function ObjectiveMission::refreshTeamScores()
{
   %nt = getNumTeams();
   // edit:  hide the flag team
   %nt--;
   Team::setScore(-1, "%t\t  0", 0);
   for(%i = -1; %i < %nt; %i++)
      Team::setScore(%i, "%t\t  " @ $teamScore[%i], $teamScore[%i]);
   TRabbit::displayFinalScores();
}

// tab
function Game::refreshClientScore(%clientId){
   %team = Client::getTeam(%clientId);
   if(%team == -1) // observers go last.
      %team = 9;

   %score = 	$TRabbit::PlyrScoreContribution[%clientId];
   %clientId.score = %score;
   // objective mission sorts by team first.
   Client::setScore(%clientId, "%n\t%t\t  " @ %score  @ "\t%p\t%l", %score + (9 - %team) * 10000);
   //Client::setScore(%clientId, "%n\t%t\t\t%p\t%l", 0);

}

function TRabbit::updateTeamScores(){	
	echo("Updating team scores");	
	for (%i = 0; %i < 2; %i++){
		echo("SCOREDATA: " @ %i @ " has " @ $TRabbit::StyleScore[%i] @ " points.");
		$teamScore[%i] = ($TRabbit::TimeScore[%i] + $TRabbit::StyleScore[%i]);
	}
	ObjectiveMission::refreshTeamScores();
}

function evaluateAward(%awardID, %playerID, %value) {
	if (Client::getTeam(%playerId) < 0)
		return;

	%playerName = Client::getName(%playerID);

	// Check the match record
	if (%value > $TRabbit::awardValue[%awardID]) {
		$TRabbit::awardValue[%awardID] = %value;
		$TRabbit::awardPlayerName[%awardID] = %playerName;
	}

	// Check the server record
	// Only set records if there are a minimum number of clients present
	// (but always check speed and height record)
	if ((getNumClients() > $TRabbit::minimumClientsForRecords) ||
	    (%awardID == $speedAwardID) || (%awardID == $heightAwardID))
	    if(%value > $TRabbit::recordValue[%awardID]) {
		$TRabbit::recordValue[%awardID] = %value;
		$TRabbit::recordPlayerName[%awardID] = %playerName;
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////
// Timing functions
///////////////////////////////////////////////////////////////////////////////////
function Game::checkTimeLimit(){
   // if no timeLimit set or timeLimit set to 0,
   // just reschedule the check for a minute hence
   $timeLimitReached = false;
   if(!$Server::timeLimit){
      schedule("Game::checkTimeLimit();", 60);
      return;
   }
   %curTimeLeft = ($Server::timeLimit * 60) + $missionStartTime - getSimTime();
   if(%curTimeLeft <= 0){
      $timeLimitReached = true;
      $TRabbit::performDynamicUpdate = False;
      TRabbit::objectivesScreen();
      export("$TRabbit::record*", "config\\trRecords.cs", False);
      for (%i = 0; %i < $numAwards; %i++) {
	$TRabbit::awardPlayerName[%i] = "n/a";
	$TRabbit::awardValue[%i] = 0;
      }
      TRabbit::restoreServerDefaults();
      Server::nextMission();
   }
   else{
   // wierdness here, usually overruns timelimit before ending
//      echo("DEBUG : checking time limit every  20 seconds " @ getSimtime());
      schedule("Game::checkTimeLimit();", 1);
      UpdateClientTimes(%curTimeLeft);
   }
}

// Updates player speed once per timeslice (disabled for now)
// Checks post-grab info and hot potato time
function updateDynamicInfo()
{
	if ($TRabbit::Carrier > 0){
		%player = Client::getOwnedObject($TRabbit::Carrier);
		%carrierVelocity = Item::getVelocity(%player);
		$TRabbit::CarrierSpeed = Vector::getDistance(%carrierVelocity, "0 0 0") * 3.6;
		//echo("DEBUG: carrier speed is " @ $flaggerSpeed);
   		$TRabbit::Carrier.potatoTime += $TRabbit::updateTimeSlice;

   		%player = $TRabbit::Carrier;
   		%playerPosition = GameBase::getPosition(%player);
   		%playerVelocity = Item::getVelocity(%player);
   		%playerSpeed = Vector::getDistance(%playerVelocity, "0 0 0");
   		%playerHeight = getWord(%playerPosition, 2);

   		%playerName = Client::getName($TRabbit::Carrier);
   
   		// 5-second post-grab messages
   		if ($TRabbit::Carrier.potatoTime == 5){
			%realPlayerSpeed = %playerSpeed * 3.6;
			if (%playerSpeed > 50)
				MessageAll(2, %playerName @ " goes SUPERFAST at " @ %realPlayerSpeed @ " km/h!~wwind1.wav");
			else if (%playerSpeed > 20)
				MessageAll(2, %playerName @ " is cruising at " @ %realPlayerSpeed @ " km/h.");

			evaluateAward($speedAwardID, $TRabbit::Carrier, %realPlayerSpeed);
  		 }
   		// 10-second post-grab messages
  		 else if ($TRabbit::Carrier.potatoTime == 10){
			if (%playerHeight > 280) {
				MessageAll(2, %playerName @ " has HUGE air, " @ %playerHeight @ " metres!~wWind2.wav");
				evaluateAward($heightAwardID, $TRabbit::Carrier, %playerHeight);
			}
   		}

   		// Hot potato warning
   		else if ($TRabbit::Carrier.potatoTime == ($TRabbit::potatoTimeLimit - 5)){
    		     MessageAllExcept($TRabbit::Carrier, 0, "The flag is getting hot!");
    		     Client::sendMessage($TRabbit::Carrier, 1, "Hot potato in 5 seconds!  Get ready to pass!~wLeftMissionArea.wav");
  		 }

   		if ($TRabbit::Carrier.potatoTime >= $TRabbit::potatoTimeLimit){
    		     Client::sendMessage($TRabbit::Carrier, 1, "Hot potato!  Pass the flag!~wLeftMissionArea.wav");
     		    $TRabbit::Carrier.isHot = True;
		    schedule("hotPotatoDamage();",1);  
  		 }

	}

	else {
		$TRabbit::CarrierSpeed = 0;
		$TRabbit::Carrier.potatoTime = 0;
		$TRabbit::Carrier.isHot = False;
	}
     	if ($TRabbit::performDynamicUpdate)
		schedule("updateDynamicInfo();", $TRabbit::updateTimeSlice);
}

// Repeatedly damage the flag carrier after a certain amount of time
function hotPotatoDamage(){                           
    if ($TRabbit::Carrier < 0)
	return;                 
    %client = $TRabbit::Carrier;
    %player = Client::getOwnedObject(%client);
    //Player::blowUp(%player);                                        
    if(%client.isHot){                                                                                                                                         
         if(!Player::isDead(%player)){                                                  
           	Player::setDamageFlash(%client,0.1);  
		%damage = GameBase::getDamageLevel(%player);                                 

           	GameBase::setDamageLevel(%player,%damage + 0.05); 
 	   	schedule("hotPotatoDamage();",1);
	   	if(Player::isDead(%player)){
             		//playNextAnim(%client);
	     		//%curDie = $PlayerAnim::DieBlownBack;//$PlayerAnim::DieSpin;
	     		//Player::setAnimation(%player, %curDie);
             		//playNextAnim(%client);
         		Player::blowUp(%player);
             		Client::onKilled(%client, %client, $PotatoDamageType); 
	   	}  
	  }                                                                                                                    
    }                                                                                                          
}       

// Scheduled immediately after flag drop, slightly delayed
function delayedFlagVelocity(%player, %flag){
  $TRabbit::flagDropVelocity = Item::getVelocity(%flag);
  echo("POST-DROPOFF : checking flag velocity " @ $TRabbit::flagDropVelocity);
  
  %playerClient = Player::getClient(%player);
  %playerName = Client::getName(%playerClient);
  $TRabbit::flagDropSpeed = Vector::getDistance($TRabbit::flagDropVelocity,"0 0 0");
  echo("POST-DROPOFF : checking flag speed " @ $TRabbit::flagDropSpeed);

}

function TRabbit::flagPointTimer(){
   if ($TRabbit::Carrier == "")
	return;

   %player = Client::getOwnedObject($TRabbit::Carrier);
   %currentTime = getSimTime();  
   if ($TRabbit::lastToPassThrough == ""){
      TRabbit::InitNewFlagCarrier();
      return;
   }
   if ($TRabbit::Carrier != $TRabbit::lastToPassThrough){
      echo(Client::getName($TRabbit::LastToPassThrough) @ " is no longer Flag Carrier, no points awarded - simtime : " @ getsimTime());  
      $TRabbit::lastToPassThrough = "";
      return; //flag carrier changed, kill thread
   }

   %carrierTeam = GameBase::getTeam($TRabbit::Carrier);
   //$TRabbit::Carrier.score += $TRabbit::pointsPerTimeSlice;
   $TRabbit::TimeScore[%carrierTeam] += $TRabbit::pointsPerTimeSlice;
   $TRabbit::PlyrScoreContribution[$TRabbit::Carrier] += $TRabbit::pointsPerTimeSlice;
   Game::refreshClientScore($TRabbit::Carrier);

   TRabbit::updateTeamScores();


   // Team grab time bonus stuff
   echo("SUPERBONUS: current = " @ %currentTime @ "  grab = " @ $TRabbit::teamGrabTime);
   echo("SUPERBONUS:  limit = " @ $TRabbit::teamTimeLimit);
   //if ((%currentTime - $TRabbit::teamGrabTime) > ($TRabbit::teamTimeLimit - 5)) {
	//MessageAll(2, "Super bonus in " @ $TRabbit::scoreTimer @ " seconds!");
   //}
   //else if ((%currentTime - $TRabbit::teamGrabTime) > $TRabbit::teamTimeLimit) {
//	funTest();
//	MessageAll(2, "SUPER BONUS!");
  //}

   Game::refreshClientScore($TRabbit::Carrier);
   //echo("DEBUG : Awarding Point to " @ Client::getName($TRabbit::Carrier) @ "simtime : " @ getsimtime());

   schedule ("TRabbit::flagPointTimer();", $TRabbit::scoreTimer);
}


///////////////////////////////////////////////////////////////////////////////////////////////
// Flag functions
///////////////////////////////////////////////////////////////////////////////////
function Flag::commonDropCode(%player, %type) {
//funTest3();
   %playerClient = Player::getClient(%player);
   if (%playerClient != $TRabbit::Carrier)
      return;  //not sure why this function is called on every player death, but this 
   
   %playerPosition = GameBase::getPosition(%player);
   %playerVelocity = Item::getVelocity(%player);

   if (Player::isDead(%player)) {
	echo("DEAD PASS");
	$TRabbit::lastPassID = $deadPassID;
	$TRabbit::flaggerGotKilled = true;
	$TRabbit::passDirection = "";
	$TRabbit::passerSpeed = 0;
   } else {
	echo("ALIVE PASS");
   // Stat-track:  number of drops
        $TRabbit::plyrNumFlagDrops[%playerClient] += 1;
	$TRabbit::lastPassID = $normalPassID;
	$TRabbit::flaggerGotKilled = false;
	$TRabbit::passDirection = Vector::getFromRot(GameBase::getRotation(%player));
	$TRabbit::passerSpeed = Vector::getDistance(%playerVelocity, "0 0 0");
   }
   
   if ($TRabbit::thisDropTime != "")
	$TRabbit::lastDropTime = $TRabbit::thisDropTime;

   $TRabbit::thisDropTime = getSimTime();
   echo("PASSID = " @ $TRabbit::lastPassID);

   %playerTeam = GameBase::getTeam(%player);
   %flag = %player.carryFlag;
   echo("FLAG ID = " @ %flag);
   %flagTeam = GameBase::getTeam(%flag);
   %dropClientName = Client::getName(%playerClient);
   %currentTime = getSimTime();

   %playerRotation = GameBase::getRotation(%player);
   %flagVelocity = Item::getVelocity(%flag);
   %flagPosition = GameBase::getPosition(%flag);

   // Set all observers to flag
   if (%flagTeam >= 0) {
   	for(%cl = Client::getFirst(); %cl != -1; %cl = Client::getNext(%cl)) 
      		if (GameBase::getTeam(%cl) == -1)
			Observer::setTargetObject(%cl, %flag);
   }

  %client = Player::getClient(%player);
   if(GameBase::getLOSInfo(%player,3)) {
	// GetLOSInfo sets the following globals:
	// 	los::position
	// 	los::normal
	// 	los::object
	%obj = getObjectType($los::object);
	if (%obj != "SimTerrain" || %obj != "InteriorShape") {
   		echo("DEBUG : see the ground");
	}
	else{
	   echo("DEBUG : no ground in sight");
	}
   }
   echo("DROPOFF : checking player position " @ %playerPosition);
   echo("DROPOFF : checking player velocity " @ %playerVelocity);
   echo("DROPOFF : checking player rotation " @ %playerRotation);
   echo("DROPOFF : checking flag velocity " @ %flagVelocity);
   echo("DROPOFF : checking flag position " @ %flagposition);
   $TRabbit::flagDropper = %playerClient;
   $TRabbit::dropperVelocity = %playerVelocity;
   $TRabbit::flagDroppedVelocity = %flagVelocity;
   $TRabbit::flagPosition = %flagPosition;
   $TRabbit::ObserverTarget = %flag;
   $TRabbit::flagDropTime = %currentTime;
   //Flag info at time of drop is usually 0 0 0, so check again in half a second
   schedule("delayedFlagVelocity(" @ %player @ ", " @ %flag @ ");",0.5); 


   //$TRabbit::scoreTimer = 0;
   $TRabbit::Carrier.potatoTime = 0;
   $TRabbit::Carrier.isHot = False;
   $TRabbit::Carrier = "";
   %flagHeld = %currentTime - $TRabbit::FlagGrabTimeStamp[%playerClient];
   $TRabbit::PlyrTtlFlagHeld[%playerClient] += %flagHeld;
   if (%flagHeld > $TRabbit::PlyrLongestFlagHeld[%playerClient])
      $TRabbit::PlyrLongestFlagHeld[%playerclient] = %flagHeld;
   

   //schedule("TRabbit::changeTeam($TRabbit::flagDropper, 0);", 0.2);  //switch player to team 0 - delay it .2 secs so not counted as team kill
   $TRabbit::FlagLastTouched[%playerClient] = %currentTime;

   MessageAllExcept(%playerClient, 1, %dropClientName @ " dropped the flag!");
   //Client::sendMessage(%playerClient, 1, "You dropped the flag.");
}

// Flag drop event handler
function Flag::onDrop(%player, %type){
   Flag::commonDropCode(%player, %type);
   %flag = %player.carryFlag;
   
   GameBase::throw(%flag, %player, 10, false);
   Item::hide(%flag, false);
   Player::setItemCount(%player, "Flag", 0);
   %flag.carrier = -2;
   %player.carryFlag = "";
   %flag.dropFade = 1;

   if (%player.outArea != ""){
      Flag::checkReturn(%flag, %flag.pickupSequence);
      $TRabbit::FlagOutOfArea = 1;
   }
   else
      schedule("Flag::checkReturn(" @ %flag @ ", " @ %flag.pickupSequence @ ");", $flagReturnTime);

   TRabbit::clearWaypoint(%flag);
}

// Custom flag drop event handler to make the flag shoot upward
function Flag::onDrop2(%player, %power){
   Flag::commonDropCode(%player, "");
   %flag = %player.carryFlag;
   
   GameBase::throw(%flag, %player, 7, false);

   // Give it a little boost  =)
   %flagVelocity = Item::getVelocity(%flag);
   %flagx = getWord(%flagVelocity, 0);
   %flagy = getWord(%flagVelocity, 1);
   %flagz = getWord(%flagVelocity, 2);
   %newFlagVelocity = %flagx @ " " @ %flagy @ " " @ %flagz + %power;
   Item::setVelocity(%flag, %newFlagVelocity);
   Item::hide(%flag, false);
   Player::setItemCount(%player, "Flag", 0);
   %flag.carrier = -2;
   %player.carryFlag = "";
   %flag.dropFade = 1;

   if (%player.outArea != ""){
      Flag::checkReturn(%flag, %flag.pickupSequence);
      $TRabbit::FlagOutOfArea = 1;
   }
   else
      schedule("Flag::checkReturn(" @ %flag @ ", " @ %flag.pickupSequence @ ");", $flagReturnTime);

   TRabbit::clearWaypoint(%flag);
}

function Flag::checkReturn(%flag, %sequenceNum){
   %teamPenalty = 0;
   %flagTeam = $TRabbit::teamThatGrabbed;
   if(%flag.pickupSequence == %sequenceNum){
      if(%flag.dropFade){ 
         GameBase::startFadeOut(%flag);
         %flag.dropFade= "";
         %flag.fadeOut= 1;
         schedule("Flag::checkReturn(" @ %flag @ ", " @ %sequenceNum @ ");", 2.5);
      }
      else {
	  if (%flagTeam == 0)
		%otherTeam = 1;
	  else
		%otherTeam = 0;

          if ($TRabbit::FlagOutOfArea){
		teamPenaltyMessage(%flagTeam, $oobFlagPenaltyID);
		%teamPenalty = %teamPenalty + $penaltyAmount[$oobFlagPenaltyID];
            	//TeamMessages(1, %flagteam, "The flag was dropped outside the mission area", -2, "", "The flag was dropped outside the mission area");
            	//TeamMessages(1, %flagteam, "and was returned to base.~wflagreturn.wav", -2, "", "and was returned to base.~wflagreturn.wav");
          	TeamMessages2(1, %flagteam, "The flag was returned to base.", 0, %otherTeam, "The flag was returned to base.~wflagreturn.wav");
            	$TRabbit::FlagOutOfArea = "";   
            }
	 else {
		teamPenaltyMessage(%flagTeam, $flagReturnPenaltyID);
		%teamPenalty = %teamPenalty + $penaltyAmount[$flagReturnPenaltyID];
          	TeamMessages2(1, %flagteam, "The flag was returned to base.", 0, %otherTeam, "The flag was returned to base.~wflagreturn.wav");
	   }
         GameBase::setPosition(%flag, %flag.originalPosition);
	 $TRabbit::teamGrabTime = "";
         Item::setVelocity(%flag, "0 0 0");
         %flag.atHome = true;
	 $TRabbit::flagAtHome = true;
         GameBase::startFadeIn(%flag);
         %flag.fadeOut= "";
   	 $TRabbit::StyleScore[$TRabbit::teamThatGrabbed] -= %teamPenalty;
 	 $TRabbit::PlyrScoreContribution[$TRabbit::flagDropper] -= %teamPenalty;
         Game::refreshClientScore($TRabbit::flagDropper);
	 $TRabbit::flagDropper = "";
	 $TRabbit::lastPassID = $deadPassID;
 	 $TRabbit::SpecialGrab = "";
	 $TRabbit::SpecialTime = 0;
	 TRabbit::updateTeamScores();
      }
   }
}

function Flag::objectiveInit(%this){
//   echo("DEBUG : Flag::ObjectiveInit called");
   %this.originalPosition = GameBase::getPosition(%this);
   %this.atHome = true;
   %this.pickupSequence = 0;
   %this.carrier = -1;
   %this.holdingTeam = -1;
   %this.holder = "";
   %this.enemyCaps = 0;
   %this.caps[0] = 0;
   %this.caps[1] = 0;
   %this.caps[2] = 0;
   %this.caps[3] = 0;
   %this.caps[4] = 0;

   %this.caps[5] = 0;
   %this.caps[6] = 0;
   %this.caps[7] = 0;
   $teamFlag[GameBase::getTeam(%this)] = %this;
   $TRabbit::theFlag = %this;
   $TRabbit::ObserverTarget = %this;
   return true;
}

//********************************************************************************************
// FLAG COLLISION EVENT HANDLER (this is where most bonuses occur)		
//********************************************************************************
function Flag::onCollision(%this, %object){
   if(getObjectType(%object) != "Player")
      return;
   if(%this.carrier > 0)
      return; // spurious collision
   if(Player::isAIControlled(%object))
   	return;   
   %playerClient = Player::getClient(%object);
   %flagTeam = GameBase::getTeam(%this);
   if (%flagTeam < 0) {
        %thisTeam = GameBase::GetTeam(%playerClient);
	if (%thisTeam == 0)
		%otherTeam = 1;
	else
		%otherTeam = 0;
	teamBonusMessage(%thisTeam, %otherTeam, $crazyFlagBonusID, 0);
	$TRabbit::PlyrScoreContribution[%playerClient] += $TRabbit::bonusAmount[$crazyFlagBonusID, 0];
	$TRabbit::StyleScore[%thisTeam] += $TRabbit::bonusAmount[$crazyFlagBonusID, 0];
	TRabbit::updateTeamScores();
        Game::refreshClientScore(%playerClient);
	deleteObject(%this);
	return;
   }

   $TRabbit::theFlag = %this;
   %name = Item::getItemData(%this);
   %playerTeam = GameBase::getTeam(%object);
   %touchClientName = Client::getName(%playerClient);
   %flagPosition = GameBase::getPosition(%this);

   if ($TRabbit::flagDropper != "")
  	 %teamThatDropped = GameBase::GetTeam($TRabbit::flagDropper);
   else
	%teamThatDropped = "";
   %teamThatGrabbed = GameBase::GetTeam(%playerClient);

   // Don't allow anyone to stand in one spot and keep grabbing
   if (%teamThatDropped == %teamThatGrabbed) {
	%flagx = getWord(%flagPosition, 0);
   	%flagy = getWord(%flagPosition, 1);
   	%oldflagx = getWord($TRabbit::lastFlagGrabPosition, 0);
   	%oldflagy = getWord($TRabbit::lastFlagGrabPosition, 1);
   	%flagdiffx = %flagx - %oldflagx;
   	%flagdiffy = %flagy - %oldflagy;
   	if (%flagdiffx < 0) %flagdiffx = -%flagdiffx;
   	if (%flagdiffy < 0) %flagdiffy = -%flagdiffy;
   	if ((%flagdiffx < $TRabbit::minFlagMove) || (%flagdiffy < $TRabbit::minFlagMove))
		if (%playerClient == $TRabbit::flagGrabber) return;
   }

   %passerClient = $TRabbit::flagGrabber;
   $TRabbit::flagGrabber = %playerClient;

   %currentTime = getSimTime();
   // Number of seconds before player can grab flag again after dropping it
   if (((%currentTime - $TRabbit::FlagLastTouched[%playerClient]) < $TRabbit::repeatedGrabRestriction)
	&& ($TRabbit::flagDropper == %playerClient))
   { 
      echo ("diff : " @ %currentTime - $TRabbit::FlagLastTouched[%playerClient]);
      return;
   }

   // Balancing code to prevent flag hogging
   if ((%teamThatGrabbed == %teamThatDropped) && ($TRabbit::teamGrabTime != "") && 
       ((%currentTime - $TRabbit::teamGrabTime) > $TRabbit::teamTimeLimit)) {
	return;
   }

   if(%object.carryFlag == ""){
       if(%object.outArea == "") {
            if(%this.holdingTeam == %playerTeam)
               return;
            
            // make sure that flag is not already held when the flag is touched by a player
            // remember, if flag isn't held, TRabbitcarrier should be ""
            if ($TRabbit::carrier > 0){
               echo("DEBUG : Held flag touched by another player");
               return;
            }

	    $TRabbit::lastFlagGrabPosition = %flagPosition;
   	    %flagVelocity = Item::getVelocity(%this);
	    %flagSpeed = Vector::getDistance(%flagVelocity,"0 0 0");

	    // Set all observers to flag carrier
	    for(%cl = Client::getFirst(); %cl != -1; %cl = Client::getNext(%cl))
      		if (GameBase::getTeam(%cl) == -1)
	    		Observer::setTargetClient(%cl, %playerClient);

	    $TRabbit::ObserverTarget = %playerClient;

            $TRabbit::FlagGrabTimeStamp[%playerClient] = %currentTime;
            $TRabbit::Carrier = %playerClient;
	    //$TRabbit::scoreTimer = 0;
   	    $TRabbit::Carrier.potatoTime = 0;
            $TRabbit::Carrier.isHot = False;
	    $TRabbit::teamThatGrabbed = GameBase::getTeam(%playerClient);

            schedule("TRabbit::flagPointTimer();", $TRabbit::scoreTimer + 0.05);
            echo($TRabbit::carrier @ " grabbed the flag at - simtime : " @ getsimtime());
            TRabbit::WaypointToCarrier($TRabbit::carrier);
            $TRabbit::PlyrNumGrabs[%playerClient] +=1;    

	    // Mount the flag
            Player::setItemCount(%object, Flag, 1);
            Player::mountItem(%object, Flag, $FlagSlot, %flagTeam);
            Item::hide(%this, true);
            //$flagAtHome[1] = false;
            %this.atHome = false;
            %this.carrier = %object;
            %this.pickupSequence++;
            %object.carryFlag = %this;
            if(%this.fadeOut) {
               GameBase::startFadeIn(%this);
               %this.fadeOut= "";
            }

	    // Don't allow self-passing
	    if($TRabbit::flagDropper != $TRabbit::Carrier)
	    {
		// Pre-scoring calculations
   		%playerVelocity = Item::getVelocity(%object);
		%playerSpeed = Vector::getDistance(%playerVelocity, "0 0 0");
		%playerRotation = GameBase::getRotation(%object);
		%dropperVelocity = Item::getVelocity($TRabbit::flagDropper);
		%dropperSpeed = Vector::getDistance(%dropperVelocity, "0 0 0");
   		echo("PICKUP : flag velocity " @ %flagVelocity);
   		echo("PICKUP : flag speed " @ %flagSpeed);
   		echo("PICKUP : player velocity " @ %playerVelocity);

		echo("PICKUP : team drop " @ %teamThatDropped);
		echo("PICKUP : team grab " @ %teamThatGrabbed);

		%dropperClient = $TRabbit::flagDropper;
		%dropperName = Client::getName(%dropperClient);
		%grabberName = Client::getName(%playerClient);
		
		echo(%dropperName @ " to " @ %grabberName @ "  PASSID = " @ $TRabbit::lastPassID);
		
		// Grab speed bonuses
		// I coded these loops before I knew that the language supported while loops ;)
		%done = false;
		for (%a = $numGrabSpeedBonuses - 1; (%a >= 0) && (!%done); %a--){
			if (%playerSpeed > $bonusGoalValue[$grabSpeedBonusID, %a]){
				teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $grabSpeedBonusID, %a);
				%teamBonus += $bonusAmount[$grabSpeedBonusID, %a];
				%done = true;
			}
		}

		// Flag speed bonuses
		%done = false;
		%grabberOrPasserMoving = ((%playerSpeed > 15) || (%dropperSpeed > 15));
		for (%a = $numFlagSpeedBonuses - 1; (%a >= 0) && (!%done); %a--){
			if (%grabberOrPasserMoving && (%flagSpeed > $bonusGoalValue[$flagSpeedBonusID, %a])){
				teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $flagSpeedBonusID, %a);
				%teamBonus += $bonusAmount[$flagSpeedBonusID, %a];
				%done = true;
			}
		}

		// Extra pass speed bonuses
		%done = false;
		%extraTimeDiff = getSimTime() - $TRabbit::thisDropTime;
		if ((%teamThatDropped == %teamThatGrabbed) && ($TRabbit::lastPassID == $normalPassID)
		    && ($TRabbit::SpecialGrab == "") && (%extraTimeDiff <= 3	))
		for (%a = $numExtraPassSpeedBonuses - 1; (%a >= 0) && (!%done); %a--){
			if ((%playerSpeed + %dropperSpeed) > $bonusGoalValue[$extraPassSpeedBonusID, %a]){
				teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $extraPassSpeedBonusID, %a);
				%teamBonus += $bonusAmount[$extraPassSpeedBonusID, %a];
				%done = true;
			}
		}

		// Mid-air grab bonuses
		%done = false;
		%grabberOrPasserMoving = ((%playerSpeed > 0.4) || (%dropperSpeed > 0.4));
		//%flagMoving = (%flagSpeed > 0.8);
		//%flagz = getWord(%flagPosition, 2);
		for (%a = $numMidairGrabBonuses - 1; (%a >= 0) && (!%done); %a--){
			//%modifiedDistance = %flagz - $bonusGoalValue[$midairGrabBonusID, %a];
			if (gamebase::getlosinfo(%object,$bonusGoalValue[$midairGrabBonusID, %a],"-1.57 0 0")){
			} else {
			   %losx = getWord($los::normal, 0);
				echo("LOS::OBJECT = " @ %obj);
				echo("LOS::NORMAL = " @ $los::normal);
				echo("LOS::POSITION = " @ $los::position);
				echo("losz = " @ $los::position);
			   if (%losx >= 0) {
				// If there is a player directly below this player, do a getlos on him instead

				 if ((%grabberOrPasserMoving) && !($TRabbit::flagAtHome) &&
				    ($TRabbit::SpecialGrab != $gogoGadgetBonusID)) {
					teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $midairGrabBonusID, %a);
					%teamBonus += $bonusAmount[$midairGrabBonusID, %a];
					%done = true;
				}
			   }
			}
		}

		// Grab direction bonus
		%done = false;
		%playerDirection = Vector::getFromRot(%playerRotation);
		%velx = getWord(%playerVelocity, 0);
		%vely = getWord(%playerVelocity, 1);
		%tempVel = %velx @ " " @ %vely @ " 0";
		%normVel = Vector::normalize(%tempVel);
		%dotProd = Vector::dot(%playerDirection, %normVel);
		//echo("BACKWARD:  facedir = " @ %playerDirection @ "  vel = " @ %normVel);
		//echo("BACKWARD:  dotprod = " @ %dotProd);
		%goodEnough = ((%playerSpeed >= 12) || (!gamebase::getlosinfo(%object,6,"-1.57 0 0")));
		for (%a = $numGrabDirectionBonuses - 1; (%a >= 0) && (!%done); %a--){
			if ((%goodEnough) && (%dotProd < $bonusGoalValue[$grabDirectionBonusID, %a]) &&
				($TRabbit::SpecialGrab != $gogoGadgetBonusID)){
				teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $grabDirectionBonusID, %a);
				%teamBonus += $bonusAmount[$grabDirectionBonusID, %a];
				%done = true;
			}
		}

		// Pass direction bonus
		if (($TRabbit::passDirection != "") && ($TRabbit::SpecialGrab != $marioBonusID) &&
			((%currentTime - $TRabbit::flagDropTime) <= 3) && (%teamThatDropped == %teamThatGrabbed) &&
				($TRabbit::SpecialGrab != $gogoGadgetBonusID)) {
			%dotProd = Vector::dot(%normVel, $TRabbit::passDirection);
			echo("CHECKING PASS BONUS, dotprod = " @ %dotprod);
			%goodEnough = ((%playerSpeed >= 8) || (!gamebase::getlosinfo(%object,6,"-1.57 0 0")));
			for (%a = $numPassDirectionBonuses - 1; (%a >= 0) && (!%done); %a--){
				if ((%goodEnough) && (%dotProd > $bonusGoalValue[$passDirectionBonusID, %a])){
					teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $passDirectionBonusID, %a);
					%teamBonus += $bonusAmount[$passDirectionBonusID, %a];
					%done = true;
				}
			}
		}

		%flagOnGround = gamebase::getlosinfo(%object, 5,"-1.57 0 0");
		%playerOnGround = gamebase::getlosinfo(%this, 2.7,"-1.57 0 0");
		// Mario grab check
		%currentTime = getSimTime();
		if (($TRabbit::SpecialGrab == $marioBonusID) && (%currentTime - $TRabbit::SpecialTime < 1)) {
			teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $marioBonusID, 0);
			%teamBonus += $bonusAmount[$marioBonusID, 0];
		}
		else if (($TRabbit::SpecialGrab == $inverseMarioBonusID) 
				&& (%currentTime - $TRabbit::SpecialTime < 5.5)
				&& (%currentTime - $TRabbit::SpecialTime > 1)
			 	&& (!%flagOnGround)) {
			teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $inverseMarioBonusID, 0);
			%teamBonus += $bonusAmount[$inverseMarioBonusID, 0];
		}

		// Go-go Gadget check
		if ($TRabbit::SpecialGrab == $gogoGadgetBonusID) {
			%teamBonus += $bonusAmount[$gogoGadgetBonusID,0];
			$TRabbit::PlyrScoreContribution[%teamThatGrabbed] += %teamBonus;		
			teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $gogoGadgetBonusID, 0);
			$TRabbit::lastPassID = $normalPassID;  // Passer died, but it was a normal pass
		}

		// KTS check
		if ($TRabbit::SpecialGrab == $kidneyThiefBonusID) {
			if (%currentTime - $TRabbit::SpecialTime < 3) {
				teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $kidneyThiefBonusID, 0);
				%teamBonus += $bonusAmount[$kidneyThiefBonusID, 0];
				$TRabbit::PlyrNumKTS[%playerClient] += 1;
			}
			else
				$TRabbit::SpecialGrab = "";
		}

		// Determine interception/turnover/pass multipliers
		%interception = False;
		%turnover = False;
		%bonusMultiplier = 1;
		%displayInterceptionMessage = False;
	
		if (!$TRabbit::flagAtHome) {
			// CASE 1:  Pass between teammates
			if ((%teamThatDropped == %teamThatGrabbed) && (%dropperName != "") && (%grabberName != "")){
				//%message = %message @ "<F0>" @  %dropperName @ " to " @ %grabberName @ "\n";
				if ((%passerClient != "") && ($TRabbit::lastPassID == $normalPassID)) {
					// Stat-track:  number of pass completions
					$TRabbit::plyrNumCompletions[%passerClient] += 1;
					$TRabbit::plyrNumReceptions[%playerClient] += 1;
					%bonusMultiplier = 2;
				}
			}
			// CASE 2:  Turnover, interception or KTS
			else{  
				$TRabbit::teamGrabTime = %currentTime;
				// CASE 2a:  KTS
				if ($TRabbit::SpecialGrab == $kidneyThiefBonusID)
					%bonusMultiplier = 2;
				else {
				// CASE 2b: Interception and turnover  
					if ($TRabbit::lastPassID == $normalPassID)
						%bonusMultiplier = 2;
					// Give a turnover bonus only if not a KTS
					%teamBonus += $bonusAmount[$interceptionBonusID, $deadPassID];
					teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $interceptionBonusID, $deadPassID);

				}

				if ($TRabbit::lastPassID == $deadPassID)
					%turnover = True;
				else {
					%interception = True;
					%teamPenalty = $penaltyAmount[$interceptionPenaltyID];
					$TRabbit::StyleScore[%teamThatDropped] -= %teamPenalty;
					$TRabbit::PlyrScoreContribution[%passerClient] -= %teamPenalty;
					$TRabbit::PlyrPassPoints[%passerClient] -= %teamPenalty;
					%displayInterceptionMessage = True;
				}	
			}
		}

		// Pass sequences
		//%grabberOrPasserMoving = ((%playerSpeed > 15) || (%dropperSpeed > 15));
		%sequenceTimeDiff = getSimTime() - $TRabbit::lastDropTime;
		echo("***************TIME DIFF********** = " @ %sequenceTimeDiff);
		echo("MOVING? = " @ %grabberOrPasserMoving);
		if (($TRabbit::lastPassID == $normalPassID) && (!%interception) &&
			(%sequenceTimeDiff <= $bonusGoalValue[$passSequenceBonusID,0]) &&
			%grabberOrPasserMoving && %teamBonus >= 1) {
			$TRabbit::currentSequenceCount++;
			if ($TRabbit::currentSequenceCount > $numPassSequenceBonuses + 1)
				$TRabbit::currentSequenceCount = 2;
			if ($TRabbit::currentSequenceCount >= 2) {
				%bonusIndex = $TRabbit::currentSequenceCount - 2;
				%teamBonus += $bonusAmount[$passSequenceBonusID, %bonusIndex];
				teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $passSequenceBonusID, %bonusIndex);
			}	
		}
		else
			$TRabbit::currentSequenceCount = 1;

		// Scavenger grab check
		%scavTimeDiff = getSimTime() - $TRabbit::thisDropTime;
		if ((%scavTimeDiff <= $bonusGoalValue[$scavengerBonusID, 0]) &&
		    ($TRabbit::lastPassID != $normalPassID)) {
			%teamBonus += $bonusAmount[$scavengerBonusID, 0];
			teamBonusMessage(%teamThatGrabbed, %teamThatDropped, $scavengerBonusID, 0);
		}

		%individualBonus = %teamBonus;	
		%teamBonus = %teamBonus * %bonusMultiplier;
		
		// Track interceptions
		if (%interception) {
		 	$TRabbit::PlyrNumInterceptions[%playerClient] += 1;
			$TRabbit::PlyrInterceptionPoints[%playerClient] += %teambonus;
		}

		// If it's a pass, both the passer and grabber get individual contribution points
		if ((!%interception) && ($TRabbit::lastPassID == $normalPassID)) {
			$TRabbit::PlyrScoreContribution[%passerClient] += %individualBonus;
			$TRabbit::PlyrPassPoints[%passerClient] += %individualBonus;
			$TRabbit::PlyrScoreContribution[%playerClient] += %individualBonus;
			$TRabbit::PlyrReceivePoints[%playerClient] += %individualBonus;
		}
		// Otherwise, the grabber's contribution is the entire team bonus
		else
			$TRabbit::PlyrScoreContribution[%playerClient] += %teamBonus;

		if (%teamBonus > 0) {
			%message = "";
			$TRabbit::StyleScore[%teamThatGrabbed] += %teamBonus;
			TRabbit::updateTeamScores();

			if (%bonusMultiplier > 1)
				%message = %message @ "(" @ %bonusMultiplier @ "x) ";

			if (%interception)
				%message = %message @ "   [INTERCEPTION";
			else if (%turnover)
				%message = %message @ "   [TURNOVER";
			else if ($TRabbit::lastPassID != $deadPassID)
				%message = %message @ "   [PASS";
			else
				%message = %message @ "   [PICKUP";

			// Add some extra text in the case of KTS
			if (%turnover && $TRabbit::SpecialGrab == $kidneyThiefBonusID)
				%message = %message @ " KTS";

			%message = %message @ ", total bonus = " @ %teamBonus @ "]";

			// For interceptions and turnovers, add sounds
			if (%interception || %turnover) {
				%message1 = %message @ "~wCapturedTower.wav";
				%message2 = %message @ "~wError_Message.wav";
			} else {
				%message1 = %message;
				%message2 = %message;
			}
			teamMessages2(0, %teamThatGrabbed, %message1, 1, %teamThatDropped, %message2); 

		}
		if (%displayInterceptionMessage)
			teamPenaltyMessage(%teamThatDropped, $interceptionPenaltyID);


		// Update client scores
		Game::refreshClientScore(%playerClient);
	        Game::refreshClientScore(%passerClient);

           	//MessageAllExcept(%playerClient, 0, %touchClientName @ " took the flag! ~wflag1.wav");

           	//Client::sendMessage(%playerClient, 1, "You took the flag! ~wflag1.wav");
	    }
	    else
		Client::sendMessage(%playerClient, 0, "This is TEAM Rabbit.  Stop passing to yourself.");
		// Reset special grab info
		$TRabbit::SpecialGrab = "";
		$TRabbit::SpecialTime = 0;

		// Play some sounds
        	messageAll(0, "~wflag1.wav");	    
		Client::sendMessage(%playerClient, 0, "~wmine_act.wav");
         }
         else
            Client::sendMessage(%playerClient, 1, "Flag not in mission area.");
     }
     $TRabbit::flagAtHome = false;
}


///////////////////////////////////////////////////////////////////////////////////////////////
// Client bonus/penalty message display functions
///////////////////////////////////////////////////////////////////////////////////

//function TRabbit::printBonus(%bonusType, %bonusLevel, %location){
//	if (%location == 0)
//  		topPrintAll("<jc><f0>" @ $TRabbit::bonus[%bonusType,%bonusLevel].message, 0.75);
//	else if (%location == 1)
//   		centerPrintAll("<jc><f0>" @ $TRabbit::bonus[%bonusType,%bonusLevel].message, 0.75);
//	else if (%location == 2)
//		bottomPrintAll("<jc><f0>" @ $TRabbit::bonus[%bonusType,%bonusLevel].message, 0.75);
//}

function TRabbit::printFancyBonus1(%bonusType, %bonusLevel){
   for(%i = 0; %i < 3; %i++){
	// Can't seem to schedule local strings
   	schedule("TRabbit::printBonus(" @ %bonusType @ ", " @ %bonusLevel @ ", " @ %i @ ");", 0.75 * %i);   	
   }
}

function TRabbit::printBonus(%bonusMessage){
	//centerPrintAll("<jc><f0>" @ %bonusMessage, 1.3);
	topPrintAll("<jc><f0>" @ %bonusMessage, 1.3);
	bottomPrintAll("<jc><f0>" @ %bonusMessage, 1.3);
}

// Modified to allow two different message types
function teamBonusMessage(%team1, %team2, %bonusID, %bonusLevel, %playerName)
{
	%message = "(+" @ $bonusAmount[%bonusID, %bonusLevel] @ ") " @ $bonusMessage[%bonusID, %bonusLevel];
	teamMessages2(0, %team1, %message, 1, %team2, %message);
	if (%playerName != "") {
		%message2 = "   (compliments of " @ %playerName @ ")";
		teamMessages2(0, %team1, %message2, 0, %team2, %message2);
	}

	if (%bonusLevel >= 3) {
	// Only print super-dooper bonuses in the center
		%message = "";
		if (%playerName != "")
			%message = %message @ "<jc><f2>" @ %playerName;
		else
			%message = %message @ "<jc><f2>" @ Client::getName($TRabbit::flagGrabber);
		%message = %message @ "\n\n<jc><f3>" @ $bonusMessage[%bonusID, %bonusLevel];
		MessageAll(0, $TRabbit::superBonusSound);
		//centerPrintAll(%message, 1.6);
		topPrintAll(%message, 1.6);
		bottomPrintAll(%message, 1.6);
	}
	// Offset each bonus sound so they don't overlap so much
	schedule("MessageAll(0, \"" @ $bonusSound[%bonusID, %bonusLevel] @ "\");", %bonusID / $TRabbit::numBonuses);

}

function teamPenaltyMessage(%team, %penaltyID)
{	
	// Wish I could just do %otherTeam = !%team
	if (%team == 0)
		%otherTeam = 1;
	else
		%otherTeam = 0;

	%message = "(-" @ $penaltyAmount[%penaltyID] @ ") ";
	%observerMessage = %message @ $penaltyMessage[%penaltyID];
	%penaltyTeamMessage = %message @ "Your team's penalty:  " @ $penaltyMessage[%penaltyID];
	%otherTeamMessage = %message @ "Their team's penalty:  " @ $penaltyMessage[%penaltyID];
	teamMessages2(1, %team, %penaltyTeamMessage, 0, %otherTeam, %otherTeamMessage, %observerMessage);
	schedule("MessageAll(0, \"" @ $penaltySound[%penaltyID] @ "\");", 0.5);

}

function teamMessages2(%mtype, %team1, %message1, %mtype2, %team2, %message2, %message3)
{
   %numPlayers = getNumClients();
   if (%message3 == "")
	%observerMessage = %message1;
   else
	%observerMessage = %message3;

   for(%i = 0; %i < %numPlayers; %i = %i + 1)
   {
      %id = getClientByIndex(%i);
      if(Client::getTeam(%id) == %team1)
      {
         Client::sendMessage(%id, %mtype, %message1);
      }
      else if(%message2 != "" && Client::getTeam(%id) == %team2)
      {
         Client::sendMessage(%id, %mtype2, %message2);
      }
      else
	 Client::sendMessage(%id, 1, %observerMessage);
   }
}



///////////////////////////////////////////////////////////////////////////////////////////////
// Fun functions for crazy flag events
///////////////////////////////////////////////////////////////////////////////////
function fadeOutObject(%object)
{
   GameBase::startFadeOut(%object);
   schedule("deleteObject(" @ %object @ ");", 2.5, %object);
}


function funTest(%player, %numFlags) {
   if (%numFlags == "")
	%numberToSpawn = 10;
   else
	%numberToSpawn = %numFlags;

   for (%i = 0; %i < %numberToSpawn; %i++)
   {
      // create a flag
      %flag = newObject("", Item, Flag, 1, false, false, true);
 	 	addToSet("MissionCleanup", %flag);
      
      //if (%i < %numberSinglePointFlags)
         %flag.value = 1;
      //else
      //   %flag.value = 2;
          
      %flag.carrier = -2;
      
      GameBase::setTeam(%flag, -1);
      GameBase::throw(%flag, $TRabbit::Carrier, 10, false);
      
      //if the flag hasn't been picked up in specified time, fade it out
      schedule("fadeOutObject(" @ %flag @ ");", $TRabbit::bonusFlagTimeout, %flag);
      
      //randomize the direction a bit so the flags don't all bunch up
      %curVelocity = Item::getVelocity(%flag);
      %velX = getWord(%curVelocity, 0) + floor(getRandom() * 20) - 10;
      %velY = getWord(%curVelocity, 1) + floor(getRandom() * 20) - 10;
      %velZ = getWord(%curVelocity, 2) + floor(getRandom() * 20) - 10;
      %velZ = %velZ * 2;
      Item::setVelocity(%flag, %velX @ " " @ %velY @ " " @ %velZ);

   }
      Flag::onDrop(%player);
}

function funTest2(%player) {
	%playerTeam = GameBase::getTeam(%player);
	%spawnPoint = Game::pickRandomSpawn(%playerTeam);
	%spawnPosition = Game::getPosition(%spawnPoint);
	// get a random rotation
	// set a vector from rotation
	%directionVec = "10 0 0";
	%currentDir = "-291 -214 162";//%spawnPoint;
	for (%i = 0; %i < 10; %i++) {
		%currentDir = Vector::add(%currentDir, %directionVec);
      		// create a flag
      		%flag = newObject("", Item, Flag, 1, false, false, true);
 	 	addToSet("MissionCleanup", %flag);
      		%flag.value = 1;
                %flag.carrier = -2;
  	      	GameBase::setTeam(%flag, -1);
      		%posX = getWord(%currentDir, 0);
      		%posY = getWord(%currentDir, 1);
      		%posZ = getWord(%currentDir, 2);
		%newPos = %posX @ " " @ %posY @ " " @ %posZ + 150;
      		GameBase::setPosition(%flag, %newPos);
      
      		//if the flag hasn't been picked up in specified time, fade it out
      		schedule("fadeOutObject(" @ %flag @ ");", $TRabbit::bonusFlagTimeout, %flag);
     }
}

$TRabbit::test3Timer = 0;

function funTest3() {
      $TRabbit::test3Timer += 0.03;
      %curVelocity = GameBase::getPosition($TRabbit::theFlag);
      %velX = getWord(%curVelocity, 0) + (getRandom() * 1.5) - 0.75;
      %velY = getWord(%curVelocity, 1) + (getRandom() * 1.5) - 0.75;
      %velZ = getWord(%curVelocity, 2); // + floor(getRandom() * 1.4);
	%newVel = %velX @ " " @ %velY @ " " @ %velZ;
	GameBase::setPosition($TRabbit::theFlag, %newVel);
	$TRabbit::theFlag.lightColor = getRandom() @ " " @ getRandom() @ " " @ getRandom();
	if ($TRabbit::test3Timer > 10) {
		$TRabbit::test3Timer = 0;
		return;
	}
	else
		schedule("funTest3();", 0.03);
}

function funTest4(%player) {
      $TRabbit::test3Timer += 0.1;
      %curPosition = GameBase::getPosition(%player);
	for (%i = 0; %i < 1; %i++) {
      		// create a flag
      		%flag = newObject("", Item, Flag, 1, false, false, true);
 	 	addToSet("MissionCleanup", %flag);
      		%flag.value = 1;
                %flag.carrier = -2;
  	      	GameBase::setTeam(%flag, -1);
      		%posX = getWord(%curPosition, 0);
      		%posY = getWord(%curPosition, 1);
      		%posZ = getWord(%curPosition, 2);
		%newPos = %posX @ " " @ %posY @ " " @ %posZ + ((%i + 1) * 10);
      		GameBase::setPosition(%flag, %newPos);
      
      		//if the flag hasn't been picked up in specified time, fade it out
      		schedule("fadeOutObject(" @ %flag @ ");", $TRabbit::bonusFlagTimeout, %flag);
     }

	if ($TRabbit::test3Timer > 10) {
		$TRabbit::test3Timer = 0;
		return;
	}
	else
		schedule("funTest3();", 0.1);
}


function delayedBeaconCheck(%playerClient)
{
	// Do a post-beacon speed check
	%carrierVelocity = Item::getVelocity(%playerClient);
	echo("POST-BEACON : check velocity " @ %carrierVelocity);
	%carrierSpeed = Vector::getDistance(%carrierVelocity,"0 0 0");
	echo("POST-BEACON : check speed " @ %carrierSpeed);
	if (%carrierSpeed < $TRabbit::bonusBeaconStopThreshold){
		%playerName = Client::getName(%playerClient);
		messageall(0, "Choo Choo Stop by " @ %playerName @ "!~wshieldhit.wav");
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////
// Beacon functions
///////////////////////////////////////////////////////////////////////////////////

// Detect flag carrier beacon-stop
function Beacon::onUse(%player,%item)
{
	%playerClient = Player::getClient(%player);
	if (%playerClient == $TRabbit::Carrier){
		%carrierVelocity = Item::getVelocity(%playerClient);
		echo("BEACON : check velocity " @ %carrierVelocity);
		%carrierSpeed = Vector::getDistance(%carrierVelocity,"0 0 0");
		echo("BEACON : check speed " @ %carrierSpeed);
		if (Beacon::deployShape(%player,%item)) {
			Player::decItemCount(%player,%item);
			Item::pop(%item);
			if (%carrierSpeed > $TRabbbit::bonusBeaconStopSpeed){
				// Now schedule a check to make sure the carrier stopped
				schedule ("delayedBeaconCheck(" @ %playerClient @ ");", 0.5);
			}	
		}	
	}
	else{
		if (Beacon::deployShape(%player,%item)) {
			Player::decItemCount(%player,%item);
			//%itemData = getItemData(%item);
	           	//GameBase::setDamageLevel(%itemData,GameBase::getDamageLevel(%itemData) + 0.05); 
			//Item::pop(%item);
   			//GameBase::setIsTarget(%this,false);
		}
	}
}

// Added one line to auto-destroy beacon
function Beacon::deployShape(%player,%item)
{
 	%client = Player::getClient(%player);
	if (GameBase::getLOSInfo(%player,3)) {
		// GetLOSInfo sets the following globals:
		// 	los::position
		// 	los::normal
		// 	los::object
		%obj = getObjectType($los::object);
		if (%obj == "SimTerrain" || %obj == "InteriorShape") {
			// Try to stick it straight up or down, otherwise
			// just use the surface normal
			if (Vector::dot($los::normal,"0 0 1") > 0.6) {
				%rot = "0 0 0";
			}
			else {
				if (Vector::dot($los::normal,"0 0 -1") > 0.6) {
					%rot = "3.14159 0 0";
				}
				else {
					%rot = Vector::getRotation($los::normal);
				}
			}
		  	%set=newObject("set",SimSet);
			%num=containerBoxFillSet(%set,$StaticObjectType | $ItemObjectType | $SimPlayerObjectType,$los::position,0.3,0.3,0.3,1);
			deleteObject(%set);
			if(!%num) {
				%team = GameBase::getTeam(%player);
				if($TeamItemMax[%item] > $TeamItemCount[%team @ %item] || $TestCheats) {
					%beacon = newObject("Target Beacon", "StaticShape", "DefaultBeacon", true);
				   addToSet("MissionCleanup", %beacon);
					//, CameraTurret, true);
					GameBase::setTeam(%beacon,GameBase::getTeam(%player));
					GameBase::setRotation(%beacon,%rot);
					GameBase::setPosition(%beacon,$los::position);
					Gamebase::setMapName(%beacon,"Target Beacon");
   			   		Beacon::onEnabled(%beacon);
					Client::sendMessage(%client,0,"Beacon deployed");
					//playSound(SoundPickupBackpack,$los::position);
					$TeamItemCount[GameBase::getTeam(%beacon) @ "Beacon"]++;
					fadeOutObject(%beacon);  // Auto-destroy
					return true;
				}
				else
					Client::sendMessage(%client,0,"Deployable Item limit reached");
			}
			else
				Client::sendMessage(%client,0,"Unable to deploy - Item in the way");
		}
		else {
			Client::sendMessage(%client,0,"Can only deploy on terrain or buildings");
		}
	}
	else {
		Client::sendMessage(%client,0,"Deploy position out of range");
	}
	return false;
}


function doubleCheckFlagTeleport(%playerClient)
{
	if ($TRabbit::flagCarrier == "")
	{
		Flag::onCollision($TRabbit::theFlag, Client::getOwnedObject(%playerClient));
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Damage and kill functions
///////////////////////////////////////////////////////////////////////////////////

// Detect all kill bonuses here
function Player::onDamage(%this,%type,%value,%pos,%vec,%mom,%vertPos,%quadrant,%object)
{
	%teamBonus = 0;
	%midairBonus = -1;
	if (Player::isExposed(%this)) {
      		%damagedClient = Player::getClient(%this);
      		%shooterClient = %object;
		%shooterName = Client::getName(%shooterClient);
		%damagedTeam = GameBase::GetTeam(%damagedClient);
		%shooterTeam = GameBase::GetTeam(%shooterClient);

		Player::applyImpulse(%this,%mom);
		if($teamplay && %damagedClient != %shooterClient && Client::getTeam(%damagedClient) == Client::getTeam(%shooterClient) ) {
			if (%shooterClient != -1) {
				%curTime = getSimTime();
			   if ((%curTime - %this.DamageTime > 3.5 || %this.LastHarm != %shooterClient) && %damagedClient != %shooterClient && $Server::TeamDamageScale > 0) {
					if(%type != $MineDamageType) {
						Client::sendMessage(%shooterClient,0,"You just harmed Teammate " @ Client::getName(%damagedClient) @ "!");
						Client::sendMessage(%damagedClient,0,"You took Friendly Fire from " @ Client::getName(%shooterClient) @ "!");
					}
					else {
						Client::sendMessage(%shooterClient,0,"You just harmed Teammate " @ Client::getName(%damagedClient) @ " with your mine!");
						Client::sendMessage(%damagedClient,0,"You just stepped on Teamate " @ Client::getName(%shooterClient) @ "'s mine!");
					}
					%this.LastHarm = %shooterClient;
					%this.DamageStamp = %curTime;
				}
			}
			%friendFire = $Server::TeamDamageScale;
		}
		else if(%type == $ImpactDamageType && Client::getTeam(%object.clLastMount) == Client::getTeam(%damagedClient)) 
			%friendFire = $Server::TeamDamageScale;
		else  
			%friendFire = 1.0;	

		if (!Player::isDead(%this)) {
			%armor = Player::getArmor(%this);
			//More damage applyed to head shots
			if(%vertPos == "head" && %type == $LaserDamageType) {
				if(%armor == "harmor") { 
					if(%quadrant == "middle_back" || %quadrant == "middle_front" || %quadrant == "middle_middle") {
						%value += (%value * 0.3);
					}
				}
				else {
					%value += (%value * 0.3);
				}
			}
//**** BEGIN Unnecessary Roughness
			%shooterPosition = GameBase::getPosition(%shooterClient);
			if ($TRabbit::Carrier == "")
				%flagPosition = GameBase::getPosition($TRabbit::theFlag);
			else
				%flagPosition = GameBase::getPosition($TRabbit::Carrier);
			%shooterDistance = Vector::getDistance(%shooterPosition, %flagPosition);
			if(%shooterDistance > $TRabbit::roughnessDistance) {
				echo("***************UNNECESSARY ROUGHNESS DETECTED***********");
			}


//**** END Unnecessary Roughness

//**** BEGIN Disc damage detection

			if((%type == $ExplosionDamageType) && (%damagedTeam != %shooterTeam) &&
			   (%damagedClient == $TRabbit::Carrier || %shooterClient == $TRabbit::Carrier)) {
				// Georgeson backstab
				%backstab = ((%quadrant == "back_left") || (%quadrant == "back_right"));
				if (%backstab) {
					//teamBonusMessage(%shooterTeam, %damagedTeam, $georgesonBonusID, 0);
        				Client::sendMessage(%shooterClient, 0, "(+" @ $bonusAmount[$georgesonBonusID, 0] @ ") " @
						$bonusMessage[$georgesonBonusID, 0]);					
					%teamBonus += $bonusAmount[$georgesonBonusID, 0];
					$TRabbit::plyrNumGeorgesonBackstabs[%shooterClient] += 1;

				}
				// Enemy MA detection
				%done = false;
				echo("DISC DAMAGE:  " @ %value);
				for (%a = $numFlaggerMidairDamageBonuses - 1; (%a >= 0) && (!%done); %a--){
					if (GameBase::getlosinfo(%this,$bonusGoalValue[$flaggerMidairDamageBonusID, %a],"-1.57 0 0")) {
					} else if (%value > $TRabbit::midairDiscDamageThreshold) {
						// Set a flag to display the MA message later
						%midairBonus = %a;
						%teamBonus += $bonusAmount[$flaggerMidairDamageBonusID, %a];
						if (%damagedClient == $TRabbit::Carrier) {
							if (%a >= 1)
								// Shoot out 5, 10 or 15 flags
								funTest(%this, (%a * 5));
								//Flag::OnDrop(%this);

							else
								Flag::OnDrop(%this);
							$TRabbit::PlyrShootingPoints[%shooterClient] += %teamBonus;
						}
						else
							%value = %value * 4;   // Kill him
						$TRabbit::plyrNumMidairDiscs[%shooterClient] += 1;
						%done = true;
					}

				}
				$TRabbit::StyleScore[%shooterTeam] += %teamBonus;
				$TRabbit::PlyrScoreContribution[%shooterClient] += %teamBonus;
				Game::refreshClientScore(%shooterClient);
				TRabbit::updateTeamScores();
				%teamBonus = 0;
			}

			$TRabbit::killPenalty = true;
			// Friendly MA detection (go-go gadget grab)
			if((%type == $ExplosionDamageType) && (%damagedTeam == %shooterTeam) &&
			   (%damagedClient == $TRabbit::Carrier) && (%shooterClient != $TRabbit::Carrier)) {
				if (GameBase::getlosinfo(%this,$bonusGoalValue[$gogoGadgetBonusID, 0],"-1.57 0 0")) {
				} else if (%value > $TRabbit::midairDiscDamageThreshold) {
					$TRabbit::plyrNumMidairDiscs[%shooterClient] += 1;
					Game::refreshClientScore(%shooterClient);
					schedule("doubleCheckFlagTeleport(" @ %shooterClient @ ");", 0.3);
					//%shooterPosition = GameBase::getPosition(%shooterClient);
					//GameBase::setPosition($TRabbit::theFlag, %shooterPosition);
	
					%value = %value * 4;   // Kill him
					$TRabbit::killPenalty = false;

					// Allow both players involved to touch the flag again soon
					Flag::onDrop(%this);
					$TRabbit::FlagLastTouched[%damagedClient] -= $TRabbit::repeatedGrabRestriction;
					$TRabbit::FlagLastTouched[%shooterClient] -= $TRabbit::repeatedGrabRestriction;
					Item::setVelocity($TRabbit::theFlag, "0 0 0");

					$TRabbit::SpecialGrab = $gogoGadgetBonusID;
					$TRabbit::SpecialTime = getSimTime();
					Flag::onCollision($TRabbit::theFlag, Client::getOwnedObject(%shooterClient));
				}

			}
//**** END Disc damage detection


			//If Shield Pack is on
			if (%type != -1 && %this.shieldStrength) {
				%energy = GameBase::getEnergy(%this);
				%strength = %this.shieldStrength;
				if (%type == $ShrapnelDamageType || %type == $MortarDamageType)
					%strength *= 0.75;
				%absorb = %energy * %strength;
				if (%value < %absorb) {
					GameBase::setEnergy(%this,%energy - ((%value / %strength)*%friendFire));
					%thisPos = getBoxCenter(%this);
					%offsetZ =((getWord(%pos,2))-(getWord(%thisPos,2)));
					GameBase::activateShield(%this,%vec,%offsetZ);
					%value = 0;
				}
				else {
					GameBase::setEnergy(%this,0);
					%value = %value - %absorb;
				}
			}
  			if (%value) {
				%value = $DamageScale[%armor, %type] * %value * %friendFire;
            			%dlevel = GameBase::getDamageLevel(%this) + %value;
            			%spillOver = %dlevel - %armor.maxDamage;
				GameBase::setDamageLevel(%this,%dlevel);
				%flash = Player::getDamageFlash(%this) + %value * 2;
				if (%flash > 0.75) 
					%flash = 0.75;
				Player::setDamageFlash(%this,%flash);
				//If player not dead then play a random hurt sound
				if(!Player::isDead(%this)) { 
					if(%damagedClient.lastDamage < getSimTime()) {
						%sound = radnomItems(3,injure1,injure2,injure3);
						playVoice(%damagedClient,%sound);
						%damagedClient.lastdamage = getSimTime() + 1.5;
					}
				}
				else {

	%damagedTeam = GameBase::GetTeam(%damagedClient);
	%shooterTeam = GameBase::GetTeam(%shooterClient);


//***** BEGIN Friendly kill penalties
	if ((Client::getTeam(%damagedClient) == Client::getTeam(%shooterClient)) &&
	    (%damagedClient != %shooterClient) &&
	    ($TRabbit::killPenalty)) {
	    	if (%damagedClient == $TRabbit::flagGrabber)
			%fkID = $ownFlaggerKillPenaltyID;
		else
			%fkID = $teammateKillPenaltyID;
		teamPenaltyMessage(%shooterTeam, %fkID);
		%teamPenalty = $penaltyAmount[%fkID];
		$TRabbit::StyleScore[%shooterTeam] -= %teamPenalty;
		$TRabbit::PlyrScoreContribution[%shooterClient] -= %teamPenalty;
		$TRabbit::PlyrShootingPoints[%shooterClient] -= %teamPenalty;
		$TRabbit::PlyrNumTeamKills[%shooterClient] += 1;
		Game::refreshClientScore(%shooterClient);
		TRabbit::updateTeamScores();
	}
//***** END Friendly kill penalties

//***** BEGIN enemy kill detection
	//%damagedClient = Player::getClient(%this);
	//%shooterClient = %object;
	%teamBonus = 0;
	%victimVelocity = Item::getVelocity(%this);
	%victimSpeed = Vector::getDistance(%victimVelocity, "0 0 0");
	echo("KILLTRACK : check victim speed " @ %victimSpeed @ ".." @ %damagedClient @ "," @ $TRabbit::flagGrabber);
	if ((%damagedClient == $TRabbit::flagGrabber) && ($TRabbit::flaggerGotKilled) &&
	    (%damagedClient != %shooterClient) &&
	    (%damagedTeam != %shooterTeam)){
		if(%type == $ShrapnelDamageType) {
			// Grenade kill
			if (GameBase::getlosinfo(%this,$bonusGoalValue[$midairGrenadeBonusID, 0],"-1.57 0 0")) {
			} else {
				teamBonusMessage(%shooterTeam, %damagedTeam, $midairGrenadeBonusID, 0);
				%teamBonus += $bonusAmount[$midairGrenadeBonusID, 0];
			}
		}
		if(%type != $BulletDamageType){
			// Fast kill
			%done = false;
			for (%a = $numFlaggerKillBonuses - 1; (%a >= 0) && (!%done); %a--){
				if (%victimSpeed > $bonusGoalValue[$flaggerKillBonusID, %a]){
					teamBonusMessage(%shooterTeam, %damagedTeam, $flaggerKillBonusID, %a);
					%teamBonus += $bonusAmount[$flaggerKillBonusID, %a];
					%done = true;
				}

			}
		}
		else{
			echo("KILLTRACK : chain kill");
			// ChainKill
			%done = false;
			for (%a = $numFlaggerChainKillBonuses - 1; (%a >= 0) && (!%done); %a--){
				if (%victimSpeed > $bonusGoalValue[$flaggerChainKillBonusID, %a]){
					teamBonusMessage(%shooterTeam, %damagedTeam, $flaggerChainKillBonusID, %a);
					%teamBonus += $bonusAmount[$flaggerChainKillBonusID, %a];
					%done = true;
				}
			}
		}
	}

	// Track flag carrier kill stat
   	if ((%damagedClient == $TRabbit::flagGrabber) && (%shooterClient != $TRabbit::flagGrabber))
		$TRabbit::plyrNumFlaggerKills[%shooterClient] += 1;

	$TRabbit::PlyrShootingPoints[%shooterClient] += %teamBonus;

	// Rabid Rabbit
	if ((%shooterClient == $TRabbit::Carrier) &&
	    (%damagedClient != %shooterClient) &&
	    (%damagedTeam != %shooterTeam)) {
		teamBonusMessage(%shooterTeam, %damagedTeam, $rabidRabbitBonusID, 0);
		%teamBonus += $bonusAmount[$rabidRabbitBonusID, 0];
	}

	%damagedPosition = GameBase::getPosition(%this);
	%carrierPosition = GameBase::getPosition($TRabbit::Carrier);
	%distanceFromCarrier = Vector::getDistance(%damagedPosition, %carrierPosition);
	echo("VP = " @ %damagedPosition @ "   CP = " @ %carrierPosition @ "   DISTANCEFC = " @ %distanceFromCarrier);
	%carrierTeam = GameBase::getTeam($TRabbit::Carrier);

	// Hare helper
	if  (($TRabbit::Carrier != "") && (%damagedClient != %shooterClient) &&
	    (%damagedTeam != %shooterTeam) && (%carrierTeam == %shooterTeam) &&
	    (%distanceFromCarrier <= $bonusGoalValue[$hareHelperBonusID, 0]) &&
	    (%shooterClient != $TRabbit::Carrier)) {
		//teamBonusMessage(%shooterTeam, %damagedTeam, $hareHelperBonusID, 0);
        	Client::sendMessage(%shooterClient, 0, "(+" @ $bonusAmount[$hareHelperBonusID, 0] @ ") " @
			$bonusMessage[$hareHelperBonusID, 0]);
		%teamBonus += $bonusAmount[$hareHelperBonusID, 0];
	}
	
	// Update score info
	$TRabbit::PlyrScoreContribution[%shooterClient] += %teamBonus;
	Game::refreshClientScore(%shooterClient);
	$TRabbit::StyleScore[%shooterTeam] += %teamBonus;
	TRabbit::updateTeamScores();

//***** END enemy kill detection


               				if(%spillOver > 0.5 && (%type== $ExplosionDamageType || %type == $ShrapnelDamageType || %type== $MortarDamageType|| %type == $MissileDamageType)) {
		 				Player::trigger(%this, $WeaponSlot, false);
						%weaponType = Player::getMountedItem(%this,$WeaponSlot);
						if(%weaponType != -1)
							Player::dropItem(%this,%weaponType);
                				Player::blowUp(%this);
					}
					else
					{
						if ((%value > 0.40 && (%type== $ExplosionDamageType || %type == $ShrapnelDamageType || %type== $MortarDamageType || %type == $MissileDamageType )) || (Player::getLastContactCount(%this) > 6) ) {
					  		if(%quadrant == "front_left" || %quadrant == "front_right") 
								%curDie = $PlayerAnim::DieBlownBack;
							else
								%curDie = $PlayerAnim::DieForward;
						}
						else if( Player::isCrouching(%this) ) 
							%curDie = $PlayerAnim::Crouching;							
						else if(%vertPos=="head") {
							if(%quadrant == "front_left" ||	%quadrant == "front_right"	) 
								%curDie = radnomItems(2, $PlayerAnim::DieHead, $PlayerAnim::DieBack);
						  	else 
								%curDie = radnomItems(2, $PlayerAnim::DieHead, $PlayerAnim::DieForward);
						}
						else if (%vertPos == "torso") {
							if(%quadrant == "front_left" ) 
								%curDie = radnomItems(3, $PlayerAnim::DieLeftSide, $PlayerAnim::DieChest, $PlayerAnim::DieForwardKneel);
							else if(%quadrant == "front_right") 
								%curDie = radnomItems(3, $PlayerAnim::DieChest, $PlayerAnim::DieRightSide, $PlayerAnim::DieSpin);
							else if(%quadrant == "back_left" ) 
								%curDie = radnomItems(4, $PlayerAnim::DieLeftSide, $PlayerAnim::DieGrabBack, $PlayerAnim::DieForward, $PlayerAnim::DieForwardKneel);
							else if(%quadrant == "back_right") 
								%curDie = radnomItems(4, $PlayerAnim::DieGrabBack, $PlayerAnim::DieRightSide, $PlayerAnim::DieForward, $PlayerAnim::DieForwardKneel);
						}
						else if (%vertPos == "legs") {
							if(%quadrant == "front_left" ||	%quadrant == "back_left") 
								%curDie = $PlayerAnim::DieLegLeft;
							if(%quadrant == "front_right" ||	%quadrant == "back_right") 
								%curDie = $PlayerAnim::DieLegRight;
						}
						Player::setAnimation(%this, %curDie);
					}
					if(%type == $ImpactDamageType && %object.clLastMount != "")  
						%shooterClient = %object.clLastMount;
					Client::onKilled(%damagedClient,%shooterClient, %type);
				}
			}
		}
	}
	// Now display MA message, if applicable
	if (%midairBonus >= 0)
		teamBonusMessage(%shooterTeam, %damagedTeam, $flaggerMidairDamageBonusID, %midairBonus, %shooterName);
}


function Client::onKilled(%playerId, %killerId, %damageType)
{
   echo("GAME: kill " @ %killerId @ " " @ %playerId @ " " @ %damageType);
   %playerId.guiLock = true;
   Client::setGuiMode(%playerId, $GuiModePlay);

   %ridx = floor(getRandom() * ($numDeathMsgs - 0.01));
   %victimName = Client::getName(%playerId);

   // Apply hot potato penalty here if desired
   if (%damageType == $PotatoDamageType){
	MessageAll(0, %victimName @ " got burned!");
   	Game::clientKilled(%playerId, %killerId);
   }
	if(!String::ICompare(Client::getGender(%playerId), "Male"))
   {
      %playerGender = "his";

   }
	else
	{
		%playerGender = "her";
	}


   if(!%killerId)
   {
      messageAll(0, strcat(%victimName, " dies."), $DeathMessageMask);
      %playerId.scoreDeaths++;
  }

   else if(%killerId == %playerId)
   {
   %victimTeam = GameBase::GetTeam(%playerID);
	//  %oopsMsg = sprintf($deathMsg[-2, %ridx], %victimName, %playerGender);
      //MessageAll(0, %oopsMsg, $DeathMessageMask);
	teamMessages(2, %victimTeam, "(" @ %victimName @ " is respawning)");
      %playerId.scoreDeaths++;
      //%playerId.score--;
      Game::refreshClientScore(%playerId);
   }
   else
   {
		if(!String::ICompare(Client::getGender(%killerId), "Male"))
		{
			%killerGender = "his";
		}
		else
		{
			%killerGender = "her";
		}
      if($teamplay && $TRabbit::killPenalty && (Client::getTeam(%killerId) == Client::getTeam(%playerId)))
      {
		if(%damageType != $MineDamageType) 
	    	messageAll(0, strcat(Client::getName(%killerId), 
   	        " mows down ", %killerGender, " teammate, ", %victimName), $DeathMessageMask);
		else 
	         messageAll(0, strcat(Client::getName(%killerId), 
   	     	" killed ", %killerGender, " teammate, ", %victimName ," with a mine."), $DeathMessageMask);
		 %killerId.scoreDeaths++;
       %killerId.score--;
       Game::refreshClientScore(%killerId);
      }
      else
      {

	     %obitMsg = sprintf($deathMsg[%damageType, %ridx], Client::getName(%killerId),
	       %victimName, %killerGender, %playerGender);
         messageAll(0, %obitMsg, $DeathMessageMask);
         %killerId.scoreKills++;
         %playerId.scoreDeaths++;  // test play mode
         //%killerId.score++;
         Game::refreshClientScore(%killerId);
         Game::refreshClientScore(%playerId);
      }
   }

   // Give the player a score update
   %playerTeam = GameBase::getTeam(%playerId);
   if (%playerTeam == 0)
      %otherTeam = 1;
   else
      %otherTeam = 0;
   %playerTeamScore = $teamScore[%playerTeam];
   %otherTeamScore = $teamScore[%otherTeam];
   if (%playerTeamScore > %otherTeamScore) {
	%winOrLose = "winning";
	%scoreMargin = %playerTeamScore - %otherTeamScore;
   }
   else if (%playerTeamScore < %otherTeamScore){
	%winOrLose = "losing";
	%scoreMargin = %otherTeamScore - %playerTeamScore;
   } 
   else
	%winOrLose = "tie";

   if (%winOrLose == "tie")
	centerPrint(%playerId, "<jc>The score is tied.", 2);
   else
   centerPrint(%playerId, "<jc>Your score:  " @ %playerTeamScore
	@ " points\nTheir score:  " @ %otherTeamScore @ " points\n"
	@ "\nYour team is " @ %winOrLose @ " by " @ %scoreMargin @ " points.", 2);

   Game::clientKilled(%playerId, %killerId);
}



///////////////////////////////////////////////////////////////////////////////////////////////
// Player collision functions
///////////////////////////////////////////////////////////////////////////////////

// Detect flagger collisions here
function Player::onCollision(%this,%object)
{

//**** BEGIN Mario/KTS detection
	%playerClient = Player::getClient(%this);
        %hitterClient = Player::getClient(%object);
	%playerTeam = GameBase::getTeam(%playerClient);
	%hitterTeam = GameBase::getTeam(%object);
	%playerName = Client::getName(%playerClient);
	%hitterName = Client::getName(%hitterClient);
	if ((getObjectType(%object) == "Player") && (getObjectType(%this) == "Player") &&
            ($TRabbit::Carrier == %playerClient)  && (%playerName != "") && (%hitterName != "")) {
		%playerPosition = GameBase::getPosition(%this);
		%playerHeight = getWord(%playerPosition,2);
		%hitterPosition = GameBase::getPosition(%object);
		%hitterHeight = getWord(%hitterPosition,2);
		%hitterVelocity = Item::getVelocity(%object);
		%hitterSpeed = Vector::getDistance(%hitterVelocity, "0 0 0");
		if (%playerTeam == %hitterTeam) {
			//Mario grab
			echo("MARIO:  playerHeight = " @ %playerHeight @ ";  hitterheight = " @ %hitterHeight);
			if (%hitterHeight - %playerHeight > $bonusGoalValue[$marioBonusID, 0]) {
				$TRabbit::SpecialGrab = $marioBonusID;
				$TRabbit::SpecialTime = getSimTime();
				messageall(0, %hitterName @ " trounced on " @ %playerName @ "'s head!");
				Flag::onDrop2(%this, 14);
			}
			//Inverse Mario grab
			else if (%playerHeight - %hitterHeight > $bonusGoalValue[$inverseMarioBonusID, 0]) {
				$TRabbit::SpecialGrab = $inverseMarioBonusID;
				$TRabbit::SpecialTime = getSimTime();
				messageall(0, %hitterName @ " smacked " @ %playerName @ "'s ass!");
				Flag::onDrop2(%this, 30);

			}
		}
		else {
   			%currentTime = getSimTime();
			// Don't allow recent thiefs to re-steal immediately
   			// Number of seconds before player can grab flag again after dropping it
   			if ((%currentTime - $TRabbit::FlagLastTouched[%hitterClient]) < $TRabbit::repeatedGrabRestriction)			    // || (%hitterSpeed < 0.1))
      				return;
 
			//Kidney Thief Steal
			$TRabbit::SpecialGrab = $kidneyThiefBonusID;
			$TRabbit::SpecialTime = getSimTime();

			//Flag::onDrop(%this);
			messageAll(0, %hitterName @ " picked " @ %playerName @ "'s pocket!");
			//GameBase::setPosition($TRabbit::theFlag, %hitterPosition);
			Flag::onDrop(%this);
			Flag::onCollision($TRabbit::theFlag, %object);
		}
		//echo("PLAYER HIT, speed " @ %hitterSpeed);
	}
//**** END Mario/KTS detection

	else
	if (Player::isDead(%this)) {
		if (getObjectType(%object) == "Player") {
			// Transfer all our items to the player
			%sound = false;
			%max = getNumItems();
			for (%i = 0; %i < %max; %i = %i + 1) {
				%count = Player::getItemCount(%this,%i);
				if (%count) {
					%delta = Item::giveItem(%object,getItemData(%i),%count);
					if (%delta > 0) {
						Player::decItemCount(%this,%i,%delta);
						%sound = true;
					}
				}
			}
			if (%sound) {
				// Play pickup if we gave him anything
				playSound(SoundPickupItem,GameBase::getPosition(%this));
			}
		}
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////
// Mission boundary functions
///////////////////////////////////////////////////////////////////////////////////

//Player has a total of 10 seconds per life allowed outside designated mission area.
//After a player expends this 10 sec, the player is remotely killed.
function Player::leaveMissionArea(%player){
   %cl = Player::getClient(%player);
   Client::sendMessage(%cl,1,"You have left the mission area.~wLeftMissionArea.wav");
   %player.outArea=1;
   alertPlayer(%player, 3);
}


//checking for timeout of dieSeqCount
function Player::checkLMATimeout(%player, %seqCount)
{
   echo("DEBUG : checking player timeout " @ %player @ " " @ %seqCount);
   if(%player.dieSeqCount == %seqCount)
      remoteKill(Player::getClient(%player));
}


function Player::enterMissionArea(%player)
{
   %player.outArea="";
   %player.dieSeqCount = 0;
   %player.timeLeft = %player.timeLeft - (getSimTime() - %player.leaveTime);
}

  
 function alertPlayer(%player, %count){                                                
    if(%player.outArea == 1){                                                          
       %clientId = Player::getClient(%player);                                         
       Client::sendMessage(%clientId,1,"~w.wav");                       
                                                                                       
       if(%count > 1)                                                                  
          schedule("alertPlayer(" @ %player @ ", " @ %count - 1 @ ");",1.5,%clientId); 
       else                                                                            
          schedule("leaveMissionAreaDamage(" @ %clientId @ ");",1,%clientId);          
    }                                                                                  
 }                                                                                     


 function leaveMissionAreaDamage(%client){                                            
    %player = Client::getOwnedObject(%client);                                        
                                                                                      

    if(%player.outArea == 1){                                                         
       if(!Player::isDead(%player)){                                                  
         Player::setDamageFlash(%client,0.1);                                        
          GameBase::setDamageLevel(%player,GameBase::getDamageLevel(%player) + 0.05); 
 	  schedule("leaveMissionAreaDamage(" @ %client @ ");",1);                           
       }                                                                              
       else {                                                                         
          playNextAnim(%client);	                                                    
          Client::onKilled(%client, %client);                                         
       }                                                                              
    }                                                                                 
 }                                                                                    



///////////////////////////////////////////////////////////////////////////////////////////////
// Waypoint-related functions
///////////////////////////////////////////////////////////////////////////////////

function Game::playerSpawned(%pl, %clientId, %armor){	
   //TRabbit::changeTeam(%clientId, 0);  //switch player to team 0
      
   %clientId.spawn= 1;
   for(%i = 0; (%item = $spawnBuyList[%i]) != ""; %i++)
      buyItem(%clientId,%item);	
   %clientId.spawn= "";

   Player::useItem(%pl,$spawnWeapon);
   $TRabbit::FlagLastTouched[%clientID] = -30;  // set reset timestamp to allow player to grab flag
   TRabbit::resetWaypoint(%clientId);	
}


function TRabbit::initNewFlagCarrier(){
    if ($TRabbit::Carrier < 0){
       echo("DEBUG : Oops!  Dropped it before function was called!  Killing thread.");
       return;
    }
    $TRabbit::Carrier.isHot = False;
    $TRabbit::lastToPassThrough = $TRabbit::Carrier;
    echo(Client::getName($TRabbit::carrier) @ " is the new flag carrier");
    TRabbit::FlagPointTimer();
}

function TRabbit::resetWaypoint(%client){
   
   if (($TRabbit::Carrier > 0) && (%client != $TRabbit::carrier)){      
      %carrier = $TRabbit::Carrier;
      %name = Client::getName(%carrier);
      issueTargCommand(%client, %client, 0,"Get the flag!  [" @ %name @ "]", %carrier);
      echo("DEBUG : Waypoint reset");
   }
   else
      echo("DEBUG : No Waypoint set");
}
 
function TRabbit::WaypointToCarrier(%carrier){
   %numclients = getNumClients();
   %name = Client::getName(%carrier);
   %carrierTeam = GameBase::getTeam(%carrier);

   for (%i = 0; %i < %numclients; %i++){ 
      %client = getClientByIndex(%i);
      %clientTeam = GameBase::getTeam(%client);
      if (%client == $TRabbit::carrier) {
	 // Give the carrier a waypoint to his current closest teammate
         %closestMate = "";
         %closestMateDistance = 9999;
	 %carrierPosition = GameBase::getPosition($TRabbit::Carrier);
	 for (%j = 0; %j < %numclients; %j++) {
		%mate = getClientByIndex(%j);
      		%mateTeam = GameBase::getTeam(%mate);
		if ((%carrierTeam == %mateTeam) && (%client != %mate)) {
			%matePosition = GameBase::getPosition(%mate);
			%distanceToMate = Vector::getDistance(%carrierPosition, %matePosition);
			if (%distanceToMate < %closestMateDistance) {
				%closestMateDistance = %distanceToMate;
				%closestMate = %mate;
			}
	 	}
	}
	 if (%closestMate == "")
	         IssueTargCommand(%client, %client, 0, "You have the flag!", %carrier - 2048);
	 else {
		 %mateName = Client::getName(%closestMate);
		 IssueTargCommand(%client, %client, 0, "You have the flag!  WP: " @ %mateName, %closestMate - 2048);
	}
      } else {
	 if (%clientTeam == %carrierTeam) 
		%message = "Your teammate ";
	 else
		%message = "The enemy ";      
         IssueTargCommand(%client, %client, 0, %message @ %name @ " has the flag!", %carrier - 2048);
     } 
	}
echo("DEBUG : Waypoint to carrier set " @ %client @ "  " @ %name @ "  " @ %carrier);
}



function TRabbit::clearWaypoint(%flag){
   %numclients = getNumClients();
   %name = Client::getName(%carrier);
   %flagPosition = GameBase::getPosition(%flag);
   %flagx = getWord(%flagPosition, 0);
   %flagy = getWord(%flagPosition, 1);
   for (%i = 0; %i < %numclients; %i++){ 
      %client = getClientByIndex(%i);
      //setCommandStatus(%client, 0, "Flag has been dropped.	");
      issueCommand(%client, %client, 0, "Flag dropped near current waypoint!", %flagx, %flagy);
   } 
   echo("DEBUG : Waypoint cleared");
}



///////////////////////////////////////////////////////////////////////////////////////////////
// Legacy Rabbit functions
///////////////////////////////////////////////////////////////////////////////////

// switches player's team to whichever team is passed to it
function TRabbit::changeTeam(%playerId, %team)
{
   GameBase::setTeam(%playerId, %team); //switch team 
}

// called when mission cycles to 
// see if a player is still holding flag 
// to capture time held & quit awarding points
function TRabbit::FlagHeldCheck(){
   if ($TRabbit::Carrier > 0){
         %plyr = $TRabbit::carrier;
         $TRabbit::Carrier = -1;  
         %flagHeld = getSimTime() - $TRabbit::FlagGrabTimeStamp[%plyr];
         $TRabbit::PlyrTtlFlagHeld[%plyr] += %flagHeld;
         if (%flagHeld > $TRabbit::PlyrLongestFlagHeld[%plyr])
            $TRabbit::PlyrLongestFlagHeld[%plyr] = %flagHeld;      
   } 
}


// assign average time held for all players
// based on their (total time held / flag grabs)
function TRabbit::getAvgHolds(){
   %numClients = getNumClients();
   for (%z = 0; %z < %numClients; %z++){
      %plyr = getClientByIndex(%z);
      if ($TRabbit::PlyrTtlFlagHeld[%plyr] > 0) 
         $TRabbit::PlyrAvgFlagHeld[%plyr] = $TRabbit::PlyrTtlFlagHeld[%plyr] / $TRabbit::PlyrFlagGrabs[%plyr];
      else
         $TRabbit::PlyrAvgFlagHeld[%plyr] = 0;
   }
}
 

// check all clients, to see who held flag longest
function TRabbit::getLongestFlag(){
   %numClients = getNumClients();
   for (%z = 0; %z < %numClients; %z++){
     %plyr = getClientByIndex(%z);
      if ($TRabbit::PlyrLongestFlagHeld[%plyr] > $TRabbit::LongestFlagHeld){
         $TRabbit::PlayerHoldingLongest = %plyr;
         $TRabbit::LongestFlagHeld = $TRabbit::PlyrLongestFlagHeld[%plyr]; 
      }
   }
}



///////////////////////////////////////////////////////////////////////////////////////////////
// Miscellaneous functions (mostly small changes to existing functions)
///////////////////////////////////////////////////////////////////////////////////

function TRabbit::invalidateItems(){
   %count =0;
   for (%i = 0; $TRabbit::Item[%i, ItemType] != ""; %i++){
      if ($TRabbit::Item[%i, Allowed] != true){
         $invList[$TRabbit::Item[%i, ItemType]] = 0;
         $remoteInvList[$TRabbit::Item[%i, ItemType]] = 0;
         $ammoPackMax[$TRabbit::Item[%i, ItemType]] = 0;  //to stop players from getting these items via ammopack (circumvent game bug)  
         $TRabbit::banList[%count] = $TRabbit::Item[%i, DisplayName];
//         echo("DEBUG : Removing " @ $TRabbit::banList[%count]);
         %count++;
      }
   } 
   $TRabbit::banList[%count] = "";  //place blank entry at end of list to end        
}


function TRabbit::validateItems(){
   for (%i = 0; $TRabbit::Item[%i, ItemType] != ""; %i++){
      if ($TRabbit::Item[%i, Allowed] != true){
         $invList[$TRabbit::Item[%i, ItemType]] = 1;
         $remoteinvList[$TRabbit::Item[%i, ItemType]] = 1;
         // echo("DEBUG : Restoring " @ $TRabbit::Item[%i, displayName]);
      }
   } 
   $AmmoPackMax[BulletAmmo] = 150; //reset any $ammoPackMax values we might have changed in TRabbit::invalidateItems
   $AmmoPackMax[PlasmaAmmo] = 30;
   $AmmoPackMax[DiscAmmo] = 15;
   $AmmoPackMax[GrenadeAmmo] = 15;
   $AmmoPackMax[MortarAmmo] = 10;
   $AmmoPackMax[MineAmmo] = 5;
   $AmmoPackMax[Grenade] = 10;
   $AmmoPackMax[Beacon] = 10;
   exec("Objectives.cs");  //redefine Flag:: functions (and several others) in case next mission isn't TRabbit
}


function ObjectiveMission::initCheck(%object){
//   echo("DEBUG : ObjectiveMission::init called");
   if(GameBase::virtual(%object, objectiveInit))
      addToSet("MissionCleanup/ObjectivesSet", %object);
}

function remoteMissionChangeNotify(%serverManagerId, %nextMission)
{
   if(%serverManagerId == 2048)
   {
      //cls();  remmed this so I could see the console
      echo("DEBUG : Server mission complete - changing to mission: ", %nextMission);
      // echo("DEBUG : Flushing Texture Cache");
      flushTextureCache();
      schedule("purgeResources(true);", 3);
   }
}



function processMenuOptions(%clientId, %option)
{
   %opt = getWord(%option, 0);
   %cl = getWord(%option, 1);

   if(%opt == "fteamchange")
   {
      %clientId.ptc = %cl;
      Client::buildMenu(%clientId, "Pick a team:", "FPickTeam", true);
      Client::addMenuItem(%clientId, "0Observer", -2);
      //if ($Game::MissionType == "TRabbit"){
         Client::addMenuItem(%clientId, "1" @ getTeamName(0), 0);
         Client::addMenuItem(%clientId, "2" @ getTeamName(1), 1);
      //}
      //else{
      //   Client::addMenuItem(%clientId, "1Automatic", -1);
      //   for(%i = 0; %i < getNumTeams(); %i = %i + 1)
      //      Client::addMenuItem(%clientId, (%i+2) @ getTeamName(%i), %i);
      //}
      return;
   }      
   else if(%opt == "changeteams")
   {
      if(!$matchStarted || !$Server::TourneyMode)
      {
         Client::buildMenu(%clientId, "Pick a team:", "PickTeam", true);
         Client::addMenuItem(%clientId, "0Observer", -2);
         //if ($Game::MissionType == "TRabbit"){
            Client::addMenuItem(%clientId, "1" @ getTeamName(0), 0);
	    Client::addMenuItem(%clientId, "2" @ getTeamName(1), 1);
	 //}
         //else{
         //   Client::addMenuItem(%clientId, "1Automatic", -1);
         //   for(%i = 0; %i < getNumTeams(); %i = %i + 1)
         //      Client::addMenuItem(%clientId, (%i+2) @ getTeamName(%i), %i);
        // }
         return;
      }
   }
   else if(%opt == "mute")
      %clientId.muted[%cl] = true;
   else if(%opt == "unmute")
      %clientId.muted[%cl] = "";
   else if(%opt == "vkick")
   {
      %cl.voteTarget = true;
      Admin::startVote(%clientId, "kick " @ Client::getName(%cl), "kick", %cl);
   }
   else if(%opt == "vadmin")
   {
      %cl.voteTarget = true;
      Admin::startVote(%clientId, "admin " @ Client::getName(%cl), "admin", %cl);
   }
   else if(%opt == "vsmatch")
      Admin::startVote(%clientId, "start the match", "smatch", 0);
   else if(%opt == "vetd")
      Admin::startVote(%clientId, "enable team damage", "etd", 0);
   else if(%opt == "vdtd")
      Admin::startVote(%clientId, "disable team damage", "dtd", 0);
   else if(%opt == "etd")
      Admin::setTeamDamageEnable(%clientId, true);
   else if(%opt == "dtd")
      Admin::setTeamDamageEnable(%clientId, false);
   else if(%opt == "vcffa")
      Admin::startVote(%clientId, "change to Free For All mode", "ffa", 0);
   else if(%opt == "vctourney")
      Admin::startVote(%clientId, "change to Tournament mode", "tourney", 0);
   else if(%opt == "cffa")
      Admin::setModeFFA(%clientId);
   else if(%opt == "ctourney")
      Admin::setModeTourney(%clientId);
   else if(%opt == "voteYes" && %cl == $curVoteCount)
   {
      %clientId.vote = "yes";
      centerprint(%clientId, "", 0);
   }
   else if(%opt == "voteNo" && %cl == $curVoteCount)
   {
      %clientId.vote = "no";
      centerprint(%clientId, "", 0);
   }
   else if(%opt == "kick")
   {
      Client::buildMenu(%clientId, "Confirm kick:", "kaffirm", true);
      Client::addMenuItem(%clientId, "1Kick " @ Client::getName(%cl), "yes " @ %cl);
      Client::addMenuItem(%clientId, "2Don't kick " @ Client::getName(%cl), "no " @ %cl);
      return;
   }
   else if(%opt == "admin")
   {
      Client::buildMenu(%clientId, "Confirm admim:", "aaffirm", true);
      Client::addMenuItem(%clientId, "1Admin " @ Client::getName(%cl), "yes " @ %cl);
      Client::addMenuItem(%clientId, "2Don't admin " @ Client::getName(%cl), "no " @ %cl);
      return;
   }
   else if(%opt == "ban")
   {
      Client::buildMenu(%clientId, "Confirm Ban:", "baffirm", true);
      Client::addMenuItem(%clientId, "1Ban " @ Client::getName(%cl), "yes " @ %cl);
      Client::addMenuItem(%clientId, "2Don't ban " @ Client::getName(%cl), "no " @ %cl);
      return;
   }
   else if(%opt == "smatch")
      Admin::startMatch(%clientId);
   else if(%opt == "vcmission" || %opt == "cmission")
   {
      Admin::changeMissionMenu(%clientId, %opt == "cmission");
      return;
   }
   else if(%opt == "ctimelimit")
   {
      Client::buildMenu(%clientId, "Change Time Limit:", "ctlimit", true);
      Client::addMenuItem(%clientId, "110 Minutes", 10);
      Client::addMenuItem(%clientId, "215 Minutes", 15);
      Client::addMenuItem(%clientId, "320 Minutes", 20);
      Client::addMenuItem(%clientId, "425 Minutes", 25);
      Client::addMenuItem(%clientId, "530 Minutes", 30);
      Client::addMenuItem(%clientId, "645 Minutes", 45);
      Client::addMenuItem(%clientId, "760 Minutes", 60);
      Client::addMenuItem(%clientId, "8No Time Limit", 0);
      return;
   }
   else if(%opt == "reset")
   {
      Client::buildMenu(%clientId, "Confirm Reset:", "raffirm", true);
      Client::addMenuItem(%clientId, "1Reset", "yes");
      Client::addMenuItem(%clientId, "2Don't Reset", "no");
      return;
   }
   else if(%opt == "observe")
   {
      Observer::setTargetClient(%clientId, %cl);
      return;
   }
   Game::menuRequest(%clientId);
}


// added a call to my TRabbit::JoinInit function to reset residual scores
function Game::initialMissionDrop(%clientId)
{
      TRabbit::JoinInit(%clientId);
	Client::setGuiMode(%clientId, $GuiModePlay);

   if($Server::TourneyMode)
      GameBase::setTeam(%clientId, -1);
   else
   {
      if(%clientId.observerMode == "observerFly" || %clientId.observerMode == "observerOrbit")
      {
	      %clientId.observerMode = "observerOrbit";
	      %clientId.guiLock = "";
         Observer::jump(%clientId);
         return;
      }
      %numTeams = getNumTeams();
      %curTeam = Client::getTeam(%clientId);

      if(%curTeam >= %numTeams || (%curTeam == -1 && (%numTeams < 2 || $Server::AutoAssignTeams)) )
         //GameBase::setTeam(%clientId, 0);
         Game::assignClientTeam(%clientId);
   }    
	Client::setControlObject(%clientId, Client::getObserverCamera(%clientId));
   %camSpawn = Game::pickObserverSpawn(%clientId);
   Observer::setFlyMode(%clientId, GameBase::getPosition(%camSpawn), 
	   GameBase::getRotation(%camSpawn), true, true);

   if(Client::getTeam(%clientId) == -1)
   {
      %clientId.observerMode = "pickingTeam";

      if($Server::TourneyMode && ($matchStarted || $matchStarting))
      {
         %clientId.observerMode = "observerOrbit";
         return;
      }
      else if($Server::TourneyMode)
      {
         if($Server::TeamDamageScale)
            %td = "ENABLED";
         else
            %td = "DISABLED";
         bottomprint(%clientId, "<jc><f1>Server is running in Competition Mode\nPick a team.\nTeam damage is " @ %td, 0);
      }
      Client::buildMenu(%clientId, "Pick a team:", "InitialPickTeam");
      Client::addMenuItem(%clientId, "0Observe", -2);

      Client::addMenuItem(%clientId, "1" @ getTeamName(0), 0);
      %clientId.justConnected = "";
   }
   else 
   {
      //Client::setSkin(%clientId, $Client::info[%ClientId, 0]);  //use custom skin
      
      if(%clientId.justConnected)
      {
         centerprint(%clientId, $Server::JoinMOTD, 0);
         %clientId.observerMode = "displayRules";
         %clientId.justConnected = "";
      }
      else if(%clientId.observerMode == "justJoined")
      {
         centerprint(%clientId, "");
         %clientId.observerMode = "";
         Game::playerSpawn(%clientId, false);
      }
      else
         Game::playerSpawn(%clientId, false);
	}
	if($TeamEnergy[Client::getTeam(%clientId)] != "Infinite")
		$TeamEnergy[Client::getTeam(%clientId)] += $InitialPlayerEnergy;
	%clientId.teamEnergy = 0;
}

// Override to just recognize 2 teams
function Game::assignClientTeam(%playerId)
{
   if($teamplay)
   {
      %name = Client::getName(%playerId);
      %numTeams = 2; //getNumTeams();
      if($teamPreset[%name] != "")
      {
         if($teamPreset[%name] < %numTeams)
         {
            GameBase::setTeam(%playerId, $teamPreset[%name]);
            echo(Client::getName(%playerId), " was preset to team ", $teamPreset[%name]);
            return;
         }            
      }
      %numPlayers = getNumClients();
      for(%i = 0; %i < %numTeams; %i = %i + 1)
         %numTeamPlayers[%i] = 0;

      for(%i = 0; %i < %numPlayers; %i = %i + 1)
      {
         %pl = getClientByIndex(%i);
         if(%pl != %playerId)
         {
            %team = Client::getTeam(%pl);
            %numTeamPlayers[%team] = %numTeamPlayers[%team] + 1;
         }
      }
      %leastPlayers = %numTeamPlayers[0];
      %leastTeam = 0;
      for(%i = 1; %i < %numTeams; %i = %i + 1)
      {
         if( (%numTeamPlayers[%i] < %leastPlayers) || 
            ( (%numTeamPlayers[%i] == %leastPlayers) && 
            ($teamScore[%i] < $teamScore[%leastTeam] ) ))
         {
            %leastTeam = %i;
            %leastPlayers = %numTeamPlayers;
         }
      }
      GameBase::setTeam(%playerId, %leastTeam);
      echo(Client::getName(%playerId), " was automatically assigned to team ", %leastTeam);
   }
   else
   {
      GameBase::setTeam(%playerId, 0);
   }
}

function Vote::changeMission(){
   $timeLimitReached = true;
   TRabbit::objectivesScreen();
}

// players can use stations from either team
function Station::onCollision(%this, %object)
{
	if(%this.target == ""){
		dbecho(3, "STATION: Collision (" @ %this @ "," @ %object @ ")");
		%obj = getObjectType(%object);
		if (%obj == "Player" && isPlayerBusy(%object) == 0) {
  		 	%client = Player::getClient(%object);
			//Don't check the player's team
 			//if(GameBase::getTeam(%object) == GameBase::getTeam(%this) || GameBase::getTeam(%this) == -1) {
				if (GameBase::getDamageState(%this) == "Enabled") {
					if (GameBase::isPowered(%this)) { 
						if(%this.enterTime == "")
							%this.enterTime = getSimTime();
						GameBase::setActive(%this,true);
					}
					else 
						Client::sendMessage(%client,0,"Unit is not powered");
				}
				else 
					Client::sendMessage(%client,0,"Unit is disabled");
			//}
			//else 
			//if(Station::getTarget(%this) == %object)
   	   		//{
			//	%curTime = getSimTime();
			//	if(%curTime - %object.stationDeniedStamp > 3.5 && GameBase::getDamageState(%this) == "Enabled") {
			//		Client::clearItemShopping(%client);
			//		Station::onDeactivate(%this);
			//		Station::onEndSequence(%this,1);
			//		if(Client::getGuiMode(%client) != 1)
			//			Client::setGuiMode(%client,1);
			//		%object.stationDeniedStamp = %curTime;
			//		Client::sendMessage(%client,0,"--ACCESS DENIED-- Wrong Team ~waccess_denied.wav");
			//	}
			//}
		}
	}
}



// Borrowed these from arena
// Fixed some typos/wording
function checkResources(%player,%item,%delta,%noMessage)
{
	%client = Player::getClient(%player);
	%team = Client::getTeam(%client);
	%extraAmmo = 0 ;
	if (Player::getMountedItem(%client,$BackpackSlot) == ammopack && $AmmoPackMax[%item] != "") {
		%extraAmmo = $AmmoPackMax[%item];
		if(%delta == $ItemMax[Player::getArmor(%client), %item]) 
			%delta = %delta + %extraAmmo;
	}
	if($TestCheats == 0 && %client.spawn == "") {
		%energy = $TeamEnergy[%team];
    	%station = %player.Station;
		%sName = GameBase::getDataName(%station);
		if(%sName == DeployableInvStation || %sName == DeployableAmmoStation)
		{
			%energy = %station.Energy;
		}
		if(%energy != "Infinite") 
		{
			if (%item.price * %delta > %energy)	
				%delta = %energy / %item.price;

			if(%delta < 1 ) 
			{
				if(%noMessage == "")
					Client::sendMessage(%client,0,"Couldn't buy " @ %item.description @ " - "@ %energy @ " Energy points left");
				return 0;
			}
		}
	}  			
	if(%item == RepairPatch) {
		%pDamage = GameBase::getDamageLevel(%player);
		if(GameBase::getDamageLevel(%player) > 0) 
			return 1;
		return 0;
	
	}
	else if($TeamItemMax[%item] != "" && !$TestCheats) 
	{
			if($TeamItemMax[%item] <= $TeamItemCount[%team, %item]) {
			Client::sendMessage(%client,0,"Item limit reached for " @ %item.description @ "s");
			return 0;
		}
	}
	else if(%item.className == Weapon) {
		%armor = Player::getArmor(%client);
		%wcount = Player::getItemClassCount(%client,"Weapon");
		if (Player::getItemClassCount(%client,"Weapon") >= $MaxWeapons[%armor]) {
			Client::sendMessage(%client,0,"Too many weapons for " @ $ArmorName[%armor].description @ " to carry");
			return 0;
		}

   }
	if(%item.className != Armor && %item.className != Vehicle) {
	   %count = Player::getItemCount(%client,%item);
	  	%max = $ItemMax[(Player::getArmor(%client)), %item] + %extraAmmo ;
	   if(%delta + %count >= %max) 
			%delta = %max - %count;
	}
	return %delta;
}

function buyItem(%client,%item)
{
	%player = Client::getOwnedObject(%client);
	%armor = Player::getArmor(%client);
	//%numCurrentItems = Player::getItemCount(%client, %item);
	//%canBuy = (%numCurrentItems < $ItemMax[%armor, %item]);
	//echo("SPAWNBUY:  item = " @ %item @ "  currentnum = " @ %numCurrentItems);
	if (($ServerCheats || Client::isItemShoppingOn(%client,%item) || $TestCheats || %client.spawn) && 
		($ItemMax[%armor, %item] || %item.className == Armor || %item.className == Vehicle || $TestCheats)) {
		if (%item.className == Armor) {
			// Assign armor by requested type & gender 
			%buyarmor = $ArmorType[Client::getGender(%client), %item];
			if(%armor != %buyarmor || Player::getItemCount(%client,%item) == 0)	{
				teamEnergyBuySell(%player,$ArmorName[%armor].price);
				if(checkResources(%player,%item,1)) {
					teamEnergyBuySell(%player,$ArmorName[%buyarmor].price * -1);
					Player::setArmor(%client,%buyarmor);
					checkMax(%client,%buyarmor);
					armorChange(%client);
     				Player::setItemCount(%client, $ArmorName[%armor], 0);  
     				Player::setItemCount(%client, %item, 1);  
					if (Player::getMountedItem(%client,$BackpackSlot) == ammopack) 
						fillAmmoPack(%client);	
					if ($TeamItemMax[%item] != "")
						$TeamItemCount[GameBase::getTeam(%client),%item]++; 
					return 1;
				}

				teamEnergyBuySell(%player,$ArmorName[%armor].price * -1);
			}
		}
		else if (%item.className == Backpack) {
			if($TeamItemMax[%item] != "") {						
				if($TeamItemCount[GameBase::getTeam(%client) @ %item] >= $TeamItemMax[%item])
			 	  return 0;
			 }

			// Only one backpack per armor.
			%pack = Player::getMountedItem(%client,$BackpackSlot);
			if (%pack != -1) {
				if(%pack == ammopack) 
					checkMax(%client,%armor);
				else if(%pack == EnergyPack) {
					if(Player::getItemCount(%client,"LaserRifle") > 0) {
						Client::sendMessage(%client,0,"Sold energy pack - auto selling laser rifle");
						remoteSellItem(%client,22);						
					}
				}	
				teamEnergyBuySell(%player,%pack.price);
				Player::decItemCount(%client,%pack);
			}			   
			if (checkResources(%player,%item,1) || $testCheats) {
				teamEnergyBuySell(%player,%item.price * -1);
				Player::incItemCount(%client,%item);
				Player::useItem(%client,%item);									 
				if(%item == ammopack) 
					fillAmmoPack(%client);
				if ($TeamItemMax[%item] != "")
						$TeamItemCount[GameBase::getTeam(%client), %item]++; 
				return 1;
			}
			else if(%pack != -1) {
				teamEnergyBuySell(%player,%pack.price * -1);
				Player::incItemCount(%client,%pack);
				Player::useItem(%client,%pack);									 
				if(%pack == ammopack) 
					fillAmmoPack(%client);
			}				 
		}
		else if(%item.className == Weapon) 
		{
			if(checkResources(%player,%item,1)) 
			{
				if(%item == LaserRifle && Player::getItemCount(%client,"EnergyPack") == 0) 
				{
					buyItem(%client,"EnergyPack");
					Client::sendMessage(%client,0,"Bought laser rifle - auto buying energy pack");
				}
				Player::incItemCount(%client,%item);
				teamEnergyBuySell(%player,(%item.price * -1));
				%ammoItem =  %item.imageType.ammoType; 
				if(%ammoItem != "") 
				{
					%delta = checkResources(%player,%ammoItem,$ItemMax[%armor, %ammoItem]);
					if(%delta || $testCheats) 
					{
						teamEnergyBuySell(%player,(%ammoItem.price * -1 * %delta));
						Player::incItemCount(%client,%ammoitem,%delta);
					}
				}
				if ($TeamItemMax[%item] != "")
					$TeamItemCount[GameBase::getTeam(%client),%item]++; 
				return 1;
			}
		}
	 	else if(%item.className == Vehicle) {
		   if($TeamItemCount[GameBase::getTeam(%client) @ %item] < $TeamItemMax[%item]) {
				%shouldBuy = VehicleStation::checkBuying(%client,%item);
				if(%shouldBuy == 1) {
					teamEnergyBuySell(%player,(%item.price * -1));
					return 1;
				}			
 				else if(%shouldBuy == 2)
					return 1;
			}
		}
		else {
			if($TeamItemMax[%item] != "") {						
				if($TeamItemCount[GameBase::getTeam(%client) @ %item] >= $TeamItemMax[%item])
			 	  return 0;
			 }
		    %delta = checkResources(%player,%item,$ItemMax[%armor, %item]);
			 if(%delta || $testCheats) {
				// Annoying...can't seem to limit the number of hand grenades
				// So manually get rid of 'em  ;(
				if (%item == Grenade)
					%delta = $ItemMax[larmor, Grenade];
				teamEnergyBuySell(%player,(%item.price * -1 * %delta));
				Player::incItemCount(%client,%item,%delta);
				return 1;
			}
		}
		
 	}


	return 0;
}

function remoteSellItem(%client,%type)
{
	if (isPlayerBusy(%client))
		return;

	%item = getItemData(%type);
	%player = Client::getOwnedObject(%client);
	if ($ServerCheats || Client::isItemShoppingOn(%client,%item) || $TestCheats) 
	{
		if(Player::getItemCount(%client,%item) && %item.className != Armor) 
		{
			%numsell = 1;
			if(%item.className == Ammo || %item.className == HandAmmo) 
			{
				%count = Player::getItemCount(%client, %item);
				if(%count < $SellAmmo[%item]) 
					%numsell = %count; 
				else 
					%numsell = $SellAmmo[%item];
			}
			else if (%item == ammopack) 
				checkMax(%client,Player::getArmor(%client));
			else if($TeamItemMax[%item] != "") 
			{
				if(%item.className == Vehicle) 
					$TeamItemCount[(Client::getTeam(%client)) @ %item]--;
				else
					$TeamItemCount[(Client::getTeam(%client)),%item]--;
			}
			if(%item == EnergyPack) 
			{ 
				if(Player::getItemCount(%client,"LaserRifle") > 0) 
				{
					Client::sendMessage(%client,0,"Sold energy pack - auto selling laser rifle");
					remoteSellItem(%client,22);						
				}
			}
			teamEnergyBuySell(%player,%item.price * %numsell);
			Player::setItemCount(%player,%item,(%count-%numsell));
			updateBuyingList(%client);
			Client::SendMessage(%client,0,"~wbuysellsound.wav");
			return 1;
		}
	}
	Client::sendMessage(%client,0,"Cannot sell item ~wC_BuySell.wav");
}

// Don't allow players to pickup laser rifles
function Item::onCollision(%this,%object)
{
	if (getObjectType(%object) == "Player") {
		%item = Item::getItemData(%this);
		if (%item == LaserRifle)
			return 0;
		%count = Player::getItemCount(%object,%item);
		if (Item::giveItem(%object,%item,Item::getCount(%this))) {
			Item::playPickupSound(%this);
			Item::respawn(%this);
		}
	}
}

function Game::playerSpawn(%clientId, %respawn)
{
   if(!$ghosting)
      return false;

	Client::clearItemShopping(%clientId);
   %spawnMarker = Game::pickPlayerSpawn(%clientId, %respawn);
   if(!%respawn)
   {
      // initial drop
      bottomprint(%clientId, "<jc><f0>Mission: <f1>" @ $missionName @ "   <f0>Mission Type: <f1>" @ $Game::missionType @ "\n<f0>Press <f1>'O'<f0> for specific objectives.", 5);
   }
	if(%spawnMarker) {   
		%clientId.guiLock = "";
	 	%clientId.dead = "";
	   if(%spawnMarker == -1)
	   {
	      %spawnPos = "0 0 300";
	      %spawnRot = "0 0 0";
	   }
	   else
	   {
	      %spawnPos = GameBase::getPosition(%spawnMarker);
	      %spawnRot = GameBase::getRotation(%spawnMarker);
	   }

		if(!String::ICompare(Client::getGender(%clientId), "Male"))
	      %armor = "larmor";
	   else
	      %armor = "lfemale";

	   %pl = spawnPlayer(%armor, %spawnPos, %spawnRot);
	   echo("SPAWN: cl:" @ %clientId @ " pl:" @ %pl @ " marker:" @ %spawnMarker @ " armor:" @ %armor);
	   if(%pl != -1)
	   {
	      GameBase::setTeam(%pl, Client::getTeam(%clientId));
	      Client::setOwnedObject(%clientId, %pl);
	      Game::playerSpawned(%pl, %clientId, %armor, %respawn);
	      
	      if($matchStarted)
	         Client::setControlObject(%clientId, %pl);
	      else
	      {
	         %clientId.observerMode = "pregame";
	         Client::setControlObject(%clientId, Client::getObserverCamera(%clientId));
	         Observer::setOrbitObject(%clientId, %pl, 3, 3, 3);
	      }
	   }
      return true;
	}
	else {
		Client::sendMessage(%clientId,0,"Sorry No Respawn Positions Are Empty - Try again later ");
      return false;
	}
}

function TRabbit::restoreServerDefaults() {
   // Reset team names
   for (%i = 0; %i <= 7; %i++) {
	$Server::teamName[%i] = $TRabbit::origTeamName[%i];
	$Server::teamSkin[%i] = $TRabbit::origTeamSkin[%i];
        $TRabbit::origTeamSkin[%i] = "";
	$TRabbit::origTeamName[%i] = "";
   }

   $Server::JoinMOTD = $TRabbit::origJoinMOTD;
   $TRabbit::origJoinMOTD = "";

   $TeamItemCount[0,HeavyArmor] = "";
   $TeamItemCount[1,HeavyArmor] = "";
   $TeamItemCount[0,LaserRifle] = "";
   $TeamItemCount[1,LaserRifle] = "";
   $TeamItemMax[HeavyArmor] = "";
   $TeamItemMax[LaserRifle] = "";
}

// This was modified to reload any scripts we've changed in case the
// next map is non-TRabbit
function Server::loadMission(%missionName, %immed)
{
   if($loadingMission)
      return;

   %missionFile = "missions\\" $+ %missionName $+ ".mis";
   if(File::FindFirst(%missionFile) == "")
   {
      %missionName = $firstMission;
      %missionFile = "missions\\" $+ %missionName $+ ".mis";
      if(File::FindFirst(%missionFile) == "")
      {
         echo("invalid nextMission and firstMission...");
         echo("aborting mission load.");
         return;
      }
   }
   echo("Notfifying players of mission change: ", getNumClients(), " in game");
   for(%cl = Client::getFirst(); %cl != -1; %cl = Client::getNext(%cl))
   {
      Client::setGuiMode(%cl, $GuiModeVictory);
      %cl.guiLock = true;
      %cl.nospawn = true;
      remoteEval(%cl, missionChangeNotify, %missionName);
   }

   exec(ArmorData);
   exec(StaticShape);
   exec(Station);
   exec(Item);
   exec(Beacon);
   exec(Player);
   exec(baseProjData);
   exec(observer);
   exec(comchat);
   exec(game);
   exec(inventory);

   $loadingMission = true;
   $missionName = %missionName;
   $missionFile = %missionFile;
   $prevNumTeams = getNumTeams();

   deleteObject("MissionGroup");
   deleteObject("MissionCleanup");
   deleteObject("ConsoleScheduler");
   resetPlayerManager();
   resetGhostManagers();
   $matchStarted = false;
   $countdownStarted = false;
   $ghosting = false;

   resetSimTime(); // deal with time imprecision

   newObject(ConsoleScheduler, SimConsoleScheduler);
   if(!%immed)
      schedule("Server::finishMissionLoad();", 18);
   else
      Server::finishMissionLoad();      
}

function onExit()
{
   if ($Game::missionType == "TRabbit") {
      TRabbit::restoreServerDefaults();
      // Reset team names
      for (%i = 0; %i <= 7; %i++) {
        $TRabbit::origTeamSkin[%i] = "";
	$TRabbit::origTeamName[%i] = "";
      }
      $TRabbit::origJoinMOTD = "";
   }
        
   if(isObject(playGui))
      storeObject(playGui, "config\\play.gui");

   saveActionMap("config\\config.cs", "actionMap.sae", "playMap.sae", "pdaMap.sae");

	//update the video mode - since it can be changed with alt-enter
	$pref::VideoFullScreen = isFullScreenMode(MainWindow);

   checkMasterTranslation();
	echo("exporting pref::* to prefs.cs");
   export("pref::*", "config\\ClientPrefs.cs", False);
   export("Server::*", "config\\ServerPrefs.cs", False);
   export("pref::lastMission", "config\\ServerPrefs.cs", True);
   BanList::export("config\\banlist.cs");
}

///////////////////////////////////////////////////////////////////////////////////////////////
// Observer functions
///////////////////////////////////////////////////////////////////////////////////
$TRabbit::ObserverZoom = "";
$TRabbit::ObserverRotation = "";
$TRabbit::ObserverZoomDir = "";
$TRabbit::ObserverZoomFlag = "";
$TRabbit::ObserverFirstPerson = "";

// Crowd cheering stuff (not yet implemented)
SoundProfileData Profile3dNear
{
   baseVolume = 0;
   minDistance = 5.0;
   maxDistance = 40.0;
   flags = SFX_IS_HARDWARE_3D;
};

SoundData SoundTest
{
   wavFileName = "male2.wcheer2.wav";
   profile = Profile3dNear;
};

function remoteSay(%clientId, %team, %message)
{
   echo("**SAYCHECK: " @ %message);
   %msg = %clientId @ " \"" @ escapeString(%message) @ "\"";

   // check for flooding if it's a broadcast OR if it's team in FFA
   if($Server::FloodProtectionEnabled && (!$Server::TourneyMode || !%team))
   {
      // we use getIntTime here because getSimTime gets reset.
      // time is measured in 32 ms chunks... so approx 32 to the sec
      %time = getIntegerTime(true) >> 5;
      if(%clientId.floodMute)
      {
         %delta = %clientId.muteDoneTime - %time;
         if(%delta > 0)
         {
            Client::sendMessage(%clientId, $MSGTypeGame, "FLOOD! You cannot talk for " @ %delta @ " seconds.");
            return;
         }
         %clientId.floodMute = "";
         %clientId.muteDoneTime = "";
      }
      %clientId.floodMessageCount++;
      // funky use of schedule here:
      schedule(%clientId @ ".floodMessageCount--;", 5, %clientId);
      if(%clientId.floodMessageCount > 4)
      {
         %clientId.floodMute = true;
         %clientId.muteDoneTime = %time + 10;
         Client::sendMessage(%clientId, $MSGTypeGame, "FLOOD! You cannot talk for 10 seconds.");
         return;
      }
   }

   if(%team)
   {
      if($dedicated)
         echo("SAYTEAM: " @ %msg);
      %team = Client::getTeam(%clientId);
      for(%cl = Client::getFirst(); %cl != -1; %cl = Client::getNext(%cl))
         if(Client::getTeam(%cl) == %team && !%cl.muted[%clientId])
            Client::sendMessage(%cl, $MsgTypeTeamChat, %message, %clientId);
   }
   else
   {
      if($dedicated)
         echo("SAY: " @ %msg);
      %team = Client::getTeam(%clientId);
      for(%cl = Client::getFirst(); %cl != -1; %cl = Client::getNext(%cl))
         if(!%cl.muted[%clientId]) {
		if ((%team < 0) && (Client::getTeam(%cl) != %team)) {
			// Intercept observer chat here
   			// Chop off the extended tags.
   			%idx = String::FindSubStr(%message, "~");
   			if (%idx != -1) {
				%sound = String::GetSubStr(%message, %idx, 10000);
				%short = String::GetSubStr(%msg, 0, %idx-1);
				echo("**SAYCHECK2: " @ %sound);
				%fullSound = "~wmale5." @ %sound;
				//Client::sendMessage(%cl, $MsgTypeGame, %sound); //, %clientId);
				%obsCam = Client::getObserverCamera(%clientId);
				%pos = GameBase::getPosition(%obsCam);
				//playSound(SoundTest,%pos);

			}
		}
		else
	        	Client::sendMessage(%cl, -1, %message, %clientId);
	}
   }
}

function Observer::enterObserverMode(%clientId)
{
   echo("NOW OBSERVING");
   if((%clientId.observerMode == "observerOrbit") || (%clientId.observerMode == "observerFly"))
      return false;
 
      %clientId.observerMode = "observerOrbit";



   Client::clearItemShopping(%clientId);
   %player = Client::getOwnedObject(%clientId);
   if(%player != -1 && getObjectType(%player) == "Player" && !Player::isDead(%player)) {
		playNextAnim(%clientId);
	   Player::kill(%clientId);
	}

   %clientId.observerMode = "observerOrbit";
   //Observer::setTargetObject(%clientId, $TRabbit::theFlag);
   if ($TRabbit::ObserverTarget > 8000)
        Observer::setTargetObject(%clientId, $TRabbit::ObserverTarget);
   else
        Observer::setTargetClient(%clientId, $TRabbit::ObserverTarget);

   GameBase::setTeam(%clientId, -1);
   remotePlayMode(%clientId);
   centerprint(%clientId, "<jc><f2>You are now following the action.\n" @ 
		"<f0>Press fire to switch perspectives.", 3);
   return true;
}


function processMenuPickTeam(%clientId, %team, %adminClient)
{
	checkPlayerCash(%clientId);
   if(%team != -1 && %team == Client::getTeam(%clientId))
      return;

   if(%clientId.observerMode == "justJoined")
   {
      %clientId.observerMode = "";
      centerprint(%clientId, "");
   }

   if((!$matchStarted || !$Server::TourneyMode || %adminClient) && %team == -2)
   {
      if(Observer::enterObserverMode(%clientId))
      {
         %clientId.notready = "";
         if(%adminClient == "") 
            messageAll(0, Client::getName(%clientId) @ " became an observer.");
         else
            messageAll(0, Client::getName(%clientId) @ " was forced into observer mode by " @ Client::getName(%adminClient) @ ".");
			Game::resetScores(%clientId);	
		   Game::refreshClientScore(%clientId);
		}
      return;
   }

   %player = Client::getOwnedObject(%clientId);
   if(%player != -1 && getObjectType(%player) == "Player" && !Player::isDead(%player)) {
		playNextAnim(%clientId);
	   Player::kill(%clientId);
	}
   %clientId.observerMode = "";
   if(%adminClient == "")
      messageAll(0, Client::getName(%clientId) @ " changed teams.");
   else
      messageAll(0, Client::getName(%clientId) @ " was teamchanged by " @ Client::getName(%adminClient) @ ".");

   if(%team == -1)
   {
      Game::assignClientTeam(%clientId);
      %team = Client::getTeam(%clientId);
   }
   GameBase::setTeam(%clientId, %team);
   %clientId.teamEnergy = 0;
	Client::clearItemShopping(%clientId);
	if(Client::getGuiMode(%clientId) != 1)
		Client::setGuiMode(%clientId,1);		
	Client::setControlObject(%clientId, -1);

   Game::playerSpawn(%clientId, false);
	%team = Client::getTeam(%clientId);
	if($TeamEnergy[%team] != "Infinite")
		$TeamEnergy[%team] += $InitialPlayerEnergy;
   if($Server::TourneyMode && !$CountdownStarted)
   {
      bottomprint(%clientId, "<f1><jc>Press FIRE when ready.", 0);
      %clientId.notready = true;
   }
}

function TRabbit::delayedSpawn(%clientId) {
	%clientId.observerMode = "";
        Game::playerSpawn(%clientId, false);
}

function Observer::triggerUp(%client)
{
   if (%client.observerMode == "waitingForRules")
	return;

   if(%client.observerMode == "dead")
   {
      if(%client.dieTime + $Server::respawnTime < getSimTime())
      {
         if(Game::playerSpawn(%client, true))
         {
            %client.observerMode = "";
            Observer::checkObserved(%client);
         }
      }
   }
   else if(%client.observerMode == "observerOrbit"){
      //Observer::nextObservable(%client);
   //$TRabbit::ObserverZoomFlag[%client] = false;
	$TRabbit::ObserverFirstPerson[%client] = !$TRabbit::ObserverFirstPerson[%client];
      if ($TRabbit::ObserverTarget > 8000)
           Observer::setTargetObject(%client, $TRabbit::ObserverTarget);
      else
           Observer::setTargetClient(%client, $TRabbit::ObserverTarget);
   }
   else if(%client.observerMode == "observerFly")
   {
      %camSpawn = Game::pickObserverSpawn(%client);
      Observer::setFlyMode(%client, GameBase::getPosition(%camSpawn), 
	      GameBase::getRotation(%camSpawn), true, true);
   }
   // Added "displayRules"
   else if(%client.observerMode == "displayRules")
   {
	%client.observerMode = "waitingForRules";
	centerprint(%client, $TRabbit::Rules, $TRabbit::rulesDelay);
	schedule("TRabbit::delayedSpawn(" @ %client @ ");", $TRabbit::rulesDelay);
	
   }
   else if(%client.observerMode == "justJoined")
   {
      %client.observerMode = "";
      Game::playerSpawn(%client, false);
   }
   else if(%client.observerMode == "pregame" && $Server::TourneyMode)
   {
      if($CountdownStarted)
         return;

      if(%client.notready)
      {
         %client.notready = "";
         MessageAll(0, Client::getName(%client) @ " is READY.");
         if(%client.notreadyCount < 3)
            bottomprint(%client, "<f1><jc>Waiting for match start (FIRE if not ready).", 0);
         else 
            bottomprint(%client, "<f1><jc>Waiting for match start.", 0);
      }
      else
      {
         %client.notreadyCount++;
         if(%client.notreadyCount < 4)
         {
            %client.notready = true;
            MessageAll(0, Client::getName(%client) @ " is NOT READY.");
            bottomprint(%client, "<f1><jc>Press FIRE when ready.", 0);
         }
         return;
      }
      Game::CheckTourneyMatchStart();
   }
}


function Observer::triggerDown(%client)
{

	//$TRabbit::ObserverZoomFlag[%client] = true;
        //Observer::doZoom(%client);

	//echo("SET ZOOM TO " @ $TRabbit::ObserverZoom[%client]);

	
	//%obsCam = Client::getObserverCamera(%client);
	//%obsPos = GameBase::getPosition(%obsCam);
	//%obsRot = GameBase::getRotation(%obsCam);
	//echo("OBSPOS = " @ %obsPos);
	//echo("OBSROT = " @ %obsRot);
	//GameBase::setPosition(%obsCam, "0 0 0");
}

function Observer::setTargetClient(%client, %target)
{
   if(%client.observerMode != "observerOrbit")
      return false;

   %owned = Client::getOwnedObject(%target);
   if(%owned == -1)
      return false;

   if ($TRabbit::ObserverZoom[%client] == "")
	$TRabbit::ObserverZoom[%client] = 14;

   //%obsCam = Client::getObserverCamera(%client);
   //%obsRotRad = GameBase::getRotation(%obsCam);
   //%obsRot = Vector::getFromRot(%obsRotRad);
   //echo("OBSROT = " @ %obsRot);
   //%obsx = getWord(%obsRot, 0);
   //%obsy = getWord(%obsRot, 1);
   //%obsz = getWord(%obsRot, 2);
   %zoom = 15;  //$TRabbit::ObserverZoom[%client];

   if ($TRabbit::ObserverFirstPerson[%client]) {
	%zoomx = -3;
	%zoomy = -1;
	%zoomz = -0;
   }
   else {
        %zoomx = %zoom;
	%zoomy = %zoom;
   	%zoomz = %zoom;
   }

   //%newobsx = %zoom;
   //%newobsy = %zoom;
   //%newobsz = %zoom;
   //echo("NEWOBSROT = " @ %newobsx @ " " @ %newobsy @ " " @ %newobsz);


   //echo("SETTING zoom = " @  %zoom);
   Observer::setOrbitObject(%client, %target, %zoomx, %zoomy, %zoomz);
   bottomprint(%client, "<jc>Observing " @ Client::getName(%target), 5);
   %client.observerTarget = %target;
   return true;
}


function Observer::setTargetObject(%client, %target)
{
   %owned = %target;
   if(%owned == -1)
      return false;
   //echo("ZOOM AT SET = " @ $TRabbit::ObserverZoom[%client]);
   //if ($TRabbit::ObserverZoom[%client] == "")
//	$TRabbit::ObserverZoom[%client] = 14;

   //%obsCam = Client::getObserverCamera(%client);
   //%obsRotRad = GameBase::getRotation(%obsCam);
   //echo("OBSROTRAD = " @ %obsRotRad);
   //%obsRot = Vector::getFromRot(%obsRotRad);
   //echo("OBSROT = " @ %obsRot);
   //%obsx = getWord(%obsRotRad, 0);
   //%obsy = getWord(%obsRotRad, 1);
   //%obsz = getWord(%obsRotRad, 2);

   //%newobsx = 10;//%zoom * 2;//%obsx;
   //%newobsy = 10;//%zoom;
   //%newobsz = -10;//%zoom;// * 3;// * %obsz;
   //echo("NEWOBSROT = " @ %newobsx @ " " @ %newobsy @ " " @ %newobsz);

   // When switching to the flag in 1st-person, zoom out instead
   %zoom = 15;  

   //echo("SETTING zoom = " @  %zoom);
   Observer::setOrbitObject(%client, %target, %zoom, %zoom, %zoom);
   //GameBase::setRotation(%obsCam, %obsRotRad);
   //%newRot = GameBase::getRotation(%obsCam);
   //echo("ROT of " @ %obsCam @ " SET TO " @ %newRot);

   //bottomprint(%client, "<jc>KineticFlagCam(tm)", 3);
   %client.observerTarget = %target;
   return true;
}

function Observer::jump(%client)
{
   if(%client.observerMode == "observerFly")
   {
      %client.observerMode = "observerOrbit";
      %client.observerTarget = %client;
      Observer::nextObservable(%client);
   }
   else if(%client.observerMode == "observerOrbit")
   {
	//%zoomdir = $TRabbit::ObserverZoomDir[%client];
      //if ((%zoomdir == "in") || (%zoomdir == ""))
	//	$TRabbit::ObserverZoomDir[%client] = "out";
	//else
	//	$TRabbit::ObserverZoomDir[%client] = "in";

      //bottomprint(%client, "<jc><f0>Press fire to zoom <f2>" @ $TRabbit::ObserverZoomDir[%client], 1);

      //%client.observerTarget = "";
      //%client.observerMode = "observerFly";

      //%camSpawn = Game::pickObserverSpawn(%client);
      //Observer::setFlyMode(%client, GameBase::getPosition(%camSpawn), 
	//      GameBase::getRotation(%camSpawn), true, true);
   }
}




  
echo("******* TRabbit.cs loaded successfully ********");