//------------------------------------------------------------------------------
// File: svr_cmdmethods.cs
// This file is used for 'commandToServer' callbacks from clients when a command
// button has been pressed
// Author: Matthew Rudge
//------------------------------------------------------------------------------

//-Server Commands--------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
//! Callback when the recruit command button has been clicked on the client
//! \param %client Client that clicked button
//! \param %ghost Ghost target that has command
//! \param %param Client information for recruit command
//! \param %clCmd Command to client after unit is successfully created and
//! ghosted
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnRecruitCmdBtn(%client, %ghost, %param, %clCmd)
{
   // Get client sent information
   %cb      = %clCmd;
   %cmdData = getWord(%param, 0);
   %type    = getWord(%param, 1);
   %index   = getWord(%param, 2);
   
   %tgt = %client.resolveObjectFromGhostIndex(%ghost);
   if(!isObject(%tgt)) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   
   
   // Target needs to be on player team
   if(%tgt.getTeam() != $OST_PLAYER) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   
   // Get building component
   %cmpBldg = slgQueryInterface(%tgt, $CID_BUILDING);
   if(!isObject(%cmpBldg)) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   
   if(!%cmdData.canPurchaseCommand()) {
      %error = slgGetUIString("id_errhire_nogold");
      %unit  = slgGetObjectString(%type);
      %error = slgFormatUIString(%error, %cmdData.goldCost, %unit);
      tsSendAlertMessage(%error);
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   
   // If we have enough resources then deduct resources
   %cmdData.purchaseCommand();
   %object = CreateSaveObject(%type, "", %tgt.getTeam());
   if(!isObject(%object)) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   
   // Place object at door location of target
   %bldgPos = %tgt.getPosition();
   %doorPos = %cmpBldg.getDoor();
   %location = slgGetCharacterPlacement(getWord(%doorPos, 0), getWord(%doorPos, 1));
   %xLoc = getWord(%location, 0);
   %yLoc = getWord(%location, 1);
   %object.setPosition(%xLoc, %yLoc);
   %object.health = %type.healthMax;
   
   // Schedule recruit reponse
   schedule(100, 0, "checkForRecruitResponse", %client, %cb, %tgt, %object, %index);
}

////////////////////////////////////////////////////////////////////////////////
//! Callback when the demolish command button has been clicked on the client
//! \param %client Client that clicked button
//! \param %target Target of demolish command and command data
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnDemolishCmdBtn(%client, %target)
{
   if(!isObject(%client)) {
      return;
   }
   
   %svrTgt = %client.resolveObjectFromGhostIndex(%target);
   if(!isObject(%svrTgt)) {
      return;
   }
   
   // Target should be on player's team
   if(%svrTgt.getTeam() != $OST_PLAYER) {
      return;
   }
   
   // Target should be a building
   if(!slgIsBuilding(%svrTgt)) {
      return;
   }
   
   // Switch to destruction state
   %svrTgt.health = 0;
}

////////////////////////////////////////////////////////////////////////////////
//! Callback when the quit job command button has been pressed on the client
//! \param %client Client that clicked button
//! \param %target Target character that is quitting and command data
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnQuitJobCmdBtn(%client, %target)
{
   if(!isObject(%client)) {
      return;
   }
   
   // Get target object
   %svrTgt = %client.resolveObjectFromGhostIndex(%target);
   if(!isObject(%svrTgt)) {
      return;
   }
   
   // Target should be a character and be employed
   %cmpChar = slgQueryInterface(%svrTgt, $CID_CHARACTER);
   if(!isObject(%cmpChar)) {
      return;
   }
   if(!%cmpChar.hasWork()) {
      return;
   }
   
   // Unemploy character
   slgUnemployObject(%svrTgt);
}

////////////////////////////////////////////////////////////////////////////////
//! Callback when the dismiss hired unit command button has been pressed on the 
//! client
//! \param %client Client that clicked button
//! \param %target Target character that is being dismissed and command data
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnDismissCmdBtn(%client, %target)
{
   %svrTgt = %client.resolveObjectFromGhostIndex(%target);
   if(!isObject(%client) || !isObject(%svrTgt)) {
      return;
   }
   
   // Target should be a character
   %cmpChar = slgQueryInterface(%svrTgt, $CID_CHARACTER);
   if(!isObject(%cmpChar)) {
      return;
   }
   
   // Target should be on the player's team
   if(!%svrTgt.isOnTeam($OST_PLAYER)) {
      return;
   }
   
   // Let AI know to remove character from play (walk to edge of map? 
   // Do something besides delete?)
   %svrTgt.delete();
   commandToClient(%client, 'RemoveFromSelection', %target);
}

////////////////////////////////////////////////////////////////////////////////
//! Callback when the production swap command button has been clicked on the 
//! client
//! \param %client Client that clicked button
//! \param %target Ghost target that has command
//! \param %param Client information for swap command. Contains CommandData id
//! and produce being swapped to
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnProductionSwapCmdBtn(%client, %target, %param)
{
   // Get client sent information
   %cmdData = getWord(%param, 0);
   %produce = getWord(%param, 1);
   %index   = getWord(%param, 2);
   
   if(!isObject(%client)) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   
   // Get server object
   %svrTgt = %client.resolveObjectFromGhostIndex(%target);
   if(!isObject(%svrTgt)) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   %cmpBldg = slgQueryInterface(%svrTgt, $CID_BUILDING);
   if(!isObject(%cmpBldg)) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   
   // Target needs to be on player team
   if(!%svrTgt.isOnTeam($OST_PLAYER)) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   
   // "Purchase" command
   if(!%cmdData.canPurchaseCommand()) {
      notifyClientCmdBtnStatus(%client, %index, false);
      return;
   }
   %cmdData.purchaseCommand();
   
   
   // Swap produce
   // Pulling in gold exclusively
   if(%produce $= "gold") {
      %cmpBldg.startExclusiveProduce($Resource::Gold);
   }
   // Pulling in wood exclusively
   else if(%produce $= "wood") {
      %cmpBldg.startExclusiveProduce($Resource::Wood);
   }
   // Pulling in food exclusively
   else if(%produce $= "food") {
      %cmpBldg.startExclusiveProduce($Resource::Food);
   }
   else if(%produce $= "notax") {
      %cmpBldg.setCurrentTax(%produce);
   }
   else if(%produce $= "lowtax") {
      %cmpBldg.setCurrentTax(%produce);
   }
   else if(%produce $= "hightax") {
      %cmpBldg.setCurrentTax(%produce);
   }
   // Swapping out crop or livestock
   else {
      %cmpBldg.setProduce(%produce);
   }
   
   // Notify client of success
   notifyClientCmdBtnStatus(%client, %index, true);
}

////////////////////////////////////////////////////////////////////////////////
//! Callback when the item purchase command button has been clicked on the 
//! client
//! \param %client Client that clicked button
//! \param %param Client information for purchase command. Contains 
//! CommandData id and item purchased
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnItemPurchaseCmdBtn(%client, %param)
{
   if(!isObject(%client)) {
      return;
   }
   
   // Get command data
   %cmdData = getWord(%param, 0);
   if(!isObject(%cmdData)) {
      return;
   }
   
   // Get item
   %item = getWord(%param, 1);
   
   // Make sure item can be purchased
   if(!%cmdData.canPurchaseCommand()) {
      if(%item == $INV_DYNAMITE) {
         %error = slgGetUIString("id_errdyn_nogold");
         %error = slgFormatUIString(%error, %cmdData.goldCost);
         tsSendAlertMessage(%error);
      }
      else if(%item == $INV_HEALING) {
         %error = slgGetUIString("id_errheal_nogold");
         %error = slgFormatUIString(%error, %cmdData.goldCost);
         tsSendAlertMessage(%error);
      }
      return;
   }
   
   // Get slot for item
   %slot = invGetSlotForItem(%client, %item);
   if(%slot == -1) {
      return;
   }
   
   // Make sure we can add another item
   if(!invCanPushItem(%client, %slot)) {
      return;
   }
   
   // Purchase item
   %cmdData.purchaseCommand();
   invPushItemInInventory(%client, %slot);
   MsgSender.postMsg($MSG_TOOLPURCHASE, $MRT_LOCAL, %item);
}

////////////////////////////////////////////////////////////////////////////////
//! Callback when the building upgrade command button has been clicked on the 
//! client
//! \param %client Client that clicked button
//! \param %target Ghost target that has command
//! \param %param Client information for command. Contains new building type
//! after upgrade and command data datablock
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnBldgUpgradeCmdBtn(%client, %target, %param)
{
   // Needs to be a valid building
   %svrTgt = %client.resolveObjectFromGhostIndex(%target);
   if(!isObject(%svrTgt)) {
      return;
   }
   %oldCmpBldg = slgQueryInterface(%svrTgt, $CID_BUILDING);
   if(!isObject(%oldCmpBldg)) {
      return;
   }
   
   // Building needs to be on player team
   if(!%svrTgt.isOnTeam($OST_PLAYER)) {
      return;
   }
   
   // Get command data and type of building
   %cmdData = getWord(%param, 0);
   %type    = getWord(%param, 1);
   
   // Check if command can be purchased
   if(!%cmdData.canPurchaseCommand()) {
      %error = slgGetUIString("id_errupgrade_noresources");
      %bldg  = slgGetObjectString(%svrTgt.getType());
      %error = slgFormatUIString(%error, %cmdData.goldCost, %cmdData.woodCost, %bldg);
      tsSendAlertMessage(%error);
      return;
   }
   %cmdData.purchaseCommand();
   
   // Upgrade
   UpgradeBuilding(%oldCmpBldg, %type);
}

////////////////////////////////////////////////////////////////////////////////
//! Callback when the resource trade command button has been clicked on the 
//! client
//! \param %client Client that clicked button
//! \param %param Client information for resource trade command. Contains 
//! CommandData id
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnResourceTradeCmdBtn(%client, %param)
{
   %cmdData = %param;
   
   // Check if we can purchase the command
   if(!%cmdData.canPurchaseCommand()) {
      %error = slgGetUIString("id_errtrade_noresources");
      if(%cmdData.goldCost > 0) {
         %cost = %cmdData.goldCost;
         %need = slgGetUIString("id_resource_gold");
         if(%cmdData.woodGain > 0) {
            %gain = %cmdData.woodGain;
            %want = slgGetUIString("id_resource_wood");
         }
         else if(%cmdData.foodGain > 0) {
            %gain = %cmdData.foodGain;
            %want = slgGetUIString("id_resource_food");
         }
      }
      else if(%cmdData.woodCost > 0) {
         %cost = %cmdData.woodCost;
         %need = slgGetUIString("id_resource_wood");
         %gain = %cmdData.goldGain;
         %want = slgGetUIString("id_resource_gold");
      }
      else if(%cmdData.foodCost > 0) {
         %cost = %cmdData.foodCost;
         %need = slgGetUIString("id_resource_food");
         %gain = %cmdData.goldGain;
         %want = slgGetUIString("id_resource_gold");
      }
      %error = slgFormatUIString(%error, %cost, %need, %gain, %want);
      tsSendAlertMessage(%error);
      return;
   }
   
   // Purchase command
   %cmdData.purchaseCommand();
   
   // Play sound
   commandToClient(%client, 'PlaySFXSound', audio_itemsell);
}

////////////////////////////////////////////////////////////////////////////////
//! Callback when the parade command button has been clicked on the client
//! \param %client Client that clicked button
//! \param %target Ghost target that has command
//! \param %param Client information for command. Contains command data id that
//! generated button that issued click
////////////////////////////////////////////////////////////////////////////////
function serverCmdOnParadeCmdBtn(%client, %target, %param)
{
   if(!isObject(%client)) {
      return;
   }
   
   // Get target
   %svrTgt = %client.resolveObjectFromGhostIndex(%target);
   if(!isObject(%svrTgt)) {
      return;
   }
   
   // Target must be on player team and must be a building
   if(!%svrTgt.isOnTeam($OST_PLAYER)) {
      return;
   }
   if(!slgIsBuilding(%svrTgt)) {
      return;
   }
   
   // Get command data
   %cmdData = %param;
   
   // Purchase command
   if(!%cmdData.canPurchaseCommand()) {
      return;
   }
   %cmdData.purchaseCommand();
   
   // Create particle effect over target building
   
   // Start parade
   paradeStart(%cmdData, %svrTgt);
}

////////////////////////////////////////////////////////////////////////////////
//! This callback is received when the accept button on the task dialog has
//! been pressed. Server determines if resource requirement is met and notifies
//! task system and client as appropriate
//! \param %client Client that issued request
//! \param %rscStr String parameter that contains resource and resource count
//! information
////////////////////////////////////////////////////////////////////////////////
function serverCmdAcceptTaskBtnClk(%client, %rscStr)
{
   %word = 0;
   %rscCnt = getWordCount(%rscStr) / 2;
   
   // For each resource do
   for(%i = 0; %i < %rscCnt; %i++) {
      // Get the resource and count
      %rsc = getWord(%rscStr, %word);
      %word++;
      %count = getWord(%rscStr, %word);
      %word++;
      
      // If we don't have enough resources we can't accept
      if(rsGetResourceCount(%rsc) < %count) {
         commandToClient(%client, 'AcceptTaskBtnClkAck', false);
         return;
      }
      
      // Deduct resources
      else {
         %svrRsc = rsGetResource(%rsc);
         %svrRsc.decreaseCount(%count);
      }
   }
   
   // Success
   commandToClient(%client, 'AcceptTaskBtnClkAck', true);
}

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

function UpdateObjectToPlace(%object)
{
   $ObjectToPlace = %object;
}

/*
function serverCmdDestroyLinkObject(%client, %ghostID)
{
   %object = %client.resolveObjectFromGhostIndex(%ghostID);
   while (isObject(%object) == true)
   {
      %nextObject = %object.getNextLinkObj();
      %object.DeleteObject();
      %object = %nextObject;
   }
}
*/

//-Dispatcher Commands----------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
//! Check if the build command has been sent and detect if the build should be 
//! executed 
//! \param %target Target of command
//! \param %selectedList List of selected objects
//! \param %client Client that issued command
//! \retval bool True if the command was successful
////////////////////////////////////////////////////////////////////////////////
$ObjectToPlace = 0;
$ClientToPlace = 0;
function onBuildCommand(%target, %selectedList, %client)
{
   // make sure there is a building target
   %targetList = CmdInterpreter.interpretTarget();
   if (%targetList.getSize() == 0)
   {
      echo("Warning: build command sent with no building targets.  Nothing can be built.");
      csEndWaitForCmd();
      return false;
   }
   
   // the target must be a position for a newly placed building,
   // but if a valid target object is given, let AI component
   // determine who gets to the building first to actually
   // build the building
   if (PlayGui.hasObject() == false && isObject(%target) == true)
   {
      if (AICmd_Build(%target, %selectedList))
      {
         // set the builder for the building
         %builder  = %selectedList.getID(0);
         %building = slgQueryInterface(%target, $CID_BUILDING);
         %building.builder = %builder;
      }
      csEndWaitForCmd();
      return true;
   }
   
   // if there is no object to place, we cannot place it
   if (isObject($ObjectToPlace) == false)
   {
      csEndWaitForCmd();
      return false;
   }
   
   // check if the object is attached to the cursor
   %object = PlayGui.getObject();
   if (isObject(%object) == false)
   {
      csEndWaitForCmd();
      return false;
   }
   
   // if you cannot place the object, do not try to place the object
   if (CanPlaceObject(%object) == false ||
      %object.CanGetToDoor() == false)
   {
      %object = PlayGui.getObject();
      %ghostID = ServerConnection.getGhostID(%object);
      clientCmdSendHudBuildMessage(%ghostID);
      csEndWaitForCmd();
      return false;
   }

   // get the building target, and if it can be placed where it is
   // currently located, then the build command should succeed;
   // otherwise, it cannot be placed
   %oldPosition = $ObjectToPlace.position;
   
   // use the position of the client-side object
   %client = ClientGroup.getObject(0);
   %ghostID = %client.getGhostID($ObjectToPlace);
   %clientObject = ServerConnection.resolveGhostID(%ghostID);
   $ObjectToPlace.position = %clientObject.position;
   //$ObjectToPlace.position = %target;
   updateObjectPlacement($ObjectToPlace);
   if (CanPlaceObject($ObjectToPlace) == true)
   {
      // if we are placing a link object (a bridge), we need to figure
      // out which bridge door we are going to to start the building      
      if ($ObjectToPlace.isLinkObj() == true)
      {
         %character = %selectedList.getID(0);
         %ai = slgQueryInterface(%character, $CID_AI);
         
         %first = $ObjectToPlace.getFirstLinkObj();
         %firstComponent = slgQueryInterface(%first, $CID_BUILDING);
         %firstDoor = %firstComponent.getDoor();
         %firstDistance = %ai.pathingDistanceToLocation(getWord(%firstDoor, 0),
            getWord(%firstDoor, 1));

         %last = $ObjectToPlace.getLastLinkObj();
         %lastComponent = slgQueryInterface(%last, $CID_BUILDING);
         %lastDoor = %lastComponent.getDoor();
         %lastDistance = %ai.pathingDistanceToLocation(getWord(%lastDoor, 0),
            getWord(%lastDoor, 1));
         
         if (%firstDistance == -1 && %lastDistance == -1)
         {
            %client = ClientGroup.getObject(0);
            %ghostID = %client.getGhostId($ObjectToPlace);
            commandToClient(%client, 'SendHudBuildMessage', %ghostID);
            csEndWaitForCmd();
            return false;
         }
         
         %direction = 1;
         
         if (%firstDistance == -1)
         {
            %direction = -1;
         }
         else if (%lastDistance != -1 && %lastDistance < %firstDistance)
         {
            %direction = -1;
         }
         
         if (%direction == -1)
         {
            $ObjectToPlace = $ObjectToPlace.getLastLinkObj();
         }
         
         $ObjectToPlace.linkStartDirection = %direction;
      }

      // if the ai has determined that it can also build the building,
      // tell the client to remove the building object from the cursor,
      // and start the build process
      %success = AICmd_Build($ObjectToPlace, %selectedList, true);
      if (%success == true)
      {         
         // set the builder for the building
         %builder  = %selectedList.getID(0);
         %building = slgQueryInterface($ObjectToPlace, $CID_BUILDING);
         %building.builder = %builder;
         
         SendGhostToClient($ClientToPlace, 'RemoveFromCursor', $ObjectToPlace);

         // when the building construction is placed, tell the client to
         // display how many resources have been lost due to the transaction
         %datablock = $ObjectToPlace.getDatablock();
         SendProductionToClient($ObjectToPlace, -%datablock.goldCost @
            " gold " @ -%datablock.woodCost @ " wood");

         /*
         // now that the object is being placed, it should be saved into
         // mission files, then start the construction
         if ($ObjectToPlace.isLinkObj() == true)
         {
            %client = ClientGroup.getObject(0);
            %ghostID = %client.getGhostID($ObjectToPlace);
            commandToClient(%client, 'UpdateBridgeLength', %ghostID);
         }
         else
         {
            PlaceConstruction($ObjectToPlace);
         }
         */
         
         PlaceConstruction($ObjectToPlace);
      }
      else
      {
         csEndWaitForCmd();
      }
      
      return %success;
   }
   
   %client = ClientGroup.getObject(0);
   %ghostID = %client.getGhostId($ObjectToPlace);
   commandToClient(%client, 'SendHudBuildMessage', %ghostID);
   csEndWaitForCmd();
   return false;
}

////////////////////////////////////////////////////////////////////////////////
//! Called when the server receives an employ event
//! \param %target Target of employ command
//! \param %selObjs List of selected objects
//! \param %client Client that issued command
//! \retval bool True if the command was successful
////////////////////////////////////////////////////////////////////////////////
function onEmployCommand(%target, %selObjs, %client)
{
   if(!isObject(%selObjs)) {
      return false;
   }
   
   // Target must be an object of some sort
   if(!isObject(%target)) {
      return false;
   }
   
   // Target should be on our team
   if(!%target.isOnTeam($OST_PLAYER)) {
      slgSendHudMessage(%client, "id_erremploy_wrongteam", %target.getType());
      return false;
   }
   
   // Should only be one selected object
   if(%selObjs.getSize() != 1) {
      return false;
   }
   
   // Selected object should be on our team
   %selObj = %selObjs.getID(0);
   if(!isObject(%selObj)) {
      return false;
   }
   if(%selObj.getTeam() != $OST_PLAYER) {
      return false;
   }
   
   // Selected object should be a character and target should be a building
   %cmpChar = slgQueryInterface(%selObj, $CID_CHARACTER);
   if(!isObject(%cmpChar)) {
      return false;
   }
   %cmpBldg = slgQueryInterface(%target, $CID_BUILDING);
   if(!isObject(%cmpBldg)) {
      return false;
   }
   
   if(%cmpBldg.hasStatus($BuildingStatus::NoGold)
   || %cmpBldg.hasStatus($BuildingStatus::NoWood)) {
      slgSendHudMessage(%client, "id_erremploy_noresource");
      return false;
   }
   
   // Character should be looking for employment
   if(%cmpChar.hasWork()) {
      return false;
   }
   
   // Character should be able to work
   if(!%cmpChar.getDataBlock().canWork) {
      return false;
   }
   
   // Character protesting
   if(%cmpChar.isProtestingHome()) {
      %msg = slgGetUIString("id_erremploy_protesting");
      %msg = slgFormatUIString(%msg, %selObj.name);
      commandToClient(%client, 'SendHudMessage', %msg);
      return false;
   }
   
   // Building should have employment opportunity
   if(!%cmpBldg.canAddEmployee()) {
      return false;
   }

   // Employ
   %target.employing = true;
   slgEmployObject(%selObj, %target);
   %target.employing = "";
   
   //Dispatch the AI command so that the unit visually becomes employed.
   AICmd_Employ(%target,%selObjs);
   return true;
}

////////////////////////////////////////////////////////////////////////////////
//! Called when the server receives a pick-up or quick job event
//! \param %target Target of pick-up or quick job command
//! \param %selObjs List of selected objects
//! \param %client Client that issued command
//! \retval bool True if the command was successful
////////////////////////////////////////////////////////////////////////////////
function onPropCommand(%target, %selObjs, %client)
{
   if(!isObject(%target) || !isObject(%selObjs)) {
      return false;
   }

   // Should have at least one person selected
   if(!%selObjs.getSize()) {
      return false;
   }
   
   // selected objects must be on player team (note that the target
   // IS NOT required to be on the player team; they can be neutral or
   // other, so this was removed)
   if(!%selObjs.isOnTeam($OST_PLAYER)) {
      return false;
   }
   
   // Target must be a prop and selected objects must be characters
   %cmpProp = slgQueryInterface(%target, $CID_PROP);
   if(!isObject(%cmpProp)) {
      return false;
   }
   if(!%selObjs.isOfObjectType($CID_CHARACTER)) {
      return false;
   }
   
   // Target prop must be a pick-up or a quick job
   if(!%cmpProp.isPickUpProp() && !%cmpProp.isJobProp()) {
      return false;
   }
   
   // Get size of selected list
   %count = %selObjs.getSize();
   
   // If prop is a quick job prop, then group selected must contain someone to
   // pick it up (hero or civ)
   if(%cmpProp.isJobProp()) {
      %bJobOk = false;
      for(%i = 0; %i < %count; %i++) {
         %object  = %selObjs.getID(%i);
         %cmpChar = slgQueryInterface(%object, $CID_CHARACTER);
         if(%cmpChar.canQuickJob()) {
            %bJobOk = true;
            break;
         }
      }
      if(!%bJobOk) {
         if(%count > 1) {
            %msg = slgGetUIString("id_error_combat_quick_job");
         }
         else {
            %msg  = slgGetUIString("id_error_combat_quick_job_single");
            %type = slgGetObjectString(%selObjs.getID(0).getType());
            %msg  = slgFormatUIString(%msg, %type);
         }
         sendFeedbackMsg(%client, %msg);
         return false;
      }
   }
   
   // Get the character closest to the prop that is not collecting anything,
   // if possible. If any characters are pulling from the same prop, then bail
   %smPropDis = "";
   %smNoneDis = "";
   %smPropObj = 0;
   %smNoneObj = 0;
   
   for(%i = 0; %i < %count; %i++) {
      %object  = %selObjs.getID(%i);
      %cmpChar   = slgQueryInterface(%object, $CID_CHARACTER);
      
      // If this is a job prop and this unit can not quick job then
      // this unit can not be considered
      if(%cmpProp.isJobProp() && !%cmpChar.canQuickJob()) {
         continue;
      }
      
      // Calculate square distance to target
      %distance = %object.sqDistanceTo(%target);
      
      // Character collecting prop
      if(%cmpChar.isCollecting()) {
         // Already pulling from this prop
         if(%cmpChar.getCollectionProp() == %target) {
            return false;
         }
         else {
            // If we already have an object and its distance is equal to or
            // smaller than this object's distance to the prop then continue
            if(isObject(%smPropObj) && %smPropDis <= %distance) {
               continue;
            }
            %smPropDis = %distance;
            %smPropObj = %object;
         }
      }
      // Character not collecting prop
      else {
         // If we already have an object and its distance is equal to or
         // smaller than this object's distance to the prop then continue
         if(isObject(%smNoneObj) && %smNoneDis <= %distance) {
            continue;
         }
         %smNoneDis = %distance;
         %smNoneObj = %object;
      }
   }
   
   // Get best character choice to collect prop (prefer one not collecting to one
   // that is)
   if(isObject(%smPropObj) && !isObject(%smNoneObj)) {
      %object = %smPropObj;
      
      // Stop collection from the old prop by destroying the collection timer
      //  before continuing on
      %cmpChar = slgQueryInterface(%object, $CID_CHARACTER);
      if(isObject(%cmpChar.collectTimer)) {
         %cmpChar.collectTimer.delete();
         %cmpChar.collectTimer = 0;
      }
   }
   else {
      %object = %smNoneObj;
   }
   
   //Dispatch the AI command so that the unit visually picks up the object.
   %pickupList = new SLGameObjList();
   %pickupList.addObject(%object);
   AICmd_Pickup(%target,%pickupList);
   %pickupList.delete();
   
   return true;
}

////////////////////////////////////////////////////////////////////////////////
//! Called when the server receives a repair event
//! \param %target Target of repair command
//! \param %selObjs List of selected objects
//! \param %client Client that issued command
//! \retval bool True if the command was successful
////////////////////////////////////////////////////////////////////////////////
function onRepairCommand(%target, %selObjs, %client)
{
   if(!isObject(%target) || !isObject(%selObjs)) {
      return false;
   }
   
   // Should only have one person selected
   if(%selObjs.getSize() != 1) {
      return false;
   }
   
   // Target should be a building
   %cmpBldg = slgQueryInterface(%target, $CID_BUILDING);
   if(!isObject(%cmpBldg)) {
      return false;
   }
   
   // Building should be in production state
   if(%cmpBldg.getState() != $BuildingState::Production) {
      return false;
   }
   
   // Building should need to be repaired
   if(%target.health >= %target.getMaxHealth()) {
      return false;
   }
   
   // Objects should be on same team
   if(!%selObjs.isOnTeam($OST_PLAYER)) {
      return false;
   }
   if(!%target.isOnTeam($OST_PLAYER)) {
      slgSendHudMessage(%client, "id_errrepair_wrongteam", %target.getType());
      return false;
   }
   
   // At this point, we should instruct the character to move towards object to heal it
   if(!AICmd_Repair(%target, %selObjs)) {
      return false;
   }
   return true;
}

////////////////////////////////////////////////////////////////////////////////
//! Called when the server receives a tool use event
//! \param %target Target of tool use command
//! \param %selObjs List of selected objects
//! \param %client Client that issued command
//! \retval bool True if the command was successful
////////////////////////////////////////////////////////////////////////////////
function onToolCommand(%target, %selObjs, %client)
{
   if(!isObject(%selObjs) || !isObject(%client)) {
      return false;
   }
   
   // Selected objects (if any) should be on player team
   if(!%selObjs.isOnTeam($OST_PLAYER)) {
      return false;
   }
   
   %tool = invServerGetSelectedItem(%client);
   
   // Execute tools and notify client on success
   %success = toolsOnExecute(%tool, %target, %selObjs);
   if(%success) {
      commandToClient(%client, 'onToolExecuteSuccess', %tool);
   }
   return %success;
}

////////////////////////////////////////////////////////////////////////////////
//! Called when the server receives a fight fire event
//! \param %target Target of fight fire command
//! \param %selObjs List of selected objects
//! \param %client Client that issued command
//! \retval bool True if the command was successful
////////////////////////////////////////////////////////////////////////////////
function onFightFireCommand(%target, %selObjs, %client)
{
   if(!isObject(%target) || !isObject(%selObjs)) {
      return false;
   }
   
   // Selected objects should be on player team
   if(!%selObjs.isOnTeam($OST_PLAYER)) {
      return false;
   }
   
   // Target should be a building on the player's team
   if(!%target.isOnTeam($OST_PLAYER)) {
      slgSendHudMessage(%client, "id_errfightfire_wrongteam", %target.getType());
      return false;
   }
   %cmpBldg = slgQueryInterface(%target, $CID_BUILDING);
   if(!isObject(%cmpBldg)) {
      return false;
   }
   
   // Target should be on fire
   if(!%cmpBldg.onFire()) {
      return false;
   }
   
   // There should be a well or water tower
   %bldgList = slgGetServerBuildingList();
   if(!isObject(%bldgList)) {
      return false;
   }
   if(!%bldgList.containsObject("well", $OST_PLAYER) &&
      !%bldgList.containsObject("watertower", $OST_PLAYER)) {
      return false;
   }
   
   // Notify AI to fight fire
   return AICmd_FightFire(%target,%selObjs);
}

////////////////////////////////////////////////////////////////////////////////
//! Called when the server receives a reform event
//! \param %target Target of reform command
//! \param %selObjs List of selected objects
//! \param %client Client that issued command
//! \retval bool True if the command was successful
////////////////////////////////////////////////////////////////////////////////
function onReformCommand(%target, %selObjs, %client)
{
   if(!isObject(%target) || !isObject(%selObjs)) {
      return false;
   }
   
   // Check team
   if(!%target.isOnTeam($OST_PLAYER)) {
      return false;
   }
   if(!%selObjs.isOnTeam($OST_PLAYER)) {
      return false;
   }
   
   // Should be a character
   %cmpChar = slgQueryInterface(%target, $CID_CHARACTER);
   if(!isObject(%cmpChar)) {
      return false;
   }
   
   // Should be drunk
   if(!%cmpChar.inState($CharacterState::Drunk)) {
      return false;
   }
   
   // Selected objects need to be characters and need to be able to reform drunks
   %selSize = %selObjs.getSize();
   for(%i = 0; %i < %selSize; %i++) {
      %selChar = slgQueryInterface(%selObjs.getID(%i), $CID_CHARACTER);
      if(!isObject(%selChar)) {
         return false;
      }
      if(!%selChar.getDatablock().canReformDrunk) {
         return false;
      }
   }
   
   // Sheriff's office needs to exist
   %count = slgGetServerBuildingListMatchCount(
      "SheriffsOffice", 
      $OST_PLAYER, 
      $BuildingState::Production
   );
   if(%count <= 0) {
      slgSendAlertMessage(%client, "id_cmderr_nosheriff");
      return false;
   }
   
   //Call AI
   if(!AICmd_ReformDrunk(%target, %selObjs.getID(0)))
      return false;
   
   // Call for reform
   MsgSender.postMsg($MSG_SLGOBJREFORM, $MRT_LOCAL, %target, %selObjs.getID(0));
   return true;
}
//------------------------------------------------------------------------------

//-Helper Methods---------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
//! Sends a feedback message to the client when a command fails for some reason
//! \param %client Client to send to
//! \param %msg Message to send
////////////////////////////////////////////////////////////////////////////////
function sendFeedbackMsg(%client, %msg)
{
   commandToClient(%client, 'SendHudMessage', %msg);
}

////////////////////////////////////////////////////////////////////////////////
//! Notifies the client if a command for a command button has succeeded or not
////////////////////////////////////////////////////////////////////////////////
function notifyClientCmdBtnStatus(%client, %index, %success)
{
   commandToClient(%client, 'CmdBtnStatus', %index, %success);
}

////////////////////////////////////////////////////////////////////////////////
//! Scheduled event that will send a recruit command response to the client
//! after the object recruited has a valid ghost id
//! \param %client Client to send to
//! \param %method Method on client
//! \param %bldg Building that recruited object
//! \param %recruit Object recruited
//! \param %index Index of command button
////////////////////////////////////////////////////////////////////////////////
function checkForRecruitResponse(%client, %method, %bldg, %recruit, %index)
{
   // Get the ghost id
   %ghost = %client.getGhostID(%recruit);
   
   // If there is a valid ghost, notify client about recruit
   if(%ghost != -1) {
      commandToClient(%client, %method, %client.getGhostID(%bldg), %ghost, %index);
   }
   
   // Otherwise reschedule event
   else {
      schedule(100, 0, "checkForRecruitResponse", %client, %method, %bldg, %recruit, %index);
   }
}

////////////////////////////////////////////////////////////////////////////////
//! Used to swap people after a building has been upgraded (changed) and has
//! entered the production state
//! \param %oldBldgObj Old building that will be deleted
//! \param %newBldgObj Building upgrade
////////////////////////////////////////////////////////////////////////////////
function checkForPeopleSwap(%oldBldgObj, %newBldgObj)
{
   if(!isObject(%oldBldgObj) || !isObject(%newBldgObj)) {
      return;
   }
   
   // Get building components
   %oldCmpBldg = slgQueryInterface(%oldBldgObj, $CID_BUILDING);
   %newCmpBldg = slgQueryInterface(%newBldgObj, $CID_BUILDING);
   
   // Ready to swap people
   if(%newCmpBldg.getState() == $BuildingState::Production)
   {
      // send the creation message
      slgSendObjCreateMsgLocal(%newBldgObj);
      
      // Copy employees
      %objs = new SLGameObjList();
      %cnt = %oldCmpBldg.getEmployeeCount();
      while(%cnt > 0) {
         %char = %oldCmpBldg.getEmployee(0);
         slgUnemployObject(%char);
         slgEmployObject(%char, %newBldgObj);
         %objs.addObject(%char);
         %cnt = %oldCmpBldg.getEmployeeCount();
      }
      AICmd_Employ(%newBldgObj, %objs);
      %objs.delete();
      
      // Copy tenants
      %cnt = %oldCmpBldg.getTenantCount();
      while(%cnt > 0) {
         %char = %oldCmpBldg.getTenant(0);
         slgUnhouseObject(%char);
         slgHouseObject(%char, %newBldgObj);
         %cnt = %oldCmpBldg.getTenantCount();
      }
      
      // Copy hiders   
      %cnt = %oldCmpBldg.getHiderCount();
      while(%cnt > 0) {
         %char = %oldCmpBldg.getHider(0);
         slgUnhideObject(%char);
         slgHideObject(%char, %newBldgObj);
         %cnt = %oldCmpBldg.getHiderCount();
      }
      
      // Destroy old object
      if(isObject(%oldCmpBldg.timer)) {
         %oldCmpBldg.timer.delete();
      }
      %oldBldgObj.DeleteObject();
      
      // Mesh of new building should now be shown
      %newBldgObj.showMesh(true);
      
      // update the train
      slgTrain_PickTrain();
   }
   
   // Reschedule
   else {
      schedule(100, 0, "checkForPeopleSwap", %oldBldgObj, %newBldgObj);
   }
}
//------------------------------------------------------------------------------

// End svr_cmdmethods.cs