forked from Jaysyn/PRC8
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.
377 lines
13 KiB
Plaintext
377 lines
13 KiB
Plaintext
|
|
// 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;
|
|
} |