//::///////////////////////////////////////////////
//:: Two-Weapon Rend
//:: prc_tw_rend
//:://////////////////////////////////////////////
/** @file
    TWO-WEAPON REND [EPIC]
    Prerequisites: Dex 15, base attack bonus +9,
    Improved Two-Weapon Fighting, Two-Weapon Fighting.

    Benefit: If the character hits an opponent with a
    weapon in each hand in the same round, he or she
    may automatically rend the opponent. This deals
    additional damage equal to the base damage of the
    smaller weapon (if both weapons are of same size,
    the weapon in main hand is used) plus 1 1/2 times
    the character’s Strength modifier. Base weapon
    damage includes an enhancement bonus on damage,
    if any.
    The character can only rend once per round,
    regardless of how many successful attacks he or
    she makes.

    @author Ornedan
    @date   Created - 2006.07.05
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////

#include "prc_alterations"

const string REND_FIRST_MAINHAND_HIT_PREFIX = "PRC_TWRend_MainHandHitBy_";
const string REND_FIRST_OFFHAND_HIT_PREFIX  = "PRC_TWRend_OffHandHitBy_";
const string REND_LOCK                      = "PRC_TWRend_Used";

void main()
{
    object oPC, oItem;
    int nEvent = GetRunningEvent();

    if(DEBUG) DoDebug("prc_tw_rend running, event: " + IntToString(nEvent));

    // We're being called from the OnHit eventhook, so deal the damage
    if(nEvent == EVENT_ITEM_ONHIT)
    {
        oPC            = OBJECT_SELF;
        oItem          = GetSpellCastItem();
        object oTarget = PRCGetSpellTargetObject();
        if(DEBUG) DoDebug("prc_tw_rend: OnHit:\n"
                        + "oPC = " + DebugObject2Str(oPC) + "\n"
                        + "oItem = " + DebugObject2Str(oItem) + "\n"
                        + "oTarget = " + DebugObject2Str(oTarget) + "\n"
                          );

        // Only run if called by a melee weapon and rend hasn't already been used for this round
        if(IPGetIsMeleeWeapon(oItem) && !GetLocalInt(oPC, REND_LOCK))
        {
            string sPCOID = ObjectToString(oPC);

            // Determine if the weapon is the mainhand one or the offhand one
            int bIsMainHand = oItem == GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);

            // Determine if the other hand has hit
            int bBothHandsHit;
            if(bIsMainHand)
                bBothHandsHit = GetLocalInt(oTarget, REND_FIRST_OFFHAND_HIT_PREFIX + sPCOID);
            else
                bBothHandsHit = GetLocalInt(oTarget, REND_FIRST_MAINHAND_HIT_PREFIX + sPCOID);

            if(DEBUG) DoDebug("prc_tw_rend: OnHit: bBothHandsHit = " + DebugBool2String(bBothHandsHit));

            // If both hands did hit, run the rending code
            if(bBothHandsHit)
            {
                // Get the equipped weapons
                object oRightHand = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
                object oLeftHand  = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,  oPC);

                // Make sure both are valid before continuing. If the PC is changing their loadout mid-battle,
                // they are not going to be able to rend things at the same time.
                if(!GetIsObjectValid(oRightHand) || !GetIsObjectValid(oLeftHand))
                {
                    if(DEBUG) DoDebug("prc_tw_rend: OnHit: One of the weapons was not present:\n"
                                    + "oRightHand = " + DebugObject2Str(oRightHand) + "\n"
                                    + "oLeftHand = "  + DebugObject2Str(oLeftHand)  + "\n"
                                      );
                    return;
                }

                // Determine which is smaller, preferring the right hand in case of equal size
                int nRightSize  = StringToInt(Get2DACache("baseitems", "WeaponSize", GetBaseItemType(oRightHand)));
                int nLeftSize   = StringToInt(Get2DACache("baseitems", "WeaponSize", GetBaseItemType(oLeftHand)));
                object oSmaller = nRightSize >= nLeftSize ? oRightHand : oLeftHand;
                int nSmaller    = GetBaseItemType(oSmaller);

                // Determine dice to roll
                int nDieSize = StringToInt(Get2DACache("baseitems", "DieToRoll", nSmaller));
                int nNumDice = StringToInt(Get2DACache("baseitems", "NumDice",   nSmaller));

                // Determine damage bonus from enhancement
                int nBonus = 0;
                itemproperty ipTest = GetFirstItemProperty(oSmaller);
                while(GetIsItemPropertyValid(ipTest))
                {
                    // Get the highest enhancement bonus property on the item
                    if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_ENHANCEMENT_BONUS)
                        nBonus = max(nBonus, GetItemPropertyCostTableValue(ipTest));

                    ipTest = GetNextItemProperty(oSmaller);
                }

                // Add STR modifier to damage bonus
                nBonus += FloatToInt(1.5f * GetAbilityModifier(ABILITY_STRENGTH, oPC));

                // Start with bonus and add damage rolls
                int nDamage = nBonus;
                for(; nNumDice > 0; nNumDice--)
                    nDamage += Random(nDieSize) + 1;

                // Apply effects. Damage type is slashing, since it seems most appropriate
                effect eLink =                          EffectDamage(nDamage, DAMAGE_TYPE_SLASHING);
                       eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_COM_BLOOD_CRT_RED));
                ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink, oTarget);

                // Do some feedback
                //                            * PCName rends TargetName *
                FloatingTextStringOnCreature("* " + GetName(oPC) + " " + GetStringByStrRef(0x01000000 + 51197) + " " + GetName(oTarget) + " *",
                                             oPC,
                                             TRUE);

                // Set the feat used for this round, queue lock variable deletion
                SetLocalInt(oPC, REND_LOCK, TRUE);
                DelayCommand(6.0f, DeleteLocalInt(oPC, REND_LOCK));
            }
            else
            {
                // Just a single hit in so far, set marker local and queue it's deletion
                string sVar = (bIsMainHand ? REND_FIRST_MAINHAND_HIT_PREFIX : REND_FIRST_OFFHAND_HIT_PREFIX) + sPCOID;
                SetLocalInt(oTarget, sVar, TRUE);
                DelayCommand(6.0f, DeleteLocalInt(oTarget, sVar));
            }
        }// end if - Item is a melee weapon and Two-Weapon Rend hasn't already been used up for the round
    }// end if - Running OnHit event
    // We are called from the OnPlayerEquipItem eventhook. Add OnHitCast: Unique Power to oPC's weapon
    else if(nEvent == EVENT_ONPLAYEREQUIPITEM)
    {
        oPC   = GetItemLastEquippedBy();
        oItem = GetItemLastEquipped();
        if(DEBUG) DoDebug("prc_tw_rend - OnEquip");

        // Only applies to melee weapons
        if(IPGetIsMeleeWeapon(oItem))
        {
            // Add eventhook to the item
            AddEventScript(oItem, EVENT_ITEM_ONHIT, "prc_tw_rend", TRUE, FALSE);

            // Add the OnHitCastSpell: Unique needed to trigger the event
            IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 99999.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
        }
    }
    // We are called from the OnPlayerUnEquipItem eventhook. Remove OnHitCast: Unique Power from oPC's weapon
    else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM)
    {
        oPC   = GetItemLastUnequippedBy();
        oItem = GetItemLastUnequipped();
        if(DEBUG) DoDebug("prc_tw_rend - OnUnEquip");

        // Only applies to melee weapons
        if(IPGetIsMeleeWeapon(oItem))
        {
            // Add eventhook to the item
            RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "prc_tw_rend", TRUE, FALSE);

            // Remove the temporary OnHitCastSpell: Unique
            RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
        }
    }
}