// duel arena game mode


if (!$gameModeAdded["DuelArena"])
{
$gameModeAdded["DuelArena"] = true;
$gameModeName[$nGameMode] = "DuelArena";
$gameModePrintName[$nGameMode] = "Duel Arena";
$gameModePrintInServerList[$nGameMode] = true;
$nGameMode ++;
}



$preDuelCountdown = 2500;
$postRoundCountdown = 1500;
$getInFightCountdown = 2500;
$postDuelCountDown = 6000;
$postDuelLeaderboardCountdown = 5000;

////////////////////////////////////////////////////////////////////////////////
// initialisation stuff

// called when the server loads the map
function DuelArena::ServerStarted(%this)
{

   if ($debugMissionLoad)
      echo("GMServerStarted DuelArena");

   $GMMissionArea = MissionArea;

   $gameModePrintText = "";

   $clientPrintText = "";

   $warnCloseOOB = true;

   
   $fightInfo.needSightForTarget = false;
   $fightInfo.isDuelArena = true;

   
   $nDuels = 0;

   $nextDuelID = 0;


   $lastDuelName1 = "-";
   $lastDuelName2 = "-";
   $lastDuelVictor = "-";
   $lastDuelBreakdown = "-";


     


   $roundTimeGameOption = 0;
   $handicapAllowedGameOption = 1;
   $arenaSizeGameOption = 2;
   $roundsPerDuelGameOption = 3;

   


   

   $gameModeOptions.name[0] = "Round Time";
   $gameModeOptions.value[0] = $Pref::Server::daRoundTime;
   $gameModeOptions.choice[0,0] = "10";
   $gameModeOptions.choice[0,1] = "30";
   $gameModeOptions.choice[0,2] = "45";
   $gameModeOptions.choice[0,3] = "60";
   $gameModeOptions.choice[0,4] = "75";
   $gameModeOptions.choice[0,5] = "90";
   $gameModeOptions.choice[0,6] = "Unlimited";

   $gameModeOptions.name[1] = "Handicaps Allowed";
   $gameModeOptions.value[1] = $Pref::Server::daHandicapAllowed;
   $gameModeOptions.choice[1,0] = "yes";
   $gameModeOptions.choice[1,1] = "no";

   $gameModeOptions.name[2] = "Arena Size";
   $gameModeOptions.value[2] = $Pref::Server::daArenaSize;
   $gameModeOptions.choice[2,0] = "40";
   $gameModeOptions.choice[2,1] = "90";
   $gameModeOptions.choice[2,2] = "120";
   $gameModeOptions.choice[2,3] = "150";
   $gameModeOptions.choice[2,4] = "200";
   $gameModeOptions.choice[2,5] = "None";

   $gameModeOptions.name[3] = "Rounds Per Duel";
   $gameModeOptions.value[3] = $Pref::Server::daRoundsPerDuel;
   $gameModeOptions.choice[3,0] = "1";
   $gameModeOptions.choice[3,1] = "3";
   $gameModeOptions.choice[3,2] = "5";
   $gameModeOptions.choice[3,3] = "7";
   $gameModeOptions.choice[3,4] = "9";
   
   setWeaponsListOn($Pref::Server::daDefaultWeaponList, $Pref::Server::daWeaponLists);

}




function lookForPossibleDuels()
{
   error("look for possible duels");

   %nWaitingClients = 0;

   for (%i = 0; %i < ClientGroup.getCount(); %i ++)
   {
      %o = ClientGroup.getObject(%i);

      error("client " @ %o SPC %o.isABot SPC %o.name);

      if (!%o.inFight && %o.isAwaitingDuel && !%o.postDuelDeadTime && !%o.beingKicked)
      {
         %wc[%nWaitingClients] = %o;
         %nWaitingClients ++;


         //error("lfpd: client " @ %o @ " waiting since " @ %o.lastDuelTime);
      }
   }


   if (%nWaitingClients == 0)
      return;
   else if (%nWaitingClients == 1)
   {
      messageClient(%wc[0], 'beep', 'There are no available players right now, please wait for a duel to finish.');

      return;
   }
   else if (%nWaitingClients == 2)
   {
      arrangeDuel(%wc[0], %wc[1]);
   }
   else
   {
      %min = 0;
      %minTime = %wc[0].lastDuelTime;

      for (%i = 1; %i < %nWaitingClients; %i ++)
      {
         if (%wc[%i].lastDuelTime < %minTime)
         {
            %minTime = %wc[%i].lastDuelTime; 
            %min = %i;
         }     
      }

      %wc[%min] = %wc[%nWaitingClients - 1];
      %nWaitingClients --;
      
      %c1 = %min;
      
      %min = 0;
      %minTime = %wc[0].lastDuelTime;

      for (%i = 1; %i < %nWaitingClients; %i ++)
      {
         if (%wc[%i].lastDuelTime < %minTime)
         {
            %minTime = %wc[%i].lastDuelTime; 
            %min = %i;
         }     
      }

      %c2 = %min;

      arrangeDuel(%wc[%c1], %wc[%c2]);

      lookForPossibleDuels();
   }
}


function arrangeDuel(%client1, %client2)
{
   %duelID = $nextDuelID;

   $duelIsOn[%duelID] = true;

   $nDuels ++;
   $nextDuelID ++;

   $preDuelDeadTime[%duelID] = true;
   $postRoundDeadTime[%duelID] = false;

   %client1.duelingWith = %client2;
   %client2.duelingWith = %client1;

   $duelClient1[%duelID] = %client1;
   $duelClient2[%duelID] = %client2;

   %client1.duelID = %duelID;
   %client2.duelID = %duelID;



   // highly unlikely 200 duels would start before one has finished
   if ($nextDuelID > 200)
      $nextDuelID = 0;

   changeClientAwaitingStatus(%client1, false, false);
   changeClientAwaitingStatus(%client2, false, false);

   %client1.duelStatus = "duelling " @ %client2.name;
   %client2.duelStatus = "duelling " @ %client1.name;

   sendDAClientInfo(%client1);
   sendDAClientInfo(%client2);

   serverCmdstopDAObserving(%client1);
   serverCmdstopDAObserving(%client2);

   preDuelStage1(%client1, %client2, %duelID);

}


