function Hexfield::onLevelLoaded(%this)
{
   // create a new owner representation marker below this hexfield
   %this.ownerRepresentationMarker = new t2dStaticSprite()
   {
      scenegraph = %this.scenegraph;
      Layer = %this.Layer + 1;
      imageMap = $pref::Game::OwnerRepresentationMarkerImageMap;
      Position = %this.Position;
      size = "0 0";
   };
   
   // set initial owning time, if field is initially owned
   if(%this.getOwner() !$= "")
      %this.setOwner(%this.getOwner());
   
   // if this is a resource field, register with resource controller
   %fieldSpecial = %this.getFieldSpecial();
   if(%fieldSpecial $= "resource1" || %fieldSpecial $= "resource2" || %fieldSpecial $= "resource3")
      resControl.addResourceField(%this);
      
   // update state
   %this.update();
}

function Hexfield::onMouseDown(%this, %modifier, %worldPos, %clicks)
{       
   // determine human player
   %humanPlayer = gameInstance.getHumanPlayer();
   
   // determine action to perform
   if(%this.areRefreshRequirementsMet(%humanPlayer))
   {
      if(!%this.refresh(%humanPlayer))
         alxPlay(errorSound);
   }
   else if(%this.areConquerRequirementsMet(%humanPlayer))
   {
      if(!%this.conquer(%humanPlayer))
         alxPlay(errorSound);
   }
   else
     alxPlay(errorSound); 
}

//function Hexfield::onRightMouseDown(%this, %modifier, %worldPos, %clicks)
//{
   //// determine human player
   //%humanPlayer = gameInstance.getHumanPlayer();
   //
   //if(%this.areCreateBaseRequirementsMet(%humanPlayer))
   //{
      //if(!%this.createBase(%humanPlayer))
         //alxPlay(errorSound);
   //}
   //else
      //alxPlay(errorSound);
//}

