2026/04/20 Update

Aberrations shouldn't show up on the default Druid PnP Wildshape list.
Added Assassin to GetIsBioSpellCastClass()
Updated CloakedCastingDC() to work with Factotum's Cunning Brilliance.
Greatly expanded the possible class abilities for Factotum's Cunning Brilliance.
Fixed Sublime Chord related bug in PRCGetIsRealSpellKnownByClass().
This commit is contained in:
Jaysyn904
2026-04-20 15:53:14 -04:00
parent 0c813b4954
commit 0e9dabdfb3
7 changed files with 857 additions and 547 deletions

View File

@@ -10,8 +10,9 @@ 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_inc_factotum"
#include "prc_add_spl_pen"
// #include "prc_inc_spells"
// #include "prc_class_const"
// #include "prc_feat_const"
@@ -444,7 +445,32 @@ int AngrySpell(int spell_id, int nSchool, object oCaster)
return nDC;
}
int CloakedCastingDC(int spell_id, object oTarget, object oCaster)
int CloakedCastingDC(int spell_id, object oTarget, object oCaster)
{
int nDC;
int iBeguiler = GetLevelByClass(CLASS_TYPE_BEGUILER, oCaster);
int iFactotum = GetLevelByClass(CLASS_TYPE_FACTOTUM, oCaster);
int iEffectiveLevel = 0;
// Check if character has Beguiler levels OR has learned Cloaked Casting via Cunning Brilliance
if(iBeguiler || (iFactotum && GetIsAbilitySaved(oCaster, FEAT_CLOAKED_CASTING)))
{
if(GetIsDeniedDexBonusToAC(oTarget, oCaster, TRUE))
{
// Use Beguiler level if available, otherwise use Factotum level
iEffectiveLevel = iBeguiler ? iBeguiler : iFactotum;
if(iEffectiveLevel >= 14)
nDC = 2;
else if(iEffectiveLevel >= 2)
nDC = 1;
}
}
return nDC;
}
/* int CloakedCastingDC(int spell_id, object oTarget, object oCaster)
{
int nDC;
int iBeguiler = GetLevelByClass(CLASS_TYPE_BEGUILER, oCaster);
@@ -461,7 +487,7 @@ int CloakedCastingDC(int spell_id, object oTarget, object oCaster)
}
return nDC;
}
} */
// Wyrmbane Helm
int WyrmbaneHelmDC(object oTarget, object oCaster)

View File

@@ -203,6 +203,10 @@ const int FEAT_CHARMING_THE_ARROW = 25998;
//:: Skill Based Feats
const int FEAT_JUMP = 2884;
//:: Beguiler
const int FEAT_CLOAKED_CASTING = 23592;
const int FEAT_SURPRISE_CASTING = 23593;
//:: Lion of Talisid
const int FEAT_LOT_LIONS_COURAGE = 25614;
const int FEAT_LOT_LIONS_POUNCE = 25615;
@@ -3241,9 +3245,10 @@ const int FEAT_CWSM_FRIGHTFUL_PRESENCE = 2359;
const int FEAT_VIRTUOSO_REVEALING_MELODY = 4176;
const int FEAT_VIRTUOSO_PERFORMANCE = 4177;
// hexblade feats
const int FEAT_HEXCURSE = 3664;
const int FEAT_SWIFT_CAST = 3827;
//:: Hexblade feats
const int FEAT_HEXCURSE = 3664;
const int FEAT_METTLE = 3665;
const int FEAT_SWIFT_CAST = 3827;
// Status markers
const int FEAT_INCORPOREAL = 4166;

View File

@@ -532,7 +532,8 @@ int GetIsBioSpellCastClass(int nClass)
|| nClass == CLASS_TYPE_SHAMAN
|| nClass == CLASS_TYPE_DRUID
|| nClass == CLASS_TYPE_PALADIN
|| nClass == CLASS_TYPE_RANGER;
|| nClass == CLASS_TYPE_RANGER
|| nClass == CLASS_TYPE_ASSASSIN;
}
int GetIsNSBClass(int nClass)
@@ -675,8 +676,19 @@ int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJ
string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookSpell);
if (sSpellLevel != "")
nSpellLevel = StringToInt(sSpellLevel);
if ((GetLevelByClass(nClass) < nSpellLevel) || nSpellLevel == -1)
return FALSE; // not high enough level
if (nClass == CLASS_TYPE_SUBLIME_CHORD)
{
// Sublime Chord gets access to 4th level spells at level 1
// Skip level requirement check for this class
}
else
{
// Original level check for other classes
if ((GetLevelByClass(nClass) < nSpellLevel) || nSpellLevel == -1)
return FALSE; // not high enough level
}
/* if ((GetLevelByClass(nClass) < nSpellLevel) || nSpellLevel == -1)
return FALSE; // not high enough level */
// at this stage, prepared casters know the spell and only spontaneous classes need checking
// there are exceptions and these need hardcoding:

