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.
151 lines
6.1 KiB
Plaintext
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;
|
|
} |