// stage 1: show the pre duel screens

function preDuelStage1(%client1, %client2, %duelID)
{
   if (!$duelIsOn[%duelID])
      return;

   %pdTime = $preDuelCountdown;

   doClientPreDuelScreen(%client1, %client2);
   doClientPreDuelScreen(%client2, %client1);
   //messageClient(%client1, 'showPreDuelScreen', '', %pdTime + $getInFightCountdown, %client2);
   //messageClient(%client2, 'showPreDuelScreen', '', %pdTime + $getInFightCountdown, %client1);

   schedule(%pdTime, 0, "preDuelStage2", %client1, %client2, %duelID);
}


function doClientPreDuelScreen(%client, %client2)
{
   commandToClient(%client, 'ShowPreDuelStage', 0, %client2.name, 300);
   schedule(1500, 0, "commandToClient", %client, 'ShowPreDuelStage', 1, "", 300);
   schedule(3000, 0, "commandToClient", %client, 'ShowPreDuelStage', 2, "", 300);
}


// stage 2: actually start the duel


function preDuelStage2(%client1, %client2, %duelID)
{
   arrangeDuelStage2(%client1, %client2, %duelID);
}



function arrangeDuelStage2(%client1, %client2, %duelID)
{
   if (!$duelIsOn[%duelID])
      return;

   //error("Arranging duel between: " @ %client1 SPC %client2);

   



   


   $roundNumber[%duelID] = 0;
   $postRoundDeadTime[%duelID] = false;

   %client1.roundWins = 0;
   %client1.roundLosses = 0;

   %client2.roundWins = 0;
   %client2.roundLosses = 0;
   


   $duelSpace[%duelID] = findAndUseFreeDuelSpace();


   %client1.roundBreakdown = "";
   %client2.roundBreakdown = "";


   ///////////////////////
   // lets start the action

   startRound(%client1, %client2, %duelID);



}



function startRound(%client1, %client2, %duelID)
{
   if (!$duelIsOn[%duelID])
      return;

   //error("startRound: " @ %client1 SPC %client2 SPC %duelID);


   $preDuelDeadTime[%duelID] = false;

   ////////////////////////////////////////////////////////////////
   // get random start location

   %x = getRandom() * 2048 - 1024;
   %y = getRandom() * 2048 - 1024;


   // get a unique location for the duel

   %x += 4096 * $duelSpace[%duelID];






   
   %x2 = %x + 30;

   %y2 = %y + 30;

   %z = getTerrainOrWaterHeight(%x SPC %y) + 20;

   %z2 = getTerrainOrWaterHeight(%x2 SPC %y2) + 20;

   if (%z > %z2)
      %z2 = %z;
   else
      %z = %z2;

   
   
   //////////////////////////////////////////////////
   // get duel limits

   if ($gameModeOptions.value[$arenaSizeGameOption] !$= "none")
   {
      $fightInfo.arenaGame = true;

      %areaStart = (%x - $gameModeOptions.value[$arenaSizeGameOption] * 0.5) SPC (%y - $gameModeOptions.value[$arenaSizeGameOption] * 0.5) SPC (%z - 500);
      %areaExtent = $gameModeOptions.value[$arenaSizeGameOption] + 30 SPC $gameModeOptions.value[$arenaSizeGameOption] + 30 SPC "560";


      %newLZ = getMinBoundsZ(%areaStart, %areaExtent);

      %z = %newLZ;
      %z2 = %newLZ;


      %areaStart = (%x - $gameModeOptions.value[$arenaSizeGameOption] * 0.5) SPC (%y - $gameModeOptions.value[$arenaSizeGameOption] * 0.5) SPC (%newLZ - 500);
      %areaExtent = $gameModeOptions.value[$arenaSizeGameOption] + 30  SPC $gameModeOptions.value[$arenaSizeGameOption] + 30  SPC "560";

      error("Arena: " @ %areaStart SPC ", " SPC %areaExtent);
   }
   else
   {
      $fightInfo.arenaGame = false;
   }

   

   //////////////////////////////////////////////////

   
   %c1w = %client1.joinRightWeap;
   %c2w = %client2.joinRightWeap;

   %client1.setCameraObject(%client1.camera);
   %client2.setCameraObject(%client1.camera);

   if (!%client1.isABot)
   {
      %client1.futurePlayer = createPlayerFor(%client1, %client1.joinCharacter, -1, %c1w);
      //dtJoinFight(%client1, %client1.joinCharacter, -1, 0, 0, %c1w, %x SPC %y SPC %z);
   }
   else
   {
      %client1.futurePlayer = createPlayerFor(%client1, %client1.joinCharacter, "fakeGarnetPro", %c1w);
      //dtJoinFight(%client1, %client1.joinCharacter, "fakeGarnetPro", 0, 0, %c1w, %x SPC %y SPC %z);
   }


   if (!%client2.isABot)
   {
      %client2.futurePlayer = createPlayerFor(%client2, %client2.joinCharacter, -1, %c2w);
      //dtJoinFight(%client2, %client2.joinCharacter, -1, 1, 0, %c2w, %x2 SPC %y2 SPC %z2);
   }
   else
   {
      %client2.futurePlayer = createPlayerFor(%client2, %client2.joinCharacter, "fakeGarnetPro", %c2w);
      //dtJoinFight(%client2, %client2.joinCharacter, "fakeGarnetPro", 1, 0, %c2w, %x2 SPC %y2 SPC %z2);
   }


   %client1.futurePlayer.setTransform(%x SPC %y SPC %z);
   %client2.futurePlayer.setTransform(%x2 SPC %y2 SPC %z2);

   

   ////////////////////////////////////////////////
   // 

   if ($gameModeOptions.value[$arenaSizeGameOption] !$= "none")
   {
      %client1.futurePlayer.setMissionArea(%areaStart, %areaExtent);
      %client2.futurePlayer.setMissionArea(%areaStart, %areaExtent);
   }

   if ($gameModeOptions.value[$handicapAllowedGameOption] $= "yes")
   {
      %client1.futurePlayer.applyDamage(%client1.handicap);
      %client2.futurePlayer.applyDamage(%client2.handicap);
   }

   deleteArena(%client1, %client2, %duelID);

   if ($gameModeOptions.value[$arenaSizeGameOption] !$= "none")
      drawArenaBounds(%areaStart, %areaExtent, %client1.futurePlayer, %client2.futurePlayer, %duelID);


   //error("players: " SPC %client1.futurePlayer SPC %client2.futurePlayer SPC "sent mission area of " @ %areaStart SPC %areaExtent);

   %client1.futurePlayer.instantTurn = true;
   %client2.futurePlayer.instantTurn = true;

   //%client1.wapCam.setPlayerObject(%client1.futurePlayer);
   //%client2.wapCam.setPlayerObject(%client2.futurePlayer);

   schedule(1000, 0, "targetEachOther", %client1, %client2);


   schedule($getInFightCountdown, 0, "startRoundStage2", %client1, %client2, %duelID);
}