function Hexfield::onMouseEnter(%this, %modifier, %worldPos, %clicks)
{  
   // renew mouse position
   %worldPos = sceneWindow2D.getMousePosition();   
   
   // determine human player
   %humanPlayer = gameInstance.getHumanPlayer();   
   
   // highlight field
   if(isObject(hexfield_highlight))
      hexfield_highlight.safeDelete();
   new t2dStaticSprite(hexfield_highlight)
   {
      scenegraph = %this.scenegraph;
      Layer = 0;
      Position = %this.Position;
      size = %this.size;
      imageMap = hexfield_glowImageMap;
   };
   
   // create status message
   %statusMessage = "";

   // attach field type to status message
   switch$(%this.getSpecial())
   {
      case "base":
         %statusMessage = %statusMessage @ "Basisfeld.";
         
      case "resource1":
         %statusMessage = %statusMessage @ "Geringes Ressourcenfeld.";
      
      case "resource2":
         %statusMessage = %statusMessage @ "Mittleres Ressourcenfeld.";
      
      case "resource3":
         %statusMessage = %statusMessage @ "Reiches Ressourcenfeld.";
      
      default:
         %statusMessage = %statusMessage @ "Leeres Feld.";
   }
   
   // add blank
   %statusMessage = %statusMessage @ " ";
   
   // attach owning time left to status message
   if(isObject(%this.getOwner()) && %this.getSpecial() !$= "base")
      %statusMessage = %statusMessage @ "Noch" SPC mFloatLength(%this.owningTimeLeft / 1000, 1) SPC "Sekunden ";
   else if(isObject(%this.getOwner()) && %this.getSpecial() $= "base")
      %statusMessage = %statusMessage @ "Dauerhaft ";
   
   if(isObject(%this.getOwner()) && %humanPlayer.getId() == %this.getOwner().getId())
      %statusMessage = %statusMessage @ "unter Ihrer Kontrolle.";
   else if(isObject(%this.getOwner()))
      %statusMessage = %statusMessage @ "unter gegnerischer Kontrolle.";
      
   // add break
   //%statusMessage = %statusMessage NL "Left click: ";
   
   // attach left click action   
   %cost = "";
   if(%this.areConquerRequirementsMet(%humanPlayer))
   {
      //set cursor
      if(%this.getConquerCost(%humanPlayer) <= %humanPlayer.getActions())
         Canvas.setCursor(ConquerCursor);
      else
         Canvas.setCursor(ConquerImpossibleCursor);
      
      %cost = %this.getConquerCost(%humanPlayer);
      //%statusMessage = %statusMessage @ "Conquer field" SPC "(" @ %this.getConquerCost(%humanPlayer) @ ").";
   }
   else if(%this.areRefreshRequirementsMet(%humanPlayer))
   {
      //set cursor
      if(%this.getRefreshCost(%humanPlayer) <= %humanPlayer.getActions())
         Canvas.setCursor(ConquerCursor);
      else
         Canvas.setCursor(ConquerImpossibleCursor);
         
      %cost = %this.getRefreshCost(%humanPlayer);
      //%statusMessage = %statusMessage @ "Refresh field" SPC "(" @ %this.getRefreshCost(%humanPlayer) @ ").";
   }
   else
   {
      //set cursor
      Canvas.setCursor(DefaultCursor);
      
      //%statusMessage = %statusMessage @ "-";
   }
      
   //// add pipe
   //%statusMessage = %statusMessage SPC "| Right click: ";
   //
   //// attach right click action
   //if(%this.areCreateBaseRequirementsMet(%humanPlayer))
      //%statusMessage = %statusMessage @ "Create base" SPC "(" @ %this.getCreateBaseCost(%humanPlayer) @ ").";
   //else
      //%statusMessage = %statusMessage @ "-";
      
   // attach mouse over info box to the mouse cursor
   if(%cost !$= "")
   {
      if(isObject(mouseOverInfoBox))
         mouseOverInfoBox.safeDelete();
         
      if(%cost <= %humanPlayer.getActions())
         %color = "1 1 1 1";
      else
         %color = "1 0 0 1";

      new t2dTextObject(mouseOverInfoBox) {
         canSaveDynamicFields = "1";
         scenegraph = sceneWindow2D.getSceneGraph();
         Layer = 0;
         Position = getWord(%worldPos, 0) + 4 SPC getWord(%worldPos, 1) + 2.625;
         size = "2.500 2.500";
         font = "Verdana";
         text = %cost;
         wordWrap = "0";
         hideOverflow = "0";
         textAlign = "Left";
         lineHeight = "2.500";
         aspectRatio = "1";
         lineSpacing = "0";
         characterSpacing = "0";
         autoSize = "0";
         fontSizes = "20";
         textColor = %color;
         bilinearFilter = "0";
         snapToInteger = "0";
         noUnicode = "0";
      };
   }

   //statusbar.write(%statusMessage);
   statusbar2.text = %statusMessage;
   
   // schedule next mouseover refresh
   %this.mouseEnterSchedule = %this.schedule(20, "onMouseEnter", %modifier, %worldPos, %clicks);
}

function Hexfield::onMouseLeave(%this, %modifier, %worldPos, %clicks)
{
   // cancel pending mouseover refreshes
   if(isEventPending(%this.mouseEnterSchedule))
      cancel(%this.mouseEnterSchedule);
   
   // reset cursor
   Canvas.setCursor(DefaultCursor);
   
   // unhighlight field
   if(isObject(hexfield_highlight))
      hexfield_highlight.safeDelete();
   
   // empty status bar
   statusbar2.text = "";
   
   // delete mouse over info box
   if(isObject(mouseOverInfoBox))
      mouseOverInfoBox.safeDelete();
   //statusbar.clear();
}

function Hexfield::getState(%this)
{
   return %this.state;
}

function Hexfield::setState(%this, %state)
{
   %this.state = %state;
   //%this.update();
}

function Hexfield::getSpecial(%this)
{
   return %this.fieldSpecial;
}

