/////////////////////////////////////////////////////////////////////////////////////////////////
//:: This is the prc_dispel_magic functions declarations.   The functions themselves are at the bottom
//:: of the file.       I got tired of circular include statement errors and just decided to make
//:: these both be just one file by adding my text to theirs.
///////////////////////////////////////////////////////////////////////////////////////////////

// GZ: Number of spells in GetSpellBreachProtections
const int PRC_SPELLS_MAX_BREACH = 33;

//:: This is my remake of the spellsDispelMagic found in x0_i0_spells.   It's pretty much
//:: identical to the old one except instead of calling the EffectDispelMagicBest() and
//:: EffectDispelMagicAll() scripting functions it calls the ones I've specified in this
//:: file to replace them.
void spellsDispelMagicMod(object oTarget, int nCasterLevel, effect eVis, effect eImpac, int bAll = TRUE, int bBreachSpells = FALSE);

//:: This is my remake of spellsDispelAoE().  It's very different, and very short.   It
//:: takes advantage of the way I've reworked AoE's so that it can simply use the caster
//:: level stored in the AoE and do a proper dispel check against it.
void spellsDispelAoEMod(object oTargetAoE, object oCaster, int nCasterLevel);

//:: This function is to replace EffectDispelMagicBest().   It goes through the references
//:: in the three arrays that store the caster levels and references to effects on oTarget,
//:: chooses the one with the highest caster level, and attempts to dispel it using the
//:: caster level entry in the array that corresponds to the spell itself.
void DispelMagicBestMod(object oTarget, int nCasterLevel);

//:: This function is to replace EffectDispelMagicAll().  It goest through all the references
//:: in the three arrays that store the caster levels and references to effects on oTarget, and
//:: attempts a dispel on each of them.  It only checks to dispel whole spells, not individual
//:: separate effects one spell may place on a person.
void DispelMagicAllMod(object oTarget, int nCasterLevel);

//:: This function sorts the 3 arrays in descending order of caster level, so entry 0 is the
//:: highest, and the last entry is the lowest.  It only gets called from inside DispelMagicBest()
void SortAll3Arrays(object oTarget);

//:: This function is just a helper function to include Infestation of Maggots among the list
//:: of spells in effect on oTarget, so it can be sorted with the rest. It's only called by
//:: DispelMagicBest()
void HandleInfestationOfMaggots(object oTarget);

// This is only meant to be called withing SetAllAoEInts()  I've heard terrible stories that
// say if an object is destroyed, it's local variables may remain in place eating up memory
// so I decided I'd better mop up after setting all of these.
void DeleteAllAoEInts(object oAoE);

// Returns the AoE's entire caster level, including any from prc's as stored in the local variable
int AoECasterLevel(object oAoE = OBJECT_SELF);

// * Performs a spell breach up to nTotal spell are removed and
// * nSR spell resistance is  lowered. nSpellId can be used to override
// * the originating spell ID. If not specified, SPELL_GREATER_SPELL_BREACH
// * is used
void PRCDoSpellBreach(object oTarget, int nTotal, int nSR, int nSpellId = -1);

// * Performs a spell breach up to nTotal spells are removed and nSR spell
// * resistance is lowered.
int PRCGetSpellBreachProtection(int nLastChecked);

// * Remove all spell protections of a specific type
int PRCRemoveProtections(int nSpell_ID, object oTarget, int nCount);

// * Handle dispel magic of AoEs
void spellsDispelAoE(object oTargetAoE, object oCaster, int nCasterLevel);

// * dispel magic on one or multiple targets.
// * if bAll is set to TRUE, all effects are dispelled from a creature
// * else it will only dispel the best effect from each creature (used for AoE)
// * Specify bBreachSpells to add Mord's Disjunction to the dispel
void spellsDispelMagic(object oTarget, int nCasterLevel, effect eVis, effect eImpac, int bAll = TRUE, int bBreachSpells = FALSE);

// Mysteries have a -4 when dispelling spells and vice versa
int GetIsMystery(int nSpellId);

#include "prc_effect_inc"
#include "lookup_2da_spell"
#include "spinc_remeffct"
#include "prcsp_engine"

//////////////////////////////////////////////////////////////////////////////////////////////////////


//:: Copy of the original function with 1 minor change: calls DispelMagicAll() and
//:: DispelMagicBest() instead of EffectDispelMagicAll() and EffectDispelMagicBest()
//:: That is the only change.
//------------------------------------------------------------------------------
// Attempts a dispel on one target, with all safety checks put in.
//------------------------------------------------------------------------------
void spellsDispelMagicMod(object oTarget, int nCasterLevel, effect eVis, effect eImpac, int bAll = TRUE, int bBreachSpells = FALSE)
{
    //--------------------------------------------------------------------------
    // Don't dispel magic on petrified targets
    // this change is in to prevent weird things from happening with 'statue'
    // creatures. Also creature can be scripted to be immune to dispel
    // magic as well.
    //--------------------------------------------------------------------------
    if (PRCGetHasEffect(EFFECT_TYPE_PETRIFY, oTarget) == TRUE
        || GetLocalInt(oTarget, "X1_L_IMMUNE_TO_DISPEL") == 10)
    {
        return;
    }

    effect eDispel;
    float fDelay = PRCGetRandomDelay(0.1, 0.3);
    int nId = PRCGetSpellId();
    if (GetItemPossessedBy(OBJECT_SELF, "WOL_Aradros") == GetItemInSlot(INVENTORY_SLOT_NECK, OBJECT_SELF) && GetIsObjectValid(GetItemPossessedBy(OBJECT_SELF, "WOL_Aradros"))) nCasterLevel += 1;
    
    //--------------------------------------------------------------------------
    // Fire hostile event only if the target is hostile...
    //--------------------------------------------------------------------------

    if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF))
        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nId));
    else
        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nId, FALSE));

    //--------------------------------------------------------------------------
    // GZ: Bugfix. Was always dispelling all effects, even if used for AoE
    //--------------------------------------------------------------------------
    if (bAll == TRUE )
    {
        //:: This is the first of 2 changes I made.
        DispelMagicAllMod(oTarget, nCasterLevel);

        // The way it used to get done.
        //eDispel = EffectDispelMagicAll(nCasterLevel);

        //----------------------------------------------------------------------
        // GZ: Support for Mord's disjunction
        //----------------------------------------------------------------------
        if (bBreachSpells)
        {
            PRCDoSpellBreach(oTarget, 6, 10, nId);
        }
    }
    else
    {
        //:: This is the second of the 2 changes I made.
        //:: There are no other changes.
        DispelMagicBestMod(oTarget, nCasterLevel);

        // The way it used to get done
        //eDispel = EffectDispelMagicBest(nCasterLevel);

        if (bBreachSpells)
        {
           PRCDoSpellBreach(oTarget, 2, 10, nId);
        }
    }

    DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
    DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDispel, oTarget));
}

