212 lines
8.4 KiB
Plaintext
212 lines
8.4 KiB
Plaintext
|
//::///////////////////////////////////////////////
|
||
|
//:: Name Rainbow Blast
|
||
|
//:: FileName sp_rainbow_blast.nss
|
||
|
//:://////////////////////////////////////////////
|
||
|
/**@file Rainbow Blast
|
||
|
Evocation [Light]
|
||
|
Level: Sorcerer/wizard 3
|
||
|
Components: V, S, M
|
||
|
Casting Time: 1 standard action
|
||
|
Range: 120 ft.
|
||
|
Area: 120-ft. line
|
||
|
Duration: Instantaneous
|
||
|
Saving Throw: Reflex half
|
||
|
Spell Resistance: Yes
|
||
|
|
||
|
This spell is a wide-spectrum blast of
|
||
|
radiant energy composed of all five
|
||
|
energy types. Rainbow blast deals 1d6
|
||
|
points of damage from each of the five
|
||
|
energy types (acid, cold, electricity,
|
||
|
fire, and sonic), for a total of 5d6 points
|
||
|
of damage. Creatures apply resistance
|
||
|
to energy separately for each type of
|
||
|
damage.
|
||
|
As you gain in levels, the damage
|
||
|
die increases in size. At 7th level the
|
||
|
spell deals 5d8 points of damage, at 9th
|
||
|
level it deals 5d10 points of damage,
|
||
|
and at 11th level it deals 5d12 points of
|
||
|
damage; one die for each of the five
|
||
|
energy types.
|
||
|
Focus: A small clear gem or crystal
|
||
|
prism worth at least 50 gp.
|
||
|
|
||
|
Author: Tenjac
|
||
|
Created: 6/28/07
|
||
|
*/
|
||
|
//:://////////////////////////////////////////////
|
||
|
//:://////////////////////////////////////////////
|
||
|
|
||
|
#include "prc_inc_spells"
|
||
|
#include "spinc_bolt"
|
||
|
|
||
|
int GetDieType(int nCasterLevel)
|
||
|
{
|
||
|
|
||
|
if(nCasterLevel > 20) return 22;
|
||
|
if(nCasterLevel > 18) return 20;
|
||
|
if(nCasterLevel > 16) return 18;
|
||
|
if(nCasterLevel > 14) return 16;
|
||
|
if(nCasterLevel > 12) return 14;
|
||
|
if(nCasterLevel > 10) return 12;
|
||
|
if(nCasterLevel > 8) return 10;
|
||
|
if(nCasterLevel > 6) return 8;
|
||
|
return 6;
|
||
|
}
|
||
|
|
||
|
void DoBoltVFX(location lCaster, location lTarget)
|
||
|
{
|
||
|
// Do VFX. This is moderately heavy, so it isn't duplicated by Twin Power
|
||
|
float fAngle = GetRelativeAngleBetweenLocations(lCaster, lTarget);
|
||
|
float fRadius = FeetToMeters(5.0f);
|
||
|
float fVFXLength = GetVFXLength(lCaster, 36.6f, GetRelativeAngleBetweenLocations(lCaster, lTarget));
|
||
|
// A tube of beams, radius 5ft, starting 1m from manifester and running for the length of the line
|
||
|
BeamGengon(DURATION_TYPE_TEMPORARY, VFX_BEAM_MIND, lCaster, fRadius, fRadius,
|
||
|
1.0f, fVFXLength, // Start 1m from the manifester, end at LOS end
|
||
|
8, // 8 sides
|
||
|
4.5f, "prc_invisobj",
|
||
|
0.0f, // Drawn instantly
|
||
|
0.0f, 0.0f, 45.0f, "y", fAngle, 0.0f,
|
||
|
-1, -1, 0.0f, 1.0f, // No secondary VFX
|
||
|
4.5f
|
||
|
);
|
||
|
}
|
||
|
|
||
|
void main()
|
||
|
{
|
||
|
if(!X2PreSpellCastCode()) return;
|
||
|
|
||
|
PRCSetSchool(SPELL_SCHOOL_EVOCATION);
|
||
|
|
||
|
object oCaster = OBJECT_SELF;
|
||
|
location lTarget = PRCGetSpellTargetLocation();
|
||
|
location lCaster = GetLocation(OBJECT_SELF);
|
||
|
vector vOrigin = GetPosition(OBJECT_SELF);
|
||
|
|
||
|
int nCasterLevel = PRCGetCasterLevel();
|
||
|
int nPenetr = nCasterLevel + SPGetPenetr();
|
||
|
int nDieSides = GetDieType(nCasterLevel);
|
||
|
|
||
|
DoBoltVFX(lCaster, lTarget);
|
||
|
|
||
|
int nDamage;
|
||
|
int nSaveDC;
|
||
|
float fDelay;
|
||
|
|
||
|
|
||
|
// individual effect
|
||
|
effect eDamage;
|
||
|
|
||
|
// spell damage effects
|
||
|
// Loop over targets in the spell shape
|
||
|
object oTarget = MyFirstObjectInShape(SHAPE_SPELLCYLINDER, 36.6f, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, vOrigin);
|
||
|
while(GetIsObjectValid(oTarget))
|
||
|
{
|
||
|
if(oTarget != oCaster && spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oCaster))
|
||
|
{
|
||
|
// Let the AI know
|
||
|
PRCSignalSpellEvent(oTarget, TRUE, SPELL_RAINBOW_BLAST, oCaster);
|
||
|
|
||
|
// Make an SR check
|
||
|
if(!PRCDoResistSpell(oCaster, oTarget, nPenetr))
|
||
|
{
|
||
|
nSaveDC = PRCGetSaveDC(oTarget, OBJECT_SELF);
|
||
|
|
||
|
fDelay = GetDistanceBetweenLocations(lCaster, GetLocation(oTarget)) / 20.0f;
|
||
|
|
||
|
// Roll fire damage
|
||
|
nDamage = PRCGetMetaMagicDamage(DAMAGE_TYPE_FIRE, 1, nDieSides);
|
||
|
// Adjust damage according to Reflex Save, Evasion or Improved Evasion
|
||
|
nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_FIRE);
|
||
|
if(nDamage > 0)
|
||
|
{
|
||
|
eDamage = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_FIRE);
|
||
|
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
||
|
DelayCommand(1.0f + fDelay, PRCBonusDamage(oTarget));
|
||
|
DelayCommand(1.0f + fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FLAME_S), oTarget));
|
||
|
}// end if - There was still damage remaining to be dealt after adjustments
|
||
|
|
||
|
// Roll acid damage
|
||
|
nDamage = PRCGetMetaMagicDamage(DAMAGE_TYPE_ACID, 1, nDieSides);
|
||
|
// Adjust damage according to Reflex Save, Evasion or Improved Evasion
|
||
|
nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_ACID);
|
||
|
if(nDamage > 0)
|
||
|
{
|
||
|
eDamage = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_ACID);
|
||
|
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
||
|
DelayCommand(1.0f + fDelay, PRCBonusDamage(oTarget));
|
||
|
DelayCommand(1.0f + fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_ACID_S), oTarget));
|
||
|
}// end if - There was still damage remaining to be dealt after adjustments
|
||
|
|
||
|
// Roll cold damage
|
||
|
nDamage = PRCGetMetaMagicDamage(DAMAGE_TYPE_COLD, 1, nDieSides);
|
||
|
// Cold has a fort save for half
|
||
|
if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_COLD))
|
||
|
{
|
||
|
if (GetHasMettle(oTarget, SAVING_THROW_FORT))
|
||
|
nDamage = 0;
|
||
|
nDamage /= 2;
|
||
|
}
|
||
|
|
||
|
if(nDamage > 0)
|
||
|
{
|
||
|
eDamage = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_COLD);
|
||
|
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
||
|
DelayCommand(1.0f + fDelay, PRCBonusDamage(oTarget));
|
||
|
DelayCommand(1.0f + fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FROST_S), oTarget));
|
||
|
}// end if - There was still damage remaining to be dealt after adjustments
|
||
|
|
||
|
// Roll electrical damage
|
||
|
nDamage = PRCGetMetaMagicDamage(DAMAGE_TYPE_ELECTRICAL, 1, nDieSides);
|
||
|
// Adjust damage according to Reflex Save, Evasion or Improved Evasion
|
||
|
nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_ELECTRICITY);
|
||
|
if(nDamage > 0)
|
||
|
{
|
||
|
eDamage = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_ELECTRICAL);
|
||
|
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
||
|
DelayCommand(1.0f + fDelay, PRCBonusDamage(oTarget));
|
||
|
DelayCommand(1.0f + fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_LIGHTNING_S), oTarget));
|
||
|
}// end if - There was still damage remaining to be dealt after adjustments
|
||
|
|
||
|
// Roll sonic damage
|
||
|
nDamage = PRCGetMetaMagicDamage(DAMAGE_TYPE_SONIC, 1, nDieSides);
|
||
|
// Adjust damage according to Reflex Save, Evasion or Improved Evasion
|
||
|
nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_SONIC);
|
||
|
if(nDamage > 0)
|
||
|
{
|
||
|
eDamage = PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_SONIC);
|
||
|
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
||
|
DelayCommand(1.0f + fDelay, PRCBonusDamage(oTarget));
|
||
|
DelayCommand(1.0f + fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_SONIC), oTarget));
|
||
|
}// end if - There was still damage remaining to be dealt after adjustments
|
||
|
}// end if - SR check
|
||
|
}// end if - Target validity check
|
||
|
|
||
|
// Get next target
|
||
|
oTarget = MyNextObjectInShape(SHAPE_SPELLCYLINDER, 36.6f, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, vOrigin);
|
||
|
}// end while - Target loop
|
||
|
|
||
|
PRCSetSchool();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|