Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
210 lines
9.0 KiB
Plaintext
210 lines
9.0 KiB
Plaintext
/*
|
||
----------------
|
||
Energy Bolt
|
||
|
||
psi_pow_enbolt
|
||
----------------
|
||
|
||
6/11/04 by Stratovarius
|
||
|
||
Psychokinesis [see text]
|
||
Level: Psion/wilder 3
|
||
Manifesting Time: 1 standard action
|
||
Range: 120 ft.
|
||
Area: 120-ft. line
|
||
Duration: Instantaneous
|
||
Saving Throw: Reflex half or Fortitude half; see text
|
||
Power Resistance: Yes
|
||
Power Points: 5
|
||
Metapsionics: Empower, Maximize, Twin, Widen
|
||
|
||
Upon manifesting this power, you choose cold, electricity, fire, or sonic.
|
||
You release a powerful stroke of energy of the chosen type that deals 5d6
|
||
points of damage to every creature or object within the area. The beam
|
||
begins at your fingertips.
|
||
|
||
Cold: A bolt of this energy type deals +1 point of damage per die. The
|
||
saving throw to reduce damage from a cold bolt is a Fortitude save
|
||
instead of a Reflex save.
|
||
Electricity: Manifesting a bolt of this energy type provides a +2 bonus to
|
||
the save DC and a +2 bonus on manifester level checks for the
|
||
purpose of overcoming power resistance.
|
||
Fire: A bolt of this energy type deals +1 point of damage per die.
|
||
Sonic: A bolt of this energy type deals -1 point of damage per die and
|
||
ignores an object’s hardness.
|
||
|
||
This power’s subtype is the same as the type of energy you manifest.
|
||
|
||
Augment: For every additional power point you spend, this power’s damage
|
||
increases by one die (d6). For each extra two dice of damage,
|
||
this power’s save DC increases by 1.
|
||
*/
|
||
|
||
#include "psi_inc_psifunc"
|
||
#include "psi_inc_pwresist"
|
||
#include "psi_spellhook"
|
||
#include "prc_inc_spells"
|
||
#include "psi_inc_enrgypow"
|
||
|
||
|
||
float GetVFXLength(location lManifester, float fLength, float fAngle);
|
||
|
||
void main()
|
||
{
|
||
/*
|
||
Spellcast Hook Code
|
||
Added 2004-11-02 by Stratovarius
|
||
If you want to make changes to all powers,
|
||
check psi_spellhook to find out more
|
||
|
||
*/
|
||
|
||
if (!PsiPrePowerCastCode())
|
||
{
|
||
// If code within the PrePowerCastHook (i.e. UMD) reports FALSE, do not run this spell
|
||
return;
|
||
}
|
||
|
||
// End of Spell Cast Hook
|
||
|
||
object oManifester = OBJECT_SELF;
|
||
struct manifestation manif =
|
||
EvaluateManifestation(oManifester, OBJECT_INVALID,
|
||
PowerAugmentationProfile(2,
|
||
1, PRC_UNLIMITED_AUGMENTATION
|
||
),
|
||
METAPSIONIC_EMPOWER | METAPSIONIC_MAXIMIZE | METAPSIONIC_TWIN | METAPSIONIC_WIDEN
|
||
);
|
||
|
||
if(manif.bCanManifest)
|
||
{
|
||
struct energy_adjustments enAdj =
|
||
EvaluateEnergy(manif.nSpellID, POWER_ENERGYBOLT_COLD, POWER_ENERGYBOLT_ELEC, POWER_ENERGYBOLT_FIRE, POWER_ENERGYBOLT_SONIC,
|
||
VFX_BEAM_COLD, VFX_BEAM_LIGHTNING, VFX_BEAM_FIRE, VFX_BEAM_MIND);
|
||
int nDC = GetManifesterDC(oManifester) + manif.nTimesGenericAugUsed + enAdj.nDCMod;
|
||
int nPen = GetPsiPenetration(oManifester) + enAdj.nPenMod;
|
||
int nNumberOfDice = 5 + manif.nTimesAugOptUsed_1;
|
||
int nDieSize = 6;
|
||
int nDamage;
|
||
location lManifester = GetLocation(oManifester);
|
||
location lTarget = PRCGetSpellTargetLocation();
|
||
vector vOrigin = GetPosition(oManifester);
|
||
float fLength = EvaluateWidenPower(manif, FeetToMeters(120.0f));
|
||
float fDelay;
|
||
effect eVis = EffectVisualEffect(enAdj.nVFX1);
|
||
effect eDamage;
|
||
object oTarget;
|
||
|
||
// Do VFX. This is moderately heavy, so it isn't duplicated by Twin Power
|
||
float fAngle = GetRelativeAngleBetweenLocations(lManifester, lTarget);
|
||
float fSpiralStartRadius = FeetToMeters(1.0f);
|
||
float fRadius = FeetToMeters(5.0f);
|
||
float fDuration = 4.5f;
|
||
float fVFXLength = GetVFXLength(lManifester, fLength, GetRelativeAngleBetweenLocations(lManifester, lTarget));
|
||
// A tube of beams, radius 5ft, starting 1m from manifester and running for the length of the line
|
||
BeamGengon(DURATION_TYPE_TEMPORARY, enAdj.nVFX2, lManifester, fRadius, fRadius,
|
||
1.0f, fVFXLength, // Start 1m from the manifester, 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 manifester with with radius 1ft and ending with radius 5ft at the end of the line
|
||
BeamPolygonalSpring(DURATION_TYPE_TEMPORARY, enAdj.nVFX2, lManifester, fSpiralStartRadius, fRadius,
|
||
0.0f, fVFXLength, // Start at the manifester, 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
|
||
);
|
||
|
||
// Handle Twin Power
|
||
int nRepeats = manif.bTwin ? 2 : 1;
|
||
for(; nRepeats > 0; nRepeats--)
|
||
{
|
||
// Loop over targets in the line shape
|
||
oTarget = MyFirstObjectInShape(SHAPE_SPELLCYLINDER, fLength, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, vOrigin);
|
||
while(GetIsObjectValid(oTarget))
|
||
{
|
||
if(oTarget != oManifester &&
|
||
spellsIsTarget(oTarget, SPELL_TARGET_STANDARDHOSTILE, oManifester)
|
||
)
|
||
{
|
||
// Let the AI know
|
||
PRCSignalSpellEvent(oTarget, TRUE, manif.nSpellID, oManifester);
|
||
// Make an SR check
|
||
if(PRCMyResistPower(oManifester, oTarget, nPen))
|
||
{
|
||
// Roll damage
|
||
nDamage = MetaPsionicsDamage(manif, nDieSize, nNumberOfDice, 0, enAdj.nBonusPerDie, TRUE, FALSE);
|
||
// Target-specific stuff
|
||
nDamage = GetTargetSpecificChangesToDamage(oTarget, oManifester, nDamage, TRUE, TRUE);
|
||
|
||
// Do save
|
||
if(enAdj.nSaveType == SAVING_THROW_TYPE_COLD)
|
||
{
|
||
// Cold has a fort save for half
|
||
if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, enAdj.nSaveType))
|
||
{
|
||
if (GetHasMettle(oTarget, SAVING_THROW_FORT))
|
||
nDamage = 0;
|
||
nDamage /= 2;
|
||
}
|
||
}
|
||
else
|
||
// Adjust damage according to Reflex Save, Evasion or Improved Evasion
|
||
nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, enAdj.nSaveType);
|
||
|
||
if(nDamage > 0)
|
||
{
|
||
fDelay = GetDistanceBetweenLocations(lManifester, GetLocation(oTarget)) / 20.0f;
|
||
eDamage = EffectDamage(nDamage, enAdj.nDamageType);
|
||
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget));
|
||
DelayCommand(1.0f + fDelay, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, 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, fLength, lTarget, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, vOrigin);
|
||
}// end while - Target loop
|
||
}// end for - Twin Power
|
||
}// end if - Successfull manifestation
|
||
}
|
||
|
||
float GetVFXLength(location lManifester, float fLength, float fAngle)
|
||
{
|
||
float fLowerBound = 0.0f;
|
||
float fUpperBound = fLength;
|
||
float fVFXLength = fLength / 2;
|
||
vector vVFXOrigin = GetPositionFromLocation(lManifester);
|
||
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;
|
||
}
|