
$SB::WODec = 0.004; // whiteout 
$SB::DFDec = 0.02; // damageFlash

if ($Host::DefaultTimeLimit $= "" || $Host::DefaultTimeLimit < 5)
   $Host::DefaultTimeLimit = $Host::TimeLimit;

function VerifyCDCheck(%func)
{
   call(%func);
}

function CreateServer(%mission, %missionType)
{
   DestroyServer();

   // Load all the server defaults in the event something is missing
   $PrefSuccess = compile("prefs/serverprefs.cs");
   exec("prefs/serverprefs.cs");
   if ($PrefSuccess == false)
      logEcho("Failed to compile ServerPrefs.cs, unable to load latest copy using backup.");
   else
      export("$Host::*", "prefs/ServerPrefs.bak", false);

   $HavocSuccess = compile("prefs/havoc.cs");
   exec("prefs/havoc.cs");
   if  ($HavocSuccess == false)
      logEcho("Failed to compile Havoc.cs, unable to load latest copy using backup.");
   else
      export("$Havoc::*", "prefs/Havoc.bak", false);

   exec("scripts/havocdefaults.cs");
   exec("prefs/banlist.cs");

   // Load server data blocks
   exec("scripts/commanderMapIcons.cs");
   exec("scripts/markers.cs"); 
   exec("scripts/serverAudio.cs");
   exec("scripts/damageTypes.cs");
   exec("scripts/deathMessages.cs");
   exec("scripts/inventory.cs");
   exec("scripts/camera.cs");
   exec("scripts/particleEmitter.cs");    // Must exist before item.cs and explosion.cs
   exec("scripts/particleDummies.cs");
   exec("scripts/projectiles.cs");        // Must exits before item.cs
   exec("scripts/player.cs");
   exec("scripts/gameBase.cs");
   exec("scripts/staticShape.cs");
   exec("scripts/emp.cs");
   exec("scripts/burn.cs");
   exec("scripts/weaponhelp.cs");
   exec("scripts/effects.cs");
   exec("scripts/weapons.cs");
   exec("scripts/turret.cs");
   exec("scripts/pack.cs");
   exec("scripts/extras/jetpack.cs");
   exec("scripts/weapTurretCode.cs");
   exec("scripts/vehicles/vehicle_spec_fx.cs");
   exec("scripts/vehicles/serverVehicleHud.cs");
   exec("scripts/vehicles/vehicle_bomber.cs");
   exec("scripts/vehicles/vehicle_shrike.cs");
   exec("scripts/vehicles/vehicle_havoc.cs");
   exec("scripts/vehicles/vehicle_wildcat.cs");
   exec("scripts/vehicles/vehicle_tank.cs");
   exec("scripts/vehicles/vehicle_mpb.cs");
   exec("scripts/vehicles/vehicle.cs");
   exec("Scripts/turrets/DepthChargeBarrelLarge.cs");
   exec("scripts/packs/TAG.cs");
   exec("scripts/ai.cs");
   exec("scripts/item.cs");
   exec("scripts/station.cs");
   exec("scripts/simGroup.cs");
   exec("scripts/trigger.cs");
   exec("scripts/forceField.cs");
   exec("scripts/lightning.cs");
   exec("scripts/weather.cs");
   exec("scripts/deployables.cs");
   exec("scripts/packs/MissilePack.cs");
   exec("scripts/items.cs");
   exec("scripts/specials.cs");
   exec("scripts/stationSetInv.cs");
   exec("scripts/navGraph.cs");
   exec("scripts/targetManager.cs");
   exec("scripts/serverCommanderMap.cs");
   exec("scripts/environmentals.cs");
   exec("scripts/power.cs");
   exec("scripts/serverTasks.cs");
   exec("scripts/Admin.cs");
   exec("scripts/WaterLevel.cs");
   exec("scripts/Artillery.cs");
   exec("scripts/InventoryHUD.cs");
   exec("scripts/item.cs");
   exec("scripts/itemreset.cs");

   //automatically load any mission type that follows naming convention typeGame.name.cs
   %search = "scripts/*Game.cs";    

   for(%file = findFirstFile(%search); %file !$= ""; %file = findNextFile(%search))
   {
      %type = fileBase(%file); // get the name of the script      
      exec("scripts/" @ %type @ ".cs");
   }
  
   $missionSequence = 0;
   $CurrentMissionType = %missionType;
   $HostGameBotCount = 0;
   $HostGamePlayerCount = 0;

   if ($HostGameType !$= "SinglePlayer")
      allowConnections(true);

   $ServerGroup = new SimGroup (ServerGroup);

   if (%mission $= "")
   {
      %mission = $HostMissionFile[$HostMission[0,0]];
      %missionType = $HostTypeName[0];
   }

   if ($HostGameType $= "Online" && $pref::Net::DisplayOnMaster !$= "Never")
      schedule(0,0,startHeartbeat);

   // setup the bots for this server
   if ($Host::BotsEnabled)
      initGameBots( %mission, %missionType ); 
      
   // load the mission...
   loadMission(%mission, %missionType, true);

}

function initGameBots( %mission, %mType )
{
   echo( "adding bots..." );
   
   AISystemEnabled( false );
   if ( $Host::BotCount > 0 && %mType !$= "SinglePlayer" )
   {
      // Make sure this mission is bot enabled:
      for ( %idx = 0; %idx < $HostMissionCount; %idx++ )
      {
         if ( $HostMissionFile[%idx] $= %mission )
            break;
      }

      if ( $BotEnabled[%idx] )
      {
         if ( $Host::BotCount > 16 )
            $HostGameBotCount = 16;
         else
            $HostGameBotCount = $Host::BotCount;

         if ( $Host::BotCount > $Host::MaxPlayers - 1 )
            $HostGameBotCount = $Host::MaxPlayers - 1;

         //set the objective reassessment timeslice var
         $AITimeSliceReassess = 0;
         aiConnectMultiple( $HostGameBotCount, $Host::MinBotDifficulty, $Host::MaxBotDifficulty, -1 );
      }
      else
      {   
         $HostGameBotCount = 0;
      }
   }
}

function findNextCycleMission()
{
   %numPlayers = ClientGroup.getCount();
   %tempMission = $CurrentMission;
   %failsafe = 0;
   while (1)
   {
      %nextMissionIndex = getNextMission(%tempMission, $CurrentMissionType);
      %nextPotentialMission = $HostMissionFile[%nextMissionIndex];

      //just cycle to the next if we've gone all the way around...
      if (%nextPotentialMission $= $CurrentMission || %failsafe >= 1000)
      {
         %nextMissionIndex = getNextMission($CurrentMission, $CurrentMissionType);
         return $HostMissionName[%nextMissionIndex];
      }

      //get the player count limits for this mission
      %limits = $Host::MapPlayerLimits[%nextPotentialMission, $CurrentMissionType];
      if (%limits $= "")
         return %nextPotentialMission;
      else
      {
         %minPlayers = getWord(%limits, 0);
         %maxPlayers = getWord(%limits, 1);

         if ((%minPlayers < 0 || %numPlayers >= %minPlayers) && (%maxPlayers < 0 || %numPlayers <= %maxPlayers))
            return %nextPotentialMission;
      }

      //since we didn't return the mission, we must not have an acceptable number of players - check the next
      %tempMission = %nextPotentialMission;
      %failsafe++;
   }
}

function CycleMissions()
{
   echo( "cycling mission. " @ ClientGroup.getCount() @ " clients in game." );
   %nextMission = findNextCycleMission();
   messageAll( 'MsgClient', 'Loading %1 (%2)...', %nextMission, $MissionTypeDisplayName );
   loadMission( %nextMission, $CurrentMissionType );
}

function DestroyServer()
{
   $missionRunning = false;
   allowConnections(false);
   stopHeartbeat();
   BeaconGroup.delete();
   MissionGroup.delete();
   MissionCleanup.delete();
   if(isObject(game))
   {
      game.deactivatePackages();
      game.delete();
   }
   if(isObject($ServerGroup))
      $ServerGroup.delete();

   // delete all the connections:
   while(ClientGroup.getCount())
   {
      %client = ClientGroup.getObject(0);
      if (%client.isAIControlled())
         %client.drop();
      else
         %client.delete();
   }

   // delete all the data blocks... 
   // this will cause problems if there are any connections
   deleteDataBlocks();
   
   // reset the target manager
   resetTargetManager();

   export( "$Host::*", "prefs/ServerPrefs.cs", false );
   purgeResources();
}

function Disconnect()
{
   if ( isObject( ServerConnection ) )
      ServerConnection.delete();

   DisconnectedCleanup();
   DestroyServer();
}

function DisconnectedCleanup()
{
   // clear the chat hud message vector
   HudMessageVector.clear();
   if ( isObject( PlayerListGroup ) )
      PlayerListGroup.delete();
   
   // terminate all playing sounds
   alxStopAll();
   
   // clean up voting
   voteHud.voting = false;
   mainVoteHud.setvisible(0);
   
   // clear all print messages
   clientCmdclearBottomPrint();
   clientCmdClearCenterPrint();

   // clear the inventory and weapons hud
   weaponsHud.clearAll();
   inventoryHud.clearAll();
   
   // back to the launch screen
   Canvas.setContent(LaunchGui);
   if ( isObject( MusicPlayer ) )
      MusicPlayer.stop();
   clearTextureHolds();
   purgeResources();

   // Restart the email check:
   if ( !EmailGui.checkingEmail && EmailGui.checkSchedule $= "" )
      CheckEmail( true );

   IRCClient::onLeaveGame();
}

function ban(%Client, %Admin)
{
   // You can't ban me, I'm the Gingerbread man...
   if (Is(%Client) == true)
      return;

   // Add to both lists
   BanList::add(%client.GUID, %client.getAddress(), $Host::BanTime);
   $BanList[%client.GUID] = %Client.Name;

   Export("$BanList*", "prefs/banlist.cs", false);

   messageAll('MsgAdminForce', '\c2The Admin has banned %1 from the server.', %Client.name);

   // Tell the Player they were banned   
   messageClient(%Client, 'onClientBanned', "");
   messageAllExcept(%client, -1, 'MsgClientDrop', "", %client.name, %client);
   
   // Kill and delete this client
   if (isObject(%Client.player))
      %Client.player.scriptKill(0);
   
   %Client.schedule(1000, "delete");
   logEcho(%Client.Name @ " banned from the server.");
}

// We pass the GUID as well, in case this guy leaves the server.
function kick(%Client, %Admin, %GUID)
{
   if(%Admin)
   {
      messageAll('MsgAdminForce', '\c2The Admin has kicked %1.', %client.name);
   } else {
      if (%Client.isAIControlled() == true && $Host::AllowBotKicks == false)
      {
         %Message = "Bots may not be kicked by a vote on this server.";
         messageAll('MsgAdminForce', %Message);
         return;
      }

      messageAll('MsgVotePassed', '\c2%1 was kicked by vote.', %client.name);
   }
   
   messageClient(%Client, 'onClientKicked', "");
   messageAllExcept(%Client, -1, 'MsgClientDrop', "", %Client.name, %Client);

   if (%Client.isAIControlled())
   {
      $HostGameBotCount--;
      %client.drop();
      return;
   }

   if (isObject(%Client.player))
      %Client.player.scriptKill(0);

   // If not me, then make it hard for them to come back
   if (IS(%Client) != true)
   {
      BanList::add(%GUID, "0", $Host::KickBanTime);
      $KickList[%GUID] = %Client.Name;
   }
   Game.kickGuid = "";

   %Client.schedule(1000, "delete");
   logEcho(%Client.Name @ " kicked from the server.");
}

function getValidVoicePitch(%voice, %voicePitch)
{
   if (%voicePitch < -1.0)
      %voicePitch = -1.0;
   else if (%voicePitch > 1.0)
      %voicePitch = 1.0;

   //Voice pitch range is from 0.5 to 2.0, however, we should tighten the range to
   //avoid players sounding like mickey mouse, etc...
   //see if we're pitching down - clamp the min pitch at 0.875
   if (%voicePitch < 0)
      return (1.0 + (0.125 * %voicePitch));

   //max voice pitch is 1.125
   else if (%voicePitch > 0)
      return 1.0 + (0.125 * %voicePitch);

   else
      return 1.0;
}

