//::///////////////////////////////////////////////
//:: Name      Eldritch Blast - Normal
//:: FileName  inv_eldtch_blast.nss
//:://////////////////////////////////////////////

#include "prc_inc_combat"
#include "prc_inc_sp_tch"
#include "inv_inc_invfunc"
#include "inv_invokehook"
#include "inv_inc_blast"

//internal function for delayed damage
void DoDelayedBlast(object oTarget, int nDamageType = DAMAGE_TYPE_FIRE, int nVFX = VFX_IMP_FLAME_M)
{
    ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(2), nDamageType), oTarget);
    ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(nVFX), oTarget);
}

void main()
{
    // Ugly hack to tell PreInvocationCastCode() that we are casting as warlock
    object oPC = OBJECT_SELF;
    SetLocalInt(oPC, PRC_INVOKING_CLASS, CLASS_TYPE_WARLOCK + 1);
    DelayCommand(0.0f, DeleteLocalInt(oPC, PRC_INVOKING_CLASS));

    if(!PreInvocationCastCode()) return;

    object oTarget = PRCGetSpellTargetObject();
    int nEssence = GetLocalInt(oPC, "BlastEssence");
    int nEssence2 = GetLocalInt(oPC, "BlastEssence2");
    int nEssenceData = GetLocalInt(oPC, "EssenceData");
    int nEssenceData2 = GetLocalInt(oPC, "EssenceData2");
    effect eEssence;

    //remove Corrupting Blast essence - it's a one-shot power
    if(nEssence == INVOKE_CORRUPTING_BLAST)
        DeleteLocalInt(oPC, "BlastEssence");
    else if(nEssence2 == INVOKE_CORRUPTING_BLAST)
        DeleteLocalInt(oPC, "BlastEssence2");

    //calculate DC for essence effects
    int nInvLevel = GetInvokerLevel(oPC, CLASS_TYPE_WARLOCK);
    int nBlastLvl = min((nInvLevel + 1) / 2, 9);
    nBlastLvl = max(max(nEssenceData & 0xF, nEssenceData2 & 0xF), nBlastLvl);
    int nDC = 10 + nBlastLvl + GetAbilityModifier(ABILITY_CHARISMA);
    if(GetHasFeat(FEAT_LORD_OF_ALL_ESSENCES)) nDC += 2;

    int nDamageType = nEssence ? (nEssenceData >>> 4) & 0xFFF : DAMAGE_TYPE_MAGICAL;
    int nDamageType2 = nEssence2 ? (nEssenceData2 >>> 4) & 0xFFF : DAMAGE_TYPE_MAGICAL;

    //Set correct blast damage type
    if(nDamageType != nDamageType2)
    {
        if(nDamageType != DAMAGE_TYPE_MAGICAL)
        {
            if(nDamageType2 == DAMAGE_TYPE_MAGICAL)
                nDamageType2 = nDamageType;
        }
        else if(nDamageType2 != DAMAGE_TYPE_MAGICAL)
        {
            nDamageType = nDamageType2;
        }
    }

    //get beam and impact vfx
    int nBeamVFX, nVis;
    switch(nDamageType)
    {
        case DAMAGE_TYPE_FIRE:     nBeamVFX = VFX_BEAM_FIRE;         nVis = VFX_IMP_FLAME_M;         break;
        case DAMAGE_TYPE_COLD:     nBeamVFX = VFX_BEAM_COLD;         nVis = VFX_IMP_FROST_S;         break;
        case DAMAGE_TYPE_ACID:     nBeamVFX = VFX_BEAM_DISINTEGRATE; nVis = VFX_IMP_ACID_S;          break;
        case DAMAGE_TYPE_NEGATIVE: nBeamVFX = VFX_BEAM_BLACK;        nVis = VFX_IMP_NEGATIVE_ENERGY; break;
        default:                   nBeamVFX = VFX_BEAM_DISINTEGRATE; nVis = VFX_IMP_LIGHTNING_S;     break;
    }

    effect eVis = EffectVisualEffect(nVis);

    //add second vfx if needed
    if(nDamageType != nDamageType2)
    {
        switch(nDamageType2)
        {
            case DAMAGE_TYPE_FIRE:     nVis = VFX_IMP_FLAME_M;         break;
            case DAMAGE_TYPE_COLD:     nVis = VFX_IMP_FROST_S;         break;
            case DAMAGE_TYPE_ACID:     nVis = VFX_IMP_ACID_S;          break;
            case DAMAGE_TYPE_NEGATIVE: nVis = VFX_IMP_NEGATIVE_ENERGY; break;
        }
        eVis = EffectLinkEffects(eVis, EffectVisualEffect(nVis));
    }

    int nDam = d6(GetBlastDamageDices(oPC, nInvLevel));
    if(GetHasSpellEffect(INVOKE_WILD_FRENZY, oPC))
        nDam += 2;

    int nAtkBns = GetAttackBonus(oTarget, oPC, OBJECT_INVALID, FALSE, TOUCH_ATTACK_RANGED_SPELL);
    if(GetHasFeat(FEAT_ELDRITCH_SCULPTOR))
        nAtkBns += 2;

    //Penetrating Blast
    int nPenetr = nInvLevel + SPGetPenetr();
    if(nEssence == INVOKE_PENETRATING_BLAST || nEssence2 == INVOKE_PENETRATING_BLAST)
        nPenetr += 4;

    //Bane Blast
    int nRace = MyPRCGetRacialType(oTarget);
    if(nRace == ((nEssenceData >>> 16) & 0xFF) - 1
    || nRace == ((nEssenceData2 >>> 16) & 0xFF) - 1)
        nDam += d6(2);

    int nHellFire = 0;
    if(GetIsHellFireBlast(oPC))
    {
        if(HellFireConDamage(oPC))
        {
            nHellFire = GetLevelByClass(CLASS_TYPE_HELLFIRE_WARLOCK, oPC) * 2;
            nBeamVFX = VFX_BEAM_FIRE;
        }
    }

    //Hammer Blast
    if(GetObjectType(oTarget) != OBJECT_TYPE_CREATURE && nEssence != INVOKE_HAMMER_BLAST && nEssence2 != INVOKE_HAMMER_BLAST)
    {
        nDam /= 2;
        if(nDam < 1) nDam = 1;
        nHellFire /= 2;
    }

    if(!GetIsReactionTypeFriendly(oTarget))
    {
        //Fire cast spell at event for the specified target
        SignalEvent(oTarget, EventSpellCastAt(oPC, INVOKE_ELDRITCH_BLAST));

        int iAttackRoll = PRCDoRangedTouchAttack(oTarget, TRUE, oPC, nAtkBns);
        if(iAttackRoll)
        {
            //Make SR Check
            int iSR = PRCDoResistSpell(oPC, oTarget, nPenetr);
            if(!iSR)
            {
                 //Apply secondary effects from essence invocations
                 if(nEssence == INVOKE_PENETRATING_BLAST || nEssence2 == INVOKE_PENETRATING_BLAST)
                 {
                     eEssence = EffectSpellResistanceDecrease(5);
                     if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, TurnsToSeconds(1));
                 }
                 if((nEssence == INVOKE_HINDERING_BLAST || nEssence2 == INVOKE_HINDERING_BLAST) && PRCGetIsAliveCreature(oTarget))
                 {
                     eEssence = EffectSlow();
                     if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
                 }
                 if(nEssence == INVOKE_BINDING_BLAST || nEssence2 == INVOKE_BINDING_BLAST)
                 {
                     eEssence = EffectStunned();
                     if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
                 }
                 if(nEssence == INVOKE_BEWITCHING_BLAST || nEssence2 == INVOKE_BEWITCHING_BLAST)
                 {
                     eEssence = PRCEffectConfused();
                     if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
                 }
                 if((nEssence == INVOKE_BESHADOWED_BLAST || nEssence2 == INVOKE_BESHADOWED_BLAST) && PRCGetIsAliveCreature(oTarget))
                 {
                     eEssence = EffectBlindness();
                     if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
                 }
                 if((nEssence == INVOKE_HELLRIME_BLAST || nEssence2 == INVOKE_HELLRIME_BLAST))
                 {
                     eEssence = EffectAbilityDecrease(ABILITY_DEXTERITY, 4);
                     if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, TurnsToSeconds(10));
                 }
                 if(nEssence == INVOKE_UTTERDARK_BLAST || nEssence2 == INVOKE_UTTERDARK_BLAST)
                 {
                     eEssence = EffectNegativeLevel(2);
                     if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, HoursToSeconds(1));
                 }
                 if(nEssence == INVOKE_FRIGHTFUL_BLAST || nEssence2 == INVOKE_FRIGHTFUL_BLAST)
                 {
                     effect eDur2 = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
                     effect eFear = EffectFrightened();
                     effect eAttackD = EffectAttackDecrease(2);
                     effect eDmgD = EffectDamageDecrease(2,DAMAGE_TYPE_BLUDGEONING|DAMAGE_TYPE_PIERCING|DAMAGE_TYPE_SLASHING);
                     effect SaveD = EffectSavingThrowDecrease(SAVING_THROW_ALL,2);
                     effect Skill = EffectSkillDecrease(SKILL_ALL_SKILLS,2);

                     eEssence = EffectLinkEffects(eDmgD, eDur2);
                     eEssence = EffectLinkEffects(eEssence, eAttackD);
                     eEssence = EffectLinkEffects(eEssence, SaveD);
                     eEssence = EffectLinkEffects(eEssence, eFear);
                     eEssence = EffectLinkEffects(eEssence, Skill);

                     if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, TurnsToSeconds(1));
                 }
                 if(nEssence == INVOKE_NOXIOUS_BLAST || nEssence2 == INVOKE_NOXIOUS_BLAST)
                 {
                     eEssence = EffectDazed();
                     if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, TurnsToSeconds(1));
                 }
                 if(nEssence == INVOKE_CORRUPTING_BLAST || nEssence2 == INVOKE_CORRUPTING_BLAST)
                 {
                     if(CheckTurnUndeadUses(oPC, 1))
                     {
                         int nRed = GetLevelByClass(CLASS_TYPE_ELDRITCH_DISCIPLE, oPC) / 2;
                         if(nRed < 1) nRed = 1;
                         eEssence = EffectSavingThrowDecrease(SAVING_THROW_WILL, nRed);
                         eEssence = EffectLinkEffects(eEssence, EffectVisualEffect(VFX_DUR_MIND_AFFECTING_NEGATIVE));
                         ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
                     }
                     else
                         SpeakStringByStrRef(40550);//"This ability is tied to your turn undead ability, which has no more uses for today."
                 }
                 if((nEssence == INVOKE_SICKENING_BLAST || nEssence2 == INVOKE_SICKENING_BLAST) && PRCGetIsAliveCreature(oTarget))
                 {
                    eEssence = EffectSickened();
                    if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
                        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, 60.0);
                 }
                 if((nEssence == INVOKE_BRIMSTONE_BLAST || nEssence2 == INVOKE_BRIMSTONE_BLAST) && !GetLocalInt(oTarget, "BrimstoneFire"))
                 {
                     if(!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_FIRE))
                     {
                         SetLocalInt(oTarget, "BrimstoneFire", TRUE);
                         int nDuration = nInvLevel / 5;
                         DelayCommand(RoundsToSeconds(nDuration), DeleteLocalInt(oTarget, "BrimstoneFire"));

                         int i;
                         float fRound = RoundsToSeconds(1);
                         for(i = 1; i <= nDuration; i++)
                         {
                             DelayCommand(fRound * i, DoDelayedBlast(oTarget));
                         }
                     }
                 }
                 //Apply the VFX impact
                 ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
             }
             //Vitriolic ignores SR
             if(nEssence == INVOKE_VITRIOLIC_BLAST || nEssence2 == INVOKE_VITRIOLIC_BLAST)
             {
                 //Apply the VFX impact
                 if(iSR) ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);

                 //Apply secondary effect from essence invocations
                 int nDuration = nInvLevel / 5;

                 int i;
                 float fRound = RoundsToSeconds(1);
                 for(i = 1; i <= nDuration; i++)
                 {
                     DelayCommand(fRound * i, DoDelayedBlast(oTarget, DAMAGE_TYPE_ACID, VFX_IMP_ACID_S));
                 }
             }
             //Apply damage effect
             ApplyBlastDamage(oPC, oTarget, iAttackRoll, iSR, nDam, nDamageType, nDamageType2, nHellFire);
        }
        //Beam VFX.
        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBeam(nBeamVFX, oPC, BODY_NODE_HAND, !iAttackRoll), oTarget, 1.0f);

        //Apply Spellblast or Greatreach Blast effect
        DoSpellBlast(oPC, iAttackRoll);

        if(GetHasFeat(FEAT_ELDRITCH_SCULPTOR, oPC))
        {
            if(!GetLocalInt(oPC, "UsingSecondBlast"))
            {
                SetLocalInt(oPC, "UsingSecondBlast", TRUE);
                UseInvocation(INVOKE_ELDRITCH_SPEAR, CLASS_TYPE_WARLOCK, 0, TRUE);
            }
            else
                DeleteLocalInt(oPC, "UsingSecondBlast");
        }
    }
}
