PRC8_fork/trunk/smp/smp_s_chainlight.nss

208 lines
7.8 KiB
Plaintext
Raw Normal View History

/*:://////////////////////////////////////////////
//:: Spell Name Chain Lightning
//:: Spell FileName SMP_S_ChainLight
//:://////////////////////////////////////////////
//:: In Game Spell desctiption
//:://////////////////////////////////////////////
Evocation [Electricity]
Level: Air 6, Sor/Wiz 6
Components: V, S, F
Casting Time: 1 standard action
Range: Long (40M)
Targets: One primary target, plus one secondary target/level, within a 10M radius.
Enemies only, Creatures first.
Duration: Instantaneous
Saving Throw: Reflex half
Spell Resistance: Yes
This spell creates an electrical discharge that begins as a single stroke
commencing from your fingertips. Unlike lightning bolt, chain lightning
strikes one object or creature initially, then arcs to other targets.
The bolt deals 1d6 points of electricity damage per caster level (maximum
20d6) to the primary target. After it strikes, lightning can arc to a number
of secondary targets equal to your caster level (maximum 20). The secondary
bolts each strike one target and deal half as much damage as the primary one
did (rounded down).
Each target can attempt a Reflex saving throw for half damage. You choose
secondary targets as you like, but they must all be within 30 feet of the
primary target, and no target can be struck more than once. You can choose
to affect fewer secondary targets than the maximum.
Focus: A bit of fur; a piece of amber, glass, or a crystal rod; plus one
silver pin for each of your caster levels.
//:://////////////////////////////////////////////
//:: Spell Effects Applied / Notes
//:://////////////////////////////////////////////
Say, 20d6 to primary target, it'd be 10d6 to all secondary ones.
As spell, mainly copied a bit from bioware as its the same way Id to it.
Note that it has more "advanced" targeting: if we target a door, all doors
in the area are hit before other things, while the same is in the case of
placables and creatures.
//:://////////////////////////////////////////////
//:: Created By: Jasperre
//::////////////////////////////////////////////*/
#include "SMP_INC_SPELLS"
// ZZaaapp! Returns the total targets affected of nTargetType's.
int ChainLightningTargets(location lTarget, float fDelay, int nDice, int nMetaMagic, object oCaster, int nSpellSaveDC, int nLimit, int nTargetTypes, object oFirstTarget);
void main()
{
// Spell Hook Check.
if(!SMP_SpellHookCheck()) return;
// Declare major variables
object oCaster = OBJECT_SELF;
object oFirstTarget = GetSpellTargetObject();
location lTarget = GetLocation(oFirstTarget);
int nCasterLevel = SMP_GetCasterLevel();
int nSpellSaveDC = SMP_GetSpellSaveDC();
int nDice = SMP_LimitInteger(nCasterLevel, 20);
int nMetaMagic = SMP_GetMetaMagicFeat();
int nTotalSecondaryAffected;
// Delay increases by 0.1/target, from 0.0
float fDelay = 0.0;
// Declare effects
int nDam;
effect eLightningBeam = EffectBeam(VFX_BEAM_LIGHTNING, oCaster, BODY_NODE_HAND);
effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S);
// Initial target damage
if(GetIsObjectValid(oFirstTarget) && GetIsReactionTypeHostile(oFirstTarget) &&
!GetFactionEqual(oFirstTarget))
{
// Apply lightning effect
SMP_ApplyDuration(oFirstTarget, eLightningBeam, 0.5);
// Signal spell cast at
SMP_SignalSpellCastAt(oFirstTarget, SMP_SPELL_CHAIN_LIGHTNING);
// Spell Resistance and Immunity check
if(!SMP_SpellResistanceCheck(oCaster, oFirstTarget, fDelay))
{
// New damage
nDam = SMP_MaximizeOrEmpower(6, nDice, nMetaMagic);
// Reflex save
nDam = SMP_GetAdjustedDamage(SAVING_THROW_REFLEX, nDam, oFirstTarget, nSpellSaveDC, SAVING_THROW_TYPE_ELECTRICITY, oCaster);
// Apply damage if any
if(nDam > 0)
{
DelayCommand(fDelay, SMP_ApplyDamageVFXToObject(oFirstTarget, eVis, nDam, DAMAGE_TYPE_ELECTRICAL));
}
}
}
else
{
// Stop if it can't work (PvP, etc)
return;
}
// Now, we target all of that object type
int nTargetType = GetObjectType(oFirstTarget);
// Round dice by half
nDice = SMP_LimitInteger(nDice/2, 10);
// Do first one
int nRemaining = ChainLightningTargets(lTarget, fDelay, nDice, nMetaMagic, oCaster, nSpellSaveDC, nCasterLevel, nTargetType, oFirstTarget);
// If no targets left, stop
if(nRemaining <= 0) return;
// Next, do the other 2 at once!
if(nTargetType == OBJECT_TYPE_CREATURE)
{
nTargetType = OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE;
}
else if(nTargetType == OBJECT_TYPE_DOOR)
{
nTargetType = OBJECT_TYPE_CREATURE | OBJECT_TYPE_PLACEABLE;
}
else //if(nTargetType == OBJECT_TYPE_PLACEABLE)
{
nTargetType = OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR;
}
// New loop of remaining targets, up to nRemaining
ChainLightningTargets(lTarget, fDelay, nDice, nMetaMagic, oCaster, nSpellSaveDC, nRemaining, nTargetType, oFirstTarget);
}
int ChainLightningTargets(location lTarget, float fDelay, int nDice, int nMetaMagic, object oCaster, int nSpellSaveDC, int nLimit, int nTargetTypes, object oFirstTarget)
{
// Total affected can be up to nLimit.
int nTotalSecondaryAffected = FALSE;
// Declare effects
effect eVis = EffectVisualEffect(VFX_IMP_LIGHTNING_S);
// No sound
effect eLightningBeam = EffectBeam(VFX_BEAM_SILENT_LIGHTNING, oFirstTarget, BODY_NODE_CHEST);
// Note: eLightningBeam will be silent every other beam, to lessen the
// impact of it's sounds firing.
int bBeam = FALSE;// When TRUE.
// Damage
int nDam;
// Get objects with nTargetTypes as variable. 10M
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, TRUE, nTargetTypes);
while(GetIsObjectValid(oTarget) && nTotalSecondaryAffected <= nLimit)
{
// Faction check - Cannot hit original target neither
if(oTarget != oFirstTarget && GetIsReactionTypeHostile(oTarget) &&
!GetFactionEqual(oTarget))
{
// Visual effect of lightning for a short duration
DelayCommand(fDelay, SMP_ApplyDuration(oTarget, eLightningBeam, 0.5));
// Signal spell cast at event
SMP_SignalSpellCastAt(oTarget, SMP_SPELL_CHAIN_LIGHTNING);
// Spell Resistance and Immunity check
if(!SMP_SpellResistanceCheck(oCaster, oTarget, fDelay))
{
// New damage
nDam = SMP_MaximizeOrEmpower(6, nDice, nMetaMagic);
// Reflex save
nDam = SMP_GetAdjustedDamage(SAVING_THROW_REFLEX, nDam, oFirstTarget, nSpellSaveDC, SAVING_THROW_TYPE_ELECTRICITY, oCaster);
// Apply damage if any
if(nDam > 0)
{
DelayCommand(fDelay, SMP_ApplyDamageVFXToObject(oTarget, eVis, nDam, DAMAGE_TYPE_ELECTRICAL));
}
}
// Make the lightning beam effect start from oTarget now
// - Remember bBeam!
if(bBeam == TRUE)
{
// LOUD
eLightningBeam = EffectBeam(VFX_BEAM_LIGHTNING, oTarget, BODY_NODE_CHEST);
bBeam = FALSE;
}
else //if(bBeam == FALSE)
{
// No sound
eLightningBeam = EffectBeam(VFX_BEAM_SILENT_LIGHTNING, oTarget, BODY_NODE_CHEST);
bBeam = TRUE;
}
// Increase delay by 0.1.
fDelay += 0.1;
// Increase targets by 1
nTotalSecondaryAffected++;
}
// Next in 10M
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_COLOSSAL, lTarget, TRUE, nTargetTypes);
}
return nTotalSecondaryAffected;
}