function GameConnection::onConnect(%Client, %Name, %RaceGender, %Skin, %Voice, %VoicePitch, %Arg1, %Arg2)
{
   // Get the client's unique id:
   %AuthInfo = %Client.getAuthInfo();
   %Client.GUID = getField(%AuthInfo, 3);

   if (IsBanned(%Client) == true)
      %Client.delete();

   if (IsKicked(%Client) == true)
      %Client.delete();

   %Client.setMissionCRC($missionCRC);
   sendLoadInfoToClient(%Client);
   schedule(12500, 0, sendHavocInfoToClient, %Client);

   %Client.AuthInfo = %AuthInfo;

   // if hosting this server, set this client to a Master Admin
   if(%client.getAddress() $= "Local")
   {   
      %client.isAdmin = true;
      %client.isSuperAdmin = true;
      %client.isMasterAdmin = true;
   } else {
      if (isOnMasterAdminList(%Client) == true)
      {
         %client.isAdmin = true;
         %client.isSuperAdmin = true;
         %client.isMasterAdmin = true;
      } else if (isOnSuperAdminList(%Client) == true)
      {
         %client.isAdmin = true;
         %client.isSuperAdmin = true;   
      }
      else if(isOnAdminList(%Client) == true)
      {
         %Client.isAdmin = true;
      }
   }

   // Sex/Race defaults
   switch$ ( %raceGender )
   {
      case "Human Male":
         %client.sex = "Male";
         %client.race = "Human";

      case "Human Female":
         %client.sex = "Female";
         %client.race = "Human";

      case "Bioderm":
         %client.sex = "Male";
         %client.race = "Bioderm";

      default:
         error("Invalid race/gender combo passed: " @ %raceGender);
         %client.sex = "Male";
         %client.race = "Human";
   }
   %client.armor = "Medium";

   // Override the connect name if this server does not allow smurfs,
   // except for me who should be able to play without being bothered.
   if (IS(%Client) == true)
   {
      %Client.IS = true;

      %RealName = getField(%AuthInfo, 0);

      if (%RealName $= "Dev_")
         %Name = "Dev";
      else
         %Name = %RealName;

      %client.name = addTaggedString(%Name);
      %client.isSmurf = false;
   }

   %RealName = getField(%AuthInfo, 0);
   if ($PlayingOnline && $Host::NoSmurfs == true && %Client.IS != true)
      %Name = %RealName;

   // Ask the Client if they have the havoc client, if it responds it will
   // be set as true.
   commandToClient(%Client, 'HasHavocClient', %Client);   

   if (getSubStr(%RealName, 0, 2) $= "Dev" && IS(%Client) != true)
      %RealName = "Dumbass";

   if (%Client.IS != true)
   {
      if (strcmp(%name, %realName) == 0)
      {
         %client.isSmurf = false;

         // Add the tribal tag:
         %tag = getField(%authInfo, 1);
         %append = getField(%authInfo, 2);
         if (%append)
            %name = "\cp\c6" @ %name @ "\c7" @ %tag @ "\co";
         else
            %name = "\cp\c7" @ %tag @ "\c6" @ %name @ "\co";

         %client.sendGuid = %client.guid;
      } else {
         %client.isSmurf = true;
         %client.sendGuid = 0;
         %name = stripTrailingSpaces(strToPlayerName(%name));
         if (strlen(%name) < 3)
            %name = "Poser";
      
         // Make sure the alias is unique:
         %isUnique = true;
         %count = ClientGroup.getCount();
         for ( %i = 0; %i < %count; %i++ )
         {
            %test = ClientGroup.getObject( %i );
            %rawName = stripChars( detag( getTaggedString( %test.name ) ), "\cp\co\c6\c7\c8\c9" );
            if ( strcmp( %name, %rawName ) == 0 )
            {
               %isUnique = false;
               break;
            }
         }

         // Append a number to make the alias unique:
         if ( !%isUnique )
         {
            %suffix = 1;
            while ( !%isUnique )
            {
               %nameTry = %name @ "." @ %suffix;
               %isUnique = true;

               %count = ClientGroup.getCount();
               for ( %i = 0; %i < %count; %i++ )
               {
                  %test = ClientGroup.getObject( %i );
                  %rawName = stripChars( detag( getTaggedString( %test.name ) ), "\cp\co\c6\c7\c8\c9" );
                  if ( strcmp( %nameTry, %rawName ) == 0 )
                  {
                     %isUnique = false;
                     break;
                  }
               }

               %suffix++;
            }

            // Success!
            %name = %nameTry;

            if (%Name !$= %RealName)
               $PlayerAlias[%Name] = %RealName;
         }

         $PlayerLog[%RealName] = %AuthInfo;      

         %smurfName = %name;
         // Tag the name with the "smurf" color:
         %name = "\cp\c8" @ %name @ "\co";
      }

      %client.name = addTaggedString(%name);
   }

   if (%client.isSmurf == true)
      %client.nameBase = %smurfName;
   else
      %client.nameBase = %realName;

   %client.justConnected = true;
   %client.isReady = false;
   %client.ShowHelp = true;
   %client.TKs = 0;

   // Make sure that the connecting client is not trying to use a bot skin:
   %temp = detag(%skin);
   if (%temp $= "basebot" || %temp $= "basebbot")
      %client.skin = addTaggedString("base");
   else
      %client.skin = addTaggedString(%skin);

   // full reset of client target manager
   clientResetTargets(%client, false);

   %client.voice = %voice;
   %client.voiceTag = addtaggedString(%voice);
   
   //set the voice pitch based on a lookup table from their chosen voice
   %client.voicePitch = getValidVoicePitch(%voice, %voicePitch);

   %client.target = allocClientTarget(%client, %client.name, %client.skin, %client.voiceTag, '_ClientConnection', 0, 0, %client.voicePitch);
   %client.score = 0;
   %client.team = 0;
   
   $instantGroup = ServerGroup;
   $instantGroup = MissionCleanup;

//   echo("CADD: " @ %client @ " " @ %client.getAddress());

   %count = ClientGroup.getCount();
   for(%cl = 0; %cl < %count; %cl++)
   {
      %recipient = ClientGroup.getObject(%cl);
      if((%recipient != %client))
      {
         // These should be "silent" versions of these messages...
         messageClient(%client, 'MsgClientJoin', "", 
               %recipient.name, 
               %recipient, 
               %recipient.target, 
               %recipient.isAIControlled(), 
               %recipient.isAdmin, 
               %recipient.isSuperAdmin, 
               %recipient.isSmurf, 
               %recipient.sendGuid);

         messageClient(%client, 'MsgClientJoinTeam', "", %recipient.name, $teamName[%recipient.team], %recipient, %recipient.team ); 
      }
   }

//   commandToClient(%client, 'getManagerID', %client);

   commandToClient(%client, 'setBeaconNames', "Target Beacon", "Marker Beacon", "Bomb Target");

   if ($CurrentMissionType !$= "SinglePlayer") 
   {
      messageClient(%client, 'MsgClientJoin', '\c2Welcome to Havoc for Tribes2 %1.', 
            %name, 
            %client, 
            %client.target, 
            false,   // isBot 
            %client.isAdmin, 
            %client.isSuperAdmin, 
            %client.isSmurf, 
            %client.sendGuid );

      messageAllExcept(%client, -1, 'MsgClientJoin', '\c1%1 joined the game.', 
            %name, 
            %client, 
            %client.target, 
            false,   // isBot 
            %client.isAdmin, 
            %client.isSuperAdmin, 
            %client.isSmurf,
            %client.sendGuid );
   } else {
      messageClient(%client, 'MsgClientJoin', "\c0Mission Insertion complete...", 
            %name, 
            %client, 
            %client.target, 
            false,   // isBot 
            false,   // isAdmin 
            false,   // isSuperAdmin 
            false,   // isSmurf
            %client.sendGuid);
   }

//   if ($Host::BotsEnabled == true && $Host::MaxBots > 0)
//   {
//      %ClientCount = clientGroup.getCount();
//
//      // if number of players exceeds limit and there is at least one
//      // bot in the game, then have the bot drop
//      if ((%ClientCount >= $Host::MaxBots) && ($HostGameBotCount > 0))
//      {
//         %Bot = GetBotToDrop();
//
//         $HostGameBotCount--;
//         %botCl.drop();
//      }   
//   } else {
//   }

$HostGamePlayerCount++;

   //Game.missionStart(%client);
   setDefaultInventory(%client);

   // Suggest a player get the havoc client.
   if (%Client.HavocClient != true)
      schedule(16500, 0, bottomPrint, %Client, "You don't have the Havoc Client, go to www.havoctribe.org to download it today!", 10, 1);
   else {
      if (%Client.ClientUpdateNotify == true)
      {
         %Message = "Your client has been updated to version " @ $HavocClientVersion;
         schedule(16500, 0, bottomPrint, %Client, %Message, 10, 1);
      }
   }

   if ($missionRunning == true)
      %client.startMission();

}

function GameConnection::onDrop(%client, %reason)
{
   if(isObject(Game))
      Game.onClientLeaveGame(%client);
   
   if ( $CurrentMissionType $= "SinglePlayer" ) 
      messageAllExcept(%client, -1, 'MsgClientDrop', "", %client.name, %client);
   else
      messageAllExcept(%client, -1, 'MsgClientDrop', '\c1%1 has left the game.', %client.name, %client);

   if ( isObject( %client.camera ) )
      %client.camera.delete();

   freeClientTarget(%client);
   removeTaggedString(%client.name);
   echo("CDROP: " @ %client @ " " @ %client.getAddress());

//   if ($Host::BotsEnabled == true && $Host::MaxBots > 0)
//   {
//      %numPlayers = ClientGroup.getCount();
//
//      // check numPlayers with limit
//      if (%numPlayers <= $MinPlayersWithNoBots)
//      {
//         // check if there are any non-bot players left
//         // otherwise on game end, there is an infinite loop
//         while (%i < %numPlayer)
//         {
//            %client = ClientGroup.getObject(%i);
//            if (%client.isAIcontrolled() == false)
//            {
//               aiConnectMultiple(1, $Host::MinBotDifficulty, $Host::MaxBotDifficulty, -1 );
//               $HostGameBotCount++;
//               break;      // and jump out of loop
//            }
//
//            %i++;
//         }
//      }
//   } else {
//   }

   $HostGamePlayerCount--;


   // reset the server if everyone has left the game
   if( $HostGamePlayerCount - $HostGameBotCount == 0 && $Host::Dedicated == true)
      schedule(0, 0, "resetServerDefaults");
}

function GetBotToDrop()
{
   %Team1Score = $TeamScore[1];
   %Team2Score = $TeamScore[2];
   if (%Team1Score > %Team2Score)
   {
      %LoosingTeam = 2;
   } else {
      if (%Team2Score > %Team1Score)
      {
         %LoosingTeam = 1;   
      } else { 
         // Randomly pick a team if equal
         %LoosingTeam = mFloor(getRandom() * 2) + 1;
      }
   }

   %AltBot = 0;
   %Bot = 0;
   %BotCount = 0;

   %Team1Count = 0;
   %Team2Count = 0;

   %i = 0;
   %ClientCount = clientGroup.getCount();
   while (%i < %ClientCount)
   {
      %Client = clientGroup.getObject(%i);
      if (%Client.isAIControlled() == true)
      {
         %BotCount++;

         // If we can, pick a bot on the team that is loosing.
         if (%Client.team == %LoosingTeam)
            %Bot = %Client;
         else
            %AltBot = %Client;
      }

      if (%Client.team == 1)      
         %Team1Count++;
      else
         %Team2Count++;

      %i++;
   }

   // If there isn't a bot on the chosen team, then drop from the team the only bots we have
   if (%Bot == 0 && %BotCount > 0)
   {
      return(%AltBot);
   } else {
      // If teams are mostly even, then go ahead and change out the loosing team's bot
      if (%Team1Count - %Team2Count >= -1 && %Team1Count - %Team2Count <= 1)
      {
         return(%Bot);
      } else {
         if (%Team1Count > %Team2Count)
         {
            if (%LoosingTeam == 1)
               return(%Bot);
            else
               return(%AltBot);
  
         } else {
            if (%LoosingTeam == 2)
               return(%Bot);
            else
               return(%AltBot);

         }
      }
   }
}

function dismountPlayers()
{
   // make sure all palyers are dismounted from vehicles and have normal huds
   %count = ClientGroup.getCount();
   for(%cl = 0; %cl < %count; %cl++)
   {
      %client = ClientGroup.getObject(%cl);
      %player = %client.player;
      if(%player.isMounted()) {
         %player.unmount();
         commandToClient(%client, 'setHudMode', 'Standard', "", 0);
      }
   }
}

function loadMission( %missionName, %missionType, %firstMission )
{
   if (!$pref::NoClearConsole)
      cls();
   buildLoadInfo( %missionName, %missionType );
   
   // reset all of these
   ClearCenterPrintAll();
   ClearBottomPrintAll();
   
   if($Host::TournamentMode == true)
      resetTournamentPlayers();
   
   // Send load info to all the connected clients:
   %count = ClientGroup.getCount();
   for ( %cl = 0; %cl < %count; %cl++ )
   {
      %client = ClientGroup.getObject( %cl );
      if ( !%client.isAIControlled() )
         sendLoadInfoToClient( %client );
   }

   // allow load condition to exit out
   schedule(0,ServerGroup,loadMissionStage1,%missionName,%missionType,%firstMission);
}
   
