Updated AMS marker feats. Removed arcane & divine marker feats. Updated Dread Necromancer for epic progression. Updated weapon baseitem models. Updated new weapons for crafting & npc equip. Updated prefix. Updated release archive.
1068 lines
53 KiB
Plaintext
1068 lines
53 KiB
Plaintext
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//:: 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(){}
|