/////////////////////////////////////////////////////////////////////////////////////
//::  This one's so small I hope not to lose track of it.

//:: Replaces the normal spellsDispelAoE
//:: I reworked all AoE's to store their caster level as a local int on themselves,
//:: so it's possible to just do a proper caster level check instead of doing
//:: something complicated.

void spellsDispelAoEMod(object oTargetAoE, object oCaster, int nCasterLevel)
{
   int ModWeave;
   int nBonus = 0;
   string SchoolWeave = lookup_spell_school(GetLocalInt(oTargetAoE, "X2_AoE_SpellID"));
   int Weave = GetHasFeat(FEAT_SHADOWWEAVE,oCaster)+ GetLocalInt(oCaster, "X2_AoE_SpecDispel");
   if (GetLocalInt(oTargetAoE, " X2_Effect_Weave_ID_") && !Weave) ModWeave = 4;
   if (SchoolWeave=="V" ||SchoolWeave=="T"  ) ModWeave = 0;
   if (GetLocalInt(oTargetAoE, "PRC_Power_DispellingBuffer_Active")) nBonus += 5;
   if (GetHasFeat(FEAT_SPELL_GIRDING, oTargetAoE)) nBonus += 2;
   if (GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oTargetAoE) >= 1) nBonus += 6;
   if (GetItemPossessedBy(oCaster, "WOL_Aradros") == GetItemInSlot(INVENTORY_SLOT_NECK, oCaster) && GetIsObjectValid(GetItemPossessedBy(oCaster, "WOL_Aradros"))) nCasterLevel += 1;

   int iDice = d20(1);
//   SendMessageToPC(GetFirstPC(), "Spell :"+ IntToString(PRCGetSpellId())+" T "+GetName(oTargetAoE));
//   SendMessageToPC(GetFirstPC(), "Dispell :"+IntToString(iDice + nCasterLevel)+" vs DC :"+IntToString(11 + GetLocalInt(oTargetAoE, "X2_AoE_Caster_Level")+ModWeave)+" Weave :"+IntToString(ModWeave)+" "+SchoolWeave);

   if(iDice + nCasterLevel >= GetLocalInt(oTargetAoE, "X2_AoE_Caster_Level") + ModWeave + nBonus)
   {
     DestroyObject(oTargetAoE);
   }
}

 ///////////////////////////////////////////////////////////////////////////////////


//:: Goes through all the references to effects stored in the 3 variable arrays,
//:: picks the one with the highest caster level (breaking ties by just keeping the
//:: first one it comes to) and then attempts a dispel check on it.
//:: It goes by spell, not spell effect, so a successful check removes all spell
//:: affects from that spell itself.

void DispelMagicBestMod(object oTarget, int nCasterLevel)
{
  /// I *really*  want to rewrite this one so that it simply dispels the most useful effect
  /// instead of just the one with the highest caster level.
  /// Sure hate to dispel mage armor on somebody who's immune to necromancy.   Difficult Decision, these.


  //:: calls a function to determine whether infestation of maggots is in effect
  //:: on the target.   If so, it adds it to the 3 arrays so it can be sorted with them.

  HandleInfestationOfMaggots(oTarget);

  //:: calls a function to arrange the values in the 3 arrays in order of highest caster level to lowest
  //:: Index 0 will be the highest, and nLastEntry will be the lowest.

  SortAll3Arrays(oTarget);

  int nCurrentEntry;
  int nLastEntry = GetLocalInt(oTarget, "X2_Effects_Index_Number");

  int nEffectSpellID, nEffectCastLevel;
  object oEffectCaster = OBJECT_SELF;
  int ModWeave;
  int nBonus = 0;

  string sSelf = "Dispelled: ";
  string sCast = "Dispelled on "+GetName(oTarget)+": ";

  int Weave = GetHasFeat(FEAT_SHADOWWEAVE,OBJECT_SELF)+ GetLocalInt(OBJECT_SELF, "X2_AoE_SpecDispel");
  if (GetLocalInt(oTarget, "PRC_Power_DispellingBuffer_Active")) nBonus += 5;
  if (GetHasFeat(FEAT_SPELL_GIRDING, oTarget)) nBonus += 2;
  if (GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oTarget) >= 1) nBonus += 6;
  nCasterLevel += GetEssentiaInvestedFeat(oEffectCaster, FEAT_SOULTOUCHED_SPELLCASTING);

  for(nCurrentEntry = 0; nCurrentEntry <= nLastEntry; nCurrentEntry++)
  {
    nEffectSpellID = GetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nCurrentEntry));
    oEffectCaster = GetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nCurrentEntry));
    //:: Make sure the effect it refers to is still in place before making it
    //:: number one.
    if(IsStillRealEffect(nEffectSpellID, oEffectCaster, oTarget))
    {
      ModWeave = 0;
      string SchoolWeave = lookup_spell_school(nEffectSpellID);
      string SpellName = GetStringByStrRef(StringToInt(lookup_spell_name(nEffectSpellID)));
      nEffectCastLevel = GetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrentEntry));
      if (GetLocalInt(oTarget, " X2_Effect_Weave_ID_"+ IntToString(nCurrentEntry)) && !Weave) ModWeave = 4;
      if (SchoolWeave=="V" ||SchoolWeave=="T"  ) ModWeave = 0;
      
      // -4 for Mystery vs Spell and Spell vs Mystery
      // If you have no Shadowcasting classes, you've got to be using another magic system to dispel
      if ((!GetLevelByClass(CLASS_TYPE_SHADOWCASTER, OBJECT_SELF) && !GetLevelByClass(CLASS_TYPE_SHADOWSMITH, OBJECT_SELF)) && GetIsMystery(nEffectSpellID)) nCasterLevel -= 4;
      // Likewise, if you're a Shadowcaster, you get a -4 penalty to dispel non-Mysteries. Magic number is MYST_SHADOWS_FADE
      if (PRCGetSpellId() == 18386 && !GetIsMystery(nEffectSpellID)) nCasterLevel -= 4;      

      int iDice = d20(1);