function loadMissionStage1(%missionName, %missionType, %firstMission)
{
   // if a mission group was there, delete prior mission stuff
   if(isObject(MissionGroup))
   {
      // clear out the previous mission paths
      for(%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
      {
         // clear ghosts and paths from all clients
         %cl = ClientGroup.getObject(%clientIndex);
         %cl.resetGhosting();
         %cl.clearPaths();
         %cl.isReady = "";
         %cl.matchStartReady = false;
      }
      Game.endMission();
      $lastMissionTeamCount = Game.numTeams;
      
      BeaconGroup.delete();
      MissionGroup.delete();
      MissionCleanup.delete();
      Game.deactivatePackages();
      Game.delete();
      $ServerGroup.delete();
      $ServerGroup = new SimGroup(ServerGroup);
   }
   
   $CurrentMission = %missionName;
   $CurrentMissionType = %missionType;
   
   createInvBanCount();
   echo("LOADING MISSION: " @ %missionName);
   
   // increment the mission sequence (used for ghost sequencing)
   $missionSequence++;
   
   // if this isn't the first mission, allow some time for the server
   // to transmit information to the clients:
  
// jff: $currentMission  already being used for this purpose, used in 'finishLoadMission'
   $MissionName = %missionName;
   $missionRunning = false;

   if(!%firstMission)
      schedule(15000, ServerGroup, loadMissionStage2);
   else
      loadMissionStage2();
}


function loadMissionStage2()
{
   // create the mission group off the ServerGroup
   echo("Stage 2 load");
   $instantGroup = ServerGroup;

   new SimGroup (MissionCleanup);
   
   if($CurrentMissionType $= "")
   {
      new ScriptObject(Game) {
         class = DefaultGame;
      };
   }
   else
   {
      new ScriptObject(Game) {
         class = $CurrentMissionType @ "Game";
         superClass = DefaultGame;
      };
   }
   // allow the game to activate any packages.
   Game.activatePackages();

   // reset the target manager
   resetTargetManager();

   %file = "missions/" @ $missionName @ ".mis";
   if(!isFile(%file))
      return;

   // send the mission file crc to the clients (used for mission lighting)
   $missionCRC = getFileCRC(%file);
   %count = ClientGroup.getCount();
   for(%i = 0; %i < %count; %i++)
   {
      %client = ClientGroup.getObject(%i);
      if(!%client.isAIControlled())
         %client.setMissionCRC($missionCRC);
   }

   $countDownStarted = false;
   exec(%file);
   $instantGroup = MissionCleanup;
   
   // pre-game mission stuff
   if(!isObject(MissionGroup))
   {
      error("No 'MissionGroup' found in mission \"" @ $missionName @ "\".");
      schedule(3000, ServerGroup, CycleMissions);
      return;
   }

   MissionGroup.cleanNonType($CurrentMissionType);
   
   // construct paths
   pathOnMissionLoadDone();
   
   $ReadyCount = 0;
   $MatchStarted = false;
   $CountdownStarted = false;
   AISystemEnabled( false );

   // Set the team damage here so that the game type can override it:
   if ( isDemo() )
      $TeamDamage = 0;
   else if ( $Host::TournamentMode )
      $TeamDamage = 1;
   else
      $TeamDamage = $Host::TeamDamageOn;

   //the demo version always has team damage off
   if (isDemo())
      $TeamDamage = 0;

   Game.missionLoadDone();
   
   // start all the clients in the mission
   $missionRunning = true;
   for(%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
      ClientGroup.getObject(%clientIndex).startMission();
      
   if(!$MatchStarted && $LaunchMode !$= "NavBuild" && $LaunchMode !$= "SpnBuild" )
   {
      if( !isDemo() && $Host::TournamentMode )
         checkTourneyMatchStart();
      else if( $currentMissionType !$= "SinglePlayer" )
         checkMissionStart();
   }
   
   // offline graph builder... 
   if( $LaunchMode $= "NavBuild" )
      buildNavigationGraph( "Nav" );
      
   if( $LaunchMode $= "SpnBuild" )
      buildNavigationGraph( "Spn" );
   purgeResources();
   disableCyclingConnections(false);
   $LoadingMission = false;
}
   
function ShapeBase::cleanNonType(%this, %type)
{
   if(%this.missionTypesList $= "")
      return;
      
   for(%i = 0; (%typei = getWord(%this.missionTypesList, %i)) !$= ""; %i++)
      if(%typei $= %type)
         return;
         
   // first 32 targets are team targets (never allocated/freed)
   // - must reallocate the target if unhiding
   if(%this.getTarget() >= 32)
   {
      freeTarget(%this.getTarget());
      %this.setTarget(-1);
   }

   %this.hide(true);
}

function SimObject::cleanNonType(%this, %type)
{
}

function SimGroup::cleanNonType(%this, %type)
{
   for (%i = 0; %i < %this.getCount(); %i++)
      %this.getObject(%i).cleanNonType(%type);
}

function GameConnection::endMission(%this)
{
   commandToClient(%this, 'MissionEnd', $missionSequence);
}

//--------------------------------------------------------------------------
// client start phases:
// 0: start mission
// 1: got phase1 done
// 2: got datablocks done
// 3: got phase2 done
// 4: got phase3 done
function GameConnection::startMission(%this)
{
   // send over the information that will display the server info
   // when we learn it got there, we'll send the data blocks
   %this.currentPhase = 0;
   commandToClient(%this, 'MissionStartPhase1', $missionSequence, $MissionName, MissionGroup.musicTrack);
}

function serverCmdMissionStartPhase1Done(%client, %seq)
{
   if(%seq != $missionSequence || !$MissionRunning)
      return;

   if(%client.currentPhase != 0)
      return;
   %client.currentPhase = 1;
      
   // when the datablocks are transmitted, we'll send the ghost always objects   
   %client.transmitDataBlocks($missionSequence);
}

function GameConnection::dataBlocksDone( %client, %missionSequence )
{
   echo("GOT DATA BLOCKS DONE FOR: " @ %client);
   if(%missionSequence != $missionSequence)
      return;

   if(%client.currentPhase != 1)
      return;
   %client.currentPhase = 2;

   // only want to set this once... (targets will not be updated/sent until a 
   // client has this flag set)
   if(!%client.getReceivedDataBlocks())
   {
      %client.setReceivedDataBlocks(true);
      sendTargetsToClient(%client);
   }

   commandToClient(%client, 'MissionStartPhase2', $missionSequence);
}

function serverCmdMissionStartPhase2Done(%client, %seq)
{
   if(%seq != $missionSequence || !$MissionRunning)
      return;

   if(%client.currentPhase != 2)
      return;
   %client.currentPhase = 3;

   // when all this good love is over, we'll know that the mission lighting is done
   %client.transmitPaths();
   
   // setup the client team state
   if ( $CurrentMissionType !$= "SinglePlayer" ) 
      serverSetClientTeamState( %client );
   
   // start ghosting
   %client.activateGhosting();
   %client.camera.scopeToClient(%client);
   
   // to the next phase...
   commandToClient(%client, 'MissionStartPhase3', $missionSequence, $CurrentMission);
}

function serverCmdMissionStartPhase3Done(%client, %seq)
{
   if(%seq != $missionSequence || !$MissionRunning)
      return;

   if(%client.currentPhase != 3)
      return;
   %client.currentPhase = 4;

   %client.isReady = true;
   Game.clientMissionDropReady(%client);
}

function serverSetClientTeamState( %client )
{
   // set all player states prior to mission drop ready
   
   // create a new camera for this client
   %client.camera = new Camera() 
   {
      dataBlock = Observer;
   };

   if( isObject( %client.rescheduleVote ) )
      Cancel( %client.rescheduleVote );
   %client.canVote = true;
   %client.rescheduleVote = "";
   
   MissionCleanup.add( %client.camera ); // we get automatic cleanup this way.
   
   %observer = false;
   if( !$Host::TournamentMode )
   {
      if( %client.justConnected )
      {
         %client.justConnected = false;
         %client.camera.getDataBlock().setMode( %client.camera, "justJoined" );
      }
      else
      {
         // server just changed maps - this guy was here before
         if( %client.lastTeam !$= "" )
         {   
            // see if this guy was an observer from last game
            if(%client.lastTeam == 0)
            {
               %observer = true;
               
               %client.camera.getDataBlock().setMode( %client.camera, "ObserverFly" );
            }
            else  // let this player join the team he was on last game
            {
               if(Game.numTeams > 1 && %client.lastTeam <= Game.numTeams )
               {   
                  Game.clientJoinTeam( %client, %client.lastTeam, false );
               }
               else
               {   
                  Game.assignClientTeam( %client );
                  
                  // spawn the player
                  Game.spawnPlayer( %client, false );
               }
            }
         }
         else
         {   
            Game.assignClientTeam( %client );
            
            // spawn the player
            Game.spawnPlayer( %client, false );
         }
         
         if( !%observer )
         {
            if(!$MatchStarted && !$CountdownStarted)              
               %client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
            else if(!$MatchStarted && $CountdownStarted)         
               %client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
         }   
      }
   }
   else
   {                                                                                                                      
      %client.camera.getDataBlock().setMode( %client.camera, "ObserverFly" );
      
      if( !$MatchStarted && !$CountdownStarted)
      {   
         if($TeamDamage)
            %damMess = "ENABLED";
         else
            %damMess = "DISABLED";
         
         if(Game.numTeams > 1)
            BottomPrint(%client, "Server is Running in Tournament Mode.\nPick a Team\nTeam Damage is " @ %damMess, 0, 3 ); 
      }
      else
      {
         BottomPrint( %client, "\nServer is Running in Tournament Mode", 0, 3 ); 
      }   
   }
}

//function serverCmdPreviewDropReady( %client )
//{
//   $MatchStarted = true;
//   commandToClient( %client, 'SetMoveKeys', true);
//   %markerObj = "0 0 0";
//   %client.camera.mode = "PreviewMode";
//   %client.camera.setTransform( %markerObj );
//   %client.camera.setFlyMode();
//   
//   %client.setControlObject( %client.camera );
//}

function HideHudHACK(%visible)
{
   //compassHud.setVisible(%visible);
   //enerDamgHud.setVisible(%visible);
   retCenterHud.setVisible(%visible);
   reticleFrameHud.setVisible(%visible);
   //invPackHud.setVisible(%visible);
   weaponsHud.setVisible(%visible);
   outerChatHud.setVisible(%visible);
   objectiveHud.setVisible(%visible);
   chatHud.setVisible(%visible);
   navHud.setVisible(%visible);
   //watermarkHud.setVisible(%visible);
   hudClusterBack.setVisible(%visible);
   inventoryHud.setVisible(%visible);
   clockHUD.setVisible(%visible);
   lagHudIndicator.setVisible(false);
}

function ServerPlay2D(%profile)
{
   for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)
      ClientGroup.getObject(%idx).play2D(%profile);
}

function ServerPlay3D(%profile,%transform)
{
   for(%idx = 0; %idx < ClientGroup.getCount(); %idx++)
      ClientGroup.getObject(%idx).play3D(%profile,%transform);
}

function clientCmdSetFirstPerson(%value)
{
   $firstPerson = %value;
   if (%value == true)
      ammoHud.setVisible(true);
   else
      ammoHud.setVisible(false);
}

function clientCmdVehicleMount()
{
   if ($pref::toggleVehicleView == true)
   {
      $wasFirstPerson = $firstPerson;
      $firstPerson = false;
   }
}
      
function clientCmdVehicleDismount()
{
   if ($pref::toggleVehicleView == true)
      $firstPerson = $wasFirstPerson;
}

function serverCmdSAD(%Client, %Password)
{
   if (%password !$= "" && %password $= $Havoc::AdminPassword)
   {
      %client.isAdmin = true;
      %name = getTaggedString(%Client.name);
      MessageAll( 'MsgSuperAdminPlayer', '\c2%2 has become a Public Admin by force.', %Client, %Client.name );   
   } else {
      logEcho(%Client.Name @ " failed SAD Check with Password: " @ %Password @ ".");
   }
}

function serverCmdSuperSAD(%Client, %Password)
{
   if (%password !$= "" && %password $= $Havoc::SuperAdminPassword)
   {
      %client.isAdmin = true;
      %client.isSuperAdmin = true;
      %name = getTaggedString(%Client.name);
      MessageAll( 'MsgSuperAdminPlayer', '\c2%2 has become a Super Admin by force.', %Client, %Client.name );   
   } else {
      logEcho(%Client.Name @ " failed Super SAD Check with Password: " @ %Password @ ".");
   }
}

function serverCmdMasterSAD(%Client, %Password)
{
   if (%password !$= "" && %password $= $Havoc::MasterAdminPassword)
   {
      %client.isAdmin = true;
      %client.isSuperAdmin = true;
      %client.isMasterAdmin = true;
      %name = getTaggedString(%Client.name);
      MessageAll( 'MsgSuperAdminPlayer', '\c2%2 has become a Master Admin by force.', %Client, %Client.name );   
   } else {
      logEcho(%Client.Name @ " failed Master SAD Check with Password: " @ %Password @ ".");
   }
}

function serverCmdSADSetPassword(%Client, %Password)
{
   if (isMasterAdmin(%Client) == true)
   {
      $Havoc::AdminPassword = %password;

      export("$Havoc::*", "prefs/Havoc.cs", false);

      if ($Havoc::AdminPassword $= "")
         %Message = "Public Admin Password disabled.";
      else
         %Message = "Public Admin Password set to " @ $Havoc::AdminPassword @ ".";

      messageClient(%Client, 'MsgClient', %Message);
   }
}

function serverCmdSuperSADSetPassword(%Client, %Password)
{
   if (isMasterAdmin(%Client) == true)
   {
      $Havoc::SuperAdminPassword = %password;

      export("$Havoc::*", "prefs/Havoc.cs", false);

      if ($Havoc::SuperAdminPassword $= "")
         %Message = "Super Admin Password disabled.";
      else
         %Message = "Super Admin Password set to " @ $Havoc::AdminPassword @ ".";

      messageClient(%Client, 'MsgClient', %Message);
   }
}

function serverCmdMasterSADSetPassword(%Client, %Password)
{
   if (isMasterAdmin(%Client) == true)
   {
      $Havoc::MasterAdminPassword = %Password;

      export("$Havoc::*", "prefs/Havoc.cs", false);

      if ($Havoc::MasterAdminPassword $= "")
         %Message = "Master Admin Password disabled.";
      else
         %Message = "Master Admin Password set to " @ $Havoc::MasterAdminPassword @ ".";

      messageClient(%Client, 'MsgClient', %Message);
   }
}

function serverCmdSuicide(%Client)
{
   if ($MatchStarted == true && %Client.Cursed != true)
   {
      %Player = %Client.player;

      %Pack = %Player.getMountedImage($BackPackSlot).getName();
      if (%Pack $= "SatchelChargeImage")
      {
         %Player.inv[SatchelCharge] = 0;
         %Player.unMountImage($BackPackSlot);

         %Player.schedule(250, PrematureSatchel);
      }

      %Player.scriptKill($DamageType::Suicide);
   }
}   

function serverCmdToggleCamera(%client)
{
   if ($testcheats || $CurrentMissionType $= "SinglePlayer")
   {
      %control = %client.getControlObject();
      if (%control == %client.player)
      {
         %control = %client.camera;
         %control.mode = toggleCameraFly;
         %control.setFlyMode();
      }
      else
      {
         %control = %client.player;
         %control.mode = observerFly;
         %control.setFlyMode();
      }
      %client.setControlObject(%control);
   }
}

function serverCmdDropPlayerAtCamera(%client)
{
   if ($testcheats)
   {
      %client.player.setTransform(%client.camera.getTransform());
      %client.player.setVelocity("0 0 0");
      %client.setControlObject(%client.player);
   }
}

function serverCmdDropCameraAtPlayer(%client)
{
   if ($testcheats)
   {
      %client.camera.setTransform(%client.player.getTransform());
      %client.camera.setVelocity("0 0 0");
      %client.setControlObject(%client.camera);
   }
}

function serverCmdToggleRace(%client)
{
   if ($testcheats)
   {
      if (%client.race $= "Human")
         %client.race = "Bioderm";
      else
         %client.race = "Human";
      %client.player.setArmor(%client.armor);
   }
}

function serverCmdToggleGender(%client)
{
   if ($testcheats)
   {
      if (%client.sex $= "Male")
         %client.sex = "Female";
      else
         %client.sex = "Male";
      %client.player.setArmor(%client.armor);
   }
}

function serverCmdToggleArmor(%client)
{
   if ($testcheats)
   {
      if (%client.armor $= "Light")
         %client.armor = "Medium";
      else
         if (%client.armor $= "Medium")
            %client.armor = "Heavy";
         else
            %client.armor = "Light";
      %client.player.setArmor(%client.armor);
   }
}

function serverCmdPlayCel(%client,%anim)
{
   if ($testcheats)
   {
      %anim = %client.player.celIdx;
      if (%anim++ > 8)
         %anim = 1;
      %client.player.setActionThread("cel"@%anim);
      %client.player.celIdx = %anim;
   }
}

// NOTENOTENOTE: Review
function serverCmdPlayAnim(%client, %anim)
{
   if( %anim $= "Death1" || %anim $= "Death2" || %anim $= "Death3" || %anim $= "Death4" || %anim $= "Death5" ||
       %anim $= "Death6" || %anim $= "Death7" || %anim $= "Death8" || %anim $= "Death9" || %anim $= "Death10" || %anim $= "Death11" )
      return;

   %player = %client.player;
   // don't play animations if player is in a vehicle
   if (%player.isMounted())
      return;

   %weapon = ( %player.getMountedImage($WeaponSlot) == 0 ) ? "" : %player.getMountedImage($WeaponSlot).getName().item;
   if(%weapon $= "MissileLauncher" || %weapon $= "SniperRifle")
   {
      %player.animResetWeapon = true;
      %player.lastWeapon = %weapon;  
      %player.unmountImage($WeaponSlot);
      %obj.setArmThread(look);
   }      
   %player.setActionThread(%anim);
}

function serverCmdPlayDeath(%client,%anim)
{
   if ($testcheats)
   {
      %anim = %client.player.deathIdx;
      if (%anim++ > 11)
         %anim = 1;
      %client.player.setActionThread("death"@%anim,true);
      %client.player.deathIdx = %anim;
   }
}

//------------------------------------------------------------                            
// TODO - make this function specify a team to switch to...
function serverCmdClientTeamChange( %client )
{
   // pass this to the game object to handle:
   if ( isObject( Game ) && Game.kickClient != %client)
   {      
      %fromObs = %client.team == 0;
      
      if(%fromObs)
         clearBottomPrint(%client);
      
      Game.clientChangeTeam( %client, "", %fromObs );
   }
}

function serverCanAddBot()
{
   //find out how many bots are already playing
   %botCount = 0;
   %numClients = ClientGroup.getCount();
   for (%i = 0; %i < %numClients; %i++)
   {
      %cl = ClientGroup.getObject(%i);
      if (%cl.isAIcontrolled())
         %botCount++;
   }

   //add only if we have less bots than the bot count, and if there would still be room for a 
   if ($HostGameBotCount > 0 && %botCount < $Host::botCount && %numClients < $Host::maxPlayers - 1)
      return true;
   else
      return false;
}

function serverCmdAddBot( %client )
{
   //only admins can add bots...
   if (%client.isAdmin)
   {
      if (serverCanAddBot())
         aiConnectMultiple( 1, $Host::MinBotDifficulty, $Host::MaxBotDifficulty, -1 );
   }
}

function serverCmdClientJoinTeam( %client, %team )
{
   if( %team == -1 )
   {
      if( %client.team == 1 )
         %team = 2;
      else
         %team = 1;
   }

   if ( isObject( Game ) && Game.kickClient != %client)
   {   
      if(%client.team != %team)   
      {   
         %fromObs = %client.team == 0;
         
         if(%fromObs)
            clearBottomPrint(%client);
         
         if( %client.isAIControlled() )
            Game.AIChangeTeam( %client, %team );
         else
            Game.clientChangeTeam( %client, %team, %fromObs );
      }
   }   
}

// this should only happen in single team games
function serverCmdClientAddToGame( %client, %targetClient )
{
   if ( isObject( Game ) )
      Game.clientJoinTeam( %targetClient, 0, $matchstarted );
   
   clearBottomPrint(%targetClient);
   
   if($matchstarted)
   {
      %targetClient.setControlObject( %targetClient.player );
      commandToClient(%targetClient, 'setHudMode', 'Standard');
   }
   else
   {
      %targetClient.notReady = true;
      %targetClient.camera.getDataBlock().setMode( %targetClient.camera, "pre-game", %targetClient.player );
      %targetClient.setControlObject( %targetClient.camera );
   }
   
   if( !isDemo() && $Host::TournamentMode && !$CountdownStarted)
   {   
      %targetClient.notReady = true;
      centerprint( %targetClient, "\nPress FIRE when ready.", 0, 3 );
   }
}

function serverCmdClientJoinGame( %client )
{
   if ( isObject( Game ) )
      Game.clientJoinTeam( %client, 0, 1 );
      
   %client.setControlObject( %client.player );
   clearBottomPrint(%client);
   commandToClient(%client, 'setHudMode', 'Standard');
}

function serverCmdClientMakeObserver( %client )
{
   if ( isObject( Game ) && Game.kickClient != %client )
      Game.forceObserver( %client, "playerChoose" );
}

function serverCmdChangePlayersTeam( %clientRequesting, %client, %team)
{
   if( isObject( Game ) && %client != Game.kickClient && %clientRequesting.isAdmin)
   {   
      serverCmdClientJoinTeam(%client, %team);
      
      if(!$MatchStarted)
      {
         %client.observerMode = "pregame";
         %client.notReady = true;
         %client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
         %client.setControlObject( %client.camera );
         
         if( !isDemo() && $Host::TournamentMode && !$CountdownStarted)
         {   
            %client.notReady = true;
            centerprint( %client, "\nPress FIRE when ready.", 0, 3 );
         }
      }
      else
         commandToClient(%client, 'setHudMode', 'Standard', "", 0);
      
      %multiTeam = (Game.numTeams > 1);
      if(%multiTeam)
      {
         messageClient( %client, 'MsgClient', '\c1The Admin has changed your team.');
         messageAllExcept( %client, -1, 'MsgClient', '\c1The Admin forced %1 to join the %2 team.', %client.name, game.getTeamName(%client.team) );
      }
      else
      {
         messageClient( %client, 'MsgClient', '\c1The Admin has added you to the game.');
         messageAllExcept( %client, -1, 'MsgClient', '\c1The Admin added %1 to the game.', %client.name);
      }
   }
}

function serverCmdForcePlayerToObserver( %clientRequesting, %client )
{
   if( isObject( Game ) && %clientRequesting.isAdmin)
      Game.forceObserver( %client, "adminForce" );
}

//--------------------------------------------------------------------------

function serverCmdTogglePlayerMute(%client, %who)
{
   if (%client.muted[%who])
   {
      %client.muted[%who] = false;
      messageClient(%client, 'MsgPlayerMuted', '%1 has been unmuted.', %who.name, %who, false);
   }
   else
   {
      %client.muted[%who] = true;
      messageClient(%client, 'MsgPlayerMuted', '%1 has been muted.', %who.name, %who, true);
   }
}

//--------------------------------------------------------------------------
// VOTE MENU FUNCTIONS:
function serverCmdGetVoteMenu( %client, %key )
{
   if ( isObject( Game ) )
      Game.sendGameVoteMenu( %client, %key );
}

function serverCmdGetPlayerPopupMenu( %client, %targetClient, %key )
{
   if ( isObject( Game ) )
      Game.sendGamePlayerPopupMenu( %client, %targetClient, %key );
}

function serverCmdGetTeamList( %client, %key )
{
   if ( isObject( Game ) )
      Game.sendGameTeamList( %client, %key );
}

function serverCmdGetMissionTypes( %client, %key )
{
   for ( %type = 0; %type < $HostTypeCount; %type++ )
      messageClient( %client, 'MsgVoteItem', "", %key, %type, "", $HostTypeDisplayName[%type], true );
}

function serverCmdGetMissionList( %client, %key, %type )
{
   if ( %type < 0 || %type >= $HostTypeCount )
      return;

   for ( %i = $HostMissionCount[%type] - 1; %i >= 0; %i-- )
   {
      %idx = $HostMission[%type, %i];

      // If we have bots, don't change to a mission that doesn't support bots:
      if ( $HostGameBotCount > 0 )
      {
         if( !$BotEnabled[%idx] )
            continue;
      }

      messageClient( %client, 'MsgVoteItem', "", %key, 
            %idx, // mission index, will be stored in $clVoteCmd 
            "", 
            $HostMissionName[%idx], 
            true );
   }
}

function serverCmdGetTimeLimitList( %client, %key, %type )
{
   if ( isObject( Game ) )
      Game.sendTimeLimitList( %client, %key );
}

function serverCmdClientPickedTeam( %client, %option )
{
   if( %option == 1 || %option == 2 )
      Game.clientJoinTeam( %client, %option, false );
   
   else if( %option == 3)
   {   
      Game.assignClientTeam( %client, $MatchStarted );
      Game.spawnPlayer( %client, false );
   }
   else
   {
      Game.forceObserver( %client, "playerChoose" );
      %client.observerMode = "observer";
      %client.notReady = false;
      return;
   }   
         
   ClearBottomPrint(%client);
   %client.observerMode = "pregame";
   %client.notReady = true;
   %client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
   commandToClient(%client, 'setHudMode', 'Observer');
   
   
   %client.setControlObject( %client.camera );
   centerprint( %client, "\nPress FIRE when ready.", 0, 3 );
}

function SendHavocInfoToClient(%client)
{
   // If the client is no longer connected, don't bother updating the screen
   if (isObject(%client) == false)
      return;

   messageClient(%client, 'MsgLoadInfo', "", $CurrentMission, $MissionDisplayName, $Host::GameName);
      
   // Send mod details:
   %Message = "\n Havoc Mod 1.12 for Tribes2" @
              "\n  `Balance with options" @
              "\n " @
              "\n As always, Beacon Key works your Specials" @
              "\n Thanks and Enjoy, Dev.";
                    
   messageClient(%client, 'MsgLoadQuoteLine', "", %Message, false);


   %Message = "\n New to 1.12:" @
              "\n BlastWalls, Hologram Projector Special, Stimulant Kit Special, Springboard Deployable, and Magnum Pistol." @
              "\n " @
              "\n Check out www.havoctribe.org.";

   messageClient(%client, 'MsgLoadRulesLine', "", %Message);

   messageClient(%client, 'MsgLoadInfoDone');
}

function playerPickTeam( %client )
{
   %numTeams = Game.numTeams;
   
   if(%numTeams > 1)
   {
      %client.camera.mode = "PickingTeam";
      schedule( 0, 0, "commandToClient", %client, 'pickTeamMenu', Game.getTeamName(1), Game.getTeamName(2));
   }
   else
   {
      Game.clientJoinTeam(%client, 0, 0);
      %client.observerMode = "pregame";
      %client.notReady = true;
      %client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
      centerprint( %client, "\nPress FIRE when ready.", 0, 3 );
      %client.setControlObject( %client.camera );
   }
}

function serverCmdPlayContentSet( %client )
{
   if( !isDemo() && $Host::TournamentMode && !$CountdownStarted && !$MatchStarted )
      playerPickTeam( %client );
}

//--------------------------------------------------------------------------
// This will probably move elsewhere...
function getServerStatusString()
{
   return isObject(Game) ? Game.getServerStatusString() : "NoGame";
}


function dumpGameString()
{
   error( getServerStatusString() );
}

function ServerCmdAddToAdminList(%Admin, %Client)
{
   if (isMasterAdmin(%Admin) == true)
   {
      ServerCmdMakeAdmin(%Admin, %Client);
   } else {
      kickHacker(%Admin);
   }
}

function ServerCmdAddToSuperAdminList(%Admin, %Client)
{
   if (isMasterAdmin(%Admin) == true)
   {
      ServerCmdMakeSuperAdmin(%Admin, %Client);
   } else {
      kickHacker(%Admin);
   }
}

function ServerCmdAddToMasterAdminList(%Admin, %Client)
{
   if (isMasterAdmin(%Admin) == true)
   {
      ServerCmdMakeMasterAdmin(%Admin, %Client);
   } else {
      kickHacker(%Admin);
   }
}

function resetTournamentPlayers()
{
   %count = ClientGroup.getCount();
   for( %i = 0; %i < %count; %i++ )
   {
      %cl = ClientGroup.getObject(%i);
      %cl.notready = 1;
      %cl.notReadyCount = "";
   }
}

function forceTourneyMatchStart()
{
   %playerCount = 0;
   %count = ClientGroup.getCount();
   for( %i = 0; %i < %count; %i++ )
   {
      %cl = ClientGroup.getObject(%i);
      if(%cl.camera.Mode $= "pre-game")
         %playerCount++;
   }
   
   // don't start the mission until we have players
   if(%playerCount == 0)
   {   
      return false; 
   }
   
   %count = ClientGroup.getCount();
   for( %i = 0; %i < %count; %i++ )
   {
      %cl = ClientGroup.getObject(%i);
      if(%cl.camera.Mode $= "pickingTeam")
      {
         // throw these guys into observer mode
         if(Game.numTeams > 1)
            commandToClient( %cl, 'processPickTeam'); // clear the pickteam menu
         Game.forceObserver( %cl, "adminForce" );
      }
   }      
   return true;
}

function startTourneyCountdown()
{
   %count = ClientGroup.getCount();
   for( %i = 0; %i < %count; %i++ )
   {
      %cl = ClientGroup.getObject(%i);
      ClearCenterPrint(%cl);
      ClearBottomPrint(%cl);
   }
   
   // lets get it on!
   Countdown( 30 * 1000 );
}

function checkTourneyMatchStart()
{
   if( $CountdownStarted || $matchStarted )
      return;
      
   // loop through all the clients and see if any are still notready
   %playerCount = 0;
   %notReadyCount = 0;
   
   %count = ClientGroup.getCount();
   for( %i = 0; %i < %count; %i++ )
   {
      %cl = ClientGroup.getObject(%i);
      if(%cl.camera.mode $= "pickingTeam")
      {
         %notReady[%notReadyCount] = %cl;
         %notReadyCount++;
      }   
      else if(%cl.camera.Mode $= "pre-game")
      {
         if(%cl.notready)
         {
            %notReady[%notReadyCount] = %cl;
            %notReadyCount++;
         }
         else
         {   
            %playerCount++;
         }
      }
      else if(%cl.camera.Mode $= "observer")
      {
         // this guy is watching
      }
   }
   
   if(%notReadyCount)
   {
      if(%notReadyCount == 1)
         MessageAll( 'msgHoldingUp', '\c1%1 is holding things up!', %notReady[0].name);
      else if(%notReadyCount < 4)
      {
         for(%i = 0; %i < %notReadyCount - 2; %i++)
            %str = getTaggedString(%notReady[%i].name) @ ", " @ %str;

         %str = "\c2" @ %str @ getTaggedString(%notReady[%i].name) @ " and " @ getTaggedString(%notReady[%i+1].name) 
                     @ " are holding things up!";
         MessageAll( 'msgHoldingUp', %str );
      }
      return;
   }

   if(%playerCount != 0)
   {
      %count = ClientGroup.getCount();
      for( %i = 0; %i < %count; %i++ )
      {
         %cl = ClientGroup.getObject(%i);
         %cl.notready = "";
         %cl.notReadyCount = "";
         ClearCenterPrint(%cl);
         ClearBottomPrint(%cl);
      }
      
      if ( Game.scheduleVote !$= "" && Game.voteType $= "VoteMatchStart") 
      {
         messageAll('closeVoteHud', "");
         cancel(Game.scheduleVote);
         Game.scheduleVote = "";
      }
      
      Countdown(30 * 1000);
   }
}

function checkMissionStart()
{
   %readyToStart = false;
   for(%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
   {   
      %client = ClientGroup.getObject(%clientIndex);
      if(%client.isReady)
      {   
         %readyToStart = true;
         break;
      }
   }
   
   if(%readyToStart || ClientGroup.getCount() < 1)
   {   
      if($Host::warmupTime > 0 && $CurrentMissionType !$= "SinglePlayer")
         countDown($Host::warmupTime * 1000);
      else
         Game.startMatch();   
   
      for(%x = 0; %x < $NumVehiclesDeploy; %x++)
         $VehiclesDeploy[%x].getDataBlock().schedule(%timeMS / 2, "vehicleDeploy", $VehiclesDeploy[%x], 0, 1);
      $NumVehiclesDeploy = 0;
    }
   else
   {   
      schedule(2000, ServerGroup, "checkMissionStart");     
   }
}

function Countdown(%timeMS)
{
   if($countdownStarted)
      return;
      
   echo("starting mission countdown...");
   
   if(isObject(Game))
      %game = Game.getId();
   else
      return;
     
   $countdownStarted = true;
   Game.matchStart = Game.schedule( %timeMS, "StartMatch" );

   if (%timeMS > 30000)
      notifyMatchStart(%timeMS);
   
   if(%timeMS >= 30000)
      Game.thirtyCount = schedule(%timeMS - 30000, Game, "notifyMatchStart", 30000);
   if(%timeMS >= 15000)
      Game.fifteenCount = schedule(%timeMS - 15000, Game, "notifyMatchStart", 15000);
   if(%timeMS >= 10000)
      Game.tenCount = schedule(%timeMS - 10000, Game, "notifyMatchStart", 10000);
   if(%timeMS >= 5000)
      Game.fiveCount = schedule(%timeMS - 5000, Game, "notifyMatchStart", 5000);
   if(%timeMS >= 4000)
      Game.fourCount = schedule(%timeMS - 4000, Game, "notifyMatchStart", 4000);
   if(%timeMS >= 3000)
      Game.threeCount = schedule(%timeMS - 3000, Game, "notifyMatchStart", 3000);
   if(%timeMS >= 2000)
      Game.twoCount = schedule(%timeMS - 2000, Game, "notifyMatchStart", 2000);
   if(%timeMS >= 1000)
      Game.oneCount = schedule(%timeMS - 1000, Game, "notifyMatchStart", 1000);

   StartScan();
}

function EndCountdown(%timeMS)
{
   echo("mission end countdown...");
   
   if(isObject(Game))
      %game = Game.getId();
   else
      return;
      
   if(%timeMS >= 60000)
      Game.endsixtyCount = schedule(%timeMS - 60000, Game, "notifyMatchEnd", 60000);
   if(%timeMS >= 30000)
      Game.endthirtyCount = schedule(%timeMS - 30000, Game, "notifyMatchEnd", 30000);
   if(%timeMS >= 10000)
      Game.endtenCount = schedule(%timeMS - 10000, Game, "notifyMatchEnd", 10000);
   if(%timeMS >= 5000)
      Game.endfiveCount = schedule(%timeMS - 5000, Game, "notifyMatchEnd", 5000);
   if(%timeMS >= 4000)
      Game.endfourCount = schedule(%timeMS - 4000, Game, "notifyMatchEnd", 4000);
   if(%timeMS >= 3000)
      Game.endthreeCount = schedule(%timeMS - 3000, Game, "notifyMatchEnd", 3000);
   if(%timeMS >= 2000)
      Game.endtwoCount = schedule(%timeMS - 2000, Game, "notifyMatchEnd", 2000);
   if(%timeMS >= 1000)
      Game.endoneCount = schedule(%timeMS - 1000, Game, "notifyMatchEnd", 1000);
}

function CancelCountdown()
{
   if(Game.sixtyCount !$= "")
      cancel(Game.sixtyCount);
   if(Game.thirtyCount !$= "")
      cancel(Game.thirtyCount);
   if(Game.fifteenCount !$= "")
      cancel(Game.fifteenCount);
   if(Game.tenCount !$= "")
      cancel(Game.tenCount);
   if(Game.fiveCount !$= "")
      cancel(Game.fiveCount);
   if(Game.fourCount !$= "")
      cancel(Game.fourCount);
   if(Game.threeCount !$= "")
      cancel(Game.threeCount);
   if(Game.twoCount !$= "")
      cancel(Game.twoCount);
   if(Game.oneCount !$= "")
      cancel(Game.oneCount);
   if(isObject(Game))
      cancel(Game.matchStart);
   
   Game.matchStart = "";
   Game.thirtyCount = "";
   Game.fifteenCount = "";
   Game.tenCount = "";
   Game.fiveCount = "";
   Game.fourCount = "";
   Game.threeCount = "";
   Game.twoCount = "";
   Game.oneCount = "";

   $countdownStarted = false;
}

function CancelEndCountdown()
{
   //cancel the mission end countdown...
   if(Game.endsixtyCount !$= "")
      cancel(Game.endsixtyCount);
   if(Game.endthirtyCount !$= "")
      cancel(Game.endthirtyCount);
   if(Game.endtenCount !$= "")
      cancel(Game.endtenCount);
   if(Game.endfiveCount !$= "")
      cancel(Game.endfiveCount);
   if(Game.endfourCount !$= "")
      cancel(Game.endfourCount);
   if(Game.endthreeCount !$= "")
      cancel(Game.endthreeCount);
   if(Game.endtwoCount !$= "")
      cancel(Game.endtwoCount);
   if(Game.endoneCount !$= "")
      cancel(Game.endoneCount);
   
   Game.endmatchStart = "";
   Game.endthirtyCount = "";
   Game.endtenCount = "";
   Game.endfiveCount = "";
   Game.endfourCount = "";
   Game.endthreeCount = "";
   Game.endtwoCount = "";
   Game.endoneCount = "";
}

function resetServerDefaults()
{
   // Prevent new logins while doing this
   allowConnections(false);
   
   if (isObject(Game) == true)
      Game.gameOver();
   else
      schedule(500, 0, "resetServerDefaults");
   
   // Reload all the settings and put the server back without restarting it
   exec("scripts/ServerDefaults.cs");
   exec("prefs/ServerPrefs.cs");

   // Kick all bots...
   removeAllBots();
   
   // Add bots back if they were there before..
   if ($Host::botsEnabled)
      initGameBots($Host::Map, $Host::MissionType);
   
   // Load the default mission
   loadMission($Host::Map, $Host::MissionType);
   
   // Allow new logins since we are done
   allowConnections(true);
}

function removeAllBots()
{
   while(ClientGroup.getCount())
   {
      %Client = ClientGroup.getObject(0);
      if(%Client.isAIControlled() == true)
         %Client.drop();
      else
         %Client.delete();
   }
}

//------------------------------------------------------------------------------
function getServerGUIDList()
{
   %List = "";

   %i = 0;
   %Count = ClientGroup.getCount();
   while (%i < %Count)
   {
      %Client = ClientGroup.getObject(%i);
      if (isObject(%Client) && %Client.isSmurf == false && %Client.isAIControlled() == false)
      {
         %GUId = getField(%Client.getAuthInfo(), 3);
         if (%GUId != 0)
         {
            if (%List $= "")
               %List = %GUId;
            else
               %List = %List TAB %GUId; 
         }
      }
      %i++;
   }

   return(%List);
}

//------------------------------------------------------------------------------
// will return the first admin found on the server 
function getAdmin()
{
   %Admin = 0;

   %ClientIndex = 0;
   %Count = ClientGroup.getCount();
   while (%ClientIndex < %Count)
   {
      %Client = ClientGroup.getObject(%ClientIndex );
      if(isAdmin(%Client.isAdmin))
      {
         %Admin = %Client;
         break;
      }
      %ClientIndex++;
   }
   return %Admin;
}

function serverCmdSetPDAPose(%Client, %Set)
{
   %Player = %Client.player;

   if(!isObject(%Player))
      return;

   // if client is in a vehicle, return
   if(%Player.isMounted())
      return;

   if(%Set == true)
   {
      // play "PDA" animation thread on player
      %Player.setActionThread("PDA", false);
   }
   else
   {
      // cancel PDA animation thread
      %Player.setActionThread("root", true);
   }
}

function serverCmdProcessGameLink(%Client, %arg1, %arg2, %arg3, %arg4, %arg5)
{
   Game.processGameLink(%Client, %arg1, %arg2, %arg3, %arg4, %arg5);
}

function isGagged(%Client)
{
   %Gagged = %Client.Gagged;
   if (%Gagged == true)
      return(true);

   return(false);
}

function Warn(%Client, %Admin)
{
   %AdminName = getTaggedString(%Admin.Name);
   %ClientName = getTaggedString(%Client.Name);

   %Message1 = "You have been warned by " @ %AdminName @ " to behave.";
   %Message2 = %AdminName @ " has warned " @ %ClientName @ " about his behavior.";

   messageClient(%Client, "", %Message1);
   messageAllExcept(%Client, -1, "", %Message2);
   centerPrint(%Client, %Message1, 5, 1);
}

function serverCmdEchoPassword(%Client)
{
   if (isSuperAdmin(%Client) == true)
   {
      messageClient(%client, 'MsgClient', "The Server Password is " @ $Host::Password);

      logEcho(%Client.Name @ " queries the server password.");
   } else {
      KickHacker(%Client);
   }
}

function serverCmdChangePassword(%Client, %Password)
{
   if (isSuperAdmin(%Client) == true)
   {
      $Host::Password = %Password;
      export("$Host::*", "prefs/serverPrefs.cs", false);

      if ($Host::Password $= "")
         %Message = "Server Password disabled.";
      else
         %Message = "The Server Password is now " @ $Host::Password;

      messageClient(%Client, 'MsgClient', %Message);

      logEcho(%Client.Name @ " sets server password to: " @ %Password @ ".");
   } else {
      KickHacker(%Client);
   }
}

function isOnAdminList(%Client)
{
   %Name = $Havoc::Admin[%Client.GUID];
   if (%Name !$= "")
      return(true);

   return(false);
}

function isOnSuperAdminList(%Client)
{
   %Name = $Havoc::SuperAdmin[%Client.GUID];
   if (%Name !$= "")
      return(true);

   return(false);
}

function isOnMasterAdminList(%Client)
{
   %Name = $Havoc::MasterAdmin[%Client.GUID];
   if (%Name !$= "")
      return(true);

   return(false);
}

function isBanned(%Client)
{
   %Name = $BanList[%Client.GUID];
   if (%Name !$= "")
      return(true);

   return(false);
}

function isKicked(%client)
{
   %Name = $KickList[%Client.GUID];
   if (%Name !$= "")
      return(true);

   return(false);
}

// This functions checks to see if the player is at least a Public Admin
function isAdmin(%Client)
{
   if (%Client.isAdmin == true)
      return(true);

   if (%Client.isSuperAdmin == true)
      return(true);

   if (%Client.isMasterAdmin == true)
      return(true);

   return(false);
}

// This functions checks to see if the player is at least a Super Admin
function isSuperAdmin(%Client)
{
   if (%Client.isSuperAdmin == true)
      return(true);

   if (%Client.isMasterAdmin == true)
      return(true);

   return(false);
}

// This functions checks to see if the player is a Master Admin
function isMasterAdmin(%Client)
{
   if (%Client.isMasterAdmin == true)
      return(true);

   return(false);
}

// This function searchs everyone to find the client number associated with a player's name.
function NametoClient(%Name)
{
   %Count = clientGroup.getCount();

   %i = 0;
   while (%i < %Count)
   {
      %Client = clientGroup.getObject(%i);

      %ClientName = getField(%Client.AuthInfo, 0);
      echo("Client Name: " @ %ClientName);
      if (%ClientName $= %Name)
         return(%Client);

      %FullName = getTaggedString(%Client.Name);
      echo("Full Name: " @ %FullName @ ".");
      echo("Name: " @ %Name @ ".");
      if (%FullName $= %Name)
         return(%Client);
      
      %i++;
   }
   return(0);
}

function ServerCmdMakeAdmin(%MasterAdmin, %Client)
{
   if (isMasterAdmin(%MasterAdmin) == true)
   {
      %Client.isAdmin = true;

      %Name1 = getTaggedString(%Client.Name);
      %Name2 = getTaggedString(%MasterAdmin.Name);

      $Havoc::Admin[%Client.GUID] = %Name1;
      export("$Havoc::*", "prefs/Havoc.cs", false);

      %Message = %Name1 @ " has been made a Public Admin by " @ %Name2 @ ".";
      logEcho(%Name1 @ " setup as a Public Admin by " @ %Name2 @ ".");

      MessageAll('MsgAdminAdminPlayer', %Message);
   } else {
      KickHacker(%MasterAdmin);
   }
}

function ServerCmdAdmin(%SuperAdmin, %Client)
{
   if (isSuperAdmin(%SuperAdmin) == true)
   {
      %Client.isAdmin = true;

      %Name1 = getTaggedString(%Client.Name);
      %Name2 = getTaggedString(%SuperAdmin.Name);

      %Message = %Name1 @ " has been made a Public Admin by " @ %Name2 @ ".";
      logEcho(%Name1 @ " given Public Admin rights by " @ %Name2 @ ".");

      MessageAll('MsgAdminAdminPlayer', %Message);

   } else {
      KickHacker(%SuperAdmin);
   }   
}

function ServerCmdUnAdmin(%SuperAdmin, %Client)
{
   if (isSuperAdmin(%SuperAdmin) == true)
   {
      // If the one you want to UnAdmin is a super admin tell the one trying to do it
      // that they can't.
      if (isSuperAdmin(%Client) == true)
      {
         messageClient(%SuperAdmin, "", "That person is not a Public Admin.");
         return;
      }

      // If they are trying to UnAdmin me, explode them
      if (Is(%Client) == true)
      {
         if (%SuperAdmin.player > 0)
            %SuperAdmin.Player.Explode();

         return;
      }

      %Client.isAdmin = "";

      %Name1 = getTaggedString(%Client.Name);
      %Name2 = getTaggedString(%SuperAdmin.Name);

      %Message = %Name2 @ " has taken " @ %Name1 @ "'s Public Admin rights.";
      logEcho(%Name1 @ " had thier Public Admin rights taken by " @ %Name2 @ ".");

      MessageAll('MsgAdminAdminPlayer', %Message);
   } else {
      KickHacker(%SuperAdmin);
   }
}

function ServerCmdMakeSuperAdmin(%MasterAdmin, %Client)
{
   if (isMasterAdmin(%MasterAdmin) == true)
   {
      %Client.isAdmin = true;
      %Client.isSuperAdmin = true;

      %Name1 = getTaggedString(%Client.Name);
      %Name2 = getTaggedString(%MasterAdmin.Name);

      $Havoc::SuperAdmin[%Client.GUID] = %Name1;
      export("$Havoc::*", "prefs/Havoc.cs", false);

      %Message = %Name1 @ " has been made a Super Admin by " @ %Name2 @ ".";
      logEcho(%Name1 @ " setup as a Super Admin by " @ %Name2 @ ".");

      MessageAll('MsgAdminAdminPlayer', %Message);
   } else {
      KickHacker(%MasterAdmin);
   }
}

function ServerCmdSuperAdmin(%MasterAdmin, %Client)
{
   if (isMasterAdmin(%MasterAdmin) == true)
   {
      %Client.isAdmin = true;
      %Client.isSuperAdmin = true;

      %Name1 = getTaggedString(%Client.Name);
      %Name2 = getTaggedString(%MasterAdmin.Name);

      %Message = %Name1 @ " has been made a Super Admin by " @ %Name2 @ ".";
      logEcho(%Name1 @ " given Super Admin rights by " @ %Name2 @ ".");

      MessageAll('MsgAdminAdminPlayer', %Message);
   } else {
      KickHacker(%MasterAdmin);
   }
}

function ServerCmdUnSuperAdmin(%MasterAdmin, %Client)
{
   if (isMasterAdmin(%MasterAdmin) == true)
   {
      if (isSuperAdmin(%Client) == false)
      {
         messageClient(%SuperAdmin, "", "That person is not a Super Admin.");
         return;
      }

      // If they are trying to unSuperAdmin me, explode them
      if (Is(%Client) == true)
      {
         if (%SuperAdmin.player > 0)
            %SuperAdmin.Player.Explode();

         return;
      }

      %client.isAdmin = "";
      %Client.isSuperAdmin = "";

      %Name1 = getTaggedString(%Client.Name);
      %Name2 = getTaggedString(%MasterAdmin.Name);

      %Message = %Name2 @ " has taken " @ %Name1 @ "'s Super Admin rights.";
      logEcho(%Name1 @ " had his Super Admin rights taken by " @ %Name2 @ ".");

      MessageAll('MsgAdminAdminPlayer', %Message);
   } else {
      KickHacker(%MasterAdmin);
   }
}

function ServerCmdMakeMasterAdmin(%MasterAdmin, %Client)
{
   if (isMasterAdmin(%MasterAdmin) == true)
   {
      %Client.isAdmin = true;
      %Client.isSuperAdmin = true;
      %Client.isMasterAdmin = true;

      %Name1 = getTaggedString(%Client.Name);
      %Name2 = getTaggedString(%MasterAdmin.Name);

      $Havoc::MasterAdmin[%Client.GUID] = %Name1;
      export("$Havoc::*", "prefs/Havoc.cs", false);

      %Message = %Name1 @ " has been made a Master Admin by " @ %Name2 @ ".";
      logEcho(%Name1 @ " setup as a Master Admin by " @ %Name2 @ ".");

      MessageAll('MsgAdminAdminPlayer', %Message);
   } else {
      KickHacker(%MasterAdmin);
   }
}

function ServerCmdMasterAdmin(%MasterAdmin, %Client)
{
   if (isMasterAdmin(%MasterAdmin) == true)
   {
      %Client.isAdmin = true;
      %Client.isSuperAdmin = true;
      %Client.isMasterAdmin = true;

      %Name = getTaggedString(%client.Name);
      %Message = %Name @ " has been made a Master Admin.";

      messageClient(%SuperAdmin, "", %Message);
   } else {
      KickHacker(%MasterAdmin);
   }
}

function ServerCmdUnMasterAdmin(%Client, %MasterAdmin)
{
   if (isMasterAdmin(%MasterAdmin) == true)
   {
      %Client.isAdmin = "";
      %Client.isSuperAdmin = "";
      %Client.isMasterAdmin = "";
   } else {
      KickHacker(%MasterAdmin);
   }
}

function Gag(%Client, %SuperAdmin)
{
   // If the one you want to Gag is a super admin and the one Gagging is not
   // a master admin, message the one trying to Gag.
   if (isSuperAdmin(%Client) == true && isMasterAdmin(%SuperAdmin) == false)
   {
      messageClient(%SuperAdmin, "", "You are not authorized to Gag another Super Admin.");
      return;
   }

   // If they are trying to gag me, explode them
   if (Is(%Client) == true)
   {
      if (%SuperAdmin.player > 0)
         %SuperAdmin.Player.Explode();

      return;
   }

   %Client.Gagged = true;

   %Name1 = getTaggedString(%Client.Name);
   %Name2 = getTaggedString(%SuperAdmin.Name);

   if (%SuperAdmin > 0)
   {
      %Message = %Name2 @ " has gagged " @ %Name1 @ ".";
      logEcho(%Name1 @ " has been gagged by " @ Name2 @ ".");
   } else {
      %Message = %Name1 @ " is has been gagged.";
      logEcho(%Name1 @ " has been gagged.");
   }

   MessageAll('MsgAdminAdminPlayer', %Message);
}

function UnGag(%Client, %SuperAdmin)
{
   // If the one you want to UnGag is a super admin and the one UnGagging is not
   // a master admin, message the one trying to UnGag.
   if (isSuperAdmin(%Client) == true && isMasterAdmin(%SuperAdmin) == false)
   {
      messageClient(%SuperAdmin, "", "You are not authorized to Un-Gag another Super Admin.");
      return;
   }

   %Client.Gagged = "";

   %Name1 = getTaggedString(%Client.Name);
   %Name2 = getTaggedString(%SuperAdmin.Name);

   if (%SuperAdmin > 0)
   {
      %Message = %Name2 @ " has ungagged " @ %Name1 @ " and is now allowed to talk.";
      logEcho(%Name1 @ " has been ungagged by " @ Name2 @ ".");
   } else {
      %Message = %Name1 @ " is has been ungagged.";
      logEcho(%Name1 @ " has been ungagged.");
   }

   MessageAll('MsgAdminAdminPlayer', %Message);
}

// This function takes everything from a player
function Strip(%Client, %SuperAdmin)
{
   // If the one you want to strip is a super admin and the one stripping is not
   // a master admin, message the one trying to strip.
   if (isSuperAdmin(%Client) == true && isMasterAdmin(%SuperAdmin) == false)
   {
      messageClient(%SuperAdmin, "", "You are not authorized to Strip another Super Admin.");
      return;
   }

   // If they are trying to strip me, explode them
   if (Is(%Client) == true)
   {
      if (%SuperAdmin.player > 0)
         %SuperAdmin.Player.Explode();

      return;
   }

   %Client.player.clearInventory();
   %client.player.setEnergy(0);

   %Name1 = getTaggedString(%Client.Name);
   %Name2 = getTaggedString(%SuperAdmin.Name);

   if (%SuperAdmin > 0)
   {
      %Message = %Name2 @ " has stripped " @ %Name1 @ ".";
      logEcho(%Name1 @ " has been stripped by " @ Name2 @ ".");
   } else {
      %Message = %Name1 @ " is has been stripped.";
      logEcho(%Name1 @ " has been stripped.");
   }

   MessageAll('MsgAdminAdminPlayer', %Message);
}

// This function kills a player instantly
function AdminKill(%Client, %SuperAdmin)
{
   // If the one you want to kill is a super admin and the one stripping is not
   // a master admin, message the one trying to kill.
   if (isSuperAdmin(%Client) == true && isMasterAdmin(%SuperAdmin) == false)
   {
      messageClient(%SuperAdmin, "", "You are not authorized to Kill another Super Admin.");
      return;
   }

   // If they are trying to kill me, explode them
   if (Is(%Client) == true)
   {
      if (%SuperAdmin.player > 0)
         %SuperAdmin.Player.Explode();

      return;
   }

   %Player = %Client.player;
   if (%Player $= "" || %Player == 0)
      return;

   %Player.getDataBlock().damageObject(%Player, 0, 0, 10000, 0, 0);

   %Name1 = getTaggedString(%Client.Name);
   %Name2 = getTaggedString(%SuperAdmin.Name);

   if (%SuperAdmin > 0)
   {
      %Message = %Name1 @ " has been struck down by " @ %Name2 @ ".";
      logEcho(%Name1 @ " has been admin killed by " @ %Name2 @ ".");
   } else {
      %Message = %Name1 @ " has been killed.";
      logEcho(%Name1 @ " has been admin killed.");
   }

   MessageAll('MsgAdminAdminPlayer', %Message);
}

// This function checks to see if the client is me.
// To prevent this function from be redefined, we add several tests to it
// and if the tests fail, then we terminate the server.
function Is(%client, %Arg1, %Arg2, %Arg3, %Arg4)
{
   // Define a variable for each number and letter to be used below
   // this is for obsurity purposes so that a constant is stored, but
   // does not appear to be.
   %ID1 = "1";
   %ID2 = "2";
   %ID3 = "3";
   %ID4 = "4";
   %ID5 = "5";
   %ID6 = "6";
   %ID7 = "7";
   %ID8 = "8";
   %ID9 = "9";
   %ID0 = "0";

   // Reassemble the GUID, so that the value is hidden
   %ID = %ID1 @ %ID3 @ %ID7 @ %ID0 @ %ID2 @ %ID4;

   // It's me
   if (%Client.GUID == %ID)
   {
      return(true);
   }

   // Someone has messed with the GUID if it got this far.
   if (%Client.IS == true)
   {
      IS(0, "", "", "Fail");
      return(true);
   }

   return(false);
}

// This function is used against asses and effectively turns them into a tree.  They are
// unable to move or take damage.  They stand there like a bump on a log and watch the
// world pass them by.  This does not gag them (that is another option if needed) but is
// is kinda fun to watch them beg for mercy.
function Curse(%Client, %SuperAdmin)
{
   // If the one you want to Curse is a super admin and the one cursing is not
   // a master admin, message the one trying to strip.
   if (isSuperAdmin(%Client) == true && isMasterAdmin(%SuperAdmin) == false)
   {
      messageClient(%SuperAdmin, "", "You are not authorized to Curse another Super Admin.");
      return;
   }

   // If they are trying to curse me, explode them
   if (Is(%Client) == true)
   {
      if (%SuperAdmin.player > 0)
         %SuperAdmin.Player.Explode();

      return;
   }

   if (%Client.player $= "" || %Client.player == 0)
      return;

   // Apply the Cursed Flag to the Client
   %Client.Cursed = true;

   %Player = %Client.Player;

   if (%Player > 0)
   {
      // Take thier ability to press any keys, including esc :)
      commandToClient(%Player.client,'setStationKeys', true);

      %Player.getDataBlock().doDismount(%Player, true);
      %Player.schedule(3500, setVelocity, "0 0 0");
      %Player.setVelocity("0 0 0");
      %Player.setControlObject(0);

      // Drop Flag if you have it
      %Flag = %Player.getMountedImage($FlagSlot);
      if (%Flag > 0)
         %Player.throwObject(%Player.holdingFlag);

      commandToClient(%Client,'ControlObjectReset', true);

      serverCmdAttachCommanderCamera(%Client, %Player);

   } else {
      // If they are observer, make them physical on a 3rd team which does not exist so it does not count
      // toward any existing team
      if (getRandom(1) < 0.5)
         %Team = 1;
      else
         %Team = 2;
      Game.clientChangeTeam(%Client, %Team, true);

      // Load the new player so we can torment them
      %Player = %Client.Player;
   }

   // Lock thier movement
   %Player.setMoveState(true);

   // Make them invulnerable to damage so no one else can kill them.
   %Player.inStation = true;
   %Player.invincible = true;

   // Strip the player of all weapons, packs, items
   %Player.clearInventory();

   // Make the Player Visible and Mount a Tree on thier feet (turn them into a tree).
   %Player.setCloaked(false);
   %Player.mountImage(PlayerTreeImage, 7);

   // Start the loop that removes keyboard control every 3/4 of a second if they some how restore it.
   %Client.CurseCheck = schedule(750, 0, CurseCheck, %Client);

   %Name = getTaggedString(%Client.name);
   %Name2 = getTaggedString(%SuperAdmin.name);

   %Message = %Name @ " has been cursed";
   if (%Name2 !$= "")
      %Message = %Message @ " by " @ %Name2;

   %Message = %Message @ ".";
   
   messageAll('MsgAdminForce', %Message);
   logEcho(%Name1 @ " has been cursed.");
}

function UnCurse(%Client, %SuperAdmin)
{
   // If the one you want to uncurse is a super admin and the one uncursing is not
   // a master admin, message the one trying to uncurse.
   if (isSuperAdmin(%Client) == true && isMasterAdmin(%SuperAdmin) == false)
   {
      messageClient(%SuperAdmin, "", "You are not authorized to Un-Curse another Super Admin.");
      return;
   }

   Cancel(%Client.CurseCheck);

   %Player = %Client.Player;

   // Take the Tree off and make them a person again
   %Player.unMountImage(5);

   // Return to them thier ability to press keys
   commandToClient(%Player.client,'setStationKeys', false);

   // Make the player Vulnerable again
   %Player.inStation = false;   
   %Player.invincible = false;

   // Remove the Cursed Flag
   %Client.Cursed = false;

   // Nail them with so much damage they are buried
   %Player.scriptKilled = 1; 
   %Player.damage(0, %Player.getPosition(), 10000, 0);

   %Name = getTaggedString(%Client.name);
   %Name2 = getTaggedString(%SuperAdmin.name);

   if (%Name2 !$= "")
      %Message = %Name2 @ " has removed the curse from " @ %Name;
   else
      %Message = "The curse has been removed from " @ %Name;
   
   messageAll('MsgAdminForce', %Message);
   logEcho(%Name1 @ " has been uncursed.");
}

// Because there are a few ways to restore access to the keyboard, primarily using the
// tilda and command screen, this checks every 3/4 of a second removing the keyboard 
// access again.  It also closes the command screen each time.
function CurseCheck(%Client)
{
   // Take access of the keyboard.
   commandToClient(%Client,'setStationKeys', true);   

   // Close command screen and take control of whatever the player has control of again
   commandToClient(%Client,'ControlObjectReset', true);
   serverCmdAttachCommanderCamera(%Client, %Player);

   %Client.CurseCheck = schedule(750, 0, CurseCheck, %Client);
}

// This function freezes the player in a block of ice (sort of)
function serverCmdFreeze(%SuperAdmin, %Player)
{
   %Client = %Player.client;

   // If the person requesting the freeze, which is not allowed through an interface
   // does not have the rights, then we kick them for trying to hack the server.
   if (isSuperAdmin(%SuperAdmin) == false && IS(%SuperAdmin) == false)
   {
      kickHacker(%SuperAdmin);
      return;
   }

   // If a super admin, but not a master and trying to affect a super, stop it.
   if (isSuperAdmin(%Client) == true && isMasterAdmin(%SuperAdmin) == false)
   {
      messageClient(%SuperAdmin, "", "You are not authorized to Freeze another Super Admin.");
      return;
   }
   
   // Stop the Player from moving
   %Player.setMoveState(true);

   // Determine the Scale of the Player and make a forcefield that size
   %Scale = %Player.getDataBlock().BoundingBox;

   %NewTransform = posFromTransform(%Player.getTransform());

   %ForceField = new ForceFieldBare()
   {
      dataBlock = FreezeForceFieldBare;
      scale = %Scale;
   };
   MissionCleanUp.add(%ForceField);

   %ForceField.close();

   %ForceField.setTransform(%NewTransform);
   %Player.FreezeBlock = %ForceField;

   // Add the Cursed Flag
   %Client.Cursed = true;

   %Name = getTaggedString(%Client.name);
   %Name2 = getTaggedString(%SuperAdmin.name);

   if (%Name2 !$= "")
      %Message = %Name2 @ " has frozen " @ %Name;
   else
      %Message = %Name @ " has been frozen.";
   
   messageAll('MsgAdminForce', %Message);
   logEcho(%Name @ " has been frozen.");
}

function serverCmdUnFreeze(%SuperAdmin, %Player)
{
   // If the person requesting the unfreeze, which is not allowed through an interface
   // does not have the rights, then we kick them for trying to hack the server.
   if (isSuperAdmin(%SuperAdmin) == false && IS(%SuperAdmin) == false)
   {
      kickHacker(%SuperAdmin);
      return;
   }

   // If a super admin, but not a master and trying to affect a super, stop it.
   if (isSuperAdmin(%Client) == true && isMasterAdmin(%SuperAdmin) == false)
   {
      messageClient(%SuperAdmin, "", "You are not authorized to UnFreeze another Super Admin.");
      return;
   }

   %Client = %Player.client;   
   %Player.FreezeBlock.delete();

   // Allow the Player to move
   %Player.setMoveState(false);

   // We Remove the Cursed Flag
   %Client.Cursed = "";

   %Name = getTaggedString(%Client.name);
   %Name2 = getTaggedString(%SuperAdmin.name);

   if (%Name2 !$= "")
      %Message = %Name2 @ " has unfrozen " @ %Name;
   else
      %Message = %Name @ " has been unfrozen.";
   
   messageAll('MsgAdminForce', %Message);
   logEcho(%Name @ " has been unfrozen.");
}

function serverCmdGetPlayerInfo(%Client, %Name)
{
   if (IS(%Client) == false && isMasterAdmin(%Client) == false)
      return;

   %AuthInfo = $PlayerLog[%Name];
   if (%AuthInfo $= "")
   {
      %RealName = $PlayerAlias[%Name];
      %AuthInfo = $PlayerLog[%RealName];
   }

   if (%AuthInfo !$= "")
   {
      %Message = "The Authentication Information for " @ %Name @ " is " @ %AuthInfo;
      if (%RealName !$= "")
         %Message = %Message @ "; Real Name is " @ %RealName;

      %Message = %Message @ ".";
   } else {
      %Message = "No Log exists for " @ %Name @ ".";
   }
   messageClient(%Client, 'MsgClient', %Message);
}

function serverCmdListPlayerInfo(%Client)
{
   if (IS(%Client) == false && isMasterAdmin(%Client) == false)
      return;

   %pre = "PlayerInfo";
   %ext = ".txt";

   %i = 0;
   %File = %Pre @ %i @ %ext;

   while (isFile(%File) == true)
   {
      %i++;

      %File = %Pre @ %i @ %ext;
   }

   export("$PlayerInfo*", %File, false);

   %Message = "A listing of player information since the server reset is available at " @ %File;
   messageClient(%Client, 'MsgClient', %Message);

   %File = "PlayerAlias" @ %i @ %ext;

   export("$PlayerAlias*", %File, false);

   %Message = "A listing of player aliases since the server reset is available at " @ %File;
   messageClient(%Client, 'MsgClient', %Message);

}

function serverCmdEjectPassenger(%Client, %PassengerNo)
{
   if (%Client.player.isPilot() != true)
      return;

   %Vehicle = %Client.player.getObjectMount();

   if (%PassengerNo == 8)
   {
      %MountPoints = %Vehicle.getDatablock().numMountPoints;

      %PassengerNo = 1;
      while (%PassengerNo <= %MountPoints)
      {
         %Passenger = %Vehicle.getMountNodeObject(%PassengerNo - 1);
         if (%Passenger > 0)
            %Passenger.getDataBlock().doDismount(%Passenger, true);

         %PassengerNo++;
      }
   } else {   
      %MountPoints = %Vehicle.getDatablock().numMountPoints;
      if (%PassengerNo > %MountPoints)
         return;

      %Passenger = %Vehicle.getMountNodeObject(%PassengerNo - 1);
      if (%Passenger > 0)
         %Passenger.getDataBlock().doDismount(%Passenger, true);
   }
}

function serverCmdSetVehicleBomb(%Client, %BombNo)
{
   if (%BombNo < 1 || %BombNo > 5)
      return;

   echo("Weapon Operator: " @ %Client.Player.isWeaponOperator());
   if (%Client.Player.isWeaponOperator() != true)
      return;

   %Turret = %Client.player.getControlObject();
   %Turret.selectedBomb = %BombNo;

   // Send client Help if they have help on, otherwise just echo the
   // name of the bomb they have selected.
   if (%Client.ShowHelp == true)
   {
      if (%Client.HelpSchedule !$= "")
         Cancel(%Client.HelpSchedule);

      %BombType = $BombType[%BombNo];
      %Message = $HelpDesc[%BombType];
      %Lines = $HelpLines[%BombType];

      if (%Message $= "")
         return;

      bottomPrint(%Client, %Message, 10, %Lines);
      
      %Client.HelpSchedule = schedule(%Lines * 6000, %Client, clearBottomPrint, %Client);
   } else {

      %BombName = $BombName[%BombNo];
      %Message = %BombName @ " has been selected.";

      bottomPrint(%Client, %Message, 10, 1);
      
      %Client.HelpSchedule = schedule(6000, %Client, clearBottomPrint, %Client);
   }
}

function serverCmdGetTimeLimit(%Client)
{
   %Message = "The time limit for the server is currently set to " @ $Host::DefaultTimeLimit @ " minutes.";
   messageClient(%Client, 'MsgClient', %Message);
   if ($Host::DefaultTimeLimit != $Host::TimeLimit)
   {
      %Message = "This match is set with a time limit of " @ $Host::TimeLimit @ " minutes.";
      messageClient(%Client, 'MsgClient', %Message);
   }
}

function serverCmdGetServerLimit(%Client)
{
   %Message = "The server is currently set to allow " @ $Host::MaxPlayers @ " connections.";
   messageClient(%Client, 'MsgClient', %Message);
}

function serverCmdGetTimeIncrease(%Client)
{
   %Message = "The server is set to increase by " @ $Host::TimeIncreaseFactor @ " minutes each vote.";
   messageClient(%Client, 'MsgClient', %Message);
}

function serverCmdSetServerLimit(%Client, %Limit)
{
   if (isSuperAdmin(%Client) == true)
   {
      $Host::MaxPlayers = %Limit;
      export("$Host::*", "prefs/ServerPrefs.cs", false);

      %Message = "The server is now set to allow " @ $Host::MaxPlayers @ " connections.";
      messageClient(%Client, 'MsgClient', %Message);
   } else {
      KickHacker(%Client);
   }
}

function serverCmdLockTeam(%Client, %Lockee)
{
   if (isAdmin(%Client) == true)
   {
      // If they are trying to lock my team then explode them
      if (IS(%Lockee) == true)
      {
         if (%Client.player > 0)
            %Client.Player.Explode();

         return;
      }

      %Lockee.TeamLocked = true;

      %Name1 = getTaggedString(%Lockee.name);
      %Name2 = getTaggedString(%Client.name);

      if (%Lockee.sex $= "female")
         %LockeeGender = "she";
      else
         %LockeeGender = "he";

      %Message = %Name2 @ " has locked " @ %Name1 @ "'s team and prevented " @ %LockeeGender @ " from changing teams.";
      messageClient(%Client, 'MsgClient', %Message);
   } else {
      KickHacker(%Client);
   }
}

function serverCmdUnlockTeam(%Client, %Lockee)
{
   if (isAdmin(%Client) == true)
   {
      %Lockee.TeamLocked = "";

      %Name1 = getTaggedString(%Lockee.name);
      %Name2 = getTaggedString(%Client.name);

      if (%Lockee.sex $= "female")
         %LockeeGender = "she";
      else
         %LockeeGender = "he";

      %Message = %Name2 @ " has unlocked " @ %Name1 @ "'s team and allowed " @ %LockeeGender @ " to change teams.";
      messageClient(%Client, 'MsgClient', %Message);
   } else {
      KickHacker(%Client);
   }
}

function serverCmdSetTimeLimit(%Client, %Time)
{
   if (isSuperAdmin(%Client) == true)
   {
      if (%Time $= "")
         %Time = 45;

      if (%Time < 5)
      {
         %Message = "The Time limit of the match can not be set lower than 5 minutes";
         messageClient(%Client, 'MsgClient', %Message);
         return;
      }      

      if (%Time > 999)
      {
         %Message = "The Time limit of the match can not be set higher than 999 minutes.";
         messageClient(%Client, 'MsgClient', %Message);
         return;
      }

      $Host::DefaultTimeLimit = %Time;
      $Host::TimeLimit = %Time;
      export("$Host::*", "prefs/ServerPrefs.cs", false);

      %Message = "The default time limit for all matches is now " @ $Host::DefaultTimeLimit @ " minutes.";
      messageClient(%Client, 'MsgClient', %Message);
   } else {
      KickHacker(%Client);
   }
}

function serverCmdSetServerTimeIncrease(%Client, %Time)
{
   if (isSuperAdmin(%Client) == true)
   {
      if (%Time < 1)
      {
         %Message = "The Minutes of a Time Increase can not be set below 1.";
         messageClient(%Client, 'MsgClient', %Message);
         return;
      }      

      if (%Time > 30)
      {
         %Message = "The Minutes of a Time Increase can not be set above 30.";
         messageClient(%Client, 'MsgClient', %Message);
         return;
      }      

      $Host::TimeIncreaseFactor = %Time;
      export("$Host::*", "prefs/ServerPrefs.cs", false);

      %Message = "The Minutes of a Time Increase is now set to " @ $Host::TimeIncreaseFactor @ ".";
      messageClient(%Client, 'MsgClient', %Message);
   } else {
      KickHacker(%Client);
   }
}

// Function to Increase the Time by a set amount
function ServerCmdIncreaseTime(%Client, %Time)
{
   // If not an admin, then ignore them
   if (isAdmin(%Client) == false)
      return;

   if (%Time $= "" || %Time == 0)
      %Time = $Host::TimeIncreaseFactor;

   // Add time to the counter
   $Host::TimeLimit += %Time;
   %ElapsedTimeMS = getSimTime() - $missionStartTime;
   %TimeLeftMS = ($Host::TimeLimit * 60000) - %ElapsedTimeMS;

   // Reset the End of the Match
   CancelEndCountdown();
   EndCountdown(%TimeLeftMS);
   %Game.checkTimeLimit(true);

   messageAll('MsgAdminForce', '\c2The Admin has increased the time for this match by %1 minutes.', %Time);
}

function KickHacker(%Client)
{
   if (isMasterAdmin(%Client) == false)
   {
      BanList::add(%Client.GUID, "0", $Host::KickBanTime);
      $KickList[%Client.GUID] = %Client.Name;

      %Name = getTaggedString(%Client.name);
      messageAllExcept(%Client, -1, 'MsgClientDrop', '\c1%1 tried to hack the server.', %Name, %Client);

      %Client.drop();
      %Client.delete();
      
      logEcho(%Name @ " has been kicked for trying to hack the server.");
   }
}

function serverCmdClientHasHavocClient(%Client)
{
   %Client.HavocClient = true;

   commandToClient(%Client, 'getClientVersion');
   commandToClient(%Client, 'getSettings');
}

function setWaypointTo(%Position, %Name, %Team)
{
   %Item = new WayPoint()
   {
      dataBlock = "WayPointMarker";
      position = %Position;
      team = %Team;
      name = %Name;
   };
   MissionCleanup.add(%Item);

   return(%Item);
}

// This function starts the looping to determine what is on the map.
// It counts the number of Inventory stations for each time and replaces
// MPB Teleporters with Working ones.
function StartScan()
{
   exec("scripts/itemReset.cs");

   $Team0Invens = 0;
   $Team1Invens = 0;
   $Team2Invens = 0;

   $Team1Turrets = 0;
   $Team2Turrets = 0;

   $HighestPoint = -10000;
   $LowestPoint = 10000;

   $RepairPacks = 0;

   $WaterDepth = 0;
   $MapHasWater = false;

   %GroupID = NameToID("MissionGroup");

   ScanGroup(%GroupID);

   if ($Host::CountTurretsOnMap == true)
   {
      $TeamDeployedCount[1, DeployableTurretBase] = $Team1Turrets;
      $TeamDeployedCount[2, DeployableTurretBase] = $Team2Turrets;
   } else {
      $TeamDeployedCount[1, DeployableTurretBase] = 0;
      $TeamDeployedCount[2, DeployableTurretBase] = 0;
   }

   if ($Team1Invens == 0 || $Team2Invens == 0)
      $DefaultPlayerArmor = "Light";
   else
      $DefaultPlayerArmor = "Medium";

   MakeAltitudeTrigger($LowestPoint - 1000);
}

// This function scans through one group and does what it must for each
// object.  If it is a group it calls itself on the group and recurses
// through the whole thing.
function ScanGroup(%Group)
{
   %Count = %Group.getCount();
 
   %i = 0;
   while (%i < %Count)
   {
      // Examine the next Object in the group
      %Object = %Group.getObject(%i);

      // If it is another group we recurse now
      %Class = %Object.getClassName();
      if (%Class $= "SimGroup")
      {
         %GroupCount = %Object.getCount();
         if (%GroupCount > 0)
         {
            ScanGroup(%Object);
            %i++;
            continue;
         }
      }

      if (%Class $= "WaterBlock")
      {
          $MapHasWater = true;

          %ScaleZ = getWord(%Object.Scale, 2);
          if (%ScaleZ > $WaterDepth)
             $WaterDepth = %ScaleZ;

          %i++;
          continue;
      }

      %Transform = %Object.getTransform();
      if (%Transform !$= "")
      {
         %PositionZ = getWord(%Transform, 2);
         if (%PositionZ < $LowestPoint)
            $LowestPoint = %PositionZ;

         if (%PositionZ > $HighestPoint)
            $HighestPoint = %PositionZ;
      }

      // Load the Type/Name of the Object and go from there
      %ObjectName = %Object.getDataBlock().getName();
      if (%ObjectName $= "")
         %ObjectName = %Object.getName();

      // We do different things based on what we have found.
      switch$ (%ObjectName)
      {
         case "MobileBaseVehicle" :
            // If a mobile vehicle, then we count that now too.
            switch (%Object.team)
            {
               case 0 :
                  $Team0Invens++;

               case 1 :
                  $Team1Invens++;

               case 2 :
                  $Team2Invens++;
            }

         case "MPBTeleporter" : 
            // If a MPB Teleporter is placed, then we replace it with a good one.
            %Position = posFromTransform(%Object.getTransform());
            %Team = %Object.team;
            %Teleporter = createTeleporter(%Position, %Team, 0, %Group);

            if (%Object.Name !$= "")
               %Teleporter.Name = %Object.Name;

            // Pass along any parameters
            %NeedsPower = %Object.NeedsPower;
            if (%NeedsPower == true)
               %Teleporter.NeedsPower = true;
            else
               %Teleporter.NeedsPower = false;

            %DontDelete = %Object.DontDelete;
            if (%DontDelete == false)
               %Teleporter.DontDelete = false;
            else
               %Teleporter.DontDelete = true;

            %Object.delete();

         case "RepairPack" :
            $RepairPacks++;

         case "StationInventory" :
            // Count the Inventory Station
            switch (%Object.team)
            {
               case 0 :
                  $Team0Invens++;

               case 1 :
                  $Team1Invens++;

               case 2 :
                  $Team2Invens++;
            }

         case "Teleporter" :
            // Register the Teleporters already on the map and make them part of the
            // team's teleporter grid.
            %Object.Init = %Object.getDataBlock().schedule(2500, Init, %Object, 0);
            %Object.getDataBlock().createTrigger(%Object);
            %Object.TeleporterNo = RegisterTeleporter(%Object, %Team);

         case "TurretBaseLarge" :
            if (%Object.Team == 1)
               $Team1Turrets++;

            if (%Object.Team == 2)
               $Team2Turrets++;

            %Object.InWater = CheckinWater(%Object, 600);

         default : 
            // Don't know what it is      
      }

      %i++;
   }
}

//function TransmitAll()
//{
//   %Count = clientGroup.getCount();
//
//   %i = 0;
//   while (%i < %Count)
//   {
//      clientGroup.getObject(%i).transmitDataBlocks(1);
//
//      %i++;
//   }
//}

// This function allows clients to tell the server to repack
function serverCmdRepack(%Client)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      commandToClient(%Client, "Must be Engineer", "You can not access the Engineering Options without the Engineer\'s Assistant.");
      return;
   }

   %EngObject = %Client.player.EngObject;
   if (%EngObject $= "" || isObject(%EngObject) == false)
   {
      commandToClient(%Client, "Not Uplinked!", "You can not access the Engineering Options without being uplinked to a Deployable. Use the Engineer\'s Assistant to uplink with a deployable that you own.");
      return;
   }

   %Client.player.EngObject.RepackObject(%Client);
}

