// v2.0.0 -
//::////////////////////////////////////////////////////////////////////////////
//:: FileName:  hark_i0_match
//::////////////////////////////////////////////////////////////////////////////
/*
   Library for 'matching' functions. These functions check to see whether a
  given value matches one of a long set of constants, so they're simple but
  big and ugly.
*/
//::////////////////////////////////////////////////////////////////////////////


// * CONSTANTS


const int NW_TALENT_PROTECT = 1;
const int NW_TALENT_ENHANCE = 2;


// * FUNCTION PROTOTYPES


// Used to break protections into 3 categories:
// COMBAT, SPELL and ELEMENTAL.
// sClass should be one of: FIGHTER, CLERIC, MAGE, MONSTER
// nType should always be:  NW_TALENT_PROTECT
int GetMatchCompatibility(talent tUse, string sClass, int nType);

int GetRemovalSpell();

// Returns TRUE if oTarget has effects that would prevent them from attempting to heal.
int MatchCantHealEffects(object oTarget);

// * Do I have any effect on me that came from a mind affecting spell?
int MatchDoIHaveAMindAffectingSpellOnMe(object oTarget);

// * if the passed in spell is an area of effect spell of any kind
int MatchAreaOfEffectSpell(int nSpell);

// * Is this spell a combat protection spells?
int MatchCombatProtections(talent tUse);

// * Is this talent a protection against spells?
int MatchSpellProtections(talent tUse);

// * Is this talent a protection against elemental damage?
int MatchElementalProtections(talent tUse);

// * Is this item a single-handed weapon?
int MatchSingleHandedWeapon(object oItem);

// TRUE if the item is a double-handed weapon
int MatchDoubleHandedWeapon(object oItem);

// TRUE if the item is a melee weapon
int MatchMeleeWeapon(object oItem);

// TRUE if the item is a shield.
int MatchShield(object oItem);

// TRUE if the item is a crossbow.
int MatchCrossbow(object oItem);

// TRUE if the item is a longbow or shortbow.
int MatchNormalBow(object oItem);

// * is this a mind affecting spell?
int MatchMindAffectingSpells(int iSpell);

// * is this a charm type spell?
int MatchPersonSpells(int iSpell);

// TRUE if this spell is one of the Reverse Healing touch Attacks.
int MatchInflictTouchAttack(int nSpell);

// TRUE if the creature is an elemental, undead, or golem.
int MatchNonliving(int nRacialType);

// Variation of GetHasEffect. (Uses the EFFECT_TYPE constants)
// Checks oTarget for nEffectType1.
// Returns TRUE if oTarget has this effect.
int GetHasEffect1(int nEffectType1, object oTarget = OBJECT_SELF);

// Variation of GetHasEffect. (Uses the EFFECT_TYPE constants)
// Checks oTarget for nEffectType1 & nEffectType2.
// Returns TRUE if oTarget has either effect.
int GetHasEffect2(int nEffectType1, int nEffectType2, object oTarget = OBJECT_SELF);

// Variation of GetHasEffect. (Uses the EFFECT_TYPE constants)
// Checks oTarget for nEffectType1, nEffectType2 & nEffectType3.
// Returns TRUE if oTarget has any of the three effects.
int GetHasEffect3(int nEffectType1, int nEffectType2, int nEffectType3, object oTarget = OBJECT_SELF);

// Returns TRUE if oHench has the necessary skills to level in nClassType. Uses the CLASS_TYPE_* constants.
int GetCanLevelInClass(int nClassType, object oHench = OBJECT_SELF);


// * FUNCTION DEFINITIONS