function startRoundStage2(%client1, %client2, %duelID)
{
   if (!$duelIsOn[%duelID])
      return;

   if ($gameModeOptions.value[$roundTimeGameOption] !$= "unlimited")
   {
      %duelDuration = $gameModeOptions.value[$roundTimeGameOption] * 1000;

      commandToClient(%client1, 'SetTimer', %duelDuration);
      commandToClient(%client2, 'SetTimer', %duelDuration);

      cancel($duelEndSchedule[%duelID]);

      $duelEndSchedule[%duelID] = schedule(%duelDuration + 1000, 0, "duelTimeout", %duelID);
   }
   else
   {
      commandToClient(%client1, 'SetTimer', -1);
      commandToClient(%client2, 'SetTimer', -1);
   }

   
   $postRoundDeadTime[%duelID] = false;


   %client1.setCameraObject(%client1.wapCam);
   %client2.setCameraObject(%client1.wapCam);

   messageClient(%client1, 'hideDuelArenaContent', '', 0);
   messageClient(%client2, 'hideDuelArenaContent', '', 0);

   if (!%client1.isABot)
   {
      dtJoinFight(%client1, %client1.joinCharacter, -1, 0, 0, %c1w, 0, %client1.futurePlayer);
   }
   else
   {
      dtJoinFight(%client1, %client1.joinCharacter, "fakeGarnetPro", 0, 0, %c1w, 0, %client1.futurePlayer);
   }


   if (!%client2.isABot)
   {
      dtJoinFight(%client2, %client2.joinCharacter, -1, 1, 0, %c2w, 0, %client2.futurePlayer);
   }
   else
   {
      dtJoinFight(%client2, %client2.joinCharacter, "fakeGarnetPro", 1, 0, %c2w, 0, %client2.futurePlayer);
   }

   %client1.futurePlayer.instantTurn = false;
   %client2.futurePlayer.instantTurn = false;

   setScopeFlags(%client1.futurePlayer);
   setScopeFlags(%client2.futurePlayer);

   obsClientEnteringRound(%client1);
   obsClientEnteringRound(%client2);
}



function targetEachOther(%client1, %client2)
{
   %client1.futurePlayer.setTargetObject(%client2.futurePlayer);
   %client2.futurePlayer.setTargetObject(%client1.futurePlayer);
}



function findAndUseFreeDuelSpace()
{
   %i = 0;

   while (%i < 50)
   {
      if (!$duelSpaceBeingUsed[%i])
      {
         $duelSpaceBeingUsed[%i] = true;
         return %i;
      }


      %i ++;
   }


   //error("findAndUseFreeDuelSpace: no free spaces found!  Shouldn't happen!");

   return -1;
}


function freeDuelSpace(%id)
{
   $duelSpaceBeingUsed[%id] = false;

}








function endRound(%winner, %loser, %timeOut, %draw, %drop)
{
   if ($debugNoRoundEnd)
      return;

   clearScopeFlags(%winner);
   clearScopeFlags(%loser);


   %duelID = %winner.client.duelID;

   error("endRound: %w %l %id %ison" SPC %winner SPC %loser SPC %duelID SPC $duelIsOn[%duelID] SPC %draw SPC %drop);

   if ($duelIsOn[%duelID] && !$postRoundDeadTime[%duelID])
   {
         if (%timeout)
         {
            %winner.client.lastBlow = "Time out";
            %loser.client.lastBlow = "Time out";
         }
         else if (%drop)
         {
            %winner.client.lastBlow = "Drop";
            %loser.client.lastBlow = "Drop";
         }


         $postRoundDeadTime[%duelID] = true;

         // must be done after postRoundDeadTime = true

         if (%winner.isAlive())
         {
            dtOnDeath(%winner, false);
         }
      
         if (%loser.isAlive() && !%drop)
         {
            %loser.setDamageLevel(110);
         }


         commandToClient(%loser.client, 'SetTimer', -1);
         commandToClient(%winner.client, 'SetTimer', -1);


         if (!%draw)
         {
            %winner.client.roundWins ++;
            %loser.client.roundLosses ++;

            %winner.client.roundBreakdown = %winner.client.roundBreakdown @ "W ";
            %loser.client.roundBreakdown = %loser.client.roundBreakdown @ "L ";
         }
         else
         {
            %winner.client.roundBreakdown = %winner.client.roundBreakdown @ "D ";
            %loser.client.roundBreakdown = %loser.client.roundBreakdown @ "D "; 
         }

         
      
         %winnerWonDuel = (%winner.client.roundWins > ($gameModeOptions.value[$roundsPerDuelGameOption] / 2));
         %loserWonDuel = (%loser.client.roundWins > ($gameModeOptions.value[$roundsPerDuelGameOption] / 2));

         
         obsClientLeavingRound(%winner.client);
         obsClientLeavingRound(%loser.client);

         //error("endRound2: " SPC %winnerWonDuel SPC %winner.client.roundWins SPC $gameModeOptions.value[$roundsPerDuelGameOption] SPC %loserWonDuel SPC %loser.client.roundWins SPC %winner.client.lastBlow SPC %lose.client.lastBlow);


         if (%winnerWonDuel || %loserWonDuel)
         {
            // duel ended

            schedule(2000, 0, "deleteArena", %winner.client, %loser.client, %duelID);

            if (%winnerWonDuel)
               endDuel(%winner.client, %loser.client, %duelID);
            else
               endDuel(%loser.client, %winner.client, %duelID);
         }
         else
         {
            // next round

            $roundNumber[%duelID] ++;

            %brTime = $postRoundCountdown;

            
            doBetweenRoundScreen(%winner.client, true, %draw, %duelID, %timeOut);
            doBetweenRoundScreen(%loser.client, false, %draw, %duelID, %timeOut);
         
            //messageClient(%winner.client, 'showBetweenRoundScreen', '', %brTime + $getInFightCountdown, true, %winner.client.roundWins, %winner.client.roundLosses, %loser.client.lastBlow, %draw);
            //messageClient(%loser.client, 'showBetweenRoundScreen', '', %brTime + $getInFightCountdown , false, %loser.client.roundWins, %loser.client.roundLosses, %loser.client.lastBlow, %draw);
           

            schedule(%brTime, 0, "startRound", %winner.client, %loser.client, %duelID);
         }   
  
   }
}



