Major include update for 8 class support

Major include update for 8 class support

inv_inc_invfunc.nss		- GetHighestInvokerLevel(), GetFirstInvocationClassPosition(), GetPrimaryInvocationClass()

inc_epicspellfnc.nss	- GetCanLearnSeed()

inc_newspellbook.nss 	- CheckNewSpellbooks(), GetSpellslotLevel()

moi_inc_moifunc.nss		- GetHighestMeldshaperLevel(), GetPrimaryIncarnumClass(), GetFirstIncarnumClassPosition()

nw_o2_coninclude.nss	- nDetermineClassToUse()

prc_inc_castlvl.nss		- GetArcanePRCLevels(), GetDivinePRCLevels(), GetFirstArcaneClassPosition(), GetFirstDivineClassPosition(), GetPrimaryArcaneClass(), GetPrimaryDivineClass(), GetPrimarySpellcastingClass(), UrPriestCL(), GetLevelByTypeArcane(), GetLevelByTypeDivine(), [Needs marker feats]

prc_inc_clsfunc.nss		- [Needs marker feats]

prc_inc_core.nss		- PRCGetSpellLevel(), UseNewSpellBook(), PRCGetHasSpell(), PRCGetIsRealSpellKnown()

prc_inc_domain.nss		- CastDomainSpell()

prc_inc_function.nss	- SetupCharacterData(), [Needs marker feats]

prc_inc_itmrstr.nss		- _prc_inc_itmrstr_ApplyWizardry()

prc_inc_leadersh.nss	- StoreCohort()

prc_inc_spells.nss		- GetPrCAdjustedCasterLevelByType(), GetLevelByTypeArcaneFeats(), GetLevelByTypeDivineFeats(), PRCDecrementRemainingSpellUses(), PRCGetSpellUsesLeft()

prc_shifter_info.nss	- _prc_inc_PrintDebugItem(), _prc_inc_PrintShape()

psi_inc_core.nss		- GetHighestManifesterLevel(), GetPrimaryPsionicClass(), GetFirstPsionicClassPosition()

shd_inc_shdfunc.nss		- GetHighestShadowcasterLevel(), GetPrimaryShadowMagicClass(), GetFirstShadowMagicClassPosition()

tob_inc_recovery.nss	- RecoverPrCAbilities()

tob_inc_tobfunc.nss		- GetHighestInitiatorLevel(), GetPrimaryBladeMagicClass(), GetFirstBladeMagicClassPosition()

true_inc_trufunc.nss	- GetHighestTrueSpeakerLevel()
This commit is contained in:
Jaysyn904 2023-03-11 01:13:46 -05:00
parent b266d1350e
commit a668275943
19 changed files with 25873 additions and 0 deletions

View File