//::////////////////////////////////////////////////////////////////////////////
int GetMatchCompatibility(talent tUse, string sClass, int nType)
{
    int bValid;
    if(nType == NW_TALENT_PROTECT)
    {
        if(sClass == "FIGHTER")
        {
            if(MatchCombatProtections(tUse))
            {
                bValid = TRUE;
            }
        }
        else if(sClass == "MAGE")
        {
            if(MatchSpellProtections(tUse))
            {
                bValid = TRUE;
            }
            else if(MatchElementalProtections(tUse))
            {
                bValid = TRUE;
            }
        }
        else if(sClass == "CLERIC" || sClass == "MONSTER")
        {
            if(MatchCombatProtections(tUse))
            {
                bValid = TRUE;
            }
            else if(MatchElementalProtections(tUse))
            {
                bValid = TRUE;
            }
        }
    }

    return bValid;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchCombatProtections(talent tUse)
{
    int nIndex = GetIdFromTalent(tUse);

    if(nIndex == SPELL_PREMONITION ||
       nIndex == SPELL_ELEMENTAL_SHIELD ||
       nIndex == SPELL_GREATER_STONESKIN ||
       nIndex == SPELL_SHADOW_SHIELD ||
       nIndex == SPELL_ETHEREAL_VISAGE ||
       nIndex == SPELL_STONESKIN ||
       nIndex == SPELL_GHOSTLY_VISAGE)
    {
        return TRUE;
    }
    return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchSpellProtections(talent tUse)
{
    int nIndex = GetIdFromTalent(tUse);

    if(nIndex == SPELL_GREATER_SPELL_MANTLE ||
       nIndex == SPELL_SPELL_MANTLE ||
       nIndex == SPELL_LESSER_SPELL_MANTLE ||
       nIndex == SPELL_SHADOW_SHIELD ||
       nIndex == SPELL_GLOBE_OF_INVULNERABILITY ||
       nIndex == SPELL_MINOR_GLOBE_OF_INVULNERABILITY ||
       nIndex == SPELL_ETHEREAL_VISAGE ||
       nIndex == SPELL_GHOSTLY_VISAGE ||
       nIndex == SPELL_SPELL_RESISTANCE ||
       nIndex == SPELL_PROTECTION_FROM_SPELLS ||
       nIndex == SPELL_NEGATIVE_ENERGY_PROTECTION)
    {
        return TRUE;
    }
    return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchAreaOfEffectSpell(int nSpell)
{
    int nMatch = FALSE;

    switch (nSpell)
    {
        case SPELL_BLADE_BARRIER: nMatch = TRUE; break;
        case SPELL_CLOUDKILL: nMatch = TRUE; break;
        case SPELL_STINKING_CLOUD: nMatch = TRUE; break;
        case SPELL_WALL_OF_FIRE: nMatch = TRUE; break;
        case SPELL_INCENDIARY_CLOUD:nMatch = TRUE; break;
        case SPELL_ENTANGLE:nMatch = TRUE; break;
        case SPELL_EVARDS_BLACK_TENTACLES:nMatch = TRUE; break;
        case 454:nMatch = TRUE; break;
        case 445: nMatch = TRUE; break;
    }
    return nMatch;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchElementalProtections(talent tUse)
{
    int nIndex = GetIdFromTalent(tUse);

    if(nIndex == SPELL_ENERGY_BUFFER ||
       nIndex == SPELL_PROTECTION_FROM_ELEMENTS ||
       nIndex == SPELL_RESIST_ELEMENTS ||
       nIndex == SPELL_ENDURE_ELEMENTS)
    {
        return TRUE;
    }
    return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int GetRemovalSpell()
{
  if (GetHasSpell(SPELL_DISPEL_MAGIC, OBJECT_SELF) == TRUE)
    { return SPELL_DISPEL_MAGIC; }
  return -1;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchCantHealEffects(object oTarget)
{
  effect eCheck = GetFirstEffect(oTarget);
  while (GetIsEffectValid(eCheck))
    {
     switch (GetEffectType(eCheck))
        {
         case EFFECT_TYPE_BLINDNESS:
         case EFFECT_TYPE_CHARMED:
         case EFFECT_TYPE_CONFUSED:
         case EFFECT_TYPE_DARKNESS:
         case EFFECT_TYPE_DAZED:
         case EFFECT_TYPE_DOMINATED:
         case EFFECT_TYPE_ENTANGLE:
         case EFFECT_TYPE_FRIGHTENED:
         case EFFECT_TYPE_PARALYZE:
         case EFFECT_TYPE_PETRIFY:
         case EFFECT_TYPE_POLYMORPH:
         case EFFECT_TYPE_SLEEP:
         case EFFECT_TYPE_STUNNED:
         case EFFECT_TYPE_TURNED:
           return TRUE;
           break;
         default: break;
        }
     eCheck = GetNextEffect(oTarget);
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchDoIHaveAMindAffectingSpellOnMe(object oTarget)
{
  if (GetHasSpellEffect(SPELL_SLEEP, oTarget) ||
      GetHasSpellEffect(SPELL_DAZE, oTarget) ||
      GetHasSpellEffect(SPELL_HOLD_ANIMAL, oTarget) ||
      GetHasSpellEffect(SPELL_HOLD_MONSTER, oTarget) ||
      GetHasSpellEffect(SPELL_HOLD_PERSON, oTarget) ||
      GetHasSpellEffect(SPELL_CHARM_MONSTER, oTarget) ||
      GetHasSpellEffect(SPELL_CHARM_PERSON, oTarget) ||
      GetHasSpellEffect(SPELL_CHARM_PERSON_OR_ANIMAL, oTarget) ||
      GetHasSpellEffect(SPELL_MASS_CHARM, oTarget) ||
      GetHasSpellEffect(SPELL_DOMINATE_ANIMAL, oTarget) ||
      GetHasSpellEffect(SPELL_DOMINATE_MONSTER, oTarget) ||
      GetHasSpellEffect(SPELL_DOMINATE_PERSON, oTarget) ||
      GetHasSpellEffect(SPELL_CONFUSION, oTarget))
    { return TRUE; }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchMindAffectingSpells(int iSpell)
{
    switch (iSpell) {
        case SPELL_SLEEP:
        case SPELL_DAZE:
        case SPELL_HOLD_ANIMAL:
        case SPELL_HOLD_MONSTER:
        case SPELL_HOLD_PERSON:
        case SPELL_CHARM_MONSTER:
        case SPELL_CHARM_PERSON:
        case SPELL_CHARM_PERSON_OR_ANIMAL:
        case SPELL_MASS_CHARM:
        case SPELL_DOMINATE_ANIMAL:
        case SPELL_DOMINATE_MONSTER:
        case SPELL_DOMINATE_PERSON:
        case SPELL_CONFUSION:
        case SPELL_SPHERE_OF_CHAOS:
        case SPELL_CLOAK_OF_CHAOS:
            return TRUE; break;
        default: break;
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchPersonSpells(int iSpell)
{
   switch (iSpell) {
        case SPELL_HOLD_PERSON:
        case SPELL_CHARM_PERSON:
        case SPELL_DOMINATE_PERSON:
            return TRUE; break;

        default: break;
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchSingleHandedWeapon(object oItem)
{
    switch (GetBaseItemType(oItem)) {
        case BASE_ITEM_BATTLEAXE:
        case BASE_ITEM_CLUB:
        case BASE_ITEM_DAGGER:
        case BASE_ITEM_HANDAXE:
        case BASE_ITEM_KAMA:
        case BASE_ITEM_KATANA:
        case BASE_ITEM_KUKRI:
        case BASE_ITEM_LIGHTFLAIL:
        case BASE_ITEM_HEAVYFLAIL:
        case BASE_ITEM_LIGHTHAMMER:
        case BASE_ITEM_LIGHTMACE:
        case BASE_ITEM_LONGSWORD:
        case BASE_ITEM_MORNINGSTAR:
        case BASE_ITEM_BASTARDSWORD:
        case BASE_ITEM_RAPIER:
        case BASE_ITEM_SICKLE:
        case BASE_ITEM_SCIMITAR:
        case BASE_ITEM_SHORTSWORD:
        case BASE_ITEM_WARHAMMER: return TRUE;
        break;

        default: break;
     }
     return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchDoubleHandedWeapon(object oItem)
{
    switch (GetBaseItemType(oItem)) {
    case BASE_ITEM_DIREMACE:
    case BASE_ITEM_DOUBLEAXE:
    case BASE_ITEM_GREATAXE:
    case BASE_ITEM_GREATSWORD:
    case BASE_ITEM_HALBERD:
    case BASE_ITEM_MAGICSTAFF:
    case BASE_ITEM_QUARTERSTAFF:
    case BASE_ITEM_TWOBLADEDSWORD:
        return TRUE;
    }
    return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchMeleeWeapon(object oItem)
{
    return (MatchSingleHandedWeapon(oItem) || MatchDoubleHandedWeapon(oItem));
}
//::////////////////////////////////////////////////////////////////////////////
int MatchShield(object oItem)
{
    switch (GetBaseItemType(oItem)) {
    case BASE_ITEM_SMALLSHIELD:
    case BASE_ITEM_LARGESHIELD:
    case BASE_ITEM_TOWERSHIELD:
        return TRUE;
    }
    return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchCrossbow(object oItem)
{
    switch (GetBaseItemType(oItem)) {
    case BASE_ITEM_HEAVYCROSSBOW:
    case BASE_ITEM_LIGHTCROSSBOW:
        return TRUE;
    }
    return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchNormalBow(object oItem)
{
    switch (GetBaseItemType(oItem)) {
    case BASE_ITEM_LONGBOW:
    case BASE_ITEM_SHORTBOW:
        return TRUE;
    }
    return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchInflictTouchAttack(int nSpell)
{
    int nMatch = FALSE;
    switch (nSpell)
    {
        case SPELL_INFLICT_CRITICAL_WOUNDS:
        case SPELL_INFLICT_LIGHT_WOUNDS:
        case SPELL_INFLICT_MINOR_WOUNDS:
        case SPELL_INFLICT_MODERATE_WOUNDS:
        case SPELL_INFLICT_SERIOUS_WOUNDS:
        case SPELL_HARM: nMatch = TRUE; break;
   }
   return nMatch;
}
//::////////////////////////////////////////////////////////////////////////////
int MatchNonliving(int nRacialType)
{
    int nMatch = FALSE;

    switch (nRacialType)
    {
        case RACIAL_TYPE_CONSTRUCT:
        case RACIAL_TYPE_ELEMENTAL:
        case RACIAL_TYPE_UNDEAD: nMatch = TRUE; break;
    }
  return nMatch;
}
//::////////////////////////////////////////////////////////////////////////////
int GetHasEffect1(int nEffectType1, object oTarget = OBJECT_SELF)
{
  effect eCheck = GetFirstEffect(oTarget);
  while (GetIsEffectValid(eCheck))
    {
     int nTestEffect = GetEffectType(eCheck);
     if (nTestEffect == nEffectType1) { return TRUE; }
     eCheck = GetNextEffect(oTarget);
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int GetHasEffect2(int nEffectType1, int nEffectType2, object oTarget = OBJECT_SELF)
{
  effect eCheck = GetFirstEffect(oTarget);
  while (GetIsEffectValid(eCheck))
    {
     int nTestEffect = GetEffectType(eCheck);
     if (nTestEffect == nEffectType1) { return TRUE; }
     if (nTestEffect == nEffectType2) { return TRUE; }
     eCheck = GetNextEffect(oTarget);
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int GetHasEffect3(int nEffectType1, int nEffectType2, int nEffectType3, object oTarget = OBJECT_SELF)
{
  effect eCheck = GetFirstEffect(oTarget);
  while (GetIsEffectValid(eCheck))
    {
     int nTestEffect = GetEffectType(eCheck);
     if (nTestEffect == nEffectType1) { return TRUE; }
     if (nTestEffect == nEffectType2) { return TRUE; }
     if (nTestEffect == nEffectType3) { return TRUE; }
     eCheck = GetNextEffect(oTarget);
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
int GetCanLevelInClass(int nClassType, object oHench = OBJECT_SELF)
{
  if (nClassType == CLASS_TYPE_INVALID || !GetIsObjectValid(oHench))
    {
     return FALSE;
    }
  if (nClassType == CLASS_TYPE_ARCANE_ARCHER)
    {
     return ((GetRacialType(oHench) == RACIAL_TYPE_ELF ||
              GetRacialType(oHench) == RACIAL_TYPE_HALFELF) &&
              GetBaseAttackBonus(oHench) >= 6 &&
             (GetHasFeat(FEAT_WEAPON_FOCUS_LONGBOW, oHench) ||
              GetHasFeat(FEAT_WEAPON_FOCUS_SHORTBOW, oHench)) &&
              GetHasFeat(FEAT_POINT_BLANK_SHOT, oHench) &&
             (GetLevelByClass(CLASS_TYPE_SORCERER, oHench) > 0 ||
              GetLevelByClass(CLASS_TYPE_WIZARD, oHench) > 0));
    }
  if (nClassType == CLASS_TYPE_ASSASSIN)
    {
     return (GetAlignmentGoodEvil(oHench) == ALIGNMENT_EVIL &&
             GetSkillRank(SKILL_HIDE, oHench) >= 8 &&
             GetSkillRank(SKILL_MOVE_SILENTLY, oHench) >= 8);
    }
  if (nClassType == CLASS_TYPE_BARBARIAN)
    {
     return (GetAlignmentLawChaos(oHench) != ALIGNMENT_LAWFUL);
    }
  if (nClassType == CLASS_TYPE_BARD)
    {
     return (GetAlignmentLawChaos(oHench) != ALIGNMENT_LAWFUL);
    }
  if (nClassType == CLASS_TYPE_BLACKGUARD)
    {
     return (GetAlignmentGoodEvil(oHench) == ALIGNMENT_EVIL &&
             GetSkillRank(SKILL_HIDE, oHench) >= 5 &&
             GetHasFeat(FEAT_CLEAVE, oHench) &&
             GetBaseAttackBonus(oHench) >= 6);
    }
  if (nClassType == CLASS_TYPE_CLERIC)
    {
     return TRUE;
    }
  if (nClassType == CLASS_TYPE_DRUID)
    {
     return (GetAlignmentGoodEvil(oHench) == ALIGNMENT_NEUTRAL ||
             GetAlignmentLawChaos(oHench) == ALIGNMENT_NEUTRAL);
    }
  if (nClassType == CLASS_TYPE_FIGHTER)
    {
     return TRUE;
    }
  if (nClassType == CLASS_TYPE_HARPER)
    {
     return (GetAlignmentGoodEvil(oHench) != ALIGNMENT_EVIL &&
             GetSkillRank(SKILL_SEARCH, oHench) >= 4 &&
             GetSkillRank(SKILL_PERSUADE, oHench) >= 8 &&
             GetSkillRank(SKILL_LORE, oHench) >= 6 &&
             GetSkillRank(SKILL_DISCIPLINE, oHench) >= 4 &&
             GetHasFeat(FEAT_ALERTNESS, oHench) &&
             GetHasFeat(FEAT_IRON_WILL, oHench));
    }
  if (nClassType == CLASS_TYPE_MONK)
    {
     return (GetAlignmentLawChaos(oHench) == ALIGNMENT_LAWFUL);
    }
  if (nClassType == CLASS_TYPE_PALADIN)
    {
     return (GetAlignmentGoodEvil(oHench) == ALIGNMENT_GOOD &&
             GetAlignmentLawChaos(oHench) == ALIGNMENT_LAWFUL);
    }
  if (nClassType == CLASS_TYPE_RANGER)
    {
     return TRUE;
    }
  if (nClassType == CLASS_TYPE_ROGUE)
    {
     return TRUE;
    }
  if (nClassType == CLASS_TYPE_SHADOWDANCER)
    {
     return (GetSkillRank(SKILL_HIDE, oHench) >= 10 &&
             GetSkillRank(SKILL_TUMBLE, oHench) >= 5 &&
             GetSkillRank(SKILL_MOVE_SILENTLY, oHench) >= 8 &&
             GetHasFeat(FEAT_DODGE, oHench) &&
             GetHasFeat(FEAT_MOBILITY, oHench));
    }
  if (nClassType == CLASS_TYPE_SORCERER)
    {
     return TRUE;
    }
  if (nClassType == CLASS_TYPE_WIZARD)
    {
     return TRUE;
    }
  return FALSE;
}
//::////////////////////////////////////////////////////////////////////////////
//void main(){}
