Updated Vow of Poverty. Added Sanctify Ki Strike, Holy Strike, Fist of Heavens, Vow of Abstinence, Vow of Chastity & Gift of Faith. (@fenac). Turned off the Taunt & Parry skills. Re-disabled AC & save bonuses from Tumble & Spellcraft. Updated min() & max() to PRCmin() & PRCmax() to not conflict with similarly named NUI adjacent functions. Set Point Blank Shot to 30' per PnP. Added icon for Chosen of Evil. Started work on Hidden Talent. Created Psionics function cheatsheet. 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", PRCMax(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", PRCMax(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(){}
|