@ -0,0 +1,275 @@
//:: Updated for .35 by Jaysyn 2023/03/10
int GetFeatForSeed(int nSeedID);
int GetIPForSeed(int nSeedID);
int GetDCForSeed(int nSeedID);
int GetClassForSeed(int nSeedID);
int GetCanLearnSeed(object oPC, int nSeedID);
int GetSeedFromAbrev(string sAbrev);
string GetNameForSeed(int nSeedID);
int GetDCForSpell(int nSpellID);
int GetFeatForSpell(int nSpellID);
int GetResearchFeatForSpell(int nSpellID);
int GetIPForSpell(int nSpellID);
int GetResearchIPForSpell(int nSpellID);
int GetCastXPForSpell(int nSpellID);
string GetSchoolForSpell(int nSpellID);
int GetR1ForSpell(int nSpellID);
int GetR2ForSpell(int nSpellID);
int GetR3ForSpell(int nSpellID);
int GetR4ForSpell(int nSpellID);
string GetNameForSpell(int nSpellID);
int GetSpellFromAbrev(string sAbrev);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "inc_utility"
//#include "inc_epicspelldef"
// SEED FUNCTIONS
int GetFeatForSeed(int nSeedID)
{
return StringToInt(Get2DACache("epicspellseeds", "FeatID", nSeedID));
}
int GetIPForSeed(int nSeedID)
{
return StringToInt(Get2DACache("epicspellseeds", "FeatIPID", nSeedID));
}
int GetDCForSeed(int nSeedID)
{
return StringToInt(Get2DACache("epicspellseeds", "DC", nSeedID));
}
int GetClassForSeed(int nSeedID)
{
return StringToInt(Get2DACache("epicspellseeds", "Class", nSeedID));
}
int GetSeedFromAbrev(string sAbrev)
{
sAbrev = GetStringLowerCase(sAbrev);
if(GetStringLeft(sAbrev, 8) == "epic_sd_")
sAbrev = GetStringRight(sAbrev, GetStringLength(sAbrev)-8);
int i = 0;
string sLabel = GetStringLowerCase(Get2DACache("epicspellseeds", "LABEL", i));
while(sLabel != "")
{
if(sAbrev == sLabel)
return i;
i++;
sLabel = GetStringLowerCase(Get2DACache("epicspellseeds", "LABEL", i));
}
return -1;
}
string GetNameForSeed(int nSeedID)
{
int nFeat = GetFeatForSeed(nSeedID);
string sName = GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeat)));
return sName;
}
/*
Bit-flags set in epicspellseeds.2da in Class column
used to restrict access to epic spell seeds for some classes
ie: 13 means that only clerics, sorcerers and wizards can learn that seed (1 + 4 + 8),
all classes can use == 32767
*/
int _Class2BitFlag(int nClass)
{
switch(nClass)
{
case CLASS_TYPE_CLERIC: return 1;
case CLASS_TYPE_DRUID: return 2;
case CLASS_TYPE_SORCERER: return 4;
case CLASS_TYPE_WIZARD: return 8;
case CLASS_TYPE_HEALER: return 16;
case CLASS_TYPE_BEGUILER: return 32;
case CLASS_TYPE_SUBLIME_CHORD: return 64;
case CLASS_TYPE_DREAD_NECROMANCER: return 128;
case CLASS_TYPE_MYSTIC: return 256;
case CLASS_TYPE_ARCHIVIST: return 512;
case CLASS_TYPE_SHAMAN: return 4096;
case CLASS_TYPE_FAVOURED_SOUL: return 8192;
case CLASS_TYPE_WARMAGE: return 16384;
case CLASS_TYPE_UR_PRIEST: return 1;
case CLASS_TYPE_BLIGHTER: return 2;
}
return -1;
}
int _CheckEpicSpellcastingForClass(object oPC, int nClass)
{
if(GetHitDice(oPC) < 21)
return FALSE;
switch(nClass)
{
case CLASS_TYPE_CLERIC: return GetIsEpicCleric(oPC);
case CLASS_TYPE_DRUID: return GetIsEpicDruid(oPC);
case CLASS_TYPE_SORCERER: return GetIsEpicSorcerer(oPC);
case CLASS_TYPE_WIZARD: return GetIsEpicWizard(oPC);
case CLASS_TYPE_HEALER: return GetIsEpicHealer(oPC);
case CLASS_TYPE_BEGUILER: return GetIsEpicBeguiler(oPC);
case CLASS_TYPE_SUBLIME_CHORD: return GetIsEpicSublimeChord(oPC);
case CLASS_TYPE_DREAD_NECROMANCER: return GetIsEpicDreadNecromancer(oPC);
case CLASS_TYPE_ARCHIVIST: return GetIsEpicArchivist(oPC);
case CLASS_TYPE_SHAMAN: return GetIsEpicShaman(oPC);
case CLASS_TYPE_FAVOURED_SOUL: return GetIsEpicFavSoul(oPC);
case CLASS_TYPE_WARMAGE: return GetIsEpicWarmage(oPC);
case CLASS_TYPE_BLIGHTER: return GetIsEpicBlighter(oPC);
case CLASS_TYPE_UR_PRIEST: return GetIsEpicUrPriest(oPC);
}
return FALSE;
}
int GetCanLearnSeed(object oPC, int nSeedID)
{
int nRestr = GetClassForSeed(nSeedID);
int i, nClass;
for(i = 1; i <= 8; i++)
{
nClass = GetClassByPosition(i, oPC);
if(_CheckEpicSpellcastingForClass(oPC, nClass)//this class has epic spellcasting
&& (nRestr & _Class2BitFlag(nClass)))//and was added to class column in epicspellseeds.2da
{
return TRUE;
}
}
return FALSE;
}
// SPELL FUNCTIONS
int GetDCForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "DC", nSpellID));
}
int GetFeatForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "SpellFeatID", nSpellID));
}
int GetResearchFeatForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "ResFeatID", nSpellID));
}
int GetIPForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "SpellFeatIPID", nSpellID));
}
int GetResearchIPForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "ResFeatIPID", nSpellID));
}
int GetCastXPForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "CastingXP", nSpellID));
}
string GetSchoolForSpell(int nSpellID)
{
return Get2DACache("epicspells", "School", nSpellID);
}
int GetR1ForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "Prereq1", nSpellID));
}
int GetR2ForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "Prereq2", nSpellID));
}
int GetR3ForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "Prereq3", nSpellID));
}
int GetR4ForSpell(int nSpellID)
{
return StringToInt(Get2DACache("epicspells", "Prereq4", nSpellID));
}
int GetS1ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed1", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetS2ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed2", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetS3ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed3", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetS4ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed4", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetS5ForSpell(int nSpellID)
{
string sSeed = Get2DACache("epicspells", "PrereqSeed5", nSpellID);
if(sSeed == "")
return -1;
return StringToInt(sSeed);
}
int GetSpellFromAbrev(string sAbrev)
{
sAbrev = GetStringLowerCase(sAbrev);
if(GetStringLeft(sAbrev, 8) == "epic_sp_")
sAbrev = GetStringRight(sAbrev, GetStringLength(sAbrev)-8);
if(DEBUG) DoDebug("sAbrew to check vs: " + sAbrev);
int i = 0;
string sLabel = GetStringLowerCase(Get2DACache("epicspells", "LABEL", i));
while(sLabel != "")
{
if(DEBUG) DoDebug("sLabel to check vs: " + sLabel);
if(sAbrev == sLabel)
{
if(DEBUG) DoDebug("SpellID: " + IntToString(i));
return i;
}
i++;
sLabel = GetStringLowerCase(Get2DACache("epicspells", "LABEL", i));
}
return -1;
}
string GetNameForSpell(int nSpellID)
{
int nFeat = GetFeatForSpell(nSpellID);
string sName = GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeat)));
return sName;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,496 @@
//::///////////////////////////////////////////////
//:: Invocation include: Miscellaneous
//:: inv_inc_invfunc
//::///////////////////////////////////////////////
/** @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
Updated for .35 by Jaysyn 2023/03/10
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//////////////////////////////////////////////////
/* 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(){}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,729 @@
/* Core functions taken from high up the branch
which are needed lower. */
//:: Updated for .35 by Jaysyn 2023/03/10
//////////////////////////////////////////////////
/* Function Prototypes */
//////////////////////////////////////////////////
// wrapper for getspelltargetlocation
location PRCGetSpellTargetLocation(object oCaster = OBJECT_SELF);
// Avoids adding passive spellcasting to the character's action queue by
// creating an object specifically to cast the spell on the character.
//
// NOTE: The spell script must refer to the PC as PRCGetSpellTargetObject()
// otherwise this function WILL NOT WORK. Do not make any assumptions
// about the PC being OBJECT_SELF.
void ActionCastSpellOnSelf(int iSpell, int nMetaMagic = METAMAGIC_NONE, object oTarget = OBJECT_SELF);
// This is a wrapper function that causes OBJECT_SELF to fire the defined spell
// at the defined level. The target is automatically the object or location
// that the user selects. Useful for SLA's to perform the casting of a true
// spell. This is useful because:
//
// 1) If the original's spell script is updated, so is this one.
// 2) The spells are identified as the true spell. That is, they ARE the true spell.
// 3) Spellhooks (such as item crafting) that can only identify true spells
// will easily work.
//
// This function should only be used when SLA's are meant to simulate true
// spellcasting abilities, such as those seen when using feats with subradials
// to simulate spellbooks.
void ActionCastSpell(int iSpell, int iCasterLev = 0, int iBaseDC = 0, int iTotalDC = 0,
int nMetaMagic = METAMAGIC_NONE, int nClass = CLASS_TYPE_INVALID,
int bUseOverrideTargetLocation=FALSE, int bUseOverrideTargetObject=FALSE,
object oOverrideTarget=OBJECT_INVALID, int bInstantCast=TRUE, int bUseOverrideMetaMagic=FALSE);
/**
* Checks whether the given creature is committing an action, or
* under such effects that cause a breach of concentration.
*
* @param oConcentrator The creature to test
* @return TRUE if concentration is broken, FALSE otherwise
*/
int GetBreakConcentrationCheck(object oConcentrator);
/**
* Checks for breaks in concentration for an ongoing effect, and removes
* the effect if concentration is broken.
*
* @param oCaster The creature who cast the effect
* @param SpellID The id of the spell the effect belongs to
* @param oTarget The creature or object that is the target of the effect
* @param nDuration The duration the effect lasts in seconds.
*/
void CheckConcentrationOnEffect(object oCaster, int SpellID, object oTarget, int nDuration);
// gets the spell level adjustment to the nMetaMagic, including boni from the Improved Metamagic (epic) feat
int GetMetaMagicSpellLevelAdjustment(int nMetaMagic);
// Returns true if a spellcaster
int GetIsBioSpellCastClass(int nClass);
// Returns true for spell casters with spellbooks
int GetIsNSBClass(int nClass);
// returns the spelllevel of nSpell as it can be cast by oCreature
int PRCGetSpellLevel(object oCreature, int nSpell);
// returns if a character should be using the newspellbook when casting
int UseNewSpellBook(object oCreature);
// wrapper for GetHasSpell, works for newspellbook 'fake' spells too
// should return 0 if called with a normal spell when a character should be using the newspellbook
int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF);
// checks if oPC knows the specified spell
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
int PRCGetIsRealSpellKnown(int nRealSpellID, object oPC = OBJECT_SELF);
// checks if oPC knows the specified spell
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
// this will only check the spellbook of the class specified
int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJECT_SELF);
//routes to action cast spell, but puts a wrapper around to tell other functions its a
//SLA, so dont craft etc
//also defaults the totalDC to 10+spellevel+chamod
// moved from prc_inc_racial
void DoRacialSLA(int nSpellID, int nCasterlevel = 0, int nTotalDC = 0, int bInstantCast = FALSE);
/**
* Deletes a stored manifestation structure.
*
* @param oObject The object on which the structure is stored
* @param sName The name under which the structure is stored
*/
void DeleteLocalManifestation(object oObject, string sName);
/**
* Deletes a stored mystery structure.
*
* @param oObject The object on which the structure is stored
* @param sName The name under which the structure is stored
*/
void DeleteLocalMystery(object oObject, string sName);
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
// metamagic spell level adjustments for Bioware provided metamagic feats
const int METAMAGIC_EXTEND_LEVEL = 1;
const int METAMAGIC_SILENT_LEVEL = 1;
const int METAMAGIC_STILL_LEVEL = 1;
const int METAMAGIC_EMPOWER_LEVEL = 2;
const int METAMAGIC_MAXIMIZE_LEVEL = 3;
const int METAMAGIC_QUICKEN_LEVEL = 4;
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "lookup_2da_spell"
#include "inc_lookups"
#include "prc_inc_damage"
#include "prc_inc_sb_const" // Spell Book Constants
#include "x0_i0_position"
/*
access to prc_inc_nwscript via prc_inc_damage
access to PRCGetSpell* via prc_inc_damage
*/
//////////////////////////////////////////////////
/* Function Definitions */
//////////////////////////////////////////////////
//wrapper for GetSpellTargetLocation()
location PRCGetSpellTargetLocation(object oCaster = OBJECT_SELF)
{
// check if there is an override location on the module, and return that
// bioware did not define a LOCATION_INVALID const, so we must signal a valid override location by setting a local int on the module
if(GetLocalInt(GetModule(), PRC_SPELL_TARGET_LOCATION_OVERRIDE))
{
if (DEBUG) DoDebug("PRCGetSpellTargetLocation: found override target location on module");
return GetLocalLocation(GetModule(), PRC_SPELL_TARGET_LOCATION_OVERRIDE);
}
// check if there is an override location on the caster, and return that
// bioware did not define a LOCATION_INVALID const, so we signal a valid override location by setting a local int on oCaster
if (GetLocalInt(oCaster, PRC_SPELL_TARGET_LOCATION_OVERRIDE))
{
if (DEBUG) DoDebug("PRCGetSpellTargetLocation: found override target location on caster "+GetName(oCaster));
return GetLocalLocation(oCaster, PRC_SPELL_TARGET_LOCATION_OVERRIDE);
}
// The rune/gem/skull always targets the one who activates it.
object oItem = PRCGetSpellCastItem(oCaster);
if(GetIsObjectValid(oItem) && (GetResRef(oItem) == "prc_rune_1" ||
GetResRef(oItem) == "prc_skulltalis" || GetTag(oItem) == "prc_attunegem"))
return GetLocation(GetItemPossessor(oItem));
if (GetLocalInt(oCaster, "BlackLabyrinth") && d10() < 3)
return GenerateNewLocationFromLocation(GetSpellTargetLocation(), FeetToMeters(5.0*d4()), IntToFloat(Random(360)), IntToFloat(Random(360)));
// if we made it here, we must use Bioware's function
return GetSpellTargetLocation();
}
void ActionCastSpellOnSelf(int iSpell, int nMetaMagic = METAMAGIC_NONE, object oTarget = OBJECT_SELF)
{
if(!GetIsObjectValid(oTarget)) oTarget = OBJECT_SELF;
object oCastingObject = CreateObject(OBJECT_TYPE_PLACEABLE, "x0_rodwonder", GetLocation(oTarget));
AssignCommand(oCastingObject, ActionCastSpellAtObject(iSpell, oTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
if (DEBUG) DoDebug("ActionCastSpellOnSelf: Casting Spell "+IntToString(iSpell)+" on "+GetName(oTarget));
DestroyObject(oCastingObject, 6.0);
}
void ActionCastSpell(int iSpell, int iCasterLev = 0, int iBaseDC = 0, int iTotalDC = 0,
int nMetaMagic = METAMAGIC_NONE, int nClass = CLASS_TYPE_INVALID,
int bUseOverrideTargetLocation=FALSE, int bUseOverrideTargetObject=FALSE,
object oOverrideTarget=OBJECT_INVALID, int bInstantCast=TRUE, int bUseOverrideMetaMagic=FALSE)
{
//if its a hostile spell, clear the action queue
//this stops people stacking hostile spells to be instacast
//at the end, for example when coming out of invisibility
// X - hope this is not needed if spells are cast normally
//if(Get2DACache("spells", "HostileSetting", iSpell) == "1" && bInstantCast)
// ClearAllActions();
object oTarget = PRCGetSpellTargetObject();
location lLoc = PRCGetSpellTargetLocation();
//set the overriding values
if (iCasterLev != 0)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE, iCasterLev));
if (iTotalDC != 0)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE, iTotalDC));
if (iBaseDC != 0)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE, iBaseDC));
if (nClass != CLASS_TYPE_INVALID)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE, nClass));
if (bUseOverrideMetaMagic)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE, nMetaMagic));
else if (nMetaMagic != METAMAGIC_NONE)
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_METAMAGIC_ADJUSTMENT, nMetaMagic));
if (bUseOverrideTargetLocation)
{
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE, TRUE));
//location must be set outside of this function at the moment
//cant pass a location into a function as an optional parameter
//go bioware for not defining an invalid location constant
}
if (bUseOverrideTargetObject)
{
ActionDoCommand(SetLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE, TRUE));
ActionDoCommand(SetLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE, oOverrideTarget));
}
ActionDoCommand(SetLocalInt(OBJECT_SELF, "UsingActionCastSpell", TRUE));
if(DEBUG) DoDebug("ActionCastSpell SpellId: " + IntToString(iSpell));
if(DEBUG) DoDebug("ActionCastSpell Caster Level: " + IntToString(iCasterLev));
if(DEBUG) DoDebug("ActionCastSpell Base DC: " + IntToString(iBaseDC));
if(DEBUG) DoDebug("ActionCastSpell Total DC: " + IntToString(iTotalDC));
if(DEBUG) DoDebug("ActionCastSpell Metamagic: " + IntToString(nMetaMagic));
if(DEBUG) DoDebug("ActionCastSpell Caster Class: " + IntToString(nClass));
if(DEBUG) DoDebug("ActionCastSpell Target: " + GetName(oTarget));
if(DEBUG) DoDebug("ActionCastSpell Override Target: " + GetName(oOverrideTarget));
//cast the spell
if (GetIsObjectValid(oOverrideTarget))
ActionCastSpellAtObject(iSpell, oOverrideTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
else if (GetIsObjectValid(oTarget))
ActionCastSpellAtObject(iSpell, oTarget, nMetaMagic, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
else
ActionCastSpellAtLocation(iSpell, lLoc, nMetaMagic, TRUE, PROJECTILE_PATH_TYPE_DEFAULT, bInstantCast);
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, "UsingActionCastSpell"));
//clean up afterwards
if(bInstantCast)//give scripts time to read the variables
{
if (iCasterLev != 0)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE)));
if (iTotalDC != 0)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE)));
if (iBaseDC != 0)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE)));
if (nClass != CLASS_TYPE_INVALID)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE)));
if (nMetaMagic != METAMAGIC_NONE)
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE)));
if (bUseOverrideTargetLocation)
{
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE)));
//location must be set outside of this function at the moment
//cant pass a location into a function as an optional parameter
//go bioware for not defining an invalid location constant
}
if (bUseOverrideTargetObject)
{
ActionDoCommand(DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE)));
ActionDoCommand(DelayCommand(1.0, DeleteLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE)));
}
}
else
{
if (iCasterLev != 0)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_CASTERLEVEL_OVERRIDE));
if (iTotalDC != 0)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_DC_TOTAL_OVERRIDE));
if (iBaseDC != 0)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_DC_BASE_OVERRIDE));
if (nClass != CLASS_TYPE_INVALID)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_CASTERCLASS_OVERRIDE));
if (bUseOverrideMetaMagic)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_OVERRIDE));
else if (nMetaMagic != METAMAGIC_NONE)
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_METAMAGIC_ADJUSTMENT));
if (bUseOverrideTargetLocation)
{
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_LOCATION_OVERRIDE));
//location must be set outside of this function at the moment
//cant pass a location into a function as an optional parameter
//go bioware for not defining an invalid location constant
}
if (bUseOverrideTargetObject)
{
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE));
ActionDoCommand(DeleteLocalObject(OBJECT_SELF, PRC_SPELL_TARGET_OBJECT_OVERRIDE));
}
}
/*
//The problem with this approace is that the effects are then applies by the original spell, which could go wrong. What to do?
SetLocalInt(OBJECT_SELF, PRC_SPELLID_OVERRIDE, GetSpellId());
DelayCommand(1.0, DeleteLocalInt(OBJECT_SELF, PRC_SPELLID_OVERRIDE));
string sScript = Get2DACache("spells", "ImpactScript", iSpell);
ExecuteScript(sScript, OBJECT_SELF);
*/
}
int GetBreakConcentrationCheck(object oConcentrator)
{
if (GetHasSpellEffect(VESTIGE_DAHLVERNAR, oConcentrator) && !GetLocalInt(oConcentrator, "PactQuality"+IntToString(VESTIGE_DAHLVERNAR))) return TRUE;
int nAction = GetCurrentAction(oConcentrator);
// creature doing anything that requires attention and breaks concentration
if (nAction == ACTION_DISABLETRAP || nAction == ACTION_TAUNT ||
nAction == ACTION_PICKPOCKET || nAction == ACTION_ATTACKOBJECT ||
nAction == ACTION_COUNTERSPELL || nAction == ACTION_FLAGTRAP ||
nAction == ACTION_CASTSPELL || nAction == ACTION_ITEMCASTSPELL)
{
return TRUE;
}
//suffering a mental effect
effect e1 = GetFirstEffect(oConcentrator);
int nType;
while (GetIsEffectValid(e1))
{
nType = GetEffectType(e1);
if (nType == EFFECT_TYPE_STUNNED || nType == EFFECT_TYPE_PARALYZE ||
nType == EFFECT_TYPE_SLEEP || nType == EFFECT_TYPE_FRIGHTENED ||
nType == EFFECT_TYPE_PETRIFY || nType == EFFECT_TYPE_CONFUSED ||
nType == EFFECT_TYPE_DOMINATED || nType == EFFECT_TYPE_POLYMORPH)
{
return TRUE;
}
e1 = GetNextEffect(oConcentrator);
}
// add to on damage event
AddEventScript(oConcentrator, EVENT_VIRTUAL_ONDAMAGED, "prc_od_conc", FALSE, FALSE);
if(GetLocalInt(oConcentrator, "CONC_BROKEN")) // won't be set first time around regardless
{
DeleteLocalInt(oConcentrator, "CONC_BROKEN"); // reset for next spell
return TRUE;
}
return FALSE;
}
void CheckConcentrationOnEffect(object oCaster, int SpellID, object oTarget, int nDuration)
{
int nDur = GetLocalInt(oCaster, "Conc" + IntToString(SpellID));
if(GetBreakConcentrationCheck(oCaster) == TRUE && nDur < nDuration)
{
FloatingTextStringOnCreature("*Concentration Broken*", oCaster);
DeleteLocalInt(oCaster, "Conc" + IntToString(SpellID));
PRCRemoveSpellEffects(SpellID, oCaster, oTarget);
}
else if(nDur < nDuration)
{
SetLocalInt(oCaster, "Conc" + IntToString(SpellID), nDur + 3);
DelayCommand(3.0, CheckConcentrationOnEffect(oCaster, SpellID, oTarget, nDuration));
}
else
{
DeleteLocalInt(oCaster, "Conc" + IntToString(SpellID));
}
}
int PRCGetSpellLevelForClass(int nSpell, int nClass)
{
string sSpellLevel = "";
if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER)
sSpellLevel = Get2DACache("spells", "Wiz_Sorc", nSpell);
else if (nClass == CLASS_TYPE_RANGER)
sSpellLevel = Get2DACache("spells", "Ranger", nSpell);
else if (nClass == CLASS_TYPE_PALADIN)
sSpellLevel = Get2DACache("spells", "Paladin", nSpell);
else if (nClass == CLASS_TYPE_DRUID)
sSpellLevel = Get2DACache("spells", "Druid", nSpell);
else if (nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_UR_PRIEST || nClass == CLASS_TYPE_OCULAR)
sSpellLevel = Get2DACache("spells", "Cleric", nSpell);
else if (nClass == CLASS_TYPE_BARD)
sSpellLevel = Get2DACache("spells", "Bard", nSpell);
else if (nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK)
sSpellLevel = Get2DACache("spells", "Cultist", nSpell);
else if (nClass == CLASS_TYPE_NENTYAR_HUNTER)
sSpellLevel = Get2DACache("spells", "Nentyar", nSpell);
else if (nClass == CLASS_TYPE_SHADOWLORD)
sSpellLevel = Get2DACache("spells", "Telflammar", nSpell);
else if (nClass == CLASS_TYPE_SLAYER_OF_DOMIEL)
sSpellLevel = Get2DACache("spells", "Domiel", nSpell);
else if (nClass == CLASS_TYPE_SOHEI)
sSpellLevel = Get2DACache("spells", "Sohei", nSpell);
else if (nClass == CLASS_TYPE_VASSAL)
sSpellLevel = Get2DACache("spells", "Bahamut", nSpell);
else if (nClass == CLASS_TYPE_BLACKGUARD)
sSpellLevel = Get2DACache("spells", "Blackguard", nSpell);
else if (nClass == CLASS_TYPE_KNIGHT_CHALICE)
sSpellLevel = Get2DACache("spells", "Chalice", nSpell);
else if (nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE)
sSpellLevel = Get2DACache("spells", "MiddleCircle", nSpell);
else if (nClass == CLASS_TYPE_SOLDIER_OF_LIGHT)
sSpellLevel = Get2DACache("spells", "SoLight", nSpell);
else if (nClass == CLASS_TYPE_BLIGHTER)
sSpellLevel = Get2DACache("spells", "Blighter", nSpell);
else if (nClass == CLASS_TYPE_HEALER)
sSpellLevel = Get2DACache("spells", "Healer", nSpell);
else if (nClass == CLASS_TYPE_SHAMAN)
sSpellLevel = Get2DACache("spells", "Shaman", nSpell);
else if (nClass == CLASS_TYPE_INVALID)
sSpellLevel = Get2DACache("spells", "Innate", nSpell);
if (sSpellLevel != "")
return StringToInt(sSpellLevel);
// 2009-9-21: Support real spell ID's. -N-S
// PRCGetSpellLevel() is called several times in the Bioware spellhooking script.
// That means it will always pass a "real" spell ID to this function, but new-spellbook users won't have the real spell!
// GetSpellLevel() takes the fake spell ID, so this function was always failing.
//int nSpellLevel = GetSpellLevel(nSpell, nClass);
int nSpellLevel = -1;
int nSpellbookID = RealSpellToSpellbookID(nClass, nSpell);
if (nSpellbookID == -1)
nSpellLevel = GetSpellLevel(nSpell, nClass);
else
{
string sFile = GetFileForClass(nClass);
string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookID);
if (sSpellLevel != "")
nSpellLevel = StringToInt(sSpellLevel);
}
return nSpellLevel;
}
// returns the spelllevel of nSpell as it can be cast by oCreature
int PRCGetSpellLevel(object oCreature, int nSpell)
{
/*if (!PRCGetHasSpell(nSpell, oCreature))
return -1;*/
int nClass = PRCGetLastSpellCastClass();
int nSpellLevel = PRCGetSpellLevelForClass(nSpell, nClass);
if (nSpellLevel != -1)
return nSpellLevel;
int i;
for (i=1;i<=8;i++)
{
nClass = GetClassByPosition(i, oCreature);
int nCharLevel = GetLevelByClass(nClass, oCreature);
if (nCharLevel)
{
nSpellLevel = PRCGetSpellLevelForClass(nSpell, nClass);
if (nSpellLevel != -1)
return nSpellLevel;
}
}
//return innate level
return StringToInt(Get2DACache("spells", "Innate", nSpell));
}
// gets the spell level adjustment to the nMetaMagic, including boni from the Improved Metamagic (epic) feat
int GetMetaMagicSpellLevelAdjustment(int nMetaMagic)
{
int nAdj;
if (nMetaMagic == 0) return nAdj;
if (nMetaMagic & METAMAGIC_EXTEND) nAdj += METAMAGIC_EXTEND_LEVEL;
if (nMetaMagic & METAMAGIC_SILENT) nAdj += METAMAGIC_SILENT_LEVEL;
if (nMetaMagic & METAMAGIC_STILL) nAdj += METAMAGIC_STILL_LEVEL;
if (nMetaMagic & METAMAGIC_EMPOWER) nAdj += METAMAGIC_EMPOWER_LEVEL;
if (nMetaMagic & METAMAGIC_MAXIMIZE) nAdj += METAMAGIC_MAXIMIZE_LEVEL;
if (nMetaMagic & METAMAGIC_QUICKEN) nAdj += METAMAGIC_QUICKEN_LEVEL;
return nAdj;
}
int GetIsBioSpellCastClass(int nClass)
{
return nClass == CLASS_TYPE_WIZARD
|| nClass == CLASS_TYPE_SORCERER
|| nClass == CLASS_TYPE_BARD
|| nClass == CLASS_TYPE_CLERIC
|| nClass == CLASS_TYPE_HEALER
|| nClass == CLASS_TYPE_BLIGHTER
|| nClass == CLASS_TYPE_BLACKGUARD
|| nClass == CLASS_TYPE_UR_PRIEST
|| nClass == CLASS_TYPE_OCULAR
|| nClass == CLASS_TYPE_SLAYER_OF_DOMIEL
|| nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK
|| nClass == CLASS_TYPE_NENTYAR_HUNTER
|| nClass == CLASS_TYPE_SHADOWLORD
|| nClass == CLASS_TYPE_SOHEI
|| nClass == CLASS_TYPE_SOLDIER_OF_LIGHT
|| nClass == CLASS_TYPE_VASSAL
|| nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE
|| nClass == CLASS_TYPE_KNIGHT_CHALICE
|| nClass == CLASS_TYPE_SHAMAN
|| nClass == CLASS_TYPE_DRUID
|| nClass == CLASS_TYPE_PALADIN
|| nClass == CLASS_TYPE_RANGER;
}
int GetIsNSBClass(int nClass)
{
return !GetIsBioSpellCastClass(nClass)
&& GetSpellbookTypeForClass(nClass) != SPELLBOOK_TYPE_INVALID;
}
// returns if a character should be using the newspellbook when casting
int UseNewSpellBook(object oCreature)
{
int i;
for (i = 1; i <= 8; i++)
{
int nClass = GetClassByPosition(i, oCreature);
if(GetIsNSBClass(nClass))
return TRUE;
}
// Special case
if(GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCreature))
return TRUE;
int nPrimaryArcane = GetPrimaryArcaneClass(oCreature);
//check they have bard/sorc in first arcane slot
if(nPrimaryArcane != CLASS_TYPE_BARD && nPrimaryArcane != CLASS_TYPE_SORCERER)
return FALSE;
//check they have arcane PrC or Draconic Breath/Arcane Grace
if(!GetArcanePRCLevels(oCreature)
&& !(GetHasFeat(FEAT_DRACONIC_GRACE, oCreature) || GetHasFeat(FEAT_DRACONIC_BREATH, oCreature)))
return FALSE;
//check if the newspellbooks are disabled
if((GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK) && nPrimaryArcane == CLASS_TYPE_SORCERER) ||
(GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK) && nPrimaryArcane == CLASS_TYPE_BARD))
return FALSE;
//check they have bard/sorc levels
if(!GetLevelByClass(CLASS_TYPE_BARD) && !GetLevelByClass(CLASS_TYPE_SORCERER))
return FALSE;
//at this point, they should be using the new spellbook
return TRUE;
}
// wrapper for GetHasSpell, works for newspellbook 'fake' spells too (and metamagic)
// should return 0 if called with a normal spell when a character should be using the newspellbook
int PRCGetHasSpell(int nRealSpellID, object oCreature = OBJECT_SELF)
{
if(!PRCGetIsRealSpellKnown(nRealSpellID, oCreature))
return 0;
int nUses = GetHasSpell(nRealSpellID, oCreature);
int nClass, nSpellbookID, nCount, nMeta, i, j;
int nSpellbookType, nSpellLevel;
string sFile, sFeat;
for(i = 1; i <= 8; i++)
{
nClass = GetClassByPosition(i, oCreature);
sFile = GetFileForClass(nClass);
nSpellbookType = GetSpellbookTypeForClass(nClass);
nSpellbookID = RealSpellToSpellbookID(nClass, nRealSpellID);
nMeta = RealSpellToSpellbookIDCount(nClass, nRealSpellID);
if (nSpellbookID != -1)
{ //non-spellbook classes should return -1
for(j = nSpellbookID; j <= nSpellbookID + nMeta; j++)
{
sFeat = Get2DACache(sFile, "ReqFeat", j);
if(sFeat != "")
{
if(!GetHasFeat(StringToInt(sFeat), oCreature))
continue;
}
if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
{
nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), j);
if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
if(nCount > 0)
{
nUses += nCount;
}
}
else if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
{
nSpellLevel = StringToInt(Get2DACache(sFile, "Level", j));
nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel);
if(DEBUG) DoDebug("PRCGetHasSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
if(nCount > 0)
{
nUses += nCount;
}
}
}
}
}
if(DEBUG) DoDebug("PRCGetHasSpell: RealSpellID = " + IntToString(nRealSpellID) + ", Uses = " + IntToString(nUses));
return nUses;
}
// checks if oPC knows the specified spell
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
int PRCGetIsRealSpellKnown(int nRealSpellID, object oPC = OBJECT_SELF)
{
if(GetHasSpell(nRealSpellID, oPC)) //FUGLY HACK: bioware class having uses of the spell
return TRUE; // means they know the spell (close enough)
int nClass;
int nClassSlot = 1;
while(nClassSlot <= 8)
{
nClass = GetClassByPosition(nClassSlot, oPC);
if(GetIsDivineClass(nClass) || GetIsArcaneClass(nClass))
if(PRCGetIsRealSpellKnownByClass(nRealSpellID, nClass, oPC))
return TRUE;
nClassSlot++;
}
// got here means no match
return FALSE;
}
// checks if oPC knows the specified spell
// only works for classes that use the PRC spellbook, there is currently no way to do this for Bioware spellcasters
// this will only check the spellbook of the class specified
int PRCGetIsRealSpellKnownByClass(int nRealSpellID, int nClass, object oPC = OBJECT_SELF)
{
// check for whether bard and sorc are using the prc spellbooks
if (nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER)
{
if(!UseNewSpellBook(oPC))
return FALSE;
}
// get the cls_spell_***.2da index for the real spell
int nSpellbookSpell = RealSpellToSpellbookID(nClass, nRealSpellID);
// if the spell does not exist in the spellbook, return FALSE
if (nSpellbookSpell == -1)
return FALSE;
// next check if the PC is high enough level to know the spell
string sFile = GetFileForClass(nClass);
int nSpellLevel = -1;
string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookSpell);
if (sSpellLevel != "")
nSpellLevel = StringToInt(sSpellLevel);
if ((GetLevelByClass(nClass) < nSpellLevel) || nSpellLevel == -1)
return FALSE; // not high enough level
// at this stage, prepared casters know the spell and only spontaneous classes need checking
// there are exceptions and these need hardcoding:
if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED) && nClass != CLASS_TYPE_ARCHIVIST)
return TRUE;
// spontaneous casters have all their known spells as hide feats
// get the featID of the spell
int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookSpell));
if (GetHasFeat(nFeatID, oPC))
return TRUE;
return FALSE;
}
//routes to action cast spell, but puts a wrapper around to tell other functions its a
//SLA, so dont craft etc
//also defaults th totalDC to 10+spellevel+chamod
//this is Base DC, not total DC. SLAs are still spells, so spell focus should still apply.
void DoRacialSLA(int nSpellID, int nCasterlevel = 0, int nTotalDC = 0, int bInstantCast = FALSE)
{
if(DEBUG) DoDebug("Spell DC passed to DoRacialSLA: " + IntToString(nTotalDC));
if(nTotalDC == 0)
nTotalDC = 10
+StringToInt(Get2DACache("spells", "Innate", nSpellID))
+GetAbilityModifier(ABILITY_CHARISMA);
ActionDoCommand(SetLocalInt(OBJECT_SELF, "SpellIsSLA", TRUE));
if(DEBUG) DoDebug("Spell DC entered in ActionCastSpell: " + IntToString(nTotalDC));
ActionCastSpell(nSpellID, nCasterlevel, 0, nTotalDC, METAMAGIC_NONE, CLASS_TYPE_INVALID, FALSE, FALSE, OBJECT_INVALID, bInstantCast);
//ActionCastSpell(nSpellID, nCasterlevel, 0, nTotalDC);
ActionDoCommand(DeleteLocalInt(OBJECT_SELF, "SpellIsSLA"));
}
void DeleteLocalManifestation(object oObject, string sName)
{
DeleteLocalObject(oObject, sName + "_oManifester");
DeleteLocalInt(oObject, sName + "_bCanManifest");
DeleteLocalInt(oObject, sName + "_nPPCost");
DeleteLocalInt(oObject, sName + "_nPsiFocUsesRemain");
DeleteLocalInt(oObject, sName + "_nManifesterLevel");
DeleteLocalInt(oObject, sName + "_nSpellID");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_1");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_2");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_3");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_4");
DeleteLocalInt(oObject, sName + "_nTimesAugOptUsed_5");
DeleteLocalInt(oObject, sName + "_nTimesGenericAugUsed");
DeleteLocalInt(oObject, sName + "_bChain");
DeleteLocalInt(oObject, sName + "_bEmpower");
DeleteLocalInt(oObject, sName + "_bExtend");
DeleteLocalInt(oObject, sName + "_bMaximize");
DeleteLocalInt(oObject, sName + "_bSplit");
DeleteLocalInt(oObject, sName + "_bTwin");
DeleteLocalInt(oObject, sName + "_bWiden");
DeleteLocalInt(oObject, sName + "_bQuicken");
}
void DeleteLocalMystery(object oObject, string sName)
{
DeleteLocalObject(oObject, sName + "_oShadow");
DeleteLocalInt(oObject, sName + "_bCanMyst");
DeleteLocalInt(oObject, sName + "_nShadowcasterLevel");
DeleteLocalInt(oObject, sName + "_nMystId");
DeleteLocalInt(oObject, sName + "_nPen");
DeleteLocalInt(oObject, sName + "_bIgnoreSR");
DeleteLocalInt(oObject, sName + "_bEmpower");
DeleteLocalInt(oObject, sName + "_bExtend");
DeleteLocalInt(oObject, sName + "_bMaximize");
DeleteLocalInt(oObject, sName + "_bQuicken");
DeleteLocalInt(oObject, sName + "_nSaveDC");
DeleteLocalFloat(oObject, sName + "_fDur");
}

View File