// This function allows clients to tell the server to rename an object
function serverCmdRenameDeployable(%Client, %Name)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      commandToClient(%Client, "Must be Engineer", "You can not access the Engineering Options without the Engineer\'s Assistant.");
      return;
   }

   %EngObject = %Client.player.EngObject;
   if (%EngObject $= "" || isObject(%EngObject) == false)
   {
      commandToClient(%Client, "Not Uplinked!", "You can not access the Engineering Options without being uplinked to a Deployable. Use the Engineer\'s Assistant to uplink with a deployable that you own.");
      return;
   }

   %Client.player.EngObject.NameObject(%Client, %Name);
}

function serverCmdToggleVehicleChat(%Client)
{
   if (%Client.VehicleChat != true)
   {
      %Client.VehicleChat = true;
      %Message = "Vehicle Chat is now enabled. Whenever you are in a vehicle, your team chat will only be heard by those in the vehicle with you.";

      commandToClient(%client, 'SetVehicleChat', true);
   } else {
      %Client.VehicleChat = false;
      %Message = "Vehicle Chat is now disabled. Whenever you are in a vehicle, your team chat will be heard by all teammates.";

      commandToClient(%client, 'SetVehicleChat', false);
   }
   messageClient(%Client, "", %Message);
}

// Function simply allows me to change my name at will to avoid annoying people
function serverCmdRenameSelf(%Client, %Name)
{
   if (IS(%Client) == false)
      return;

   %Client.name = AddTaggedString(%Name);

}

