2026/01/2 Update

Sun Domain power actually destroys undead.
Fixed BCM's Pouncing Strike.
Monkey Grip only applies penalty when appropriate.
Forsaker should stack all sources of Spell Resistance.
Hexblade's Dark Companion retains the sanctuary effect across game saves.
Ottiluke's Resilient Sphere is a Reflex save, not a WIll save.
This commit is contained in:
Jaysyn904
2026-01-25 10:00:51 -05:00
parent 68ca3a56ca
commit 43cf043470
10 changed files with 242 additions and 52 deletions

View File

@@ -1,7 +1,50 @@
//::///////////////////////////////////////////////
//:: Sun Domain Power
//:: prc_dom_sun.nss
//:://////////////////////////////////////////////
/*
Type of Feat: Domain.
Specifics: Once per day, you can perform a greater turning
against undead in place of a regular turning. The greater
turning destroys undead instead of turning them.
Use: Selected.
*/
//:://////////////////////////////////////////////
#include "inc_newspellbook"
#include "prc_inc_domain"
#include "prc_inc_spells"
void main()
{
object oPC = OBJECT_SELF;
// Used by the uses per day check code for bonus domains
if(!DecrementDomainUses(PRC_DOMAIN_SUN, oPC)) return;
if(!CheckTurnUndeadUses(oPC, 1))
{
SpeakStringByStrRef(40550);
return;
}
// Mystics with sun domain can turn undead, but can't use greater turning
int bMystic = GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) && GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC);
void main()
if(bMystic)
{
if(!GetHasFeat(FEAT_TURN_UNDEAD, oPC))
return;
}
ActionDoCommand(SetLocalInt(oPC, "UsingSunDomain", TRUE));
ActionCastSpellAtObject(SPELLABILITY_TURN_UNDEAD, oPC, METAMAGIC_ANY, TRUE);
ActionDoCommand(DelayCommand(0.1f, DeleteLocalInt(oPC, "UsingSunDomain")));
}
/* void main()
{
object oPC = OBJECT_SELF;
@@ -20,4 +63,4 @@ void main()
ActionCastSpell(SPELLABILITY_TURN_UNDEAD);
ActionDoCommand(DecrementRemainingFeatUses(oPC, FEAT_TURN_UNDEAD));
ActionDoCommand(DeleteLocalInt(oPC, "UsingSunDomain"));
}
} */

View File

@@ -9,6 +9,101 @@
#include "prc_inc_combat"
#include "inc_dynconv"
#include "prc_alterations"
int PRCStackSpellResistance(object oPC)
{
int nTotalSR = 0;
// Racial Spell Resistance
int nRacialSR = 0;
if(GetHasFeat(FEAT_SPELL27, oPC)) nRacialSR = 27;
else if(GetHasFeat(FEAT_SPELL25, oPC)) nRacialSR = 25;
else if(GetHasFeat(FEAT_SPELL23, oPC)) nRacialSR = 23;
else if(GetHasFeat(FEAT_SPELL22, oPC)) nRacialSR = 22;
else if(GetHasFeat(FEAT_SPELL21, oPC)) nRacialSR = 21;
else if(GetHasFeat(FEAT_SPELL20, oPC)) nRacialSR = 20;
else if(GetHasFeat(FEAT_SPELL19, oPC)) nRacialSR = 19;
else if(GetHasFeat(FEAT_SPELL18, oPC)) nRacialSR = 18;
else if(GetHasFeat(FEAT_SPELL17, oPC)) nRacialSR = 17;
else if(GetHasFeat(FEAT_SPELL16, oPC)) nRacialSR = 16;
else if(GetHasFeat(FEAT_SPELL15, oPC)) nRacialSR = 15;
else if(GetHasFeat(FEAT_SPELL14, oPC)) nRacialSR = 14;
else if(GetHasFeat(FEAT_SPELL13, oPC)) nRacialSR = 13;
else if(GetHasFeat(FEAT_SPELL11, oPC)) nRacialSR = 11;
else if(GetHasFeat(FEAT_SPELL10, oPC)) nRacialSR = 10;
else if(GetHasFeat(FEAT_SPELL8, oPC)) nRacialSR = 8;
else if(GetHasFeat(FEAT_SPELL5, oPC)) nRacialSR = 5;
if(nRacialSR > 0)
{
nTotalSR += nRacialSR + GetHitDice(oPC); // Base SR + 1 per level
}
// Improved Spell Resistance feats (epic feats, +2 SR each, stackable)
int nImprovedSR = 0;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_1, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_2, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_3, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_4, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_5, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_6, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_7, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_8, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_9, oPC)) nImprovedSR += 2;
if(GetHasFeat(FEAT_EPIC_IMPROVED_SPELL_RESISTANCE_10, oPC)) nImprovedSR += 2;
nTotalSR += nImprovedSR;
// Class-based Spell Resistance
int nMonkLvl = GetLevelByClass(CLASS_TYPE_MONK, oPC);
int nForsakerLvl = GetLevelByClass(CLASS_TYPE_FORSAKER, oPC);
int nEnlightenedFistLvl = GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oPC);
int nDraconicMysteriesLvl = GetLevelByClass(CLASS_TYPE_INITIATE_DRACONIC, oPC);
int nSanctifiedMindLvl = GetLevelByClass(CLASS_TYPE_SANCTIFIED_MIND, oPC);
int nUrPriestLvl = GetLevelByClass(CLASS_TYPE_UR_PRIEST, oPC);
// Monk Diamond Soul (level 13+)
if(nMonkLvl >= 13)
{
nTotalSR += (nMonkLvl + 10);
}
// Forsaker SR
if(nForsakerLvl > 0)
{
nTotalSR += (10 + nForsakerLvl);
}
// Enlightened Fist Diamond Soul (level 9+)
if(nEnlightenedFistLvl >= 9)
{
nTotalSR += (10 + nMonkLvl + nEnlightenedFistLvl);
}
// Initiate of Draconic Mysteries (level 7+)
if(nDraconicMysteriesLvl >= 7)
{
nTotalSR += (15 + nDraconicMysteriesLvl);
}
// Sanctified Mind Power Resistance (level 6+)
if(nSanctifiedMindLvl >= 6)
{
nTotalSR += (5 + GetHitDice(oPC));
}
// Ur-Priest Divine Spell Resistance
if(nUrPriestLvl >= 8)
{
nTotalSR += 20; // SR 20 at level 8+
}
else if(nUrPriestLvl >= 4)
{
nTotalSR += 15; // SR 15 at level 4-7
}
return nTotalSR;
}
void main()
{
@@ -37,7 +132,13 @@ void main()
int nForsakerLvlCheck;
int nBonus = nForsakerLvl/2;
int nRegen = 1 + nForsakerLvl/4;
int nSR = 10 + nForsakerLvl;
int nSR = 10 + nForsakerLvl;
// Calculate stacked spell resistance for Forsaker special case
int nTotalSR = PRCStackSpellResistance(oPC);
// Apply combined SR as single property
IPSafeAddItemProperty(oSkin, ItemPropertyBonusSpellResistance(GetSRByValue(nTotalSR)), 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);
if(nEvent == FALSE)
{

View File

@@ -34,7 +34,9 @@ void main()
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_GLOW_GREY));//VFX_DUR_PROT_PRC_SHADOW_ARMOR
eLink = EffectLinkEffects(eLink, EffectCutsceneGhost());
eLink = EffectLinkEffects(eLink, EffectEthereal());
eLink = TagEffect(eLink, "DARK_COMPANION");
eLink = UnyieldingEffect(eLink);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oCompanion);
}

