PRC8/nwn/nwnprc/trunk/newspellbook/inv_eldtch_shape.nss
Jaysyn904 e641b42f84 Exalted update
Updated Vow of Poverty. Added Sanctify Ki Strike, Holy Strike, Fist of Heavens, Vow of Abstinence, Vow of Chastity & Gift of Faith.  (@fenac).  Turned off the Taunt & Parry skills.  Re-disabled AC & save bonuses from Tumble & Spellcraft.   Updated min() & max() to PRCmin() & PRCmax() to not conflict with similarly named NUI adjacent functions.  Set Point Blank Shot to 30' per PnP.  Added icon for Chosen of Evil.  Started work on Hidden Talent.  Created Psionics function cheatsheet.  Updated release archive.
2025-01-29 22:46:38 -05:00

347 lines
16 KiB
Plaintext

//::///////////////////////////////////////////////
//:: Name Eldritch Blast - Normal
//:: FileName inv_eldtch_blast.nss
//:://////////////////////////////////////////////
#include "prc_inc_sp_tch"
#include "inv_inc_invfunc"
#include "inv_invokehook"
#include "inv_inc_blast"
//internal function for delayed damage
void DoDelayedBlast(object oTarget, int nDamageType = DAMAGE_TYPE_FIRE, int nVFX = VFX_IMP_FLAME_M)
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(2), nDamageType), oTarget);
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(nVFX), oTarget);
}
void main()
{
// Ugly hack to tell PreInvocationCastCode() that we are casting as warlock
object oPC = OBJECT_SELF;
SetLocalInt(oPC, PRC_INVOKING_CLASS, CLASS_TYPE_WARLOCK + 1);
DelayCommand(0.0f, DeleteLocalInt(oPC, PRC_INVOKING_CLASS));
if(!PreInvocationCastCode()) return;
object oBeamTarget = PRCGetSpellTargetObject();
location lTargetArea = PRCGetSpellTargetLocation();
int nEssence = GetLocalInt(oPC, "BlastEssence");
int nEssence2 = GetLocalInt(oPC, "BlastEssence2");
int nEssenceData = GetLocalInt(oPC, "EssenceData");
int nEssenceData2 = GetLocalInt(oPC, "EssenceData2");
effect eEssence;
//If no beam target object, make one
if (!GetIsObjectValid(oBeamTarget))
{
oBeamTarget = CreateObject(OBJECT_TYPE_PLACEABLE, "prc_invisobj", lTargetArea);
}
//remove Corrupting Blast essence - it's a one-shot power
if(nEssence == INVOKE_CORRUPTING_BLAST)
DeleteLocalInt(oPC, "BlastEssence");
else if(nEssence2 == INVOKE_CORRUPTING_BLAST)
DeleteLocalInt(oPC, "BlastEssence2");
int nBlast = GetSpellId();
int bSculptor = GetHasFeat(FEAT_ELDRITCH_SCULPTOR, oPC);
int nShape, nShapeLevel, bDoom;
float fRange;
if(nBlast == INVOKE_ELDRITCH_CONE)
{
nShape = SHAPE_SPELLCONE;
fRange = bSculptor ? FeetToMeters(60.0) : FeetToMeters(30.0);
nShapeLevel = 5;
}
else if(nBlast == INVOKE_ELDRITCH_LINE)
{
nShape = SHAPE_SPELLCYLINDER;
fRange = bSculptor ? FeetToMeters(120.0) : FeetToMeters(60.0);
nShapeLevel = 5;
}
else if(nBlast == INVOKE_ELDRITCH_DOOM)
{
bDoom = TRUE;
nShape = SHAPE_SPHERE;
fRange = bSculptor ? FeetToMeters(40.0) : FeetToMeters(20.0);
nShapeLevel = 8;
}
//calculate DC for essence effects
int nInvLevel = GetInvokerLevel(oPC, CLASS_TYPE_WARLOCK);
int nBlastLvl = PRCMin((nInvLevel + 1) / 2, 9);
nBlastLvl = PRCMax(nShapeLevel, PRCMax(PRCMax(nEssenceData & 0xF, nEssenceData2 & 0xF), nBlastLvl));
int nDC = 10 + nBlastLvl + GetAbilityModifier(ABILITY_CHARISMA);
if(GetHasFeat(FEAT_LORD_OF_ALL_ESSENCES)) nDC += 2;
int nDmgDice = GetBlastDamageDices(oPC, nInvLevel);
int nDamageType = nEssence ? (nEssenceData >>> 4) & 0xFFF : DAMAGE_TYPE_MAGICAL;
int nDamageType2 = nEssence2 ? (nEssenceData2 >>> 4) & 0xFFF : DAMAGE_TYPE_MAGICAL;
//Set correct blast damage type
if(nDamageType != nDamageType2)
{
if(nDamageType != DAMAGE_TYPE_MAGICAL)
{
if(nDamageType2 == DAMAGE_TYPE_MAGICAL)
nDamageType2 = nDamageType;
}
else if(nDamageType2 != DAMAGE_TYPE_MAGICAL)
{
nDamageType = nDamageType2;
}
}
//get beam and impact vfx
int nBeamVFX, nVis, nReflexSaveType;
switch(nDamageType)
{
case DAMAGE_TYPE_FIRE:
nBeamVFX = bDoom ? VFX_IMP_PULSE_FIRE : VFX_BEAM_FIRE;
nVis = VFX_IMP_FLAME_M;
nReflexSaveType = SAVING_THROW_TYPE_FIRE;
break;
case DAMAGE_TYPE_COLD:
nBeamVFX = bDoom ? VFX_IMP_PULSE_COLD : VFX_BEAM_COLD;
nVis = VFX_IMP_FROST_S;
nReflexSaveType = SAVING_THROW_TYPE_COLD;
break;
case DAMAGE_TYPE_ACID:
nBeamVFX = bDoom ? VFX_IMP_PULSE_WATER : VFX_BEAM_DISINTEGRATE;
nVis = VFX_IMP_ACID_S;
nReflexSaveType = SAVING_THROW_TYPE_ACID;
break;
case DAMAGE_TYPE_NEGATIVE:
nBeamVFX = bDoom ? VFX_IMP_PULSE_NEGATIVE : VFX_BEAM_BLACK;
nVis = VFX_IMP_NEGATIVE_ENERGY;
nReflexSaveType = SAVING_THROW_TYPE_NEGATIVE;
break;
default:
nBeamVFX = bDoom ? VFX_IMP_PULSE_NEGATIVE : VFX_BEAM_DISINTEGRATE;
nVis = VFX_IMP_LIGHTNING_S;
nReflexSaveType = SAVING_THROW_TYPE_SPELL;
break;
}
effect eVis = EffectVisualEffect(nVis);
//add second vfx if needed
if(nDamageType != nDamageType2)
{
switch(nDamageType2)
{
case DAMAGE_TYPE_FIRE: nVis = VFX_IMP_FLAME_M; break;
case DAMAGE_TYPE_COLD: nVis = VFX_IMP_FROST_S; break;
case DAMAGE_TYPE_ACID: nVis = VFX_IMP_ACID_S; break;
case DAMAGE_TYPE_NEGATIVE: nVis = VFX_IMP_NEGATIVE_ENERGY; break;
}
eVis = EffectLinkEffects(eVis, EffectVisualEffect(nVis));
}
int nHellFire = 0;
if(GetIsHellFireBlast(oPC))
{
if(HellFireConDamage(oPC))
{
nHellFire = GetLevelByClass(CLASS_TYPE_HELLFIRE_WARLOCK, oPC) * 2;
nBeamVFX = bDoom ? VFX_IMP_PULSE_FIRE : VFX_BEAM_FIRE;
}
}
//Penetrating Blast
int nPenetr = nInvLevel + SPGetPenetr();
if(nEssence == INVOKE_PENETRATING_BLAST || nEssence2 == INVOKE_PENETRATING_BLAST)
nPenetr += 4;
//Get first target in spell area
object oTarget = MyFirstObjectInShape(nShape, fRange, lTargetArea, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetPosition(oPC));
while(GetIsObjectValid(oTarget))
{
int nDamage = d6(nDmgDice);
if(GetHasSpellEffect(INVOKE_WILD_FRENZY, oPC))
nDamage += 2;
//Bane Blast
int nRace = MyPRCGetRacialType(oTarget);
if(nRace == ((nEssenceData >>> 16) & 0xFF) - 1
|| nRace == ((nEssenceData2 >>> 16) & 0xFF) - 1)
nDamage += d6(2);
//Hammer Blast
if(GetObjectType(oTarget) != OBJECT_TYPE_CREATURE && nEssence != INVOKE_HAMMER_BLAST && nEssence2 != INVOKE_HAMMER_BLAST)
{
nDamage /= 2;
if(nDamage < 1) nDamage = 1;
nHellFire /= 2;
}
int nRep = bDoom ? SPELL_TARGET_SELECTIVEHOSTILE : SPELL_TARGET_STANDARDHOSTILE;
// This heals friendly undead targets with negative energy damage
if (nDamageType == DAMAGE_TYPE_NEGATIVE && bDoom && GetIsFriend(oTarget, oPC) && MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(nDamage), oTarget);
else if(spellsIsTarget(oTarget, nRep, oPC) && oTarget != oPC)
{
//Fire cast spell at event for the specified target
SignalEvent(oTarget, EventSpellCastAt(oPC, INVOKE_ELDRITCH_BLAST));
float fDelay = GetDistanceBetween(oPC, oTarget)/20;
nDamage = PRCGetReflexAdjustedDamage(nDamage, oTarget, nDC, nReflexSaveType);
if(nDamage > 0)
{
//Make SR Check
int iSR = PRCDoResistSpell(oPC, oTarget, nPenetr);
if(!iSR)
{
//Apply secondary effects from essence invocations
if(nEssence == INVOKE_PENETRATING_BLAST || nEssence2 == INVOKE_PENETRATING_BLAST)
{
eEssence = EffectSpellResistanceDecrease(5);
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, TurnsToSeconds(1));
}
if((nEssence == INVOKE_HINDERING_BLAST || nEssence2 == INVOKE_HINDERING_BLAST) && PRCGetIsAliveCreature(oTarget))
{
eEssence = EffectSlow();
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
}
if(nEssence == INVOKE_BINDING_BLAST || nEssence2 == INVOKE_BINDING_BLAST)
{
eEssence = EffectStunned();
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
}
if(nEssence == INVOKE_BEWITCHING_BLAST || nEssence2 == INVOKE_BEWITCHING_BLAST)
{
eEssence = PRCEffectConfused();
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
}
if((nEssence == INVOKE_BESHADOWED_BLAST || nEssence2 == INVOKE_BESHADOWED_BLAST) && PRCGetIsAliveCreature(oTarget))
{
eEssence = EffectBlindness();
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
}
if((nEssence == INVOKE_HELLRIME_BLAST || nEssence2 == INVOKE_HELLRIME_BLAST))
{
eEssence = EffectAbilityDecrease(ABILITY_DEXTERITY, 4);
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, TurnsToSeconds(10));
}
if(nEssence == INVOKE_UTTERDARK_BLAST || nEssence2 == INVOKE_UTTERDARK_BLAST)
{
eEssence = EffectNegativeLevel(2);
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, HoursToSeconds(1));
}
if(nEssence == INVOKE_FRIGHTFUL_BLAST || nEssence2 == INVOKE_FRIGHTFUL_BLAST)
{
effect eDur2 = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
effect eFear = EffectFrightened();
effect eAttackD = EffectAttackDecrease(2);
effect eDmgD = EffectDamageDecrease(2,DAMAGE_TYPE_BLUDGEONING|DAMAGE_TYPE_PIERCING|DAMAGE_TYPE_SLASHING);
effect SaveD = EffectSavingThrowDecrease(SAVING_THROW_ALL,2);
effect Skill = EffectSkillDecrease(SKILL_ALL_SKILLS,2);
eEssence = EffectLinkEffects(eDmgD, eDur2);
eEssence = EffectLinkEffects(eEssence, eAttackD);
eEssence = EffectLinkEffects(eEssence, SaveD);
eEssence = EffectLinkEffects(eEssence, eFear);
eEssence = EffectLinkEffects(eEssence, Skill);
if(!PRCMySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_FEAR))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, TurnsToSeconds(1));
}
if(nEssence == INVOKE_NOXIOUS_BLAST || nEssence2 == INVOKE_NOXIOUS_BLAST)
{
eEssence = EffectDazed();
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, TurnsToSeconds(1));
}
if(nEssence == INVOKE_CORRUPTING_BLAST || nEssence2 == INVOKE_CORRUPTING_BLAST)
{
if(CheckTurnUndeadUses(oPC, 1))
{
int nRed = GetLevelByClass(CLASS_TYPE_ELDRITCH_DISCIPLE, oPC) / 2;
if(nRed < 1) nRed = 1;
eEssence = EffectSavingThrowDecrease(SAVING_THROW_WILL, nRed);
eEssence = EffectLinkEffects(eEssence, EffectVisualEffect(VFX_DUR_MIND_AFFECTING_NEGATIVE));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, RoundsToSeconds(1));
}
else
SpeakStringByStrRef(40550);//"This ability is tied to your turn undead ability, which has no more uses for today."
}
if((nEssence == INVOKE_SICKENING_BLAST || nEssence2 == INVOKE_SICKENING_BLAST) && PRCGetIsAliveCreature(oTarget))
{
eEssence = EffectSickened();
if(!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_SPELL))
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eEssence, oTarget, 60.0);
}
if((nEssence == INVOKE_BRIMSTONE_BLAST || nEssence2 == INVOKE_BRIMSTONE_BLAST) && !GetLocalInt(oTarget, "BrimstoneFire"))
{
if(!PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_FIRE))
{
SetLocalInt(oTarget, "BrimstoneFire", TRUE);
int nDuration = nInvLevel / 5;
DelayCommand(RoundsToSeconds(nDuration), DeleteLocalInt(oTarget, "BrimstoneFire"));
int i;
float fRound = RoundsToSeconds(1);
for(i = 1; i <= nDuration; i++)
{
DelayCommand(fRound * i, DoDelayedBlast(oTarget));
}
}
}
//Apply the VFX impact
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
}
//Vitriolic ignores SR
if(nEssence == INVOKE_VITRIOLIC_BLAST || nEssence2 == INVOKE_VITRIOLIC_BLAST)
{
//Apply the VFX impact
if(iSR) ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
//Apply secondary effect from essence invocations
int nDuration = nInvLevel / 5;
int i;
float fRound = RoundsToSeconds(1);
for(i = 1; i <= nDuration; i++)
{
DelayCommand(fRound * i, DoDelayedBlast(oTarget, DAMAGE_TYPE_ACID, VFX_IMP_ACID_S));
}
}
//Apply damage effect
ApplyBlastDamage(oPC, oTarget, 1, iSR, nDamage, nDamageType, nDamageType2, nHellFire, FALSE);
}
}
//Get next target in spell area
oTarget = MyNextObjectInShape(nShape, fRange, lTargetArea, TRUE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetPosition(oPC));
if(DEBUG) DoDebug("inv_eldtch_shape: Next target is: " + DebugObject2Str(oTarget));
}
if(nBlast == INVOKE_ELDRITCH_LINE)
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBeam(nBeamVFX, oPC, BODY_NODE_HAND, FALSE), oBeamTarget, 1.0f);
else if(nBlast == INVOKE_ELDRITCH_DOOM)
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(nBeamVFX), lTargetArea, 1.0f);
//Remove the created beam target object if it exists
if (GetResRef(oBeamTarget) == "prc_invisobj") DestroyObject(oBeamTarget, 3.0);
if(bSculptor)
{
if(!GetLocalInt(oPC, "UsingSecondBlast"))
{
SetLocalInt(oPC, "UsingSecondBlast", TRUE);
UseInvocation(nBlast, CLASS_TYPE_WARLOCK, 0, TRUE);
}
else
DeleteLocalInt(oPC, "UsingSecondBlast");
}
}