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.
251 lines
12 KiB
Plaintext
251 lines
12 KiB
Plaintext
/*
|
||
----------------
|
||
Energy Push
|
||
|
||
psi_pow_enpush
|
||
----------------
|
||
|
||
6/11/04 by Stratovarius
|
||
*/ /** @file
|
||
Energy Push
|
||
|
||
Psychokinesis [see text]
|
||
Level: Psion/wilder 2
|
||
Manifesting Time: 1 standard action
|
||
Range: Medium (100 ft. + 10 ft./ level)
|
||
Duration: Instantaneous
|
||
Saving Throw: Reflex half or Fortitude half; see text
|
||
Power Resistance: Yes
|
||
Power Points: 3
|
||
Metapsionics: Chain, Empower, Maximize, Twin
|
||
|
||
Upon manifesting this power, you choose cold, electricity, fire, or sonic.
|
||
You project a solid blast of energy of the chosen type at a target, dealing
|
||
it 2d6 points of damage. In addition, if a subject of up to one size
|
||
category larger than you fails a Strength check (DC equal to the save DC of
|
||
this power), the driving force of the energy blast pushes it back 5 feet
|
||
plus another 5 feet for every 5 points of damage it takes. If a wall or
|
||
other solid object prevents the subject from being pushed back, the subject
|
||
instead slams into the object and takes an extra 2d6 points of damage from
|
||
the impact (no save).
|
||
|
||
Cold: A blast of this energy type deals +1 point of damage per die (damage
|
||
from impact remains at 2d6 points). The saving throw to reduce damage
|
||
from a cold push is a Fortitude save instead of a Reflex save.
|
||
Electricity: Manifesting a blast 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 blast of this energy type deals +1 point of damage per die (damage
|
||
from impact remains at 2d6 points).
|
||
Sonic: A blast of this energy type deals -1 point of damage per die (damage
|
||
from impact remains at 2d6 points) and ignores an object’s hardness.
|
||
|
||
This power’s subtype is the same as the type of energy you manifest.
|
||
|
||
Augment: For every 2 additional power points you spend, this power’s damage
|
||
increases by one die (d6) and its save DC increases by 1. The damage
|
||
increase applies to both the initial blast and any damage from
|
||
impact with an object.
|
||
*/
|
||
|
||
#include "psi_inc_psifunc"
|
||
#include "psi_inc_pwresist"
|
||
#include "psi_spellhook"
|
||
#include "prc_inc_spells"
|
||
#include "psi_inc_enrgypow"
|
||
|
||
void DoPush(object oTarget, object oManifester, int nDC, int nNumberOfDice, int nDamageDealt);
|
||
|
||
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;
|
||
object oMainTarget = PRCGetSpellTargetObject();
|
||
struct manifestation manif =
|
||
EvaluateManifestation(oManifester, oMainTarget,
|
||
PowerAugmentationProfile(PRC_NO_GENERIC_AUGMENTS,
|
||
2, PRC_UNLIMITED_AUGMENTATION
|
||
),
|
||
METAPSIONIC_CHAIN | METAPSIONIC_EMPOWER | METAPSIONIC_MAXIMIZE | METAPSIONIC_TWIN
|
||
);
|
||
|
||
if(manif.bCanManifest)
|
||
{
|
||
struct energy_adjustments enAdj =
|
||
EvaluateEnergy(manif.nSpellID, POWER_ENERGYPUSH_COLD, POWER_ENERGYPUSH_ELEC, POWER_ENERGYPUSH_FIRE, POWER_ENERGYPUSH_SONIC,
|
||
VFX_BEAM_COLD, VFX_BEAM_LIGHTNING, VFX_BEAM_FIRE, VFX_BEAM_MIND);
|
||
|
||
int nDC = GetManifesterDC(oManifester) + manif.nTimesAugOptUsed_1 + enAdj.nDCMod;
|
||
int nPen = GetPsiPenetration(oManifester) + enAdj.nPenMod;
|
||
int nNumberOfDice = 2 + manif.nTimesAugOptUsed_1;
|
||
int nDieSize = 6;
|
||
int nOriginalDamage, nDamage, i;
|
||
effect eVis = EffectVisualEffect(enAdj.nVFX1);
|
||
effect eRay = EffectBeam(enAdj.nVFX2, oManifester, BODY_NODE_HAND);
|
||
effect eDamage;
|
||
object oChainTarget;
|
||
|
||
// Determine Chain Power targets
|
||
if(manif.bChain)
|
||
EvaluateChainPower(manif, oMainTarget, TRUE);
|
||
|
||
// Let the AI know
|
||
PRCSignalSpellEvent(oMainTarget, TRUE, manif.nSpellID, oManifester);
|
||
if(manif.bChain)
|
||
for(i = 0; i < array_get_size(oManifester, PRC_CHAIN_POWER_ARRAY); i++)
|
||
PRCSignalSpellEvent(array_get_object(oManifester, PRC_CHAIN_POWER_ARRAY, i), TRUE, manif.nSpellID, oManifester);
|
||
|
||
// Handle Twin Power
|
||
int nRepeats = manif.bTwin ? 2 : 1;
|
||
for(; nRepeats > 0; nRepeats--)
|
||
{
|
||
// Make an SR check
|
||
if(PRCMyResistPower(oManifester, oMainTarget, nPen))
|
||
{
|
||
// Roll damage
|
||
nDamage = MetaPsionicsDamage(manif, nDieSize, nNumberOfDice, 0, enAdj.nBonusPerDie, TRUE, FALSE);
|
||
// Target-specific stuff
|
||
nDamage = GetTargetSpecificChangesToDamage(oMainTarget, 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, oMainTarget, nDC, enAdj.nSaveType))
|
||
{
|
||
if (GetHasMettle(oMainTarget, SAVING_THROW_FORT))
|
||
// This script does nothing if it has Mettle, bail
|
||
nDamage = 0;
|
||
nDamage /= 2;
|
||
}
|
||
}
|
||
else
|
||
// Adjust damage according to Reflex Save, Evasion or Improved Evasion
|
||
nDamage = PRCGetReflexAdjustedDamage(nDamage, oMainTarget, nDC, enAdj.nSaveType);
|
||
|
||
// Apply VFX and damage to chained target, assuming there is still damage left to deal after modification
|
||
if(nDamage > 0)
|
||
{
|
||
// Apply damage
|
||
eDamage = EffectDamage(nDamage, enAdj.nDamageType);
|
||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oMainTarget);
|
||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oMainTarget);
|
||
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oMainTarget, 1.7, FALSE);
|
||
// Do the push effect on the target
|
||
DoPush(oMainTarget, oManifester, nDC, nNumberOfDice, nDamage);
|
||
|
||
// Apply damage to Chain targets
|
||
if(manif.bChain)
|
||
{
|
||
// Halve the damage
|
||
nOriginalDamage = nDamage / 2;
|
||
|
||
for(i = 0; i < array_get_size(oManifester, PRC_CHAIN_POWER_ARRAY); i++)
|
||
{
|
||
oChainTarget = array_get_object(oManifester, PRC_CHAIN_POWER_ARRAY, i);
|
||
|
||
// Determine damage
|
||
nDamage = nOriginalDamage;
|
||
// Target-specific stuff
|
||
nDamage = GetTargetSpecificChangesToDamage(oChainTarget, 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, oChainTarget, nDC, enAdj.nSaveType))
|
||
nDamage /= 2;
|
||
}
|
||
else
|
||
// Adjust damage according to Reflex Save, Evasion or Improved Evasion
|
||
nDamage = PRCGetReflexAdjustedDamage(nDamage, oChainTarget, nDC, enAdj.nSaveType);
|
||
|
||
// Apply VFX and damage to chained target, assuming there is still damage left to deal after modification
|
||
if(nDamage > 0)
|
||
{
|
||
eDamage = EffectDamage(nDamage, enAdj.nDamageType);
|
||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oChainTarget);
|
||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oChainTarget);
|
||
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBeam(enAdj.nVFX2, oMainTarget, BODY_NODE_CHEST), oChainTarget, 1.7, FALSE);
|
||
// Do the push effect on the target
|
||
DoPush(oChainTarget, oManifester, nDC, nNumberOfDice, nDamage);
|
||
}// end if - There was still damage remaining to be dealt after adjustments
|
||
}// end for - Chain targets
|
||
}// end if - Chain Power
|
||
}// end if - There was still damage remaining to be dealt after adjustments
|
||
}// end if - SR check
|
||
}// end for - Twin Power
|
||
}// end if - Successfull manifestation
|
||
}
|
||
|
||
void DoPush(object oTarget, object oManifester, int nDC, int nNumberOfDice, int nDamageDealt)
|
||
{
|
||
// Check size
|
||
if(PRCGetCreatureSize(oTarget) <= (PRCGetCreatureSize(oManifester) + 1))
|
||
{
|
||
// Check STR
|
||
if((d20() + GetAbilityModifier(ABILITY_STRENGTH, oTarget)) < nDC)
|
||
{
|
||
// Calculate how far the creature gets pushed
|
||
float fDistance = FeetToMeters(5.0f) * (1 + (nDamageDealt / 5));
|
||
// Determine if they hit a wall on the way
|
||
location lManifester = GetLocation(oManifester);
|
||
location lTargetOrigin = GetLocation(oTarget);
|
||
vector vAngle = AngleToVector(GetRelativeAngleBetweenLocations(lManifester, lTargetOrigin));
|
||
vector vTargetOrigin = GetPosition(oTarget);
|
||
vector vTarget = vTargetOrigin + (vAngle * fDistance);
|
||
|
||
if(!LineOfSightVector(vTargetOrigin, vTarget))
|
||
{
|
||
// Hit a wall, binary search for the wall
|
||
float fEpsilon = 1.0f; // Search precision
|
||
float fLowerBound = 0.0f; // The lower search bound, initialise to 0
|
||
float fUpperBound = fDistance; // The upper search bound, initialise to the initial distance
|
||
fDistance = fDistance / 2; // The search position, set to middle of the range
|
||
|
||
do{
|
||
// Create test vector for this iteration
|
||
vTarget = vTargetOrigin + (vAngle * fDistance);
|
||
|
||
// Determine which bound to move.
|
||
if(LineOfSightVector(vTargetOrigin, vTarget))
|
||
fLowerBound = fDistance;
|
||
else
|
||
fUpperBound = fDistance;
|
||
|
||
// Get the new middle point
|
||
fDistance = (fUpperBound + fLowerBound) / 2;
|
||
}while(fabs(fUpperBound - fLowerBound) > fEpsilon);
|
||
}
|
||
|
||
// Create the final target vector
|
||
vTarget = vTargetOrigin + (vAngle * fDistance);
|
||
|
||
// Determine damage and apply it
|
||
int nDamage = d6(nNumberOfDice); // Assume the die size stays static
|
||
effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING, DAMAGE_POWER_ENERGY); // Slamming into a solid object
|
||
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oTarget);
|
||
|
||
// Move the target
|
||
location lTargetDestination = Location(GetArea(oTarget), vTarget, GetFacing(oTarget));
|
||
AssignCommand(oTarget, ClearAllActions(TRUE));
|
||
AssignCommand(oTarget, JumpToLocation(lTargetDestination));
|
||
}// end if - The target failed the Strength check
|
||
}// end if - The target is small enough
|
||
}
|