//      SendMessageToPC(GetFirstPC(), "Spell :"+ IntToString(nEffectSpellID)+" T "+GetName(oTarget)+" C "+GetName(oEffectCaster));
//      SendMessageToPC(GetFirstPC(), "Dispell :"+ IntToString(iDice + nCasterLevel)+" vs DC :"+IntToString(11 + nEffectCastLevel+ModWeave)+" Mod Weave"+IntToString(ModWeave)+" "+SchoolWeave);
      if(iDice + nCasterLevel >= 11 + nEffectCastLevel + ModWeave + nBonus)
      {
        if(nEffectSpellID != SPELL_INFESTATION_OF_MAGGOTS)
        {// If it isn't infestation of maggots we remove it one way, if it is, we remove it another.
            effect eToDispel = GetFirstEffect(oTarget);
            while(GetIsEffectValid(eToDispel))
            {
                if(GetEffectSpellId(eToDispel) == nEffectSpellID)
                {
                    if(GetEffectCreator(eToDispel) == oEffectCaster)
                    {
                      if(GetEffectSpellId(eToDispel) == INVOKE_RETRIBUTIVE_INVISIBILITY && GetLocalInt(oTarget, "DangerousInvis"))
                      {
                        location lTarget = GetLocation(oTarget);
                        effect eRetrVis = EffectVisualEffect(VFX_IMP_SONIC);
                        effect eRetrPulse = EffectVisualEffect(VFX_IMP_PULSE_WIND);
                        effect eRetrStun = EffectStunned();
                        effect eDam;
                        int nDamage;
                        int nDC;
                        float fDelay;
                        int RICasterLvl = GetLocalInt(oTarget, "DangerousInvis");
                        SPApplyEffectToObject(DURATION_TYPE_INSTANT, eRetrPulse, oTarget);
                        DeleteLocalInt(oTarget, "DangerousInvis");
                        
                        //Declare the spell shape, size and the location.  Capture the first target object in the shape.
                        object oVictim = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(20.0), lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
                        //Cycle through the targets within the spell shape until an invalid object is captured.
                        while (GetIsObjectValid(oVictim))
                        {
                            if (spellsIsTarget(oVictim, SPELL_TARGET_STANDARDHOSTILE, oTarget))
                            {
                                    //Fire cast spell at event for the specified target
                                    SignalEvent(oVictim, EventSpellCastAt(oTarget, INVOKE_RETRIBUTIVE_INVISIBILITY));
                                    //Get the distance between the explosion and the target to calculate delay
                                    fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oVictim))/20;
                                    if (!PRCDoResistSpell(oTarget, oVictim, RICasterLvl, fDelay))
                                    {
                                        //Roll damage for each target
                                        nDamage = d6(4);
                                        //nDamage += ApplySpellBetrayalStrikeDamage(oVictim, oTarget, FALSE);
                                        nDC = 16 + GetAbilityModifier(ABILITY_CHARISMA, oTarget);
                                        
                                        //save
                                        if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
                                        {
                                            nDamage = nDamage / 2;
                                            if(GetHasMettle(oTarget, SAVING_THROW_FORT)) nDamage = 0;
                                        }
                                        else
                                            DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRetrStun, oVictim, RoundsToSeconds(1)));
                                            
                                        if(nDamage > 0)
                                        {
                                            //Set the damage effect
                                            eDam = PRCEffectDamage(oVictim, nDamage, DAMAGE_TYPE_SONIC);
                                            // Apply effects to the currently selected target.
                                            DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oVictim));
                                            PRCBonusDamage(oVictim);
                                            //This visual effect is applied to the target object not the location as above.  This visual effect
                                            //represents the flame that erupts on the target not on the ground.
                                            DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eRetrVis, oVictim));
                                        }
                                     }
                                
                            }
                           //Select the next target within the spell shape.
                           oVictim = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(20.0), lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
                        }
                      }
                      else if(GetEffectSpellId(eToDispel) == INVOKE_PAINFUL_SLUMBER_OF_AGES && GetLocalInt(oTarget, "PainfulSleep"))
                      {
                          effect eSleepDam = EffectDamage(GetLocalInt(oTarget, "PainfulSleep"), DAMAGE_TYPE_MAGICAL);
                          ApplyEffectToObject(DURATION_TYPE_INSTANT, eSleepDam, oTarget);
                          DeleteLocalInt(oTarget, "PainfulSleep");
                          RemoveEventScript(oTarget, EVENT_VIRTUAL_ONDAMAGED, "inv_painsleep", FALSE, FALSE);
                      }
                      
                      RemoveEffect(oTarget, eToDispel);
                      
                      if (GetLevelByClass(CLASS_TYPE_NOCTUMANCER))
                      {
                          int nExist = GetLocalInt(OBJECT_SELF, "CaptureMagic");
                          int nSpellLevel = StringToInt(Get2DACache("spells", "Innate", nEffectSpellID));
                          SetLocalInt(OBJECT_SELF, "CaptureMagic", max(nExist, nSpellLevel/2));
                          if (GetLevelByClass(CLASS_TYPE_NOCTUMANCER) >= 10) 
                              ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectSpellImmunity(nEffectSpellID)), OBJECT_SELF, 60.0);                          
                      }
                      
                      if(GetSpellId() == INVOKE_VORACIOUS_DISPELLING)
                      {
                          //Get spell level
                          int nEffectSpellLevel = StringToInt(Get2DACache("spells", "Innate", nEffectSpellID));
                          //Damage = spell level
                          effect eSlashDam = EffectDamage(DAMAGE_TYPE_MAGICAL, nEffectSpellLevel);

                          SPApplyEffectToObject(DURATION_TYPE_INSTANT, eSlashDam, oTarget);
                      }
                      
                      else if(GetSpellId() == INVOKE_DEVOUR_MAGIC)
                      {
                          //Get spell level
                          int nEffectSpellLevel = StringToInt(Get2DACache("spells", "Innate", nEffectSpellID));
                          //HP = 5 * spell level
                          effect eDracHP = EffectTemporaryHitpoints(5 * nEffectSpellLevel);

                          //can't stack HP from multiple dispels
                          if (GetHasSpellEffect(GetSpellId(),OBJECT_SELF))
                          {
                              PRCRemoveSpellEffects(GetSpellId(), OBJECT_SELF, OBJECT_SELF);
                          }
                  
                          SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDracHP, OBJECT_SELF, 60.0);
                      }

                      else if(GetSpellId() == SPELL_SLASHING_DISPEL)
                      {
                          //Get spell level
                          int nEffectSpellLevel = StringToInt(Get2DACache("spells", "Innate", nEffectSpellID));
                          //Damage = 2 * spell level
                          effect eSlashDam = EffectDamage(DAMAGE_TYPE_MAGICAL, 2 * nEffectSpellLevel);

                          SPApplyEffectToObject(DURATION_TYPE_INSTANT, eSlashDam, oTarget);
                      }

                    }// end if effect comes from this caster
                }// end if effect comes from this spell
                eToDispel = GetNextEffect(oTarget);
            }// end of while loop
        }// end if infestation is not the spell
        else
        {
          DeleteLocalInt(oTarget, "XP2_L_SPELL_CASTER_LVL_" + IntToString (SPELL_INFESTATION_OF_MAGGOTS));
          // Deleting this variable is what actually ends the spell effect's damage.
          DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (SPELL_INFESTATION_OF_MAGGOTS));
          DeleteLocalInt(oTarget,"XP2_L_SPELL_WEAVE" + IntToString (SPELL_INFESTATION_OF_MAGGOTS));
          effect eToDispel = GetFirstEffect(oTarget);
          while(GetIsEffectValid(eToDispel))
          {
            //:: We don't worry about who cast it.  A person can only really have one infestation
            //:: going on at a time, I think.
            if(GetEffectSpellId(eToDispel) == nEffectSpellID)
            {
              RemoveEffect(oTarget, eToDispel);
            }// end if effect comes from this spell
            eToDispel = GetNextEffect(oTarget);
          }// end of while loop
        }// end else

        //:: Since the effect has been removed, delete the references to it.
        //:: This will help out the sweeping function when it gets called next (not now, though)
        // These are stored for one round for Spell Rebirth
        SetLocalInt(oTarget, "TrueSpellRebirthSpellId", GetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nCurrentEntry)));
        SetLocalInt(oTarget, "TrueSpellRebirthCasterLvl", GetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrentEntry)));
        DelayCommand(6.0, DeleteLocalInt(oTarget, "TrueSpellRebirthSpellId"));
        DelayCommand(6.0, DeleteLocalInt(oTarget, "TrueSpellRebirthCasterLvl"));

        DeleteLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nCurrentEntry));
        DeleteLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrentEntry));
        DeleteLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nCurrentEntry));
        DeleteLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nCurrentEntry));

        //:: Display a message to all involved.
        SendMessageToPC(OBJECT_SELF, sCast+SpellName);
        if (oTarget != OBJECT_SELF) SendMessageToPC(oTarget, sSelf+SpellName);

        //:: If the check was successful, then we're done.
        return;
      }// end if check is successful.
    }// end if is still a valid spell.
    else
    {
        // These are stored for one round for Spell Rebirth
        SetLocalInt(oTarget, "TrueSpellRebirthSpellId", GetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nCurrentEntry)));
        SetLocalInt(oTarget, "TrueSpellRebirthCasterLvl", GetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrentEntry)));
        DelayCommand(6.0, DeleteLocalInt(oTarget, "TrueSpellRebirthSpellId"));
        DelayCommand(6.0, DeleteLocalInt(oTarget, "TrueSpellRebirthCasterLvl"));

      // If it's not a real effect anymore, then delete the variables that refer to it.
      DeleteLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nCurrentEntry));
      DeleteLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrentEntry));
      DeleteLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nCurrentEntry));
      DeleteLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nCurrentEntry));
    }// end of else statement.

  }// end of for loop

  // If we got here, the return function above never ran, so nothing got removed:
  SendMessageToPC(OBJECT_SELF, sCast+"None");
  if (oTarget != OBJECT_SELF) SendMessageToPC(oTarget, sSelf+"None");
} // End Of Function

