#include "tob_inc_tobfunc"
#include "prc_inc_combmove"

void DelayedDamageHB(object oPC, int nCount);

int LevelToDelayedDamage(int nLevel)
{
	int nDelayedDamage = -1;
	
	if (nLevel == 20) nDelayedDamage = 30;
	else if (nLevel >= 16) nDelayedDamage = 25;
	else if (nLevel >= 12) nDelayedDamage = 20;
	else if (nLevel >= 8) nDelayedDamage = 15;
	else if (nLevel >= 4) nDelayedDamage = 10;
	else if (nLevel >= 1) nDelayedDamage = 5;
	
	return nDelayedDamage;
}

void IndomitableSoul(object oPC)
{
        int nSave = GetAbilityModifier(ABILITY_CHARISMA, oPC);
        // Can't be negative.
        if (0 > nSave) nSave = 0;
        // Charisma to Will saves
        effect eFort = ExtraordinaryEffect(EffectSavingThrowIncrease(SAVING_THROW_WILL, nSave));
        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eFort, oPC);
        if (DEBUG) DoDebug("Indomitable Soul applied.");
}

void DelayedDamageHB(object oPC, int nCount)
{
    int nCurHP = GetCurrentHitPoints(oPC);
    int nPreHP = GetLocalInt(oPC, "CrusaderHP");
    int nClass = GetLevelByClass(CLASS_TYPE_CRUSADER, oPC);
    object oHand   = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
    
    if (nPreHP > nCurHP)
    {
            // Check current delayed damage pool and max delayed
            int nDelayedPool = GetLocalInt(oPC, "DelayedDamage");
            int nMaxDelayed = LevelToDelayedDamage(nClass);
            //if (DEBUG) DoDebug("Delayed Pool equals: "+IntToString(nDelayedPool));
            //if (DEBUG) DoDebug("Maximum Delayed equals: "+IntToString(nMaxDelayed));
        
            // If there is space left
            if (nMaxDelayed > nDelayedPool)
            {
                // Amount remaining
                int nRemainingPool = nMaxDelayed - nDelayedPool;
                //if (DEBUG) DoDebug("Remaining Pool equals: "+IntToString(nRemainingPool));
                // Damage dealt
                int nDamageTaken = nPreHP - nCurHP;
                int nHeal = 0;
                //if (DEBUG) DoDebug("Damage Taken equals: "+IntToString(nDamageTaken));
                // Prevents player from regaining more HP than damage taken
                if(nDamageTaken >= nRemainingPool)
                    nHeal = nRemainingPool;
                else
                    nHeal = nDamageTaken;
                    
                //if (DEBUG) DoDebug("Heal Amount equals: "+IntToString(nHeal));
                // Heal them the Delayed Damage
                //effect eHeal = EffectHeal(nHeal);
                if (!GetLocalInt(oPC, "CrusaderBreak")) //ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oPC);
                	if (GetMaxHitPoints(oPC) >=  nCurHP + nHeal)
                		SetCurrentHitPoints(oPC, nCurHP + nHeal); // Done this way so it doesn't show up on the char screen
                
                // Mark the Local Int with current damage plus whatever else was healed
                SetLocalInt(oPC, "DelayedDamage", nDelayedPool + nHeal);
            }    
    }
    if (nCount == 24)
    {
        // Get the amount of damage prevented
        int nDelayedPool = GetLocalInt(oPC, "DelayedDamage");
        //if (DEBUG) DoDebug("Your delayed damage pool: " + IntToString(nDelayedPool));
        if (nDelayedPool > 0)
        {
            // Furious counterstrike is delayed damage / 5
            int nBonus = nDelayedPool / 5;
            // Minimum of one if you have delayed damage
            if (nBonus == 0 && nDelayedPool > 0) nBonus = 1;
            //if (DEBUG) DoDebug("Your furious counterstrike: " + IntToString(nBonus));
            // Calculate damage type and apply
            int nDamageType = GetWeaponDamageType(oHand);
            effect eLink = EffectLinkEffects(EffectAttackIncrease(nBonus), EffectDamageIncrease(GetIntToDamage(nBonus), nDamageType));
            eLink = EffectLinkEffects(eLink, EffectVisualEffect(PSI_DUR_BURST));
            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(eLink), oPC, 6.0);
            // Visuals
            //effect eVis = EffectVisualEffect(VFX_DUR_MARK_OF_THE_HUNTER);
            //ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
            
            // Now apply the delayed damage
            int nTest = GetCurrentHitPoints(oPC);
            if (nTest - nDelayedPool > 0) SetCurrentHitPoints(oPC, nTest - nDelayedPool);
            else // If this triggers, the PC is dead
            {
            	ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDamage(nDelayedPool, DAMAGE_TYPE_POSITIVE, DAMAGE_POWER_ENERGY)), oPC);
            	ApplyEffectToObject(DURATION_TYPE_INSTANT, SupernaturalEffect(EffectDeath(TRUE)), oPC);
            }	
            int nTest2 = GetCurrentHitPoints(oPC);
            if ((nTest - nDelayedPool) != nTest2) SetLocalInt(oPC, "CrusaderBreak", TRUE);
            else DeleteLocalInt(oPC, "CrusaderBreak");
        }   
        // Clean up local int for this round
        DeleteLocalInt(oPC, "DelayedDamage");
        //if (DEBUG) DoDebug("Deleted delayed damage: " + IntToString(GetLocalInt(oPC, "DelayedDamage"))); 
        nCount = 0; // Reset the loop
    }
    SetLocalInt(oPC, "CrusaderHP", GetCurrentHitPoints(oPC));
    DelayCommand(0.25, DelayedDamageHB(oPC, nCount+1));
}