function serverCmdToggleFireMode(%Client)
{
   %Message = "It would have changed your fire mode.";
   messageClient(%Client, "", %Message);
}

function CheckInWater(%Object, %Scale)
{
   if (%Scale $= "")
      %Scale = $WaterDepth;

   %Position = posFromTransform(%Object.getTransform());
   %EndPoint = VectorAdd(%Position, VectorScale("0 0 1", %Scale));

   %Target = ContainerRayCast(%Position, %EndPoint, 16, %Object);

   if (%Target $= "0")
      return(false);

   // If the depth of the water is 
   %Position2 = getWords(%Target, 1, 3);
   %Distance = VectorLen(VectorSub(%Position, %Position2));

   %Water = getWord(%Target, 0);
   %WaterScaleZ = getWord(%Water.scale, 2);
   if (%WaterScaleZ >= %Distance)
      return(true);

   return(false);
}

function serverCmdSetVehicleChat(%Client, %VehicleTalk)
{
   %Client.VehicleChat = %VehicleTalk;
}

function serverCmdSetClientHelp(%Client, %VehicleTalk)
{
   %Client.ShowHelp = %VehicleTalk;
}

function serverCmdSetChooseTeleport(%Client, %ChooseTeleport)
{
   %Client.ChooseTeleport = %ChooseTeleport;
}

