//::///////////////////////////////////////////////
//:: Shining Blade of Heironeous include
//:: prc_inc_sbheir
//::///////////////////////////////////////////////

#include "prc_inc_util"
#include "inc_item_props"

const int SHINING_BLADE_LEVEL_SHOCK = 1;
const int SHINING_BLADE_LEVEL_HOLY = 2;
const int SHINING_BLADE_LEVEL_BRILLIANT = 3;

const string PRC_ShiningBlade_Generation = "PRC_ShiningBlade_Generation";
const string PRC_ShiningBlade_Level = "PRC_ShiningBladeLevel";
const string PRC_ShiningBlade_Duration = "PRC_ShiningBladeDuration";

void ShiningBlade_RemoveProperties(object oWeapon, int nLevel)
{
    itemproperty iTest = GetFirstItemProperty(oWeapon);
    while(GetIsItemPropertyValid(iTest))
    {
        int bRemove = FALSE;
        if (GetItemPropertyDurationType(iTest) == DURATION_TYPE_TEMPORARY)
        {
            switch(GetItemPropertyType(iTest))
            {
                case ITEM_PROPERTY_DAMAGE_BONUS:
                    if (nLevel >= SHINING_BLADE_LEVEL_SHOCK)
                        bRemove = (GetItemPropertySubType(iTest) == IP_CONST_DAMAGETYPE_ELECTRICAL) && (GetItemPropertyCostTableValue(iTest) == DAMAGE_BONUS_1d6);
                    break;
                case ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP:
                    if (nLevel >= SHINING_BLADE_LEVEL_HOLY)
                        bRemove = (GetItemPropertySubType(iTest) == IP_CONST_ALIGNMENTGROUP_EVIL) && (GetItemPropertyParam1Value(iTest) == IP_CONST_DAMAGETYPE_DIVINE) && (GetItemPropertyCostTableValue(iTest) == DAMAGE_BONUS_2d6);
                    break;
                case ITEM_PROPERTY_LIGHT:
                    if (nLevel >= SHINING_BLADE_LEVEL_BRILLIANT)
                        bRemove = TRUE;
                    break;
            }
        }
        if (bRemove)
            RemoveItemProperty(oWeapon, iTest);
        iTest = GetNextItemProperty(oWeapon);
    }
}

void ShockBlade_ApplyProperties(object oWeapon, int nDuration)
{
    //Remove any old properties
    
    ShiningBlade_RemoveProperties(oWeapon, SHINING_BLADE_LEVEL_SHOCK);

    //Add the new properties

    if (nDuration)
        AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_ELECTRICAL, DAMAGE_BONUS_1d6), oWeapon, RoundsToSeconds(nDuration));
}

void HolyBlade_ApplyProperties(object oWeapon, int nDuration)
{
    //Remove any old properties
    
    ShiningBlade_RemoveProperties(oWeapon, SHINING_BLADE_LEVEL_HOLY);

    //Add the new properties

    if (nDuration)
    {
        AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_ELECTRICAL, DAMAGE_BONUS_1d6), oWeapon, RoundsToSeconds(nDuration));
        AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL, IP_CONST_DAMAGETYPE_DIVINE, DAMAGE_BONUS_2d6), oWeapon, RoundsToSeconds(nDuration));
    }
}

void BrilliantBlade_ApplyProperties(object oWeapon, int nDuration)
{
    //Remove any old properies
    
    ShiningBlade_RemoveProperties(oWeapon, SHINING_BLADE_LEVEL_BRILLIANT);

    //Add the new properties

    if (nDuration)
    {
        AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_ELECTRICAL, DAMAGE_BONUS_1d6), oWeapon, RoundsToSeconds(nDuration));
        AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL, IP_CONST_DAMAGETYPE_DIVINE, DAMAGE_BONUS_2d6), oWeapon, RoundsToSeconds(nDuration));
        AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyLight(IP_CONST_LIGHTBRIGHTNESS_BRIGHT, IP_CONST_LIGHTCOLOR_WHITE), oWeapon, RoundsToSeconds(nDuration));
    }
}