void main()
{
    int nEvent = GetRunningEvent();
    //if(DEBUG) DoDebug("tob_crusader running, event: " + IntToString(nEvent));

    // Get the PC. This is event-dependent
    object oPC;
    switch(nEvent)
    {
        case EVENT_ITEM_ONHIT:          oPC = OBJECT_SELF;               break;
        case EVENT_ONPLAYEREQUIPITEM:   oPC = GetItemLastEquippedBy();   break;
        case EVENT_ONPLAYERUNEQUIPITEM: oPC = GetItemLastUnequippedBy(); break;
        case EVENT_ONHEARTBEAT:         oPC = OBJECT_SELF;               break;

        default:
            oPC = OBJECT_SELF;
    }

    object oItem;
    object oArmour = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
    object oHand   = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
    int nClass = GetLevelByClass(CLASS_TYPE_CRUSADER, oPC);

    // We aren't being called from any event, instead from EvalPRCFeats
    if(nEvent == FALSE)
    {
    	// Saving throw bonus, charisma, does not stack with paladin
    	//if (nClass >= 2 && GetLevelByClass(CLASS_TYPE_PALADIN, oPC) == 0)IndomitableSoul(oPC);
        // Hook in the events, needed from level 1 for Steely Resolve
        //if(DEBUG) DoDebug("tob_crusader: Adding eventhooks");
        //AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM,   "tob_crusader", TRUE, FALSE);
        //AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "tob_crusader", TRUE, FALSE);
        AddEventScript(oPC, EVENT_ONHEARTBEAT,         "tob_crusader", TRUE, FALSE);
        //AddEventScript(oPC, EVENT_VIRTUAL_ONDAMAGED,   "tob_crusader", TRUE, FALSE);
        if (!GetLocalInt(oPC, "DelayedDamageHB")) 
        {
            DelayedDamageHB(oPC, 1);
            SetLocalInt(oPC, "DelayedDamageHB", TRUE);
        }    
    }
    // Damage reduction from Steely Resolve
    /*else if(nEvent == EVENT_VIRTUAL_ONDAMAGED)
    {
        FloatingTextStringOnCreature("Ouch ouch ouch!", oPC);
    }
    // Damage reduction from Steely Resolve
    else if(nEvent == EVENT_ITEM_ONHIT)
    {
        oItem          = GetSpellCastItem();
        object oTarget = PRCGetSpellTargetObject();
        if(DEBUG) DoDebug("tob_crusader: OnHit:\n"
                        + "oPC = " + DebugObject2Str(oPC) + "\n"
                        + "oItem = " + DebugObject2Str(oItem) + "\n"
                        + "oTarget = " + DebugObject2Str(oTarget) + "\n"
                          );

        // Only applies to armours
        if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
        {
        	// Check current delayed damage pool and max delayed
		    int nDelayedPool = GetLocalInt(oPC, "DelayedDamage");
		    int nMaxDelayed = LevelToDelayedDamage(nClass);
            if (DEBUG) DoDebug("Delayed Pool equals: "+IntToString(nDelayedPool));
            if (DEBUG) DoDebug("Maximum Delayed equals: "+IntToString(nMaxDelayed));
		
		    // If there is space left
		    if (nMaxDelayed > nDelayedPool)
		    {
		    	// Amount remaining
		    	int nRemainingPool = nMaxDelayed - nDelayedPool;
                if (DEBUG) DoDebug("Remaining Pool equals: "+IntToString(nRemainingPool));
		    	// Damage dealt
		    	int nDamageTaken = GetTotalDamageDealt();
     	    	int nHeal = 0;
                if (DEBUG) DoDebug("Damage Taken equals: "+IntToString(nDamageTaken));
		    	// Prevents player from regaining more HP than damage taken
		    	if(nDamageTaken >= nRemainingPool)
		    		nHeal = nRemainingPool;
		    	else
		    		nHeal = nDamageTaken;
                    
                if (DEBUG) DoDebug("Heal Amount equals: "+IntToString(nHeal));
                // Heal them the Delayed Damage
		    	effect eHeal = EffectHeal(nHeal);
		    	ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oPC);
		    	
		    	// Mark the Local Int with current damage plus whatever else was healed
		    	SetLocalInt(oPC, "DelayedDamage", nDelayedPool + nHeal);
		    }
        }// end if - Item is an armour
    }// end if - Running OnHit event
    // We are called from the OnPlayerEquipItem eventhook. Add OnHitCast: Unique Power to oPC's armour
    else if(nEvent == EVENT_ONPLAYEREQUIPITEM)
    {
        oPC   = GetItemLastEquippedBy();
        oItem = GetItemLastEquipped();
        if(DEBUG) DoDebug("tob_crusader - OnEquip");

        // Only applies to armours
        if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
        {
            // Add eventhook to the item
            AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_crusader", 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 armour
    else if(nEvent == EVENT_ONPLAYERUNEQUIPITEM)
    {
        oPC   = GetItemLastUnequippedBy();
        oItem = GetItemLastUnequipped();
        if(DEBUG) DoDebug("tob_crusader - OnUnEquip");

        // Only applies to armours
        if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR)
        {
            // Add eventhook to the item
            RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_crusader", TRUE, FALSE);

            // Remove the temporary OnHitCastSpell: Unique
            RemoveSpecificProperty(oItem, ITEM_PROPERTY_ONHITCASTSPELL, IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 0, 1, "", 1, DURATION_TYPE_TEMPORARY);
        }
    }*/
    // This is used to determine the bonus from Furious Counterstrike
    else if(nEvent == EVENT_ONHEARTBEAT)
    {
        //if they are deleveled completely out of Crusader, no need to keep running these
        if(!GetLevelByClass(CLASS_TYPE_CRUSADER, oPC))
        {
            RemoveEventScript(oPC, EVENT_ONPLAYEREQUIPITEM,   "tob_crusader", TRUE, FALSE);
            RemoveEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "tob_crusader", TRUE, FALSE);
            RemoveEventScript(oPC, EVENT_ONHEARTBEAT,         "tob_crusader", TRUE, FALSE);
        }
    }
}