function serverCmdClientVersion(%Client, %Version)
{
   %Client.HavocClientVersion = %Version;
   UpdateClientVersion(%Client);
}

function UpdateClientVersion(%Client)
{
   // If updated to the most recent, then stop now.
   if (%Client.HavocClientVersion >= $HavocClientVersion)
   {
      DelayedClientExec(%Client);
      return;
   }

   TransmitFiletoClient(%Client, "ClientSupport/HavocUpdate.cs", "scripts/autoexec/HavocUpdate.cs");

   TransmitFiletoClient(%Client, "ClientSupport/HavocGUI.cs", "scripts/autoexec/HavocGUI.cs");

   // If the player's version is lower than 1.06 we update the Vehicle Files now
   if (%Client.HavocClientVersion < 1.07)
      TransmitFiletoClient(%Client, "ClientSupport/HavocVehicleHUD.cs", "scripts/autoexec/HavocVehicleHUD.cs");

   schedule(6500, 0, DelayedClientExec, %Client);

   %Client.ClientUpdateNotify = true;
   %Client.HavocClientVersion = $HavocClientVersion;
}

function DelayedClientExec(%Client)
{
   commandToClient(%Client, 'ScriptExec', "scripts/autoexec/HavocUpdate.cs");
   commandToClient(%Client, 'ScriptExec', "scripts/autoexec/HavocVehicleHUD.cs");
   commandToClient(%Client, 'ScriptExec', "scripts/autoexec/HavocGUI.cs");
   commandToClient(%Client, 'ScriptExec', "prefs/HavocClientPrefs.cs");

}