///////////////////////////////////////////////////////////////////////////////////////////////////////

//:: Goes through and tries to remove each and every spell effect, doing a
//:: separate caster level check for each spell.   It goes by spell, not spell
//:: effect, so a successful check removes all spell affects from that spell
//:: itself.

void DispelMagicAllMod(object oTarget, int nCasterLevel)
{

  int nIndex = 0;
  int nEffectSpellID;
  int nEffectCasterLevel;
  object oEffectCaster = OBJECT_SELF;
  int ModWeave;
  int nBonus = 0;

  int nLastEntry = GetLocalInt(oTarget, "X2_Effects_Index_Number");
  effect eToDispel;

  string sList, SpellName;
  string sSelf = "Dispelled: ";
  string sCast = "Dispelled on "+GetName(oTarget)+": ";

  int Weave = GetHasFeat(FEAT_SHADOWWEAVE,OBJECT_SELF)+ GetLocalInt(OBJECT_SELF, "X2_AoE_SpecDispel");
  if (GetLocalInt(oTarget, "PRC_Power_DispellingBuffer_Active")) nBonus += 5;
  if (GetHasFeat(FEAT_SPELL_GIRDING, oTarget)) nBonus += 2;
  if (GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oTarget) >= 1) nBonus += 6;
  nCasterLevel += GetEssentiaInvestedFeat(oEffectCaster, FEAT_SOULTOUCHED_SPELLCASTING);

  //:: Do the dispel check for each and every spell in effect on oTarget.
  for(nIndex; nIndex <= nLastEntry; nIndex++)
  {
    nEffectSpellID = GetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nIndex));
    if(GetHasSpellEffect(nEffectSpellID, oTarget))
    {
      ModWeave = 0;
      string SchoolWeave = lookup_spell_school(nEffectSpellID);
      SpellName = GetStringByStrRef(StringToInt(lookup_spell_name(nEffectSpellID)));
      nEffectCasterLevel = GetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nIndex));
      if (GetLocalInt(oTarget, " X2_Effect_Weave_ID_"+ IntToString(nIndex)) && !Weave) ModWeave = 4;
      if (SchoolWeave=="V" ||SchoolWeave=="T"  ) ModWeave = 0;
      
      // -4 for Mystery vs Spell and Spell vs Mystery
      // If you have no Shadowcasting classes, you've got to be using another magic system to dispel
      if ((!GetLevelByClass(CLASS_TYPE_SHADOWCASTER, OBJECT_SELF) && !GetLevelByClass(CLASS_TYPE_SHADOWSMITH, OBJECT_SELF)) && GetIsMystery(nEffectSpellID)) nCasterLevel -= 4;
      // Likewise, if you're a Shadowcaster, you get a -4 penalty to dispel non-Mysteries. Magic number is MYST_SHADOWS_FADE
      if (PRCGetSpellId() == 18386 && !GetIsMystery(nEffectSpellID)) nCasterLevel -= 4;

      int iDice = d20(1);
 //     SendMessageToPC(GetFirstPC(), "Spell :"+ IntToString(nEffectSpellID)+" T "+GetName(oTarget)+" C "+GetName(GetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nIndex))));
 //     SendMessageToPC(GetFirstPC(), "Dispell :"+IntToString(iDice + nCasterLevel)+" vs DC :"+IntToString(11 + nEffectCasterLevel+ModWeave)+" Weave :"+IntToString(ModWeave)+" "+SchoolWeave);

      if(iDice + nCasterLevel >= 11 + nEffectCasterLevel + ModWeave + nBonus)
      {
        sList += SpellName+", ";
        oEffectCaster = GetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nIndex));

        //:: Was going to use this function but upon reading it it became apparent it might not remove
        //:: all of the given spells effects, but just one instead.

        //PRCRemoveSpellEffects(nEffectSpellID, oEffectCaster, oTarget);

        //:: If the check is successful, go through and remove all effects originating
        //:: from that particular spell.
        effect eToDispel = GetFirstEffect(oTarget);
        while(GetIsEffectValid(eToDispel))
        {
          if(GetEffectSpellId(eToDispel) == nEffectSpellID)
          {
            if(GetEffectCreator(eToDispel) == oEffectCaster)
            {
              
              if(GetEffectSpellId(eToDispel) == INVOKE_RETRIBUTIVE_INVISIBILITY && GetLocalInt(oTarget, "DangerousInvis"))
              {
                  location lTarget = GetLocation(oTarget);
                  effect eRetrVis = EffectVisualEffect(VFX_IMP_SONIC);
                  effect eRetrPulse = EffectVisualEffect(VFX_IMP_PULSE_WIND);
                  effect eRetrStun = EffectStunned();
                  int RICasterLvl = GetLocalInt(oTarget, "DangerousInvis");
                  effect eDam;
                  int nDamage;
                  float fDelay;
                  int nDC;
                  SPApplyEffectToObject(DURATION_TYPE_INSTANT, eRetrPulse, oTarget);
                  DeleteLocalInt(oTarget, "DangerousInvis");
                        
                  //Declare the spell shape, size and the location.  Capture the first target object in the shape.
                  object oVictim = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(20.0), lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
                  //Cycle through the targets within the spell shape until an invalid object is captured.
                  while (GetIsObjectValid(oVictim))
                  {
                      if (spellsIsTarget(oVictim, SPELL_TARGET_STANDARDHOSTILE, oTarget))
                      {
                              //Fire cast spell at event for the specified target
                              SignalEvent(oVictim, EventSpellCastAt(oTarget, INVOKE_RETRIBUTIVE_INVISIBILITY));
                              //Get the distance between the explosion and the target to calculate delay
                              fDelay = GetDistanceBetweenLocations(lTarget, GetLocation(oVictim))/20;
                              if (!PRCDoResistSpell(oTarget, oVictim, RICasterLvl, fDelay))
                              {
                                  //Roll damage for each target
                                  nDamage = d6(4);
                                  nDamage += ApplySpellBetrayalStrikeDamage(oVictim, oTarget, FALSE);
                                  nDC = 16 + GetAbilityModifier(ABILITY_CHARISMA, oTarget);
                                        
                                  //save
                                  if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
                                  {
                                      nDamage = nDamage / 2;
                                      if(GetHasMettle(oTarget, SAVING_THROW_FORT)) nDamage = 0;
                                  }
                                  else
                                      DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRetrStun, oVictim, RoundsToSeconds(1)));
                                            
                                  if(nDamage > 0)
                                  {
                                      //Set the damage effect
                                      eDam = PRCEffectDamage(oVictim, nDamage, DAMAGE_TYPE_SONIC);
                                      // Apply effects to the currently selected target.
                                      DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oVictim));
                                      PRCBonusDamage(oVictim);
                                      //This visual effect is applied to the target object not the location as above.  This visual effect
                                      //represents the flame that erupts on the target not on the ground.
                                      DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eRetrVis, oVictim));
                                  }
                               }
                          
                       }
                       //Select the next target within the spell shape.
                       oVictim = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(20.0), lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE);
                   }
               }
               
               else if(GetEffectSpellId(eToDispel) == INVOKE_PAINFUL_SLUMBER_OF_AGES && GetLocalInt(oTarget, "PainfulSleep"))
               {
                    effect eSleepDam = EffectDamage(GetLocalInt(oTarget, "PainfulSleep"), DAMAGE_TYPE_MAGICAL);
                    ApplyEffectToObject(DURATION_TYPE_INSTANT, eSleepDam, oTarget);
                    DeleteLocalInt(oTarget, "PainfulSleep");
                    RemoveEventScript(oTarget, EVENT_VIRTUAL_ONDAMAGED, "inv_painsleep", FALSE, FALSE);
               }
               
              RemoveEffect(oTarget, eToDispel);
              
              if (GetLevelByClass(CLASS_TYPE_NOCTUMANCER))
              {
                  int nExist = GetLocalInt(OBJECT_SELF, "CaptureMagic");
                  int nSpellLevel = StringToInt(Get2DACache("spells", "Innate", nEffectSpellID));
                  SetLocalInt(OBJECT_SELF, "CaptureMagic", max(nExist, nSpellLevel/2));
                  if (GetLevelByClass(CLASS_TYPE_NOCTUMANCER) >= 10) 
                      ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectSpellImmunity(nEffectSpellID)), OBJECT_SELF, 60.0);  
              }              

              if(GetSpellId() == INVOKE_VORACIOUS_DISPELLING)
              {
                  //Get spell level
                  int nEffectSpellLevel = StringToInt(Get2DACache("spells", "Innate", nEffectSpellID));
                  //Damage = spell level
                  effect eSlashDam = EffectDamage(DAMAGE_TYPE_MAGICAL, nEffectSpellLevel);

                  SPApplyEffectToObject(DURATION_TYPE_INSTANT, eSlashDam, oTarget);
              }
                      
              else if(GetSpellId() == INVOKE_DEVOUR_MAGIC)
              {
                  //Get spell level
                  int nEffectSpellLevel = StringToInt(Get2DACache("spells", "Innate", nEffectSpellID));
                  //HP = 5 * spell level
                  effect eDracHP = EffectTemporaryHitpoints(5 * nEffectSpellLevel);
                  
                  //can't stack HP from multiple dispels
                  if (GetHasSpellEffect(GetSpellId(),OBJECT_SELF))
                  {
                      PRCRemoveSpellEffects(GetSpellId(), OBJECT_SELF, OBJECT_SELF);
                  }

                  SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDracHP, OBJECT_SELF, 60.0);
              }

              else if(GetSpellId() == SPELL_SLASHING_DISPEL)
              {
              //Get spell level
              int nEffectSpellLevel = StringToInt(Get2DACache("spells", "Innate", nEffectSpellID));
              //Damage = 2 * spell level
              effect eSlashDam = EffectDamage(DAMAGE_TYPE_MAGICAL, 2 * nEffectSpellLevel);

              SPApplyEffectToObject(DURATION_TYPE_INSTANT, eSlashDam, oTarget);
              }
 
              //Spell Removal Check
              SpellRemovalCheck(oEffectCaster, oTarget);

            }// end if effect comes from this caster
          }// end if effect comes from this spell
          eToDispel = GetNextEffect(oTarget);
        }// end of while loop


    // These are stored for one round for Spell Rebirth
        SetLocalInt(oTarget, "TrueSpellRebirthSpellId", GetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nIndex)));
        SetLocalInt(oTarget, "TrueSpellRebirthCasterLvl", GetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nIndex)));
        DelayCommand(6.0, DeleteLocalInt(oTarget, "TrueSpellRebirthSpellId"));
        DelayCommand(6.0, DeleteLocalInt(oTarget, "TrueSpellRebirthCasterLvl"));

        // Delete the saved references to the spell's effects.
        // This will save some time when reordering things a bit.
        DeleteLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nIndex));
        DeleteLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nIndex));
        DeleteLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nIndex));
        DeleteLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nIndex));

      }// end of if caster check is sucessful
    }// end of if oTarget has effects from this spell
  }// end of for statement


  // Additional Code to dispel any infestation of maggots effects.

  // If check to take care of infestation of maggots is in effect.
  // with the highest caster level on it right now.
  // If it is, we remove it instead of the other effect.
  int bHasInfestationEffects = GetLocalInt(oTarget,"XP2_L_SPELL_CASTER_LVL_" + IntToString (SPELL_INFESTATION_OF_MAGGOTS));

  if(bHasInfestationEffects)
  {
    ModWeave =0;
    if (GetLocalInt(oTarget, " XP2_L_SPELL_WEAVE" +IntToString (SPELL_INFESTATION_OF_MAGGOTS)) && !Weave) ModWeave = 4;

    if(d20(1) + nCasterLevel >= bHasInfestationEffects + 11 + ModWeave + nBonus)
    {
      DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (SPELL_INFESTATION_OF_MAGGOTS));
      DeleteLocalInt(oTarget,"XP2_L_SPELL_CASTER_LVL_" + IntToString (SPELL_INFESTATION_OF_MAGGOTS));
      effect eToDispel = GetFirstEffect(oTarget);
      nEffectSpellID = SPELL_INFESTATION_OF_MAGGOTS;

      SpellName = GetStringByStrRef(StringToInt(lookup_spell_name(nEffectSpellID)));
      sList += SpellName+", ";

      while(GetIsEffectValid(eToDispel))
      {
        if(GetEffectSpellId(eToDispel) == nEffectSpellID)
        {
          RemoveEffect(oTarget, eToDispel);
        }// end if effect comes from this spell
        eToDispel = GetNextEffect(oTarget);
      }// end of while loop
    }// end if caster level check was a success.
  }// end if infestation of maggots is in effect on oTarget/

  // If the loop to rid the target of the effects of infestation of maggots
  // runs at all, this next loop won't because eToDispel has to be invalid for this
  // loop to terminate and the other to begin - but it won't begin if eToDispel is
  // already invalid :)

  if (sList == "") sList = "None  ";
  sList = GetStringLeft(sList, GetStringLength(sList) - 2); // truncate the last ", "

  SendMessageToPC(OBJECT_SELF, sCast+sList);
  if (oTarget != OBJECT_SELF) SendMessageToPC(oTarget, sSelf+sList);

}// End of function.

