/*

    Henchman Inventory And Battle AI

    This file contains a modified form of the original TalentMeleeAttack.
    Major modification to not randomly pick feats to use.

*/

#include "hench_i0_equip"


// void main() {    }


int MeleeAttackBonus(object oTarget = OBJECT_SELF)
{
    int nReturn = 0;
    // Primary weapon...if enchanted, add a few on.
    object oWeaponRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
    if(GetItemHasItemProperty(oWeaponRight, ITEM_PROPERTY_ENHANCEMENT_BONUS)) nReturn++;
    if(GetItemHasItemProperty(oWeaponRight, ITEM_PROPERTY_ATTACK_BONUS)) nReturn++;
    object oWeaponLeft = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
    int nOffHandWeaponSize = GetMeleeWeaponSize(oWeaponLeft);
    if (nOffHandWeaponSize > 0)
    {
        if (nOffHandWeaponSize == GetCreatureSize(oTarget))
        {
            nReturn -= 2;
        }
        else
        {
            // TODO more could be done here
            nReturn -= 4;
        }
    }
    // Finess only if we are using a proper weapon (ie no monster attacks)
    int nStrMod = GetAbilityModifier(ABILITY_STRENGTH, oTarget);
    int nDexMod = GetAbilityModifier(ABILITY_DEXTERITY, oTarget);
    if(GetHasFeat(FEAT_WEAPON_FINESSE) && (nDexMod > nStrMod) && GetIsObjectValid(oWeaponRight))
    {
        nReturn += nDexMod;
    }
    else
    {
        nReturn += nStrMod;
    }
    return nReturn;
}


int RangeAttackBonus(object oTarget = OBJECT_SELF)
{
    int nReturn = 0;
    // Primary weapon...if enchanted, add a few on.
    object oWeaponRight = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
    if(GetItemHasItemProperty(oWeaponRight, ITEM_PROPERTY_ENHANCEMENT_BONUS)) nReturn++;
    if(GetItemHasItemProperty(oWeaponRight, ITEM_PROPERTY_ATTACK_BONUS)) nReturn++;
        
    int nDexMod = GetAbilityModifier(ABILITY_DEXTERITY, oTarget);
    int nWisMod = GetAbilityModifier(ABILITY_WISDOM, oTarget);
    if (GetHasFeat(FEAT_ZEN_ARCHERY) && (nWisMod > nDexMod) && GetWeaponRanged(oWeaponRight))
    {
        nReturn += nWisMod;
    }
    else
    {
        nReturn += nDexMod;
    }    
    return nReturn;
}


// MELEE ATTACK OTHERS
/*
    ISSUE 1: Talent Melee Attack should set the Last Spell Used to 0 so that melee casters can use
    a single special ability.

    Auldar: Made changes here to use Taunt when appropriate as well as more accurate calculations for
    To-Hit vs Target AC.

    Tony: Made major changes in using attack feats. Heavily modified code from Jasperre.
*/