View File

@@ -240,7 +240,171 @@ int GetIsAbilitySaved(object oPC, int nAbil)
return nCount;
}
void FactotumTriggerAbil(object oPC, int nAbil)
void FactotumTriggerAbil(object oPC, int nAbil)
{
object oSkin = GetPCSkin(oPC);
effect eEffect;
if (nAbil == FEAT_BARBARIAN_RAGE)
ExecuteScript("NW_S1_BarbRage", oPC);
else if (nAbil == FEAT_BARBARIAN_ENDURANCE)
eEffect = EffectBonusFeat(IP_CONST_FEAT_BarbEndurance);
else if (nAbil == FEAT_SNEAK_ATTACK)
{
SetLocalInt(oPC, "FactotumSneak", TRUE);
DelayCommand(0.1, ExecuteScript("prc_sneak_att", oPC));
DelayCommand(59.9, DeleteLocalInt(oPC, "FactotumSneak"));
DelayCommand(60.0, ExecuteScript("prc_sneak_att", oPC));
}
else if (nAbil == FEAT_METTLE) // Mettle
{
eEffect = EffectBonusFeat(FEAT_METTLE);
/* SetLocalInt(oPC, "FactotumMettle", TRUE);
DelayCommand(60.0, DeleteLocalInt(oPC, "FactotumMettle")); */
}
else if (nAbil == FEAT_CRUSADER_SMITE)
{
eEffect = EffectBonusFeat(FEAT_CRUSADER_SMITE);
}
else if (nAbil == FEAT_CLOAKED_CASTING)
{
eEffect = EffectBonusFeat(FEAT_CLOAKED_CASTING);
}
else if (nAbil == FEAT_DRAGONSHAMAN_RESOLVE)
{
// Draconic Resolve - immunity to sleep, paralysis, fear
eEffect = EffectImmunity(IMMUNITY_TYPE_PARALYSIS);
eEffect = EffectLinkEffects(eEffect, EffectImmunity(IMMUNITY_TYPE_SLEEP));
eEffect = EffectLinkEffects(eEffect, EffectImmunity(IMMUNITY_TYPE_FEAR));
}
// Favored Enemy feats
else if (nAbil == FEAT_FAVORED_ENEMY_ABERRATION)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_ABERRATION);
else if (nAbil == FEAT_FAVORED_ENEMY_ANIMAL)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_ANIMAL);
else if (nAbil == FEAT_FAVORED_ENEMY_BEAST)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_BEAST);
else if (nAbil == FEAT_FAVORED_ENEMY_CONSTRUCT)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_CONSTRUCT);
else if (nAbil == FEAT_FAVORED_ENEMY_DRAGON)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_DRAGON);
else if (nAbil == FEAT_FAVORED_ENEMY_DWARF)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_DWARF);
else if (nAbil == FEAT_FAVORED_ENEMY_ELEMENTAL)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_ELEMENTAL);
else if (nAbil == FEAT_FAVORED_ENEMY_ELF)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_ELF);
else if (nAbil == FEAT_FAVORED_ENEMY_FEY)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_FEY);
else if (nAbil == FEAT_FAVORED_ENEMY_GIANT)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_GIANT);
else if (nAbil == FEAT_FAVORED_ENEMY_GNOME)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_GNOME);
else if (nAbil == FEAT_FAVORED_ENEMY_GOBLINOID)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_GOBLINOID);
else if (nAbil == FEAT_FAVORED_ENEMY_HALFELF)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_HALFELF);
else if (nAbil == FEAT_FAVORED_ENEMY_HALFLING)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_HALFLING);
else if (nAbil == FEAT_FAVORED_ENEMY_HALFORC)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_HALFORC);
else if (nAbil == FEAT_FAVORED_ENEMY_HUMAN)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_HUMAN);
else if (nAbil == FEAT_FAVORED_ENEMY_MAGICAL_BEAST)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_MAGICAL_BEAST);
else if (nAbil == FEAT_FAVORED_ENEMY_MONSTROUS)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_MONSTROUS);
else if (nAbil == FEAT_FAVORED_ENEMY_ORC)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_ORC);
else if (nAbil == FEAT_FAVORED_ENEMY_OOZE)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_OOZE);
else if (nAbil == FEAT_FAVORED_ENEMY_OUTSIDER)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_OUTSIDER);
else if (nAbil == FEAT_FAVORED_ENEMY_PLANT)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_PLANT);
else if (nAbil == FEAT_FAVORED_ENEMY_REPTILIAN)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_REPTILIAN);
else if (nAbil == FEAT_FAVORED_ENEMY_SHAPECHANGER)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_SHAPECHANGER);
else if (nAbil == FEAT_FAVORED_ENEMY_UNDEAD)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_UNDEAD);
else if (nAbil == FEAT_FAVORED_ENEMY_VERMIN)
eEffect = EffectBonusFeat(FEAT_FAVORED_ENEMY_VERMIN);
// Other existing abilities
else if (nAbil == FEAT_NATURE_SENSE)
{
eEffect = EffectBonusFeat(FEAT_NATURE_SENSE);
}
else if (nAbil == FEAT_WOODLAND_STRIDE)
{
eEffect = EffectBonusFeat(FEAT_WOODLAND_STRIDE);
}
else if (nAbil == FEAT_TRACKLESS_STEP)
{
eEffect = EffectBonusFeat(FEAT_TRACKLESS_STEP);
}
else if (nAbil == FEAT_RESIST_NATURES_LURE)
{
eEffect = EffectBonusFeat(FEAT_RESIST_NATURES_LURE);
}
else if (nAbil == FEAT_VENOM_IMMUNITY)
{
effect eImmunity = EffectImmunity(IMMUNITY_TYPE_POISON);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmunity, oPC, 60.0);
}
else if (nAbil == FEAT_EVASION)
{
eEffect = EffectBonusFeat(FEAT_EVASION);
}
else if (nAbil == FEAT_STILL_MIND)
{
eEffect = EffectBonusFeat(FEAT_STILL_MIND);
}
else if (nAbil == FEAT_PURITY_OF_BODY)
{
// Purity of Body - disease immunity
effect eImmunity = EffectImmunity(IMMUNITY_TYPE_DISEASE);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmunity, oPC, 60.0);
}
else if (nAbil == FEAT_IMPROVED_EVASION)
{
eEffect = EffectBonusFeat(FEAT_IMPROVED_EVASION);
}
else if (nAbil == FEAT_USE_POISON)
{
eEffect = EffectBonusFeat(FEAT_USE_POISON);
}
else if (nAbil == FEAT_DIVINE_HEALTH)
{
// Divine Health - disease immunity
effect eImmunity = EffectImmunity(IMMUNITY_TYPE_DISEASE);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eImmunity, oPC, 60.0);
}
else if (nAbil == FEAT_CRIPPLING_STRIKE)
{
eEffect = EffectBonusFeat(FEAT_CRIPPLING_STRIKE);
}
else if (nAbil == FEAT_DEFENSIVE_ROLL)
{
eEffect = EffectBonusFeat(FEAT_DEFENSIVE_ROLL);
}
else if (nAbil == FEAT_OPPORTUNIST)
{
eEffect = EffectBonusFeat(FEAT_OPPORTUNIST);
}
else if (nAbil == FEAT_SLIPPERY_MIND)
{
eEffect = EffectBonusFeat(FEAT_SLIPPERY_MIND);
}
eEffect = TagEffect(eEffect, "FactotumCunningBrilliance");
eEffect = ExtraordinaryEffect(eEffect);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEffect, oPC, 60.0);
}
/* void FactotumTriggerAbil(object oPC, int nAbil)
{
object oSkin = GetPCSkin(oPC);
itemproperty ipIP;
@@ -264,7 +428,7 @@ void FactotumTriggerAbil(object oPC, int nAbil)
ipIP = PRCItemPropertyBonusFeat(IP_CONST_FEAT_CRUSADER_SMITE);
IPSafeAddItemProperty(oSkin, ipIP, 60.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
} */
void TriggerInspiration(object oPC, int nCombat)
{