function doBetweenRoundScreen(%client, %won, %draw, %duelID, %timeOut)
{
   if (%timeOut && %draw)
      %initStage = 7;
   else if (%timeOut && %won)
      %initStage = 5;
   else if (%timeOut)
      %initStage = 6;
   else if (%draw)
      %initStage = 0;
   else if (%won)
      %initStage = 1;
   else
      %initStage = 2;

   %roundN = $roundNumber[%duelID] + 1;

   commandToClient(%client, 'ShowBetweenRoundsStage', %initStage, %roundN, 300);
   schedule(2000, 0, "commandToClient", %client, 'ShowBetweenRoundsStage', 3, %roundN, 300);
   schedule(3500, 0, "commandToClient", %client, 'ShowBetweenRoundsStage', 4, %roundN, 300);
}

function endDuel(%winner, %loser, %duelID)
{
   reportDAResult(%winner, %loser, %winner.roundBreakdown);


   %winner.duels ++;
   %loser.duels ++;

   %winner.wins ++;
   %loser.losses ++;

   duelChangeScore(%loser);
   duelChangeScore(%winner);

   
      
   
      
   
   %loser.lastDuelTime = getSimTime();
   // we give priority of next duel to the winner
   %winner.lastDuelTime = getSimTime() - 10;
   

   


   freeDuelSpace($duelSpace[%duelID]);

   //////////////////////////////////////////////////////

   %winner.lastOpponentName = %loser.name;
   %winner.lastOpponentVictorious = "Won";
   %winner.lastDuelBreakdown = %winner.roundBreakdown;
   %winner.duelStatus = "Awaiting Duel";

   sendDAClientInfo(%winner);

   //////////////////////////////////////////////////////

   %loser.lastOpponentName = %winner.name;
   %loser.lastOpponentVictorious = "Lost";
   %loser.lastDuelBreakdown = %loser.roundBreakdown;
   %loser.duelStatus = "Awaiting Duel";

   sendDAClientInfo(%loser);


   /////////////////////////////////////////////////////////

   postDuelStage1(%loser);

   postDuelStage1(%winner);



   //////////////////////////////////////////////////////

   $lastDuelName1 = %winner.name;
   $lastDuelName2 = %loser.name;
   $lastDuelVictor = %winner.name;
   $lastDuelBreakdown = %winner.roundBreakdown;

   sendAllLastDuelInfo();
   
   //////////////////////////////////////////////////////

   cancel($duelEndSchedule[%duelID]);
   $duelIsOn[%duelID] = false;
   $nDuels --;



   if ($singlePlayer && $spProgression)
   {
      if (%winner == $me)
         $lastSpDidIWin = true;
      else
         $lastSpDidIWin = false;
   }  
}



// stage 1: we show the end duel screen on the client for x seconds

function postDuelStage1(%client)
{
   %client.postDuelDeadTime = true;

   changeClientAwaitingStatus(%client, true, false);

   %edsTime = $postDuelCountDown;

   //messageClient(%client, 'showPostDuelScreen', '', %edsTime, %client.lastBlow, %client.lastOpponentVictorious, %client.lastDuelBreakdown);
   doPostDuel(%client);


   schedule(%edsTime, 0, "postDuelStage2", %client);
}

function doPostDuel(%client)
{
   if (%client.roundWins > ($gameModeOptions.value[$roundsPerDuelGameOption] / 2))
   {
      %winner = %client.name;
      %loser = %client.lastOpponentName;
      %initStage = 0;
   }
   else
   {
      %winner = %client.lastOpponentName;
      %loser = %client.name;
      %initStage = 1;
   }
   

   commandToClient(%client, 'ShowEndDuelStage', %initStage, %winner, %loser, %client.lastDuelBreakdown, 300);
   schedule(2000, 0, "commandToClient", %client, 'ShowEndDuelStage', 2, "", "", "", 300);
}


// stage 2: we now show the main leaderboard on the client, but don't arrange a duel for x seconds

function postDuelStage2(%client)
{
   %msTime = $postDuelLeaderboardCountdown;

   messageClient(%client, 'showLeaderboardScreen', '', %msTime);

   schedule(%msTime, 0, "postDuelStage3", %client);
}


// stage 3: we're now ready to start duelling again

function postDuelStage3(%client)
{
   %client.postDuelDeadTime = false;

   

   lookForPossibleDuels();
}



function changeClientAwaitingStatus(%client, %status, %inform)
{
   if (!%client)
      return;

   %client.isAwaitingDuel = %status;

   if (%inform)
   {
      if (%status)
         %client.duelStatus = "Awaiting Duel";
      else
         %client.duelStatus = "Sitting Out";

      sendDAClientInfo(%client);

      commandToClient(%client, 'setAwaiting', %status);
   }

   if (%status)
      lookForPossibleDuels();
}



function duelTimeout(%duelID)
{
   if ($duelIsOn[%duelID] && !$postRoundDeadTime[%duelID])
   {
      %client1 = $duelClient1[%duelID];
      %client2 = $duelClient2[%duelID];

      
         if (%client1.player.getDamageLevel() > %client2.player.getDamageLevel())
         {
            endRound(%client2.player, %client1.player, true, false, false);
         }
         else if (%client1.player.getDamageLevel() < %client2.player.getDamageLevel())
         {
            endRound(%client1.player, %client2.player, true, false, false);
         }
         else
         {
            endRound(%client2.player, %client1.player, true, true, false);
         }
      
   }
}