int HenchTalentMeleeAttack(object oIntruder, float fThresholdDistance, int iMeleeAttackers, int iCreatureType)
{
    object oTarget = oIntruder;

    if (iCreatureType == 0)
    {
       MonsterBattleCry();
    }
    else if (iCreatureType == 1)
    {
       HenchBattleCry();
    }

    object oRightWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND);
    int bRangedWeapon = GetWeaponRanged(oRightWeapon);
    if(GetHasFeat(FEAT_SNEAK_ATTACK))
    {
            //Sneak Attack Flanking attack
        float fRange = iMeleeAttackers ? 3.5 : bRangedWeapon ? 50.0 : 5.0;
        int iEnemyAC, iAC = 100;
        object oRealMaster = GetRealMaster();
        int bEnemyMaster = FALSE;
        object oLastSneakTarget = GetLocalObject(OBJECT_SELF, "LastSneakTarget");
        object oAttackTarget;
        int nCnt = 1;
        object oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
        object oBest = OBJECT_INVALID;
        while(GetIsObjectValid(oEnemy) && GetDistanceToObject(oEnemy) <= fRange)
        {
            if(!GetPlotFlag(oEnemy) && !GetIsImmune(oEnemy, IMMUNITY_TYPE_SNEAK_ATTACK, OBJECT_SELF))
            {
                oAttackTarget = GetAttackTarget(oEnemy);
                if(oAttackTarget != OBJECT_SELF)
                {
                    if (oEnemy == oLastSneakTarget)
                    {
                        oBest = oEnemy;
                        break;
                    }
                    iEnemyAC = GetAC(oEnemy);
                    if (oAttackTarget == oRealMaster)
                    {
                        if (!bEnemyMaster)
                        {
                            bEnemyMaster = TRUE;
                            iAC = iEnemyAC;
                            oBest = oEnemy;
                        }
                        else if(iAC > iEnemyAC)
                        {
                            iAC = iEnemyAC;
                            oBest = oEnemy;
                        }
                    }
                    else if(iAC > iEnemyAC)
                    {
                        iAC = iEnemyAC;
                        oBest = oEnemy;
                    }
                }
            }
            nCnt++;
            oEnemy = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_IS_ALIVE, TRUE);
        }

        if (GetIsObjectValid(oBest))
        {
            oTarget = oBest;
            SetLocalObject(OBJECT_SELF, "LastSneakTarget", oBest);
            HenchEquipAppropriateWeapons(oTarget, fThresholdDistance, iCreatureType == 1);
            ActionAttack(oTarget);
            return TRUE;
        }
    }

    HenchEquipAppropriateWeapons(oTarget, fThresholdDistance, iCreatureType == 1);

    int iAC = GetAC(oTarget);
    int iNewBAB = GetBaseAttackBonus(OBJECT_SELF) + 5 + d4(2);

    if(bRangedWeapon)
    {
        iNewBAB += RangeAttackBonus();

        // Less Get's. We need -2 for all ranged feats.
        if((iNewBAB - 2) >= iAC)
        {
/*
            Tony K during testing it appears this doesn't work. Also found a reference in NWN forums about
            called shot not working for ranged
            // At a -2 to hit, this can disarm the arms or legs...speed or attack bonus
            if(d8() == 1 && GetHasFeat(FEAT_CALLED_SHOT) && !GetHasFeatEffect(FEAT_CALLED_SHOT, oTarget)
                && !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT, OBJECT_SELF))
            {
                ActionUseFeat(FEAT_CALLED_SHOT, oTarget);
                return TRUE;
            } */
            // This provides another attack, at -2 to hit.
            if(GetHasFeat(FEAT_RAPID_SHOT))
            {
                ActionUseFeat(FEAT_RAPID_SHOT, oTarget);
                return TRUE;
            }
        }
        ActionAttack(oTarget);
        return TRUE;
    }
    iNewBAB += MeleeAttackBonus();
    
    float relativeChallenge = iCreatureType == 1 ? IntToFloat(GetHitDice(OBJECT_SELF)) : GetChallengeRating(OBJECT_SELF);
    relativeChallenge -= GetIsPC(oTarget) || GetHenchman(GetMaster(oTarget)) == OBJECT_SELF ? IntToFloat(GetHitDice(oTarget)) : GetChallengeRating(oTarget);
    
    // For use against them evil pests! Top - one use only anyway.
    if(GetHasFeat(FEAT_SMITE_EVIL) && GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL &&
        relativeChallenge <= 2.0)
    {
        ActionUseFeat(FEAT_SMITE_EVIL, oTarget);
        return TRUE;
    }
    if (d6() == 1 && !GetIsImmune(oTarget, IMMUNITY_TYPE_CRITICAL_HIT, OBJECT_SELF) && (iNewBAB >= iAC))
    {
        int bHasQuiveringPalm = GetHasFeat(FEAT_QUIVERING_PALM);
        int bHasStunningFist = GetHasFeat(FEAT_STUNNING_FIST);
        int bHasSAP = GetHasFeat(FEAT_SAP);
        int bHasCalledShot = GetHasFeat(FEAT_CALLED_SHOT) && d3() == 1;
        if ((bHasQuiveringPalm || bHasStunningFist || bHasSAP || bHasCalledShot) &&
            relativeChallenge <= 2.0  &&
            (GetCharacterLevel(OBJECT_SELF) / 2 + 10 + GetAbilityModifier(ABILITY_WISDOM) >=
            GetFortitudeSavingThrow(oTarget) + 5 + Random(15)))
        {
            if (bHasQuiveringPalm && !GetIsObjectValid(oRightWeapon))
            {
                ActionUseFeat(FEAT_QUIVERING_PALM, oTarget);
                return TRUE;
            }
            if(!GetHasAnyEffect3(EFFECT_TYPE_STUNNED, EFFECT_TYPE_PARALYZE, EFFECT_TYPE_DAZED, oTarget))
            {
                if (bHasStunningFist)
                {
                    int iMod = iNewBAB;
                    if (GetIsObjectValid(oRightWeapon) || (GetLevelByClass(CLASS_TYPE_MONK) == 0))
                    {
                        iMod -= 4;
                    }
                    if (iMod >= iAC)
                    {
                        ActionUseFeat(FEAT_STUNNING_FIST, oTarget);
                        return TRUE;
                    }
                }
                // OK, not for PCs, but may be on an NPC. -4 Attack. Above the one below.
                else if(bHasSAP)
                {
                   if((iNewBAB - 4) >= iAC)
                    {
                        ActionUseFeat(FEAT_SAP, oTarget);
                        return TRUE;
                    }
                }
                // At a -2 to hit, this can disarm the arms or legs...speed or attack bonus
                else if(((iNewBAB - 2) >= iAC) && !GetHasFeatEffect(FEAT_CALLED_SHOT, oTarget))
                {
                    ActionUseFeat(FEAT_CALLED_SHOT, oTarget);
                    return TRUE;
                }
            }
        }
    }
    // Tony K add chance for knockdown?
    int bHasImprovedKnockdown = GetHasFeat(FEAT_IMPROVED_KNOCKDOWN);
    if((bHasImprovedKnockdown || GetHasFeat(FEAT_KNOCKDOWN)) &&
        !GetIsImmune(oTarget, IMMUNITY_TYPE_KNOCKDOWN, OBJECT_SELF) &&
        !GetHasFeatEffect(FEAT_KNOCKDOWN, oTarget) &&
        !GetHasFeatEffect(FEAT_IMPROVED_KNOCKDOWN, oTarget))
    {
        // By far the BEST feat to use - knocking them down lets you freely attack them!
        // These return 1-5, based on size.
        int iOurSize = GetCreatureSize(OBJECT_SELF);
        int iTheirSize = GetCreatureSize(oTarget);
        if (bHasImprovedKnockdown)
        {
            iOurSize++;
        }
        int bUse = iOurSize > iTheirSize;
        if (!bUse && ((iOurSize + 1) >= iTheirSize))
        {
            int iMod = iNewBAB - 4;
                // check if one size larger
            if (iOurSize != iTheirSize)
            {
                iMod -= 4;
            }
            if(iMod >= iAC)
            {
                bUse = iMod > GetSkillRank(SKILL_DISCIPLINE, oTarget);
            }
        }
        if(bUse)
        {
            ActionUseFeat(bHasImprovedKnockdown ? FEAT_IMPROVED_KNOCKDOWN : FEAT_KNOCKDOWN, oTarget);
            return TRUE;
        }
    }
        
    if (GetCombatCondition(X0_COMBAT_FLAG_DEFENSIVE))
    {
        int bHasExpertise = GetHasFeat(FEAT_EXPERTISE);
        int bHasImprovedExpertise = GetHasFeat(FEAT_IMPROVED_EXPERTISE);
        if (bHasExpertise || bHasImprovedExpertise)
        {
            if(bHasImprovedExpertise && (iNewBAB - 10) >= iAC)
            {
                ActionUseFeat(FEAT_IMPROVED_EXPERTISE, oTarget);
                return TRUE;
            }
            if((iNewBAB - 5) >= iAC)
            {
                ActionUseFeat(FEAT_EXPERTISE, oTarget);
                return TRUE;
            }
        }
    
        // Only use parry on an active melee attacker, and
        // only if our parry skill > our AC - 10
        object oEnemy = GetLastHostileActor();
        if (GetIsObjectValid(oEnemy) 
            && GetAttackTarget(oEnemy) == OBJECT_SELF 
            && GetIsMeleeAttacker(oEnemy)) 
        {
            int nParrySkill = GetSkillRank(SKILL_PARRY);
            int nAC = GetAC(OBJECT_SELF);
            if (nParrySkill > (nAC - 10) )
            {
                ActionUseSkill(SKILL_PARRY, oTarget);
                return TRUE;
            }
        }
    }

