// v2.0.0 -
//::////////////////////////////////////////////////////////////////////////////
//:: FileName:  hark_i0_enhance
//::////////////////////////////////////////////////////////////////////////////
/*
   This file contains code used by henchman when buffing up the party. Modified
  by Pausanias from the original Talent* functions.
*/
//::////////////////////////////////////////////////////////////////////////////
#include "hark_i0_henlvl"
//::////////////////////////////////////////////////////////////////////////////


// * FUNCTION PROTOTYPES


int HenchTalentSummonAllies(int nForce = FALSE);

int GetWasCast(int nIndex, object oTarget);

int HenchTalentUseProtectionOthers(object oDefault = OBJECT_INVALID, int iClearActions = TRUE);

int HenchTalentEnhanceOthers(object oDefault = OBJECT_INVALID, int iAvoidInvisibility = FALSE, int iClearActions = TRUE);


// * FUNCTION DEFINITIONS


//::////////////////////////////////////////////////////////////////////////////
int HenchTalentSummonAllies(int nForce = FALSE)
{
  talent tUse;
  object oMaster = GetRealMaster();
  if (!GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_SUMMONED)) &&
     (nForce || !GetLocalInt(OBJECT_SELF, "DontSummon")))
    {
     tUse = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_OBTAIN_ALLIES, 20);
     if (GetIsTalentValid(tUse))
       {
        ClearActions(CLEAR_I0_ENHANCE_HenchTalentSummonAllies);
        // This is for henchmen wizards, so they dont run off and get killed
        // summoning in allies.
        if (GetIsObjectValid(oMaster))
          { ActionUseTalentAtLocation(tUse, GetLocation(oMaster)); }
        else
          { ActionUseTalentAtLocation(tUse, GetLocation(OBJECT_SELF)); }
        return TRUE;
       }
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int GetWasCast(int nIndex, object oTarget)
{
  int nCast = GetLocalInt(oTarget, "nCast");
  int i;
  for (i = 1; i <= nCast; ++i)
    {
     if (GetIntArray(oTarget, "IndexCast", i) == nIndex) { return TRUE; }
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int HenchTalentUseProtectionOthers(object oDefault = OBJECT_INVALID, int iClearActions = TRUE)
{
  talent tUse, tMass;
  int nType, nFriends, nIndex;
  int nCnt = 1;
  int bValid = FALSE;
  object oTarget;
  object oMaster = GetRealMaster();
  tUse = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE, 20);
  tMass = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT, 20);

  // Pausanias: added option for the spell to have a specified target.
  if (oDefault == OBJECT_INVALID)
    {
     oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);

     // Override the nearest target if the master wants aggressive buff spells.
     if (GetAssociateState(NW_ASC_AGGRESSIVE_BUFF) && GetAssociateState(NW_ASC_HAVE_MASTER))
       { oTarget = oMaster; }

     // Do not enhance target it if it's running away.
     if (oTarget != oMaster)
       {
        if (GetLocalInt(oTarget, "RunningAway"))
          { return FALSE; }
       }
    }
  else
    {
     oTarget = oDefault;

     // Try to get a protection that the target doesn't already have.
     int iDone = FALSE;
     int nTry = 1;
     while (!iDone && GetIsTalentValid(tUse) && nTry <= 5)
       {
        nType = GetTypeFromTalent(tUse);
        nIndex = GetIdFromTalent(tUse);
        iDone = TRUE;
        if (nType == TALENT_TYPE_SPELL)
          {
           if (GetHasSpellEffect(nIndex, oTarget) || GetWasCast(nIndex, oTarget))
             { iDone = FALSE; }
          }
        if (nType == TALENT_TYPE_FEAT)
          {
           if (GetHasFeatEffect(nIndex, oTarget) || GetWasCast(nIndex, oTarget))
             { iDone = FALSE; }
          }
        if (!iDone)
          { tUse = GetCreatureTalentRandom(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE); }
        ++nTry;
       }
     if (!iDone)
       {
        SetLocalInt(OBJECT_SELF, "MaxedOut", TRUE);
        return FALSE;
       }
     else
       {
        if (!iClearActions)
          {
           int nCast = GetLocalInt(oTarget, "nCast");
           ++nCast;
           SetLocalInt(oTarget, "nCast", nCast);
           SetIntArray(oTarget, "IndexCast", nCast, nIndex);
          }
        SetLocalInt(OBJECT_SELF, "MaxedOut", FALSE);
       }
    }

  // Pausanias: Reset spell cast counter.
  SetLocalInt(OBJECT_SELF, "nRoundsSkipped", 0);

  while (GetIsObjectValid(oTarget))
    {
     int iValidTarget = TRUE;

     // Do not enhance target it if it's running away or too far.
     if (oTarget != oMaster)
       {
        if (GetLocalInt(oTarget, "RunningAway"))
          { iValidTarget = FALSE; }
        if (GetDistanceBetween(oTarget, OBJECT_SELF) > 10.0)
          { iValidTarget = FALSE; }
       }

     if (GetIsTalentValid(tUse) && iValidTarget)
       {
        nType = GetTypeFromTalent(tUse);
        nIndex = GetIdFromTalent(tUse);
        if (nType == TALENT_TYPE_SPELL)
          {
           if (!GetHasSpellEffect(nIndex, oTarget))
             {
              if (iClearActions)
                { ClearActions(CLEAR_I0_ENHANCE_HenchTalentUseProOther_1); }
              ActionUseTalentOnObject(tUse, oTarget);
              return TRUE;
             }
          }
        else if(nType == TALENT_TYPE_FEAT)
          {
           if (!GetHasFeatEffect(nIndex, oTarget))
             {
              if (iClearActions)
                {
                 ClearActions(CLEAR_I0_ENHANCE_HenchTalentUseProOther_2);
                 ActionUseTalentOnObject(tUse, OBJECT_SELF);
                }
              else
                { ActionDoCommand(ActionUseTalentOnObject(tUse, OBJECT_SELF)); }
              return TRUE;
             }
          }
        else
          {
           if (iClearActions)
             { ClearActions(CLEAR_I0_ENHANCE_HenchTalentUseProOther_3); }
           ActionUseTalentOnObject(tUse, oTarget);
           return TRUE;
          }
       }
     nCnt++;
     if (oDefault == OBJECT_INVALID)
       { oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); }
     else
       { oTarget = OBJECT_INVALID; }
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int HenchTalentEnhanceOthers(object oDefault = OBJECT_INVALID, int iAvoidInvisibility = FALSE, int iClearActions = TRUE)
{
  talent tInvis;
  talent tUse, tMass;
  int nType, nFriends, nIndex;
  int nCnt = 1;
  int bValid = FALSE;
  object oTarget;
  object oMaster = GetRealMaster();

  // Pausanias: reset spell cast counter.
  SetLocalInt(OBJECT_SELF, "nRoundsSkipped", 0);

  tUse = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE, 20);
  tMass = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_AREAEFFECT, 20);

  // Pausanias: added option to specify a target.
  if (oDefault == OBJECT_INVALID)
    {
     oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);

     // Override the nearest target if the master wants aggressive buff spells.
     if (GetAssociateState(NW_ASC_AGGRESSIVE_BUFF) && GetAssociateState(NW_ASC_HAVE_MASTER))
       { oTarget = oMaster; }
    }
  else
    {
     oTarget = oDefault;

     // Pausanias: Try to get a buff that the target doesn't already have. Also
     // try to avoid invisibility spells if so indicated. This inelegant
     // approach is necessitate by GetHasSpell and GetCreatureHasTalent not
     // working properly for bards/sorcerers.
     int iDone = FALSE;
     int nTry = 1;
     int nMaxTries = 20;
     int iFoundInvis = FALSE;
     while (!iDone && GetIsTalentValid(tUse) && nTry <= nMaxTries)
       {
        nType = GetTypeFromTalent(tUse);
        nIndex = GetIdFromTalent(tUse);
        iDone = TRUE;
        if (iAvoidInvisibility)
          {
           if (nIndex == SPELL_INVISIBILITY || nIndex == SPELL_IMPROVED_INVISIBILITY)
             {
              if (nTry < nMaxTries)
                {
                 iDone = FALSE;
                 iFoundInvis = TRUE;
                 tInvis = tUse;
                }
             }
           if (nTry == nMaxTries && iFoundInvis)
             {
              tUse = tInvis;
              nType = GetTypeFromTalent(tUse);
              nIndex = GetIdFromTalent(tUse);
             }
          }
        if (nType == TALENT_TYPE_SPELL)
          {
           if (GetHasSpellEffect(nIndex,oTarget) || GetWasCast(nIndex,oTarget))
             { iDone = FALSE; }
           if (nIndex == SPELL_HASTE)
             {
              if (GetHasEffect1(EFFECT_TYPE_HASTE) || GetCreatureHasItemProperty(ITEM_PROPERTY_HASTE, oTarget))
                { iDone = FALSE; }
             }
          }
        if (nType == TALENT_TYPE_FEAT)
          {
           if (GetHasFeatEffect(nIndex,oTarget) || GetWasCast(nIndex,oTarget))
             { iDone = FALSE; }
          }
        if (!iDone)
          { tUse = GetCreatureTalentRandom(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE); }
        ++nTry;
       }
     if (!iDone)
       {
        SetLocalInt(OBJECT_SELF, "MaxedOut", TRUE);
        return FALSE;
       }
     else
       {
        SetLocalInt(OBJECT_SELF, "MaxedOut", FALSE);
        if (!iClearActions)
          {
           int nCast = GetLocalInt(oTarget, "nCast");
           ++nCast;
           SetLocalInt(oTarget, "nCast", nCast);
           SetIntArray(oTarget, "IndexCast", nCast, nIndex);
          }
       }
    }

  while (GetIsObjectValid(oTarget))
    {
     int iValidTarget = TRUE;

     // Do not enhance target it if it's running away or too far.
     if (oTarget != oMaster)
       {
        if (GetLocalInt(oTarget, "RunningAway"))
          { iValidTarget = FALSE; }
        if (GetDistanceBetween(oTarget, OBJECT_SELF) > 10.0)
          { iValidTarget = FALSE; }
       }

     if (GetIsTalentValid(tUse) && iValidTarget)
       {
        nType = GetTypeFromTalent(tUse);
        nIndex = GetIdFromTalent(tUse);
        if (nType == TALENT_TYPE_SPELL)
          {
           if (!GetHasSpellEffect(nIndex, oTarget))
             {
              if (iClearActions)
                { ClearActions(CLEAR_I0_ENHANCE_HenchTalentEnhancOther_1); }
              ActionUseTalentOnObject(tUse, oTarget);
              return TRUE;
             }
          }
        else if (nType == TALENT_TYPE_FEAT)
          {
           if (!GetHasFeatEffect(nIndex, oTarget))
             {
              if (iClearActions)
                {
                 ClearActions(CLEAR_I0_ENHANCE_HenchTalentEnhancOther_2);
                 ActionUseTalentOnObject(tUse, oTarget);
                }
              else
                { ActionDoCommand(ActionUseTalentOnObject(tUse, oTarget)); }
              return TRUE;
             }
          }
        else
          {
           if (iClearActions)
             { ClearActions(CLEAR_I0_ENHANCE_HenchTalentEnhancOther_3); }
           ActionUseTalentOnObject(tUse, oTarget);
           return TRUE;
          }
       }
     nCnt++;
     if (oDefault == OBJECT_INVALID)
       { oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE); }
     else
       { oTarget = OBJECT_INVALID; }
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
//void main(){}
