2025/08/30 Update

Added the Repair Damage line of spells.
Stigmata is an activatable general feat.
Cleaned up old prepared caster lines in feat.2da & spells.2da.
Master Wand is an epic feat.
Updated Favoured Soul spell list.
Updated Sorcerer spell list.
Updated Dread Necromancer Advanced Learning list.
Updated fileends to support above changes.
This commit is contained in:
Jaysyn904
2025-08-29 16:23:15 -04:00
parent 79104964db
commit a61d514630
113 changed files with 153673 additions and 81209 deletions

View File

@@ -49,7 +49,7 @@ dead after being hit by a fireball).
// Validates and tracks mirror image alignment with master
void TrackMirrorImage(object oSummoned)
{
DoDebug("sp_mirror >> TrackMirrorImage: Running.");
if(DEBUG) DoDebug("sp_mirror >> TrackMirrorImage: Running.");
if (!GetIsObjectValid(oSummoned))
{
@@ -109,7 +109,7 @@ void StartMirrorImageTracking(object oSummoned, object oMaster)
SetLocalObject(oSummoned, "oMaster", oMaster);
DoDebug("sp_mirror >> StartMirrorImageTracking: Firing TrackMirrorImage().");
if(DEBUG) DoDebug("sp_mirror >> StartMirrorImageTracking: Firing TrackMirrorImage().");
TrackMirrorImage(oSummoned);
}

View File

@@ -0,0 +1,188 @@
/** @file
sp_repairinflict.nss
Repair / Inflict Damage (construct) handler.
Mirrors nw_s0_cureinflict structure and mass behaviour.
*/
#include "prc_sp_func"
#include "prc_inc_function"
#include "prc_inc_sp_tch"
#include "prc_add_spell_dc"
int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nSpellID, int bIsRepair)
{
int nMetaMagic = PRCGetMetaMagicFeat();
int bMass = IsMassRepair(nSpellID) || IsMassInflictDamage(nSpellID);
int nHealVFX;
int nEnergyType = DAMAGE_TYPE_MAGICAL;
int nSpellLevel = StringToInt(lookup_spell_level(PRCGetSpellId()));
int nDice = bMass ? nSpellLevel - 4 : nSpellLevel;
int bHeal;
int nAmount;
switch(nDice) //nDice == 0 for minor => small vfx
{
case 0: nHealVFX = VFX_IMP_MAGBLUE; break;
case 1: nHealVFX = VFX_IMP_MAGBLUE; break;
case 2: nHealVFX = VFX_IMP_MAGBLUE; break;
case 3: nHealVFX = VFX_IMP_LIGHTNING_S; break;
case 4: default: nHealVFX = VFX_IMP_MAGBLUE; break;
}
/* switch(nDice) //nDice == 0 for minor => small vfx
{
case 0: nHealVFX = VFX_IMP_HEAD_HEAL; break;
case 1: nHealVFX = VFX_IMP_HEALING_S; break;
case 2: nHealVFX = VFX_IMP_HEALING_M; break;
case 3: nHealVFX = VFX_IMP_HEALING_L; break;
case 4: default: nHealVFX = VFX_IMP_HEALING_G; break;
} */
// Repair/Inflict construct bonus: +1 per caster level, max +5
int nExtraDamage = PRCMin(nCasterLevel, 5);
// Mass spell AoE targeting (same mass behaviour as cure/inflict)
location lLoc;
if(bMass)
{
lLoc = PRCGetSpellTargetLocation();
oTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lLoc, TRUE);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(bIsRepair ? VFX_FNF_LOS_HOLY_20 : VFX_FNF_LOS_EVIL_20), lLoc);
}
float fDelay = 0.0;
int nAffected = 0;
int nMaxAffected= bMass ? nCasterLevel : 1;
int iAttackRoll = 1;
while(GetIsObjectValid(oTarget))
{
// Skip non-creatures or creatures that are not constructs.
if(GetObjectType(oTarget) != OBJECT_TYPE_CREATURE || MyPRCGetRacialType(oTarget) != RACIAL_TYPE_CONSTRUCT)
{
oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lLoc, TRUE);
continue;
}
if(bMass) fDelay = PRCGetRandomDelay();
// Compute heal/damage amount
if(nMetaMagic & METAMAGIC_MAXIMIZE)
{
nAmount = nDice * 8 + nExtraDamage;
}
else
nAmount = d8(nDice) + nExtraDamage;
if((nMetaMagic & METAMAGIC_EMPOWER))
nAmount += (nAmount / 2);
// Minor (dice == 0) => 1 point
if(nDice == 0)
nAmount = 1;
// Determine heal vs harm. For this handler:
// - Repair spells heal constructs.
// - InflictDamage spells harm constructs.
bHeal = bIsRepair;
// Repair (healing constructs)
if(bHeal && !spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, oCaster)) // assume only heal non-hostiles
{
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectHeal(nAmount, oTarget), oTarget));
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(nHealVFX), oTarget));
SignalEvent(oTarget, EventSpellCastAt(oCaster, nSpellID, FALSE));
nAffected++;
}
// Inflict Damage (harm constructs)
else if(!bHeal && spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, oCaster))
{
// Add any per-dice flat additions similar to cure/inflict behaviour
nAmount += SpellDamagePerDice(OBJECT_SELF, nDice);
// Roll touch attack if not mass
iAttackRoll = bMass ? TRUE : PRCDoMeleeTouchAttack(oTarget);
if(iAttackRoll > 0)
{
SignalEvent(oTarget, EventSpellCastAt(oCaster, nSpellID));
// Inflict-damage spells are subject to SR. Repair spells are not.
if(!PRCDoResistSpell(oCaster, oTarget, nCasterLevel + SPGetPenetr()))
{
/* int MySavingThrow(
int nSavingThrow,
object oTarget,
int nDC,
SAVING_THROW_TYPE_NONE,
object oSaveVersus = OBJECT_SELF,
float fDelay = 0.0f ); */
// Inflict damage spells: Will save for half
//int nSave = WillSave(oTarget, PRCGetSaveDC(oCaster, nSpellID));
int nSave = PRCMySavingThrow(SAVING_THROW_WILL, oTarget, PRCGetSaveDC(oTarget, oCaster, nSpellID), SAVING_THROW_TYPE_SPELL, OBJECT_SELF, fDelay);
int nFinal = nAmount;
if(nSave == 1) // successful save
nFinal /= 2;
effect eDam = PRCEffectDamage(oTarget, nFinal, nEnergyType);
DelayCommand(fDelay + 1.0, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HARM), oTarget));
}
}
nAffected++;
}
// Terminate loop if target limit reached
if(nAffected >= nMaxAffected)
break;
// Next in AoE
oTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, lLoc, TRUE);
}
return bMass ? TRUE : iAttackRoll; // TRUE if charges should be decremented
}
void main()
{
if (!X2PreSpellCastCode()) return;
int nSpellID = PRCGetSpellId();
// Determine whether this is a repair (heal) or inflict-damage (harm) spell
int bIsRepair = IsMassRepair(nSpellID) || IsRepair(nSpellID); // implement IsRepair/IsMassRepair in your spell table if not present
int nSchool = SPELL_SCHOOL_TRANSMUTATION;
PRCSetSchool(nSchool);
object oCaster = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
int nCasterLevel = PRCGetCasterLevel(oCaster);
// Check for holding charge
int nEvent = GetLocalInt(oCaster, PRC_SPELL_EVENT);
if(!nEvent) // normal cast
{
// can't hold the charge with mass repair/inflict spells
if(GetLocalInt(oCaster, PRC_SPELL_HOLD) && oCaster == oTarget && IsTouchSpell(nSpellID))
{
SetLocalSpellVariables(oCaster, 1);
return;
}
DoSpell(oCaster, oTarget, nCasterLevel, nSpellID, bIsRepair);
}
else
{
if(nEvent & PRC_SPELL_EVENT_ATTACK)
{
if(DoSpell(oCaster, oTarget, nCasterLevel, nSpellID, bIsRepair))
DecrementSpellCharges(oCaster);
}
}
PRCSetSchool();
}