function duelChangeScore(%client)
{
   if (%client.duels == 0)
      %score = 0;
   else
      %score = mFloor(100 * (%client.wins / %client.duels));

   setRubies(%client, %client.duels);

   if (%client.isABot)
      changeBotScore(%client, %score);
   else
      %client.setScore(%score);
}


///////////////////////////////////////////////////////////////////////////////
// player/client management stuff

// new client entering the game
function DuelArena::ClientEnterGame(%this, %client)
{
   commandToClient(%client, 'DuelArenaStarted');

   %client.wins = 0;
   %client.losses = 0;
   %client.draws = 0;
   %client.duels = 0;

   duelChangeScore(%client);

   %client.duelStatus = "Connecting";
   
   %client.lastOpponentName = "-";
   %client.lastOpponentVictorious = "-";
   %client.lastDuelBreakdown = "-";

   %client.handicap = 0;

   
   commandToClient(%client, 'setDuelOptionsInfo', $gameModeOptions.value[$roundsPerDuelGameOption], $gameModeOptions.value[$roundsPerDuelGameOption], $gameModeOptions.value[$roundTimeGameOption]);

   // bots are always up for a duel
   if (%client.isABot)
      changeClientAwaitingStatus(%client, true, true);
   else
      changeClientAwaitingStatus(%client, false, true);

   if ($debugMissionLoad)
      echo("GMClientEnterGame DuelArena");

   %client.lastDuelTime = getSimTime();

   sendLastDuelInfo(%client);

   sendDAClientInfo(%client);

   sendAllClientInfoTo(%client);


   if (ClientGroup.getCount() >= $nSlots)
   {
      kick(%client);
   }
}

// client fully loaded
function DuelArena::ClientFullyLoaded(%this, %client)
{
   if ($debugMissionLoad)
      echo("GMClientFullyLoaded DuelArena");

   %client.camera.setTransform(VectorAdd(CameraStartPoint.position, "0 4048 0") SPC CameraStartPoint.rotation);

   messageClient(%client, 'showLeaderboardScreen', '');


   if ($singlePlayer)
   {
      serverCmdAddBotRequest(%client, $singlePlayerDuelObj.character, $singlePlayerDuelObj.ai, 0, 0, $singlePlayerDuelObj.weapon, false, "0 0 0", $singlePlayerDuelObj.name);
   
      if ($spProgression)
         $firstSPLD = true;
   }

   //if (!%client.isAwaitingDuel)
   //   messageClient(%client, 'beep', 'To start duelling, left click.');
}



function serverCmdSetJoinCharacter(%client, %char)
{
   %client.joinCharacter = %char;
 
}




// returns true if this client is allowed to join the match
function DuelArena::CanJoinMatch(%this, %client)
{
   if (!%client.inFight && !%client.isABot)
      changeClientAwaitingStatus(%client, !%client.isAwaitingDuel, true);

   return false;
}

// called on a player joining the match.  Newclient indicates whether the client has been in the match before
function DuelArena::JoinMatch(%this, %client, %character, %newClient, %team)
{

   if (%client.player.isABot)
   {
      %client.player.setAiState(%client.garnetProfile);
   }
}


function testDrop()
{
   $DATESTDROP = true;

   $currentGameMode.ClientDropped(ClientGroup.getObject(1), "bone");
}


// called on a client dropping for any reason
function DuelArena::ClientDropped(%this, %client, %reason)
{
   error("Deel arena client dropped: " @ %client SPC %client.duelID SPC $duelIsOn[%client.duelID]);

   daDealClientDrop(%client, %reason);
}

function daDealClientDrop(%client, %reason)
{
   error("daDealClientDrop: " @ %client SPC %reason);

   if ($duelIsOn[%client.duelID])
   {
      

      %duelID = %client.duelID;

      cancel($DADropSched[%duelID]);


      if ($preDuelDeadTime[%duelID])
      {
         // if right at the beginning, we wait a little while

         $DADropSched[%duelID] = schedule(7000, 0, "daDealClientDrop", %client, %reason);
      }
      else
      {
         if ($duelClient1[%duelID] == %client)
         {
            %winner = $duelClient2[%duelID];
         }
         else
         {
            %winner = $duelClient1[%duelID];
         }

         %client.lastBlow = "Drop";
         %winner.lastBlow = "Drop";

         //error("Client dropped next " SPC %did SPC %winner);

         %winner.roundWins = $gameModeOptions.value[$roundsPerDuelGameOption];

         
         if (!$postRoundDeadTime[%duelID])
            endRound(%winner.player, %client.player, false, false, true);
         else
            endDuel(%winner, %client, %duelID);
      }
   }

   if (!$DATESTDROP)
      removeDAClientInfo(%client);   
}

// called on a client leaving the match
function DuelArena::ClientLeavingMatch(%this, %client)
{
   cancel(%client.botResurrectSchedule);
}

// called on player death or client leaving the match
function DuelArena::RemovePlayer(%this, %player)
{
   
   %duelID = %player.client.duelID;

   error("DA RemovePlayer" SPC %player.dropped);

   if ($duelIsOn[%duelID] && !$postRoundDeadTime[%duelID])
   {
      if (!%player.dropped)
      {
         %loser = %player;

         if ($duelClient1[%duelID] == %player.client)
            %winner = $duelClient2[%duelID].player;
         else
            %winner = $duelClient1[%duelID].player;

         endRound(%winner, %loser, false, false, false);
      }
      else
      {
         daDealClientDrop(%player.client, "");
      }
   }
}

// call the client and tell him what colours we want the IFFs to be
function DuelArena::SendClientIFFInfo(%this, %client)
{
   commandToClient(%client, 'setIFFColours', "0 1 0", "1 0 0", "0 0 1", "0 1 1", false);
}

function DuelArena::playerHasNewTarget(%this, %player, %target)
{

}


//////////////////////////////////////////////////////////////////
// action stuff

