635 lines
24 KiB
Plaintext
635 lines
24 KiB
Plaintext
|
//::///////////////////////////////////////////////
|
||
|
//:: x2_i0_spells
|
||
|
//:: Copyright (c) 2001 Bioware Corp.
|
||
|
//:://////////////////////////////////////////////
|
||
|
/*
|
||
|
Expansion 2 and above include file for spells
|
||
|
*/
|
||
|
//:://////////////////////////////////////////////
|
||
|
//:: Created By: Andrew Nobbs
|
||
|
//:: Created On: Nov 2002
|
||
|
//:: Updated On: 2003/09/10 - Georg Zoeller
|
||
|
//:://////////////////////////////////////////////
|
||
|
#include "x2_inc_itemprop"
|
||
|
#include "x0_i0_spells"
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// GZ: These constants are used with for the AOE behavior AI
|
||
|
//------------------------------------------------------------------------------
|
||
|
const int X2_SPELL_AOEBEHAVIOR_FLEE = 0;
|
||
|
const int X2_SPELL_AOEBEHAVIOR_IGNORE = 1;
|
||
|
const int X2_SPELL_AOEBEHAVIOR_GUST = 2;
|
||
|
const int X2_SPELL_AOEBEHAVIOR_DISPEL_L = SPELL_LESSER_DISPEL;
|
||
|
const int X2_SPELL_AOEBEHAVIOR_DISPEL_N = SPELL_DISPEL_MAGIC;
|
||
|
const int X2_SPELL_AOEBEHAVIOR_DISPEL_G = SPELL_GREATER_DISPELLING;
|
||
|
const int X2_SPELL_AOEBEHAVIOR_DISPEL_M = SPELL_MORDENKAINENS_DISJUNCTION;
|
||
|
const int X2_SPELL_AOEBEHAVIOR_DISPEL_C = 727;
|
||
|
|
||
|
|
||
|
// * Will pass back a linked effect for all of the bad tide of battle effects.
|
||
|
effect CreateBadTideEffectsLink();
|
||
|
// * Will pass back a linked effect for all of the good tide of battle effects.
|
||
|
effect CreateGoodTideEffectsLink();
|
||
|
// * Passes in the slashing weapon type
|
||
|
int GetSlashingWeapon(object oItem);
|
||
|
// * Passes in the melee weapon type
|
||
|
int GetMeleeWeapon(object oItem);
|
||
|
// * Passes in if the item is magical or not.
|
||
|
int GetIsMagicalItem(object oItem);
|
||
|
// * Passes back the stat bonus of the characters magical stat, if any.
|
||
|
int GetIsMagicStatBonus(object oCaster);
|
||
|
|
||
|
// * Save DC against Epic Spells is the relevant ability score of the caster
|
||
|
// * + 20. The hightest ability score of the casting relevants is 99.99% identical
|
||
|
// * with the one that is used for casting, so we just take it.
|
||
|
// * if used by a placeable, it is equal to the placeables WILL save field.
|
||
|
int GetEpicSpellSaveDC(object oCaster);
|
||
|
|
||
|
// * Checks the character for the thundering rage feat and will apply temporary massive critical
|
||
|
// * to the worn weapons
|
||
|
// * Checks and runs Rerrifying Rage feat
|
||
|
void CheckAndApplyEpicRageFeats(int nRounds);
|
||
|
|
||
|
// * Do a mind blast
|
||
|
// nDC - DC of the Save to resist
|
||
|
// nRounds - Rounds the stun effect holds
|
||
|
// fRange - Range of the EffectCone
|
||
|
void DoMindBlast(int nDC, int nDuration, float fRange);
|
||
|
|
||
|
|
||
|
//::///////////////////////////////////////////////
|
||
|
//:: CreateBadTideEffectsLink
|
||
|
//:: Copyright (c) 2001 Bioware Corp.
|
||
|
//:://////////////////////////////////////////////
|
||
|
/*
|
||
|
Creates the linked bad effects for Battletide.
|
||
|
*/
|
||
|
//:://////////////////////////////////////////////
|
||
|
//:: Created By:
|
||
|
//:: Created On:
|
||
|
//:://////////////////////////////////////////////
|
||
|
effect CreateBadTideEffectsLink()
|
||
|
{
|
||
|
//Declare major variables
|
||
|
effect eSaves = EffectSavingThrowDecrease(SAVING_THROW_ALL,2);
|
||
|
effect eAttack = EffectAttackDecrease(2);
|
||
|
effect eDamage = EffectDamageDecrease(2,DAMAGE_TYPE_SLASHING);
|
||
|
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
|
||
|
//Link the effects
|
||
|
effect eLink = EffectLinkEffects(eAttack,eDamage);
|
||
|
eLink = EffectLinkEffects(eLink,eSaves);
|
||
|
eLink = EffectLinkEffects(eLink,eDur);
|
||
|
return eLink;
|
||
|
}
|
||
|
|
||
|
//::///////////////////////////////////////////////
|
||
|
//:: CreateGoodTideEffectsLink
|
||
|
//:: Copyright (c) 2001 Bioware Corp.
|
||
|
//:://////////////////////////////////////////////
|
||
|
/*
|
||
|
Creates the linked good effects for Battletide.
|
||
|
*/
|
||
|
//:://////////////////////////////////////////////
|
||
|
//:: Created By:
|
||
|
//:: Created On:
|
||
|
//:://////////////////////////////////////////////
|
||
|
effect CreateGoodTideEffectsLink()
|
||
|
{
|
||
|
//Declare major variables
|
||
|
effect eSaves = EffectSavingThrowIncrease(SAVING_THROW_ALL,2);
|
||
|
effect eAttack = EffectAttackIncrease(2);
|
||
|
effect eDamage = EffectDamageIncrease(2);
|
||
|
effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE);
|
||
|
//Link the effects
|
||
|
effect eLink = EffectLinkEffects(eAttack,eDamage);
|
||
|
eLink = EffectLinkEffects(eLink,eSaves);
|
||
|
eLink = EffectLinkEffects(eLink,eDur);
|
||
|
return eLink;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// AN, 2003
|
||
|
// Returns TRUE if oItem is a slashing weapon
|
||
|
// 1.70: made the function custom content weapons compatible
|
||
|
//------------------------------------------------------------------------------
|
||
|
int GetSlashingWeapon(object oItem)
|
||
|
{
|
||
|
int nBaseItem = GetBaseItemType(oItem);
|
||
|
if(nBaseItem == BASE_ITEM_INVALID)
|
||
|
return FALSE;
|
||
|
switch(StringToInt(Get2DAString("baseitems","WeaponType",nBaseItem)))
|
||
|
{
|
||
|
case 3://slashing
|
||
|
case 4://slashing+piercing
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// AN, 2003
|
||
|
// Returns TRUE if oItem is a ranged weapon
|
||
|
//------------------------------------------------------------------------------
|
||
|
int GetIsRangedWeapon(object oItem)
|
||
|
{
|
||
|
// GZ: replaced if statement with engine function
|
||
|
return GetWeaponRanged(oItem);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// AN, 2003
|
||
|
// Returns TRUE, if oItem is a melee weapon
|
||
|
// 1.70: made the function custom content weapons compatible
|
||
|
//------------------------------------------------------------------------------
|
||
|
int GetMeleeWeapon(object oItem)
|
||
|
{
|
||
|
int nBaseItem = GetBaseItemType(oItem);
|
||
|
if(nBaseItem == BASE_ITEM_INVALID || GetWeaponRanged(oItem))
|
||
|
return FALSE;
|
||
|
return StringToInt(Get2DAString("baseitems","WeaponType",nBaseItem)) > 0;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// AN, 2003
|
||
|
// Returns TRUE if oItem has any item property that classifies it as magical item
|
||
|
// 1.70: negative item properties, thieves tool and trap are not considered
|
||
|
// anymore and added arcane spell failure and bonus spell slots into consideration
|
||
|
//------------------------------------------------------------------------------
|
||
|
int GetIsMagicalItem(object oItem)
|
||
|
{
|
||
|
itemproperty ip = GetFirstItemProperty(oItem);
|
||
|
while(GetIsItemPropertyValid(ip))
|
||
|
{
|
||
|
switch(GetItemPropertyType(ip))
|
||
|
{
|
||
|
case ITEM_PROPERTY_ABILITY_BONUS:
|
||
|
case ITEM_PROPERTY_AC_BONUS:
|
||
|
case ITEM_PROPERTY_AC_BONUS_VS_ALIGNMENT_GROUP:
|
||
|
case ITEM_PROPERTY_AC_BONUS_VS_DAMAGE_TYPE:
|
||
|
case ITEM_PROPERTY_AC_BONUS_VS_RACIAL_GROUP:
|
||
|
case ITEM_PROPERTY_AC_BONUS_VS_SPECIFIC_ALIGNMENT:
|
||
|
case ITEM_PROPERTY_ATTACK_BONUS:
|
||
|
case ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP:
|
||
|
case ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP:
|
||
|
case ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT:
|
||
|
case ITEM_PROPERTY_BASE_ITEM_WEIGHT_REDUCTION:
|
||
|
case ITEM_PROPERTY_BONUS_FEAT:
|
||
|
case ITEM_PROPERTY_CAST_SPELL:
|
||
|
case ITEM_PROPERTY_DAMAGE_BONUS:
|
||
|
case ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP:
|
||
|
case ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP:
|
||
|
case ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT:
|
||
|
case ITEM_PROPERTY_DAMAGE_REDUCTION:
|
||
|
case ITEM_PROPERTY_DAMAGE_RESISTANCE:
|
||
|
case ITEM_PROPERTY_DAMAGE_VULNERABILITY:
|
||
|
case ITEM_PROPERTY_DARKVISION:
|
||
|
// case ITEM_PROPERTY_DECREASED_ABILITY_SCORE:
|
||
|
// case ITEM_PROPERTY_DECREASED_AC:
|
||
|
// case ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER:
|
||
|
// case ITEM_PROPERTY_DECREASED_DAMAGE:
|
||
|
// case ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER:
|
||
|
// case ITEM_PROPERTY_DECREASED_SAVING_THROWS:
|
||
|
// case ITEM_PROPERTY_DECREASED_SAVING_THROWS_SPECIFIC:
|
||
|
// case ITEM_PROPERTY_DECREASED_SKILL_MODIFIER:
|
||
|
case ITEM_PROPERTY_ENHANCED_CONTAINER_REDUCED_WEIGHT:
|
||
|
case ITEM_PROPERTY_ENHANCEMENT_BONUS:
|
||
|
case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP:
|
||
|
case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP:
|
||
|
case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT:
|
||
|
case ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE:
|
||
|
case ITEM_PROPERTY_EXTRA_RANGED_DAMAGE_TYPE:
|
||
|
case ITEM_PROPERTY_FREEDOM_OF_MOVEMENT:
|
||
|
case ITEM_PROPERTY_HASTE:
|
||
|
case ITEM_PROPERTY_HOLY_AVENGER:
|
||
|
case ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE:
|
||
|
case ITEM_PROPERTY_IMMUNITY_MISCELLANEOUS:
|
||
|
case ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL:
|
||
|
case ITEM_PROPERTY_IMMUNITY_SPELL_SCHOOL:
|
||
|
case ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL:
|
||
|
case ITEM_PROPERTY_IMPROVED_EVASION:
|
||
|
case ITEM_PROPERTY_KEEN:
|
||
|
case ITEM_PROPERTY_LIGHT:
|
||
|
case ITEM_PROPERTY_MASSIVE_CRITICALS:
|
||
|
case ITEM_PROPERTY_MIGHTY:
|
||
|
case ITEM_PROPERTY_MIND_BLANK://never implemented itemproperty, but nvm
|
||
|
case ITEM_PROPERTY_MONSTER_DAMAGE:
|
||
|
// case ITEM_PROPERTY_NO_DAMAGE:
|
||
|
case ITEM_PROPERTY_ON_HIT_PROPERTIES:
|
||
|
case ITEM_PROPERTY_ON_MONSTER_HIT:
|
||
|
case ITEM_PROPERTY_POISON://never implemented itemproperty, but nvm
|
||
|
case ITEM_PROPERTY_REGENERATION:
|
||
|
case ITEM_PROPERTY_REGENERATION_VAMPIRIC:
|
||
|
case ITEM_PROPERTY_SAVING_THROW_BONUS:
|
||
|
case ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC:
|
||
|
case ITEM_PROPERTY_SKILL_BONUS:
|
||
|
case ITEM_PROPERTY_SPELL_RESISTANCE:
|
||
|
// case ITEM_PROPERTY_THIEVES_TOOLS:
|
||
|
// case ITEM_PROPERTY_TRAP:
|
||
|
case ITEM_PROPERTY_TRUE_SEEING:
|
||
|
case ITEM_PROPERTY_TURN_RESISTANCE:
|
||
|
case ITEM_PROPERTY_UNLIMITED_AMMUNITION:
|
||
|
case ITEM_PROPERTY_ONHITCASTSPELL:
|
||
|
case ITEM_PROPERTY_ARCANE_SPELL_FAILURE:
|
||
|
case ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N:
|
||
|
return TRUE;
|
||
|
}
|
||
|
ip = GetNextItemProperty(oItem);
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//::///////////////////////////////////////////////
|
||
|
//:: GetIsMagicStatBonus
|
||
|
//:: Copyright (c) 2001 Bioware Corp.
|
||
|
//:://////////////////////////////////////////////
|
||
|
/*
|
||
|
Returns the modifier from the ability
|
||
|
score that matters for this caster
|
||
|
*/
|
||
|
//:://////////////////////////////////////////////
|
||
|
//:: Created By:
|
||
|
//:: Created On:
|
||
|
//:://////////////////////////////////////////////
|
||
|
|
||
|
int GetIsMagicStatBonus(object oCaster)
|
||
|
{
|
||
|
//Declare major variables
|
||
|
int nClass;
|
||
|
int nAbility;
|
||
|
|
||
|
if(nClass = GetLevelByClass(CLASS_TYPE_WIZARD, oCaster))
|
||
|
{
|
||
|
if(nClass > 0)
|
||
|
{
|
||
|
nAbility = ABILITY_INTELLIGENCE;
|
||
|
}
|
||
|
}
|
||
|
if(nClass = GetLevelByClass(CLASS_TYPE_BARD, oCaster) || GetLevelByClass(CLASS_TYPE_SORCERER, oCaster))
|
||
|
{
|
||
|
if(nClass > 0)
|
||
|
{
|
||
|
nAbility = ABILITY_CHARISMA;
|
||
|
}
|
||
|
}
|
||
|
else if(nClass = GetLevelByClass(CLASS_TYPE_CLERIC, oCaster) || GetLevelByClass(CLASS_TYPE_DRUID, oCaster)
|
||
|
|| GetLevelByClass(CLASS_TYPE_PALADIN, oCaster) || GetLevelByClass(CLASS_TYPE_RANGER, oCaster))
|
||
|
{
|
||
|
if(nClass > 0)
|
||
|
{
|
||
|
nAbility = ABILITY_WISDOM;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return GetAbilityModifier(nAbility, oCaster);
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// Patch 1.70:
|
||
|
// -both additional functions were deleted and put into this one
|
||
|
// -thundering rage try to apply bonuses to creature weapons, if barbarian doesn't have weapons
|
||
|
// and if he haven't got even creature one, then this feat add deafness onhit to gloves (if exists)
|
||
|
//------------------------------------------------------------------------------
|
||
|
void CheckAndApplyEpicRageFeats(int nRounds)
|
||
|
{
|
||
|
object oBarbarian = OBJECT_SELF;
|
||
|
float fDuration = RoundsToSeconds(nRounds);
|
||
|
|
||
|
if(GetHasFeat(FEAT_EPIC_TERRIFYING_RAGE,oBarbarian))//if barbarian has terrifying rage
|
||
|
{
|
||
|
effect eAOE = EffectAreaOfEffect(AOE_MOB_FEAR,"x2_s2_terrage_A","","");
|
||
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,ExtraordinaryEffect(eAOE),oBarbarian,fDuration);//apply fear aura
|
||
|
}//end of terrifying rage
|
||
|
|
||
|
if(!GetHasFeat(FEAT_EPIC_THUNDERING_RAGE,oBarbarian))//if player don't have thundering rage,
|
||
|
{ //this function ends
|
||
|
return;
|
||
|
}
|
||
|
//declare variables, because they will be used multiple times
|
||
|
itemproperty critical = ItemPropertyMassiveCritical(IP_CONST_DAMAGEBONUS_2d6);
|
||
|
itemproperty vfx = ItemPropertyVisualEffect(ITEM_VISUAL_SONIC);
|
||
|
itemproperty onhit = ItemPropertyOnHitProps(IP_CONST_ONHIT_DEAFNESS,IP_CONST_ONHIT_SAVEDC_20,IP_CONST_ONHIT_DURATION_25_PERCENT_3_ROUNDS);
|
||
|
|
||
|
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oBarbarian);
|
||
|
if(GetIsObjectValid(oWeapon))//barbarian has weapon
|
||
|
{
|
||
|
IPSafeAddItemProperty(oWeapon,critical,fDuration,X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE,TRUE);
|
||
|
IPSafeAddItemProperty(oWeapon,vfx,fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE);
|
||
|
IPSafeAddItemProperty(oWeapon,onhit,fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE);
|
||
|
|
||
|
oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oBarbarian);
|
||
|
if(GetIsObjectValid(oWeapon))//barbarian has two weapons
|
||
|
{
|
||
|
IPSafeAddItemProperty(oWeapon,critical,fDuration,X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE,TRUE);
|
||
|
IPSafeAddItemProperty(oWeapon,vfx,fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE);
|
||
|
//no onhit for left weapon - bioware decision, perhaps balanced issue?
|
||
|
}
|
||
|
}
|
||
|
else //no weapon!
|
||
|
{
|
||
|
int bCreature;
|
||
|
int nSlot=14;
|
||
|
for(nSlot;nSlot<17;nSlot++)
|
||
|
{
|
||
|
oWeapon = GetItemInSlot(nSlot,oBarbarian);//creature weapon
|
||
|
if(GetIsObjectValid(oWeapon))
|
||
|
{
|
||
|
bCreature = TRUE;
|
||
|
IPSafeAddItemProperty(oWeapon,critical,fDuration,X2_IP_ADDPROP_POLICY_KEEP_EXISTING,TRUE,TRUE);
|
||
|
IPSafeAddItemProperty(oWeapon,onhit,fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE);
|
||
|
//no visual as it work only for non-creature weapons
|
||
|
}
|
||
|
}
|
||
|
if(!bCreature)//no creature's weapons! monk or brawler
|
||
|
{
|
||
|
oWeapon = GetItemInSlot(INVENTORY_SLOT_ARMS,oBarbarian);//gloves
|
||
|
if(GetIsObjectValid(oWeapon))
|
||
|
{
|
||
|
IPSafeAddItemProperty(oWeapon,onhit,fDuration,X2_IP_ADDPROP_POLICY_REPLACE_EXISTING,FALSE,TRUE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
//Keith Warner
|
||
|
// Do a mind blast
|
||
|
// nHitDice - HitDice/Caster Level of the creator
|
||
|
// nDC - DC of the Save to resist
|
||
|
// nRounds - Rounds the stun effect holds
|
||
|
// fRange - Range of the EffectCone
|
||
|
//------------------------------------------------------------------------------
|
||
|
void DoMindBlast(int nDC, int nDuration, float fRange)
|
||
|
{
|
||
|
int nStunTime;
|
||
|
float fDelay;
|
||
|
|
||
|
location lTargetLocation = GetSpellTargetLocation();
|
||
|
object oTarget;
|
||
|
effect eCone;
|
||
|
effect eVis = EffectVisualEffect(VFX_IMP_SONIC);
|
||
|
|
||
|
oTarget = GetFirstObjectInShape(SHAPE_SPELLCONE, fRange, lTargetLocation, TRUE);
|
||
|
|
||
|
while(GetIsObjectValid(oTarget))
|
||
|
{
|
||
|
int nApp = GetAppearanceType(oTarget);
|
||
|
int bImmune = FALSE;
|
||
|
//----------------------------------------------------------------------
|
||
|
// Hack to make mind flayers immune to their psionic attacks...
|
||
|
//----------------------------------------------------------------------
|
||
|
if (nApp == 413 ||nApp== 414 || nApp == 415)
|
||
|
{
|
||
|
bImmune = TRUE;
|
||
|
}
|
||
|
|
||
|
if(!bImmune && oTarget != OBJECT_SELF && spellsIsTarget(oTarget,SPELL_TARGET_STANDARDHOSTILE,OBJECT_SELF))
|
||
|
{
|
||
|
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId()));
|
||
|
fDelay = GetDistanceBetween(OBJECT_SELF, oTarget)/20;
|
||
|
// already stunned
|
||
|
if (GetHasSpellEffect(GetSpellId(),oTarget))
|
||
|
{
|
||
|
// only affects the targeted object
|
||
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_STUN), oTarget);
|
||
|
int nDamage;
|
||
|
if (GetLevelByClass(CLASS_TYPE_SHIFTER,OBJECT_SELF)>0)
|
||
|
{
|
||
|
nDamage = d6(GetLevelByClass(CLASS_TYPE_SHIFTER,OBJECT_SELF)/3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nDamage = d6(GetHitDice(OBJECT_SELF)/2);
|
||
|
}
|
||
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage), oTarget);
|
||
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_BIGBYS_FORCEFUL_HAND), oTarget);
|
||
|
}
|
||
|
else if (!MySavingThrow(SAVING_THROW_WILL, oTarget, nDC, SAVING_THROW_TYPE_MIND_SPELLS, OBJECT_SELF, fDelay))
|
||
|
{ //saving throw VFX added
|
||
|
//Calculate the length of the stun
|
||
|
nStunTime = nDuration;
|
||
|
//Set stunned effect
|
||
|
eCone = EffectStunned();
|
||
|
//Apply the VFX impact and effects
|
||
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget));
|
||
|
DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCone, oTarget, RoundsToSeconds(nStunTime)));
|
||
|
}
|
||
|
}
|
||
|
//Get next target in spell area
|
||
|
oTarget = GetNextObjectInShape(SHAPE_SPELLCONE, fRange, lTargetLocation, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Gelatinous Cube Paralyze attack
|
||
|
int DoCubeParalyze(object oTarget, object oSource, int nSaveDC = 16)
|
||
|
{
|
||
|
if (!MySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC, SAVING_THROW_TYPE_PARALYSE, oSource))
|
||
|
{
|
||
|
effect ePara = EffectParalyze();
|
||
|
effect eDur = EffectVisualEffect(VFX_DUR_PARALYZED);
|
||
|
ePara = EffectLinkEffects(eDur,ePara);
|
||
|
ePara = EffectLinkEffects(EffectVisualEffect(VFX_DUR_FREEZE_ANIMATION),ePara);
|
||
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,ePara,oTarget,RoundsToSeconds(3+d3())); // not 3 d6, thats not fun
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// GZ: Gel. Cube special abilities
|
||
|
// --------------------------------------------------------------------------------
|
||
|
void EngulfAndDamage(object oTarget, object oSource)
|
||
|
{
|
||
|
int nDC = 13 + GetHitDice(oSource) - 4;
|
||
|
if (!MySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, SAVING_THROW_TYPE_NONE, oSource))
|
||
|
{
|
||
|
FloatingTextStrRefOnCreature(84610,oTarget); // * Engulfed
|
||
|
int nDamage = d6(1);
|
||
|
|
||
|
effect eDamage = EffectDamage(nDamage, DAMAGE_TYPE_ACID);
|
||
|
effect eVis = EffectVisualEffect(VFX_IMP_ACID_S);
|
||
|
ApplyEffectToObject(DURATION_TYPE_INSTANT,eDamage,oTarget);
|
||
|
ApplyEffectToObject(DURATION_TYPE_INSTANT,eVis,oTarget);
|
||
|
if (!GetIsImmune(oTarget,IMMUNITY_TYPE_PARALYSIS, oSource))
|
||
|
{
|
||
|
if (DoCubeParalyze(oTarget,oSource,16))
|
||
|
{
|
||
|
FloatingTextStrRefOnCreature(84609,oTarget);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} */
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// Georg Zoeller, 2003-09-19
|
||
|
// Save DC against Epic Spells is the relevant ability score of the caster
|
||
|
// + 20. The hightest ability score of the casting relevants is 99.99% identical
|
||
|
// with the one that is used for casting, so we just take it.
|
||
|
// if used by a placeable, it is equal to the placeables WILL save field.
|
||
|
// --------------------------------------------------------------------------------
|
||
|
int GetEpicSpellSaveDC(object oCaster)
|
||
|
{
|
||
|
|
||
|
// * Placeables use their WILL Save field as caster level
|
||
|
if (GetObjectType(oCaster) == OBJECT_TYPE_PLACEABLE)
|
||
|
{
|
||
|
return GetWillSavingThrow(oCaster);
|
||
|
}
|
||
|
|
||
|
int nWis = GetAbilityModifier(ABILITY_WISDOM,oCaster);
|
||
|
int nInt = GetAbilityModifier(ABILITY_INTELLIGENCE,oCaster);
|
||
|
int nCha = GetAbilityModifier(ABILITY_CHARISMA,oCaster);
|
||
|
|
||
|
int nHigh = nWis;
|
||
|
if (nHigh < nInt)
|
||
|
{
|
||
|
nHigh = nInt;
|
||
|
}
|
||
|
if (nHigh < nCha)
|
||
|
{
|
||
|
nHigh = nCha;
|
||
|
}
|
||
|
int nRet = 20 + nHigh;
|
||
|
return nRet;
|
||
|
}
|
||
|
|
||
|
// --------------------------------------------------------------------------------
|
||
|
// GZ: Sept 2003
|
||
|
// Determines the optimal behavior against AoESpell nSpellId for a NPC
|
||
|
// use in OnSpellCastAt
|
||
|
// 1.70: made the function more elaborated with more cases of ignore behavior
|
||
|
// --------------------------------------------------------------------------------
|
||
|
int GetBestAOEBehavior(int nSpellID)
|
||
|
{
|
||
|
switch(nSpellID)
|
||
|
{
|
||
|
case SPELL_EVARDS_BLACK_TENTACLES:
|
||
|
if(GetCreatureSize(OBJECT_SELF) < CREATURE_SIZE_MEDIUM)
|
||
|
return X2_SPELL_AOEBEHAVIOR_IGNORE;
|
||
|
break;
|
||
|
case SPELL_GREASE:
|
||
|
if(GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_KNOCKDOWN) || GetHasFeat(FEAT_WOODLAND_STRIDE))
|
||
|
return X2_SPELL_AOEBEHAVIOR_IGNORE;
|
||
|
case SPELL_SPIKE_GROWTH:
|
||
|
if(spellsIsFlying(OBJECT_SELF) || GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_IS_INCORPOREAL))
|
||
|
return X2_SPELL_AOEBEHAVIOR_IGNORE;
|
||
|
break;
|
||
|
case SPELL_ENTANGLE:
|
||
|
case SPELL_VINE_MINE_ENTANGLE:
|
||
|
case SPELL_WEB:
|
||
|
if(GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_ENTANGLE) || GetHasFeat(FEAT_WOODLAND_STRIDE) || GetCreatureFlag(OBJECT_SELF, CREATURE_VAR_IS_INCORPOREAL))
|
||
|
return X2_SPELL_AOEBEHAVIOR_IGNORE;
|
||
|
break;
|
||
|
case SPELL_STINKING_CLOUD:
|
||
|
if(GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_DAZED))
|
||
|
return X2_SPELL_AOEBEHAVIOR_IGNORE;
|
||
|
case SPELL_STONEHOLD:
|
||
|
if(nSpellID == SPELL_STONEHOLD && GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_PARALYSIS))
|
||
|
return X2_SPELL_AOEBEHAVIOR_IGNORE;
|
||
|
case SPELL_MIND_FOG:
|
||
|
if(GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_MIND_SPELLS))
|
||
|
return X2_SPELL_AOEBEHAVIOR_IGNORE;
|
||
|
case SPELL_CLOUD_OF_BEWILDERMENT:
|
||
|
if(nSpellID == SPELL_CLOUD_OF_BEWILDERMENT && (GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_POISON) || (GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_BLINDNESS) && (GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_MIND_SPELLS) || GetIsImmune(OBJECT_SELF,IMMUNITY_TYPE_STUN)))))
|
||
|
return X2_SPELL_AOEBEHAVIOR_IGNORE;
|
||
|
case SPELL_CLOUDKILL:
|
||
|
case SPELL_CREEPING_DOOM:
|
||
|
case SPELL_INCENDIARY_CLOUD:
|
||
|
case SPELL_ACID_FOG:
|
||
|
if(GetHasSpell(SPELL_GUST_OF_WIND))
|
||
|
return X2_SPELL_AOEBEHAVIOR_GUST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(GetModuleSwitchValue(MODULE_SWITCH_DISABLE_AI_DISPEL_AOE) == 0)
|
||
|
{
|
||
|
if(d100() > GetLocalInt(GetModule(),MODULE_VAR_AI_NO_DISPEL_AOE_CHANCE))
|
||
|
{
|
||
|
if(GetHasSpell(SPELL_LESSER_DISPEL))
|
||
|
return X2_SPELL_AOEBEHAVIOR_DISPEL_L;
|
||
|
if(GetHasSpell(SPELL_DISPEL_MAGIC))
|
||
|
return X2_SPELL_AOEBEHAVIOR_DISPEL_N;
|
||
|
if(GetHasSpell(SPELL_GREATER_DISPELLING))
|
||
|
return X2_SPELL_AOEBEHAVIOR_DISPEL_G;
|
||
|
if(GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION))
|
||
|
return X2_SPELL_AOEBEHAVIOR_DISPEL_M;
|
||
|
}
|
||
|
}
|
||
|
return X2_SPELL_AOEBEHAVIOR_FLEE;
|
||
|
}
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// GZ: 2003-Oct-15
|
||
|
// Removes all effects from nID without paying attention to the caster as
|
||
|
// the spell can from only one caster anyway
|
||
|
// By default, it will only cancel magical effects
|
||
|
//--------------------------------------------------------------------------
|
||
|
void GZRemoveSpellEffects(int nID,object oTarget, int bMagicalEffectsOnly = TRUE)
|
||
|
{
|
||
|
effect eEff = GetFirstEffect(oTarget);
|
||
|
while (GetIsEffectValid(eEff))
|
||
|
{
|
||
|
if (GetEffectSpellId(eEff) == nID)
|
||
|
{
|
||
|
if (GetEffectSubType(eEff) != SUBTYPE_MAGICAL && bMagicalEffectsOnly)
|
||
|
{
|
||
|
// ignore
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
RemoveEffect(oTarget,eEff);
|
||
|
}
|
||
|
}
|
||
|
eEff = GetNextEffect(oTarget);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// GZ: 2003-Oct-15
|
||
|
// A different approach for timing these spells that has the positive side
|
||
|
// effects of making the spell dispellable as well.
|
||
|
// I am using the VFX applied by the spell to track the remaining duration
|
||
|
// instead of adding the remaining runtime on the stack
|
||
|
//
|
||
|
// This function returns FALSE if a delayed Spell effect from nSpell_ID has
|
||
|
// expired. See x2_s0_bigby4.nss for details
|
||
|
//------------------------------------------------------------------------------
|
||
|
int GZGetDelayedSpellEffectsExpired(int nSpell_ID, object oTarget, object oCaster)
|
||
|
{
|
||
|
|
||
|
if (!GetHasSpellEffect(nSpell_ID,oTarget) )
|
||
|
{
|
||
|
DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------------
|
||
|
// GZ: 2003-Oct-15
|
||
|
// If the caster is dead or no longer there, cancel the spell, as it is
|
||
|
// directed
|
||
|
//--------------------------------------------------------------------------
|
||
|
if( !GetIsObjectValid(oCaster))
|
||
|
{
|
||
|
GZRemoveSpellEffects(nSpell_ID, oTarget);
|
||
|
DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
if (GetIsDead(oCaster))
|
||
|
{
|
||
|
DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID));
|
||
|
GZRemoveSpellEffects(nSpell_ID, oTarget);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|