PRC8/nwn/nwnprc/trunk/newspellbook/true_brim_tongue.nss
Jaysyn904 6ec137a24e Updated AMS marker feats
Updated AMS marker feats.  Removed arcane & divine marker feats.  Updated Dread Necromancer for epic progression. Updated weapon baseitem models.  Updated new weapons for crafting & npc equip.
 Updated prefix.  Updated release archive.
2024-02-11 14:01:05 -05:00

151 lines
6.1 KiB
Plaintext

/*
----------------
Tongue of Fire
Brimstone Speaker level 1
true_brim_tongue
----------------
19/7/06 by Stratovarius
*/ /** @file
Type of Feat: Class
Prerequisite: Brimstone Speaker 1
Specifics: The Brimstone Speaker can speak a truename that translates as "tongue of fire". This ability allows them to create a line of fire 20 feet long. Those hit by the fire have a DC vs 10 + Class levels + Con modifier. There are three versions of the Tongue of Fire: 3d6 with a Truespeak DC of 25, 5d6 with a DC of 30, and 8d6 with a DC of 35. This ability is affected by the Law of Resistance.
Use: Selected.
*/
#include "true_inc_trufunc"
//#include "prc_alterations"
float GetVFXLength(location lTrueSpeaker, float fLength, float fAngle);
void main()
{
object oTrueSpeaker = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
int nSpellId = PRCGetSpellId();
int nDC;
int nDamage;
if (BRIMSTONE_FIRE_3D6 == nSpellId)
{
nDC = 25;
nDamage = d6(3);
}
else if (BRIMSTONE_FIRE_5D6 == nSpellId)
{
nDC = 30;
nDamage = d6(5);
}
else if (BRIMSTONE_FIRE_8D6 == nSpellId)
{
nDC = 35;
nDamage = d6(8);
}
//Account for Energy Draconic Aura
if (GetLocalInt(oTrueSpeaker, "FireEnergyAura") > 0)
{
nDC += GetLocalInt(oTrueSpeaker, "FireEnergyAura");
}
// Account for the law of resistance
nDC += GetLawOfResistanceDCIncrease(oTrueSpeaker, nSpellId);
if(GetIsSkillSuccessful(oTrueSpeaker, SKILL_TRUESPEAK, nDC))
{
int nSaveDC = 10 + GetLevelByClass(CLASS_TYPE_BRIMSTONE_SPEAKER, oTrueSpeaker) + GetAbilityModifier(ABILITY_CONSTITUTION, oTrueSpeaker);
// Increases the DC of the subsequent utterances
DoLawOfResistanceDCIncrease(oTrueSpeaker, nSpellId);
location lTrueSpeaker = GetLocation(oTrueSpeaker);
location lTarget = PRCGetSpellTargetLocation();
vector vOrigin = GetPosition(oTrueSpeaker);
float fLength = FeetToMeters(20.0f);
float fDelay;
// Do VFX. This is moderately heavy, so it isn't duplicated by Twin Power
float fAngle = GetRelativeAngleBetweenLocations(lTrueSpeaker, lTarget);
float fSpiralStartRadius = FeetToMeters(1.0f);
float fRadius = FeetToMeters(5.0f);
float fDuration = 4.5f;
float fVFXLength = GetVFXLength(lTrueSpeaker, fLength, GetRelativeAngleBetweenLocations(lTrueSpeaker, lTarget));
// A tube of beams, radius 5ft, starting 1m from TrueSpeaker and running for the length of the line
BeamGengon(DURATION_TYPE_TEMPORARY, VFX_BEAM_FIRE, lTrueSpeaker, fRadius, fRadius,
1.0f, fVFXLength, // Start 1m from the TrueSpeaker, end at LOS end
8, // 8 sides
fDuration, "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
fDuration
);
// A spiral inside the tube, starting from the TrueSpeaker with with radius 1ft and ending with radius 5ft at the end of the line
BeamPolygonalSpring(DURATION_TYPE_TEMPORARY, VFX_BEAM_FIRE, lTrueSpeaker, fSpiralStartRadius, fRadius,
0.0f, fVFXLength, // Start at the TrueSpeaker, end at LOS end
5, // 5 sides per revolution
fDuration, "prc_invisobj",
fVFXLength / 5, // Revolution per 5 meters
0.0f, // Drawn instantly
0.0f, "y", fAngle, 0.0f,
-1, -1, 0.0f, 1.0f, // No secondary VFX
fDuration
);
oTarget = MyFirstObjectInShape(SHAPE_SPELLCYLINDER, fLength, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, vOrigin);
while(GetIsObjectValid(oTarget))
{
if(oTarget != oTrueSpeaker &&
spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oTrueSpeaker)
)
{
// Let the AI know
SignalEvent(oTarget, EventSpellCastAt(oTrueSpeaker, nSpellId));
nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nSaveDC, SAVING_THROW_TYPE_FIRE);
if(nDamage > 0)
{
float fDelay = GetDistanceBetweenLocations(lTrueSpeaker, GetLocation(oTarget)) / 20.0f;
effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_FIRE);
effect eVis = EffectVisualEffect(VFX_IMP_FLAME_M);
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
}
}// end if - Target validity check
// Get next target
oTarget = MyNextObjectInShape(SHAPE_SPELLCYLINDER, fLength, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, vOrigin);
}
}// end if - Successful utterance
}
float GetVFXLength(location lTrueSpeaker, float fLength, float fAngle)
{
float fLowerBound = 0.0f;
float fUpperBound = fLength;
float fVFXLength = fLength / 2;
vector vVFXOrigin = GetPositionFromLocation(lTrueSpeaker);
vector vAngle = AngleToVector(fAngle);
vector vVFXEnd;
int bConverged = FALSE;
while(!bConverged)
{
// Create the test vector for this loop
vVFXEnd = vVFXOrigin + (fVFXLength * vAngle);
// Determine which bound to move.
if(LineOfSightVector(vVFXOrigin, vVFXEnd))
fLowerBound = fVFXLength;
else
fUpperBound = fVFXLength;
// Get the new middle point
fVFXLength = (fUpperBound + fLowerBound) / 2;
// Check if the locations have converged
if(fabs(fUpperBound - fLowerBound) < 2.5f)
bConverged = TRUE;
}
return fVFXLength;
}