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.
188 lines
6.5 KiB
Plaintext
188 lines
6.5 KiB
Plaintext
/** @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();
|
|
} |