View File

@@ -10,31 +10,75 @@
* This just tells it to follow the master and do nothing else.
*/
#include "inc_debug"
void main()
{
object oMaster = GetMaster();
if(!GetIsObjectValid(oMaster))
{
SetIsDestroyable(TRUE, FALSE, FALSE);
DestroyObject(OBJECT_SELF, 0.2);
}
// Forces it to move to the master's attack target so it take the penalty.
if(GetIsInCombat(oMaster))
{
object oMove = GetAttackTarget(oMaster);
if(GetIsObjectValid(oMove))
{
ClearAllActions(TRUE);
ActionForceFollowObject(GetAttackTarget(oMaster), 1.0f);
}
}
else
{
ClearAllActions(TRUE);
ActionForceFollowObject(oMaster, 4.0f);
}
#include "inc_debug"
#include "prc_misc_const"
void main()
{
object oMaster = GetMaster();
if(!GetIsObjectValid(oMaster))
{
SetIsDestroyable(TRUE, FALSE, FALSE);
DestroyObject(OBJECT_SELF, 0.2);
return;
}
// Check for missing DARK_COMPANION effects and reapply if needed
int bHasAOE = FALSE;
int bHasGhost = FALSE;
int bHasEthereal = FALSE;
effect eCheck = GetFirstEffect(OBJECT_SELF);
while(GetIsEffectValid(eCheck))
{
if(GetEffectTag(eCheck) == "DARK_COMPANION")
{
int nType = GetEffectType(eCheck);
if(nType == EFFECT_TYPE_AREA_OF_EFFECT) bHasAOE = TRUE;
if(nType == EFFECT_TYPE_CUTSCENEGHOST) bHasGhost = TRUE;
if(nType == EFFECT_TYPE_ETHEREAL) bHasEthereal = TRUE;
}
eCheck = GetNextEffect(OBJECT_SELF);
}
// Reapply all effects if any are missing
if(!bHasAOE || !bHasGhost || !bHasEthereal)
{
// Remove any existing DARK_COMPANION effects first
eCheck = GetFirstEffect(OBJECT_SELF);
while(GetIsEffectValid(eCheck))
{
if(GetEffectTag(eCheck) == "DARK_COMPANION")
{
RemoveEffect(OBJECT_SELF, eCheck);
}
eCheck = GetNextEffect(OBJECT_SELF);
}
// Reapply the complete effect package
effect eLink = EffectAreaOfEffect(VFX_PER_10_FT_INVIS, "prc_hexbl_comp_a", "prc_hexbl_comp_c", "");
eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_GLOW_GREY));
eLink = EffectLinkEffects(eLink, EffectCutsceneGhost());
eLink = EffectLinkEffects(eLink, EffectEthereal());
eLink = TagEffect(eLink, "DARK_COMPANION");
eLink = SupernaturalEffect(eLink);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, OBJECT_SELF);
}
// Movement logic
if(GetIsInCombat(oMaster))
{
object oMove = GetAttackTarget(oMaster);
if(GetIsObjectValid(oMove))
{
ClearAllActions(TRUE);
ActionForceFollowObject(GetAttackTarget(oMaster), 1.0f);
}
}
else
{
ClearAllActions(TRUE);
ActionForceFollowObject(oMaster, 4.0f);
}
}