@ -0,0 +1,585 @@
//::///////////////////////////////////////////////
//:: PRC Bonus Domains
//:: prc_inc_domain.nss
//:://////////////////////////////////////////////
//:: Handles all of the code for bonus domains.
//:://////////////////////////////////////////////
//:: Created By: Stratovarius.
//:: Created On: August 31st, 2005
//:://////////////////////////////////////////////
//:: Updated for .35 by Jaysyn 2023/03/10
// Function returns the domain in the input slot.
// A person can have a maximum of 5 bonus domains.
int GetBonusDomain(object oPC, int nSlot);
// Function will add a bonus domain to the stored list on the character.
void AddBonusDomain(object oPC, int nDomain);
// Uses the slot and level to find the appropriate spell, then casts it using ActionCastSpell
// It will also decrement a spell from that level
// If the domain does not have an appropriate spell for that level, an error message appears and nothing happens
void CastDomainSpell(object oPC, int nSlot, int nLevel);
// Takes the domain and spell level and uses it to find the appropriate spell.
// Right now it uses 2da reads on the domains.2da, although it could be scripted if desired.
int GetDomainSpell(int nDomain, int nLevel, object oPC);
// Takes the spell level, and returns the radial feat for that level.
// Used in case there is no spell of the appropriate level.
int SpellLevelToFeat(int nLevel);
// Will return the domain name as a string
// This is used to tell a PC what domains he has in what slot
string GetDomainName(int nDomain);
// This is the starter function, and fires from Enter and Levelup
// It checks all of the bonus domain feats, and gives the PC the correct domains
void CheckBonusDomains(object oPC);
// Returns the spell to be burned for CastDomainSpell
int GetBurnableSpell(object oPC, int nLevel);
// Returns the Domain Power feat
int GetDomainFeat(int nDomain);
// Returns the Uses per day of the feat entered
int GetDomainFeatUsesPerDay(int nFeat, object oPC);
// This counts down the number of times a domain has been used in a day
// Returns TRUE if the domain use is valid
// Returns FALSE if the player is out of uses per day
int DecrementDomainUses(int nDomain, object oPC);
// Used to determine which domain has cast the Turn Undead spell
// Returns the domain constant
int GetTurningDomain(int nSpell);
// Checks to see if the player has a domain.
// Looks for the domain power constants since every domain has those
int GetHasDomain(object oPC, int nDomain);
// Cleans the ints that limit the domain spells to being cast 1/day
void BonusDomainRest(object oPC);
//#include "prc_inc_clsfunc"
#include "prc_alterations"
#include "prc_getbest_inc"
#include "inc_dynconv"
int GetBonusDomain(object oPC, int nSlot)
{
/*string sName = "PRCBonusDomain" + IntToString(nSlot);
// Return value in case there is nothing in the slot
int nDomain = 0;
nDomain = GetPersistantLocalInt(oPC, sName);*/
return GetPersistantLocalInt(oPC, "PRCBonusDomain" + IntToString(nSlot));
}
void AddBonusDomain(object oPC, int nDomain)
{
//if(DEBUG) DoDebug("AddBonusDomain is running.");
// Loop through the domain slots to see if there is an open one.
int nSlot = 1;
int nTest = GetBonusDomain(oPC, nSlot);
while(nTest > 0 && 5 >= nSlot)
{
nSlot += 1;
// If the test domain and the domain to be added are the same
// shut down the function, since you don't want to add a domain twice.
if(nTest == nDomain)
{
//FloatingTextStringOnCreature("You already have this domain as a bonus domain.", oPC, FALSE);
return;
}
nTest = GetBonusDomain(oPC, nSlot);
}
// If you run out of slots, display message and end function
if (nSlot > 5)
{
FloatingTextStringOnCreature("You have more than 5 bonus domains, your last domain is lost.", oPC, FALSE);
return;
}
// If we're here, we know we have an open slot, so we add the domain into it.
string sName = "PRCBonusDomain" + IntToString(nSlot);
SetPersistantLocalInt(oPC, sName, nDomain);
FloatingTextStringOnCreature("You have " + GetStringByStrRef(StringToInt(Get2DACache("prc_domains", "Name", nDomain - 1))) + " as a bonus domain", oPC, FALSE);
}
int TestSpellTarget(object oPC, object oTarget, int nSpell)
{
int nTargetType = ~(HexToInt(Get2DACache("spells", "TargetType", nSpell)));
if(oTarget == oPC && nTargetType & 1)
{
SendMessageToPC(oPC, "You cannot target yourself!");
return FALSE;
}
else if(GetIsObjectValid(oTarget))
{
int nObjectType = GetObjectType(oTarget);
if(nObjectType == OBJECT_TYPE_CREATURE && nTargetType & 2)
{
SendMessageToPC(oPC, "You cannot target creatures");
return FALSE;
}
else if(nObjectType == OBJECT_TYPE_ITEM && nTargetType & 8)
{
SendMessageToPC(oPC, "You cannot target items");
return FALSE;
}
else if(nObjectType == OBJECT_TYPE_DOOR && nTargetType & 16)
{
SendMessageToPC(oPC, "You cannot target doors");
return FALSE;
}
else if(nObjectType == OBJECT_TYPE_PLACEABLE && nTargetType & 32)
{
SendMessageToPC(oPC, "You cannot target placeables");
return FALSE;
}
}
else if(nTargetType & 4)
{
SendMessageToPC(oPC, "You cannot target locations");
return FALSE;
}
return TRUE;
}
// Classes using new spellbook systems are handeled separately
int GetIsBioDivineClass(int nClass)
{
return nClass == CLASS_TYPE_CLERIC
|| nClass == CLASS_TYPE_DRUID
|| nClass == CLASS_TYPE_PALADIN
|| nClass == CLASS_TYPE_UR_PRIEST
|| nClass == CLASS_TYPE_RANGER;
}
void CastDomainSpell(object oPC, int nSlot, int nLevel)
{
if(GetLocalInt(oPC, "DomainCastSpell" + IntToString(nLevel))) //Already cast a spell of this level?
{
FloatingTextStringOnCreature("You have already cast your domain spell for level " + IntToString(nLevel), oPC, FALSE);
return;
}
int nSpell = GetDomainSpell(GetBonusDomain(oPC, nSlot), nLevel, oPC);
// If there is no spell for that level, you cant cast it.
if(nSpell == -1)
return;
// Subradial spells are handled through conversation
int bSubRadial = Get2DACache("spells", "SubRadSpell1", nSpell) != "";
// Domain casting feats use generic targeting, so check if spell can be cast at selected target
object oTarget = GetSpellTargetObject();
if(!bSubRadial && !TestSpellTarget(oPC, oTarget, nSpell))
return;
int nClass, nCount, nMetamagic = METAMAGIC_NONE;
// Mystic is a special case - checked first
if(GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) || GetLevelByClass(CLASS_TYPE_NIGHTSTALKER, oPC))
{
// Mystics can use metamagic with domain spells
nClass = GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) ? CLASS_TYPE_MYSTIC : CLASS_TYPE_NIGHTSTALKER;
nMetamagic = GetLocalInt(oPC, "MetamagicFeatAdjust");
int nSpellLevel = nLevel;
if(nMetamagic)
{
//Need to check if metamagic can be applied to a spell
int nMetaTest;
int nMetaType = HexToInt(Get2DACache("spells", "MetaMagic", nSpell));
switch(nMetamagic)
{
case METAMAGIC_NONE: nMetaTest = 1; break; //no need to change anything
case METAMAGIC_EMPOWER: nMetaTest = nMetaType & 1; nSpellLevel += 2; break;
case METAMAGIC_EXTEND: nMetaTest = nMetaType & 2; nSpellLevel += 1; break;
case METAMAGIC_MAXIMIZE: nMetaTest = nMetaType & 4; nSpellLevel += 3; break;
case METAMAGIC_QUICKEN: nMetaTest = nMetaType & 8; nSpellLevel += 4; break;
case METAMAGIC_SILENT: nMetaTest = nMetaType & 16; nSpellLevel += 1; break;
case METAMAGIC_STILL: nMetaTest = nMetaType & 32; nSpellLevel += 1; break;
}
if(!nMetaTest)//can't use selected metamagic with this spell
{
nMetamagic = METAMAGIC_NONE;
ActionDoCommand(SendMessageToPC(oPC, "You can't use "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpell)))+"with selected metamagic."));
nSpellLevel = nLevel;
}
else if(nLevel > 9)//now test the spell level
{
nMetamagic = METAMAGIC_NONE;
ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is to high! Casting spell without metamagic"));
nSpellLevel = nLevel;
}
else if(GetLocalInt(oPC, "PRC_metamagic_state") == 1)
SetLocalInt(oPC, "MetamagicFeatAdjust", 0);
}
nCount = persistant_array_get_int(oPC, "NewSpellbookMem_" + IntToString(CLASS_TYPE_MYSTIC), nSpellLevel);
// we can't cast metamagiced version of the spell - assuming that player want to cast the spell anyway
if(!nCount)
nCount = persistant_array_get_int(oPC, "NewSpellbookMem_" + IntToString(CLASS_TYPE_MYSTIC), nLevel);
// Do we have slots available?
if(nCount)
{
// Prepare to cast the spell
nLevel = nSpellLevel;//correct the spell level if we're using metamagic
SetLocalInt(oPC, "NSB_Class", nClass);
SetLocalInt(oPC, "NSB_SpellLevel", nLevel);
}
}
// checking 'newspellbook' classes is much faster than checking bioware spellbooks
if(!nCount)
{
int n;
for(n = 1; n < 8; n++)
{
nClass = GetClassByPosition(n, oPC);
// Check to see if you can burn a spell of that slot or if the person has already
// cast all of their level X spells for the day
if(!GetIsBioDivineClass(nClass))
{
int nSpellbook = GetSpellbookTypeForClass(nClass);
if(nSpellbook == SPELLBOOK_TYPE_SPONTANEOUS)
{
nCount = persistant_array_get_int(oPC, "NewSpellbookMem_" + IntToString(nClass), nLevel);
if(nCount)
{// Prepare to cast the spell
SetLocalInt(oPC, "NSB_Class", nClass);
SetLocalInt(oPC, "NSB_SpellLevel", nLevel);
}
}
else if(nSpellbook == SPELLBOOK_TYPE_PREPARED)
{
string sArray = "NewSpellbookMem_"+IntToString(nClass);
string sIDX = "SpellbookIDX" + IntToString(nLevel) + "_" + IntToString(nClass);
int i, nSpellbookID, nMax = persistant_array_get_size(oPC, sIDX);
for(i = 0; i < nMax; i++)
{
nSpellbookID = persistant_array_get_int(oPC, sIDX, i);
nCount = persistant_array_get_int(oPC, sArray, nSpellbookID);
if(nCount)
{
SetLocalInt(oPC, "NSB_Class", nClass);
SetLocalInt(oPC, "NSB_SpellbookID", nSpellbookID);
break;
}
}
}
}
if(nCount)
//we have found valid spell slot, no point in running this loop again
break;
}
}
// test bioware spellbooks
if(!nCount)
{
nCount = GetBurnableSpell(oPC, nLevel) + 1;//fix for Acid Fog spell
if(nCount)
{
SetLocalInt(oPC, "Domain_BurnableSpell", nCount);
nClass = GetPrimaryDivineClass(oPC);
}
}
//No spell left to burn? Tell the player that.
if(!nCount)
{
FloatingTextStringOnCreature("You have no spells left to trade for a domain spell.", oPC, FALSE);
return;
}
SetLocalInt(oPC, "DomainCast", nLevel);
if(bSubRadial)
{
SetLocalInt(oPC, "DomainOrigSpell", nSpell);
SetLocalInt(oPC, "DomainCastClass", nClass);
SetLocalObject(oPC, "DomainTarget", oTarget);
SetLocalLocation(oPC, "DomainTarget", GetSpellTargetLocation());
StartDynamicConversation("prc_domain_conv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
}
else
{
if(nMetamagic & METAMAGIC_QUICKEN)
{
//Adding Auto-Quicken III for one round - deleted after casting is finished.
object oSkin = GetPCSkin(oPC);
int nCastDur = StringToInt(Get2DACache("spells", "ConjTime", nSpell)) + StringToInt(Get2DACache("spells", "CastTime", nSpell));
itemproperty ipAutoQuicken = ItemPropertyBonusFeat(IP_CONST_NSB_AUTO_QUICKEN);
ActionDoCommand(AddItemProperty(DURATION_TYPE_TEMPORARY, ipAutoQuicken, oSkin, nCastDur/1000.0f));
}
int nDC = 10 + nLevel + GetDCAbilityModForClass(nClass, oPC);
ActionCastSpell(nSpell, 0, nDC, 0, nMetamagic, nClass, FALSE, FALSE, OBJECT_INVALID, FALSE);
ActionDoCommand(DeleteLocalInt(oPC, "DomainCast"));
}
}
int GetDomainSpell(int nDomain, int nLevel, object oPC)
{
// The -1 on nDomains is to adjust from a base 1 to a base 0 system.
string sSpell = Get2DACache("prc_domains", "Level_" + IntToString(nLevel), (nDomain - 1));
if (DEBUG) DoDebug("Domain Spell: " + sSpell);
//if (DEBUG) DoDebug("GetDomainSpell has fired");
int nSpell = -1;
if(sSpell == "")
{
FloatingTextStringOnCreature("You do not have a domain spell of that level.", oPC, FALSE);
//int nFeat = SpellLevelToFeat(nLevel);
//IncrementRemainingFeatUses(oPC, nFeat);
}
else
{
nSpell = StringToInt(sSpell);
}
return nSpell;
}
int SpellLevelToFeat(int nLevel)
{
switch(nLevel)
{
case 1: return FEAT_CAST_DOMAIN_LEVEL_ONE;
case 2: return FEAT_CAST_DOMAIN_LEVEL_TWO;
case 3: return FEAT_CAST_DOMAIN_LEVEL_THREE;
case 4: return FEAT_CAST_DOMAIN_LEVEL_FOUR;
case 5: return FEAT_CAST_DOMAIN_LEVEL_FIVE;
case 6: return FEAT_CAST_DOMAIN_LEVEL_SIX;
case 7: return FEAT_CAST_DOMAIN_LEVEL_SEVEN;
case 8: return FEAT_CAST_DOMAIN_LEVEL_EIGHT;
case 9: return FEAT_CAST_DOMAIN_LEVEL_NINE;
}
return -1;
}
string GetDomainName(int nDomain)
{
string sName;
// Check that the domain slot is not empty
if(nDomain)
{
sName = Get2DACache("prc_domains", "Name", (nDomain - 1));
sName = GetStringByStrRef(StringToInt(sName));
}
else
sName = GetStringByStrRef(6497); // "Empty Slot"
return sName;
}
void CheckBonusDomains(object oPC)
{
int nBonusDomain, nDomainFeat;
int nSlot = 1;
while(nSlot < 6)
{
nBonusDomain = GetBonusDomain(oPC, nSlot);
nDomainFeat = GetDomainFeat(nBonusDomain);
if(!GetHasFeat(nDomainFeat, oPC)) SetPersistantLocalInt(oPC, "PRCBonusDomain" + IntToString(nSlot), 0);
//SendMessageToPC(oPC, "PRCBonusDomain"+IntToString(nSlot)" = "+IntToString(nBonusDomain));
//SendMessageToPC(oPC, "PRCBonusDomain"+IntToString(nSlot)" feat = "+IntToString(GetDomainFeat(nDomainFeat)));
nSlot += 1;
}
if (GetHasFeat(FEAT_BONUS_DOMAIN_AIR, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_AIR);
if (GetHasFeat(FEAT_BONUS_DOMAIN_ANIMAL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_ANIMAL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DEATH, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DEATH);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DESTRUCTION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DESTRUCTION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_EARTH, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_EARTH);
if (GetHasFeat(FEAT_BONUS_DOMAIN_EVIL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_EVIL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_FIRE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_FIRE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_GOOD, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_GOOD);
if (GetHasFeat(FEAT_BONUS_DOMAIN_HEALING, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_HEALING);
if (GetHasFeat(FEAT_BONUS_DOMAIN_KNOWLEDGE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_KNOWLEDGE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_MAGIC, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_MAGIC);
if (GetHasFeat(FEAT_BONUS_DOMAIN_PLANT, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_PLANT);
if (GetHasFeat(FEAT_BONUS_DOMAIN_PROTECTION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_PROTECTION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_STRENGTH, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_STRENGTH);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SUN);
if (GetHasFeat(FEAT_BONUS_DOMAIN_TRAVEL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_TRAVEL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_TRICKERY, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_TRICKERY);
if (GetHasFeat(FEAT_BONUS_DOMAIN_WAR, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_WAR);
if (GetHasFeat(FEAT_BONUS_DOMAIN_WATER, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_WATER);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DARKNESS, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DARKNESS);
if (GetHasFeat(FEAT_BONUS_DOMAIN_STORM, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_STORM);
if (GetHasFeat(FEAT_BONUS_DOMAIN_METAL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_METAL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_PORTAL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_PORTAL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_FORCE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_FORCE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SLIME, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SLIME);
if (GetHasFeat(FEAT_BONUS_DOMAIN_TYRANNY, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_TYRANNY);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DOMINATION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DOMINATION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SPIDER, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SPIDER);
if (GetHasFeat(FEAT_BONUS_DOMAIN_UNDEATH, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_UNDEATH);
if (GetHasFeat(FEAT_BONUS_DOMAIN_TIME, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_TIME);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DWARF, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DWARF);
if (GetHasFeat(FEAT_BONUS_DOMAIN_CHARM, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_CHARM);
if (GetHasFeat(FEAT_BONUS_DOMAIN_ELF, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_ELF);
if (GetHasFeat(FEAT_BONUS_DOMAIN_FAMILY, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_FAMILY);
if (GetHasFeat(FEAT_BONUS_DOMAIN_FATE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_FATE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_GNOME, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_GNOME);
if (GetHasFeat(FEAT_BONUS_DOMAIN_ILLUSION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_ILLUSION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_HATRED, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_HATRED);
if (GetHasFeat(FEAT_BONUS_DOMAIN_HALFLING, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_HALFLING);
if (GetHasFeat(FEAT_BONUS_DOMAIN_NOBILITY, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_NOBILITY);
if (GetHasFeat(FEAT_BONUS_DOMAIN_OCEAN, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_OCEAN);
if (GetHasFeat(FEAT_BONUS_DOMAIN_ORC, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_ORC);
if (GetHasFeat(FEAT_BONUS_DOMAIN_RENEWAL, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_RENEWAL);
if (GetHasFeat(FEAT_BONUS_DOMAIN_RETRIBUTION, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_RETRIBUTION);
if (GetHasFeat(FEAT_BONUS_DOMAIN_RUNE, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_RUNE);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SPELLS, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SPELLS);
if (GetHasFeat(FEAT_BONUS_DOMAIN_SCALEYKIND, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_SCALEYKIND);
if (GetHasFeat(FEAT_BONUS_DOMAIN_BLIGHTBRINGER, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_BLIGHTBRINGER);
if (GetHasFeat(FEAT_BONUS_DOMAIN_DRAGON, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_DRAGON);
if (GetHasFeat(FEAT_BONUS_DOMAIN_COLD, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_COLD);
if (GetHasFeat(FEAT_BONUS_DOMAIN_WINTER, oPC)) AddBonusDomain(oPC, PRC_DOMAIN_WINTER);
//if (DEBUG) FloatingTextStringOnCreature("Check Bonus Domains is running", oPC, FALSE);
}
int GetBurnableSpell(object oPC, int nLevel)
{
int nBurnableSpell = -1;
if (nLevel == 1) nBurnableSpell = GetBestL1Spell(oPC, nBurnableSpell);
else if (nLevel == 2) nBurnableSpell = GetBestL2Spell(oPC, nBurnableSpell);
else if (nLevel == 3) nBurnableSpell = GetBestL3Spell(oPC, nBurnableSpell);
else if (nLevel == 4) nBurnableSpell = GetBestL4Spell(oPC, nBurnableSpell);
else if (nLevel == 5) nBurnableSpell = GetBestL5Spell(oPC, nBurnableSpell);
else if (nLevel == 6) nBurnableSpell = GetBestL6Spell(oPC, nBurnableSpell);
else if (nLevel == 7) nBurnableSpell = GetBestL7Spell(oPC, nBurnableSpell);
else if (nLevel == 8) nBurnableSpell = GetBestL8Spell(oPC, nBurnableSpell);
else if (nLevel == 9) nBurnableSpell = GetBestL9Spell(oPC, nBurnableSpell);
return nBurnableSpell;
}
int GetDomainFeat(int nDomain)
{
// The -1 on nDomain is to adjust from a base 1 to a base 0 system.
// Returns the domain power feat
return StringToInt(Get2DACache("domains", "GrantedFeat", nDomain - 1));
}
int GetDomainFeatUsesPerDay(int nFeat, object oPC)
{
int nUses = StringToInt(Get2DACache("feat", "USESPERDAY", nFeat));
// These are the domains that have ability based uses per day
if (nUses == 33)
{
// The Strength domain, which uses Strength when the Cleric has Kord levels
// Without Kord levels, its 1 use per day
if(nFeat == FEAT_STRENGTH_DOMAIN_POWER)
{
nUses = 1;
if(GetLevelByClass(CLASS_TYPE_MIGHTY_CONTENDER_KORD, oPC)) nUses = GetAbilityModifier(ABILITY_STRENGTH, oPC);
// Catching exceptions
if(nUses < 1) nUses = 1;
}
if(nFeat == FEAT_SUN_DOMAIN_POWER)
{
if(GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC) && GetLevelByClass(CLASS_TYPE_MYSTIC, oPC))
{
nUses = GetHasFeat(FEAT_EXTRA_TURNING, oPC) ? 7 : 3;
nUses += GetAbilityModifier(ABILITY_CHARISMA, oPC);
}
else
nUses = 1;
}
// All other ones so far are the Charisma based turning domains
nUses = 3 + GetAbilityModifier(ABILITY_CHARISMA, oPC);
}
return nUses;
}
int DecrementDomainUses(int nDomain, object oPC)
{
int nReturn = TRUE;
int nUses = GetLocalInt(oPC, "BonusDomainUsesPerDay" + GetDomainName(nDomain));
// If there is still a valid use left, remove it
if (nUses >= 1) SetLocalInt(oPC, "BonusDomainUsesPerDay" + GetDomainName(nDomain), (nUses - 1));
// Tell the player how many uses he has left
else // He has no more uses for the day
{
nReturn = FALSE;
}
FloatingTextStringOnCreature("You have " + IntToString(nUses - 1) + " uses per day left of the " + GetDomainName(nDomain) + " power.", oPC, FALSE);
return nReturn;
}
int GetTurningDomain(int nSpell)
{
switch(nSpell)
{
case SPELL_TURN_REPTILE: return PRC_DOMAIN_SCALEYKIND;
case SPELL_TURN_OOZE: return PRC_DOMAIN_SLIME;
case SPELL_TURN_SPIDER: return PRC_DOMAIN_SPIDER;
case SPELL_TURN_PLANT: return PRC_DOMAIN_PLANT;
case SPELL_TURN_AIR: return PRC_DOMAIN_AIR;
case SPELL_TURN_EARTH: return PRC_DOMAIN_EARTH;
case SPELL_TURN_FIRE: return PRC_DOMAIN_FIRE;
case SPELL_TURN_WATER: return PRC_DOMAIN_WATER;
case SPELL_TURN_BLIGHTSPAWNED: return PRC_DOMAIN_BLIGHTBRINGER;
}
return -1;
}
int GetHasDomain(object oPC, int nDomain)
{
// Get the domain power feat for the appropriate domain
int nFeat = GetDomainFeat(nDomain);
return GetHasFeat(nFeat, oPC);
}
void BonusDomainRest(object oPC)
{
// Bonus Domain ints that limit you to casting 1/day per level
int i;
for (i = 1; i < 10; i++)
{
DeleteLocalInt(oPC, "DomainCastSpell" + IntToString(i));
}
// This is code to stop you from using the Domain per day abilities more than you should be able to
int i2;
// Highest domain constant is 59
for (i2 = 1; i2 < 60; i2++)
{
// This is to ensure they only get the ints set for the domains they do have
if (GetHasDomain(oPC, i2))
{
// Store the number of uses a day here
SetLocalInt(oPC, "BonusDomainUsesPerDay" + GetDomainName(i2), GetDomainFeatUsesPerDay(GetDomainFeat(i2), oPC));
}
}
}
int GetDomainCasterLevel(object oPC)
{
return GetLevelByClass(CLASS_TYPE_CLERIC, oPC)
+ GetLevelByClass(CLASS_TYPE_MYSTIC, oPC)
+ GetLevelByClass(CLASS_TYPE_SHAMAN, oPC)
+ GetLevelByClass(CLASS_TYPE_TEMPLAR, oPC)
+ GetLevelByClass(CLASS_TYPE_BLIGHTLORD, oPC)
+ GetLevelByClass(CLASS_TYPE_CONTEMPLATIVE, oPC)
+ GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oPC);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,561 @@
/*
This include governs all the new itemproperties
Both restrictions and features
*/
//:: Updated for .35 by Jaysyn 2023/03/10
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
const string PLAYER_SPEED_INCREASE = "player_speed_increase";
const string PLAYER_SPEED_DECREASE = "player_speed_decrease";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
int DoUMDCheck(object oItem, object oPC, int nDCMod);
int CheckPRCLimitations(object oItem, object oPC = OBJECT_INVALID);
/**
* Non-returning wrapper for CheckPRCLimitations.
*/
void VoidCheckPRCLimitations(object oItem, object oPC = OBJECT_INVALID);
void CheckForPnPHolyAvenger(object oItem);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "inc_utility"
#include "prc_inc_newip"
#include "prc_inc_castlvl"
#include "inc_newspellbook"
//:: Test Void
//void main (){}
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
/*void _prc_inc_itmrstr_ApplySpeedModification(object oPC, int nEffectType, int nSpeedMod)
{
if(DEBUG) DoDebug("_prc_inc_itmrstr_ApplySpeedModification(" + DebugObject2Str(oPC) + ", " + IntToString(nEffectType) + ", " + IntToString(nSpeedMod) + ")");
// The skin object should be OBJECT_SELF here
// Clean up existing speed modification
effect eTest = GetFirstEffect(oPC);
while(GetIsEffectValid(eTest))
{
if(GetEffectCreator(eTest) == OBJECT_SELF &&
GetEffectType(eTest) == nEffectType &&
GetEffectSubType(eTest) == SUBTYPE_SUPERNATURAL
)
RemoveEffect(oPC, eTest);
eTest = GetNextEffect(oPC);
}
// Apply speed mod if there is any
if(nSpeedMod > 0)
{
effect eSpeedMod = SupernaturalEffect(nEffectType == EFFECT_TYPE_MOVEMENT_SPEED_INCREASE ?
EffectMovementSpeedIncrease(nSpeedMod) :
EffectMovementSpeedDecrease(nSpeedMod)
);
/// @todo Determine if the delay is actually needed here
DelayCommand(0.5, ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSpeedMod, oPC));
}
}
void _prc_inc_itmrstr_ApplySpeedIncrease(object oPC)
{
// Get target speed modification value. Limit to 99, since that's the effect constructor maximum value
int nSpeedMod = min(99, GetLocalInt(oPC, PLAYER_SPEED_INCREASE));
object oSkin = GetPCSkin(oPC);
AssignCommand(oSkin, _prc_inc_itmrstr_ApplySpeedModification(oPC, EFFECT_TYPE_MOVEMENT_SPEED_INCREASE, nSpeedMod));
}
void _prc_inc_itmrstr_ApplySpeedDecrease(object oPC)
{
// Get target speed modification value. Limit to 99, since that's the effect constructor maximum value
int nSpeedMod = GetLocalInt(oPC, PLAYER_SPEED_DECREASE);
object oSkin = GetPCSkin(oPC);
AssignCommand(oSkin, _prc_inc_itmrstr_ApplySpeedModification(oPC, EFFECT_TYPE_MOVEMENT_SPEED_DECREASE, nSpeedMod));
}*/
void _prc_inc_itmrstr_ApplyAoE(object oPC, object oItem, int nSubType, int nCost)
{
int nAoEID = StringToInt(Get2DACache("iprp_aoe", "AoEID", nSubType));
string sTag = Get2DACache("vfx_persistent", "LABEL", nAoEID);
effect eAoE = EffectAreaOfEffect(nAoEID,
Get2DACache("iprp_aoe", "EnterScript", nSubType),
Get2DACache("iprp_aoe", "HBScript", nSubType),
Get2DACache("iprp_aoe", "ExitScript", nSubType));
// The item applies the AoE effect
ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAoE, oPC);
// Get an object reference to the newly created AoE
location lLoc = GetLocation(oPC);
object oAoE = GetFirstObjectInShape(SHAPE_SPHERE, 1.0f, lLoc, FALSE, OBJECT_TYPE_AREA_OF_EFFECT);
while(GetIsObjectValid(oAoE))
{
// Test if we found the correct AoE
if(GetTag(oAoE) == sTag &&
!GetLocalInt(oAoE, "PRC_AoE_IPRP_Init")
)
{
SetLocalInt(oAoE, "PRC_AoE_IPRP_Init", TRUE);
break;
}
// Didn't find, get next
oAoE = GetNextObjectInShape(SHAPE_SPHERE, 1.0f, lLoc, FALSE, OBJECT_TYPE_AREA_OF_EFFECT);
}
if(!GetIsObjectValid(oAoE)) DoDebug("ERROR: _prc_inc_itmrstr_ApplyAoE: Can't find AoE created by " + DebugObject2Str(oItem));
// Set caster level override on the AoE
SetLocalInt(oAoE, PRC_CASTERLEVEL_OVERRIDE, nCost);
//if(DEBUG) DoDebug("_prc_inc_itmrstr_ApplyAoE: AoE level: " + IntToString(nCost));
}
void _prc_inc_itmrstr_ApplyWizardry(object oPC, object oItem, int nSpellLevel, string sType)
{
//properties were already applied - happens when loading a saved game
if(GetLocalInt(oItem, "PRC_Wizardry"+IntToString(nSpellLevel)))
return;
SetLocalInt(oItem, "PRC_Wizardry"+IntToString(nSpellLevel), TRUE);
int nClass, nSlots, i;
for(i = 1; i <= 8; i++)
{
nClass = GetClassByPosition(i, oPC);
if((sType == "A" && GetIsArcaneClass(nClass)) || (sType == "D" && GetIsDivineClass(nClass)))
{
if(GetAbilityScoreForClass(nClass, oPC) < nSpellLevel + 10)
continue;
int nSpellSlotLevel = GetSpellslotLevel(nClass, oPC) - 1;
string sFile = Get2DACache("classes", "SpellGainTable", nClass);
nSlots = StringToInt(Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nSpellSlotLevel));
//if(DEBUG) DoDebug("Adding "+IntToString(nSlots)" bonus slots for "+IntToString(nClass)" class.");
if(nSlots)
{
string sVar = "PRC_IPRPBonSpellSlots_" + IntToString(nClass) + "_" + IntToString(nSpellLevel);
int j = 0;
while(j < nSlots)
{
//DoDebug(IntToString(j));
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyBonusLevelSpell(nClass, nSpellLevel), oItem);
//nsb compatibility
SetLocalInt(oPC, sVar, (GetLocalInt(oPC, sVar) + 1));
j++;
}
}
}
}
SetPlotFlag(oItem, TRUE);
}
void _prc_inc_itmrstr_RemoveWizardry(object oPC, object oItem, int nSpellLevel, string sType)
{
DeleteLocalInt(oItem, "PRC_Wizardry"+IntToString(nSpellLevel));
SetPlotFlag(oItem, FALSE);
itemproperty ipTest = GetFirstItemProperty(oItem);
string sVar;
while(GetIsItemPropertyValid(ipTest))
{
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N)
{
if(GetItemPropertyCostTableValue(ipTest) == nSpellLevel)
{
int nClass = GetItemPropertySubType(ipTest);
if((sType == "A" && GetIsArcaneClass(nClass)) || (sType == "D" && GetIsDivineClass(nClass)))
{
RemoveItemProperty(oItem, ipTest);
//remove bonus slots from nsb classes
sVar = "PRC_IPRPBonSpellSlots_" + IntToString(nClass) + "_" + IntToString(nSpellLevel);
SetLocalInt(oPC, sVar, (GetLocalInt(oPC, sVar) - 1));
int nCount, nSpellbook = GetSpellbookTypeForClass(nClass);
string sArray = "NewSpellbookMem_"+IntToString(nClass);
if(nSpellbook == SPELLBOOK_TYPE_SPONTANEOUS)
{
nCount = persistant_array_get_int(oPC, sArray, nSpellLevel);
if(nCount)
{
nCount--;
persistant_array_set_int(oPC, sArray, nSpellLevel, nCount);
}
}
else if(nSpellbook == SPELLBOOK_TYPE_PREPARED)
{
string sIDX = "SpellbookIDX" + IntToString(nSpellLevel) + "_" + IntToString(nClass);
int i, nSpellbookID, nMax = persistant_array_get_size(oPC, sIDX) - 1;
for(i = nMax; i >= 0; i--)
{
nSpellbookID = persistant_array_get_int(oPC, sIDX, i);
nCount = persistant_array_get_int(oPC, sArray, nSpellbookID);
if(nCount)
{
nCount--;
persistant_array_set_int(oPC, sArray, nSpellbookID, nCount);
break;
}
}
}
}
}
}
ipTest = GetNextItemProperty(oItem);
}
}
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int GetUMDForItemCost(object oItem)
{
string s2DAEntry;
int nValue = GetGoldPieceValue(oItem);
int n2DAValue = StringToInt(s2DAEntry);
int i;
while(n2DAValue < nValue)
{
s2DAEntry = Get2DACache("skillvsitemcost", "DeviceCostMax", i);
n2DAValue = StringToInt(s2DAEntry);
i++;
}
i--;
string s2DAReqSkill = Get2DACache("skillvsitemcost", "SkillReq_Class", i);
if(s2DAReqSkill == "")
return -1;
return StringToInt(s2DAReqSkill);
}
//this is a scripted version of the bioware UMD check for using restricted items
//this also applies effects relating to new itemproperties
int DoUMDCheck(object oItem, object oPC, int nDCMod)
{
//doesnt have UMD
if(!GetHasSkill(SKILL_USE_MAGIC_DEVICE, oPC))
return FALSE;
int nSkill = GetSkillRank(SKILL_USE_MAGIC_DEVICE, oPC);
int nReqSkill = GetUMDForItemCost(oItem);
//class is a dc20 test
nReqSkill = nReqSkill - 20 + nDCMod;
if(nReqSkill > nSkill)
return FALSE;
else
return TRUE;
}
void VoidCheckPRCLimitations(object oItem, object oPC = OBJECT_INVALID)
{
CheckPRCLimitations(oItem, oPC);
}
//tests for use restrictions
//also appies effects for those IPs tat need them
/// @todo Rename. It's not just limitations anymore
int CheckPRCLimitations(object oItem, object oPC = OBJECT_INVALID)
{
// Sanity check - the item needs to be valid
if(!GetIsObjectValid(oItem))
return FALSE; /// @todo Might be better to auto-pass the limitation aspect in case of invalid item
// In case no item owner was given, find it out
if(!GetIsObjectValid(oPC))
oPC = GetItemPossessor(oItem);
// Sanity check - the item needs to be in some creature's possession for this function to make sense
if(!GetIsObjectValid(oPC))
return FALSE;
// Equip and Unequip events need some special handling
int bUnequip = GetItemLastUnequipped() == oItem && GetLocalInt(oPC, "ONEQUIP") == 1;
int bEquip = GetItemLastEquipped() == oItem && GetLocalInt(oPC, "ONEQUIP") == 2;
// Use restriction and UMD use
int bPass = TRUE;
int nUMDDC = 0;
// Speed modification. Used to determine if effects need to be applied
int nSpeedIncrease = GetLocalInt(oPC, PLAYER_SPEED_INCREASE);
int nSpeedDecrease = GetLocalInt(oPC, PLAYER_SPEED_DECREASE);
// Loop over all itemproperties on the item
itemproperty ipTest = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ipTest))
{
int ipType = GetItemPropertyType(ipTest);
/* Use restrictions. All of these can be skipped when unequipping */
if(!bUnequip)
{
if (ipType == ITEM_PROPERTY_USE_LIMITATION_ABILITY_SCORE)
{
int nValue = GetItemPropertyCostTableValue(ipTest);
if(GetAbilityScore(oPC, GetItemPropertySubType(ipTest), TRUE) < nValue)
bPass = FALSE;
nUMDDC += nValue - 15;
}
else if(ipType == ITEM_PROPERTY_USE_LIMITATION_SKILL_RANKS)
{
int nValue = GetItemPropertyCostTableValue(ipTest);
if(GetSkillRank(GetItemPropertySubType(ipTest), oPC) < nValue)
bPass = FALSE;
nUMDDC += nValue - 10;
}
else if(ipType == ITEM_PROPERTY_USE_LIMITATION_SPELL_LEVEL)
{
int nLevel = GetItemPropertyCostTableValue(ipTest);
if(GetLocalInt(oPC, "PRC_AllSpell" + IntToString(nLevel)))
bPass = FALSE;
nUMDDC += (nLevel * 2) - 20;
}
else if(ipType == ITEM_PROPERTY_USE_LIMITATION_ARCANE_SPELL_LEVEL)
{
int nLevel = GetItemPropertyCostTableValue(ipTest);
if(GetLocalInt(oPC, "PRC_ArcSpell" + IntToString(nLevel)))
bPass = FALSE;
nUMDDC += (nLevel * 2) - 20;
}
else if(ipType == ITEM_PROPERTY_USE_LIMITATION_DIVINE_SPELL_LEVEL)
{
int nLevel = GetItemPropertyCostTableValue(ipTest);
if(GetLocalInt(oPC, "PRC_DivSpell" + IntToString(nLevel)))
bPass = FALSE;
nUMDDC += (nLevel * 2) - 20;
}
else if(ipType == ITEM_PROPERTY_USE_LIMITATION_SNEAK_ATTACK)
{
int nLevel = GetItemPropertyCostTableValue(ipTest);
if(GetLocalInt(oPC, "PRC_SneakLevel" + IntToString(nLevel)))
bPass = FALSE;
nUMDDC += (nLevel * 2) - 20;
}
else if(ipType == ITEM_PROPERTY_USE_LIMITATION_GENDER)
{
if(GetGender(oPC) != GetItemPropertySubType(ipTest))
bPass = FALSE;
nUMDDC += 5;
}
}
/* Properties that apply effects. Unequip should cause cleanup here */
if(ipType == ITEM_PROPERTY_SPEED_INCREASE)
{
int iItemAdjust;
switch(GetItemPropertyCostTableValue(ipTest))
{
case 0: iItemAdjust = 10; break;
case 1: iItemAdjust = 20; break;
case 2: iItemAdjust = 30; break;
case 3: iItemAdjust = 40; break;
case 4: iItemAdjust = 50; break;
case 5: iItemAdjust = 60; break;
case 6: iItemAdjust = 70; break;
case 7: iItemAdjust = 80; break;
case 8: iItemAdjust = 90; break;
case 9: iItemAdjust = 100; break;
}
if(bUnequip)
nSpeedIncrease -= iItemAdjust;
else if(bEquip)
nSpeedIncrease += iItemAdjust;
}
else if(ipType == ITEM_PROPERTY_SPEED_DECREASE)
{
int iItemAdjust;
switch(GetItemPropertyCostTableValue(ipTest))
{
case 0: iItemAdjust = 10; break;
case 1: iItemAdjust = 20; break;
case 2: iItemAdjust = 30; break;
case 3: iItemAdjust = 40; break;
case 4: iItemAdjust = 50; break;
case 5: iItemAdjust = 60; break;
case 6: iItemAdjust = 70; break;
case 7: iItemAdjust = 80; break;
case 8: iItemAdjust = 90; break;
case 9: iItemAdjust = 99; break;
}
if(bUnequip)
nSpeedDecrease -= iItemAdjust;
else if(bEquip)
nSpeedDecrease += iItemAdjust;
}
else if(ipType == ITEM_PROPERTY_PNP_HOLY_AVENGER)
{
if(bEquip)
{
int nPaladinLevels = GetLevelByClass(CLASS_TYPE_PALADIN, oPC);
if(!nPaladinLevels)
{
//not a paladin? fake it
//not really a true PnP test
//instead it sets the paladin level
//to the UMD ranks minus the amount required
//to use a class restricted item of that value
int nSkill = GetSkillRank(SKILL_USE_MAGIC_DEVICE, oPC);
if(nSkill)
{
int nReqSkill = GetUMDForItemCost(oItem);
nSkill -= nReqSkill;
if(nSkill > 0)
nPaladinLevels = nSkill;
}
}
// Add Holy Avenger specials for Paladins (or successfull fake-Paladins)
if(nPaladinLevels)
{
DelayCommand(0.1, IPSafeAddItemProperty(oItem,
ItemPropertyEnhancementBonus(5), 99999.9));
DelayCommand(0.1, IPSafeAddItemProperty(oItem,
ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL,
IP_CONST_DAMAGETYPE_DIVINE, IP_CONST_DAMAGEBONUS_2d6), 99999.9));
//this is a normal dispel magic useage, should be specific
DelayCommand(0.1, IPSafeAddItemProperty(oItem,
ItemPropertyCastSpell(IP_CONST_CASTSPELL_DISPEL_MAGIC_5,
IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE), 99999.9));
DelayCommand(0.1, IPSafeAddItemProperty(oItem,
ItemPropertyCastSpellCasterLevel(SPELL_DISPEL_MAGIC,
nPaladinLevels), 99999.9));
}
// Non-Paladin's get +2 enhancement bonus
else
{
DelayCommand(0.1, IPSafeAddItemProperty(oItem,
ItemPropertyEnhancementBonus(2), 99999.9));
// Remove Paladin specials
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS, DURATION_TYPE_TEMPORARY, -1);
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP, DURATION_TYPE_TEMPORARY, IP_CONST_ALIGNMENTGROUP_EVIL);
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_CAST_SPELL, DURATION_TYPE_TEMPORARY);
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL, DURATION_TYPE_TEMPORARY);
}
}
else if(bUnequip)
{
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_ENHANCEMENT_BONUS,
DURATION_TYPE_TEMPORARY, -1);
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP,
DURATION_TYPE_TEMPORARY, IP_CONST_ALIGNMENTGROUP_EVIL);
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_CAST_SPELL,
DURATION_TYPE_TEMPORARY);
IPRemoveMatchingItemProperties(oItem, ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL,
DURATION_TYPE_TEMPORARY);
}
}
else if(ipType == ITEM_PROPERTY_AREA_OF_EFFECT)
{
// This should only happen on equip or unequip
if(bEquip || bUnequip)
{
// Remove existing AoE
effect eTest = GetFirstEffect(oPC);
while(GetIsEffectValid(eTest))
{
if(GetEffectCreator(eTest) == oItem
&& GetEffectType(eTest) == EFFECT_TYPE_AREA_OF_EFFECT)
{
RemoveEffect(oPC, eTest);
if(DEBUG) DoDebug("CheckPRCLimitations: Removing old AoE effect");
}
eTest = GetNextEffect(oPC);
}
// Create new AoE - Only when equipping
if(bEquip)
{
AssignCommand(oItem, _prc_inc_itmrstr_ApplyAoE(oPC, oItem, GetItemPropertySubType(ipTest), GetItemPropertyCostTable(ipTest)));
}// end if - Equip event
}// end if - Equip or Unequip event
}// end if - AoE iprp
else if(ipType == ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N)
{
// Only equippable items can provide bonus spell slots
if(bEquip || bUnequip)
{
int nSubType = GetItemPropertySubType(ipTest);
int nCost = GetItemPropertyCostTable(ipTest);
SetLocalInt(oPC,
"PRC_IPRPBonSpellSlots_" + IntToString(nSubType) + "_" + IntToString(nCost),
GetLocalInt(oPC,
"PRC_IPRPBonSpellSlots_" + IntToString(nSubType) + "_" + IntToString(nCost)
)
+ (bEquip ? 1 : -1)
);
}
}
else if(ipType == ITEM_PROPERTY_WIZARDRY)
{
int nCost = GetItemPropertyCostTableValue(ipTest);
if(bEquip)
AssignCommand(oItem, _prc_inc_itmrstr_ApplyWizardry(oPC, oItem, nCost, "A"));
else if(bUnequip)
AssignCommand(oItem, _prc_inc_itmrstr_RemoveWizardry(oPC, oItem, nCost, "A"));
}
else if(ipType == ITEM_PROPERTY_DIVINITY)
{
int nCost = GetItemPropertyCostTableValue(ipTest);
if(bEquip)
AssignCommand(oItem, _prc_inc_itmrstr_ApplyWizardry(oPC, oItem, nCost, "D"));
else if(bUnequip)
AssignCommand(oItem, _prc_inc_itmrstr_RemoveWizardry(oPC, oItem, nCost, "D"));
}
ipTest = GetNextItemProperty(oItem);
}// end while - Loop over all itemproperties
// Determine if speed modification totals had changed
if(nSpeedDecrease != GetLocalInt(oPC, PLAYER_SPEED_DECREASE))
{
SetLocalInt(oPC, PLAYER_SPEED_DECREASE, nSpeedDecrease);
//_prc_inc_itmrstr_ApplySpeedDecrease(oPC);
}
if(nSpeedIncrease != GetLocalInt(oPC, PLAYER_SPEED_INCREASE))
{
SetLocalInt(oPC, PLAYER_SPEED_INCREASE, nSpeedIncrease);
//_prc_inc_itmrstr_ApplySpeedIncrease(oPC);
}
// If some restriction would prevent item use, perform UMD skill check
// Skip in case of unequip
if(!bUnequip && !bPass)
bPass = DoUMDCheck(oItem, oPC, nUMDDC);
return bPass;
}
void CheckForPnPHolyAvenger(object oItem)
{
if(!GetPRCSwitch(PRC_PNP_HOLY_AVENGER_IPROP))
return;
itemproperty ipTest = GetFirstItemProperty(oItem);
while(GetIsItemPropertyValid(ipTest))
{
if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_HOLY_AVENGER)
{
DelayCommand(0.1, RemoveItemProperty(oItem, ipTest));
DelayCommand(0.1, IPSafeAddItemProperty(oItem, ItemPropertyPnPHolyAvenger()));
}
ipTest = GetNextItemProperty(oItem);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,669 @@
//::///////////////////////////////////////////////
//:: Shadowcasting main include: Miscellaneous
//:: shd_inc_shdfunc
//::///////////////////////////////////////////////
/** @file
Defines various functions and other stuff that
do something related to Shadowcasting.
Also acts as inclusion nexus for the general
shadowcasting includes. In other words, don't include
them directly in your scripts, instead include this.
@author Stratovarius
@date Created - 2019.02.08
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//:: Updated for .35 by Jaysyn 2023/03/10
//:: Test Void
// void main (){}
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Determines from what class's mystery list the currently being shadowcast
* mystery is shadowcast from.
*
* @param oShadow A creature shadowcasting a mystery at this moment
* @return CLASS_TYPE_* constant of the class
*/
int GetShadowcastingClass(object oShadow = OBJECT_SELF);
/**
* Determines the given creature's Shadowcaster level. If a class is specified,
* then returns the Shadowcaster level for that class. Otherwise, returns
* the Shadowcaster level for the currently active mystery.
*
* @param oShadow The creature whose Shadowcaster level to determine
* @param nSpecificClass The class to determine the creature's Shadowcaster
* level in.
* DEFAULT: CLASS_TYPE_INVALID, which means the creature's
* Shadowcaster level in regards to an ongoing mystery
* is determined instead.
* @return The Shadowcaster level
*/
int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLASS_TYPE_INVALID);
/**
* Determines whether a given creature uses ShadowMagic.
* Requires either levels in a ShadowMagic-related class or
* natural ShadowMagic ability based on race.
*
* @param oCreature Creature to test
* @return TRUE if the creature can use ShadowMagics, FALSE otherwise.
*/
int GetIsShadowMagicUser(object oCreature);
/**
* Determines the given creature's highest unmodified Shadowcaster level among its
* shadowcasting classes.
*
* @param oCreature Creature whose highest Shadowcaster level to determine
* @return The highest unmodified Shadowcaster level the creature can have
*/
int GetHighestShadowcasterLevel(object oCreature);
/**
* Determines whether a given class is a ShadowMagic-related class or not.
*
* @param nClass CLASS_TYPE_* of the class to test
* @return TRUE if the class is a ShadowMagic-related class, FALSE otherwise
*/
int GetIsShadowMagicClass(int nClass);
/**
* Gets the level of the mystery being currently shadowcast or the level
* of the mystery ID passed to it.
*
* @param oShadow The creature currently shadowcasting a mystery
* @return The level of the mystery being shadowcast
*/
int GetMysteryLevel(object oShadow, int nMystId = 0);
/**
* Returns the name of the Path
*
* @param nPath PATH_* to name
*/
string GetPathName(int nPath);
/**
* Returns the Path the mystery is in
* @param nMystId Mystery to check
*
* @return PATH_*
*/
int GetPathByMystery(int nMystId);
/**
* Returns true or false if the character has Path
* focus in the chosen path
* @param oShadow Person to check
* @param nPath Path to check
*
* @return TRUE or FALSE
*/
int GetHasPathFocus(object oShadow, int nPath);
/**
* Calculates how many shadowcaster levels are gained by a given creature from
* it's levels in prestige classes.
*
* @param oCreature Creature to calculate added shadowcaster levels for
* @return The number of shadowcaster levels gained
*/
int GetShadowMagicPRCLevels(object oShadow);
/**
* Determines which of the character's classes is their highest or first
* shadowcasting class, if any. This is the one which gains shadowcaster
* level raise benefits from prestige classes.
*
* @param oCreature Creature whose classes to test
* @return CLASS_TYPE_* of the first shadowcasting class,
* CLASS_TYPE_INVALID if the creature does not possess any.
*/
int GetPrimaryShadowMagicClass(object oCreature = OBJECT_SELF);
/**
* Determines the position of a creature's first shadowcasting class, if any.
*
* @param oCreature Creature whose classes to test
* @return The position of the first shadowcasting class {1, 2, 3} or 0 if
* the creature possesses no levels in shadowcasting classes.
*/
int GetFirstShadowMagicClassPosition(object oCreature = OBJECT_SELF);
/**
* Returns ability score needed to Shadowcast
* Type 1 is score to cast, Type 2 is score for DC
*
* @param nClass The class to check
* @return ABILITY_*
*/
int GetShadowAbilityOfClass(int nClass, int nType);
/**
* Calculates the DC of the Mystery being currently shadowcast.
*
* WARNING: Return value is not defined when a mystery isn't being shadowcast.
*
*/
int GetShadowcasterDC(object oShadow = OBJECT_SELF);
/**
* Calculates the SpellPen of the Mystery being currently shadowcast.
* Whether a Mystery is supernatural or not is checked in EvaluateMystery
*
* Currently just a placeholder returning GetShadowcasterLevel
*/
int ShadowSRPen(object oShadow, int nShadowcasterLevel);
/**
* Stores a mystery structure as a set of local variables. If
* a structure was already stored with the same name on the same object,
* it is overwritten.
*
* @param oObject The object on which to store the structure
* @param sName The name under which to store the structure
* @param myst The mystery structure to store
*/
void SetLocalMystery(object oObject, string sName, struct mystery myst);
/**
* Retrieves a previously stored mystery structure. If no structure is stored
* by the given name, the structure returned is empty.
*
* @param oObject The object from which to retrieve the structure
* @param sName The name under which the structure is stored
* @return The structure built from local variables stored on oObject under sName
*/
struct mystery GetLocalMystery(object oObject, string sName);
/**
* Returns the boost to caster level from feats
*
* @param oShadow The caster
* @param nMyst The mystery being cast
* @return Total bonus to caster level
*/
int ShadowcastingFeats(object oShadow, int nMyst);
/**
* Returns the boost to DC from nocturnal caster
*
* @param oShadow The caster
* @param nPath The path to check for
* @return Total bonus to caster level
*/
int GetHasNocturnal(object oShadow, int nPath);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "prc_alterations"
#include "shd_inc_myst"
#include "shd_inc_mystknwn"
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int GetShadowcastingClass(object oShadow = OBJECT_SELF)
{
int nReturn = GetLocalInt(oShadow, PRC_SHADOWCASTING_CLASS) - 1;
//if (DEBUG) FloatingTextStringOnCreature("GetShadowcastingClass: GetShadowcastingClass value is "+IntToString(nReturn), oShadow);
return nReturn;
}
int GetShadowcasterLevel(object oShadow = OBJECT_SELF, int nSpecificClass = CLASS_TYPE_INVALID)
{
int nAdjust = GetLocalInt(oShadow, PRC_CASTERLEVEL_ADJUSTMENT);
int nLevel = GetLocalInt(oShadow, PRC_CASTERLEVEL_OVERRIDE);
int nMyst = PRCGetSpellId(); // The fact that this will return 0 sometimes is relied upon
if (GetIsFundamental(nMyst)) nSpecificClass = CLASS_TYPE_SHADOWCASTER;
// For when you want to assign the caster level.
if(nLevel)
{
if(DEBUG) SendMessageToPC(oShadow, "GetShadowcasterLevel(): Forced-level shadowcasting at level " + IntToString(nLevel));
//DelayCommand(1.0, DeleteLocalInt(oShadow, PRC_CASTERLEVEL_OVERRIDE));
return nLevel + nAdjust;
}
if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: "+GetName(oShadow)+" is a "+IntToString(nSpecificClass), oShadow);
// The function user needs to know the character's Shadowcaster level in a specific class
// instead of whatever the character last shadowcast a mystery as
if(nSpecificClass != CLASS_TYPE_INVALID)
{
//if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: Class is Valid", oShadow);
if(GetIsShadowMagicClass(nSpecificClass))
{
//if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: Class is Shadow Magic Class", oShadow);
// Shadowcaster level is class level + prestige
nLevel = GetLevelByClass(nSpecificClass, oShadow);
if(nLevel)
{
nLevel += GetShadowMagicPRCLevels(oShadow);
nLevel += ShadowcastingFeats(oShadow, nMyst);
if (GetLocalInt(oShadow, "CaptureMagic"))
{
nLevel += GetLocalInt(oShadow, "CaptureMagic");
DeleteLocalInt(oShadow, "CaptureMagic");
}
if (GetLocalInt(oShadow, "EldritchDisrupt"))
nLevel -= 4;
if (GetLocalInt(oShadow, "EldritchVortex"))
nLevel -= 4;
}
}
}
else if(GetShadowcastingClass(oShadow) != -1)
{
//if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: GetShadowcastingClass", oShadow);
nLevel = GetLevelByClass(GetShadowcastingClass(oShadow), oShadow);
//if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: GetShadowcastingClass level "+IntToString(nLevel), oShadow);
nLevel += GetShadowMagicPRCLevels(oShadow);
//if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: GetShadowcastingClass prestige level "+IntToString(nLevel), oShadow);
nLevel += ShadowcastingFeats(oShadow, nMyst);
//if (DEBUG) FloatingTextStringOnCreature("GetShadowcasterLevel: GetShadowcastingClass feat level "+IntToString(nLevel), oShadow);
if (GetLocalInt(oShadow, "CaptureMagic"))
{
nLevel += GetLocalInt(oShadow, "CaptureMagic");
DeleteLocalInt(oShadow, "CaptureMagic");
}
if (GetLocalInt(oShadow, "EldritchDisrupt"))
nLevel -= 4;
if (GetLocalInt(oShadow, "EldritchVortex"))
nLevel -= 4;
}
if(DEBUG) FloatingTextStringOnCreature("Shadowcaster Level: " + IntToString(nLevel), oShadow, FALSE);
return nLevel + nAdjust;
}
int GetIsShadowMagicUser(object oCreature)
{
return !!(GetLevelByClass(CLASS_TYPE_SHADOWCASTER, oCreature)
|| GetLevelByClass(CLASS_TYPE_SHADOWSMITH, oCreature));
}
int GetHighestShadowcasterLevel(object oCreature)
{
int n = 0;
int nHighest;
int nTemp;
while(n <= 8)
{
if(GetClassByPosition(n, oCreature) != CLASS_TYPE_INVALID)
{
nTemp = GetShadowcasterLevel(oCreature, GetClassByPosition(n, oCreature));
if(nTemp > nHighest)
nHighest = nTemp;
}
n++;
}
return nHighest;
}
/* int GetHighestShadowcasterLevel(object oCreature)
{
return max(max(GetClassByPosition(1, oCreature) != CLASS_TYPE_INVALID ? GetShadowcasterLevel(oCreature, GetClassByPosition(1, oCreature)) : 0,
GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID ? GetShadowcasterLevel(oCreature, GetClassByPosition(2, oCreature)) : 0
),
GetClassByPosition(3, oCreature) != CLASS_TYPE_INVALID ? GetShadowcasterLevel(oCreature, GetClassByPosition(3, oCreature)) : 0
);
} */
int GetIsShadowMagicClass(int nClass)
{
return nClass == CLASS_TYPE_SHADOWCASTER
|| nClass == CLASS_TYPE_SHADOWSMITH;
}
int GetMysteryLevel(object oShadow, int nMystId = 0)
{
if (nMystId > 0) return StringToInt(lookup_spell_innate(nMystId));
int nLevel = GetLocalInt(oShadow, PRC_MYSTERY_LEVEL);
if (nLevel > 0) return nLevel;
return 0;
}
string GetPathName(int nPath)
{
int nStrRef;
switch(nPath)
{
/* case PATH_DESERT_WIND: nStrRef = 16829714; break;
case PATH_DEVOTED_SPIRIT: nStrRef = 16829715; break;
case PATH_DIAMOND_MIND: nStrRef = 16829716; break;
case PATH_IRON_HEART: nStrRef = 16829717; break;
case PATH_SETTING_SUN: nStrRef = 16829718; break;
case PATH_SHADOW_HAND: nStrRef = 16829719; break;
case PATH_STONE_DRAGON: nStrRef = 16829720; break;
case PATH_TIGER_CLAW: nStrRef = 16829721; break;
case PATH_WHITE_RAVEN: nStrRef = 16829722; break;*/
}
return GetStringByStrRef(nStrRef);
}
int GetPathByMystery(int nMystId)
{
// Shadowcaster has every mystery ever, so this is just the easy way out.
int i = GetPowerfileIndexFromRealSpellID(nMystId);
string sClass = GetAMSDefinitionFileName(CLASS_TYPE_SHADOWCASTER);
int nReturn = StringToInt(Get2DACache(sClass, "Path", i));
/*if (DEBUG) DoDebug("GetPathByMystery() i "+IntToString(i));
if (DEBUG) DoDebug("GetPathByMystery() sClass "+sClass);
if (DEBUG) DoDebug("GetPathByMystery() nReturn "+IntToString(nReturn)); */
return nReturn;
}
int GetShadowMagicPRCLevels(object oShadow)
{
int nLevel = GetLevelByClass(CLASS_TYPE_NOCTUMANCER, oShadow);
// These two don't add at 1st level
if (GetLevelByClass(CLASS_TYPE_CHILD_OF_NIGHT, oShadow))
nLevel += GetLevelByClass(CLASS_TYPE_CHILD_OF_NIGHT, oShadow) - 1;
if (GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oShadow))
nLevel += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oShadow) - 1;
return nLevel;
}
int GetPrimaryShadowMagicClass(object oCreature = OBJECT_SELF)
{
int nClass = CLASS_TYPE_INVALID;
if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE))
{
int nShadowMagicPos = GetFirstShadowMagicClassPosition(oCreature);
if (!nShadowMagicPos) return CLASS_TYPE_INVALID; // no Blade Magic shadowcasting class
nClass = GetClassByPosition(nShadowMagicPos, 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(GetIsShadowMagicClass(nClass1)) nClass1Lvl = GetLevelByClass(nClass1, oCreature);
if(GetIsShadowMagicClass(nClass2)) nClass2Lvl = GetLevelByClass(nClass2, oCreature);
if(GetIsShadowMagicClass(nClass3)) nClass3Lvl = GetLevelByClass(nClass3, oCreature);
if(GetIsShadowMagicClass(nClass4)) nClass4Lvl = GetLevelByClass(nClass4, oCreature);
if(GetIsShadowMagicClass(nClass5)) nClass5Lvl = GetLevelByClass(nClass5, oCreature);
if(GetIsShadowMagicClass(nClass6)) nClass6Lvl = GetLevelByClass(nClass6, oCreature);
if(GetIsShadowMagicClass(nClass7)) nClass7Lvl = GetLevelByClass(nClass7, oCreature);
if(GetIsShadowMagicClass(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 GetFirstShadowMagicClassPosition(object oCreature = OBJECT_SELF)
{
if (GetIsShadowMagicClass(GetClassByPosition(1, oCreature)))
return 1;
if (GetIsShadowMagicClass(GetClassByPosition(2, oCreature)))
return 2;
if (GetIsShadowMagicClass(GetClassByPosition(3, oCreature)))
return 3;
if (GetIsShadowMagicClass(GetClassByPosition(4, oCreature)))
return 4;
if (GetIsShadowMagicClass(GetClassByPosition(5, oCreature)))
return 5;
if (GetIsShadowMagicClass(GetClassByPosition(6, oCreature)))
return 6;
if (GetIsShadowMagicClass(GetClassByPosition(7, oCreature)))
return 7;
if (GetIsShadowMagicClass(GetClassByPosition(8, oCreature)))
return 8;
return 0;
}
int GetHasPathFocus(object oShadow, int nPath)
{
//if (DEBUG) DoDebug("GetHasPathFocus() nPath "+IntToString(nPath));
int nFocus, nGRFocus, nReturn;
switch(nPath)
{
case PATH_CLOAK_SHADOWS: nFocus = FEAT_PATH_FOCUS_CLOAK_SHADOWS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_CLOAK_SHADOWS ; break;
case PATH_DARK_TERRAIN: nFocus = FEAT_PATH_FOCUS_DARK_TERRAIN ; nGRFocus = FEAT_GREATER_PATH_FOCUS_DARK_TERRAIN ; break;
case PATH_EBON_WHISPERS: nFocus = FEAT_PATH_FOCUS_EBON_WHISPERS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_EBON_WHISPERS ; break;
case PATH_EYES_DARKNESS: nFocus = FEAT_PATH_FOCUS_EYES_DARKNESS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_EYES_DARKNESS ; break;
case PATH_SHUTTERS_CLOUDS: nFocus = FEAT_PATH_FOCUS_SHUTTERS_CLOUDS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_SHUTTERS_CLOUDS ; break;
case PATH_TOUCH_TWILIGHT: nFocus = FEAT_PATH_FOCUS_TOUCH_TWILIGHT ; nGRFocus = FEAT_GREATER_PATH_FOCUS_TOUCH_TWILIGHT ; break;
case PATH_UMBRAL_MIND: nFocus = FEAT_PATH_FOCUS_UMBRAL_MIND ; nGRFocus = FEAT_GREATER_PATH_FOCUS_UMBRAL_MIND ; break;
case PATH_BLACK_MAGIC: nFocus = FEAT_PATH_FOCUS_BLACK_MAGIC ; nGRFocus = FEAT_GREATER_PATH_FOCUS_BLACK_MAGIC ; break;
case PATH_BODY_SOUL: nFocus = FEAT_PATH_FOCUS_BODY_SOUL ; nGRFocus = FEAT_GREATER_PATH_FOCUS_BODY_SOUL ; break;
case PATH_DARK_REFLECTIONS: nFocus = FEAT_PATH_FOCUS_DARK_REFLECTIONS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_DARK_REFLECTIONS ; break;
case PATH_EBON_ROADS: nFocus = FEAT_PATH_FOCUS_EBON_ROADS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_EBON_ROADS ; break;
case PATH_ELEMENTAL_SHADOWS: nFocus = FEAT_PATH_FOCUS_ELEMENTAL_SHADOWS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_ELEMENTAL_SHADOWS ; break;
case PATH_UNBINDING_SHADE: nFocus = FEAT_PATH_FOCUS_UNBINDING_SHADE ; nGRFocus = FEAT_GREATER_PATH_FOCUS_UNBINDING_SHADE ; break;
case PATH_VEIL_SHADOWS: nFocus = FEAT_PATH_FOCUS_VEIL_SHADOWS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_VEIL_SHADOWS ; break;
case PATH_BREATH_TWILIGHT: nFocus = FEAT_PATH_FOCUS_BREATH_TWILIGHT ; nGRFocus = FEAT_GREATER_PATH_FOCUS_BREATH_TWILIGHT ; break;
case PATH_DARK_METAMORPHOSIS: nFocus = FEAT_PATH_FOCUS_DARK_METAMORPHOSIS; nGRFocus = FEAT_GREATER_PATH_FOCUS_DARK_METAMORPHOSIS; break;
case PATH_EBON_WALLS: nFocus = FEAT_PATH_FOCUS_EBON_WALLS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_EBON_WALLS ; break;
case PATH_EYES_NIGHT_SKY: nFocus = FEAT_PATH_FOCUS_EYES_NIGHT_SKY ; nGRFocus = FEAT_GREATER_PATH_FOCUS_EYES_NIGHT_SKY ; break;
case PATH_HEART_SOUL: nFocus = FEAT_PATH_FOCUS_HEART_SOUL ; nGRFocus = FEAT_GREATER_PATH_FOCUS_HEART_SOUL ; break;
case PATH_SHADOW_CALLING: nFocus = FEAT_PATH_FOCUS_SHADOW_CALLING ; nGRFocus = FEAT_GREATER_PATH_FOCUS_SHADOW_CALLING ; break;
case PATH_NIGHTS_LONG_FINGERS: nFocus = FEAT_PATH_FOCUS_NIGHTS_LONG_FINGERS; nGRFocus = FEAT_GREATER_PATH_FOCUS_NIGHTS_LONG_FINGERS; break;
case PATH_DARKENED_ALLEYS: nFocus = FEAT_PATH_FOCUS_DARKENED_ALLEYS ; nGRFocus = FEAT_GREATER_PATH_FOCUS_DARKENED_ALLEYS ; break;
case PATH_SHADOWSCAPE: nFocus = FEAT_PATH_FOCUS_SHADOWSCAPE ; nGRFocus = FEAT_GREATER_PATH_FOCUS_SHADOWSCAPE ; break;
}
if(GetHasFeat(nFocus, oShadow))
nReturn = 1;
if(GetHasFeat(nGRFocus, oShadow))
nReturn = 2;
//if (DEBUG) DoDebug("GetHasPathFocus() nReturn "+IntToString(nReturn));
// If none of those trigger.
return nReturn;
}
int GetShadowAbilityOfClass(int nClass, int nType)
{
if (nClass == CLASS_TYPE_SHADOWSMITH) return ABILITY_INTELLIGENCE;
// Intelligence for max mystery known
if (nClass == CLASS_TYPE_SHADOWCASTER && nType == 1) return ABILITY_INTELLIGENCE;
// Charisma for DC
if (nClass == CLASS_TYPE_SHADOWCASTER && nType == 2) return ABILITY_CHARISMA;
// Technically, never gets here but the compiler does not realise that
return -1;
}
int GetShadowcasterDC(object oShadow = OBJECT_SELF)
{
// Things we need for DC Checks
int nMystId = PRCGetSpellId();
int nShadEvo = GetLocalInt(oShadow, "ShadowEvoking");
if (nShadEvo > 0)
nMystId = nShadEvo; // This is used to get the proper DC for Shadow Evocation mysteries
int nLevel = GetMysteryLevel(oShadow, nMystId);
int nClass = GetShadowcastingClass(oShadow);
int nShadow = GetShadowcasterLevel(oShadow);
int nAbi = GetAbilityModifier(GetShadowAbilityOfClass(nClass, 2), oShadow);
int nPath = GetPathByMystery(nMystId);
int nPFocus = GetHasPathFocus(oShadow, nPath);
int nNoct = GetHasNocturnal(oShadow, nPath);
nShadow -= nPFocus; // These don't count here
// DC is 10 + Mystery level + ability
int nDC = 10 + nLevel + nAbi;
// If total Shadowcaster level is >= 13, change the DC for level 3 and under mysteries
// DC is 10 + 1/2 Shadowcaster level + ability
if (GetIsMysterySupernatural(oShadow, nMystId, nClass))
nDC = 10 + nShadow/2 + nAbi;
nDC += nPFocus;
nDC += nNoct;// It's a 0 if it doesn't exist
return nDC;
}
int ShadowSRPen(object oShadow, int nShadowcasterLevel)
{
return nShadowcasterLevel;
}
void SetLocalMystery(object oObject, string sName, struct mystery myst)
{
//SetLocal (oObject, sName + "_", );
SetLocalObject(oObject, sName + "_oShadow", myst.oShadow);
SetLocalInt(oObject, sName + "_bCanMyst", myst.bCanMyst);
SetLocalInt(oObject, sName + "_nShadowcasterLevel", myst.nShadowcasterLevel);
SetLocalInt(oObject, sName + "_nMystId", myst.nMystId);
SetLocalInt(oObject, sName + "_nPen", myst.nPen);
SetLocalInt(oObject, sName + "_bIgnoreSR", myst.bIgnoreSR);
SetLocalInt(oObject, sName + "_bEmpower", myst.bEmpower);
SetLocalInt(oObject, sName + "_bExtend", myst.bExtend);
SetLocalInt(oObject, sName + "_bMaximize", myst.bMaximize);
SetLocalInt(oObject, sName + "_bQuicken", myst.bQuicken);
SetLocalInt(oObject, sName + "_nSaveDC", myst.nSaveDC);
SetLocalFloat(oObject, sName + "_fDur", myst.fDur);
}
struct mystery GetLocalMystery(object oObject, string sName)
{
struct mystery myst;
myst.oShadow = GetLocalObject(oObject, sName + "_oShadow");
myst.bCanMyst = GetLocalInt(oObject, sName + "_bCanMyst");
myst.nShadowcasterLevel = GetLocalInt(oObject, sName + "_nShadowcasterLevel");
myst.nMystId = GetLocalInt(oObject, sName + "_nMystId");
myst.nPen = GetLocalInt(oObject, sName + "_nPen");
myst.bIgnoreSR = GetLocalInt(oObject, sName + "_bIgnoreSR");
myst.bEmpower = GetLocalInt(oObject, sName + "_bEmpower");
myst.bExtend = GetLocalInt(oObject, sName + "_bExtend");
myst.bMaximize = GetLocalInt(oObject, sName + "_bMaximize");
myst.bQuicken = GetLocalInt(oObject, sName + "_bQuicken");
myst.nSaveDC = GetLocalInt(oObject, sName + "_nSaveDC");
myst.fDur = GetLocalFloat(oObject, sName + "_fDur");
return myst;
}
int ShadowcastingFeats(object oShadow, int nMyst)
{
int nReturn = 0;
int nPath = GetPathByMystery(nMyst);
nReturn += GetHasPathFocus(oShadow, nPath);
return nReturn;
}
int GetHasNocturnal(object oShadow, int nPath)
{
int nNocturnal, nReturn;
switch(nPath)
{
case PATH_CLOAK_SHADOWS: nNocturnal = FEAT_NOCTURNAL_CASTER_CLOAK_SHADOWS ; break;
case PATH_DARK_TERRAIN: nNocturnal = FEAT_NOCTURNAL_CASTER_DARK_TERRAIN ; break;
case PATH_EBON_WHISPERS: nNocturnal = FEAT_NOCTURNAL_CASTER_EBON_WHISPERS ; break;
case PATH_EYES_DARKNESS: nNocturnal = FEAT_NOCTURNAL_CASTER_EYES_DARKNESS ; break;
case PATH_SHUTTERS_CLOUDS: nNocturnal = FEAT_NOCTURNAL_CASTER_SHUTTERS_CLOUDS ; break;
case PATH_TOUCH_TWILIGHT: nNocturnal = FEAT_NOCTURNAL_CASTER_TOUCH_TWILIGHT ; break;
case PATH_UMBRAL_MIND: nNocturnal = FEAT_NOCTURNAL_CASTER_UMBRAL_MIND ; break;
case PATH_BLACK_MAGIC: nNocturnal = FEAT_NOCTURNAL_CASTER_BLACK_MAGIC ; break;
case PATH_BODY_SOUL: nNocturnal = FEAT_NOCTURNAL_CASTER_BODY_SOUL ; break;
case PATH_DARK_REFLECTIONS: nNocturnal = FEAT_NOCTURNAL_CASTER_DARK_REFLECTIONS ; break;
case PATH_EBON_ROADS: nNocturnal = FEAT_NOCTURNAL_CASTER_EBON_ROADS ; break;
case PATH_ELEMENTAL_SHADOWS: nNocturnal = FEAT_NOCTURNAL_CASTER_ELEMENTAL_SHADOWS ; break;
case PATH_UNBINDING_SHADE: nNocturnal = FEAT_NOCTURNAL_CASTER_UNBINDING_SHADE ; break;
case PATH_VEIL_SHADOWS: nNocturnal = FEAT_NOCTURNAL_CASTER_VEIL_SHADOWS ; break;
case PATH_BREATH_TWILIGHT: nNocturnal = FEAT_NOCTURNAL_CASTER_BREATH_TWILIGHT ; break;
case PATH_DARK_METAMORPHOSIS: nNocturnal = FEAT_NOCTURNAL_CASTER_DARK_METAMORPHOSIS; break;
case PATH_EBON_WALLS: nNocturnal = FEAT_NOCTURNAL_CASTER_EBON_WALLS ; break;
case PATH_EYES_NIGHT_SKY: nNocturnal = FEAT_NOCTURNAL_CASTER_EYES_NIGHT_SKY ; break;
case PATH_HEART_SOUL: nNocturnal = FEAT_NOCTURNAL_CASTER_HEART_SOUL ; break;
case PATH_SHADOW_CALLING: nNocturnal = FEAT_NOCTURNAL_CASTER_SHADOW_CALLING ; break;
case PATH_NIGHTS_LONG_FINGERS:nNocturnal = FEAT_NOCTURNAL_CASTER_NIGHTS_LONG_FINGERS; break;
case PATH_DARKENED_ALLEYS: nNocturnal = FEAT_NOCTURNAL_CASTER_DARKENED_ALLEYS ; break;
case PATH_SHADOWSCAPE: nNocturnal = FEAT_NOCTURNAL_CASTER_SHADOWSCAPE ; break;
}
if(GetHasFeat(nNocturnal, oShadow) && GetIsNight())
nReturn = 1;
// If none of those trigger.
return nReturn;
}

View File

@ -0,0 +1,652 @@
//::///////////////////////////////////////////////
//:: Tome of Battle include: Maneuver Recovery
//:: tob_inc_martlore
//::///////////////////////////////////////////////
/** @file
Defines various functions and other stuff that
do something related to recovery and readying maneuvers
See page #28 of Tome of Battle
Functions below are called by the initiator as
he makes a maneuver, or when recovering or readying
@author Stratovarius
@date Created - 2007.3.25
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//:: Updated for .35 by Jaysyn 2023/03/10
//:: Test Void
//void main (){}
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
const int MANEUVER_READIED = 1;
const int MANEUVER_RECOVERED = 2;
const int MANEUVER_GRANTED = 3;
const int MANEVUER_WITHHELD = 4;
const string _MANEUVER_LIST_RDYMODIFIER = "_ReadyModifier";
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Gets the number of Maneuvers a character has readied
*
* @param oPC The creature whose Maneuvers to check
* @param nList The list to check. One of MANEUVER_LIST_*
* @return The number of Maneuvers readied
*/
int GetReadiedCount(object oPC, int nList);
/**
* Gets the maximum number of Maneuvers a character may ready.
*
* @param oPC Character to determine maximum Maneuvers readied
* @param nList MANEUVER_LIST_* of the list to determine maximum Maneuvers for
* @return Maximum number of Maneuvers that oPC may ready
*/
int GetMaxReadiedCount(object oPC, int nList);
/**
* Gets the value of the Maneuvers readied modifier, which is a value that is added
* to the 2da-specified maximum Maneuvers readied to determine the actual maximum.
*
* @param oCreature The creature whose modifier to get
* @param nList The list the maximum Maneuvers readied from which the modifier
* modifies. One of MANEUVER_LIST_*
*/
int GetReadiedManeuversModifier(object oCreature, int nList);
/**
* Sets the value of the Maneuvers readied modifier, which is a value that is added
* to the 2da-specified maximum Maneuvers readied to determine the actual maximum.
*
* @param oCreature The creature whose modifier to set
* @param nList The list the maximum Maneuvers readied from which the modifier
* modifies. One of MANEUVER_LIST_*
*/
void SetReadiedManeuversModifier(object oCreature, int nList, int nNewValue);
/**
* Readies the chosen Maneuver. Also checks to see if there are any slots left
*
* @param oPC Character readying maneuver
* @param nList MANEUVER_LIST_* of the list to ready
* @param nMoveId Maneuver to ready
*/
void ReadyManeuver(object oPC, int nList, int nMoveId);
/**
* Returns whether maneuver is readied or not
*
* @param oPC Character to check
* @param nList MANEUVER_LIST_*
* @param nMoveId Maneuver to check
* @return TRUE or FALSE
*/
int GetIsManeuverReadied(object oPC, int nList, int nMoveId);
/**
* Returns whether maneuver is expended or not
*
* @param oPC Character to check
* @param nList MANEUVER_LIST_*
* @param nMoveId Maneuver to check
* @return TRUE or FALSE
*/
int GetIsManeuverExpended(object oPC, int nList, int nMoveId);
/**
* Expends the chosen Maneuver.
*
* @param oPC Character to check
* @param nList MANEUVER_LIST_*
* @param nMoveId Maneuver to expend
*/
void ExpendManeuver(object oPC, int nList, int nMoveId);
/**
* Clears all local ints marking maneuvers as expended
*
* @param oPC Character to clear
* @param nList MANEUVER_LIST_*
*/
void RecoverExpendedManeuvers(object oPC, int nList);
/**
* Recovers the chosen Maneuver.
*
* @param oPC Character to check
* @param nList MANEUVER_LIST_*
* @param nMoveId Maneuver to recover
*/
void RecoverManeuver(object oPC, int nList, int nMoveId);
/**
* Checks to see if the PC is in a Warblade recovery round
* This prevents all use of maneuvers or stances during that round.
*
* @param oPC Character to clear
* @return TRUE or FALSE
*/
int GetIsWarbladeRecoveryRound(object oPC);
/**
* Marks maneuvers as granted or withheld.
*
* @param oPC Character to grant maneuvers to
* @param nList MANEUVER_LIST_*
*/
void GrantManeuvers(object oPC, int nList);
/**
* Clears all local ints marking maneuvers as readied
*
* @param oPC Character to clear
* @param nList MANEUVER_LIST_*
*/
void ClearReadiedManeuvers(object oPC, int nList);
/**
* Grants a withheld maneuver
* Only works on Crusaders
*
* @param oPC Character to grant maneuvers to
* @param nList MANEUVER_LIST_*
* @param nMoveId Maneuver to grant
*/
void GrantWithheldManeuver(object oPC, int nList, int nMoveId = -1);
/**
* Returns whether maneuver is granted or not
* Only works on Crusaders
*
* @param oPC Character to check
* @param nMoveId Maneuver to check
* @return TRUE or FALSE
*/
int GetIsManeuverGranted(object oPC, int nMoveId);
/**
* Clears all local ints marking maneuvers as granted or withheld
* Only works on Crusaders
*
* @param oPC Character to clear
*/
void ClearGrantedWithheldManeuvers(object oPC);
/**
* Starting function for Crusader recovery, calls DoCrusaderGranting
* Only works on Crusaders
*
* @param oPC Crusader
*/
void BeginCrusaderGranting(object oPC);
/**
* Recursive function granting maneuvers each round in combat
* Will end when combat ends
* Only works on Crusaders
*
* @param oPC Crusader
* @param nTrip Round of combat. Takes values from 1 to 5, always starts with 1.
*/
void DoCrusaderGranting(object oPC, int nTrip);
/**
* Returns TRUE if a maneuver was expended, FALSE otherwise
* @param oPC Character to check
* @param nList MANEUVER_LIST_*
* @param nDiscipline DISCIPLINE_* the maneuver has to be from
*
* @return TRUE or FALSE
*/
int ExpendRandomManeuver(object oPC, int nList, int nDiscipline = -1);
/**
* Clears all local ints marking maneuvers as expended
*
* @param oPC Character to clear
* @param nPRC Specific PRC to recover, else all.
*/
void RecoverPrCAbilities(object oPC);
/**
* Heals 3 + 1 point per character level ones per minute
*
* @param oPC Character to heal
*/
void VitalRecovery(object oPC);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "inc_lookups"
#include "tob_inc_tobfunc"
//////////////////////////////////////////////////
/* Internal functions */
//////////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int GetReadiedCount(object oPC, int nList)
{
return GetLocalInt(oPC, "ManeuverReadied" + IntToString(nList));
}
int GetMaxReadiedCount(object oPC, int nList)
{
int nLevel = GetLevelByClass(nList, oPC);
// 2das start at Row 0
int nMaxReadied = StringToInt(Get2DACache(GetAMSKnownFileName(nList), "ManeuversReadied", nLevel-1));
// Add in the custom modifier
nMaxReadied += GetReadiedManeuversModifier(oPC, nList);
if(nList == MANEUVER_LIST_SWORDSAGE)
nMaxReadied += GetHasFeat(FEAT_EXTRA_GRANTED_MANEUVER, oPC);
if(DEBUG) DoDebug("tob_inc_recovery: MaxManeuvers Readied: " +IntToString(nMaxReadied));
return nMaxReadied;
}
int GetReadiedManeuversModifier(object oCreature, int nList)
{
return GetPersistantLocalInt(oCreature, _MANEUVER_LIST_NAME_BASE + IntToString(nList) + _MANEUVER_LIST_RDYMODIFIER);
}
void SetReadiedManeuversModifier(object oCreature, int nList, int nNewValue)
{
SetPersistantLocalInt(oCreature, _MANEUVER_LIST_NAME_BASE + IntToString(nList) + _MANEUVER_LIST_RDYMODIFIER, nNewValue);
}
void ReadyManeuver(object oPC, int nList, int nMoveId)
{
int nCount = GetReadiedCount(oPC, nList);
int nMaxCount = GetMaxReadiedCount(oPC, nList);
// If the PC can ready a maneuver and hasn't filled them all up
if(nMaxCount > nCount)
{
nCount++;
SetLocalInt(oPC, "ManeuverReadied" + IntToString(nList) + IntToString(nCount), nMoveId);
SetLocalInt(oPC, "ManeuverReadied" + IntToString(nList), nCount);
if(DEBUG) DoDebug("tob_inc_recovery: ReadyManeuver: " +IntToString(nMoveId));
}
else
FloatingTextStringOnCreature("All maneuvers are readied", oPC, FALSE);
}
int GetIsManeuverReadied(object oPC, int nList, int nMoveId)
{
// Counting through the local ints to determine if this one is readied
int i, nMax = GetReadiedCount(oPC, nList);
for(i = 1; i <= nMax; i++)
{
// If the value is valid, return true
if(GetLocalInt(oPC, "ManeuverReadied" + IntToString(nList) + IntToString(i)) == nMoveId)
{
if(DEBUG) DoDebug("tob_inc_recovery: GetIsManeuverReadied: " + IntToString(nMoveId));
return TRUE;
}
}
return FALSE;
}
int GetIsManeuverExpended(object oPC, int nList, int nMoveId)
{
// Counting through the local ints to determine if this one is expended
int i, nMax = GetLocalInt(oPC, "ManeuverExpended" + IntToString(nList));
for(i = 1; i <= nMax; i++)
{
// returns if the maneuver is expended
if(GetLocalInt(oPC, "ManeuverExpended" + IntToString(nList) + IntToString(i)) == nMoveId)
{
if(DEBUG) DoDebug("tob_inc_recovery: GetIsManeuverExpended: " +IntToString(nMoveId));
return TRUE;
}
}
return FALSE;
}
void ExpendManeuver(object oPC, int nList, int nMoveId)
{
int nCount = GetLocalInt(oPC, "ManeuverExpended" + IntToString(nList)) + 1;
// This will mark the Maneuver Expended
SetLocalInt(oPC, "ManeuverExpended" + IntToString(nList) + IntToString(nCount), nMoveId);
SetLocalInt(oPC, "ManeuverExpended" + IntToString(nList), nCount);
if(DEBUG) DoDebug("tob_inc_recovery: Expending Maneuver: " + IntToString(nMoveId));
}
void RecoverExpendedManeuvers(object oPC, int nList)
{
if(DEBUG) DoDebug("tob_inc_recovery: Clearing expended maneuvers");
// Counting through the local ints to clear them all
int i, nMax = GetLocalInt(oPC, "ManeuverExpended" + IntToString(nList));
DeleteLocalInt(oPC, "ManeuverExpended" + IntToString(nList));
for(i = 1; i <= nMax; i++)
{
// Clear them all
DeleteLocalInt(oPC, "ManeuverExpended" + IntToString(nList) + IntToString(i));
}
// Do Grant/Withheld Maneuvers whenever this is called on a Crusader
if (nList == MANEUVER_LIST_CRUSADER)
{
// Make sure to clear them all first
ClearGrantedWithheldManeuvers(oPC);
// Then re-grant/withhold them
GrantManeuvers(oPC, nList);
}
if (GetHasFeat(FEAT_VITAL_RECOVERY, oPC)) VitalRecovery(oPC);
}
void RecoverManeuver(object oPC, int nList, int nMoveId)
{
// Counting through the local ints to determine if this one is expended
int i, nMax = GetLocalInt(oPC, "ManeuverExpended" + IntToString(nList));
for(i = 1; i <= nMax; i++)
{
// If it has been expended, clear that
if(GetLocalInt(oPC, "ManeuverExpended" + IntToString(nList) + IntToString(i)) == nMoveId)
{
DeleteLocalInt(oPC, "ManeuverExpended" + IntToString(nList) + IntToString(i));
if(DEBUG) DoDebug("tob_inc_recovery: Recovering Maneuver: " + IntToString(nMoveId));
}
}
if (GetHasFeat(FEAT_VITAL_RECOVERY, oPC)) VitalRecovery(oPC);
}
int GetIsWarbladeRecoveryRound(object oPC)
{
if(DEBUG) DoDebug("tob_inc_recovery: Warblade recovery check");
return GetLocalInt(oPC, "WarbladeRecoveryRound");
}
void GrantRandomManeuver(object oPC, int nList = MANEUVER_LIST_CRUSADER)
{
int nMax = GetLocalInt(oPC, "GrantRand#");
if(!nMax) return;//nothing to grant
SetLocalInt(oPC, "GrantRand#", nMax - 1);
int x = Random(nMax)+1;
int nMoveId = GetLocalInt(oPC, "GrantRand#" + IntToString(x));
if(x != nMax)
SetLocalInt(oPC, "GrantRand#" + IntToString(x), GetLocalInt(oPC, "GrantRand#" + IntToString(nMax)));
DeleteLocalInt(oPC, "GrantRand#" + IntToString(nMax));
//GrantWithheldManeuver(oPC, MANEUVER_LIST_CRUSADER, MoveId);
// No point in granting an expended maneuver
if(GetIsManeuverExpended(oPC, nList, nMoveId))
RecoverManeuver(oPC, nList, nMoveId);
int i = 1;
while(i)
{
// If it hits a non-valid, break
if(!GetLocalInt(oPC, "ManeuverGranted" + IntToString(i))) break;
i++;
}
SetLocalInt(oPC, "ManeuverGranted" + IntToString(i), nMoveId);
}
void ListGrantedManeuvers(object oPC)
{
int i;
for(i = 1; i <= 4; i++)
{
int nMoveId = GetLocalInt(oPC, "ManeuverGranted" + IntToString(i));
int nExpended = GetIsManeuverExpended(oPC, MANEUVER_LIST_CRUSADER, nMoveId);
if (nMoveId > 0 && !nExpended) FloatingTextStringOnCreature(GetManeuverName(nMoveId) + " is granted", oPC, FALSE);
}
}
void GrantManeuvers(object oPC, int nList = MANEUVER_LIST_CRUSADER)
{
// Only crusader level matters for this
int nLevel = GetLevelByClass(CLASS_TYPE_CRUSADER, oPC);
// 2das start at Row 0
int nGranted = StringToInt(Get2DACache(GetAMSKnownFileName(nList), "ManeuversGranted", nLevel-1));
nGranted += GetReadiedManeuversModifier(oPC, nList);
nGranted += GetHasFeat(FEAT_EXTRA_GRANTED_MANEUVER, oPC);
// Counting through the local ints to determine how many are readied
int i, nMaxReadied = GetReadiedCount(oPC, nList);
SetLocalInt(oPC, "GrantRand#", nMaxReadied);
for(i = 1; i <= nMaxReadied; i++)
{
// build temporary array for GrantRandomManeuver() function
int nMoveId = GetLocalInt(oPC, "ManeuverReadied" + IntToString(nList) + IntToString(i));
if(nMoveId)
SetLocalInt(oPC, "GrantRand#" + IntToString(i), nMoveId);
}
for(i = 1; i <= nGranted; i++)
{
GrantRandomManeuver(oPC);
}
ListGrantedManeuvers(oPC);
}
void ClearReadiedManeuvers(object oPC, int nList)
{
if(DEBUG) DoDebug("tob_inc_recovery: Clearing readied maneuvers");
// Counting through the local ints to clear them all
int i, nMax = GetReadiedCount(oPC, nList);
DeleteLocalInt(oPC, "ManeuverReadied" + IntToString(nList));
for(i = 1; i <= nMax; i++)
{
// Clear them all
DeleteLocalInt(oPC, "ManeuverReadied" + IntToString(nList) + IntToString(i));
}
}
/*void GrantWithheldManeuver(object oPC, int nList, int nMoveId = -1)
{
int i;
string sPsiFile = GetAMSKnownFileName(nList);
// 2das start at Row 0
int nLevel = GetInitiatorLevel(oPC, nList);
int nGranted = StringToInt(Get2DACache(sPsiFile, "ManeuversGranted", nLevel-1));
int nReadied = StringToInt(Get2DACache(sPsiFile, "ManeuversReadied", nLevel-1));
if(DEBUG) DoDebug("tob_inc_recovery: Maneuvers Granted: " + IntToString(nGranted));
if(DEBUG) DoDebug("tob_inc_recovery: Maneuvers Readied: " + IntToString(nReadied));
// If someone input a maneuver
if (nMoveId > 0)
{
// No point in granting an expended maneuver
if (GetIsManeuverExpended(oPC, nList, nMoveId))
RecoverManeuver(oPC, nList, nMoveId);
// 3 is always the number withheld
for(i = nGranted; i < nReadied; i++)
{
// Making sure it gets marked properly
int nGrantId = GetLocalInt(oPC, "ManeuverWithheld" + IntToString(i));
// If it exists, mark it as ready and break out
if (nMoveId == nGrantId)
{
if(DEBUG) DoDebug("tob_inc_recovery: Withheld Maneuver Granted: " + IntToString(nMoveId));
DeleteLocalInt(oPC, "ManeuverWithheld" + IntToString(i));
FloatingTextStringOnCreature(GetManeuverName(nMoveId) + " is granted", oPC, FALSE);
SetLocalInt(oPC, "ManeuverGranted" + IntToString(i), nMoveId);
break;
}
}
}
else
{
// 3 is always the number withheld
for(i = nGranted; i < nReadied; i++)
{
nMoveId = GetLocalInt(oPC, "ManeuverWithheld" + IntToString(i));
// If it exists, mark it as ready and break out
if (nMoveId > 0)
{
if(DEBUG) DoDebug("tob_inc_recovery: Withheld Maneuver Granted: " + IntToString(nMoveId));
DeleteLocalInt(oPC, "ManeuverWithheld" + IntToString(i));
FloatingTextStringOnCreature(GetManeuverName(nMoveId) + " is granted", oPC, FALSE);
SetLocalInt(oPC, "ManeuverGranted" + IntToString(i), nMoveId);
break;
}
}
}
}*/
int GetIsManeuverGranted(object oPC, int nMoveId)
{
if(DEBUG) DoDebug("tob_inc_recovery: GetIsManeuverGranted Start");
// Counting through the local ints to determine if this one is expended
int i, nMax = GetReadiedCount(oPC, MANEUVER_LIST_CRUSADER);
for(i = 1; i <= nMax; i++)
{
// returns if the maneuver is expended
if(GetLocalInt(oPC, "ManeuverGranted" + IntToString(i)) == nMoveId)
{
if(DEBUG) DoDebug("tob_inc_recovery: GetIsManeuverGranted: " + IntToString(nMoveId));
return TRUE;
}
}
return FALSE;
}
void ClearGrantedWithheldManeuvers(object oPC)
{
if(DEBUG) DoDebug("tob_inc_recovery: Clearing Granted and Withheld Maneuvers");
// Counting through the local ints to clear them all
int i, nMax = GetReadiedCount(oPC, MANEUVER_LIST_CRUSADER);
for(i = 1; i <= nMax; i++)
{
// Clear them all
DeleteLocalInt(oPC, "ManeuverGranted" + IntToString(i));
}
}
void BeginCrusaderGranting(object oPC)
{
if(DEBUG) DoDebug("BeginCrusaderGranting(): Entered Function");
// Stops it from being called more than once.
if(GetLocalInt(oPC, "CrusaderGrantLoop")) return;
SetLocalInt(oPC, "CrusaderGrantLoop", TRUE);
// Starts the granting process
if(DEBUG) DoDebug("BeginCrusaderGranting(): DoCrusaderGranting called");
DoCrusaderGranting(oPC, 1);
}
void DoCrusaderGranting(object oPC, int nTrip)
{
if(DEBUG) DoDebug("DoCrusaderGranting(): Entered Function on Round #" + IntToString(nTrip));
// First round of combat, no granting.
// Last round of the 5, clear and recover/grant maneuvers
if (nTrip >= 5) // Granted maneuvers empty, restart
{
if(DEBUG) DoDebug("DoCrusaderGranting(): RecoverExpendedManeuvers");
RecoverExpendedManeuvers(oPC, MANEUVER_LIST_CRUSADER);
nTrip = 1;
}
else if (nTrip > 1)
{
// Rounds 2-4, grant a single maneuver
if(DEBUG) DoDebug("DoCrusaderGranting(): GrantWithheldManeuver");
//GrantWithheldManeuver(oPC, MANEUVER_LIST_CRUSADER);
GrantRandomManeuver(oPC);
ListGrantedManeuvers(oPC);
}
if(DEBUG) DoDebug("DoCrusaderGranting(): Above Recursive");
// If in combat, keep the loop going
if (GetIsInCombat(oPC))
{
if(DEBUG) DoDebug("DoCrusaderGranting(): In Combat");
DelayCommand(6.0, DoCrusaderGranting(oPC, ++nTrip)); // Increment counter
}
else // Recover and stop loop otherwise.
{
if(DEBUG) DoDebug("DoCrusaderGranting(): Out of Combat Maneuver Recovery");
RecoverExpendedManeuvers(oPC, MANEUVER_LIST_CRUSADER);
// Resent Int for next time out
DeleteLocalInt(oPC, "CrusaderGrantLoop");
}
if(DEBUG) DoDebug("DoCrusaderGranting(): Ending");
}
int ExpendRandomManeuver(object oPC, int nList, int nDiscipline = -1)
{
// Counting through the local ints to determine if maneuver can be expended
int i, nMax = GetReadiedCount(oPC, nList);
for(i = 1; i <= nMax; i++)
{
// If the value is valid, next step
int nMoveId = GetLocalInt(oPC, "ManeuverReadied" + IntToString(nList) + IntToString(i));
if(nMoveId > 0)
{
// Make sure the disciplines match
if(nDiscipline == -1 || GetDisciplineByManeuver(nMoveId) == nDiscipline)
{
// If not expended
if(!GetIsManeuverExpended(oPC, nList, nMoveId))
{
// Expend the damn thing and go home
ExpendManeuver(oPC, nList, nMoveId);
return TRUE;
}
}
}
}
// If we're here, failed.
return FALSE;
}
void RecoverPrCAbilities(object oPC)
{
int i;
for(i = 2; i <= 8; i++) // PrC abilities: check last seven slots
{
int nClass = GetClassByPosition(i, oPC);
if(DEBUG) DoDebug("RecoverPrCAbilities" + IntToString(nClass));
switch(nClass)
{
case CLASS_TYPE_INVALID:
if(DEBUG) DoDebug("RecoverPrCAbilities: no class to recover");
break;
case CLASS_TYPE_JADE_PHOENIX_MAGE:
DeleteLocalInt(oPC, "JPM_Empowering_Strike_Expended");
DeleteLocalInt(oPC, "JPM_Quickening_Strike_Expended");
break;
case CLASS_TYPE_DEEPSTONE_SENTINEL:
DeleteLocalInt(oPC, "DPST_Awaken_Stone_Dragon_Expended");
break;
case CLASS_TYPE_ETERNAL_BLADE:
DeleteLocalInt(oPC, "ETBL_Eternal_Training_Expended");
DeleteLocalInt(oPC, "ETBL_Island_In_Time_Expended");
// Remove bonus to racial type from eternal training
PRCRemoveEffectsFromSpell(oPC, ETBL_RACIAL_TYPE);
break;
}
}
}
void VitalRecovery(object oPC)
{
if (GetLocalInt(oPC, "VitalRecovery")) return; //Once a minute
int nHD = GetHitDice(oPC);
effect eHeal = EffectHeal(nHD+3); // That's it
effect eVis = EffectVisualEffect(VFX_IMP_HEALING_M);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oPC);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);
SetLocalInt(oPC, "VitalRecovery", TRUE);
DelayCommand(60.0, DeleteLocalInt(oPC, "VitalRecovery"));
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,839 @@
//::///////////////////////////////////////////////
//:: Truenaming include: Misceallenous
//:: true_inc_trufunc
//::///////////////////////////////////////////////
/** @file
Defines various functions and other stuff that
do something related to the truenaming implementation.
Also acts as inclusion nexus for the general
truenaming includes. In other words, don't include
them directly in your scripts, instead include this.
@author Stratovarius
@date Created - 2006.7.18
*/
//:://////////////////////////////////////////////
//:://////////////////////////////////////////////
//:: Updated for .35 by Jaysyn 2023/03/11
//:: Test Void
//void main (){}
//////////////////////////////////////////////////
/* Constants */
//////////////////////////////////////////////////
//////////////////////////////////////////////////
/* Function prototypes */
//////////////////////////////////////////////////
/**
* Determines from what class's Utterance list the currently being truespoken
* Utterance is truespoken from.
*
* @param oTrueSpeaker A creature uttering a Utterance at this moment
* @return CLASS_TYPE_* constant of the class
*/
int GetTruespeakingClass(object oTrueSpeaker = OBJECT_SELF);
/**
* Determines the given creature's truespeaker level. If a class is specified,
* then returns the truespeaker level for that class. Otherwise, returns
* the truespeaker level for the currently active utterance.
*
* @param oTrueSpeaker The creature whose truespeaker level to determine
* @param nSpecificClass The class to determine the creature's truespeaker
* level in.
* @param nUseHD If this is set, it returns the Character Level of the calling creature.
* DEFAULT: CLASS_TYPE_INVALID, which means the creature's
* truespeaker level in regards to an ongoing utterance
* is determined instead.
* @return The truespeaker level
*/
int GetTruespeakerLevel(object oTrueSpeaker, int nSpecificClass = CLASS_TYPE_INVALID, int nUseHD = FALSE);
/**
* Determines whether a given creature uses truenaming.
* Requires either levels in a truenaming-related class or
* natural truenaming ability based on race.
*
* @param oCreature Creature to test
* @return TRUE if the creature can use truenames, FALSE otherwise.
*/
int GetIsTruenamingUser(object oCreature);
/**
* Determines the given creature's highest undmodified truespeaker level among it's
* uttering classes.
*
* @param oCreature Creature whose highest truespeaker level to determine
* @return The highest unmodified truespeaker level the creature can have
*/
int GetHighestTrueSpeakerLevel(object oCreature);
/**
* Determines whether a given class is a truenaming-related class or not.
*
* @param nClass CLASS_TYPE_* of the class to test
* @return TRUE if the class is a truenaming-related class, FALSE otherwise
*/
int GetIsTruenamingClass(int nClass);
/**
* Gets the level of the Utterance being currently truespoken.
* WARNING: Return value is not defined when a Utterance is not being truespoken.
*
* @param oTrueSpeaker The creature currently uttering a utterance
* @return The level of the Utterance being truespoken
*/
int GetUtteranceLevel(object oTrueSpeaker);
/**
* Determines a creature's ability score in the uttering ability of a given
* class.
*
* @param oTrueSpeaker Creature whose ability score to get
* @param nClass CLASS_TYPE_* constant of a uttering class
*/
int GetTruenameAbilityScoreOfClass(object oTrueSpeaker, int nClass);
/**
* Determines the uttering ability of a class.
*
* @param nClass CLASS_TYPE_* constant of the class to determine the uttering stat of
* @return ABILITY_* of the uttering stat. ABILITY_CHARISMA for non-TrueSpeaker
* classes.
*/
int GetTruenameAbilityOfClass(int nClass);
/**
* Calculates the DC of the Utterance being currently truespoken.
* Base value is 10 + Utterance level + ability modifier in uttering stat
*
* WARNING: Return value is not defined when a Utterance is not being truespoken.
*
*/
int GetTrueSpeakerDC(object oTrueSpeaker = OBJECT_SELF);
/**
* Determines the truespeaker's level in regards to truespeaker checks to overcome
* spell resistance.
*
* WARNING: Return value is not defined when a Utterance is not being truespoken.
*
* @param oTrueSpeaker A creature uttering a Utterance at the moment
* @return The creature's truespeaker level, adjusted to account for
* modifiers that affect spell resistance checks.
*/
int GetTrueSpeakPenetration(object oTrueSpeaker = OBJECT_SELF);
/**
* Marks an utterance as active for the Law of Sequence.
* Called from the Utterance
*
* @param oTrueSpeaker Caster of the Utterance
* @param nSpellId SpellId of the Utterance
* @param fDur Duration of the Utterance
*/
void DoLawOfSequence(object oTrueSpeaker, int nSpellId, float fDur);
/**
* Checks to see whether the law of sequence is active
* Utterance fails if it is.
*
* @param oTrueSpeaker Caster of the Utterance
* @param nSpellId SpellId of the Utterance
*
* @return True if the Utterance is active, False if it is not.
*/
int CheckLawOfSequence(object oTrueSpeaker, int nSpellId);
/**
* Returns the name of the Utterance
*
* @param nSpellId SpellId of the Utterance
*/
string GetUtteranceName(int nSpellId);
/**
* Returns the name of the Lexicon
*
* @param nLexicon LEXICON_* to name
*/
string GetLexiconName(int nLexicon);
/**
* Returns the Lexicon the Utterance is in
* @param nSpellId Utterance to check
*
* @return LEXICON_*
*/
int GetLexiconByUtterance(int nSpellId);
/**
* Affects all of the creatures with Speak Unto the Masses
*
* @param oTrueSpeaker Caster of the Utterance
* @param oTarget Original Target of Utterance
* @param utter The utterance structure returned by EvaluateUtterance
*/
void DoSpeakUntoTheMasses(object oTrueSpeaker, object oTarget, struct utterance utter);
/**
* Affects all of the creatures with Speak Unto the Masses
*
* @param oTrueSpeaker Caster of the Utterance
* @param oTarget Original Target of Utterance
* @param utter The utterance structure returned by EvaluateUtterance
*/
void DoWordOfNurturingReverse(object oTrueSpeaker, object oTarget, struct utterance utter);
/**
* Affects all of the creatures with Speak Unto the Masses
*
* @param oTrueSpeaker Caster of the Utterance
* @param oTarget Original Target of Utterance
* @param utter The utterance structure returned by EvaluateUtterance
* @param nBeats Number of rounds to fire this utterance
* @param nDamageType DAMAGE_TYPE_*
*/
void DoEnergyNegation(object oTrueSpeaker, object oTarget, struct utterance utter, int nBeats, int nDamageType);
/**
* Checks to see if the chosen target of the Crafted Tool utterance is valid.
* If it is not valid, it will search through all slots, starting with right hand weapon
* to try and find a valid target.
*
* @param oTrueSpeaker Caster of the Utterance
* @param oTarget Target of the utterance
*
* @return Item in slot, or, if there are no valid objects on the creature, OBJECT_INVALID.
* If the target is an item, it returns the item.
*/
object CraftedToolTarget(object oTrueSpeaker, object oTarget);
/**
* Enforces the cross class cap on the Truespeech skill
*
* @param oTrueSpeaker The PC whose feats to check.
* @return TRUE if needed to relevel, FALSE otherwise.
*/
int CheckTrueSpeechSkill(object oTrueSpeaker);
/**
* Applies modifications to a utterance's damage that depend on some property
* of the target.
* Currently accounts for:
* - Mental Resistance
* - Greater Utterance Specialization
* - Intellect Fortress
*
* @param oTarget A creature being dealt damage by a utterance
* @param oTrueSpeaker The creature uttering the damaging utterance
* @param nDamage The amount of damage the creature would be dealt
*
* @param bIsHitPointDamage Is the damage HP damage or something else?
* @param bIsEnergyDamage Is the damage caused by energy or something else? Only relevant if the damage is HP damage.
*
* @return The amount of damage, modified by oTarget's abilities
*/
/*int GetTargetSpecificChangesToDamage(object oTarget, object oTrueSpeaker, int nDamage,
int bIsHitPointDamage = TRUE, int bIsEnergyDamage = FALSE);
*/
/**
* Returns how many Cadence feats an Acolyte of the Ego has
*
* @param oTrueSpeaker The PC whose feats to check.
* @return The count of feats
*/
int GetCadenceCount(object oTrueSpeaker);
//////////////////////////////////////////////////
/* Includes */
//////////////////////////////////////////////////
#include "prc_alterations"
#include "true_inc_utter"
#include "true_inc_truknwn"
//////////////////////////////////////////////////
/* Function definitions */
//////////////////////////////////////////////////
int GetTruespeakingClass(object oTrueSpeaker = OBJECT_SELF)
{
return GetLocalInt(oTrueSpeaker, PRC_TRUESPEAKING_CLASS) - 1;
}
int GetTruespeakerLevel(object oTrueSpeaker, int nSpecificClass = CLASS_TYPE_INVALID, int nUseHD = FALSE)
{
int nLevel;
int nAdjust = GetLocalInt(oTrueSpeaker, PRC_CASTERLEVEL_ADJUSTMENT);
// Bereft's speak syllables and use their character level.
if (GetIsSyllable(PRCGetSpellId())) nUseHD = TRUE;
// If this is set, return the user's HD
if (nUseHD) return GetHitDice(oTrueSpeaker);
// The function user needs to know the character's truespeaker level in a specific class
// instead of whatever the character last truespoken a Utterance as
if(nSpecificClass != CLASS_TYPE_INVALID)
{
if(GetIsTruenamingClass(nSpecificClass))
{
int nClassLevel = GetLevelByClass(nSpecificClass, oTrueSpeaker);
if (nClassLevel > 0)
{
nLevel = nClassLevel;
}
}
// A character's truespeaker level gained from non-uttering classes is always a nice, round zero
else
return 0;
}
// Item Spells
if(GetItemPossessor(GetSpellCastItem()) == oTrueSpeaker)
{
if(DEBUG) SendMessageToPC(oTrueSpeaker, "Item casting at level " + IntToString(GetCasterLevel(oTrueSpeaker)));
return GetCasterLevel(oTrueSpeaker) + nAdjust;
}
// For when you want to assign the caster level.
else if(GetLocalInt(oTrueSpeaker, PRC_CASTERLEVEL_OVERRIDE) != 0)
{
if(DEBUG) SendMessageToPC(oTrueSpeaker, "Forced-level uttering at level " + IntToString(GetCasterLevel(oTrueSpeaker)));
DelayCommand(1.0, DeleteLocalInt(oTrueSpeaker, PRC_CASTERLEVEL_OVERRIDE));
nLevel = GetLocalInt(oTrueSpeaker, PRC_CASTERLEVEL_OVERRIDE);
}
else if(GetTruespeakingClass(oTrueSpeaker) != CLASS_TYPE_INVALID)
{
//Gets the level of the uttering class
int nUtteringClass = GetTruespeakingClass(oTrueSpeaker);
nLevel = GetLevelByClass(nUtteringClass, oTrueSpeaker);
}
// If everything else fails, use the character's first class position
if(nLevel == 0)
{
if(DEBUG) DoDebug("Failed to get truespeaker level for creature " + DebugObject2Str(oTrueSpeaker) + ", using first class slot");
else WriteTimestampedLogEntry("Failed to get truespeaker level for creature " + DebugObject2Str(oTrueSpeaker) + ", using first class slot");
nLevel = GetLevelByPosition(1, oTrueSpeaker);
}
nLevel += nAdjust;
// This spam is technically no longer necessary once the truespeaker level getting mechanism has been confirmed to work
// if(DEBUG) FloatingTextStringOnCreature("TrueSpeaker Level: " + IntToString(nLevel), oTrueSpeaker, FALSE);
return nLevel;
}
int GetIsTruenamingUser(object oCreature)
{
return !!(GetLevelByClass(CLASS_TYPE_TRUENAMER, oCreature) ||
GetLevelByClass(CLASS_TYPE_BEREFT, oCreature)
);
}
int GetHighestTrueSpeakerLevel(object oCreature)
{
int n = 0;
int nHighest;
int nTemp;
while(n <= 8)
{
if(GetClassByPosition(n, oCreature) != CLASS_TYPE_INVALID)
{
nTemp = GetTruespeakerLevel(oCreature, GetClassByPosition(n, oCreature));
if(nTemp > nHighest)
nHighest = nTemp;
}
n++;
}
return nHighest;
}
/* int GetHighestTrueSpeakerLevel(object oCreature)
{
return max(max(GetClassByPosition(1, oCreature) != CLASS_TYPE_INVALID ? GetTruespeakerLevel(oCreature, GetClassByPosition(1, oCreature)) : 0,
GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID ? GetTruespeakerLevel(oCreature, GetClassByPosition(2, oCreature)) : 0
),
GetClassByPosition(3, oCreature) != CLASS_TYPE_INVALID ? GetTruespeakerLevel(oCreature, GetClassByPosition(3, oCreature)) : 0
);
} */
int GetIsTruenamingClass(int nClass)
{
return (nClass == CLASS_TYPE_TRUENAMER ||
nClass == CLASS_TYPE_BEREFT
);
}
int GetUtteranceLevel(object oTrueSpeaker)
{
return GetLocalInt(oTrueSpeaker, PRC_UTTERANCE_LEVEL);
}
int GetTruenameAbilityScoreOfClass(object oTrueSpeaker, int nClass)
{
return GetAbilityScore(oTrueSpeaker, GetTruenameAbilityOfClass(nClass));
}
int GetTruenameAbilityOfClass(int nClass){
switch(nClass)
{
case CLASS_TYPE_TRUENAMER:
return ABILITY_CHARISMA;
default:
return ABILITY_CHARISMA;
}
// Technically, never gets here but the compiler does not realise that
return -1;
}
int GetTrueSpeakerDC(object oTrueSpeaker = OBJECT_SELF)
{
// Things we need for DC Checks
int nSpellId = PRCGetSpellId();
object oTarget = PRCGetSpellTargetObject();
int nRace = MyPRCGetRacialType(oTarget);
// DC is 10 + 1/2 Truenamer level + Ability (Charisma)
int nClass = GetTruespeakingClass(oTrueSpeaker);
int nDC = 10;
nDC += GetLevelByClass(nClass, oTrueSpeaker) / 2;
nDC += GetAbilityModifier(GetTruenameAbilityOfClass(nClass), oTrueSpeaker);
int nFeat = -1;
// Focused Lexicon. Bonus vs chosen racial type //:: [PRC .35] Needs update for new racialtypes
switch(nRace)
{
case RACIAL_TYPE_ABERRATION: nFeat = FEAT_FOCUSED_LEXICON_ABERRATION; break;
case RACIAL_TYPE_ANIMAL: nFeat = FEAT_FOCUSED_LEXICON_ANIMAL; break;
case RACIAL_TYPE_BEAST: nFeat = FEAT_FOCUSED_LEXICON_BEAST; break;
case RACIAL_TYPE_CONSTRUCT: nFeat = FEAT_FOCUSED_LEXICON_CONSTRUCT; break;
case RACIAL_TYPE_DRAGON: nFeat = FEAT_FOCUSED_LEXICON_DRAGON; break;
case RACIAL_TYPE_DWARF: nFeat = FEAT_FOCUSED_LEXICON_DWARF; break;
case RACIAL_TYPE_ELEMENTAL: nFeat = FEAT_FOCUSED_LEXICON_ELEMENTAL; break;
case RACIAL_TYPE_ELF: nFeat = FEAT_FOCUSED_LEXICON_ELF; break;
case RACIAL_TYPE_FEY: nFeat = FEAT_FOCUSED_LEXICON_FEY; break;
case RACIAL_TYPE_GIANT: nFeat = FEAT_FOCUSED_LEXICON_GIANT; break;
case RACIAL_TYPE_GNOME: nFeat = FEAT_FOCUSED_LEXICON_GNOME; break;
case RACIAL_TYPE_HALFELF: nFeat = FEAT_FOCUSED_LEXICON_HALFELF; break;
case RACIAL_TYPE_HALFLING: nFeat = FEAT_FOCUSED_LEXICON_HALFLING; break;
case RACIAL_TYPE_HALFORC: nFeat = FEAT_FOCUSED_LEXICON_HALFORC; break;
case RACIAL_TYPE_HUMAN: nFeat = FEAT_FOCUSED_LEXICON_HUMAN; break;
case RACIAL_TYPE_HUMANOID_GOBLINOID: nFeat = FEAT_FOCUSED_LEXICON_GOBLINOID; break;
case RACIAL_TYPE_HUMANOID_MONSTROUS: nFeat = FEAT_FOCUSED_LEXICON_MONSTROUS; break;
case RACIAL_TYPE_HUMANOID_ORC: nFeat = FEAT_FOCUSED_LEXICON_ORC; break;
case RACIAL_TYPE_HUMANOID_REPTILIAN: nFeat = FEAT_FOCUSED_LEXICON_REPTILIAN; break;
case RACIAL_TYPE_MAGICAL_BEAST: nFeat = FEAT_FOCUSED_LEXICON_MAGICALBEAST; break;
case RACIAL_TYPE_OOZE: nFeat = FEAT_FOCUSED_LEXICON_OOZE; break;
case RACIAL_TYPE_OUTSIDER: nFeat = FEAT_FOCUSED_LEXICON_OUTSIDER; break;
case RACIAL_TYPE_SHAPECHANGER: nFeat = FEAT_FOCUSED_LEXICON_SHAPECHANGER; break;
case RACIAL_TYPE_UNDEAD: nFeat = FEAT_FOCUSED_LEXICON_UNDEAD; break;
case RACIAL_TYPE_VERMIN: nFeat = FEAT_FOCUSED_LEXICON_VERMIN; break;
}
if(nFeat > -1 && GetHasFeat(nFeat, oTrueSpeaker))
{
nDC += 1;
nFeat = -1;
}
// Utterance Focus. DC Bonus for a chosen utterance
switch(nSpellId)
{
case UTTER_BREATH_CLEANSING_R: nFeat = FEAT_UTTERANCE_FOCUS_BREATH_CLEANSING; break;
case UTTER_BREATH_RECOVERY_R: nFeat = FEAT_UTTERANCE_FOCUS_BREATH_RECOVERY; break;
case UTTER_ELDRITCH_ATTRACTION: nFeat = FEAT_UTTERANCE_FOCUS_ELDRITCH_ATTRACTION; break;
case UTTER_ELDRITCH_ATTRACTION_R: nFeat = FEAT_UTTERANCE_FOCUS_ELDRITCH_ATTRACTION; break;
case UTTER_MORALE_BOOST_R: nFeat = FEAT_UTTERANCE_FOCUS_MORALE_BOOST; break;
case UTTER_PRETERNATURAL_CLARITY_R: nFeat = FEAT_UTTERANCE_FOCUS_PRETERNATURAL_CLARITY; break;
case UTTER_SENSORY_FOCUS_R: nFeat = FEAT_UTTERANCE_FOCUS_SENSORY_FOCUS; break;
case UTTER_SILENT_CASTER_R: nFeat = FEAT_UTTERANCE_FOCUS_SILENT_CASTER; break;
case UTTER_SINGULAR_MIND_R: nFeat = FEAT_UTTERANCE_FOCUS_SINGULAR_MIND; break;
case UTTER_TEMPORAL_SPIRAL_R: nFeat = FEAT_UTTERANCE_FOCUS_TEMPORAL_SPIRAL; break;
case UTTER_TEMPORAL_TWIST_R: nFeat = FEAT_UTTERANCE_FOCUS_TEMPORAL_TWIST; break;
case UTTER_WARD_PEACE_R: nFeat = FEAT_UTTERANCE_FOCUS_WARD_PEACE; break;
case UTTER_SHOCKWAVE: nFeat = FEAT_UTTERANCE_FOCUS_SHOCKWAVE; break;
}
if(nFeat > -1 && GetHasFeat(nFeat, oTrueSpeaker))
nDC += 1;
return nDC;
}
int GetTrueSpeakPenetration(object oTrueSpeaker = OBJECT_SELF)
{
int nPen = GetTruespeakerLevel(oTrueSpeaker);
// According to Page 232 of Tome of Magic, Spell Pen as a feat counts, so here it is.
if(GetHasFeat(FEAT_EPIC_SPELL_PENETRATION, oTrueSpeaker)) nPen += 6;
else if(GetHasFeat(FEAT_GREATER_SPELL_PENETRATION, oTrueSpeaker)) nPen += 4;
else if(GetHasFeat(FEAT_SPELL_PENETRATION, oTrueSpeaker)) nPen += 2;
// Blow away SR totally, just add 9000
// Does not work on Syllables, only utterances
if (GetLocalInt(oTrueSpeaker, TRUE_IGNORE_SR) && !GetIsSyllable(PRCGetSpellId())) nPen += 9000;
if(DEBUG) DoDebug("GetTrueSpeakPenetration(" + GetName(oTrueSpeaker) + "): " + IntToString(nPen));
return nPen;
}
void DoLawOfSequence(object oTrueSpeaker, int nSpellId, float fDur)
{
// This makes sure everything is stored using the Normal, and not the reverse
string sSpellId = GetNormalUtterSpellId(nSpellId);
SetLocalInt(oTrueSpeaker, LAW_OF_SEQUENCE_VARNAME + sSpellId, TRUE);
DelayCommand(fDur, DeleteLocalInt(oTrueSpeaker, LAW_OF_SEQUENCE_VARNAME + sSpellId));
}
int CheckLawOfSequence(object oTrueSpeaker, int nSpellId)
{
// Turns this off
if (GetPRCSwitch(PRC_LAW_OF_SEQUENCE)) return FALSE;
// This makes sure everything is stored using the Normal, and not the reverse
return GetLocalInt(oTrueSpeaker, LAW_OF_SEQUENCE_VARNAME + GetNormalUtterSpellId(nSpellId));
}
string GetUtteranceName(int nSpellId)
{
return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellId)));
}
string GetLexiconName(int nLexicon)
{
int nStrRef;
switch(nLexicon)
{
case LEXICON_EVOLVING_MIND: nStrRef = 16828478; break;
case LEXICON_CRAFTED_TOOL: nStrRef = 16828479; break;
case LEXICON_PERFECTED_MAP: nStrRef = 16828480; break;
}
return GetStringByStrRef(nStrRef);
}
int GetLexiconByUtterance(int nSpellId)
{
int i, nUtter;
for(i = 0; i < GetPRCSwitch(FILE_END_CLASS_POWER) ; i++)
{
nUtter = StringToInt(Get2DACache("cls_true_utter", "SpellID", i));
if(nUtter == nSpellId)
{
return StringToInt(Get2DACache("cls_true_utter", "Lexicon", i));
}
}
// This should never happen
return -1;
}
void DoSpeakUntoTheMasses(object oTrueSpeaker, object oTarget, struct utterance utter)
{
// Check for Speak Unto the Masses, exit function if not set
if (!GetLocalInt(oTrueSpeaker, TRUE_SPEAK_UNTO_MASSES)) return;
// Speak to the Masses affects all creatures of the same race in the AoE
int nRacial = MyPRCGetRacialType(oTarget);
object oSkin;
// Loop over targets
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, FeetToMeters(30.0), GetLocation(oTarget), TRUE, OBJECT_TYPE_CREATURE);
while(GetIsObjectValid(oAreaTarget))
{
if(DEBUG) DoDebug("Speak Unto the Masses: While entered");
// Skip the original target/truespeaker, its already been hit
if (oAreaTarget != oTarget && oAreaTarget != oTrueSpeaker)
{
if(DEBUG) DoDebug("Speak Unto the Masses: Target check");
// Targeting limitations
if(MyPRCGetRacialType(oAreaTarget) == nRacial)
{
if(DEBUG) DoDebug("Speak Unto the Masses: Racial Check");
// Only affect friends or ignore it
if (GetIsFriend(oAreaTarget, oTrueSpeaker) || !utter.bFriend)
{
if(DEBUG) DoDebug("Speak Unto the Masses: Friend Check");
// Do SR, or ignore if its a friendly utterance.
if (!PRCDoResistSpell(utter.oTrueSpeaker, oAreaTarget, utter.nPen) || utter.bIgnoreSR)
{
if(DEBUG) DoDebug("Speak Unto the Masses: SR Check");
// Saving throw, ignore it if there is no DC to check
if(!PRCMySavingThrow(utter.nSaveThrow, oAreaTarget, utter.nSaveDC, utter.nSaveType, OBJECT_SELF) ||
utter.nSaveDC == 0)
{
if(DEBUG) DoDebug("Speak Unto the Masses: Saving Throw");
// Itemproperty, if there is one
oSkin = GetPCSkin(oAreaTarget);
if (GetIsItemPropertyValid(utter.ipIProp1))
{
if(DEBUG) DoDebug("Speak Unto the Masses: IProp1");
IPSafeAddItemProperty(oSkin, utter.ipIProp1, utter.fDur, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
// Itemproperty, if there is one
if (GetIsItemPropertyValid(utter.ipIProp2))
{
if(DEBUG) DoDebug("Speak Unto the Masses: IProp2");
IPSafeAddItemProperty(oSkin, utter.ipIProp2, utter.fDur, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
// Itemproperty, if there is one
if (GetIsItemPropertyValid(utter.ipIProp3))
{
if(DEBUG) DoDebug("Speak Unto the Masses: IProp3");
IPSafeAddItemProperty(oSkin, utter.ipIProp3, utter.fDur, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
}
// Duration Effects
SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, utter.eLink, oAreaTarget, utter.fDur, TRUE, utter.nSpellId, utter.nTruespeakerLevel);
if(DEBUG) DoDebug("Speak Unto the Masses: Duration");
// Impact Effects
SPApplyEffectToObject(DURATION_TYPE_INSTANT, utter.eLink2, oAreaTarget);
if(DEBUG) DoDebug("Speak Unto the Masses: Instant");
// Utterance Specific code down here
DoWordOfNurturingReverse(oTrueSpeaker, oAreaTarget, utter);
if(DEBUG) DoDebug("Speak Unto the Masses: Word of Nurturing Reverse");
if (utter.nSpellId == UTTER_ENERGY_NEGATION_R)
DoEnergyNegation(oTrueSpeaker, oTarget, utter, FloatToInt(utter.fDur / 6.0), GetLocalInt(oTrueSpeaker, "TrueEnergyNegation"));
} // end if - Saving Throw
} // end if - Spell Resistance
} // end if - Friend Check
}// end if - Targeting check
}
// Get next target
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, FeetToMeters(30.0), GetLocation(oTarget), TRUE, OBJECT_TYPE_CREATURE);
}// end while - Target loop
}
void DoWordOfNurturingReverse(object oTrueSpeaker, object oTarget, struct utterance utter)
{
// Returns TRUE upon concentration failure
if (GetBreakConcentrationCheck(oTrueSpeaker)) return;
int nDamage;
// First, find out what utterance we're using
if (utter.nSpellId == UTTER_WORD_NURTURING_MINOR_R) nDamage = d6();
else if (utter.nSpellId == UTTER_WORD_NURTURING_LESSER_R) nDamage = d6(2);
else if (utter.nSpellId == UTTER_WORD_NURTURING_MODERATE_R) nDamage = d6(4);
else if (utter.nSpellId == UTTER_WORD_NURTURING_POTENT_R) nDamage = d6(6);
else if (utter.nSpellId == UTTER_WORD_NURTURING_CRITICAL_R) nDamage = d6(8);
else if (utter.nSpellId == UTTER_WORD_NURTURING_GREATER_R) nDamage = d6(10);
// Empower it
if(utter.bEmpower) nDamage += (nDamage/2);
// If we're using this, target has already failed SR and Saves
effect eImp = EffectLinkEffects(EffectVisualEffect(VFX_IMP_MAGLAW), EffectDamage(nDamage));
SPApplyEffectToObject(DURATION_TYPE_INSTANT, eImp, oTarget);
}
void DoEnergyNegation(object oTrueSpeaker, object oTarget, struct utterance utter, int nBeats, int nDamageType)
{
int nDamage = d6(2);
// Empower it
if(utter.bEmpower) nDamage += (nDamage/2);
// Impact VFX
utter.eLink2 = EffectLinkEffects(EffectVisualEffect(VFX_IMP_MAGVIO), EffectDamage(nDamage, nDamageType));
// Impact Effects
SPApplyEffectToObject(DURATION_TYPE_INSTANT, utter.eLink2, oTarget);
nBeats -= 1;
if (nBeats > 0)
DelayCommand(6.0, DoEnergyNegation(oTrueSpeaker, oTarget, utter, nBeats, nDamageType));
}
object CraftedToolTarget(object oTrueSpeaker, object oTarget)
{
// Check to see if its a weapon or item of some sort
// Return it if its a valid base item type
if (GetBaseItemType(oTarget) != BASE_ITEM_INVALID) return oTarget;
object oItem = OBJECT_INVALID;
// These are utterances that only target weapons
if (PRCGetSpellId() == UTTER_KEEN_WEAPON || PRCGetSpellId() == UTTER_SUPPRESS_WEAPON || PRCGetSpellId() == UTTER_TRANSMUTE_WEAPON)
{
// By the time we're here, it should only be creatures, not items as targets
oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
// Only do this for Keen
if (PRCGetSpellId() == UTTER_KEEN_WEAPON)
{
// Put the bonus on the ammo rather than the bow if its ranged
if( GetBaseItemType(oItem) == BASE_ITEM_LONGBOW || GetBaseItemType(oItem) == BASE_ITEM_SHORTBOW )
{
oItem = GetItemInSlot(INVENTORY_SLOT_ARROWS, oTarget);
}
else if(GetBaseItemType(oItem) == BASE_ITEM_LIGHTCROSSBOW || GetBaseItemType(oItem) == BASE_ITEM_HEAVYCROSSBOW)
{
oItem = GetItemInSlot(INVENTORY_SLOT_BOLTS, oTarget);
}
else if(GetBaseItemType(oItem) == BASE_ITEM_SLING)
{
oItem = GetItemInSlot(INVENTORY_SLOT_BULLETS, oTarget);
}
}
// If its a valid weapon, return it
if (GetBaseItemType(oItem) != BASE_ITEM_INVALID) return oItem;
// Check the spare hand, and make sure its not a shield
oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
// If its a valid weapon and not a shield, return it
if (GetBaseItemType(oItem) != BASE_ITEM_INVALID &&
GetBaseItemType(oItem) != BASE_ITEM_LARGESHIELD &&
GetBaseItemType(oItem) != BASE_ITEM_SMALLSHIELD &&
GetBaseItemType(oItem) != BASE_ITEM_TOWERSHIELD) return oItem;
}// These ones target only armour
else if (PRCGetSpellId() == UTTER_FORTIFY_ARMOUR_SNEAK || PRCGetSpellId() == UTTER_FORTIFY_ARMOUR_CRIT)
{
return GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget);
}// This one targets scrolls and potions
else if (PRCGetSpellId() == UTTER_METAMAGIC_CATALYST_EMP || PRCGetSpellId() == UTTER_METAMAGIC_CATALYST_EXT ||
PRCGetSpellId() == UTTER_METAMAGIC_CATALYST_MAX)
{
oItem = GetFirstItemInInventory(oTarget);
while(GetIsObjectValid(oItem))
{
if (GetBaseItemType(oItem) == BASE_ITEM_SCROLL || GetBaseItemType(oItem) == BASE_ITEM_POTIONS)
{
return oItem;
}
oItem = GetNextItemInInventory(oTarget);
}
}
else // For the rest of the utterances, any item is a valid target.
{
// Get the PC's chosen inventory slot
int nSlot = GetLocalInt(oTrueSpeaker, "TrueCraftedToolTargetSlot");
oItem = GetItemInSlot(nSlot, oTarget);
// If the chosen item isn't valid, we go into the choice progession
// Yes, its a long chain
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_HEAD, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_LEFTRING, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_NECK, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_CLOAK, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_ARMS, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_BOOTS, oTarget);
if (!GetIsObjectValid(oItem))
{
oItem = GetItemInSlot(INVENTORY_SLOT_BELT, oTarget);
}
}
}
}
}
}
}
}
}
}
}
}
return oItem;
}
int CheckTrueSpeechSkill(object oTrueSpeaker)
{
// The max for a class skill is 3 + 1 per level. We just divide this in half for Cross Class
int nMax = GetHitDice(oTrueSpeaker) + 3;
nMax /= 2;
// We want base ranks only
int nRanks = GetSkillRank(SKILL_TRUESPEAK, oTrueSpeaker, TRUE);
// The Truenamer class has Truespeech as a class skill, so no relevel
if (GetLevelByClass(CLASS_TYPE_TRUENAMER, oTrueSpeaker) > 0) return FALSE;
// Same for this class
else if (GetLevelByClass(CLASS_TYPE_BEREFT, oTrueSpeaker) > 0) return FALSE;
// And this one
else if (GetLevelByClass(CLASS_TYPE_BRIMSTONE_SPEAKER, oTrueSpeaker) > 0) return FALSE;
// If they have the feat, no relevel
else if(GetHasFeat(FEAT_TRUENAME_TRAINING, oTrueSpeaker)) return FALSE;
// Now we check the values. If they have too many ranks, relevel.
else if (nRanks > nMax)
{
// Relevel
FloatingTextStringOnCreature("You cannot have more than " + IntToString(nMax) + " in TrueSpeech.", oTrueSpeaker, FALSE);
return TRUE;
}
// No relevel normally
return FALSE;
}
/*
int GetTargetSpecificChangesToDamage(object oTarget, object oTrueSpeaker, int nDamage,
int bIsHitPointDamage = TRUE, int bIsEnergyDamage = FALSE)
{
// Greater Utterance Specialization - +2 damage on all HP-damaging utterances when target is within 30ft
if(bIsHitPointDamage &&
GetHasFeat(FEAT_GREATER_Utterance_SPECIALIZATION, oTrueSpeaker) &&
GetDistanceBetween(oTarget, oTrueSpeaker) <= FeetToMeters(30.0f)
)
nDamage += 2;
// Intellect Fortress - Halve damage dealt by utterances that allow PR. Goes before DR (-like) reductions
if(GetLocalInt(oTarget, "PRC_Utterance_IntellectFortress_Active") &&
Get2DACache("spells", "ItemImmunity", PRCGetSpellId()) == "1"
)
nDamage /= 2;
// Mental Resistance - 3 damage less for all non-energy damage and ability damage
if(GetHasFeat(FEAT_MENTAL_RESISTANCE, oTarget) && !bIsEnergyDamage)
nDamage -= 3;
// Reasonable return values only
if(nDamage < 0) nDamage = 0;
return nDamage;
}
*/
// Test main
//void main(){}
int GetCadenceCount(object oTrueSpeaker)
{
int nClass = GetLevelByClass(CLASS_TYPE_ACOLYTE_EGO, oTrueSpeaker);
if (GetLocalInt(oTrueSpeaker, "ResonantVoice") == TRUE)
{
nClass += 3; //Adds 3 to class level
}
int nCount = nClass/2; //Get a cadence feat at 2, 4, 6, 8, 10 levels.
if (nCount > 6) nCount = 6; //Can't go above 6 with Resonant Voice active
// Return total
return nCount;
}