///////////////////////////////////////////////////////////////////////////////////////////
//:: Sorts the 3 arrays in order of highest at index 0 on up to lowest at index nLastEntry
//////////////////////////////////////////////////////////////////////////////////////////

void SortAll3Arrays(object oTarget)
{

  int nLastEntry = GetLocalInt(oTarget, "X2_Effects_Index_Number");
  int nCurrEntry;
  int nCurrEntry2;
  int nSpellID, nSpellIDHigh, nCasterLvl, nCasterLvl2, nHighCastLvl, nHighestEntry,iWeave,iWeaveHigh;
  object oMaker, oMakerHigh;

  for(nCurrEntry = 0; nCurrEntry <= nLastEntry; nCurrEntry++)
  {
    nCasterLvl = GetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrEntry));
    nHighCastLvl = nCasterLvl;

    for(nCurrEntry2 = nCurrEntry + 1; nCurrEntry2 <= nLastEntry; nCurrEntry2++)
    {
      nCasterLvl2 = GetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrEntry2));

      if(nCasterLvl2 >= nHighCastLvl)
      {
        nHighestEntry = nCurrEntry2;
        nHighCastLvl = nCasterLvl2;
      }
    }// End of second for statement.
    if(nHighCastLvl != nCasterLvl)
    // If the entry we're currently looking at already is the highest caster level left,
    // we leave it there.  Otherwise we swap the highest level entry with this one.
    // nHighCastLvl will still be equal to nCasterLvl unless a higher level effect was found.
    {
      nSpellID = GetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nCurrEntry));
      oMaker = GetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nCurrEntry));
      iWeave = GetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nCurrEntry));

      nSpellIDHigh = GetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nHighestEntry));
      oMakerHigh = GetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nHighestEntry));
      iWeaveHigh = GetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nHighestEntry));

      DeleteLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrEntry));
      DeleteLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nCurrEntry));
      DeleteLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nCurrEntry));
      DeleteLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nCurrEntry));

      DeleteLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nHighestEntry));
      DeleteLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nHighestEntry));
      DeleteLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nHighestEntry));
      DeleteLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nHighestEntry));

      ///////////////////////////////////////////////////////////////////////////////
      SetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nCurrEntry), nHighCastLvl);
      SetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nCurrEntry), nSpellIDHigh);
      SetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nCurrEntry), oMakerHigh);
      SetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nCurrEntry), iWeaveHigh);

      //
      SetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nHighestEntry),nCasterLvl);
      SetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nHighestEntry), nSpellID);
      SetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nHighestEntry), oMaker);
      SetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nHighestEntry), iWeave);

    }  // End if the caster levels of the 2 entries are actually different.
  }// End of first for statement.
}

