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.
347 lines
16 KiB
Plaintext
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 = min((nInvLevel + 1) / 2, 9);
|
|
nBlastLvl = max(nShapeLevel, max(max(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");
|
|
}
|
|
}
|