//
// Auldar: Give 10% chance to Taunt if target is within 3.5 meters and is a challenge, if Skill points have been
// spent in Taunt skill indicating intention to use, and a taunt isn't in effect
//
    if ((d10 () == 1) && ((relativeChallenge <= 2.0) ||
        (GetCharacterLevel(oTarget) > (GetCharacterLevel(OBJECT_SELF) - 2)))
        && (GetDistanceToObject(oTarget) <= 3.5))
    {
    // Auldar: Adding a check for the Taunt skill, and ensuring that noone with ONLY a CHA mod to
    // Taunt will use the skill.
    // This confirms that some points are spent in the skill indicating an intention for the NPC to use them.
    // Also using 69MEH69's idea to check for a negative modifier so we don't subtract a negative number (ie add)
    // to the skill check
        int chaCheck = GetAbilityModifier(ABILITY_CHARISMA);
        int tauCheck = GetSkillRank(SKILL_TAUNT);
        if (((tauCheck - chaCheck) > 0) && ((tauCheck + 5 + d4(2)) > GetSkillRank(SKILL_CONCENTRATION, oTarget)))
        {
            ActionUseSkill(SKILL_TAUNT, oTarget);
            return TRUE;
        }
    }
    object oTargetRightWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
    if(d10() == 1 && (GetHasFeat(FEAT_IMPROVED_DISARM) || GetHasFeat(FEAT_DISARM)) &&
        GetIsObjectValid(oRightWeapon))
    {
        if (GetIsObjectValid(oTargetRightWeapon) && !GetWeaponRanged(oTargetRightWeapon))
        {
            int iWeaponSize = GetMeleeWeaponSize(oRightWeapon);
            int iTargetWeaponSize = GetMeleeWeaponSize(oTargetRightWeapon);

            // No AOO, and only a -4 penalty to hit.
            if(GetHasFeat(FEAT_IMPROVED_DISARM))
            {
                // Apply weapon size penalites/bonuses to check - Use right weapons.
                int iMod = iWeaponSize - iTargetWeaponSize;
                if(iMod != 0) iMod += (iMod * 4);
                if((iNewBAB - 4 + iMod) >= iAC)
                {
                    ActionUseFeat(FEAT_IMPROVED_DISARM, oTarget);
                    return TRUE;
                }
            }
            // Provokes an AOO. Improved does not, but this is -6, and bonuses depend on weapons used (sizes)
            else if(d2() == 1)
            {
                // Apply weapon size penalites/bonuses to check - Use right weapons.
                int iMod = iWeaponSize - iTargetWeaponSize;
                if(iMod != 0) iMod += (iMod * 4);
                if((iNewBAB - 6 + iMod) >= iAC)
                {
                    ActionUseFeat(FEAT_DISARM, oTarget);
                    return TRUE;
                }
            }
        }
    }

    // This activates an extra attack, at -2 to hit. Of course, only unarmed and kama
    if(GetHasFeat(FEAT_FLURRY_OF_BLOWS) && ((iNewBAB - 2) >= iAC) && (!GetIsObjectValid(oRightWeapon) ||
        (GetBaseItemType(oRightWeapon) == BASE_ITEM_KAMA)))
    {
        ActionUseFeat(FEAT_FLURRY_OF_BLOWS, oTarget);
        return TRUE;
    }
    // -10 to hit - make sure by extra 5
    if(GetHasFeat(FEAT_IMPROVED_POWER_ATTACK) && ((iNewBAB - 15) >= iAC))
    {
        ActionUseFeat(FEAT_IMPROVED_POWER_ATTACK, oTarget);
        return TRUE;
    }
    // is a -5 to hit - make sure by extra 5
    if(GetHasFeat(FEAT_POWER_ATTACK) && ((iNewBAB - 10) >= iAC))
    {
        ActionUseFeat(FEAT_POWER_ATTACK, oTarget);
        return TRUE;
    }
    ActionAttack(oTarget);
    return TRUE;
}