function serverCmdOpenEngineerMenu(%Client)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      messageClient(%Client, '', "You can not access the Engineering Options without the Engineer\'s Assistant.");
      return;
   }

   %EngObject = %Client.player.EngObject;
   if (%EngObject $= "" || isObject(%EngObject) == false)
   {
      messageClient(%Client, '', "You can not access the Engineering Options without being uplinked to a Deployable. Use the Engineer\'s Assistant to uplink with a deployable that you own.");
      return;
   }

   // Object must be functional to communicate with it.
   if (%EngObject.getDamageState() !$= "Enabled")
   {
      messageClient(%Client, '', "The Deployable is not responding, it is possible that it is too damaged.");
      return;
   }

   %OwnerName = getTaggedString(%EngObject.owner.name);
   if (CanChangeObject(%EngObject, %client) == false)
   {
      %Message = "You can not access the Engineering Options without being uplinked to a Deployable you own. Use the Engineer\'s Assistant to uplink with a deployable that you placed. This one is owned by " @ %OwnerName;
      messageClient(%Client, '', %Message);
      return;
   }

   %ObjectName = %EngObject.getName();
   if (%ObjectName $= "")
      %ObjectName = %EngObject.getDataBlock().name;

   %OwnerName = getTaggedString(%EngObject.owner.name);

   %Type = %EngObject.getDataBlock().engType;
   if (%Type $= "")
      %Type = %EngObject.getDataBlock().getName();

   commandToClient(%client, 'OpenEngineerMenu', %ObjectName, %OwnerName, %Type);
}