// called on a player-player collision
function DuelArena::OnHit(%this, %hiter, %hitee, %myHitbox, %hisHitbox, %myForce, %hisForce, %myMult, %hisMult, %winner, %myV2, %hisV2)
{
   if (%hiter.client.duelingWith == %hitee.client)
   {
      return standardHitDamage(%hiter, %hitee, %myHitbox, %hisHitbox, %myForce, %hisForce, %myMult, %hisMult, %winner, %myV2, %hisV2);
   }
   else
      return 0;
}





// called when a player is killed by an opponent
function DuelArena::OnKilled(%this, %killee, %killer, %reason)
{
   error("DA onKilled call");

   if (%reason $= "swordBlow")
      %lastBlowText = %killee.lastHitbox SPC "for" SPC mFloor(%killee.lastDamage);
   else if (%reason $= "ringOut")
      %lastBlowText = "Ring Out";
   else if (%reason $= "timeOut")
      %lastBlowText = "Time Out";


   //error("Setting last blow as " SPC %lastBlowText);


   %killee.client.lastBlow = %lastBlowText;
   %killer.client.lastBlow = %lastBlowText;

   schedule(1000, 0, "standardKillMessage", %killee, %killer, %reason); 

   endRound(%killer, %killee, false, false, false);
}


// called on a player's death
function DuelArena::OnDeath(%this, %player)
{
   
}



function DuelArena::playerHitItem(%this, %player, %item)
{

}

/////////////////////////////////////////////////////////////////////
// mission area stuff

// called when the player enters the MissionArea mission area struct
function DuelArena::OnEnterMissionArea(%this, %player)
{
   cancel(%player.ringoutDamageSchedule);
}

// called when the player leaves the MissionArea mission area struct
function DuelArena::OnLeaveMissionArea(%this, %player)
{
   //error("player " SPC %player SPC "left the arena" SPC %player.getTransform());


   if ($gameModeOptions.value[$arenaSizeGameOption] !$= "none" && %player.isAlive() && !$postRoundDeadTime[%player.client.duelID] && $duelIsOn[%player.client.duelID])
   {
      damagePlayerRingout(%player);
   }
}



function damagePlayerRingout(%player)
{
   cancel(%player.ringoutDamageSchedule);

   if (!$postRoundDeadTime[%player.client.duelID] && $duelIsOn[%player.client.duelID])
   {
      messageClient(%player.client, 'playSound', "", "ringOutSound");

      //%player.applyDamageFromRingout($gameModeOptions.value[$OOBDamageGameOption]);

      %player.ringoutDamageSchedule = schedule(1000, 0, "damagePlayerRingout", %player);
   }
}


////////////////////////////////////////////////////////////////////
// mission end cleanup


function DuelArena::OnMissionEnded(%this)
{
   $fightInfo.isDuelArena = false;
}

////////////////////////////////////////////////////////////////////
// ball stuff

// player collides with the ball
function DuelArena::PlayerHitBall(%this, %player, %hitboxID, %ball)
{

}



/////////////////////////////////////////////////////////



function DuelArena::optionChanged(%this, %id, %previousVal, %newVal)
{
   for (%i = 0; %i < ClientGroup.getCount(); %i ++)
   {  
      %c = ClientGroup.getObject(%i);

      commandToClient(%c, 'setDuelOptionsInfo', $gameModeOptions.value[$roundsPerDuelGameOption], $gameModeOptions.value[$roundsPerDuelGameOption], $gameModeOptions.value[$roundTimeGameOption]);
   }
}



/////////////////////////////////////////////////////







function sendDAClientInfo(%client)
{
   messageAll('setClientDAStats', '', %client, %client.name, %client.score, %client.wins, %client.losses, %client.lastOpponentName,
       %client.lastOpponentVictorious, %client.lastDuelBreakdown, %client.duelStatus);
}



function sendAllClientInfoTo(%client)
{
   for (%i = 0; %i < ClientGroup.getCount(); %i ++)
   {  
      %c = ClientGroup.getObject(%i);


      messageClient(%client, 'setClientDAStats', '', %c, %c.name, %c.score, %c.wins, %c.losses, %c.lastOpponentName,
       %c.lastOpponentVictorious, %c.lastDuelBreakdown, %c.duelStatus);
   }
}





function removeDAClientInfo(%client)
{
   messageAll('removeClientDAStats', '', %client);
}


function sendAllLastDuelInfo()
{
   for (%i = 0; %i < ClientGroup.getCount(); %i ++)
   {  
      %c = ClientGroup.getObject(%i);

      sendLastDuelInfo(%c);
   }
}


function sendLastDuelInfo(%client)
{
   commandToClient(%client, 'setLastDuelInfo', $lastDuelName1, $lastDuelName2, $lastDuelBreakdown);

}




function getMinBoundsZ(%areaStart, %areaExtent)
{
   %xEx = getWord(%areaExtent, 0) @ " 0 0";
   %yEx = "0 " @ getWord(%areaExtent, 1) @ " 0";
   %zEx = "0 0 " @ getWord(%areaExtent, 2) - 50;

   %corner1 = VectorAdd(%areaStart, %zEx);
   %corner2 = VectorAdd(VectorAdd(%areaStart, %zEx), %xEx);
   %corner3 = VectorAdd(VectorAdd(%areaStart, %zEx), %yEx);
   %corner4 = VectorAdd(VectorAdd(VectorAdd(%areaStart, %zEx), %yEx), %xEx);

   %z = getWord(%corner1, 2);

   %hz1 = getTerrainOrWaterHeight(getWords(%corner1, 0, 1));
   %hz2 = getTerrainOrWaterHeight(getWords(%corner2, 0, 1));
   %hz3 = getTerrainOrWaterHeight(getWords(%corner3, 0, 1));
   %hz4 = getTerrainOrWaterHeight(getWords(%corner4, 0, 1));

   if (%hz1 > %z)
      %z = %hz1;

   if (%hz2 > %z)
      %z = %hz2;

   if (%hz3 > %z)
      %z = %hz3;

   if (%hz4 > %z)
      %z = %hz4;

   return %z;
}