//////////////////////////////////////////////////////////////////////////////////////////////
//:: Finished sorting.
/////////////////////////////////////////////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////////////////////
//:: Infestation of maggots is a special case because it won't end until a local
//:: int is deleted.   It must be handled specially.
/////////////////////////////////////////////////////////////////////////////////
void HandleInfestationOfMaggots(object oTarget)
{
                          //:: Special to trap an infestation of maggots effect.
  int nHasInfestationEffect = GetLocalInt(oTarget, "XP2_L_SPELL_CASTER_LVL_" + IntToString (SPELL_INFESTATION_OF_MAGGOTS));

  int nLastEntry = GetLocalInt(oTarget, "X2_Effects_Index_Number");
  if(nHasInfestationEffect)
  {
    // If they have infestation of maggots on them, then add it to the end of the list.
    // I would add it during the spell script itself but it might get swept up before the spell has
    // really ended, I fear.
    nLastEntry++;
    DeleteLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nLastEntry));
    DeleteLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nLastEntry));
    DeleteLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nLastEntry));
    DeleteLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nLastEntry));
    DeleteLocalInt(oTarget, "X2_Effects_Index_Number");

    SetLocalInt(oTarget, " X2_Effect_Spell_ID_" + IntToString(nLastEntry), SPELL_INFESTATION_OF_MAGGOTS);
    SetLocalInt(oTarget, " X2_Effect_Cast_Level_" + IntToString(nLastEntry), nHasInfestationEffect);
    SetLocalInt(oTarget, " X2_Effect_Weave_ID_" + IntToString(nLastEntry), GetLocalInt(oTarget, " XP2_L_SPELL_WEAVE" +IntToString (SPELL_INFESTATION_OF_MAGGOTS)));
    //:: Won't bother with this one. I think a creature can only have one infestation at a time.
    //SetLocalObject(oTarget, " X2_Effect_Caster_" + IntToString(nLastEntry));
    SetLocalInt(oTarget, "X2_Effects_Index_Number", nLastEntry);
  }
}
//////////////////////////////////////////////////////////////////////////////////////////////
//:: End of section to trap infestation of maggots.
////////////////////////////////////////////////////////////////////////////////////////////

