// Module Constants const float CACHE_TIMEOUT_CAST = 2.0; const string CASTER_LEVEL_TAG = "PRCEffectiveCasterLevel"; // Constants that dictate ResistSpell results const int SPELL_RESIST_FAIL = 0; const int SPELL_RESIST_PASS = 1; const int SPELL_RESIST_GLOBE = 2; const int SPELL_RESIST_MANTLE = 3; int PRCDoResistSpell(object oCaster, object oTarget, int nEffCasterLvl=0, float fDelay = 0.0); int CheckSpellfire(object oCaster, object oTarget, int bFriendly = FALSE); #include "prc_inc_racial" //#include "prc_feat_const" //#include "prc_class_const" //#include "prcsp_reputation" #include "prcsp_archmaginc" //#include "prc_add_spell_dc" #include "prc_add_spl_pen" // // This function is a wrapper should someone wish to rewrite the Bioware // version. This is where it should be done. // int PRCResistSpell(object oCaster, object oTarget) { return ResistSpell(oCaster, oTarget); } // // This function is a wrapper should someone wish to rewrite the Bioware // version. This is where it should be done. // int PRCGetSpellResistance(object oTarget, object oCaster) { int iSpellRes = GetSpellResistance(oTarget); int nHD = GetHitDice(oTarget); //racial pack SR int iRacialSpellRes = 0; if(GetHasFeat(FEAT_SPELL27, oTarget)) iRacialSpellRes = 27 + nHD; else if(GetHasFeat(FEAT_SPELL25, oTarget)) iRacialSpellRes = 25 + nHD; else if(GetHasFeat(FEAT_SPELL23, oTarget)) iRacialSpellRes = 23 + nHD; else if(GetHasFeat(FEAT_SPELL22, oTarget)) iRacialSpellRes = 22 + nHD; else if(GetHasFeat(FEAT_SPELL21, oTarget)) iRacialSpellRes = 21 + nHD; else if(GetHasFeat(FEAT_SPELL20, oTarget)) iRacialSpellRes = 20 + nHD; else if(GetHasFeat(FEAT_SPELL19, oTarget)) iRacialSpellRes = 19 + nHD; else if(GetHasFeat(FEAT_SPELL18, oTarget)) iRacialSpellRes = 18 + nHD; else if(GetHasFeat(FEAT_SPELL17, oTarget)) iRacialSpellRes = 17 + nHD; else if(GetHasFeat(FEAT_SPELL16, oTarget)) iRacialSpellRes = 16 + nHD; else if(GetHasFeat(FEAT_SPELL15, oTarget)) iRacialSpellRes = 15 + nHD; else if(GetHasFeat(FEAT_SPELL14, oTarget)) iRacialSpellRes = 14 + nHD; else if(GetHasFeat(FEAT_SPELL13, oTarget)) iRacialSpellRes = 13 + nHD; else if(GetHasFeat(FEAT_SPELL11, oTarget)) iRacialSpellRes = 11 + nHD; else if(GetHasFeat(FEAT_SPELL10, oTarget)) iRacialSpellRes = 10 + nHD; else if(GetHasFeat(FEAT_SPELL8, oTarget)) iRacialSpellRes = 8 + nHD; else if(GetHasFeat(FEAT_SPELL5, oTarget)) iRacialSpellRes = 5 + nHD; if(iRacialSpellRes > iSpellRes) iSpellRes = iRacialSpellRes; // Exalted Companion, can also be used for Celestial Template if(GetLocalInt(oTarget, "CelestialTemplate") || GetLocalInt(oTarget, "PseudonaturalTemplate")) { int nSR = nHD * 2; if (nSR > 25) nSR = 25; if (nSR > iSpellRes) iSpellRes = nSR; } // Enlightened Fist SR = 10 + monk level + enlightened fist level if(GetHasFeat(FEAT_EF_DIAMOND_SOUL, oTarget)) { int nEF = 10 + GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oTarget) + GetLevelByClass(CLASS_TYPE_MONK, oTarget); if(nEF > iSpellRes) iSpellRes = nEF; } // Contemplative SR = 15 + contemplative level if(GetHasFeat(FEAT_DIVINE_SOUL, oTarget)) { int nCont = 15 + GetLevelByClass(CLASS_TYPE_CONTEMPLATIVE, oTarget); if(nCont > iSpellRes) iSpellRes = nCont; } // Marrutact if(GetRacialType(oTarget) == RACIAL_TYPE_MARRUTACT) { int nCont = 9 + GetHitDice(oTarget); if(nCont > iSpellRes) iSpellRes = nCont; } // Exordius Weapon of Legacy if(GetLocalInt(oTarget, "ExordiusSR")) { int nCont = 5 + GetHitDice(oTarget); if(nCont > iSpellRes) iSpellRes = nCont; } // Hammer of Witches Weapon of Legacy if(GetLocalInt(oTarget, "HammerWitchesSR")) { // SR vs arcane only if(GetIsArcaneClass(PRCGetLastSpellCastClass(oCaster))) { int nCont = 5 + GetHitDice(oTarget); if(nCont > iSpellRes) iSpellRes = nCont; } } // Ur-Priest if(GetLevelByClass(CLASS_TYPE_UR_PRIEST, oTarget) >= 4) { // SR vs divine only if(GetIsDivineClass(PRCGetLastSpellCastClass(oCaster))) { int nCont = 15; if (GetLevelByClass(CLASS_TYPE_UR_PRIEST, oTarget) >= 8) nCont = 20; if(nCont > iSpellRes) iSpellRes = nCont; } } // Dread Carapace Heart Bind if(GetIsIncarnumUser(oTarget)) { if (GetIsMeldBound(oTarget, MELD_DREAD_CARAPACE) == CHAKRA_CROWN) { int nCont = 5 + (4 * GetEssentiaInvested(oTarget, MELD_DREAD_CARAPACE)); if(nCont > iSpellRes) iSpellRes = nCont; } if (GetHasSpellEffect(MELD_SPELLWARD_SHIRT, oTarget)) // MELD_SPELLWARD_SHIRT { int nCont = 5 + (4 * GetEssentiaInvested(oTarget, MELD_SPELLWARD_SHIRT)); if(nCont > iSpellRes) iSpellRes = nCont; } } // Foe Hunter SR stacks with normal SR when a spell is cast by their hated enemy if(GetHasFeat(FEAT_HATED_ENEMY_SR, oTarget) && GetLocalInt(oTarget, "HatedFoe") == MyPRCGetRacialType(oCaster)) { iSpellRes += 15 + GetLevelByClass(CLASS_TYPE_FOE_HUNTER, oTarget); } // Adds +4 to SR if(GetHasFeat(FEAT_PSYCHIC_REFUSAL, oTarget)) iSpellRes += 4; // Forsaker SR adds to existing if(GetLevelByClass(CLASS_TYPE_FORSAKER, oTarget)) iSpellRes = iSpellRes + 10 + GetLevelByClass(CLASS_TYPE_FORSAKER, oTarget); return iSpellRes; } // // If a spell is resisted, display the effect // void PRCShowSpellResist(object oCaster, object oTarget, int nResist, float fDelay = 0.0) { // If either caster/target is a PC send them a message if (GetIsPC(oCaster)) { string message = nResist == SPELL_RESIST_FAIL ? "Target is affected by the spell." : "Target resisted the spell."; SendMessageToPC(oCaster, message); } if (GetIsPC(oTarget)) { string message = nResist == SPELL_RESIST_FAIL ? "You are affected by the spell." : "You resisted the spell."; SendMessageToPC(oTarget, message); } if (nResist != SPELL_RESIST_FAIL) { // Default to a standard resistance int eve = VFX_IMP_MAGIC_RESISTANCE_USE; // Check for other resistances if (nResist == SPELL_RESIST_GLOBE) eve = VFX_IMP_GLOBE_USE; else if (nResist == SPELL_RESIST_MANTLE) eve = VFX_IMP_SPELL_MANTLE_USE; // Render the effect DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(eve), oTarget)); } } // // This function overrides the BioWare MyResistSpell. // TODO: Change name to PRCMyResistSpell. // int PRCDoResistSpell(object oCaster, object oTarget, int nEffCasterLvl=0, float fDelay = 0.0) { int nResist; // Check if the archmage shape mastery applies to this target if (CheckSpellfire(oCaster, oTarget) || CheckMasteryOfShapes(oCaster, oTarget) || ExtraordinarySpellAim(oCaster, oTarget) || (GetLocalInt(oCaster, "WOL_DesertWindFireball") && GetSpellId() == SPELL_FIREBALL)) nResist = SPELL_RESIST_MANTLE; else if(GetLevelByClass(CLASS_TYPE_BEGUILER, oCaster) >= 20 && GetIsDeniedDexBonusToAC(oTarget, oCaster, TRUE)) { //Beguilers of level 20+ automatically overcome SR of targets denied Dex bonus to AC nResist = SPELL_RESIST_FAIL; } else if(GetLocalInt(oCaster, "CunningBreach")) { //Factotum can pay to breach all SR for a round nResist = SPELL_RESIST_FAIL; } //using vitriolic blast with eldritch spellweave else if(oTarget == GetLocalObject(oCaster, "SPELLWEAVE_TARGET") && GetLocalInt(oCaster, "BlastEssence") == INVOKE_VITRIOLIC_BLAST) { nResist = SPELL_RESIST_FAIL; } else { // Check immunities and mantles, otherwise ignore the result completely nResist = PRCResistSpell(oCaster, oTarget); //Resonating Resistance if((nResist <= SPELL_RESIST_PASS) && (GetHasSpellEffect(SPELL_RESONATING_RESISTANCE, oTarget))) { nResist = PRCResistSpell(oCaster, oTarget); } if (nResist <= SPELL_RESIST_PASS) { nResist = SPELL_RESIST_FAIL; // Because the version of this function was recently changed to // optionally allow the caster level, we must calculate it here. // The result will be cached for a period of time. if (!nEffCasterLvl) { nEffCasterLvl = GetLocalInt(oCaster, CASTER_LEVEL_TAG); if (!nEffCasterLvl) { nEffCasterLvl = PRCGetCasterLevel(oCaster) + SPGetPenetr(); SetLocalInt(oCaster, CASTER_LEVEL_TAG, nEffCasterLvl); DelayCommand(CACHE_TIMEOUT_CAST, DeleteLocalInt(oCaster, CASTER_LEVEL_TAG)); } } // Pernicious Magic // +4 caster level vs SR Weave user (not Evoc & Trans spells) int iWeav; if (GetHasFeat(FEAT_PERNICIOUSMAGIC,oCaster)) { if (!GetHasFeat(FEAT_SHADOWWEAVE,oTarget)) { int nSchool = GetLocalInt(oCaster, "X2_L_LAST_SPELLSCHOOL_VAR"); if ( nSchool != SPELL_SCHOOL_EVOCATION && nSchool != SPELL_SCHOOL_TRANSMUTATION ) iWeav=4; } } // A tie favors the caster. if ((nEffCasterLvl + d20(1)+iWeav) < PRCGetSpellResistance(oTarget, oCaster)) nResist = SPELL_RESIST_PASS; } } // Karsites heal from resisting a spell if(GetRacialType(oTarget) == RACIAL_TYPE_KARSITE && nResist == SPELL_RESIST_PASS) { int nSpellLevel = StringToInt(Get2DACache("spells", "Innate", PRCGetSpellId())); ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(nSpellLevel*2), oTarget); } PRCShowSpellResist(oCaster, oTarget, nResist, fDelay); return nResist; } //Returns the maximum number of spellfire levels oPC can store int SpellfireMax(object oPC) { //can't absorb spells without feat if(!GetHasFeat(FEAT_SPELLFIRE_WIELDER, oPC)) return 0; int nCON = GetAbilityScore(oPC, ABILITY_CONSTITUTION); int i, nCount; for (i = FEAT_EPIC_SPELLFIRE_WIELDER_I; i <= FEAT_EPIC_SPELLFIRE_WIELDER_X; i++) { if (GetHasFeat(i, oPC)) nCON = nCON + 4; } if (DEBUG) DoDebug("SpellfireMax nCon is "+IntToString(nCON)); int nStorage = ((GetLevelByClass(CLASS_TYPE_SPELLFIRE, oPC) + 1) / 2) + 1; if(nStorage > 5) nStorage = 5; return nCON * nStorage; } //Increases the number of stored spellfire levels on a creature void AddSpellfireLevels(object oPC, int nLevels) { int nMax = SpellfireMax(oPC); int nStored = GetPersistantLocalInt(oPC, "SpellfireLevelStored"); nStored += nLevels; if(nStored > nMax) nStored = nMax; //capped SetPersistantLocalInt(oPC, "SpellfireLevelStored", nStored); } //Checks if spell target can absorb spells by being a spellfire wielder int CheckSpellfire(object oCaster, object oTarget, int bFriendly = FALSE) { //can't absorb spells without feat if(!GetHasFeat(FEAT_SPELLFIRE_WIELDER, oTarget)) return 0; //Can't absorb own spells/powers if switch is set if(GetPRCSwitch(PRC_SPELLFIRE_DISALLOW_CHARGE_SELF) && oTarget == oCaster) return 0; //abilities rely on access to weave if(GetHasFeat(FEAT_SHADOWWEAVE, oTarget)) return 0; int nSpellID = PRCGetSpellId(); if(!bFriendly && GetLocalInt(oCaster, "IsAOE_" + IntToString(nSpellID))) return 0; //can't absorb hostile AOE spells int nSpellfireLevel = GetPersistantLocalInt(oTarget, "SpellfireLevelStored"); if(DEBUG) DoDebug("CheckSpellfire: " + IntToString(nSpellfireLevel) + " levels stored", oTarget); int nMax = SpellfireMax(oTarget); if(DEBUG) DoDebug("CheckSpellfire: Maximum " + IntToString(nMax), oTarget); //can't absorb any more spells, sanity check if(nSpellfireLevel >= nMax) return 0; //increasing stored levels int nSpellLevel = GetLocalInt(oCaster, "PRC_CurrentManifest_PowerLevel"); //replicates GetPowerLevel(oCaster); if(!nSpellLevel) //not a power //avoids compiler problems { //with includes string sInnate = Get2DACache("spells", "Innate", nSpellID);//lookup_spell_innate(nSpellID); if(sInnate == "") return 0; //no innate level, unlike cantrips nSpellLevel = StringToInt(sInnate); } /* string sInnate = Get2DACache("spells", "Innate", nSpellID); if(sInnate == "") return 0; //no innate level, unlike cantrips int nSpellLevel = StringToInt(sInnate); */ AddSpellfireLevels(oTarget, nSpellLevel); //absorbed return 1; }