function drawArenaBounds(%areaStart, %areaExtent, %p1, %p2, %duelID)
{
   if ($dontDrawArena)
      return;


   $flagScale = "0.7 0.7 0.7";
   $flagPoleScale = "0.2 0.2 7";

   $flagHeightOffset = 30;

   $flagOffset = "0 0 0";

   %xEx = getWord(%areaExtent, 0) @ " 0 0";
   %yEx = "0 " @ getWord(%areaExtent, 1) @ " 0";
   %zEx = "0 0 " @ getWord(%areaExtent, 2) - 250;

   %corner1 = VectorAdd(%areaStart, %zEx);
   %corner2 = VectorAdd(VectorAdd(%areaStart, %zEx), %xEx);
   %corner3 = VectorAdd(VectorAdd(%areaStart, %zEx), %yEx);
   %corner4 = VectorAdd(VectorAdd(VectorAdd(%areaStart, %zEx), %yEx), %xEx);

   %h1 = getTerrainHeight(getWords(%corner1, 0, 1)) - $flagHeightOffset;
   %h2 = getTerrainHeight(getWords(%corner2, 0, 1)) - $flagHeightOffset;
   %h3 = getTerrainHeight(getWords(%corner3, 0, 1)) - $flagHeightOffset;
   %h4 = getTerrainHeight(getWords(%corner4, 0, 1)) - $flagHeightOffset;

   %corner1 = setWord(%corner1, 2, %h1);
   %corner2 = setWord(%corner2, 2, %h2);
   %corner3 = setWord(%corner3, 2, %h3);
   %corner4 = setWord(%corner4, 2, %h4);

   $flag1[%duelID] = new StaticShape()
   {
      dataBlock = FlagTop;
      position = %corner1;
      useClothSim = true;
      scale = $flagScale;
   };

   $flag2[%duelID] = new StaticShape()
   {
      dataBlock = FlagTop;
      position = %corner2;
      useClothSim = true;
      scale = $flagScale;
   };

   $flag3[%duelID] = new StaticShape()
   {
      dataBlock = FlagTop;
      position = %corner3;
      useClothSim = true;
      scale = $flagScale;
   };

   $flag4[%duelID] = new StaticShape()
   {
      dataBlock = FlagTop;
      position = %corner4;
      useClothSim = true;
      scale = $flagScale;
   };




   MissionCleanup.add($flag1[%duelID]);
   MissionCleanup.add($flag2[%duelID]);
   MissionCleanup.add($flag3[%duelID]);
   MissionCleanup.add($flag4[%duelID]);
}



function setScopeFlags(%player)
{
   //%duelID = %player.client.duelID;

   //%player.setScopeFlags($flag1[%duelID], $flag2[%duelID], $flag3[%duelID], $flag4[%duelID]);
}

function clearScopeFlags(%player)
{
   //%player.setScopeFlags(0, 0, 0, 0);
}


function deleteArena(%c1, %c2, %duelId)
{
   safeDeleteItem($flag1[%duelID]);
   safeDeleteItem($flag2[%duelID]);
   safeDeleteItem($flag3[%duelID]);
   safeDeleteItem($flag4[%duelID]);

}






//////////////////////////


function serverCmdchangeDAHandicap(%client, %hc)
{
   if (%hc >= 0 && %hc < 100)
   {
      %client.handicap = %hc;

      if ($gameModeOptions.value[$handicapAllowedGameOption] !$= "yes")
      {
         messageClient(%client, '', 'The handicap option is currently turned off');
      }
   }
}




/////////////////////////



function obsClientEnteringRound(%client)
{
   for (%i = 0; %i < ClientGroup.getCount(); %i ++)
   {
      %c = ClientGroup.getObject(%i);

      if (%c.obsTarget == %client)
      {
         DAClientObserveNow(%c);
      }
   }
}


function obsClientLeavingRound(%client)
{
   for (%i = 0; %i < ClientGroup.getCount(); %i ++)
   {
      %c = ClientGroup.getObject(%i);

      if (%c.obsTarget == %client)
      {
         obsStandby(%c);
         
      }
   }
}




/////////////////////////



function serverCmdObserveDAClient(%voyeur, %girl)
{
   if ($duelIsOn[%voyeur.duelID])
   {
      return;
   }


   %found = false;

   if (%girl == %voyeur)
   {
      messageClient(%voyeur, 'playSound', 'You cannot observe yourself!', "badBeep");
      return;
   }

   if (%girl.duelStatus $= "Sitting Out" || %girl.duelStatus $= "Connecting")
   {
      messageClient(%voyeur, 'playSound', 'He\'s not fighting at the moment.', "badBeep");
      return;
   }

   for (%i = 0; %i < ClientGroup.getCount(); %i ++)
   {
      if (ClientGroup.getObject(%i) == %girl)
      {        
         %found = true;
         break;
      }  
   }

   if (!%found)
   {
      messageClient(%voyeur, 'playSound', 'Observe client not found', "badBeep");
      return;
   }


   // okay, we've got this far and the girl exists.

   %voyeur.obsTarget = %girl;

   commandToClient(%voyeur, 'DAObsStandby', %girl.name);

   %voyeur.setCameraObject(%voyeur.camera);

   

   if ($duelIsOn[%girl.duelID] && !$postRoundDeadTime[%girl.duelID])
   {
      DAClientObserveNow(%voyeur);
   }
}


function DAClientObserveNow(%voyeur)
{
   cancel(%voyeur.retryGhostSchedule);

   %p = %voyeur.obsTarget.player;

   %gi = %voyeur.getGhostIndex(%p);

   %voyeur.camera.setTransform(%p.getTransform());
   %voyeur.wapcam.setTransform(%p.getTransform());

   if (%gi == -1)
   {
      %voyeur.retryGhostSchedule = schedule(500, 0, "DAClientObserveNow", %voyeur);
   }
   else
   {
      %voyeur.wapCam.setPlayerObject(%p);
      %voyeur.setCameraObject(%voyeur.wapcam);

      commandToClient(%voyeur, 'DAStartObserving', %gi, %voyeur.getGhostIndex(%voyeur.wapcam), %voyeur.obsTarget.name);
   }
}


function serverCmdstopDAObserving(%voyeur)
{

   %voyeur.obsTarget = 0;

   %voyeur.setCameraObject(%voyeur.camera);

   commandToClient(%voyeur, 'DAStopObserving', false);
}


function obsStandby(%c)
{  
   %c.setCameraObject(%c.camera);

   commandToClient(%c, 'DAObsStandby', %c.obsTarget.name);
}