function Hexfield::setSpecial(%this, %special)
{
   %this.fieldSpecial = %special;
   //%this.update();
}

function Hexfield::getOwner(%this)
{
   return %this.owningPlayer;
}

function Hexfield::setOwner(%this, %owningPlayer)
{
   %this.owningPlayer = %owningPlayer;
   
   // reset AI analyze flag
   %this.alreadyAnalyzed = false;
   
   // reset owning counter   
   if(%this.owningPlayer !$= "")
      %this.owningTimeLeft = $pref::Game::InitialOwningTime;
   else
      %this.owningTimeLeft = 0;

   // re-initialize updating
   if(%this.owningTimeLeft > 0 && !isEventPending(%this.updateTickSchedule))
      %this.updateTickSchedule = %this.schedule($pref::Game::FieldUpdateTick, "update");
}

function Hexfield::getFieldSpecial(%this)
{
   return %this.fieldSpecial;
}

function Hexfield::update(%this)
{  
   // decrease owning time, if this is not a base
   if(%this.getSpecial() !$= "base" && %this.owningTimeLeft > 0)
      %this.owningTimeLeft -= $pref::Game::FieldUpdateTick;
   
   // if owning time up, make field neutral again
   if(%this.owningTimeLeft <= 0)
   {
      %fieldowner = %this.getOwner();
      if(isObject(%fieldowner))
      {
         %fieldowner.addFields(-1);
         
         // play player specific sound
         if(%fieldowner.getId() == playerOne.getId())
            alxPlay(controlOverPlayerOneSound);
         else
            alxPlay(controlOverPlayerTwoSound);
      }
      %this.setOwner("");
   }
   
   // determine players and field owner
   %playerOne = playerOne.getId();
   %playerTwo = playerTwo.getId();
   %fieldowner = %this.getOwner();
   if(isObject(%fieldowner))
      %fieldownerId = %fieldowner.getId();
   
   // switch by field type
   switch$(%this.getFieldSpecial())
   {
      case "resource1":
         %this.setImageMap($pref::Game::Resource1FieldImageMap);
         
      case "resource2":
         %this.setImageMap($pref::Game::Resource2FieldImageMap);
         
      case "resource3":
         %this.setImageMap($pref::Game::Resource3FieldImageMap);
         
      case "base":
         %this.setImageMap($pref::Game::BaseFieldImageMap);
         
      default:
         %this.setImageMap($pref::Game::NeutralFieldImageMap);
   }
   
   // switch by owner
   switch(%fieldownerId)
   {
      case %playerOne:
         %this.ownerRepresentationMarker.setBlendColor($pref::Game::PlayerOneColor);
         
      case %playerTwo:
         %this.ownerRepresentationMarker.setBlendColor($pref::Game::PlayerTwoColor);
         
      default:
         %this.ownerRepresentationMarker.setBlendColor($pref::Game::NeutralColor);
   }
   
   // resize owner representation marker to match remaining owning time
   %sizeX = getWord($pref::Game::FieldSize, 0) * mSqrt(%this.owningTimeLeft) / mSqrt($pref::Game::InitialOwningTime);
   %sizeY = getWord($pref::Game::FieldSize, 1) * mSqrt(%this.owningTimeLeft) / mSqrt($pref::Game::InitialOwningTime);
   %this.ownerRepresentationMarker.setSize(%sizeX SPC %sizeY);
   
   // change color of field by state
   switch(%this.getState())
   {
      case $pref::Game::InactiveFieldState:
         %this.setBlendAlpha($pref::Game::InactiveFieldAlpha);
         
      case $pref::Game::ActiveFieldState:
         %this.setBlendAlpha($pref::Game::ActiveFieldAlpha);
         
      default:
         %this.setBlendAlpha($pref::Game::InactiveFieldAlpha);
   }
   
   // if owning time on a resource field is almost up, re-analyze situation for AI, so it may refresh this field
   if(!%this.alreadyAnalyzed
      && (%this.fieldSpecial $= "resource1" || %this.fieldSpecial $= "resource2" || %this.fieldSpecial $= "resource3")
      && %fieldownerId == gameInstance.getAIPlayer().getId()
      && %this.getOwningTimeLeft() <= mMax($pref::Game::ResourceGainTick - resControl.getResourceBonus(gameInstance.getAIPlayer()) SPC $pref::Game::MinimumResourceGainTick) * ($pref::Game::ResourceLimit - gameInstance.getAIPlayer().getResource()))
   {
      %this.alreadyAnalyzed = true;
      opponentAI.analyzeSituation();
   }
   
   // re-update next tick
   if(%this.owningTimeLeft > 0)
      %this.updateTickSchedule = %this.schedule($pref::Game::FieldUpdateTick, "update");
}