// Just returns the stored value.
int AoECasterLevel(object oAoE = OBJECT_SELF)
{
   int toReturn = GetLocalInt(oAoE, "X2_AoE_Caster_Level");
   return toReturn;
}

void PRCDoSpellBreach(object oTarget, int nTotal, int nSR, int nSpellId = -1)
{
    if (nSpellId == -1)
    {
        nSpellId =  SPELL_GREATER_SPELL_BREACH;
    }
    effect eSR = EffectSpellResistanceDecrease(nSR);
    effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);

    effect eVis = EffectVisualEffect(VFX_IMP_BREACH);
    int nCnt, nIdx;
    if(!GetIsReactionTypeFriendly(oTarget))
    {
        //Fire cast spell at event for the specified target
        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellId ));
        //Search through and remove protections.
        while(nCnt <= PRC_SPELLS_MAX_BREACH && nIdx < nTotal)
        {
            nIdx = nIdx + PRCRemoveProtections(PRCGetSpellBreachProtection(nCnt), oTarget, nCnt);
            nCnt++;
        }
        effect eLink = EffectLinkEffects(eDur, eSR);
        //--------------------------------------------------------------------------
        // This can not be dispelled
        //--------------------------------------------------------------------------
        eLink = ExtraordinaryEffect(eLink);
        SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, RoundsToSeconds(10),TRUE);
    }
    ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);

}

//------------------------------------------------------------------------------
// Returns the nLastChecked-nth highest spell on the creature for use in
// the spell breach routines
// Please modify the constatn PRC_SPELLS_MAX_BREACH at the top of this file
// if you change the number of spells.
//------------------------------------------------------------------------------
int PRCGetSpellBreachProtection(int nLastChecked)
{
    //--------------------------------------------------------------------------
    // GZ: Protections are stripped in the order they appear here
    //--------------------------------------------------------------------------
    if(nLastChecked == 1) {return SPELL_GREATER_SPELL_MANTLE;}
    else if (nLastChecked == 2){return SPELL_PREMONITION;}
    else if(nLastChecked == 3) {return SPELL_SPELL_MANTLE;}
    else if(nLastChecked == 4) {return SPELL_SHADOW_SHIELD;}
    else if(nLastChecked == 5) {return SPELL_GREATER_STONESKIN;}
    else if(nLastChecked == 6) {return SPELL_ETHEREAL_VISAGE;}
    else if(nLastChecked == 7) {return SPELL_GLOBE_OF_INVULNERABILITY;}
    else if(nLastChecked == 8) {return SPELL_ENERGY_BUFFER;}
    else if(nLastChecked == 9) {return 443;} // greater sanctuary
    else if(nLastChecked == 10) {return SPELL_MINOR_GLOBE_OF_INVULNERABILITY;}
    else if(nLastChecked == 11) {return SPELL_SPELL_RESISTANCE;}
    else if(nLastChecked == 12) {return SPELL_STONESKIN;}
    else if(nLastChecked == 13) {return SPELL_LESSER_SPELL_MANTLE;}
    else if(nLastChecked == 14) {return SPELL_MESTILS_ACID_SHEATH;}
    else if(nLastChecked == 15) {return SPELL_MIND_BLANK;}
    else if(nLastChecked == 16) {return SPELL_ELEMENTAL_SHIELD;}
    else if(nLastChecked == 17) {return SPELL_PROTECTION_FROM_SPELLS;}
    else if(nLastChecked == 18) {return SPELL_PROTECTION_FROM_ELEMENTS;}
    else if(nLastChecked == 19) {return SPELL_RESIST_ELEMENTS;}
    else if(nLastChecked == 20) {return SPELL_DEATH_ARMOR;}
    else if(nLastChecked == 21) {return SPELL_GHOSTLY_VISAGE;}
    else if(nLastChecked == 22) {return SPELL_ENDURE_ELEMENTS;}
    else if(nLastChecked == 23) {return SPELL_SHADOW_SHIELD;}
    else if(nLastChecked == 24) {return SPELL_SHADOW_CONJURATION_MAGE_ARMOR;}
    else if(nLastChecked == 25) {return SPELL_NEGATIVE_ENERGY_PROTECTION;}
    else if(nLastChecked == 26) {return SPELL_SANCTUARY;}
    else if(nLastChecked == 27) {return SPELL_MAGE_ARMOR;}
    else if(nLastChecked == 28) {return SPELL_STONE_BONES;}
    else if(nLastChecked == 29) {return SPELL_SHIELD;}
    else if(nLastChecked == 30) {return SPELL_SHIELD_OF_FAITH;}
    else if(nLastChecked == 31) {return SPELL_LESSER_MIND_BLANK;}
    else if(nLastChecked == 32) {return SPELL_IRONGUTS;}
    else if(nLastChecked == 33) {return SPELL_RESISTANCE;}
    return nLastChecked;
}