function serverCmdcycleDAObserving(%voyeur)
{
  //error("cycle obs, current target " @ %voyeur.obsTarget);

   %count = ClientGroup.getCount();

   //error("count = " @ %count);

   %address = -1;

   %validList = new SimSet() {};

   for (%i = 0; %i < %count; %i ++)
   {
      %c = ClientGroup.getObject(%i);

      if (%c == %voyeur.obsTarget)
      {
         %address = %validList.getCount();
      }
      else if (%c == %voyeur)
      {
      }
      else
      {
         %validList.add(%c);
      }
   }

   //error("address: " @ %address SPC "and size of vl = " @ %validList.getCount());

   if (%validList.getCount() == 0)
   {
      
   }
   else
   {
      if (%address == -1 || %validList.getCount() <= %address)
      {
         %t = %validList.getObject(0);

         //error("no next, going to " @ %t);

         serverCmdObserveDAClient(%voyeur, %t);
      }
      else
      {  
         %t = %validList.getObject(%address);

         //error("going to next " @ %t);

         serverCmdObserveDAClient(%voyeur, %t);      
      }   
   }

   %validList.delete();
}






/////////////////////////////////////////////
// single player stuff

$nSinglePlayerBotObs = 0;
$singlePlayerBotOb[$nSinglePlayerBotObs] = "DaOpEdBurns";
$nSinglePlayerBotObs ++;
$singlePlayerBotOb[$nSinglePlayerBotObs] = "DaOpBlunder";
$nSinglePlayerBotObs ++;
$singlePlayerBotOb[$nSinglePlayerBotObs] = "DaOpTwitchy";
$nSinglePlayerBotObs ++;
$singlePlayerBotOb[$nSinglePlayerBotObs] = "DaOpOmroth";
$nSinglePlayerBotObs ++;
$singlePlayerBotOb[$nSinglePlayerBotObs] = "DaOpDeaconVries";
$nSinglePlayerBotObs ++;
$singlePlayerBotOb[$nSinglePlayerBotObs] = "DaOpChaseStephens";
$nSinglePlayerBotObs ++;
$singlePlayerBotOb[$nSinglePlayerBotObs] = "DaOpEdge";
$nSinglePlayerBotObs ++;



function singlePlayerStartMission()
{
   $me.joinCharacter = %selected_character = omphrNameToModelName(PLCharacterList.getText());
   $me.joinRightWeap = PLRightWeaponList.getText();

   $progLostYet = false;

   DALeaderboardWindow.setvisible(0);

   $arcadeWon = false;

   //$singlePlayerDuelObj = DaOpEdge;

   showProgressionContent();
}


function singlePlayerReadyForFight()
{
   $me.postDuelDeadTime = false;
   changeClientAwaitingStatus($me, true, true);
}


function singlePlayerWinDuel()
{
   error("SINGLE PLAYER WON DUEL" SPC $arcadeWon);

   // RESPECT THE HAX
   if ($arcadeWon)
      return;

   if ($hackDontMoveOn)
   {
      return;
   }

   $hackDontMoveOn = true;
   schedule(3000, 0, "eval", "$hackDontMoveOn = false;");

   cancel($addNextBotSched);

   changeClientAwaitingStatus($me, false, true);

   serverCmdKickAllBots();

   if (isDemoVersion() && $singlePlayerDuelObj $= DaOpBlunder)
   {
      showArcadeDemoEndContent();
   }
   else
   {
      if ($singlePlayerDuelObj $= "DaOpEdge")
      {
         error("WON WON WON WON WON");
         $arcadeWon = true;
         showWinWinContent();
      }
      else
      {
         $addNextBotSched = schedule(1000, 0, "loadNextSinglePlayerBot");
         schedule(1200, 0, "showProgressionContent");
      }

      
   }
}


function showProgressionContent()
{
   ArcadeAdvanceButton.setVisible(1);
   ArcadeBuyButton.setVisible(0);
   loadArcadeText($singlePlayerDuelObj);
   Canvas.pushDialog(ArcadeModeStoryBox);
}





function showWinWinContent()
{
   ArcadeAdvanceButton.setVisible(0);
   ArcadeBuyButton.setVisible(0);
   loadArcadeText("win");
   Canvas.pushDialog(ArcadeModeStoryBox);
}


function showArcadeDemoEndContent()
{
   ArcadeAdvanceButton.setVisible(0);
   ArcadeBuyButton.setVisible(1);
   loadArcadeText("demoEnd");
   Canvas.pushDialog(ArcadeModeStoryBox);
}


function loadNextSinglePlayerBot()
{
   %currentObj = $singlePlayerDuelObj;

   if (%currentObj $= "DaOpEdge")
   {
      error("next bot called with edge as current!  BAD!!");
      return;
   }

   %nextObj = "";
   for (%i = 0; %i < $nSinglePlayerBotObs; %i ++)
   {
      if ($singlePlayerBotOb[%i] $= %currentObj)
      {
         %nextObj = $singlePlayerBotOb[%i + 1];

         if (!$progLostYet)
         {
            $pref::botUnlocked[%i] = true;
            
            if (%i == 1)
               $pref::ffa1Unlocked = true;
            else if (%i == 2)
               $pref::tdm1Unlocked = true;
            else if (%i == 3)
               $pref::ffa2Unlocked = true;
            else if (%i == 5)
               $pref::tdm2Unlocked = true;
            else if (%i == 6)
               $pref::ffa3Unlocked = true;
         }

         break;
      }
   }

   $singlePlayerDuelObj = %nextObj;

   serverCmdAddBotRequest(%client, $singlePlayerDuelObj.character, $singlePlayerDuelObj.ai, 0, 0, $singlePlayerDuelObj.weapon, false, "0 0 0", $singlePlayerDuelObj.name);
   
}


      

function singlePlayerLoseDuel()
{
   changeClientAwaitingStatus($me, false, true);

   $progLostYet = true;

   showLossContent();
}


function showLossContent()
{
   MessageBoxYesNo($sid::spLoseTitle, $sid::spLoseText, "singlePlayerReadyForFight();", "schedule(1000, 0, \"disconnect\");"); // we need this schedule so that this popup dissapears 
}