//------------------------------------------------------------------------------
// File: client_cmdinterpret.cs
// This file contains the command interpreter methods
// Author: Matthew Rudge
//------------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
//! Interprets a possible target by casting a ray from the cursor on the camera
//! plane and parallel to the view vector
//! \return SLGameObjList List of objects that are hit
////////////////////////////////////////////////////////////////////////////////
function CmdInterpreter::interpretTarget(%this)
{
   // Using the camera, find a possible object that has been hit
   if(!isObject(PlayGui))
      return "0";
   
   %objSearch = $TypeMasks::TerrainObjectType;
   if (PlayGui.hasObject() == false)
   {
      %objSearch += $TypeMasks::PropObjectType +
         $TypeMasks::BuildingObjectType + $TypeMasks::CharacterObjectType;   
   }
   else
   {
      %objSearch += $TypeMasks::CliffObjectType;
   }

   PlayGui.pointRollover($pointSelectionLength, %objSearch);
   gSelection.updateGroupFromPt($CS_TARGETGROUP);
   %objsHit = gSelection.getSelectedGroup($CS_TARGETGROUP);
   
   // Return objects hit
   return %objsHit;
}

////////////////////////////////////////////////////////////////////////////////
//! Interprets a possible command for a target with the currently selected group
//! \param %target Id of target of command
//! \param %selGrp Id of selected group
//! \return eCmdSysCommands Command system command 
////////////////////////////////////////////////////////////////////////////////
function CmdInterpreter::interpretCommand(%this, %target, %selGrp)
{
   // Nobody selected
   if(%selGrp.getSize() == 0) {
      return $CSC_NONE;
   }
   
   // Everyone selected should be on the player's team and a character
   %selSize = %selGrp.getSize();
   for(%i = 0; %i < %selSize; %i++) {
      // Get object
      %selObj = %selGrp.getID(%i);
      if(!isObject(%selObj)) {
         return $CSC_NONE;
      }
      
      // Check team
      if(!%selObj.isOnTeam($OST_PLAYER)) {
         return $CSC_NONE;
      }
      
      // Check character
      %cmpChar = slgQueryInterface(%selObj, $CID_CHARACTER);
      if(!isObject(%cmpChar)) {
         return $CSC_NONE;
      }
      
      // Characters can not be in one of these states
      if(%cmpChar.inState($CharacterState::Drunk)) {
         if(!csCmdDragRunning()) {
            %selObj.playVocal("DDNY");
         }
         return $CSC_NONE;
      }
      if(%selObj.isHealing) {
         return $CSC_NONE;
      }
   }
   
   // Interpret the command based on the type of the target
   if(slgIsTerrain(%target)) {
      return $CSC_MOVE;
   }
   else if(slgIsCharacter(%target)) {
      return %this.interpretCmdOnCharacter(%target, %selGrp);
   }
   else if(slgIsBuilding(%target)) {
      return %this.interpretCmdOnBuilding(%target, %selGrp);
   }
   else if(slgIsProp(%target)) {
      return %this.interpretCmdOnProp(%target, %selGrp);
   }
   else {
      return $CSC_NONE;
   }
}

////////////////////////////////////////////////////////////////////////////////
// Interprets what commands are possible on the targeted character
//! \param %target Id of target of command
//! \param %selGrp Id of selected group
//! \return eCmdSysCommands Command system command 
////////////////////////////////////////////////////////////////////////////////
function CmdInterpreter::interpretCmdOnCharacter(%this, %target, %selGrp)
{
   // Get target team
   %tgtTeam = %target.getTeam();

   // Reform if drunk and not in reform state
   if(%tgtTeam == $OST_PLAYER) {
      %cmpChar = slgQueryInterface(%target, $CID_CHARACTER);
      if(%cmpChar.inState($CharacterState::Drunk) && 
        !%cmpChar.inState($CharacterState::Reform)) {
         
         // Characters need to be able to reform drunks
         %size = %selGrp.getSize();
         for(%i = 0; %i < %size; %i++) {
            %selChar = slgQueryInterface(%selGrp.getID(%i), $CID_CHARACTER);
            if(!%selChar.getDatablock().canReformDrunk) {
               return $CSC_MOVE;
            }
         }
         return $CSC_REFORM;
      }
   }
   
   // Attack if on enemy team
   else if(%tgtTeam != $OST_NEUTRAL &&
           %tgtTeam != $OST_NONE) {
        return $CSC_ATTACK;
   }
   
   // Default is move
   return $CSC_MOVE;
}

