Spell update
Added the following spells: Regenerate Light Wounds, Regenerate Moderate Wounds, Regenerate Serious Wounds, Regenerate Critical Wounds, Spirit Worm, Tortoise Shell, Speed of the Wind & Spiritual Weapon. Updated Force Missiles & Chasing Perfection. Updated Acid Fog to be more like pen & paper. Updated release archive.
This commit is contained in:
@@ -15,9 +15,83 @@
|
||||
|
||||
|
||||
//:: modified by mr_bumpkin Dec 4, 2003
|
||||
|
||||
//:: This spell isn't supposed to have a saving throw.
|
||||
//:: modified by Jaysyn: 2024-08-25 14:41:58
|
||||
|
||||
|
||||
#include "prc_inc_spells"
|
||||
#include "prc_add_spell_dc"
|
||||
|
||||
void main()
|
||||
{
|
||||
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
|
||||
|
||||
//Declare major variables
|
||||
object oCaster = GetAreaOfEffectCreator();
|
||||
object oTarget = GetEnteringObject();
|
||||
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
effect eVis = EffectVisualEffect(VFX_IMP_ACID_S);
|
||||
effect eSlow = EffectMovementSpeedDecrease(50);
|
||||
float fDelay = PRCGetRandomDelay(1.0, 2.2);
|
||||
int nPenetr = GetLocalInt(OBJECT_SELF, "X2_AoE_Caster_Level") + SPGetPenetr(oCaster);
|
||||
|
||||
if (spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oCaster))
|
||||
{
|
||||
//Fire cast spell at event for the target
|
||||
SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_ACID_FOG));
|
||||
//Spell resistance check
|
||||
if(!PRCDoResistSpell(oCaster, oTarget, nPenetr, fDelay))
|
||||
{
|
||||
//Roll Damage
|
||||
//Enter Metamagic conditions
|
||||
int nDamage = d6(2);
|
||||
if (nMetaMagic & METAMAGIC_MAXIMIZE)
|
||||
nDamage = 12;//Damage is at max
|
||||
if (nMetaMagic & METAMAGIC_EMPOWER)
|
||||
nDamage = nDamage + (nDamage/2); //Damage/Healing is +50%
|
||||
// Acid Sheath adds +1 damage per die to acid descriptor spells
|
||||
if (GetHasDescriptor(SPELL_ACID_FOG, DESCRIPTOR_ACID) && GetHasSpellEffect(SPELL_MESTILS_ACID_SHEATH, oCaster))
|
||||
nDamage += 2;
|
||||
nDamage += SpellDamagePerDice(oCaster, 2);
|
||||
|
||||
//slowing effect
|
||||
SPApplyEffectToObject(DURATION_TYPE_PERMANENT, eSlow, oTarget,0.0f,FALSE);
|
||||
// * BK: Removed this because it reduced damage, didn't make sense nDamage = d6();
|
||||
|
||||
|
||||
//Set Damage Effect with the modified damage
|
||||
effect eDam = PRCEffectDamage(oTarget, nDamage, GetLocalInt(OBJECT_SELF, "Acid_Fog_Damage"));
|
||||
//Apply damage and visuals
|
||||
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
||||
DelayCommand(fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
|
||||
PRCBonusDamage(oTarget);
|
||||
}
|
||||
}
|
||||
PRCSetSchool();
|
||||
}
|
||||
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Acid Fog: On Enter
|
||||
//:: NW_S0_AcidFogA.nss
|
||||
//:: Copyright (c) 2001 Bioware Corp.
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
All creatures within the AoE take 2d6 acid damage
|
||||
per round and upon entering if they fail a Fort Save
|
||||
their movement is halved.
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Preston Watamaniuk
|
||||
//:: Created On: May 17, 2001
|
||||
//:://///////////////////////////////////////////
|
||||
|
||||
|
||||
//:: modified by mr_bumpkin Dec 4, 2003
|
||||
/* #include "prc_inc_spells"
|
||||
#include "prc_add_spell_dc"
|
||||
|
||||
void main()
|
||||
{
|
||||
PRCSetSchool(SPELL_SCHOOL_CONJURATION);
|
||||
@@ -67,4 +141,4 @@ void main()
|
||||
}
|
||||
}
|
||||
PRCSetSchool();
|
||||
}
|
||||
} */
|
@@ -5,8 +5,8 @@
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
All creatures within the AoE take 2d6 acid damage
|
||||
per round and upon entering if they fail a Fort Save
|
||||
their movement is halved.
|
||||
per round and their movement is halved.
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Preston Watamaniuk
|
||||
@@ -18,7 +18,8 @@
|
||||
//:: modified by mr_bumpkin Dec 4, 2003
|
||||
#include "prc_inc_spells"
|
||||
|
||||
|
||||
//:: This spell isn't supposed to have a saving throw.
|
||||
//:: modified by Jaysyn: 2024-08-25 14:41:58
|
||||
|
||||
void main()
|
||||
{
|
||||
|
@@ -5,8 +5,8 @@
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
All creatures within the AoE take 2d6 acid damage
|
||||
per round and upon entering if they fail a Fort Save
|
||||
their movement is halved.
|
||||
per round and their movement is halved.
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Preston Watamaniuk
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
|
||||
//:: modified by mr_bumpkin Dec 4, 2003
|
||||
|
||||
//:: This spell isn't supposed to have a saving throw.
|
||||
//:: modified by Jaysyn: 2024-08-25 14:41:58
|
||||
|
||||
#include "prc_inc_spells"
|
||||
#include "prc_add_spell_dc"
|
||||
|
||||
@@ -58,11 +62,6 @@ void main()
|
||||
int nSaveType = ChangedSaveType(nDamageType);
|
||||
float fDelay = PRCGetRandomDelay(0.4, 1.2);
|
||||
|
||||
if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, nSaveType, oCaster, fDelay))
|
||||
{
|
||||
// This script does nothing if it has Mettle else deal only 1/2 damage
|
||||
nDamage = GetHasMettle(oTarget, SAVING_THROW_FORT) ? 0 : nDamage / 2;
|
||||
}
|
||||
//Fire cast spell at event for the affected target
|
||||
SignalEvent(oTarget, EventSpellCastAt(oCaster, SPELL_ACID_FOG));
|
||||
//Spell resistance check
|
||||
|
@@ -1,5 +1,10 @@
|
||||
/**@file Chasing Perfection
|
||||
[sp_chasperfect.nss]
|
||||
//::///////////////////////////////////////////////
|
||||
//:: [Chasing Perfection]
|
||||
//:: [sp_chasperfect.nss]
|
||||
//:: [Tenjac & Jaysyn 20240807]
|
||||
//::
|
||||
//::///////////////////////////////////////////////
|
||||
/**@file Chasing Perfection
|
||||
(Player's Handbook II, p. 106)
|
||||
|
||||
Transmutation
|
||||
@@ -23,13 +28,7 @@ enhancement bonus to each of its ability scores.
|
||||
Material Component: A statuette of a celestial or
|
||||
fiend worth 50 gp.
|
||||
|
||||
**/
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Author: Tenjac & Jaysyn
|
||||
// Date: 2024/08/07
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
**/////////////////////////////////////////////////
|
||||
#include "prc_inc_sp_tch"
|
||||
#include "prc_sp_func"
|
||||
#include "prc_add_spell_dc"
|
||||
@@ -42,9 +41,10 @@ int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nEvent)
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDur += fDur;
|
||||
|
||||
PRCSignalSpellEvent(oTarget, FALSE, SPELL_CHASING_PERFECTION, oCaster);
|
||||
//:: Fire spell cast at event for target
|
||||
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, PRCGetSpellId(), FALSE));
|
||||
|
||||
// Check for existing ability enhancing spells
|
||||
//:: Check for existing ability enhancing spells
|
||||
effect eExistingSpellEffect = GetFirstEffect(oTarget);
|
||||
|
||||
int nBoostSTR = 4;
|
||||
@@ -128,17 +128,22 @@ int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nEvent)
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Check the Spellhook
|
||||
//:: Run the Spellhook
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
//:: Set the Spell School
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
//:: Declare major variables
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
|
||||
//:: Prevent spell stacking
|
||||
PRCRemoveEffectsFromSpell(oTarget, PRCGetSpellId());
|
||||
|
||||
int nEvent = GetLocalInt(oCaster, PRC_SPELL_EVENT); //use bitwise & to extract flags
|
||||
|
||||
if(!nEvent) //normal cast
|
||||
{
|
||||
if(GetLocalInt(oCaster, PRC_SPELL_HOLD) && oCaster == oTarget)
|
||||
|
@@ -1,10 +1,12 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Force Missiles
|
||||
//:: sp_forcemissiles
|
||||
//:: Copyright (c) 2022 PRC
|
||||
//:: [Force Missiles]
|
||||
//:: [sp_forcemissiles.nss]
|
||||
//:: Created By: Jaysyn / Tsurani Nevericy
|
||||
//:: Created On: 20220726
|
||||
//:: Last Updated By: Jaysyn
|
||||
//:: Last Updated On: 2024-08-16 10:01:17
|
||||
//:://////////////////////////////////////////////
|
||||
/*/
|
||||
Force Missiles
|
||||
/**@file Force Missiles
|
||||
(Spell Compendium, p. 98)
|
||||
|
||||
Evocation [Force]
|
||||
@@ -33,109 +35,106 @@ You gain one missile for every four caster levels. You can make more than one
|
||||
missile strike a single target, if desired. However,you must designate targets
|
||||
before rolling for spell resistance or damage.
|
||||
|
||||
/*/
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Created By: Tsurani Nevericy
|
||||
//:: Created On: 05/15/2024
|
||||
//:://////////////////////////////////////////////
|
||||
//:: Last Updated By: Tsurani Nevericy
|
||||
//:: Last Updated On: 05/15/2024
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "prc_sp_func"
|
||||
#include "prc_inc_spells"
|
||||
*///////////////////////////////////////////////////////////
|
||||
#include "x2_inc_spellhook"
|
||||
#include "prc_inc_spells"
|
||||
|
||||
void SendMissileBomb(object oCaster, object oTarget, float fDelay=0.0, float fTime=0.0)
|
||||
{
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nPenetr = nCasterLevel + SPGetPenetr();
|
||||
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_MIRV), oTarget);
|
||||
location lLoc = GetLocation(oTarget);
|
||||
object oLoop = GetFirstObjectInShape(SHAPE_SPHERE, 5.0, lLoc, TRUE);
|
||||
object oLoop = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(5.0), lLoc, TRUE);
|
||||
|
||||
while (GetIsObjectValid(oLoop))
|
||||
{
|
||||
SignalEvent(oLoop, EventSpellCastAt(oCaster, PRCGetSpellId()));
|
||||
int nDam;
|
||||
|
||||
if (oLoop == oTarget)
|
||||
{
|
||||
int nDam = d6(2);
|
||||
nDam = d6(2);
|
||||
if (nMetaMagic == METAMAGIC_MAXIMIZE)
|
||||
nDam = 12;
|
||||
nDam = 12;
|
||||
if (nMetaMagic == METAMAGIC_EMPOWER)
|
||||
nDam += nDam/2;
|
||||
nDam += nDam/2;
|
||||
|
||||
DelayCommand(fTime, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam, DAMAGE_TYPE_MAGICAL), oLoop));
|
||||
DelayCommand(fTime, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_IMP_MAGBLUE, FALSE, 4.0f), oLoop));
|
||||
}
|
||||
else if (!PRCDoResistSpell(oCaster, oLoop, FloatToInt(fDelay)))
|
||||
else if (!PRCDoResistSpell(oCaster, oLoop, nPenetr, fDelay))
|
||||
{
|
||||
int nDam = d6(1);
|
||||
nDam = d6(1);
|
||||
if (nMetaMagic == METAMAGIC_MAXIMIZE)
|
||||
nDam = 6;
|
||||
nDam = 6;
|
||||
if (nMetaMagic == METAMAGIC_EMPOWER)
|
||||
nDam += nDam/2;
|
||||
nDam += nDam/2;
|
||||
|
||||
DelayCommand(fTime, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDam, DAMAGE_TYPE_MAGICAL), oLoop));
|
||||
DelayCommand(fTime, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_IMP_MAGBLUE), oLoop));
|
||||
}
|
||||
oLoop = GetNextObjectInShape(SHAPE_SPHERE, 5.0, lLoc, TRUE);
|
||||
|
||||
oLoop = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(5.0), lLoc, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
//Implements the spell impact, put code here
|
||||
// if called in many places, return TRUE if
|
||||
// stored charges should be decreased
|
||||
// eg. touch attack hits
|
||||
//
|
||||
// Variables passed may be changed if necessary
|
||||
int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nEvent)
|
||||
void main()
|
||||
{
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
int nSaveDC = PRCGetSaveDC(oTarget, oCaster);
|
||||
int nPenetr = nCasterLevel + SPGetPenetr();
|
||||
int i;
|
||||
int nTargets;
|
||||
int nCnt = 1;
|
||||
float fDist, fDelay, fDelay2, fTime;
|
||||
//:: Check the Spellhook
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
if (nCasterLevel > 40) nCasterLevel = 40;
|
||||
int nMissiles = nCasterLevel/4;
|
||||
if (nMissiles < 1) nMissiles = 1;
|
||||
//:: Set the Spell School
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
location lTarget = PRCGetSpellTargetLocation();
|
||||
//:: Declare major variables
|
||||
int i;
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget;
|
||||
float fDist, fDelay, fDelay2 = 0.0, fTime;
|
||||
int nTargets = 0;
|
||||
int nCnt = 1;
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nPenetr = nCasterLevel + SPGetPenetr();
|
||||
if (nCasterLevel > 40) nCasterLevel = 40;
|
||||
int nMissiles = nCasterLevel / 4;
|
||||
if (nMissiles < 1) nMissiles = 1;
|
||||
|
||||
location lTarget = GetSpellTargetLocation();
|
||||
oTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(30.0), lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
|
||||
oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 9.144, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
while (GetIsObjectValid(oTarget))
|
||||
{
|
||||
if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, oCaster) && oTarget != oCaster)
|
||||
{
|
||||
nTargets++;
|
||||
}
|
||||
oTarget = GetNextObjectInShape(SHAPE_SPHERE, 9.144, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(30.0), lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
}
|
||||
if (!nTargets)
|
||||
return FALSE;
|
||||
|
||||
if (nTargets == 0)
|
||||
return;
|
||||
|
||||
int nExtraMissiles = nMissiles / nTargets;
|
||||
|
||||
if (nExtraMissiles <= 0)
|
||||
if (nExtraMissiles < 1)
|
||||
nExtraMissiles = 1;
|
||||
|
||||
int nRemainder = 0;
|
||||
int nRemainder = nMissiles % nTargets;
|
||||
|
||||
if (nTargets > nMissiles) nTargets = nMissiles;
|
||||
oTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(30.0), lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
|
||||
nRemainder = nMissiles % nTargets;
|
||||
|
||||
oTarget = GetFirstObjectInShape(SHAPE_SPHERE, 9.144, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
while (GetIsObjectValid(oTarget) && nCnt <= nTargets)
|
||||
{
|
||||
if (spellsIsTarget(oTarget, SPELL_TARGET_SELECTIVEHOSTILE, oCaster) && oTarget != oCaster)
|
||||
{
|
||||
if (!PRCDoResistSpell(oCaster, oTarget, FloatToInt(fDelay)))
|
||||
if (!PRCDoResistSpell(oCaster, oTarget, nPenetr, fDelay))
|
||||
{
|
||||
int i;
|
||||
for (i=1; i <= nExtraMissiles + nRemainder; i++)
|
||||
for (i = 0; i < nExtraMissiles + nRemainder; i++)
|
||||
{
|
||||
fDist = GetDistanceBetween(oCaster, oTarget);
|
||||
fDelay = fDist/(3.0 * log(fDist) + 2.0);
|
||||
fDelay = fDist / (3.0 * log(fDist) + 2.0);
|
||||
fTime = fDelay;
|
||||
fDelay2 += 0.1;
|
||||
fTime += fDelay2;
|
||||
@@ -149,49 +148,8 @@ int DoSpell(object oCaster, object oTarget, int nCasterLevel, int nEvent)
|
||||
nCnt++;
|
||||
nRemainder = 0;
|
||||
}
|
||||
oTarget = GetNextObjectInShape(SHAPE_SPHERE, 9.144, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Check the Spellhook
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
//:: Set the Spell School
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int i;
|
||||
int nTargets;
|
||||
int nCnt = 1;
|
||||
float fDist, fDelay, fDelay2, fTime;
|
||||
|
||||
int nEvent = GetLocalInt(oCaster, PRC_SPELL_EVENT); //use bitwise & to extract flags
|
||||
if(!nEvent) //normal cast
|
||||
{
|
||||
if(GetLocalInt(oCaster, PRC_SPELL_HOLD) && oCaster == oTarget)
|
||||
{ //holding the charge, casting spell on self
|
||||
SetLocalSpellVariables(oCaster, 1); //change 1 to number of charges
|
||||
return;
|
||||
}
|
||||
DoSpell(oCaster, oTarget, nCasterLevel, nEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(nEvent & PRC_SPELL_EVENT_ATTACK)
|
||||
{
|
||||
if(DoSpell(oCaster, oTarget, nCasterLevel, nEvent))
|
||||
DecrementSpellCharges(oCaster);
|
||||
}
|
||||
oTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(30.0), lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
||||
}
|
||||
//:: Unset the Spell school
|
||||
PRCSetSchool();
|
||||
}
|
||||
|
||||
//::///////////////////////////////////////////////////////////////////
|
||||
PRCSetSchool();
|
||||
}
|
178
nwn/nwnprc/trunk/spells/sp_regen_wounds.nss
Normal file
178
nwn/nwnprc/trunk/spells/sp_regen_wounds.nss
Normal file
@@ -0,0 +1,178 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: [Regenerate X Wounds]
|
||||
//:: [sp_regen_wounds.nss]
|
||||
//:: [Jaysyn - PRC8 2024-08-29 12:26:52]
|
||||
//::
|
||||
//:: Handles all Regen X Wounds spells
|
||||
//::
|
||||
//::///////////////////////////////////////////////
|
||||
/**@file Regenerate X Wounds
|
||||
(Masters of the Wild: A Guidebook to Barbarians,
|
||||
Druids, and Rangers)
|
||||
|
||||
Conjuration (Healing)
|
||||
Level: Cleric 1-4, Druid 1-4,
|
||||
Components: V, S,
|
||||
Casting Time: 1 action
|
||||
Range: Touch
|
||||
Target: Living creature touched
|
||||
Duration: 10 rounds + 1 round/level
|
||||
Saving Throw: Will negates (harmless)
|
||||
Spell Resistance: Yes (harmless)
|
||||
|
||||
With a touch of your hand, you boost the subject's
|
||||
life energy, granting him or her the fast healing
|
||||
ability for the duration of the spell.
|
||||
|
||||
This healing applies only to damage sustained during
|
||||
the spell's duration, not to that from previous injuries.
|
||||
|
||||
The subject heals 1 hit point per round of such
|
||||
damage until the spell ends and is automatically stabilized
|
||||
if he or she begins dying from hit point loss during that time.
|
||||
|
||||
Regenerate light wounds does not restore hit points lost from
|
||||
starvation, thirst, or suffocation, nor does it allow a creature
|
||||
to regrow or attach lost body parts.
|
||||
|
||||
The effects of multiple regenerate spells do not stack, only
|
||||
the highest-level effect applies.
|
||||
|
||||
Applying a second regenerate spell of equal level extends the
|
||||
first spell's duration by the full duration of the second spell.
|
||||
|
||||
*//////////////////////////////////////////////////
|
||||
#include "x2_inc_spellhook"
|
||||
#include "prc_inc_spells"
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Check the Spellhook
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
//:: Set the Spell School
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
//:: Declare major variables
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
|
||||
int nSpellId = PRCGetSpellId();
|
||||
int nMetamagic = PRCGetMetaMagicFeat();
|
||||
int nRegenRate = 0;
|
||||
int nDuration = 10 + PRCGetCasterLevel(oCaster); // Duration in rounds
|
||||
int nCurrentHP = GetCurrentHitPoints(oTarget);
|
||||
int nInitialHP = GetLocalInt(oTarget, "INITIAL_HIT_POINTS");
|
||||
|
||||
//:: Update Initial HP if the current HP are higher than the stored Initial HP
|
||||
if (nCurrentHP > nInitialHP)
|
||||
{
|
||||
nInitialHP = nCurrentHP;
|
||||
SetLocalInt(oTarget, "INITIAL_HIT_POINTS", nInitialHP);
|
||||
if(DEBUG) DoDebug("sp_regen_wounds: Updated Initial HP to " + IntToString(nInitialHP) + ".");
|
||||
}
|
||||
|
||||
if (GetRacialType(oTarget) != RACIAL_TYPE_CONSTRUCT && GetRacialType(oTarget) != RACIAL_TYPE_UNDEAD)
|
||||
{
|
||||
if(DEBUG) DoDebug("sp_regen_wounds: Initial HP = " + IntToString(nInitialHP) + ".");
|
||||
|
||||
switch (nSpellId)
|
||||
{
|
||||
case SPELL_REGEN_LIGHT_WOUNDS:
|
||||
{
|
||||
nRegenRate = 1;
|
||||
break;
|
||||
}
|
||||
case SPELL_REGEN_MODERATE_WOUNDS:
|
||||
{
|
||||
nRegenRate = 2;
|
||||
break;
|
||||
}
|
||||
case SPELL_REGEN_SERIOUS_WOUNDS:
|
||||
{
|
||||
nRegenRate = 3;
|
||||
break;
|
||||
}
|
||||
case SPELL_REGEN_CRITICAL_WOUNDS:
|
||||
{
|
||||
nRegenRate = 4;
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
|
||||
if (nMetamagic == METAMAGIC_EXTEND)
|
||||
{
|
||||
nDuration *= 2;
|
||||
}
|
||||
|
||||
// Get the current regeneration effect and its duration
|
||||
int nCurrentRegen = GetLocalInt(oTarget, "REGEN_RATE");
|
||||
int nExistingDuration = 0;
|
||||
int bSameSpell = FALSE;
|
||||
|
||||
effect eExisting = GetFirstEffect(oTarget);
|
||||
while (GetIsEffectValid(eExisting))
|
||||
{
|
||||
if (GetEffectTag(eExisting) == "REGEN_WOUNDS")
|
||||
{
|
||||
if(DEBUG) DoDebug("sp_regen_wounds: Found existing Regeneration effect via EffectTag.");
|
||||
if (nCurrentRegen == nRegenRate)
|
||||
{
|
||||
bSameSpell = TRUE;
|
||||
if(DEBUG) DoDebug("sp_regen_wounds: Same regeneration spell detected.");
|
||||
nExistingDuration = GetEffectDurationRemaining(eExisting) / 6; // Convert seconds to rounds
|
||||
if(DEBUG) DoDebug("sp_regen_wounds: Existing Duration = " + IntToString(nExistingDuration));
|
||||
if (nRegenRate >= nCurrentRegen)
|
||||
{
|
||||
// Remove existing effect if new spell is stronger
|
||||
RemoveEffect(oTarget, eExisting);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't apply weaker spell
|
||||
PRCSetSchool();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (nRegenRate >= nCurrentRegen)
|
||||
{
|
||||
// Remove existing effect if new spell is stronger
|
||||
RemoveEffect(oTarget, eExisting);
|
||||
}
|
||||
}
|
||||
eExisting = GetNextEffect(oTarget);
|
||||
}
|
||||
|
||||
// Only add the duration if the new spell is the same
|
||||
if (bSameSpell)
|
||||
{
|
||||
nDuration += nExistingDuration;
|
||||
if(DEBUG) DoDebug("sp_regen_wounds: Same regeneration spell detected, " + IntToString(nDuration) + " rounds remaining.");
|
||||
}
|
||||
|
||||
// Set the new regeneration rate and duration
|
||||
SetLocalInt(oTarget, "REGEN_RATE", nRegenRate);
|
||||
SetLocalInt(oTarget, "REGEN_WOUNDS_REMAINING", nDuration);
|
||||
|
||||
effect eVis = EffectVisualEffect(1330); //:: VFX_DUR_BF_IOUN_STONE_GREEN
|
||||
effect eFakeRegen = EffectRunScript("rs_regen_wounds", "rs_regen_wounds", "rs_regen_wounds", 6.0f, IntToString(nRegenRate));
|
||||
|
||||
eFakeRegen = SetEffectSpellId(eFakeRegen, nSpellId);
|
||||
eFakeRegen = EffectLinkEffects(eVis, eFakeRegen);
|
||||
eFakeRegen = TagEffect(eFakeRegen, "REGEN_WOUNDS");
|
||||
|
||||
//:: Remove any old effect & prevent spell stacking
|
||||
PRCRemoveEffectsFromSpell(oTarget, nSpellId);
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eFakeRegen, oTarget, RoundsToSeconds(nDuration));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessageToPC(oCaster, "Regenerate Wounds only works on living creatures.");
|
||||
//:: Unset the Spell School
|
||||
PRCSetSchool();
|
||||
return;
|
||||
}
|
||||
}
|
87
nwn/nwnprc/trunk/spells/sp_speed_wind.nss
Normal file
87
nwn/nwnprc/trunk/spells/sp_speed_wind.nss
Normal file
@@ -0,0 +1,87 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: [Speed of the Wind]
|
||||
//:: [sp_speed_wind.nss]
|
||||
//:: [Yaballa: 7/9/2003]
|
||||
//:: Modified by: Jaysyn 2024-08-20 20:06:06
|
||||
//::
|
||||
//::///////////////////////////////////////////////
|
||||
/**@file Speed of the Wind
|
||||
(Masters of the Wild: A Guidebook to Barbarians, Druids, and Rangers)
|
||||
|
||||
Transmutation
|
||||
Level: Druid 2,
|
||||
Components: V, S,
|
||||
Casting Time: 1 action
|
||||
Range: Touch
|
||||
Target: Living creature touched
|
||||
Duration: 10 minutes/level
|
||||
Saving Throw: Will negates
|
||||
Spell Resistance: Yes
|
||||
|
||||
With this spell, you can grant the ephemeral quickness
|
||||
of a sudden breeze. The subject gains a +4 enhancement
|
||||
bonus to Dexterity and a -2 enhancement penalty to
|
||||
Constitution.
|
||||
*/////////////////////////////////////////////////
|
||||
#include "x2_inc_spellhook"
|
||||
|
||||
void ApplySpeedOfTheWindEffect(object oTarget, int nCasterLevel, int nMetamagic)
|
||||
{
|
||||
//:: Declare variables
|
||||
int nDuration = nCasterLevel;
|
||||
|
||||
//:: Handle metamagic
|
||||
if(nMetamagic & METAMAGIC_EXTEND)
|
||||
{
|
||||
nDuration = nDuration * 2;
|
||||
}
|
||||
//:: Set up effects
|
||||
effect eDex = EffectAbilityIncrease(ABILITY_DEXTERITY, 4);
|
||||
effect eCon = EffectAbilityDecrease(ABILITY_CONSTITUTION, 2);
|
||||
effect eVis1 = EffectVisualEffect(VFX_IMP_IMPROVE_ABILITY_SCORE);
|
||||
effect eVis2 = EffectVisualEffect(VFX_IMP_HEAD_EVIL);
|
||||
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEUTRAL);
|
||||
effect eLink = EffectLinkEffects(eDex, eCon);
|
||||
eLink = EffectLinkEffects(eLink, eDur);
|
||||
|
||||
// Add visual effects to indicate the spell's impact
|
||||
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, TurnsToSeconds(nDuration));
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis1, oTarget);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Check the Spellhook
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
//:: Set the Spell School
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
//:: Declare major variables
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = GetSpellTargetObject();
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nMetamagic = PRCGetMetaMagicFeat();
|
||||
|
||||
//:: Fire spell cast at event for target
|
||||
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, PRCGetSpellId(), FALSE));
|
||||
|
||||
//:: If the target is Undead or a Construct, exit the script
|
||||
if (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD || MyPRCGetRacialType(oTarget) == RACIAL_TYPE_CONSTRUCT)
|
||||
{
|
||||
SendMessageToPC(oCaster, "Only creatures with Constitution scores can be affected by Speed of the Wind");
|
||||
//:: Unset the Spell school
|
||||
PRCSetSchool();
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Prevent spell stacking
|
||||
PRCRemoveEffectsFromSpell(oTarget, PRCGetSpellId());
|
||||
|
||||
//:: Apply the Speed of the Wind effects to the target
|
||||
ApplySpeedOfTheWindEffect(oTarget, nCasterLevel, nMetamagic);
|
||||
|
||||
//:: Unset the Spell school
|
||||
PRCSetSchool();
|
||||
}
|
216
nwn/nwnprc/trunk/spells/sp_spiritweapon.nss
Normal file
216
nwn/nwnprc/trunk/spells/sp_spiritweapon.nss
Normal file
@@ -0,0 +1,216 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: [Spiritual Weapon]
|
||||
//:: [sp_spiritweapon.nss]
|
||||
//:: [Jaysyn 2024-08-23 07:58:14]
|
||||
//::
|
||||
//::
|
||||
//::///////////////////////////////////////////////
|
||||
/**@ Spiritual Weapon
|
||||
(Player's Handbook v.3.5, p. 283)
|
||||
|
||||
Evocation [Force]
|
||||
Level: Cleric 2, Knight of the Chalice 2, War 2, Mysticism 2,
|
||||
Components: V, S, DF,
|
||||
Casting Time: 1 standard action
|
||||
Range: Medium (100 ft. + 10 ft./level)
|
||||
Effect: Magic weapon of force
|
||||
Duration: 1 round/level (D)
|
||||
Saving Throw: None
|
||||
Spell Resistance: Yes
|
||||
|
||||
A weapon made of pure force springs into existence and attacks
|
||||
opponents at a distance, as you direct it, dealing 1d8 force
|
||||
damage per hit, +1 point per three caster levels (maximum +5
|
||||
at 15th level). The weapon takes the shape of a weapon
|
||||
favored by your deity or a weapon with some spiritual
|
||||
significance or symbolism to you (see below) and has the
|
||||
same threat range and critical multipliers as a real weapon
|
||||
of its form. It strikes the opponent you designate, starting
|
||||
with one attack in the round the spell is cast and continuing
|
||||
each round thereafter on your turn. It uses your base attack
|
||||
bonus (possibly allowing it multiple attacks per round in
|
||||
subsequent rounds) plus your Wisdom modifier as its attack
|
||||
bonus. It strikes as a spell, not as a weapon, so, for
|
||||
example, it can damage creatures that have damage
|
||||
reduction. As a force effect, it can strike incorporeal
|
||||
creatures without the normal miss chance associated with
|
||||
incorporeality. The weapon always strikes from your
|
||||
direction. It does not get a flanking bonus or help a
|
||||
combatant get one. Your feats (such as Weapon Focus)
|
||||
or combat actions (such as charge) do not affect the
|
||||
weapon. If the weapon goes beyond the spell range, if
|
||||
it goes out of your sight, or if you are not directing
|
||||
it, the weapon returns to you and hovers.
|
||||
|
||||
Each round after the first, you can use a move action to
|
||||
redirect the weapon to a new target. If you do not,
|
||||
the weapon continues to attack the previous round's
|
||||
target. On any round that the weapon switches targets,
|
||||
it gets one attack. Subsequent rounds of attacking that
|
||||
target allow the weapon to make multiple attacks if your
|
||||
base attack bonus would allow it to. Even if the spiritual
|
||||
weapon is a ranged weapon, use the spell's range, not the
|
||||
weapon's normal range increment, and switching targets
|
||||
still is a move action.
|
||||
|
||||
A spiritual weapon cannot be attacked or harmed by
|
||||
physical attacks, but dispel magic, disintegrate, a
|
||||
sphere of annihilation, or a rod of cancellation affects it.
|
||||
A spiritual weapon's AC against touch attacks is 12 (10 +
|
||||
size bonus for Tiny object).
|
||||
|
||||
If an attacked creature has spell resistance, you make a
|
||||
caster level check (1d20 + caster level) against that
|
||||
spell resistance the first time the spiritual weapon
|
||||
strikes it. If the weapon is successfully resisted, the
|
||||
spell is dispelled. If not, the weapon has its normal
|
||||
full effect on that creature for the duration of the spell.
|
||||
*///////////////////////////////////////////////////////////
|
||||
#include "x2_inc_spellhook"
|
||||
#include "inc_spirit_weapn"
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Check the Spellhook
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
//:: Set the Spell School
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
int nRunEvent = GetRunningEvent();
|
||||
|
||||
if (nRunEvent == EVENT_NPC_ONSPELLCASTAT)
|
||||
{
|
||||
// Get the caster of the spell
|
||||
object oCaster = GetLastSpellCaster();
|
||||
int nCasterLevel = GetCasterLevel(oCaster);
|
||||
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: EVENT_NPC_ONSPELLCASTAT triggered.");
|
||||
|
||||
// Get the spell ID
|
||||
int nSpellId = GetLastSpell();
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Dispel spell ID: " + IntToString(nSpellId));
|
||||
|
||||
// Check if the spell ID is a dispel spell
|
||||
if (nSpellId == SPELL_DISPEL_MAGIC || nSpellId == SPELL_LESSER_DISPEL || nSpellId == SPELL_GREATER_DISPELLING || nSpellId == SPELL_MORDENKAINENS_DISJUNCTION
|
||||
|| nSpellId == SPELL_SLASHING_DISPEL || nSpellId == SPELL_DISPELLING_TOUCH || nSpellId == SPELL_PIXIE_DISPEL || nSpellId == SPELL_GREAT_WALL_OF_DISPEL)
|
||||
{
|
||||
// Get the target of the spell
|
||||
object oTarget = OBJECT_SELF;
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Spell targeted at: " + GetName(oTarget));
|
||||
|
||||
// Check if the target is OBJECT_SELF
|
||||
if (oTarget == OBJECT_SELF)
|
||||
{
|
||||
// Retrieve the original caster of the Spiritual Weapon spell from oSummon
|
||||
object oSummon = OBJECT_SELF;
|
||||
object oOriginalCaster = GetLocalObject(oSummon, "MY_CASTER");
|
||||
|
||||
// Ensure oOriginalCaster is valid
|
||||
if (GetIsObjectValid(oOriginalCaster))
|
||||
{
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Original caster found. Caster level: " + IntToString(GetCasterLevel(oOriginalCaster)));
|
||||
|
||||
// Determine the DC for the dispel check
|
||||
int nDispelDC = 11 + GetCasterLevel(oOriginalCaster);
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Dispel DC: " + IntToString(nDispelDC));
|
||||
|
||||
// Determine the maximum cap for the dispel check
|
||||
int nDispelCap = 0;
|
||||
if (nSpellId == SPELL_LESSER_DISPEL)
|
||||
nDispelCap = 5;
|
||||
else if (nSpellId == SPELL_DISPEL_MAGIC || nSpellId == SPELL_SLASHING_DISPEL || nSpellId == SPELL_DISPELLING_TOUCH || nSpellId == SPELL_PIXIE_DISPEL || nSpellId == INVOKE_VORACIOUS_DISPELLING)
|
||||
nDispelCap = 10;
|
||||
else if (nSpellId == SPELL_GREATER_DISPELLING || nSpellId == SPELL_GREAT_WALL_OF_DISPEL)
|
||||
nDispelCap = 15;
|
||||
else if (nSpellId == SPELL_MORDENKAINENS_DISJUNCTION)
|
||||
nDispelCap = 0; // No cap for Disjunction
|
||||
|
||||
// Roll for the dispel check
|
||||
int nDispelRoll = d20();
|
||||
int nCappedCasterLevel = nCasterLevel;
|
||||
|
||||
if (nDispelCap > 0 && nCasterLevel > nDispelCap)
|
||||
nCappedCasterLevel = nDispelCap;
|
||||
|
||||
nDispelRoll += nCappedCasterLevel;
|
||||
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Dispel roll: " + IntToString(nDispelRoll) + " (Caster Level: " + IntToString(nCappedCasterLevel) + ", Cap: " + IntToString(nDispelCap) + ")");
|
||||
|
||||
// Compare the dispel result to the DC
|
||||
if (nDispelRoll >= nDispelDC)
|
||||
{
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Dispel check succeeded.");
|
||||
|
||||
// Dispel succeeded, destroy oSummon and the item in its right hand
|
||||
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oSummon);
|
||||
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Dispel Magic succeeded. Destroying Spiritual Weapon and its right hand item.");
|
||||
|
||||
// Set flags and destroy objects with delays
|
||||
SetPlotFlag(oWeapon, FALSE);
|
||||
SetPlotFlag(oSummon, FALSE);
|
||||
SetImmortal(oSummon, FALSE);
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_DISPEL), oSummon);
|
||||
|
||||
// Destroy the weapon and summon with delays
|
||||
if (GetIsObjectValid(oWeapon))
|
||||
{
|
||||
DelayCommand(0.5f, DestroyObject(oWeapon));
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Spiritual Weapon destruction scheduled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: No weapon found in right hand.");
|
||||
}
|
||||
|
||||
DelayCommand(1.0f, DestroyObject(oSummon));
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Spiritual Weapon Summon destruction scheduled.");
|
||||
}
|
||||
else
|
||||
{
|
||||
RegisterSummonEvents(oSummon);
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Dispel check failed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DEBUG) DoDebug("sp_spiritweapon: Original caster not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//:: Declare major variables
|
||||
object oCaster = OBJECT_SELF;
|
||||
location lTarget = PRCGetSpellTargetLocation();
|
||||
int nClass = PRCGetLastSpellCastClass();
|
||||
int nDuration = PRCGetCasterLevel(oCaster);
|
||||
int nSwitch = GetPRCSwitch(PRC_SUMMON_ROUND_PER_LEVEL);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
|
||||
effect eSummon = EffectSummonCreature("prc_spirit_weapn");
|
||||
effect eVis = EffectVisualEffect(1200); //:: VFX_FNF_STRIKE_HOLY_SILENT
|
||||
|
||||
if(nDuration < 1)
|
||||
nDuration = 1;
|
||||
|
||||
//:: Make metamagic check for extend
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
nDuration *= 2; //Duration is +100%
|
||||
|
||||
float fDuration = nSwitch ? RoundsToSeconds(nDuration * nSwitch):
|
||||
TurnsToSeconds(nDuration);
|
||||
|
||||
//:: Apply the VFX impact and summon effect
|
||||
MultisummonPreSummon();
|
||||
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, lTarget, fDuration);
|
||||
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, lTarget);
|
||||
|
||||
DelayCommand(1.0, CreateSpiritualWeapon(oCaster, fDuration, nClass));
|
||||
|
||||
//:: Unset the Spell school
|
||||
PRCSetSchool();
|
||||
}
|
134
nwn/nwnprc/trunk/spells/sp_spiritworm.nss
Normal file
134
nwn/nwnprc/trunk/spells/sp_spiritworm.nss
Normal file
@@ -0,0 +1,134 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: [Spirit Worm]
|
||||
//:: [sp_spiritworm.nss]
|
||||
//:: [Jaysyn - PRC8 2024-08-20 20:42:32]
|
||||
//::
|
||||
//::
|
||||
//::///////////////////////////////////////////////
|
||||
/**@file Spirit Worm
|
||||
(Spell Compendium, p. 202)
|
||||
|
||||
Necromancy
|
||||
Level: Sorcerer 1, Wizard 1,
|
||||
Components: V, S, M,
|
||||
Casting Time: 1 standard action
|
||||
Range: Touch
|
||||
Target: Living creature touched
|
||||
Duration: 1 round/level, up to 5 rounds; see text
|
||||
Saving Throw: Fortitude negates; see text
|
||||
Spell Resistance: Yes
|
||||
|
||||
You press the bit of blackened bone against your
|
||||
foe and intone the spell. The bone vanishes,
|
||||
leaving a mottled bruise where it touched.
|
||||
|
||||
You create a lingering decay in the spirit and
|
||||
body of the target. If the target fails its saving
|
||||
throw, it takes 1 point of Constitution damage each
|
||||
round while the spell lasts (maximum 5 points).
|
||||
The victim can attempt a Fortitude saving throw
|
||||
each round, and success negates the Constitution
|
||||
damage for that round and ends the spell.
|
||||
|
||||
Material Component: A piece of fire-blackened
|
||||
ivory or bone carved in the shape of a segmented
|
||||
worm.
|
||||
*/////////////////////////////////////////////////
|
||||
#include "prc_inc_sp_tch"
|
||||
#include "prc_add_spell_dc"
|
||||
|
||||
void SpiritWormDamage(object oTarget, object oCaster, int nDuration, int nMetaMagic, int nSpellID)
|
||||
{
|
||||
//:: Exit if the target is dead or duration has expired
|
||||
if (GetIsDead(oTarget) || nDuration <= 0)
|
||||
return;
|
||||
|
||||
//:: Calculate caster level and spell penetration
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nPenetr = nCasterLevel + SPGetPenetr();
|
||||
|
||||
//:: Check for spell resistance
|
||||
if (!PRCDoResistSpell(oCaster, oTarget, nPenetr))
|
||||
{
|
||||
//:: Calculate Fortitude Save DC
|
||||
int nFortSaveDC = PRCGetSpellSaveDC(nSpellID, -1, oCaster);
|
||||
int bSuccess = FortitudeSave(oTarget, nFortSaveDC, SAVING_THROW_TYPE_NEGATIVE, oCaster);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
//:: Apply Constitution Damage
|
||||
effect eDamage = EffectAbilityDecrease(ABILITY_CONSTITUTION, 1);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget);
|
||||
|
||||
//:: Reduce duration and apply damage in the next round
|
||||
nDuration--;
|
||||
DelayCommand(6.0f, SpiritWormDamage(oTarget, oCaster, nDuration, nMetaMagic, nSpellID));
|
||||
}
|
||||
else
|
||||
{
|
||||
//:: Indicate successful save
|
||||
effect eSuccess = EffectVisualEffect(VFX_IMP_FORTITUDE_SAVING_THROW_USE);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eSuccess, oTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Check the Spellhook
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
//:: Set the Spell School
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
//:: Declare major variables
|
||||
int nSpellID = PRCGetSpellId();
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
|
||||
int nCasterLvl = PRCGetCasterLevel(oCaster);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
int nPenetr = nCasterLvl + SPGetPenetr();
|
||||
int nDuration = nCasterLvl;
|
||||
|
||||
//:: Limit the duration to a maximum of 5 rounds
|
||||
if (nDuration > 5) nDuration = 5;
|
||||
if (nMetaMagic & METAMAGIC_EXTEND)
|
||||
nDuration *= 2;
|
||||
|
||||
//:: Only affect hostile targets
|
||||
if (!GetIsReactionTypeFriendly(oTarget, oCaster))
|
||||
{
|
||||
SignalEvent(oTarget, EventSpellCastAt(oCaster, nSpellID));
|
||||
|
||||
//:: Calculate Fortitude Save DC
|
||||
int nFortSaveDC = PRCGetSpellSaveDC(nSpellID, -1, oCaster);
|
||||
int bSuccess = FortitudeSave(oTarget, nFortSaveDC, SAVING_THROW_TYPE_NEGATIVE, oCaster);
|
||||
|
||||
if (bSuccess)
|
||||
{
|
||||
//:: Indicate successful save
|
||||
effect eSuccess = EffectVisualEffect(VFX_IMP_FORTITUDE_SAVING_THROW_USE);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eSuccess, oTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
//:: Check for spell resistance
|
||||
if (!PRCDoResistSpell(oCaster, oTarget, nPenetr))
|
||||
{
|
||||
//:: Setup initial visual effect
|
||||
effect eVis = EffectVisualEffect(VFX_IMP_NEGATIVE_ENERGY);
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
|
||||
|
||||
//:: Prevent spell stacking
|
||||
PRCRemoveEffectsFromSpell(oTarget, PRCGetSpellId());
|
||||
|
||||
//:: Apply Constitution Damage Per Round
|
||||
SpiritWormDamage(oTarget, oCaster, nDuration, nMetaMagic, nSpellID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//:: Unset the Spell School
|
||||
PRCSetSchool();
|
||||
}
|
123
nwn/nwnprc/trunk/spells/sp_tortoiseshell.nss
Normal file
123
nwn/nwnprc/trunk/spells/sp_tortoiseshell.nss
Normal file
@@ -0,0 +1,123 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: [Tortoise Shell]
|
||||
//:: [sp_tortiseshell.nss]
|
||||
//:: [Jaysyn 2024-08-20 22:12:12]
|
||||
//::
|
||||
//::///////////////////////////////////////////////
|
||||
/**@file Tortoise Shell
|
||||
(Spell Compendium, p. 221)
|
||||
|
||||
Transmutation
|
||||
Level: Druid 6,
|
||||
Components: V, S, DF,
|
||||
Casting Time: 1 standard action
|
||||
Range: Touch
|
||||
Target: Living creature touched
|
||||
Duration: 10 minutes/level
|
||||
Saving Throw: None
|
||||
Spell Resistance: Yes (harmless)
|
||||
|
||||
In the blink of an eye, the creature you touched
|
||||
grows the armor plating of a tortoise across its
|
||||
torso and a tough, leathery skin elsewhere.
|
||||
|
||||
Tortoise shell grants a +6 enhancement bonus to
|
||||
the subject's existing natural armor bonus. This
|
||||
enhancement bonus increases by 1 for every three
|
||||
caster levels beyond 11th, to a maximum of +9 at
|
||||
20th level.
|
||||
|
||||
The enhancement bonus provided by tortoise shell
|
||||
stacks with the target's natural armor bonus, but
|
||||
not with other enhancement bonuses to natural
|
||||
armor. A creature without natural armor has an
|
||||
effective natural armor of +0, much as a character
|
||||
wearing only normal clothing has an armor bonus of
|
||||
+0.
|
||||
|
||||
Tortoise shell slows a creature's movement as if
|
||||
it were wearing heavy armor. An elf subject to
|
||||
tortoise shell, for example, would have a speed
|
||||
of 20 feet and could run only 60 feet per round.
|
||||
The spell affects only a creature's speed; tortoise
|
||||
shell doesn't carry an armor check penalty or an
|
||||
arcane spell failure chance.
|
||||
*/////////////////////////////////////////////////
|
||||
#include "x2_inc_spellhook"
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Check the Spellhook
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
//:: Set the Spell School
|
||||
PRCSetSchool(GetSpellSchool(PRCGetSpellId()));
|
||||
|
||||
//:: Declare major variables
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
|
||||
//:: Prevent spell stacking
|
||||
PRCRemoveEffectsFromSpell(oTarget, PRCGetSpellId());
|
||||
|
||||
//:: Get the caster's level and check for Extend Spell feat
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
|
||||
//:: Calculate the enhancement bonus
|
||||
int nBonus = 6 + (nCasterLevel > 11 ? (nCasterLevel - 11) / 3 : 0);
|
||||
nBonus = nBonus > 9 ? 9 : nBonus; // Max bonus is +9
|
||||
|
||||
//:: Initialize existing natural armor bonus
|
||||
int nExistingNaturalArmor = 0;
|
||||
|
||||
//:: Check for items in inventory that provide Natural AC bonus
|
||||
object oItem = GetItemInSlot(INVENTORY_SLOT_NECK, oTarget);
|
||||
if (GetIsObjectValid(oItem))
|
||||
{
|
||||
//:: Directly get the Armor Class value from the item
|
||||
int nItemAC = GetItemACValue(oItem);
|
||||
if (nItemAC > nExistingNaturalArmor)
|
||||
{
|
||||
nExistingNaturalArmor = nItemAC;
|
||||
}
|
||||
}
|
||||
|
||||
//:: Calculate the final bonus to apply
|
||||
int nFinalBonus = nBonus - nExistingNaturalArmor;
|
||||
if (nFinalBonus < 0) nFinalBonus = 0; // Ensure no negative bonus
|
||||
|
||||
//:: Determine the base duration of the effects (10 minutes per caster level)
|
||||
float fBaseDuration = TurnsToSeconds(10 * nCasterLevel);
|
||||
//:: Check if the caster has the Extend Spell feat
|
||||
float fDuration = (nMetaMagic & METAMAGIC_EXTEND) ? fBaseDuration * 2.0 : fBaseDuration;
|
||||
|
||||
//:: Setup the natural armor effect
|
||||
effect eNaturalArmor = EffectACIncrease(nFinalBonus);
|
||||
|
||||
//:: Setup the movement speed penalty effect
|
||||
//:: Normal speed is 30 feet per round, spell reduces to 20 feet per round (1/3 slower)
|
||||
int nSpeedDecreasePercent = 33; // Percentage to slow the movement speed
|
||||
effect eSlow = EffectMovementSpeedDecrease(nSpeedDecreasePercent);
|
||||
|
||||
//:: Create the visual effects
|
||||
effect eVFXNaturalArmor = EffectVisualEffect(VFX_IMP_HEAD_NATURE);
|
||||
effect eVFXMovementSpeed = EffectVisualEffect(VFX_IMP_SLOW);
|
||||
effect eVFXACBonus = EffectVisualEffect(VFX_IMP_AC_BONUS);
|
||||
effect eVFXBarkskin = EffectVisualEffect(VFX_DUR_PROT_BARKSKIN);
|
||||
|
||||
//:: Combine primary effects
|
||||
effect eLink = EffectLinkEffects(eNaturalArmor, eSlow);
|
||||
eLink = EffectLinkEffects(eLink, eVFXBarkskin);
|
||||
|
||||
//:: Apply the primary effects with duration
|
||||
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDuration);
|
||||
|
||||
//:: Apply visual effects instantly
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVFXNaturalArmor, oTarget);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVFXMovementSpeed, oTarget);
|
||||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVFXACBonus, oTarget);
|
||||
|
||||
//:: Unset the Spell school
|
||||
PRCSetSchool();
|
||||
}
|
Reference in New Issue
Block a user