Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
755 lines
26 KiB
Plaintext
755 lines
26 KiB
Plaintext
// Get the DC to save against for a spell (10 + spell level + relevant ability
|
|
// bonus). This can be called by a creature or by an Area of Effect object.
|
|
// Takes into account PRC classes
|
|
int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJECT_SELF);
|
|
|
|
// Use this function to get the adjustments to a spell or SLAs saving throw
|
|
// from the various class effects
|
|
// Update this function if any new classes change saving throws
|
|
int PRCGetSaveDC(object oTarget, object oCaster, int nSpellID = -1);
|
|
|
|
//called just from above and from inc_epicspells
|
|
int GetChangesToSaveDC(object oTarget, object oCaster, int nSpellID, int nSchool);
|
|
|
|
#include "prc_add_spl_pen"
|
|
//#include "prc_inc_spells"
|
|
//#include "prc_class_const"
|
|
//#include "prc_feat_const"
|
|
//#include "lookup_2da_spell"
|
|
//#include "prcsp_archmaginc"
|
|
//#include "prc_alterations"
|
|
//#include "prc_inc_racial"
|
|
#include "inc_newspellbook"
|
|
|
|
int GetCorruptSpellFocus(int nSpellID, object oCaster)
|
|
{
|
|
int nCorrupt = FALSE;
|
|
if(nSpellID == SPELL_ABSORB_STRENGTH
|
|
|| nSpellID == SPELL_APOCALYPSE_FROM_THE_SKY
|
|
|| nSpellID == SPELL_CLAWS_OF_THE_BEBILITH
|
|
|| nSpellID == SPELL_DEATH_BY_THORNS
|
|
|| nSpellID == SPELL_EVIL_WEATHER
|
|
|| nSpellID == SPELL_FANGS_OF_THE_VAMPIRE_KING
|
|
|| nSpellID == SPELL_LAHMS_FINGER_DARTS
|
|
|| nSpellID == SPELL_POWER_LEECH
|
|
|| nSpellID == SPELL_RAPTURE_OF_RUPTURE
|
|
|| nSpellID == SPELL_RED_FESTER
|
|
|| nSpellID == SPELL_ROTTING_CURSE_OF_URFESTRA
|
|
|| nSpellID == SPELL_SEETHING_EYEBANE
|
|
|| nSpellID == SPELL_TOUCH_OF_JUIBLEX)
|
|
nCorrupt = TRUE;
|
|
|
|
if (GetHasFeat(FEAT_GREATER_CORRUPT_SPELL_FOCUS, oCaster) && nCorrupt) return 2;
|
|
else if (GetHasFeat(FEAT_CORRUPT_SPELL_FOCUS, oCaster) && nCorrupt) return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int GetHeartWarderDC(int spell_id, int nSchool, object oCaster)
|
|
{
|
|
// Check the curent school
|
|
if(nSchool != SPELL_SCHOOL_ENCHANTMENT)
|
|
return 0;
|
|
|
|
if(!GetHasFeat(FEAT_VOICE_SIREN, oCaster))
|
|
return 0;
|
|
|
|
// Bonus Requires Verbal Spells
|
|
string VS = GetStringLowerCase(Get2DACache("spells", "VS",spell_id));
|
|
if(FindSubString(VS, "v") == -1)
|
|
return 0;
|
|
|
|
// These feats provide greater bonuses or remove the Verbal requirement
|
|
if(PRCGetMetaMagicFeat(oCaster, FALSE) & METAMAGIC_SILENT
|
|
|| GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ENCHANTMENT, oCaster)
|
|
|| GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ENCHANTMENT, oCaster))
|
|
return 0;
|
|
|
|
return 2;
|
|
}
|
|
|
|
//Elemental Savant DC boost based on elemental spell type.
|
|
int ElementalSavantDC(int spell_id, int nElement, object oCaster)
|
|
{
|
|
int nDC = 0;
|
|
|
|
// All Elemental Savants will have this feat
|
|
// when they first gain a DC bonus.
|
|
if(GetHasFeat(FEAT_ES_FOCUS_1, oCaster))
|
|
{
|
|
// Any value that does not match one of the enumerated feats
|
|
int feat, nES;
|
|
nES = GetLevelByClass(CLASS_TYPE_ELEMENTAL_SAVANT, oCaster);
|
|
|
|
// Specify the elemental type rather than lookup by class?
|
|
if(nElement & DESCRIPTOR_FIRE)
|
|
{
|
|
feat = FEAT_ES_FIRE;
|
|
}
|
|
else if(nElement & DESCRIPTOR_COLD)
|
|
{
|
|
feat = FEAT_ES_COLD;
|
|
}
|
|
else if(nElement & DESCRIPTOR_ELECTRICITY)
|
|
{
|
|
feat = FEAT_ES_ELEC;
|
|
}
|
|
else if(nElement & DESCRIPTOR_ACID)
|
|
{
|
|
feat = FEAT_ES_ACID;
|
|
}
|
|
|
|
// Now determine the bonus
|
|
if(feat && GetHasFeat(feat, oCaster))
|
|
nDC = (nES + 1) / 3;
|
|
}
|
|
// SendMessageToPC(GetFirstPC(), "Your Elemental Focus modifier is " + IntToString(nDC));
|
|
return nDC;
|
|
}
|
|
|
|
// This does other spell focus feats, starting with Spell Focus: Cold
|
|
int SpellFocus(int nSpellId, int nElement, object oCaster)
|
|
{
|
|
int nDC = 0;
|
|
|
|
// Specify the elemental type
|
|
if(nElement & DESCRIPTOR_COLD)
|
|
{
|
|
if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_COLD, oCaster))
|
|
nDC += 2;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_COLD, oCaster))
|
|
nDC += 1;
|
|
}
|
|
if (GetHasDescriptor(nSpellId, DESCRIPTOR_CHAOTIC) && GetHasFeat(FEAT_SPELL_FOCUS_CHAOS, oCaster)) nDC += 1;
|
|
if (GetHasDescriptor(nSpellId, DESCRIPTOR_EVIL) && GetHasFeat(FEAT_SPELL_FOCUS_EVIL, oCaster)) nDC += 1;
|
|
if (GetHasDescriptor(nSpellId, DESCRIPTOR_GOOD) && GetHasFeat(FEAT_SPELL_FOCUS_GOOD, oCaster)) nDC += 1;
|
|
if (GetHasDescriptor(nSpellId, DESCRIPTOR_LAWFUL) && GetHasFeat(FEAT_SPELL_FOCUS_LAWFUL, oCaster)) nDC += 1;
|
|
|
|
return nDC;
|
|
}
|
|
|
|
//Red Wizard DC boost based on spell school specialization
|
|
int RedWizardDC(int spell_id, int nSchool, object oCaster)
|
|
{
|
|
int iRedWizard = GetLevelByClass(CLASS_TYPE_RED_WIZARD, oCaster);
|
|
int nDC;
|
|
|
|
if(iRedWizard)
|
|
{
|
|
int iRWSpec;
|
|
switch(nSchool)
|
|
{
|
|
case SPELL_SCHOOL_ABJURATION: iRWSpec = FEAT_RW_TF_ABJ; break;
|
|
case SPELL_SCHOOL_CONJURATION: iRWSpec = FEAT_RW_TF_CON; break;
|
|
case SPELL_SCHOOL_DIVINATION: iRWSpec = FEAT_RW_TF_DIV; break;
|
|
case SPELL_SCHOOL_ENCHANTMENT: iRWSpec = FEAT_RW_TF_ENC; break;
|
|
case SPELL_SCHOOL_EVOCATION: iRWSpec = FEAT_RW_TF_EVO; break;
|
|
case SPELL_SCHOOL_ILLUSION: iRWSpec = FEAT_RW_TF_ILL; break;
|
|
case SPELL_SCHOOL_NECROMANCY: iRWSpec = FEAT_RW_TF_NEC; break;
|
|
case SPELL_SCHOOL_TRANSMUTATION: iRWSpec = FEAT_RW_TF_TRS; break;
|
|
}
|
|
|
|
if(iRWSpec && GetHasFeat(iRWSpec, oCaster))
|
|
nDC = iRedWizard / 2;
|
|
}
|
|
// SendMessageToPC(GetFirstPC(), "Your Spell Power modifier is " + IntToString(nDC));
|
|
return nDC;
|
|
}
|
|
|
|
//Red Wizards recieve a bonus against their specialist schools
|
|
// this is done by lowering the DC of spells cast against them
|
|
int RedWizardDCPenalty(int spell_id, int nSchool, object oTarget)
|
|
{
|
|
int nDC;
|
|
int iRW = GetLevelByClass(CLASS_TYPE_RED_WIZARD, oTarget);
|
|
if(iRW)
|
|
{
|
|
int iRWSpec;
|
|
switch(nSchool)
|
|
{
|
|
case SPELL_SCHOOL_ABJURATION: iRWSpec = FEAT_RW_TF_ABJ; break;
|
|
case SPELL_SCHOOL_CONJURATION: iRWSpec = FEAT_RW_TF_CON; break;
|
|
case SPELL_SCHOOL_DIVINATION: iRWSpec = FEAT_RW_TF_DIV; break;
|
|
case SPELL_SCHOOL_ENCHANTMENT: iRWSpec = FEAT_RW_TF_ENC; break;
|
|
case SPELL_SCHOOL_EVOCATION: iRWSpec = FEAT_RW_TF_EVO; break;
|
|
case SPELL_SCHOOL_ILLUSION: iRWSpec = FEAT_RW_TF_ILL; break;
|
|
case SPELL_SCHOOL_NECROMANCY: iRWSpec = FEAT_RW_TF_NEC; break;
|
|
case SPELL_SCHOOL_TRANSMUTATION: iRWSpec = FEAT_RW_TF_TRS; break;
|
|
}
|
|
|
|
if(iRWSpec && GetHasFeat(iRWSpec, oTarget))
|
|
nDC -= iRW > 4 ? (iRW - 1) / 2 : (iRW + 1) / 2;
|
|
}
|
|
return nDC;
|
|
}
|
|
|
|
int ShadowAdeptDCPenalty(int spell_id, int nSchool, object oTarget)
|
|
{
|
|
int nDC;
|
|
int iShadow = GetLevelByClass(CLASS_TYPE_SHADOW_ADEPT, oTarget);
|
|
if(iShadow)
|
|
{
|
|
if(nSchool == SPELL_SCHOOL_ENCHANTMENT
|
|
|| nSchool == SPELL_SCHOOL_NECROMANCY
|
|
|| nSchool == SPELL_SCHOOL_ILLUSION)
|
|
{
|
|
nDC -= (iShadow + 1) / 3;
|
|
}
|
|
//SendMessageToPC(GetFirstPC(), "Your Spell Save modifier is " + IntToString(nDC));
|
|
}
|
|
return nDC;
|
|
}
|
|
|
|
//Tattoo Focus DC boost based on spell school specialization
|
|
int TattooFocus(int spell_id, int nSchool, object oCaster)
|
|
{
|
|
int nDC;
|
|
int iRWSpec;
|
|
switch(nSchool)
|
|
{
|
|
case SPELL_SCHOOL_ABJURATION: iRWSpec = FEAT_RW_TF_ABJ; break;
|
|
case SPELL_SCHOOL_CONJURATION: iRWSpec = FEAT_RW_TF_CON; break;
|
|
case SPELL_SCHOOL_DIVINATION: iRWSpec = FEAT_RW_TF_DIV; break;
|
|
case SPELL_SCHOOL_ENCHANTMENT: iRWSpec = FEAT_RW_TF_ENC; break;
|
|
case SPELL_SCHOOL_EVOCATION: iRWSpec = FEAT_RW_TF_EVO; break;
|
|
case SPELL_SCHOOL_ILLUSION: iRWSpec = FEAT_RW_TF_ILL; break;
|
|
case SPELL_SCHOOL_NECROMANCY: iRWSpec = FEAT_RW_TF_NEC; break;
|
|
case SPELL_SCHOOL_TRANSMUTATION: iRWSpec = FEAT_RW_TF_TRS; break;
|
|
}
|
|
|
|
if(iRWSpec && GetHasFeat(iRWSpec, oCaster))
|
|
nDC = 1;
|
|
|
|
return nDC;
|
|
}
|
|
|
|
int ShadowWeaveDC(int spell_id, int nSchool, object oCaster)
|
|
{
|
|
// Account for the Shadow Weave feat
|
|
int nDC = ShadowWeave(oCaster, spell_id, nSchool) == 1;
|
|
|
|
// Account for Shadow Adept levels
|
|
int iShadow = GetLevelByClass(CLASS_TYPE_SHADOW_ADEPT, oCaster);
|
|
if(iShadow && nDC)
|
|
// Shadow Spell Power
|
|
nDC += iShadow / 3;
|
|
|
|
return nDC;
|
|
}
|
|
|
|
int KOTCSpellFocusVsDemons(object oTarget, object oCaster)
|
|
{
|
|
if(GetLevelByClass(CLASS_TYPE_KNIGHT_CHALICE, oCaster) >= 1)
|
|
{
|
|
if(MyPRCGetRacialType(oTarget) == RACIAL_TYPE_OUTSIDER)
|
|
{
|
|
if(GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL)
|
|
{
|
|
return 2;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int BloodMagusBloodComponent(object oCaster)
|
|
{
|
|
int nDC = 0;
|
|
if (GetLevelByClass(CLASS_TYPE_BLOOD_MAGUS, oCaster) > 0 && GetLocalInt(oCaster, "BloodComponent") == TRUE)
|
|
{
|
|
nDC = 1;
|
|
effect eSelfDamage = EffectDamage(1, DAMAGE_TYPE_MAGICAL);
|
|
// To make sure it doesn't cause a conc check
|
|
DelayCommand(1.0, ApplyEffectToObject(DURATION_TYPE_INSTANT, eSelfDamage, oCaster));
|
|
}
|
|
return nDC;
|
|
}
|
|
|
|
int RunecasterRunePowerDC(object oCaster)
|
|
{
|
|
int nDC;
|
|
|
|
if(GetHasSpellEffect(SPELL_RUNE_CHANT))
|
|
{
|
|
int nClass = GetLevelByClass(CLASS_TYPE_RUNECASTER, oCaster);
|
|
|
|
if (nClass >= 30) nDC = 10;
|
|
else if (nClass >= 27) nDC = 9;
|
|
else if (nClass >= 24) nDC = 8;
|
|
else if (nClass >= 21) nDC = 7;
|
|
else if (nClass >= 18) nDC = 6;
|
|
else if (nClass >= 15) nDC = 5;
|
|
else if (nClass >= 12) nDC = 4;
|
|
else if (nClass >= 9) nDC = 3;
|
|
else if (nClass >= 5) nDC = 2;
|
|
else if (nClass >= 2) nDC = 1;
|
|
}
|
|
return nDC;
|
|
}
|
|
|
|
//Unheavened spell
|
|
int UnheavenedAdjustment(object oTarget, object oCaster)
|
|
{
|
|
if(GetHasSpellEffect(SPELL_UNHEAVENED, oTarget))
|
|
{
|
|
if((MyPRCGetRacialType(oCaster) == RACIAL_TYPE_OUTSIDER) && (GetAlignmentGoodEvil(oCaster) == ALIGNMENT_GOOD))
|
|
{
|
|
return -4;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Soul Eater's 10th level Soul Power ability. If they've drained in the last 24h, they get +2 to DCs
|
|
int SoulEaterSoulPower(object oCaster)
|
|
{
|
|
return (GetLocalInt(oCaster, "PRC_SoulEater_HasDrained") && GetLevelByClass(CLASS_TYPE_SOUL_EATER, oCaster) >= 10) ? 2 : 0;
|
|
}
|
|
|
|
//:: Saint Template gets a +2 DC on all spells, powers & abilites.
|
|
int SaintHolySpellPower(object oCaster)
|
|
{
|
|
if(GetHasFeat(FEAT_TEMPLATE_SAINT_HOLY_POWER, oCaster))
|
|
{
|
|
if (GetAlignmentGoodEvil(oCaster) == ALIGNMENT_GOOD)
|
|
{
|
|
return 2;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
//:: If it gets here, the caster does not have the feat
|
|
return 0;
|
|
}
|
|
|
|
//Draconic Power's elemental boost to spell DCs
|
|
int DraconicPowerDC(int spell_id, int nElement, object oCaster)
|
|
{
|
|
if(GetHasFeat(FEAT_DRACONIC_POWER, oCaster))
|
|
{
|
|
// Compare heritage type and elemental type
|
|
if(nElement & DESCRIPTOR_FIRE)
|
|
{
|
|
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_BS, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_GD, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_RD, oCaster))
|
|
return 1;
|
|
}
|
|
else if(nElement & DESCRIPTOR_COLD)
|
|
{
|
|
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_CR, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_SR, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_TP, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_WH, oCaster))
|
|
return 1;
|
|
}
|
|
else if(nElement & DESCRIPTOR_ELECTRICITY)
|
|
{
|
|
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_BL, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_BZ, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_SA, oCaster))
|
|
return 1;
|
|
}
|
|
else if(nElement & DESCRIPTOR_ACID)
|
|
{
|
|
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_BK, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_CP, oCaster)
|
|
|| GetHasFeat(FEAT_DRACONIC_HERITAGE_GR, oCaster))
|
|
return 1;
|
|
}
|
|
else if(nElement & DESCRIPTOR_SONIC)
|
|
{
|
|
if(GetHasFeat(FEAT_DRACONIC_HERITAGE_EM, oCaster))
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
//if it gets here, the caster does not have the feat, or is a heritage type without a NWN element (e.g. Amethyst)
|
|
return 0;
|
|
}
|
|
|
|
//Energy Draconc Aura's elemental boost to spell DCs
|
|
int EnergyAuraDC(int spell_id, int nElement, object oCaster)
|
|
{
|
|
// Compare aura type and elemental type
|
|
if(nElement & DESCRIPTOR_FIRE)
|
|
return GetLocalInt(oCaster, "FireEnergyAura");
|
|
|
|
else if(nElement & DESCRIPTOR_COLD)
|
|
return GetLocalInt(oCaster, "ColdEnergyAura");
|
|
|
|
else if(nElement & DESCRIPTOR_ELECTRICITY)
|
|
return GetLocalInt(oCaster, "ElecEnergyAura");
|
|
|
|
else if(nElement & DESCRIPTOR_ACID)
|
|
return GetLocalInt(oCaster, "AcidEnergyAura");
|
|
|
|
//if it gets here, the caster is not in this type of Draconic Aura
|
|
return 0;
|
|
}
|
|
|
|
//Spirit Folk get a better save vs elemental stuff
|
|
int SpiritFolkAdjustment(int spell_id, int nElement, object oTarget)
|
|
{
|
|
if(nElement & DESCRIPTOR_FIRE && GetHasFeat(FEAT_BONUS_SEA, oTarget))
|
|
{
|
|
return -2;
|
|
}
|
|
else if(nElement & DESCRIPTOR_COLD && GetHasFeat(FEAT_BONUS_RIVER, oTarget))
|
|
{
|
|
return -2;
|
|
}
|
|
else if(nElement & DESCRIPTOR_ACID && GetHasFeat(FEAT_BONUS_BAMBOO, oTarget))
|
|
{
|
|
return -2;
|
|
}
|
|
|
|
//if it gets here, the target is not a Spirit Folk
|
|
return 0;
|
|
}
|
|
|
|
//Angry Spell for Rage Mage class
|
|
int AngrySpell(int spell_id, int nSchool, object oCaster)
|
|
{
|
|
int nDC;
|
|
|
|
if(GetHasSpellEffect(SPELL_SPELL_RAGE, oCaster))
|
|
{
|
|
if(nSchool == SPELL_SCHOOL_ABJURATION
|
|
|| nSchool == SPELL_SCHOOL_CONJURATION
|
|
|| nSchool == SPELL_SCHOOL_EVOCATION
|
|
|| nSchool == SPELL_SCHOOL_NECROMANCY
|
|
|| nSchool == SPELL_SCHOOL_TRANSMUTATION)
|
|
{
|
|
if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oCaster) >= 10)
|
|
nDC = 4;
|
|
else if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oCaster) >= 5)
|
|
nDC = 2;
|
|
}
|
|
}
|
|
|
|
return nDC;
|
|
}
|
|
|
|
int CloakedCastingDC(int spell_id, object oTarget, object oCaster)
|
|
{
|
|
int nDC;
|
|
int iBeguiler = GetLevelByClass(CLASS_TYPE_BEGUILER, oCaster);
|
|
|
|
if(iBeguiler)
|
|
{
|
|
if(GetIsDeniedDexBonusToAC(oTarget, oCaster, TRUE))
|
|
{
|
|
if(iBeguiler >= 14)
|
|
nDC = 2;
|
|
else if(iBeguiler >= 2)
|
|
nDC = 1;
|
|
}
|
|
}
|
|
|
|
return nDC;
|
|
}
|
|
|
|
// Wyrmbane Helm
|
|
int WyrmbaneHelmDC(object oTarget, object oCaster)
|
|
{
|
|
// You get nothing if you aren't wielding the legacy item
|
|
object oWOL = GetItemPossessedBy(oCaster, "WOL_Wyrmbane");
|
|
if(oWOL != GetItemInSlot(INVENTORY_SLOT_HEAD, oCaster)) return 0;
|
|
|
|
if((MyPRCGetRacialType(oTarget) == RACIAL_TYPE_DRAGON))
|
|
{
|
|
return 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Arkamoi Strength From Magic
|
|
int StrengthFromMagic(object oCaster)
|
|
{
|
|
if (GetRacialType(oCaster) != RACIAL_TYPE_ARKAMOI)
|
|
return 0;
|
|
|
|
if (GetIsArcaneClass(PRCGetLastSpellCastClass(oCaster)))
|
|
return GetLocalInt(oCaster, "StrengthFromMagic");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int PRCGetSpellSaveDC(int nSpellID = -1, int nSchool = -1, object oCaster = OBJECT_SELF)
|
|
{
|
|
if(nSpellID == -1)
|
|
nSpellID = PRCGetSpellId();
|
|
if(nSchool == -1)
|
|
nSchool = GetSpellSchool(nSpellID);
|
|
|
|
int nClass = PRCGetLastSpellCastClass(oCaster);
|
|
int nDC = 10;
|
|
|
|
if(nClass == CLASS_TYPE_BARD)
|
|
nDC += StringToInt(Get2DACache("Spells", "Bard", nSpellID));
|
|
else if(nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_UR_PRIEST || nClass == CLASS_TYPE_OCULAR)
|
|
nDC += StringToInt(Get2DACache("Spells", "Cleric", nSpellID));
|
|
else if(nClass == CLASS_TYPE_DRUID)
|
|
nDC += StringToInt(Get2DACache("Spells", "Druid", nSpellID));
|
|
else if(nClass == CLASS_TYPE_RANGER)
|
|
nDC += StringToInt(Get2DACache("Spells", "Ranger", nSpellID));
|
|
else if(nClass == CLASS_TYPE_PALADIN)
|
|
nDC += StringToInt(Get2DACache("Spells", "Paladin", nSpellID));
|
|
else if (nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK)
|
|
nDC += StringToInt(Get2DACache("spells", "Cultist", nSpellID));
|
|
else if (nClass == CLASS_TYPE_NENTYAR_HUNTER)
|
|
nDC += StringToInt(Get2DACache("spells", "Nentyar", nSpellID));
|
|
else if (nClass == CLASS_TYPE_SHADOWLORD)
|
|
nDC += StringToInt(Get2DACache("spells", "Telflammar", nSpellID));
|
|
else if (nClass == CLASS_TYPE_SLAYER_OF_DOMIEL)
|
|
nDC += StringToInt(Get2DACache("spells", "Domiel", nSpellID));
|
|
else if (nClass == CLASS_TYPE_SOHEI)
|
|
nDC += StringToInt(Get2DACache("spells", "Sohei", nSpellID));
|
|
else if (nClass == CLASS_TYPE_VASSAL)
|
|
nDC += StringToInt(Get2DACache("spells", "Bahamut", nSpellID));
|
|
else if (nClass == CLASS_TYPE_BLACKGUARD)
|
|
nDC += StringToInt(Get2DACache("spells", "Blackguard", nSpellID));
|
|
else if (nClass == CLASS_TYPE_KNIGHT_CHALICE)
|
|
nDC += StringToInt(Get2DACache("spells", "Chalice", nSpellID));
|
|
else if (nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE)
|
|
nDC += StringToInt(Get2DACache("spells", "MiddleCircle", nSpellID));
|
|
else if (nClass == CLASS_TYPE_SOLDIER_OF_LIGHT)
|
|
nDC += StringToInt(Get2DACache("spells", "SoLight", nSpellID));
|
|
else if (nClass == CLASS_TYPE_BLIGHTER)
|
|
nDC += StringToInt(Get2DACache("spells", "Blighter", nSpellID));
|
|
else if (nClass == CLASS_TYPE_HEALER)
|
|
nDC += StringToInt(Get2DACache("spells", "Healer", nSpellID));
|
|
else if (nClass == CLASS_TYPE_SHAMAN)
|
|
nDC += StringToInt(Get2DACache("spells", "Shaman", nSpellID));
|
|
else if(nClass == CLASS_TYPE_WIZARD
|
|
|| nClass == CLASS_TYPE_SORCERER)
|
|
nDC += StringToInt(Get2DACache("Spells", "Wiz_Sorc", nSpellID));
|
|
else if(nClass != CLASS_TYPE_INVALID)
|
|
{
|
|
int nSpellbookID = RealSpellToSpellbookID(nClass, nSpellID);
|
|
string sFile = GetFileForClass(nClass);
|
|
nDC += StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
|
|
}
|
|
else
|
|
nDC += StringToInt(Get2DACache("Spells", "Innate", nSpellID));
|
|
|
|
// This is here because a Cleric casting a domain spell like Chain Lightning has a 0 in the cleric column, resulting in a DC of 10
|
|
if (nDC == 10 && nClass == CLASS_TYPE_CLERIC)
|
|
nDC += StringToInt(Get2DACache("Spells", "Innate", nSpellID));
|
|
|
|
nDC += GetDCAbilityModForClass(nClass, oCaster);
|
|
|
|
object oItem = GetSpellCastItem();
|
|
|
|
int nEpic = 6;
|
|
int nGreat = 4;
|
|
int nSF = 2;
|
|
|
|
if (GetPRCSwitch(PRC_35_SPELL_FOCUS))
|
|
{
|
|
nEpic = 3;
|
|
nGreat = 2;
|
|
nSF = 1;
|
|
}
|
|
|
|
if(DEBUG && !GetIsObjectValid(oItem)) DoDebug("PRCGetSpellSaveDC oItem is OBJECT_INVALID");
|
|
if(DEBUG) DoDebug("PRCGetSpellSaveDC oCaster "+GetName(oCaster)+", nSpell "+IntToString(nSpellID)+", nSchool "+IntToString(nSchool)+", nClass "+IntToString(nClass)+", oItem "+GetName(oItem));
|
|
|
|
if(!GetIsObjectValid(oItem) || (GetBaseItemType(oItem) == BASE_ITEM_MAGICSTAFF && GetPRCSwitch(PRC_STAFF_CASTER_LEVEL)))
|
|
{
|
|
if(nSchool == SPELL_SCHOOL_EVOCATION)
|
|
{
|
|
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_EVOCATION, oCaster))
|
|
nDC+=nEpic;
|
|
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_EVOCATION, oCaster))
|
|
nDC+=nGreat;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_EVOCATION, oCaster))
|
|
nDC+=nSF;
|
|
}
|
|
else if(nSchool == SPELL_SCHOOL_TRANSMUTATION)
|
|
{
|
|
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_TRANSMUTATION, oCaster))
|
|
nDC+=nEpic;
|
|
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_TRANSMUTATION, oCaster))
|
|
nDC+=nGreat;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_TRANSMUTATION, oCaster))
|
|
nDC+=nSF;
|
|
}
|
|
else if(nSchool == SPELL_SCHOOL_NECROMANCY)
|
|
{
|
|
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_NECROMANCY, oCaster))
|
|
nDC+=nEpic;
|
|
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_NECROMANCY, oCaster))
|
|
nDC+=nGreat;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_NECROMANCY, oCaster))
|
|
nDC+=nSF;
|
|
}
|
|
else if(nSchool == SPELL_SCHOOL_ILLUSION)
|
|
{
|
|
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ILLUSION, oCaster))
|
|
nDC+=nEpic;
|
|
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ILLUSION, oCaster))
|
|
nDC+=nGreat;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_ILLUSION, oCaster))
|
|
nDC+=nSF;
|
|
}
|
|
else if(nSchool == SPELL_SCHOOL_ABJURATION)
|
|
{
|
|
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ABJURATION, oCaster))
|
|
nDC+=nEpic;
|
|
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ABJURATION, oCaster))
|
|
nDC+=nGreat;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_ABJURATION, oCaster))
|
|
nDC+=nSF;
|
|
}
|
|
else if(nSchool == SPELL_SCHOOL_CONJURATION)
|
|
{
|
|
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_CONJURATION, oCaster))
|
|
nDC+=nEpic;
|
|
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_CONJURATION, oCaster))
|
|
nDC+=nGreat;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_CONJURATION, oCaster))
|
|
nDC+=nSF;
|
|
}
|
|
else if(nSchool == SPELL_SCHOOL_DIVINATION)
|
|
{
|
|
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_DIVINATION, oCaster))
|
|
nDC+=nEpic;
|
|
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_DIVINATION, oCaster))
|
|
nDC+=nGreat;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_DIVINATION, oCaster))
|
|
nDC+=nSF;
|
|
}
|
|
else if(nSchool == SPELL_SCHOOL_ENCHANTMENT)
|
|
{
|
|
if(GetHasFeat(FEAT_EPIC_SPELL_FOCUS_ENCHANTMENT, oCaster))
|
|
nDC+=nEpic;
|
|
else if(GetHasFeat(FEAT_GREATER_SPELL_FOCUS_ENCHANTMENT, oCaster))
|
|
nDC+=nGreat;
|
|
else if(GetHasFeat(FEAT_SPELL_FOCUS_ENCHANTMENT, oCaster))
|
|
nDC+=nSF;
|
|
}
|
|
}
|
|
|
|
return nDC;
|
|
}
|
|
|
|
int PRCGetSaveDC(object oTarget, object oCaster, int nSpellID = -1)
|
|
{
|
|
object oItem = GetSpellCastItem();
|
|
if(nSpellID == -1)
|
|
nSpellID = PRCGetSpellId();
|
|
int nSchool = GetSpellSchool(nSpellID);
|
|
int nDC;
|
|
// at this point, if it's still -1 then this is running on an AoE
|
|
if (nSpellID == -1)
|
|
{
|
|
// get the needed values off the AoE
|
|
nSpellID = GetLocalInt(OBJECT_SELF, "X2_AoE_SpellID");
|
|
nDC = GetLocalInt(OBJECT_SELF, "X2_AoE_BaseSaveDC");
|
|
nSchool = GetSpellSchool(nSpellID);
|
|
}
|
|
else // not persistent AoE script
|
|
{
|
|
//10+spelllevel+stat(cha default)
|
|
nDC = PRCGetSpellSaveDC(nSpellID, nSchool, oCaster);
|
|
}
|
|
|
|
// For when you want to assign the caster DC
|
|
//this does not take feat/race/class into account, it is an absolute override
|
|
if (GetLocalInt(oCaster, PRC_DC_TOTAL_OVERRIDE) != 0)
|
|
{
|
|
nDC = GetLocalInt(oCaster, PRC_DC_TOTAL_OVERRIDE);
|
|
if(DEBUG) DoDebug("Forced-DC PRC_DC_TOTAL_OVERRIDE casting at DC " + IntToString(nDC));
|
|
}
|
|
// For when you want to assign the caster DC
|
|
//this does take feat/race/class into account, it only overrides the baseDC
|
|
else if (GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE) != 0)
|
|
{
|
|
nDC = GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE);
|
|
if(nDC == -1)
|
|
nDC = PRCGetSpellSaveDC(nSpellID, nSchool, oCaster);
|
|
|
|
if(DEBUG) DoDebug("Forced Base-DC casting at DC " + IntToString(nDC));
|
|
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID, nSchool);
|
|
}
|
|
else if(GetIsObjectValid(oItem) && !(GetBaseItemType(oItem) == BASE_ITEM_MAGICSTAFF && GetPRCSwitch(PRC_STAFF_CASTER_LEVEL)))
|
|
{
|
|
//code for getting new ip type
|
|
itemproperty ipTest = GetFirstItemProperty(oItem);
|
|
while(GetIsItemPropertyValid(ipTest))
|
|
{
|
|
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_CAST_SPELL_DC)
|
|
{
|
|
int nSubType = GetItemPropertySubType(ipTest);
|
|
nSubType = StringToInt(Get2DACache("iprp_spells", "SpellIndex", nSubType));
|
|
if(nSubType == nSpellID)
|
|
{
|
|
nDC = GetItemPropertyCostTableValue (ipTest);
|
|
break;//end while
|
|
}
|
|
}
|
|
ipTest = GetNextItemProperty(oItem);
|
|
}
|
|
int nType = GetBaseItemType(oItem);
|
|
if(nType == BASE_ITEM_MAGICWAND || nType == BASE_ITEM_ENCHANTED_WAND)
|
|
{
|
|
if (GetHasFeat(FEAT_WAND_MASTERY, oCaster))
|
|
nDC += 2;
|
|
}
|
|
}
|
|
else
|
|
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID, nSchool);
|
|
|
|
// Karsus's Heavy Magic ability
|
|
if(GetIsObjectValid(oItem) && GetHasSpellEffect(VESTIGE_KARSUS, oCaster) && GetLocalInt(oCaster, "ExploitVestige") != VESTIGE_KARSUS_HEAVY_MAGIC && (GetLevelByClass(CLASS_TYPE_BINDER, oCaster) || GetHasFeat(FEAT_PRACTICED_BINDER, oCaster)))
|
|
nDC += 2;
|
|
|
|
//target-based adjustments go here
|
|
nDC += RedWizardDCPenalty(nSpellID, nSchool, oTarget);
|
|
nDC += ShadowAdeptDCPenalty(nSpellID, nSchool, oTarget);
|
|
return nDC;
|
|
|
|
}
|
|
|
|
//called just from above and from inc_epicspells
|
|
int GetChangesToSaveDC(object oTarget, object oCaster, int nSpellID, int nSchool)
|
|
{
|
|
int nDC;
|
|
int nElement = GetIsElementalSpell(nSpellID);
|
|
|
|
if(nElement)
|
|
{
|
|
nDC += ElementalSavantDC(nSpellID, nElement, oCaster);
|
|
nDC += SpiritFolkAdjustment(nSpellID, nElement, oTarget);
|
|
nDC += SpellFocus(nSpellID, nElement, oCaster);
|
|
nDC += DraconicPowerDC(nSpellID, nElement, oCaster);
|
|
nDC += EnergyAuraDC(nSpellID, nElement, oCaster);
|
|
}
|
|
nDC += GetHeartWarderDC(nSpellID, nSchool, oCaster);
|
|
nDC += GetSpellPowerBonus(oCaster);
|
|
nDC += ShadowWeaveDC(nSpellID, nSchool, oCaster);
|
|
nDC += RedWizardDC(nSpellID, nSchool, oCaster);
|
|
nDC += TattooFocus(nSpellID, nSchool, oCaster);
|
|
nDC += KOTCSpellFocusVsDemons(oTarget, oCaster);
|
|
//nDC += BloodMagusBloodComponent(oCaster);
|
|
nDC += RunecasterRunePowerDC(oCaster);
|
|
nDC += UnheavenedAdjustment(oTarget, oCaster);
|
|
nDC += SoulEaterSoulPower(oCaster);
|
|
nDC += AngrySpell(nSpellID, nSchool, oCaster);
|
|
nDC += CloakedCastingDC(nSpellID, oTarget, oCaster);
|
|
nDC += GetCorruptSpellFocus(nSpellID, oCaster);
|
|
nDC += Soulcaster(oCaster, nSpellID);
|
|
nDC += WyrmbaneHelmDC(oTarget, oCaster);
|
|
nDC += StrengthFromMagic(oCaster);
|
|
nDC += SaintHolySpellPower(oCaster);
|
|
nDC += GetLocalInt(oCaster, PRC_DC_ADJUSTMENT);//this is for builder use
|
|
return nDC;
|
|
}
|
|
|
|
// Test main
|
|
//void main(){}
|