////////////////////////////////////////////////////////////////////////////////
// Interprets what commands are possible on the targeted building
//! \param %target Id of target of command
//! \param %selGrp Id of selected group
//! \return eCmdSysCommands Command system command
////////////////////////////////////////////////////////////////////////////////
function CmdInterpreter::interpretCmdOnBuilding(%this, %target, %selGrp)
{
   // Get target team
   %tgtTeam = %target.getTeam();
         
   // Single selection commands
   if(%selGrp.getSize() == 1) {
      %selObj = %selGrp.getID(0);
      
      // Target on same or neutral team
      if(%tgtTeam == $OST_PLAYER || %tgtTeam == $OST_NEUTRAL || %tgtTeam == $OST_NONE) {
         return %this.interpretSngleCmdOnTeamBldg(%target, %selObj);
      }
            
      // Target on enemy team
      else {
         return $CSC_ATTACK;
      }
   }
   
   // Multiple selection commands
   else {
      // Target on same team
      if(%tgtTeam == $OST_PLAYER) {
         return %this.interpretMultiCmdOnTeamBldg(%target, %selGrp);
      }
      
      // Target on neutral team
      else if(%tgtTeam == $OST_NEUTRAL || %tgtTeam == $OST_NONE) {
         return $CSC_MOVE;
      }
      
      // Target on enemy team
      else {
         return $CSC_ATTACK;
      }
   }
}

////////////////////////////////////////////////////////////////////////////////
//! Interprets what commands are possible on the targeted prop
//! \param %target Id of target of command
//! \param %selGrp Id of selected group
//! \return eCmdSysCommands Command system command
////////////////////////////////////////////////////////////////////////////////
function CmdInterpreter::interpretCmdOnProp(%this, %target, %selGrp)
{
   // Get prop component
   %cmpProp = slgQueryInterface(%target, $CID_PROP);
   if(!isObject(%cmpProp)) {
      return $CSC_NONE;
   }
   
   // Pick up prop
   if(%cmpProp.isPickUpProp()) {
      return $CSC_PICKUP;
   }
   
   // Quick job prop
   else if(%cmpProp.isJobProp()) {
      return $CSC_QUICKJOB;
   }
   
   // Otherwise walk to prop
   else {
      return $CSC_MOVE;
   }
}

////////////////////////////////////////////////////////////////////////////////
//! Interprets what commands are possible on the targeted team building with
//! only one object selected.
//! \param %target Id of target building
//! \param %selObj Id of selected object
//! \return eCmdSysCommands Command system command
////////////////////////////////////////////////////////////////////////////////
function CmdInterpreter::interpretSngleCmdOnTeamBldg(%this, %target, %selObj)
{ 
   // Target should have building component
   %cmpBldg = slgQueryInterface(%target, $CID_BUILDING);
   if(!isObject(%cmpBldg)) {
      return $CSC_NONE;
   }
   
   // Get character component
   %cmpChar = slgQueryInterface(%selObj, $CID_CHARACTER);
   if(!isObject(%cmpChar)) {
      return $CSC_NONE;
   }
   
   // Get state of building
   %bldgState = %cmpBldg.getState();
   
   // Production state
   if(%bldgState == $BuildingState::Production) {
      
      // If building is on fire then
      if(%cmpBldg.onFire()) {
         %clientBldgs = slgGetClientBuildingList();
         if(!isObject(%clientBldgs)) {
            return $CSC_MOVE;
         }
         
         // If there is a building to supply water than fight it
         if(%clientBldgs.containsObject("well", $OST_PLAYER) ||
            %clientBldgs.containsObject("watertower", $OST_PLAYER)) {
            return $CSC_FIGHTFIRE;
         }
         
         // Just move to it
         return $CSC_MOVE;
      }
      
      // If building is not at max health then
      if(%target.health < %target.getMaxHealth()) {
         // If not already under repair then repair it
         if(!%cmpBldg.underRepair()) {
            return $CSC_REPAIR;
         }
      }
      
      // Employ at building
      if(%cmpBldg.canAddEmployee()) {
         if(!%cmpChar.hasWork() && %cmpChar.getDataBlock().canWork) {
            return $CSC_EMPLOY;
         }
      }
      
      // Default is move
      return $CSC_MOVE;
   }
   
   // pre-construction
   else if(%bldgState == $BuildingState::NoState) {
      if(%target.isLinkObj()) {
         %target = %target.getFirstLinkObj();
      }
      if(%target.getTeam() == $OST_PLAYER) {
         return $CSC_BUILD;
      }
      
      // Default is move
      return $CSC_MOVE;
   }
   
   // Destroy state and Construction state
   else {
      return $CSC_MOVE;
   }
}

////////////////////////////////////////////////////////////////////////////////
//! Interprets what commands are possible on targeted team building with
//! multiple objects selected.
//! \param %target Id of targeted object
//! \param %selGrp Id of object list
//! \return eCmdSysCommands Command system command
////////////////////////////////////////////////////////////////////////////////
function CmdInterpreter::interpretMultiCmdOnTeamBldg(%this, %target, %selGrp)
{
   // For now just move
   return $CSC_MOVE;
}

// End client_cmdinterpret.cs