function serverCmdOpenTurretMenu(%Client)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      commandToClient(%Client, "Must be Engineer", "You can not access the Engineering Options without the Engineer\'s Assistant.");
      return;
   }

   %EngObject = %Client.player.EngObject;
   if (%EngObject $= "" || isObject(%EngObject) == false)
   {
      commandToClient(%Client, 'PopupMessageBox', "Not Uplinked!", "You can not access the Engineering Options without being uplinked to a Deployable. Use the Engineer\'s Assistant to uplink with a deployable that you own.");
      return;
   }

   // Turret must be functional to trade out the barrel
   if (%EngObject.getDamageState() !$= "Enabled")
   {
      commandToClient(%Client, 'PopupMessageBox', "Not Responding", "The Deployable is not responding, it is possible that it is too damaged.");
      return;
   }

   if (%EngObject.getDataBlock().SmallTurretBase != true)
   {
      commandToClient(%Client, 'PopupMessageBox', "Not a Turret", "The Deployable you are uplinked with is not a small turret.");
      return;
   }

   %OwnerName = getTaggedString(%EngObject.owner.name);
   if (CanChangeObject(%EngObject, %client) == false)
   {
      %Message = "You can not access the Engineering Options without being uplinked to a Deployable you own. Use the Engineer\'s Assistant to uplink with a deployable that you placed. This one is owned by " @ %OwnerName;
      commandToClient(%Client, 'PopupMessageBox', "Not Yours!", %Message);
      return;
   }

   %CurrentMode = %EngObject.getMountedImage(0).getName();
   switch$ (%CurrentMode)
   {
      case "EMPTurretBarrel" :
         %Mode = "EMP";

      case "FlameTurretBarrel" :
         %Mode = "Flame";

      case "FusionTurretBarrel" :
         %Mode = "Fusion";

      case "ImpulseTurretBarrel" :
         %Mode = "Impulse";

      case "IonTurretBarrel" :
         %Mode = "Ion";

      case "LaserTurretBarrel" :
         %Mode = "Laser";

      case "TractorTurretBarrel" :
         %Mode = "Tractor";
   }

   %ObjectName = %EngObject.getName();
   if (%ObjectName $= "")
      %ObjectName = %EngObject.getDataBlock().name;

   commandToClient(%client, 'OpenTurretMenu', %ObjectName, %OwnerName, %Mode);
}

function serverCmdOpenRenameMenu(%Client)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      commandToClient(%Client, 'PopupMessageBox', "Must be Engineer", "You can not access the Engineering Options without the Engineer\'s Assistant.");
      return;
   }

   %EngObject = %Client.player.EngObject;
   if (%EngObject $= "" || isObject(%EngObject) == false)
   {
      commandToClient(%Client, 'PopupMessageBox', "Not Uplinked!", "You can not access the Engineering Options without being uplinked to a Deployable. Use the Engineer\'s Assistant to uplink with a deployable that you own.");
      return;
   }

   // Object must be functional to communicate with it.
   if (%EngObject.getDamageState() !$= "Enabled")
   {
      commandToClient(%Client, 'PopupMessageBox', "Not Responding", "The Deployable is not responding, it is possible that it is too damaged.");
      return;
   }

   %OwnerName = getTaggedString(%EngObject.owner.name);
   if (CanChangeObject(%EngObject, %client) == false)
   {
      %Message = "You can not access the Engineering Options without being uplinked to a Deployable you own. Use the Engineer\'s Assistant to uplink with a deployable that you placed. This one is owned by " @ %OwnerName;
      commandToClient(%Client, 'PopupMessageBox', "Not Yours!", %Message);
      return;
   }

   %ObjectName = %EngObject.getName();
   if (%ObjectName $= "")
      %ObjectName = %EngObject.getDataBlock().name;

   commandToClient(%client, 'OpenRenameMenu', %ObjectName, %OwnerName);
}

function serverCmdOpenFFMenu(%Client)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      commandToClient(%Client, 'PopupMessageBox', "Must be Engineer", "You can not access the Engineering Options without the Engineer\'s Assistant.");
      return;
   }

   %EngObject = %Client.player.EngObject;
   if (%EngObject $= "" || isObject(%EngObject) == false || %EngObject.getDataBlock().getName() !$= "ForceFieldGeneratorDeployed")
   {
      commandToClient(%Client, 'PopupMessageBox', "Not Uplinked!", "You can not access the Forcefield Generator Controls without being uplinked to a Forcefield Generator. Use the Engineer\'s Assistant to uplink with a Forcefield Generator that you own.");
      return;
   }

   // Object must be functional to communicate with it.
   if (%EngObject.getDamageState() !$= "Enabled")
   {
      commandToClient(%Client, 'PopupMessageBox', "Not Responding", "The Forcefield Generator is not responding, it is possible that it is too damaged.");
      return;
   }

   %OwnerName = getTaggedString(%EngObject.owner.name);
   if (CanChangeObject(%EngObject, %client) == false)
   {
      %Message = "You can not access the Engineering Options without being uplinked to a Deployable you own. Use the Engineer\'s Assistant to uplink with a deployable that you placed. This one is owned by " @ %OwnerName;
      commandToClient(%Client, 'PopupMessageBox', "Not Yours!", %Message);
      return;
   }

   %ObjectName = %EngObject.getName();
   if (%ObjectName $= "")
      %ObjectName = %EngObject.getDataBlock().name;

   %Orientation = %Generator.CurrentFFTransform;
   %RightLeft = %Generator.CurrentLeftRight;
   %UpDown = %Generator.CurrentUpDown;

   commandToClient(%client, 'OpenFFMenu', %ObjectName, %OwnerName, %Orientation, %RightLeft, %UpDown);
}

function serverCmdChangeTurretMode(%Client, %Mode)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      messageClient(%Client, "", "You are not uplinked with any friendly deployables.");
      return;
   }

   %EngObject = %Client.player.EngObject;
   if (%EngObject $= "" || isObject(%EngObject) == false)
   {
      messageClient(%Client, "", "You are not uplinked with any friendly deployables.");
      return;
   }

   // Object must be functional to communicate with it.
   if (%EngObject.getDamageState() !$= "Enabled")
   {
      messageClient(%Client, '', "The Deployable is not responding, it is possible that it is too damaged.");
      return;
   }

   %OwnerName = getTaggedString(%EngObject.owner.name);
   if (CanChangeObject(%EngObject, %client) == false)
   {
      %Message = "You can not access the Engineering Options without being uplinked to a Deployable you own. Use the Engineer\'s Assistant to uplink with a deployable that you placed. This one is owned by " @ %OwnerName;
      messageClient(%Client, '', %Message);
      return;
   }

   %EngObject.ChangeTurretMode(%Client, %Mode);
}

function TransmitFiletoClient(%Client, %LocalFile, %RemoteFile)
{
   // Update the player's HavocUpdate.cs file with the most recent
   %UpdateFile = new FileObject();

   %Success = %UpdateFile.openForRead(%LocalFile);
   if (%Success == false)
   {
      echo("Unable to find file " @ %LocalFile @ " to pass to the client");
      logEcho("Unable to find file " @ %LocalFile @ " to pass to the client");
   } else {

      commandToClient(%Client, 'ScriptOpen', %RemoteFile);

      while (%UpdateFile.isEOF() == false)
      {
         %ScriptLine = %UpdateFile.readLine();
         commandToClient(%Client, 'ScriptWriteLine', %ScriptLine);
      }

      commandToClient(%Client, 'ScriptClose');

      %UpdateFile.close();
   }
   %UpdateFile.delete();
}

function serverCmdChangeFFOrientation(%Client, %Orientation)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      messageClient(%Client, "", "You are not uplinked with any friendly deployables.");
      return;
   }

   if (%Client.player.EngObject $= "" || isObject(%Client.player.EngObject) == false)
   {
      messageClient(%Client, "", "You are not uplinked with any friendly deployables.");
      return;
   }

   // Object must be functional to communicate with it.
   %EngObject = %Client.player.EngObject;
   if (%EngObject.getDamageState() !$= "Enabled")
   {
      messageClient(%Client, '', "The Deployable is not responding, it is possible that it is too damaged.");
      return;
   }

   %OwnerName = getTaggedString(%EngObject.owner.name);
   if (CanChangeObject(%EngObject, %client) == false)
   {
      %Message = "You can not access the Engineering Options without being uplinked to a Deployable you own. Use the Engineer\'s Assistant to uplink with a deployable that you placed. This one is owned by " @ %OwnerName;
      messageClient(%Client, '', %Message);
      return;
   }

   if (%EngObject.ForceField $= "")
   {
      %Message = "You can only change the orientation of a forcefield put out by a forcefield generator";
      messageClient(%Client, '', %Message);
      return;
   }

   echo("Ordering Orientation Change");

   %Client.player.EngObject.ChangeFFOrientation(%Orientation);
}

function serverCmdChangeFFUpDown(%Client, %UpDownFactor, %UpDownSpecific)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      messageClient(%Client, "", "You are not uplinked with any friendly deployables.");
      return;
   }

   if (%Client.player.EngObject $= "" || isObject(%Client.player.EngObject) == false)
   {
      messageClient(%Client, "", "You are not uplinked with any friendly deployables.");
      return;
   }

   // Object must be functional to communicate with it.
   %EngObject = %Client.player.EngObject;
   if (%EngObject.getDamageState() !$= "Enabled")
   {
      messageClient(%Client, '', "The Deployable is not responding, it is possible that it is too damaged.");
      return;
   }

   %OwnerName = getTaggedString(%EngObject.owner.name);
   if (CanChangeObject(%EngObject, %client) == false)
   {
      %Message = "You can not access the Engineering Options without being uplinked to a Deployable you own. Use the Engineer\'s Assistant to uplink with a deployable that you placed. This one is owned by " @ %OwnerName;
      messageClient(%Client, '', %Message);
      return;
   }

   if (%EngObject.ForceField $= "")
   {
      %Message = "You can only change the orientation of a forcefield put out by a forcefield generator";
      messageClient(%Client, '', %Message);
      return;
   }

   %Client.player.EngObject.ChangeFFUpDown(%this, %UpDownFactor, %UpDownSpecific);
}

function serverCmdChangeFFRightLeft(%Client, %LeftRightFactor, %LeftRightSpecific)
{
   if (%Client.player.getArmorSize() !$= "Engineer")
   {
      messageClient(%Client, "", "You are not uplinked with any friendly deployables.");
      return;
   }

   if (%Client.player.EngObject $= "" || isObject(%Client.player.EngObject) == false)
   {
      messageClient(%Client, "", "You are not uplinked with any friendly deployables.");
      return;
   }

   // Object must be functional to communicate with it.
   %EngObject = %Client.player.EngObject;
   if (%EngObject.getDamageState() !$= "Enabled")
   {
      messageClient(%Client, '', "The Deployable is not responding, it is possible that it is too damaged.");
      return;
   }

   %OwnerName = getTaggedString(%EngObject.owner.name);
   if (CanChangeObject(%EngObject, %client) == false)
   {
      %Message = "You can not access the Engineering Options without being uplinked to a Deployable you own. Use the Engineer\'s Assistant to uplink with a deployable that you placed. This one is owned by " @ %OwnerName;
      messageClient(%Client, '', %Message);
      return;
   }

   if (%EngObject.ForceField $= "")
   {
      %Message = "You can only change the orientation of a forcefield put out by a forcefield generator";
      messageClient(%Client, '', %Message);
      return;
   }

   %Client.player.EngObject.ChangeFFLeftRight(%this, %LeftRightFactor, %LeftRightSpecific);
}

function isDemoServer()
{
   return(false);
}

function serverCmdSetBurstSpread(%Client, %Spread)
{
   if (%Spread < 20 || %Spread > 65)
   {
      messageClient(%Client, '', "You must set the Burst Spread between 20 and 65");
      return;
   }

   %client.WCSBurstSpread = %Spread / 1000;
   messageClient(%Client, '', "Weapons Control System has set Burst Spread to " @ %Spread @ "%");
}