function Hexfield::getAllNeighbors(%this)
{
   %name = %this.getName();
   %name = strreplace(%name, "_", " ");
   
   %coordX = getWord(%name, 1);
   %coordY = getWord(%name, 2);
   
   %neighborList = "";
   %neighbor1 = "hexfield_" @ %coordX - 1 @ "_" @ %coordY - 1;
   %neighbor2 = "hexfield_" @ %coordX - 1 @ "_" @ %coordY + 1;
   %neighbor3 = "hexfield_" @ %coordX     @ "_" @ %coordY - 2;
   %neighbor4 = "hexfield_" @ %coordX     @ "_" @ %coordY + 2;
   %neighbor5 = "hexfield_" @ %coordX + 1 @ "_" @ %coordY - 1;
   %neighbor6 = "hexfield_" @ %coordX + 1 @ "_" @ %coordY + 1;
   
   for(%i = 1; %i <= 6; %i++)
   {
      if(isObject(%neighbor[%i]))
         if(%neighborList $= "")
            %neighborList = %neighbor[%i];
         else
            %neighborList = %neighborList SPC %neighbor[%i];
   }
   
   return %neighborList;
}

function Hexfield::conquer(%this, %conqueringPlayer)
{  
   %actionCost = %this.getConquerCost(%conqueringPlayer);
   
   if(%conqueringPlayer.getActions() >= %actionCost)  // does the player posess enough actions?
   {
      // play player specific conquer sound
      if(%conqueringPlayer.getId() == playerOne.getId()) 
         alxPlay(conquerPlayerOneSound);
      else
         alxPlay(conquerPlayerTwoSound);
      
      %fieldowner = %this.getOwner();
      
      // remove one field from the former owner
      if(isObject(%fieldowner))
         %fieldowner.addFields(-1);
         
      // if this is a base, remove base
      if(%this.getSpecial() $= "base")
      {
         %fieldowner.addBases(-1);
         %this.setSpecial("");
      }
      
      // make conqueror the new owner
      %conqueringPlayer.addActions(-%actionCost);
      %this.setOwner(%conqueringPlayer);
      %conqueringPlayer.addFields(1);
      
      // re-analyze situation for AI
      if(isObject(opponentAI))
         opponentAI.analyzeSituation();      
      
      return true;
   }
   return false;
}

function Hexfield::areConquerRequirementsMet(%this, %conqueringPlayer)
{  
   // determine owner of this field
   %fieldowner = %this.getOwner();
   if(isObject(%fieldowner))
      %fieldownerId = %fieldowner.getId();
   
   return %fieldownerId != %conqueringPlayer.getId()
      && %this.getState() != $pref::Game::InactiveFieldState
      && %this.getCountOfOwnedNeighbors(%conqueringPlayer) >= 1;
}

