PRC8_fork/nwn/nwnprc/trunk/psionics/psi_pow_enrtrt.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

259 lines
13 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
----------------
Energy Retort
psi_pow_enrtrt
----------------
11/12/04 by Stratovarius
*/ /** @file
Energy Retort
Psychokinesis [see text]
Level: Psion/wilder 3
Manifesting Time: 1 standard action
Range: Personal and close (25 ft. + 5 ft./2 levels); see text
Targets: You and creature or object attacking you; see text
Duration: 1 min./level
Saving Throw: Reflex half or Fortitude half; see text
Power Resistance: Yes
Power Points: 5
Metapsionics: Chain, Empower, Extend, Maximize
Upon manifesting this power, you choose cold, electricity, fire, or sonic.
You weave a field of potential energy of the chosen type around your body.
The first successful attack made against you in each round during the
powers duration prompts a response from the field without any effort on
your part. The attack may be physical, the effect of a power, or the effect
of a spell (including spell-like, supernatural, and extraordinary
abilities). An “ectoburst” discharges from the field, targeting the source
of the attack and dealing 4d6 points of damage of the chosen energy type.
To be affected, a target must be within close range. The ectoburst is a
ranged touch attack.
Cold: A field of this energy type deals +1 point of damage per die. The
saving throw to reduce damage from a cold retort is a Fortitude save
instead of a Reflex save.
Electricity: Manifesting a field 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 field of this energy type deals +1 point of damage per die.
Sonic: A field of this energy type deals -1 point of damage per die and
ignores an objects hardness.
This powers subtype is the same as the type of energy you manifest.
Augment: For every additional power point you spend, this powers duration
increases by 1 minute.
*/
#include "psi_inc_psifunc"
#include "psi_inc_pwresist"
#include "psi_spellhook"
#include "prc_inc_sp_tch"
#include "psi_inc_enrgypow"
const string ENERGY_RETORT_VARNAME_BASE = "PRC_Power_EnergyRetort_";
void DispelMonitor(object oManifester, object oTarget, int nSpellID, int nBeatsRemaining);
void main()
{
// Are we running the manifestation part or the onhit part?
if(GetRunningEvent() != EVENT_ONHIT)
{
// Power use hook
if (!PsiPrePowerCastCode()) return;
object oManifester = OBJECT_SELF;
object oTarget = PRCGetSpellTargetObject();
struct manifestation manif =
EvaluateManifestation(oManifester, oTarget,
PowerAugmentationProfile(PRC_NO_GENERIC_AUGMENTS,
1, PRC_UNLIMITED_AUGMENTATION
),
METAPSIONIC_CHAIN | METAPSIONIC_EMPOWER | METAPSIONIC_EXTEND | METAPSIONIC_MAXIMIZE
);
if(manif.bCanManifest)
{
int nDC = GetManifesterDC(oManifester);
int nPen = GetPsiPenetration(oManifester);
effect eDur = EffectVisualEffect(VFX_DUR_ELEMENTAL_SHIELD);
float fDuration = 60.0f * (manif.nManifesterLevel + manif.nTimesAugOptUsed_1);
if(manif.bExtend) fDuration *= 2;
// Get the OnHitCast: Unique on the target's armor / hide
ExecuteScript("prc_keep_onhit_a", oTarget);
// Hook eventscript
AddEventScript(oTarget, EVENT_ONHIT, "psi_pow_enrtrt", TRUE, FALSE);
// Store data for use when hit
SetLocalManifestation(oTarget, ENERGY_RETORT_VARNAME_BASE + "Manifestation", manif);
SetLocalInt(oTarget, ENERGY_RETORT_VARNAME_BASE + "DC", nDC);
SetLocalInt(oTarget, ENERGY_RETORT_VARNAME_BASE + "SRPenetration", nPen);
// Do VFX for the monitor to look for
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDur, oTarget, fDuration, TRUE, manif.nSpellID, manif.nManifesterLevel);
// Start effect end monitor
DelayCommand(6.0f, DispelMonitor(oManifester, oTarget, manif.nSpellID, FloatToInt(fDuration) / 6));
}// end if - Successfull manifestation
}// end if - Manifesting a power
else
{
object oHit = OBJECT_SELF;
object oItem = GetSpellCastItem();
// Make sure the one doing the triggering hit was someone else
if(GetBaseItemType(oItem) == BASE_ITEM_ARMOR ||
GetBaseItemType(oItem) == BASE_ITEM_CREATUREITEM
)
{
// Once per round lock
if(GetLocalInt(oHit, ENERGY_RETORT_VARNAME_BASE + "UsedForRound"))
return;
else
{
SetLocalInt(oHit, ENERGY_RETORT_VARNAME_BASE + "UsedForRound", TRUE);
DelayCommand(6.0f, DeleteLocalInt(oHit, ENERGY_RETORT_VARNAME_BASE + "UsedForRound"));
}
// Get data from the original manifestation
struct manifestation manif = GetLocalManifestation(oHit, ENERGY_RETORT_VARNAME_BASE + "Manifestation");
object oMainTarget = PRCGetSpellTargetObject();
struct energy_adjustments enAdj =
EvaluateEnergy(manif.nSpellID, POWER_ENERGYRETORT_COLD, POWER_ENERGYRETORT_ELEC, POWER_ENERGYRETORT_FIRE, POWER_ENERGYRETORT_SONIC,
VFX_BEAM_COLD, VFX_BEAM_LIGHTNING, VFX_BEAM_FIRE, VFX_BEAM_MIND);
int nDC = GetLocalInt(oHit, ENERGY_RETORT_VARNAME_BASE + "DC") + enAdj.nDCMod;
int nPen = GetLocalInt(oHit, ENERGY_RETORT_VARNAME_BASE + "SRPenetration") + enAdj.nPenMod;
int nNumberOfDice = 4;
int nDieSize = 6;
int nTouchAttack,
nOriginalDamage,
nDamage,
i;
effect eVis = EffectVisualEffect(enAdj.nVFX1);
effect eRay,
eDamage;
float fRange = FeetToMeters(25.0f + (5.0f * (manif.nManifesterLevel / 2)));
object oChainTarget;
// Test range
if(GetDistanceBetween(oHit, oMainTarget) <= fRange)
{
// Determine Chain Power targets
if(manif.bChain)
EvaluateChainPower(manif, oMainTarget, TRUE);
// Let the AI know
PRCSignalSpellEvent(oMainTarget, TRUE, manif.nSpellID, manif.oManifester);
if(manif.bChain)
for(i = 0; i < array_get_size(manif.oManifester, PRC_CHAIN_POWER_ARRAY); i++)
PRCSignalSpellEvent(array_get_object(manif.oManifester, PRC_CHAIN_POWER_ARRAY, i), TRUE, manif.nSpellID, manif.oManifester);
// Touch attack the main target
nTouchAttack = PRCDoRangedTouchAttack(oMainTarget);
// Shoot the ray
eRay = EffectBeam(enAdj.nVFX2, manif.oManifester, BODY_NODE_HAND, !(nTouchAttack > 0));
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eRay, oMainTarget, 1.7, FALSE);
if(nTouchAttack > 0)
{
//Check for Power Resistance
if(PRCMyResistPower(manif.oManifester, oMainTarget, nPen))
{
// Roll damage
nDamage = MetaPsionicsDamage(manif, nDieSize, nNumberOfDice, 0, enAdj.nBonusPerDie, TRUE, TRUE);
// Target-specific stuff
nDamage = GetTargetSpecificChangesToDamage(oMainTarget, manif.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 the main target, assuming there is still damage left to deal after modification
if(nDamage > 0)
{
// Apply the damage. Critical hits & precision damage apply
ApplyTouchAttackDamage(manif.oManifester, oMainTarget, nTouchAttack, nDamage, enAdj.nDamageType);
// Apply damage to Chain targets
if(manif.bChain)
{
// Halve the damage
nOriginalDamage = nDamage / 2;
for(i = 0; i < array_get_size(manif.oManifester, PRC_CHAIN_POWER_ARRAY); i++)
{
// Get target to affect
oChainTarget = array_get_object(manif.oManifester, PRC_CHAIN_POWER_ARRAY, i);
// Determine damage
nDamage = nOriginalDamage;
// Target-specific stuff
nDamage = GetTargetSpecificChangesToDamage(oChainTarget, manif.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)
{
// Apply VFX and damage to chained target
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);
}// end if - There was still damage remaining to be dealt after adjustments
}// end for - Chain targets
}// end if - Chain Power
}// end if - There is damage left to be dealt
}// end if - SR check
}// end if - Touch attack hit
}// end if - Range check
}// end if - Manifester was the one hit in the triggering attack
}// end else - Running OnHit event
}
void DispelMonitor(object oManifester, object oTarget, int nSpellID, int nBeatsRemaining)
{
// Has the power ended since the last beat, or does the duration run out now
if((--nBeatsRemaining == 0) ||
PRCGetDelayedSpellEffectsExpired(nSpellID, oTarget, oManifester)
)
{
if(DEBUG) DoDebug("psi_pow_enrtrt: Expired, cleaning up");
// Clear the effect presence marker
DeleteLocalManifestation(oTarget, ENERGY_RETORT_VARNAME_BASE + "Manifestation");
DeleteLocalInt(oTarget, ENERGY_RETORT_VARNAME_BASE + "DC");
DeleteLocalInt(oTarget, ENERGY_RETORT_VARNAME_BASE + "SRPenetration");
// Remove the eventscript
RemoveEventScript(oTarget, EVENT_ONHIT, "psi_pow_enrtrt", TRUE, FALSE);
}
else
DelayCommand(6.0f, DispelMonitor(oManifester, oTarget, nSpellID, nBeatsRemaining));
}