int PRCRemoveProtections(int nSpell_ID, object oTarget, int nCount)
{
    //Declare major variables
    effect eProtection;
    int nCnt = 0;
    if(GetHasSpellEffect(nSpell_ID, oTarget))
    {
        //Search through the valid effects on the target.
        eProtection = GetFirstEffect(oTarget);
        while (GetIsEffectValid(eProtection))
        {
            //If the effect was created by the spell then remove it
            if(GetEffectSpellId(eProtection) == nSpell_ID)
            {
                RemoveEffect(oTarget, eProtection);
                //return 1;
                nCnt++;
            }
            //Get next effect on the target
            eProtection = GetNextEffect(oTarget);
        }
    }
    if(nCnt > 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

//------------------------------------------------------------------------------
// Attempts a dispel on one target, with all safety checks put in.
//------------------------------------------------------------------------------
void spellsDispelMagic(object oTarget, int nCasterLevel, effect eVis, effect eImpac, int bAll = TRUE, int bBreachSpells = FALSE)
{
    //--------------------------------------------------------------------------
    // Don't dispel magic on petrified targets
    // this change is in to prevent weird things from happening with 'statue'
    // creatures. Also creature can be scripted to be immune to dispel
    // magic as well.
    //--------------------------------------------------------------------------
    if (PRCGetHasEffect(EFFECT_TYPE_PETRIFY, oTarget) == TRUE || GetLocalInt(oTarget, "X1_L_IMMUNE_TO_DISPEL") == 10)
    {
        return;
    }

    effect eDispel;
    float fDelay = PRCGetRandomDelay(0.1, 0.3);
    int nId = PRCGetSpellId();

    //--------------------------------------------------------------------------
    // Fire hostile event only if the target is hostile...
    //--------------------------------------------------------------------------
    if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, OBJECT_SELF))
    {

        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nId));
    }
    else
    {
        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nId, FALSE));
    }

    //--------------------------------------------------------------------------
    // GZ: Bugfix. Was always dispelling all effects, even if used for AoE
    //--------------------------------------------------------------------------
    if (bAll == TRUE )
    {
        eDispel = EffectDispelMagicAll(nCasterLevel);
        //----------------------------------------------------------------------
        // GZ: Support for Mord's disjunction
        //----------------------------------------------------------------------
        if (bBreachSpells)
        {
            PRCDoSpellBreach(oTarget, 6, 10, nId);
        }
    }
    else
    {
        eDispel = EffectDispelMagicBest(nCasterLevel);
        if (bBreachSpells)
        {
           PRCDoSpellBreach(oTarget, 2, 10, nId);
        }
    }

    DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
    DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eDispel, oTarget));
}

//------------------------------------------------------------------------------
// Handle Dispelling Area of Effects
// Before adding this AoE's got automatically destroyed. Since NWN does not give
// the required information to do proper dispelling on AoEs, we do some simulated
// stuff here:
// - Base chance to dispel is 25, 50, 75 or 100% depending on the spell
// - Chance is modified positive by the caster level of the spellcaster as well
// - as the relevant ability score
// - Chance is modified negative by the highest spellcasting class level of the
//   AoE creator and the releavant ability score.
// Its bad, but its not worse than just dispelling the AoE as the game did until
// now
//------------------------------------------------------------------------------
void spellsDispelAoE(object oTargetAoE, object oCaster, int nCasterLevel)
{
    object oCreator = GetAreaOfEffectCreator(oTargetAoE);
    int nChance;
    int nId   = PRCGetSpellId();
    int nClassCaster = PRCGetLastSpellCastClass();
    if ( nId == SPELL_LESSER_DISPEL )
    {
        nChance = 25;
    }
    else if ( nId == SPELL_DISPEL_MAGIC)
    {
        nChance = 50;
    }
    else if ( nId == SPELL_GREATER_DISPELLING )
    {
        nChance = 75;
    }
    else if ( nId == SPELL_MORDENKAINENS_DISJUNCTION )
    {
        nChance = 100;
    }


    nChance += ((nCasterLevel + (GetAbilityScoreForClass(nClassCaster, oCaster)-10)/2) - (GetCasterLevel(oCreator))); // yes this is a sucky stupid hack

    //--------------------------------------------------------------------------
    // the AI does cheat here, because it can not react as well as a player to
    // AoE effects. Also DMs are always successful
    //--------------------------------------------------------------------------
    if (!GetIsPC(oCaster))
    {
        nChance +=30;
    }

    if (oCaster == oCreator)
    {
        nChance = 100;
    }

    int nRand = Random(100);

    if ((nRand < nChance )|| GetIsDM(oCaster) || GetIsDMPossessed(oCaster))
    {
        FloatingTextStrRefOnCreature(100929,oCaster);  // "AoE dispelled"
        DestroyObject (oTargetAoE);
    }
    else
    {
        FloatingTextStrRefOnCreature(100930,oCaster); // "AoE not dispelled"
    }

}

int GetIsMystery(int nSpellId)
{
    // They're all next to one another in the 2da
    if (nSpellId >= 18352 && nSpellId < 18450)
        return TRUE;
    return FALSE;    
}

// Test main
//void main(){}