void BrilliantBlade_ApplyAttackBonuses(object oPC, int bOnHand, int bOffHand)
{
    //ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectAttackIncrease(20, nAttackBonusHand)), oPC, RoundsToSeconds(nDuration));
        //This applies the attack bonus only to hands currently containing longsword, 
        //but incorrectly the bonus is still active if the longsword is exchanged for another weapon.

    //AddItemProperty(DURATION_TYPE_TEMPORARY, ItemPropertyAttackBonus(20), oWeapon, RoundsToSeconds(nDuration));
        //This adds the bonus only to the correct wielded weapon(s), but won't increase AB with
        //a longsword that one is not wielding at the time the bonus is applied.
        //Note: theoretically, we should increase the AB of the weapon by 20, not set it to 20; however, since the AB
        //cap is 20, and the AB of a weapon is included in the cap, it makes little practical difference.
        //NOTE: this provide +20 DR penetration, so it's a no-go (see http://nwn.wikia.com/wiki/Damage_reduction)            

    SetCompositeAttackBonus(oPC, "SB_BrilliantBlade_R", bOnHand?20:0, ATTACK_BONUS_ONHAND);
    SetCompositeAttackBonus(oPC, "SB_BrilliantBlade_L", bOffHand?20:0, ATTACK_BONUS_OFFHAND);
}

void ShiningBlade_ApplyProperties(object oWeapon, int nDuration, int nLevel)
{
    switch(nLevel)
    {
        case SHINING_BLADE_LEVEL_SHOCK:
            ShockBlade_ApplyProperties(oWeapon, nDuration);
            break;

        case SHINING_BLADE_LEVEL_HOLY:
            HolyBlade_ApplyProperties(oWeapon, nDuration);
            break;

        case SHINING_BLADE_LEVEL_BRILLIANT:
            BrilliantBlade_ApplyProperties(oWeapon, nDuration);
            break;
    }
}

void ShiningBlade_ApplyAttackBonuses(object oPC, int bOnHand, int bOffHand, int nLevel)
{
    if (nLevel >= SHINING_BLADE_LEVEL_BRILLIANT)
        BrilliantBlade_ApplyAttackBonuses(oPC, bOnHand, bOffHand);
    else
        BrilliantBlade_ApplyAttackBonuses(oPC, FALSE, FALSE);
}

void ShiningBlade_ExpireBonuses(object oPC, int nGeneration, int nLevel)
{
    int nShiningBladeGeneration = GetLocalInt(oPC, PRC_ShiningBlade_Generation);
    if (nGeneration == nShiningBladeGeneration)
    {
        if (DEBUG) DoDebug("Expiring Shining Blade bonuses");

        //Zero out variables so that equipping a weapon doesn't reapply the expired bonuses
        SetLocalInt(oPC, PRC_ShiningBlade_Duration, 0);
        SetLocalInt(oPC, PRC_ShiningBlade_Level, 0);

        //Expire bonsues on wielded weapons
        object oOnHandWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
        object oOffHandWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
        if (GetBaseItemType(oOnHandWeapon) == BASE_ITEM_LONGSWORD)
            ShiningBlade_RemoveProperties(oOnHandWeapon, nLevel);
        if (GetBaseItemType(oOffHandWeapon) == BASE_ITEM_LONGSWORD)
            ShiningBlade_RemoveProperties(oOffHandWeapon, nLevel);

        //Expire attack bonuses
        ShiningBlade_ApplyAttackBonuses(oPC, FALSE, FALSE, nLevel);
    }
    else
    {
        //The Brilliant/Holy/Shock Blade feat has been used again since this removal was scheduled, 
        //so don't expire--the next application of the feat will expire them
        //when *it's* time runs out.
        if (DEBUG) DoDebug("Not expiring Shining Blade bonuses: " + IntToString(nGeneration) + ", " + IntToString(nShiningBladeGeneration));
    }
}

void ShiningBlade_ScheduleBonusExpiration(object oPC, int nDuration, int nLevel)
{
    int nGeneration = PRC_NextGeneration(GetLocalInt(oPC, PRC_ShiningBlade_Generation));
    SetLocalInt(oPC, PRC_ShiningBlade_Generation, nGeneration);
    DelayCommand(RoundsToSeconds(nDuration), ShiningBlade_ExpireBonuses(oPC, nGeneration, nLevel));
}
