Updated Invoking include to allow invoking past 3rd class. Updated epic spell include to allow epic spellcasting past 3rd class. Updated nwscript compiler for .35. Added .35 change log / notes.
495 lines
16 KiB
Plaintext
495 lines
16 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Invocation include: Miscellaneous
|
|
//:: tob_inc_tobfunc
|
|
//::///////////////////////////////////////////////
|
|
/** @file
|
|
Defines various functions and other stuff that
|
|
do something related to Invocation implementation.
|
|
|
|
Also acts as inclusion nexus for the general
|
|
invocation includes. In other words, don't include
|
|
them directly in your scripts, instead include this.
|
|
|
|
@author Fox
|
|
@date Created - 2008.1.25
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:://////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Constants */
|
|
//////////////////////////////////////////////////
|
|
|
|
const int INVOCATION_DRACONIC = 1;
|
|
const int INVOCATION_WARLOCK = 2;
|
|
|
|
const int INVOCATION_LEAST = 2;
|
|
const int INVOCATION_LESSER = 4;
|
|
const int INVOCATION_GREATER = 6;
|
|
const int INVOCATION_DARK = 8;
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Determines from what class's invocation list the currently casted
|
|
* invocation is cast from.
|
|
*
|
|
* @param oInvoker A creature invoking at this moment
|
|
* @return CLASS_TYPE_* constant of the class
|
|
*/
|
|
int GetInvokingClass(object oInvoker = OBJECT_SELF);
|
|
|
|
/**
|
|
* Determines the given creature's Invoker level. If a class is specified,
|
|
* then returns the Invoker level for that class. Otherwise, returns
|
|
* the Invoker level for the currently active invocation.
|
|
*
|
|
* @param oInvoker The creature whose Invoker level to determine
|
|
* @param nSpecificClass The class to determine the creature's Invoker
|
|
* level in.
|
|
* @param bPracticedInvoker If this is set, it will add the bunus from
|
|
* Practiced Invoker feat.
|
|
* @return The Invoker level
|
|
*/
|
|
int GetInvokerLevel(object oInvoker = OBJECT_SELF, int nSpecificClass = CLASS_TYPE_INVALID, int bPracticedInvoker = TRUE);
|
|
|
|
/**
|
|
* Determines whether a given creature uses Invocations.
|
|
* Requires either levels in an invocation-related class or
|
|
* natural Invocation ability based on race.
|
|
*
|
|
* @param oCreature Creature to test
|
|
* @return TRUE if the creature can use Invocations, FALSE otherwise.
|
|
*/
|
|
int GetIsInvocationUser(object oCreature);
|
|
|
|
/**
|
|
* Determines the given creature's highest undmodified Invoker level among it's
|
|
* invoking classes.
|
|
*
|
|
* @param oCreature Creature whose highest Invoker level to determine
|
|
* @return The highest unmodified Invoker level the creature can have
|
|
*/
|
|
int GetHighestInvokerLevel(object oCreature);
|
|
|
|
/**
|
|
* Determines whether a given class is an invocation-related class or not.
|
|
*
|
|
* @param nClass CLASS_TYPE_* of the class to test
|
|
* @return TRUE if the class is an invocation-related class, FALSE otherwise
|
|
*/
|
|
int GetIsInvocationClass(int nClass);
|
|
|
|
/**
|
|
* Gets the level of the invocation being currently cast.
|
|
* WARNING: Return value is not defined when an invocation is not being cast.
|
|
*
|
|
* @param oInvoker The creature currently casting an invocation
|
|
* @return The level of the invocation being cast
|
|
*/
|
|
int GetInvocationLevel(object oInvoker);
|
|
|
|
/**
|
|
* Returns the name of the invocation
|
|
*
|
|
* @param nSpellId SpellId of the invocation
|
|
*/
|
|
string GetInvocationName(int nSpellId);
|
|
|
|
/**
|
|
* Calculates how many invoker levels are gained by a given creature from
|
|
* it's levels in prestige classes.
|
|
*
|
|
* @param oCreature Creature to calculate added invoker levels for
|
|
* @return The number of invoker levels gained
|
|
*/
|
|
int GetInvocationPRCLevels(object oCaster);
|
|
|
|
/**
|
|
* Determines which of the character's classes is their highest or first invocation
|
|
* casting class, if any. This is the one which gains invoker level raise benefits
|
|
* from prestige classes.
|
|
*
|
|
* @param oCreature Creature whose classes to test
|
|
* @return CLASS_TYPE_* of the first invocation casting class,
|
|
* CLASS_TYPE_INVALID if the creature does not possess any.
|
|
*/
|
|
int GetPrimaryInvocationClass(object oCreature = OBJECT_SELF);
|
|
|
|
/**
|
|
* Determines the position of a creature's first invocation casting class, if any.
|
|
*
|
|
* @param oCreature Creature whose classes to test
|
|
* @return The position of the first invocation class {1, 2, 3} or 0 if
|
|
* the creature possesses no levels in invocation classes.
|
|
*/
|
|
int GetFirstInvocationClassPosition(object oCreature = OBJECT_SELF);
|
|
|
|
/**
|
|
* Ruterns the number of damage dices that oInvokers eldritch blast has
|
|
*
|
|
* @param oInvoker Creature whose blast to test
|
|
* @param nInvokerLevel Invoker level
|
|
* @return The number of damage dices
|
|
*/
|
|
int GetBlastDamageDices(object oInvoker, int nInvokerLevel);
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Includes */
|
|
//////////////////////////////////////////////////
|
|
|
|
//#include "prc_alterations"
|
|
#include "inv_inc_invknown"
|
|
#include "inv_inc_invoke"
|
|
#include "inv_inc_blast"
|
|
#include "prc_add_spell_dc"
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Internal functions */
|
|
//////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function definitions */
|
|
//////////////////////////////////////////////////
|
|
|
|
int GetInvokingClass(object oInvoker = OBJECT_SELF)
|
|
{
|
|
return GetLocalInt(oInvoker, PRC_INVOKING_CLASS) - 1;
|
|
}
|
|
|
|
/*int PracticedInvoker(object oInvoker, int iInvokingClass, int iInvokingLevels)
|
|
{
|
|
int nFeat;
|
|
int iAdjustment = GetHitDice(oInvoker) - iInvokingLevels;
|
|
if(iAdjustment > 4) iAdjustment = 4;
|
|
if(iAdjustment < 0) iAdjustment = 0;
|
|
|
|
switch(iInvokingClass)
|
|
{
|
|
case CLASS_TYPE_DRAGONFIRE_ADEPT: nFeat = FEAT_PRACTICED_INVOKER_DRAGONFIRE_ADEPT; break;
|
|
case CLASS_TYPE_WARLOCK: nFeat = FEAT_PRACTICED_INVOKER_WARLOCK; break;
|
|
default: return 0;
|
|
}
|
|
|
|
if(GetHasFeat(nFeat, oInvoker))
|
|
return iAdjustment;
|
|
|
|
return 0;
|
|
}*/
|
|
|
|
int GetInvokerLevel(object oInvoker = OBJECT_SELF, int nSpecificClass = CLASS_TYPE_INVALID, int bPracticedInvoker = TRUE)
|
|
{
|
|
int nAdjust = GetLocalInt(oInvoker, PRC_CASTERLEVEL_ADJUSTMENT);
|
|
int nLevel = GetLocalInt(oInvoker, PRC_CASTERLEVEL_OVERRIDE);
|
|
|
|
// For when you want to assign the caster level.
|
|
if(nLevel)
|
|
{
|
|
if(DEBUG) SendMessageToPC(oInvoker, "Forced-level Invoking at level " + IntToString(GetCasterLevel(oInvoker)));
|
|
//DelayCommand(1.0, DeleteLocalInt(oInvoker, PRC_CASTERLEVEL_OVERRIDE));
|
|
return nLevel + nAdjust;
|
|
}
|
|
|
|
if(nSpecificClass == CLASS_TYPE_INVALID)
|
|
nSpecificClass = GetInvokingClass(oInvoker);
|
|
|
|
if(nSpecificClass != -1)
|
|
{
|
|
if(!GetIsInvocationClass(nSpecificClass))
|
|
return 0;
|
|
|
|
if(nSpecificClass == CLASS_TYPE_DRAGON_SHAMAN)
|
|
nLevel = max(GetLevelByClass(nSpecificClass, oInvoker) - 4, 1); // Can't go below 1
|
|
else
|
|
nLevel = GetLevelByClass(nSpecificClass, oInvoker);
|
|
if(DEBUG) DoDebug("Invoker Class Level is: " + IntToString(nLevel));
|
|
if(GetPrimaryInvocationClass(oInvoker) == nSpecificClass)
|
|
{
|
|
//Invoker level is class level + any arcane spellcasting or invoking levels in any PRCs
|
|
nLevel += GetInvocationPRCLevels(oInvoker);
|
|
}
|
|
/*if(bPracticedInvoker)
|
|
nLevel += PracticedInvoker(oInvoker, nSpecificClass, nLevel);*/
|
|
}
|
|
else
|
|
nLevel = GetLevelByClass(GetPrimaryInvocationClass(oInvoker), oInvoker);
|
|
|
|
nLevel += nAdjust;
|
|
SetLocalInt(oInvoker, "InvokerLevel", nLevel);
|
|
return nLevel;
|
|
}
|
|
|
|
int GetIsInvocationUser(object oCreature)
|
|
{
|
|
return !!(GetLevelByClass(CLASS_TYPE_DRAGONFIRE_ADEPT, oCreature) ||
|
|
GetLevelByClass(CLASS_TYPE_WARLOCK, oCreature) ||
|
|
GetLevelByClass(CLASS_TYPE_DRAGON_SHAMAN, oCreature)
|
|
);
|
|
}
|
|
|
|
|
|
int GetHighestInvokerLevel(object oCreature)
|
|
{
|
|
int n = 0;
|
|
int nHighest;
|
|
int nTemp;
|
|
|
|
while(n <= 8)
|
|
{
|
|
if(GetClassByPosition(n, oCreature) != CLASS_TYPE_INVALID)
|
|
{
|
|
nTemp = GetInvokerLevel(oCreature, GetClassByPosition(n, oCreature));
|
|
|
|
if(nTemp > nHighest)
|
|
nHighest = nTemp;
|
|
}
|
|
n++;
|
|
|
|
}
|
|
|
|
return nHighest;
|
|
}
|
|
|
|
/* int GetHighestInvokerLevel(object oCreature)
|
|
{
|
|
return max(max(GetClassByPosition(1, oCreature) != CLASS_TYPE_INVALID ? GetInvokerLevel(oCreature, GetClassByPosition(1, oCreature)) : 0,
|
|
GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID ? GetInvokerLevel(oCreature, GetClassByPosition(2, oCreature)) : 0
|
|
),
|
|
GetClassByPosition(3, oCreature) != CLASS_TYPE_INVALID ? GetInvokerLevel(oCreature, GetClassByPosition(3, oCreature)) : 0
|
|
);
|
|
} */
|
|
|
|
int GetIsInvocationClass(int nClass)
|
|
{
|
|
int bTest = nClass == CLASS_TYPE_DRAGONFIRE_ADEPT
|
|
|| nClass == CLASS_TYPE_WARLOCK
|
|
|| nClass == CLASS_TYPE_DRAGON_SHAMAN;
|
|
return bTest;
|
|
}
|
|
|
|
int GetInvocationLevel(object oInvoker)
|
|
{
|
|
return GetLocalInt(oInvoker, PRC_INVOCATION_LEVEL);
|
|
}
|
|
|
|
string GetInvocationName(int nSpellId)
|
|
{
|
|
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellId)));
|
|
}
|
|
|
|
int GetInvocationPRCLevels(object oCaster)
|
|
{
|
|
int nLevel = GetLevelByClass(CLASS_TYPE_HELLFIRE_WARLOCK, oCaster)
|
|
+ GetLevelByClass(CLASS_TYPE_ELDRITCH_DISCIPLE, oCaster)
|
|
+ GetLevelByClass(CLASS_TYPE_ELDRITCH_THEURGE, oCaster);
|
|
|
|
//_some_ arcane spellcasting levels boost invocations
|
|
if(GetLocalInt(oCaster, "INV_Caster") == 2)
|
|
nLevel += (GetLevelByClass(CLASS_TYPE_ACOLYTE, oCaster) + 1) / 2
|
|
+ (GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oCaster) + 1) / 2
|
|
+ GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST, oCaster)
|
|
+ GetLevelByClass(CLASS_TYPE_MAESTER, oCaster)
|
|
+ (GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT, oCaster) + 1) / 2;
|
|
|
|
return nLevel;
|
|
}
|
|
|
|
int GetPrimaryInvocationClass(object oCreature = OBJECT_SELF)
|
|
{
|
|
int nClass;
|
|
|
|
if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE)) //: Kinda pointless for .35
|
|
{
|
|
int nInvocationPos = GetFirstInvocationClassPosition(oCreature);
|
|
if (!nInvocationPos) return CLASS_TYPE_INVALID; // no invoking class
|
|
|
|
nClass = GetClassByPosition(nInvocationPos, oCreature);
|
|
}
|
|
else
|
|
{
|
|
int nClassLvl;
|
|
int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8;
|
|
int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl;
|
|
|
|
nClass1 = GetClassByPosition(1, oCreature);
|
|
nClass2 = GetClassByPosition(2, oCreature);
|
|
nClass3 = GetClassByPosition(3, oCreature);
|
|
nClass4 = GetClassByPosition(4, oCreature);
|
|
nClass5 = GetClassByPosition(5, oCreature);
|
|
nClass6 = GetClassByPosition(6, oCreature);
|
|
nClass7 = GetClassByPosition(7, oCreature);
|
|
nClass8 = GetClassByPosition(8, oCreature);
|
|
|
|
if(GetIsInvocationClass(nClass1)) nClass1Lvl = GetLevelByClass(nClass1, oCreature);
|
|
if(GetIsInvocationClass(nClass2)) nClass2Lvl = GetLevelByClass(nClass2, oCreature);
|
|
if(GetIsInvocationClass(nClass3)) nClass3Lvl = GetLevelByClass(nClass3, oCreature);
|
|
if(GetIsInvocationClass(nClass4)) nClass4Lvl = GetLevelByClass(nClass4, oCreature);
|
|
if(GetIsInvocationClass(nClass5)) nClass5Lvl = GetLevelByClass(nClass5, oCreature);
|
|
if(GetIsInvocationClass(nClass6)) nClass6Lvl = GetLevelByClass(nClass6, oCreature);
|
|
if(GetIsInvocationClass(nClass7)) nClass7Lvl = GetLevelByClass(nClass7, oCreature);
|
|
if(GetIsInvocationClass(nClass8)) nClass8Lvl = GetLevelByClass(nClass8, oCreature);
|
|
|
|
nClass = nClass1;
|
|
nClassLvl = nClass1Lvl;
|
|
|
|
if(nClass2Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass2;
|
|
nClassLvl = nClass2Lvl;
|
|
}
|
|
if(nClass3Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass3;
|
|
nClassLvl = nClass3Lvl;
|
|
}
|
|
if(nClass4Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass4;
|
|
nClassLvl = nClass4Lvl;
|
|
}
|
|
if(nClass5Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass5;
|
|
nClassLvl = nClass5Lvl;
|
|
}
|
|
if(nClass6Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass6;
|
|
nClassLvl = nClass6Lvl;
|
|
}
|
|
if(nClass7Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass7;
|
|
nClassLvl = nClass7Lvl;
|
|
}
|
|
if(nClass8Lvl > nClassLvl)
|
|
{
|
|
nClass = nClass8;
|
|
nClassLvl = nClass8Lvl;
|
|
}
|
|
|
|
if(nClassLvl == 0)
|
|
nClass = CLASS_TYPE_INVALID;
|
|
}
|
|
|
|
return nClass;
|
|
}
|
|
|
|
int GetFirstInvocationClassPosition(object oCreature = OBJECT_SELF)
|
|
{
|
|
if (GetIsInvocationClass(GetClassByPosition(1, oCreature)))
|
|
return 1;
|
|
if (GetIsInvocationClass(GetClassByPosition(2, oCreature)))
|
|
return 2;
|
|
if (GetIsInvocationClass(GetClassByPosition(3, oCreature)))
|
|
return 3;
|
|
if (GetIsInvocationClass(GetClassByPosition(4, oCreature)))
|
|
return 4;
|
|
if (GetIsInvocationClass(GetClassByPosition(5, oCreature)))
|
|
return 5;
|
|
if (GetIsInvocationClass(GetClassByPosition(6, oCreature)))
|
|
return 6;
|
|
if (GetIsInvocationClass(GetClassByPosition(7, oCreature)))
|
|
return 7;
|
|
if (GetIsInvocationClass(GetClassByPosition(8, oCreature)))
|
|
return 8;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int GetInvocationSaveDC(object oTarget, object oCaster, int nSpellID = -1)
|
|
{
|
|
int nDC;
|
|
// For when you want to assign the caster DC
|
|
//this does not take feat/race/class into account, it is an absolute override
|
|
if (GetLocalInt(oCaster, PRC_DC_TOTAL_OVERRIDE) != 0)
|
|
{
|
|
nDC = GetLocalInt(oCaster, PRC_DC_TOTAL_OVERRIDE);
|
|
DoDebug("Forced-DC PRC_DC_TOTAL_OVERRIDE casting at DC " + IntToString(nDC));
|
|
return nDC;
|
|
}
|
|
// For when you want to assign the caster DC
|
|
//this does take feat/race/class into account, it only overrides the baseDC
|
|
if(GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE) > 0)
|
|
{
|
|
nDC = GetLocalInt(oCaster, PRC_DC_BASE_OVERRIDE);
|
|
if(DEBUG) DoDebug("Forced Base-DC casting at DC " + IntToString(nDC));
|
|
}
|
|
else
|
|
{
|
|
if(nSpellID == -1) nSpellID = PRCGetSpellId();
|
|
//10+spelllevel+stat(cha default)
|
|
nDC = 10;
|
|
nDC += StringToInt(Get2DACache("Spells", "Innate", nSpellID));
|
|
nDC += GetAbilityModifier(ABILITY_CHARISMA, oCaster);
|
|
}
|
|
nDC += GetChangesToSaveDC(oTarget, oCaster, nSpellID, 0);
|
|
|
|
return nDC;
|
|
}
|
|
|
|
void ClearInvocationLocalVars(object oPC)
|
|
{
|
|
//Invocations
|
|
if (DEBUG) DoDebug("Clearing invocation flags");
|
|
DeleteLocalObject(oPC, "ChillingFog");
|
|
//Endure Exposure wearing off
|
|
array_delete(oPC, "BreathProtected");
|
|
DeleteLocalInt(oPC, "DragonWard");
|
|
|
|
//cleaning targets of Endure exposure cast by resting caster
|
|
if (array_exists(oPC, "BreathProtectTargets"))
|
|
{
|
|
if(DEBUG) DoDebug("Checking for casts of Endure Exposure");
|
|
int nBPTIndex = 0;
|
|
int bCasterDone = FALSE;
|
|
int bTargetDone = FALSE;
|
|
object oBreathTarget;
|
|
while(!bCasterDone)
|
|
{
|
|
oBreathTarget = array_get_object(oPC, "BreathProtectTargets", nBPTIndex);
|
|
if(DEBUG) DoDebug("Possible target: " + GetName(oBreathTarget) + " - " + ObjectToString(oBreathTarget));
|
|
if(oBreathTarget != OBJECT_INVALID)
|
|
{
|
|
//replace caster with target... always immune to own breath, so good way to erase caster from array without deleting whole array
|
|
int nBPIndex = 0;
|
|
|
|
while(!bTargetDone)
|
|
{
|
|
if(DEBUG) DoDebug("Checking " + GetName(oBreathTarget));
|
|
//if it matches, remove and end
|
|
if(array_get_object(oBreathTarget, "BreathProtected", nBPIndex) == oPC)
|
|
{
|
|
array_set_object(oBreathTarget, "BreathProtected", nBPIndex, oBreathTarget);
|
|
bTargetDone = TRUE;
|
|
if(DEBUG) DoDebug("Found caster, clearing.");
|
|
}
|
|
//if it is not end of array, keep going
|
|
else if(array_get_object(oBreathTarget, "BreathProtected", nBPTIndex) != OBJECT_INVALID)
|
|
{
|
|
nBPIndex++;
|
|
}
|
|
else
|
|
bTargetDone = TRUE;
|
|
|
|
}
|
|
|
|
nBPTIndex++;
|
|
bTargetDone = FALSE;
|
|
|
|
}
|
|
else
|
|
{
|
|
array_delete(oPC, "BreathProtectTargets");
|
|
bCasterDone = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test main
|
|
//void main(){}
|