function Hexfield::getConquerCost(%this, %conqueringPlayer)
{
   // determine owner of this field
   %fieldowner = %this.getOwner();
   if(isObject(%fieldowner))
      %fieldownerId = %fieldowner.getId();
   
   // determine opponent strength
   %opponent = %conqueringPlayer.getOpponent();
   %opponentOwnedNeighborCount = %this.getCountOfOwnedNeighbors(%opponent);
   if(%fieldownerId == %opponent.getId())
      %opponentOwnedNeighborCount += 2;

   if(%opponentOwnedNeighborCount > 0) // at least 1 neighbor field is owned by the opponent
   {
      %selfOwnedNeighborCount = %this.getCountOfOwnedNeighbors(%conqueringPlayer);
      %costMalus = (%opponentOwnedNeighborCount - %selfOwnedNeighborCount) * $pref::Game::CostMalusFactorPerFieldConquerAction;
      if(%costMalus > 0)
         return $pref::Game::CostBaseConquerAction + %costMalus;
      else
         return $pref::Game::CostBaseConquerAction;
   }
   else  // no fields are owned by the opponent
      return $pref::Game::CostBaseConquerAction;
}

function Hexfield::refresh(%this, %refreshingPlayer)
{
   %actionCost = %this.getRefreshCost(%refreshingPlayer);

   if(%refreshingPlayer.getActions() >= %actionCost)  // does the player posess enough actions?
   {
      %refreshingPlayer.addActions(-%actionCost);
      %this.setOwner(%refreshingPlayer);
      
      // play player specific refresh sound
      if(%refreshingPlayer.getId() == playerOne.getId()) 
         alxPlay(conquerPlayerOneSound);
      else
         alxPlay(conquerPlayerTwoSound);
      
      return true;
   }
   
   return false;
}
function Hexfield::areRefreshRequirementsMet(%this, %refreshingPlayer)
{
   // determine owner of this field
   %fieldowner = %this.getOwner();
   if(isObject(%fieldowner))
      %fieldownerId = %fieldowner.getId();
   
   return %fieldownerId == %refreshingPlayer.getId()
      && %this.getSpecial() !$= "base";
}

function Hexfield::getRefreshCost(%this, %refreshingPlayer)
{
   return $pref::Game::CostBaseConquerAction;
}

function Hexfield::createBase(%this, %baseCreatingPlayer)
{
   %actionCost = %this.getCreateBaseCost(%baseCreatingPlayer);
   
   if(%baseCreatingPlayer.getActions() >= %actionCost)  // does the player posess enough actions?
   {
      %baseCreatingPlayer.addActions(-%actionCost);
      %this.setSpecial("base");
      %this.setOwner(%baseCreatingPlayer);
      %baseCreatingPlayer.addBases(1);
      
      return true;
   }
   return false;
}

function Hexfield::areCreateBaseRequirementsMet(%this, %baseCreatingPlayer)
{
   // determine owner of this field
   %fieldowner = %this.getOwner();
   if(isObject(%fieldowner))
      %fieldownerId = %fieldowner.getId();
   
   return %fieldownerId == %baseCreatingPlayer.getId()
      && %this.fieldSpecial $= "";
}

function Hexfield::getCreateBaseCost(%this, %baseCreatingPlayer)
{
   return $pref::Game::CostBaseDefendAction + $pref::Game::CostMalusPerBaseDefendAction * (%baseCreatingPlayer.getBases() - 1);   
}

function Hexfield::getCountOfOwnedNeighbors(%this, %owningPlayer)
{
   %neighborList = %this.getAllNeighbors();
   %numberOfNeighbors = getWordCount(%neighborList);
   
   %countOfOwnedNeighbors = 0;
   for(%i = 0; %i < %numberOfNeighbors; %i++)
   {
      %neighbor = getWord(%neighborList, %i);
      %fieldowner = %neighbor.getOwner();
      
      if(isObject(%fieldowner))
         %fieldownerId = %fieldowner.getId();
      else
         %fieldownerId = "";
         
      if(%fieldownerId == %owningPlayer.getId())
         %countOfOwnedNeighbors++;
   }
   
   return %countOfOwnedNeighbors;
}

function Hexfield::getOwningTimeLeft(%this)
{
   return %this.owningTimeLeft;
}