From a6682759433cbd196e002e8335a4ac6b7449dd34 Mon Sep 17 00:00:00 2001
From: Jaysyn904 <68194417+Jaysyn904@users.noreply.github.com>
Date: Sat, 11 Mar 2023 01:13:46 -0500
Subject: [PATCH] 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()
---
 trunk/include/inc_epicspellfnc.nss |  275 ++
 trunk/include/inc_newspellbook.nss | 1340 ++++++++
 trunk/include/inv_inc_invfunc.nss  |  496 +++
 trunk/include/moi_inc_moifunc.nss  | 1559 +++++++++
 trunk/include/nw_o2_coninclude.nss | 4791 ++++++++++++++++++++++++++++
 trunk/include/prc_inc_castlvl.nss  | 1823 +++++++++++
 trunk/include/prc_inc_clsfunc.nss  | 1618 ++++++++++
 trunk/include/prc_inc_core.nss     |  729 +++++
 trunk/include/prc_inc_domain.nss   |  585 ++++
 trunk/include/prc_inc_function.nss | 1837 +++++++++++
 trunk/include/prc_inc_itmrstr.nss  |  561 ++++
 trunk/include/prc_inc_leadersh.nss | 1043 ++++++
 trunk/include/prc_inc_spells.nss   | 3047 ++++++++++++++++++
 trunk/include/prc_shifter_info.nss | 1436 +++++++++
 trunk/include/psi_inc_core.nss     | 1312 ++++++++
 trunk/include/shd_inc_shdfunc.nss  |  669 ++++
 trunk/include/tob_inc_recovery.nss |  652 ++++
 trunk/include/tob_inc_tobfunc.nss  | 1261 ++++++++
 trunk/include/true_inc_trufunc.nss |  839 +++++
 19 files changed, 25873 insertions(+)
 create mode 100644 trunk/include/inc_epicspellfnc.nss
 create mode 100644 trunk/include/inc_newspellbook.nss
 create mode 100644 trunk/include/inv_inc_invfunc.nss
 create mode 100644 trunk/include/moi_inc_moifunc.nss
 create mode 100644 trunk/include/nw_o2_coninclude.nss
 create mode 100644 trunk/include/prc_inc_castlvl.nss
 create mode 100644 trunk/include/prc_inc_clsfunc.nss
 create mode 100644 trunk/include/prc_inc_core.nss
 create mode 100644 trunk/include/prc_inc_domain.nss
 create mode 100644 trunk/include/prc_inc_function.nss
 create mode 100644 trunk/include/prc_inc_itmrstr.nss
 create mode 100644 trunk/include/prc_inc_leadersh.nss
 create mode 100644 trunk/include/prc_inc_spells.nss
 create mode 100644 trunk/include/prc_shifter_info.nss
 create mode 100644 trunk/include/psi_inc_core.nss
 create mode 100644 trunk/include/shd_inc_shdfunc.nss
 create mode 100644 trunk/include/tob_inc_recovery.nss
 create mode 100644 trunk/include/tob_inc_tobfunc.nss
 create mode 100644 trunk/include/true_inc_trufunc.nss

diff --git a/trunk/include/inc_epicspellfnc.nss b/trunk/include/inc_epicspellfnc.nss
new file mode 100644
index 00000000..f345ac5f
--- /dev/null
+++ b/trunk/include/inc_epicspellfnc.nss
@@ -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;
+}
\ No newline at end of file
diff --git a/trunk/include/inc_newspellbook.nss b/trunk/include/inc_newspellbook.nss
new file mode 100644
index 00000000..57217e0f
--- /dev/null
+++ b/trunk/include/inc_newspellbook.nss
@@ -0,0 +1,1340 @@
+
+
+/* Steps for adding a new spellbook
+
+Prepared:
+Make cls_spgn_*.2da
+Make cls_spcr_*.2da
+Make blank cls_spell_*.2da
+Add cls_spgn_*.2da to classes.2da
+Add class entry in prc_classes.2da
+Add the spellbook feat (#1999) to cls_feat_*.2da at the appropriate level
+Add class to GetSpellbookTypeForClass() below
+Add class to GetAbilityScoreForClass() below
+Add class to bKnowsAllClassSpells() below if necessary
+Add class to GetIsArcaneClass() or GetIsDivineClass() in prc_inc_castlvl as appropriate
+Add class to GetCasterLevelModifier() in prc_inc_castlvl if necessary
+Add class to SetupLookupStage() in inc_lookups
+Add class to GetCasterLvl() in prc_inc_spells
+Add Practiced Spellcaster feat to feat.2da and to PracticedSpellcasting() in prc_inc_castlvl
+Run the assemble_spellbooks.bat file
+Make the prc_* scripts in newspellbook. The filenames can be found under the spell entries for the class in spells.2da.
+
+Spont:
+Make cls_spgn_*.2da
+Make cls_spkn_*.2da
+Make cls_spcr_*.2da
+Make blank cls_spell_*.2da
+Add cls_spkn_*.2da and cls_spgn_*.2da to classes.2da
+Add class entry in prc_classes.2da
+Add class to GetSpellbookTypeForClass() below
+Add class to GetAbilityScoreForClass() below
+Add class to bKnowsAllClassSpells() below if necessary
+Add class to GetIsArcaneClass() or GetIsDivineClass() in prc_inc_castlvl as appropriate
+Add class to GetCasterLevelModifier() in prc_inc_castlvl if necessary
+Add class to SetupLookupStage() in inc_lookups
+Add class to GetCasterLvl() in prc_inc_spells
+Add Practiced Spellcaster feat to feat.2da and to PracticedSpellcasting() in prc_inc_castlvl
+Add class to prc_amagsys_gain if(CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, MinimumSpellLevel, MaximumSpellLevel))
+Add class to ExecuteScript("prc_amagsys_gain", oPC) list in EvalPRCFeats in prc_inc_function
+Run the assemble_spellbooks.bat file
+Make the prc_* scripts in newspellbook
+
+prc_classes.2da entry:
+Label       - name for the class
+Name        - tlk file strref
+SpellCaster - does the class cast spells? 0 = No, 1 = Yes (used for bonus spellslot item properties)
+SBType      - S = spontaneous, P = prepared
+AL          - does the class use Advanced Learning of any type? 0 = No, 1 = Yes
+*/
+
+//////////////////////////////////////////////////
+/*             Function prototypes              */
+//////////////////////////////////////////////////
+
+int GetSpellbookTypeForClass(int nClass);
+int GetAbilityScoreForClass(int nClass, object oPC);
+
+/**
+ * Determines the given character's DC-modifying ability modifier for
+ * the given class' spells. Handles split-score casters.
+ *
+ * @param nClass The spellcasting class for whose spells to determine ability mod to DC for
+ * @param oPC    The character whose abilities to examine
+ * @return       The DC-modifying ability score's ability modifier value
+ */
+int GetDCAbilityModForClass(int nClass, object oPC);
+
+string GetFileForClass(int nClass);
+int GetSpellslotLevel(int nClass, object oPC);
+int GetItemBonusSlotCount(object oPC, int nClass, int nSpellLevel);
+int GetSlotCount(int nLevel, int nSpellLevel, int nAbilityScore, int nClass, object oItemPosessor = OBJECT_INVALID);
+int bKnowsAllClassSpells(int nClass);
+int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC);
+int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass);
+int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass);
+void AddSpellUse(object oPC, int nSpellbookID, int nClass, string sFile, string sArrayName, int nSpellbookType, object oSkin, int nFeatID, int nIPFeatID, string sIDX = "");
+void RemoveSpellUse(object oPC, int nSpellID, int nClass);
+// int GetSpellUses(object oPC, int nSpellID, int nClass);
+int GetSpellLevel(int nSpellID, int nClass);
+void SetupSpells(object oPC, int nClass);
+void CheckAndRemoveFeat(object oHide, itemproperty ipFeat);
+void WipeSpellbookHideFeats(object oPC);
+void CheckNewSpellbooks(object oPC);
+void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGIC_NONE, int bInstantSpell = FALSE);
+void CastSpontaneousSpell(int nClass, int bInstantSpell = FALSE);
+void CastPreparedSpell(int nClass, int nMetamagic = METAMAGIC_NONE, int bInstantSpell = FALSE);
+
+//////////////////////////////////////////////////
+/*                 Constants                    */
+//////////////////////////////////////////////////
+
+/*     stored in "prc_inc_sb_const"
+    Accessed via "prc_inc_core"    */
+
+//////////////////////////////////////////////////
+/*                  Includes                    */
+//////////////////////////////////////////////////
+
+// ** THIS ORDER IS IMPORTANT **
+
+//#include "prc_effect_inc"         //access via prc_inc_core
+//#include "inc_lookups"            //access via prc_inc_core
+#include "prc_inc_core"
+#include "inc_sp_gain_mem"          //providing child access to prc_inc_core
+                                    //Must load in this order.
+//#include "prc_inc_castlvl"        //access via prc_inc_core
+//#include "prc_inc_descrptr"       //access via prc_inc_core
+
+
+//////////////////////////////////////////////////
+/*             Function definitions             */
+//////////////////////////////////////////////////
+
+int GetSpellbookTypeForClass(int nClass)
+{
+    switch(nClass)
+    {
+        case CLASS_TYPE_ARCHIVIST:
+        case CLASS_TYPE_BLACKGUARD:
+        case CLASS_TYPE_BLIGHTER:
+        case CLASS_TYPE_CLERIC:
+        case CLASS_TYPE_CULTIST_SHATTERED_PEAK:
+        case CLASS_TYPE_DRUID:
+        case CLASS_TYPE_HEALER:
+        case CLASS_TYPE_KNIGHT_CHALICE:
+        case CLASS_TYPE_KNIGHT_MIDDLECIRCLE:
+        case CLASS_TYPE_NENTYAR_HUNTER:
+        case CLASS_TYPE_OCULAR:
+        case CLASS_TYPE_PALADIN:
+        case CLASS_TYPE_RANGER:
+        case CLASS_TYPE_SHADOWLORD:
+        case CLASS_TYPE_SHAMAN:
+        case CLASS_TYPE_SLAYER_OF_DOMIEL:
+        case CLASS_TYPE_SOHEI:
+        case CLASS_TYPE_SOLDIER_OF_LIGHT:
+        case CLASS_TYPE_UR_PRIEST:
+        case CLASS_TYPE_VASSAL:
+        case CLASS_TYPE_VIGILANT:
+        case CLASS_TYPE_WIZARD:
+            return SPELLBOOK_TYPE_PREPARED;
+        case CLASS_TYPE_ASSASSIN:
+        case CLASS_TYPE_BARD:
+        case CLASS_TYPE_BEGUILER:
+        case CLASS_TYPE_CELEBRANT_SHARESS:
+        case CLASS_TYPE_DREAD_NECROMANCER:
+        case CLASS_TYPE_DUSKBLADE:
+        case CLASS_TYPE_FAVOURED_SOUL:
+        case CLASS_TYPE_HARPER:
+        case CLASS_TYPE_HEXBLADE:
+        case CLASS_TYPE_JUSTICEWW:
+        case CLASS_TYPE_KNIGHT_WEAVE:
+        case CLASS_TYPE_SORCERER:
+        case CLASS_TYPE_SUBLIME_CHORD:
+        case CLASS_TYPE_SUEL_ARCHANAMACH:
+        case CLASS_TYPE_WARMAGE:
+            return SPELLBOOK_TYPE_SPONTANEOUS;
+		// shapechanger HD count as sorcerer for aranea.	
+		case CLASS_TYPE_SHAPECHANGER: 
+			return SPELLBOOK_TYPE_SPONTANEOUS;
+		// Multiple races	
+		case CLASS_TYPE_MONSTROUS: 
+			return SPELLBOOK_TYPE_SPONTANEOUS;			
+		// Gloura as Bard	
+		case CLASS_TYPE_FEY: 
+			return SPELLBOOK_TYPE_SPONTANEOUS;			
+		// Drider as Sorc	
+		case CLASS_TYPE_ABERRATION: 
+			return SPELLBOOK_TYPE_SPONTANEOUS;			
+        //outsider HD count as sorc for raks
+        case CLASS_TYPE_OUTSIDER: {
+            /// @todo Will eventually need to add a check here to differentiate between races. Not all are sorcerers, just most
+            return SPELLBOOK_TYPE_SPONTANEOUS;
+        }
+    }
+    return SPELLBOOK_TYPE_INVALID;
+}
+
+int GetAbilityScoreForClass(int nClass, object oPC)
+{
+    switch(nClass)
+    {
+        case CLASS_TYPE_BLACKGUARD:
+        case CLASS_TYPE_BLIGHTER:
+        case CLASS_TYPE_CLERIC:
+        case CLASS_TYPE_DRUID:
+        case CLASS_TYPE_FIST_OF_ZUOKEN:
+        case CLASS_TYPE_HEALER:
+        case CLASS_TYPE_JUSTICEWW:
+        case CLASS_TYPE_KNIGHT_CHALICE:
+        case CLASS_TYPE_KNIGHT_MIDDLECIRCLE:
+        case CLASS_TYPE_NENTYAR_HUNTER:
+        case CLASS_TYPE_OCULAR:
+        case CLASS_TYPE_PALADIN:
+        case CLASS_TYPE_PSYWAR:
+        case CLASS_TYPE_RANGER:
+        case CLASS_TYPE_SHAMAN:
+        case CLASS_TYPE_SLAYER_OF_DOMIEL:
+        case CLASS_TYPE_SOHEI:
+        case CLASS_TYPE_SOLDIER_OF_LIGHT:
+        case CLASS_TYPE_UR_PRIEST:
+        case CLASS_TYPE_VASSAL:
+        case CLASS_TYPE_VIGILANT:
+        case CLASS_TYPE_WARMIND:
+            return GetAbilityScore(oPC, ABILITY_WISDOM);
+        case CLASS_TYPE_ARCHIVIST:
+        case CLASS_TYPE_ASSASSIN:
+        case CLASS_TYPE_BEGUILER:
+        case CLASS_TYPE_CULTIST_SHATTERED_PEAK:
+        case CLASS_TYPE_DUSKBLADE:
+        case CLASS_TYPE_PSION:
+        case CLASS_TYPE_PSYCHIC_ROGUE:
+        case CLASS_TYPE_SHADOWCASTER:
+        case CLASS_TYPE_SHADOWLORD:
+        case CLASS_TYPE_WIZARD:
+            return GetAbilityScore(oPC, ABILITY_INTELLIGENCE);
+        case CLASS_TYPE_BARD:
+        case CLASS_TYPE_CELEBRANT_SHARESS:
+        case CLASS_TYPE_DREAD_NECROMANCER:
+        case CLASS_TYPE_FAVOURED_SOUL:
+        case CLASS_TYPE_HARPER:
+        case CLASS_TYPE_HEXBLADE:
+        case CLASS_TYPE_KNIGHT_WEAVE:
+        case CLASS_TYPE_SORCERER:
+        case CLASS_TYPE_SUBLIME_CHORD:
+        case CLASS_TYPE_SUEL_ARCHANAMACH:
+        case CLASS_TYPE_WARMAGE:
+        case CLASS_TYPE_WILDER:
+            return GetAbilityScore(oPC, ABILITY_CHARISMA);
+        //shapeshifter HD count as sorc for aranea
+        case CLASS_TYPE_SHAPECHANGER: 
+        	return GetAbilityScore(oPC, ABILITY_CHARISMA);
+		// Multiple races	
+		case CLASS_TYPE_MONSTROUS: 
+			return GetAbilityScore(oPC, ABILITY_CHARISMA);
+		// Gloura as Bard	
+		case CLASS_TYPE_FEY: 
+			return GetAbilityScore(oPC, ABILITY_CHARISMA);
+		// Drider as Sorc	
+		case CLASS_TYPE_ABERRATION: 
+			return GetAbilityScore(oPC, ABILITY_CHARISMA);
+        //outsider HD count as sorc for raks
+        case CLASS_TYPE_OUTSIDER: {
+            /// @todo Will eventually need to add a check here to differentiate between races. Not all are sorcerers, just most
+            return GetAbilityScore(oPC, ABILITY_CHARISMA);
+        }
+    }
+    return GetAbilityScore(oPC, ABILITY_CHARISMA);    //default for SLAs?
+}
+
+int GetDCAbilityModForClass(int nClass, object oPC)
+{
+    switch(nClass)
+    {
+        case CLASS_TYPE_BLACKGUARD:
+        case CLASS_TYPE_BLIGHTER:
+        case CLASS_TYPE_CLERIC:
+        case CLASS_TYPE_DRUID:
+        case CLASS_TYPE_FAVOURED_SOUL:
+        case CLASS_TYPE_FIST_OF_ZUOKEN:
+        case CLASS_TYPE_JUSTICEWW:
+        case CLASS_TYPE_KNIGHT_CHALICE:
+        case CLASS_TYPE_KNIGHT_MIDDLECIRCLE:
+        case CLASS_TYPE_OCULAR:
+        case CLASS_TYPE_NENTYAR_HUNTER:
+        case CLASS_TYPE_PALADIN:
+        case CLASS_TYPE_PSYWAR:
+        case CLASS_TYPE_RANGER:
+        case CLASS_TYPE_SHAMAN:
+        case CLASS_TYPE_SLAYER_OF_DOMIEL:
+        case CLASS_TYPE_SOHEI:
+        case CLASS_TYPE_SOLDIER_OF_LIGHT:
+        case CLASS_TYPE_UR_PRIEST:
+        case CLASS_TYPE_VASSAL:
+        case CLASS_TYPE_VIGILANT:
+        case CLASS_TYPE_WARMIND:
+            return GetAbilityModifier(ABILITY_WISDOM, oPC);
+        case CLASS_TYPE_ARCHIVIST:
+        case CLASS_TYPE_ASSASSIN:
+        case CLASS_TYPE_BEGUILER:
+        case CLASS_TYPE_CULTIST_SHATTERED_PEAK:
+        case CLASS_TYPE_DUSKBLADE:        
+        case CLASS_TYPE_PSION:
+        case CLASS_TYPE_PSYCHIC_ROGUE:
+        case CLASS_TYPE_SHADOWLORD:
+        case CLASS_TYPE_WIZARD:
+            return GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
+        case CLASS_TYPE_BARD:
+        case CLASS_TYPE_CELEBRANT_SHARESS:
+        case CLASS_TYPE_DREAD_NECROMANCER:
+        case CLASS_TYPE_HARPER:
+        case CLASS_TYPE_HEALER:
+        case CLASS_TYPE_HEXBLADE:
+        case CLASS_TYPE_SHADOWCASTER:
+        case CLASS_TYPE_SORCERER:
+        case CLASS_TYPE_SUBLIME_CHORD:
+        case CLASS_TYPE_SUEL_ARCHANAMACH:
+        case CLASS_TYPE_WARMAGE:
+        case CLASS_TYPE_WILDER:
+            return GetAbilityModifier(ABILITY_CHARISMA, oPC);
+        //shapechanger HD count as sorc for aranea
+        case CLASS_TYPE_SHAPECHANGER: 
+        	return GetAbilityScore(oPC, ABILITY_CHARISMA);
+		// Multiple races	
+		case CLASS_TYPE_MONSTROUS: 
+			return GetAbilityScore(oPC, ABILITY_CHARISMA);
+		// Gloura as Bard	
+		case CLASS_TYPE_FEY: 
+			return GetAbilityScore(oPC, ABILITY_CHARISMA);
+		// Drider as Sorc	
+		case CLASS_TYPE_ABERRATION: 
+			return GetAbilityScore(oPC, ABILITY_CHARISMA);		
+        //outsider HD count as sorc for raks
+        case CLASS_TYPE_OUTSIDER: {
+            /// @todo Will eventually need to add a check here to differentiate between races. Not all are sorcerers, just most
+            return GetAbilityModifier(ABILITY_CHARISMA, oPC);
+        }
+    }
+    return GetAbilityModifier(ABILITY_CHARISMA, oPC);    //default for SLAs?
+}
+
+string GetFileForClass(int nClass)
+{
+    string sFile = Get2DACache("classes", "FeatsTable", nClass);
+    sFile = "cls_spell" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061231
+    //if(DEBUG) DoDebug("GetFileForClass(" + IntToString(nClass) + ") = " + sFile);
+    return sFile;
+}
+
+int GetSpellslotLevel(int nClass, object oPC)
+{
+    int nLevel = GetLevelByClass(nClass, oPC);
+    
+    //Raks cast as sorcs
+    if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
+        nLevel = GetLevelByClass(CLASS_TYPE_OUTSIDER, oPC);
+    else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI) //Arkamoi cast as sorcs
+        nLevel = GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC);
+    else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_DRIDER) //Driders cast as sorcs
+        nLevel = GetLevelByClass(CLASS_TYPE_ABERRATION, oPC);   
+    else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS) //Redspawn Arcaniss cast as 3/4 sorcs
+        nLevel = GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC)*3/4;  
+    else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT) //Marrutact cast as 6/7 sorcs
+        nLevel = GetLevelByClass(CLASS_TYPE_MONSTROUS, oPC)*6/7;          
+    else if(nClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oPC) && GetRacialType(oPC) == RACIAL_TYPE_GLOURA) //Gloura cast as bards
+        nLevel = GetLevelByClass(CLASS_TYPE_FEY, oPC);         
+    else if(nClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_ARANEA) //Aranea cast as sorcs
+        nLevel = GetLevelByClass(CLASS_TYPE_SHAPECHANGER, oPC);         
+    
+    int nArcSpellslotLevel;
+    int nDivSpellslotLevel;
+    int i;
+    for(i = 1; i <= 8; i++)
+    {
+        int nTempClass = GetClassByPosition(i, oPC);
+        //spellcasting prc
+        int nArcSpellMod = StringToInt(Get2DACache("classes", "ArcSpellLvlMod", nTempClass));
+        int nDivSpellMod = StringToInt(Get2DACache("classes", "DivSpellLvlMod", nTempClass));
+        /*//special case for combat medic class
+        if(nTempClass == CLASS_TYPE_COMBAT_MEDIC && (nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_WITCH))
+            nArcSpellMod = 1;*/
+
+        if(nArcSpellMod == 1)
+            nArcSpellslotLevel += GetLevelByClass(nTempClass, oPC);
+        else if(nArcSpellMod > 1)
+            nArcSpellslotLevel += (GetLevelByClass(nTempClass, oPC) + 1) / nArcSpellMod;
+        if(nDivSpellMod == 1)
+            nDivSpellslotLevel += GetLevelByClass(nTempClass, oPC);
+        else if(nDivSpellMod > 1)
+            nDivSpellslotLevel += (GetLevelByClass(nTempClass, oPC) + 1) / nDivSpellMod;
+    }
+    
+    if(GetPrimaryArcaneClass(oPC) == nClass)
+        nLevel += nArcSpellslotLevel;
+    if(GetPrimaryDivineClass(oPC) == nClass)
+        nLevel += nDivSpellslotLevel;
+        
+    // For this special instance, we know that this is the only prestige class
+    if (nClass == CLASS_TYPE_SORCERER && GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oPC))
+    	nLevel = GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oPC) + GetLevelByClass(CLASS_TYPE_SORCERER, oPC);
+    	
+    if(DEBUG) DoDebug("GetSpellslotLevel(" + IntToString(nClass) + ", " + GetName(oPC) + ") = " + IntToString(nLevel));
+    return nLevel;
+}
+
+int GetItemBonusSlotCount(object oPC, int nClass, int nSpellLevel)
+{
+    // Value maintained by CheckPRCLimitations()
+    return GetLocalInt(oPC, "PRC_IPRPBonSpellSlots_" + IntToString(nClass) + "_" + IntToString(nSpellLevel));
+}
+
+int GetSlotCount(int nLevel, int nSpellLevel, int nAbilityScore, int nClass, object oItemPosessor = OBJECT_INVALID)
+{
+    // Ability score limit rule: Must have casting ability score of at least 10 + spel level to be able to cast spells of that level at all
+    if(nAbilityScore < nSpellLevel + 10)
+        return 0;
+    int nSlots;
+    string sFile;
+    /*// Bioware casters use their classes.2da-specified tables
+    if(    nClass == CLASS_TYPE_WIZARD
+        || nClass == CLASS_TYPE_SORCERER
+        || nClass == CLASS_TYPE_BARD
+        || nClass == CLASS_TYPE_CLERIC
+        || nClass == CLASS_TYPE_DRUID
+        || nClass == CLASS_TYPE_PALADIN
+        || nClass == CLASS_TYPE_RANGER)
+    {*/
+        sFile = Get2DACache("classes", "SpellGainTable", nClass);
+    /*}
+    // New spellbook casters use the cls_spbk_* tables
+    else
+    {
+        sFile = Get2DACache("classes", "FeatsTable", nClass);
+        sFile = "cls_spbk" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061231
+    }*/
+
+    string sSlots = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1);
+    if(sSlots == "")
+    {
+        nSlots = -1;
+        //if(DEBUG) DoDebug("GetSlotCount: Problem getting slot numbers for " + IntToString(nSpellLevel) + " " + IntToString(nLevel) + " " + sFile);
+    }
+    else
+        nSlots = StringToInt(sSlots);
+    if(nSlots == -1)
+        return 0;
+
+    // Add spell slots from items
+    if(GetIsObjectValid(oItemPosessor))
+        nSlots += GetItemBonusSlotCount(oItemPosessor, nClass, nSpellLevel);
+
+    // Add spell slots from high ability score. Level 0 spells are exempt
+    if(nSpellLevel == 0)
+        return nSlots;
+    else 
+    {
+        int nAbilityMod = nClass == CLASS_TYPE_ARCHIVIST ? GetAbilityModifier(ABILITY_WISDOM, oItemPosessor) : (nAbilityScore - 10) / 2;
+        if(nAbilityMod >= nSpellLevel) // Need an ability modifier at least equal to the spell level to gain bonus slots
+            nSlots += ((nAbilityMod - nSpellLevel) / 4) + 1;
+        return nSlots;
+    }
+}
+
+//if the class doesn't learn all available spells on level-up add it here
+int bKnowsAllClassSpells(int nClass)
+{
+    switch(nClass)
+    {
+        //case CLASS_TYPE_WIZARD:
+        case CLASS_TYPE_ARCHIVIST:
+        case CLASS_TYPE_ASSASSIN:
+        case CLASS_TYPE_BARD:
+        case CLASS_TYPE_CELEBRANT_SHARESS:
+        case CLASS_TYPE_CULTIST_SHATTERED_PEAK:
+        case CLASS_TYPE_DUSKBLADE:
+        case CLASS_TYPE_FAVOURED_SOUL:
+        case CLASS_TYPE_HEXBLADE:
+        case CLASS_TYPE_JUSTICEWW:
+        case CLASS_TYPE_KNIGHT_WEAVE:
+        case CLASS_TYPE_SORCERER:
+        case CLASS_TYPE_SUBLIME_CHORD:
+        case CLASS_TYPE_SUEL_ARCHANAMACH:
+            return FALSE;
+
+        // Everyone else
+        default:
+            return TRUE;
+    }
+    return TRUE;
+}
+
+int GetSpellKnownMaxCount(int nLevel, int nSpellLevel, int nClass, object oPC)
+{
+    // If the character doesn't have any spell slots available on for this level, it can't know any spells of that level either
+    /// @todo Check rules. There might be cases where this doesn't hold
+    if(!GetSlotCount(nLevel, nSpellLevel, GetAbilityScoreForClass(nClass, oPC), nClass))
+        return 0;
+    int nKnown;
+    string sFile;
+    // Bioware casters use their classes.2da-specified tables
+    /*if(    nClass == CLASS_TYPE_WIZARD
+        || nClass == CLASS_TYPE_SORCERER
+        || nClass == CLASS_TYPE_BARD
+        || nClass == CLASS_TYPE_CLERIC
+        || nClass == CLASS_TYPE_DRUID
+        || nClass == CLASS_TYPE_PALADIN
+        || nClass == CLASS_TYPE_RANGER)
+    {*/
+        sFile = Get2DACache("classes", "SpellKnownTable", nClass);
+    /*}
+    else
+    {
+        sFile = Get2DACache("classes", "FeatsTable", nClass);
+        sFile = "cls_spkn" + GetStringRight(sFile, GetStringLength(sFile) - 8); // Hardcoded the cls_ part. It's not as if any class uses some other prefix - Ornedan, 20061231
+    }*/
+
+    string sKnown = Get2DACache(sFile, "SpellLevel" + IntToString(nSpellLevel), nLevel - 1);
+    if(DEBUG) DoDebug("GetSpellKnownMaxCount(" + IntToString(nLevel) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ", " + GetName(oPC) + ") = " + sKnown);
+    if(sKnown == "")
+    {
+        nKnown = -1;
+        //if(DEBUG) DoDebug("GetSpellKnownMaxCount: Problem getting known numbers for " + IntToString(nSpellLevel) + " " + IntToString(nLevel) + " " + sFile);
+    }
+    else
+        nKnown = StringToInt(sKnown);
+    if(nKnown == -1)
+        return 0;
+
+    // Bard and Sorcerer only have new spellbook spells known if they have taken prestige classes that increase spellcasting
+    if(nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_BARD)
+    {
+        if((GetLevelByClass(nClass) == nLevel) //no PrC
+          && !(GetHasFeat(FEAT_DRACONIC_GRACE, oPC) || GetHasFeat(FEAT_DRACONIC_BREATH, oPC))) //no Draconic feats that apply
+            return 0;
+    }
+    return nKnown;
+}
+
+int GetSpellKnownCurrentCount(object oPC, int nSpellLevel, int nClass)
+{
+    // Check short-term cache
+    string sClassNum = IntToString(nClass);
+    if(GetLocalInt(oPC, "GetSKCCCache_" + IntToString(nSpellLevel) + "_" + sClassNum))
+        return GetLocalInt(oPC, "GetSKCCCache_" + IntToString(nSpellLevel) + "_" + sClassNum) - 1;
+
+    // Loop over all spells known and count the number of spells of each level known
+    int i;
+    int nKnown;
+    int nKnown0, nKnown1, nKnown2, nKnown3, nKnown4;
+    int nKnown5, nKnown6, nKnown7, nKnown8, nKnown9;
+    string sFile = GetFileForClass(nClass);
+    for(i = 0; i < persistant_array_get_size(oPC, "Spellbook" + sClassNum); i++)
+    {
+        int nNewSpellbookID = persistant_array_get_int(oPC, "Spellbook" + sClassNum, i);
+        int nLevel = StringToInt(Get2DACache(sFile, "Level", nNewSpellbookID));
+        switch(nLevel)
+        {
+            case 0: nKnown0++; break; case 1: nKnown1++; break;
+            case 2: nKnown2++; break; case 3: nKnown3++; break;
+            case 4: nKnown4++; break; case 5: nKnown5++; break;
+            case 6: nKnown6++; break; case 7: nKnown7++; break;
+            case 8: nKnown8++; break; case 9: nKnown9++; break;
+        }
+    }
+
+    // Pick the level requested for returning
+    switch(nSpellLevel)
+    {
+        case 0: nKnown = nKnown0; break; case 1: nKnown = nKnown1; break;
+        case 2: nKnown = nKnown2; break; case 3: nKnown = nKnown3; break;
+        case 4: nKnown = nKnown4; break; case 5: nKnown = nKnown5; break;
+        case 6: nKnown = nKnown6; break; case 7: nKnown = nKnown7; break;
+        case 8: nKnown = nKnown8; break; case 9: nKnown = nKnown9; break;
+    }
+    if(DEBUG) DoDebug("GetSpellKnownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + sClassNum + ") = " + IntToString(nKnown));
+    if(DEBUG) DoDebug("GetSpellKnownCurrentCount(i " + IntToString(i) + ", nKnown0 " + IntToString(nKnown0) + ", nKnown1 " + IntToString(nKnown1) + ", nKnown2 " + IntToString(nKnown2) + ", nKnown3 " + IntToString(nKnown3) + ", nKnown4 " + IntToString(nKnown4) + ", nKnown5 " + IntToString(nKnown5) + ", nKnown6 " + IntToString(nKnown6) + ", nKnown7 " + IntToString(nKnown7) + ", nKnown8 " + IntToString(nKnown8) + ", nKnown9 " + IntToString(nKnown9));
+    if(DEBUG) DoDebug("GetSpellKnownCurrentCount(persistant_array_get_size "+IntToString(persistant_array_get_size(oPC, "Spellbook" + sClassNum)));
+
+    // Cache the values for 1 second
+    SetLocalInt(oPC, "GetSKCCCache_0_" + sClassNum, nKnown0 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_1_" + sClassNum, nKnown1 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_2_" + sClassNum, nKnown2 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_3_" + sClassNum, nKnown3 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_4_" + sClassNum, nKnown4 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_5_" + sClassNum, nKnown5 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_6_" + sClassNum, nKnown6 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_7_" + sClassNum, nKnown7 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_8_" + sClassNum, nKnown8 + 1);
+    SetLocalInt(oPC, "GetSKCCCache_9_" + sClassNum, nKnown9 + 1);
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_0_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_1_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_2_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_3_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_4_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_5_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_6_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_7_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_8_" + sClassNum));
+    DelayCommand(1.0, DeleteLocalInt(oPC, "GetSKCCCache_9_" + sClassNum));
+
+    return nKnown;
+}
+
+int GetSpellUnknownCurrentCount(object oPC, int nSpellLevel, int nClass)
+{
+    // Get the lookup token created by MakeSpellbookLevelLoop()
+    string sTag = "SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nSpellLevel);
+    object oCache = GetObjectByTag(sTag);
+    if(!GetIsObjectValid(oCache))
+    {
+        if(DEBUG) DoDebug("GetSpellUnknownCurrentCount: " + sTag + " is not valid");
+        return 0;
+    }
+    // Read the total number of spells on the given level and determine how many are already known
+    int nTotal = array_get_size(oCache, "Lkup");
+    int nKnown = GetSpellKnownCurrentCount(oPC, nSpellLevel, nClass);
+    int nUnknown = nTotal - nKnown;
+
+    if(DEBUG) DoDebug("GetSpellUnknownCurrentCount(" + GetName(oPC) + ", " + IntToString(nSpellLevel) + ", " + IntToString(nClass) + ") = " + IntToString(nUnknown));
+    return nUnknown;
+}
+
+void AddSpellUse(object oPC, int nSpellbookID, int nClass, string sFile, string sArrayName, int nSpellbookType, object oSkin, int nFeatID, int nIPFeatID, string sIDX = "")
+{
+    /*
+    string sFile = GetFileForClass(nClass);
+    string sArrayName = "NewSpellbookMem_"+IntToString(nClass);
+    int nSpellbookType = GetSpellbookTypeForClass(nClass);
+    object oSkin = GetPCSkin(oPC);
+    int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
+    //add the feat only if they dont already have it
+    int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
+    */
+    object oToken = GetHideToken(oPC);
+
+    // Add the spell use feats and set a marker local that tells for CheckAndRemoveFeat() to skip removing this feat
+    string sIPFeatID = IntToString(nIPFeatID);
+    SetLocalInt(oSkin, "NewSpellbookTemp_" + sIPFeatID, TRUE);
+    AddSkinFeat(nFeatID, nIPFeatID, oSkin, oPC);
+
+    // Increase the current number of uses
+    if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
+    {
+        //sanity test
+        if(!persistant_array_exists(oPC, sArrayName))
+        {
+            if(DEBUG) DoDebug("ERROR: AddSpellUse: " + sArrayName + " array does not exist, creating");
+            persistant_array_create(oPC, sArrayName);
+        }
+
+        int nUses = persistant_array_get_int(oPC, sArrayName, nSpellbookID);
+        nUses++;
+        persistant_array_set_int(oPC, sArrayName, nSpellbookID, nUses);
+        if(DEBUG) DoDebug("AddSpellUse: " + sArrayName + "[" + IntToString(nSpellbookID) + "] = " + IntToString(array_get_int(oPC, sArrayName, nSpellbookID)));
+
+        //Create index array - to avoid duplicates mark only 1st use of nSpellbookID
+        if(nUses == 1)
+        {
+            if(!persistant_array_exists(oPC, sIDX))
+                persistant_array_create(oPC, sIDX);
+
+            persistant_array_set_int(oPC, sIDX, array_get_size(oPC, sIDX), nSpellbookID);
+        }
+    }
+    else if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+    {
+        //sanity test
+        if(!persistant_array_exists(oPC, sArrayName))
+        {
+            if(DEBUG) DoDebug("ERROR: AddSpellUse: " + sArrayName + " array does not exist, creating");
+            persistant_array_create(oPC, sArrayName);
+        }
+        /*int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
+        int nCount = persistant_array_get_int(oPC, sArrayName, nSpellLevel);
+        if(nCount < 1)
+        {
+            int nLevel = GetSpellslotLevel(nClass, oPC);
+            int nAbility = GetAbilityScoreForClass(nClass, oPC);
+            nCount = GetSlotCount(nLevel, nSpellLevel, nAbility, nClass, oPC);
+            array_set_int(oPC, sArrayName, nSpellLevel, nCount);
+        }*/
+        if(DEBUG) DoDebug("AddSpellUse() called on spontaneous spellbook. nIPFeatID = " + sIPFeatID);
+    }
+}
+
+void RemoveSpellUse(object oPC, int nSpellID, int nClass)
+{
+    string sFile = GetFileForClass(nClass);
+    int nSpellbookID = SpellToSpellbookID(nSpellID);
+    if(nSpellbookID == -1)
+    {
+        if(DEBUG) DoDebug("ERROR: RemoveSpellUse: Unable to resolve spell to spellbookID: " + IntToString(nSpellID) + " in file " + sFile);
+        return;
+    }
+    if(!persistant_array_exists(oPC, "NewSpellbookMem_"+IntToString(nClass)))
+    {
+        if(DEBUG) DoDebug("RemoveSpellUse: NewSpellbookMem_" + IntToString(nClass) + " does not exist, creating.");
+        persistant_array_create(oPC, "NewSpellbookMem_"+IntToString(nClass));
+    }
+
+    // Reduce the remaining uses of the given spell by 1 (except never reduce uses below 0).
+    // Spontaneous spellbooks reduce the number of spells of the spell's level remaining
+    int nSpellbookType = GetSpellbookTypeForClass(nClass);
+    if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
+    {
+        int nCount = persistant_array_get_int(oPC, "NewSpellbookMem_" + IntToString(nClass), nSpellbookID);
+        if(nCount > 0)
+            persistant_array_set_int(oPC, "NewSpellbookMem_" + IntToString(nClass), nSpellbookID, nCount - 1);
+    }
+    else if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+    {
+        int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
+        int nCount = persistant_array_get_int(oPC, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel);
+        if(nCount > 0)
+            persistant_array_set_int(oPC, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel, nCount - 1);
+    }
+}
+
+int GetSpellLevel(int nSpellID, int nClass)
+{
+    string sFile = GetFileForClass(nClass);
+    int nSpellbookID = SpellToSpellbookID(nSpellID);
+    if(nSpellbookID == -1)
+    {
+        if(DEBUG) DoDebug("ERROR: GetSpellLevel: Unable to resolve spell to spellbookID: "+IntToString(nSpellID)+" "+sFile);
+        return -1;
+    }
+
+    // get spell level
+    int nSpellLevel = -1;
+    string sSpellLevel = Get2DACache(sFile, "Level", nSpellbookID);
+
+    if (sSpellLevel != "")
+        nSpellLevel = StringToInt(sSpellLevel);
+
+    return nSpellLevel;
+}
+
+//called inside for loop in SetupSpells(), delayed to prevent TMI
+void SpontaneousSpellSetupLoop(object oPC, int nClass, string sFile, object oSkin, int i)
+{
+    int nSpellbookID = persistant_array_get_int(oPC, "Spellbook" + IntToString(nClass), i);
+    string sIPFeatID = Get2DACache(sFile, "IPFeatID", nSpellbookID);
+    int nIPFeatID = StringToInt(sIPFeatID);
+    int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
+    //int nRealSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
+    SetLocalInt(oSkin, "NewSpellbookTemp_" + sIPFeatID, TRUE);
+
+    AddSkinFeat(nFeatID, nIPFeatID, oSkin, oPC);
+}
+
+void SetupSpells(object oPC, int nClass)
+{
+    string sFile = GetFileForClass(nClass);
+    string sClass = IntToString(nClass);
+    string sArrayName = "NewSpellbookMem_" + sClass;
+    object oSkin = GetPCSkin(oPC);
+    int nLevel = GetSpellslotLevel(nClass, oPC);
+    int nAbility = GetAbilityScoreForClass(nClass, oPC);
+    int nSpellbookType = GetSpellbookTypeForClass(nClass);
+    
+        if(DEBUG) DoDebug("SetupSpells\n"
+                        + "nClass = " + IntToString(nClass) + "\n"
+                        + "nSpellslotLevel = " + IntToString(nLevel) + "\n"
+                        + "nAbility = " + IntToString(nAbility) + "\n"
+                        + "nSpellbookType = " + IntToString(nSpellbookType) + "\n"
+                        + "sFile = " + sFile + "\n"
+                          );    
+
+    // For spontaneous spellbooks, set up an array that tells how many spells of each level they can cast
+    // And add casting feats for each spell known to the caster's hide
+
+    if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+    {
+        // Spell slots
+        int nSpellLevel, nSlots;
+        for(nSpellLevel = 0; nSpellLevel <= 9; nSpellLevel++)
+        {
+            nSlots = GetSlotCount(nLevel, nSpellLevel, nAbility, nClass, oPC);
+            persistant_array_set_int(oPC, sArrayName, nSpellLevel, nSlots);
+        }
+
+        int i;
+        for(i = 0; i < persistant_array_get_size(oPC, "Spellbook" + sClass); i++)
+        {   //adding feats
+            SpontaneousSpellSetupLoop(oPC, nClass, sFile, oSkin, i);
+        }
+    }// end if - Spontaneous spellbook
+
+    // For prepared spellbooks, add spell uses and use feats according to spells memorised list
+    else if(nSpellbookType == SPELLBOOK_TYPE_PREPARED && !GetIsBioSpellCastClass(nClass))
+    {
+        int nSpellLevel, nSlot, nSlots, nSpellbookID;
+        string sArrayName2, sIDX;
+        for(nSpellLevel = 0; nSpellLevel <= 9; nSpellLevel++)
+        {
+            sArrayName2 = "Spellbook" + IntToString(nSpellLevel) + "_" + sClass; // Minor optimisation: cache the array name string for multiple uses
+            sIDX = "SpellbookIDX" + IntToString(nSpellLevel) + "_" + sClass;
+            nSlots = GetSlotCount(nLevel, nSpellLevel, nAbility, nClass, oPC);
+            nSlot;
+            for(nSlot = 0; nSlot < nSlots; nSlot++)
+            {
+                //done when spells are added to it
+                nSpellbookID = persistant_array_get_int(oPC, sArrayName2, nSlot);
+                if(nSpellbookID != 0)
+                {
+                    AddSpellUse(oPC, nSpellbookID, nClass, sFile, sArrayName, nSpellbookType, oSkin,
+                        StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID)),
+                        StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID)),
+                        sIDX);
+                }
+            }
+        }
+    }
+}
+
+void CheckAndRemoveFeat(object oHide, itemproperty ipFeat)
+{
+    int nSubType = GetItemPropertySubType(ipFeat);
+    if(!GetLocalInt(oHide, "NewSpellbookTemp_" + IntToString(nSubType)))
+    {
+        RemoveItemProperty(oHide, ipFeat);
+        DeleteLocalInt(oHide, "NewSpellbookTemp_" + IntToString(nSubType));
+        if(DEBUG) DoDebug("CheckAndRemoveFeat: DeleteLocalInt(oHide, NewSpellbookTemp_" + IntToString(nSubType) + ");");
+        if(DEBUG) DoDebug("CheckAndRemoveFeat: Removing item property");
+    }
+    else
+    {
+        DeleteLocalInt(oHide, "NewSpellbookTemp_" + IntToString(nSubType));
+        if(DEBUG) DoDebug("CheckAndRemoveFeat: DeleteLocalInt(oHide, NewSpellbookTemp_" + IntToString(nSubType) + ");");
+    }
+}
+
+void WipeSpellbookHideFeats(object oPC)
+{
+    object oHide = GetPCSkin(oPC);
+    itemproperty ipTest = GetFirstItemProperty(oHide);
+    while(GetIsItemPropertyValid(ipTest))
+    {
+        int nSubType = GetItemPropertySubType(ipTest);
+        if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_BONUS_FEAT &&
+              ((nSubType > SPELLBOOK_IPRP_FEATS_START && nSubType < SPELLBOOK_IPRP_FEATS_END) ||
+               (nSubType > SPELLBOOK_IPRP_FEATS_START2 && nSubType < SPELLBOOK_IPRP_FEATS_END2))
+          )
+        {
+            DelayCommand(1.0f, CheckAndRemoveFeat(oHide, ipTest));
+        }
+        ipTest = GetNextItemProperty(oHide);
+    }
+}
+
+void CheckNewSpellbooks(object oPC)
+{
+    WipeSpellbookHideFeats(oPC);
+    int i;
+    for(i = 1; i <= 8; i++)
+    {
+        int nClass = GetClassByPosition(i, oPC);
+        int nLevel = GetLevelByClass(nClass, oPC);
+
+        if(DEBUG) DoDebug("CheckNewSpellbooks\n"
+                        + "nClass = " + IntToString(nClass) + "\n"
+                        + "nLevel = " + IntToString(nLevel) + "\n"
+                          );
+        //if bard/sorc newspellbook is disabled after selecting
+        //remove those from radial
+        if(   (GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK) && nClass == CLASS_TYPE_BARD)
+            ||(GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK) && nClass == CLASS_TYPE_SORCERER))
+        {
+            //do nothing
+        }
+        else if(nLevel)
+        {
+			//Aranea cast as sorcs
+            if(nClass == CLASS_TYPE_SHAPECHANGER
+                && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC)
+                && GetRacialType(oPC) == RACIAL_TYPE_ARANEA)
+                nClass = CLASS_TYPE_SORCERER;
+            //raks cast as sorcs
+            if(nClass == CLASS_TYPE_OUTSIDER
+                && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC)
+                && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
+                nClass = CLASS_TYPE_SORCERER;
+                
+            //Arkamoi cast as sorcs
+            if(nClass == CLASS_TYPE_MONSTROUS
+                && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC)
+                && GetRacialType(oPC) == RACIAL_TYPE_ARKAMOI)                
+                nClass = CLASS_TYPE_SORCERER;
+                
+            //Redspawn cast as sorcs
+            if(nClass == CLASS_TYPE_MONSTROUS
+                && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC)
+                && GetRacialType(oPC) == RACIAL_TYPE_REDSPAWN_ARCANISS)                
+                nClass = CLASS_TYPE_SORCERER;    
+                
+            //Marrutact cast as sorcs
+            if(nClass == CLASS_TYPE_MONSTROUS
+                && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC)
+                && GetRacialType(oPC) == RACIAL_TYPE_MARRUTACT)                
+                nClass = CLASS_TYPE_SORCERER;                 
+                
+            //Driders cast as sorcs
+            if(nClass == CLASS_TYPE_ABERRATION
+                && !GetLevelByClass(CLASS_TYPE_SORCERER, oPC)
+                && GetRacialType(oPC) == RACIAL_TYPE_DRIDER)                
+                nClass = CLASS_TYPE_SORCERER;    
+                
+            //Gloura cast as bards
+            if(nClass == CLASS_TYPE_FEY
+                && !GetLevelByClass(CLASS_TYPE_BARD, oPC)
+                && GetRacialType(oPC) == RACIAL_TYPE_GLOURA)                
+                nClass = CLASS_TYPE_BARD;                  
+            //remove persistant locals used to track when all spells cast
+            string sArrayName = "NewSpellbookMem_"+IntToString(nClass);
+            if(persistant_array_exists(oPC, sArrayName))
+            {
+                if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED)
+                {
+                    int nSpellLevel, i, Max;
+                    string sIDX, sSpellbookID, sClass = IntToString(nClass);
+                    for(nSpellLevel = 0; nSpellLevel <= 9; nSpellLevel++)
+                    {
+                        sIDX = "SpellbookIDX" + IntToString(nSpellLevel) + "_" + sClass;
+                        Max = persistant_array_get_size(oPC, sIDX);
+                        for(i = 0; i < Max; i++)
+                        {
+                            sSpellbookID = persistant_array_get_string(oPC, sIDX, i);
+                            if(sSpellbookID != "")
+                            {
+                                DeletePersistantLocalString(oPC, sArrayName+"_"+sSpellbookID);
+                            }
+                        }
+                        persistant_array_delete(oPC, sIDX);
+                    }
+                }
+                else
+                {
+                    persistant_array_delete(oPC, sArrayName);
+                    persistant_array_create(oPC, sArrayName);
+                }
+            }
+            //delay it so wipespellbookhidefeats has time to start to run
+            //but before the deletes actually happen
+            DelayCommand(0.1, SetupSpells(oPC, nClass));
+        }
+    }
+}
+
+//NewSpellbookSpell() helper functions
+int bTargetingAllowed(int nSpellID);
+void CheckPrepSlots(int nClass, int nSpellID, int nSpellbookID, int bIsAction = FALSE);
+void CheckSpontSlots(int nClass, int nSpellID, int nSpellSlotLevel, int bIsAction = FALSE);
+void DoCleanUp(int nMetamagic);
+
+void CastSpontaneousSpell(int nClass, int bInstantSpell = FALSE)
+{
+    //get the spellbook ID
+    int nFakeSpellID = GetSpellId();
+    int nSpellID = GetPowerFromSpellID(nFakeSpellID);
+    if(nSpellID == -1) nSpellID = 0;
+
+    //Check the target first
+    if(!bTargetingAllowed(nSpellID))
+        return;
+
+    // if OBJECT_SELF is fighting - stop fighting and cast spell
+    if(GetCurrentAction() == ACTION_ATTACKOBJECT)
+        ClearAllActions();
+
+    //if its a subradial spell, get the master
+    int nMasterFakeSpellID = StringToInt(Get2DACache("spells", "Master", nFakeSpellID));
+    if(!nMasterFakeSpellID)
+        nMasterFakeSpellID = nFakeSpellID;
+
+    int nSpellbookID = SpellToSpellbookID(nMasterFakeSpellID);
+
+    // Paranoia - It should not be possible to get here without having the spells available array existing
+    if(!persistant_array_exists(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass)))
+    {
+        if(DEBUG) DoDebug("ERROR: NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + " array does not exist");
+        persistant_array_create(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass));
+    }
+
+    int nSpellLevel = StringToInt(Get2DACache(GetFileForClass(nClass), "Level", nSpellbookID));
+
+    // Make sure the caster has uses of this spell remaining
+    // 2009-9-20: Add metamagic feat abilities. -N-S
+    int nMetamagic = GetLocalInt(OBJECT_SELF, "MetamagicFeatAdjust");
+    if(nMetamagic)
+    {
+        //Need to check if metamagic can be applied to a spell
+        int nMetaTest;
+        int nMetaType = HexToInt(Get2DACache("spells", "MetaMagic", nSpellID));
+
+        int nSpellSlotLevel = nSpellLevel;
+        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(OBJECT_SELF, "You can't use "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)))+"with selected metamagic."));
+            nSpellLevel = nSpellSlotLevel;
+        }
+        else if(nSpellLevel > 9)//now test the spell level
+        {
+            nMetamagic = METAMAGIC_NONE;
+            ActionDoCommand(SendMessageToPC(OBJECT_SELF, "Modified spell level is to high! Casting spell without metamagic"));
+            nSpellLevel = nSpellSlotLevel;
+        }
+        else if(GetLocalInt(OBJECT_SELF, "PRC_metamagic_state") == 1)
+            SetLocalInt(OBJECT_SELF, "MetamagicFeatAdjust", 0);
+    }
+
+    CheckSpontSlots(nClass, nSpellID, nSpellLevel);
+    if(GetLocalInt(OBJECT_SELF, "NSB_Cast"))
+        ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE));
+    else
+        return;
+
+    // Calculate DC. 10 + spell level on the casting class's list + DC increasing ability mod
+    //int nDC = 10 + nSpellLevel + GetDCAbilityModForClass(nClass, OBJECT_SELF);
+    // This is wrong and is breaking things, and is already calculated in the function it calls anyway - Strat
+
+    //remove any old effects
+    //seems cheat-casting breaks hardcoded removal
+    //and cant remove effects because I dont know all the targets!
+    if(!bInstantSpell)
+    {
+        //Handle quicken metamagic and Duskblade's Quick Cast
+        if((nMetamagic & METAMAGIC_QUICKEN) || GetLocalInt(OBJECT_SELF, "QuickCast"))
+        {
+            //Adding Auto-Quicken III - deleted after casting has finished.
+            object oSkin = GetPCSkin(OBJECT_SELF);
+            int nCastDur = StringToInt(Get2DACache("spells", "ConjTime", nSpellID)) + StringToInt(Get2DACache("spells", "CastTime", nSpellID));
+            itemproperty ipAutoQuicken = ItemPropertyBonusFeat(IP_CONST_NSB_AUTO_QUICKEN);
+            ActionDoCommand(AddItemProperty(DURATION_TYPE_TEMPORARY, ipAutoQuicken, oSkin, nCastDur/1000.0f));
+            DeleteLocalInt(OBJECT_SELF, "QuickCast");
+        }
+    }
+
+    //cast the spell
+    //dont need to override level, the spellscript will calculate it
+    //class is read from "NSB_Class"
+    ActionCastSpell(nSpellID, 0, -1, 0, nMetamagic, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, bInstantSpell);
+
+    //Clean up
+    ActionDoCommand(DoCleanUp(nMetamagic));
+}
+
+void CastPreparedSpell(int nClass, int nMetamagic = METAMAGIC_NONE, int bInstantSpell = FALSE)
+{
+    object oPC = OBJECT_SELF;
+
+    //get the spellbook ID
+    int nFakeSpellID = GetSpellId();
+    int nSpellID = GetPowerFromSpellID(nFakeSpellID);
+    if(nSpellID == -1) nSpellID = 0;
+
+    //Check the target first
+    if(!bTargetingAllowed(nSpellID))
+        return;
+
+    // if OBJECT_SELF is fighting - stop fighting and cast spell
+    if(GetCurrentAction() == ACTION_ATTACKOBJECT)
+        ClearAllActions();
+
+    //if its a subradial spell, get the master
+    int nMasterFakeSpellID = StringToInt(Get2DACache("spells", "Master", nFakeSpellID));
+    if(!nMasterFakeSpellID)
+        nMasterFakeSpellID = nFakeSpellID;
+
+    int nSpellbookID = SpellToSpellbookID(nMasterFakeSpellID);
+
+    // Paranoia - It should not be possible to get here without having the spells available array existing
+    if(!persistant_array_exists(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass)))
+    {
+        if(DEBUG) DoDebug("ERROR: NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + " array does not exist");
+        persistant_array_create(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass));
+    }
+
+    int nSpellLevel = StringToInt(Get2DACache(GetFileForClass(nClass), "Level", nSpellbookID));
+
+    // Make sure the caster has uses of this spell remaining
+    CheckPrepSlots(nClass, nSpellID, nSpellbookID);
+    if(GetLocalInt(OBJECT_SELF, "NSB_Cast"))
+        ActionDoCommand(CheckPrepSlots(nClass, nSpellID, nSpellbookID, TRUE));
+    else
+        return;
+
+    // Calculate DC. 10 + spell level on the casting class's list + DC increasing ability mod
+    //int nDC = 10 + nSpellLevel + GetDCAbilityModForClass(nClass, OBJECT_SELF);
+    // This is wrong and is breaking things, and is already calculated in the function it calls anyway - Strat
+
+    //remove any old effects
+    //seems cheat-casting breaks hardcoded removal
+    //and cant remove effects because I dont know all the targets!
+    if(!bInstantSpell)
+    {
+        //Handle quicken metamagic and Duskblade's Quick Cast
+        if((nMetamagic & METAMAGIC_QUICKEN) || GetLocalInt(OBJECT_SELF, "QuickCast"))
+        {
+            //Adding Auto-Quicken III - deleted after casting has finished.
+            object oSkin = GetPCSkin(OBJECT_SELF);
+            int nCastDur = StringToInt(Get2DACache("spells", "ConjTime", nSpellID)) + StringToInt(Get2DACache("spells", "CastTime", nSpellID));
+            itemproperty ipAutoQuicken = ItemPropertyBonusFeat(IP_CONST_NSB_AUTO_QUICKEN);
+            ActionDoCommand(AddItemProperty(DURATION_TYPE_TEMPORARY, ipAutoQuicken, oSkin, nCastDur/1000.0f));
+            DeleteLocalInt(OBJECT_SELF, "QuickCast");
+        }
+        else if(nClass == CLASS_TYPE_HEALER)
+        {
+            if(GetHasFeat(FEAT_EFFORTLESS_HEALING)
+            && GetIsOfSubschool(nSpellID, SUBSCHOOL_HEALING))
+            {
+                object oSkin = GetPCSkin(OBJECT_SELF);
+                //all spells from healing subschool except Close Wounds have casting time of 2.5s
+                float fCastDur = nSpellID == SPELL_CLOSE_WOUNDS ? 1.0f : 2.5f;
+                itemproperty ipImpCombatCast = ItemPropertyBonusFeat(IP_CONST_NSB_IMP_COMBAT_CAST);
+                ActionDoCommand(AddItemProperty(DURATION_TYPE_TEMPORARY, ipImpCombatCast, oSkin, fCastDur));
+            }
+        }
+    }
+
+    //cast the spell
+    //dont need to override level, the spellscript will calculate it
+    //class is read from "NSB_Class"
+    ActionCastSpell(nSpellID, 0, -1, 0, nMetamagic, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, bInstantSpell);
+
+    //Clean up
+    ActionDoCommand(DoCleanUp(nMetamagic));
+}
+
+void NewSpellbookSpell(int nClass, int nSpellbookType, int nMetamagic = METAMAGIC_NONE, int bInstantSpell = FALSE)
+{
+    object oPC = OBJECT_SELF;
+
+    // if oPC is fighting - stop fighting and cast spell
+    if(GetCurrentAction(oPC) == ACTION_ATTACKOBJECT)
+        ClearAllActions();
+
+    //get the spellbook ID
+    int nFakeSpellID = GetSpellId();
+    int nSpellID = GetPowerFromSpellID(nFakeSpellID);
+    if(nSpellID == -1) nSpellID = 0;
+
+    //Check the target first
+    if(!bTargetingAllowed(nSpellID))
+        return;
+
+    //if its a subradial spell, get the master
+    int nMasterFakeSpellID = StringToInt(Get2DACache("spells", "Master", nFakeSpellID));
+    if(!nMasterFakeSpellID)
+        nMasterFakeSpellID = nFakeSpellID;
+
+    int nSpellbookID = SpellToSpellbookID(nMasterFakeSpellID);
+
+    // Paranoia - It should not be possible to get here without having the spells available array existing
+    if(!persistant_array_exists(oPC, "NewSpellbookMem_" + IntToString(nClass)))
+    {
+        if(DEBUG) DoDebug("ERROR: NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + " array does not exist");
+        persistant_array_create(oPC, "NewSpellbookMem_" + IntToString(nClass));
+    }
+
+    string sFile = GetFileForClass(nClass);
+    int nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
+
+    // Make sure the caster has uses of this spell remaining
+    // 2009-9-20: Add metamagic feat abilities. -N-S
+    if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
+    {
+        CheckPrepSlots(nClass, nSpellID, nSpellbookID);
+        if(GetLocalInt(oPC, "NSB_Cast"))
+            ActionDoCommand(CheckPrepSlots(nClass, nSpellID, nSpellbookID, TRUE));
+        else
+            return;
+    }
+    else if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+    {
+        nMetamagic = GetLocalInt(oPC, "MetamagicFeatAdjust");
+        if(nMetamagic)
+        {
+            //Need to check if metamagic can be applied to a spell
+            int nMetaTest;
+            int nMetaType = HexToInt(Get2DACache("spells", "MetaMagic", nSpellID));
+
+            int nSpellSlotLevel = nSpellLevel;
+            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", nSpellID)))+"with selected metamagic."));
+                nSpellLevel = nSpellSlotLevel;
+            }
+            else if(nSpellLevel > 9)//now test the spell level
+            {
+                nMetamagic = METAMAGIC_NONE;
+                ActionDoCommand(SendMessageToPC(oPC, "Modified spell level is to high! Casting spell without metamagic"));
+                nSpellLevel = nSpellSlotLevel;
+            }
+            else if(GetLocalInt(oPC, "PRC_metamagic_state") == 1)
+                SetLocalInt(oPC, "MetamagicFeatAdjust", 0);
+        }
+
+        CheckSpontSlots(nClass, nSpellID, nSpellLevel);
+        if(GetLocalInt(oPC, "NSB_Cast"))
+            ActionDoCommand(CheckSpontSlots(nClass, nSpellID, nSpellLevel, TRUE));
+        else
+            return;
+    }
+
+    // Calculate DC. 10 + spell level on the casting class's list + DC increasing ability mod
+    //int nDC = 10 + nSpellLevel + GetDCAbilityModForClass(nClass, OBJECT_SELF);
+    // This is wrong and is breaking things, and is already calculated in the function it calls anyway - Strat
+
+    //remove any old effects
+    //seems cheat-casting breaks hardcoded removal
+    //and cant remove effects because I dont know all the targets!
+    if(!bInstantSpell)
+    {
+        //Handle quicken metamagic and Duskblade's Quick Cast
+        if((nMetamagic & METAMAGIC_QUICKEN) || GetLocalInt(oPC, "QuickCast"))
+        {
+            //Adding Auto-Quicken III - deleted after casting has finished.
+            object oSkin = GetPCSkin(oPC);
+            int nCastDur = StringToInt(Get2DACache("spells", "ConjTime", nSpellID)) + StringToInt(Get2DACache("spells", "CastTime", nSpellID));
+            itemproperty ipAutoQuicken = ItemPropertyBonusFeat(IP_CONST_NSB_AUTO_QUICKEN);
+            ActionDoCommand(AddItemProperty(DURATION_TYPE_TEMPORARY, ipAutoQuicken, oSkin, nCastDur/1000.0f));
+            DeleteLocalInt(oPC, "QuickCast");
+        }
+        else if(nClass == CLASS_TYPE_HEALER)
+        {
+            if(GetHasFeat(FEAT_EFFORTLESS_HEALING)
+            && GetIsOfSubschool(nSpellID, SUBSCHOOL_HEALING))
+            {
+                object oSkin = GetPCSkin(oPC);
+                //all spells from healing subschool except Close Wounds have casting time of 2.5s
+                float fCastDur = nSpellID == SPELL_CLOSE_WOUNDS ? 1.0f : 2.5f;
+                itemproperty ipImpCombatCast = ItemPropertyBonusFeat(IP_CONST_NSB_IMP_COMBAT_CAST);
+                ActionDoCommand(AddItemProperty(DURATION_TYPE_TEMPORARY, ipImpCombatCast, oSkin, fCastDur));
+            }
+        }
+    }
+
+    //cast the spell
+    //dont need to override level, the spellscript will calculate it
+    //class is read from "NSB_Class"
+    ActionCastSpell(nSpellID, 0, -1, 0, nMetamagic, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, bInstantSpell);
+
+    //Clean up
+    ActionDoCommand(DoCleanUp(nMetamagic));
+}
+
+int bTargetingAllowed(int nSpellID)
+{
+    object oTarget = GetSpellTargetObject();
+    if(GetIsObjectValid(oTarget))
+    {
+        int nTargetType = ~(HexToInt(Get2DACache("spells", "TargetType", nSpellID)));
+
+        //test targetting self
+        if(oTarget == OBJECT_SELF)
+        {
+            if(nTargetType & 1)
+            {
+                if(DEBUG) DoDebug("bTargetingAllowed: You cannot target yourself.");
+                return FALSE;
+            }
+        }
+        //test targetting others
+        else if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
+        {
+            if(nTargetType & 2)
+            {
+                if(DEBUG) DoDebug("bTargetingAllowed: You cannot target creatures.");
+                return FALSE;
+            }
+        }
+    }
+    return TRUE;
+}
+
+void CheckPrepSlots(int nClass, int nSpellID, int nSpellbookID, int bIsAction = FALSE)
+{
+    DeleteLocalInt(OBJECT_SELF, "NSB_Cast");
+    int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellbookID);
+    if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellbookID) + "] = " + IntToString(nCount));
+    if(nCount < 1)
+    {
+        string sSpellName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+        // "You have no castings of " + sSpellName + " remaining"
+        string sMessage   = ReplaceChars(GetStringByStrRef(16828411), "<spellname>", sSpellName);
+
+        FloatingTextStringOnCreature(sMessage, OBJECT_SELF, FALSE);
+        if(bIsAction)
+            ClearAllActions();
+    }
+    else
+    {
+        SetLocalInt(OBJECT_SELF, "NSB_Cast", 1);
+        if(bIsAction)
+        {
+            SetLocalInt(OBJECT_SELF, "NSB_Class", nClass);
+            SetLocalInt(OBJECT_SELF, "NSB_SpellbookID", nSpellbookID);
+        }
+    }
+}
+
+void CheckSpontSlots(int nClass, int nSpellID, int nSpellSlotLevel, int bIsAction = FALSE)
+{
+    DeleteLocalInt(OBJECT_SELF, "NSB_Cast");
+    int nCount = persistant_array_get_int(OBJECT_SELF, "NewSpellbookMem_" + IntToString(nClass), nSpellSlotLevel);
+    if(DEBUG) DoDebug("NewSpellbookSpell: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(nSpellSlotLevel) + "] = " + IntToString(nCount));
+    if(nCount < 1)
+    {
+        // "You have no castings of spells of level " + IntToString(nSpellLevel) + " remaining"
+        string sMessage   = ReplaceChars(GetStringByStrRef(16828409), "<spelllevel>", IntToString(nSpellSlotLevel));
+        FloatingTextStringOnCreature(sMessage, OBJECT_SELF, FALSE);
+        if(bIsAction)
+            ClearAllActions();
+    }
+    else
+    {
+        SetLocalInt(OBJECT_SELF, "NSB_Cast", 1);
+        if(bIsAction)
+        {
+            SetLocalInt(OBJECT_SELF, "NSB_Class", nClass);
+            SetLocalInt(OBJECT_SELF, "NSB_SpellLevel", nSpellSlotLevel);
+        }
+    }
+}
+
+void DoCleanUp(int nMetamagic)
+{
+    if(nMetamagic & METAMAGIC_QUICKEN)
+    {
+        object oSkin = GetPCSkin(OBJECT_SELF);
+        RemoveItemProperty(oSkin, ItemPropertyBonusFeat(IP_CONST_NSB_AUTO_QUICKEN));
+    }
+    DeleteLocalInt(OBJECT_SELF, "NSB_Class");
+    DeleteLocalInt(OBJECT_SELF, "NSB_SpellLevel");
+    DeleteLocalInt(OBJECT_SELF, "NSB_SpellbookID");
+}
\ No newline at end of file
diff --git a/trunk/include/inv_inc_invfunc.nss b/trunk/include/inv_inc_invfunc.nss
new file mode 100644
index 00000000..c78ec4d4
--- /dev/null
+++ b/trunk/include/inv_inc_invfunc.nss
@@ -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(){}
diff --git a/trunk/include/moi_inc_moifunc.nss b/trunk/include/moi_inc_moifunc.nss
new file mode 100644
index 00000000..05a10903
--- /dev/null
+++ b/trunk/include/moi_inc_moifunc.nss
@@ -0,0 +1,1559 @@
+//::///////////////////////////////////////////////
+//:: Meldshaping/Incarnum main include: Miscellaneous
+//:: moi_inc_moifunc
+//::///////////////////////////////////////////////
+/** @file
+    Defines various functions and other stuff that
+    do something related to Meldshaping.
+
+    Also acts as inclusion nexus for the general
+    meldshaping includes. In other words, don't include
+    them directly in your scripts, instead include this.
+
+    @author Stratovarius
+    @date   Created - 2019.12.28
+	
+	Updated for .35 by Jaysyn 2023/03/10
+*/
+//:://////////////////////////////////////////////
+//:://////////////////////////////////////////////
+
+//:: Test Void
+//void main () {}
+
+//////////////////////////////////////////////////
+/*             Function prototypes              */
+//////////////////////////////////////////////////
+
+/**
+ * Determines the given creature's Meldshaper level. 
+ *
+ * @param oMeldshaper    The creature whose Meldshaper level to determine
+ * @param nSpecificClass The class to determine the creature's Meldshaper
+ *                       level in.
+ * @param nMeld          The meld to test, since Incarnum does level by meld
+ *
+ * @return               The Meldshaper level
+ */
+int GetMeldshaperLevel(object oMeldshaper, int nSpecificClass, int nMeld);
+
+/**
+ * Determines the given creature's highest unmodified Meldshaper level among its
+ * Meldshaping classes.
+ *
+ * @param oMeldshaper Creature whose highest Meldshaper level to determine
+ * @return          The highest unmodified Meldshaper level the creature can have
+ */
+int GetHighestMeldshaperLevel(object oMeldshaper);
+
+/**
+ * Determines whether a given class is a Incarnum-related class or not.
+ *
+ * @param nClass CLASS_TYPE_* of the class to test
+ * @return       TRUE if the class is a Incarnum-related class, FALSE otherwise
+ */
+int GetIsIncarnumClass(int nClass);
+
+/**
+ * Calculates how many Meldshaper levels are gained by a given creature from
+ * it's levels in prestige classes.
+ *
+ * @param oMeldshaper Creature to calculate added Meldshaper levels for
+ * @return          The number of Meldshaper levels gained
+ */
+int GetIncarnumPRCLevels(object oMeldshaper);
+
+/**
+ * Determines which of the character's classes is their highest or first 
+ * Meldshaping class, if any. This is the one which gains Meldshaper 
+ * level raise benefits from prestige classes.
+ *
+ * @param oMeldshaper Creature whose classes to test
+ * @return          CLASS_TYPE_* of the first Meldshaping class,
+ *                  CLASS_TYPE_INVALID if the creature does not possess any.
+ */
+int GetPrimaryIncarnumClass(object oMeldshaper = OBJECT_SELF);
+
+/**
+ * Determines the position of a creature's first Meldshaping class, if any.
+ *
+ * @param oMeldshaper Creature whose classes to test
+ * @return          The position of the first Meldshaping class {1, 2, 3} or 0 if
+ *                  the creature possesses no levels in Meldshaping classes.
+ */
+int GetFirstIncarnumClassPosition(object oMeldshaper = OBJECT_SELF);
+
+/**
+ * Checks every second to see if temporary essentia has been lost
+ *
+ * @param oMeldshaper  The meldshaper
+ */
+void SpawnTempEssentiaChecker(object oMeldshaper);
+
+/**
+ * Returns total value of temporary essentia for the meldshaper
+ *
+ * @param oMeldshaper The meldshaper
+ * 
+ * @return        Total value of temporary essentia
+ */
+int GetTemporaryEssentia(object oMeldshaper);
+
+/**
+ * Essentia put into feats is locked away for 24 hours/until next rest
+ *
+ * @param oMeldshaper The meldshaper
+ * 
+ * @return        Total value of locked essentia
+ */
+int GetFeatLockedEssentia(object oMeldshaper);
+
+/**
+ * Total essentia a character has access to
+ *
+ * @param oMeldshaper The meldshaper
+ * 
+ * @return        Total value of essentia available
+ */
+int GetTotalEssentia(object oMeldshaper);
+
+/**
+ * Total essentia a character has access to, minus feat locked essentia
+ *
+ * @param oMeldshaper The meldshaper
+ * 
+ * @return        Total value of essentia available, minus feat locked essentia
+ */
+int GetTotalUsableEssentia(object oMeldshaper);
+
+/**
+ * Returns the slot associated to a given chakra
+ *
+ * @param nChakra Chakra constant
+ * 
+ * @return        Slot constant
+ */
+int ChakraToSlot(int nChakra);
+
+/**
+ * Returns the total binds the character can have for that class and level
+ *
+ * @param oMeldshaper The meldshaper 
+ * @param nClass      The class to check
+ * 
+ * @return        Slot constant
+ */
+int GetMaxBindCount(object oMeldshaper, int nClass);
+
+//////////////////////////////////////////////////
+/*                  Includes                    */
+//////////////////////////////////////////////////
+
+#include "prc_inc_natweap"
+#include "prc_inc_function"
+
+//////////////////////////////////////////////////
+/*             Function definitions             */
+//////////////////////////////////////////////////
+
+int GetMeldshaperLevel(object oMeldshaper, int nSpecificClass, int nMeld)
+{
+    int nLevel;
+
+    if (DEBUG) DoDebug("GetMeldshaperLevel: "+GetName(oMeldshaper)+" is a "+IntToString(nSpecificClass));
+
+    if(GetIsIncarnumClass(nSpecificClass))
+    {
+        // Meldshaper level is class level + prestige
+        nLevel = GetLevelByClass(nSpecificClass, oMeldshaper);
+        if(nLevel)
+        {
+        	// Prevents people double-dipping prestige levels
+            if (nSpecificClass == GetPrimaryIncarnumClass(oMeldshaper)) 
+            {
+            	nLevel += GetIncarnumPRCLevels(oMeldshaper);
+            	nLevel += GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper); // Necrocarnate is here because it doesn't add to anything other than meldshaper level
+            }	
+            if (nSpecificClass == CLASS_TYPE_SOULBORN) nLevel /= 2;                   
+        }   
+    }
+    
+    if(DEBUG) DoDebug("Meldshaper Level: " + IntToString(nLevel));
+    // Being bound to the Totem Chakra increases the level by one.
+	if (GetIsMeldBound(oMeldshaper, nMeld) == CHAKRA_TOTEM) nLevel++;
+    return nLevel;
+}
+
+int GetIncarnumLevelForClass(int nSpecificClass, object oMeldshaper)
+{
+    int nLevel;
+
+    if (DEBUG) DoDebug("GetMeldshaperLevel: "+GetName(oMeldshaper)+" is a "+IntToString(nSpecificClass));
+
+    if(GetIsIncarnumClass(nSpecificClass))
+    {
+        // Meldshaper level is class level + prestige
+        nLevel = GetLevelByClass(nSpecificClass, oMeldshaper);
+        if(nLevel)
+        {
+        	// Prevents people double-dipping prestige levels
+            if (nSpecificClass == GetPrimaryIncarnumClass(oMeldshaper)) nLevel += GetIncarnumPRCLevels(oMeldshaper);                 
+        }   
+    }
+    if(nSpecificClass == CLASS_TYPE_UMBRAL_DISCIPLE || nSpecificClass == CLASS_TYPE_INCANDESCENT_CHAMPION || nSpecificClass == CLASS_TYPE_NECROCARNATE)
+    	nLevel = GetLevelByClass(nSpecificClass, oMeldshaper);
+    
+    if(DEBUG) DoDebug("GetIncarnumLevelForClass: " + IntToString(nLevel));
+    return nLevel;
+}
+
+int GetHighestMeldshaperLevel(object oMeldshaper)
+{
+	int n = 0;
+	int nHighest;
+	int nTemp;
+	
+    while(n <= 8)
+	{
+		if(GetClassByPosition(n, oMeldshaper) != CLASS_TYPE_INVALID)
+		{
+			nTemp = GetMeldshaperLevel(oMeldshaper, GetClassByPosition(n, oMeldshaper), -1);
+			
+			if(nTemp > nHighest) 
+				nHighest = nTemp;
+		}
+	n++;
+
+	}
+	
+	return nHighest;
+}
+
+/* int GetHighestMeldshaperLevel(object oMeldshaper)
+{
+    return max(max(GetClassByPosition(1, oMeldshaper) != CLASS_TYPE_INVALID ? GetMeldshaperLevel(oMeldshaper, GetClassByPosition(1, oMeldshaper), -1) : 0,
+                   GetClassByPosition(2, oMeldshaper) != CLASS_TYPE_INVALID ? GetMeldshaperLevel(oMeldshaper, GetClassByPosition(2, oMeldshaper), -1) : 0
+                   ),
+               GetClassByPosition(3, oMeldshaper) != CLASS_TYPE_INVALID ? GetMeldshaperLevel(oMeldshaper, GetClassByPosition(3, oMeldshaper), -1) : 0
+               );
+} */
+
+int GetIsIncarnumClass(int nClass)
+{
+    return nClass == CLASS_TYPE_INCARNATE
+         || nClass == CLASS_TYPE_SOULBORN
+         || nClass == CLASS_TYPE_TOTEMIST
+         || nClass == CLASS_TYPE_SPINEMELD_WARRIOR;
+}
+
+int GetIncarnumPRCLevels(object oMeldshaper)
+{
+    int nLevel = GetLevelByClass(CLASS_TYPE_SAPPHIRE_HIERARCH, oMeldshaper);
+    nLevel += GetLevelByClass(CLASS_TYPE_SOULCASTER, oMeldshaper);
+    
+    // These two don't add at 1st level
+    if (GetLevelByClass(CLASS_TYPE_IRONSOUL_FORGEMASTER, oMeldshaper))
+        nLevel += GetLevelByClass(CLASS_TYPE_IRONSOUL_FORGEMASTER, oMeldshaper) - 1;
+    // Totem Rager    
+	if (GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper) >= 6)
+		nLevel += (GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper)) -2;
+	else if (GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper))
+		nLevel += (GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper)) -1;
+	//This is an odd one	
+	if (GetLevelByClass(CLASS_TYPE_WITCHBORN_BINDER, oMeldshaper))
+	{
+		nLevel += (GetLevelByClass(CLASS_TYPE_WITCHBORN_BINDER, oMeldshaper)+1)/2;
+		
+		if (GetLevelByClass(CLASS_TYPE_WITCHBORN_BINDER, oMeldshaper) >= 10) nLevel += 1;
+	}	
+
+    /*if (GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oMeldshaper))
+        nLevel += GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oMeldshaper) - 1;        
+*/
+    return nLevel;
+}
+
+int GetPrimaryIncarnumClass(object oMeldshaper = OBJECT_SELF)
+{
+    int nClass = CLASS_TYPE_INVALID;
+
+    if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE))
+    {
+        int nIncarnumPos = GetFirstIncarnumClassPosition(oMeldshaper);
+        if (!nIncarnumPos) return CLASS_TYPE_INVALID; // no Blade Magic Meldshaping class
+
+        nClass = GetClassByPosition(nIncarnumPos, oMeldshaper);
+    }
+    else
+    {
+        int nClassLvl;
+        int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8;
+        int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl;
+		
+		nClass1 = GetClassByPosition(1, oMeldshaper);
+        nClass2 = GetClassByPosition(2, oMeldshaper);
+        nClass3 = GetClassByPosition(3, oMeldshaper);
+		nClass4 = GetClassByPosition(4, oMeldshaper);
+		nClass5 = GetClassByPosition(5, oMeldshaper);
+		nClass6 = GetClassByPosition(6, oMeldshaper);
+		nClass7 = GetClassByPosition(7, oMeldshaper);
+		nClass8 = GetClassByPosition(8, oMeldshaper);
+		
+        if(GetIsIncarnumClass(nClass1)) nClass1Lvl = GetLevelByClass(nClass1, oMeldshaper);
+        if(GetIsIncarnumClass(nClass2)) nClass2Lvl = GetLevelByClass(nClass2, oMeldshaper);
+        if(GetIsIncarnumClass(nClass3)) nClass3Lvl = GetLevelByClass(nClass3, oMeldshaper);
+		if(GetIsIncarnumClass(nClass4)) nClass4Lvl = GetLevelByClass(nClass4, oMeldshaper);
+		if(GetIsIncarnumClass(nClass5)) nClass5Lvl = GetLevelByClass(nClass5, oMeldshaper);
+		if(GetIsIncarnumClass(nClass6)) nClass6Lvl = GetLevelByClass(nClass6, oMeldshaper);
+		if(GetIsIncarnumClass(nClass7)) nClass7Lvl = GetLevelByClass(nClass7, oMeldshaper);
+		if(GetIsIncarnumClass(nClass8)) nClass8Lvl = GetLevelByClass(nClass8, oMeldshaper);
+
+        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 GetFirstIncarnumClassPosition(object oMeldshaper = OBJECT_SELF)
+{
+    if (GetIsIncarnumClass(GetClassByPosition(1, oMeldshaper)))
+        return 1;
+    if (GetIsIncarnumClass(GetClassByPosition(2, oMeldshaper)))
+        return 2;
+    if (GetIsIncarnumClass(GetClassByPosition(3, oMeldshaper)))
+        return 3;
+    if (GetIsIncarnumClass(GetClassByPosition(4, oMeldshaper)))
+        return 4;
+    if (GetIsIncarnumClass(GetClassByPosition(5, oMeldshaper)))
+        return 5;
+    if (GetIsIncarnumClass(GetClassByPosition(6, oMeldshaper)))
+        return 6;
+    if (GetIsIncarnumClass(GetClassByPosition(7, oMeldshaper)))
+        return 7;
+    if (GetIsIncarnumClass(GetClassByPosition(8, oMeldshaper)))
+        return 8;
+
+    return 0;
+}
+
+string GetMeldFile(int nClass = -1)
+{
+	//string sFile;
+	//if (nClass == CLASS_TYPE_INCARNATE) sFile = "cls_meld_incarn";
+	
+	return "soulmelds";
+}
+
+string GetMeldshapingClassFile(int nClass)
+{
+	string sFile;
+	if (nClass == CLASS_TYPE_INCARNATE) sFile = "cls_mlkn_incarn";
+	else if (nClass == CLASS_TYPE_SOULBORN) sFile = "cls_mlkn_soulbn";
+	else if (nClass == CLASS_TYPE_TOTEMIST) sFile = "cls_mlkn_totem";
+	else if (nClass == CLASS_TYPE_SPINEMELD_WARRIOR) sFile = "cls_mlkn_spnmld";
+	else if (nClass == CLASS_TYPE_UMBRAL_DISCIPLE) sFile = "cls_mlkn_umbral";
+	else if (nClass == CLASS_TYPE_INCANDESCENT_CHAMPION) sFile = "cls_mlkn_incand";
+	else if (nClass == CLASS_TYPE_NECROCARNATE) sFile = "cls_mlkn_necrnm";
+	
+	return sFile;
+}
+
+int GetMeldshapingClass(object oMeldshaper)
+{
+	int nClass = -1;
+	// If there's levels in the class and haven't already done it
+	if (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) && !GetLocalInt(oMeldshaper, "FirstMeldDone")) nClass = CLASS_TYPE_INCARNATE;
+	else if (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) && !GetLocalInt(oMeldshaper, "SecondMeldDone")) nClass = CLASS_TYPE_SOULBORN;
+	else if (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) && !GetLocalInt(oMeldshaper, "ThirdMeldDone")) nClass = CLASS_TYPE_TOTEMIST;
+	else if (GetLevelByClass(CLASS_TYPE_SPINEMELD_WARRIOR, oMeldshaper) && !GetLocalInt(oMeldshaper, "FourthMeldDone")) nClass = CLASS_TYPE_SPINEMELD_WARRIOR;
+	if (DEBUG) DoDebug("GetMeldshapingClass is "+IntToString(nClass));
+	return nClass;
+}
+
+int GetMaxShapeSoulmeldCount(object oMeldshaper, int nClass)
+{
+	int nMax = StringToInt(Get2DACache(GetMeldshapingClassFile(nClass), "Soulmelds", GetIncarnumLevelForClass(nClass, oMeldshaper)-1));
+	if (nClass == GetPrimaryIncarnumClass(oMeldshaper)) 
+	{
+		nMax += StringToInt(Get2DACache(GetMeldshapingClassFile(CLASS_TYPE_NECROCARNATE), "Soulmelds", GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper)));
+    	int i;
+    	for(i = FEAT_BONUS_SOULMELD_1; i <= FEAT_BONUS_SOULMELD_10; i++)
+    	    if(GetHasFeat(i, oMeldshaper)) nMax++;
+    }
+    
+	int nCon = GetAbilityScore(oMeldshaper, ABILITY_CONSTITUTION, TRUE)-10;
+	if (GetHasFeat(FEAT_UNDEAD_MELDSHAPER, oMeldshaper)) nCon = GetAbilityScore(oMeldshaper, ABILITY_WISDOM, TRUE)-10;
+	//Limited to Con score - 10 or class limit, whichever is less
+	nMax = min(nMax, nCon);	
+	
+    if (DEBUG) DoDebug("GetMaxShapeSoulmeldCount is "+IntToString(nMax));
+    return nMax;
+}
+
+int GetTotalSoulmeldCount(object oMeldshaper)
+{
+	int nMax = GetMaxShapeSoulmeldCount(oMeldshaper, CLASS_TYPE_INCARNATE);	
+		nMax += GetMaxShapeSoulmeldCount(oMeldshaper, CLASS_TYPE_SOULBORN);
+		nMax += GetMaxShapeSoulmeldCount(oMeldshaper, CLASS_TYPE_TOTEMIST);
+		nMax += GetMaxShapeSoulmeldCount(oMeldshaper, CLASS_TYPE_SPINEMELD_WARRIOR);
+		nMax += GetMaxShapeSoulmeldCount(oMeldshaper, CLASS_TYPE_NECROCARNATE);
+	
+    if (DEBUG) DoDebug("GetTotalSoulmeldCount is "+IntToString(nMax));
+    return nMax;
+}
+
+int GetMaxBindCount(object oMeldshaper, int nClass)
+{
+	int nMax = StringToInt(Get2DACache(GetMeldshapingClassFile(nClass), "ChakraBinds", GetIncarnumLevelForClass(nClass, oMeldshaper)-1));
+	if (nClass == GetPrimaryIncarnumClass(oMeldshaper)) 
+	{
+		nMax += StringToInt(Get2DACache(GetMeldshapingClassFile(CLASS_TYPE_NECROCARNATE), "ChakraBinds", GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper)));
+	   	int i;
+	   	for(i = FEAT_EXTRA_CHAKRA_BIND_1; i <= FEAT_EXTRA_CHAKRA_BIND_10; i++)
+   	    	if(GetHasFeat(i, oMeldshaper)) nMax += 1;
+   	}    
+    if (DEBUG) DoDebug("GetMaxBindCount is "+IntToString(nMax));
+    return nMax;
+}
+
+void ShapeSoulmeld(object oMeldshaper, int nMeld)
+{
+	PRCRemoveSpellEffects(nMeld, oMeldshaper, oMeldshaper);
+	GZPRCRemoveSpellEffects(nMeld, oMeldshaper, FALSE);
+	ActionCastSpellOnSelf(nMeld);
+	if (DEBUG) DoDebug("Shaping Soulmeld "+IntToString(nMeld)+" on "+GetName(oMeldshaper));
+}		
+
+void MarkMeldShaped(object oMeldshaper, int nMeld, int nClass)
+{
+	if (DEBUG) DoDebug("MarkMeldShaped nMeld is "+IntToString(nMeld));
+	int nCont = TRUE;
+	int nTest, i;
+	while (nCont)
+	{
+		nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(nClass)+IntToString(i));
+		if (DEBUG) DoDebug("MarkMeldShaped nTest is "+IntToString(nTest));
+		if (!nTest) // If it's blank
+		{
+			SetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(nClass)+IntToString(i), nMeld);
+			if (DEBUG) DoDebug("MarkMeldShaped SetLocal");
+			nCont = FALSE; // Break the loop
+		}
+		else
+			i++; // Increment the counter to check
+	}
+}
+
+void ClearMeldShapes(object oMeldshaper)
+{
+	object oSkin = GetPCSkin(oMeldshaper);
+	ScrubPCSkin(oMeldshaper, oSkin);
+	int i;
+    for (i = 0; i <= 22; i++)
+    {
+		DeleteLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_INCARNATE)+IntToString(i));
+		DeleteLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_SOULBORN)+IntToString(i));
+		DeleteLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_TOTEMIST)+IntToString(i));
+		DeleteLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_SPINEMELD_WARRIOR)+IntToString(i));
+		DeleteLocalInt(oMeldshaper, "UsedMeld"+IntToString(CLASS_TYPE_SPINEMELD_WARRIOR)+IntToString(i));
+		DeleteLocalInt(oMeldshaper, "UsedMeld"+IntToString(CLASS_TYPE_INCARNATE)+IntToString(i));
+		DeleteLocalInt(oMeldshaper, "UsedMeld"+IntToString(CLASS_TYPE_SOULBORN)+IntToString(i));
+		DeleteLocalInt(oMeldshaper, "UsedMeld"+IntToString(CLASS_TYPE_TOTEMIST)+IntToString(i));
+		DeleteLocalInt(oMeldshaper, "BoundMeld"+IntToString(i));
+		int nTest = GetLocalInt(oMeldshaper, "SpellInvestCheck"+IntToString(i));
+    	if (nTest)
+    		DeleteLocalInt(oMeldshaper, "SpellEssentia"+IntToString(nTest));
+    	DeleteLocalInt(oMeldshaper, "SpellInvestCheck"+IntToString(i));	
+    	DeleteLocalInt(oMeldshaper, "ExpandedSoulmeld"+IntToString(i));	
+    	DeleteLocalInt(oMeldshaper, "UsedBladeMeld"+IntToString(i));	
+    }
+    for (i = 18700; i < 18799; i++)
+    {
+		DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(i));
+    } 
+    for (i = 8869; i < 8889; i++)
+    {
+		DeleteLocalInt(oMeldshaper, "FeatEssentia"+IntToString(i));
+    }    
+    DeleteLocalInt(oMeldshaper, "ArcaneFocusBound");
+    if (GetLocalInt(oMeldshaper, "DiademPurelight")) 
+    {
+    	SetLocalInt(oMeldshaper, "PRCInLight", GetLocalInt(oMeldshaper, "PRCInLight")-1); 
+    	DeleteLocalInt(oMeldshaper, "DiademPurelight");     
+    }
+    
+    if (GetLocalInt(oMeldshaper, "PlanarChasubleLimit") > 7) 
+    	DeleteLocalInt(oMeldshaper, "PlanarChasubleLimit");
+    else
+    	SetLocalInt(oMeldshaper, "PlanarChasubleLimit", GetLocalInt(oMeldshaper, "PlanarChasubleLimit")+1);
+    
+    DeleteLocalInt(oMeldshaper, "GorgonMaskLimit");
+    DeleteLocalInt(oMeldshaper, "IncarnateAvatarSpeed");
+    DeleteLocalInt(oMeldshaper, "LamiaBeltSpeed");
+    DeleteLocalInt(oMeldshaper, "LifebondVestmentsTimer");
+    DeleteLocalInt(oMeldshaper, "MidnightAugPower");
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18973"); // MELD_DUSKLING_SPEED
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18691"); // MELD_SPINE_ENHANCEMENT
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18687"); // MELD_IRONSOUL_SHIELD
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18685"); // MELD_IRONSOUL_ARMOR
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18683"); // MELD_IRONSOUL_WEAPON
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18681"); // MELD_UMBRAL_STEP  
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18679"); // MELD_UMBRAL_SHADOW
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18677"); // MELD_UMBRAL_SIGHT 
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18675"); // MELD_UMBRAL_SOUL  
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18673"); // MELD_UMBRAL_KISS  
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18670"); // MELD_INCANDESCENT_STRIKE
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18668"); // MELD_INCANDESCENT_HEAL       
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18666"); // MELD_INCANDESCENT_COUNTENANCE
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18663"); // MELD_INCANDESCENT_RAY        
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18659"); // MELD_INCANDESCENT_AURA    
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18634"); // MELD_WITCH_MELDSHIELD
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18636"); // MELD_WITCH_DISPEL    
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18638"); // MELD_WITCH_SHACKLES  
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18640"); // MELD_WITCH_ABROGATION
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18642"); // MELD_WITCH_SPIRITFLAY
+    DeleteLocalInt(oMeldshaper, "MeldEssentia18644"); // MELD_WITCH_INTEGUMENT 
+    DeleteLocalInt(oMeldshaper, "NecrocarnumCircletPen");
+    DeleteLocalInt(oMeldshaper, "AstralVambraces");
+    DeleteLocalInt(oMeldshaper, "TemporaryEssentia");
+    DestroyObject(GetItemPossessedBy(oMeldshaper, "moi_incarnatewpn")); // Remove any weapons created by Incarnate Weapon
+    
+    // Clean up any the natural weapons that are lying around
+    ClearNaturalWeapons(oMeldshaper);    
+    // Nuke the creature weapons. If the normal form is supposed to have natural weapons, they'll get re-constructed
+    if(GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oMeldshaper))) MyDestroyObject(GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oMeldshaper));
+    if(GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oMeldshaper))) MyDestroyObject(GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oMeldshaper));
+    if(GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oMeldshaper))) MyDestroyObject(GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oMeldshaper));    
+    
+    if (GetLocalInt(oMeldshaper, "ClearEventTotem")) ClearEventScriptList(oMeldshaper, EVENT_ITEM_ONHIT, TRUE, TRUE);   
+} 
+
+int GetShapedMeldsCount(object oMeldshaper)
+{
+	int i, nCount, nTest;
+    for (i = 0; i <= 20; i++)
+    {
+		nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_INCARNATE)+IntToString(i));
+		if (nTest) // If it's not blank
+			nCount++;	
+		nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_SOULBORN)+IntToString(i));
+		if (nTest) // If it's not blank
+			nCount++;	
+		nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_TOTEMIST)+IntToString(i));
+		if (nTest) // If it's not blank
+			nCount++;	
+		nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_SPINEMELD_WARRIOR)+IntToString(i));
+		if (nTest) // If it's not blank
+			nCount++;				
+    }
+    if (DEBUG) DoDebug("GetTotalShapedMelds is "+IntToString(nCount));
+    return nCount;
+}
+
+int GetTotalShapedMelds(object oMeldshaper, int nClass)
+{
+	int i, nCount, nTest;
+    for (i = 0; i <= 20; i++)
+    {
+		nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(nClass)+IntToString(i));
+		if (nTest) // If it's not blank
+			nCount++;	
+    }
+    if (DEBUG) DoDebug("GetTotalShapedMelds is "+IntToString(nCount));
+    return nCount;
+}
+
+int CheckSplitChakra(object oMeldshaper, int nSlot)
+{
+	if (nSlot == INVENTORY_SLOT_HEAD  && GetHasFeat(FEAT_SPLIT_CHAKRA_CROWN    , oMeldshaper)) return TRUE;	
+	if (nSlot == INVENTORY_SLOT_BOOTS && GetHasFeat(FEAT_SPLIT_CHAKRA_FEET     , oMeldshaper)) return TRUE;
+	if (nSlot == INVENTORY_SLOT_ARMS  && GetHasFeat(FEAT_SPLIT_CHAKRA_HANDS    , oMeldshaper)) return TRUE;
+	if (nSlot == INVENTORY_SLOT_ARMS  && GetHasFeat(FEAT_SPLIT_CHAKRA_ARMS     , oMeldshaper)) return TRUE;
+	if (nSlot == INVENTORY_SLOT_HEAD  && GetHasFeat(FEAT_SPLIT_CHAKRA_BROW     , oMeldshaper)) return TRUE;
+	if (nSlot == INVENTORY_SLOT_CLOAK && GetHasFeat(FEAT_SPLIT_CHAKRA_SHOULDERS, oMeldshaper)) return TRUE;
+	if (nSlot == INVENTORY_SLOT_NECK  && GetHasFeat(FEAT_SPLIT_CHAKRA_THROAT   , oMeldshaper)) return TRUE;
+	if (nSlot == INVENTORY_SLOT_BELT  && GetHasFeat(FEAT_SPLIT_CHAKRA_WAIST    , oMeldshaper)) return TRUE;
+	if (nSlot == INVENTORY_SLOT_CHEST && GetHasFeat(FEAT_SPLIT_CHAKRA_HEART    , oMeldshaper)) return TRUE;	
+	if (nSlot == INVENTORY_SLOT_CHEST && GetHasFeat(FEAT_SPLIT_CHAKRA_SOUL     , oMeldshaper)) return TRUE;
+	
+	return FALSE;	
+}
+
+void BindMeldToChakra(object oMeldshaper, int nMeld, int nChakra, int nClass)
+{
+	// Make sure it's not in use already, and that you have any binds to make
+	if (!GetIsChakraBound(oMeldshaper, nChakra) && GetMaxBindCount(oMeldshaper, nClass))
+	{
+		//FloatingTextStringOnCreature("BindMeldToChakra: nMeld "+IntToString(nMeld)+" nChakra "+IntToString(nChakra), oMeldshaper);
+		SetLocalInt(oMeldshaper, "BoundMeld"+IntToString(nChakra), nMeld);
+		ShapeSoulmeld(oMeldshaper, nMeld);
+		int nSlot = ChakraToSlot(DoubleChakraToChakra(nChakra)); // Can't have an item in a bound slot, unless Split Chakra
+		if (!CheckSplitChakra(oMeldshaper, nSlot)) ForceUnequip(oMeldshaper, GetItemInSlot(nSlot, oMeldshaper), nSlot);
+	}
+}
+
+int GetTotalBoundMelds(object oMeldshaper)
+{
+	int i, nCount, nTest;
+    for (i = 0; i <= 22; i++)
+    {
+		nTest = GetLocalInt(oMeldshaper, "BoundMeld"+IntToString(i));
+		if (nTest) // If it's not blank
+			nCount++;	
+    }
+    if (DEBUG) DoDebug("GetTotalBoundMelds is "+IntToString(nCount));
+    return nCount;
+}
+
+int GetIsChakraUsed(object oMeldshaper, int nChakra, int nClass)
+{
+	int nTest = GetLocalInt(oMeldshaper, "UsedMeld"+IntToString(nClass)+IntToString(nChakra));
+	
+    if (DEBUG) DoDebug("GetIsChakraUsed is "+IntToString(nTest));
+    return nTest;
+}
+
+void SetChakraUsed(object oMeldshaper, int nMeld, int nChakra, int nClass)
+{
+	// This isn't the same as binding, but can only have one soulmeld in each chakra
+	// Each class has its own limit on this, as per p20 of MoI
+	if (!GetIsChakraUsed(oMeldshaper, nChakra, nClass))
+	{
+		SetLocalInt(oMeldshaper, "UsedMeld"+IntToString(nClass)+IntToString(nChakra), nMeld);
+	}
+}
+
+int ChakraToSlot(int nChakra)
+{
+	if (nChakra == CHAKRA_CROWN    ) return INVENTORY_SLOT_HEAD;	
+	if (nChakra == CHAKRA_FEET     ) return INVENTORY_SLOT_BOOTS;
+	if (nChakra == CHAKRA_HANDS    ) return INVENTORY_SLOT_ARMS;
+	if (nChakra == CHAKRA_ARMS     ) return INVENTORY_SLOT_ARMS;
+	if (nChakra == CHAKRA_BROW     ) return INVENTORY_SLOT_HEAD;
+	if (nChakra == CHAKRA_SHOULDERS) return INVENTORY_SLOT_CLOAK;
+	if (nChakra == CHAKRA_THROAT   ) return INVENTORY_SLOT_NECK;
+	if (nChakra == CHAKRA_WAIST    ) return INVENTORY_SLOT_BELT;
+	if (nChakra == CHAKRA_HEART    ) return INVENTORY_SLOT_CHEST;	
+	if (nChakra == CHAKRA_SOUL     ) return INVENTORY_SLOT_CHEST;
+	if (nChakra == CHAKRA_TOTEM    ) return -1; // no slot associated
+	
+	return -1;
+}	
+
+void ChakraBindUnequip(object oMeldshaper, object oItem)
+{    
+    int nTest = FALSE;
+    if (GetItemInSlot(INVENTORY_SLOT_HEAD, oMeldshaper) == oItem && (GetIsChakraBound(oMeldshaper, CHAKRA_CROWN) || GetIsChakraBound(oMeldshaper, CHAKRA_BROW))) nTest = INVENTORY_SLOT_HEAD + 1;
+    else if (GetItemInSlot(INVENTORY_SLOT_BOOTS, oMeldshaper) == oItem && GetIsChakraBound(oMeldshaper, CHAKRA_FEET)) nTest = INVENTORY_SLOT_BOOTS + 1;
+    else if (GetItemInSlot(INVENTORY_SLOT_ARMS, oMeldshaper) == oItem && (GetIsChakraBound(oMeldshaper, CHAKRA_ARMS) || GetIsChakraBound(oMeldshaper, CHAKRA_HANDS))) nTest = INVENTORY_SLOT_ARMS + 1;
+    else if (GetItemInSlot(INVENTORY_SLOT_CLOAK, oMeldshaper) == oItem && GetIsChakraBound(oMeldshaper, CHAKRA_SHOULDERS)) nTest = INVENTORY_SLOT_CLOAK + 1;
+    else if (GetItemInSlot(INVENTORY_SLOT_NECK, oMeldshaper) == oItem && GetIsChakraBound(oMeldshaper, CHAKRA_THROAT)) nTest = INVENTORY_SLOT_NECK + 1;
+    else if (GetItemInSlot(INVENTORY_SLOT_BELT, oMeldshaper) == oItem && GetIsChakraBound(oMeldshaper, CHAKRA_WAIST)) nTest = INVENTORY_SLOT_BELT + 1;
+    else if (GetItemInSlot(INVENTORY_SLOT_CHEST, oMeldshaper) == oItem && (GetIsChakraBound(oMeldshaper, CHAKRA_SOUL) || GetIsChakraBound(oMeldshaper, CHAKRA_HEART))) nTest = INVENTORY_SLOT_CHEST + 1;
+	if (DEBUG) DoDebug("ChakraBindUnequip is "+IntToString(nTest-1));
+	if (nTest && !CheckSplitChakra(oMeldshaper, nTest-1) && GetIsItemPropertyValid(GetFirstItemProperty(oItem)) && oItem != GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oMeldshaper) && oItem != GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oMeldshaper) &&
+		   oItem != GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oMeldshaper) && oItem != GetItemInSlot(INVENTORY_SLOT_CARMOUR, oMeldshaper)) // If it's bound you can't equip in that slot
+	{
+		nTest = nTest - 1;
+		ForceUnequip(oMeldshaper, GetItemInSlot(nTest, oMeldshaper), nTest);
+		FloatingTextStringOnCreature("You cannot equip a magical item when you have bound a meld to the same chakra!", oMeldshaper, FALSE);
+	}
+}
+
+string ChakraToString(int nChakra)
+{
+	string sReturn = "";
+	if (nChakra == CHAKRA_CROWN     || nChakra == CHAKRA_DOUBLE_CROWN    ) sReturn = "Crown";	
+	if (nChakra == CHAKRA_FEET      || nChakra == CHAKRA_DOUBLE_FEET     ) sReturn = "Feet";
+	if (nChakra == CHAKRA_HANDS     || nChakra == CHAKRA_DOUBLE_HANDS    ) sReturn = "Hands";
+	if (nChakra == CHAKRA_ARMS      || nChakra == CHAKRA_DOUBLE_ARMS     ) sReturn = "Arms";
+	if (nChakra == CHAKRA_BROW      || nChakra == CHAKRA_DOUBLE_BROW     ) sReturn = "Brow";
+	if (nChakra == CHAKRA_SHOULDERS || nChakra == CHAKRA_DOUBLE_SHOULDERS) sReturn = "Shoulders";
+	if (nChakra == CHAKRA_THROAT    || nChakra == CHAKRA_DOUBLE_THROAT   ) sReturn = "Throat";
+	if (nChakra == CHAKRA_WAIST     || nChakra == CHAKRA_DOUBLE_WAIST    ) sReturn = "Waist";
+	if (nChakra == CHAKRA_HEART     || nChakra == CHAKRA_DOUBLE_HEART    ) sReturn = "Heart";	
+	if (nChakra == CHAKRA_SOUL      || nChakra == CHAKRA_DOUBLE_SOUL     ) sReturn = "Soul";
+	if (nChakra == CHAKRA_TOTEM     || nChakra == CHAKRA_DOUBLE_TOTEM    ) sReturn = "Totem";
+	
+	if (DEBUG) DoDebug("ChakraToString is "+IntToString(nChakra)+", Return is "+sReturn);
+	return sReturn;
+}
+
+int GetCanBindChakra(object oMeldshaper, int nChakra)
+{
+	if (nChakra == CHAKRA_CROWN &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 2)) return TRUE;
+	else if (nChakra == CHAKRA_FEET &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 4)) return TRUE;	
+	else if (nChakra == CHAKRA_HANDS &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 4)) return TRUE;
+	else if (nChakra == CHAKRA_ARMS &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 9)) return TRUE;	
+	else if (nChakra == CHAKRA_BROW &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 9)) return TRUE;	
+	else if (nChakra == CHAKRA_SHOULDERS &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 9)) return TRUE;	
+	else if (nChakra == CHAKRA_THROAT &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 14)) return TRUE;	
+	else if (nChakra == CHAKRA_WAIST &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 14)) return TRUE;	
+	else if (nChakra == CHAKRA_HEART &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 16)) return TRUE;	
+	else if (nChakra == CHAKRA_SOUL &&
+	   (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper) >= 19)) return TRUE;	
+	   
+	if (nChakra == CHAKRA_CROWN &&
+	   (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) >= 8)) return TRUE;
+	else if (nChakra == CHAKRA_FEET &&
+	   (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) >= 8)) return TRUE;	
+	else if (nChakra == CHAKRA_HANDS &&
+	   (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) >= 8)) return TRUE;
+	else if (nChakra == CHAKRA_ARMS &&
+	   (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) >= 14)) return TRUE;	
+	else if (nChakra == CHAKRA_BROW &&
+	   (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) >= 14)) return TRUE;	
+	else if (nChakra == CHAKRA_SHOULDERS &&
+	   (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) >= 14)) return TRUE;	
+	else if (nChakra == CHAKRA_THROAT &&
+	   (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) >= 18)) return TRUE;	
+	else if (nChakra == CHAKRA_WAIST &&
+	   (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper) >= 18)) return TRUE;	 
+	   
+	if (nChakra == CHAKRA_CROWN &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 5)) return TRUE;
+	else if (nChakra == CHAKRA_FEET &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 5)) return TRUE;	
+	else if (nChakra == CHAKRA_HANDS &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 5)) return TRUE;
+	else if (nChakra == CHAKRA_ARMS &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 9)) return TRUE;	
+	else if (nChakra == CHAKRA_BROW &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 9)) return TRUE;	
+	else if (nChakra == CHAKRA_SHOULDERS &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 9)) return TRUE;	
+	else if (nChakra == CHAKRA_THROAT &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 14)) return TRUE;	
+	else if (nChakra == CHAKRA_WAIST &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 14)) return TRUE;	
+	else if (nChakra == CHAKRA_HEART &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 17)) return TRUE;	
+	else if (nChakra == CHAKRA_TOTEM &&
+	   (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper) >= 2)) return TRUE;	
+	   
+	if (nChakra == CHAKRA_ARMS &&
+	   (GetLevelByClass(CLASS_TYPE_SPINEMELD_WARRIOR, oMeldshaper) >= 7)) return TRUE;	
+	   
+	if (nChakra == CHAKRA_CROWN &&
+	   (GetLevelByClass(CLASS_TYPE_SOULCASTER, oMeldshaper) >= 3)) return TRUE;
+	else if (nChakra == CHAKRA_FEET &&
+	   (GetLevelByClass(CLASS_TYPE_SOULCASTER, oMeldshaper) >= 3)) return TRUE;	
+	else if (nChakra == CHAKRA_HANDS &&
+	   (GetLevelByClass(CLASS_TYPE_SOULCASTER, oMeldshaper) >= 3)) return TRUE;	   
+	else if (nChakra == CHAKRA_ARMS &&
+	   (GetLevelByClass(CLASS_TYPE_SOULCASTER, oMeldshaper) >= 8)) return TRUE;	
+	else if (nChakra == CHAKRA_BROW &&
+	   (GetLevelByClass(CLASS_TYPE_SOULCASTER, oMeldshaper) >= 8)) return TRUE;	
+	else if (nChakra == CHAKRA_SHOULDERS &&
+	   (GetLevelByClass(CLASS_TYPE_SOULCASTER, oMeldshaper) >= 8)) return TRUE;	
+
+	if (nChakra == CHAKRA_ARMS &&
+	   (GetLevelByClass(CLASS_TYPE_IRONSOUL_FORGEMASTER, oMeldshaper) >= 4)) return TRUE;
+	else if (nChakra == CHAKRA_WAIST &&
+	   (GetLevelByClass(CLASS_TYPE_IRONSOUL_FORGEMASTER, oMeldshaper) >= 6)) return TRUE;	
+	else if (nChakra == CHAKRA_SHOULDERS &&
+	   (GetLevelByClass(CLASS_TYPE_IRONSOUL_FORGEMASTER, oMeldshaper) >= 8)) return TRUE;	   
+	else if (nChakra == CHAKRA_HEART &&
+	   (GetLevelByClass(CLASS_TYPE_IRONSOUL_FORGEMASTER, oMeldshaper) >= 10)) return TRUE;	
+	   
+	if (nChakra == CHAKRA_CROWN &&
+		(GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper) >=4)) return TRUE;
+	else if (nChakra == CHAKRA_FEET &&
+		(GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper) >=4)) return TRUE;   
+	else if (nChakra == CHAKRA_HANDS &&
+		(GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper) >=4)) return TRUE;	
+	else if (nChakra == CHAKRA_ARMS &&
+		(GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper) >=9)) return TRUE;
+	else if (nChakra == CHAKRA_BROW &&
+		(GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper) >=9)) return TRUE;
+	else if (nChakra == CHAKRA_SHOULDERS &&
+		(GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper) >=9)) return TRUE;
+		
+	if (nChakra == CHAKRA_ARMS &&
+	   (GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper) >= 3)) return TRUE;	
+	else if (nChakra == CHAKRA_BROW &&
+	   (GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper) >= 3)) return TRUE;	
+	else if (nChakra == CHAKRA_SHOULDERS &&
+	   (GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper) >= 3)) return TRUE;	
+	else if (nChakra == CHAKRA_THROAT &&
+	   (GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper) >= 8)) return TRUE;	
+	else if (nChakra == CHAKRA_WAIST &&
+	   (GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper) >= 8)) return TRUE;	
+	else if (nChakra == CHAKRA_HEART &&
+	   (GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper) >= 11)) return TRUE;	
+	else if (nChakra == CHAKRA_SOUL &&
+	   (GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper) >= 13)) return TRUE;	
+	   
+	if (nChakra == CHAKRA_CROWN && GetHasFeat(FEAT_OPEN_LEAST_CHAKRA_CROWN, oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_FEET      && GetHasFeat(FEAT_OPEN_LEAST_CHAKRA_FEET      , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_HANDS     && GetHasFeat(FEAT_OPEN_LEAST_CHAKRA_HANDS     , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_ARMS      && GetHasFeat(FEAT_OPEN_LESSER_CHAKRA_ARMS     , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_BROW      && GetHasFeat(FEAT_OPEN_LESSER_CHAKRA_BROW     , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_SHOULDERS && GetHasFeat(FEAT_OPEN_LESSER_CHAKRA_SHOULDERS, oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_THROAT    && GetHasFeat(FEAT_OPEN_GREATER_CHAKRA_THROAT  , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_WAIST     && GetHasFeat(FEAT_OPEN_GREATER_CHAKRA_WAIST   , oMeldshaper)) return TRUE; 
+	else if (nChakra == CHAKRA_HEART     && GetHasFeat(FEAT_OPEN_HEART_CHAKRA           , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_SOUL      && GetHasFeat(FEAT_OPEN_SOUL_CHAKRA            , oMeldshaper)) return TRUE;
+	
+	if (nChakra == CHAKRA_DOUBLE_CROWN && GetHasFeat(FEAT_DOUBLE_CHAKRA_CROWN, oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_FEET      && GetHasFeat(FEAT_DOUBLE_CHAKRA_FEET     , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_HANDS     && GetHasFeat(FEAT_DOUBLE_CHAKRA_HANDS    , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_ARMS      && GetHasFeat(FEAT_DOUBLE_CHAKRA_ARMS     , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_BROW      && GetHasFeat(FEAT_DOUBLE_CHAKRA_BROW     , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_SHOULDERS && GetHasFeat(FEAT_DOUBLE_CHAKRA_SHOULDERS, oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_THROAT    && GetHasFeat(FEAT_DOUBLE_CHAKRA_THROAT   , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_WAIST     && GetHasFeat(FEAT_DOUBLE_CHAKRA_WAIST    , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_HEART     && GetHasFeat(FEAT_DOUBLE_CHAKRA_HEART    , oMeldshaper)) return TRUE;
+	else if (nChakra == CHAKRA_DOUBLE_SOUL      && GetHasFeat(FEAT_DOUBLE_CHAKRA_SOUL     , oMeldshaper)) return TRUE;	
+	else if (nChakra == CHAKRA_DOUBLE_TOTEM     && GetHasFeat(FEAT_DOUBLE_CHAKRA_TOTEM    , oMeldshaper)) return TRUE;
+	       
+	return FALSE;   
+}
+
+int GetMaxEssentiaCount(object oMeldshaper, int nClass)
+{
+	int nMax = StringToInt(Get2DACache(GetMeldshapingClassFile(nClass), "Essentia", GetIncarnumLevelForClass(nClass, oMeldshaper)-1));
+    if (DEBUG) DoDebug("GetMaxEssentiaCount is "+IntToString(nMax));
+    return nMax;
+}
+
+void SpawnTempEssentiaChecker(object oMeldshaper)
+{
+	int nCur = GetTemporaryEssentia(oMeldshaper);
+	int nPrv = GetLocalInt(oMeldshaper, "TempEssTest");
+	int nRed = nPrv - nCur;
+	// If we've lost some
+	if (nPrv > nCur)
+	{
+		int i, nCount, nTest;
+    	for (i = 18700; i < 18799; i++)
+    	{
+			nTest = GetLocalInt(oMeldshaper, "TempEssentiaAmount"+IntToString(i));
+			if (nTest) // If it's not blank
+			{
+				if (DEBUG) DoDebug("Found "+IntToString(nTest)+" Temp Essentia in Meld "+IntToString(i));
+				// There's still some temp essentia left in the meld
+				if (nTest > nRed)
+				{
+					int nChange = nTest-nRed;
+					SetLocalInt(oMeldshaper, "TempEssentiaAmount"+IntToString(i), nChange);
+					SetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(i), GetEssentiaInvested(oMeldshaper, i)-nChange);
+					ShapeSoulmeld(oMeldshaper, i);
+					if (DEBUG) DoDebug("Reducing Essentia in Meld "+IntToString(i)+" by "+IntToString(nChange));
+				}
+				else // Means the reduction is higher than the temp essentia ammount
+				{
+					// No more temp essentia here
+					DeleteLocalInt(oMeldshaper, "TempEssentiaAmount"+IntToString(i));
+					SetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(i), GetEssentiaInvested(oMeldshaper, i)-nTest);
+					ShapeSoulmeld(oMeldshaper, i);
+					if (DEBUG) DoDebug("Deleted Temp Essentia in Meld "+IntToString(i)+", total "+IntToString(nTest));
+				}
+				
+				// Reduce the remaining amount of reduction by the amount we just used up
+				nRed = nRed - nTest;
+				if (DEBUG) DoDebug("Remaining Temp Essentia to reduce "+IntToString(nRed));
+				if (0 >= nRed) break; // End the loop if we're done
+			}	
+    	}	
+	}
+	// If we still have some left
+	if (nCur > 0) 
+	{
+		SetLocalInt(oMeldshaper, "TempEssTest", nCur);
+		DelayCommand(1.0, SpawnTempEssentiaChecker(oMeldshaper));
+	}
+	else 
+		DeleteLocalInt(oMeldshaper, "TempEssTest");
+}
+
+void InvestEssentia(object oMeldshaper, int nMeld, int nEssentia)
+{
+	// Use up expanded soulmeld capacity
+	if (nEssentia > 1000) 
+	{
+		nEssentia -= 1000;
+		SetIsSoulmeldCapacityUsed(oMeldshaper, nMeld);
+	}
+	int nClass = GetMeldShapedClass(oMeldshaper, nMeld);
+	// Special capacity of 1/2 class level
+	if (nMeld == MELD_SPINE_ENHANCEMENT) nEssentia = min(nEssentia, (GetLevelByClass(CLASS_TYPE_SPINEMELD_WARRIOR, oMeldshaper)/2));
+	else if (nEssentia > GetMaxEssentiaCapacity(oMeldshaper, nClass, nMeld)) nEssentia = GetMaxEssentiaCapacity(oMeldshaper, nClass, nMeld);
+	// Can't invest more than you have
+	if (nEssentia > GetTotalUsableEssentia(oMeldshaper)) nEssentia = GetTotalUsableEssentia(oMeldshaper);
+	
+	// All of this garbage to handle temporary essentia
+	if (GetLocalInt(oMeldshaper, "InvestingTempEssentia"))
+	{
+		SetLocalInt(oMeldshaper, "TempEssentiaAmount"+IntToString(nMeld), nEssentia);
+		SpawnTempEssentiaChecker(oMeldshaper);
+		DeleteLocalInt(oMeldshaper, "InvestingTempEssentia");
+	}
+	
+	FloatingTextStringOnCreature("Investing "+IntToString(nEssentia)+" essentia into "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nMeld))), oMeldshaper, FALSE);
+	SetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(nMeld), nEssentia);
+	SetLocalInt(oMeldshaper, "EssentiaRound"+IntToString(nMeld), TRUE); // This is used by Melds that only trigger on the round that essentia is invested into it
+	DelayCommand(6.0, DeleteLocalInt(oMeldshaper, "EssentiaRound"+IntToString(nMeld)));
+}
+
+int GetTotalEssentiaInvested(object oMeldshaper)
+{
+	int i, nCount, nTest;
+    for (i = 18700; i < 18799; i++)
+    {
+		nTest = GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(i));
+		if (nTest) // If it's not blank
+			nCount += nTest;	
+    }
+    nCount += GetFeatLockedEssentia(oMeldshaper);
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_SPINE_ENHANCEMENT)); // MELD_SPINE_ENHANCEMENT
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_IRONSOUL_SHIELD)); // MELD_IRONSOUL_SHIELD
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_IRONSOUL_ARMOR)); // MELD_IRONSOUL_ARMOR
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_IRONSOUL_WEAPON)); // MELD_IRONSOUL_WEAPON
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_STEP  )); // MELD_UMBRAL_STEP  
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_SHADOW)); // MELD_UMBRAL_SHADOW
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_SIGHT )); // MELD_UMBRAL_SIGHT 
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_SOUL  )); // MELD_UMBRAL_SOUL  
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_KISS  )); // MELD_UMBRAL_KISS  
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_DUSKLING_SPEED)); // MELD_DUSKLING_SPEED
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_STRIKE)); // MELD_INCANDESCENT_STRIKE
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_HEAL       )); // MELD_INCANDESCENT_HEAL       
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_COUNTENANCE)); // MELD_INCANDESCENT_COUNTENANCE
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_RAY        )); // MELD_INCANDESCENT_RAY        
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_AURA       )); // MELD_INCANDESCENT_AURA       
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_MELDSHIELD)); // MELD_WITCH_MELDSHIELD
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_DISPEL    )); // MELD_WITCH_DISPEL    
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_SHACKLES  )); // MELD_WITCH_SHACKLES  
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_ABROGATION)); // MELD_WITCH_ABROGATION
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_SPIRITFLAY)); // MELD_WITCH_SPIRITFLAY
+    nCount += GetLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_INTEGUMENT)); // MELD_WITCH_INTEGUMENT   
+    if (DEBUG) DoDebug("GetTotalEssentiaInvested is "+IntToString(nCount));
+    return nCount;
+}
+
+int EssentiaIDToRealID(int nEssentiaID)
+{
+	int i, nReal, nTest;
+    for (i = 1; i < 100; i++)
+    {
+		nTest = StringToInt(Get2DACache("soulmelds", "EssentiaID", i));
+		if (nTest == nEssentiaID) // If it's been found
+		{
+			nReal = StringToInt(Get2DACache("soulmelds", "SpellID", i));	
+			break;
+		}	
+    }
+    
+    if (nEssentiaID == 18690) nReal = MELD_SPINE_ENHANCEMENT;
+    else if (nEssentiaID == 18686) nReal = MELD_IRONSOUL_SHIELD;
+    else if (nEssentiaID == 18684) nReal = MELD_IRONSOUL_ARMOR;
+    else if (nEssentiaID == 18682) nReal = MELD_IRONSOUL_WEAPON;
+    else if (nEssentiaID == 18680) nReal = MELD_UMBRAL_STEP;
+    else if (nEssentiaID == 18678) nReal = MELD_UMBRAL_SHADOW;
+    else if (nEssentiaID == 18676) nReal = MELD_UMBRAL_SIGHT;
+    else if (nEssentiaID == 18674) nReal = MELD_UMBRAL_SOUL;
+    else if (nEssentiaID == 18672) nReal = MELD_UMBRAL_KISS;
+    else if (nEssentiaID == 18669) nReal = MELD_INCANDESCENT_STRIKE;
+    else if (nEssentiaID == 18667) nReal = MELD_INCANDESCENT_HEAL       ;
+    else if (nEssentiaID == 18665) nReal = MELD_INCANDESCENT_COUNTENANCE;
+    else if (nEssentiaID == 18662) nReal = MELD_INCANDESCENT_RAY        ;
+    else if (nEssentiaID == 18661) nReal = MELD_INCANDESCENT_AURA       ;
+    else if (nEssentiaID == 18633) nReal = MELD_WITCH_MELDSHIELD;
+    else if (nEssentiaID == 18635) nReal = MELD_WITCH_DISPEL;    
+    else if (nEssentiaID == 18637) nReal = MELD_WITCH_SHACKLES;
+    else if (nEssentiaID == 18639) nReal = MELD_WITCH_ABROGATION;
+    else if (nEssentiaID == 18641) nReal = MELD_WITCH_SPIRITFLAY;
+    else if (nEssentiaID == 18643) nReal = MELD_WITCH_INTEGUMENT;    
+    
+    if (DEBUG) DoDebug("EssentiaToRealID: nEssentiaID "+IntToString(nEssentiaID)+" nReal "+IntToString(nReal));
+    return nReal; // Return the real spellID
+}
+
+void DrainEssentia(object oMeldshaper)
+{
+	//FloatingTextStringOnCreature("DrainEssentia", oMeldshaper);
+	int i;
+    for (i = 18700; i < 18799; i++)
+    {
+		DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(i));
+    }  
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_DUSKLING_SPEED));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_SPINE_ENHANCEMENT));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_IRONSOUL_SHIELD));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_IRONSOUL_ARMOR));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_IRONSOUL_WEAPON));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_STEP  ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_SHADOW));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_SIGHT ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_SOUL  ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_UMBRAL_KISS  ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_STRIKE));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_HEAL       ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_COUNTENANCE));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_RAY        ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_INCANDESCENT_AURA       ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_MELDSHIELD));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_DISPEL    ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_SHACKLES  ));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_ABROGATION));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_SPIRITFLAY));
+    DeleteLocalInt(oMeldshaper, "MeldEssentia"+IntToString(MELD_WITCH_INTEGUMENT));    
+}
+
+void WipeMelds(object oMeldshaper)
+{
+	//FloatingTextStringOnCreature("WipeMelds", oMeldshaper);
+	int i;
+    for (i = 18700; i < 18799; i++)
+    {
+		PRCRemoveSpellEffects(i, oMeldshaper, oMeldshaper);
+		GZPRCRemoveSpellEffects(i, oMeldshaper, FALSE);
+    }
+    PRCRemoveSpellEffects(MELD_DUSKLING_SPEED, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_DUSKLING_SPEED, oMeldshaper, FALSE);
+    PRCRemoveSpellEffects(MELD_SPINE_ENHANCEMENT, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_SPINE_ENHANCEMENT, oMeldshaper, FALSE);    
+    PRCRemoveSpellEffects(MELD_IRONSOUL_SHIELD, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_IRONSOUL_SHIELD, oMeldshaper, FALSE);  
+    PRCRemoveSpellEffects(MELD_IRONSOUL_ARMOR, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_IRONSOUL_ARMOR, oMeldshaper, FALSE);  
+    PRCRemoveSpellEffects(MELD_IRONSOUL_WEAPON, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_IRONSOUL_WEAPON, oMeldshaper, FALSE);          
+    PRCRemoveSpellEffects(MELD_UMBRAL_STEP, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_UMBRAL_STEP, oMeldshaper, FALSE);      
+    PRCRemoveSpellEffects(MELD_UMBRAL_SHADOW, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_UMBRAL_SHADOW, oMeldshaper, FALSE);      
+    PRCRemoveSpellEffects(MELD_UMBRAL_SIGHT, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_UMBRAL_SIGHT, oMeldshaper, FALSE);      
+    PRCRemoveSpellEffects(MELD_UMBRAL_SOUL, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_UMBRAL_SOUL, oMeldshaper, FALSE);      
+    PRCRemoveSpellEffects(MELD_UMBRAL_KISS, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_UMBRAL_KISS, oMeldshaper, FALSE);          
+    PRCRemoveSpellEffects(MELD_INCANDESCENT_STRIKE, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_INCANDESCENT_STRIKE, oMeldshaper, FALSE); 
+    PRCRemoveSpellEffects(MELD_WITCH_MELDSHIELD, oMeldshaper, oMeldshaper);
+    GZPRCRemoveSpellEffects(MELD_WITCH_MELDSHIELD, oMeldshaper, FALSE);     
+    for (i = 18647; i < 18657; i++)
+    {
+		PRCRemoveSpellEffects(i, oMeldshaper, oMeldshaper);
+		GZPRCRemoveSpellEffects(i, oMeldshaper, FALSE);
+    }    
+}
+
+void ReshapeMelds(object oMeldshaper)
+{
+	// Check each class and run the loop
+	if (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper))
+	{
+		int i, nTest;
+    	for (i = 0; i <= 20; i++)
+    	{
+			nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_INCARNATE)+IntToString(i));
+			if (nTest) // If it's not blank, recast it
+			{
+				//FloatingTextStringOnCreature("ReshapeMelds: CLASS_TYPE_INCARNATE nTest "+IntToString(nTest), oMeldshaper);
+				ActionCastSpellOnSelf(nTest);
+			}	
+    	}
+    }
+	if (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper))
+	{
+		int i, nTest;
+    	for (i = 0; i <= 20; i++)
+    	{
+			nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_SOULBORN)+IntToString(i));
+			if (nTest) // If it's not blank, recast it
+			{
+				//FloatingTextStringOnCreature("ReshapeMelds: CLASS_TYPE_SOULBORN nTest "+IntToString(nTest), oMeldshaper);
+				ActionCastSpellOnSelf(nTest);
+			}	
+    	}
+    }
+	if (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper))
+	{
+		int i, nTest;
+    	for (i = 0; i <= 20; i++)
+    	{
+			nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_TOTEMIST)+IntToString(i));
+			if (nTest) // If it's not blank, recast it
+			{
+				//FloatingTextStringOnCreature("ReshapeMelds: CLASS_TYPE_TOTEMIST nTest "+IntToString(nTest), oMeldshaper);
+				ActionCastSpellOnSelf(nTest);
+			}	
+    	}
+    }    
+	if (GetLevelByClass(CLASS_TYPE_SPINEMELD_WARRIOR, oMeldshaper))
+	{
+		ActionCastSpellOnSelf(MELD_SPINE_ENHANCEMENT);
+		int i, nTest;
+    	for (i = 0; i <= 20; i++)
+    	{
+			nTest = GetLocalInt(oMeldshaper, "ShapedMeld"+IntToString(CLASS_TYPE_SPINEMELD_WARRIOR)+IntToString(i));
+			if (nTest) // If it's not blank, recast it
+			{
+				//FloatingTextStringOnCreature("ReshapeMelds: CLASS_TYPE_TOTEMIST nTest "+IntToString(nTest), oMeldshaper);
+				ActionCastSpellOnSelf(nTest);
+			}	
+    	}
+    }     
+    int nIron = GetLevelByClass(CLASS_TYPE_IRONSOUL_FORGEMASTER, oMeldshaper);
+	if (nIron)
+	{
+		ActionCastSpellOnSelf(MELD_IRONSOUL_SHIELD);
+		if (nIron >= 5) ActionCastSpellOnSelf(MELD_IRONSOUL_ARMOR);
+		if (nIron >= 9) ActionCastSpellOnSelf(MELD_IRONSOUL_WEAPON);		
+	}
+    int nUmbral = GetLevelByClass(CLASS_TYPE_UMBRAL_DISCIPLE, oMeldshaper);
+	if (nUmbral)
+	{
+		ActionCastSpellOnSelf(MELD_UMBRAL_STEP);
+		if (nUmbral >= 3) ActionCastSpellOnSelf(MELD_UMBRAL_SHADOW);
+		if (nUmbral >= 7) ActionCastSpellOnSelf(MELD_UMBRAL_SIGHT);		
+		if (nUmbral >= 9) ActionCastSpellOnSelf(MELD_UMBRAL_SOUL);
+		if (nUmbral >= 10) ActionCastSpellOnSelf(MELD_UMBRAL_KISS);
+	}	
+    int nIncand = GetLevelByClass(CLASS_TYPE_INCANDESCENT_CHAMPION, oMeldshaper);
+	if (nIncand)
+	{
+		ActionCastSpellOnSelf(MELD_INCANDESCENT_STRIKE);
+	}	
+	if(GetLevelByClass(CLASS_TYPE_WITCHBORN_BINDER, oMeldshaper)) ActionCastSpellOnSelf(MELD_WITCH_MELDSHIELD);
+    if (GetRacialType(oMeldshaper) == RACIAL_TYPE_DUSKLING) ActionCastSpellOnSelf(MELD_DUSKLING_SPEED);
+}
+
+int EssentiaToD4(int nEssentia)
+{
+	if (nEssentia == 1    )   return IP_CONST_DAMAGEBONUS_1d4;	
+	else if (nEssentia == 2)  return IP_CONST_DAMAGEBONUS_2d4;
+	else if (nEssentia == 3)  return IP_CONST_DAMAGEBONUS_3d4;
+	else if (nEssentia == 4)  return IP_CONST_DAMAGEBONUS_4d4;
+	else if (nEssentia == 5)  return IP_CONST_DAMAGEBONUS_5d4;
+	else if (nEssentia == 6)  return IP_CONST_DAMAGEBONUS_6d4;
+	else if (nEssentia == 7)  return IP_CONST_DAMAGEBONUS_7d4;
+	else if (nEssentia == 8)  return IP_CONST_DAMAGEBONUS_8d4;
+	else if (nEssentia == 9)  return IP_CONST_DAMAGEBONUS_9d4;	
+	else if (nEssentia >= 10) return IP_CONST_DAMAGEBONUS_10d4;
+	
+	return -1;
+}
+
+int IncarnateAlignment(object oMeldshaper)
+{
+	int nReturn = FALSE;
+	
+	if (GetAlignmentLawChaos(oMeldshaper) == ALIGNMENT_LAWFUL && GetAlignmentGoodEvil(oMeldshaper) == ALIGNMENT_NEUTRAL)
+	{
+		nReturn = TRUE;
+	}
+	else if (GetAlignmentLawChaos(oMeldshaper) == ALIGNMENT_CHAOTIC && GetAlignmentGoodEvil(oMeldshaper) == ALIGNMENT_NEUTRAL)
+	{
+		nReturn = TRUE;
+	}	
+	else if (GetAlignmentLawChaos(oMeldshaper) == ALIGNMENT_NEUTRAL && GetAlignmentGoodEvil(oMeldshaper) == ALIGNMENT_GOOD)
+	{
+		nReturn = TRUE;
+	}
+	else if (GetAlignmentLawChaos(oMeldshaper) == ALIGNMENT_NEUTRAL && GetAlignmentGoodEvil(oMeldshaper) == ALIGNMENT_EVIL)
+	{
+		nReturn = TRUE;
+	}
+	
+	return nReturn;
+}
+
+int GetOpposition(object oMeldshaper, object oTarget)
+{
+	int nReturn = FALSE;
+	if (GetAlignmentLawChaos(oMeldshaper) == ALIGNMENT_LAWFUL && GetAlignmentGoodEvil(oMeldshaper) == ALIGNMENT_GOOD && (GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL || GetAlignmentLawChaos(oTarget) == ALIGNMENT_CHAOTIC))
+		nReturn = TRUE;
+	if (GetAlignmentLawChaos(oMeldshaper) == ALIGNMENT_LAWFUL && GetAlignmentGoodEvil(oMeldshaper) == ALIGNMENT_EVIL && (GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD || GetAlignmentLawChaos(oTarget) == ALIGNMENT_CHAOTIC))
+		nReturn = TRUE;
+	if (GetAlignmentLawChaos(oMeldshaper) == ALIGNMENT_CHAOTIC && GetAlignmentGoodEvil(oMeldshaper) == ALIGNMENT_GOOD && (GetAlignmentGoodEvil(oTarget) == ALIGNMENT_EVIL || GetAlignmentLawChaos(oTarget) == ALIGNMENT_LAWFUL))
+		nReturn = TRUE;
+	if (GetAlignmentLawChaos(oMeldshaper) == ALIGNMENT_CHAOTIC && GetAlignmentGoodEvil(oMeldshaper) == ALIGNMENT_EVIL && (GetAlignmentGoodEvil(oTarget) == ALIGNMENT_GOOD || GetAlignmentLawChaos(oTarget) == ALIGNMENT_LAWFUL))
+		nReturn = TRUE;	
+		
+	return nReturn;	
+}
+
+void SetTemporaryEssentia(object oMeldshaper, int nEssentia)
+{
+	if (DEBUG) DoDebug("Set Temporary Essentia from "+IntToString(GetLocalInt(oMeldshaper, "TemporaryEssentia"))+" to "+IntToString(GetLocalInt(oMeldshaper, "TemporaryEssentia")+nEssentia));
+	SetLocalInt(oMeldshaper, "TemporaryEssentia", GetLocalInt(oMeldshaper, "TemporaryEssentia")+nEssentia);
+}
+
+int GetTemporaryEssentia(object oMeldshaper)
+{
+	return GetLocalInt(oMeldshaper, "TemporaryEssentia");
+}
+
+int GetMaxEssentiaCapacityFeat(object oMeldshaper)
+{
+	int nMax = 1; // Always can invest one
+	int nHD = GetHitDice(oMeldshaper);
+	if (nHD >= 31) nMax = 5;
+	else if (nHD >= 18) nMax = 4;
+	else if (nHD >= 12) nMax = 3;
+	else if (nHD >= 6) nMax = 2;
+	
+	if (GetLocalInt(oMeldshaper, "DivineSoultouch")) nMax += 1;
+	if (GetLocalInt(oMeldshaper, "IncandescentOverload")) nMax += max(GetAbilityModifier(ABILITY_CHARISMA, oMeldshaper), 1);
+	if (GetHasFeat(FEAT_IMPROVED_ESSENTIA_CAPACITY, oMeldshaper)) nMax += 1;
+	
+	// Don't allow more than they have
+	if (nMax > GetTotalUsableEssentia(oMeldshaper)) nMax = GetTotalUsableEssentia(oMeldshaper);
+
+	if (DEBUG) DoDebug("GetMaxEssentiaCapacityFeat: nHD "+IntToString(nHD)+" nMax "+IntToString(nMax));
+	return nMax;
+}
+
+void SapphireSmiteUses(object oMeldshaper, int nEssentia)
+{
+	int i;
+
+    for (i = 1; i <= nEssentia; i++)
+    {
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_SMITE_GOOD_ALIGN); // Fist of Raziel
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_SMITE_EVIL); // Paladin
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_SMITE_GOOD); // Blackguard
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_KIAI_SMITE); // CW Samurai		
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_CRUSADER_SMITE); // Crusader
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_SMITE_UNDEAD); // Soldier of Light
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_SHADOWBANE_SMITE); // Shadowbane
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_KILLOREN_ASPECT_D); // Killoren
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_SMITE_OPPOSITION); // Soulborn
+		IncrementRemainingFeatUses(oMeldshaper, FEAT_CULTIST_SMITE_MAGE); // Cultist of the Shattered Peak
+    }
+}
+
+void AzureEnmity(object oMeldshaper, int nEssentia)
+{
+	effect eLink = EffectLinkEffects(EffectSkillIncrease(SKILL_BLUFF, nEssentia), EffectSkillIncrease(SKILL_LISTEN, nEssentia));
+	       eLink = EffectLinkEffects(eLink, EffectSkillIncrease(SKILL_SENSE_MOTIVE, nEssentia));
+	       eLink = EffectLinkEffects(eLink, EffectSkillIncrease(SKILL_SPOT, nEssentia));
+	       eLink = EffectLinkEffects(eLink, EffectDamageIncrease(IPGetDamageBonusConstantFromNumber(nEssentia), DAMAGE_TYPE_BASE_WEAPON));
+
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_ABERRATION, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_ABERRATION)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_ANIMAL, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_ANIMAL)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_BEAST, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_BEAST)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_CONSTRUCT, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_CONSTRUCT)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_DRAGON, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_DRAGON)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_DWARF, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_DWARF)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_ELEMENTAL, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_ELEMENTAL)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_ELF, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_ELF)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_FEY, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_FEY)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_GIANT, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_GIANT)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_GNOME, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_GNOME)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_GOBLINOID, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_HUMANOID_GOBLINOID)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_HALFELF, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_HALFELF)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_HALFLING, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_HALFLING)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_HALFORC, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_HALFORC)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_HUMAN, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_HUMAN)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_MAGICAL_BEAST, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_MAGICAL_BEAST)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_MONSTROUS, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_HUMANOID_MONSTROUS)), oMeldshaper, 9999.0);
+    if(GetHasFeat(RACIAL_TYPE_HUMANOID_ORC, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_HUMANOID_ORC)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_OUTSIDER, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_OUTSIDER)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_REPTILIAN, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_HUMANOID_REPTILIAN)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_SHAPECHANGER, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_SHAPECHANGER)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_UNDEAD, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_UNDEAD)), oMeldshaper, 9999.0);
+    if(GetHasFeat(FEAT_FAVORED_ENEMY_VERMIN, oMeldshaper))
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(VersusRacialTypeEffect(eLink, RACIAL_TYPE_VERMIN)), oMeldshaper, 9999.0);
+}
+
+void DoFeatBonus(object oMeldshaper, int nFeat, int nEssentia)
+{
+	effect eLink;
+	if (nFeat == FEAT_CERULEAN_FORTITUDE) eLink = EffectSavingThrowIncrease(SAVING_THROW_FORT, nEssentia);
+	else if (nFeat == FEAT_CERULEAN_REFLEXES) eLink = EffectSavingThrowIncrease(SAVING_THROW_REFLEX, nEssentia);
+	else if (nFeat == FEAT_CERULEAN_WILL) eLink = EffectSavingThrowIncrease(SAVING_THROW_WILL, nEssentia);
+	else if (nFeat == FEAT_AZURE_TALENT) ExecuteScript("moi_ft_aztalent", oMeldshaper);
+	else if (nFeat == FEAT_AZURE_TOUGHNESS) eLink = EffectTemporaryHitpoints(3*nEssentia);
+	else if (nFeat == FEAT_HEALING_SOUL) FeatUsePerDay(oMeldshaper, FEAT_HEALING_SOUL, -1, 0, nEssentia);
+	else if (nFeat == FEAT_SAPPHIRE_SMITE) SapphireSmiteUses(oMeldshaper, nEssentia);
+	else if (nFeat == FEAT_AZURE_ENMITY) AzureEnmity(oMeldshaper, nEssentia);
+	
+	ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(eLink), oMeldshaper, 9999.0);
+}
+
+void InvestEssentiaFeat(object oMeldshaper, int nFeat, int nEssentia)
+{
+	// Jump out if there's no feat
+	if (!GetHasFeat(nFeat, oMeldshaper)) return;
+	
+	int nMax = GetMaxEssentiaCapacityFeat(oMeldshaper);
+	
+	// Bonuses to specific feat caps
+	if (nFeat == FEAT_COBALT_RAGE && GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oMeldshaper)) nMax++;
+	
+	// No breaking the rules
+	if (nEssentia > nMax) nEssentia = nMax;
+	// Can't invest more than you have
+	if (nEssentia > GetTotalUsableEssentia(oMeldshaper)) nEssentia = GetTotalUsableEssentia(oMeldshaper);	
+	
+	FloatingTextStringOnCreature("Investing "+IntToString(nEssentia)+" essentia into "+GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeat))), oMeldshaper);
+	DoFeatBonus(oMeldshaper, nFeat, nEssentia);
+	SetLocalInt(oMeldshaper, "FeatEssentia"+IntToString(nFeat), nEssentia);
+}
+
+void DoClassBonus(object oMeldshaper, int nFeat, int nEssentia)
+{
+
+}
+
+void InvestEssentiaClass(object oMeldshaper, int nFeat, int nEssentia)
+{
+	// Jump out if there's no feat
+	if (!GetHasFeat(nFeat, oMeldshaper)) return;
+	
+	// No breaking the rules
+	if (nEssentia > GetMaxEssentiaCapacityFeat(oMeldshaper)) nEssentia = GetMaxEssentiaCapacityFeat(oMeldshaper);
+	// Can't invest more than you have
+	if (nEssentia > GetTotalUsableEssentia(oMeldshaper)) nEssentia = GetTotalUsableEssentia(oMeldshaper);	
+	
+	FloatingTextStringOnCreature("Investing "+IntToString(nEssentia)+" essentia into "+GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeat))), oMeldshaper);
+	DoClassBonus(oMeldshaper, nFeat, nEssentia);
+	SetLocalInt(oMeldshaper, "ClassEssentia"+IntToString(nFeat), nEssentia);
+}
+
+void InvestEssentiaSpell(object oMeldshaper, int nFeat, int nEssentia)
+{
+	FloatingTextStringOnCreature("Investing "+IntToString(nEssentia)+" essentia into "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nFeat))), oMeldshaper);
+	SetLocalInt(oMeldshaper, "SpellEssentia"+IntToString(nFeat), nEssentia);
+	if (!GetLocalInt(oMeldshaper, "SpellInvestCheck1")) SetLocalInt(oMeldshaper, "SpellInvestCheck1", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck2")) SetLocalInt(oMeldshaper, "SpellInvestCheck2", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck3")) SetLocalInt(oMeldshaper, "SpellInvestCheck3", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck4")) SetLocalInt(oMeldshaper, "SpellInvestCheck4", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck5")) SetLocalInt(oMeldshaper, "SpellInvestCheck5", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck6")) SetLocalInt(oMeldshaper, "SpellInvestCheck6", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck7")) SetLocalInt(oMeldshaper, "SpellInvestCheck7", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck8")) SetLocalInt(oMeldshaper, "SpellInvestCheck8", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck9")) SetLocalInt(oMeldshaper, "SpellInvestCheck9", nFeat);
+	else if (!GetLocalInt(oMeldshaper, "SpellInvestCheck10")) SetLocalInt(oMeldshaper, "SpellInvestCheck10", nFeat);
+}
+
+int GetFeatLockedEssentia(object oMeldshaper)
+{
+	int nTotal, i, nTest;
+    for (i = 8869; i < 8889; i++)
+    {
+		nTest = GetLocalInt(oMeldshaper, "FeatEssentia"+IntToString(i));
+		if (nTest) // If it's not blank
+			nTotal += nTest;	
+    } 
+    for (i = 0; i < 11; i++)
+    {
+		nTest = GetLocalInt(oMeldshaper, "SpellInvestCheck"+IntToString(i));
+		if (nTest) // If it's not blank
+			nTotal += GetLocalInt(oMeldshaper, "SpellEssentia"+IntToString(nTest));	
+    }     
+    if (DEBUG) DoDebug("GetFeatLockedEssentia return value "+IntToString(nTotal));
+    return nTotal;
+}
+
+int IncarnumFeats(object oMeldshaper)
+{
+	int nEssentia;
+	
+	if (GetHasFeat(FEAT_AZURE_ENMITY, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_CERULEAN_FORTITUDE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_CERULEAN_REFLEXES, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_CERULEAN_WILL, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_AZURE_TALENT, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_AZURE_TOUCH, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_AZURE_TOUGHNESS, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_AZURE_TURNING, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_AZURE_WILD_SHAPE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_COBALT_CHARGE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_COBALT_EXPERTISE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_COBALT_POWER, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_COBALT_RAGE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_HEALING_SOUL, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_INCARNUM_SPELLSHAPING, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_INDIGO_STRIKE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_MIDNIGHT_AUGMENTATION, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_MIDNIGHT_DODGE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_MIDNIGHT_METAMAGIC, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_PSYCARNUM_BLADE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_SAPPHIRE_SMITE, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_SOULTOUCHED_SPELLCASTING, oMeldshaper)) nEssentia += 1;
+	if (GetHasFeat(FEAT_BONUS_ESSENTIA, oMeldshaper)) 
+	{	
+		nEssentia += 1;
+		if(GetIsIncarnumUser(oMeldshaper))
+			nEssentia += 1; // Yes, this is correct
+	}		
+	if (GetRacialType(oMeldshaper) == RACIAL_TYPE_DUSKLING) nEssentia += 1;
+	if (GetRacialType(oMeldshaper) == RACIAL_TYPE_AZURIN) nEssentia += 1;
+
+   	int i;
+   	for(i = FEAT_EPIC_ESSENTIA_1; i <= FEAT_EPIC_ESSENTIA_6; i++)
+   	    if(GetHasFeat(i, oMeldshaper)) nEssentia += 3;
+	
+	if (DEBUG) DoDebug("IncarnumFeats return value "+IntToString(nEssentia));
+	return nEssentia;
+}
+
+void AddNecrocarnumEssentia(object oMeldshaper, int nEssentia)
+{
+	int nNecrocarnum = GetLocalInt(oMeldshaper, "NecrocarnumEssentia");
+	SetLocalInt(oMeldshaper, "NecrocarnumEssentia", nNecrocarnum+nEssentia);
+	// It lasts for 24 hours, then remove it back out
+	DelayCommand(HoursToSeconds(24), SetLocalInt(oMeldshaper, "NecrocarnumEssentia", GetLocalInt(oMeldshaper, "NecrocarnumEssentia")-nEssentia));
+}
+
+int GetTotalEssentia(object oMeldshaper)
+{
+	int nEssentia;
+	
+	if (GetLevelByClass(CLASS_TYPE_INCARNATE, oMeldshaper)) nEssentia += GetMaxEssentiaCount(oMeldshaper, CLASS_TYPE_INCARNATE);
+	if (GetLevelByClass(CLASS_TYPE_SOULBORN, oMeldshaper))  nEssentia += GetMaxEssentiaCount(oMeldshaper, CLASS_TYPE_SOULBORN);
+	if (GetLevelByClass(CLASS_TYPE_TOTEMIST, oMeldshaper))  nEssentia += GetMaxEssentiaCount(oMeldshaper, CLASS_TYPE_TOTEMIST);
+	if (GetLevelByClass(CLASS_TYPE_SPINEMELD_WARRIOR, oMeldshaper))  nEssentia += GetMaxEssentiaCount(oMeldshaper, CLASS_TYPE_SPINEMELD_WARRIOR);
+	if (GetLevelByClass(CLASS_TYPE_UMBRAL_DISCIPLE, oMeldshaper))  nEssentia += GetMaxEssentiaCount(oMeldshaper, CLASS_TYPE_UMBRAL_DISCIPLE);
+	if (GetLevelByClass(CLASS_TYPE_NECROCARNATE, oMeldshaper)) nEssentia += GetLocalInt(oMeldshaper, "NecrocarnumEssentia");
+	if (GetLevelByClass(CLASS_TYPE_WITCHBORN_BINDER, oMeldshaper) >= 2) nEssentia += 1;
+	if (GetLevelByClass(CLASS_TYPE_WITCHBORN_BINDER, oMeldshaper) >= 6) nEssentia += 1;
+	
+	nEssentia += IncarnumFeats(oMeldshaper);
+	if (DEBUG) DoDebug("GetTotalEssentia return value "+IntToString(nEssentia));
+	return nEssentia;
+}
+
+int GetTotalUsableEssentia(object oMeldshaper)
+{
+	return GetTotalEssentia(oMeldshaper) - GetFeatLockedEssentia(oMeldshaper);
+}
+
+int GetIncarnumFeats(object oMeldshaper)
+{
+	int nTotal, i;
+    for (i = 8868; i < 8910; i++)
+    {
+		if (GetHasFeat(i, oMeldshaper)) 
+			nTotal += 1;	
+    }  
+    if (DEBUG) DoDebug("GetIncarnumFeats return value "+IntToString(nTotal));
+    return nTotal;
+}
+
+int GetIsBlademeldUsed(object oMeldshaper, int nChakra)
+{
+	int nTest = GetLocalInt(oMeldshaper, "UsedBladeMeld"+IntToString(nChakra));
+	
+    if (DEBUG) DoDebug("GetIsBlademeldUsed is "+IntToString(nTest));
+    return nTest;
+}
+
+void SetBlademeldUsed(object oMeldshaper, int nChakra)
+{
+	if (!GetIsBlademeldUsed(oMeldshaper, nChakra))
+	{
+		SetLocalInt(oMeldshaper, "UsedBladeMeld"+IntToString(nChakra), nChakra);
+	}
+}
+
+string GetBlademeldDesc(int nChakra)
+{
+	string sString;
+	if (nChakra == CHAKRA_CROWN    ) sString = "You gain a +4 bonus on disarm checks and on Sense Motive";
+	if (nChakra == CHAKRA_FEET     ) sString = "You gain a +2 bonus on Initiative";
+	if (nChakra == CHAKRA_HANDS    ) sString = "You gain a +1 bonus on damage";
+	if (nChakra == CHAKRA_ARMS     ) sString = "You gain a +2 bonus on attack rolls";
+	if (nChakra == CHAKRA_BROW     ) sString = "You gain the Blind-Fight feat";
+	if (nChakra == CHAKRA_SHOULDERS) sString = "You gain immunity to criticals but not sneak attacks";
+	if (nChakra == CHAKRA_THROAT   ) sString = "At will as a standard action, each enemy within 60 feet who can hear you shout must save or become shaken for 1 round (Will DC 10 + incarnum blade level + Con modifier).";
+	if (nChakra == CHAKRA_WAIST    ) sString = "You gain a +10 bonus on checks made to avoid being bull rushed, grappled, tripped, or overrun. You also gain Uncanny Dodge";
+	if (nChakra == CHAKRA_HEART    ) sString = "You gain temporary hit points equal to twice your character level (maximum +40)";
+	if (nChakra == CHAKRA_SOUL     ) sString = "You break DR up to +3, and deal 1d6 damage to creatures of one opposed alignment";
+    
+	return sString;
+}
+
+int ChakraToBlademeld(int nChakra)
+{
+	int nMeld;
+	if (nChakra == CHAKRA_CROWN    ) nMeld = MELD_BLADEMELD_CROWN;    
+	if (nChakra == CHAKRA_FEET     ) nMeld = MELD_BLADEMELD_FEET;     
+	if (nChakra == CHAKRA_HANDS    ) nMeld = MELD_BLADEMELD_HANDS;    
+	if (nChakra == CHAKRA_ARMS     ) nMeld = MELD_BLADEMELD_ARMS;     
+	if (nChakra == CHAKRA_BROW     ) nMeld = MELD_BLADEMELD_BROW;     
+	if (nChakra == CHAKRA_SHOULDERS) nMeld = MELD_BLADEMELD_SHOULDERS;
+	if (nChakra == CHAKRA_THROAT   ) nMeld = MELD_BLADEMELD_THROAT;   
+	if (nChakra == CHAKRA_WAIST    ) nMeld = MELD_BLADEMELD_WAIST;    
+	if (nChakra == CHAKRA_HEART    ) nMeld = MELD_BLADEMELD_HEART;    
+	if (nChakra == CHAKRA_SOUL     ) nMeld = MELD_BLADEMELD_SOUL;     
+    
+	return nMeld;
+}
\ No newline at end of file
diff --git a/trunk/include/nw_o2_coninclude.nss b/trunk/include/nw_o2_coninclude.nss
new file mode 100644
index 00000000..4a250bd0
--- /dev/null
+++ b/trunk/include/nw_o2_coninclude.nss
@@ -0,0 +1,4791 @@
+//::///////////////////////////////////////////////
+//:: NW_O2_CONINCLUDE.nss
+//:: Copyright (c) 2001 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+  This include file handles the random treasure
+  distribution for treasure from creatures and containers
+
+ [ ] Documented
+*/
+//:://////////////////////////////////////////////
+//:: Created By:  Brent, Andrew
+//:: Created On:  November - May
+//::
+//:: Updated for .35 by Jaysyn 2023/03/10
+//:://////////////////////////////////////////////
+// :: MODS
+// April 23 2002: Removed animal parts. They were silly.
+// May 6 2002: Added Undead to the EXCLUSION treasure list (they drop nothing now)
+//  - redistributed treasure (to lessen amoun   t of armor and increase 'class specific treasure'
+//  - Rangers with heavy armor prof. will be treated as Fighters else as Barbarians
+//  - Gave wizards, druids and monk their own function
+// MAY 29 2002: Removed the heal potion from treasure
+//              Moved nymph cloak +4 to treasure bracket 6
+//              Added Monk Enhancement items to random treasure
+
+#include "prc_class_const"
+
+// * ---------
+// * CONSTANTS
+// * ---------
+
+// * tweaking constants
+
+    // * SIX LEVEL RANGES
+    const int RANGE_1_MIN = 0;
+    const int RANGE_1_MAX = 5;
+    const int RANGE_2_MIN = 6;
+    const int RANGE_2_MAX = 8;
+
+    const int RANGE_3_MIN = 9;
+    const int RANGE_3_MAX = 10;
+
+    const int RANGE_4_MIN = 11;
+    const int RANGE_4_MAX = 13;
+
+    const int RANGE_5_MIN = 14;
+    const int RANGE_5_MAX = 16;
+
+    const int RANGE_6_MIN = 17;
+    const int RANGE_6_MAX = 100;
+
+    // * NUMBER OF ITEMS APPEARING
+    const int NUMBER_LOW_ONE   = 100; const int NUMBER_MED_ONE    = 60; const int NUMBER_HIGH_ONE   = 40;  const int NUMBER_BOSS_ONE = 100;
+    const int NUMBER_LOW_TWO   = 0;   const int NUMBER_MED_TWO    = 30; const int NUMBER_HIGH_TWO   = 40;  const int NUMBER_BOSS_TWO = 0;
+    const int NUMBER_LOW_THREE = 0;   const int NUMBER_MED_THREE  = 10; const int NUMBER_HIGH_THREE = 20;  const int NUMBER_BOSS_THREE = 0;
+
+    const int NUMBER_BOOK_ONE = 75;
+    const int NUMBER_BOOK_TWO = 20;
+    const int NUMBER_BOOK_THREE = 5;
+
+    // * AMOUNT OF GOLD BY VALUE
+    const float LOW_MOD_GOLD = 0.5;   const float MEDIUM_MOD_GOLD = 1.0; const float HIGH_MOD_GOLD = 3.0;
+    // * FREQUENCY OF ITEM TYPE APPEARING BY TREASURE TYPE
+    const int LOW_PROB_BOOK    = 1;  const int MEDIUM_PROB_BOOK =   1;  const int HIGH_PROB_BOOK =1;
+    const int LOW_PROB_ANIMAL  = 0;  const int MEDIUM_PROB_ANIMAL = 0;  const int HIGH_PROB_ANIMAL = 0;
+    const int LOW_PROB_JUNK    = 2;  const int MEDIUM_PROB_JUNK =    1;  const int HIGH_PROB_JUNK = 1;
+    const int LOW_PROB_GOLD = 43;    const int MEDIUM_PROB_GOLD =   38; const int HIGH_PROB_GOLD = 15;
+    const int LOW_PROB_GEM  = 9;     const int MEDIUM_PROB_GEM =    15; const int HIGH_PROB_GEM = 15;
+    const int LOW_PROB_JEWEL = 4;    const int MEDIUM_PROB_JEWEL =  6; const int HIGH_PROB_JEWEL = 15;
+    const int LOW_PROB_ARCANE = 3;   const int MEDIUM_PROB_ARCANE = 3; const int HIGH_PROB_ARCANE = 3;
+    const int LOW_PROB_DIVINE = 3;   const int MEDIUM_PROB_DIVINE = 3;  const int HIGH_PROB_DIVINE = 3;
+    const int LOW_PROB_AMMO = 10;    const int MEDIUM_PROB_AMMO =   5;  const int HIGH_PROB_AMMO  =   3;
+    const int LOW_PROB_KIT = 5;      const int MEDIUM_PROB_KIT =    5;  const int HIGH_PROB_KIT   =   5;
+    const int LOW_PROB_POTION =17;   const int MEDIUM_PROB_POTION = 20; const int HIGH_PROB_POTION=   9;
+    const int LOW_PROB_TABLE2 = 3;   const int MEDIUM_PROB_TABLE2 = 3; const int HIGH_PROB_TABLE2=   30;
+
+
+// * readability constants
+
+const int    TREASURE_LOW = 1;
+const int    TREASURE_MEDIUM = 2;
+const int    TREASURE_HIGH = 3;
+const int    TREASURE_BOSS = 4;
+const int    TREASURE_BOOK = 5;
+
+
+// * JUMP_LEVEL is used in a Specific item function
+// * in the case where a generic item is called for within that function
+// * it will create a generic item by adding JUMP_LEVEL to the character's
+// * hit die for the purposes of the treasure evaluation.
+// * May 2002: Lowered JUMP_LEVEL from 3 to 2
+
+const int JUMP_LEVEL = 2;
+
+
+//* Declarations
+    void CreateGenericExotic(object oTarget, object oAdventurer, int nModifier = 0);
+    void CreateGenericMonkWeapon(object oTarget, object oAdventurer, int nModifier = 0);
+    void CreateSpecificMonkWeapon(object oTarget, object oAdventurer, int nModifier = 0);
+    void CreateGenericDruidWeapon(object oTarget, object oAdventurer, int nModifier = 0);
+    void CreateSpecificDruidWeapon(object oTarget, object oAdventurer, int nModifier = 0);
+    void CreateGenericWizardWeapon(object oTarget, object oAdventurer, int nModifier = 0);
+    void CreateSpecificWizardWeapon(object oTarget, object oAdventurer, int nModifier = 0);
+    int nDetermineClassToUse(object oCharacter);
+
+
+// *
+// * IMPLEMENTATION
+// *
+
+// * Comment the speakstring in to debug treasure generation
+void dbSpeak(string s)
+{
+//   SpeakString(s);
+}
+
+//* made this function to help with debugging
+void dbCreateItemOnObject(string sItemTemplate, object oTarget = OBJECT_SELF, int nStackSize = 1)
+{
+/*
+    if (sItemTemplate == "")
+    {
+        PrintString("blank item passed into dbCreateItemOnObject. Please report as bug to Brent.");
+    }
+    dbSpeak(sItemTemplate);
+*/
+
+    //sItemTemplate = GetStringLowerCase
+
+    if (nStackSize == 1)
+    {
+        // * checks to see if this is a throwing item and if it is
+        // * it creates more
+
+        string sRoot = GetSubString(sItemTemplate, 0, 6);
+        //dbSpeak("ROOT: " + sRoot);
+        if (GetStringLowerCase(sRoot) == "nw_wth")
+        {
+            nStackSize = Random(30) + 1;
+        }
+    }
+    object oItem = CreateItemOnObject(sItemTemplate, oTarget, nStackSize);
+/*
+    if (GetIsObjectValid(oItem) == FALSE && sItemTemplate != "NW_IT_GOLD001")
+    {
+
+        // * check to see if item is there in a stack, if not give warning
+        if (GetIsObjectValid(GetItemPossessedBy(oTarget, GetStringUpperCase(sItemTemplate))) == FALSE &&
+            GetIsObjectValid(GetItemPossessedBy(oTarget, GetStringLowerCase(sItemTemplate))) == FALSE)
+        {
+            PrintString("**DESIGN***");
+            PrintString("******" + sItemTemplate + " is an invalid item template. Please report as bug to Brent.");
+            PrintString("*******");
+        }
+    }
+*/
+}
+
+
+// *
+// * GET FUNCTIONS
+// *
+
+// * Returns the object that either last opened the container or destroyed it
+object GetLastOpener()
+{
+    if (GetIsObjectValid(GetLastOpenedBy()) == TRUE)
+    {
+        //dbSpeak("LastOpener: GetLastOpenedBy " + GetTag(GetLastOpenedBy()));
+        return GetLastOpenedBy();
+    }
+    else
+    if (GetIsObjectValid(GetLastKiller()) == TRUE)
+    {
+        //dbSpeak("LastOpener: GetLastAttacker");
+        return GetLastKiller();
+    }
+    //dbSpeak("LastOpener: The Object is Invalid you weenie!");
+    return OBJECT_INVALID;
+}
+
+//::///////////////////////////////////////////////
+//:: GetRange
+//:: Copyright (c) 2002 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+    Returns true if nHD matches the correct
+    level range for the indicated nCategory.
+    (i.e., First to Fourth level characters
+    are considered Range1)
+*/
+//:://////////////////////////////////////////////
+//:: Created By:  Brent
+//:: Created On:
+//:://////////////////////////////////////////////
+int GetRange(int nCategory, int nHD)
+{
+    int nMin = 0; int nMax = 0;
+    switch (nCategory)
+    {
+        case 6: nMin = RANGE_6_MIN; nMax = RANGE_6_MAX; break;
+        case 5: nMin = RANGE_5_MIN; nMax = RANGE_5_MAX; break;
+        case 4: nMin = RANGE_4_MIN; nMax = RANGE_4_MAX; break;
+        case 3: nMin = RANGE_3_MIN; nMax = RANGE_3_MAX; break;
+        case 2: nMin = RANGE_2_MIN; nMax = RANGE_2_MAX; break;
+        case 1: nMin = RANGE_1_MIN; nMax = RANGE_1_MAX; break;
+    }
+
+   //dbSpeak("nMin = " + IntToString(nMin));
+   //dbSpeak("nMax = " + IntToString(nMax));
+   //dbSpeak("GetRange.nHD = " + IntToString(nHD));
+   if (nHD >= nMin && nHD <= nMax)
+   {
+    return TRUE;
+   }
+
+  return FALSE;
+
+}
+
+//::///////////////////////////////////////////////
+//:: GetNumberOfItems
+//:: Copyright (c) 2002 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+    Returns the number of items to create.
+*/
+//:://////////////////////////////////////////////
+//:: Created By:  Brent
+//:: Created On:
+//:://////////////////////////////////////////////
+int GetNumberOfItems(int nTreasureType)
+{
+    int nItems = 0;
+    int nRandom = 0;
+
+    int nProbThreeItems = 0;
+    int nProbTwoItems = 0;
+    int nProbOneItems = 0;
+
+    if (nTreasureType == TREASURE_LOW)
+    {
+     nProbThreeItems = NUMBER_LOW_THREE;
+     nProbTwoItems = NUMBER_LOW_TWO;
+     nProbOneItems = NUMBER_LOW_ONE;
+    }
+    else
+    if (nTreasureType == TREASURE_MEDIUM)
+    {
+     nProbThreeItems = NUMBER_MED_THREE;
+     nProbTwoItems = NUMBER_MED_TWO;
+     nProbOneItems = NUMBER_MED_ONE;
+    }
+    else
+    if (nTreasureType == TREASURE_HIGH)
+    {
+     nProbThreeItems = NUMBER_HIGH_THREE;
+     nProbTwoItems = NUMBER_HIGH_TWO;
+     nProbOneItems = NUMBER_HIGH_ONE;
+    }
+    else
+    if (nTreasureType == TREASURE_BOSS)
+    {
+     nProbThreeItems = NUMBER_BOSS_THREE;
+     nProbTwoItems = NUMBER_BOSS_TWO;
+     nProbOneItems = NUMBER_BOSS_ONE;
+    }
+    else
+    if (nTreasureType == TREASURE_BOOK)
+    {
+     nProbThreeItems = NUMBER_BOOK_THREE;
+     nProbTwoItems = NUMBER_BOOK_TWO;
+     nProbOneItems = NUMBER_BOOK_ONE;
+    }
+
+
+    nRandom = d100();
+    if (nRandom <= nProbThreeItems)
+    {
+        nItems = 3;
+    }
+    else
+    if (nRandom <= nProbTwoItems + nProbThreeItems)
+    {
+        nItems = 2;
+    }
+    else
+    {
+        nItems = 1;
+    }
+
+    // * May 13 2002: Cap number of items, in case of logic error
+    if (nItems > 3)
+    {
+        nItems = 3;
+    }
+
+    return nItems;
+}
+
+
+// *
+// * TREASURE GENERATION FUNCTIONS
+// *
+    // *
+    // * Non-Scaling Treasure
+    // *
+    void CreateBook(object oTarget)
+    {
+        int nBook1 = Random(31) + 1;
+        string sRes = "NW_IT_BOOK01";
+
+        if (nBook1 < 10)
+        {
+            sRes = "NW_IT_BOOK00" + IntToString(nBook1);
+        }
+        else
+        {
+            sRes = "NW_IT_BOOK0" + IntToString(nBook1);
+        }
+        //dbSpeak("Create book");
+        dbCreateItemOnObject(sRes, oTarget);
+    }
+
+    void CreateAnimalPart(object oTarget)
+    {
+
+        string sRes = "";
+        int nResult = Random(3) + 1;
+        switch (nResult)
+        {
+            case 1: sRes = "NW_IT_MSMLMISC20"; break;
+            case 2: sRes = "NW_IT_MMIDMISC05"; break;
+            case 3: sRes = "NW_IT_MMIDMISC06"; break;
+        }
+        //dbSpeak("animal");
+        dbCreateItemOnObject(sRes, oTarget);
+    }
+
+    void CreateJunk(object oTarget)
+    {
+        string sRes = "NW_IT_TORCH001";
+        int NUM_ITEMS = 6;
+        int nResult = Random(NUM_ITEMS) + 1;
+        int nKit = 0;
+        switch (nResult)
+        {
+            case 1: sRes = "NW_IT_MPOTION021"; break; //ale
+            case 2: sRes = "NW_IT_MPOTION021"; break;   // ale
+            case 3: sRes = "NW_IT_MPOTION023"; break; // wine
+            case 4: sRes = "NW_IT_MPOTION021"; break; // ale
+            case 5: sRes = "NW_IT_MPOTION022"; break; // spirits
+            case 6: sRes = "NW_IT_TORCH001"; break; //torch
+        }
+        //dbSpeak("CreateJunk");
+        dbCreateItemOnObject(sRes, oTarget);
+    }
+    // *
+    // * Scaling Treasure
+    // *
+    void CreateGold(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0)
+    {
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+        int nAmount = 0;
+
+        if (GetRange(1, nHD))
+        {
+            nAmount = d10();
+        }
+        else if (GetRange(2, nHD))
+        {
+            nAmount = d20();
+        }
+        else if (GetRange(3, nHD))
+        {
+            nAmount = d20(2);
+        }
+        else if (GetRange(4, nHD))
+        {
+            nAmount = d20(5);
+        }
+        else if (GetRange(5, nHD))
+        {
+            nAmount = d20(8);
+        }
+        else if (GetRange(6, nHD))
+        {
+            nAmount = d20(10);
+        }
+        float nMod = 0.0;
+        if (nTreasureType == TREASURE_LOW) nMod = LOW_MOD_GOLD;
+        else if (nTreasureType == TREASURE_MEDIUM) nMod = MEDIUM_MOD_GOLD;
+        else if (nTreasureType == TREASURE_HIGH) nMod = HIGH_MOD_GOLD;
+
+        // * always at least 1gp is created
+        nAmount = FloatToInt(nAmount * nMod);
+        if (nAmount <= 0)
+        {
+            nAmount = 1;
+        }
+        //dbSpeak("gold");
+        dbCreateItemOnObject("NW_IT_GOLD001", oTarget, nAmount);
+    }
+    void CreateGem(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0)
+    {
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+        string sGem = "nw_it_gem001";
+        if (GetRange(1, nHD))
+        {
+            int nRandom = Random(9) + 1;
+            switch (nRandom)
+            {
+                case 1: sGem = "nw_it_gem001";  break;
+                case 2: sGem = "nw_it_gem007";  break;
+                case 3: sGem = "nw_it_gem002";  break;
+                case 4: case 5: sGem = "nw_it_gem004"; break;
+                case 6: case 7: sGem = "nw_it_gem014"; break;
+                case 8: sGem = "nw_it_gem003";         break;
+                case 9: sGem = "nw_it_gem015";         break;
+            }
+        }
+        else if (GetRange(2, nHD))               // 30 GP Avg; 150 gp Max
+        {
+            int nRandom = d12();
+            switch (nRandom)
+            {
+                case 1: sGem = "nw_it_gem001";         break;
+                case 2: sGem = "nw_it_gem007";         break;
+                case 3: sGem = "nw_it_gem002";         break;
+                case 4: sGem = "nw_it_gem004";         break;
+                case 5: case 6: sGem = "nw_it_gem014";  break;
+                case 7: case 8: sGem = "nw_it_gem003";  break;
+                case 9: case 10: sGem = "nw_it_gem015"; break;
+                case 11: sGem = "nw_it_gem011";         break;
+                case 12: sGem = "nw_it_gem013";         break;
+            }
+
+        }
+        else if (GetRange(3, nHD))  // 75GP Avg; 500 gp max
+        {
+            int nRandom = d2();
+            switch (nRandom)
+            {
+                case 1: sGem = "nw_it_gem013";         break;
+                case 2: sGem = "nw_it_gem010";         break;
+            }
+
+        }
+        else if (GetRange(4, nHD))  // 150 gp avg; 1000 gp max
+        {
+            int nRandom = d3();
+            switch (nRandom)
+            {
+                case 1: sGem = "nw_it_gem013";  break;
+                case 2: sGem = "nw_it_gem010";    break;
+                case 3: sGem = "nw_it_gem008";           break;
+            }
+        }
+        else if (GetRange(5, nHD))  // 300 gp avg; any
+        {
+            int nRandom = d6();
+            switch (nRandom)
+            {
+                case 1: sGem = "nw_it_gem013";  break;
+                case 2: sGem = "nw_it_gem010";    break;
+                case 3: case 4: sGem = "nw_it_gem008";           break;
+                case 5: sGem = "nw_it_gem009";           break;
+                case 6: sGem = "nw_it_gem009";           break;
+            }
+        }
+        else if (GetRange(6, nHD))// * Anything higher than level 15    500 gp avg; any
+        {
+            int nRandom = Random(8) + 1;
+            switch (nRandom)
+            {
+                case 1: sGem = "nw_it_gem013";  break;
+                case 2: sGem = "nw_it_gem010";    break;
+                case 3: case 4: sGem = "nw_it_gem008";           break;
+                case 5: sGem = "nw_it_gem009";           break;
+                case 6: sGem = "nw_it_gem009";           break;
+                case 7: sGem = "nw_it_gem006";           break;
+                case 8: sGem = "nw_it_gem012";           break;
+            }
+        }
+      //dbSpeak("Create Gem");
+      dbCreateItemOnObject(sGem, oTarget, 1);
+    }
+    void CreateJewel(object oTarget, object oAdventurer, int nTreasureType, int nModifier = 0)
+    {
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+        string sJewel = "";
+
+        if (GetRange(1, nHD))        // 15 gp avg; 75 gp max
+        {
+          int nRandom = d2();
+          switch (nRandom)
+          {
+            case 1: sJewel = "nw_it_mring021";   break;
+            case 2: sJewel = "nw_it_mneck020";   break;
+          }
+        }
+        else if (GetRange(2, nHD))   // 30 GP Avg; 150 gp Max
+        {
+          int nRandom = d6();
+          switch (nRandom)
+          {
+            case 1: sJewel = "nw_it_mring021";            break;
+            case 2: case 3: sJewel = "nw_it_mneck020";    break;
+            case 4: sJewel = "nw_it_mring022";            break;
+            case 5: case 6: sJewel = "nw_it_mneck023";            break;          }
+        }
+        else if (GetRange(3, nHD))  // 75GP Avg; 500 gp max
+        {
+          int nRandom = d6();
+          switch (nRandom)
+          {
+            case 1: sJewel = "nw_it_mring021";           break;
+            case 2: case 3: sJewel = "nw_it_mneck020";   break;
+            case 4: case 5: sJewel = "nw_it_mring022";   break;
+            case 6: sJewel = "nw_it_mneck021";           break;
+          }
+        }
+        else if (GetRange(4, nHD))  // 150 gp avg; 1000 gp max
+        {
+          int nRandom = d6();
+          switch (nRandom)
+          {
+            case 1: sJewel = "nw_it_mring021";            break;
+            case 2: sJewel = "nw_it_mring022";            break;
+            case 3: case 4: case 5: sJewel = "nw_it_mneck021";    break;
+            case 6: sJewel = "nw_it_mring023";            break;
+          }
+        }
+        else if (GetRange(5, nHD))  // 300 gp avg; any
+        {
+          int nRandom = d8();
+          switch (nRandom)
+          {
+            case 1: sJewel = "nw_it_mring022";           break;
+            case 2: case 3: sJewel = "nw_it_mneck021";   break;
+            case 4: case 5: case 6: sJewel = "nw_it_mring023"; break;
+            case 7: case 8: sJewel = "nw_it_mneck022";               break;
+          }
+        }
+        else if (GetRange(6, nHD))
+        {
+          int nRandom = d6();
+          switch (nRandom)
+          {
+            case 1: sJewel = "nw_it_mring022";              break;
+            case 2: sJewel = "nw_it_mneck021";              break;
+            case 3: case 4: sJewel = "nw_it_mring023";      break;
+            case 5: case 6: sJewel = "nw_it_mneck022";      break;
+          }
+        }
+      //dbSpeak("Create Jewel");
+
+      dbCreateItemOnObject(sJewel, oTarget, 1);
+
+    }
+    // * returns the valid upper limit for any arcane spell scroll
+    int TrimLevel(int nScroll, int nLevel)
+    {   int nMax = 5;
+        switch (nLevel)
+        {
+            case 0: nMax = 4; break;
+            case 1: nMax = 13; break;
+            case 2: nMax = 21; break;
+            case 3: nMax = 15; break;
+            case 4: nMax = 17; break;
+            case 5: nMax = 13; break;
+            case 6: nMax = 14; break;
+            case 7: nMax = 8; break;
+            case 8: nMax = 9; break;
+            case 9: nMax = 12; break;
+        }
+        if (nScroll > nMax) nScroll = nMax;
+        return nScroll;
+
+    }
+    // * nModifier is to 'raise' the level of the oAdventurer
+    void CreateArcaneScroll(object oTarget, object oAdventurer, int nModifier = 0)
+    {
+        int nMaxSpells = 21;
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+        int nScroll = 1;
+        int nLevel = 1;
+
+        if (GetRange(1, nHD))           // l 1-2
+        {
+          nLevel = d2();
+          nScroll =  Random(nMaxSpells) + 1;
+        }
+        else if (GetRange(2, nHD))      // l 1-4
+        {
+          nLevel = d4();
+          nScroll =  Random(nMaxSpells) + 1;
+        }
+        else if (GetRange(3, nHD))    // l 2-6
+        {
+          nLevel = d6();
+          if (nLevel < 2) nLevel = 2;
+
+          nScroll =  Random(nMaxSpells) + 1;
+        }
+        else if (GetRange(4, nHD))   // l 3-8
+        {
+          nLevel = d8();
+          if (nLevel < 3) nLevel = 3;
+
+          nScroll =  Random(nMaxSpells) + 1;
+        }
+        else if (GetRange(5, nHD))   // l 4-9
+        {
+          nLevel = d8() + 1;
+          if (nLevel < 4) nLevel = 4;
+
+          nScroll =  Random(nMaxSpells) + 1;
+        }
+        else if (GetRange(6, nHD))   // 5 -9
+        {
+          nLevel = d8() + 1;
+          if (nLevel < 5) nLevel = 5;
+
+          nScroll =  Random(nMaxSpells) + 1;
+        }
+
+        // * Trims the level of the scroll to match the max # of scrolls in each level range
+        nScroll = TrimLevel(nScroll, nLevel);
+
+        string sRes = "nw_it_sparscr216";
+
+        if (nScroll < 10)
+        {
+            sRes = "NW_IT_SPARSCR" + IntToString(nLevel) + "0" + IntToString(nScroll);
+        }
+        else
+        {
+            sRes = "NW_IT_SPARSCR" + IntToString(nLevel) + IntToString(nScroll);
+        }
+          dbCreateItemOnObject(sRes, oTarget, 1);
+        }
+
+    void CreateDivineScroll(object oTarget, object oAdventurer, int nModifier=0)
+    {
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+        string sScroll = "";
+        if (GetRange(1, nHD))
+        {
+            int nRandom = d4();
+            switch (nRandom)
+            {
+                case 1: sScroll = "nw_it_spdvscr201"; break;
+                case 2: sScroll = "nw_it_spdvscr202"; break;
+                case 3: sScroll = "nw_it_spdvscr203"; break;
+                case 4: sScroll = "nw_it_spdvscr204"; break;
+            }
+        }
+        else if (GetRange(2, nHD))
+        {
+            int nRandom = d8();
+            switch (nRandom)
+            {
+                case 1: sScroll = "nw_it_spdvscr201"; break;
+                case 2: sScroll = "nw_it_spdvscr202";break;
+                case 3: sScroll = "nw_it_spdvscr203"; break;
+                case 4: sScroll = "nw_it_spdvscr204"; break;
+                case 5: sScroll = "nw_it_spdvscr301"; break;
+                case 6: sScroll = "nw_it_spdvscr302"; break;
+                case 7: sScroll = "nw_it_spdvscr401"; break;
+                case 8: sScroll = "nw_it_spdvscr402"; break;
+            }
+
+        }
+        else if (GetRange(3, nHD))
+        {
+            int nRandom = Random(9) + 1;
+            switch (nRandom)
+            {
+                case 1: sScroll = "nw_it_spdvscr201"; break;
+                case 2: sScroll = "nw_it_spdvscr202"; break;
+                case 3: sScroll = "nw_it_spdvscr203"; break;
+                case 4: sScroll = "nw_it_spdvscr204"; break;
+                case 5: sScroll = "nw_it_spdvscr301"; break;
+                case 6: sScroll = "nw_it_spdvscr302"; break;
+                case 7: sScroll = "nw_it_spdvscr401"; break;
+                case 8: sScroll = "nw_it_spdvscr402"; break;
+                case 9: sScroll = "nw_it_spdvscr501"; break;
+            }
+
+        }
+        else
+        {
+            int nRandom = Random(7) + 1;
+            switch (nRandom)
+            {
+                case 1: sScroll = "nw_it_spdvscr301"; break;
+                case 2: sScroll = "nw_it_spdvscr302";  break;
+                case 3: sScroll = "nw_it_spdvscr401"; break;
+                case 4: sScroll = "nw_it_spdvscr402"; break;
+                case 5: sScroll = "nw_it_spdvscr501"; break;
+                case 6: sScroll = "nw_it_spdvscr701"; break;
+                case 7: sScroll = "nw_it_spdvscr702";  break;
+            }
+        }
+        //dbSpeak("Divine Scroll");
+
+        dbCreateItemOnObject(sScroll, oTarget, 1);
+
+    }
+    void CreateAmmo(object oTarget, object oAdventurer, int nModifier=0)
+    {
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+        string sAmmo = "";
+
+        if (GetRange(1, nHD))           // * 200 gp max
+        {
+            int nRandom = d3();
+            switch (nRandom)
+            {
+                case 1: sAmmo = "nw_wamar001";  break;
+                case 2: sAmmo = "nw_wambo001";  break;
+                case 3: sAmmo = "nw_wambu001";  break;
+            }
+          }
+        else if (GetRange(2, nHD))       // * 800 gp max
+        {
+            int nRandom = d6();
+            switch (nRandom)
+            {
+                case 1: sAmmo = "nw_wamar001";  break;
+                case 2: sAmmo = "nw_wambo001";  break;
+                case 3: sAmmo = "nw_wambu001";  break;
+                case 4: sAmmo = "nw_wammar001"; break;
+                case 5: sAmmo = "nw_wammbo001"; break;
+                case 6: sAmmo = "nw_wammbo002"; break;
+            }
+        }
+        else if (GetRange(3, nHD))    // *  - 2500 gp
+        {
+            int nRandom = d20();
+            switch (nRandom)
+            {
+                case 1: sAmmo = "nw_wamar001";   break;
+                case 2: sAmmo = "nw_wambo001";   break;
+                case 3: sAmmo = "nw_wambu001";   break;
+                case 4: sAmmo = "nw_wammar001";  break;
+                case 5: sAmmo = "nw_wammbo001";  break;
+                case 6: sAmmo = "nw_wammbo002";   break;
+                case 7: sAmmo = "nw_wammbo003";  break;
+                case 8: sAmmo = "nw_wammbu002";  break;
+                case 9: sAmmo = "nw_wammar002";  break;
+                case 10: sAmmo = "nw_wammar001"; break;
+                case 11: sAmmo = "nw_wammar003"; break;
+                case 12: sAmmo = "nw_wammar004"; break;
+                case 13: sAmmo = "nw_wammar005"; break;
+                case 14: sAmmo = "nw_wammar006"; break;
+                case 15: sAmmo = "nw_wammbo004";  break;
+                case 16: sAmmo = "nw_wammbo005"; break;
+                case 17: sAmmo = "nw_wammbu004"; break;
+                case 18: sAmmo = "nw_wammbu005"; break;
+                case 19: sAmmo = "nw_wammbu006"; break;
+                case 20: sAmmo = "nw_wammbu007"; break;
+            }
+        }
+        else
+        {
+            int nRandom = d20();
+            switch (nRandom)
+            {
+                case 1: sAmmo = "nw_wamar001";      break;
+                case 2: sAmmo = "nw_wammbu001";     break;
+                case 3: sAmmo = "nw_wammbu003";     break;
+                case 4: sAmmo = "nw_wammar001";     break;
+                case 5: sAmmo = "nw_wammbo001";      break;
+                case 6: sAmmo = "nw_wammbo002";     break;
+                case 7: sAmmo = "nw_wammbo003";     break;
+                case 8: sAmmo = "nw_wammbu002";     break;
+                case 9: sAmmo = "nw_wammar002";     break;
+                case 10: sAmmo = "nw_wammar001";    break;
+                case 11: sAmmo = "nw_wammar003";    break;
+                case 12: sAmmo = "nw_wammar004";     break;
+                case 13: sAmmo = "nw_wammar005";    break;
+                case 14: sAmmo = "nw_wammar006";    break;
+                case 15: sAmmo = "nw_wammbo004";    break;
+                case 16: sAmmo = "nw_wammbo005";    break;
+                case 17: sAmmo = "nw_wammbu004";    break;
+                case 18: sAmmo = "nw_wammbu005";    break;
+                case 19: sAmmo = "nw_wammbu006";    break;
+                case 20: sAmmo = "nw_wammbu007";    break;
+            }
+        }
+        //dbSpeak("ammo");
+        dbCreateItemOnObject(sAmmo, oTarget, Random(30) + 1); // create up to 30 of the specified ammo type
+    }
+
+    void CreateTrapKit(object oTarget, object oAdventurer, int nModifier = 0)
+    {
+      int nHD = GetHitDice(oAdventurer) + nModifier;
+      string sKit = "";
+        if (GetRange(1, nHD))      // 200
+        {
+            int nRandom = d3();
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_trap001";    break;
+                case 2: sKit = "nw_it_trap029";    break;
+                case 3: sKit = "nw_it_trap033";    break;
+            }
+        }
+        else if (GetRange(2, nHD))  // 800
+        {
+            int nRandom = d12();
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_trap001";    break;
+                case 2: sKit = "nw_it_trap029";    break;
+                case 3: sKit = "nw_it_trap033";    break;
+                case 4: sKit = "nw_it_trap002";    break;
+                case 5: sKit = "nw_it_trap030";    break;
+                case 6: sKit = "nw_it_trap037";    break;
+                case 7: sKit = "nw_it_trap034";   break;
+                case 8: sKit = "nw_it_trap005";   break;
+                case 9: sKit = "nw_it_trap038";   break;
+                case 10: sKit = "nw_it_trap041";   break;
+                case 11: sKit = "nw_it_trap003";    break;
+                case 12: sKit = "nw_it_trap031";   break;
+            }
+
+        }
+        else if (GetRange(3, nHD))   // 200 - 2500
+        {
+            int nRandom = Random(17) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_trap002";  break;
+                case 2: sKit = "nw_it_trap030";  break;
+                case 3: sKit = "nw_it_trap037";  break;
+                case 4: sKit = "nw_it_trap034";   break;
+                case 5: sKit = "nw_it_trap005";  break;
+                case 6: sKit = "nw_it_trap038";   break;
+                case 7: sKit = "nw_it_trap041";   break;
+                case 8: sKit = "nw_it_trap003";   break;
+                case 9: sKit = "nw_it_trap031";   break;
+                case 10: sKit = "nw_it_trap035";   break;
+                case 11: sKit = "nw_it_trap006";   break;
+                case 12: sKit = "nw_it_trap042";   break;
+                case 13: sKit = "nw_it_trap004";   break;
+                case 14: sKit = "nw_it_trap032";   break;
+                case 15: sKit = "nw_it_trap039";    break;
+                case 16: sKit = "nw_it_trap009";   break;
+                case 17: sKit = "nw_it_trap036";   break;
+            }
+
+       }
+        else if (GetRange(4, nHD))  // 800 - 10000
+        {
+            int nRandom = Random(19) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_trap035";  break;
+                case 2: sKit = "nw_it_trap006";  break;
+                case 3: sKit = "nw_it_trap042";  break;
+                case 4: sKit = "nw_it_trap004";   break;
+                case 5: sKit = "nw_it_trap032";   break;
+                case 6: sKit = "nw_it_trap039";   break;
+                case 7: sKit = "nw_it_trap009";   break;
+                case 8: sKit = "nw_it_trap036";   break;
+                case 9: sKit = "nw_it_trap013";   break;
+                case 10: sKit = "nw_it_trap040";  break;
+                case 11: sKit = "nw_it_trap007";  break;
+                case 12: sKit = "nw_it_trap043";  break;
+                case 13: sKit = "nw_it_trap010";  break;
+                case 14: sKit = "nw_it_trap017";  break;
+                case 15: sKit = "nw_it_trap021"; break;
+                case 16: sKit = "nw_it_trap014"; break;
+                case 17: sKit = "nw_it_trap025"; break;
+                case 18: sKit = "nw_it_trap008";  break;
+                case 19: sKit = "nw_it_trap044";  break;
+            }
+
+        }
+        else if (GetRange(5, nHD))  // 2000 -16500
+        {
+            int nRandom = Random(18) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_trap039";   break;
+                case 2: sKit = "nw_it_trap009";   break;
+                case 3: sKit = "nw_it_trap036";   break;
+                case 4: sKit = "nw_it_trap013";   break;
+                case 5: sKit = "nw_it_trap040";   break;
+                case 6: sKit = "nw_it_trap007";   break;
+                case 7: sKit = "nw_it_trap043";   break;
+                case 8: sKit = "nw_it_trap010";  break;
+                case 9: sKit = "nw_it_trap017";  break;
+                case 10: sKit = "nw_it_trap021";  break;
+                case 11: sKit = "nw_it_trap014";  break;
+                case 12: sKit = "nw_it_trap025";  break;
+                case 13: sKit = "nw_it_trap008";  break;
+                case 14: sKit = "nw_it_trap044";  break;
+                case 15: sKit = "nw_it_trap018";  break;
+                case 16: sKit = "nw_it_trap011";  break;
+                case 17: sKit = "nw_it_trap022";  break;
+                case 18: sKit = "nw_it_trap026";  break;
+            }
+
+        }
+        else if (GetRange(6, nHD))   // 2000 - ?
+        {
+            int nRandom = Random(27) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_trap039";  break;
+                case 2: sKit = "nw_it_trap009";  break;
+                case 3: sKit = "nw_it_trap036";  break;
+                case 4: sKit = "nw_it_trap013";  break;
+                case 5: sKit = "nw_it_trap040";  break;
+                case 6: sKit = "nw_it_trap007";  break;
+                case 7: sKit = "nw_it_trap043";  break;
+                case 8: sKit = "nw_it_trap010"; break;
+                case 9: sKit = "nw_it_trap017"; break;
+                case 10: sKit = "nw_it_trap021"; break;
+                case 11: sKit = "nw_it_trap014"; break;
+                case 12: sKit = "nw_it_trap025"; break;
+                case 13: sKit = "nw_it_trap008"; break;
+                case 14: sKit = "nw_it_trap044"; break;
+                case 15: sKit = "nw_it_trap018"; break;
+                case 16: sKit = "nw_it_trap011"; break;
+                case 17: sKit = "nw_it_trap022"; break;
+                case 18: sKit = "nw_it_trap026"; break;
+                case 19: sKit = "nw_it_trap015"; break;
+                case 20: sKit = "nw_it_trap012"; break;
+                case 21: sKit = "nw_it_trap019"; break;
+                case 22: sKit = "nw_it_trap023"; break;
+                case 23: sKit = "nw_it_trap016"; break;
+                case 24: sKit = "nw_it_trap027"; break;
+                case 25: sKit = "nw_it_trap020"; break;
+                case 26: sKit = "nw_it_trap024"; break;
+                case 27: sKit = "nw_it_trap028"; break;
+             }
+
+        }
+        //dbSpeak("Create Trapkit");
+        dbCreateItemOnObject(sKit, oTarget, 1);
+
+    }
+    void CreateHealingKit(object oTarget, object oAdventurer, int nModifier = 0)
+    {
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+        string sKit = "";
+        if (GetRange(1, nHD))      // 200
+        {
+            int nRandom = Random(1) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_medkit001";  break;
+            }
+        }
+        else if (GetRange(2, nHD))  // 800
+        {
+            int nRandom = Random(2) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_medkit001";  break;
+                case 2: sKit = "nw_it_medkit002";  break;
+            }
+
+        }
+        else if (GetRange(3, nHD))   // 200 - 2500
+        {
+            int nRandom = Random(2) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_medkit002"; break;
+                case 2: sKit = "nw_it_medkit003";  break;
+            }
+
+       }
+        else if (GetRange(4, nHD))  // 800 - 10000
+        {
+            int nRandom = Random(2) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_medkit003";break;
+                case 2: sKit = "nw_it_medkit004"; break;
+            }
+
+        }
+        else if (GetRange(5, nHD))  // 2000 -16500
+        {
+            int nRandom = Random(2) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_medkit003"; break;
+                case 2: sKit = "nw_it_medkit004";break;
+            }
+
+        }
+        else if (GetRange(6, nHD))   // 2000 - ?
+        {
+            int nRandom = Random(2) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_medkit003"; break;
+                case 2: sKit = "nw_it_medkit004";break;
+             }
+
+        }
+        //dbSpeak("Create Healing Kit");
+
+        dbCreateItemOnObject(sKit, oTarget, 1);
+
+    }
+    void CreateLockPick(object oTarget, object oAdventurer, int nModifier = 0)
+    {
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+        string sKit = "";
+        if (GetRange(1, nHD))      // 200
+        {
+            int nRandom = d8();
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_picks001";   break;
+                case 2: sKit = "nw_it_picks002";   break;
+                case 3: sKit = "nw_it_picks001";   break;
+                case 4: sKit = "nw_it_picks001";   break;
+                case 5: sKit = "nw_it_picks001";   break;
+                case 6: sKit = "nw_it_picks001";   break;
+                case 7: sKit = "nw_it_picks001";   break;
+                case 8: sKit = "nw_it_picks001";   break;
+            }
+        }
+        else if (GetRange(2, nHD))  // 800
+        {
+            int nRandom = d6();
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_picks001";   break;
+                case 2: sKit = "nw_it_picks002";    break;
+                case 3: sKit = "nw_it_picks003";   break;
+                case 4: sKit = "nw_it_picks002";    break;
+                case 5: sKit = "nw_it_picks002";    break;
+                case 6: sKit = "nw_it_picks002";    break;
+            }
+
+        }
+        else if (GetRange(3, nHD))   // 200 - 2500
+        {
+            int nRandom = Random(2) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_picks003";  break;
+                case 2: sKit = "nw_it_picks004";  break;
+            }
+
+       }
+        else if (GetRange(4, nHD))  // 800 - 10000
+        {
+            int nRandom = Random(1) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_picks004";  break;
+            }
+
+        }
+        else if (GetRange(5, nHD))  // 2000 -16500
+        {
+            int nRandom = Random(1) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_picks004"; break;
+            }
+
+        }
+        else if (GetRange(6, nHD))   // 2000 - ?
+        {
+            int nRandom = Random(1) + 1;
+            switch (nRandom)
+            {
+                case 1: sKit = "nw_it_picks004"; break;
+             }
+
+        }
+       //dbSpeak("Create Lockpick");
+
+        dbCreateItemOnObject(sKit, oTarget, 1);
+
+    }
+    void CreateKit(object oTarget, object oAdventurer, int nModifier = 0)
+    {
+        // * April 23 2002: Major restructuring of this function
+        // * to allow me to
+
+        switch (Random(8) + 1)
+        {
+            case 1: CreateTrapKit(oTarget, oAdventurer, nModifier); break;
+            case 2: case 3: case 4: case 5: CreateHealingKit(oTarget, oAdventurer, nModifier); break;
+            case 6: case 7: case 8: CreateLockPick(oTarget, oAdventurer, nModifier); break;
+        }
+    }
+
+    void CreatePotion(object oTarget, object oAdventurer, int nModifier = 0)
+    {
+        string sPotion = "";
+        int nHD = GetHitDice(oAdventurer) + nModifier;
+
+        if (GetRange(1, nHD))
+        {
+            int nRandom = d10();
+            switch (nRandom)
+            {
+                case 1: case 2: case 3: case 4: sPotion = "nw_it_mpotion001"; break;
+                case 5: case 6: case 7: sPotion = "nw_it_mpotion020";  break;
+                case 8: sPotion = "nw_it_mpotion002";  break;
+                case 9: sPotion = "nw_it_mpotion009";  break;
+                case 10: sPotion = "nw_it_mpotion005";  break;
+            }
+
+        }
+        else if (GetRange(2, nHD))
+        {
+           int nRandom = Random(29) + 1;
+            switch (nRandom)
+            {
+                case 1: case 2: case 3: sPotion = "nw_it_mpotion001"; break;
+                case 4: case 5: case 6: case 7: case 8: sPotion = "nw_it_mpotion020";  break;
+                case 9: case 10: case 11: case 12: sPotion = "nw_it_mpotion002";  break;
+                case 13: case 14: sPotion = "nw_it_mpotion003";  break;
+                case 15: sPotion = "nw_it_mpotion009";  break;
+                case 16: sPotion = "nw_it_mpotion005";  break;
+                case 17: sPotion = "nw_it_mpotion007";  break;
+                case 18: sPotion = "nw_it_mpotion008";  break;
+                case 19: sPotion = "nw_it_mpotion010";  break;
+                case 20: sPotion = "nw_it_mpotion011";  break;
+                case 21: sPotion = "nw_it_mpotion013";  break;
+                case 22: sPotion = "nw_it_mpotion014";  break;
+                case 23: sPotion = "nw_it_mpotion015";  break;
+                case 24: sPotion = "nw_it_mpotion016";  break;
+                case 25: sPotion = "nw_it_mpotion017";  break;
+                case 26: sPotion = "nw_it_mpotion018";  break;
+                case 27: sPotion = "nw_it_mpotion019";  break;
+                case 28: sPotion = "nw_it_mpotion004";  break;
+                case 29: sPotion = "nw_it_mpotion006";  break;
+            }
+        }
+        else if (GetRange(3, nHD))
+        {
+           int nRandom = Random(29) + 1;
+            switch (nRandom)
+            {
+                case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
+                case 9: case 10: case 11: case 12:
+                case 13: case 14: sPotion = "nw_it_mpotion003";  break;
+                case 15: sPotion = "nw_it_mpotion009";  break;
+                case 16: sPotion = "nw_it_mpotion005";  break;
+                case 17: sPotion = "nw_it_mpotion007";  break;
+                case 18: sPotion = "nw_it_mpotion008";  break;
+                case 19: sPotion = "nw_it_mpotion010";  break;
+                case 20: sPotion = "nw_it_mpotion011";  break;
+                case 21: sPotion = "nw_it_mpotion013";  break;
+                case 22: sPotion = "nw_it_mpotion014";  break;
+                case 23: sPotion = "nw_it_mpotion015";  break;
+                case 24: sPotion = "nw_it_mpotion016";  break;
+                case 25: sPotion = "nw_it_mpotion017";  break;
+                case 26: sPotion = "nw_it_mpotion018";  break;
+                case 27: sPotion = "nw_it_mpotion019";  break;
+                case 28: sPotion = "nw_it_mpotion004";  break;
+                case 29: sPotion = "nw_it_mpotion006";  break;
+            }
+        }
+        else if (GetRange(4, nHD))
+        {
+           int nRandom = Random(29) + 1;
+            switch (nRandom)
+            {
+                case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
+                case 9: case 10: case 11: case 12: sPotion = "nw_it_mpotion003"; break;
+                case 13: case 14: sPotion = "nw_it_mpotion003";  break;
+                case 15: sPotion = "nw_it_mpotion009";  break;
+                case 16: sPotion = "nw_it_mpotion005";  break;
+                case 17: sPotion = "nw_it_mpotion007";  break;
+                case 18: sPotion = "nw_it_mpotion008";  break;
+                case 19: sPotion = "nw_it_mpotion010";  break;
+                case 20: sPotion = "nw_it_mpotion011";  break;
+                case 21: sPotion = "nw_it_mpotion013";  break;
+                case 22: sPotion = "nw_it_mpotion014";  break;
+                case 23: sPotion = "nw_it_mpotion015";  break;
+                case 24: sPotion = "nw_it_mpotion016";  break;
+                case 25: sPotion = "nw_it_mpotion017";  break;
+                case 26: sPotion = "nw_it_mpotion018";  break;
+                case 27: sPotion = "nw_it_mpotion019";  break;
+                case 28: sPotion = "nw_it_mpotion004";  break;
+                case 29: sPotion = "nw_it_mpotion006";  break;
+            }
+        }
+        else  // keep 5 and 6 the same
+        {
+           int nRandom = Random(29) + 1;
+            switch (nRandom)
+            {
+                case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
+                case 9: sPotion = "nw_it_mpotion003" ;
+                case 10: case 11: case 12: case 13: case 14: sPotion = "nw_it_mpotion003";  break;
+                case 15: sPotion = "nw_it_mpotion009";  break;
+                case 16: sPotion = "nw_it_mpotion005";  break;
+                case 17: sPotion = "nw_it_mpotion007";  break;
+                case 18: sPotion = "nw_it_mpotion008";  break;
+                case 19: sPotion = "nw_it_mpotion010";  break;
+                case 20: sPotion = "nw_it_mpotion011";  break;
+                case 21: sPotion = "nw_it_mpotion013";  break;
+                case 22: sPotion = "nw_it_mpotion014";  break;
+                case 23: sPotion = "nw_it_mpotion015";  break;
+                case 24: sPotion = "nw_it_mpotion016";  break;
+                case 25: sPotion = "nw_it_mpotion017";  break;
+                case 26: sPotion = "nw_it_mpotion018";  break;
+                case 27: sPotion = "nw_it_mpotion019";  break;
+                case 28: sPotion = "nw_it_mpotion004";  break;
+                case 29: sPotion = "nw_it_mpotion006";  break;
+            }
+        }
+        //dbSpeak("Create Potion");
+        dbCreateItemOnObject(sPotion, oTarget, 1);
+    }
+    //::///////////////////////////////////////////////
+    //:: CreateTable2GenericItem
+    //:: Copyright (c) 2002 Bioware Corp.
+    //:://////////////////////////////////////////////
+    /*
+        Creates an item based upon the class of
+        oAdventurer
+    */
+    //:://////////////////////////////////////////////
+    //:: Created By:  Brent
+    //:: Created On:
+    //:://////////////////////////////////////////////
+        void CreateGenericMiscItem(object oTarget, object oAdventurer, int nModifier=0)
+        {
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+            string sItem = "";
+            if (GetRange(1, nHD))    // * 200
+            {
+                int nRandom = Random(9) + 1;
+                switch (nRandom)
+                {
+                 case 1: sItem = "nw_it_mglove004"; break;
+                 case 2: sItem = "nw_it_mglove004"; break;
+                 case 3: sItem = "nw_it_mglove005"; break;
+                 case 4: sItem = "nw_it_mglove006"; break;
+                 case 5: sItem = "nw_it_mglove007"; break;
+                 case 6: sItem = "nw_it_mglove008"; break;
+                 case 7: sItem = "nw_it_mglove009"; break;
+                 case 8: sItem = "nw_mcloth006"; break;
+                 case 9: sItem = "nw_it_mglove012"; break;
+                }
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                int nRandom = Random(25) + 1;
+                switch (nRandom)
+                {
+                 case 1: sItem = "nw_mcloth006"; break;
+                 case 2: sItem = "nw_it_mring009"; break;
+                 case 3: sItem = "nw_it_mring009"; break;
+                 case 4: sItem = "nw_it_mring010"; break;
+                 case 5: sItem = "nw_it_mring011"; break;
+                 case 6: sItem = "nw_it_mboots010"; break;
+                 case 7: sItem = "nw_it_mneck024"; break;
+                 case 8: sItem = "nw_mcloth007"; break;
+                 case 9: sItem = "nw_it_mring024"; break;
+                 case 10: sItem = "nw_it_mring012"; break;
+                 case 11: sItem = "nw_mcloth008"; break;
+                 case 12: sItem = "nw_it_mglove010"; break;
+                 case 13: sItem = "nw_it_mglove011"; break;
+                 case 14: sItem = "nw_it_mglove013"; break;
+                 case 15: sItem = "nw_it_mglove014"; break;
+                 case 16: sItem = "nw_it_mglove015"; break;
+                 case 17: sItem = "nw_maarcl097"; break;
+                 case 18: sItem = "nw_maarcl097"; break;
+                 case 19: sItem = "nw_maarcl099"; break;
+                 case 20: sItem = "nw_it_mneck032"; break;
+                 case 21: sItem = "nw_mcloth010"; break;
+                 case 22: sItem = "nw_it_mbracer002"; break;
+                 case 23: sItem = "nw_it_mneck001"; break;
+                 case 24: sItem = "nw_maarcl055"; break;
+                 case 25: sItem = "nw_mcloth009"; break;
+                }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                int nRandom = Random(44) + 1;
+                switch (nRandom)
+                {
+                 case 1: sItem = "nw_it_mring009"; break;
+                 case 2: sItem = "nw_it_mring009"; break;
+                 case 3: sItem = "nw_it_mring010"; break;
+                 case 4: sItem = "nw_it_mring011"; break;
+                 case 5: sItem = "nw_it_mboots010"; break;
+                 case 6: sItem = "nw_it_mneck024"; break;
+                 case 7: sItem = "nw_mcloth007"; break;
+                 case 8: sItem = "nw_it_mring024"; break;
+                 case 9: sItem = "nw_it_mring012"; break;
+                 case 10: sItem = "nw_mcloth008"; break;
+                 case 11: sItem = "nw_it_mglove010"; break;
+                 case 12: sItem = "nw_it_mglove011"; break;
+                 case 13: sItem = "nw_it_mglove013"; break;
+                 case 14: sItem = "nw_it_mglove014"; break;
+                 case 15: sItem = "nw_it_mglove015"; break;
+                 case 16: sItem = "nw_it_contain003"; break;
+                 case 17: sItem = "nw_maarcl097"; break;
+                 case 18: sItem = "nw_maarcl099"; break;
+                 case 19: sItem = "nw_it_mneck032"; break;
+                 case 20: sItem = "nw_mcloth010"; break;
+                 case 21: sItem = "nw_it_mbracer002"; break;
+                 case 22: sItem = "nw_it_mneck001"; break;
+                 case 23: sItem = "nw_maarcl055"; break;
+                 case 24: sItem = "nw_mcloth009"; break;
+                 case 25: sItem = "nw_it_mring001"; break;
+                 case 26: sItem = "nw_it_mboots001"; break;
+                 case 27: sItem = "nw_it_mbracer001"; break;
+                 case 28: sItem = "nw_it_mneck007"; break;
+                 case 29: sItem = "nw_maarcl096"; break;
+                 case 30: sItem = "nw_it_mglove003"; break;
+                 case 31: sItem = "nw_it_contain004"; break;
+                 case 32: sItem = "nw_it_mneck031"; break;
+                 case 33: sItem = "nw_it_mring006"; break;
+                 case 34: sItem = "nw_it_mneck006"; break;
+                 case 35: sItem = "nw_it_mneck029"; break;
+                 case 36: sItem = "nw_it_mring013"; break;
+                 case 37: sItem = "nw_it_mboots011"; break;
+                 case 38: sItem = "nw_it_mneck025"; break;
+                 case 39: sItem = "nw_it_mbelt009"; break;
+                 case 40: sItem = "nw_it_mbelt010"; break;
+                 case 41: sItem = "nw_it_mbelt011"; break;
+                 case 42: sItem = "nw_it_mring025"; break;
+                 case 43: sItem = "nw_it_mring025"; break;
+                 case 44: sItem = "nw_maarcl031"; break;
+
+                }
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                int nRandom = Random(48) + 1;
+                switch (nRandom)
+                {
+                 case 1: sItem = "nw_it_mring001"; break;
+                 case 2: sItem = "nw_it_mboots001"; break;
+                 case 3: sItem = "nw_it_mbracer001"; break;
+                 case 4: sItem = "nw_it_mneck007"; break;
+                 case 5: sItem = "nw_maarcl096"; break;
+                 case 6: sItem = "nw_it_mglove003"; break;
+                 case 7: sItem = "nw_it_mneck031"; break;
+                 case 8: sItem = "nw_it_mneck031"; break;
+                 case 9: sItem = "nw_it_mring006"; break;
+                 case 10: sItem = "nw_it_mneck006"; break;
+                 case 11: sItem = "nw_it_mneck029"; break;
+                 case 12: sItem = "nw_it_mring013"; break;
+                 case 13: sItem = "nw_it_mboots011"; break;
+                 case 14: sItem = "nw_it_mneck025"; break;
+                 case 15: sItem = "nw_it_mbelt009"; break;
+                 case 16: sItem = "nw_it_mbelt010"; break;
+                 case 17: sItem = "nw_it_mbelt011"; break;
+                 case 18: sItem = "nw_it_mring025"; break;
+                 case 19: sItem = "nw_it_mring025"; break;
+                 case 20: sItem = "nw_it_mbracer007"; break;
+                 case 21: sItem = "nw_it_mbracer007"; break;
+                 case 22: sItem = "nw_it_mneck012"; break;
+                 case 23: sItem = "nw_maarcl088"; break;
+                 case 24: sItem = "nw_it_mboots012"; break;
+                 case 25: sItem = "nw_it_mneck026"; break;
+                 case 26: sItem = "nw_it_mboots006"; break;
+                 case 27: sItem = "nw_it_mbracer003"; break;
+                 case 28: sItem = "nw_it_mneck008"; break;
+                 case 29: sItem = "nw_it_mring008"; break;
+                 case 30: sItem = "nw_maarcl056"; break;
+                 case 31: sItem = "nw_maarcl092"; break;
+                 case 32: sItem = "nw_it_mring014"; break;
+                 case 33: sItem = "nw_it_mneck016"; break;
+                 case 34: sItem = "nw_it_mboots013"; break;
+                 case 35: sItem = "nw_it_mneck027"; break;
+                 case 36: sItem = "nw_it_mbracer008"; break;
+                 case 37: sItem = "nw_it_mneck013"; break;
+                 case 38: sItem = "nw_maarcl089"; break;
+                 case 39: sItem = "nw_it_mbelt012"; break;
+                 case 40: sItem = "nw_it_mbelt013"; break;
+                 case 41: sItem = "nw_it_mbelt014"; break;
+                 case 42: sItem = "nw_it_mring027"; break;
+                 case 43: sItem = "nw_it_mboots007"; break;
+                 case 44: sItem = "nw_it_mbracer004"; break;
+                 case 45: sItem = "nw_it_mneck009"; break;
+                 case 46: sItem = "nw_it_mring018"; break;
+                 case 47: sItem = "nw_maarcl093"; break;
+                 case 48: sItem = "nw_it_mboots002"; break;
+
+                }
+            }
+            else if (GetRange(5, nHD))   // * 2500 - 16500
+            {
+                int nRandom = Random(42) + 1;
+                switch (nRandom)
+                {
+                 case 1: sItem = "nw_it_mbracer007"; break;
+                 case 2: sItem = "nw_it_mbracer007"; break;
+                 case 3: sItem = "nw_it_mneck012"; break;
+                 case 4: sItem = "nw_maarcl088"; break;
+                 case 5: sItem = "nw_it_mboots012"; break;
+                 case 6: sItem = "nw_it_mneck026"; break;
+                 case 7: sItem = "nw_it_mboots006"; break;
+                 case 8: sItem = "nw_it_mbracer003"; break;
+                 case 9: sItem = "nw_it_mneck008"; break;
+                 case 10: sItem = "nw_it_mring008"; break;
+                 case 11: sItem = "nw_maarcl056"; break;
+                 case 12: sItem = "nw_maarcl092"; break;
+                 case 13: sItem = "nw_it_mring014"; break;
+                 case 14: sItem = "nw_it_mneck016"; break;
+                 case 15: sItem = "nw_it_mboots013"; break;
+                 case 16: sItem = "nw_it_mneck027"; break;
+                 case 17: sItem = "nw_it_mbracer008"; break;
+                 case 18: sItem = "nw_it_mneck013"; break;
+                 case 19: sItem = "nw_maarcl089"; break;
+                 case 20: sItem = "nw_it_mbelt012"; break;
+                 case 21: sItem = "nw_it_mbelt013"; break;
+                 case 22: sItem = "nw_it_mbelt014"; break;
+                 case 23: sItem = "nw_it_mring027"; break;
+                 case 24: sItem = "nw_it_mboots007"; break;
+                 case 25: sItem = "nw_it_mbracer004"; break;
+                 case 26: sItem = "nw_it_mneck009"; break;
+                 case 27: sItem = "nw_it_mring018"; break;
+                 case 28: sItem = "nw_maarcl093"; break;
+                 case 29: sItem = "nw_it_mboots002"; break;
+                 case 30: sItem = "nw_it_mboots014"; break;
+                 case 31: sItem = "nw_it_mneck028"; break;
+                 case 32: sItem = "nw_it_mring015"; break;
+                 case 33: sItem = "nw_it_mbracer009"; break;
+                 case 34: sItem = "nw_it_mneck014"; break;
+                 case 35: sItem = "nw_maarcl090"; break;
+                 case 36: sItem = "nw_it_mring028"; break;
+                 case 37: sItem = "nw_it_mneck017"; break;
+                 case 38: sItem = "nw_it_mboots008"; break;
+                 case 39: sItem = "nw_it_mbracer005"; break;
+                 case 40: sItem = "nw_it_mneck010"; break;
+                 case 41: sItem = "nw_it_mmidmisc02"; break;
+                 case 42: sItem = "nw_it_mring019"; break;
+                }
+            }
+            else if (GetRange(6, nHD))   // * 8000 - 25000
+            {
+                int nRandom = Random(30) + 1;
+                switch (nRandom)
+                {
+                 case 1: sItem = "nw_it_mring027"; break;
+                 case 2: sItem = "nw_it_mboots007"; break;
+                 case 3: sItem = "nw_it_mbracer004"; break;
+                 case 4: sItem = "nw_it_mneck009"; break;
+                 case 5: sItem = "nw_it_mring018"; break;
+                 case 6: sItem = "nw_maarcl093"; break;
+                 case 7: sItem = "nw_it_mboots002"; break;
+                 case 8: sItem = "nw_it_mboots014"; break;
+                 case 9: sItem = "nw_it_mneck028"; break;
+                 case 10: sItem = "nw_it_mring015"; break;
+                 case 11: sItem = "nw_it_mbracer009"; break;
+                 case 12: sItem = "nw_it_mneck014"; break;
+                 case 13: sItem = "nw_maarcl090"; break;
+                 case 14: sItem = "nw_it_mring028"; break;
+                 case 15: sItem = "nw_it_mneck017"; break;
+                 case 16: sItem = "nw_it_mboots008"; break;
+                 case 17: sItem = "nw_it_mbracer005"; break;
+                 case 18: sItem = "nw_it_mneck010"; break;
+                 case 19: sItem = "nw_it_mmidmisc02"; break;
+                 case 20: sItem = "nw_maarcl094"; break;
+                 case 21: sItem = "nw_it_mring019"; break;
+                 case 22: sItem = "nw_it_mring016"; break;
+                 case 23: sItem = "nw_it_mbracer010"; break;
+                 case 24: sItem = "nw_it_mneck015"; break;
+                 case 25: sItem = "nw_maarcl091"; break;
+                 case 26: sItem = "nw_it_mboots009"; break;
+                 case 27: sItem = "nw_it_mbracer006"; break;
+                 case 28: sItem = "nw_it_mneck011"; break;
+                 case 29: sItem = "nw_maarcl095"; break;
+                 case 30: sItem = "nw_it_mneck018"; break;
+                }
+             }
+             //dbSpeak("Create Misc");
+
+             dbCreateItemOnObject(sItem, oTarget, 1);
+         }
+
+         // * this function just returns an item that is more appropriate
+         // * for this class. Only wizards, sorcerers, clerics, monks, rogues and bards get this
+        void CreateGenericClassItem(object oTarget, object oAdventurer, int nSpecific =0)
+        {
+
+
+            if (GetLevelByClass(CLASS_TYPE_DRUID, oAdventurer)>= 1)
+            {
+                if (nSpecific == 0)
+                {
+                    CreateGenericDruidWeapon(oTarget, oAdventurer);
+                }
+                else
+                {
+                    CreateSpecificDruidWeapon(oTarget, oAdventurer);
+                }
+            }
+            else
+            if (GetLevelByClass(CLASS_TYPE_WIZARD, oAdventurer)>= 1 || GetLevelByClass(CLASS_TYPE_SORCERER, oAdventurer) >= 1)
+            {
+                // * 30% chance of getting a magic scroll else get a weapon suited for a wizard
+                if (Random(100) + 1 > 70)
+                {
+                    // * grab an arcane scroll as if the wizard had +4 levels
+                    CreateArcaneScroll(oTarget, oAdventurer, 4);
+                }
+                else
+                if (nSpecific == 0)
+                {
+                    CreateGenericWizardWeapon(oTarget, oAdventurer);
+                }
+                else
+                {
+                    CreateSpecificWizardWeapon(oTarget, oAdventurer);
+                }
+
+
+            }
+            else
+            if (GetLevelByClass(CLASS_TYPE_CLERIC, oAdventurer)>= 1)
+            {
+                  int nRandom = Random(4) + 1;
+                  string sItem = "nw_it_medkit001";
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_it_medkit001"; break;
+                       case 2: sItem = "nw_it_medkit002"; break;
+                       case 3: sItem = "nw_it_medkit003"; break;
+                       case 4: sItem = "nw_it_medkit004"; break;
+                   }
+                  dbCreateItemOnObject(sItem, oTarget, 1);
+            }
+            else
+            if (GetLevelByClass(CLASS_TYPE_MONK, oAdventurer)>= 1)
+            {
+                //dbSpeak("in monk function");
+                if (nSpecific == 0)
+                {
+                    CreateGenericMonkWeapon(oTarget, oAdventurer);
+                }
+                else
+                {
+                    CreateSpecificMonkWeapon(oTarget, oAdventurer);
+                }
+            }
+            else
+            if (GetLevelByClass(CLASS_TYPE_ROGUE, oAdventurer)>= 1)
+            {
+                // * give a misc item as if a couple levels higher
+                CreateGenericMiscItem(oTarget, oAdventurer, 2);
+            }
+            else
+            if (GetLevelByClass(CLASS_TYPE_BARD, oAdventurer)>= 1)
+            {
+                // * give a misc item as if a couple levels higher
+                CreateGenericMiscItem(oTarget, oAdventurer, 2);
+            }
+
+        }
+        void CreateGenericRodStaffWand(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                int nRandom = Random(3) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wmgwn013"; break;
+                    case 2: sItem = "nw_wmgwn006"; break;
+                    case 3: sItem = "nw_it_gem002";  break;  // gem for variety
+                }
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                int nRandom = Random(3) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wmgwn013"; break;
+                    case 2: sItem = "nw_wmgwn006"; break;
+                    case 3: sItem = "nw_it_gem002";  break;// gem for variety
+                }
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                int nRandom = Random(4) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wmgwn006"; break;
+                    case 2: sItem = "nw_wmgwn004"; break;
+                    case 3: sItem = "nw_wmgrd002"; break;
+                    case 4: sItem = "nw_wmgwn012"; break;
+                }
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                int nRandom = Random(11) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wmgwn004"; break;
+                    case 2: sItem = "nw_wmgwn002"; break;
+                    case 3: sItem = "nw_wmgwn007"; break;
+                    case 4: sItem = "nw_wmgwn003"; break;
+                    case 5: sItem = "nw_wmgwn010"; break;
+                    case 6: sItem = "nw_wmgwn011"; break;
+                    case 7: sItem = "nw_wmgwn005"; break;
+                    case 8: sItem = "nw_wmgwn008"; break;
+                    case 9: sItem = "nw_wmgwn009"; break;
+                    case 10: sItem = "nw_wmgrd002"; break;
+                    case 11: sItem = "nw_wmgwn012"; break;
+                }
+
+            }
+            else  // * 2500 - 16500
+            {
+                int nRandom = d8();
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wmgwn002"; break;
+                    case 2: sItem = "nw_wmgwn007"; break;
+                    case 3: sItem = "nw_wmgwn003"; break;
+                    case 4: sItem = "nw_wmgwn010"; break;
+                    case 5: sItem = "nw_wmgwn011"; break;
+                    case 6: sItem = "nw_wmgwn005"; break;
+                    case 7: sItem = "nw_wmgwn008"; break;
+                    case 8: sItem = "nw_wmgwn009"; break;
+                }
+
+            }
+          //dbSpeak("Generic Rod staff wand");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+
+        void CreateGenericMonkWeapon(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                  int nRandom = Random(10) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthsh001"; break;
+                       case 2: sItem = "nw_wblcl001"; break;
+                       case 3: sItem = "nw_wdbqs001"; break;
+                       case 4: sItem = "nw_wbwsl001"; break;
+                       case 5: sItem = "nw_wswdg001"; break;
+                       case 6: sItem = "nw_wspka001"; break;
+                       case 7: sItem = "nw_wbwxh001"; break;
+                       case 8: sItem = "nw_waxhn001"; break;
+                       case 9: sItem = "nw_wbwxl001"; break;
+                       case 10: sItem = "nw_wthmsh002"; break;
+                   }
+
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                  int nRandom = Random(14) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthsh001"; break;
+                       case 2: sItem = "nw_wblcl001"; break;
+                       case 3: sItem = "nw_wdbqs001"; break;
+                       case 4: sItem = "nw_wbwsl001"; break;
+                       case 5: sItem = "nw_wswdg001"; break;
+                       case 6: sItem = "nw_wspka001"; break;
+                       case 7: sItem = "nw_wbwxh001"; break;
+                       case 8: sItem = "nw_waxhn001"; break;
+                       case 9: sItem = "nw_wbwxl001"; break;
+                       case 10: sItem = "nw_wthmsh002"; break;
+                       case 11: sItem = "nw_wbwmsl001"; break;
+                       case 12: sItem = "nw_wbwmxh002"; break;
+                       case 13: sItem = "nw_wthmsh008"; break;
+                       case 14: sItem = "nw_wbwmxl002"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(13) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmsl001"; break;
+                       case 2: sItem = "nw_wbwmxh002"; break;
+                       case 3: sItem = "nw_wthmsh008"; break;
+                       case 4: sItem = "nw_wbwmxl002"; break;
+                       case 5: sItem = "nw_wthmsh009"; break;
+                       case 6: sItem = "nw_wblmcl002"; break;
+                       case 7: sItem = "nw_wdbmqs002"; break;
+                       case 8: sItem = "nw_wswmdg002"; break;
+                       case 9: sItem = "nw_wspmka002"; break;
+                       case 10: sItem = "nw_waxmhn002"; break;
+                       case 11: sItem = "nw_wbwmsl009"; break;
+                       case 12: sItem = "nw_wbwmxh008"; break;
+                       case 13: sItem = "nw_wbwmxl008"; break;
+                   }
+
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(17) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmsh009"; break;
+                       case 2: sItem = "nw_wblmcl002"; break;
+                       case 3: sItem = "nw_wdbmqs002"; break;
+                       case 4: sItem = "nw_wswmdg002"; break;
+                       case 5: sItem = "nw_wspmka002"; break;
+                       case 6: sItem = "nw_waxmhn002"; break;
+                       case 7: sItem = "nw_wbwmsl009"; break;
+                       case 8: sItem = "nw_wbwmxh008"; break;
+                       case 9: sItem = "nw_wbwmxl008"; break;
+                       case 10: sItem = "nw_wbwmsl010"; break;
+                       case 11: sItem = "nw_wbwmxh009"; break;
+                       case 12: sItem = "nw_wbwmxl009"; break;
+                       case 13: sItem = "nw_wblmcl010"; break;
+                       case 14: sItem = "nw_wdbmqs008"; break;
+                       case 15: sItem = "nw_wswmdg008"; break;
+                       case 16: sItem = "nw_wspmka008"; break;
+                       case 17: sItem = "nw_waxmhn010"; break;
+                   }
+            }
+            else  // * 2500 - 16500
+            {
+                  int nRandom = Random(13) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmsl010"; break;
+                       case 2: sItem = "nw_wbwmxh009"; break;
+                       case 3: sItem = "nw_wbwmxl009"; break;
+                       case 4: sItem = "nw_wblmcl010"; break;
+                       case 5: sItem = "nw_wdbmqs008"; break;
+                       case 6: sItem = "nw_wswmdg008"; break;
+                       case 7: sItem = "nw_wspmka008"; break;
+                       case 8: sItem = "nw_waxmhn010"; break;
+                       case 9: sItem = "nw_wblmcl011"; break;
+                       case 10: sItem = "nw_wdbmqs009"; break;
+                       case 11: sItem = "nw_wswmdg009"; break;
+                       case 12: sItem = "nw_wspmka009"; break;
+                       case 13: sItem = "nw_waxmhn011"; break;
+                   }
+            }
+          //dbSpeak("Generic Monk Weapon");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateSpecificMonkWeapon(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                  int nRandom = Random(3) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmsh003"; break;
+                       case 2: sItem = "nw_wthmsh006"; break;
+                       case 3: CreateGenericMonkWeapon(oTarget, oAdventurer, JUMP_LEVEL); return; break;
+                  }
+
+            }
+            else if (GetRange(2, nHD))   // * 2500
+            {
+                  int nRandom = Random(8) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmsh003"; break;
+                       case 2: sItem = "nw_wthmsh006"; break;
+                       case 3: sItem = "nw_wthmsh004"; break;
+                       case 4: sItem = "nw_wthmsh007"; break;
+                       case 5: sItem = "NW_IT_MGLOVE016"; break;
+                       case 6: sItem = "NW_IT_MGLOVE021"; break;
+                       case 7: sItem = "NW_IT_MGLOVE026"; break;
+                       case 8: CreateGenericMonkWeapon(oTarget, oAdventurer, JUMP_LEVEL); return; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(21) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmsh006"; break;
+                       case 2: sItem = "nw_wthmsh004"; break;
+                       case 3: sItem = "nw_wthmsh007"; break;
+                       case 4: sItem = "nw_wbwmsl005"; break;
+                       case 5: sItem = "nw_wbwmxh005"; break;
+                       case 6: sItem = "nw_wspmka004"; break;
+                       case 7: sItem = "nw_wbwmxl005"; break;
+                       case 8: sItem = "nw_wspmka007"; break;
+                       case 9: sItem = "nw_wswmdg006"; break;
+                       case 10: sItem = "nw_wspmka005"; break;
+                       case 11: sItem = "NW_IT_MGLOVE016"; break;
+                       case 12: sItem = "NW_IT_MGLOVE021"; break;
+                       case 13: sItem = "NW_IT_MGLOVE026"; break;
+
+                       case 14: sItem = "NW_IT_MGLOVE017"; break;
+                       case 15: sItem = "NW_IT_MGLOVE022"; break;
+                       case 16: sItem = "NW_IT_MGLOVE027"; break;
+
+                       case 17: sItem = "NW_IT_MGLOVE018"; break;
+                       case 18: sItem = "NW_IT_MGLOVE023"; break;
+                       case 19: sItem = "NW_IT_MGLOVE028"; break;
+
+                       case 20: sItem = "NW_IT_MGLOVE029"; break;
+                       case 21: sItem = "NW_IT_MGLOVE030"; break;
+
+
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 -16500
+            {
+                  int nRandom = Random(22) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmsl005"; break;
+                       case 2: sItem = "nw_wbwmxh005"; break;
+                       case 3: sItem = "nw_wspmka004"; break;
+                       case 4: sItem = "nw_wbwmxl005"; break;
+                       case 5: sItem = "nw_wspmka007"; break;
+                       case 6: sItem = "nw_wswmdg006"; break;
+                       case 7: sItem = "nw_wspmka005"; break;
+                       case 8: sItem = "nw_wblmcl004"; break;
+                       case 9: sItem = "nw_wblmcl003"; break;
+                       case 10: sItem = "nw_wbwmsl003"; break;
+                       case 11: sItem = "nw_wbwmxh003"; break;
+                       case 12: sItem = "nw_waxmhn004"; break;
+                       case 13: sItem = "nw_wbwmxl003"; break;
+
+                       case 14: sItem = "NW_IT_MGLOVE017"; break;
+                       case 15: sItem = "NW_IT_MGLOVE022"; break;
+
+                       case 16: sItem = "NW_IT_MGLOVE018"; break;
+                       case 17: sItem = "NW_IT_MGLOVE023"; break;
+                       case 18: sItem = "NW_IT_MGLOVE028"; break;
+
+                       case 19: sItem = "NW_IT_MGLOVE029"; break;
+                       case 20: sItem = "NW_IT_MGLOVE030"; break;
+
+                       case 21: sItem = "NW_IT_MGLOVE019"; break;
+                       case 22: sItem = "NW_IT_MGLOVE024"; break;
+
+
+                   }
+
+            }
+            else  // * 16000 +
+            {
+                  int nRandom = Random(24) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmxl003"; break;
+                       case 2: sItem = "nw_wspmka006"; break;
+                       case 3: sItem = "nw_wbwmxl004"; break;
+                       case 4: sItem = "nw_wspmka003"; break;
+                       case 5: sItem = "nw_wbwmxl007"; break;
+                       case 6: sItem = "nw_waxmhn003"; break;
+                       case 7: sItem = "nw_wblmcl005"; break;
+                       case 8: sItem = "nw_wswmdg004"; break;
+                       case 9: sItem = "nw_wbwmsl007"; break;
+                       case 10: sItem = "nw_wbwmxh004"; break;
+                       case 11: sItem = "nw_waxmhn005"; break;
+                       case 12: sItem = "nw_wbwmxh007"; break;
+                       case 13: sItem = "nw_wswmdg003"; break;
+                       case 14: sItem = "nw_wswmdg007"; break;
+                       case 15: sItem = "nw_wbwmsl006"; break;
+                       case 16: sItem = "nw_wbwmsl008"; break;
+                       case 17: sItem = "nw_wblmcl006"; break;
+                       case 18: sItem = "nw_wbwmsl004"; break;
+                       case 19: sItem = "nw_waxmhn006"; break;
+                       case 20: sItem = "nw_wbwmxh006"; break;
+                       case 21: sItem = "nw_wswmdg005"; break;
+                       case 22: sItem = "nw_wbwmxl006"; break;
+
+                       case 23: sItem = "NW_IT_MGLOVE020"; break;
+                       case 24: sItem = "NW_IT_MGLOVE025"; break;
+
+                   }
+
+            }
+           //dbSpeak("Specific Monk Weapon");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+
+        }
+
+        void CreateGenericDruidWeapon(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                  int nRandom = Random(8) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthdt001"; break;
+                       case 2: sItem = "nw_wblcl001"; break;
+                       case 3: sItem = "nw_wdbqs001"; break;
+                       case 4: sItem = "nw_wplss001"; break;
+                       case 5: sItem = "nw_wswdg001"; break;
+                       case 6: sItem = "nw_wspsc001"; break;
+                       case 7: sItem = "nw_wswsc001"; break;
+                       case 8: sItem = "nw_wthmdt002"; break;
+                   }
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                  int nRandom = Random(11) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthdt001"; break;
+                       case 2: sItem = "nw_wblcl001"; break;
+                       case 3: sItem = "nw_wdbqs001"; break;
+                       case 4: sItem = "nw_wplss001"; break;
+                       case 5: sItem = "nw_wswdg001"; break;
+                       case 6: sItem = "nw_wspsc001"; break;
+                       case 7: sItem = "nw_wswsc001"; break;
+                       case 8: sItem = "nw_wthmdt002"; break;
+                       case 9: sItem = "nw_wthmdt005"; break;
+                       case 10: sItem = "nw_wbwmsl001"; break;
+                       case 11: sItem = "nw_wthmdt008"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(13) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmdt005"; break;
+                       case 2: sItem = "nw_wbwmsl001"; break;
+                       case 3: sItem = "nw_wthmdt008"; break;
+                       case 4: sItem = "nw_wthmdt009"; break;
+                       case 5: sItem = "nw_wthmdt006"; break;
+                       case 6: sItem = "nw_wblmcl002"; break;
+                       case 7: sItem = "nw_wdbmqs002"; break;
+                       case 8: sItem = "nw_wplmss002"; break;
+                       case 9: sItem = "nw_wswmdg002"; break;
+                       case 10: sItem = "nw_wspmsc002"; break;
+                       case 11: sItem = "nw_wswmsc002"; break;
+                       case 12: sItem = "nw_wthmdt003"; break;
+                       case 13: sItem = "nw_wbwmsl009"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(19) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmdt009"; break;
+                       case 2: sItem = "nw_wthmdt006"; break;
+                       case 3: sItem = "nw_wblmcl002"; break;
+                       case 4: sItem = "nw_wdbmqs002"; break;
+                       case 5: sItem = "nw_wplmss002"; break;
+                       case 6: sItem = "nw_wswmdg002"; break;
+                       case 7: sItem = "nw_wspmsc002"; break;
+                       case 8: sItem = "nw_wswmsc002"; break;
+                       case 9: sItem = "nw_wthmdt003"; break;
+                       case 10: sItem = "nw_wbwmsl009"; break;
+                       case 11: sItem = "nw_wthmdt007"; break;
+                       case 12: sItem = "nw_wthmdt004"; break;
+                       case 13: sItem = "nw_wbwmsl010"; break;
+                       case 14: sItem = "nw_wblmcl010"; break;
+                       case 15: sItem = "nw_wdbmqs008"; break;
+                       case 16: sItem = "nw_wplmss010"; break;
+                       case 17: sItem = "nw_wswmdg008"; break;
+                       case 18: sItem = "nw_wspmsc010"; break;
+                       case 19: sItem = "nw_wswmsc010"; break;
+                   }
+
+            }
+            else  // * 2500 - 16500
+            {
+                  int nRandom = Random(15) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmdt007"; break;
+                       case 2: sItem = "nw_wthmdt004"; break;
+                       case 3: sItem = "nw_wbwmsl010"; break;
+                       case 4: sItem = "nw_wblmcl010"; break;
+                       case 5: sItem = "nw_wdbmqs008"; break;
+                       case 6: sItem = "nw_wplmss010"; break;
+                       case 7: sItem = "nw_wswmdg008"; break;
+                       case 8: sItem = "nw_wspmsc010"; break;
+                       case 9: sItem = "nw_wswmsc010"; break;
+                       case 10: sItem = "nw_wblmcl011"; break;
+                       case 11: sItem = "nw_wdbmqs009"; break;
+                       case 12: sItem = "nw_wplmss011"; break;
+                       case 13: sItem = "nw_wswmdg009"; break;
+                       case 14: sItem = "nw_wspmsc011"; break;
+                       case 15: sItem = "nw_wswmsc011"; break;
+                   }
+
+            }
+          //dbSpeak("Generic Druid weapon");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+
+
+        }
+        void CreateSpecificDruidWeapon(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericDruidWeapon(oTarget, oAdventurer, JUMP_LEVEL); return;
+
+            }
+            else if (GetRange(2, nHD))   // * 2500
+            {
+                CreateGenericDruidWeapon(oTarget, oAdventurer, JUMP_LEVEL); return;
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmqs005"; break;
+                       case 2: sItem = "nw_wdbmqs006"; break;
+                       case 3: sItem = "nw_wbwmsl005"; break;
+                       case 4: sItem = "nw_wswmdg006"; break;
+                       case 5: CreateGenericDruidWeapon(oTarget, oAdventurer, JUMP_LEVEL); return; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 -16500
+            {
+                  int nRandom = Random(10) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmqs005"; break;
+                       case 2: sItem = "nw_wdbmqs006"; break;
+                       case 3: sItem = "nw_wbwmsl005"; break;
+                       case 4: sItem = "nw_wswmdg006"; break;
+                       case 5: sItem = "nw_wblmcl004"; break;
+                       case 6: sItem = "nw_wdbmqs004"; break;
+                       case 7: sItem = "nw_wblmcl003"; break;
+                       case 8: sItem = "nw_wbwmsl003"; break;
+                       case 9: sItem = "nw_wswmsc004"; break;
+                       case 10: sItem = "nw_wplmss005"; break;
+                   }
+
+            }
+            else  // * 16000 +
+            {
+                  int nRandom = Random(18) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmqs003"; break;
+                       case 2: sItem = "nw_wblmcl005"; break;
+                       case 3: sItem = "nw_wplmss007"; break;
+                       case 4: sItem = "nw_wswmdg004"; break;
+                       case 5: sItem = "nw_wbwmsl007"; break;
+                       case 6: sItem = "nw_wplmss006"; break;
+                       case 7: sItem = "nw_wswmsc006"; break;
+                       case 8: sItem = "nw_wswmdg003"; break;
+                       case 9: sItem = "nw_wswmdg007"; break;
+                       case 10: sItem = "nw_wswmsc007"; break;
+                       case 11: sItem = "nw_wbwmsl006"; break;
+                       case 12: sItem = "nw_wbwmsl008"; break;
+                       case 13: sItem = "nw_wdbmqs007"; break;
+                       case 14: sItem = "nw_wblmcl006"; break;
+                       case 15: sItem = "nw_wbwmsl004"; break;
+                       case 16: sItem = "nw_wswmsc005"; break;
+                       case 17: sItem = "nw_wplmss004"; break;
+                       case 18: sItem = "nw_wswmdg005"; break;
+                   }
+
+            }
+          //dbSpeak("specific druid weapon");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+
+        }
+
+        void CreateGenericWizardWeapon(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wblcl001"; break;
+                       case 2: sItem = "nw_wdbqs001"; break;
+                       case 3: sItem = "nw_wswdg001"; break;
+                       case 4: sItem = "nw_wbwxh001"; break;
+                       case 5: sItem = "nw_wbwxl001"; break;
+                   }
+
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                  int nRandom = Random(6) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wblcl001"; break;
+                       case 2: sItem = "nw_wdbqs001"; break;
+                       case 3: sItem = "nw_wswdg001"; break;
+                       case 4: sItem = "nw_wbwxh001"; break;
+                       case 5: sItem = "nw_wbwxl001"; break;
+                       case 6: sItem = "nw_wbwmxl002"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(6) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmxl002"; break;
+                       case 2: sItem = "nw_wblmcl002"; break;
+                       case 3: sItem = "nw_wdbmqs002"; break;
+                       case 4: sItem = "nw_wswmdg002"; break;
+                       case 5: sItem = "nw_wbwmxh008"; break;
+                       case 6: sItem = "nw_wbwmxl008"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(10) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wblmcl002"; break;
+                       case 2: sItem = "nw_wdbmqs002"; break;
+                       case 3: sItem = "nw_wswmdg002"; break;
+                       case 4: sItem = "nw_wbwmxh008"; break;
+                       case 5: sItem = "nw_wbwmxl008"; break;
+                       case 6: sItem = "nw_wbwmxh009"; break;
+                       case 7: sItem = "nw_wbwmxl009"; break;
+                       case 8: sItem = "nw_wblmcl010"; break;
+                       case 9: sItem = "nw_wdbmqs008"; break;
+                       case 10: sItem = "nw_wswmdg008"; break;
+                   }
+
+            }
+            else  // * 2500 - 16500
+            {
+                  int nRandom = Random(8) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmxh009"; break;
+                       case 2: sItem = "nw_wbwmxl009"; break;
+                       case 3: sItem = "nw_wblmcl010"; break;
+                       case 4: sItem = "nw_wdbmqs008"; break;
+                       case 5: sItem = "nw_wswmdg008"; break;
+                       case 6: sItem = "nw_wblmcl011"; break;
+                       case 7: sItem = "nw_wdbmqs009"; break;
+                       case 8: sItem = "nw_wswmdg009"; break;
+                   }
+
+            }
+          //dbSpeak("Generic Wizard or Sorcerer Weapon");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+
+        }
+        void CreateSpecificWizardWeapon(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericWizardWeapon(oTarget, oAdventurer, JUMP_LEVEL); return;
+            }
+            else if (GetRange(2, nHD))   // * 2500
+            {
+                CreateGenericWizardWeapon(oTarget, oAdventurer, JUMP_LEVEL); return;
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmqs005"; break;
+                       case 2: sItem = "nw_wdbmqs006"; break;
+                       case 3: sItem = "nw_wbwmxh005"; break;
+                       case 4: sItem = "nw_wbwmxl005"; break;
+                       case 5: sItem = "nw_wswmdg006"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 -16500
+            {
+                  int nRandom = Random(10) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmqs005"; break;
+                       case 2: sItem = "nw_wdbmqs006"; break;
+                       case 3: sItem = "nw_wbwmxh005"; break;
+                       case 4: sItem = "nw_wbwmxl005"; break;
+                       case 5: sItem = "nw_wswmdg006"; break;
+                       case 6: sItem = "nw_wblmcl004"; break;
+                       case 7: sItem = "nw_wdbmqs004"; break;
+                       case 8: sItem = "nw_wblmcl003"; break;
+                       case 9: sItem = "nw_wbwmxh003"; break;
+                       case 10: sItem = "nw_wbwmxl003"; break;
+                   }
+
+            }
+            else  // * 16000 +
+            {
+                  int nRandom = Random(15) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmxl003"; break;
+                       case 2: sItem = "nw_wdbmqs003"; break;
+                       case 3: sItem = "nw_wbwmxl004"; break;
+                       case 4: sItem = "nw_wbwmxl007"; break;
+                       case 5: sItem = "nw_wblmcl005"; break;
+                       case 6: sItem = "nw_wswmdg004"; break;
+                       case 7: sItem = "nw_wbwmxh004"; break;
+                       case 8: sItem = "nw_wbwmxh007"; break;
+                       case 9: sItem = "nw_wswmdg003"; break;
+                       case 10: sItem = "nw_wswmdg007"; break;
+                       case 11: sItem = "nw_wdbmqs007"; break;
+                       case 12: sItem = "nw_wblmcl006"; break;
+                       case 13: sItem = "nw_wbwmxh006"; break;
+                       case 14: sItem = "nw_wswmdg005"; break;
+                       case 15: sItem = "nw_wbwmxl006"; break;
+                   }
+
+            }
+          //dbSpeak("Specific Wizard or Sorcerer Weapon");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+
+        }
+
+        void CreateGenericSimple(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+           string sItem = "";
+           int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                int nRandom = d12();
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wthdt001"; break;
+                    case 2: sItem = "nw_wblcl001"; break;
+                    case 3: sItem = "nw_wbwsl001"; break;
+                    case 4: sItem = "nw_wplss001"; break;
+                    case 5: sItem = "nw_wdbqs001"; break;
+                    case 6: sItem = "nw_wswdg001"; break;
+                    case 7: sItem = "nw_wblml001"; break;
+                    case 8: sItem = "nw_wbwxh001"; break;
+                    case 9: sItem = "nw_wspsc001"; break;
+                    case 10: sItem = "nw_wblms001"; break;
+                    case 11: sItem = "nw_wbwxl001"; break;
+                    case 12: sItem = "nw_wthmdt002"; break;
+                }
+
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                int nRandom = Random(17) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wthdt001"; break;
+                    case 2: sItem = "nw_wblcl001"; break;
+                    case 3: sItem = "nw_wbwsl001"; break;
+                    case 4: sItem = "nw_wplss001"; break;
+                    case 5: sItem = "nw_wdbqs001"; break;
+                    case 6: sItem = "nw_wswdg001"; break;
+                    case 7: sItem = "nw_wblml001"; break;
+                    case 8: sItem = "nw_wbwxh001"; break;
+                    case 9: sItem = "nw_wspsc001"; break;
+                    case 10: sItem = "nw_wblms001"; break;
+                    case 11: sItem = "nw_wbwxl001"; break;
+                    case 12: sItem = "nw_wthmdt002"; break;
+                    case 13: sItem = "nw_wthmdt005"; break;
+                    case 14: sItem = "nw_wbwmsl001"; break;
+                    case 15: sItem = "nw_wbwmxh002"; break;
+                    case 16: sItem = "nw_wthmdt008"; break;
+                    case 17: sItem = "nw_wbwmxl002"; break;
+                }
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                int nRandom = Random(19) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wthmdt005"; break;
+                    case 2: sItem = "nw_wbwmsl001"; break;
+                    case 3: sItem = "nw_wbwmxh002"; break;
+                    case 4: sItem = "nw_wthmdt008"; break;
+                    case 5: sItem = "nw_wbwmxl002"; break;
+                    case 6: sItem = "nw_wthmdt009"; break;
+                    case 7: sItem = "nw_wthmdt006"; break;
+                    case 8: sItem = "nw_wblmcl002"; break;
+                    case 9: sItem = "nw_wplmss002"; break;
+                    case 10: sItem = "nw_wdbmqs002"; break;
+                    case 11: sItem = "nw_wswmdg002"; break;
+                    case 12: sItem = "nw_wblmml002"; break;
+                    case 13: sItem = "nw_wspmsc002"; break;
+                    case 14: sItem = "nw_wblmms002"; break;
+                    case 15: sItem = "nw_wthmdt003"; break;
+                    case 16: sItem = "nw_wthmdt003"; break;
+                    case 17: sItem = "nw_wbwmsl009"; break;
+                    case 18: sItem = "nw_wbwmxh008"; break;
+                    case 19: sItem = "nw_wbwmxl008"; break;
+                }
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                int nRandom = Random(27) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wthmdt009"; break;
+                    case 2: sItem = "nw_wthmdt006"; break;
+                    case 3: sItem = "nw_wblmcl002"; break;
+                    case 4: sItem = "nw_wplmss002"; break;
+                    case 5: sItem = "nw_wdbmqs002"; break;
+                    case 6: sItem = "nw_wswmdg002"; break;
+                    case 7: sItem = "nw_wblmml002"; break;
+                    case 8: sItem = "nw_wspmsc002"; break;
+                    case 9: sItem = "nw_wblmms002"; break;
+                    case 10: sItem = "nw_wthmdt003"; break;
+                    case 11: sItem = "nw_wthmdt003"; break;
+                    case 12: sItem = "nw_wbwmsl009"; break;
+                    case 13: sItem = "nw_wbwmxh008"; break;
+                    case 14: sItem = "nw_wbwmxl008"; break;
+                    case 15: sItem = "nw_wthmdt007"; break;
+                    case 16: sItem = "nw_wthmdt004"; break;
+                    case 17: sItem = "nw_wbwmsl010"; break;
+                    case 18: sItem = "nw_wbwmxh009"; break;
+                    case 19: sItem = "nw_wbwmxl009"; break;
+                    case 20: sItem = "nw_wbwmsl005"; break;
+                    case 21: sItem = "nw_wblmcl010"; break;
+                    case 22: sItem = "nw_wplmss010"; break;
+                    case 23: sItem = "nw_wdbmqs008"; break;
+                    case 24: sItem = "nw_wswmdg008"; break;
+                    case 25: sItem = "nw_wblmml011"; break;
+                    case 26: sItem = "nw_wspmsc010"; break;
+                    case 27: sItem = "nw_wblmms010"; break;
+
+
+
+                }
+
+            }
+            else if (GetRange(5, nHD))   // * 2500 - 16500
+            {
+                int nRandom = Random(23) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wthmdt007"; break;
+                    case 2: sItem = "nw_wthmdt004"; break;
+                    case 3: sItem = "nw_wbwmsl010"; break;
+                    case 4: sItem = "nw_wbwmxh009"; break;
+                    case 5: sItem = "nw_wbwmxl009"; break;
+                    case 6: sItem = "nw_wbwmsl005"; break;
+                    case 7: sItem = "nw_wblmcl010"; break;
+                    case 8: sItem = "nw_wplmss010"; break;
+                    case 9: sItem = "nw_wdbmqs008"; break;
+                    case 10: sItem = "nw_wswmdg008"; break;
+                    case 11: sItem = "nw_wblmml011"; break;
+                    case 12: sItem = "nw_wspmsc010"; break;
+                    case 13: sItem = "nw_wblmms010"; break;
+                    case 14: sItem = "nw_wblmms010"; break;
+                    case 15: sItem = "nw_wblmms010"; break;
+                    case 16: sItem = "nw_wblmms010"; break;
+                    case 17: sItem = "nw_wblmcl011"; break;
+                    case 18: sItem = "nw_wplmss011"; break;
+                    case 19: sItem = "nw_wdbmqs009"; break;
+                    case 20: sItem = "nw_wswmdg009"; break;
+                    case 21: sItem = "nw_wblmml012"; break;
+                    case 22: sItem = "nw_wspmsc011"; break;
+                    case 23: sItem = "nw_wblmms011"; break;
+
+
+
+                }
+            }
+            else if (GetRange(6, nHD))   // * 8000 - 25000
+            {
+                int nRandom = Random(7) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wblmcl011"; break;
+                    case 2: sItem = "nw_wplmss011"; break;
+                    case 3: sItem = "nw_wdbmqs009"; break;
+                    case 4: sItem = "nw_wswmdg009"; break;
+                    case 5: sItem = "nw_wblmml012"; break;
+                    case 6: sItem = "nw_wspmsc011"; break;
+                    case 7: sItem = "nw_wblmms011"; break;
+
+
+
+                }
+            }
+            //dbSpeak("Create Generic SImple; Specific = " + IntToString(nModifier));
+
+            dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateGenericMartial(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+           string sItem = "";
+
+            int nHD = GetHitDice(oAdventurer) +nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                int nRandom = Random(17) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wthax001"; break;
+                    case 2: sItem = "nw_wblhl001"; break;
+                    case 3: sItem = "nw_waxhn001"; break;
+                    case 4: sItem = "nw_wblfl001"; break;
+                    case 5: sItem = "nw_waxbt001"; break;
+                    case 6: sItem = "nw_wplhb001"; break;
+                    case 7: sItem = "nw_wswss001"; break;
+                    case 8: sItem = "nw_wblhw001"; break;
+                    case 9: sItem = "nw_wblfh001"; break;
+                    case 10: sItem = "nw_wswls001"; break;
+                    case 11: sItem = "nw_wswsc001"; break;
+                    case 12: sItem = "nw_waxgr001"; break;
+                    case 13: sItem = "nw_wswrp001"; break;
+                    case 14: sItem = "nw_wbwsh001"; break;
+                    case 15: sItem = "nw_wswbs001"; break;
+                    case 16: sItem = "nw_wswgs001"; break;
+                    case 17: sItem = "nw_wbwln001"; break;
+                }
+
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                int nRandom = Random(20) + 1;
+                switch (nRandom)
+                {
+                    case 1: sItem = "nw_wthax001"; break;
+                    case 2: sItem = "nw_wblhl001"; break;
+                    case 3: sItem = "nw_waxhn001"; break;
+                    case 4: sItem = "nw_wblfl001"; break;
+                    case 5: sItem = "nw_waxbt001"; break;
+                    case 6: sItem = "nw_wplhb001"; break;
+                    case 7: sItem = "nw_wswss001"; break;
+                    case 8: sItem = "nw_wblhw001"; break;
+                    case 9: sItem = "nw_wblfh001"; break;
+                    case 10: sItem = "nw_wswls001"; break;
+                    case 11: sItem = "nw_wswsc001"; break;
+                    case 12: sItem = "nw_waxgr001"; break;
+                    case 13: sItem = "nw_wswrp001"; break;
+                    case 14: sItem = "nw_wbwsh001"; break;
+                    case 15: sItem = "nw_wswbs001"; break;
+                    case 16: sItem = "nw_wswgs001"; break;
+                    case 17: sItem = "nw_wbwln001"; break;
+                    case 18: sItem = "nw_wthmax002"; break;
+                    case 19: sItem = "nw_wbwmsh002"; break;
+                    case 20: sItem = "nw_wbwmln002"; break;
+                }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                int nRandom = Random(20) + 1;
+                switch (nRandom)
+                {
+                         case 1: sItem = "nw_wthmax002"; break;
+                         case 2: sItem = "nw_wbwmsh002"; break;
+                         case 3: sItem = "nw_wbwmln002"; break;
+                         case 4: sItem = "nw_wblmhl002"; break;
+                         case 5: sItem = "nw_waxmhn002"; break;
+                         case 6: sItem = "nw_wblmfl002"; break;
+                         case 7: sItem = "nw_waxmbt002"; break;
+                         case 8: sItem = "nw_wplmhb002"; break;
+                         case 9: sItem = "nw_wblmhw002"; break;
+                         case 10: sItem = "nw_wblmfh002"; break;
+                         case 11: sItem = "nw_wswmls002"; break;
+                         case 12: sItem = "nw_wswmsc002"; break;
+                         case 13: sItem = "nw_waxmgr002"; break;
+                         case 14: sItem = "nw_wswmrp002"; break;
+                         case 15: sItem = "nw_wswmbs002"; break;
+                         case 16: sItem = "nw_wswmgs002"; break;
+                         case 17: sItem = "nw_wthmax008"; break;
+                         case 18: sItem = "nw_wbwmsh008"; break;
+                         case 19: sItem = "nw_wbwmln008"; break;
+                         case 20: sItem = "nw_wswmss002"; break;
+
+                 }
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                int nRandom = Random(33) + 1;
+                switch (nRandom)
+                {
+                     case 1: sItem = "nw_wblmhl002"; break;
+                     case 2: sItem = "nw_waxmhn002"; break;
+                     case 3: sItem = "nw_wblmfl002"; break;
+                     case 4: sItem = "nw_waxmbt002"; break;
+                     case 5: sItem = "nw_wplmhb002"; break;
+                     case 6: sItem = "nw_wblmhw002"; break;
+                     case 7: sItem = "nw_wblmfh002"; break;
+                     case 8: sItem = "nw_wswmls002"; break;
+                     case 9: sItem = "nw_wswmsc002"; break;
+                     case 10: sItem = "nw_waxmgr002"; break;
+                     case 11: sItem = "nw_wswmrp002"; break;
+                     case 12: sItem = "nw_wswmbs002"; break;
+                     case 13: sItem = "nw_wswmgs002"; break;
+                     case 14: sItem = "nw_wthmax008"; break;
+                     case 15: sItem = "nw_wbwmsh008"; break;
+                     case 16: sItem = "nw_wbwmln008"; break;
+                     case 17: sItem = "nw_wbwmsh009"; break;
+                     case 18: sItem = "nw_wbwmln009"; break;
+                     case 19: sItem = "nw_wblmhl010"; break;
+                     case 20: sItem = "nw_waxmhn010"; break;
+                     case 21: sItem = "nw_wblmfl010"; break;
+                     case 22: sItem = "nw_waxmbt010"; break;
+                     case 23: sItem = "nw_wplmhb010"; break;
+                     case 24: sItem = "nw_wblmhw011"; break;
+                     case 25: sItem = "nw_wblmfh010"; break;
+                     case 26: sItem = "nw_wswmls010"; break;
+                     case 27: sItem = "nw_waxmgr009"; break;
+                     case 28: sItem = "nw_wswmbs009"; break;
+                     case 29: sItem = "nw_wswmgs011"; break;
+                     case 30: sItem = "nw_wswmrp010"; break;
+                    case 31: sItem = "nw_wswmsc010"; break;
+                    case 32: sItem = "nw_wswmss002"; break;
+                    case 33: sItem = "nw_wswmss009"; break;
+                 }
+
+            }
+            else if (GetRange(5, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(20) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmsh009"; break;
+                       case 2: sItem = "nw_wbwmln009"; break;
+                       case 3: sItem = "nw_wblmhl010"; break;
+                       case 4: sItem = "nw_waxmhn010"; break;
+                       case 5: sItem = "nw_wblmfl010"; break;
+                       case 6: sItem = "nw_waxmbt010"; break;
+                       case 7: sItem = "nw_wplmhb010"; break;
+                       case 8: sItem = "nw_wblmhw011"; break;
+                       case 9: sItem = "nw_wblmfh010"; break;
+                       case 10: sItem = "nw_wswmls010"; break;
+                       case 11: sItem = "nw_waxmgr009"; break;
+                       case 12: sItem = "nw_wswmbs009"; break;
+                       case 13: sItem = "nw_wswmgs011"; break;
+                       case 14: sItem = "nw_wthmax009"; break;
+                        case 15: sItem = "nw_wswmrp010"; break;
+                        case 16: sItem = "nw_wswmrp011"; break;
+                        case 17: sItem = "nw_wswmsc010"; break;
+                        case 18: sItem = "nw_wswmss009"; break;
+                        case 19: sItem = "nw_wswmsc011"; break;
+                        case 20: sItem = "nw_wswmss011"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(14) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmax009"; break;
+                       case 2: sItem = "nw_waxmhn011"; break;
+                       case 3: sItem = "nw_wblmfl011"; break;
+                       case 4: sItem = "nw_waxmbt011"; break;
+                       case 5: sItem = "nw_wplmhb011"; break;
+                       case 6: sItem = "nw_wblmhw012"; break;
+                       case 7: sItem = "nw_wblmfh011"; break;
+                       case 8: sItem = "nw_wswmls012"; break;
+                       case 9: sItem = "nw_waxmgr011"; break;
+                       case 10: sItem = "nw_wswmbs010"; break;
+                       case 11: sItem = "nw_wswmgs012"; break;
+                        case 12: sItem = "nw_wswmrp011"; break;
+                        case 13: sItem = "nw_wswmsc011"; break;
+                        case 14: sItem = "nw_wswmss011"; break;
+                   }
+
+            }
+
+            //dbSpeak("Create Generic Martial");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateGenericExotic(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+            string sItem = "";
+
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthsh001"; break;
+                       case 2: sItem = "nw_wspka001"; break;
+                       case 3: sItem = "nw_wspku001"; break;
+                       case 4: sItem = "nw_wplsc001"; break;
+                       case 5: sItem = "nw_wdbax001"; break;
+                       case 6: sItem = "nw_wdbma001"; break;
+                       case 7: sItem = "nw_wswka001"; break;
+                       case 8: sItem = "nw_wthmsh002"; break;
+                       case 9: sItem = "nw_wdbsw001"; break;
+                   }
+
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                  int nRandom = Random(17) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthsh001"; break;
+                       case 2: sItem = "nw_wspka001"; break;
+                       case 3: sItem = "nw_wspku001"; break;
+                       case 4: sItem = "nw_wplsc001"; break;
+                       case 5: sItem = "nw_wdbax001"; break;
+                       case 6: sItem = "nw_wdbma001"; break;
+                       case 7: sItem = "nw_wswka001"; break;
+                       case 8: sItem = "nw_wthmsh002"; break;
+                       case 9: sItem = "nw_wdbsw001"; break;
+                       case 10: sItem = "nw_wthmsh005"; break;
+                       case 11: sItem = "nw_wspmka002"; break;
+                       case 12: sItem = "nw_wspmku002"; break;
+                       case 13: sItem = "nw_wplmsc002"; break;
+                       case 14: sItem = "nw_wdbmax002"; break;
+                       case 15: sItem = "nw_wdbmma002"; break;
+                       case 16: sItem = "nw_wswmka002"; break;
+                       case 17: sItem = "nw_wdbmsw002"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbsw001"; break;
+                       case 2: sItem = "nw_wthmsh005"; break;
+                       case 3: sItem = "nw_wspmka002"; break;
+                       case 4: sItem = "nw_wspmku002"; break;
+                       case 5: sItem = "nw_wplmsc002"; break;
+                       case 6: sItem = "nw_wdbmax002"; break;
+                       case 7: sItem = "nw_wdbmma002"; break;
+                       case 8: sItem = "nw_wswmka002"; break;
+                       case 9: sItem = "nw_wdbmsw002"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(17) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmsh005"; break;
+                       case 2: sItem = "nw_wspmka002"; break;
+                       case 3: sItem = "nw_wspmku002"; break;
+                       case 4: sItem = "nw_wplmsc002"; break;
+                       case 5: sItem = "nw_wdbmax002"; break;
+                       case 6: sItem = "nw_wdbmma002"; break;
+                       case 7: sItem = "nw_wswmka002"; break;
+                       case 8: sItem = "nw_wdbmsw002"; break;
+                       case 9: sItem = "nw_wthmsh008"; break;
+                       case 10: sItem = "nw_wspmka008"; break;
+                       case 11: sItem = "nw_wspmku008"; break;
+                       case 12: sItem = "nw_wplmsc010"; break;
+                       case 13: sItem = "nw_wdbmax010"; break;
+                       case 14: sItem = "nw_wdbmma010"; break;
+                       case 15: sItem = "nw_wswmka010"; break;
+                       case 16: sItem = "nw_wdbmsw010"; break;
+                       case 17: sItem = "nw_wthmsh009"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(13) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wspmka008"; break;
+                       case 2: sItem = "nw_wspmku008"; break;
+                       case 3: sItem = "nw_wplmsc010"; break;
+                       case 4: sItem = "nw_wdbmax010"; break;
+                       case 5: sItem = "nw_wdbmma010"; break;
+                       case 6: sItem = "nw_wswmka010"; break;
+                       case 7: sItem = "nw_wdbmsw010"; break;
+                       case 8: sItem = "nw_wthmsh009"; break;
+                       case 9: sItem = "nw_wspmka009"; break;
+                       case 10: sItem = "nw_wspmku009"; break;
+                       case 11: sItem = "nw_wplmsc011"; break;
+                       case 12: sItem = "nw_wdbmax011"; break;
+                       case 13: sItem = "nw_wdbmma011"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 8000 - 25000
+            {
+            int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmsw010"; break;
+                       case 2: sItem = "nw_wthmsh009"; break;
+                       case 3: sItem = "nw_wspmka009"; break;
+                       case 4: sItem = "nw_wspmku009"; break;
+                       case 5: sItem = "nw_wplmsc011"; break;
+                       case 6: sItem = "nw_wdbmax011"; break;
+                       case 7: sItem = "nw_wdbmma011"; break;
+                       case 8: sItem = "nw_wswmka011"; break;
+                       case 9: sItem = "nw_wdbmsw011"; break;
+                   }
+
+            }
+                  //dbSpeak("Create generic exotic");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateGenericLightArmor(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+            string sItem = "";
+
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_aarcl009"; break;
+                       case 2: sItem = "nw_ashsw001"; break;
+                       case 3: sItem = "nw_aarcl001"; break;
+                       case 4: sItem = "nw_aarcl002"; break;
+                       case 5: sItem = "nw_aarcl012"; break;
+                   }
+
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_aarcl009"; break;
+                       case 2: sItem = "nw_ashsw001"; break;
+                       case 3: sItem = "nw_aarcl001"; break;
+                       case 4: sItem = "nw_aarcl002"; break;
+                       case 5: sItem = "nw_aarcl012"; break;
+                       case 6: sItem = "nw_maarcl043"; break;
+                       case 7: sItem = "nw_ashmsw002"; break;
+                       case 8: sItem = "nw_maarcl044"; break;
+                       case 9: sItem = "nw_maarcl045"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(8) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl043"; break;
+                       case 2: sItem = "nw_ashmsw002"; break;
+                       case 3: sItem = "nw_maarcl044"; break;
+                       case 4: sItem = "nw_maarcl045"; break;
+                       case 5: sItem = "nw_maarcl072"; break;
+                       case 6: sItem = "nw_ashmsw008"; break;
+                       case 7: sItem = "nw_maarcl071"; break;
+                       case 8: sItem = "nw_maarcl075"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl072"; break;
+                       case 2: sItem = "nw_ashmsw008"; break;
+                       case 3: sItem = "nw_maarcl071"; break;
+                       case 4: sItem = "nw_maarcl075"; break;
+                       case 5: sItem = "nw_maarcl084"; break;
+                       case 6: sItem = "nw_ashmsw009"; break;
+                       case 7: sItem = "nw_maarcl083"; break;
+                       case 8: sItem = "nw_maarcl087"; break;
+                       case 9: sItem = "nw_maarcl079"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl084"; break;
+                       case 2: sItem = "nw_ashmsw009"; break;
+                       case 3: sItem = "nw_maarcl083"; break;
+                       case 4: sItem = "nw_maarcl087"; break;
+                       case 5: sItem = "nw_maarcl079"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl084"; break;
+                       case 2: sItem = "nw_ashmsw009"; break;
+                       case 3: sItem = "nw_maarcl083"; break;
+                       case 4: sItem = "nw_maarcl087"; break;
+                       case 5: sItem = "nw_maarcl079"; break;
+                   }
+
+            }
+                  //dbSpeak("Create Generic light");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateGenericMediumArmor(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+            string sItem = "";
+            if (GetRange(1, nHD))    // * 200
+            {
+                 int nRandom = Random(10) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_arhe001"; break;
+                       case 2: sItem = "nw_arhe002"; break;
+                       case 3: sItem = "nw_arhe003"; break;
+                       case 4: sItem = "nw_arhe004"; break;
+                       case 5: sItem = "nw_arhe005"; break;
+                       case 6: sItem = "nw_aarcl008"; break;
+                       case 7: sItem = "nw_ashlw001"; break;
+                       case 8: sItem = "nw_aarcl003"; break;
+                       case 9: sItem = "nw_aarcl004"; break;
+                       case 10: sItem = "nw_aarcl010"; break;
+                   }
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                  int nRandom = Random(17) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_arhe001"; break;
+                       case 2: sItem = "nw_arhe002"; break;
+                       case 3: sItem = "nw_arhe003"; break;
+                       case 4: sItem = "nw_arhe004"; break;
+                       case 5: sItem = "nw_arhe005"; break;
+                       case 6: sItem = "nw_aarcl008"; break;
+                       case 7: sItem = "nw_ashlw001"; break;
+                       case 8: sItem = "nw_aarcl003"; break;
+                       case 9: sItem = "nw_aarcl004"; break;
+                       case 10: sItem = "nw_aarcl010"; break;
+                       case 11: sItem = "nw_maarcl047"; break;
+                       case 12: sItem = "nw_ashmlw002"; break;
+                       case 13: sItem = "nw_maarcl046"; break;
+                       case 14: sItem = "nw_maarcl048"; break;
+                       case 15: sItem = "nw_maarcl035"; break;
+                       case 16: sItem = "nw_maarcl049"; break;
+                       case 17: sItem = "nw_maarcl050"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl047"; break;
+                       case 2: sItem = "nw_ashmlw002"; break;
+                       case 3: sItem = "nw_maarcl046"; break;
+                       case 4: sItem = "nw_maarcl048"; break;
+                       case 5: sItem = "nw_maarcl035"; break;
+                       case 6: sItem = "nw_maarcl049"; break;
+                       case 7: sItem = "nw_maarcl050"; break;
+                       case 8: sItem = "nw_maarcl070"; break;
+                       case 9: sItem = "nw_ashmlw008"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                   int nRandom = Random(14) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl035"; break;
+                       case 2: sItem = "nw_maarcl049"; break;
+                       case 3: sItem = "nw_maarcl050"; break;
+                       case 4: sItem = "nw_maarcl070"; break;
+                       case 5: sItem = "nw_ashmlw008"; break;
+                       case 6: sItem = "nw_maarcl067"; break;
+                       case 7: sItem = "nw_maarcl073"; break;
+                       case 8: sItem = "nw_maarcl065"; break;
+                       case 9: sItem = "nw_maarcl066"; break;
+                       case 10: sItem = "nw_maarcl082"; break;
+                       case 11: sItem = "nw_ashmlw009"; break;
+                       case 12: sItem = "nw_maarcl085"; break;
+                       case 13: sItem = "nw_maarcl077"; break;
+                       case 14: sItem = "nw_maarcl078"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(11) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl070"; break;
+                       case 2: sItem = "nw_ashmlw008"; break;
+                       case 3: sItem = "nw_maarcl067"; break;
+                       case 4: sItem = "nw_maarcl073"; break;
+                       case 5: sItem = "nw_maarcl065"; break;
+                       case 6: sItem = "nw_maarcl066"; break;
+                       case 7: sItem = "nw_maarcl082"; break;
+                       case 8: sItem = "nw_ashmlw009"; break;
+                       case 9: sItem = "nw_maarcl085"; break;
+                       case 10: sItem = "nw_maarcl077"; break;
+                       case 11: sItem = "nw_maarcl078"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(11) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl070"; break;
+                       case 2: sItem = "nw_ashmlw008"; break;
+                       case 3: sItem = "nw_maarcl067"; break;
+                       case 4: sItem = "nw_maarcl073"; break;
+                       case 5: sItem = "nw_maarcl065"; break;
+                       case 6: sItem = "nw_maarcl066"; break;
+                       case 7: sItem = "nw_maarcl082"; break;
+                       case 8: sItem = "nw_ashmlw009"; break;
+                       case 9: sItem = "nw_maarcl085"; break;
+                       case 10: sItem = "nw_maarcl077"; break;
+                       case 11: sItem = "nw_maarcl078"; break;
+                   }
+
+            }
+                  //dbSpeak("Create Generic medium");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateGenericHeavyArmor(object oTarget, object oAdventurer, int nModifier = 0)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer) + nModifier;
+
+            if (GetRange(1, nHD))    // * 200
+            {
+                  int nRandom = Random(3) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_ashto001"; break;
+                       case 2: sItem = "nw_aarcl005"; break;
+                       case 3: sItem = "nw_aarcl011"; break;
+                   }
+
+            }
+            else if (GetRange(2, nHD))   // * 800
+            {
+                  int nRandom = Random(6) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_ashto001"; break;
+                       case 2: sItem = "nw_aarcl005"; break;
+                       case 3: sItem = "nw_aarcl011"; break;
+                       case 4: sItem = "nw_aarcl006"; break;
+                       case 5: sItem = "nw_ashmto002"; break;
+                       case 6: sItem = "nw_maarcl051"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_aarcl005"; break;
+                       case 2: sItem = "nw_aarcl011"; break;
+                       case 3: sItem = "nw_aarcl006"; break;
+                       case 4: sItem = "nw_ashmto002"; break;
+                       case 5: sItem = "nw_maarcl051"; break;
+                       case 6: sItem = "nw_maarcl052"; break;
+                       case 7: sItem = "nw_aarcl007"; break;
+                       case 8: sItem = "nw_maarcl053"; break;
+                       case 9: sItem = "nw_ashmto008"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(15) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl051"; break;
+                       case 2: sItem = "nw_maarcl052"; break;
+                       case 3: sItem = "nw_aarcl007"; break;
+                       case 4: sItem = "nw_maarcl053"; break;
+                       case 5: sItem = "nw_ashmto008"; break;
+                       case 6: sItem = "nw_maarcl064"; break;
+                       case 7: sItem = "nw_maarcl074"; break;
+                       case 8: sItem = "nw_maarcl069"; break;
+                       case 9: sItem = "nw_maarcl068"; break;
+                       case 10: sItem = "nw_ashmto003"; break;
+                       case 11: sItem = "nw_ashmto009"; break;
+                       case 12: sItem = "nw_maarcl076"; break;
+                       case 13: sItem = "nw_maarcl086"; break;
+                       case 14: sItem = "nw_maarcl081"; break;
+                       case 15: sItem = "nw_maarcl080"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(10) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_ashmto008"; break;
+                       case 2: sItem = "nw_maarcl064"; break;
+                       case 3: sItem = "nw_maarcl074"; break;
+                       case 4: sItem = "nw_maarcl069"; break;
+                       case 5: sItem = "nw_maarcl068"; break;
+                       case 6: sItem = "nw_ashmto009"; break;
+                       case 7: sItem = "nw_maarcl076"; break;
+                       case 8: sItem = "nw_maarcl086"; break;
+                       case 9: sItem = "nw_maarcl081"; break;
+                       case 10: sItem = "nw_maarcl080"; break;
+                   }
+
+
+            }
+            else if (GetRange(6, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_ashmto009"; break;
+                       case 2: sItem = "nw_maarcl076"; break;
+                       case 3: sItem = "nw_maarcl086"; break;
+                       case 4: sItem = "nw_maarcl081"; break;
+                       case 5: sItem = "nw_maarcl080"; break;
+                   }
+
+            }
+                 // dbSpeak("Create Generic heavy");
+
+           dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        // *
+        // * SPECIC TREASURE ITEMS (re: Named Items)
+        // *
+        void CreateSpecificMiscItem(object oTarget,object oAdventurer)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer);
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericMiscItem(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(2, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(3) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: CreateGenericMiscItem(oTarget, oAdventurer, JUMP_LEVEL); return; break;
+                       case 2: sItem = "nw_maarcl057"; break;
+                       case 3: sItem = "nw_it_mbelt005"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(13) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl057"; break;
+                       case 2: sItem = "nw_it_mbelt005"; break;
+                       case 3: sItem = "nw_maarcl101"; break;
+                       case 4: sItem = "nw_maarcl102"; break;
+                       case 5: sItem = "nw_maarcl103"; break;
+                       case 6: sItem = "nw_it_mglove001"; break;
+                       case 7: sItem = "nw_maarcl100"; break;
+                       case 8: sItem = "nw_it_mbracer011"; break;
+                       case 9: sItem = "nw_it_mmidmisc04"; break;
+                       case 10: sItem = "nw_it_mring003"; break;
+                       case 11: sItem = "nw_it_mbelt006"; break;
+                       case 12: sItem = "nw_it_mbelt002"; break;
+                       case 13: sItem = "nw_it_mmidmisc03"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(19) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl101"; break;
+                       case 2: sItem = "nw_maarcl101"; break;
+                       case 3: sItem = "nw_maarcl102"; break;
+                       case 4: sItem = "nw_maarcl103"; break;
+                       case 5: sItem = "nw_it_mglove001"; break;
+                       case 6: sItem = "nw_maarcl100"; break;
+                       case 7: sItem = "nw_it_mbracer011"; break;
+                       case 8: sItem = "nw_it_mmidmisc04"; break;
+                       case 9: sItem = "nw_it_mring003"; break;
+                       case 10: sItem = "nw_it_mbelt006"; break;
+                       case 11: sItem = "nw_it_mbelt002"; break;
+                       case 12: sItem = "nw_it_mmidmisc03"; break;
+                       case 13: sItem = "nw_it_mring002"; break;
+                       case 14: sItem = "nw_it_mbelt004"; break;
+                       case 15: sItem = "nw_it_mring005"; break;
+                       case 16: sItem = "nw_it_mboots005"; break;
+                       case 17: sItem = "nw_it_mring007"; break;
+                       case 18: sItem = "nw_it_mneck003"; break;
+                       case 19: sItem = "nw_it_mbelt007"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(15) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_it_mbelt002"; break;
+                       case 2: sItem = "nw_it_mbelt002"; break;
+                       case 3: sItem = "nw_it_mmidmisc03"; break;
+                       case 4: sItem = "nw_it_mring002"; break;
+                       case 5: sItem = "nw_it_mbelt004"; break;
+                       case 6: sItem = "nw_it_mring005"; break;
+                       case 7: sItem = "nw_it_mboots005"; break;
+                       case 8: sItem = "nw_it_mring007"; break;
+                       case 9: sItem = "nw_it_mneck003"; break;
+                       case 10: sItem = "nw_it_mbelt007"; break;
+                       case 11: sItem = "nw_it_mboots004"; break;
+                       case 12: sItem = "nw_it_mboots003"; break;
+                       case 13: sItem = "nw_it_mneck005"; break;
+                       case 14: sItem = "nw_it_mbelt008"; break;
+                       case 15: sItem = "nw_it_mring020"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 16000 and up
+            {
+                  int nRandom = Random(19) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_it_mboots004"; break;
+                       case 2: sItem = "nw_it_mboots004"; break;
+                       case 3: sItem = "nw_it_mboots003"; break;
+                       case 4: sItem = "nw_it_mneck005"; break;
+                       case 5: sItem = "nw_it_mbelt008"; break;
+                       case 6: sItem = "nw_it_mring020"; break;
+                       case 7: sItem = "nw_it_mbelt001"; break;
+                       case 8: sItem = "nw_it_mring017"; break;
+                       case 9: sItem = "nw_mcloth001"; break;
+                       case 10: sItem = "nw_it_mneck019"; break;
+                       case 11: sItem = "nw_it_mneck002"; break;
+                       case 12: sItem = "nw_it_mneck004"; break;
+                       case 13: sItem = "nw_it_mmidmisc01"; break;
+                       case 14: sItem = "nw_mcloth002"; break;
+                       case 15: sItem = "nw_mcloth003"; break;
+                       case 16: sItem = "nw_mcloth004"; break;
+                       case 17: sItem = "nw_it_mbelt003"; break;
+                       // * new items
+                       case 18: sItem = "NW_IT_MBELT020"; break;
+                       case 19: sItem = "NW_IT_MBELT021"; break;
+                   }
+
+            }
+                dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateSpecificRodStaffWand(object oTarget, object oAdventurer)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer);
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericRodStaffWand(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(2, nHD))   // * 200 - 2500
+            {
+                CreateGenericRodStaffWand(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(4) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wmgst004"; break;
+                       case 2: sItem = "nw_wmgst006"; break;
+                       case 3: sItem = "nw_wmgmrd003"; break;
+                       case 4: sItem = "nw_wmgst004"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(7) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wmgmrd003"; break;
+                       case 2: sItem = "nw_wmgst006"; break;
+                       case 3: sItem = "nw_wmgmrd003"; break;
+                       case 4: sItem = "nw_wmgst004"; break;
+                       case 5: sItem = "nw_wmgst005"; break;
+                       case 6: sItem = "nw_wmgmrd004"; break;
+                       case 7: sItem = "nw_wmgrd002"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(8) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wblmcl012"; break;
+                       case 2: sItem = "nw_wmgmrd003"; break;
+                       case 3: sItem = "nw_wmgst004"; break;
+                       case 4: sItem = "nw_wmgst005"; break;
+                       case 5: sItem = "nw_wblmcl012"; break;
+                       case 6: sItem = "nw_wmgmrd004"; break;
+                       case 7: sItem = "nw_wmgst002"; break;
+                       case 8: sItem = "nw_wmgmrd005"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 16000 and up
+            {
+                  int nRandom = Random(6) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wmgmrd004"; break;
+                       case 2: sItem = "nw_wmgst002"; break;
+                       case 3: sItem = "nw_wmgmrd005"; break;
+                       case 4: sItem = "nw_wmgmrd002"; break;
+                       case 5: sItem = "nw_wmgst003"; break;
+                       case 6: sItem = "nw_wblmcl012"; break;
+                   }
+
+            }
+                dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+
+
+        void CreateSpecificSimple(object oTarget, object oAdventurer)
+        {
+           string sItem = "";
+            int nHD = GetHitDice(oAdventurer);
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericSimple(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(2, nHD))   // * 200 - 2500
+            {
+                CreateGenericSimple(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmqs005"; break;
+                       case 2: sItem = "nw_wdbmqs005"; break;
+                       case 3: sItem = "nw_wdbmqs006"; break;
+                       case 4: sItem = "nw_wbwmxh005"; break;
+                       case 5: sItem = "nw_wbwmxl005"; break;
+                       case 6: sItem = "nw_wswmdg006"; break;
+                       case 7: sItem = "nw_wblmml006"; break;
+                       case 8: sItem = "nw_wspmsc004"; break;
+                       case 9: sItem = "nw_wblmms007"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(22) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmqs006"; break;
+                       case 2: sItem = "nw_wdbmqs005"; break;
+                       case 3: sItem = "nw_wdbmqs006"; break;
+                       case 4: sItem = "nw_wbwmxh005"; break;
+                       case 5: sItem = "nw_wbwmxl005"; break;
+                       case 6: sItem = "nw_wswmdg006"; break;
+                       case 7: sItem = "nw_wblmml006"; break;
+                       case 8: sItem = "nw_wspmsc004"; break;
+                       case 9: sItem = "nw_wblmms007"; break;
+                       case 10: sItem = "nw_wblmms003"; break;
+                       case 11: sItem = "nw_wblmcl004"; break;
+                       case 12: sItem = "nw_wspmsc006"; break;
+                       case 13: sItem = "nw_wspmsc006"; break;
+                       case 14: sItem = "nw_wdbmqs004"; break;
+                       case 15: sItem = "nw_wblmcl003"; break;
+                       case 16: sItem = "nw_wbwmsl003"; break;
+                       case 17: sItem = "nw_wbwmxh003"; break;
+                       case 18: sItem = "nw_wspmsc003"; break;
+                       case 19: sItem = "nw_wplmss005"; break;
+                       case 20: sItem = "nw_wplmss005"; break;
+                       case 21: sItem = "nw_wbwmxl003"; break;
+                       case 22: sItem = "nw_wblmml004"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(27) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wblmms003"; break;
+                       case 2: sItem = "nw_wblmms003"; break;
+                       case 3: sItem = "nw_wblmcl004"; break;
+                       case 4: sItem = "nw_wspmsc006"; break;
+                       case 5: sItem = "nw_wspmsc006"; break;
+                       case 6: sItem = "nw_wdbmqs004"; break;
+                       case 7: sItem = "nw_wblmcl003"; break;
+                       case 8: sItem = "nw_wbwmsl003"; break;
+                       case 9: sItem = "nw_wbwmxh003"; break;
+                       case 10: sItem = "nw_wspmsc003"; break;
+                       case 11: sItem = "nw_wplmss005"; break;
+                       case 12: sItem = "nw_wplmss005"; break;
+                       case 13: sItem = "nw_wbwmxl003"; break;
+                       case 14: sItem = "nw_wblmml004"; break;
+                       case 15: sItem = "nw_wdbmqs003"; break;
+                       case 16: sItem = "nw_wbwmxl004"; break;
+                       case 17: sItem = "nw_wbwmxl007"; break;
+                       case 18: sItem = "nw_wblmml005"; break;
+                       case 19: sItem = "nw_wblmcl005"; break;
+                       case 20: sItem = "nw_wplmss007"; break;
+                       case 21: sItem = "nw_wswmdg004"; break;
+                       case 22: sItem = "nw_wbwmsl007"; break;
+                       case 23: sItem = "nw_wblmml007"; break;
+                       case 24: sItem = "nw_wblmml007"; break;
+                       case 25: sItem = "nw_wbwmxh004"; break;
+                       case 26: sItem = "nw_wplmss006"; break;
+                       case 27: sItem = "nw_wbwmxh007"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 16000 and up
+            {
+                  int nRandom = Random(31) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wbwmxl003"; break;
+                       case 2: sItem = "nw_wbwmxl003"; break;
+                       case 3: sItem = "nw_wblmml004"; break;
+                       case 4: sItem = "nw_wdbmqs003"; break;
+                       case 5: sItem = "nw_wbwmxl004"; break;
+                       case 6: sItem = "nw_wbwmxl007"; break;
+                       case 7: sItem = "nw_wblmml005"; break;
+                       case 8: sItem = "nw_wblmcl005"; break;
+                       case 9: sItem = "nw_wplmss007"; break;
+                       case 10: sItem = "nw_wswmdg004"; break;
+                       case 11: sItem = "nw_wbwmsl007"; break;
+                       case 12: sItem = "nw_wblmml007"; break;
+                       case 13: sItem = "nw_wblmml007"; break;
+                       case 14: sItem = "nw_wbwmxh004"; break;
+                       case 15: sItem = "nw_wplmss006"; break;
+                       case 16: sItem = "nw_wbwmxh007"; break;
+                       case 17: sItem = "nw_wblmms006"; break;
+                       case 18: sItem = "nw_wswmdg003"; break;
+                       case 19: sItem = "nw_wswmdg007"; break;
+                       case 20: sItem = "nw_wblmms004"; break;
+                       case 21: sItem = "nw_wbwmsl006"; break;
+                       case 22: sItem = "nw_wbwmsl008"; break;
+                       case 23: sItem = "nw_wblmml008"; break;
+                       case 24: sItem = "nw_wdbmqs007"; break;
+                       case 25: sItem = "nw_wblmcl006"; break;
+                       case 26: sItem = "nw_wbwmsl004"; break;
+                       case 27: sItem = "nw_wbwmxh006"; break;
+                       case 28: sItem = "nw_wplmss004"; break;
+                       case 29: sItem = "nw_wswmdg005"; break;
+                       case 30: sItem = "nw_wbwmxl006"; break;
+                       case 31: sItem = "nw_wspmsc005"; break;
+
+                   }
+
+            }
+                dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateSpecificMartial(object oTarget, object oAdventurer)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer);
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericMartial(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(2, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(3) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: CreateGenericMartial(oTarget, oAdventurer, JUMP_LEVEL); return; break;
+                       case 2: sItem = "nw_wthmax005"; break;
+                       case 3: sItem = "nw_wthmax007"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(14) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmax003"; break;
+                       case 2: sItem = "nw_wthmax005"; break;
+                       case 3: sItem = "nw_wthmax007"; break;
+                       case 4: sItem = "nw_wthmax003"; break;
+                       case 5: sItem = "nw_wthmax004"; break;
+                       case 6: sItem = "nw_wthmax006"; break;
+                       case 7: sItem = "nw_wswmrp004"; break;
+                       case 8: sItem = "nw_wswmrp004"; break;
+                       case 9: sItem = "nw_wblmfl004"; break;
+                       case 10: sItem = "nw_wblmhl004"; break;
+                       case 11: sItem = "nw_wbwmsh003"; break;
+                       case 12: sItem = "nw_wblmhw006"; break;
+                       case 13: sItem = "nw_wblmhw006"; break;
+                       case 14: sItem = "nw_wbwmln004"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(28) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wblmfl005"; break;
+                       case 2: sItem = "nw_wthmax007"; break;
+                       case 3: sItem = "nw_wthmax003"; break;
+                       case 4: sItem = "nw_wthmax004"; break;
+                       case 5: sItem = "nw_wthmax006"; break;
+                       case 6: sItem = "nw_wswmrp004"; break;
+                       case 7: sItem = "nw_wswmrp004"; break;
+                       case 8: sItem = "nw_wblmfl004"; break;
+                       case 9: sItem = "nw_wblmhl004"; break;
+                       case 10: sItem = "nw_wbwmsh003"; break;
+                       case 11: sItem = "nw_wblmhw006"; break;
+                       case 12: sItem = "nw_wblmhw006"; break;
+                       case 13: sItem = "nw_wbwmln004"; break;
+                       case 14: sItem = "nw_wblmfl005"; break;
+                       case 15: sItem = "nw_wswmgs006"; break;
+                       case 16: sItem = "nw_waxmgr003"; break;
+                       case 17: sItem = "nw_wplmhb004"; break;
+                       case 18: sItem = "nw_wblmhw005"; break;
+                       case 19: sItem = "nw_wblmfh004"; break;
+                       case 20: sItem = "nw_wblmfh008"; break;
+                       case 21: sItem = "nw_wbwmsh006"; break;
+                       case 22: sItem = "nw_wswmsc004"; break;
+                       case 23: sItem = "nw_waxmgr006"; break;
+                       case 24: sItem = "nw_wswmrp005"; break;
+                       case 25: sItem = "nw_wswmls007"; break;
+                       case 26: sItem = "nw_wswmgs004"; break;
+                       case 27: sItem = "nw_waxmhn004"; break;
+                       case 28: sItem = "nw_wswmbs005"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(42) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wblmhw006"; break;
+                       case 2: sItem = "nw_wblmhw006"; break;
+                       case 3: sItem = "nw_wblmhw006"; break;
+                       case 4: sItem = "nw_wbwmln004"; break;
+                       case 5: sItem = "nw_wblmfl005"; break;
+                       case 6: sItem = "nw_wswmgs006"; break;
+                       case 7: sItem = "nw_waxmgr003"; break;
+                       case 8: sItem = "nw_wplmhb004"; break;
+                       case 9: sItem = "nw_wblmhw005"; break;
+                       case 10: sItem = "nw_wblmfh004"; break;
+                       case 11: sItem = "nw_wblmfh008"; break;
+                       case 12: sItem = "nw_wbwmsh006"; break;
+                       case 13: sItem = "nw_wswmsc004"; break;
+                       case 14: sItem = "nw_waxmgr006"; break;
+                       case 15: sItem = "nw_wswmrp005"; break;
+                       case 16: sItem = "nw_wswmls007"; break;
+                       case 17: sItem = "nw_wswmgs004"; break;
+                       case 18: sItem = "nw_waxmhn004"; break;
+                       case 19: sItem = "nw_wswmbs005"; break;
+                       case 20: sItem = "nw_wblmhl005"; break;
+                       case 21: sItem = "nw_wblmhl011"; break;
+                       case 22: sItem = "nw_wswmss005"; break;
+                       case 23: sItem = "nw_wplmhb003"; break;
+                       case 24: sItem = "nw_wbwmln007"; break;
+                       case 25: sItem = "nw_wbwmln007"; break;
+                       case 26: sItem = "nw_wbwmsh007"; break;
+                       case 27: sItem = "nw_waxmbt006"; break;
+                       case 28: sItem = "nw_wswmbs006"; break;
+                       case 29: sItem = "nw_wblmfl007"; break;
+                       case 30: sItem = "nw_waxmhn003"; break;
+                       case 31: sItem = "nw_wblmhl006"; break;
+                       case 32: sItem = "nw_wblmfl006"; break;
+                       case 33: sItem = "nw_wswmls005"; break;
+                       case 34: sItem = "nw_wswmss004"; break;
+                       case 35: sItem = "nw_wbwmln006"; break;
+                       case 36: sItem = "nw_wblmhw003"; break;
+                       case 37: sItem = "nw_wblmfh006"; break;
+                       case 38: sItem = "nw_wswmsc006"; break;
+                       case 39: sItem = "nw_waxmhn005"; break;
+                       case 40: sItem = "nw_wblmfh003"; break;
+                       case 41: sItem = "nw_wswmls006"; break;
+                       case 42: sItem = "nw_wswmrp007"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 16000 and up
+            {
+                  int nRandom = Random(55) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wblmhl005"; break;
+                       case 2: sItem = "nw_wblmhl005"; break;
+                       case 3: sItem = "nw_wblmhl011"; break;
+                       case 4: sItem = "nw_wswmss005"; break;
+                       case 5: sItem = "nw_wplmhb003"; break;
+                       case 6: sItem = "nw_wbwmln007"; break;
+                       case 7: sItem = "nw_wbwmln007"; break;
+                       case 8: sItem = "nw_wbwmsh007"; break;
+                       case 9: sItem = "nw_waxmbt006"; break;
+                       case 10: sItem = "nw_wswmbs006"; break;
+                       case 11: sItem = "nw_wblmfl007"; break;
+                       case 12: sItem = "nw_waxmhn003"; break;
+                       case 13: sItem = "nw_wblmhl006"; break;
+                       case 14: sItem = "nw_wblmfl006"; break;
+                       case 15: sItem = "nw_wswmls005"; break;
+                       case 16: sItem = "nw_wswmss004"; break;
+                       case 17: sItem = "nw_wbwmln006"; break;
+                       case 18: sItem = "nw_wblmhw003"; break;
+                       case 19: sItem = "nw_wblmfh006"; break;
+                       case 20: sItem = "nw_wswmsc006"; break;
+                       case 21: sItem = "nw_waxmhn005"; break;
+                       case 22: sItem = "nw_wblmfh003"; break;
+                       case 23: sItem = "nw_wswmls006"; break;
+                       case 24: sItem = "nw_wswmrp007"; break;
+                       case 25: sItem = "nw_wswmgs005"; break;
+                       case 26: sItem = "nw_wswmgs005"; break;
+                       case 27: sItem = "nw_waxmgr005"; break;
+                       case 28: sItem = "nw_wplmhb007"; break;
+                       case 29: sItem = "nw_wswmsc007"; break;
+                       case 30: sItem = "nw_wswmrp006"; break;
+                       case 31: sItem = "nw_wswmss006"; break;
+                       case 32: sItem = "nw_wblmhl009"; break;
+                       case 33: sItem = "nw_wswmbs007"; break;
+                       case 34: sItem = "nw_wbwmln005"; break;
+                       case 35: sItem = "nw_wblmfh005"; break;
+                       case 36: sItem = "nw_wswmgs003"; break;
+                       case 37: sItem = "nw_waxmbt003"; break;
+                       case 38: sItem = "nw_wswmls004"; break;
+                       case 39: sItem = "nw_wbwmsh005"; break;
+                       case 40: sItem = "nw_wbwmsh005"; break;
+                       case 41: sItem = "nw_waxmbt004"; break;
+                       case 42: sItem = "nw_waxmbt004"; break;
+                       case 43: sItem = "nw_wblmhl003"; break;
+                       case 44: sItem = "nw_wblmhl003"; break;
+                       case 45: sItem = "nw_wswmbs003"; break;
+                       case 46: sItem = "nw_waxmbt005"; break;
+                       case 47: sItem = "nw_waxmhn006"; break;
+                       case 48: sItem = "nw_wswmss003"; break;
+                       case 49: sItem = "nw_wswmsc005"; break;
+                       case 50: sItem = "nw_wplmhb006"; break;
+                       case 51: sItem = "nw_wbwmsh004"; break;
+                       case 52: sItem = "nw_wswmbs004"; break;
+                       case 53: sItem = "nw_wbwmln003"; break;
+                       case 54: sItem = "nw_wblmhw004"; break;
+                       case 55: sItem = "nw_waxmgr004"; break;
+                   }
+
+            }
+                dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateSpecificExotic(object oTarget, object oAdventurer)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer);
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                  int nRandom = Random(3) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: CreateGenericExotic(oTarget, oAdventurer, JUMP_LEVEL); return; break;
+                       case 2: sItem = "nw_wthmsh003"; break;
+                       case 3: sItem = "nw_wthmsh006"; break;
+                   }
+
+            }
+            else if (GetRange(2, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: CreateGenericExotic(oTarget, oAdventurer, JUMP_LEVEL); return; break;
+                       case 2: sItem = "nw_wthmsh003"; break;
+                       case 3: sItem = "nw_wthmsh006"; break;
+                       case 4: sItem = "nw_wthmsh004"; break;
+                       case 5: sItem = "nw_wthmsh007"; break;
+                   }
+
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(14) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wthmsh006"; break;
+                       case 2: sItem = "nw_wthmsh006"; break;
+                       case 3: sItem = "nw_wthmsh004"; break;
+                       case 4: sItem = "nw_wthmsh007"; break;
+                       case 5: sItem = "nw_wspmku006"; break;
+                       case 6: sItem = "nw_wdbmma003"; break;
+                       case 7: sItem = "nw_wswmka005"; break;
+                       case 8: sItem = "nw_wspmka004"; break;
+                       case 9: sItem = "nw_wspmka007"; break;
+                       case 10: sItem = "nw_wdbmax006"; break;
+                       case 11: sItem = "nw_wdbmsw006"; break;
+                       case 12: sItem = "nw_wspmku005"; break;
+                       case 13: sItem = "nw_wdbmsw007"; break;
+                       case 14: sItem = "nw_wspmka005"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(16) + 1;
+                  switch (nRandom)
+                  {
+                       case 1:sItem = "nw_wthmsh007"; break;
+                       case 2: sItem = "nw_wthmsh007"; break;
+                       case 3: sItem = "nw_wspmku006"; break;
+                       case 4: sItem = "nw_wdbmma003"; break;
+                       case 5: sItem = "nw_wswmka005"; break;
+                       case 6: sItem = "nw_wspmka004"; break;
+                       case 7: sItem = "nw_wspmka007"; break;
+                       case 8: sItem = "nw_wdbmax006"; break;
+                       case 9: sItem = "nw_wdbmsw006"; break;
+                       case 10: sItem = "nw_wspmku005"; break;
+                       case 11: sItem = "nw_wdbmsw007"; break;
+                       case 12: sItem = "nw_wspmka005"; break;
+                       case 13: sItem = "nw_wplmsc003"; break;
+                       case 14: sItem = "nw_wdbmax005"; break;
+                       case 15: sItem = "nw_wspmku004"; break;
+                       case 16: sItem = "nw_wdbmma005"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(17) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wplmsc003"; break;
+                       case 2: sItem = "nw_wspmka005"; break;
+                       case 3: sItem = "nw_wplmsc003"; break;
+                       case 4: sItem = "nw_wdbmax005"; break;
+                       case 5: sItem = "nw_wspmku004"; break;
+                       case 6: sItem = "nw_wdbmma005"; break;
+                       case 7: sItem = "nw_wdbmma005"; break;
+                       case 8: sItem = "nw_wdbmax004"; break;
+                       case 9: sItem = "nw_wdbmma004"; break;
+                       case 10: sItem = "nw_wswmka007"; break;
+                       case 11: sItem = "nw_wdbmsw005"; break;
+                       case 12: sItem = "nw_wspmka006"; break;
+                       case 13: sItem = "nw_wspmka003"; break;
+                       case 14: sItem = "nw_wdbmax007"; break;
+                       case 15: sItem = "nw_wplmsc006"; break;
+                       case 16: sItem = "nw_wspmku007"; break;
+                       case 17: sItem = "nw_wdbmma006"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 16000 and up
+            {
+                  int nRandom = Random(21) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_wdbmma005"; break;
+                       case 2: sItem = "nw_wdbmma005"; break;
+                       case 3: sItem = "nw_wdbmma005"; break;
+                       case 4: sItem = "nw_wdbmax004"; break;
+                       case 5: sItem = "nw_wdbmma004"; break;
+                       case 6: sItem = "nw_wswmka007"; break;
+                       case 7: sItem = "nw_wdbmsw005"; break;
+                       case 8: sItem = "nw_wspmka006"; break;
+                       case 9: sItem = "nw_wspmka003"; break;
+                       case 10: sItem = "nw_wdbmax007"; break;
+                       case 11: sItem = "nw_wplmsc006"; break;
+                       case 12: sItem = "nw_wspmku007"; break;
+                       case 13: sItem = "nw_wdbmma006"; break;
+                       case 14: sItem = "nw_wspmku003"; break;
+                       case 15: sItem = "nw_wswmka006"; break;
+                       case 16: sItem = "nw_wplmsc005"; break;
+                       case 17: sItem = "nw_wplmsc005"; break;
+                       case 18: sItem = "nw_wswmka004"; break;
+                       case 19: sItem = "nw_wswmka004"; break;
+                       case 20: sItem = "nw_wdbmsw004"; break;
+                       case 21: sItem = "nw_wplmsc004"; break;
+                   }
+
+            }
+                dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateSpecificLightArmor(object oTarget, object oAdventurer)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer);
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericLightArmor(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(2, nHD))   // * 200 - 2500
+            {
+                  int nRandom = Random(3) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: CreateGenericLightArmor(oTarget, oAdventurer, JUMP_LEVEL); return; break;
+                       case 2: sItem = "nw_ashmsw011"; break;
+                       case 3: sItem = "nw_ashmsw010"; break;
+                   }
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_ashmsw011"; break;
+                       case 2: sItem = "nw_ashmsw011"; break;
+                       case 3: sItem = "nw_ashmsw010"; break;
+                       case 4: sItem = "nw_maarcl011"; break;
+                       case 5: sItem = "nw_ashmsw006"; break;
+                       case 6: sItem = "nw_maarcl017"; break;
+                       case 7: sItem = "nw_ashmsw005"; break;
+                       case 8: sItem = "nw_maarcl013"; break;
+                       case 9: sItem = "nw_maarcl012"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(13) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl011"; break;
+                       case 2: sItem = "nw_maarcl011"; break;
+                       case 3: sItem = "nw_ashmsw006"; break;
+                       case 4: sItem = "nw_maarcl017"; break;
+                       case 5: sItem = "nw_ashmsw005"; break;
+                       case 6: sItem = "nw_maarcl013"; break;
+                       case 7: sItem = "nw_maarcl012"; break;
+                       case 8: sItem = "nw_ashmsw004"; break;
+                       case 9: sItem = "nw_maarcl006"; break;
+                       case 10: sItem = "nw_maarcl032"; break;
+                       case 11: sItem = "nw_maarcl003"; break;
+                       case 12: sItem = "nw_maarcl002"; break;
+                       case 13: sItem = "nw_maarcl007"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(11) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl012"; break;
+                       case 2: sItem = "nw_maarcl012"; break;
+                       case 3: sItem = "nw_ashmsw004"; break;
+                       case 4: sItem = "nw_maarcl006"; break;
+                       case 5: sItem = "nw_maarcl032"; break;
+                       case 6: sItem = "nw_maarcl003"; break;
+                       case 7: sItem = "nw_maarcl002"; break;
+                       case 8: sItem = "nw_maarcl005"; break;
+                       case 9: sItem = "nw_ashmsw003"; break;
+                       case 10: sItem = "nw_maarcl001"; break;
+                       case 11: sItem = "nw_maarcl034"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 16000 and up
+            {
+                  int nRandom = Random(11) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl005"; break;
+                       case 2: sItem = "nw_maarcl005"; break;
+                       case 3: sItem = "nw_ashmsw003"; break;
+                       case 4: sItem = "nw_maarcl001"; break;
+                       case 5: sItem = "nw_maarcl034"; break;
+                       case 6: sItem = "nw_maarcl008"; break;
+                       case 7: sItem = "nw_ashmsw007"; break;
+                       case 8: sItem = "nw_maarcl033"; break;
+                       case 9: sItem = "nw_mcloth005"; break;
+                       case 10: sItem = "nw_maarcl009"; break;
+                       case 11: sItem = "nw_maarcl004"; break;
+                   }
+
+            }
+              dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateSpecificMediumArmor(object oTarget, object oAdventurer)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer);
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericMediumArmor(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(2, nHD))   // * 200 - 2500
+            {
+                CreateGenericMediumArmor(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(5) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_armhe008"; break;
+                       case 2: sItem = "nw_armhe008"; break;
+                       case 3: sItem = "nw_armhe007"; break;
+                       case 4: sItem = "nw_armhe009"; break;
+                       case 5: sItem = "nw_armhe010"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(9) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_armhe008"; break;
+                       case 2: sItem = "nw_armhe008"; break;
+                       case 3: sItem = "nw_armhe007"; break;
+                       case 4: sItem = "nw_armhe009"; break;
+                       case 5: sItem = "nw_armhe010"; break;
+                       case 6: sItem = "nw_armhe006"; break;
+                       case 7: sItem = "nw_ashmlw007"; break;
+                       case 8: sItem = "nw_ashmlw005"; break;
+                       case 9: sItem = "nw_maarcl016"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(12) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_armhe009"; break;
+                       case 2: sItem = "nw_armhe009"; break;
+                       case 3: sItem = "nw_armhe010"; break;
+                       case 4: sItem = "nw_armhe006"; break;
+                       case 5: sItem = "nw_ashmlw007"; break;
+                       case 6: sItem = "nw_ashmlw005"; break;
+                       case 7: sItem = "nw_maarcl016"; break;
+                       case 8: sItem = "nw_maarcl036"; break;
+                       case 9: sItem = "nw_ashmlw004"; break;
+                       case 10: sItem = "nw_maarcl037"; break;
+                       case 11: sItem = "nw_maarcl040"; break;
+                       case 12: sItem = "nw_ashmlw006"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 16000 and up
+            {
+                  int nRandom = Random(12) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl016"; break;
+                       case 2: sItem = "nw_maarcl016"; break;
+                       case 3: sItem = "nw_maarcl036"; break;
+                       case 4: sItem = "nw_ashmlw004"; break;
+                       case 5: sItem = "nw_maarcl037"; break;
+                       case 6: sItem = "nw_maarcl040"; break;
+                       case 7: sItem = "nw_ashmlw006"; break;
+                       case 8: sItem = "nw_ashmlw003"; break;
+                       case 9: sItem = "nw_maarcl014"; break;
+                       case 10: sItem = "nw_maarcl039"; break;
+                       case 11: sItem = "nw_maarcl010"; break;
+                       case 12: sItem = "nw_maarcl015"; break;
+                   }
+
+            }
+                  dbCreateItemOnObject(sItem, oTarget, 1);
+        }
+        void CreateSpecificHeavyArmor(object oTarget, object oAdventurer)
+        {
+            string sItem = "";
+            int nHD = GetHitDice(oAdventurer);
+
+            if (GetRange(1, nHD))    // * 800
+            {
+                CreateGenericHeavyArmor(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(2, nHD))   // * 200 - 2500
+            {
+                CreateGenericHeavyArmor(oTarget, oAdventurer, JUMP_LEVEL);
+                return;
+            }
+            else if (GetRange(3, nHD))   // * 800 - 10000
+            {
+                  int nRandom = Random(6) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl026"; break;
+                       case 2: sItem = "nw_maarcl026"; break;
+                       case 3: sItem = "nw_maarcl021"; break;
+                       case 4: sItem = "nw_ashmto003"; break;
+                       case 5: sItem = "nw_maarcl029"; break;
+                       case 6: sItem = "nw_maarcl020"; break;
+                   }
+
+            }
+            else if (GetRange(4, nHD))   // * 2500 - 16500
+            {
+                  int nRandom = Random(13) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl021"; break;
+                       case 2: sItem = "nw_maarcl026"; break;
+                       case 3: sItem = "nw_maarcl021"; break;
+                       case 4: sItem = "nw_ashmto003"; break;
+                       case 5: sItem = "nw_maarcl029"; break;
+                       case 6: sItem = "nw_maarcl020"; break;
+                       case 7: sItem = "nw_ashmto006"; break;
+                       case 8: sItem = "nw_maarcl041"; break;
+                       case 9: sItem = "nw_ashmto005"; break;
+                       case 10: sItem = "nw_ashmto007"; break;
+                       case 11: sItem = "nw_ashmto010"; break;
+                       case 12: sItem = "nw_maarcl022"; break;
+                       case 13: sItem = "nw_maarcl018"; break;
+                   }
+
+            }
+            else if (GetRange(5, nHD))   // * 8000 - 25000
+            {
+                  int nRandom = Random(13) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl020"; break;
+                       case 2: sItem = "nw_maarcl020"; break;
+                       case 3: sItem = "nw_ashmto006"; break;
+                       case 4: sItem = "nw_maarcl041"; break;
+                       case 5: sItem = "nw_ashmto005"; break;
+                       case 6: sItem = "nw_ashmto007"; break;
+                       case 7: sItem = "nw_ashmto010"; break;
+                       case 8: sItem = "nw_maarcl022"; break;
+                       case 9: sItem = "nw_maarcl018"; break;
+                       case 10: sItem = "nw_maarcl024"; break;
+                       case 11: sItem = "nw_ashmto011"; break;
+                       case 12: sItem = "nw_maarcl042"; break;
+                       case 13: sItem = "nw_maarcl054"; break;
+                   }
+
+            }
+            else if (GetRange(6, nHD))   // * 16000 and up
+            {
+                  int nRandom = Random(10) + 1;
+                  switch (nRandom)
+                  {
+                       case 1: sItem = "nw_maarcl018"; break;
+                       case 2: sItem = "nw_maarcl018"; break;
+                       case 3: sItem = "nw_maarcl024"; break;
+                       case 4: sItem = "nw_ashmto011"; break;
+                       case 5: sItem = "nw_maarcl042"; break;
+                       case 6: sItem = "nw_maarcl054"; break;
+                       case 7: sItem = "nw_ashmto004"; break;
+                       case 8: sItem = "nw_maarcl025"; break;
+                       case 9: sItem = "nw_maarcl028"; break;
+                       case 10: sItem = "nw_maarcl027"; break;
+                   }
+
+            }
+                  dbCreateItemOnObject(sItem, oTarget, 1);
+
+        }
+        // * if nSpecific is = 1 then spawn in 'named' items at the higher levels
+    void CreateTable2Item(object oTarget, object oAdventurer, int nSpecific=0)
+    {
+        //dbSpeak("In CreateTable2Item");
+        string sItem = "";
+        int nProbMisc = 0;
+        int nProbClass = 0;
+        int nProbRodStaffWand = 0;
+        int nProbSimple = 0;
+        int nProbMartial = 0;
+        int nProbExotic = 0;
+        int nProbLight = 0;
+        int nProbMedium = 0;
+        int nProbHeavy = 0;
+
+        int nSpecialRanger = 0; // 2 Means to treat the ranger as a barbarian. A 1 is to treat it as a fighter
+
+
+        // * May 2002: Changed using Preston's multiclass function
+        // * it randomly chooses one of your classes
+        int nClass =  nDetermineClassToUse(oAdventurer);
+
+
+        // * SPECIAL RANGER BEHAVIOR
+        // * If the ranger has the Heavy Armor proficiency, will treat the ranger
+        if ( nClass == CLASS_TYPE_RANGER && GetHasFeat(FEAT_ARMOR_PROFICIENCY_HEAVY))
+        {
+            nSpecialRanger = 1;
+        }
+        else
+        if (nClass == CLASS_TYPE_RANGER)
+        {
+            nSpecialRanger = 2;
+        }
+
+
+
+        //* SETUP probabilities based on Class
+        if ( nClass == CLASS_TYPE_FIGHTER || nClass == CLASS_TYPE_PALADIN || nSpecialRanger == 1
+          || nClass == CLASS_TYPE_ANTI_PALADIN || nClass == CLASS_TYPE_BRAWLER || nClass == CLASS_TYPE_CRUSADER
+          || nClass == CLASS_TYPE_DUSKBLADE || nClass == CLASS_TYPE_KNIGHT || nClass == CLASS_TYPE_MARSHAL
+          || nClass == CLASS_TYPE_PSYWAR || nClass == CLASS_TYPE_SOHEI)
+        {
+            //dbSpeak("I am fighter or paladin or heavy ranger");
+            nProbMisc = 20;
+            nProbClass = 0;
+            nProbRodStaffWand = 5;
+            nProbSimple = 5;
+            nProbMartial = 20;
+            nProbExotic = 10;
+            nProbLight = 5;
+            nProbMedium = 15;
+            nProbHeavy = 20;
+        }
+        else
+        if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER)
+        {
+            //dbSpeak("I am wizard or sorcerer");
+            nProbMisc = 40;
+            nProbClass = 30;
+            nProbRodStaffWand = 15;
+            nProbSimple = 3;
+            nProbMartial = 3;
+            nProbExotic = 3;
+            nProbLight = 2;
+            nProbMedium = 2;
+            nProbHeavy = 2;
+        }
+        else
+        if (nClass == CLASS_TYPE_BARBARIAN || nSpecialRanger == 2 || nClass == CLASS_TYPE_BOWMAN
+         || nClass == CLASS_TYPE_HEXBLADE || nClass == CLASS_TYPE_WARBLADE)
+        {
+            //dbSpeak("I am barbarian or light ranger");
+
+            nProbMisc = 20;
+            nProbClass = 0;
+            nProbRodStaffWand = 5;
+            nProbSimple = 17;
+            nProbMartial = 27;
+            nProbExotic = 15;
+            nProbLight = 8;
+            nProbMedium = 5;
+            nProbHeavy = 3;
+        }
+        else
+        if (nClass == CLASS_TYPE_ARCHIVIST || nClass == CLASS_TYPE_DRAGON_SHAMAN || nClass == CLASS_TYPE_FAVOURED_SOUL
+         || nClass == CLASS_TYPE_MYSTIC || nClass == CLASS_TYPE_WARMAGE || nClass == CLASS_TYPE_TEMPLAR)
+        {
+            //type 1
+            nProbMisc = 25;
+            nProbClass = 0;
+            nProbRodStaffWand = 15;
+            nProbSimple = 15;
+            nProbMartial = 8;
+            nProbExotic = 6;
+            nProbLight = 15;
+            nProbMedium = 10;
+            nProbHeavy = 6;
+        }
+        else
+        if (nClass == CLASS_TYPE_NOBLE || nClass == CLASS_TYPE_SWASHBUCKLER || nClass == CLASS_TYPE_SWORDSAGE
+         || nClass == CLASS_TYPE_ULTIMATE_RANGER)
+        {
+            //type 2
+            nProbMisc = 27;
+            nProbClass = 0;
+            nProbRodStaffWand = 5;
+            nProbSimple = 15;
+            nProbMartial = 20;
+            nProbExotic = 10;
+            nProbLight = 10;
+            nProbMedium = 8;
+            nProbHeavy = 5;
+        }
+        else
+        if (nClass == CLASS_TYPE_BEGUILER || nClass == CLASS_TYPE_DREAD_NECROMANCER || nClass == CLASS_TYPE_HEALER
+         || nClass == CLASS_TYPE_SCOUT || nClass == CLASS_TYPE_SHAMAN || nClass == CLASS_TYPE_SOULKNIFE
+         || nClass == CLASS_TYPE_TRUENAMER || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_WILDER)
+        {
+            //type 3
+            nProbMisc = 45;
+            nProbClass = 0;
+            nProbRodStaffWand = 7;
+            nProbSimple = 15;
+            nProbMartial = 5;
+            nProbExotic = 5;
+            nProbLight = 15;
+            nProbMedium = 4;
+            nProbHeavy = 4;
+        }
+        else
+        if (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_PSION || nClass == CLASS_TYPE_WITCH)
+        {
+            //type 4
+            nProbMisc = 50;
+            nProbClass = 0;
+            nProbRodStaffWand = 10;
+            nProbSimple = 20;
+            nProbMartial = 5;
+            nProbExotic = 5;
+            nProbLight = 4;
+            nProbMedium = 3;
+            nProbHeavy = 3;
+        }
+        else
+        if (nClass == CLASS_TYPE_NINJA)
+        {
+            //type 5
+            nProbMisc = 45;
+            nProbClass = 0;
+            nProbRodStaffWand = 2;
+            nProbSimple = 12;
+            nProbMartial = 6;
+            nProbExotic = 26;
+            nProbLight = 3;
+            nProbMedium = 3;
+            nProbHeavy = 3;
+        }
+        else
+        if (nClass == CLASS_TYPE_CW_SAMURAI || nClass == CLASS_TYPE_SAMURAI)
+        {
+            //type 6
+            nProbMisc = 25;
+            nProbClass = 0;
+            nProbRodStaffWand = 5;
+            nProbSimple = 5;
+            nProbMartial = 10;
+            nProbExotic = 20;
+            nProbLight = 10;
+            nProbMedium = 20;
+            nProbHeavy = 5;
+        }
+        else
+        if (nClass == CLASS_TYPE_CLERIC)
+        {
+            //dbSpeak("I am cleric");
+
+            nProbMisc = 20;
+            nProbClass = 10;
+            nProbRodStaffWand = 10;
+            nProbSimple = 25;
+            nProbMartial = 7;
+            nProbExotic = 5;
+            nProbLight = 5;
+            nProbMedium = 8;
+            nProbHeavy = 10;
+        }
+        else
+        if (nClass == CLASS_TYPE_DRUID)
+        {
+            //dbSpeak("I am druid");
+
+            nProbMisc = 20;
+            nProbClass = 25;
+            nProbRodStaffWand = 15;
+            nProbSimple = 10;
+            nProbMartial = 5;
+            nProbExotic = 5;
+            nProbLight = 10;
+            nProbMedium = 5;
+            nProbHeavy = 5;
+        }
+        else
+        if (nClass == CLASS_TYPE_MONK)
+        {
+            //dbSpeak("I am monk");
+            nProbMisc = 20;
+            nProbClass = 50;
+            nProbRodStaffWand = 2;
+            nProbSimple = 7;
+            nProbMartial = 2;
+            nProbExotic = 7;
+            nProbLight = 4;
+            nProbMedium = 4;
+            nProbHeavy = 4;
+        }
+        else
+        if (nClass == CLASS_TYPE_ROGUE || nClass == CLASS_TYPE_PSYCHIC_ROGUE)
+        {
+            //dbSpeak("I am rogue");
+
+            nProbMisc = 25;
+            nProbClass = 10;
+            nProbRodStaffWand = 10;
+            nProbSimple = 25;
+            nProbMartial = 5;
+            nProbExotic = 5;
+            nProbLight = 10;
+            nProbMedium = 5;
+            nProbHeavy = 5;
+        }
+        else
+        if (nClass == CLASS_TYPE_BARD)
+        {
+            //dbSpeak("I am bard");
+
+            nProbMisc = 25;
+            nProbClass = 5;
+            nProbRodStaffWand = 5;
+            nProbSimple = 25;
+            nProbMartial = 10;
+            nProbExotic = 10;
+            nProbLight = 10;
+            nProbMedium = 5;
+            nProbHeavy = 5;
+        }
+        //else
+        //{
+        //    dbSpeak("No Valid Class");
+        //}
+        //dbSpeak("Table2Item: After Class Distribution");
+        //* Create Items based on Probabilities
+        int nRandom = d100();
+        if (nRandom <= nProbMisc)
+        {
+            if (nSpecific == 0) CreateGenericMiscItem(oTarget, oAdventurer);
+            else CreateSpecificMiscItem(oTarget, oAdventurer);
+
+        }
+        else
+        if (nRandom <= nProbMisc + nProbClass)
+        {   // * no need for a seperate specific function here
+            CreateGenericClassItem(oTarget, oAdventurer, nSpecific);
+        }
+        else
+        if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand)
+        {
+            if (nSpecific == 0) CreateGenericRodStaffWand(oTarget, oAdventurer);
+            else CreateSpecificRodStaffWand(oTarget, oAdventurer);
+        }
+        else
+        if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple)
+        {
+            if (nSpecific == 0) CreateGenericSimple(oTarget, oAdventurer);
+            else CreateSpecificSimple(oTarget, oAdventurer);
+        }
+        else
+        if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial)
+        {
+
+             if (nSpecific == 0) CreateGenericMartial(oTarget, oAdventurer);
+             else CreateSpecificMartial(oTarget, oAdventurer);
+        }
+        else
+        if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial + nProbExotic)
+        {
+            if (nSpecific == 0) CreateGenericExotic(oTarget, oAdventurer);
+            else CreateSpecificExotic(oTarget, oAdventurer);
+        }
+        else
+        if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial + nProbExotic + nProbLight)
+        {
+            if (nSpecific == 0) CreateGenericLightArmor(oTarget, oAdventurer);
+            else CreateSpecificLightArmor(oTarget, oAdventurer);
+        }
+        else
+        if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial + nProbExotic + nProbLight + nProbMedium)
+        {
+            if (nSpecific == 0) CreateGenericMediumArmor(oTarget, oAdventurer);
+            else CreateSpecificMediumArmor(oTarget, oAdventurer);
+        }
+        else
+        if (nRandom <= nProbMisc + nProbClass + nProbRodStaffWand + nProbSimple + nProbMartial + nProbExotic + nProbLight + nProbMedium + nProbHeavy)
+        {
+            if (nSpecific == 0) CreateGenericHeavyArmor(oTarget, oAdventurer);
+            else CreateSpecificHeavyArmor(oTarget, oAdventurer);
+        }
+        //else
+        //{
+        //    dbSpeak("Generic Generic or Specific; error: 3524");
+        //}
+    }
+
+//::///////////////////////////////////////////////
+//:: GenerateTreasure
+//:: Copyright (c) 2001 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+   Generate Treasure
+   NOTE: When used by NPCs, the treasure is scaled
+   to how powerful the NPC is.
+
+   If used by containers, it is scaled by how
+   powerful the PC is.
+
+   PARAMETERS
+   oLastOpener = The creature that opened the container
+   oCreateOn = The place to put the treasure. If this is
+    invalid then the treasure is placed on oLastOpener
+
+
+*/
+//:://////////////////////////////////////////////
+//:: Created By:  Andrew
+//:: Created On:
+//:://////////////////////////////////////////////
+void GenerateTreasure(int nTreasureType, object oLastOpener, object oCreateOn)
+{
+
+    //dbSpeak("*********************NEW TREASURE*************************");
+
+    // * abort treasure if no one opened the container
+    if (GetIsObjectValid(oLastOpener) == FALSE)
+    {
+        //dbSpeak("Aborted.  No valid Last Opener");
+        return;
+    }
+
+    // * if no valid create on object, then create on oLastOpener
+    if (oCreateOn == OBJECT_INVALID)
+    {
+        oCreateOn = oLastOpener;
+    }
+
+    // * if an Animal then generate 100% animal treasure
+
+    // not done yet
+    // * VARIABLES
+   int nProbBook =   0;
+   int nProbAnimal = 0;
+   int nProbJunk =   0;
+   int nProbGold = 0;
+   int nProbGem = 0;
+   int nProbJewel = 0;
+   int nProbArcane = 0;
+   int nProbDivine = 0;
+   int nProbAmmo = 0;
+   int nProbKit = 0;
+   int nProbPotion = 0;
+   int nProbTable2 = 0;
+
+   int nSpecific = 0;
+   int i = 0;
+   int nNumberItems = GetNumberOfItems(nTreasureType);
+
+   // * Set Treasure Type Values
+   if (nTreasureType == TREASURE_LOW)
+   {
+    nProbBook   = LOW_PROB_BOOK;
+    nProbAnimal = LOW_PROB_ANIMAL;
+    nProbJunk   = LOW_PROB_JUNK;
+    nProbGold   = LOW_PROB_GOLD;
+    nProbGem    = LOW_PROB_GEM;
+    nProbJewel  = LOW_PROB_JEWEL;
+    nProbArcane = LOW_PROB_ARCANE;
+    nProbDivine  = LOW_PROB_DIVINE;
+    nProbAmmo = LOW_PROB_AMMO ;
+    nProbKit = LOW_PROB_KIT;
+    nProbPotion = LOW_PROB_POTION;
+    nProbTable2 = LOW_PROB_TABLE2;
+   }
+   else if (nTreasureType == TREASURE_MEDIUM)
+   {
+    nProbBook   = MEDIUM_PROB_BOOK;
+    nProbAnimal = MEDIUM_PROB_ANIMAL;
+    nProbJunk   = MEDIUM_PROB_JUNK;
+    nProbGold   = MEDIUM_PROB_GOLD;
+    nProbGem    = MEDIUM_PROB_GEM;
+    nProbJewel  = MEDIUM_PROB_JEWEL;
+    nProbArcane = MEDIUM_PROB_ARCANE;
+    nProbDivine  = MEDIUM_PROB_DIVINE;
+    nProbAmmo = MEDIUM_PROB_AMMO ;
+    nProbKit = MEDIUM_PROB_KIT;
+    nProbPotion = MEDIUM_PROB_POTION;
+    nProbTable2 = MEDIUM_PROB_TABLE2;
+   }
+   else if (nTreasureType == TREASURE_HIGH)
+   {
+    nProbBook   = HIGH_PROB_BOOK;
+    nProbAnimal = HIGH_PROB_ANIMAL;
+    nProbJunk   = HIGH_PROB_JUNK;
+    nProbGold   = HIGH_PROB_GOLD;
+    nProbGem    = HIGH_PROB_GEM;
+    nProbJewel  = HIGH_PROB_JEWEL;
+    nProbArcane = HIGH_PROB_ARCANE;
+    nProbDivine  = HIGH_PROB_DIVINE;
+    nProbAmmo = HIGH_PROB_AMMO ;
+    nProbKit = HIGH_PROB_KIT;
+    nProbPotion = HIGH_PROB_POTION;
+    nProbTable2 = HIGH_PROB_TABLE2;
+   }
+   else if (nTreasureType == TREASURE_BOSS)
+   { //dbSpeak("boss");
+    nProbTable2 = 100;
+    nSpecific = 1;
+   }
+   else if (nTreasureType == TREASURE_BOOK)
+   {
+    nProbBook = 90;
+    nProbArcane = 6;
+    nProbDivine = 4;
+   }
+
+   //dbSpeak("Generate Treasure nSpecific = " + IntToString(nSpecific));
+
+   for (i = 1; i <= nNumberItems; i++)
+   {
+     int nRandom = d100();
+     if (nRandom <= nProbBook)
+        CreateBook(oCreateOn);                                // * Book
+     else if (nRandom <= nProbBook + nProbAnimal)
+        CreateAnimalPart(oCreateOn);                          // * Animal
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk)
+        CreateJunk(oCreateOn);                                // * Junk
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold)
+        CreateGold(oCreateOn, oLastOpener, nTreasureType);    // * Gold
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem)
+        CreateGem(oCreateOn, oLastOpener, nTreasureType);     // * Gem
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel)
+        CreateJewel(oCreateOn, oLastOpener, nTreasureType);   // * Jewel
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane)
+        CreateArcaneScroll(oCreateOn, oLastOpener);   // * Arcane Scroll
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine)
+        CreateDivineScroll(oCreateOn, oLastOpener);   // * Divine Scroll
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine + nProbAmmo)
+        CreateAmmo(oCreateOn, oLastOpener);   // * Ammo
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine + nProbAmmo + nProbKit)
+        CreateKit(oCreateOn, oLastOpener);   // * Healing, Trap, or Thief kit
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine + nProbAmmo + nProbKit + nProbPotion)
+        CreatePotion(oCreateOn, oLastOpener);   // * Potion
+     else if (nRandom <= nProbBook + nProbAnimal + nProbJunk + nProbGold + nProbGem + nProbJewel + nProbArcane + nProbDivine + nProbAmmo + nProbKit + nProbPotion + nProbTable2)
+     {
+        CreateTable2Item(oCreateOn, oLastOpener, nSpecific);   // * Weapons, Armor, Misc - Class based
+     }
+     //else
+     // dbSpeak("other stuff");
+
+
+
+   }
+}
+void GenerateLowTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID)
+{
+ GenerateTreasure(TREASURE_LOW, oLastOpener, oCreateOn);
+}
+void GenerateMediumTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID)
+{
+ GenerateTreasure(TREASURE_MEDIUM, oLastOpener, oCreateOn);
+}
+void GenerateHighTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID)
+{
+ GenerateTreasure(TREASURE_HIGH, oLastOpener, oCreateOn);
+}
+void GenerateBossTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID)
+{
+ GenerateTreasure(TREASURE_BOSS, oLastOpener, oCreateOn);
+}
+void GenerateBookTreasure(object oLastOpener, object oCreateOn=OBJECT_INVALID)
+{
+ GenerateTreasure(TREASURE_BOOK, oLastOpener, oCreateOn);
+}
+//::///////////////////////////////////////////////
+//:: GenerateNPCTreasure
+//:: Copyright (c) 2001 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+   Preferrably called from OnSpawn scripts.
+   Use the random treasure functions to generate
+   appropriate treasure for the creature to drop.
+*/
+//:://////////////////////////////////////////////
+//:: Created By: Brent
+//:: Created On: January 2002
+//:://////////////////////////////////////////////
+
+void GenerateNPCTreasure(int nTreasureValue=1, object oTreasureGetter=OBJECT_SELF, object oKiller=OBJECT_SELF)
+{
+    //DestroyObject(OBJECT_SELF);
+    // * if I am an animal ,then give me animal stuff instead
+    if (GetObjectType(oTreasureGetter) == OBJECT_TYPE_CREATURE)
+    {
+        if (
+            (GetRacialType(oTreasureGetter) == RACIAL_TYPE_UNDEAD) ||
+            (GetRacialType(oTreasureGetter) == RACIAL_TYPE_ANIMAL) ||
+            (GetRacialType(oTreasureGetter) == RACIAL_TYPE_BEAST) ||
+            (GetRacialType(oTreasureGetter) == RACIAL_TYPE_MAGICAL_BEAST) ||
+            (GetRacialType(oTreasureGetter) == RACIAL_TYPE_VERMIN)
+           )
+        {
+            //CreateAnimalPart(oTreasureGetter);
+            // April 23 2002: Removed animal parts. They are silly.
+            return;
+        }
+    }
+
+    if (nTreasureValue == 1)
+    {
+        // April 2002: 30% chance of not getting any treasure now
+        // if a creature
+        if (Random(100)+1 >= 75)
+        {
+            GenerateTreasure(TREASURE_LOW, oTreasureGetter, oKiller);
+        }
+    }
+    else
+    if (nTreasureValue == 2)
+    {
+        GenerateTreasure(TREASURE_MEDIUM, oTreasureGetter, oKiller);
+    }
+    else
+    if (nTreasureValue == 3)
+    {
+        GenerateTreasure(TREASURE_HIGH, oTreasureGetter, oKiller);
+    }
+    else
+    if (nTreasureValue == 4)
+    {
+        GenerateBossTreasure(oKiller, oTreasureGetter);
+    }
+
+}
+
+// *
+// * Theft Prevention
+// *
+
+//::///////////////////////////////////////////////
+//:: ShoutDisturbed
+//:: Copyright (c) 2001 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+
+*/
+//:://////////////////////////////////////////////
+//:: Created By:
+//:: Created On:
+//:://////////////////////////////////////////////
+
+// * Container shouts if disturbed
+void ShoutDisturbed()
+{
+    if (GetIsDead(OBJECT_SELF) == TRUE)
+    {
+            object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE);
+        //Cycle through the targets within the spell shape until an invalid object is captured.
+        while (GetIsObjectValid(oTarget))
+        {
+           if (GetFactionEqual(oTarget, OBJECT_SELF) == TRUE)
+           {
+               // * Make anyone who is a member of my faction hostile if I am violated
+           object oAttacker = GetLastAttacker();
+           SetIsTemporaryEnemy(oAttacker,oTarget);
+           AssignCommand(oTarget, ActionAttack(oAttacker));
+           }
+           oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE);
+        }
+    }
+    else if (GetIsOpen(OBJECT_SELF) == TRUE)
+    {
+            object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE);
+        //Cycle through the targets within the spell shape until an invalid object is captured.
+        while (GetIsObjectValid(oTarget))
+        {
+           if (GetFactionEqual(oTarget, OBJECT_SELF) == TRUE)
+           {
+               // * Make anyone who is a member of my faction hostile if I am violated
+           object oAttacker = GetLastOpener();
+           SetIsTemporaryEnemy(oAttacker,oTarget);
+           AssignCommand(oTarget, ActionAttack(oAttacker));
+
+           }
+           oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, GetLocation(OBJECT_SELF), TRUE, OBJECT_TYPE_CREATURE);
+        }
+    }
+}
+
+int nGetIsBaseClass(int nClass)
+{
+  return (nClass <= CLASS_TYPE_WIZARD ||
+           nClass == CLASS_TYPE_ANTI_PALADIN ||
+           nClass == CLASS_TYPE_ARCHIVIST ||
+           nClass == CLASS_TYPE_BEGUILER ||
+           nClass == CLASS_TYPE_BOWMAN ||
+           nClass == CLASS_TYPE_BRAWLER ||
+           nClass == CLASS_TYPE_CRUSADER ||
+           nClass == CLASS_TYPE_DRAGON_SHAMAN ||
+           nClass == CLASS_TYPE_DRAGONFIRE_ADEPT ||
+           nClass == CLASS_TYPE_DREAD_NECROMANCER ||
+           nClass == CLASS_TYPE_DUSKBLADE ||
+           nClass == CLASS_TYPE_FAVOURED_SOUL ||
+           nClass == CLASS_TYPE_HEALER ||
+           nClass == CLASS_TYPE_HEXBLADE ||
+           nClass == CLASS_TYPE_KNIGHT ||
+           nClass == CLASS_TYPE_MARSHAL ||
+           nClass == CLASS_TYPE_MYSTIC ||
+           nClass == CLASS_TYPE_NINJA ||
+           nClass == CLASS_TYPE_NOBLE ||
+           nClass == CLASS_TYPE_PSION ||
+           nClass == CLASS_TYPE_PSYWAR ||
+           nClass == CLASS_TYPE_PSYCHIC_ROGUE ||
+           nClass == CLASS_TYPE_SAMURAI ||
+           nClass == CLASS_TYPE_CW_SAMURAI ||
+           nClass == CLASS_TYPE_SCOUT ||
+           nClass == CLASS_TYPE_SHAMAN ||
+           nClass == CLASS_TYPE_SOHEI ||
+           nClass == CLASS_TYPE_SOULKNIFE ||
+           nClass == CLASS_TYPE_SWASHBUCKLER ||
+           nClass == CLASS_TYPE_SWORDSAGE ||
+           nClass == CLASS_TYPE_TRUENAMER ||
+           nClass == CLASS_TYPE_ULTIMATE_RANGER ||
+           nClass == CLASS_TYPE_WARBLADE ||
+           nClass == CLASS_TYPE_WARLOCK ||
+           nClass == CLASS_TYPE_WARMAGE ||
+           nClass == CLASS_TYPE_WILDER ||
+           nClass == CLASS_TYPE_WITCH ||
+           nClass == CLASS_TYPE_TEMPLAR);
+}
+
+//::///////////////////////////////////////////////
+//:: Determine Class to Use
+//:: Copyright (c) 2002 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+    Determines which of a NPCs three classes to
+    use in the random treasure system
+*/
+//:://////////////////////////////////////////////
+//:: Created By: Preston Watamaniuk
+//:: Created On: April 4, 2002
+//:://////////////////////////////////////////////
+
+int nDetermineClassToUse(object oCharacter)
+{
+    int nClass;
+    int nTotal = GetHitDice(oCharacter);
+    //dbSpeak("Hit dice " + IntToString(nTotal));
+    if (nTotal < 1)
+    {
+        nTotal = 1;
+    }
+/*
+    float fTotal = IntToFloat(nTotal);
+    //if (GetIsObjectValid(oCharacter) == FALSE)
+    //{
+    //    dbSpeak("DetermineClassToUse: This character is invalid");
+    //}
+
+    int nClass1 =  GetClassByPosition(1, oCharacter);
+    int nState1 = FloatToInt((IntToFloat(GetLevelByClass(nClass1, oCharacter)) / fTotal) * 100);
+    //dbSpeak("Level 1 Class Level = " + IntToString(GetLevelByClass(nClass1,oCharacter)));
+
+    //PrintString("GENERIC SCRIPT DEBUG STRING ********** " +  GetTag(oCharacter) + "Class 1 " + IntToString(nState1));
+    //dbSpeak("State 1 " + IntToString(nState1));
+    int nClass2 = GetClassByPosition(2, oCharacter);
+    int nState2 = FloatToInt((IntToFloat(GetLevelByClass(nClass2, oCharacter)) / fTotal) * 100) + nState1;
+    //PrintString("GENERIC SCRIPT DEBUG STRING ********** " + GetTag(oCharacter) + "Class 2 " + IntToString(nState2));
+
+    int nClass3 = GetClassByPosition(3, oCharacter);
+    int nState3 = FloatToInt((IntToFloat(GetLevelByClass(nClass3, oCharacter)) / fTotal) * 100) + nState2;
+    //PrintString("GENERIC SCRIPT DEBUG STRING ********** " + GetTag(oCharacter) + "Class 3 " + IntToString(nState3));
+*/
+    int nClass1 = GetClassByPosition(1, oCharacter);
+    int nClass2 = GetClassByPosition(2, oCharacter);
+    int nClass3 = GetClassByPosition(3, oCharacter);
+    int nClass4 = GetClassByPosition(4, oCharacter);
+	int nClass5 = GetClassByPosition(5, oCharacter);
+    int nClass6 = GetClassByPosition(6, oCharacter);
+    int nClass7 = GetClassByPosition(7, oCharacter);	
+    int nClass8 = GetClassByPosition(8, oCharacter);	
+	
+    int nState1 = GetLevelByClass(nClass1, oCharacter) * 100 / nTotal;
+    int nState2 = GetLevelByClass(nClass2, oCharacter) * 100 / nTotal + nState1;
+	int nState3 = GetLevelByClass(nClass3, oCharacter) * 100 / nTotal + nState2;
+	int nState4 = GetLevelByClass(nClass4, oCharacter) * 100 / nTotal + nState3;
+	int nState5 = GetLevelByClass(nClass5, oCharacter) * 100 / nTotal + nState4;
+	int nState6 = GetLevelByClass(nClass6, oCharacter) * 100 / nTotal + nState5;
+	int nState7 = GetLevelByClass(nClass7, oCharacter) * 100 / nTotal + nState6;
+	
+    // nState8 will always be 100 if there is an eigth class, or 0 if there isn't
+    //int nState8 = GetLevelByClass(nClass3, oCharacter) * 100 / nTotal + nState7;
+
+    // correct for unrecognized classes - assumes the first class will be a non-prestige player class
+    if(nClass2 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass2))
+    {
+        nClass2 = CLASS_TYPE_INVALID;
+        nState1 = nState2;
+    }	
+    if(nClass3 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass3))
+    {
+        nClass3 = CLASS_TYPE_INVALID;
+        nState1 = nState3;
+    }
+    if(nClass4 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass4))
+    {
+        nClass4 = CLASS_TYPE_INVALID;
+        nState1 = nState4;
+    }
+    if(nClass5 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass5))
+    {
+        nClass5 = CLASS_TYPE_INVALID;
+        nState1 = nState5;
+    }	
+    if(nClass6 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass6))
+    {
+        nClass6 = CLASS_TYPE_INVALID;
+        nState1 = nState6;
+    }	
+    if(nClass7 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass7))
+    {
+        nClass7 = CLASS_TYPE_INVALID;
+        nState1 = nState7;
+    }
+    if(nClass8 != CLASS_TYPE_INVALID && !nGetIsBaseClass(nClass8))
+    {
+        nClass8 = CLASS_TYPE_INVALID;
+        if(nClass7 != CLASS_TYPE_INVALID)
+            nState7 = 100;
+        else nState1 = 100;
+    }
+
+    int nUseClass = d100();
+    //PrintString("GENERIC SCRIPT DEBUG STRING ********** " + "D100 Roll " +IntToString(nUseClass));
+
+
+    //dbSpeak("Before comparison : " + IntToString(nClass1));
+    if(nUseClass <= nState1)
+    {
+        nClass = nClass1;
+    }
+    else if(nUseClass > nState1 && nUseClass <= nState2)
+    {
+        nClass = nClass2;
+    }
+    else
+    {
+        // might be possible to end up here by accident because of a rounding error
+        // so just in case...
+        if(nClass3 == CLASS_TYPE_INVALID) nClass = nClass1;
+        else nClass = nClass3;
+    }
+
+    //dbSpeak("Class from determineClass " + IntToString(nClass));
+    return nClass;
+}
+
+//:: Test Void
+//void main () {}
+
diff --git a/trunk/include/prc_inc_castlvl.nss b/trunk/include/prc_inc_castlvl.nss
new file mode 100644
index 00000000..58c911f0
--- /dev/null
+++ b/trunk/include/prc_inc_castlvl.nss
@@ -0,0 +1,1823 @@
+
+
+/**
+ *  @file
+ *
+ * This file contains PRCGetCasterLevel() and all its accessory functions.
+ * Functions that modify caster level go in this include. Keep out irrelevent
+ * functions. If this ends up like prc_inc_spells, you get slapped.
+ */
+
+//:: Updated for .35 by Jaysyn 2023/03/10
+
+//////////////////////////////////////////////////
+/* Function prototypes                          */
+//////////////////////////////////////////////////
+
+/**
+ * Returns the caster level when used in spells.  You can use PRCGetCasterLevel()
+ * to determine a caster level from within a true spell script.  In spell-like-
+ * abilities & items, it will only return GetCasterLevel.
+ *
+ * @param oCaster   The creature casting the spell.
+ *
+ * @return          The caster level the spell was cast at.
+ */
+int PRCGetCasterLevel(object oCaster = OBJECT_SELF);
+
+/**
+ * A lookup for caster level progression for divine and arcane base classes
+ * @return an int that can be used in caster level calculations note: these use int division
+ */
+int GetCasterLevelModifier(int nClass);
+
+/**
+ * To override for custom spellcasting classes. Looks for the
+ * local int "PRC_CASTERCLASS_OVERRIDE" on oCaster. If set,
+ * this is used as the casting class, else GetLastSpellCastClass()
+ * is used.
+ *
+ * @param oCaster   The creature that last cast a spell
+ *
+ * @return          The class used to cast the spell.
+ */
+int PRCGetLastSpellCastClass(object oCaster = OBJECT_SELF);
+
+/**
+ * Returns if the given class is an arcane class.
+ *
+ * Arcane base classes are *hardcoded* into here, so new arcane
+ * base classes need adding to this function.
+ * Note: PrCs with their own spellbook eg. assassin count as base casters for this function
+ *
+ * @param oCaster   The creature to check (outsiders can have sorc caster levels)
+ *
+ * @return          TRUE if nClass is an arcane spellcasting class, FALSE otherwise
+ */
+int GetIsArcaneClass(int nClass, object oCaster = OBJECT_SELF);
+
+/**
+ * Returns if the given class is an arcane class.
+ *
+ * Divine base classes are *hardcoded* into here, so new divine
+ * base classes need adding to this function.
+ * Note: PrCs with their own spellbook eg. blackguard count as base casters for this function
+ *
+ * @param oCaster   The creature to check (not currently used)
+ *
+ * @return      TRUE if nClass is a divine spellcasting class, FALSE otherwise
+ */
+int GetIsDivineClass(int nClass, object oCaster = OBJECT_SELF);
+
+// Returns the best "natural" arcane levels of the PC in question.  Does not
+// consider feats that situationally adjust caster level.
+int GetLevelByTypeArcane(object oCaster = OBJECT_SELF);
+
+// Returns the best "natural" divine levels of the PC in question.  Does not
+// consider feats that situationally adjust caster level.
+int GetLevelByTypeDivine(object oCaster = OBJECT_SELF);
+
+/**
+ * Works out the total arcane caster levels from arcane PrCs.
+ *
+ * Arcane prestige classes are *hardcoded* into this function, so new arcane caster
+ * classes need adding to it. Rakshasa RHD count as sorc PrC levels if they also have some levels in sorc
+ * note: PrCs with their own spellbook eg. assassin are not PrCs for this function
+ *
+ * @param oCaster   The creature to check
+ * @param nCastingClass   Casting class, only ever used for UM
+ *
+ * @return          Number of arcane caster levels contributed by PrCs.
+ */
+int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID);
+
+/**
+ * Works out the total divine caster levels from arcane PrCs.
+ *
+ * Divine prestige classes are *hardcoded* into this function, so new divine caster
+ * classes need adding to it.
+ * note: PrCs with their own spellbook eg. blackguard are not PrCs for this function
+ *
+ * @param oCaster   The creature to check
+ *
+ * @return          Number of divine caster levels contributed by PrCs.
+ */
+int GetDivinePRCLevels(object oCaster);
+
+/**
+ * Gets the position of the first arcane base class.
+ *
+ * @param oCaster   The creature to check
+ *
+ * @return          The position (1,2 or 3) of the first arcane *base* class of oCaster
+ */
+int GetFirstArcaneClassPosition(object oCaster = OBJECT_SELF);
+
+/**
+ * Gets the position of the first divine base class.
+ *
+ * @param oCaster   The creature to check
+ *
+ * @return          The position (1,2 or 3) of the first divine *base* class of oCaster
+ */
+int GetFirstDivineClassPosition(object oCaster = OBJECT_SELF);
+
+/**
+ * Gets the highest or first (by position) *base* arcane class type or,
+ * if oCaster has no arcane class levels, returns CLASS_TYPE_INVALID.
+ *
+ * This will get rakshasa RHD 'class' if oCaster doesn't have sorc levels.
+ *
+ * @param oCaster   The creature to check
+ *
+ * @return          CLASS_TYPE_* of first base arcane class or CLASS_TYPE_INVALID
+ */
+int GetPrimaryArcaneClass(object oCaster = OBJECT_SELF);
+
+/**
+ * Gets the highest first (by position) *base* divine class type or,
+ * if oCaster has no divine class levels, returns CLASS_TYPE_INVALID.
+ *
+ * @param oCaster   The creature to check
+ *
+ * @return          CLASS_TYPE_* of first base divine class or CLASS_TYPE_INVALID
+ */
+int GetPrimaryDivineClass(object oCaster = OBJECT_SELF);
+
+/**
+ * Gets the highest *base* arcane or divine class type or,
+ * if oCaster has no spellcasting class levels, returns CLASS_TYPE_INVALID.
+ *
+ * @param oCaster   The creature to check
+ *
+ * @return          CLASS_TYPE_* of first base arcane/divine class or CLASS_TYPE_INVALID
+ */
+int GetPrimarySpellcastingClass(object oCaster = OBJECT_SELF);
+
+/**
+ * Gets the caster level adjustment from the Practiced Spellcaster feats.
+ *
+ * @param oCaster           The creature to check
+ * @param iCastingClass     The CLASS_TYPE* that the spell was cast by.
+ * @param iCastingLevels    The caster level for the spell calculated so far
+ *                          ie. BEFORE Practiced Spellcaster.
+ */
+int PracticedSpellcasting(object oCaster, int iCastingClass, int iCastingLevels);
+
+/**
+ * Returns the spell school of the spell passed to it.
+ *
+ * @param iSpellId  The spell to get the school of.
+ *
+ * @return          The SPELL_SCHOOL_* of the spell.
+ */
+int GetSpellSchool(int iSpellId);
+
+/**
+ * Healing spell filter.
+ *
+ * Gets if the given spell is a healing spell based on a hardcoded list. New
+ * healing spells need to be added to this.
+ *
+ * @author          GaiaWerewolf
+ * @date            18 July 2005
+ *
+ * @param nSpellId  The spell to check
+ *
+ * @return          TRUE if it is a healing spell, FALSE otherwise.
+ */
+int GetIsHealingSpell(int nSpellId);
+
+/**
+ * Gets the contribution of the archmage's High Arcana Spell Power
+ * feat to caster level.
+ *
+ * @param oCaster   The creature to check
+ *
+ * @return          caster level modifier from archmage Spell Power feats.
+ */
+int ArchmageSpellPower(object oCaster);
+
+/**
+ * Gets the caster level modifier from the Shadow Weave feat.
+ *
+ * Schools of Enchantment, Illusion, and Necromancy, and spells with the darkness
+ * descriptor altered by +1, Evocation or Transmutation (except spells with the
+ * darkness descriptor) altered by -1.
+ *
+ * @param oCaster       The creature to check
+ * @param iSpellID      The spell ID of the spell
+ * @param nSpellSchool  The spell school the cast spell is from
+ *                      if none is specified, uses GetSpellSchool()
+ *
+ * @return              caster level modifier for Shadow Weave feat.
+ */
+int ShadowWeave(object oCaster, int iSpellID, int nSpellSchool = -1);
+
+/**
+ * Gets the caster level modifier from the Divination Power class feature.
+ *
+ * Divination spells +1/3 Unseen Seer levels, all others -1/3 Unseer Seer levels
+ *
+ * @param oCaster       The creature to check
+ * @param iSpellID      The spell ID of the spell
+ * @param nSpellSchool  The spell school the cast spell is from
+ *                      if none is specified, uses GetSpellSchool()
+ *
+ * @return              caster level modifier for Divination Power feat.
+ */
+int DivinationPower(object oCaster, int nSpellSchool);
+
+/**
+ * Handles feats that modify caster level of spells with the fire
+ * descriptor.
+ *
+ * Currently this is Disciple of Meph's Fire Adept feat and Bloodline of Fire feat.
+ *
+ * @param oCaster       The creature to check
+ * @param iSpellID      The spell ID of the spell
+ *
+ * @return              Caster level modifier for fire related feats.
+ */
+int FireAdept(object oCaster, int iSpellID);
+
+/**
+ * Handles feats that modify caster level of spells with the air
+ * descriptor.
+ *
+ * Currently this is the Air Mephling's Type feat
+ *
+ * @param oCaster       The creature to check
+ * @param iSpellID      The spell ID of the spell
+ *
+ * @return              Caster level modifier for fire related feats.
+ */
+int AirAdept(object oCaster, int iSpellID);
+
+/**
+ * Handles feats that modify caster level of spells with the air
+ * descriptor.
+ *
+ * Currently this is the Air Mephling's Type feat
+ *
+ * @param oCaster       The creature to check
+ * @param iSpellID      The spell ID of the spell
+ *
+ * @return              Caster level modifier for fire related feats.
+ */
+int WaterAdept(object oCaster, int iSpellID);
+
+/**
+ * Handles feats that modify caster level of spells with the earth
+ * descriptor.
+ *
+ * Currently this is Drift Magic feat.
+ *
+ * @param oCaster       The creature to check
+ * @param iSpellID      The spell ID of the spell
+ *
+ * @return              Caster level modifier for earth related feats.
+ */
+int DriftMagic(object oCaster, int iSpellID);
+
+/**
+ * Soulcaster boost to caster level based on invested essentia
+ *
+ * @param oCaster       The creature to check
+ * @param iSpellID      The spell ID of the spell
+ *
+ * @return              Caster level modifier
+ */
+int Soulcaster(object oCaster, int iSpellID);
+
+/**
+ * Gets the caster level modifier from the Storm Magic feat.
+ *
+ * Get +1 caster level if raining or snowing in area
+ *
+ * @param oCaster       The creature to check
+ *
+ * @return              Caster level modifier for Storm Magic feat.
+ */
+int StormMagic(object oCaster);
+
+/**
+ * Gets the caster level modifier from the Cormanthyran Moon Magic feat.
+ *
+ * Get +1 caster level if outdoors, at night, with no rain.
+ *
+ * @param oCaster       The creature to check
+ *
+ * @return              Caster level modifier for Cormanthyran Moon Magic feat.
+ */
+int CormanthyranMoonMagic(object oCaster);
+
+/**
+ * Gets the caster level modifier from various domains.
+ *
+ * @param oCaster       The creature to check
+ * @param nSpellID      The spell ID of the spell
+ * @param nSpellSchool  The spell school the cast spell is from
+ *                      if none is specified, uses GetSpellSchool()
+ *
+ * @return              caster level modifier from domain powers
+ */
+int DomainPower(object oCaster, int nSpellID, int nSpellSchool = -1);
+
+/**
+ * Gets the caster level modifier from the Therapeutic Mantle Meld.
+ *
+ * @param oCaster       The creature to check
+ *
+ * @return              caster level modifier
+ */
+int TherapeuticMantle(object oCaster, int nSpellID);
+
+/**
+ * Gets the caster level modifier from the antipaladin's Death Knell SLA.
+ *
+ * @param oCaster       The creature to check
+ *
+ * @return              caster level modifier from the Death Knell SLA
+ */
+int DeathKnell(object oCaster);
+
+/**
+ * Gets the caster level modifier from the Draconic Power feat.
+ *
+ * Feat gives +1 to caster level.
+ *
+ * @param oCaster       The creature to check
+ *
+ * @return              caster level modifier from the Draconic power feat.
+ */
+int DraconicPower(object oCaster = OBJECT_SELF);
+
+/**
+ * Gets the caster level modifier from Song of Arcane Power effect.
+ *
+ * @param oCaster       The creature to check
+ *
+ * @return              caster level modifier from the Draconic power feat.
+ */
+int SongOfArcanePower(object oCaster = OBJECT_SELF);
+
+/**
+ * Gets the caster level modifier to necromancy spells for the
+ * True Necromancer PrC (all spellcasting levels are counted, both
+ * arcane and divine).
+ *
+ * @param oCaster       The creature to check
+ * @param iSpellID      The spell ID of the spell
+ * @param sType         "ARCANE" or "DIVINE" spell
+ * @param nSpellSchool  The spell school the cast spell is from
+ *                      if none is specified, uses GetSpellSchool()
+ *
+ * @return              caster level modifier for True Necro
+ */
+int TrueNecromancy(object oCaster, int iSpellID, string sType, int nSpellSchool = -1);
+
+// Nentyar Hunter casting boost
+int Nentyar(object oCaster, int nCastingClass);
+
+// +1 on spells that target armor or shields
+int ShieldDwarfWarder(object oCaster);
+
+// +1 while this feat is active
+int DarkSpeech(object oCaster);
+
+// Adds 1/2 level in all other casting classes.
+int UrPriestCL(object oCaster, int nCastingClass);
+
+// Adds Druid levels to Blighter caster level
+int BlighterCL(object oCaster, int nCastingClass);
+
+//ebonfowl: Adds CL boosts from reserve feats
+int ReserveFeatCL(object oCaster, int iSpellId);
+
+//////////////////////////////////////////////////
+/* Include section                              */
+//////////////////////////////////////////////////
+
+//#include "prc_racial_const"
+// Not needed as it has acccess via prc_inc_newip
+//#include "prc_inc_nwscript" // gets inc_2da_cache, inc_debug, prc_inc_switch
+#include "prc_inc_newip"
+//#include "prc_inc_spells"
+#include "prc_inc_descrptr"
+
+//////////////////////////////////////////////////
+/* Internal functions                           */
+//////////////////////////////////////////////////
+
+// stolen from prcsp_archmaginc.nss, modified to work in FireAdept() function
+string _GetChangedElementalType(int nSpellID, object oCaster = OBJECT_SELF)
+{
+    string spellType = Get2DACache("spells", "ImmunityType", nSpellID);//lookup_spell_type(spell_id);
+    string sType = GetLocalString(oCaster, "archmage_mastery_elements_name");
+
+    if (sType == "") sType = spellType;
+
+    return sType;
+}
+
+//ebonfowl: Adding this function to check if a spell belongs to a given domain based on the Reserve Feat 2das
+//Only works with Death, Destruction and War domains as only those domain 2das have been created
+int GetIsFromDomain (int iSpellId, string sDomain)
+{
+    string sFile = "prc_desc_" + sDomain;
+
+    int i;
+    int nListSpellID;
+
+    for (i = 0; i < 15; i++) // Adjust max i to reflect something close to the highest row number in the 2das
+    {
+        nListSpellID = StringToInt(Get2DACache(sFile, "SpellID", i));
+        if (nListSpellID == iSpellId) return TRUE;
+    }
+    return FALSE;
+}
+
+//////////////////////////////////////////////////
+/* Function Definitions                         */
+//////////////////////////////////////////////////
+
+int GetCasterLevelModifier(int nClass)
+{
+    switch(nClass) // do not change to return zero as this is used as a divisor
+    {
+        // add in new base half-caster classes here
+        case CLASS_TYPE_HEXBLADE:
+        case CLASS_TYPE_RANGER:
+        case CLASS_TYPE_PALADIN:
+        case CLASS_TYPE_ANTI_PALADIN:
+            return 2;
+    }
+    return 1; // normal progression
+}
+
+int PRCGetCasterLevel(object oCaster = OBJECT_SELF)
+{
+    int nAdjust = GetLocalInt(oCaster, PRC_CASTERLEVEL_ADJUSTMENT);//this is for builder use
+    nAdjust += GetLocalInt(oCaster, "TrueCasterLens");
+    nAdjust += GetHasSpellEffect(SPELL_VIRTUOSO_MAGICAL_MELODY, oCaster);
+
+    // For when you want to assign the caster level.
+    int iReturnLevel = GetLocalInt(oCaster, PRC_CASTERLEVEL_OVERRIDE);
+    if (iReturnLevel)
+    {
+        if (DEBUG) DoDebug("PRCGetCasterLevel: found override caster level = "+IntToString(iReturnLevel)+" with adjustment = " + IntToString(nAdjust)+", original level = "+IntToString(GetCasterLevel(oCaster)));
+        return iReturnLevel+nAdjust;
+    }
+
+    // if we made it here, iReturnLevel = 0;
+
+    int iCastingClass = PRCGetLastSpellCastClass(oCaster); // might be CLASS_TYPE_INVALID
+    if(iCastingClass == CLASS_TYPE_SUBLIME_CHORD)
+        iCastingClass = GetPrimaryArcaneClass(oCaster);
+    int iSpellId = PRCGetSpellId(oCaster);
+    object oItem = PRCGetSpellCastItem(oCaster);
+
+    // Item Spells
+    // this check is unreliable because of Bioware's implementation (GetSpellCastItem returns
+    // the last object from which a spell was cast, even if we are not casting from an item)
+    if(GetIsObjectValid(oItem))
+    {
+        int nType = GetBaseItemType(oItem);
+        if(DEBUG) DoDebug("PRCGetCasterLevel: found valid item = "+GetName(oItem));
+        // double check, just to make sure
+        if(GetItemPossessor(oItem) == oCaster) // likely item casting
+        {
+            if(GetPRCSwitch(PRC_STAFF_CASTER_LEVEL)
+                && ((nType == BASE_ITEM_MAGICSTAFF) ||
+                    (nType == BASE_ITEM_CRAFTED_STAFF))
+                )
+            {
+                iCastingClass = GetPrimarySpellcastingClass(oCaster);
+            }
+            else
+            {
+                //code for getting new ip type
+                itemproperty ipTest = GetFirstItemProperty(oItem);
+                while(GetIsItemPropertyValid(ipTest))
+                {
+                    if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_CAST_SPELL_CASTER_LEVEL)
+                    {
+                        int nSubType = GetItemPropertySubType(ipTest);
+                        nSubType = StringToInt(Get2DACache("iprp_spells", "SpellIndex", nSubType));
+                        if(nSubType == iSpellId)
+                        {
+                            iReturnLevel = GetItemPropertyCostTableValue(ipTest);
+                            if (DEBUG) DoDebug("PRCGetCasterLevel: caster level from item = "+IntToString(iReturnLevel));
+                            break; // exit the while loop
+                        }
+                    }
+                    ipTest = GetNextItemProperty(oItem);
+                }
+                // if we didn't find a caster level on the item, it must be Bioware item casting
+                if(!iReturnLevel)
+                {
+                    iReturnLevel = GetCasterLevel(oCaster);
+                    if (DEBUG) DoDebug("PRCGetCasterLevel: bioware item casting with caster level = "+IntToString(iReturnLevel));
+                }
+            }
+
+            if(nType == BASE_ITEM_MAGICWAND || nType == BASE_ITEM_ENCHANTED_WAND)
+            {   
+                if (DEBUG) DoDebug("PRCGetCasterLevel - Casting Item is a Wand at level "+IntToString(iReturnLevel));
+                if (GetHasFeat(FEAT_RECKLESS_WAND_WIELDER, oCaster) && GetLocalInt(oCaster, "RecklessWand")) // This burns an extra charge to increase caster level by 2
+                {
+                    if (DEBUG) DoDebug("PRCGetCasterLevel - Reckless Wand Active");
+                    if (GetItemCharges(oItem) > 0) // Make sure we have an extra charge to burn
+                    {
+                        iReturnLevel += 2;
+                        if (!GetLocalInt(oCaster, "RecklessWandDelay")) SetItemCharges(oItem, GetItemCharges(oItem)-1);
+                        SetLocalInt(oCaster, "RecklessWandDelay", TRUE);
+                        DelayCommand(0.5, DeleteLocalInt(oCaster, "RecklessWandDelay"));
+                        if (DEBUG) DoDebug("PRCGetCasterLevel - Reckless Wand Triggered at level "+IntToString(iReturnLevel));
+                    }
+                }    
+                if (GetHasFeat(FEAT_WAND_MASTERY, oCaster))
+                    iReturnLevel += 2;
+            } 
+        }
+        if (DEBUG) DoDebug("PRCGetCasterLevel: total item casting caster level = "+IntToString(iReturnLevel));
+    }
+
+    // get spell school here as many of the following fns use it
+    int nSpellSchool = GetSpellSchool(iSpellId);
+
+    // no item casting, and arcane caster?
+    if(!iReturnLevel && GetIsArcaneClass(iCastingClass, oCaster))
+    {
+        iReturnLevel = GetLevelByClass(iCastingClass, oCaster) / GetCasterLevelModifier(iCastingClass);
+        
+        // Casting as a sorc but don't have any levels in the class
+	    if(iCastingClass == CLASS_TYPE_SORCERER && !GetLevelByClass(CLASS_TYPE_SORCERER, oCaster))
+	    {
+	        int nRace = GetRacialType(oCaster);
+	
+	        //if the player has sorcerer levels, then it counts as a prestige class
+	        //otherwise use RHD instead of sorc levels
+	        if(nRace == RACIAL_TYPE_RAKSHASA)
+	            iReturnLevel = GetLevelByClass(CLASS_TYPE_OUTSIDER);
+	        else if(nRace == RACIAL_TYPE_DRIDER)
+	            iReturnLevel = GetLevelByClass(CLASS_TYPE_ABERRATION);
+	        else if(nRace == RACIAL_TYPE_ARKAMOI)
+	            iReturnLevel = GetLevelByClass(CLASS_TYPE_MONSTROUS);
+	        else if(nRace == RACIAL_TYPE_REDSPAWN_ARCANISS)
+	            iReturnLevel = GetLevelByClass(CLASS_TYPE_MONSTROUS)*3/4;	            
+	        else if(nRace == RACIAL_TYPE_MARRUTACT)
+	            iReturnLevel = (GetLevelByClass(CLASS_TYPE_MONSTROUS)*6/7)-1;	            
+			else if(nRace == RACIAL_TYPE_ARANEA)
+	            iReturnLevel = GetLevelByClass(CLASS_TYPE_SHAPECHANGER);
+			 
+	    }     
+        // Casting as a bard but don't have any levels in the class
+	    if(iCastingClass == CLASS_TYPE_BARD && !GetLevelByClass(CLASS_TYPE_BARD, oCaster))
+	    {
+	        int nRace = GetRacialType(oCaster);
+	
+	        //if the player has bard levels, then it counts as a prestige class
+	        //otherwise use RHD instead of bard levels
+	        if(nRace == RACIAL_TYPE_GLOURA)
+	            iReturnLevel = GetLevelByClass(CLASS_TYPE_FEY);	            
+	    }   	    
+
+        //Spell Rage ability
+        if(GetHasSpellEffect(SPELL_SPELL_RAGE, oCaster)
+        && (nSpellSchool == SPELL_SCHOOL_ABJURATION
+        || nSpellSchool == SPELL_SCHOOL_CONJURATION
+        || nSpellSchool == SPELL_SCHOOL_EVOCATION
+        || nSpellSchool == SPELL_SCHOOL_NECROMANCY
+        || nSpellSchool == SPELL_SCHOOL_TRANSMUTATION))
+        {
+            iReturnLevel = GetHitDice(oCaster);
+        }
+
+        else if(GetPrimaryArcaneClass(oCaster) == iCastingClass)
+            iReturnLevel += GetArcanePRCLevels(oCaster);
+        else if(GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCaster)) 
+        	iReturnLevel += GetArcanePRCLevels(oCaster, iCastingClass);
+
+        iReturnLevel += PracticedSpellcasting(oCaster, iCastingClass, iReturnLevel);
+
+        iReturnLevel += TrueNecromancy(oCaster, iSpellId, "ARCANE", nSpellSchool)
+            +  ShadowWeave(oCaster, iSpellId, nSpellSchool)
+            +  FireAdept(oCaster, iSpellId)
+			+  AirAdept(oCaster, iSpellId)
+			+  WaterAdept(oCaster, iSpellId)
+            +  ArchmageSpellPower(oCaster)
+            +  StormMagic(oCaster)
+            +  CormanthyranMoonMagic(oCaster)
+            +  DomainPower(oCaster, iSpellId, nSpellSchool)
+            +  DivinationPower(oCaster, nSpellSchool)
+            +  DeathKnell(oCaster)
+            +  DraconicPower(oCaster)
+            +  DriftMagic(oCaster, iSpellId)
+            +  Soulcaster(oCaster, iSpellId)
+            +  TherapeuticMantle(oCaster, iSpellId)
+            +  DarkSpeech(oCaster)
+            +  ShieldDwarfWarder(oCaster)
+            +  SongOfArcanePower(oCaster)
+            +  ReserveFeatCL(oCaster, iSpellId);
+            
+        if (GetLocalInt(oCaster, "CaptureMagic")) 
+        {
+            iReturnLevel += GetLocalInt(oCaster, "CaptureMagic");
+            DeleteLocalInt(oCaster, "CaptureMagic");
+        }            
+
+        // Get stance level bonus for Jade Phoenix Mage
+        if(GetLevelByClass(CLASS_TYPE_JADE_PHOENIX_MAGE, oCaster))
+        {
+            if (_GetChangedElementalType(iSpellId, oCaster) == "Fire" && GetLocalInt(oCaster, "ToB_JPM_FireB"))
+                iReturnLevel += 3;
+            iReturnLevel += GetLocalInt(oCaster, "ToB_JPM_MystP");
+        }
+       // Abjurant Champion uses its Base AB as Caster Level if higher
+        if(GetHasFeat(FEAT_MARTIAL_ARCANIST))
+        {
+                //Get the caster's base AB
+                int nBaseAB = GetBaseAttackBonus(oCaster);
+                if(nBaseAB > iReturnLevel)
+                {
+                 iReturnLevel = nBaseAB;
+                }  
+        }
+        if (DEBUG) DoDebug("PRCGetCasterLevel: total arcane caster level = "+IntToString(iReturnLevel));
+    }
+	
+    // no item casting and divine caster?
+    else if(!iReturnLevel && GetIsDivineClass(iCastingClass, oCaster))
+    {
+        iReturnLevel = GetLevelByClass(iCastingClass, oCaster) / GetCasterLevelModifier(iCastingClass);
+        if(GetPrimaryDivineClass(oCaster) == iCastingClass)
+            iReturnLevel += GetDivinePRCLevels(oCaster);
+
+        iReturnLevel += PracticedSpellcasting(oCaster, iCastingClass, iReturnLevel);
+
+        iReturnLevel += TrueNecromancy(oCaster, iSpellId, "DIVINE", nSpellSchool)
+            +  ShadowWeave(oCaster, iSpellId, nSpellSchool)
+            +  FireAdept(oCaster, iSpellId)
+            +  StormMagic(oCaster)
+            +  CormanthyranMoonMagic(oCaster)
+            +  Nentyar(oCaster, iCastingClass)
+            +  DomainPower(oCaster, iSpellId, nSpellSchool)
+            +  DriftMagic(oCaster, iSpellId)
+			+  AirAdept(oCaster, iSpellId)
+			+  WaterAdept(oCaster, iSpellId)
+            +  Soulcaster(oCaster, iSpellId)
+            +  ShieldDwarfWarder(oCaster)
+            +  DarkSpeech(oCaster)
+            +  DeathKnell(oCaster)
+            +  UrPriestCL(oCaster, iCastingClass)
+            +  BlighterCL(oCaster, iCastingClass)
+            +  ReserveFeatCL(oCaster, iSpellId);
+            
+        if (DEBUG) DoDebug("PRCGetCasterLevel: total divine caster level = "+IntToString(iReturnLevel));    
+    }
+
+    //at this point it must be a SLA or similar
+    if(!iReturnLevel)
+    {
+        iReturnLevel = GetCasterLevel(oCaster);
+        if (DEBUG) DoDebug("PRCGetCasterLevel: bioware caster level = "+IntToString(iReturnLevel));
+    }
+
+    iReturnLevel -= GetLocalInt(oCaster, "WoLCasterPenalty"); 
+    if (GetLocalInt(oCaster, "EldritchDisrupt"))
+        iReturnLevel -= 4;  
+    if (GetLocalInt(oCaster, "EldritchVortex"))
+        iReturnLevel -= 4;         
+    if (DEBUG) DoDebug("PRCGetCasterLevel: caster level pre adjust = "+IntToString(iReturnLevel));
+    iReturnLevel += nAdjust;
+    if (DEBUG) DoDebug("PRCGetCasterLevel: total caster level = "+IntToString(iReturnLevel));
+
+    return iReturnLevel;
+}
+
+int PRCGetLastSpellCastClass(object oCaster = OBJECT_SELF)
+{
+    // note that a barbarian has a class type constant of zero. So nClass == 0 could in principle mean
+    // that a barbarian cast the spell, However, barbarians cannot cast spells, so it doesn't really matter
+    // beware of Barbarians with UMD, though. Also watch out for spell like abilities
+    // might have to provide a fix for these (for instance: if(nClass == -1) nClass = 0;
+    int nClass = GetLocalInt(oCaster, PRC_CASTERCLASS_OVERRIDE);
+    if(nClass)
+    {
+        if(DEBUG) DoDebug("PRCGetLastSpellCastClass: found override caster class = "+IntToString(nClass)+", original class = "+IntToString(GetLastSpellCastClass()));
+        return nClass;
+    }
+    nClass = GetLastSpellCastClass();
+    //if casting class is invalid and the spell was not cast form an item it was probably cast from the new spellbook
+    int NSB_Class = GetLocalInt(oCaster, "NSB_Class");
+    if(nClass == CLASS_TYPE_INVALID && GetSpellCastItem() == OBJECT_INVALID && NSB_Class)
+        nClass = NSB_Class;
+        
+    if(DEBUG) DoDebug("PRCGetLastSpellCastClass: returning caster class = "+IntToString(nClass)+" NSB_Class = "+IntToString(NSB_Class));    
+    return nClass;
+}
+
+int GetIsArcaneClass(int nClass, object oCaster = OBJECT_SELF)
+{
+    return nClass == CLASS_TYPE_ASSASSIN
+         || nClass == CLASS_TYPE_BARD
+         || nClass == CLASS_TYPE_BEGUILER
+         || nClass == CLASS_TYPE_CELEBRANT_SHARESS
+         || nClass == CLASS_TYPE_CULTIST_SHATTERED_PEAK
+         || nClass == CLASS_TYPE_DREAD_NECROMANCER
+         || nClass == CLASS_TYPE_DUSKBLADE
+         || nClass == CLASS_TYPE_HARPER
+         || nClass == CLASS_TYPE_HEXBLADE
+         || nClass == CLASS_TYPE_KNIGHT_WEAVE
+         || nClass == CLASS_TYPE_SHADOWLORD
+         || nClass == CLASS_TYPE_SORCERER
+         || nClass == CLASS_TYPE_SUBLIME_CHORD
+         || nClass == CLASS_TYPE_SUEL_ARCHANAMACH
+         || nClass == CLASS_TYPE_WARMAGE
+         || nClass == CLASS_TYPE_WIZARD
+		 || (nClass == CLASS_TYPE_SHAPECHANGER
+				&& GetRacialType(oCaster) == RACIAL_TYPE_ARANEA
+                && !GetLevelByClass(CLASS_TYPE_SORCERER))
+         || (nClass == CLASS_TYPE_OUTSIDER
+                && GetRacialType(oCaster) == RACIAL_TYPE_RAKSHASA
+                && !GetLevelByClass(CLASS_TYPE_SORCERER))
+         || (nClass == CLASS_TYPE_ABERRATION
+                && GetRacialType(oCaster) == RACIAL_TYPE_DRIDER
+                && !GetLevelByClass(CLASS_TYPE_SORCERER))
+         || (nClass == CLASS_TYPE_MONSTROUS
+                && GetRacialType(oCaster) == RACIAL_TYPE_ARKAMOI
+                && !GetLevelByClass(CLASS_TYPE_SORCERER))
+         || (nClass == CLASS_TYPE_MONSTROUS
+                && GetRacialType(oCaster) == RACIAL_TYPE_REDSPAWN_ARCANISS
+                && !GetLevelByClass(CLASS_TYPE_SORCERER))
+         || (nClass == CLASS_TYPE_MONSTROUS
+                && GetRacialType(oCaster) == RACIAL_TYPE_MARRUTACT
+                && !GetLevelByClass(CLASS_TYPE_SORCERER))                
+         || (nClass == CLASS_TYPE_FEY
+                && GetRacialType(oCaster) == RACIAL_TYPE_GLOURA
+                && !GetLevelByClass(CLASS_TYPE_BARD));
+}
+
+int GetIsDivineClass(int nClass, object oCaster = OBJECT_SELF)
+{
+    return nClass == CLASS_TYPE_ARCHIVIST
+         || nClass == CLASS_TYPE_BLACKGUARD
+         || nClass == CLASS_TYPE_BLIGHTER
+         || nClass == CLASS_TYPE_CLERIC
+         || nClass == CLASS_TYPE_DRUID
+         || nClass == CLASS_TYPE_FAVOURED_SOUL
+         || nClass == CLASS_TYPE_HEALER
+         || nClass == CLASS_TYPE_JUSTICEWW
+         || nClass == CLASS_TYPE_KNIGHT_CHALICE
+         || nClass == CLASS_TYPE_KNIGHT_MIDDLECIRCLE
+         || nClass == CLASS_TYPE_NENTYAR_HUNTER
+         || nClass == CLASS_TYPE_OCULAR
+         || nClass == CLASS_TYPE_PALADIN
+         || nClass == CLASS_TYPE_RANGER
+         || nClass == CLASS_TYPE_SHAMAN
+         || nClass == CLASS_TYPE_SLAYER_OF_DOMIEL
+         || nClass == CLASS_TYPE_SOHEI
+         || nClass == CLASS_TYPE_SOLDIER_OF_LIGHT
+         || nClass == CLASS_TYPE_UR_PRIEST
+         || nClass == CLASS_TYPE_VASSAL
+         || nClass == CLASS_TYPE_VIGILANT;
+}
+
+int GetArcanePRCLevels(object oCaster, int nCastingClass = CLASS_TYPE_INVALID)
+{
+	int nArcane;
+	int nOozeMLevel  	= GetLevelByClass(CLASS_TYPE_OOZEMASTER, oCaster);
+	int nUM          	= GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCaster);
+	
+	int nFirstClass  	= GetClassByPosition(1, oCaster);
+	int nSecondClass 	= GetClassByPosition(2, oCaster);
+	int nThirdClass  	= GetClassByPosition(3, oCaster);
+	int nFourthClass  	= GetClassByPosition(4, oCaster);  
+	int nFifthClass  	= GetClassByPosition(5, oCaster);
+	int nSixthClass  	= GetClassByPosition(6, oCaster);
+	int nSeventhClass  	= GetClassByPosition(7, oCaster);
+	int nEightClass  	= GetClassByPosition(8, oCaster);
+   
+   if (GetFirstArcaneClassPosition(oCaster)) nArcane += GetLevelByClass(CLASS_TYPE_SOULCASTER, oCaster);
+
+   nArcane += GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ALIENIST,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ANIMA_MAGE,      oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ARCANE_HIEROPHANT, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ARCHMAGE,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ARCTRICK,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_CEREBREMANCER,   oCaster)
+           +  GetLevelByClass(CLASS_TYPE_DIABOLIST,       oCaster)
+           +  GetLevelByClass(CLASS_TYPE_DRAGONHEART_MAGE, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ELDRITCH_KNIGHT, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ELDRITCH_THEURGE, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ELEMENTAL_SAVANT,oCaster)
+           +  GetLevelByClass(CLASS_TYPE_FMM,             oCaster)
+           +  GetLevelByClass(CLASS_TYPE_FROST_MAGE,      oCaster)
+           +  GetLevelByClass(CLASS_TYPE_HARPERMAGE,      oCaster)
+           +  GetLevelByClass(CLASS_TYPE_JADE_PHOENIX_MAGE, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_MAGEKILLER,      oCaster)
+           +  GetLevelByClass(CLASS_TYPE_MASTER_ALCHEMIST, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_MASTER_HARPER,   oCaster)
+           +  GetLevelByClass(CLASS_TYPE_MYSTIC_THEURGE,  oCaster)
+           +  GetLevelByClass(CLASS_TYPE_NOCTUMANCER,     oCaster)
+           +  GetLevelByClass(CLASS_TYPE_SPELLDANCER,     oCaster)
+           +  GetLevelByClass(CLASS_TYPE_TRUENECRO,       oCaster)
+           +  GetLevelByClass(CLASS_TYPE_RED_WIZARD,      oCaster)
+           +  GetLevelByClass(CLASS_TYPE_SHADOW_ADEPT,    oCaster)
+           +  GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD,   oCaster)
+           +  GetLevelByClass(CLASS_TYPE_UNSEEN_SEER,     oCaster)
+           +  GetLevelByClass(CLASS_TYPE_VIRTUOSO,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_WAR_WIZARD_OF_CORMYR, oCaster)
+           
+           +  (GetLevelByClass(CLASS_TYPE_BLADESINGER,        oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_BONDED_SUMMONNER,   oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_PALEMASTER,         oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_HATHRAN,            oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_HAVOC_MAGE,         oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_SPELLSWORD,         oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_THRALL_OF_GRAZZT_A, oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT,    oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_RAGE_MAGE,          oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_WAYFARER_GUIDE,     oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_JUDICATOR, 		  oCaster) + 1) / 3;
+           
+           int nClass = GetLevelByClass(CLASS_TYPE_WILD_MAGE, oCaster); 
+           if (nClass)
+            nArcane += nClass - 3 + d6();
+
+    //The following changes are to prevent a mage/invoker from gaining bonus caster levels in both base classes.
+
+    if(GetLocalInt(oCaster, "INV_Caster") == 1 ||
+            (!GetLevelByClass(CLASS_TYPE_WARLOCK, oCaster) && !GetLevelByClass(CLASS_TYPE_DRAGONFIRE_ADEPT, oCaster)))
+        nArcane += (GetLevelByClass(CLASS_TYPE_ACOLYTE,              oCaster) + 1) / 2
+                +  (GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oCaster) + 1) / 2
+                +  (GetLevelByClass(CLASS_TYPE_TALON_OF_TIAMAT,      oCaster) + 1) / 2
+                +   GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST,      oCaster)
+                +   GetLevelByClass(CLASS_TYPE_MAESTER,              oCaster);
+
+
+    /* oozemaster levels count towards arcane caster level if:
+     *
+     * first class slot is arcane OR
+     * first class slot is NOT divine AND second class slot is arcane OR
+     * first AND second class slot is NOT divine AND 3rd class slot is arcane
+     */
+   if (nOozeMLevel) //:: [PRC .35]  This needs marker feats.
+   {
+       if (GetIsArcaneClass(nFirstClass, oCaster)
+           || (!GetIsDivineClass(nFirstClass, oCaster)
+                && GetIsArcaneClass(nSecondClass, oCaster))
+           || (!GetIsDivineClass(nFirstClass, oCaster)
+                && !GetIsDivineClass(nSecondClass, oCaster)
+                && GetIsArcaneClass(nThirdClass, oCaster)))
+           nArcane += nOozeMLevel / 2;
+   }
+	
+	if (nUM)
+	{
+		int nBoost = nUM - 1; //Prep caster always loses a level on first level of the class
+		if (nUM >= 4) nBoost = nUM - 2;
+		if (nUM >= 7) nBoost = nUM - 3;
+		nArcane += nBoost;
+		
+		if (nCastingClass == CLASS_TYPE_SORCERER)
+		{
+			int nBoost = 1; //Sorcerer gets the lost levels back
+			if (nUM >= 4) nBoost = 2;
+			if (nUM >= 7) nBoost = 3;
+			nArcane += nBoost; 		
+		}
+	}
+    if(GetLevelByClass(CLASS_TYPE_SORCERER, oCaster))
+    {    
+        int nRace = GetRacialType(oCaster);
+
+        //includes RHD HD as sorc
+        //if they have sorcerer levels, then it counts as a prestige class
+        //otherwise its used instead of sorc levels
+		if(nRace == RACIAL_TYPE_ARANEA)
+            nArcane += GetLevelByClass(CLASS_TYPE_SHAPECHANGER);
+        if(nRace == RACIAL_TYPE_RAKSHASA)
+            nArcane += GetLevelByClass(CLASS_TYPE_OUTSIDER);
+        if(nRace == RACIAL_TYPE_DRIDER)
+            nArcane += GetLevelByClass(CLASS_TYPE_ABERRATION);
+        if(nRace == RACIAL_TYPE_ARKAMOI)
+            nArcane += GetLevelByClass(CLASS_TYPE_MONSTROUS);
+        if(nRace == RACIAL_TYPE_REDSPAWN_ARCANISS)
+            nArcane += GetLevelByClass(CLASS_TYPE_MONSTROUS)*3/4;            
+        if(nRace == RACIAL_TYPE_MARRUTACT)
+            nArcane += (GetLevelByClass(CLASS_TYPE_MONSTROUS)*6/7)-1;             
+    }
+    
+    if(GetLevelByClass(CLASS_TYPE_BARD, oCaster))
+    {
+        int nRace = GetRacialType(oCaster);
+
+        //includes RHD HD as bard
+        //if they have bard levels, then it counts as a prestige class
+        //otherwise its used instead of bard levels
+        if(nRace == RACIAL_TYPE_GLOURA)
+            nArcane += GetLevelByClass(CLASS_TYPE_FEY);         
+    }    
+
+    return nArcane;
+}
+
+int GetDivinePRCLevels(object oCaster)
+{
+   int nDivine;
+   int nOozeMLevel = GetLevelByClass(CLASS_TYPE_OOZEMASTER, oCaster);
+
+	int nFirstClass  	= GetClassByPosition(1, oCaster);
+	int nSecondClass 	= GetClassByPosition(2, oCaster);
+	int nThirdClass  	= GetClassByPosition(3, oCaster);
+	int nFourthClass  	= GetClassByPosition(4, oCaster);  
+	int nFifthClass  	= GetClassByPosition(5, oCaster);
+	int nSixthClass  	= GetClassByPosition(6, oCaster);
+	int nSeventhClass  	= GetClassByPosition(7, oCaster);
+	int nEightClass  	= GetClassByPosition(8, oCaster);
+
+   // This section accounts for full progression classes
+   nDivine += GetLevelByClass(CLASS_TYPE_ARCANE_HIEROPHANT, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_BLIGHTLORD,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_COMBAT_MEDIC,      oCaster)
+           +  GetLevelByClass(CLASS_TYPE_CONTEMPLATIVE,     oCaster)
+           +  GetLevelByClass(CLASS_TYPE_ELDRITCH_DISCIPLE, oCaster)
+		   +  GetLevelByClass(CLASS_TYPE_FORESTMASTER,    	oCaster)
+           +  GetLevelByClass(CLASS_TYPE_FISTRAZIEL,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_HEARTWARDER,       oCaster)
+           +  GetLevelByClass(CLASS_TYPE_HIEROPHANT,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_HOSPITALER,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_MORNINGLORD,       oCaster)
+           +  GetLevelByClass(CLASS_TYPE_MYSTIC_THEURGE,    oCaster)
+           +  GetLevelByClass(CLASS_TYPE_PSYCHIC_THEURGE,   oCaster)
+           +  GetLevelByClass(CLASS_TYPE_RUBY_VINDICATOR,   oCaster)
+           +  GetLevelByClass(CLASS_TYPE_RUNECASTER,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_SACREDPURIFIER,    oCaster)
+           +  GetLevelByClass(CLASS_TYPE_SAPPHIRE_HIERARCH, oCaster)
+           +  GetLevelByClass(CLASS_TYPE_SHADOWBANE_STALKER,oCaster)
+           +  GetLevelByClass(CLASS_TYPE_STORMLORD,         oCaster)
+           +  GetLevelByClass(CLASS_TYPE_SWIFT_WING,        oCaster)
+           +  GetLevelByClass(CLASS_TYPE_TENEBROUS_APOSTATE, oCaster)
+
+           +  (GetLevelByClass(CLASS_TYPE_BFZ,                   oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_BRIMSTONE_SPEAKER,     oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_HATHRAN,               oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_MIGHTY_CONTENDER_KORD, oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_OLLAM,                 oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_ORCUS,                 oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_SHINING_BLADE,         oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_TEMPUS,                oCaster) + 1) / 2
+           +  (GetLevelByClass(CLASS_TYPE_WARPRIEST,             oCaster) + 1) / 2
+
+           +  (GetLevelByClass(CLASS_TYPE_JUDICATOR, oCaster) + 1) / 3;
+
+   if (!GetHasFeat(FEAT_SF_CODE, oCaster))
+   {
+       nDivine   += GetLevelByClass(CLASS_TYPE_SACREDFIST, oCaster);
+   }
+
+   if (nOozeMLevel)  //:: [PRC .35]  This needs marker feats.
+   {
+       if (GetIsDivineClass(nFirstClass, oCaster)
+           || (!GetIsArcaneClass(nFirstClass, oCaster)
+                && GetIsDivineClass(nSecondClass, oCaster))
+           || (!GetIsArcaneClass(nFirstClass, oCaster)
+                && !GetIsArcaneClass(nSecondClass, oCaster)
+                && GetIsDivineClass(nThirdClass, oCaster)))
+           nDivine += nOozeMLevel / 2;
+   }
+
+   return nDivine;
+}
+
+int GetFirstArcaneClassPosition(object oCaster = OBJECT_SELF)
+{
+    int i;
+    for(i = 1; i < 9; i++)
+    {
+        if(GetIsArcaneClass(GetClassByPosition(i, oCaster), oCaster))
+            return i;
+    }
+
+    return 0;
+}
+
+int GetFirstDivineClassPosition(object oCaster = OBJECT_SELF)
+{
+    int i;
+    for(i = 1; i < 9; i++)
+    {
+        if(GetIsDivineClass(GetClassByPosition(i, oCaster), oCaster))
+            return i;
+    }
+
+    return 0;
+}
+
+int GetPrimaryArcaneClass(object oCaster = OBJECT_SELF)
+{
+    int nClass;
+
+    if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE))
+    {
+        int iArcanePos = GetFirstArcaneClassPosition(oCaster);
+        if (!iArcanePos) return CLASS_TYPE_INVALID; // no arcane casting class
+
+        nClass = GetClassByPosition(iArcanePos, oCaster);
+    }
+    else
+    {
+        int i, nClassTmp, nClassLvl;
+        for(i = 1; i < 9; i++)
+        {
+            nClassTmp = GetClassByPosition(i, oCaster);
+            if(GetIsArcaneClass(nClassTmp, oCaster) && nClassTmp != CLASS_TYPE_SUBLIME_CHORD)
+            {
+                if(GetLevelByClass(nClassTmp, oCaster) > nClassLvl)
+                {
+                    nClass = nClassTmp;
+                    nClassLvl = GetLevelByClass(nClass, oCaster);
+                }
+            }
+        }
+        if(!nClassLvl)
+            return CLASS_TYPE_INVALID;
+    }
+
+    //raks, Arkamoi, driders and dragons cast as sorcs
+    if(nClass == CLASS_TYPE_OUTSIDER
+	|| nClass == CLASS_TYPE_SHAPECHANGER
+    || nClass == CLASS_TYPE_ABERRATION
+    || nClass == CLASS_TYPE_DRAGON
+    || nClass == CLASS_TYPE_MONSTROUS)
+        nClass = CLASS_TYPE_SORCERER;
+        
+    if(nClass == CLASS_TYPE_FEY)
+        nClass = CLASS_TYPE_BARD;        
+
+    return nClass;
+}
+
+int GetPrimaryDivineClass(object oCaster = OBJECT_SELF)
+{
+    int nClass;
+
+    if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE))
+    {
+        int iDivinePos = GetFirstDivineClassPosition(oCaster);
+        if (!iDivinePos) return CLASS_TYPE_INVALID; // no Divine casting class
+
+        nClass = GetClassByPosition(iDivinePos, oCaster);
+    }
+    else
+    {
+        int i, nClassTmp, nClassLvl;
+        for(i = 1; i < 9; i++)
+        {
+            nClassTmp = GetClassByPosition(i, oCaster);
+            if(GetIsDivineClass(nClassTmp, oCaster))
+            {
+                if(GetLevelByClass(nClassTmp, oCaster) > nClassLvl)
+                {
+                    nClass = nClassTmp;
+                    nClassLvl = GetLevelByClass(nClass, oCaster);
+                }
+            }
+        }
+        if(!nClassLvl)
+            return CLASS_TYPE_INVALID;
+    }
+
+    return nClass;
+}
+
+int GetPrimarySpellcastingClass(object oCaster = OBJECT_SELF)
+{
+    int bFirst = GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE);
+    int nClass;
+
+    int i, nClassTmp, nClassLvl;
+    for(i = 1; i < 9; i++)
+    {
+        nClassTmp = GetClassByPosition(i, oCaster);
+        if(GetIsArcaneClass(nClassTmp, oCaster)
+        || GetIsDivineClass(nClassTmp, oCaster)
+        && nClassTmp != CLASS_TYPE_SUBLIME_CHORD)
+        {
+            if(bFirst)
+            {
+                return nClass;
+            }
+            else if(GetLevelByClass(nClassTmp, oCaster) > nClassLvl)
+            {
+                nClass = nClassTmp;
+                nClassLvl = GetLevelByClass(nClass, oCaster);
+            }
+        }
+    }
+    if(!nClassLvl)
+        return CLASS_TYPE_INVALID;
+
+    return nClass;
+}
+
+int PracticedSpellcasting(object oCaster, int iCastingClass, int iCastingLevels)
+{
+    int nFeat;
+    int iAdjustment = GetHitDice(oCaster) - iCastingLevels;
+    if (iAdjustment > 4) iAdjustment = 4;
+    if (iAdjustment < 0) iAdjustment = 0;
+
+    switch(iCastingClass)
+    {
+        case CLASS_TYPE_BARD:                		nFeat = FEAT_PRACTICED_SPELLCASTER_BARD;                break;
+        case CLASS_TYPE_SORCERER:            		nFeat = FEAT_PRACTICED_SPELLCASTER_SORCERER;            break;
+        case CLASS_TYPE_WIZARD:              		nFeat = FEAT_PRACTICED_SPELLCASTER_WIZARD;              break;
+        case CLASS_TYPE_CLERIC:              		nFeat = FEAT_PRACTICED_SPELLCASTER_CLERIC;              break;
+        case CLASS_TYPE_DRUID:               		nFeat = FEAT_PRACTICED_SPELLCASTER_DRUID;               break;
+        case CLASS_TYPE_PALADIN:             		nFeat = FEAT_PRACTICED_SPELLCASTER_PALADIN;             break;
+        case CLASS_TYPE_RANGER:              		nFeat = FEAT_PRACTICED_SPELLCASTER_RANGER;              break;
+        case CLASS_TYPE_ASSASSIN:            		nFeat = FEAT_PRACTICED_SPELLCASTER_ASSASSIN;            break;
+        case CLASS_TYPE_BLACKGUARD:          		nFeat = FEAT_PRACTICED_SPELLCASTER_BLACKGUARD;          break;
+        case CLASS_TYPE_OCULAR:              		nFeat = FEAT_PRACTICED_SPELLCASTER_OCULAR;              break;
+        case CLASS_TYPE_HEXBLADE:            		nFeat = FEAT_PRACTICED_SPELLCASTER_HEXBLADE;            break;
+        case CLASS_TYPE_DUSKBLADE:           		nFeat = FEAT_PRACTICED_SPELLCASTER_DUSKBLADE;           break;
+        case CLASS_TYPE_HEALER:              		nFeat = FEAT_PRACTICED_SPELLCASTER_HEALER;              break;
+        case CLASS_TYPE_KNIGHT_CHALICE:      		nFeat = FEAT_PRACTICED_SPELLCASTER_KNIGHT_CHALICE;      break;
+        case CLASS_TYPE_NENTYAR_HUNTER:      		nFeat = FEAT_PRACTICED_SPELLCASTER_NENTYAR;             break;
+        case CLASS_TYPE_VASSAL:              		nFeat = FEAT_PRACTICED_SPELLCASTER_VASSAL;              break;
+        case CLASS_TYPE_UR_PRIEST:           		nFeat = FEAT_PRACTICED_SPELLCASTER_UR_PRIEST;           break;
+        case CLASS_TYPE_SOLDIER_OF_LIGHT:    		nFeat = FEAT_PRACTICED_SPELLCASTER_SOLDIER_OF_LIGHT;    break;
+        case CLASS_TYPE_SHADOWLORD:          		nFeat = FEAT_PRACTICED_SPELLCASTER_SHADOWLORD;          break;
+        case CLASS_TYPE_JUSTICEWW:           		nFeat = FEAT_PRACTICED_SPELLCASTER_JUSTICEWW;           break;
+        case CLASS_TYPE_KNIGHT_MIDDLECIRCLE: 		nFeat = FEAT_PRACTICED_SPELLCASTER_KNIGHT_MIDDLECIRCLE; break;
+        case CLASS_TYPE_SHAMAN:              		nFeat = FEAT_PRACTICED_SPELLCASTER_SHAMAN;              break;
+        case CLASS_TYPE_SLAYER_OF_DOMIEL:    		nFeat = FEAT_PRACTICED_SPELLCASTER_SLAYER_OF_DOMIEL;    break;
+        case CLASS_TYPE_SUEL_ARCHANAMACH:    		nFeat = FEAT_PRACTICED_SPELLCASTER_SUEL_ARCHANAMACH;    break;
+        case CLASS_TYPE_FAVOURED_SOUL:       		nFeat = FEAT_PRACTICED_SPELLCASTER_FAVOURED_SOUL;       break;
+        case CLASS_TYPE_SOHEI:               		nFeat = FEAT_PRACTICED_SPELLCASTER_SOHEI;               break;
+        case CLASS_TYPE_CELEBRANT_SHARESS:   		nFeat = FEAT_PRACTICED_SPELLCASTER_CELEBRANT_SHARESS;   break;
+        case CLASS_TYPE_WARMAGE:             		nFeat = FEAT_PRACTICED_SPELLCASTER_WARMAGE;             break;
+        case CLASS_TYPE_DREAD_NECROMANCER:   		nFeat = FEAT_PRACTICED_SPELLCASTER_DREAD_NECROMANCER;   break;
+        case CLASS_TYPE_CULTIST_SHATTERED_PEAK: 	nFeat = FEAT_PRACTICED_SPELLCASTER_CULTIST;             break;
+        case CLASS_TYPE_ARCHIVIST:           		nFeat = FEAT_PRACTICED_SPELLCASTER_ARCHIVIST;           break;
+        case CLASS_TYPE_BEGUILER:            		nFeat = FEAT_PRACTICED_SPELLCASTER_BEGUILER;            break;
+        case CLASS_TYPE_BLIGHTER:            		nFeat = FEAT_PRACTICED_SPELLCASTER_BLIGHTER;            break;
+        case CLASS_TYPE_HARPER:              		nFeat = FEAT_PRACTICED_SPELLCASTER_HARPER;              break;
+        default: return 0;
+    }
+
+    if(GetHasFeat(nFeat, oCaster))
+        return iAdjustment;
+
+    return 0;
+}
+
+int GetSpellSchool(int iSpellId)
+{
+    string sSpellSchool = Get2DACache("spells", "School", iSpellId);//lookup_spell_school(iSpellId);
+
+    if (sSpellSchool == "A") return SPELL_SCHOOL_ABJURATION;
+    else if (sSpellSchool == "C") return SPELL_SCHOOL_CONJURATION;
+    else if (sSpellSchool == "D") return SPELL_SCHOOL_DIVINATION;
+    else if (sSpellSchool == "E") return SPELL_SCHOOL_ENCHANTMENT;
+    else if (sSpellSchool == "V") return SPELL_SCHOOL_EVOCATION;
+    else if (sSpellSchool == "I") return SPELL_SCHOOL_ILLUSION;
+    else if (sSpellSchool == "N") return SPELL_SCHOOL_NECROMANCY;
+    else if (sSpellSchool == "T") return SPELL_SCHOOL_TRANSMUTATION;
+    else return SPELL_SCHOOL_GENERAL;
+
+    return -1;
+}
+
+/*int GetIsHealingSpell(int nSpellId)
+{
+    if (  nSpellId == SPELL_CURE_CRITICAL_WOUNDS
+       || nSpellId == SPELL_CURE_LIGHT_WOUNDS
+       || nSpellId == SPELL_CURE_MINOR_WOUNDS
+       || nSpellId == SPELL_CURE_MODERATE_WOUNDS
+       || nSpellId == SPELL_CURE_SERIOUS_WOUNDS
+       || nSpellId == SPELL_GREATER_RESTORATION
+       || nSpellId == SPELL_HEAL
+       || nSpellId == SPELL_HEALING_CIRCLE
+       || nSpellId == SPELL_MASS_HEAL
+       || nSpellId == SPELL_MONSTROUS_REGENERATION
+       || nSpellId == SPELL_REGENERATE
+       //End of stock NWN spells
+       || nSpellId == SPELL_MASS_CURE_LIGHT
+       || nSpellId == SPELL_MASS_CURE_MODERATE
+       || nSpellId == SPELL_MASS_CURE_SERIOUS
+       || nSpellId == SPELL_MASS_CURE_CRITICAL
+       || nSpellId == SPELL_PANACEA
+       )
+        return TRUE;
+
+    return FALSE;
+}*/
+
+int ArchmageSpellPower(object oCaster)
+{
+    if(GetHasFeat(FEAT_SPELL_POWER_V,   oCaster))
+        return 5;
+    if(GetHasFeat(FEAT_SPELL_POWER_IV,  oCaster))
+        return 4;
+    if(GetHasFeat(FEAT_SPELL_POWER_III, oCaster))
+        return 3;
+    if(GetHasFeat(FEAT_SPELL_POWER_II,  oCaster))
+        return 2;
+    if(GetHasFeat(FEAT_SPELL_POWER_I,   oCaster))
+        return 1;
+
+    return 0;
+}
+
+int ShadowWeave(object oCaster, int iSpellID, int nSpellSchool = -1)
+{
+   if(!GetHasFeat(FEAT_SHADOWWEAVE,oCaster))
+       return 0;
+
+   if (nSpellSchool == -1)
+       nSpellSchool = GetSpellSchool(iSpellID);
+
+   // Bonus for spells of Enhancement, Necromancy and Illusion schools and spells with Darkness descriptor
+   if(nSpellSchool == SPELL_SCHOOL_ENCHANTMENT
+   || nSpellSchool == SPELL_SCHOOL_NECROMANCY
+   || nSpellSchool == SPELL_SCHOOL_ILLUSION
+   || GetHasDescriptor(iSpellID, DESCRIPTOR_DARKNESS))
+   {
+       return 1;
+   }
+   // Penalty to spells of Evocation and Transmutation schools, except for those with Darkness descriptor
+   else if(nSpellSchool == SPELL_SCHOOL_EVOCATION
+   || nSpellSchool == SPELL_SCHOOL_TRANSMUTATION)
+   {
+       return -1;
+   }
+
+   return 0;
+}
+
+int AirAdept(object oCaster, int iSpellID)
+{
+    if(!GetHasDescriptor(iSpellID, DESCRIPTOR_AIR))
+        return 0;
+
+    int nBoost = 0;
+
+    if(GetHasFeat(FEAT_AIR_MEPHLING, oCaster))
+        nBoost += 1;
+
+    return nBoost;
+}
+
+int WaterAdept(object oCaster, int iSpellID)
+{
+    if(!GetHasDescriptor(iSpellID, DESCRIPTOR_WATER))
+        return 0;
+
+    int nBoost = 0;
+
+    if(GetHasFeat(FEAT_WATER_MEPHLING, oCaster))
+        nBoost += 1;
+
+    return nBoost;
+}
+
+int FireAdept(object oCaster, int iSpellID)
+{
+    if(!GetHasDescriptor(iSpellID, DESCRIPTOR_FIRE))
+        return 0;
+
+    int nBoost = 0;
+
+    if(GetHasFeat(FEAT_FIRE_ADEPT, oCaster))
+        nBoost += 1;
+		
+    if(GetHasFeat(FEAT_FIRE_MEPHLING, oCaster))
+        nBoost += 1;		
+
+    if(GetHasFeat(FEAT_BLOODLINE_OF_FIRE, oCaster))
+        nBoost += 2;
+        
+    if(GetRacialType(oCaster) == RACIAL_TYPE_REDSPAWN_ARCANISS)
+    	nBoost += 2;
+
+    return nBoost;
+}
+
+int DriftMagic(object oCaster, int iSpellID)
+{
+    if(!GetHasDescriptor(iSpellID, DESCRIPTOR_EARTH))
+        return 0;
+
+    int nBoost = 0;
+
+    if(GetHasFeat(FEAT_DRIFT_MAGIC, oCaster))
+        nBoost += 1;
+		
+    if(GetHasFeat(FEAT_EARTH_MEPHLING, oCaster))
+        nBoost += 1;		
+
+    return nBoost;
+}
+/*int DriftMagic(object oCaster, int iSpellID)
+{
+    if(GetHasDescriptor(iSpellID, DESCRIPTOR_EARTH) && GetHasFeat(FEAT_DRIFT_MAGIC, oCaster))
+        return 1;
+		
+    else if(GetHasDescriptor(iSpellID, DESCRIPTOR_EARTH) && GetHasFeat(FEAT_EARTH_MEPHLING, oCaster))
+        return 1;
+		
+    return 0;
+}*/
+
+int Soulcaster(object oCaster, int iSpellID)
+{
+    if(GetLocalInt(oCaster, "SpellEssentia"+IntToString(iSpellID)))
+    {
+    	int nReturn = GetLocalInt(oCaster, "SpellEssentia"+IntToString(iSpellID));
+    	DelayCommand(1.0, DeleteLocalInt(oCaster, "SpellEssentia"+IntToString(iSpellID)));
+        return nReturn;
+    }    
+
+    return 0;
+}
+
+int StormMagic(object oCaster)
+{
+    if(!GetHasFeat(FEAT_STORMMAGIC, oCaster) && !GetHasFeat(FEAT_FROZEN_MAGIC, oCaster)) return 0;
+    
+    int nBoost = 0;
+
+    int nWeather = GetWeather(GetArea(oCaster));
+    if(nWeather == WEATHER_RAIN && GetHasFeat(FEAT_STORMMAGIC, oCaster))
+        nBoost += 1;
+    if(nWeather == WEATHER_SNOW && GetHasFeat(FEAT_STORMMAGIC, oCaster))
+        nBoost += 1;        
+    if(nWeather == WEATHER_SNOW && GetHasFeat(FEAT_FROZEN_MAGIC, oCaster))
+        nBoost += 2;                
+    if (GetLocalInt(GetArea(oCaster),"FrozenMagic") && GetHasFeat(FEAT_FROZEN_MAGIC, oCaster) && nWeather != WEATHER_SNOW)
+        nBoost += 2;
+    
+    return nBoost;
+}
+
+int DivinationPower(object oCaster, int nSpellSchool)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_UNSEEN_SEER, oCaster);
+    if(!nClass) return 0;
+    
+    int nBoost = (nClass + 2) / 3;   
+        
+    if (nSpellSchool != SPELL_SCHOOL_DIVINATION)
+        nBoost *= -1; // Negative if it's not a divination spell
+    
+    return nBoost;
+}
+
+int CormanthyranMoonMagic(object oCaster)
+{
+    if (!GetHasFeat(FEAT_CORMANTHYRAN_MOON_MAGIC, oCaster)) return 0;
+
+    object oArea = GetArea(oCaster);
+
+    // The moon must be visible. Thus, outdoors, at night, with no rain.
+    if (GetWeather(oArea) != WEATHER_RAIN && GetWeather(oArea) != WEATHER_SNOW &&
+        GetIsNight() && !GetIsAreaInterior(oArea))
+    {
+        return 2;
+    }
+    return 0;
+}
+
+int Nentyar(object oCaster, int nCastingClass)
+{
+    if (nCastingClass == CLASS_TYPE_NENTYAR_HUNTER)
+    {
+        int nBonus = GetLevelByClass(CLASS_TYPE_DRUID, oCaster) + GetLevelByClass(CLASS_TYPE_CLERIC, oCaster) + GetLevelByClass(CLASS_TYPE_RANGER, oCaster)/2;
+        return nBonus;
+    }
+    return 0;
+}
+
+int ShieldDwarfWarder(object oCaster)
+{
+	if (!GetHasFeat(FEAT_SHIELD_DWARF_WARDER, oCaster)) return 0;
+	
+	object oTarget = PRCGetSpellTargetObject();
+	// If it's an item that grants an AC bonus
+    int nBase = GetBaseItemType(oTarget);
+    if (nBase == BASE_ITEM_SMALLSHIELD || nBase == BASE_ITEM_LARGESHIELD || nBase == BASE_ITEM_TOWERSHIELD || nBase == BASE_ITEM_ARMOR)	
+        return 1;
+
+    return 0;
+}
+
+int DarkSpeech(object oCaster)
+{
+	if (GetHasSpellEffect(SPELL_DARK_SPEECH_POWER, oCaster)) 
+	{
+		ExecuteScript("prc_dark_power", oCaster);		
+        return 1;
+	}
+    return 0;
+}
+
+int DomainPower(object oCaster, int nSpellID, int nSpellSchool = -1)
+{
+    int nBonus = 0;
+    if (nSpellSchool == -1)
+       nSpellSchool = GetSpellSchool(nSpellID);
+
+    // Boosts Caster level with the Illusion school by 1
+    if (nSpellSchool == SPELL_SCHOOL_ILLUSION && GetHasFeat(FEAT_DOMAIN_POWER_GNOME, oCaster))
+        nBonus += 1;
+
+    // Boosts Caster level with the Illusion school by 1
+    if (nSpellSchool == SPELL_SCHOOL_ILLUSION && GetHasFeat(FEAT_DOMAIN_POWER_ILLUSION, oCaster))
+        nBonus += 1;
+
+    // Boosts Caster level with healing spells
+    if (GetIsOfSubschool(nSpellID, SUBSCHOOL_HEALING) && GetHasFeat(FEAT_HEALING_DOMAIN_POWER, oCaster))
+        nBonus += 1;
+
+    // Boosts Caster level with the Divination school by 1
+    if (nSpellSchool == SPELL_SCHOOL_DIVINATION && GetHasFeat(FEAT_KNOWLEDGE_DOMAIN_POWER, oCaster))
+        nBonus += 1;
+
+    // Boosts Caster level with evil spells by 1
+    if (GetHasDescriptor(nSpellID, DESCRIPTOR_EVIL) && GetHasFeat(FEAT_EVIL_DOMAIN_POWER, oCaster))
+        nBonus += 1;
+
+    // Boosts Caster level with good spells by 1
+    if (GetHasDescriptor(nSpellID, DESCRIPTOR_GOOD) && GetHasFeat(FEAT_GOOD_DOMAIN_POWER, oCaster))
+        nBonus += 1;
+
+    return nBonus;
+}
+
+int TherapeuticMantle(object oCaster, int nSpellID)
+{
+	int nReturn;
+    // Boosts Caster level with healing spells
+    if (GetIsMeldBound(oCaster, MELD_THERAPEUTIC_MANTLE) == CHAKRA_SHOULDERS && GetIsOfSubschool(nSpellID, SUBSCHOOL_HEALING))
+		nReturn = GetEssentiaInvested(oCaster, MELD_THERAPEUTIC_MANTLE);
+	
+	return nReturn;
+}
+
+int DeathKnell(object oCaster)
+{
+    // If you do have the spell effect, return a +1 bonus to caster level
+    return GetHasSpellEffect(SPELL_DEATH_KNELL, oCaster);
+}
+
+int DraconicPower(object oCaster = OBJECT_SELF)
+{
+    return GetHasFeat(FEAT_DRACONIC_POWER, oCaster);
+}
+
+int SongOfArcanePower(object oCaster = OBJECT_SELF)
+{
+    int nBonus = GetLocalInt(oCaster, "SongOfArcanePower");
+    DeleteLocalInt(oCaster, "SongOfArcanePower");
+    
+    int nLevel = GetLevelByClass(CLASS_TYPE_ULTIMATE_MAGUS, oCaster);
+    nBonus += (nLevel + 2)/3;
+    
+    if(nBonus)
+        return nBonus;
+
+    return 0;
+}
+
+int TrueNecromancy(object oCaster, int iSpellID, string sType, int nSpellSchool = -1)
+{
+    int iTNLevel = GetLevelByClass(CLASS_TYPE_TRUENECRO, oCaster);
+    if (!iTNLevel)
+        return 0;
+    if (nSpellSchool == -1)
+        nSpellSchool = GetSpellSchool(iSpellID);
+    if (nSpellSchool != SPELL_SCHOOL_NECROMANCY)
+        return 0;
+
+    if (sType == "ARCANE")
+        return GetLevelByTypeDivine(oCaster); // TN and arcane levels already added.
+
+    if (sType == "DIVINE")
+        return GetLevelByTypeArcane(oCaster);
+
+    return 0;
+}
+
+int UrPriestCL(object oCaster, int nCastingClass)
+{
+	// Add 1/2 levels in all other casting classes except cleric
+    if (nCastingClass == CLASS_TYPE_UR_PRIEST)
+    {
+    	int nTotal = 0;
+	    int iFirstDivine = GetPrimaryDivineClass(oCaster);
+	    int iBest = 0;
+	    int iClass1 = GetClassByPosition(1, oCaster);
+	    int iClass2 = GetClassByPosition(2, oCaster);
+	    int iClass3 = GetClassByPosition(3, oCaster);
+	    int iClass4 = GetClassByPosition(4, oCaster);
+	    int iClass5 = GetClassByPosition(5, oCaster);
+	    int iClass6 = GetClassByPosition(6, oCaster);		
+	    int iClass7 = GetClassByPosition(7, oCaster);	
+	    int iClass8 = GetClassByPosition(8, oCaster);		
+		
+	    int iClass1Lev = GetLevelByPosition(1, oCaster);
+	    int iClass2Lev = GetLevelByPosition(2, oCaster);
+	    int iClass3Lev = GetLevelByPosition(3, oCaster);
+	    int iClass4Lev = GetLevelByPosition(4, oCaster);
+	    int iClass5Lev = GetLevelByPosition(5, oCaster);
+	    int iClass6Lev = GetLevelByPosition(6, oCaster);
+	    int iClass7Lev = GetLevelByPosition(7, oCaster);
+	    int iClass8Lev = GetLevelByPosition(8, oCaster);
+		
+	    /*if (iClass1 == CLASS_TYPE_PALADIN || iClass1 == CLASS_TYPE_RANGER) iClass1Lev = (iClass1Lev >= 4) ? (iClass1Lev / 2) : 0;
+	    if (iClass2 == CLASS_TYPE_PALADIN || iClass2 == CLASS_TYPE_RANGER) iClass2Lev = (iClass2Lev >= 4) ? (iClass2Lev / 2) : 0;
+	    if (iClass3 == CLASS_TYPE_PALADIN || iClass3 == CLASS_TYPE_RANGER) iClass3Lev = (iClass3Lev >= 4) ? (iClass3Lev / 2) : 0;
+
+	    if (iClass1 == iFirstDivine) iClass1Lev += GetDivinePRCLevels(oCaster);
+	    if (iClass2 == iFirstDivine) iClass2Lev += GetDivinePRCLevels(oCaster);
+	    if (iClass3 == iFirstDivine) iClass3Lev += GetDivinePRCLevels(oCaster);
+
+	    iClass1Lev += PracticedSpellcasting(oCaster, iClass1, iClass1Lev);
+	    iClass2Lev += PracticedSpellcasting(oCaster, iClass2, iClass2Lev);
+	    iClass3Lev += PracticedSpellcasting(oCaster, iClass3, iClass3Lev);
+
+	    if (!GetIsDivineClass(iClass1, oCaster) || iClass1 == CLASS_TYPE_UR_PRIEST) iClass1Lev = 0;
+	    if (!GetIsDivineClass(iClass2, oCaster) || iClass2 == CLASS_TYPE_UR_PRIEST) iClass2Lev = 0;
+	    if (!GetIsDivineClass(iClass3, oCaster) || iClass3 == CLASS_TYPE_UR_PRIEST) iClass3Lev = 0;
+	    
+	    nTotal += iClass1Lev + iClass2Lev + iClass3Lev;
+	    if (DEBUG) DoDebug("UrPriestCL Divine - iClass1Lev "+IntToString(iClass1Lev)+" iClass2Lev "+IntToString(iClass2Lev)+" iClass3Lev "+IntToString(iClass3Lev));*/
+	    
+    	int iFirstArcane = GetPrimaryArcaneClass(oCaster);
+		iClass1 = GetClassByPosition(1, oCaster);
+		iClass2 = GetClassByPosition(2, oCaster);
+		iClass3 = GetClassByPosition(3, oCaster);
+		iClass4 = GetClassByPosition(4, oCaster);
+		iClass5 = GetClassByPosition(5, oCaster);
+		iClass6 = GetClassByPosition(6, oCaster);		
+		iClass7 = GetClassByPosition(7, oCaster);	
+		iClass8 = GetClassByPosition(8, oCaster);		
+		
+		iClass1Lev = GetLevelByPosition(1, oCaster);
+		iClass2Lev = GetLevelByPosition(2, oCaster);
+		iClass3Lev = GetLevelByPosition(3, oCaster);
+		iClass4Lev = GetLevelByPosition(4, oCaster);
+		iClass5Lev = GetLevelByPosition(5, oCaster);
+		iClass6Lev = GetLevelByPosition(6, oCaster);
+		iClass7Lev = GetLevelByPosition(7, oCaster);
+		iClass8Lev = GetLevelByPosition(8, oCaster);
+
+    	if (iClass1 == CLASS_TYPE_HEXBLADE) iClass1Lev = (iClass1Lev >= 4) ? (iClass1Lev / 2) : 0;
+    	if (iClass2 == CLASS_TYPE_HEXBLADE) iClass2Lev = (iClass2Lev >= 4) ? (iClass2Lev / 2) : 0;
+    	if (iClass3 == CLASS_TYPE_HEXBLADE) iClass3Lev = (iClass3Lev >= 4) ? (iClass3Lev / 2) : 0;
+    	if (iClass4 == CLASS_TYPE_HEXBLADE) iClass4Lev = (iClass4Lev >= 4) ? (iClass4Lev / 2) : 0;
+    	if (iClass5 == CLASS_TYPE_HEXBLADE) iClass5Lev = (iClass5Lev >= 4) ? (iClass5Lev / 2) : 0;
+    	if (iClass6 == CLASS_TYPE_HEXBLADE) iClass6Lev = (iClass6Lev >= 4) ? (iClass6Lev / 2) : 0;
+    	if (iClass7 == CLASS_TYPE_HEXBLADE) iClass7Lev = (iClass7Lev >= 4) ? (iClass7Lev / 2) : 0;
+    	if (iClass8 == CLASS_TYPE_HEXBLADE) iClass8Lev = (iClass8Lev >= 4) ? (iClass8Lev / 2) : 0;		
+		
+    	if (iClass1 == iFirstArcane) iClass1Lev += GetArcanePRCLevels(oCaster);
+    	if (iClass2 == iFirstArcane) iClass2Lev += GetArcanePRCLevels(oCaster);
+    	if (iClass3 == iFirstArcane) iClass3Lev += GetArcanePRCLevels(oCaster);
+    	if (iClass4 == iFirstArcane) iClass4Lev += GetArcanePRCLevels(oCaster);
+    	if (iClass5 == iFirstArcane) iClass5Lev += GetArcanePRCLevels(oCaster);
+    	if (iClass6 == iFirstArcane) iClass6Lev += GetArcanePRCLevels(oCaster);
+    	if (iClass7 == iFirstArcane) iClass7Lev += GetArcanePRCLevels(oCaster);
+    	if (iClass8 == iFirstArcane) iClass8Lev += GetArcanePRCLevels(oCaster);		
+		
+		iClass1Lev += PracticedSpellcasting(oCaster, iClass1, iClass1Lev);
+		iClass2Lev += PracticedSpellcasting(oCaster, iClass2, iClass2Lev);
+		iClass3Lev += PracticedSpellcasting(oCaster, iClass3, iClass3Lev);
+		iClass4Lev += PracticedSpellcasting(oCaster, iClass4, iClass4Lev);
+		iClass5Lev += PracticedSpellcasting(oCaster, iClass5, iClass5Lev);
+		iClass6Lev += PracticedSpellcasting(oCaster, iClass6, iClass5Lev);
+		iClass7Lev += PracticedSpellcasting(oCaster, iClass7, iClass6Lev);
+		iClass8Lev += PracticedSpellcasting(oCaster, iClass8, iClass7Lev);
+
+    	if (!GetIsArcaneClass(iClass1, oCaster)) iClass1Lev = 0;
+    	if (!GetIsArcaneClass(iClass2, oCaster)) iClass2Lev = 0;
+    	if (!GetIsArcaneClass(iClass3, oCaster)) iClass3Lev = 0;		
+    	if (!GetIsArcaneClass(iClass4, oCaster)) iClass4Lev = 0;
+    	if (!GetIsArcaneClass(iClass5, oCaster)) iClass5Lev = 0;
+    	if (!GetIsArcaneClass(iClass6, oCaster)) iClass6Lev = 0;
+    	if (!GetIsArcaneClass(iClass7, oCaster)) iClass7Lev = 0;
+    	if (!GetIsArcaneClass(iClass8, oCaster)) iClass8Lev = 0;
+
+    	
+    	nTotal += iClass1Lev + iClass2Lev + iClass3Lev + iClass4Lev + iClass5Lev + iClass6Lev + iClass7Lev + iClass8Lev;
+		
+    	if (DEBUG) DoDebug("UrPriestCL Arcane - iClass1Lev "+IntToString(iClass1Lev)+" iClass2Lev "
+															+IntToString(iClass2Lev)+" iClass3Lev "
+															+IntToString(iClass3Lev)+" iClass4Lev "
+															+IntToString(iClass4Lev)+" iClass5Lev "
+															+IntToString(iClass5Lev)+" iClass6Lev "
+															+IntToString(iClass6Lev)+" iClass7Lev "
+															+IntToString(iClass7Lev)+" iClass8Lev "
+															+IntToString(iClass8Lev));
+															
+    	if (DEBUG) DoDebug("UrPriestCL Total - nTotal "+IntToString(nTotal));
+    	return nTotal/2;
+    }
+    return 0;
+}
+
+int BlighterCL(object oCaster, int nCastingClass)
+{
+    if (nCastingClass == CLASS_TYPE_BLIGHTER)
+    {
+        int nBonus = GetLevelByClass(CLASS_TYPE_DRUID, oCaster);
+        return nBonus;
+    }
+    return 0;
+}
+
+int ReserveFeatCL(object oCaster, int iSpellId)
+{
+    int nSpellSchool = GetSpellSchool(iSpellId);
+    int nCLBonus = 0;
+
+    if (GetLocalInt(oCaster, "ReserveFeatsRunning") == TRUE)
+    {
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_ACID) && GetHasFeat(FEAT_ACIDIC_SPLATTER, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_FIRE) && GetHasFeat(FEAT_FIERY_BURST, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_COLD) && GetHasFeat(FEAT_WINTERS_BLAST, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_ELECTRICITY) && GetHasFeat(FEAT_STORM_BOLT, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_SONIC) && GetHasFeat(FEAT_CLAP_OF_THUNDER, oCaster)) nCLBonus += 1;
+        if (GetIsOfSubschool(iSpellId, SUBSCHOOL_HEALING) && GetHasFeat(FEAT_TOUCH_OF_HEALING, oCaster)) nCLBonus += 1;
+        if (GetIsOfSubschool(iSpellId, SUBSCHOOL_TELEPORTATION) && GetHasFeat(FEAT_DIMENSIONAL_JAUNT, oCaster)) nCLBonus += 1;
+        if (nSpellSchool == SPELL_SCHOOL_ABJURATION && GetHasFeat(FEAT_MYSTIC_BACKLASH, oCaster)) nCLBonus += 1;
+        if (nSpellSchool == SPELL_SCHOOL_NECROMANCY && GetHasFeat(FEAT_SICKENING_GRASP, oCaster)) nCLBonus += 1;
+        if (GetIsFromDomain(iSpellId, "wardom") && GetHasFeat(FEAT_HOLY_WARRIOR, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_EARTH) && GetHasFeat(FEAT_CLUTCH_OF_EARTH, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_AIR) && GetHasFeat(FEAT_BORNE_ALOFT, oCaster)) nCLBonus += 1;
+        if ((nSpellSchool == SPELL_SCHOOL_ABJURATION) && GetHasFeat(FEAT_PROTECTIVE_WARD, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_DARKNESS) && GetHasFeat(FEAT_SHADOW_VEIL, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_LIGHT) && GetHasFeat(FEAT_SUNLIGHT_EYES, oCaster)) nCLBonus += 1;
+        if ((nSpellSchool == SPELL_SCHOOL_ENCHANTMENT) && GetHasFeat(FEAT_TOUCH_OF_DISTRACTION, oCaster)) nCLBonus += 1;
+        if (GetIsFromDomain(iSpellId, "dethdom") && GetHasFeat(FEAT_CHARNEL_MIASMA, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_WATER) && GetHasFeat(FEAT_DROWNING_GLANCE, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_FORCE) && GetHasFeat(FEAT_INVISIBLE_NEEDLE, oCaster)) nCLBonus += 1;
+        if (GetIsOfSubschool(iSpellId, SUBSCHOOL_SUMMONING) && GetHasFeat(FEAT_SUMMON_ELEMENTAL, oCaster)) nCLBonus += 1;
+        if (GetIsOfSubschool(iSpellId, SUBSCHOOL_SUMMONING) && GetHasFeat(FEAT_DIMENSIONAL_REACH, oCaster)) nCLBonus += 1;
+        if (GetHasDescriptor(iSpellId, DESCRIPTOR_AIR) && GetHasFeat(FEAT_HURRICANE_BREATH, oCaster)) nCLBonus += 1;
+        if (GetIsOfSubschool(iSpellId, SUBSCHOOL_POLYMORPH) && GetHasFeat(FEAT_MINOR_SHAPESHIFT, oCaster)) nCLBonus += 1;
+        if (GetIsOfSubschool(iSpellId, SUBSCHOOL_GLAMER) && GetHasFeat(FEAT_FACECHANGER, oCaster)) nCLBonus += 1;
+        return nCLBonus;
+    }
+    else return 0;
+}
+
+int GetLevelByTypeArcane(object oCaster = OBJECT_SELF)
+{
+    int iFirstArcane = GetPrimaryArcaneClass(oCaster);
+    int iBest = 0;
+    int iClass1 = GetClassByPosition(1, oCaster);
+    int iClass2 = GetClassByPosition(2, oCaster);
+    int iClass3 = GetClassByPosition(3, oCaster);	
+	int iClass4 = GetClassByPosition(4, oCaster);
+    int iClass5 = GetClassByPosition(5, oCaster);
+    int iClass6 = GetClassByPosition(6, oCaster);
+    int iClass7 = GetClassByPosition(8, oCaster);
+    int iClass8 = GetClassByPosition(8, oCaster);	
+	
+    int iClass1Lev = GetLevelByPosition(1, oCaster);
+    int iClass2Lev = GetLevelByPosition(2, oCaster);
+    int iClass3Lev = GetLevelByPosition(3, oCaster);
+    int iClass4Lev = GetLevelByPosition(4, oCaster);
+    int iClass5Lev = GetLevelByPosition(5, oCaster);
+    int iClass6Lev = GetLevelByPosition(6, oCaster);
+    int iClass7Lev = GetLevelByPosition(7, oCaster);
+    int iClass8Lev = GetLevelByPosition(8, oCaster);
+	
+    if (iClass1 == CLASS_TYPE_HEXBLADE) iClass1Lev = (iClass1Lev >= 4) ? (iClass1Lev / 2) : 0;
+    if (iClass2 == CLASS_TYPE_HEXBLADE) iClass2Lev = (iClass2Lev >= 4) ? (iClass2Lev / 2) : 0;
+    if (iClass3 == CLASS_TYPE_HEXBLADE) iClass3Lev = (iClass3Lev >= 4) ? (iClass3Lev / 2) : 0;
+    if (iClass4 == CLASS_TYPE_HEXBLADE) iClass4Lev = (iClass4Lev >= 4) ? (iClass4Lev / 2) : 0;
+    if (iClass5 == CLASS_TYPE_HEXBLADE) iClass5Lev = (iClass5Lev >= 4) ? (iClass5Lev / 2) : 0;
+    if (iClass6 == CLASS_TYPE_HEXBLADE) iClass6Lev = (iClass6Lev >= 4) ? (iClass6Lev / 2) : 0;
+    if (iClass7 == CLASS_TYPE_HEXBLADE) iClass7Lev = (iClass7Lev >= 4) ? (iClass7Lev / 2) : 0;
+    if (iClass8 == CLASS_TYPE_HEXBLADE) iClass8Lev = (iClass8Lev >= 4) ? (iClass8Lev / 2) : 0;
+
+    if (iClass1 == iFirstArcane) iClass1Lev += GetArcanePRCLevels(oCaster);
+    if (iClass2 == iFirstArcane) iClass2Lev += GetArcanePRCLevels(oCaster);
+    if (iClass3 == iFirstArcane) iClass3Lev += GetArcanePRCLevels(oCaster);
+    if (iClass4 == iFirstArcane) iClass4Lev += GetArcanePRCLevels(oCaster);
+    if (iClass5 == iFirstArcane) iClass5Lev += GetArcanePRCLevels(oCaster);
+    if (iClass6 == iFirstArcane) iClass6Lev += GetArcanePRCLevels(oCaster);
+    if (iClass7 == iFirstArcane) iClass7Lev += GetArcanePRCLevels(oCaster);
+    if (iClass8 == iFirstArcane) iClass8Lev += GetArcanePRCLevels(oCaster);
+
+    iClass1Lev += PracticedSpellcasting(oCaster, iClass1, iClass1Lev);
+    iClass2Lev += PracticedSpellcasting(oCaster, iClass2, iClass2Lev);
+    iClass3Lev += PracticedSpellcasting(oCaster, iClass3, iClass3Lev);
+	iClass4Lev += PracticedSpellcasting(oCaster, iClass4, iClass4Lev);
+    iClass5Lev += PracticedSpellcasting(oCaster, iClass5, iClass5Lev);
+    iClass6Lev += PracticedSpellcasting(oCaster, iClass6, iClass5Lev);
+	iClass7Lev += PracticedSpellcasting(oCaster, iClass7, iClass6Lev);
+    iClass8Lev += PracticedSpellcasting(oCaster, iClass8, iClass7Lev);
+
+    if (!GetIsArcaneClass(iClass1, oCaster)) iClass1Lev = 0;
+    if (!GetIsArcaneClass(iClass2, oCaster)) iClass2Lev = 0;
+    if (!GetIsArcaneClass(iClass3, oCaster)) iClass3Lev = 0;
+    if (!GetIsArcaneClass(iClass4, oCaster)) iClass4Lev = 0;
+    if (!GetIsArcaneClass(iClass5, oCaster)) iClass5Lev = 0;
+    if (!GetIsArcaneClass(iClass6, oCaster)) iClass6Lev = 0;
+    if (!GetIsArcaneClass(iClass7, oCaster)) iClass7Lev = 0;
+    if (!GetIsArcaneClass(iClass8, oCaster)) iClass8Lev = 0;	
+	
+    if (iClass1Lev > iBest) iBest = iClass1Lev;
+    if (iClass2Lev > iBest) iBest = iClass2Lev;
+    if (iClass3Lev > iBest) iBest = iClass3Lev;
+    if (iClass4Lev > iBest) iBest = iClass4Lev;
+    if (iClass5Lev > iBest) iBest = iClass5Lev;
+    if (iClass6Lev > iBest) iBest = iClass6Lev;
+    if (iClass7Lev > iBest) iBest = iClass7Lev;
+    if (iClass8Lev > iBest) iBest = iClass8Lev;
+
+    return iBest;
+}
+
+int GetLevelByTypeDivine(object oCaster = OBJECT_SELF)
+{
+    int iFirstDivine = GetPrimaryDivineClass(oCaster);
+    int iBest = 0;
+    int iClass1 = GetClassByPosition(1, oCaster);
+    int iClass2 = GetClassByPosition(2, oCaster);
+    int iClass3 = GetClassByPosition(3, oCaster);	
+	int iClass4 = GetClassByPosition(4, oCaster);
+    int iClass5 = GetClassByPosition(5, oCaster);
+    int iClass6 = GetClassByPosition(6, oCaster);
+    int iClass7 = GetClassByPosition(8, oCaster);
+    int iClass8 = GetClassByPosition(8, oCaster);	
+	
+    int iClass1Lev = GetLevelByPosition(1, oCaster);
+    int iClass2Lev = GetLevelByPosition(2, oCaster);
+    int iClass3Lev = GetLevelByPosition(3, oCaster);
+    int iClass4Lev = GetLevelByPosition(4, oCaster);
+    int iClass5Lev = GetLevelByPosition(5, oCaster);
+    int iClass6Lev = GetLevelByPosition(6, oCaster);
+    int iClass7Lev = GetLevelByPosition(7, oCaster);
+    int iClass8Lev = GetLevelByPosition(8, oCaster);
+
+    if (iClass1 == CLASS_TYPE_PALADIN || iClass1 == CLASS_TYPE_RANGER) iClass1Lev = (iClass1Lev >= 4) ? (iClass1Lev / 2) : 0;
+    if (iClass2 == CLASS_TYPE_PALADIN || iClass2 == CLASS_TYPE_RANGER) iClass2Lev = (iClass2Lev >= 4) ? (iClass2Lev / 2) : 0;
+    if (iClass3 == CLASS_TYPE_PALADIN || iClass3 == CLASS_TYPE_RANGER) iClass3Lev = (iClass3Lev >= 4) ? (iClass3Lev / 2) : 0;
+    if (iClass4 == CLASS_TYPE_PALADIN || iClass4 == CLASS_TYPE_RANGER) iClass1Lev = (iClass1Lev >= 4) ? (iClass1Lev / 2) : 0;
+    if (iClass5 == CLASS_TYPE_PALADIN || iClass5 == CLASS_TYPE_RANGER) iClass2Lev = (iClass2Lev >= 4) ? (iClass2Lev / 2) : 0;
+    if (iClass6 == CLASS_TYPE_PALADIN || iClass6 == CLASS_TYPE_RANGER) iClass3Lev = (iClass3Lev >= 4) ? (iClass3Lev / 2) : 0;
+	if (iClass7 == CLASS_TYPE_PALADIN || iClass7 == CLASS_TYPE_RANGER) iClass1Lev = (iClass1Lev >= 4) ? (iClass1Lev / 2) : 0;
+    if (iClass8 == CLASS_TYPE_PALADIN || iClass8 == CLASS_TYPE_RANGER) iClass2Lev = (iClass2Lev >= 4) ? (iClass2Lev / 2) : 0;
+
+    if (iClass1 == iFirstDivine) iClass1Lev += GetDivinePRCLevels(oCaster);
+    if (iClass2 == iFirstDivine) iClass2Lev += GetDivinePRCLevels(oCaster);
+    if (iClass3 == iFirstDivine) iClass3Lev += GetDivinePRCLevels(oCaster);
+    if (iClass4 == iFirstDivine) iClass4Lev += GetDivinePRCLevels(oCaster);
+    if (iClass5 == iFirstDivine) iClass5Lev += GetDivinePRCLevels(oCaster);
+    if (iClass6 == iFirstDivine) iClass6Lev += GetDivinePRCLevels(oCaster);
+    if (iClass7 == iFirstDivine) iClass7Lev += GetDivinePRCLevels(oCaster);
+    if (iClass8 == iFirstDivine) iClass8Lev += GetDivinePRCLevels(oCaster);
+
+    iClass1Lev += PracticedSpellcasting(oCaster, iClass1, iClass1Lev);
+    iClass2Lev += PracticedSpellcasting(oCaster, iClass2, iClass2Lev);
+    iClass3Lev += PracticedSpellcasting(oCaster, iClass3, iClass3Lev);
+	iClass4Lev += PracticedSpellcasting(oCaster, iClass4, iClass4Lev);
+    iClass5Lev += PracticedSpellcasting(oCaster, iClass5, iClass5Lev);
+    iClass6Lev += PracticedSpellcasting(oCaster, iClass6, iClass5Lev);
+	iClass7Lev += PracticedSpellcasting(oCaster, iClass7, iClass6Lev);
+    iClass8Lev += PracticedSpellcasting(oCaster, iClass8, iClass7Lev);
+
+    if (!GetIsDivineClass(iClass1, oCaster)) iClass1Lev = 0;
+    if (!GetIsDivineClass(iClass2, oCaster)) iClass2Lev = 0;
+    if (!GetIsDivineClass(iClass3, oCaster)) iClass3Lev = 0;
+    if (!GetIsDivineClass(iClass4, oCaster)) iClass4Lev = 0;
+    if (!GetIsDivineClass(iClass5, oCaster)) iClass5Lev = 0;
+    if (!GetIsDivineClass(iClass6, oCaster)) iClass6Lev = 0;
+    if (!GetIsDivineClass(iClass7, oCaster)) iClass7Lev = 0;
+    if (!GetIsDivineClass(iClass8, oCaster)) iClass8Lev = 0;	
+	
+    if (iClass1Lev > iBest) iBest = iClass1Lev;
+    if (iClass2Lev > iBest) iBest = iClass2Lev;
+    if (iClass3Lev > iBest) iBest = iClass3Lev;
+    if (iClass4Lev > iBest) iBest = iClass4Lev;
+    if (iClass5Lev > iBest) iBest = iClass5Lev;
+    if (iClass6Lev > iBest) iBest = iClass6Lev;
+    if (iClass7Lev > iBest) iBest = iClass7Lev;
+    if (iClass8Lev > iBest) iBest = iClass8Lev;
+
+    return iBest;
+}
+
+//:: Test Void
+//void main (){}
\ No newline at end of file
diff --git a/trunk/include/prc_inc_clsfunc.nss b/trunk/include/prc_inc_clsfunc.nss
new file mode 100644
index 00000000..89c26dc8
--- /dev/null
+++ b/trunk/include/prc_inc_clsfunc.nss
@@ -0,0 +1,1618 @@
+/*
+    Class functions.
+    This scripts holds all functions used for classes in includes.
+    This prevents us from having one include for each class or set of classes.
+
+    Stratovarius
+*/
+
+//:: Updated for .35 by Jaysyn 2023/03/10
+
+////////////////Begin Generic////////////////
+
+// Function Definitions:
+
+// Include Files:
+#include "prc_inc_spells"
+//#include "prc_alterations"
+//#include "prcsp_engine"
+//#include "prc_inc_function"
+//#include "prc_x2_itemprop"
+//#include "prc_class_const"
+//#include "prc_feat_const"
+//#include "prc_ipfeat_const"
+//#include "inc_utility"
+//
+//#include "pnp_shft_poly"
+//#include "x2_inc_spellhook"
+//#include "prc_inc_combat"
+//#include "prc_inc_sp_tch"
+
+////////////////End Generic////////////////
+
+////////////////Begin Drunken Master//////////////////////
+
+
+// Function Definitions:
+
+// Searches oPC's inventory and finds the first valid alcoholic beverage container
+// (empty) and returns TRUE if a proper container was found. This function takes
+// action and returns a boolean.
+int UseBottle(object oPC);
+
+// Searches oPC's inventory for an alcoholic beverage and if one is found it's
+// destroyed and replaced by an empty container. This function is only used in
+// the Breath of Fire spell script.
+int UseAlcohol(object oPC = OBJECT_SELF);
+
+// Removes all Alcohol effects for oTarget. Used in B o Flame.
+void RemoveAlcoholEffects(object oTarget = OBJECT_SELF);
+
+// Creates an empty bottle on oPC.
+// sTag: the tag of the alcoholic beverage used (ale, spirits, wine)
+void CreateBottleOnObject(object oPC, string sTag);
+
+
+// Applies Drunk Like a Demno effects
+void DrunkLikeDemon();
+
+// Add the non-drunken master drinking effects.
+void MakeDrunk(int nSpellID);
+
+// Have the drunken master say one of 6 phrases.
+void DrunkenMasterSpeakString();
+
+// Creates an empty bottle on oPC.
+// nBeverage: the spell id of the alcoholic beverage used (ale, spirits, wine)
+void DrunkenMasterCreateEmptyBottle(int nSpellID);
+
+// Determines the DC needed to save against the cast spell-like ability
+// replace PRCGetSaveDC
+int GetSpellDCSLA(object oCaster, int iSpelllvl,int iAbi = ABILITY_WISDOM);
+
+void DoArchmageHeirophantSLA(object oPC, object oTarget, location lTarget, int nSLAID);
+
+// Functions:
+int UseBottle(object oPC)
+{
+    object oItem = GetFirstItemInInventory(oPC);
+    //search oPC for a bottle:
+    string sTag;
+    while(oItem != OBJECT_INVALID)
+    {
+        sTag = GetTag(oItem);
+        if(sTag == "NW_IT_THNMISC001"
+        || sTag == "NW_IT_THNMISC002"
+        || sTag == "NW_IT_THNMISC003"
+        || sTag == "NW_IT_THNMISC004")
+        {
+            SetPlotFlag(oItem, FALSE);
+            DestroyObject(oItem);
+            return TRUE;
+        }
+        else
+            oItem = GetNextItemInInventory();
+    }
+    return FALSE;
+}
+
+int UseAlcohol(object oPC = OBJECT_SELF)
+{
+    object oItem = GetFirstItemInInventory(oPC);
+    //search oPC for alcohol:
+    string sTag = GetTag(oItem);
+    while(oItem != OBJECT_INVALID)
+    {
+        if(sTag == "NW_IT_MPOTION021"
+        || sTag == "NW_IT_MPOTION022"
+        || sTag == "NW_IT_MPOTION023"
+        || sTag == "DragonsBreath")
+        {
+            SetPlotFlag(oItem, FALSE);
+            if(GetItemStackSize(oItem) > 1)
+            {
+                SetItemStackSize(oItem, GetItemStackSize(oItem) - 1);
+                // Create an Empty Bottle:
+                CreateBottleOnObject(oPC, sTag);
+                return TRUE;
+            }
+            else
+            {
+                DestroyObject(oItem);
+                // Create an Empty Bottle:
+                CreateBottleOnObject(oPC, sTag);
+                return TRUE;
+            }
+        }
+        else
+            oItem = GetNextItemInInventory();
+    }
+    return FALSE;
+}
+
+void CreateBottleOnObject(object oPC, string sTag)
+{
+    if(sTag == "NW_IT_MPOTION021") // Ale
+    {
+        CreateItemOnObject("nw_it_thnmisc002", oPC);
+    }
+    else if(sTag == "NW_IT_MPOTION022") // Spirits
+    {
+        CreateItemOnObject("nw_it_thnmisc003", oPC);
+    }
+    else if(sTag == "NW_IT_MPOTION023") // Wine
+    {
+        CreateItemOnObject("nw_it_thnmisc004", oPC);
+    }
+    else // Other beverage
+    {
+        CreateItemOnObject("nw_it_thnmisc001", oPC);
+    }
+}
+
+int GetIsDrunk(object oTarget = OBJECT_SELF)
+{
+    return GetHasSpellEffect(406, oTarget)
+         || GetHasSpellEffect(407, oTarget)
+         || GetHasSpellEffect(408, oTarget);
+}
+
+void RemoveAlcoholEffects(object oTarget = OBJECT_SELF)
+{
+    PRCRemoveSpellEffects(406, OBJECT_SELF, oTarget);
+    PRCRemoveSpellEffects(407, OBJECT_SELF, oTarget);
+    PRCRemoveSpellEffects(408, OBJECT_SELF, oTarget);
+}
+
+void DrunkenRage()
+{
+    float fDuration = GetLevelByClass(CLASS_TYPE_DRUNKEN_MASTER) > 9 ? HoursToSeconds(3) : HoursToSeconds(1);
+
+    effect eLink = EffectLinkEffects(EffectAbilityIncrease(ABILITY_STRENGTH, 4), EffectAbilityIncrease(ABILITY_CONSTITUTION, 4));
+           eLink = EffectLinkEffects(eLink, EffectSavingThrowIncrease(SAVING_THROW_WILL, 2));
+           eLink = EffectLinkEffects(eLink, EffectACDecrease(2));
+           eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_BLUR));
+           eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_AURA_FIRE));
+           eLink = ExtraordinaryEffect(eLink);
+
+    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, OBJECT_SELF, fDuration);
+
+    FloatingTextStringOnCreature("Drunken Rage Activated", OBJECT_SELF);
+}
+
+void DrunkLikeDemon()
+{
+    // A Drunken Master has had a drink. Add effects:
+    effect eLink = EffectLinkEffects(EffectAbilityIncrease(ABILITY_STRENGTH, 1), EffectAbilityIncrease(ABILITY_CONSTITUTION, 1));
+           eLink = EffectLinkEffects(eLink, EffectAbilityDecrease(ABILITY_WISDOM, 1));
+           eLink = EffectLinkEffects(eLink, EffectAbilityDecrease(ABILITY_INTELLIGENCE, 1));
+           eLink = EffectLinkEffects(eLink, EffectAbilityDecrease(ABILITY_DEXTERITY, 1));
+           eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_BLUR));
+
+    //run checks to see if Dex Modifier will be changed:
+    if(!(GetAbilityModifier(ABILITY_DEXTERITY) % 2))
+    {
+           //restore AC, Ref save and Tumble to previous values
+           eLink = EffectLinkEffects(eLink, EffectACIncrease(1));
+           eLink = EffectLinkEffects(eLink, EffectSavingThrowIncrease(SAVING_THROW_REFLEX, 1));
+           eLink = EffectLinkEffects(eLink, EffectSkillIncrease(SKILL_TUMBLE, 1));
+    }
+    eLink = ExtraordinaryEffect(eLink);
+
+    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, OBJECT_SELF, HoursToSeconds(1));
+
+    FloatingTextStringOnCreature("You are Drunk Like a Demon", OBJECT_SELF);
+}
+
+void MakeDrunk(int nSpellID)
+{
+    if(Random(100) < 40)
+        AssignCommand(OBJECT_SELF, ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING));
+    else
+        AssignCommand(OBJECT_SELF, ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_DRUNK));
+
+    int nPoints;
+    switch(nSpellID)
+    {
+        case 406: nPoints = 1; break;//Ale
+        case 407: nPoints = 2; break;//Wine
+        case 408: nPoints = 3; break;//Spirits
+    }
+
+    //ApplyAbilityDamage(oTarget, ABILITY_INTELLIGENCE, nPoints, DURATION_TYPE_TEMPORARY, TRUE, 60.0);
+    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectAbilityDecrease(ABILITY_INTELLIGENCE, nPoints)), OBJECT_SELF, 60.0);
+    AssignCommand(OBJECT_SELF, ActionSpeakStringByStrRef(10499));
+}
+
+void DrunkenMasterSpeakString()
+{
+    switch(d6())
+    {
+        case 1: AssignCommand(OBJECT_SELF, ActionSpeakString("Now that's the stuff!")); break;
+        case 2: AssignCommand(OBJECT_SELF, ActionSpeakString("That one really hit the spot!")); break;
+        case 3: AssignCommand(OBJECT_SELF, ActionSpeakString("That should keep me warm!")); break;
+        case 4: AssignCommand(OBJECT_SELF, ActionSpeakString("Good stuff!")); break;
+        case 5: AssignCommand(OBJECT_SELF, ActionSpeakString("Bless the Wine Gods!")); break;
+        case 6: AssignCommand(OBJECT_SELF, ActionSpeakString("Just what I needed!")); break;
+    }
+}
+
+void DrunkenMasterCreateEmptyBottle(int nSpellID)
+{
+    switch(nSpellID)
+    {
+        case 406: CreateItemOnObject("nw_it_thnmisc002", OBJECT_SELF); break;//Ale
+        case 407: CreateItemOnObject("nw_it_thnmisc004", OBJECT_SELF); break;//Wine
+        case 408: CreateItemOnObject("nw_it_thnmisc003", OBJECT_SELF); break;//Spirits
+        default: CreateItemOnObject("nw_it_thnmisc001", OBJECT_SELF); break;//Other
+    }
+}
+
+////////////////End Drunken Master//////////////////
+
+////////////////Begin Samurai//////////////////
+
+// This function is probably utterly broken: the match found variable is not reset in the loop and the returned value will be equal to the last match - Ornedan
+int GetPropertyValue(object oWeapon, int iType, int iSubType = -1, int bDebug = FALSE);
+
+int GetPropertyValue(object oWeapon, int iType, int iSubType = -1, int bDebug = FALSE)
+{
+    int bReturn = -1;
+    if(oWeapon == OBJECT_INVALID){return FALSE;}
+    int bMatch = FALSE;
+    if (GetItemHasItemProperty(oWeapon, iType))
+    {
+        if(bDebug){AssignCommand(GetFirstPC(), SpeakString("It has the property."));}
+        itemproperty ip = GetFirstItemProperty(oWeapon);
+        while(GetIsItemPropertyValid(ip))
+        {
+            if(GetItemPropertyType(ip) == iType)
+            {
+                if(bDebug){AssignCommand(GetFirstPC(), SpeakString("Again..."));}
+                bMatch = TRUE;
+                if (iSubType > -1)
+                {
+                    if(bDebug){AssignCommand(GetFirstPC(), SpeakString("Subtype Required."));}
+                    if(GetItemPropertySubType(ip) != iSubType)
+                    {
+                        if(bDebug){AssignCommand(GetFirstPC(), SpeakString("Subtype wrong."));}
+                        bMatch = FALSE;
+                    }
+                    else
+                    {
+                        if(bDebug){AssignCommand(GetFirstPC(), SpeakString("Subtype Correct."));}
+                    }
+                }
+            }
+            if (bMatch)
+            {
+                if(bDebug){AssignCommand(GetFirstPC(), SpeakString("Match found."));}
+                if (GetItemPropertyCostTableValue(ip) > -1)
+                {
+                    if(bDebug){AssignCommand(GetFirstPC(), SpeakString("Cost value found, returning."));}
+                    bReturn = GetItemPropertyCostTableValue(ip);
+                }
+                else
+                {
+                    if(bDebug){AssignCommand(GetFirstPC(), SpeakString("No cost value for property, returning TRUE."));}
+                    bReturn = 1;
+                }
+            }
+            else
+            {
+                if(bDebug){AssignCommand(GetFirstPC(), SpeakString("Match not found."));}
+            }
+            ip = GetNextItemProperty(oWeapon);
+        }
+    }
+    return bReturn;
+}
+
+
+void WeaponUpgradeVisual();
+
+object GetSamuraiToken(object oSamurai);
+
+void WeaponUpgradeVisual()
+{
+    object oPC = GetPCSpeaker();
+    int iCost = GetLocalInt(oPC, "CODI_SAM_WEAPON_COST");
+    object oToken = GetSamuraiToken(oPC);
+    int iToken = StringToInt(GetTag(oToken));
+    int iGold = GetGold(oPC);
+    if(iGold + iToken < iCost)
+    {
+        SendMessageToPC(oPC, "You sense the gods are angered!");
+        AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, 25, FALSE);
+        object oWeapon = GetItemPossessedBy(oPC, "codi_sam_mw");
+        DestroyObject(oWeapon);
+        return;
+    }
+    else if(iToken <= iCost)
+    {
+        iCost = iCost - iToken;
+        DestroyObject(oToken);
+        TakeGoldFromCreature(iCost, oPC, TRUE);
+    }
+    else if (iToken > iCost)
+    {
+        object oNewToken = CopyObject(oToken, GetLocation(oPC), oPC, IntToString(iToken - iCost));
+        DestroyObject(oToken);
+    }
+    effect eVis = EffectVisualEffect(VFX_FNF_DISPEL_DISJUNCTION);
+    AssignCommand(oPC, ClearAllActions());
+    AssignCommand(oPC, ActionPlayAnimation(ANIMATION_LOOPING_MEDITATE,1.0,6.0));
+    AssignCommand(oPC, ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY2));
+    DelayCommand(0.1, SetCommandable(FALSE, oPC));
+    DelayCommand(6.5, SetCommandable(TRUE, oPC));
+    DelayCommand(5.0,ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, GetLocation(oPC)));
+}
+
+object GetSamuraiToken(object oSamurai)
+{
+    object oItem = GetFirstItemInInventory(oSamurai);
+    while(oItem != OBJECT_INVALID)
+    {
+        if(GetResRef(oItem) == "codi_sam_token")
+        {
+            return oItem;
+        }
+        oItem = GetNextItemInInventory(oSamurai);
+    }
+    return OBJECT_INVALID;
+}
+
+
+
+
+////////////////End Samurai//////////////////
+
+////////////////Begin Vile Feat//////////////////
+
+
+int Vile_Feat(int iTypeWeap)
+{
+       switch(iTypeWeap)
+        {
+            case BASE_ITEM_BASTARDSWORD: return GetHasFeat(FEAT_VILE_MARTIAL_BASTARDSWORD);
+            case BASE_ITEM_BATTLEAXE: return GetHasFeat(FEAT_VILE_MARTIAL_BATTLEAXE);
+            case BASE_ITEM_CLUB: return GetHasFeat(FEAT_VILE_MARTIAL_CLUB);
+            case BASE_ITEM_DAGGER: return GetHasFeat(FEAT_VILE_MARTIAL_DAGGER);
+            case BASE_ITEM_DART: return GetHasFeat(FEAT_VILE_MARTIAL_DART);
+            case BASE_ITEM_DIREMACE: return GetHasFeat(FEAT_VILE_MARTIAL_DIREMACE);
+            case BASE_ITEM_DOUBLEAXE: return GetHasFeat(FEAT_VILE_MARTIAL_DOUBLEAXE);
+            case BASE_ITEM_DWARVENWARAXE: return GetHasFeat(FEAT_VILE_MARTIAL_DWAXE);
+            case BASE_ITEM_GREATAXE: return GetHasFeat(FEAT_VILE_MARTIAL_GREATAXE);
+            case BASE_ITEM_GREATSWORD: return GetHasFeat(FEAT_VILE_MARTIAL_GREATSWORD);
+            case BASE_ITEM_HALBERD: return GetHasFeat(FEAT_VILE_MARTIAL_HALBERD);
+            case BASE_ITEM_HANDAXE: return GetHasFeat(FEAT_VILE_MARTIAL_HANDAXE);
+            case BASE_ITEM_HEAVYCROSSBOW: return GetHasFeat(FEAT_VILE_MARTIAL_HEAVYCROSSBOW);
+            case BASE_ITEM_HEAVYFLAIL: return GetHasFeat(FEAT_VILE_MARTIAL_HEAVYFLAIL);
+            case BASE_ITEM_KAMA: return GetHasFeat(FEAT_VILE_MARTIAL_KAMA);
+            case BASE_ITEM_KATANA: return GetHasFeat(FEAT_VILE_MARTIAL_KATANA);
+            case BASE_ITEM_KUKRI: return GetHasFeat(FEAT_VILE_MARTIAL_KUKRI);
+            case BASE_ITEM_LIGHTCROSSBOW: return GetHasFeat(FEAT_VILE_MARTIAL_LIGHTCROSSBOW);
+            case BASE_ITEM_LIGHTFLAIL: return GetHasFeat(FEAT_VILE_MARTIAL_LIGHTFLAIL);
+            case BASE_ITEM_LIGHTHAMMER: return GetHasFeat(FEAT_VILE_MARTIAL_LIGHTHAMMER);
+            case BASE_ITEM_LIGHTMACE: return GetHasFeat(FEAT_VILE_MARTIAL_MACE);
+            case BASE_ITEM_LONGBOW: return GetHasFeat(FEAT_VILE_MARTIAL_LONGBOW);
+            case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_VILE_MARTIAL_LONGSWORD);
+            case BASE_ITEM_MORNINGSTAR: return GetHasFeat(FEAT_VILE_MARTIAL_MORNINGSTAR);
+            case BASE_ITEM_QUARTERSTAFF: return GetHasFeat(FEAT_VILE_MARTIAL_QUARTERSTAFF);
+            case BASE_ITEM_RAPIER: return GetHasFeat(FEAT_VILE_MARTIAL_RAPIER);
+            case BASE_ITEM_SCIMITAR: return GetHasFeat(FEAT_VILE_MARTIAL_SCIMITAR);
+            case BASE_ITEM_SCYTHE: return GetHasFeat(FEAT_VILE_MARTIAL_SCYTHE);
+            case BASE_ITEM_SHORTBOW: return GetHasFeat(FEAT_VILE_MARTIAL_SHORTBOW);
+            case BASE_ITEM_SHORTSPEAR: return GetHasFeat(FEAT_VILE_MARTIAL_SPEAR);
+            case BASE_ITEM_SHORTSWORD: return GetHasFeat(FEAT_VILE_MARTIAL_SHORTSWORD);
+            case BASE_ITEM_SHURIKEN: return GetHasFeat(FEAT_VILE_MARTIAL_SHURIKEN);
+            case BASE_ITEM_SLING: return GetHasFeat(FEAT_VILE_MARTIAL_SLING);
+            case BASE_ITEM_SICKLE: return GetHasFeat(FEAT_VILE_MARTIAL_SICKLE);
+            case BASE_ITEM_TWOBLADEDSWORD: return GetHasFeat(FEAT_VILE_MARTIAL_TWOBLADED);
+            case BASE_ITEM_WARHAMMER: return GetHasFeat(FEAT_VILE_MARTIAL_WARHAMMER);
+            case BASE_ITEM_WHIP: return GetHasFeat(FEAT_VILE_MARTIAL_WHIP);
+            case BASE_ITEM_TRIDENT: return GetHasFeat(FEAT_VILE_MARTIAL_TRIDENT);
+
+            //new items
+            case BASE_ITEM_ELVEN_LIGHTBLADE: return (GetHasFeat(FEAT_VILE_MARTIAL_SHORTSWORD) || GetHasFeat(FEAT_VILE_MARTIAL_RAPIER));
+            case BASE_ITEM_ELVEN_THINBLADE: return (GetHasFeat(FEAT_VILE_MARTIAL_LONGSWORD) || GetHasFeat(FEAT_VILE_MARTIAL_RAPIER));
+            case BASE_ITEM_ELVEN_COURTBLADE: return GetHasFeat(FEAT_VILE_MARTIAL_GREATSWORD);
+        }
+
+    return FALSE;
+
+}
+
+////////////////End Vile Feat//////////////////
+
+////////////////Begin Soul Inc//////////////////
+
+const int IPRP_CONST_ONHIT_DURATION_5_PERCENT_1_ROUNDS = 20;
+
+int Sanctify_Feat(int iTypeWeap)
+{
+       switch(iTypeWeap)
+        {
+            case BASE_ITEM_BASTARDSWORD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_BASTARDSWORD);
+            case BASE_ITEM_BATTLEAXE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_BATTLEAXE);
+            case BASE_ITEM_CLUB: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_CLUB);
+            case BASE_ITEM_DAGGER: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_DAGGER);
+            case BASE_ITEM_DART: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_DART);
+            case BASE_ITEM_DIREMACE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_DIREMACE);
+            case BASE_ITEM_DOUBLEAXE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_DOUBLEAXE);
+            case BASE_ITEM_DWARVENWARAXE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_DWAXE);
+            case BASE_ITEM_GREATAXE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_GREATAXE);
+            case BASE_ITEM_GREATSWORD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_GREATSWORD);
+            case BASE_ITEM_HALBERD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_HALBERD);
+            case BASE_ITEM_HANDAXE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_HANDAXE);
+            case BASE_ITEM_HEAVYCROSSBOW: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_HEAVYCROSSBOW);
+            case BASE_ITEM_HEAVYFLAIL: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_HEAVYFLAIL);
+            case BASE_ITEM_KAMA: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_KAMA);
+            case BASE_ITEM_KATANA: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_KATANA);
+            case BASE_ITEM_KUKRI: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_KUKRI);
+            case BASE_ITEM_LIGHTCROSSBOW: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_LIGHTCROSSBOW);
+            case BASE_ITEM_LIGHTFLAIL: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_LIGHTFLAIL);
+            case BASE_ITEM_LIGHTHAMMER: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_LIGHTHAMMER);
+            case BASE_ITEM_LIGHTMACE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_MACE);
+            case BASE_ITEM_LONGBOW: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_LONGBOW);
+            case BASE_ITEM_LONGSWORD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_LONGSWORD);
+            case BASE_ITEM_MORNINGSTAR: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_MORNINGSTAR);
+            case BASE_ITEM_QUARTERSTAFF: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_QUARTERSTAFF);
+            case BASE_ITEM_RAPIER: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_RAPIER);
+            case BASE_ITEM_SCIMITAR: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SCIMITAR);
+            case BASE_ITEM_SCYTHE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SCYTHE);
+            case BASE_ITEM_SHORTBOW: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SHORTBOW);
+            case BASE_ITEM_SHORTSPEAR: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SPEAR);
+            case BASE_ITEM_SHORTSWORD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SHORTSWORD);
+            case BASE_ITEM_SHURIKEN: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SHURIKEN);
+            case BASE_ITEM_SLING: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SLING);
+            case BASE_ITEM_SICKLE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_SICKLE);
+            case BASE_ITEM_TWOBLADEDSWORD: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_TWOBLADED);
+            case BASE_ITEM_WARHAMMER: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_WARHAMMER);
+            case BASE_ITEM_WHIP: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_WHIP);
+            case BASE_ITEM_TRIDENT: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_TRIDENT);
+
+            //new items
+            case BASE_ITEM_ELVEN_LIGHTBLADE: return (GetHasFeat(FEAT_SANCTIFY_MARTIAL_SHORTSWORD) || GetHasFeat(FEAT_SANCTIFY_MARTIAL_RAPIER));
+            case BASE_ITEM_ELVEN_THINBLADE: return (GetHasFeat(FEAT_SANCTIFY_MARTIAL_LONGSWORD) || GetHasFeat(FEAT_SANCTIFY_MARTIAL_RAPIER));
+            case BASE_ITEM_ELVEN_COURTBLADE: return GetHasFeat(FEAT_SANCTIFY_MARTIAL_GREATSWORD);
+        }
+
+        return FALSE;
+}
+
+int DamageConv(int iMonsDmg)
+{
+
+   switch(iMonsDmg)
+   {
+     case IP_CONST_MONSTERDAMAGE_1d4:  return 1;
+     case IP_CONST_MONSTERDAMAGE_1d6:  return 2;
+     case IP_CONST_MONSTERDAMAGE_1d8:  return 3;
+     case IP_CONST_MONSTERDAMAGE_1d10: return 4;
+     case IP_CONST_MONSTERDAMAGE_1d12: return 5;
+     case IP_CONST_MONSTERDAMAGE_1d20: return 6;
+
+     case IP_CONST_MONSTERDAMAGE_2d4:  return 10;
+     case IP_CONST_MONSTERDAMAGE_2d6:  return 11;
+     case IP_CONST_MONSTERDAMAGE_2d8:  return 12;
+     case IP_CONST_MONSTERDAMAGE_2d10: return 13;
+     case IP_CONST_MONSTERDAMAGE_2d12: return 14;
+     case IP_CONST_MONSTERDAMAGE_2d20: return 15;
+
+     case IP_CONST_MONSTERDAMAGE_3d4:  return 20;
+     case IP_CONST_MONSTERDAMAGE_3d6:  return 21;
+     case IP_CONST_MONSTERDAMAGE_3d8:  return 22;
+     case IP_CONST_MONSTERDAMAGE_3d10: return 23;
+     case IP_CONST_MONSTERDAMAGE_3d12: return 24;
+     case IP_CONST_MONSTERDAMAGE_3d20: return 25;
+
+
+   }
+
+
+  return 0;
+}
+
+int ConvMonsterDmg(int iMonsDmg)
+{
+
+   switch(iMonsDmg)
+   {
+     case 1:  return IP_CONST_MONSTERDAMAGE_1d4;
+     case 2:  return IP_CONST_MONSTERDAMAGE_1d6;
+     case 3:  return IP_CONST_MONSTERDAMAGE_1d8;
+     case 4:  return IP_CONST_MONSTERDAMAGE_1d10;
+     case 5:  return IP_CONST_MONSTERDAMAGE_1d12;
+     case 6:  return IP_CONST_MONSTERDAMAGE_1d20;
+     case 10: return IP_CONST_MONSTERDAMAGE_2d4;
+     case 11: return IP_CONST_MONSTERDAMAGE_2d6;
+     case 12: return IP_CONST_MONSTERDAMAGE_2d8;
+     case 13: return IP_CONST_MONSTERDAMAGE_2d10;
+     case 14: return IP_CONST_MONSTERDAMAGE_2d12;
+     case 15: return IP_CONST_MONSTERDAMAGE_2d20;
+     case 20: return IP_CONST_MONSTERDAMAGE_3d4;
+     case 21: return IP_CONST_MONSTERDAMAGE_3d6;
+     case 22: return IP_CONST_MONSTERDAMAGE_3d8;
+     case 23: return IP_CONST_MONSTERDAMAGE_3d10;
+     case 24: return IP_CONST_MONSTERDAMAGE_3d12;
+     case 25: return IP_CONST_MONSTERDAMAGE_3d20;
+
+   }
+
+   return 0;
+}
+
+int MonsterDamage(object oItem)
+{
+    int iBonus;
+    int iTemp;
+    itemproperty ip = GetFirstItemProperty(oItem);
+    while(GetIsItemPropertyValid(ip))
+    {
+        if(GetItemPropertyType(ip) == ITEM_PROPERTY_MONSTER_DAMAGE)
+        {
+            iTemp = GetItemPropertyCostTableValue(ip);
+            iBonus = iTemp > iBonus ? iTemp : iBonus;
+        }
+        ip = GetNextItemProperty(oItem);
+    }
+
+    return iBonus;
+}
+
+int FeatIniDmg(object oItem)
+{
+    itemproperty ip = GetFirstItemProperty(oItem);
+    while (GetIsItemPropertyValid(ip))
+    {
+        if(GetItemPropertyType(ip) == ITEM_PROPERTY_BONUS_FEAT)
+        {
+          if(GetItemPropertySubType(ip) == IP_CONST_FEAT_WeapFocCreature)
+              return 1;
+        }
+        ip = GetNextItemProperty(oItem);
+    }
+    return 0;
+}
+
+
+void AddIniDmg(object oPC)
+{
+
+   int bUnarmedDmg = GetHasFeat(FEAT_INCREASE_DAMAGE1, oPC)
+                   + GetHasFeat(FEAT_INCREASE_DAMAGE2, oPC);
+
+   if(!bUnarmedDmg)
+       return;
+
+   object oCweapB = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B,oPC);
+   object oCweapL = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L,oPC);
+   object oCweapR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R,oPC);
+
+   int iDmg;
+   int iConv;
+   int iStr =  GetAbilityModifier(ABILITY_STRENGTH, oPC);
+   int iWis =  GetAbilityModifier(ABILITY_WISDOM, oPC);
+       iWis = iWis > iStr ? iWis : 0;
+
+
+   /*if(GetHasFeat(FEAT_INTUITIVE_ATTACK, oPC))
+   {
+     SetCompositeBonusT(oCweapB,"",iWis,ITEM_PROPERTY_ATTACK_BONUS);
+     SetCompositeBonusT(oCweapL,"",iWis,ITEM_PROPERTY_ATTACK_BONUS);
+     SetCompositeBonusT(oCweapR,"",iWis,ITEM_PROPERTY_ATTACK_BONUS);
+   }
+   if (GetHasFeat(FEAT_RAVAGEGOLDENICE, oPC))
+   {
+     AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_RAVAGEGOLDENICE,2),oCweapB,9999.0);
+     AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_RAVAGEGOLDENICE,2),oCweapL,9999.0);
+     AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_RAVAGEGOLDENICE,2),oCweapR,9999.0);
+   }*/
+
+
+   if ( oCweapB != OBJECT_INVALID && !FeatIniDmg(oCweapB))
+   {
+      iDmg =  MonsterDamage(oCweapB);
+      iConv = DamageConv(iDmg) + bUnarmedDmg;
+      iConv = (iConv > 6 && iConv < 10)  ? 6  : iConv;
+      iConv = (iConv > 15 && iConv < 20) ? 15 : iConv;
+      iConv = (iConv > 25)               ? 25 : iConv;
+      iConv = ConvMonsterDmg(iConv);
+      TotalAndRemoveProperty(oCweapB,ITEM_PROPERTY_MONSTER_DAMAGE,-1);
+      AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyMonsterDamage(iConv),oCweapB);
+      //AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapFocCreature),oCweapB);
+      IPSafeAddItemProperty(oCweapB, PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapFocCreature), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+   }
+   if ( oCweapL != OBJECT_INVALID && !FeatIniDmg(oCweapL))
+   {
+      iDmg =  MonsterDamage(oCweapL);
+      iConv = DamageConv(iDmg) + bUnarmedDmg;
+      iConv = (iConv > 6 && iConv < 10)  ? 6  : iConv;
+      iConv = (iConv > 15 && iConv < 20) ? 15 : iConv;
+      iConv = (iConv > 25)               ? 25 : iConv;
+      iConv = ConvMonsterDmg(iConv);
+      TotalAndRemoveProperty(oCweapL,ITEM_PROPERTY_MONSTER_DAMAGE,-1);
+      AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyMonsterDamage(iConv),oCweapL);
+      //AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapFocCreature),oCweapL);
+      IPSafeAddItemProperty(oCweapL, PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapFocCreature), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+   }
+   if ( oCweapR != OBJECT_INVALID && !FeatIniDmg(oCweapR))
+   {
+      iDmg =  MonsterDamage(oCweapR);
+      iConv = DamageConv(iDmg) + bUnarmedDmg;
+      iConv = (iConv > 6 && iConv < 10)  ? 6  : iConv;
+      iConv = (iConv > 15 && iConv < 20) ? 15 : iConv;
+      iConv = (iConv > 25)               ? 25 : iConv;
+      iConv = ConvMonsterDmg(iConv);
+      TotalAndRemoveProperty(oCweapR,ITEM_PROPERTY_MONSTER_DAMAGE,-1);
+      AddItemProperty(DURATION_TYPE_PERMANENT,ItemPropertyMonsterDamage(iConv),oCweapR);
+      //AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapFocCreature),oCweapR);
+      IPSafeAddItemProperty(oCweapR, PRCItemPropertyBonusFeat(IP_CONST_FEAT_WeapFocCreature), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+   }
+}
+
+void AddCriti(object oPC,object oSkin,int ip_feat_crit,int nFeat)
+{
+    // Do not add multiple instances of the same bonus feat iprop, it lags the game
+    AddSkinFeat(nFeat, ip_feat_crit, oSkin, oPC);
+}
+
+void ImpCrit(object oPC,object oSkin)
+{
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_BASTARD_SWORD,    oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_BASTARD_SWORD,    FEAT_IMPROVED_CRITICAL_BASTARD_SWORD);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_BATTLE_AXE,       oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_BATTLE_AXE,       FEAT_IMPROVED_CRITICAL_BATTLE_AXE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_CLUB,             oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_CLUB,             FEAT_IMPROVED_CRITICAL_CLUB);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_DAGGER,           oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_DAGGER,           FEAT_IMPROVED_CRITICAL_DAGGER);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_DART,             oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_DART,             FEAT_IMPROVED_CRITICAL_DART);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_DIRE_MACE,        oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_DIRE_MACE,        FEAT_IMPROVED_CRITICAL_DIRE_MACE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_DOUBLE_AXE,       oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_DOUBLE_AXE,       FEAT_IMPROVED_CRITICAL_DOUBLE_AXE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_DWAXE,            oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_DWAXE,            FEAT_IMPROVED_CRITICAL_DWAXE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_AXE,        oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_GREAT_AXE,        FEAT_IMPROVED_CRITICAL_GREAT_AXE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_SWORD,      oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_GREAT_SWORD,      FEAT_IMPROVED_CRITICAL_GREAT_SWORD);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_HALBERD,          oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_HALBERD,          FEAT_IMPROVED_CRITICAL_HALBERD);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_HAND_AXE,         oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_HAND_AXE,         FEAT_IMPROVED_CRITICAL_HAND_AXE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW,   oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_HEAVY_CROSSBOW,   FEAT_IMPROVED_CRITICAL_HEAVY_CROSSBOW);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_FLAIL,      oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_HEAVY_FLAIL,      FEAT_IMPROVED_CRITICAL_HEAVY_FLAIL);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_KAMA,             oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_KAMA,             FEAT_IMPROVED_CRITICAL_KAMA);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_KATANA,           oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_KATANA,           FEAT_IMPROVED_CRITICAL_KATANA);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_KUKRI,            oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_KUKRI,            FEAT_IMPROVED_CRITICAL_KUKRI);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW,   oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_LIGHT_CROSSBOW,   FEAT_IMPROVED_CRITICAL_LIGHT_CROSSBOW);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_FLAIL,      oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_LIGHT_FLAIL,      FEAT_IMPROVED_CRITICAL_LIGHT_FLAIL);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_HAMMER,     oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_LIGHT_HAMMER,     FEAT_IMPROVED_CRITICAL_LIGHT_HAMMER);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_MACE,       oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_LIGHT_MACE,       FEAT_IMPROVED_CRITICAL_LIGHT_MACE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_LONG_SWORD,       oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_LONG_SWORD,       FEAT_IMPROVED_CRITICAL_LONG_SWORD);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_LONGBOW,          oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_LONGBOW,          FEAT_IMPROVED_CRITICAL_LONGBOW);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_MORNING_STAR,     oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_MORNING_STAR,     FEAT_IMPROVED_CRITICAL_MORNING_STAR);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_RAPIER,           oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_RAPIER,           FEAT_IMPROVED_CRITICAL_RAPIER);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_SCIMITAR,         oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_SCIMITAR,         FEAT_IMPROVED_CRITICAL_SCIMITAR);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_SCYTHE,           oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_SCYTHE,           FEAT_IMPROVED_CRITICAL_SCYTHE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_SHORT_SWORD,      oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_SHORT_SWORD,      FEAT_IMPROVED_CRITICAL_SHORT_SWORD);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_SHORTBOW,         oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_SHORTBOW,         FEAT_IMPROVED_CRITICAL_SHORTBOW);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_SHURIKEN,         oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_SHURIKEN,         FEAT_IMPROVED_CRITICAL_SHURIKEN);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_SICKLE,           oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_SICKLE,           FEAT_IMPROVED_CRITICAL_SICKLE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_SLING,            oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_SLING,            FEAT_IMPROVED_CRITICAL_SLING);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_SPEAR,            oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_SPEAR,            FEAT_IMPROVED_CRITICAL_SPEAR);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_STAFF,            oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_STAFF,            FEAT_IMPROVED_CRITICAL_STAFF);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_THROWING_AXE,     oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_THROWING_AXE,     FEAT_IMPROVED_CRITICAL_THROWING_AXE);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD, oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_TWO_BLADED_SWORD, FEAT_IMPROVED_CRITICAL_TWO_BLADED_SWORD);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_WAR_HAMMER,       oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_WAR_HAMMER,       FEAT_IMPROVED_CRITICAL_WAR_HAMMER);
+    if(GetHasFeat(FEAT_WEAPON_FOCUS_WHIP,             oPC)) AddCriti(oPC, oSkin, IP_CONST_FEAT_IMPROVED_CRITICAL_WHIP,             FEAT_IMPROVED_CRITICAL_WHIP);
+
+}
+
+////////////////End Soul Inc//////////////////
+
+////////////////Begin Martial Strike//////////////////
+
+void MartialStrike()
+{
+   object oItem;
+   object oPC = OBJECT_SELF;
+
+   int iEquip=GetLocalInt(oPC,"ONEQUIP");
+   int iType;
+
+   if (iEquip==2)
+   {
+
+     if (!GetHasFeat(FEAT_HOLY_MARTIAL_STRIKE)) return;
+
+     oItem=GetItemLastEquipped();
+     iType= GetBaseItemType(oItem);
+
+     switch (iType)
+     {
+        case BASE_ITEM_BOLT:
+        case BASE_ITEM_BULLET:
+        case BASE_ITEM_ARROW:
+          iType=GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND));
+          break;
+        case BASE_ITEM_SHORTBOW:
+        case BASE_ITEM_LONGBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_ARROWS);
+          break;
+        case BASE_ITEM_LIGHTCROSSBOW:
+        case BASE_ITEM_HEAVYCROSSBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BOLTS);
+          break;
+        case BASE_ITEM_SLING:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BULLETS);
+          break;
+     }
+
+     AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL,IP_CONST_DAMAGETYPE_DIVINE,IP_CONST_DAMAGEBONUS_2d6),oItem,9999.0);
+     AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyVisualEffect(ITEM_VISUAL_HOLY),oItem,9999.0);
+     SetLocalInt(oItem,"MartialStrik",1);
+  }
+   else if (iEquip==1)
+   {
+     oItem=GetItemLastUnequipped();
+     iType= GetBaseItemType(oItem);
+
+     switch (iType)
+     {
+        case BASE_ITEM_BOLT:
+        case BASE_ITEM_BULLET:
+        case BASE_ITEM_ARROW:
+          iType=GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND));
+          break;
+        case BASE_ITEM_SHORTBOW:
+        case BASE_ITEM_LONGBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_ARROWS);
+          break;
+        case BASE_ITEM_LIGHTCROSSBOW:
+        case BASE_ITEM_HEAVYCROSSBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BOLTS);
+          break;
+        case BASE_ITEM_SLING:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BULLETS);
+          break;
+     }
+
+    if ( GetLocalInt(oItem,"MartialStrik"))
+    {
+      RemoveSpecificProperty(oItem,ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP,IP_CONST_ALIGNMENTGROUP_EVIL,IP_CONST_DAMAGEBONUS_2d6, 1,"",IP_CONST_DAMAGETYPE_DIVINE,DURATION_TYPE_TEMPORARY);
+      RemoveSpecificProperty(oItem,ITEM_PROPERTY_VISUALEFFECT,ITEM_VISUAL_HOLY,-1,1,"",-1,DURATION_TYPE_TEMPORARY);
+      DeleteLocalInt(oItem,"MartialStrik");
+    }
+
+   }
+   else
+   {
+
+     if (!GetHasFeat(FEAT_HOLY_MARTIAL_STRIKE)) return;
+
+     oItem=GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC);
+     iType= GetBaseItemType(oItem);
+
+     switch (iType)
+     {
+        case BASE_ITEM_BOLT:
+        case BASE_ITEM_BULLET:
+        case BASE_ITEM_ARROW:
+          iType=GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND));
+          break;
+        case BASE_ITEM_SHORTBOW:
+        case BASE_ITEM_LONGBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_ARROWS);
+          break;
+        case BASE_ITEM_LIGHTCROSSBOW:
+        case BASE_ITEM_HEAVYCROSSBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BOLTS);
+          break;
+        case BASE_ITEM_SLING:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BULLETS);
+          break;
+     }
+
+     if (!GetLocalInt(oItem,"MartialStrik"))
+     {
+       AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL,IP_CONST_DAMAGETYPE_DIVINE,IP_CONST_DAMAGEBONUS_2d6),oItem,9999.0);
+       AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyVisualEffect(ITEM_VISUAL_HOLY),oItem,9999.0);
+       SetLocalInt(oItem,"MartialStrik",1);
+     }
+     oItem=GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC);
+     iType= GetBaseItemType(oItem);
+     if ( !GetLocalInt(oItem,"MartialStrik"))
+     {
+       AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_EVIL,IP_CONST_DAMAGETYPE_DIVINE,IP_CONST_DAMAGEBONUS_2d6),oItem,9999.0);
+       AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyVisualEffect(ITEM_VISUAL_HOLY),oItem,9999.0);
+       SetLocalInt(oItem,"MartialStrik",1);
+     }
+   }
+
+
+}
+
+
+void UnholyStrike()
+{
+   object oItem;
+   object oPC = OBJECT_SELF;
+
+   int iEquip=GetLocalInt(oPC,"ONEQUIP");
+   int iType;
+
+   if (iEquip==2)
+   {
+
+     if (!GetHasFeat(FEAT_UNHOLY_STRIKE)) return;
+
+     oItem=GetItemLastEquipped();
+     iType= GetBaseItemType(oItem);
+
+     switch (iType)
+     {
+        case BASE_ITEM_BOLT:
+        case BASE_ITEM_BULLET:
+        case BASE_ITEM_ARROW:
+          iType=GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND));
+          break;
+        case BASE_ITEM_SHORTBOW:
+        case BASE_ITEM_LONGBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_ARROWS);
+          break;
+        case BASE_ITEM_LIGHTCROSSBOW:
+        case BASE_ITEM_HEAVYCROSSBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BOLTS);
+          break;
+        case BASE_ITEM_SLING:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BULLETS);
+          break;
+     }
+
+
+     AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_GOOD,IP_CONST_DAMAGETYPE_DIVINE,IP_CONST_DAMAGEBONUS_2d6),oItem,9999.0);
+     AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyVisualEffect(ITEM_VISUAL_EVIL),oItem,9999.0);
+     SetLocalInt(oItem,"UnholyStrik",1);
+  }
+   else if (iEquip==1)
+   {
+     oItem=GetItemLastUnequipped();
+     iType= GetBaseItemType(oItem);
+
+     switch (iType)
+     {
+        case BASE_ITEM_BOLT:
+        case BASE_ITEM_BULLET:
+        case BASE_ITEM_ARROW:
+          iType=GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND));
+          break;
+        case BASE_ITEM_SHORTBOW:
+        case BASE_ITEM_LONGBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_ARROWS);
+          break;
+        case BASE_ITEM_LIGHTCROSSBOW:
+        case BASE_ITEM_HEAVYCROSSBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BOLTS);
+          break;
+        case BASE_ITEM_SLING:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BULLETS);
+          break;
+     }
+
+    if ( GetLocalInt(oItem,"UnholyStrik"))
+    {
+      RemoveSpecificProperty(oItem,ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP,IP_CONST_ALIGNMENTGROUP_GOOD,IP_CONST_DAMAGEBONUS_2d6, 1,"",IP_CONST_DAMAGETYPE_DIVINE,DURATION_TYPE_TEMPORARY);
+      RemoveSpecificProperty(oItem,ITEM_PROPERTY_VISUALEFFECT,ITEM_VISUAL_EVIL,-1,1,"",-1,DURATION_TYPE_TEMPORARY);
+      DeleteLocalInt(oItem,"UnholyStrik");
+    }
+
+   }
+   else
+   {
+
+     if (!GetHasFeat(FEAT_UNHOLY_STRIKE)) return;
+
+     oItem=GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oPC);
+     iType= GetBaseItemType(oItem);
+
+     switch (iType)
+     {
+        case BASE_ITEM_BOLT:
+        case BASE_ITEM_BULLET:
+        case BASE_ITEM_ARROW:
+          iType=GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND));
+          break;
+        case BASE_ITEM_SHORTBOW:
+        case BASE_ITEM_LONGBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_ARROWS);
+          break;
+        case BASE_ITEM_LIGHTCROSSBOW:
+        case BASE_ITEM_HEAVYCROSSBOW:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BOLTS);
+          break;
+        case BASE_ITEM_SLING:
+          oItem=GetItemInSlot(INVENTORY_SLOT_BULLETS);
+          break;
+     }
+
+     if (!GetLocalInt(oItem,"UnholyStrik"))
+     {
+       AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_GOOD,IP_CONST_DAMAGETYPE_DIVINE,IP_CONST_DAMAGEBONUS_2d6),oItem,9999.0);
+       AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyVisualEffect(ITEM_VISUAL_EVIL),oItem,9999.0);
+       SetLocalInt(oItem,"UnholyStrik",1);
+     }
+     oItem=GetItemInSlot(INVENTORY_SLOT_LEFTHAND,oPC);
+     iType= GetBaseItemType(oItem);
+     if ( !GetLocalInt(oItem,"UnholyStrik"))
+     {
+       AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyDamageBonusVsAlign(IP_CONST_ALIGNMENTGROUP_GOOD,IP_CONST_DAMAGETYPE_DIVINE,IP_CONST_DAMAGEBONUS_2d6),oItem,9999.0);
+       AddItemProperty(DURATION_TYPE_TEMPORARY,ItemPropertyVisualEffect(ITEM_VISUAL_EVIL),oItem,9999.0);
+       SetLocalInt(oItem,"UnholyStrik",1);
+     }
+   }
+
+
+}
+
+////////////////End Martial Strike//////////////////
+
+////////////////Begin Soldier of Light Spells//////////////////
+/* As far as I can tell, not used at all - Ornedan
+void spellsCureMod(int nCasterLvl ,int nDamage, int nMaxExtraDamage, int nMaximized, int vfx_impactHurt, int vfx_impactHeal, int nSpellID)
+{
+    //Declare major variables
+    object oTarget = PRCGetSpellTargetObject();
+    int nHeal;
+    int nMetaMagic = PRCGetMetaMagicFeat();
+    effect eVis = EffectVisualEffect(vfx_impactHurt);
+    effect eVis2 = EffectVisualEffect(vfx_impactHeal);
+    effect eHeal, eDam;
+
+    int nExtraDamage = nCasterLvl; // * figure out the bonus damage
+    if (nExtraDamage > nMaxExtraDamage)
+    {
+        nExtraDamage = nMaxExtraDamage;
+    }
+    // * if low or normal difficulty is treated as MAXIMIZED
+    if(GetIsPC(oTarget) && GetGameDifficulty() < GAME_DIFFICULTY_CORE_RULES)
+    {
+        nDamage = nMaximized + nExtraDamage;
+    }
+    else
+    {
+        nDamage = nDamage + nExtraDamage;
+    }
+
+
+    //Make metamagic checks
+    int iBlastFaith = BlastInfidelOrFaithHeal(OBJECT_SELF, oTarget, DAMAGE_TYPE_POSITIVE, TRUE);
+    if (nMetaMagic & METAMAGIC_MAXIMIZE || iBlastFaith)
+    {
+        nDamage = nMaximized + nExtraDamage;
+        // * if low or normal difficulty then MAXMIZED is doubled.
+        if(GetIsPC(OBJECT_SELF) && GetGameDifficulty() < GAME_DIFFICULTY_CORE_RULES)
+        {
+            nDamage = nDamage + nExtraDamage;
+        }
+    }
+    if (nMetaMagic & METAMAGIC_EMPOWER || GetHasFeat(FEAT_HEALING_DOMAIN_POWER))
+    {
+        nDamage = nDamage + (nDamage/2);
+    }
+
+
+    if (MyPRCGetRacialType(oTarget) != RACIAL_TYPE_UNDEAD)
+    {
+        //Figure out the amount of damage to heal
+        nHeal = nDamage;
+        //Set the heal effect
+        eHeal = EffectHeal(nHeal);
+        //Apply heal effect and VFX impact
+        SPApplyEffectToObject(DURATION_TYPE_INSTANT, eHeal, oTarget);
+        SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget);
+        //Fire cast spell at event for the specified target
+        SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellID, FALSE));
+
+
+    }
+    //Check that the target is undead
+    else
+    {
+        int nTouch = PRCDoMeleeTouchAttack(oTarget);;
+        if (nTouch > 0)
+        {
+            if(!GetIsReactionTypeFriendly(oTarget))
+            {
+                //Fire cast spell at event for the specified target
+                SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, nSpellID));
+                if (!PRCDoResistSpell(OBJECT_SELF, oTarget,nCasterLvl+add_spl_pen(OBJECT_SELF)))
+                {
+                    eDam = EffectDamage(nDamage,DAMAGE_TYPE_NEGATIVE);
+                    //Apply the VFX impact and effects
+                    DelayCommand(1.0, SPApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget));
+                    SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
+                }
+            }
+        }
+    }
+}
+*/
+////////////////End Soldier of Light Spells//////////////////
+
+////////////////Begin Master Harper Instruments//////////////////
+
+void ActiveModeCIMM(object oTarget)
+{
+    if(!GetLocalInt(oTarget,"use_CIMM") )
+    {
+    string sScript =  GetModuleOverrideSpellscript();
+    if (sScript != "mh_spell_at_inst")
+    {
+        SetLocalString(OBJECT_SELF,"temp_spell_at_inst",sScript);
+        SetLocalString(OBJECT_SELF, "PRC_OVERRIDE_SPELLSCRIPT", "mh_spell_at_inst");
+    }
+    SetLocalInt(OBJECT_SELF,"nb_spell_at_inst",GetLocalInt(OBJECT_SELF,"nb_spell_at_inst")+1);
+    FloatingTextStrRefOnCreature(16825240,oTarget);
+    SetLocalInt(oTarget,"use_CIMM",TRUE);
+    }
+}
+
+void UnactiveModeCIMM(object oTarget)
+{
+    if(GetLocalInt(oTarget,"use_CIMM") )
+    {
+    string sScript =  GetModuleOverrideSpellscript();
+    SetLocalInt(OBJECT_SELF,"nb_spell_at_inst",GetLocalInt(OBJECT_SELF,"nb_spell_at_inst")-1);
+    if (sScript == "mh_spell_at_inst" && GetLocalInt(OBJECT_SELF,"nb_spell_at_inst") == 0)
+    {
+        SetLocalString(OBJECT_SELF, "PRC_OVERRIDE_SPELLSCRIPT", GetLocalString(OBJECT_SELF,"temp_spell_at_inst"));
+        GetLocalString(OBJECT_SELF,"temp_spell_at_inst");
+        SetLocalString(OBJECT_SELF,"temp_spell_at_inst","");
+    }
+    FloatingTextStrRefOnCreature(16825241,oTarget);
+    SetLocalInt(oTarget,"use_CIMM",FALSE);
+    }
+}
+
+////////////////End Master Harper Instruments//////////////////
+
+////////////////Begin Minstrel of the Edge//////////////////
+
+// Goes a bit further than RemoveSpellEffects -- makes sure to remove ALL effects
+// made by the Singer+Song.
+void RemoveSongEffects(int iSong, object oCaster, object oTarget)
+{
+    effect eCheck = GetFirstEffect(oTarget);
+    while (GetIsEffectValid(eCheck))
+    {
+        if (GetEffectCreator(eCheck) == oCaster && GetEffectSpellId(eCheck) == iSong)
+            RemoveEffect(oTarget, eCheck);
+        eCheck = GetNextEffect(oTarget);
+    }
+}
+
+// Stores a Song recipient to the PC as a local variable, and creates a list by using
+// an index variable.
+void StoreSongRecipient(object oRecipient, object oSinger, int iSongID, int iDuration = 0)
+{
+    int iSlot = GetLocalInt(oSinger, "SONG_SLOT");
+    int iIndex = GetLocalInt(oSinger, "SONG_INDEX_" + IntToString(iSlot)) + 1;
+    string sIndex = "SONG_INDEX_" + IntToString(iSlot);
+    string sRecip = "SONG_RECIPIENT_" + IntToString(iIndex) + "_" + IntToString(iSlot);
+    string sSong = "SONG_IN_USE_" + IntToString(iSlot);
+
+    // Store the recipient into the current used slot
+    SetLocalObject(oSinger, sRecip, oRecipient);
+
+    // Store the song information
+    SetLocalInt(oSinger, sSong, iSongID);
+
+    // Store the index of creatures we're on
+    SetLocalInt(oSinger, sIndex, iIndex);
+}
+
+// Removes all effects given by the previous song from all creatures who recieved it.
+// Now allows for two "slots", which means you can perform two songs at a time.
+void RemoveOldSongEffects(object oSinger, int iSongID)
+{
+    object oCreature;
+    int iSlotNow = GetLocalInt(oSinger, "SONG_SLOT");
+    int iSlot;
+    int iNumRecip;
+    int iSongInUse;
+    int iIndex;
+    string sIndex;
+    string sRecip;
+    string sSong;
+
+    if (GetHasFeat(FEAT_MINSTREL_GREATER_MINSTREL_SONG, oSinger))
+    {
+        // If you use the same song twice in a row you
+        // should deal with the same slot again...
+        if (GetLocalInt(oSinger, "SONG_IN_USE_" + IntToString(iSlotNow)) == iSongID)
+            iSlot = iSlotNow;
+        // Otherwise, we should toggle between slot "1" and slot "0"
+        else
+            iSlot = (iSlotNow == 1) ? 0 : 1;
+    }
+    else
+    {
+        iSlot = 0;
+    }
+
+    // Save the toggle we're on for later.
+    SetLocalInt(oSinger, "SONG_SLOT", iSlot);
+
+    // Find the proper variable names based on slot
+    sIndex = "SONG_INDEX_" + IntToString(iSlot);
+    sSong = "SONG_IN_USE_" + IntToString(iSlot);
+
+    // Store the local variables into script variables
+    iNumRecip = GetLocalInt(oSinger, sIndex);
+    iSongInUse = GetLocalInt(oSinger, sSong);
+
+    // Reset the local variables
+    SetLocalInt(oSinger, sIndex, 0);
+    SetLocalInt(oSinger, sSong, 0);
+
+    // Removes any effects from the caster first
+    RemoveSongEffects(iSongInUse, oSinger, oSinger);
+
+    // Removes any effects from the recipients
+    for (iIndex = 1 ; iIndex <= iNumRecip ; iIndex++)
+    {
+       sRecip = "SONG_RECIPIENT_" + IntToString(iIndex) + "_" + IntToString(iSlot);
+       oCreature = GetLocalObject(oSinger, sRecip);
+
+       RemoveSongEffects(iSongInUse, oSinger, oCreature);
+    }
+}
+
+
+////////////////End Minstrel of the Edge//////////////////
+
+////////////////Begin Arcane Duelist//////////////////
+
+void FlurryEffects(object oPC)
+{
+    effect Effect1 = EffectModifyAttacks(1);
+    effect Effect2 = EffectAttackDecrease(2, ATTACK_BONUS_MISC);
+
+    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, Effect1, oPC, RoundsToSeconds(10));
+    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, Effect2, oPC, RoundsToSeconds(10));
+
+}
+
+void CheckCombatDexAttack(object oPC)
+{
+//object oPC = GetLocalObject(OBJECT_SELF, "PC_IN_COMBAT_WITH_DEXATTACK_ON");
+int iCombat = GetIsInCombat(oPC);
+object oWeapon = GetLocalObject(oPC, "CHOSEN_WEAPON");
+
+    if(iCombat == TRUE && GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC) == oWeapon)
+    {
+        DelayCommand(6.0, CheckCombatDexAttack(oPC));
+    }
+    else
+    {
+      FloatingTextStringOnCreature("Dexterous Attack Mode Deactivated", oPC, FALSE);
+         effect eEffects = GetFirstEffect(oPC);
+         while (GetIsEffectValid(eEffects))
+         {
+
+         if (GetEffectType(eEffects) == EFFECT_TYPE_ATTACK_INCREASE && GetEffectSpellId(eEffects) == 1761) // dextrous attack
+            {
+             RemoveEffect(oPC, eEffects);
+            }
+
+         eEffects = GetNextEffect(oPC);
+         }
+      DeleteLocalObject(OBJECT_SELF, "PC_IN_COMBAT_WITH_DEXATTACK_ON");
+    }
+}
+
+void SPMakeAttack(object oTarget, object oImage)
+{
+    int iDead = GetIsDead(oTarget);
+
+    if(iDead == FALSE)
+    {
+     PrintString("TARGET AINT DEAD");
+     DelayCommand(6.0, SPMakeAttack(oTarget, oImage));
+     AssignCommand(oImage, ActionAttack(oTarget, FALSE));
+    }
+    if(iDead == TRUE)
+    {
+    PrintString("TARGET BE DEAD AS A DOORNAIL");
+    DestroyObject(oImage, 0.0);
+    ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3), GetLocation(oImage), 0.0);
+    }
+
+}
+
+////////////////End Arcane Duelist//////////////////
+
+////////////////Begin Corpsecrafter//////////////
+
+void CorpseCrafter(object oPC, object oSummon)
+{
+    // Hijacking this function because it's already in the right places
+    if (GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC) >= 8)
+    {
+        if (DEBUG) DoDebug("Corpsecrafter: Dread Necro");
+        int nHD = GetHitDice(oSummon);
+        effect eHP = EffectTemporaryHitpoints(nHD * 2);
+        effect eStr = EffectAbilityIncrease(ABILITY_STRENGTH, 4);
+        effect eDex = EffectAbilityIncrease(ABILITY_DEXTERITY, 4);
+        eHP = SupernaturalEffect(eHP);
+        eStr = SupernaturalEffect(EffectLinkEffects(eStr, eDex));
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHP, oSummon);
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eStr, oSummon);
+    }
+    if (GetHasFeat(FEAT_CORPSECRAFTER, oPC))
+    {
+        if (DEBUG) DoDebug("Corpsecrafter: Corpsecrafter");
+        int nHD = GetHitDice(oSummon);
+        effect eHP = EffectTemporaryHitpoints(nHD * 2);
+        effect eStr = EffectAbilityIncrease(ABILITY_STRENGTH, 4);
+        eHP = SupernaturalEffect(eHP);
+        eStr = SupernaturalEffect(eStr);
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eHP, oSummon);
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eStr, oSummon);
+    }
+    if (GetHasFeat(FEAT_BOLSTER_RESISTANCE, oPC))
+    {
+        if (DEBUG) DoDebug("Corpsecrafter: Bolster Resistance");
+        effect eTurn = EffectTurnResistanceIncrease(4);
+        eTurn = SupernaturalEffect(eTurn);
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eTurn, oSummon);
+    }
+    if (GetHasFeat(FEAT_DEADLY_CHILL, oPC))
+    {
+        if (DEBUG) DoDebug("Corpsecrafter: Deadly Chill");
+        effect eChill = EffectDamageIncrease(DAMAGE_BONUS_1d6, DAMAGE_TYPE_COLD);
+        eChill = SupernaturalEffect(eChill);
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eChill, oSummon);
+    }
+    if (GetHasFeat(FEAT_HARDENED_FLESH, oPC))
+    {
+        if (DEBUG) DoDebug("Corpsecrafter: Hardened Flesh");
+        effect eAC = EffectACIncrease(2);
+        eAC = SupernaturalEffect(eAC);
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eAC, oSummon);
+    }
+    if (GetHasFeat(FEAT_NIMBLE_BONES, oPC))
+    {
+        if (DEBUG) DoDebug("Corpsecrafter: Nimble Bones");
+        object oSkin = GetPCSkin(oPC);
+        itemproperty iInit = PRCItemPropertyBonusFeat(IP_CONST_FEAT_IMPROVED_INIT);
+        //AddItemProperty(DURATION_TYPE_PERMANENT, iInit, oSkin);
+        IPSafeAddItemProperty(oSkin, iInit, 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+
+        // Speed boost, average speed is 30 feet, so a 10 foot boost is a 33% boost
+        effect eSpeed = EffectMovementSpeedIncrease(33);
+        eSpeed = SupernaturalEffect(eSpeed);
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSpeed, oSummon);
+    }
+    if (GetHasFeat(FEAT_DESTRUCTION_RETRIBUTION, oPC))
+    {
+        if (DEBUG) DoDebug("Corpsecrafter: Destruction Retribution");
+        SetLocalInt(oSummon, "DestructionRetribution", TRUE);
+    }
+}
+
+////////////////Begin Ninja//////////////
+
+void Ninja_DecrementKi (object oPC, int iExcept = -1)
+{
+    if (iExcept != FEAT_KI_POWER)
+        DecrementRemainingFeatUses(oPC, FEAT_KI_POWER);
+    if (iExcept != FEAT_GHOST_STEP)
+        DecrementRemainingFeatUses(oPC, FEAT_GHOST_STEP);
+    if (iExcept != FEAT_GHOST_STRIKE)
+        DecrementRemainingFeatUses(oPC, FEAT_GHOST_STRIKE);
+    if (iExcept != FEAT_GHOST_WALK)
+        DecrementRemainingFeatUses(oPC, FEAT_GHOST_WALK);
+    if (iExcept != FEAT_KI_DODGE)
+        DecrementRemainingFeatUses(oPC, FEAT_KI_DODGE);
+    // for testing only
+    SetLocalInt(oPC, "prc_ninja_ki", GetLocalInt(oPC, "prc_ninja_ki") - 1);
+    ExecuteScript("prc_ninjca", oPC);
+}
+
+int Ninja_AbilitiesEnabled (object oPC)
+{
+    object oLefthand = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
+
+    if (GetBaseAC(GetItemInSlot(INVENTORY_SLOT_CHEST, oPC)) > 0 ||
+        GetBaseItemType(oLefthand) == BASE_ITEM_SMALLSHIELD ||
+        GetBaseItemType(oLefthand) == BASE_ITEM_LARGESHIELD ||
+        GetBaseItemType(oLefthand) == BASE_ITEM_TOWERSHIELD)
+        return FALSE;
+    // all Ki powers will not function when encumbered
+    if (GetIsEncumbered(oPC))
+        return FALSE;
+    return TRUE;
+}
+
+////////////////End Ninja//////////////
+
+////////////////Begin Virtuoso//////////////
+
+//Decrements the daily uses of Virtuoso Performance by the
+//  correct amount, returns FALSE if there are insufficient
+//  uses remaining to use the current feat
+int VirtuosoPerformanceDecrement(object oPC, int nSpellID)
+{
+    int nDecrement = 0;
+    int nDifference = 1122; //hack, difference in number between feat and spell 2da lines
+    switch(nSpellID)
+    {
+        case SPELL_VIRTUOSO_SUSTAINING_SONG:
+        case SPELL_VIRTUOSO_CALUMNY:
+        case SPELL_VIRTUOSO_GREATER_CALUMNY: nDecrement = 1; break;
+
+        case SPELL_VIRTUOSO_MINDBENDING_MELODY:
+        case SPELL_VIRTUOSO_MAGICAL_MELODY:
+        case SPELL_VIRTUOSO_REVEALING_MELODY: nDecrement = 2; break;
+
+        case SPELL_VIRTUOSO_SHARP_NOTE:
+        case SPELL_VIRTUOSO_JARRING_SONG:
+        case SPELL_VIRTUOSO_SONG_OF_FURY: nDecrement = 3; break;
+    }
+    if(!nDecrement) return FALSE;   //sanity check
+    int nUses = GetPersistantLocalInt(oPC, "Virtuoso_Performance_Uses");
+    if(nUses >= nDecrement)
+    {
+        SetPersistantLocalInt(oPC, "Virtuoso_Performance_Uses", nUses - nDecrement);
+        int nFeat, nDec;
+        for(nFeat = FEAT_VIRTUOSO_SUSTAINING_SONG; nFeat <= FEAT_VIRTUOSO_PERFORMANCE; nFeat++)
+        {
+            nDec = nDecrement;
+            if(nFeat == (nSpellID + nDifference))
+                nDec--; //already decremented once by being used
+            for(; nDec > 0; nDec--)
+                DecrementRemainingFeatUses(oPC, nFeat);
+        }
+        return TRUE;
+    }
+    else
+    {   //refund feat use :P
+        IncrementRemainingFeatUses(oPC, nSpellID + nDifference);
+        return FALSE;
+    }
+}
+
+////////////////End Virtuoso//////////////
+
+
+///////////////Archmage & Heirophant SLAs ///////////
+
+void DoArchmageHeirophantSLA(object oPC, object oTarget, location lTarget, int nSLAID)
+{
+    int nSLAFeatID = -1; //feat  ID of the SLA in use
+    int nSLASpellID = -1;//spell ID of the SLA in use NOT THE SPELL BEING CAST
+    //get the SLAFeatID
+    int SLA_ID;
+    switch(SLA_ID)
+    {
+        case 1: nSLAFeatID = FEAT_SPELL_LIKE_ABILITY_1; break;
+        case 2: nSLAFeatID = FEAT_SPELL_LIKE_ABILITY_2; break;
+        case 3: nSLAFeatID = FEAT_SPELL_LIKE_ABILITY_3; break;
+        case 4: nSLAFeatID = FEAT_SPELL_LIKE_ABILITY_4; break;
+        case 5: nSLAFeatID = FEAT_SPELL_LIKE_ABILITY_5; break;
+    }
+    //get the spellID of the spell your trying to cast
+    //+1 offset for unassigned
+    int nSpellID = GetPersistantLocalInt(oPC, "PRC_SLA_SpellID_"+IntToString(nSLAID))-1;
+    //test if already stored
+    if(nSpellID == -1)
+    {
+        //not stored
+        FloatingTextStringOnCreature("This SLA has not been stored yet\nThe next spell you cast will be assigned to this SLA", oPC);
+        SetLocalInt(oPC, "PRC_SLA_Store", nSLAID);
+        DelayCommand(18.0,
+            DeleteLocalInt(oPC, "PRC_SLA_Store"));
+        return;
+    }
+    else
+    {
+        //stored, recast it
+        int nSpellClass = GetPersistantLocalInt(oPC, "PRC_SLA_Class_"+IntToString(nSLAID));
+        int nMetamagic  = GetPersistantLocalInt(oPC, "PRC_SLA_Meta_"+IntToString(nSLAID));
+        int nSpellLevel = PRCGetSpellLevelForClass(nSpellID, nSpellClass);
+        int nBaseDC     = 10 + nSpellLevel + GetDCAbilityModForClass(nSpellClass, oPC);
+        //since this is targetted using a generic feat,
+        //make sure were within range and target is valid for this spell
+        //get current distance
+        /*string sRange = Get2DACache("spells", "Range", nSpellID);
+        float fDist;
+        if(GetIsObjectValid(oTarget))
+             fDist = GetDistanceToObject(oTarget);
+        else
+             fDist = GetDistanceBetweenLocations(GetLocation(oPC), lTarget);
+        //check distance is allowed
+        if(fDist < 0.0
+            || (sRange == "T" && fDist >  2.25)
+            || (sRange == "S" && fDist >  8.0 )
+            || (sRange == "M" && fDist > 20.0 )
+            || (sRange == "L" && fDist > 40.0 )
+            )
+        {
+            //out of range
+            FloatingTextStringOnCreature("You are out of range", oPC);
+            //replace the useage
+            IncrementRemainingFeatUses(oPC, nSLAFeatID);
+            //end the script
+            return;
+        }*/
+        //check object type
+        int nTargetType = HexToInt(Get2DACache("spells", "TargetType", nSpellID));
+        /*
+        # 0x01 = 1 = Self
+        # 0x02 = 2 = Creature
+        # 0x04 = 4 = Area/Ground
+        # 0x08 = 8 = Items
+        # 0x10 = 16 = Doors
+        # 0x20 = 32 = Placeables
+        */
+        int nCaster     = nTargetType &  1;
+        int nCreature   = nTargetType &  2;
+        int nLocation   = nTargetType &  4;
+        int nItem       = nTargetType &  8;
+        int nDoor       = nTargetType & 16;
+        int nPlaceable  = nTargetType & 32;
+        int nTargetValid = TRUE;
+        //test targetting self
+        if(oTarget == OBJECT_SELF)
+        {
+            if(!nCaster)
+            {
+                nTargetValid = FALSE;
+                FloatingTextStringOnCreature("You cannot target yourself", oPC);
+            }
+        }
+        //test targetting others
+        else if(GetIsObjectValid(oTarget))
+        {
+            switch(GetObjectType(oTarget))
+            {
+                case OBJECT_TYPE_CREATURE:
+                    if(!nCreature)
+                    {
+                        nTargetValid = FALSE;
+                        FloatingTextStringOnCreature("You cannot target creatures", oPC);
+                    }
+                    break;
+                case OBJECT_TYPE_ITEM:
+                    if(!nItem)
+                    {
+                        nTargetValid = FALSE;
+                        FloatingTextStringOnCreature("You cannot target items", oPC);
+                    }
+                    break;
+                case OBJECT_TYPE_DOOR:
+                    if(!nDoor)
+                    {
+                        nTargetValid = FALSE;
+                        FloatingTextStringOnCreature("You cannot target doors", oPC);
+                    }
+                    break;
+                case OBJECT_TYPE_PLACEABLE:
+                    if(!nPlaceable)
+                    {
+                        nTargetValid = FALSE;
+                        FloatingTextStringOnCreature("You cannot target placeables", oPC);
+                    }
+                    break;
+            }
+        }
+        //test if can target a location
+        else if(GetIsObjectValid(GetAreaFromLocation(lTarget)))
+        {
+            if(!nLocation)
+            {
+                nTargetValid = FALSE;
+                FloatingTextStringOnCreature("You cannot target locations", oPC);
+            }
+        }
+        //target was not valid, abort
+        if(!nTargetValid)
+        {
+            //replace the useage
+            IncrementRemainingFeatUses(oPC, nSLAFeatID);
+            //end the script
+            return;
+        }
+        //actually cast it at this point
+        //note that these are instant-spells, so we have to add the animation part too
+        /*if(GetIsObjectValid(oTarget))
+            ActionCastFakeSpellAtObject(nSpellID, oTarget);
+        else
+            ActionCastFakeSpellAtLocation(nSpellID, lTarget);*/
+        ActionDoCommand(ActionCastSpell(nSpellID, 0, nBaseDC, 0, nMetamagic, nSpellClass, 0, 0, OBJECT_INVALID, FALSE));
+    }
+}
+
+/////////////// End Archmage & Heirophant SLAs ///////////
+
+////////////////////////Alienist//////////////////////////
+int GetPhobia(object oPC)
+{
+    int nPhobia = GetPersistantLocalInt(oPC, "Alienist_Phobia");
+    if(nPhobia < 1)
+    {
+        nPhobia = Random(16) + 1;
+        SetPersistantLocalInt(oPC, "Alienist_Phobia", nPhobia);
+    }
+    return nPhobia;
+}
+
+int GetPhobiaRace(int nPhobia)
+{
+    switch(nPhobia)
+    {
+        case  1: return RACIAL_TYPE_ABERRATION;
+        case  2: return RACIAL_TYPE_ANIMAL;
+        case  3: return RACIAL_TYPE_BEAST;
+        case  4: return RACIAL_TYPE_CONSTRUCT;
+        case  5: return RACIAL_TYPE_DRAGON;
+        case  6: return RACIAL_TYPE_HUMANOID_GOBLINOID;
+        case  7: return RACIAL_TYPE_HUMANOID_MONSTROUS;
+        case  8: return RACIAL_TYPE_HUMANOID_ORC;
+        case  9: return RACIAL_TYPE_HUMANOID_REPTILIAN;
+        case 10: return RACIAL_TYPE_ELEMENTAL;
+        case 11: return RACIAL_TYPE_FEY;
+        case 12: return RACIAL_TYPE_GIANT;
+        case 13: return RACIAL_TYPE_MAGICAL_BEAST;
+        case 14: return RACIAL_TYPE_SHAPECHANGER;
+        case 15: return RACIAL_TYPE_UNDEAD;
+        case 16: return RACIAL_TYPE_VERMIN;
+    }
+    return -1;//error
+}
+
+int GetPhobiaFeat(int nPhobia)
+{
+    switch(nPhobia)
+    {
+        case  1: return IP_CONST_PHOBIA_ABERRATION;
+        case  2: return IP_CONST_PHOBIA_ANIMAL;
+        case  3: return IP_CONST_PHOBIA_BEAST;
+        case  4: return IP_CONST_PHOBIA_CONSTRUCT;
+        case  5: return IP_CONST_PHOBIA_DRAGON;
+        case  6: return IP_CONST_PHOBIA_GOBLINOID;
+        case  7: return IP_CONST_PHOBIA_MONSTROUS;
+        case  8: return IP_CONST_PHOBIA_ORC;
+        case  9: return IP_CONST_PHOBIA_REPTILIAN;
+        case 10: return IP_CONST_PHOBIA_ELEMENTAL;
+        case 11: return IP_CONST_PHOBIA_FEY;
+        case 12: return IP_CONST_PHOBIA_GIANT;
+        case 13: return IP_CONST_PHOBIA_MAGICAL_BEAST;
+        case 14: return IP_CONST_PHOBIA_SHAPECHANGER;
+        case 15: return IP_CONST_PHOBIA_UNDEAD;
+        case 16: return IP_CONST_PHOBIA_VERMIN;
+    }
+    return -1;//error
+}
+
+/////////////////////DragonSong Lyrist////////////////////////
+
+void RemoveOldSongs(object oPC)
+{
+   if(GetHasSpellEffect(SPELL_DSL_SONG_STRENGTH, oPC))   PRCRemoveEffectsFromSpell(oPC, SPELL_DSL_SONG_STRENGTH);
+   if(GetHasSpellEffect(SPELL_DSL_SONG_COMPULSION, oPC)) PRCRemoveEffectsFromSpell(oPC, SPELL_DSL_SONG_COMPULSION);
+   if(GetHasSpellEffect(SPELL_DSL_SONG_SPEED, oPC))      PRCRemoveEffectsFromSpell(oPC, SPELL_DSL_SONG_SPEED);
+   if(GetHasSpellEffect(SPELL_DSL_SONG_FEAR, oPC))       PRCRemoveEffectsFromSpell(oPC, SPELL_DSL_SONG_FEAR);
+   if(GetHasSpellEffect(SPELL_DSL_SONG_HEALING, oPC))    PRCRemoveEffectsFromSpell(oPC, SPELL_DSL_SONG_HEALING);
+}
+
+
+// Eldritch Theurge class requires arcane spellcasting and eldritch blast.
+// If a character is an Eldritch Theruge we know that she must have levels in Warlock
+// since in NWN character can have max 3 classes. We also know that Eldritch Theurge
+// is at positon 3 (unless player is cheating).
+// So we just need to check the third class.
+
+//:: [PRC .35] This function will require marker feats
+int GetETArcaneClass(object oPC)
+{
+    int nClass = GetClassByPosition(1, oPC);
+    if(nClass == CLASS_TYPE_WARLOCK)
+        nClass = GetClassByPosition(2, oPC);
+    return nClass;
+}
+
diff --git a/trunk/include/prc_inc_core.nss b/trunk/include/prc_inc_core.nss
new file mode 100644
index 00000000..3ab2def1
--- /dev/null
+++ b/trunk/include/prc_inc_core.nss
@@ -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");
+}
+
diff --git a/trunk/include/prc_inc_domain.nss b/trunk/include/prc_inc_domain.nss
new file mode 100644
index 00000000..d0709086
--- /dev/null
+++ b/trunk/include/prc_inc_domain.nss
@@ -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);
+}
\ No newline at end of file
diff --git a/trunk/include/prc_inc_function.nss b/trunk/include/prc_inc_function.nss
new file mode 100644
index 00000000..2fa5d15c
--- /dev/null
+++ b/trunk/include/prc_inc_function.nss
@@ -0,0 +1,1837 @@
+//::///////////////////////////////////////////////
+//:: [PRC Feat Router]
+//:: [inc_prc_function.nss]
+//:://////////////////////////////////////////////
+//:: This file serves as a hub for the various
+//:: PRC passive feat functions.  If you need to
+//:: add passive feats for a new PRC, link them here.
+//::
+//:: This file also contains a few multi-purpose
+//:: PRC functions that need to be included in several
+//:: places, ON DIFFERENT PRCS. Make local include files
+//:: for any functions you use ONLY on ONE PRC.
+//:://////////////////////////////////////////////
+//:: Created By: Aaon Graywolf
+//:: Created On: Dec 19, 2003
+//:://////////////////////////////////////////////
+
+//:: Updated for .35 by Jaysyn 2023/03/10
+
+//--------------------------------------------------------------------------
+// This is the "event" that is called to re-evalutate PRC bonuses.  Currently
+// it is fired by OnEquip, OnUnequip and OnLevel.  If you want to move any
+// classes into this event, just copy the format below.  Basically, this function
+// is meant to keep the code looking nice and clean by routing each class's
+// feats to their own self-contained script
+//--------------------------------------------------------------------------
+
+//:: Test Void
+//void main (){}
+
+
+//////////////////////////////////////////////////
+/*                 Constants                    */
+//////////////////////////////////////////////////
+
+const int TEMPLATE_SLA_START = 16304;
+const int TEMPLATE_SLA_END   = 16400;
+
+const string PRC_ScrubPCSkin_Generation = "PRC_ScrubPCSkin_Generation";
+const string PRC_EvalPRCFeats_Generation = "PRC_EvalPRCFeats_Generation";
+
+
+//////////////////////////////////////////////////
+/*             Function prototypes              */
+//////////////////////////////////////////////////
+
+void EvalPRCFeats(object oPC);
+
+int BlastInfidelOrFaithHeal(object oCaster, object oTarget, int iEnergyType, int iDisplayFeedback);
+
+void ScrubPCSkin(object oPC, object oSkin);
+
+void DeletePRCLocalInts(object oSkin);
+
+void DelayedAddIPFeats(int nExpectedGeneration, object oPC);
+
+void DelayedReApplyUnhealableAbilityDamage(int nExpectedGeneration, object oPC);
+
+int nbWeaponFocus(object oPC);
+
+//////////////////////////////////////////////////
+/*                  Includes                    */
+//////////////////////////////////////////////////
+
+// Minimalist includes
+#include "prc_inc_util"
+#include "prc_inc_spells"
+#include "prc_inc_stunfist"
+#include "inc_nwnx_funcs"
+#include "prc_template_con"
+
+//////////////////////////////////////////////////
+/*             Function definitions             */
+//////////////////////////////////////////////////
+
+void DeleteCharacterData(object oPC)
+{
+    DeletePersistantLocalString(oPC, "PRC_Class_Script1");
+    DeletePersistantLocalString(oPC, "PRC_Class_Script2");
+    DeletePersistantLocalString(oPC, "PRC_Class_Script3");
+	DeletePersistantLocalString(oPC, "PRC_Class_Script4");
+	DeletePersistantLocalString(oPC, "PRC_Class_Script5");
+	DeletePersistantLocalString(oPC, "PRC_Class_Script6");
+	DeletePersistantLocalString(oPC, "PRC_Class_Script7");
+	DeletePersistantLocalString(oPC, "PRC_Class_Script8");
+    DeletePersistantLocalInt(oPC, "PRC_Class_Data");
+}
+
+void SetupCharacterData(object oPC)
+{
+    // iData format:
+    // 0x01 - run alternate magic system setup
+    // 0x02 - add new metamagic feats for spontaneous casters
+    // 0x04 - run reduced arcane spell failure check
+    // use bitwise to combine flags
+
+    int i, iData, iShifting;
+    for(i = 1; i <= 8; i++)
+    {
+        int nClassType = GetClassByPosition(i, oPC);
+        if(nClassType != CLASS_TYPE_INVALID)
+        {
+            string sScript;
+            switch(nClassType)
+            {
+                case CLASS_TYPE_ABJURANT_CHAMPION:     sScript = "prc_abchamp";                     break;			
+                case CLASS_TYPE_ACOLYTE:               sScript = "prc_acolyte";                     break;
+                case CLASS_TYPE_ALIENIST:              sScript = "prc_alienist";                    break;
+                case CLASS_TYPE_ARCANE_DUELIST:        sScript = "prc_arcduel";                     break;
+                case CLASS_TYPE_ARCHIVIST:             sScript = "prc_archivist";    iData |= 0x01; break;
+                case CLASS_TYPE_ASSASSIN:                                            iData |= 0x03; break;
+                case CLASS_TYPE_BAELNORN:              sScript = "prc_baelnorn";                    break;
+                case CLASS_TYPE_BARD:                                                iData |= 0x07; break;
+                case CLASS_TYPE_BATTLESMITH:           sScript = "prc_battlesmith";                 break;
+                case CLASS_TYPE_BEGUILER:                                            iData |= 0x03; break;
+                case CLASS_TYPE_BINDER:                sScript = "bnd_binder";                      break;
+                case CLASS_TYPE_BFZ:                   sScript = "prc_bfz";                         break;
+                case CLASS_TYPE_BLACK_BLOOD_CULTIST:   sScript = "prc_bbc";                         break;
+                case CLASS_TYPE_BLACKGUARD:            sScript = "prc_blackguard";                  break;
+                case CLASS_TYPE_BLADESINGER:           sScript = "prc_bladesinger";  iData |= 0x04; break;
+                case CLASS_TYPE_BLIGHTLORD:            sScript = "prc_blightlord";                  break;
+                case CLASS_TYPE_BLOODCLAW_MASTER:      sScript = "tob_bloodclaw";                   break;
+                case CLASS_TYPE_BONDED_SUMMONNER:      sScript = "prc_bondedsumm";                  break;
+                case CLASS_TYPE_CELEBRANT_SHARESS:                                   iData |= 0x03; break;
+                case CLASS_TYPE_CHILD_OF_NIGHT:        sScript = "shd_childnight";                  break;
+                case CLASS_TYPE_COC:                   sScript = "prc_coc";                         break;
+                case CLASS_TYPE_COMBAT_MEDIC:          sScript = "prc_cbtmed";                      break;
+                case CLASS_TYPE_CONTEMPLATIVE:         sScript = "prc_contemplate";                 break;
+                case CLASS_TYPE_CRUSADER:              sScript = "tob_crusader";     iData |= 0x01; break;
+                case CLASS_TYPE_CULTIST_SHATTERED_PEAK: sScript = "prc_shatterdpeak";               break;
+                case CLASS_TYPE_CW_SAMURAI:            sScript = "prc_cwsamurai";                   break;
+                case CLASS_TYPE_DEEPSTONE_SENTINEL:    sScript = "tob_deepstone";                   break;
+                case CLASS_TYPE_DIAMOND_DRAGON:        sScript = "psi_diadra";                      break;
+                case CLASS_TYPE_DISC_BAALZEBUL:        sScript = "prc_baalzebul";                   break;
+                case CLASS_TYPE_DISCIPLE_OF_ASMODEUS:  sScript = "prc_discasmodeus";                break;
+                case CLASS_TYPE_DISCIPLE_OF_MEPH:      sScript = "prc_discmeph";                    break;
+                case CLASS_TYPE_DISPATER:              sScript = "prc_dispater";                    break;
+                case CLASS_TYPE_DRAGON_DEVOTEE:        sScript = "prc_dragdev";                     break;
+                case CLASS_TYPE_DRAGON_DISCIPLE:       sScript = "prc_dradis";                      break;
+                case CLASS_TYPE_DRAGON_SHAMAN:         sScript = "prc_dragonshaman";                break;
+                case CLASS_TYPE_DRAGONFIRE_ADEPT:      sScript = "inv_drgnfireadpt"; iData |= 0x01; break;
+                case CLASS_TYPE_DREAD_NECROMANCER:     sScript = "prc_dreadnecro";   iData |= 0x03; break;
+                case CLASS_TYPE_DRUID:                                            iShifting = TRUE; break;
+                case CLASS_TYPE_DRUNKEN_MASTER:        sScript = "prc_drunk";                       break;
+                case CLASS_TYPE_DUELIST:               sScript = "prc_duelist";                     break;
+                case CLASS_TYPE_DUSKBLADE:             sScript = "prc_duskblade";    iData |= 0x03; break;
+                case CLASS_TYPE_ENLIGHTENEDFIST:       sScript = "prc_enlfis";                      break;
+                case CLASS_TYPE_ELEMENTAL_SAVANT:      sScript = "prc_elemsavant";                  break;
+                case CLASS_TYPE_ETERNAL_BLADE:         sScript = "tob_eternalblade";                break;
+                case CLASS_TYPE_FACTOTUM:              sScript = "prc_factotum";                    break;
+                case CLASS_TYPE_FAVOURED_SOUL:         sScript = "prc_favouredsoul"; iData |= 0x03; break;
+                case CLASS_TYPE_FIST_OF_ZUOKEN:        sScript = "psi_zuoken";       iData |= 0x01; break;
+                case CLASS_TYPE_FOE_HUNTER:            sScript = "prc_foe_hntr";                    break;
+				case CLASS_TYPE_FORESTMASTER:		   sScript = "prc_forestmaster";				break;
+                case CLASS_TYPE_FORSAKER:              sScript = "prc_forsaker";                    break;
+                case CLASS_TYPE_FRE_BERSERKER:         sScript = "prc_frebzk";                      break;
+                case CLASS_TYPE_FROSTRAGER:            sScript = "prc_frostrager";                  break;
+                case CLASS_TYPE_FROST_MAGE:            sScript = "prc_frostmage";                   break;
+                case CLASS_TYPE_HALFLING_WARSLINGER:   sScript = "prc_warsling";                    break;
+                case CLASS_TYPE_HARPER:                                              iData |= 0x03; break;
+                case CLASS_TYPE_HEARTWARDER:           sScript = "prc_heartwarder";                 break;
+                case CLASS_TYPE_HENSHIN_MYSTIC:        sScript = "prc_henshin";                     break;
+                case CLASS_TYPE_HEXBLADE:                                            iData |= 0x03; break;
+                case CLASS_TYPE_HEXTOR:                sScript = "prc_hextor";                      break;
+                case CLASS_TYPE_IAIJUTSU_MASTER:       sScript = "prc_iaijutsu_mst";                break;
+                case CLASS_TYPE_INCARNATE:             sScript = "moi_incarnate";                   break;
+                case CLASS_TYPE_INCARNUM_BLADE:        sScript = "moi_iblade";                      break;
+                case CLASS_TYPE_INITIATE_DRACONIC:     sScript = "prc_initdraconic";                break;
+                case CLASS_TYPE_IRONMIND:              sScript = "psi_ironmind";                    break;
+                case CLASS_TYPE_IRONSOUL_FORGEMASTER:  sScript = "moi_ironsoul";                    break;
+                case CLASS_TYPE_JADE_PHOENIX_MAGE:     sScript = "tob_jadephoenix";                 break;
+                case CLASS_TYPE_JUDICATOR:             sScript = "prc_judicator";                   break;
+                case CLASS_TYPE_JUSTICEWW:                                           iData |= 0x03; break;
+                case CLASS_TYPE_KNIGHT:                sScript = "prc_knight";                      break;
+                case CLASS_TYPE_KNIGHT_CHALICE:        sScript = "prc_knghtch";                     break;
+                case CLASS_TYPE_KNIGHT_WEAVE:                                        iData |= 0x03; break;
+				case CLASS_TYPE_KNIGHT_SACRED_SEAL:    sScript = "bnd_kss";                         break;
+                case CLASS_TYPE_LASHER:                sScript = "prc_lasher";                      break;
+                case CLASS_TYPE_LEGENDARY_DREADNOUGHT: sScript = "prc_legendread";                  break;
+                case CLASS_TYPE_LICH:                  sScript = "pnp_lich_level";                  break;
+                case CLASS_TYPE_MAGEKILLER:            sScript = "prc_magekill";                    break;
+                case CLASS_TYPE_MASTER_HARPER:         sScript = "prc_masterh";                     break;
+                case CLASS_TYPE_MASTER_OF_NINE:        sScript = "tob_masterofnine";                break;
+                case CLASS_TYPE_MASTER_OF_SHADOW:      sScript = "shd_mastershadow";                break;
+                case CLASS_TYPE_MIGHTY_CONTENDER_KORD: sScript = "prc_contendkord";                 break;
+                case CLASS_TYPE_MORNINGLORD:           sScript = "prc_morninglord";                 break;
+                case CLASS_TYPE_NIGHTSHADE:            sScript = "prc_nightshade";                  break;
+                case CLASS_TYPE_NINJA:                 sScript = "prc_ninjca";                      break;
+                case CLASS_TYPE_OLLAM:                 sScript = "prc_ollam";                       break;
+                case CLASS_TYPE_OOZEMASTER:            sScript = "prc_oozemstr";                    break;
+                case CLASS_TYPE_ORDER_BOW_INITIATE:    sScript = "prc_ootbi";                       break;
+                case CLASS_TYPE_PEERLESS:              sScript = "prc_peerless";                    break;
+                case CLASS_TYPE_PNP_SHIFTER :                                     iShifting = TRUE; break;
+                case CLASS_TYPE_PRC_EYE_OF_GRUUMSH:    sScript = "prc_eog";                         break;
+                case CLASS_TYPE_PSION:                                               iData |= 0x01; break;
+                case CLASS_TYPE_PSYWAR:                                              iData |= 0x01; break;
+                case CLASS_TYPE_PSYCHIC_ROGUE:         sScript = "psi_psyrogue";     iData |= 0x01; break;
+                case CLASS_TYPE_PYROKINETICIST:        sScript = "psi_pyro";                        break;
+                case CLASS_TYPE_RAGE_MAGE:                                           iData |= 0x04; break;
+                case CLASS_TYPE_REAPING_MAULER :       sScript = "prc_reapmauler";                  break;
+                case CLASS_TYPE_RUBY_VINDICATOR:       sScript = "tob_rubyknight";                  break;
+                case CLASS_TYPE_RUNESCARRED:           sScript = "prc_runescarred";                 break;
+                case CLASS_TYPE_SACREDFIST:            sScript = "prc_sacredfist";                  break;
+                case CLASS_TYPE_SANCTIFIED_MIND:       sScript = "psi_sancmind";                    break;
+                case CLASS_TYPE_SAPPHIRE_HIERARCH:     sScript = "moi_sapphire";                    break;
+                case CLASS_TYPE_SCOUT:                 sScript = "prc_scout";                       break;
+                case CLASS_TYPE_SERENE_GUARDIAN:       sScript = "prc_sereneguard";                 break;
+                case CLASS_TYPE_SHADOW_ADEPT:          sScript = "prc_shadowadept";                 break;
+                case CLASS_TYPE_SHADOWCASTER:          sScript = "shd_shadowcaster"; iData |= 0x01; break;
+                case CLASS_TYPE_SHADOWSMITH:                                         iData |= 0x01; break;
+                case CLASS_TYPE_SHADOW_SUN_NINJA:      sScript = "tob_shadowsun";                   break;
+                case CLASS_TYPE_SHADOWBLADE:           sScript = "prc_sb_shdstlth";                 break;
+                case CLASS_TYPE_SHADOWMIND:            sScript = "psi_shadowmind";                  break;
+                case CLASS_TYPE_SHADOWBANE_STALKER:    sScript = "prc_shadstalker";                 break;
+                case CLASS_TYPE_SHADOW_THIEF_AMN:      sScript = "prc_amn";                         break;
+                case CLASS_TYPE_SHAMAN:                sScript = "prc_shaman";                      break;
+                case CLASS_TYPE_SHINING_BLADE:         sScript = "prc_sbheir";                      break;
+                case CLASS_TYPE_SHOU:                  sScript = "prc_shou";                        break;
+                case CLASS_TYPE_SKULLCLAN_HUNTER:      sScript = "prc_skullclan";                   break;
+                case CLASS_TYPE_SLAYER_OF_DOMIEL:      sScript = "prc_slayerdomiel";                break;
+                case CLASS_TYPE_SOHEI:                 sScript = "prc_sohei";                       break;
+                case CLASS_TYPE_SOLDIER_OF_LIGHT:      sScript = "prc_soldoflight";                 break;
+                case CLASS_TYPE_SORCERER:                                            iData |= 0x03; break;
+                case CLASS_TYPE_SOULBORN:              sScript = "moi_soulborn";                    break;
+                case CLASS_TYPE_SOUL_EATER:                                       iShifting = TRUE; break;
+                case CLASS_TYPE_SOULKNIFE:             sScript = "psi_sk_clseval";                  break;
+                case CLASS_TYPE_SPELLSWORD:            sScript = "prc_spellswd";     iData |= 0x04; break;
+                case CLASS_TYPE_SPINEMELD_WARRIOR:     sScript = "moi_spinemeld";                   break;
+                case CLASS_TYPE_STORMLORD:             sScript = "prc_stormlord";                   break;
+                case CLASS_TYPE_SUBLIME_CHORD:         sScript = "prc_schord";       iData |= 0x03; break;
+                case CLASS_TYPE_SUEL_ARCHANAMACH:                                    iData |= 0x03; break;
+                case CLASS_TYPE_SWASHBUCKLER:          sScript = "prc_swashbuckler";                break;
+                case CLASS_TYPE_SWIFT_WING:            sScript = "prc_swiftwing";                   break;
+                case CLASS_TYPE_SWORDSAGE:             sScript = "tob_swordsage";    iData |= 0x01; break;
+                case CLASS_TYPE_TALON_OF_TIAMAT:       sScript = "prc_talontiamat";                 break;
+                case CLASS_TYPE_TEMPEST:               sScript = "prc_tempest";                     break;
+                case CLASS_TYPE_TEMPUS:                sScript = "prc_battletempus";                break;
+                case CLASS_TYPE_TENEBROUS_APOSTATE:    sScript = "bnd_tenebrous";                   break;
+                case CLASS_TYPE_THAYAN_KNIGHT:         sScript = "prc_thayknight";                  break;
+                case CLASS_TYPE_THRALL_OF_GRAZZT_A:    sScript = "tog";                             break;
+                case CLASS_TYPE_THRALLHERD:            sScript = "psi_thrallherd";                  break;
+                case CLASS_TYPE_TOTEMIST:              sScript = "moi_totemist";                    break;
+                case CLASS_TYPE_TOTEM_RAGER:           sScript = "moi_totemrager";                  break;
+                case CLASS_TYPE_TRUENAMER:             sScript = "true_truenamer";   iData |= 0x01; break;
+                case CLASS_TYPE_VASSAL:                sScript = "prc_vassal";                      break;
+                case CLASS_TYPE_VIGILANT:              sScript = "prc_vigilant";                    break;
+                case CLASS_TYPE_WARBLADE:              sScript = "tob_warblade";     iData |= 0x01; break;
+                case CLASS_TYPE_WARCHIEF:              sScript = "prc_warchief";                    break;
+                case CLASS_TYPE_WARFORGED_JUGGERNAUT:  sScript = "prc_juggernaut";                  break;
+                case CLASS_TYPE_WARLOCK:               sScript = "inv_warlock";      iData |= 0x01; break;
+                case CLASS_TYPE_WARMAGE:                                             iData |= 0x03; break;
+                case CLASS_TYPE_WARMIND:               sScript = "psi_warmind";      iData |= 0x01; break;
+                case CLASS_TYPE_WEREWOLF:              sScript = "prc_werewolf";                    break;                
+                case CLASS_TYPE_WILDER:                                              iData |= 0x01; break;
+                
+                // Races that can cast spells
+                case CLASS_TYPE_DRAGON:                                              iData |= 0x03; break;
+				case CLASS_TYPE_SHAPECHANGER:                                        iData |= 0x03; break;
+                case CLASS_TYPE_OUTSIDER:                                            iData |= 0x03; break;
+                case CLASS_TYPE_ABERRATION:                                          iData |= 0x03; break;
+                case CLASS_TYPE_MONSTROUS:                                           iData |= 0x03; break;
+                case CLASS_TYPE_FEY:                                                 iData |= 0x03; break;
+            }
+            if(sScript != "")
+                SetPersistantLocalString(oPC, "PRC_Class_Script"+IntToString(i), sScript);
+        }
+        if (DEBUG) DoDebug("SetupCharacterData Class: " + IntToString(nClassType));
+        if (DEBUG) DoDebug("SetupCharacterData Data: " + IntToString(iData));
+    }
+    if(iData)
+        SetPersistantLocalInt(oPC, "PRC_Class_Data", iData);
+
+    if(iShifting)
+        SetPersistantLocalInt(oPC, "PRC_UNI_SHIFT_SCRIPT", 1);
+
+    //Setup class info for onleveldown script
+    int nCharData = ((GetClassByPosition(8, oPC) & 0xFF) << 56) |
+					((GetClassByPosition(7, oPC) & 0xFF) << 48) |
+					((GetClassByPosition(5, oPC) & 0xFF) << 40) |
+                    ((GetClassByPosition(5, oPC) & 0xFF) << 32) |
+					((GetClassByPosition(4, oPC) & 0xFF) << 24) |
+					((GetClassByPosition(3, oPC) & 0xFF) << 16) |
+                    ((GetClassByPosition(2, oPC) & 0xFF) << 8) |					
+                    (GetClassByPosition(1, oPC) & 0xFF);
+
+    SetPersistantLocalInt(oPC, "PRC_Character_Data", nCharData);
+}
+
+void DelayedExecuteScript(int nExpectedGeneration, string sScriptName, object oPC)
+{
+    if (nExpectedGeneration != GetLocalInt(oPC, PRC_EvalPRCFeats_Generation))
+    {
+        //Generation has changed, so don't apply the effect
+        return;
+    }
+    ExecuteScript(sScriptName, oPC);
+}
+
+void DelayedReApplyUnhealableAbilityDamage(int nExpectedGeneration, object oPC)
+{
+    if (nExpectedGeneration != GetLocalInt(oPC, PRC_ScrubPCSkin_Generation))
+    {
+        //Generation has changed, so don't apply the effect
+        return;
+    }
+    ReApplyUnhealableAbilityDamage(oPC);
+}
+
+int ToBFeats(object oPC)
+{
+    if(GetHasFeat(FEAT_SHADOW_BLADE, oPC) ||
+       GetHasFeat(FEAT_RAPID_ASSAULT, oPC) ||
+       GetHasFeat(FEAT_DESERT_WIND_DODGE, oPC) ||
+       GetHasFeat(FEAT_DESERT_FIRE, oPC) ||
+       GetHasFeat(FEAT_IRONHEART_AURA, oPC) ||
+       GetHasFeat(FEAT_SHADOW_TRICKSTER, oPC) ||
+       GetHasFeat(FEAT_WHITE_RAVEN_DEFENSE, oPC) ||
+       GetHasFeat(FEAT_DEVOTED_BULWARK, oPC) ||
+       GetHasFeat(FEAT_SNAP_KICK, oPC) ||
+       GetHasFeat(FEAT_THREE_MOUNTAINS, oPC) ||
+       GetHasFeat(FEAT_VAE_SCHOOL, oPC) ||
+       GetHasFeat(FEAT_INLINDL_SCHOOL, oPC) ||
+       GetHasFeat(FEAT_XANIQOS_SCHOOL, oPC) ||
+       GetHasFeat(FEAT_SHIELD_WALL, oPC) ||
+       GetHasFeat(FEAT_CROSSBOW_SNIPER, oPC) ||
+       GetHasFeat(FEAT_CRESCENT_MOON, oPC) ||
+       GetHasFeat(FEAT_QUICK_STAFF, oPC) ||
+       GetHasFeat(FEAT_BEAR_FANG, oPC) ||
+       GetHasFeat(FEAT_IMPROVED_RAPID_SHOT, oPC) ||
+       GetHasFeat(FEAT_DIRE_FLAIL_SMASH, oPC) ||
+       GetHasFeat(FEAT_SHIELD_SPECIALIZATION_LIGHT, oPC) ||
+       GetHasFeat(FEAT_SHIELD_SPECIALIZATION_HEAVY, oPC) ||
+       GetHasFeat(FEAT_FOCUSED_SHIELD, oPC) ||
+       GetHasFeat(FEAT_SHIELDMATE, oPC) ||
+       GetHasFeat(FEAT_IMPROVED_SHIELDMATE, oPC) ||
+       GetHasFeat(FEAT_SHIELDED_CASTING, oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_DESERT_WIND   , oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_DEVOTED_SPIRIT, oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_DIAMOND_MIND  , oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_IRON_HEART    , oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_SETTING_SUN   , oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_SHADOW_HAND   , oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_STONE_DRAGON  , oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_TIGER_CLAW    , oPC) ||
+       GetHasFeat(FEAT_BLADE_MEDITATION_WHITE_RAVEN   , oPC) ||
+       GetRacialType(oPC) == RACIAL_TYPE_RETH_DEKALA ||
+       GetRacialType(oPC) == RACIAL_TYPE_HADRIMOI)
+        return TRUE;
+        
+    return FALSE;    
+}
+
+void EvalPRCFeats(object oPC)
+{
+    // Player is currently making character in ConvoCC
+    // don't run EvalPRCFeats() yet
+    if(oPC == GetLocalObject(GetModule(), "ccc_active_pc"))
+        return;
+
+    int nGeneration = PRC_NextGeneration(GetLocalInt(oPC, PRC_EvalPRCFeats_Generation));
+    if (DEBUG > 1) DoDebug("EvalPRCFeats Generation: " + IntToString(nGeneration));
+    SetLocalInt(oPC, PRC_EvalPRCFeats_Generation, nGeneration);
+
+    //permanent ability changes
+    if(GetPRCSwitch(PRC_NWNX_FUNCS))
+        ExecuteScript("prc_nwnx_funcs", oPC);
+
+    //Add IP Feats to the hide
+    DelayCommand(0.0f, DelayedAddIPFeats(nGeneration, oPC));
+
+    // If there is a bonus domain, it will always be in the first slot, so just check that.
+    // It also runs things that clerics with those domains need
+    if (GetPersistantLocalInt(oPC, "PRCBonusDomain1") > 0 || GetLevelByClass(CLASS_TYPE_CLERIC, oPC))
+        DelayCommand(0.1f, ExecuteScript("prc_domain_skin", oPC));
+
+    // special add atk bonus equal to Enhancement
+    ExecuteScript("ft_sanctmartial", oPC);
+
+    //hook in the weapon size restrictions script
+    //ExecuteScript("prc_restwpnsize", oPC);
+
+    //Route the event to the appropriate class specific scripts
+    int i, iData;
+    string sScript;
+    for (i = 1; i <= 3; i++)
+    {
+        sScript = GetPersistantLocalString(oPC, "PRC_Class_Script"+IntToString(i));
+        if(sScript != "")
+        {
+        	if (DEBUG) DoDebug("PRC_Class_Script: "+sScript);
+            ExecuteScript(sScript, oPC);
+        }    
+    }
+
+    iData = GetPersistantLocalInt(oPC, "PRC_Class_Data");
+
+    // Handle alternate caster types gaining new stuff
+    if(iData & 0x01)
+        ExecuteScript("prc_amagsys_gain", oPC);
+
+    // Add ip feats for spontaneous casters using metamagic
+    if(iData & 0x02)
+        ExecuteScript("prc_metamagic", oPC);
+
+    // Handle classes with reduced arcane spell failure
+    if(iData & 0x04)
+        ExecuteScript("prc_reducedasf", oPC);
+
+    if(GetPersistantLocalInt(oPC, "PRC_UNI_SHIFT_SCRIPT"))
+        //Executing shifter-related stuff like this has these advantages:
+        //1) All races and classes that need it can get it without a different script needing to be created for each.
+        //2) PCs with shifter-related stuff from multiple classes or races don't run the same functions multiple times.
+        ExecuteScript("prc_uni_shift", oPC);
+
+    // Templates
+    //these go here so feats can be reused
+    ExecuteScript("prc_templates", oPC);
+
+    // Feats
+    //these are here so if templates add them the if check runs after the template was applied
+    ExecuteScript("prc_feats", oPC);
+    
+    if (ToBFeats(oPC))
+        ExecuteScript("tob_feats", oPC);
+        
+    if (GetIsIncarnumUser(oPC))
+        ExecuteScript("moi_events", oPC); 
+        
+    if (GetIsBinder(oPC))
+        ExecuteScript("bnd_events", oPC);        
+
+    // check if character with crafting feat has appropriate base item in her inventory
+    // x - moved from prc_onhb_indiv.nss
+    if(GetPRCSwitch(PRC_CRAFTING_BASE_ITEMS))
+        DelayCommand(0.5f, ExecuteScript("prc_crftbaseitms", oPC));
+
+    // Add the teleport management feats.
+    // 2005.11.03: Now added to all base classes on 1st level - Ornedan
+//    ExecuteScript("prc_tp_mgmt_eval", oPC);
+
+    // Size changes. Removed due to double-dipping most size adjustments
+    //ExecuteScript("prc_size", oPC);
+
+    // Speed changes
+    // The local int is for when items are requipped too quickly and this script bugs out
+    if (!GetLocalInt(oPC, "PRCSpeedDelay"))
+    {
+    	ExecuteScript("prc_speed", oPC);
+    	SetLocalInt(oPC, "PRCSpeedDelay", TRUE);
+    	DelayCommand(0.15, DeleteLocalInt(oPC, "PRCSpeedDelay"));
+    }	
+
+    // ACP system
+    if((GetIsPC(oPC) &&
+        (GetPRCSwitch(PRC_ACP_MANUAL)   ||
+         GetPRCSwitch(PRC_ACP_AUTOMATIC)
+         )
+        ) ||
+       (!GetIsPC(oPC) &&
+        GetPRCSwitch(PRC_ACP_NPC_AUTOMATIC)
+        )
+       )
+        ExecuteScript("acp_auto", oPC);
+
+// this is handled inside the PRC Options conversation now.
+/*    // Epic spells
+    if((GetCasterLvl(CLASS_TYPE_CLERIC,   oPC) >= 21 ||
+        GetCasterLvl(CLASS_TYPE_DRUID,    oPC) >= 21 ||
+        GetCasterLvl(CLASS_TYPE_SORCERER, oPC) >= 21 ||
+        GetCasterLvl(CLASS_TYPE_FAVOURED_SOUL, oPC) >= 21 ||
+        GetCasterLvl(CLASS_TYPE_HEALER, oPC) >= 21 ||
+        GetCasterLvl(CLASS_TYPE_WIZARD,   oPC) >= 21
+        ) &&
+        !GetHasFeat(FEAT_EPIC_SPELLCASTING_REST, oPC)
+       )
+    {
+        IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_FEAT_EPIC_REST), 0.0f,
+                              X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+    }*/
+
+    // Miscellaneous
+    ExecuteScript("prc_sneak_att", oPC);
+    ExecuteScript("race_skin", oPC);
+    ExecuteScript("prc_mithral", oPC);
+    if(GetPRCSwitch(PRC_ENFORCE_RACIAL_APPEARANCE) && GetIsPC(oPC))
+        ExecuteScript("race_appear", oPC);
+
+    //Reserve Feats
+    if(!GetLocalInt(oPC, "ReserveFeatsRunning"))
+    {
+        if(GetHasFeat(FEAT_HOLY_WARRIOR, oPC) || 
+           GetHasFeat(FEAT_MYSTIC_BACKLASH, oPC) || 
+           GetHasFeat(FEAT_ACIDIC_SPLATTER, oPC) || 
+           GetHasFeat(FEAT_FIERY_BURST, oPC) || 
+           GetHasFeat(FEAT_STORM_BOLT, oPC) || 
+           GetHasFeat(FEAT_WINTERS_BLAST, oPC) || 
+           GetHasFeat(FEAT_CLAP_OF_THUNDER, oPC) || 
+           GetHasFeat(FEAT_SICKENING_GRASP, oPC) || 
+           GetHasFeat(FEAT_TOUCH_OF_HEALING, oPC) || 
+           GetHasFeat(FEAT_DIMENSIONAL_JAUNT, oPC) || 
+           GetHasFeat(FEAT_CLUTCH_OF_EARTH, oPC) || 
+           GetHasFeat(FEAT_BORNE_ALOFT, oPC) || 
+           GetHasFeat(FEAT_PROTECTIVE_WARD, oPC) || 
+           GetHasFeat(FEAT_SHADOW_VEIL, oPC) || 
+           GetHasFeat(FEAT_SUNLIGHT_EYES, oPC) || 
+           GetHasFeat(FEAT_TOUCH_OF_DISTRACTION, oPC) || 
+           GetHasFeat(FEAT_UMBRAL_SHROUD, oPC) || 
+           GetHasFeat(FEAT_CHARNEL_MIASMA, oPC) || 
+           GetHasFeat(FEAT_DROWNING_GLANCE, oPC) || 
+           GetHasFeat(FEAT_INVISIBLE_NEEDLE, oPC) || 
+           GetHasFeat(FEAT_SUMMON_ELEMENTAL, oPC) || 
+           GetHasFeat(FEAT_DIMENSIONAL_REACH, oPC) || 
+           GetHasFeat(FEAT_HURRICANE_BREATH, oPC) || 
+           GetHasFeat(FEAT_MINOR_SHAPESHIFT, oPC) || 
+           GetHasFeat(FEAT_FACECHANGER, oPC))
+        {
+            ExecuteScript("prc_reservefeat", oPC);
+        }
+    }
+
+    /*if(// Psionics
+       GetLevelByClass(CLASS_TYPE_PSION,            oPC) ||
+       GetLevelByClass(CLASS_TYPE_WILDER,           oPC) ||
+       GetLevelByClass(CLASS_TYPE_PSYWAR,           oPC) ||
+       GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN,   oPC) ||
+       GetLevelByClass(CLASS_TYPE_WARMIND,          oPC) ||
+       // New spellbooks
+       GetLevelByClass(CLASS_TYPE_BARD,             oPC) ||
+       GetLevelByClass(CLASS_TYPE_SORCERER,         oPC) ||
+       GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oPC) ||
+       GetLevelByClass(CLASS_TYPE_FAVOURED_SOUL,    oPC) ||
+       GetLevelByClass(CLASS_TYPE_MYSTIC,           oPC) ||
+       GetLevelByClass(CLASS_TYPE_HEXBLADE,         oPC) ||
+       GetLevelByClass(CLASS_TYPE_DUSKBLADE,        oPC) ||
+       GetLevelByClass(CLASS_TYPE_WARMAGE,          oPC) ||
+       GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER,oPC) ||
+       GetLevelByClass(CLASS_TYPE_JUSTICEWW,        oPC) ||
+       GetLevelByClass(CLASS_TYPE_WITCH,            oPC) ||
+       GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD,    oPC) ||
+       GetLevelByClass(CLASS_TYPE_ARCHIVIST,        oPC) ||
+       GetLevelByClass(CLASS_TYPE_BEGUILER,         oPC) ||
+       GetLevelByClass(CLASS_TYPE_HARPER,           oPC) ||
+       GetLevelByClass(CLASS_TYPE_TEMPLAR,          oPC) ||
+       // Truenaming
+       GetLevelByClass(CLASS_TYPE_TRUENAMER,        oPC) ||
+       // Tome of Battle
+       GetLevelByClass(CLASS_TYPE_CRUSADER,         oPC) ||
+       GetLevelByClass(CLASS_TYPE_SWORDSAGE,        oPC) ||
+       GetLevelByClass(CLASS_TYPE_WARBLADE,         oPC) ||
+       // Invocations
+       GetLevelByClass(CLASS_TYPE_DRAGONFIRE_ADEPT, oPC) ||
+       GetLevelByClass(CLASS_TYPE_WARLOCK, oPC) ||
+       // Racial casters
+       (GetLevelByClass(CLASS_TYPE_OUTSIDER, oPC) && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
+        )
+      {
+        DelayCommand(1.0, DelayedExecuteScript(nGeneration, "prc_amagsys_gain", oPC));
+
+        //add selectable metamagic feats for spontaneous spellcasters
+        ExecuteScript("prc_metamagic", oPC);
+      }*/
+
+    // Gathers all the calls to UnarmedFists & Feats to one place.
+    // Must be after all evaluationscripts that need said functions.
+    //if(GetLocalInt(oPC, "CALL_UNARMED_FEATS") || GetLocalInt(oPC, "CALL_UNARMED_FISTS")) // ExecuteScript() is pretty expensive, do not run it needlessly - 20060702, Ornedan
+    ExecuteScript("unarmed_caller", oPC);
+
+    // Gathers all the calls to SetBaseAttackBonus() to one place
+    // Must be after all evaluationscripts that need said function.
+    ExecuteScript("prc_bab_caller", oPC);
+
+//:: [PRC .35] Needs marker feats
+    // Classes an invoker can take
+    if(GetLevelByClass(CLASS_TYPE_MAESTER,              oPC) ||
+       GetLevelByClass(CLASS_TYPE_ACOLYTE,              oPC) ||
+       GetLevelByClass(CLASS_TYPE_ENLIGHTENEDFIST,      oPC) ||
+       GetLevelByClass(CLASS_TYPE_DISCIPLE_OF_ASMODEUS, oPC))
+       {
+           //Set arcane or invocation bonus caster levels
+
+           //Arcane caster first class position, take arcane
+           if(GetFirstArcaneClassPosition(oPC) == 1)
+               SetLocalInt(oPC, "INV_Caster", 1);
+           //Invoker first class position. take invoker
+           else if(GetClassByPosition(1, oPC) == CLASS_TYPE_WARLOCK || GetClassByPosition(1, oPC) == CLASS_TYPE_DRAGONFIRE_ADEPT)
+               SetLocalInt(oPC, "INV_Caster", 2);
+           //Non arcane first class position, invoker second.  Take invoker
+           else if(GetFirstArcaneClassPosition(oPC) ==0 && (GetClassByPosition(2, oPC) == CLASS_TYPE_WARLOCK || GetClassByPosition(2, oPC) == CLASS_TYPE_DRAGONFIRE_ADEPT))
+               SetLocalInt(oPC, "INV_Caster", 2);
+           //last cas would be Non-invoker first class position, arcane second position. take arcane.
+           else
+               SetLocalInt(oPC, "INV_Caster", 1);
+       }
+}
+
+void DelayedAddIPFeats(int nExpectedGeneration, object oPC)
+{
+    if (nExpectedGeneration != GetLocalInt(oPC, PRC_EvalPRCFeats_Generation))
+    {
+        //Generation has changed, so don't apply the effect
+        return;
+    }
+
+    object oSkin = GetPCSkin(oPC);
+
+    //Horse menu
+    AddSkinFeat(FEAT_HORSE_MENU, 40, oSkin, oPC);
+
+    // Switch convo feat
+    //Now everyone gets it at level 1, but just to be on the safe side
+    AddSkinFeat(FEAT_OPTIONS_CONVERSATION, 229, oSkin, oPC);
+
+    //PnP familiars
+    if(GetHasFeat(FEAT_SUMMON_FAMILIAR, oPC) && GetPRCSwitch(PRC_PNP_FAMILIARS))
+        IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_PNP_FAMILIAR), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING);
+    else if(!GetHasFeat(FEAT_SUMMON_FAMILIAR, oPC) || !GetPRCSwitch(PRC_PNP_FAMILIARS))
+        RemoveItemProperty(oSkin, ItemPropertyBonusFeat(IP_CONST_PNP_FAMILIAR));
+
+    //PnP Spell Schools
+    if(GetPRCSwitch(PRC_PNP_SPELL_SCHOOLS)
+        && GetLevelByClass(CLASS_TYPE_WIZARD, oPC)
+        && !GetIsPolyMorphedOrShifted(oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_GENERAL,       oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_ABJURATION,    oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_CONJURATION,   oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_DIVINATION,    oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_ENCHANTMENT,   oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_EVOCATION,     oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_ILLUSION,      oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_NECROMANCY,    oPC)
+        && !GetHasFeat(FEAT_PNP_SPELL_SCHOOL_TRANSMUTATION, oPC)
+        //&& !PRCGetHasEffect(EFFECT_TYPE_POLYMORPH, oPC) //so it doesnt pop up on polymorphing
+        //&& !GetLocalInt(oSkin, "nPCShifted") //so it doenst pop up on shifting
+        )
+    {
+        if(GetXP(oPC))// ConvoCC compatibility fix
+            ExecuteScript("prc_pnp_shcc_s", oPC);
+    }
+
+    /*//Arcane Archer old imbue arrow
+    if(GetLevelByClass(CLASS_TYPE_ARCANE_ARCHER, oPC) >= 2
+        && !GetHasFeat(FEAT_PRESTIGE_IMBUE_ARROW, oPC)
+        && GetPRCSwitch(PRC_PNP_SPELL_SCHOOLS))
+    {
+        //add the old feat to the hide
+        IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(IP_CONST_FEAT_FEAT_PRESTIGE_IMBUE_ARROW), 0.0f,
+                              X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+    }*/
+
+    //handle PnP sling switch
+    if(GetPRCSwitch(PRC_PNP_SLINGS))
+    {
+        if(GetBaseItemType(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)) == BASE_ITEM_SLING)
+            IPSafeAddItemProperty(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC),
+                ItemPropertyMaxRangeStrengthMod(20),
+                999999.9);
+    }
+}
+
+void TemplateSLAs(object oPC)
+{
+    int i;
+    for(i = TEMPLATE_SLA_START; i <= TEMPLATE_SLA_END; i++)
+    {
+        DeleteLocalInt(oPC, "TemplateSLA_"+IntToString(i));
+    }
+}
+
+void DeletePRCLocalInts(object oSkin)
+{
+    // This will get rid of any SetCompositeAttackBonus LocalInts:
+    object oPC = GetItemPossessor(oSkin);
+    DeleteLocalInt(oPC, "CompositeAttackBonusR");
+    DeleteLocalInt(oPC, "CompositeAttackBonusL");
+
+    //Do not use DelayCommand for this--it's too dangerous:
+    //if SetCompositeAttackBonus is called at the wrong time the result will be incorrect.
+    DeleteNamedComposites(oPC, "PRC_ComAttBon");
+
+    // PRCGetClassByPosition and PRCGetLevelByPosition cleanup
+    // not needed now that GetClassByPosition() works for custom classes
+    // DeleteLocalInt(oPC, "PRC_ClassInPos1");
+    // DeleteLocalInt(oPC, "PRC_ClassInPos2");
+    // DeleteLocalInt(oPC, "PRC_ClassInPos3");
+    // DeleteLocalInt(oPC, "PRC_ClassLevelInPos1");
+    // DeleteLocalInt(oPC, "PRC_ClassLevelInPos2");
+    // DeleteLocalInt(oPC, "PRC_ClassLevelInPos3");
+
+    //persistant local token object cache
+    //looks like logging off then back on without the server rebooting breaks it
+    //I guess because the token gets a new ID, but the local still points to the old one
+    DeleteLocalObject(oPC, "PRC_HideTokenCache");
+
+    DeleteLocalInt(oSkin, "PRC_ArcaneSpellFailure");
+    
+    DeleteLocalInt(oPC, "PRC_SwiftActionUsed");
+    DeleteLocalInt(oPC, "PRC_MoveActionUsed");
+
+    // In order to work with the PRC system we need to delete some locals for each
+    // PRC that has a hide
+
+    //Do not use DelayCommand for this--it's too dangerous:
+    //if SetCompositeBonus is called between the time EvalPRCFeats removes item properties
+    //and the time this delayed command is executed, the result will be incorrect.
+    //Since this error case actually happens frequently with any delay here, just don't do it.
+    DeleteNamedComposites(oSkin, "PRC_CBon");
+
+    if (DEBUG) DoDebug("Clearing class flags");
+
+    // Elemental Savants
+    DeleteLocalInt(oSkin,"ElemSavantResist");
+    DeleteLocalInt(oSkin,"ElemSavantPerfection");
+    DeleteLocalInt(oSkin,"ElemSavantImmMind");
+    DeleteLocalInt(oSkin,"ElemSavantImmParal");
+    DeleteLocalInt(oSkin,"ElemSavantImmSleep");
+    // HeartWarder
+    DeleteLocalInt(oSkin,"FeyType");
+    // OozeMaster
+    DeleteLocalInt(oSkin,"IndiscernibleCrit");
+    DeleteLocalInt(oSkin,"IndiscernibleBS");
+    DeleteLocalInt(oSkin,"OneOozeMind");
+    DeleteLocalInt(oSkin,"OneOozePoison");
+    // Storm lord
+    DeleteLocalInt(oSkin,"StormLResElec");
+    // Spell sword
+    DeleteLocalInt(oSkin,"SpellswordSFBonusNormal");
+    DeleteLocalInt(oSkin,"SpellswordSFBonusEpic");
+    // Acolyte of the skin
+    DeleteLocalInt(oSkin,"AcolyteSymbBonus");
+    DeleteLocalInt(oSkin,"AcolyteResistanceCold");
+    DeleteLocalInt(oSkin,"AcolyteResistanceFire");
+    DeleteLocalInt(oSkin,"AcolyteResistanceAcid");
+    DeleteLocalInt(oSkin,"AcolyteResistanceElectric");
+    // Battleguard of Tempus
+    DeleteLocalInt(oSkin,"FEAT_WEAP_TEMPUS");
+    // Bonded Summoner
+    DeleteLocalInt(oSkin,"BondResEle");
+    DeleteLocalInt(oSkin,"BondSubType");
+    // Disciple of Meph
+    DeleteLocalInt(oSkin,"DiscMephResist");
+    DeleteLocalInt(oSkin,"DiscMephGlove");
+    // Initiate of Draconic Mysteries
+    DeleteLocalInt(oSkin,"IniSR");
+    DeleteLocalInt(oSkin,"IniStunStrk");
+    // Man at Arms
+    DeleteLocalInt(oSkin,"ManArmsCore");
+    // Telflammar Shadowlord
+    DeleteLocalInt(oSkin,"ShaDiscorp");
+    // Vile Feats
+    DeleteLocalInt(oSkin,"DeformGaunt");
+    DeleteLocalInt(oSkin,"DeformObese");
+    // Sneak Attack
+    DeleteLocalInt(oSkin,"RogueSneakDice");
+    DeleteLocalInt(oSkin,"BlackguardSneakDice");
+    // Sacred Fist
+    DeleteLocalInt(oSkin,"SacFisMv");
+    // Minstrel
+    DeleteLocalInt(oSkin,"MinstrelSFBonus"); /// @todo Make ASF reduction compositable
+    // Nightshade
+    DeleteLocalInt(oSkin,"ImmuNSWeb");
+    DeleteLocalInt(oSkin,"ImmuNSPoison");
+    // Soldier of Light
+    DeleteLocalInt(oSkin,"ImmuPF");
+    // Ultimate Ranger
+    DeleteLocalInt(oSkin,"URImmu");
+    // Thayan Knight
+    DeleteLocalInt(oSkin,"ThayHorror");
+    DeleteLocalInt(oSkin,"ThayZulkFave");
+    DeleteLocalInt(oSkin,"ThayZulkChamp");
+    // Black Flame Zealot
+    DeleteLocalInt(oSkin,"BFZHeart");
+    // Henshin Mystic
+    DeleteLocalInt(oSkin,"Happo");
+    DeleteLocalInt(oSkin,"HMInvul");
+    //Blightlord
+    DeleteLocalInt(oSkin, "WntrHeart");
+    DeleteLocalInt(oSkin, "BlightBlood");
+    // Contemplative
+    DeleteLocalInt(oSkin, "ContempDisease");
+    DeleteLocalInt(oSkin, "ContempPoison");
+    DeleteLocalInt(oSkin, "ContemplativeDR");
+    DeleteLocalInt(oSkin, "ContemplativeSR");
+    // Dread Necromancer
+    DeleteLocalInt(oSkin, "DNDamageResist");
+    // Warsling Sniper
+    DeleteLocalInt(oPC, "CanRicochet");
+    // Blood Magus
+    DeleteLocalInt(oSkin, "ThickerThanWater");
+
+    // Feats
+    DeleteLocalInt(oPC, "ForceOfPersonalityWis");
+    DeleteLocalInt(oPC, "ForceOfPersonalityCha");
+    DeleteLocalInt(oPC, "InsightfulReflexesInt");
+    DeleteLocalInt(oPC, "InsightfulReflexesDex");
+    DeleteLocalInt(oSkin, "TactileTrapsmithSearchIncrease");
+    DeleteLocalInt(oSkin, "TactileTrapsmithDisableIncrease");
+    DeleteLocalInt(oSkin, "TactileTrapsmithSearchDecrease");
+    DeleteLocalInt(oSkin, "TactileTrapsmithDisableDecrease");
+
+    // Warmind
+    DeleteLocalInt(oSkin, "EnduringBody");
+
+    // Ironmind
+    DeleteLocalInt(oSkin, "IronMind_DR");
+
+    // Suel Archanamach
+    DeleteLocalInt(oSkin, "SuelArchanamachSpellFailure");
+
+    // Favoured Soul
+    DeleteLocalInt(oSkin, "FavouredSoulResistElementAcid");
+    DeleteLocalInt(oSkin, "FavouredSoulResistElementCold");
+    DeleteLocalInt(oSkin, "FavouredSoulResistElementElec");
+    DeleteLocalInt(oSkin, "FavouredSoulResistElementFire");
+    DeleteLocalInt(oSkin, "FavouredSoulResistElementSonic");
+    DeleteLocalInt(oSkin, "FavouredSoulDR");
+
+    // Domains
+    DeleteLocalInt(oSkin, "StormDomainPower");
+
+    // Skullclan Hunter
+    DeleteLocalInt(oSkin, "SkullClanFear");
+    DeleteLocalInt(oSkin, "SkullClanDisease");
+    DeleteLocalInt(oSkin, "SkullClanProtectionEvil");
+    DeleteLocalInt(oSkin, "SkullClanSwordLight");
+    DeleteLocalInt(oSkin, "SkullClanParalysis");
+    DeleteLocalInt(oSkin, "SkullClanAbilityDrain");
+    DeleteLocalInt(oSkin, "SkullClanLevelDrain");
+
+    // Sohei
+    DeleteLocalInt(oSkin, "SoheiDamageResist");
+
+    // Dragon Disciple
+    DeleteLocalInt(oPC, "DragonDiscipleBreathWeaponUses");
+    
+    //Dragon Shaman
+    DeleteLocalInt(oPC, "DragonShamanTotem");
+
+    //Warblade
+    DeleteLocalInt(oSkin, "PRC_WEAPON_APTITUDE_APPLIED");
+
+    //Shifter(PnP)
+    DeleteLocalInt(oSkin, "PRC_SHIFTER_TEMPLATE_APPLIED");
+
+    DeleteLocalInt(oPC, "ScoutFreeMove");
+    DeleteLocalInt(oPC, "ScoutFastMove");
+    DeleteLocalInt(oPC, "ScoutBlindsight");
+
+    //Truenamer
+    // Called elsewhere now
+    /*int UtterID;
+    for(UtterID = 3526; UtterID <= 3639; UtterID++) // All utterances
+        DeleteLocalInt(oPC, "PRC_LawOfResistance" + IntToString(UtterID));
+    for(UtterID = 3418; UtterID <= 3431; UtterID++) // Syllable of Detachment to Word of Heaven, Greater
+        DeleteLocalInt(oPC, "PRC_LawOfResistance" + IntToString(UtterID));*/
+
+    //Invocations
+    DeleteLocalInt(oPC, "ChillingFogLock");
+    //Endure Exposure wearing off
+    array_delete(oPC, "BreathProtected");
+    DeleteLocalInt(oPC, "DragonWard");
+
+    //Scry on Familiar
+    DeleteLocalInt(oPC, "Scry_Familiar");
+    
+    // Undead HD
+    DeleteLocalInt(oPC, "PRCUndeadHD");
+    DeleteLocalInt(oPC, "PRCUndeadFSPen");
+
+    //Template Spell-Like Abilities
+    DelayCommand(0.5f, TemplateSLAs(oPC));
+
+    // future PRCs Go below here
+}
+
+void ScrubPCSkin(object oPC, object oSkin)
+{
+    int nGeneration = PRC_NextGeneration(GetLocalInt(oPC, PRC_ScrubPCSkin_Generation));
+    if (DEBUG > 1) DoDebug("ScrubPCSkin Generation: " + IntToString(nGeneration));
+    SetLocalInt(oPC, PRC_ScrubPCSkin_Generation, nGeneration);
+
+    int iCode = GetHasFeat(FEAT_SF_CODE,oPC);
+    int ipType, st;
+    if(!(/*GetIsPolyMorphedOrShifted(oPC) || */GetIsObjectValid(GetMaster(oPC))))
+    {
+        itemproperty ip = GetFirstItemProperty(oSkin);
+        while(GetIsItemPropertyValid(ip))
+        {
+            // Insert Logic here to determine if we spare a property
+            ipType = GetItemPropertyType(ip);
+            if(ipType == ITEM_PROPERTY_BONUS_FEAT)
+            {
+                // Check for specific Bonus Feats
+                // Reference iprp_feats.2da
+                st = GetItemPropertySubType(ip);
+
+                // Spare 400 through 570 and 398 -- epic spells & spell effects
+                //also spare the new spellbook feats (1000-12000 & 17701-24704
+                //also spare the psionic, trunaming, tob, invocation feats (12000-16000)
+                // spare template, tob stuff (16300-17700)
+                // changed by fluffyamoeba so that iprp weapon specialization, dev crit, epic weapon focus, epic weapon spec
+                // overwhelming crit and weapon of choice are no longer skipped.
+                if ((st < 400 || st > 570)
+                && st != 398
+                && (st < 1000 || st > 13520)
+                //&& (st < 1000 || st > 13999)
+                //&& (st < 14501 || st > 15999)
+                && (st < 16300 || st > 24704)
+                && (st < 223 || st > 226)         // draconic feats
+                && (st < 229 || st > 249)         // Pnp spellschool feats and PRC options feat (231-249 & 229)
+                && st != 259                      // 259 - psionic focus
+                && (st < 141 || st > 200)         // 141 - shadowmaster shades, 142-151 bonus domains casting feats, 152 - 200 bonus domain powers
+                && ( (st == IP_CONST_FEAT_PRC_POWER_ATTACK_QUICKS_RADIAL || 
+                      st == IP_CONST_FEAT_POWER_ATTACK_SINGLE_RADIAL || 
+                      st == IP_CONST_FEAT_POWER_ATTACK_FIVES_RADIAL) ? // Remove the PRC Power Attack radials if the character no longer has Power Attack
+                     !GetHasFeat(FEAT_POWER_ATTACK, oPC) :
+                     TRUE // If the feat is not relevant to this clause, always pass
+                    )
+                )
+                    RemoveItemProperty(oSkin, ip);
+            }
+            else if(ipType == ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N)
+            {
+                //bonus spellslots code here
+                //st = GetItemPropertySubType(ip);
+                RemoveItemProperty(oSkin, ip);
+            }
+            else
+                RemoveItemProperty(oSkin, ip);
+
+            // Get the next property
+            ip = GetNextItemProperty(oSkin);
+        }
+    }
+    if(iCode)
+      AddItemProperty(DURATION_TYPE_PERMANENT,PRCItemPropertyBonusFeat(381),oSkin);
+
+    // Schedule restoring the unhealable ability damage
+    DelayCommand(0.1f, DelayedReApplyUnhealableAbilityDamage(nGeneration, oPC));
+
+    // Remove all natural weapons too
+    // ClearNaturalWeapons(oPC);
+    // Done this way to remove prc_inc_natweap and prc_inc_combat from the include
+    // Should help with compile speeds and the like
+    //array_delete(oPC, "ARRAY_NAT_SEC_WEAP_RESREF");
+    //array_delete(oPC, "ARRAY_NAT_PRI_WEAP_RESREF");
+    //array_delete(oPC, "ARRAY_NAT_PRI_WEAP_ATTACKS");
+}
+
+int BlastInfidelOrFaithHeal(object oCaster, object oTarget, int iEnergyType, int iDisplayFeedback)
+{
+    //Don't bother doing anything if iEnergyType isn't either positive/negative energy
+    if(iEnergyType != DAMAGE_TYPE_POSITIVE && iEnergyType != DAMAGE_TYPE_NEGATIVE)
+        return FALSE;
+
+    //If the target is undead and damage type is negative
+    //or if the target is living and damage type is positive
+    //then we're healing.  Otherwise, we're harming.
+    int iTombTainted = GetHasFeat(FEAT_TOMB_TAINTED_SOUL, oTarget) && GetAlignmentGoodEvil(oTarget) != ALIGNMENT_GOOD;
+    int iHeal = ( iEnergyType == DAMAGE_TYPE_NEGATIVE && (MyPRCGetRacialType(oTarget) == RACIAL_TYPE_UNDEAD || iTombTainted)) ||
+                ( iEnergyType == DAMAGE_TYPE_POSITIVE && MyPRCGetRacialType(oTarget) != RACIAL_TYPE_UNDEAD && !iTombTainted);
+    int iRetVal = FALSE;
+    int iAlignDif = CompareAlignment(oCaster, oTarget);
+    string sFeedback = "";
+
+    if(iHeal){
+        if((GetHasFeat(FEAT_FAITH_HEALING, oCaster) && iAlignDif < 2)){
+            iRetVal = TRUE;
+            sFeedback = "Faith Healing";
+        }
+    }
+    else{
+        if((GetHasFeat(FEAT_BLAST_INFIDEL, oCaster) && iAlignDif >= 2)){
+            iRetVal = TRUE;
+            sFeedback = "Blast Infidel";
+        }
+    }
+
+    if(iDisplayFeedback) FloatingTextStringOnCreature(sFeedback, oCaster);
+    return iRetVal;
+}
+
+int GetShiftingFeats(object oPC)
+{
+    int nNumFeats;
+    nNumFeats = GetHasFeat(FEAT_BEASTHIDE_ELITE, oPC)
+              + GetHasFeat(FEAT_DREAMSIGHT_ELITE, oPC)
+              + GetHasFeat(FEAT_GOREBRUTE_ELITE, oPC)
+              + GetHasFeat(FEAT_LONGSTRIDE_ELITE, oPC)
+              + GetHasFeat(FEAT_LONGTOOTH_ELITE, oPC)
+              + GetHasFeat(FEAT_RAZORCLAW_ELITE, oPC)
+              + GetHasFeat(FEAT_WILDHUNT_ELITE, oPC)
+              + GetHasFeat(FEAT_EXTRA_SHIFTER_TRAIT, oPC)
+              + GetHasFeat(FEAT_HEALING_FACTOR, oPC)
+              + GetHasFeat(FEAT_SHIFTER_AGILITY, oPC)
+              + GetHasFeat(FEAT_SHIFTER_DEFENSE, oPC)
+              + GetHasFeat(FEAT_GREATER_SHIFTER_DEFENSE, oPC)
+              + GetHasFeat(FEAT_SHIFTER_FEROCITY, oPC)
+              + GetHasFeat(FEAT_SHIFTER_INSTINCTS, oPC)
+              + GetHasFeat(FEAT_SHIFTER_SAVAGERY, oPC);
+
+     return nNumFeats;
+}
+
+//Including DelayedApplyEffectToObject here because it is often used in conjunction with EvalPRCFeats and I don't know a better place to put it
+void DelayedApplyEffectToObject(int nExpectedGeneration, int nCurrentGeneration, int nDuration, effect eEffect, object oTarget, float fDuration)
+{
+    if (nExpectedGeneration != nCurrentGeneration)
+    {
+        //Generation has changed, so don't apply the effect
+        return;
+    }
+    ApplyEffectToObject(nDuration, eEffect, oTarget, fDuration);
+}
+
+//Including DelayedApplyEffectToObject here because it is often used in conjunction with EvalPRCFeats and I don't know a better place to put it
+void DelayApplyEffectToObject(float fDelay, string sGenerationName, int nDuration, effect eEffect, object oTarget, float fDuration = 0.0f)
+{
+    /*
+    There are a couple of problems that can arise in code that removes and reapplies effects; 
+    this function helps deal with those problems. One example of a typical place where these problems 
+    frequently arise is in the class scripts called by the EvalPRCFeats function.
+
+    The first problem is that when code removes and immediately reapplies a series of effects,
+    some of those effects may not actually be reapplied. This is because the RemoveEffect() function 
+    doesn't actually remove an effect, it marks it to be removed later--when the currently running 
+    script finishes. If any of the effects we reapply matches one of the effects marked to be
+    removed, that reapplied effect will be removed when the currently running script finishes
+    and so will be unexpectedly missing. To illustrate:
+        1) We start with effect A and B.
+        2) The application function is called; it removes all effects and reapplies effects B and C.
+        3) The actual removal happens when the script ends: effect A and B are removed.
+        End result: we have only effect C instead of the expected B and C.
+    The solution to this is to reapply the effects later using DelayCommand().
+    
+    This introduces a new problem. If the function that removes and reapplies the effects is called
+    multiple times quickly, it can queue up a series of delayed applications. This causes two problems:
+    if the data on which the effects are calculated changes, the earlier delayed applications can
+    apply effects that should no longer be used, but they are anyway because the delayed code doesn't
+    know this. To illustrate:
+        1) The application function is called; it removes all effects, schedules delayed application of effect A.
+        2) The application function is called again; it removes all effects, schedules delayed application of effect B.
+        3) Delayed application of effect A occurs.
+        4) Delayed application of effect B occurs.
+        End result: we have both effect A and B instead of the expected result, B alone.
+    Another problem is that we can end up with multiple copies of the same effect.
+    If this happens enough, it can cause "Effect List overflow" errors. Also, if the effect stacks
+    with itself, this gives a greater bonus or penalty than it should. To illustrate:
+        1) The application function is called; it removes all effects, schedules delayed application of effect C.
+        2) The application function is called; it removes all effects, schedules delayed application of effect C.
+        3) Delayed application of effect C occurs.
+        4) Delayed application of effect C occurs.
+        End result: we have effect C twice instead of just once.
+    The solution is to both these problems is for the application function to increment an integer each time it
+    is called and to pass this to the delayed application function. The delayed application actually happens only
+    if the generation when it runs is the same as the generation when it was scheduled. To illustrate:
+        1) We start with effect A and B applied.
+        2) The application function is called: it increments generation to 2, schedules delayed application of effect B and C.
+        3) The application function is called: it increments generation to 3, schedules delayed application of effect C.
+        4) The generation 2 delayed application function executes: it sees that the current generation is 3 and simply exits, doing nothing.
+        5) The generation 3 delayed application function executes: it sees that the current generation is 3, so it applies effect C.
+        End result: we have one copy of effect C, which is what we wanted.
+    */
+
+    if (fDelay < 0.0f || GetStringLength(sGenerationName) == 0)
+    {
+        ApplyEffectToObject(nDuration, eEffect, oTarget, fDuration);
+    }
+    else
+    {
+        int nExpectedGeneration = GetLocalInt(oTarget, sGenerationName); //This gets the generation now
+        DelayCommand(
+            fDelay, 
+            DelayedApplyEffectToObject(
+                nExpectedGeneration, 
+                GetLocalInt(oTarget, sGenerationName), //This is delayed by the DelayCommand, so it gets the generation when DelayedApplyEffectToObject is actually executed
+                nDuration, 
+                eEffect,
+                oTarget,
+                fDuration
+            )
+        );
+    }
+}
+
+//Including DelayedAddItemProperty here to keep it with DelayedApplyEffectToObject, though more properly it should probably be in inc_item_props.nss
+void DelayedAddItemProperty(int nExpectedGeneration, int nCurrentGeneration, int nDurationType, itemproperty ipProperty, object oItem, float fDuration)
+{
+    if (nExpectedGeneration != nCurrentGeneration)
+    {
+        //Generation has changed, so don't apply the effect
+        return;
+    }
+    AddItemProperty(nDurationType, ipProperty, oItem, fDuration);
+}
+
+//Including DelayAddItemProperty here to keep it with DelayApplyEffectToObject, though more properly it should probably be in inc_item_props.nss
+void DelayAddItemProperty(float fDelay, object oGenerationHolder, string sGenerationName, int nDurationType, itemproperty ipProperty, object oItem, float fDuration = 0.0f)
+{
+    /*
+    There are a couple of problems that can arise in code that removes and reapplies item properties;
+    this function helps deal with those problems. One example of a typical place where these problems 
+    frequently arise is in the class scripts called by the EvalPRCFeats function.
+
+    The first problem is that when code removes and immediately reapplies a series of item properties,
+    some of those properties may not actually be reapplied. This is because the RemoveItemProperty() function 
+    doesn't actually remove a property, it marks it to be removed later--when the currently running 
+    script finishes. If any of the properties we reapply matches one of the properties marked to be
+    removed, that reapplied property will be removed when the currently running script finishes
+    and so will be unexpectedly missing. To illustrate:
+        1) We start with properties A and B.
+        2) The application function is called; it removes all properties and reapplies properties B and C.
+        3) The actual removal happens when the script ends: property A and B are removed.
+        End result: we have only property C instead of the expected B and C.
+    The solution to this is to reapply the properties later using DelayCommand().
+    
+    This introduces a new problem. If the function that removes and reapplies the properties is called
+    multiple times quickly, it can queue up a series of delayed applications. This causes two problems:
+    if the data on which the properties are calculated changes, the earlier delayed applications can
+    apply properties that should no longer be used, but they are anyway because the delayed code doesn't
+    know this. To illustrate:
+        1) The application function is called; it removes all properties, schedules delayed application of property A.
+        2) The application function is called again; it removes all properties, schedules delayed application of property B.
+        3) Delayed application of property A occurs.
+        4) Delayed application of property B occurs.
+        End result: we have both property A and B instead of the expected result, B alone.
+    Another problem is that we can end up with multiple copies of the same property.
+    If this happens enough, it can cause "Effect List overflow" errors. Also, if the property stacks
+    with itself, this gives a greater bonus or penalty than it should. To illustrate:
+        1) The application function is called; it removes all properties, schedules delayed application of property C.
+        2) The application function is called; it removes all properties, schedules delayed application of property C.
+        3) Delayed application of property C occurs.
+        4) Delayed application of property C occurs.
+        End result: we have property C twice instead of just once.
+    The solution is to both these problems is for the application function to increment an integer each time it
+    is called and to pass this to the delayed application function. The delayed application actually happens only
+    if the generation when it runs is the same as the generation when it was scheduled. To illustrate:
+        1) We start with property A and B applied.
+        2) The application function is called: it increments generation to 2, schedules delayed application of property B and C.
+        3) The application function is called: it increments generation to 3, schedules delayed application of property C.
+        4) The generation 2 delayed application function executes: it sees that the current generation is 3 and simply exits, doing nothing.
+        5) The generation 3 delayed application function executes: it sees that the current generation is 3, so it applies property C.
+        End result: we have one copy of property C, which is what we wanted.
+    */
+    
+    if (fDelay < 0.0f || GetStringLength(sGenerationName) == 0)
+    {
+        AddItemProperty(nDurationType, ipProperty, oItem, fDuration);
+    }
+    else
+    {
+        int nExpectedGeneration = GetLocalInt(oGenerationHolder, sGenerationName); //This gets the generation now
+        DelayCommand(
+            fDelay, 
+            DelayedAddItemProperty(
+                nExpectedGeneration, 
+                GetLocalInt(oGenerationHolder, sGenerationName), //This is delayed by the DelayCommand, so it gets the generation when DelayedAddItemProperty is actually executed
+                nDurationType, 
+                ipProperty,
+                oItem,
+                fDuration
+            )
+        );
+    }
+}
+
+void FeatUsePerDay(object oPC, int iFeat, int iAbiMod = ABILITY_CHARISMA, int iMod = 0, int iMin = 1)
+{
+    if(!GetHasFeat(iFeat,oPC))
+        return;
+
+    int iAbi = GetAbilityModifier(iAbiMod, oPC);
+    iAbi = (iAbi > 0) ? iAbi : 0;
+
+    if (iAbiMod == -1) iAbi = 0;
+    iAbi += iMod;
+
+    if(iAbi < iMin)
+        iAbi = iMin;
+
+    while(GetHasFeat(iFeat, oPC))
+        DecrementRemainingFeatUses(oPC, iFeat);
+
+    while(iAbi)
+    {
+        IncrementRemainingFeatUses(oPC, iFeat);
+        iAbi--;
+    }
+}
+
+void DomainUses(object oPC)
+{
+    int nUses;
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_STRENGTH, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_STRENGTH_DOMAIN_POWER))
+    {
+        nUses = GetLevelByClass(CLASS_TYPE_MIGHTY_CONTENDER_KORD, oPC) ? GetAbilityModifier(ABILITY_STRENGTH, oPC) : 1;
+        FeatUsePerDay(oPC, FEAT_STRENGTH_DOMAIN_POWER, -1, nUses);
+    }
+    if(GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC) && GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) && PRC_Funcs_GetFeatKnown(oPC, FEAT_SUN_DOMAIN_POWER))
+    {
+        nUses = GetHasFeat(FEAT_EXTRA_TURNING, oPC) ? 7 : 3;
+        FeatUsePerDay(oPC, FEAT_SUN_DOMAIN_POWER, ABILITY_CHARISMA, nUses);
+    }
+    else if(!GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_SUN_DOMAIN_POWER))
+        FeatUsePerDay(oPC, FEAT_SUN_DOMAIN_POWER, -1, 1);
+
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_BLIGHTBRINGER, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_DOMAIN_POWER_BLIGHTBRINGER))
+        FeatUsePerDay(oPC, FEAT_DOMAIN_POWER_BLIGHTBRINGER, ABILITY_CHARISMA, 3);
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_AIR, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_AIR_DOMAIN_POWER))
+        FeatUsePerDay(oPC, FEAT_AIR_DOMAIN_POWER, ABILITY_CHARISMA, 3);
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_EARTH, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_EARTH_DOMAIN_POWER))
+        FeatUsePerDay(oPC, FEAT_EARTH_DOMAIN_POWER, ABILITY_CHARISMA, 3);
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_FIRE, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_FIRE_DOMAIN_POWER))
+        FeatUsePerDay(oPC, FEAT_FIRE_DOMAIN_POWER, ABILITY_CHARISMA, 3);
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_WATER, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_WATER_DOMAIN_POWER))
+        FeatUsePerDay(oPC, FEAT_WATER_DOMAIN_POWER, ABILITY_CHARISMA, 3);
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_SLIME, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_DOMAIN_POWER_SLIME))
+        FeatUsePerDay(oPC, FEAT_DOMAIN_POWER_SLIME, ABILITY_CHARISMA, 3);
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_SPIDER, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_DOMAIN_POWER_SPIDER))
+        FeatUsePerDay(oPC, FEAT_DOMAIN_POWER_SPIDER, ABILITY_CHARISMA, 3);
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_SCALEYKIND, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_DOMAIN_POWER_SCALEYKIND))
+        FeatUsePerDay(oPC, FEAT_DOMAIN_POWER_SCALEYKIND, ABILITY_CHARISMA, 3);
+    if(!GetHasFeat(FEAT_BONUS_DOMAIN_PLANT, oPC) || PRC_Funcs_GetFeatKnown(oPC, FEAT_PLANT_DOMAIN_POWER))
+        FeatUsePerDay(oPC, FEAT_PLANT_DOMAIN_POWER, ABILITY_CHARISMA, 3);
+}
+
+void MephlingBreath(object oPC)  //:: Mephlings
+{	
+	if(!GetHasFeat(FEAT_MEPHLING_BREATH, oPC)) 
+		return;    
+	
+	int nMephBreath = ((1 + GetHitDice(oPC)) / 4);
+	
+    FeatUsePerDay(oPC, FEAT_MEPHLING_BREATH, -1, nMephBreath);	
+}
+
+void FeatAlaghar(object oPC)
+{
+    int iAlagharLevel = GetLevelByClass(CLASS_TYPE_ALAGHAR, oPC);
+
+    if (!iAlagharLevel) return;
+
+    int iClangStrike = iAlagharLevel/3;
+    int iClangMight = (iAlagharLevel - 1)/3;
+    int iRockburst = (iAlagharLevel + 2)/4;
+
+    FeatUsePerDay(oPC, FEAT_CLANGEDDINS_STRIKE, -1, iClangStrike);
+    FeatUsePerDay(oPC, FEAT_CLANGEDDINS_MIGHT, -1, iClangMight);
+    FeatUsePerDay(oPC, FEAT_ALAG_ROCKBURST, -1, iRockburst);
+}
+
+
+void FeatDiabolist(object oPC)
+{
+   int Diabol = GetLevelByClass(CLASS_TYPE_DIABOLIST, oPC);
+
+   if (!Diabol) return;
+
+   int iUse = (Diabol + 3)/3;
+
+   FeatUsePerDay(oPC,FEAT_DIABOL_DIABOLISM_1,-1,iUse);
+   FeatUsePerDay(oPC,FEAT_DIABOL_DIABOLISM_2,-1,iUse);
+   FeatUsePerDay(oPC,FEAT_DIABOL_DIABOLISM_3,-1,iUse);
+}
+
+void FeatNinja (object oPC)
+{
+    int iNinjaLevel = GetLevelByClass(CLASS_TYPE_NINJA, oPC);
+    // Ascetic Stalker
+    if (GetHasFeat(FEAT_ASCETIC_STALKER, oPC))
+        iNinjaLevel += GetLevelByClass(CLASS_TYPE_MONK, oPC);;     
+
+    if (!iNinjaLevel) return;
+
+    int nUsesLeft = iNinjaLevel/2;
+    if (nUsesLeft < 1)
+        nUsesLeft = 1;
+        
+    // Expanded Ki Pool    
+    if (GetHasFeat(FEAT_EXPANDED_KI_POOL, oPC)) nUsesLeft += 3;
+
+    FeatUsePerDay(oPC, FEAT_KI_POWER, ABILITY_WISDOM, nUsesLeft);
+    FeatUsePerDay(oPC, FEAT_GHOST_STEP, ABILITY_WISDOM, nUsesLeft);
+    FeatUsePerDay(oPC, FEAT_GHOST_STRIKE, ABILITY_WISDOM, nUsesLeft);
+    FeatUsePerDay(oPC, FEAT_GHOST_WALK, ABILITY_WISDOM, nUsesLeft);
+    FeatUsePerDay(oPC, FEAT_KI_DODGE, ABILITY_WISDOM, nUsesLeft);
+
+    SetLocalInt(oPC, "prc_ninja_ki", nUsesLeft);
+}
+
+void BarbarianRage(object oPC)
+{
+    if(!GetHasFeat(FEAT_BARBARIAN_RAGE, oPC)) return;
+
+    int nUses = (GetLevelByClass(CLASS_TYPE_BARBARIAN, oPC) + GetLevelByClass(CLASS_TYPE_BLACK_BLOOD_CULTIST, oPC) + GetLevelByClass(CLASS_TYPE_PRC_EYE_OF_GRUUMSH, oPC)) / 4 + 1;
+    nUses += (GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oPC) + 2) / 5;
+    nUses += (GetLevelByClass(CLASS_TYPE_BATTLERAGER, oPC) + 1) / 2;
+    nUses += (GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC) + 2) / 4;
+    nUses += GetLevelByClass(CLASS_TYPE_RUNESCARRED, oPC) ? ((GetLevelByClass(CLASS_TYPE_RUNESCARRED, oPC) / 4) + 1) : 0;
+	nUses += (GetLevelByClass(CLASS_TYPE_TOTEM_RAGER, oPC) + 4) / 6;	
+
+    if(GetHasFeat(FEAT_EXTRA_RAGE, oPC)) nUses += 2;
+
+    FeatUsePerDay(oPC, FEAT_BARBARIAN_RAGE, -1, nUses);
+    FeatUsePerDay(oPC, FEAT_GREATER_RAGE, -1, nUses);
+
+    if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oPC) > 0)
+    {
+        if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oPC) > 9)
+            nUses = 3;
+        else if(GetLevelByClass(CLASS_TYPE_RAGE_MAGE, oPC) > 4)
+            nUses = 2;
+        else
+            nUses = 1;
+
+        FeatUsePerDay(oPC, FEAT_SPELL_RAGE, -1, nUses);
+    }
+}
+
+void BardSong(object oPC)
+{
+    // This is used to set the number of bardic song uses per day, as bardic PrCs can increase it
+    // or other classes can grant it on their own
+    if(!GetHasFeat(FEAT_BARD_SONGS, oPC)) return;
+
+    int nTotal = GetLevelByClass(CLASS_TYPE_BARD, oPC);
+    nTotal += GetLevelByClass(CLASS_TYPE_DIRGESINGER, oPC);
+    nTotal += GetLevelByClass(CLASS_TYPE_VIRTUOSO, oPC);
+    nTotal += GetLevelByClass(CLASS_TYPE_SUBLIME_CHORD, oPC) / 2;
+
+    if(GetHasFeat(FEAT_EXTRA_MUSIC, oPC)) nTotal += 4;
+
+    FeatUsePerDay(oPC, FEAT_BARD_SONGS, -1, nTotal);
+}
+
+void FeatVirtuoso(object oPC)
+{
+    int iVirtuosoLevel = GetLevelByClass(CLASS_TYPE_VIRTUOSO, oPC);
+    if (!iVirtuosoLevel) return;
+
+    int nUses = GetLevelByClass(CLASS_TYPE_BARD, oPC) + iVirtuosoLevel;
+    if(GetHasFeat(FEAT_EXTRA_MUSIC, oPC)) nUses += 4;
+    SetPersistantLocalInt(oPC, "Virtuoso_Performance_Uses", nUses);
+    int nFeat;
+    for(nFeat = FEAT_VIRTUOSO_SUSTAINING_SONG; nFeat <= FEAT_VIRTUOSO_PERFORMANCE; nFeat++)
+    {
+        FeatUsePerDay(oPC, nFeat, -1, nUses);
+    }
+}
+
+void HexCurse(object oPC)
+{
+    int iHexLevel = GetLevelByClass(CLASS_TYPE_HEXBLADE, oPC);
+
+    if (!iHexLevel) return;
+
+    //Hexblade's Curse
+    int nUses = (iHexLevel + 3) / 4; // every 4 levels get 1 more use
+    FeatUsePerDay(oPC, FEAT_HEXCURSE, ABILITY_CHARISMA, nUses);
+
+    //Swift Cast
+    if(iHexLevel > 13)
+        nUses = (iHexLevel + 2) / 4;
+    else if(iHexLevel > 10)
+        nUses = 3;
+    else if(iHexLevel > 7)
+        nUses = 2;
+    else if(iHexLevel > 5)
+        nUses = 1;
+    else
+        nUses = 0;
+    FeatUsePerDay(oPC, FEAT_SWIFT_CAST, -1, nUses);
+}
+
+void FeatShadowblade(object oPC)
+{
+    int iShadowLevel = GetLevelByClass(CLASS_TYPE_SHADOWBLADE, oPC);
+    if (!iShadowLevel) return;
+
+    FeatUsePerDay(oPC, FEAT_UNERRING_STRIKE, -1, iShadowLevel);
+    FeatUsePerDay(oPC, FEAT_UNEXPECTED_STRIKE, -1, iShadowLevel);
+    FeatUsePerDay(oPC, FEAT_EPHEMERAL_WEAPON, -1, iShadowLevel);
+    FeatUsePerDay(oPC, FEAT_SHADOWY_STRIKE, -1, iShadowLevel);
+    FeatUsePerDay(oPC, FEAT_FAR_SHADOW, -1, iShadowLevel);
+}
+
+void FeatNoble(object oPC)
+{
+    int iNobleLevel = GetLevelByClass(CLASS_TYPE_NOBLE, oPC);
+    if (!iNobleLevel) return;
+
+    int nBonus = 0;
+    if (iNobleLevel >= 17) nBonus = 5;
+    else if (iNobleLevel >= 13) nBonus = 4;
+    else if (iNobleLevel >= 9) nBonus = 3;
+    else if (iNobleLevel >= 5) nBonus = 2;
+    else if (iNobleLevel >= 2) nBonus = 1;
+
+    FeatUsePerDay(oPC, FEAT_NOBLE_CONFIDENCE, -1, nBonus);
+
+    nBonus = (iNobleLevel - 11) / 3 + 1;
+
+    FeatUsePerDay(oPC, FEAT_NOBLE_GREATNESS, -1, nBonus);
+}
+
+void DarkKnowledge(object oPC)
+{
+    int iArchivistLevel = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC);
+    if(!iArchivistLevel) return;
+
+    int nUses = (iArchivistLevel / 3) + 3;
+    FeatUsePerDay(oPC, FEAT_DK_TACTICS,       -1, nUses);
+    FeatUsePerDay(oPC, FEAT_DK_PUISSANCE,     -1, nUses);
+    FeatUsePerDay(oPC, FEAT_DK_FOE,           -1, nUses);
+    FeatUsePerDay(oPC, FEAT_DK_DREADSECRET,   -1, nUses);
+    FeatUsePerDay(oPC, FEAT_DK_FOREKNOWLEDGE, -1, nUses);
+}
+
+void FeatImbueArrow(object oPC)
+{
+    if(GetPRCSwitch(PRC_USE_NEW_IMBUE_ARROW))
+        FeatUsePerDay(oPC, FEAT_PRESTIGE_IMBUE_ARROW, -1, 0, 0);
+}
+
+void DragonDisciple(object oPC)
+{
+    if(!GetHasFeat(FEAT_DRAGON_DIS_BREATH, oPC))
+        return;
+
+    //Dragon Disciples that do not possess any breath weapon
+    if(GetHasFeat(FEAT_CHIANG_LUNG_DRAGON, oPC)
+    || GetHasFeat(FEAT_PAN_LUNG_DRAGON, oPC)
+    || GetHasFeat(FEAT_SHEN_LUNG_DRAGON, oPC)
+    || GetHasFeat(FEAT_TUN_MI_LUNG_DRAGON, oPC)
+    || GetHasFeat(FEAT_YU_LUNG_DRAGON, oPC))
+        DecrementRemainingFeatUses(oPC, FEAT_DRAGON_DIS_BREATH);
+}
+
+void Warlock(object oPC)
+{
+    if(GetHasFeat(FEAT_FIENDISH_RESILIENCE, oPC))
+    {
+        //Add daily Uses of Fiendish Resilience for epic warlock
+        if(GetHasFeat(FEAT_EPIC_FIENDISH_RESILIENCE_I, oPC))
+        {
+            int nFeatAmt = 0;
+            int bDone = FALSE;
+            while(!bDone)
+            {
+                if(nFeatAmt >= 9)
+                    bDone = TRUE;
+                else if(GetHasFeat(FEAT_EPIC_FIENDISH_RESILIENCE_II + nFeatAmt, oPC))
+                    nFeatAmt++;
+                else
+                    bDone = TRUE;
+            }
+            nFeatAmt++;
+            FeatUsePerDay(oPC, FEAT_FIENDISH_RESILIENCE, -1, nFeatAmt);
+        }
+        else
+            FeatUsePerDay(oPC, FEAT_FIENDISH_RESILIENCE, -1, 1);
+    }
+
+    //Hellfire infusion
+    int nCha = GetAbilityModifier(ABILITY_CHARISMA, oPC);
+    FeatUsePerDay(oPC, FEAT_HELLFIRE_INFUSION, -1, nCha);
+
+    //Eldritch Spellweave
+    nCha += 3;
+    FeatUsePerDay(oPC, FEAT_ELDRITCH_SPELLWEAVE, -1, nCha);
+}
+
+void KotMC(object oPC)
+{
+    int iKotMCLevel = GetLevelByClass(CLASS_TYPE_KNIGHT_MIDDLECIRCLE, oPC);
+    if(!iKotMCLevel) return;
+
+    int nUses = iKotMCLevel / 3;
+    FeatUsePerDay(oPC, FEAT_KOTMC_TRUE_STRIKE, -1, nUses);
+}
+
+void Templar(object oPC)
+{
+    if(!GetHasFeat(FEAT_SECULAR_AUTHORITY, oPC)) return;
+
+    int nTemplar = GetLevelByClass(CLASS_TYPE_TEMPLAR, oPC);
+    int nUses = nTemplar + ((GetHitDice(oPC) - nTemplar) / 4);
+    FeatUsePerDay(oPC, FEAT_SECULAR_AUTHORITY, -1, nUses);
+}
+
+void FeatRacial(object oPC)
+{
+    //Shifter bonus shifting uses
+    int nRace = GetRacialType(oPC);
+    if(nRace == RACIAL_TYPE_SHIFTER)
+    {
+        int nShiftFeats = GetShiftingFeats(oPC);
+        int nBonusShiftUses = (nShiftFeats / 2) + 1;
+        FeatUsePerDay(oPC, FEAT_SHIFTER_SHIFTING, -1, nBonusShiftUses);
+    }
+    else if(nRace == RACIAL_TYPE_FORESTLORD_ELF)
+    {
+        int nUses = GetHitDice(oPC) / 5 + 1;
+        FeatUsePerDay(oPC, FEAT_FORESTLORD_TREEWALK, -1, nUses);
+    }
+}
+
+void CombatMedic(object oPC)
+{
+    int iCombMed = GetLevelByClass(CLASS_TYPE_COMBAT_MEDIC, oPC);
+    if(!iCombMed) return;
+
+    FeatUsePerDay(oPC, FEAT_HEALING_KICKER_1, ABILITY_WISDOM, iCombMed);
+    FeatUsePerDay(oPC, FEAT_HEALING_KICKER_2, ABILITY_WISDOM, iCombMed);
+    FeatUsePerDay(oPC, FEAT_HEALING_KICKER_3, ABILITY_WISDOM, iCombMed);
+}
+
+void MasterOfShrouds(object oPC)
+{
+    if(!GetLevelByClass(CLASS_TYPE_MASTER_OF_SHROUDS, oPC)) return;
+
+    FeatUsePerDay(oPC, FEAT_MOS_UNDEAD_1, ABILITY_CHARISMA, 3);
+    FeatUsePerDay(oPC, FEAT_MOS_UNDEAD_2, ABILITY_CHARISMA, 3);
+    FeatUsePerDay(oPC, FEAT_MOS_UNDEAD_3, ABILITY_CHARISMA, 3);
+    FeatUsePerDay(oPC, FEAT_MOS_UNDEAD_4, ABILITY_CHARISMA, 3);
+}
+
+void SLAUses(object oPC)
+{
+    if(!GetHasFeat(FEAT_SPELL_LIKE_ABILITY_1, oPC)) return;
+
+    FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_1, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_1"));
+    FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_2, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_2"));
+    FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_3, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_3"));
+    FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_4, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_4"));
+    FeatUsePerDay(oPC, FEAT_SPELL_LIKE_ABILITY_5, -1, GetPersistantLocalInt(oPC, "PRC_SLA_Uses_5"));
+}
+
+void ShadowShieldUses(object oPC)
+{
+    if(!GetHasFeat(FEAT_SA_SHIELDSHADOW, oPC)) return;
+    FeatUsePerDay(oPC, FEAT_SA_SHIELDSHADOW, -1, GetPrCAdjustedCasterLevelByType(TYPE_ARCANE, oPC));
+}
+
+void BlighterFeats(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_BLIGHTER, oPC);
+    if(0 >= nClass) return;
+    
+    if (nClass == 3)
+        FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 1);
+    else if (nClass == 4)
+        FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 2);   
+    else if (nClass == 5)
+    {
+        FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 2);         
+        FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 1);
+    }  
+    else if (nClass == 6)
+    {
+        FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 3);         
+        FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 1);
+    } 
+    else if (nClass == 7)
+    {
+        FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 3);         
+        FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 2);
+    }  
+    else if (nClass == 8)
+    {
+        FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 4);         
+        FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 2);
+    }  
+    else if (nClass == 9)
+    {
+        FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 4);         
+        FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 3);
+    }  
+    else 
+    {
+        FeatUsePerDay(oPC, FEAT_UNDEAD_WILD_SHAPE, -1, 5);         
+        FeatUsePerDay(oPC, FEAT_CONTAGIOUS_TOUCH, -1, 3);
+    }      
+}
+
+void MysteryFeats(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_CHILD_OF_NIGHT, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 10)
+            FeatUsePerDay(oPC, FEAT_CLOAK_SHADOWS, -1, 2);
+        else if (nClass >= 6)
+            FeatUsePerDay(oPC, FEAT_CLOAK_SHADOWS, -1, 3);
+        else
+            FeatUsePerDay(oPC, FEAT_CLOAK_SHADOWS, -1, 1);        
+            
+        if (nClass >= 7)
+            FeatUsePerDay(oPC, FEAT_DANCING_SHADOWS, -1, 2);
+        else
+            FeatUsePerDay(oPC, FEAT_DANCING_SHADOWS, -1, 1);
+    }
+    nClass = GetLevelByClass(CLASS_TYPE_NOCTUMANCER, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 8)
+            FeatUsePerDay(oPC, FEAT_INNATE_COUNTERSPELL, -1, 3);
+        else if (nClass >= 5)
+            FeatUsePerDay(oPC, FEAT_INNATE_COUNTERSPELL, -1, 2);
+        else
+            FeatUsePerDay(oPC, FEAT_INNATE_COUNTERSPELL, -1, 1); 
+    }   
+    nClass = GetLevelByClass(CLASS_TYPE_SHADOWSMITH, oPC);
+    if(nClass > 0)
+    {
+        FeatUsePerDay(oPC, FEAT_TOUCH_SHADOW  , -1, nClass); 
+        FeatUsePerDay(oPC, FEAT_SHROUD_SHADOW , -1, nClass);
+        FeatUsePerDay(oPC, FEAT_SHADOW_CRAFT  , -1, nClass/2);
+        FeatUsePerDay(oPC, FEAT_ARMOR_SHADOW  , -1, nClass/2);
+        FeatUsePerDay(oPC, FEAT_ARMOR_SHADOW_Q, -1, nClass/2);
+    }    
+}
+
+void WildMage(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_WILD_MAGE, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 8)
+            FeatUsePerDay(oPC, FEAT_WILD_MAGE_RANDOM_DEFLECTOR, -1, 2);
+        else if (nClass >= 5)
+            FeatUsePerDay(oPC, FEAT_WILD_MAGE_RANDOM_DEFLECTOR, -1, 3);
+        else
+            FeatUsePerDay(oPC, FEAT_WILD_MAGE_RANDOM_DEFLECTOR, -1, 1); 
+    }        
+} 
+
+void Factotum(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_FACTOTUM, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 20)
+        {
+            FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_TURN, ABILITY_WISDOM, 0, 6);
+            FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_HEAL, ABILITY_WISDOM, 0, 6);
+        }    
+        else if (nClass >= 15)
+        {
+            FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_TURN, ABILITY_WISDOM, 0, 5);
+            FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_HEAL, ABILITY_WISDOM, 0, 5);
+        }  
+        else if (nClass >= 10)
+        {
+            FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_TURN, ABILITY_WISDOM, 0, 4);
+            FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_HEAL, ABILITY_WISDOM, 0, 4);
+        }              
+        else
+        {
+            FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_TURN, ABILITY_WISDOM, 0, 3);
+            FeatUsePerDay(oPC, FEAT_OPPORTUNISTIC_PIETY_HEAL, ABILITY_WISDOM, 0, 3);
+        }  
+    }        
+}
+
+void Sharess(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC);
+    if(nClass > 0)
+    {
+        FeatUsePerDay(oPC, FEAT_CELEBRANT_SHARESS_FASCINATE , -1, 0, nClass); 
+        FeatUsePerDay(oPC, FEAT_CELEBRANT_SHARESS_CONFUSE   , -1, 0, nClass);
+        FeatUsePerDay(oPC, FEAT_CELEBRANT_SHARESS_DOMINATE  , -1, 0, nClass);
+    } 
+}    
+
+void SoulbornDefense(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_SOULBORN, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 37)
+            FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 8);         
+        else if (nClass >= 33)
+            FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 7);         
+        else if (nClass >= 29)
+            FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 6);     
+        else if (nClass >= 25)
+            FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 5);         
+        else if (nClass >= 21)
+            FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 4);     
+        else if (nClass >= 17)
+            FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 3);    
+        else if (nClass >= 13)
+            FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 2);             
+        else
+            FeatUsePerDay(oPC, FEAT_SHARE_INCARNUM_DEFENSE, -1, 0, 1);
+    }        
+}
+
+void TotemistReshape(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_TOTEMIST, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 40)
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 9);     
+        else if (nClass >= 36)
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 8);     
+        else if (nClass >= 32)
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 7);     
+        else if (nClass >= 28)
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 6);     
+        else if (nClass >= 24)
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 5);     
+        else if (nClass >= 20)
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 4); 
+        else if (nClass >= 16)
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 3);             
+        else if (nClass >= 12)
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 2);             
+        else
+            FeatUsePerDay(oPC, FEAT_REBIND_TOTEM_SOULMELD, -1, 0, 1);
+    }        
+}
+
+void CWSamurai(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_CW_SAMURAI, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 17)
+            FeatUsePerDay(oPC, FEAT_KIAI_SMITE, -1, 0, 4); 
+        else if (nClass >= 12)
+            FeatUsePerDay(oPC, FEAT_KIAI_SMITE, -1, 0, 3);             
+        else if (nClass >= 7)
+            FeatUsePerDay(oPC, FEAT_KIAI_SMITE, -1, 0, 2);             
+        else
+            FeatUsePerDay(oPC, FEAT_KIAI_SMITE, -1, 0, 1);
+    }        
+}
+
+void CrusaderSmite(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_CRUSADER, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 18)
+            FeatUsePerDay(oPC, FEAT_CRUSADER_SMITE, -1, 0, 2);            
+        else
+            FeatUsePerDay(oPC, FEAT_CRUSADER_SMITE, -1, 0, 1);
+    }        
+}
+
+void AnimaMage(object oPC)
+{
+    int nClass = GetLevelByClass(CLASS_TYPE_ANIMA_MAGE, oPC);
+    if(nClass > 0)
+    {
+        if (nClass >= 9)
+            FeatUsePerDay(oPC, FEAT_ANIMA_VESTIGE_METAMAGIC, -1, 0, 3);    
+        else if (nClass >= 7)
+            FeatUsePerDay(oPC, FEAT_ANIMA_VESTIGE_METAMAGIC, -1, 0, 2);             
+        else
+            FeatUsePerDay(oPC, FEAT_ANIMA_VESTIGE_METAMAGIC, -1, 0, 1);
+    }        
+}
+
+void FeatSpecialUsePerDay(object oPC)
+{
+    FeatUsePerDay(oPC, FEAT_WWOC_WIDEN_SPELL, ABILITY_CHARISMA, GetLevelByClass(CLASS_TYPE_WAR_WIZARD_OF_CORMYR, oPC));
+    FeatUsePerDay(oPC, FEAT_FIST_DAL_QUOR_STUNNING_STRIKE, -1, GetLevelByClass(CLASS_TYPE_FIST_DAL_QUOR, oPC));
+    FeatUsePerDay(oPC, FEAT_AD_FALSE_KEENNESS, -1, GetLevelByClass(CLASS_TYPE_ARCANE_DUELIST, oPC));
+    FeatUsePerDay(oPC, FEAT_LASHER_STUNNING_SNAP, -1, GetLevelByClass(CLASS_TYPE_LASHER, oPC));
+    FeatUsePerDay(oPC, FEAT_AD_BLUR, -1, GetLevelByClass(CLASS_TYPE_ARCANE_DUELIST, oPC));
+    FeatUsePerDay(oPC, FEAT_SHADOW_RIDE, -1, GetLevelByClass(CLASS_TYPE_CRINTI_SHADOW_MARAUDER, oPC));
+    FeatUsePerDay(oPC, FEAT_SHADOWJUMP, -1, GetLevelByClass(CLASS_TYPE_SHADOWLORD, oPC));
+    FeatUsePerDay(oPC, FEAT_SHADOWBANE_SMITE, -1, (GetLevelByClass(CLASS_TYPE_SHADOWBANE_INQUISITOR, oPC)+2)/4);
+    FeatUsePerDay(oPC, FEAT_INCARNUM_RADIANCE, -1, (GetLevelByClass(CLASS_TYPE_INCARNATE, oPC)+2)/5);
+    FeatUsePerDay(oPC, FEAT_RAPID_MELDSHAPING, -1, (GetLevelByClass(CLASS_TYPE_INCARNATE, oPC)+1)/6);
+    FeatUsePerDay(oPC, FEAT_SMITE_OPPOSITION, -1, (GetLevelByClass(CLASS_TYPE_SOULBORN, oPC)+5)/5);
+    FeatUsePerDay(oPC, FEAT_SMITE_CHAOS, -1, (GetLevelByClass(CLASS_TYPE_SAPPHIRE_HIERARCH, oPC)+2)/3);
+    FeatUsePerDay(oPC, FEAT_INCANDESCENT_OVERLOAD, -1, (GetLevelByClass(CLASS_TYPE_INCANDESCENT_CHAMPION, oPC)-1)/3);
+    FeatUsePerDay(oPC, FEAT_NECROCARNATE_SOULSHIELD, -1, GetLevelByClass(CLASS_TYPE_NECROCARNATE, oPC)/2);
+    FeatUsePerDay(oPC, FEAT_SCION_DANTALION_SCHOLARSHIP, -1, GetLevelByClass(CLASS_TYPE_SCION_DANTALION, oPC));
+    FeatUsePerDay(oPC, FEAT_SMITE_GOOD_ALIGN, -1, (GetLevelByClass(CLASS_TYPE_FISTRAZIEL, oPC)+1)/2);
+    FeatUsePerDay(oPC, FEAT_FIST_OF_IRON, ABILITY_WISDOM, 3);
+    FeatUsePerDay(oPC, FEAT_SMITE_UNDEAD, ABILITY_CHARISMA, 3);
+    FeatUsePerDay(oPC, FEAT_COC_WRATH, ABILITY_CHARISMA, 3);
+    FeatUsePerDay(oPC, FEAT_KILLOREN_ASPECT_D, ABILITY_CHARISMA);
+    FeatUsePerDay(oPC, FEAT_AVENGING_STRIKE, ABILITY_CHARISMA, 0, 1);
+    FeatUsePerDay(oPC, FEAT_INCARNUM_BLADE_REBIND, ABILITY_CONSTITUTION, 1);
+    FeatUsePerDay(oPC, FEAT_WITCHBORN_INTEGUMENT, ABILITY_CONSTITUTION, 1);
+    FeatUsePerDay(oPC, FEAT_LIPS_RAPTUR);
+	FeatUsePerDay(oPC, FEAT_COMMAND_SPIDERS, ABILITY_CHARISMA, 3);
+	FeatUsePerDay(oPC, FEAT_FM_FOREST_DOMINION, ABILITY_CHARISMA, 3);
+    FeatDiabolist(oPC);
+    FeatAlaghar(oPC);
+    ShadowShieldUses(oPC);
+    CombatMedic(oPC);
+    FeatNinja(oPC);
+    FeatNoble(oPC);
+    MasterOfShrouds(oPC);
+    HexCurse(oPC);
+    FeatRacial(oPC);
+    FeatShadowblade(oPC);
+    SoulbornDefense(oPC);
+
+    int nDread = GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC);
+    if (nDread >= 17)
+        FeatUsePerDay(oPC, FEAT_DN_ENERVATING_TOUCH, -1, nDread);
+    else
+        FeatUsePerDay(oPC, FEAT_DN_ENERVATING_TOUCH, -1, nDread/2);
+
+    SLAUses(oPC);
+    DomainUses(oPC);
+    BardSong(oPC);
+    BarbarianRage(oPC);
+    FeatVirtuoso(oPC);
+    ResetExtraStunfistUses(oPC);
+    DarkKnowledge(oPC);
+    FeatImbueArrow(oPC);
+    DragonDisciple(oPC);
+    Warlock(oPC);
+    KotMC(oPC);
+    Templar(oPC);
+    BlighterFeats(oPC);
+    MysteryFeats(oPC);
+    WildMage(oPC);
+    Factotum(oPC);
+    Sharess(oPC);
+    TotemistReshape(oPC);
+    CWSamurai(oPC);
+    CrusaderSmite(oPC);
+    AnimaMage(oPC);
+	MephlingBreath(oPC);
+}
+
diff --git a/trunk/include/prc_inc_itmrstr.nss b/trunk/include/prc_inc_itmrstr.nss
new file mode 100644
index 00000000..7f2ca808
--- /dev/null
+++ b/trunk/include/prc_inc_itmrstr.nss
@@ -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);
+    }
+}
\ No newline at end of file
diff --git a/trunk/include/prc_inc_leadersh.nss b/trunk/include/prc_inc_leadersh.nss
new file mode 100644
index 00000000..d305b67a
--- /dev/null
+++ b/trunk/include/prc_inc_leadersh.nss
@@ -0,0 +1,1043 @@
+//:: Updated for .35 by Jaysyn 2023/03/10
+
+//////////////////////////////////////////////////
+/*                 Constants                    */
+//////////////////////////////////////////////////
+
+const string COHORT_DATABASE     = "PRCCOHORTS";
+const string COHORT_TAG          = "prc_cohort";
+
+//in the database there is the folloxing data structures:
+/*
+    int    CohortCount      (total number of cohorts)
+    object Cohort_X_obj     (cohort itself)
+    string Cohort_X_name    (cohort name)
+    int    Cohort_X_race    (cohort race)
+    int    Cohort_X_class1  (cohort class pos1)
+    int    Cohort_X_class2  (cohort class pos2)
+    int    Cohort_X_class3  (cohort class pos3)
+    int    Cohort_X_order   (cohort law/chaos measure)
+    int    Cohort_X_moral   (cohort good/evil measure)
+    int    Cohort_X_ethran  (cohort has ethran feat)
+    string Cohort_X_cdkey   (cdkey of owning player)
+*/
+
+//////////////////////////////////////////////////
+/*             Function prototypes              */
+//////////////////////////////////////////////////
+
+int GetMaximumCohortCount(object oPC);
+object GetCohort(int nID, object oPC);
+int GetCurrentCohortCount(object oPC);
+int GetCohortMaxLevel(int nLeadership, object oPC);
+void RegisterAsCohort(object oPC);
+object AddCohortToPlayer(int nCohortID, object oPC);
+void AddCohortToPlayerByObject(object oCohort, object oPC, int bDoSetup = TRUE);
+void RemoveCohortFromPlayer(object oCohort, object oPC);
+int GetLeadershipScore(object oPC = OBJECT_SELF);
+void CheckHB(object oPC);
+void AddPremadeCohortsToDB();
+void StoreCohort(object oCohort);
+
+
+//////////////////////////////////////////////////
+/*                  Includes                    */
+//////////////////////////////////////////////////
+
+#include "prc_feat_const"
+#include "nw_o2_coninclude"
+//#include "inc_utility"
+#include "inc_ecl"
+#include "inc_nwnx_funcs"
+//#include "pnp_shft_poly" //for DoRandomAppearance
+
+
+//////////////////////////////////////////////////
+/*             Function definitions             */
+//////////////////////////////////////////////////
+
+object AddCohortToPlayer(int nCohortID, object oPC)
+{
+    object oCohort = RetrieveCampaignObject(COHORT_DATABASE, "Cohort_"+IntToString(nCohortID)+"_obj", GetLocation(oPC));
+    //give it a tag
+    AssignCommand(oCohort, SetIsDestroyable(TRUE, FALSE, FALSE));
+    DestroyObject(oCohort);
+    oCohort = CopyObject(oCohort, GetLocation(oPC), OBJECT_INVALID, COHORT_TAG);
+    SetLocalInt(oCohort, "CohortID", nCohortID);
+    //pass it to the next function
+    AddCohortToPlayerByObject(oCohort, oPC);
+    return oCohort;
+}
+
+//changes portrait, head, and appearance
+//based on the target race with a degree of randomization.
+//This should only be used on NPCs, not players.
+void DoRandomAppearance(int nRace, object oTarget = OBJECT_SELF)
+{
+    //store current appearance to be safe
+    int nAppearance; //appearance to change into
+    int nHeadMax;    //max head ID, changed to random 1-max
+    int nGender = GetGender(oTarget);
+    int nPortraitMin;//minimum row in portraits.2da
+    int nPortraitMax;//maximum row in portraits.2da
+    switch(nRace)
+    {
+        case RACIAL_TYPE_DWARF:
+            nAppearance = APPEARANCE_TYPE_DWARF;
+            if(nGender == GENDER_MALE)
+            {   nHeadMax = 10; nPortraitMin =   9;  nPortraitMax =  17; }
+            else
+            {   nHeadMax = 12; nPortraitMin =   1;  nPortraitMax =   8; }
+            break;
+        case RACIAL_TYPE_ELF:
+            nAppearance = APPEARANCE_TYPE_ELF;
+            if(nGender == GENDER_MALE)
+            {   nHeadMax = 10; nPortraitMin =  31;  nPortraitMax =  40; }
+            else
+            {   nHeadMax = 16; nPortraitMin =  18;  nPortraitMax =  30; }
+            break;
+        case RACIAL_TYPE_HALFELF:
+            nAppearance = APPEARANCE_TYPE_HALF_ELF;
+            if(nGender == GENDER_MALE)
+            {   nHeadMax = 18; nPortraitMin =  93;  nPortraitMax = 112; }
+            else
+            {   nHeadMax = 15; nPortraitMin =  67;  nPortraitMax = 92;  }
+            break;
+        case RACIAL_TYPE_HALFORC:
+            nAppearance = APPEARANCE_TYPE_HALF_ORC;
+            if(nGender == GENDER_MALE)
+            {   nHeadMax = 11; nPortraitMin = 134;  nPortraitMax = 139; }
+            else
+            {   nHeadMax = 1;  nPortraitMin = 130;  nPortraitMax = 133; }
+            break;
+        case RACIAL_TYPE_HUMAN:
+            nAppearance = APPEARANCE_TYPE_HUMAN;
+            if(nGender == GENDER_MALE)
+            {   nHeadMax = 18; nPortraitMin = 93;   nPortraitMax = 112; }
+            else
+            {   nHeadMax = 15; nPortraitMin = 67;   nPortraitMax = 92;  }
+            break;
+        case RACIAL_TYPE_HALFLING:
+            nAppearance = APPEARANCE_TYPE_HALFLING;
+            if(nGender == GENDER_MALE)
+            {   nHeadMax =  8; nPortraitMin = 61;   nPortraitMax = 66; }
+            else
+            {   nHeadMax = 11; nPortraitMin = 54;   nPortraitMax = 59;  }
+            break;
+        case RACIAL_TYPE_GNOME:
+            nAppearance = APPEARANCE_TYPE_GNOME;
+            if(nGender == GENDER_MALE)
+            {   nHeadMax = 11; nPortraitMin = 47;   nPortraitMax = 53; }
+            else
+            {   nHeadMax =  9; nPortraitMin = 41;   nPortraitMax = 46;  }
+            break;
+        default: //not a normal race, abort
+            return;
+    }
+    //change the appearance
+    SetCreatureAppearanceType(oTarget, nAppearance);
+
+    //need to be delayed a bit otherwise you get "supergnome" and "exploded elf" effects
+    DelayCommand(1.1, SetCreatureBodyPart(CREATURE_PART_RIGHT_SHIN,       d2(), oTarget));
+    DelayCommand(1.2, SetCreatureBodyPart(CREATURE_PART_LEFT_SHIN,        d2(), oTarget));
+    DelayCommand(1.3, SetCreatureBodyPart(CREATURE_PART_RIGHT_THIGH,      d2(), oTarget));
+    DelayCommand(1.4, SetCreatureBodyPart(CREATURE_PART_LEFT_THIGH,       d2(), oTarget));
+    DelayCommand(1.5, SetCreatureBodyPart(CREATURE_PART_TORSO,            d2(), oTarget));
+    DelayCommand(1.6, SetCreatureBodyPart(CREATURE_PART_RIGHT_FOREARM,    d2(), oTarget));
+    DelayCommand(1.7, SetCreatureBodyPart(CREATURE_PART_LEFT_FOREARM,     d2(), oTarget));
+    DelayCommand(1.8, SetCreatureBodyPart(CREATURE_PART_RIGHT_BICEP,      d2(), oTarget));
+    DelayCommand(1.9, SetCreatureBodyPart(CREATURE_PART_LEFT_BICEP,       d2(), oTarget));
+    
+    //dont do these body parts, they dont have tattoos and weird things could happen
+    //SetCreatureBodyPart(CREATURE_PART_BELT,             d2(), oTarget);
+    //SetCreatureBodyPart(CREATURE_PART_NECK,             d2(), oTarget);
+    //SetCreatureBodyPart(CREATURE_PART_RIGHT_SHOULDER,   d2(), oTarget);
+    //SetCreatureBodyPart(CREATURE_PART_LEFT_SHOULDER,    d2(), oTarget);
+    //SetCreatureBodyPart(CREATURE_PART_RIGHT_HAND,       d2(), oTarget);
+    //SetCreatureBodyPart(CREATURE_PART_LEFT_HAND,        d2(), oTarget);
+    //SetCreatureBodyPart(CREATURE_PART_PELVIS,           d2(), oTarget);
+    //SetCreatureBodyPart(CREATURE_PART_RIGHT_FOOT,       d2(), oTarget);
+    //SetCreatureBodyPart(CREATURE_PART_LEFT_FOOT,        d2(), oTarget);
+    //randomise the head
+    DelayCommand(2.0, SetCreatureBodyPart(CREATURE_PART_HEAD, Random(nHeadMax)+1, oTarget));
+
+    //remove any wings/tails
+    SetCreatureWingType(CREATURE_WING_TYPE_NONE, oTarget);
+    SetCreatureTailType(CREATURE_TAIL_TYPE_NONE, oTarget);
+
+    int nPortraitID = Random(nPortraitMax-nPortraitMin+1)+nPortraitMin;
+    string sPortraitResRef = Get2DACache("portraits", "BaseResRef", nPortraitID);
+    sPortraitResRef = GetStringLeft(sPortraitResRef, GetStringLength(sPortraitResRef)-1); //trim the trailing _
+    SetPortraitResRef(oTarget, sPortraitResRef);
+    SetPortraitId(oTarget, nPortraitID);
+}
+
+void CancelGreatFeats(object oSpawn)
+{
+    //store how many Great X feats they have
+    //this is to fix a bioware bug where de-leveling doesnt remove the stat bonus
+    int nGreatStr;
+    int nGreatDex;
+    int nGreatCon;
+    int nGreatInt;
+    int nGreatWis;
+    int nGreatCha;
+    if     (GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_10, oSpawn)) nGreatStr = 10;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_9, oSpawn)) nGreatStr = 9;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_8, oSpawn)) nGreatStr = 8;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_7, oSpawn)) nGreatStr = 7;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_6, oSpawn)) nGreatStr = 6;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_5, oSpawn)) nGreatStr = 5;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_4, oSpawn)) nGreatStr = 4;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_3, oSpawn)) nGreatStr = 3;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_2, oSpawn)) nGreatStr = 2;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_STRENGTH_1, oSpawn)) nGreatStr = 1;
+    if     (GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_10, oSpawn)) nGreatDex = 10;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_9, oSpawn)) nGreatDex = 9;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_8, oSpawn)) nGreatDex = 8;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_7, oSpawn)) nGreatDex = 7;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_6, oSpawn)) nGreatDex = 6;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_5, oSpawn)) nGreatDex = 5;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_4, oSpawn)) nGreatDex = 4;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_3, oSpawn)) nGreatDex = 3;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_2, oSpawn)) nGreatDex = 2;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_DEXTERITY_1, oSpawn)) nGreatDex = 1;
+    if     (GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_10, oSpawn)) nGreatCon = 10;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_9, oSpawn)) nGreatCon = 9;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_8, oSpawn)) nGreatCon = 8;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_7, oSpawn)) nGreatCon = 7;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_6, oSpawn)) nGreatCon = 6;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_5, oSpawn)) nGreatCon = 5;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_4, oSpawn)) nGreatCon = 4;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_3, oSpawn)) nGreatCon = 3;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_2, oSpawn)) nGreatCon = 2;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CONSTITUTION_1, oSpawn)) nGreatCon = 1;
+    if     (GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_10, oSpawn)) nGreatInt = 10;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_9, oSpawn)) nGreatInt = 9;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_8, oSpawn)) nGreatInt = 8;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_7, oSpawn)) nGreatInt = 7;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_6, oSpawn)) nGreatInt = 6;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_5, oSpawn)) nGreatInt = 5;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_4, oSpawn)) nGreatInt = 4;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_3, oSpawn)) nGreatInt = 3;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_2, oSpawn)) nGreatInt = 2;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_INTELLIGENCE_1, oSpawn)) nGreatInt = 1;
+    if     (GetHasFeat(FEAT_EPIC_GREAT_WISDOM_10, oSpawn)) nGreatWis = 10;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_9, oSpawn)) nGreatWis = 9;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_8, oSpawn)) nGreatWis = 8;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_7, oSpawn)) nGreatWis = 7;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_6, oSpawn)) nGreatWis = 6;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_5, oSpawn)) nGreatWis = 5;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_4, oSpawn)) nGreatWis = 4;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_3, oSpawn)) nGreatWis = 3;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_2, oSpawn)) nGreatWis = 2;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_WISDOM_1, oSpawn)) nGreatWis = 1;
+    if     (GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_10, oSpawn)) nGreatCha = 10;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_9, oSpawn)) nGreatCha = 9;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_8, oSpawn)) nGreatCha = 8;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_7, oSpawn)) nGreatCha = 7;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_6, oSpawn)) nGreatCha = 6;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_5, oSpawn)) nGreatCha = 5;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_4, oSpawn)) nGreatCha = 4;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_3, oSpawn)) nGreatCha = 3;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_2, oSpawn)) nGreatCha = 2;
+    else if(GetHasFeat(FEAT_EPIC_GREAT_CHARISMA_1, oSpawn)) nGreatCha = 1;
+
+    //apply penalties to counter the GreatX feats
+    if(GetPRCSwitch(PRC_NWNX_FUNCS))
+    {
+        if(nGreatStr) PRC_Funcs_ModAbilityScore(oSpawn, ABILITY_STRENGTH, -nGreatStr);
+        if(nGreatDex) PRC_Funcs_ModAbilityScore(oSpawn, ABILITY_DEXTERITY, -nGreatDex);
+        if(nGreatCon) PRC_Funcs_ModAbilityScore(oSpawn, ABILITY_CONSTITUTION, -nGreatCon);
+        if(nGreatInt) PRC_Funcs_ModAbilityScore(oSpawn, ABILITY_INTELLIGENCE, -nGreatInt);
+        if(nGreatWis) PRC_Funcs_ModAbilityScore(oSpawn, ABILITY_WISDOM, -nGreatWis);
+        if(nGreatCha) PRC_Funcs_ModAbilityScore(oSpawn, ABILITY_CHARISMA, -nGreatCha);
+    }
+    else
+    {
+        if(nGreatStr)
+            ApplyEffectToObject(DURATION_TYPE_PERMANENT,
+                SupernaturalEffect(EffectAbilityDecrease(ABILITY_STRENGTH, nGreatStr)),
+            oSpawn);
+        if(nGreatDex)
+            ApplyEffectToObject(DURATION_TYPE_PERMANENT,
+                SupernaturalEffect(EffectAbilityDecrease(ABILITY_DEXTERITY, nGreatDex)),
+            oSpawn);
+        if(nGreatCon)
+            ApplyEffectToObject(DURATION_TYPE_PERMANENT,
+                SupernaturalEffect(EffectAbilityDecrease(ABILITY_CONSTITUTION, nGreatCon)),
+            oSpawn);
+        if(nGreatInt)
+            ApplyEffectToObject(DURATION_TYPE_PERMANENT,
+                SupernaturalEffect(EffectAbilityDecrease(ABILITY_INTELLIGENCE, nGreatInt)),
+            oSpawn);
+        if(nGreatWis)
+            ApplyEffectToObject(DURATION_TYPE_PERMANENT,
+                SupernaturalEffect(EffectAbilityDecrease(ABILITY_WISDOM, nGreatWis)),
+            oSpawn);
+        if(nGreatCha)
+            ApplyEffectToObject(DURATION_TYPE_PERMANENT,
+                SupernaturalEffect(EffectAbilityDecrease(ABILITY_CHARISMA, nGreatCha)),
+            oSpawn);
+    }
+}
+
+void AddCohortToPlayerByObject(object oCohort, object oPC, int bDoSetup = TRUE)
+{
+    //add it to the pc
+    int nMaxHenchmen = GetMaxHenchmen();
+    SetMaxHenchmen(99);
+    AddHenchman(oPC, oCohort);
+    SetMaxHenchmen(nMaxHenchmen);
+    object oSkin  = GetPCSkin(oCohort);
+
+    if(bDoSetup)
+    {
+        //if it was a premade one, give it a random name
+        //randomize its appearance using DoRandomAppearance
+        if(GetResRef(oCohort) != "")
+        {
+            string sName;
+            //first name
+            switch(MyPRCGetRacialType(oCohort))
+            {
+                case RACIAL_TYPE_DWARF:
+                    if(GetGender(oCohort) == GENDER_FEMALE)
+                        sName += RandomName(NAME_FIRST_DWARF_FEMALE);
+                    else
+                        sName += RandomName(NAME_FIRST_DWARF_MALE);
+                    break;
+                case RACIAL_TYPE_ELF:
+                    if(GetGender(oCohort) == GENDER_FEMALE)
+                        sName += RandomName(NAME_FIRST_ELF_FEMALE);
+                    else
+                        sName += RandomName(NAME_FIRST_ELF_MALE);
+                    break;
+                case RACIAL_TYPE_GNOME:
+                    if(GetGender(oCohort) == GENDER_FEMALE)
+                        sName += RandomName(NAME_FIRST_GNOME_FEMALE);
+                    else
+                        sName += RandomName(NAME_FIRST_GNOME_MALE);
+                    break;
+                case RACIAL_TYPE_HUMAN:
+                    if(GetGender(oCohort) == GENDER_FEMALE)
+                        sName += RandomName(NAME_FIRST_HUMAN_FEMALE);
+                    else
+                        sName += RandomName(NAME_FIRST_HUMAN_MALE);
+                    break;
+                case RACIAL_TYPE_HALFELF:
+                    if(GetGender(oCohort) == GENDER_FEMALE)
+                        sName += RandomName(NAME_FIRST_HALFELF_FEMALE);
+                    else
+                        sName += RandomName(NAME_FIRST_HALFELF_MALE);
+                    break;
+                case RACIAL_TYPE_HALFORC:
+                    if(GetGender(oCohort) == GENDER_FEMALE)
+                        sName += RandomName(NAME_FIRST_HALFORC_FEMALE);
+                    else
+                        sName += RandomName(NAME_FIRST_HALFORC_MALE);
+                    break;
+                case RACIAL_TYPE_HALFLING:
+                    if(GetGender(oCohort) == GENDER_FEMALE)
+                        sName += RandomName(NAME_FIRST_HALFLING_FEMALE);
+                    else
+                        sName += RandomName(NAME_FIRST_HALFLING_MALE);
+                    break;
+            }
+            sName += " ";
+            //surname
+            switch(MyPRCGetRacialType(oCohort))
+            {
+                case RACIAL_TYPE_DWARF:
+                    sName += RandomName(NAME_LAST_DWARF);
+                    break;
+                case RACIAL_TYPE_ELF:
+                    sName += RandomName(NAME_LAST_ELF);
+                    break;
+                case RACIAL_TYPE_GNOME:
+                    sName += RandomName(NAME_LAST_GNOME);
+                    break;
+                case RACIAL_TYPE_HUMAN:
+                    sName += RandomName(NAME_LAST_HUMAN);
+                    break;
+                case RACIAL_TYPE_HALFELF:
+                    sName += RandomName(NAME_LAST_HALFELF);
+                    break;
+                case RACIAL_TYPE_HALFORC:
+                    sName += RandomName(NAME_LAST_HALFORC);
+                    break;
+                case RACIAL_TYPE_HALFLING:
+                    sName += RandomName(NAME_LAST_HALFLING);
+                    break;
+            }
+            //sanity check
+            if(sName == " ")
+                sName = "";
+            //change the name
+            AssignCommand(oCohort, SetName(oCohort, sName));
+
+            //use disguise code to alter head etc
+            DoRandomAppearance(MyPRCGetRacialType(oCohort), oCohort);
+
+            //DoRandomAppearance removed wings/tails need to re-add
+            if(GetRacialType(oCohort) == RACIAL_TYPE_FEYRI)
+                SetCreatureWingType(CREATURE_WING_TYPE_DEMON, oCohort);
+            else if(GetRacialType(oCohort) == RACIAL_TYPE_AVARIEL)
+                SetCreatureWingType(CREATURE_WING_TYPE_BIRD, oCohort);
+        }
+        //if its a custom made cohort, need to cancel GreatX feats
+        else
+            CancelGreatFeats(oCohort);
+
+        //set it to the pcs level
+        int nLevel = GetCohortMaxLevel(GetLeadershipScore(oPC), oPC);
+        SetXP(oCohort, nLevel*(nLevel-1)*500);
+        SetLocalInt(oCohort, "MastersXP", GetXP(oPC));
+        DelayCommand(1.0, AssignCommand(oCohort, SetIsDestroyable(FALSE, TRUE, TRUE)));
+        DelayCommand(1.0, AssignCommand(oCohort, SetLootable(oCohort, TRUE)));
+        //set its maximum level lag
+        if(GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS))
+        {
+            //bonus cohort, no cap
+        }
+        else if(GetPRCSwitch(PRC_THRALLHERD_LEADERSHIP)
+            && GetLevelByClass(CLASS_TYPE_THRALLHERD, oPC)
+            && GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS)+1)
+        {
+            //thrallherd with switch, 1 level lag
+            SetLocalInt(oCohort, "CohortLevelLag", 1);
+        }
+        else if(GetPRCSwitch(PRC_THRALLHERD_LEADERSHIP)
+            && GetLevelByClass(CLASS_TYPE_THRALLHERD, oPC) >= 10
+            && GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS)+2)
+        {
+            //twofold master with switch, 2 level lag
+            SetLocalInt(oCohort, "CohortLevelLag", 2);
+        }
+        else
+        {
+            //other cohort have a 2 level lag
+            SetLocalInt(oCohort, "CohortLevelLag", 2);
+        }
+
+        //strip its equipment & inventory
+        object oTest  = GetFirstItemInInventory(oCohort);
+        object oToken = GetHideToken(oCohort);
+        while(GetIsObjectValid(oTest))
+        {
+            if(GetHasInventory(oTest))
+            {
+                object oTest2 = GetFirstItemInInventory(oTest);
+                while(GetIsObjectValid(oTest2))
+                {
+                    // Avoid blowing up the hide and token that just had the eventscripts stored on them
+                    if(oTest2 != oSkin && oTest2 != oToken)
+                        DestroyObject(oTest2);
+                    oTest2 = GetNextItemInInventory(oTest);
+                }
+            }
+            // Avoid blowing up the hide and token that just had the eventscripts stored on them
+            if(oTest != oSkin && oTest != oToken)
+                DestroyObject(oTest);
+            oTest = GetNextItemInInventory(oCohort);
+        }
+        int nSlot;
+        for(nSlot = 0;nSlot<14;nSlot++)
+        {
+            oTest = GetItemInSlot(nSlot, oCohort);
+            DestroyObject(oTest);
+        }
+        //get rid of any gold it has
+        TakeGoldFromCreature(GetGold(oCohort), oCohort, TRUE);
+    }
+    //clean up any leftovers on the skin
+    ScrubPCSkin(oCohort, oSkin);
+    DeletePRCLocalInts(oSkin);
+
+    //turn on its scripts
+    //normal MoB set
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONPHYSICALATTACKED,   "prc_ai_mob_attck", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONBLOCKED,            "prc_ai_mob_block", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONCOMBATROUNDEND,     "prc_ai_mob_combt", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONDAMAGED,            "prc_ai_mob_damag", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONDISTURBED,          "prc_ai_mob_distb", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONPERCEPTION,         "prc_ai_mob_percp", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONSPAWNED,            "prc_ai_mob_spawn", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONSPELLCASTAT,        "prc_ai_mob_spell", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONDEATH,              "prc_ai_mob_death", TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONRESTED,             "prc_ai_mob_rest",  TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONUSERDEFINED,        "prc_ai_mob_userd", TRUE, FALSE);
+    //dont run this, cohort-specific script replaces it
+    //AddEventScript(oCohort, EVENT_VIRTUAL_ONCONVERSATION,       "prc_ai_mob_conv",  TRUE, TRUE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONHEARTBEAT,          "prc_ai_mob_heart", TRUE, FALSE);
+    //cohort specific ones
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONCONVERSATION,       "prc_ai_coh_conv",  TRUE, FALSE);
+    AddEventScript(oCohort, EVENT_VIRTUAL_ONHEARTBEAT,          "prc_ai_coh_hb",    TRUE, FALSE);
+
+    //mark the master on the cohort
+    SetLocalObject(oCohort, "MasterObject", oPC);
+
+    //DEBUG
+    //various tests
+    if (DEBUG) DoDebug("Cohort Name="+GetName(oCohort));
+    if (DEBUG) DoDebug("Cohort HD="+IntToString(GetHitDice(oCohort)));
+    if (DEBUG) DoDebug("Cohort XP="+IntToString(GetXP(oCohort)));
+    if (DEBUG) DoDebug("Cohort GetIsPC="+IntToString(GetIsPC(oCohort)));
+    
+    // And now gear it up
+    if (!GetPRCSwitch(PRC_DISABLE_COHORT_STARTING_GEAR))
+    {
+        int i;
+        int nHD = GetHitDice(oCohort);
+        for(i = 0;i<nHD;i++)
+        {
+            GenerateBossTreasure(oCohort);
+        }        
+        object oGear = GetFirstItemInInventory(oCohort);
+        while(GetIsObjectValid(oGear))
+        {
+            SetIdentified(oGear, TRUE);
+            SetDroppableFlag(oGear, FALSE);
+            SetItemCursedFlag(oGear, TRUE);        
+            SetStolenFlag(oGear, TRUE);
+            SetPlotFlag(oGear, TRUE);
+            AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyWeightReduction(IP_CONST_REDUCEDWEIGHT_10_PERCENT), oGear);
+            
+            oGear = GetNextItemInInventory(oCohort);
+        }    
+        
+        AssignCommand(oCohort, ClearAllActions());
+        AssignCommand(oCohort, ActionEquipMostDamagingMelee());
+        AssignCommand(oCohort, ActionEquipMostEffectiveArmor());
+    }
+}
+
+void RemoveCohortFromPlayer(object oCohort, object oPC)
+{
+    int nValidPC = FALSE;
+    if(GetIsObjectValid(oPC))
+        nValidPC = TRUE;
+
+    //strip its equipment & inventory
+    object oTest = GetFirstItemInInventory(oCohort);
+    while(GetIsObjectValid(oTest))
+    {
+        if(GetHasInventory(oTest))
+        {
+            object oTest2 = GetFirstItemInInventory(oTest);
+            while(GetIsObjectValid(oTest2))
+            {
+                if(nValidPC)
+                    AssignCommand(oCohort, ActionGiveItem(oTest2, oPC));
+                else
+                    DestroyObject(oTest2);
+                oTest = GetNextItemInInventory(oTest);
+            }
+        }
+        if(nValidPC)
+            AssignCommand(oCohort, ActionGiveItem(oTest, oPC));
+        else
+            DestroyObject(oTest);
+        oTest = GetNextItemInInventory(oCohort);
+    }
+    int nSlot;
+    for(nSlot = 0;nSlot<14;nSlot++)
+    {
+        if(nValidPC)
+            AssignCommand(oCohort, ActionGiveItem(GetItemInSlot(nSlot, oCohort), oPC));
+        else
+            DestroyObject(oTest);
+    }
+    //now destroy it
+    AssignCommand(oCohort, ActionDoCommand(SetIsDestroyable(TRUE, FALSE, FALSE)));
+    AssignCommand(oCohort, ActionDoCommand(SetLootable(oCohort, FALSE)));
+    AssignCommand(oCohort, ActionDoCommand(DestroyObject(oCohort)));
+}
+
+int GetLeadershipScore(object oPC = OBJECT_SELF)
+{
+    int nLeadership = GetECL(oPC);
+    nLeadership += GetAbilityModifier(ABILITY_CHARISMA, oPC);
+    if(GetHasFeat(FEAT_MIGHT_MAKES_RIGHT, oPC)) nLeadership += GetAbilityModifier(ABILITY_STRENGTH, oPC);
+    if(GetHasFeat(FEAT_RULERSHIP, oPC)) nLeadership += 4;
+    if(GetHasFeat(FEAT_ECCLESIARCH, oPC)) nLeadership += 2;
+    if(GetHasFeat(FEAT_GREAT_DIPLOMAT, oPC)) nLeadership += 2;
+    if (GetLevelByClass(CLASS_TYPE_SHADOW_THIEF_AMN, oPC) >= 3) nLeadership += GetLevelByClass(CLASS_TYPE_SHADOW_THIEF_AMN, oPC) - 2;
+    //without epic leadership its capped at 25
+    if(!GetHasFeat(FEAT_EPIC_LEADERSHIP, oPC) && nLeadership > 25)
+        nLeadership = 25;
+
+    return nLeadership;
+}
+
+void StoreCohort(object oCohort)
+{
+    int nCohortCount = GetCampaignInt(COHORT_DATABASE, "CohortCount");
+    int i;
+    for(i=0;i<nCohortCount;i++)
+    {
+        if(GetCampaignInt(COHORT_DATABASE, "Cohort_"+IntToString(i)+"_deleted"))
+        {
+            nCohortCount = i;
+        }
+    }
+    if(GetCampaignInt(COHORT_DATABASE, "CohortCount")==nCohortCount) //no "deleted" cohorts
+        nCohortCount++;
+    //store the player
+    SetCampaignInt(COHORT_DATABASE, "CohortCount", nCohortCount);
+    StoreCampaignObject(COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_obj",    oCohort);
+    SetCampaignString(  COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_name",   GetName(oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_race",   GetRacialType(oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_class1", GetClassByPosition(1, oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_class2", GetClassByPosition(2, oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_class3", GetClassByPosition(3, oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_class4", GetClassByPosition(4, oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_class5", GetClassByPosition(5, oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_class6", GetClassByPosition(6, oCohort));	
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_class7", GetClassByPosition(7, oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_class8", GetClassByPosition(8, oCohort));	
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_order",  GetLawChaosValue(oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_moral",  GetGoodEvilValue(oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_ethran", GetHasFeat(FEAT_ETHRAN, oCohort));
+    SetCampaignString(  COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_cdkey",  GetPCPublicCDKey(oCohort));
+    SetCampaignInt(     COHORT_DATABASE, "Cohort_"+IntToString(nCohortCount)+"_deleted",   FALSE);
+}
+
+void CheckHB(object oPC)
+{
+    //make sure only 1 hb running at a time
+    if(GetLocalInt(oPC, "CohortCheckHB") > 1)
+        return;
+    SetLocalInt(oPC, "CohortCheckHB", GetLocalInt(oPC, "CohortCheckHB")+1);
+    DelayCommand(0.99,
+        SetLocalInt(oPC, "CohortCheckHB", GetLocalInt(oPC, "CohortCheckHB")-1));
+    SetCommandable(FALSE, oPC);
+    if(GetHitDice(oPC) == 40)
+    {
+        StoreCohort(oPC);
+        //restore previous xp amound
+        SetXP(oPC, GetLocalInt(oPC, "OriginalXP"));
+        //tell the player what was done
+        SendMessageToPC(oPC, "Character registered as cohort.");
+        //remove the non-commandabiltiy
+        SetCommandable(TRUE, oPC);
+        // Clean up
+        DeletePersistantLocalInt(oPC, "RegisteringAsCohort");
+        DeleteLocalInt(oPC, "OriginalXP");
+        //stop the psuedoHB
+        return;
+    }
+    DelayCommand(1.0, CheckHB(oPC));
+}
+
+void RegisterAsCohort(object oPC)
+{
+    string sMessage;
+    sMessage += "This will register you character to be selected as a cohort.\n";
+    sMessage += "As part of this process, you have to levelup to level 40.\n";
+    sMessage += "Once you reach level 40, your character will be stored.\n";
+    sMessage += "Then when the character is used as a cohort, it will follow that levelup path.\n";
+    sMessage += "Any changes to the cohort will not apply to the original character.\n";
+    //SendMessageToPC(oPC, sMessage);
+    FloatingTextStringOnCreature(sMessage, oPC);
+
+    SetLocalInt(oPC, "OriginalXP", GetXP(oPC));
+    SetXP(oPC, 40*(40-1)*500);
+    SetPersistantLocalInt(oPC, "RegisteringAsCohort", TRUE);
+    AssignCommand(GetModule(), CheckHB(oPC));
+}
+
+int LeadershipScore2CohortLevel(int nLeadership)
+{
+    switch(nLeadership)
+    {
+        case  1: return  0;
+        case  2: return  1;
+        case  3: return  2;
+        case  4:
+        case  5: return  3;
+        case  6: return  4;
+        case  7:
+        case  8: return  5;
+        case  9: return  6;
+        case 10:
+        case 11: return  7;
+        case 12: return  8;
+        case 13: return  9;
+        case 14:
+        case 15: return 10;
+        case 16: return 11;
+        case 17:
+        case 18: return 12;
+        case 19: return 13;
+        case 20: return 14;
+        case 21:
+        case 22: return 15;
+        case 23: return 16;
+        case 24:
+        case 25: return 17;
+        case 26:
+        case 27: return 18;
+        case 28:
+        case 29: return 19;
+        case 30:
+        case 31: return 20;
+        case 32:
+        case 33: return 21;
+        case 34:
+        case 35: return 22;
+        case 36:
+        case 37: return 23;
+        case 38:
+        case 39: return 24;
+        case 40:
+        case 41: return 25;
+        case 42:
+        case 43: return 26;
+        case 44:
+        case 45: return 27;
+        case 46:
+        case 47: return 28;
+        case 48:
+        case 49: return 29;
+        case 50:
+        case 51: return 30;
+        case 52:
+        case 53: return 31;
+        case 54:
+        case 55: return 32;
+        case 56:
+        case 57: return 33;
+        case 58:
+        case 59: return 34;
+        case 60: return 35;
+        case 61:
+        case 62: return 36;
+        case 63:
+        case 64: return 37;
+        case 65:
+        case 66: return 38;
+        case 67:
+        case 68: return 39;
+        case 69:
+        case 70: return 40;
+    }
+    return 0;
+}
+
+int GetCohortMaxLevel(int nLeadership, object oPC)
+{
+    //if its a bonus cohort, use the players ECL
+    int nMasterLevel = GetECL(oPC);
+    if(GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS))
+        return nMasterLevel;
+    int nLevel = LeadershipScore2CohortLevel(nLeadership);
+    //apply a level lag
+    if(GetPRCSwitch(PRC_THRALLHERD_LEADERSHIP)
+        && GetLevelByClass(CLASS_TYPE_THRALLHERD, oPC)
+        && GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS)+1)
+    {
+        //thrallherd with switch, 1 level lag
+        if(nLevel > nMasterLevel-1)
+            nLevel = nMasterLevel-1;
+    }
+    else if(GetPRCSwitch(PRC_THRALLHERD_LEADERSHIP)
+        && GetLevelByClass(CLASS_TYPE_THRALLHERD, oPC) >= 10
+        && GetCurrentCohortCount(oPC) <= GetPRCSwitch(PRC_BONUS_COHORTS)+2)
+    {
+        //twofold master with switch, 2 level lag
+        if(nLevel > nMasterLevel-2)
+            nLevel = nMasterLevel-2;
+    }
+    else
+    {
+        //other cohort have a 2 level lag
+        if(nLevel > nMasterLevel-2)
+            nLevel = nMasterLevel-2;
+            if (GetHasFeat(FEAT_IMPROVED_COHORT, oPC)) nLevel += 1;
+    }
+    //really, leadership should be capped at 25 / 17HD
+    //but this is a sanity check
+    if(nLevel > 20
+        && !GetHasFeat(FEAT_EPIC_LEADERSHIP, oPC))
+        nLevel = 20;
+    return nLevel;
+}
+
+int GetCurrentCohortCount(object oPC)
+{
+    int nCount;
+    object oTest;
+    object oOldTest;
+    int i = 1;
+    oTest = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, i);
+    while(GetIsObjectValid(oTest) && oTest != oOldTest)
+    {
+        if(GetTag(oTest) == COHORT_TAG)
+            nCount++;
+        i++;
+        oOldTest = oTest;
+        oTest = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, i);
+    }
+    return nCount;
+}
+
+object GetCohort(int nID, object oPC)
+{
+    int nCount;
+    object oTest;
+    object oOldTest;
+    int i = 1;
+    oTest = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, i);
+    while(GetIsObjectValid(oTest) && oTest != oOldTest)
+    {
+        if(GetTag(oTest) == COHORT_TAG)
+            nCount++;
+        if(nCount == nID)
+            return oTest;
+        i++;
+        oOldTest = oTest;
+        oTest = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, oPC, i);
+    }
+    return OBJECT_INVALID;
+}
+
+int GetMaximumCohortCount(object oPC)
+{
+    int nCount;
+    if(!GetLevelByClass(CLASS_TYPE_THRALLHERD, oPC))
+    {
+        if(GetHasFeat(FEAT_LEADERSHIP, oPC))
+            nCount++;
+        if(GetHasFeat(FEAT_LEGENDARY_COMMANDER, oPC))
+            nCount++;
+    }
+    //thrallherd with switch
+    else if(GetPRCSwitch(PRC_THRALLHERD_LEADERSHIP))
+    {
+        nCount++;
+        //twofold masteer
+        if(GetLevelByClass(CLASS_TYPE_THRALLHERD, oPC) > 9)
+            nCount++;
+    }
+    //hathran class
+    if(GetHasFeat(FEAT_HATH_COHORT, oPC))
+        nCount++;
+    //orc warlord with switch
+    if(GetHasFeat(FEAT_GATHER_HORDE_I, oPC)
+        && GetPRCSwitch(PRC_ORC_WARLORD_COHORT))
+        nCount++;
+    nCount += GetPRCSwitch(PRC_BONUS_COHORTS);
+    return nCount;
+}
+
+int GetIsCohortChoiceValid(string sName, int nRace, int nClass1, int nClass2, int nClass3, int nOrder, int nMoral, int nEthran, string sKey, int nDeleted, object oPC)
+{
+    //has been deleted
+    if(nDeleted)
+    {
+        DoDebug("GetIsCohortChoiceValid() is FALSE because cohort had been deleted");
+        return FALSE;
+    }
+
+    int bIsValid = TRUE;
+    int nCohortCount = GetMaximumCohortCount(oPC);
+    int i;
+    //another players cohort
+    if(GetPCPublicCDKey(oPC) != ""
+        && GetPCPublicCDKey(oPC) != sKey)
+    {
+        DoDebug("GetIsCohortChoiceValid() is FALSE because cdkey is incorrect");
+        bIsValid = FALSE;
+    }
+    //is character
+    if(bIsValid
+        && GetName(oPC) == sName)
+    {
+        DoDebug("GetIsCohortChoiceValid() is FALSE because name is in use");
+        bIsValid = FALSE;
+    }
+    //is already a cohort
+    if(bIsValid && sName != "")
+    {
+        for(i=1;i<=nCohortCount;i++)
+        {
+            object oCohort = GetCohort(i, oPC);
+            if(GetName(oCohort) == sName)
+            {
+                DoDebug("GetIsCohortChoiceValid() is FALSE because cohort is already in use.");
+                bIsValid = FALSE;
+            }
+        }
+    }
+    //hathran
+    if(bIsValid
+        && GetHasFeat(FEAT_HATH_COHORT, oPC))
+    {
+        int nEthranBarbarianCount = 0;
+        for(i=1;i<=nCohortCount;i++)
+        {
+            object oCohort = GetCohort(i, oPC);
+            if(GetIsObjectValid(oCohort)
+                &&(GetHasFeat(FEAT_HATH_COHORT, oCohort)
+                    || GetLevelByClass(CLASS_TYPE_BARBARIAN, oCohort)))
+                nEthranBarbarianCount++;
+        }
+        //must have at least one ethran or barbarian
+        if(!nEthranBarbarianCount
+            && GetCurrentCohortCount(oPC) >= GetMaximumCohortCount(oPC)-1
+            && !nEthran
+            && nClass1 != CLASS_TYPE_BARBARIAN
+            && nClass2 != CLASS_TYPE_BARBARIAN
+            && nClass3 != CLASS_TYPE_BARBARIAN)
+                bIsValid = FALSE;
+    }
+    //OrcWarlord
+    if(bIsValid
+        && GetHasFeat(FEAT_GATHER_HORDE_I, oPC)
+        && GetPRCSwitch(PRC_ORC_WARLORD_COHORT))
+    {
+        int nOrcCount = 0;
+        for(i=1;i<=nCohortCount;i++)
+        {
+            object oCohort = GetCohort(i, oPC);
+            if(GetIsObjectValid(oCohort)
+                && (MyPRCGetRacialType(oCohort) == RACIAL_TYPE_HUMANOID_ORC
+                    || MyPRCGetRacialType(oCohort) == RACIAL_TYPE_HALFORC))
+                nOrcCount++;
+        }
+        //must have at least one orc
+        if(!nOrcCount
+            && GetCurrentCohortCount(oPC) >= GetMaximumCohortCount(oPC)-1
+            && nRace != RACIAL_TYPE_HUMANOID_ORC
+            && nRace != RACIAL_TYPE_HALFORC
+            && nRace != RACIAL_TYPE_GRAYORC
+            && nRace != RACIAL_TYPE_OROG
+            && nRace != RACIAL_TYPE_TANARUKK
+            )
+            bIsValid = FALSE;
+    }
+    //Undead Leadership
+    //Wild Cohort
+        //not implemented yet
+    //return result
+    return bIsValid;
+}
+
+int GetIsCohortChoiceValidByID(int nID, object oPC)
+{
+    string sID = IntToString(nID);
+    string sName = GetCampaignString(  COHORT_DATABASE, "Cohort_"+sID+"_name");
+    int    nRace = GetCampaignInt(     COHORT_DATABASE, "Cohort_"+sID+"_race");
+    int    nClass1=GetCampaignInt(     COHORT_DATABASE, "Cohort_"+sID+"_class1");
+    int    nClass2=GetCampaignInt(     COHORT_DATABASE, "Cohort_"+sID+"_class2");
+    int    nClass3=GetCampaignInt(     COHORT_DATABASE, "Cohort_"+sID+"_class3");
+    int    nOrder= GetCampaignInt(     COHORT_DATABASE, "Cohort_"+sID+"_order");
+    int    nMoral= GetCampaignInt(     COHORT_DATABASE, "Cohort_"+sID+"_moral");
+    int    nEthran=GetCampaignInt(     COHORT_DATABASE, "Cohort_"+sID+"_ethran");
+    string sKey  = GetCampaignString(  COHORT_DATABASE, "Cohort_"+sID+"_cdkey");
+    int    nDeleted = GetCampaignInt(COHORT_DATABASE, "Cohort_"+sID+"_deleted");
+    return GetIsCohortChoiceValid(sName, nRace, nClass1, nClass2, nClass3, nOrder, nMoral, nEthran, sKey, nDeleted, oPC);
+}
+
+int GetCanRegister(object oPC)
+{
+    int bReturn = TRUE;
+    int i;
+    int nCohortCount = GetCampaignInt(COHORT_DATABASE, "CohortCount");
+    for(i=0;i<nCohortCount;i++)
+    {
+        string sName = GetCampaignString(COHORT_DATABASE, "Cohort_"+IntToString(i)+"_name");
+        if(sName == GetName(oPC)
+            && !GetCampaignInt(COHORT_DATABASE, "Cohort_"+IntToString(i)+"_deleted"))
+            bReturn = FALSE;
+    }
+    return bReturn;
+}
+
+void DeleteCohort(int nCohortID)
+{
+    //this is a bit of a fudge, but it will do for now
+    //Add Cohort overwrites the first deleted cohort
+    SetCampaignInt(COHORT_DATABASE, "Cohort_"+IntToString(nCohortID)+"_deleted", TRUE);
+}
+
+void LevelupAndStorePremadeCohort(object oCohort)
+{
+    int i;
+    //levelup the cohort
+    //if simple racial HD on, give them racial HD
+    if(GetPRCSwitch(PRC_XP_USE_SIMPLE_RACIAL_HD))
+    {
+        //get the real race
+        int nRace = GetRacialType(oCohort);
+        int nRacialHD = StringToInt(Get2DACache("ECL", "RaceHD", nRace));
+        int nRacialClass = StringToInt(Get2DACache("ECL", "RaceClass", nRace));
+        for(i=0;i<nRacialHD;i++)
+        {
+            LevelUpHenchman(oCohort, nRacialClass, TRUE);
+        }
+    }
+    //give them their 40 levels in their class
+    for(i=0;i<40;i++)
+    {
+        LevelUpHenchman(oCohort, CLASS_TYPE_INVALID, TRUE);
+    }
+    //store them
+    StoreCohort(oCohort);
+    //destroy them to clean up afterwards
+    //clean invetory first
+    object oTest = GetFirstItemInInventory(oCohort);
+    while(GetIsObjectValid(oTest))
+    {
+        DestroyObject(oTest);
+        oTest = GetNextItemInInventory(oCohort);
+    }
+    for(i=0;i<14;i++)
+    {
+        oTest = GetItemInSlot(i, oCohort);
+        DestroyObject(oTest);
+    }
+    DestroyObject(oCohort);
+}
+
+void AddPremadeCohortsToDB()
+{
+    //check not added already
+    if(GetCampaignInt(COHORT_DATABASE, "PremadeCohorts"))
+        return;
+
+    //get the limbo location
+    location lSpawn = GetLocation(GetObjectByTag("HEARTOFCHAOS"));
+    //loop over the races
+    int nRace;
+    for(nRace = 0; nRace <= 255; nRace++)
+    {
+        //check its a playable race
+        if(Get2DACache("racialtypes", "PlayerRace", nRace) == "1")
+        {
+            //loop over the classes
+            int nClass;
+            for(nClass = 0; nClass <= 10; nClass++)
+            {
+                //assemble the resref
+                string sResRef = "PRC_NPC_"+IntToString(nRace)+"_"+IntToString(nClass);
+                DoDebug("AddPremadeCohortsToDB() : sResRef = "+sResRef);
+                //create the cohort
+                object oCohort = CreateObject(OBJECT_TYPE_CREATURE, sResRef, lSpawn);
+                //check its valid
+                if(GetIsObjectValid(oCohort))
+                {
+                    ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectCutsceneGhost(), oCohort);
+                    DelayCommand(1.0, LevelupAndStorePremadeCohort(oCohort));
+                }
+            }
+        }
+    }
+
+    //make sure this is only done once
+    SetCampaignInt(COHORT_DATABASE, "PremadeCohorts", TRUE);
+}
+
+//:: Test Void
+//void main (){}
\ No newline at end of file
diff --git a/trunk/include/prc_inc_spells.nss b/trunk/include/prc_inc_spells.nss
new file mode 100644
index 00000000..2a66361a
--- /dev/null
+++ b/trunk/include/prc_inc_spells.nss
@@ -0,0 +1,3047 @@
+/*
+   ----------------
+   prc_inc_spells
+   ----------------
+
+   7/25/04 by WodahsEht
+
+   Contains many useful functions for determining caster level, mostly.  The goal
+   is to consolidate all caster level functions to this -- existing caster level
+   functions will be wrapped around the main function.
+
+   In the future, all new PrC's that add to caster levels should be added to
+   the GetArcanePRCLevels and GetDivinePRCLevels functions.  Very little else should
+   be necessary, except when new casting feats are created.
+*/
+
+//:: Updated for .35 by Jaysyn 2023/03/10
+
+
+//////////////////////////////////////////////////
+/*             Function prototypes              */
+//////////////////////////////////////////////////
+
+/**
+ * Adjusts the base class level (NOT caster level) of the class by any spellcasting PrCs
+ * @param nClass a base casting class (divine or arcane)
+ * @return The level of the class, adjusted for any appropriate PrC levels
+ */
+int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF);
+
+/**
+ * Adjusts the base caster level of the class by any spellcasting PrCs plus Practised Spellcasting feats if appropriate
+ * @param nClass a base casting class
+ * @param bAdjustForPractisedSpellcaster add practiced spellcaster feat to caster level. TRUE by default
+ * @return the caster level in the class, adjusted by any PrC levels and practised spellcaster feats as appropriate
+ */
+int GetPrCAdjustedCasterLevel(int nClassType, object oCaster = OBJECT_SELF, int bAdjustForPractisedSpellcaster = TRUE);
+
+/**
+ * finds the highest arcane or divine caster level, adjusting the base caster level of the class by any
+ * spellcasting PrCs plus Practised Spellcasting feats if appropriate
+ * @param nClassType TYPE_DIVINE or TYPE_ARCANE
+ * @param bAdjustForPractisedSpellcaster add practiced spellcaster feat to caster level. TRUE by default
+ * @return the highest arcane/divine caster level adjusted by any PrC levels and practised spellcaster feats as appropriate
+ */
+int GetPrCAdjustedCasterLevelByType(int nClassType, object oCaster = OBJECT_SELF, int bAdjustForPractisedSpellcaster = TRUE);
+
+// Returns the best "feat-adjusted" arcane levels of the PC in question.
+// Considers feats that situationally adjust caster level.
+int GetLevelByTypeArcaneFeats(object oCaster = OBJECT_SELF, int iSpellID = -1);
+
+// Returns the best "feat-adjusted" divine levels of the PC in question.
+// Considers feats that situationally adjust caster level.
+int GetLevelByTypeDivineFeats(object oCaster = OBJECT_SELF, int iSpellID = -1);
+
+//Returns Reflex Adjusted Damage. Is a wrapper function that allows the
+//DC to be adjusted based on conditions that cannot be done using iprops
+//such as saves vs spellschools, or other adjustments
+int PRCGetReflexAdjustedDamage(int nDamage, object oTarget, int nDC, int nSaveType=SAVING_THROW_TYPE_NONE, object oSaveVersus=OBJECT_SELF);
+
+//Is a wrapper function that allows the DC to be adjusted based on conditions
+//that cannot be done using iprops, such as saves vs spellschool.
+//If bImmunityCheck == FALSE: returns 0 if failure or immune, 1 if success - same as MySavingThrow
+//If bImmunityCheck == TRUE:  returns 0 if failure, 1 if success, 2 if immune
+int PRCMySavingThrow(int nSavingThrow, object oTarget, int nDC, int nSaveType=SAVING_THROW_TYPE_NONE, object oSaveVersus = OBJECT_SELF, float fDelay = 0.0, int bImmunityCheck = FALSE);
+
+// Finds caster levels by specific types (see the constants below).
+int GetCasterLvl(int iTypeSpell, object oCaster = OBJECT_SELF);
+
+//  Calculates bonus damage to a spell for Spell Betrayal Ability
+int SpellBetrayalDamage(object oTarget, object oCaster);
+
+//  Calculates damage to a spell for Spellstrike Ability
+int SpellStrikeDamage(object oTarget, object oCaster);
+
+// Create a Damage effect
+// - oTarget: spell target
+// - nDamageAmount: amount of damage to be dealt. This should be applied as an
+//   instantaneous effect.
+// - nDamageType: DAMAGE_TYPE_*
+// - nDamagePower: DAMAGE_POWER_*
+// Used to add Warmage's Edge to spells.
+effect PRCEffectDamage(object oTarget, int nDamageAmount, int nDamageType=DAMAGE_TYPE_MAGICAL, int nDamagePower=DAMAGE_POWER_NORMAL, int nMetaMagic=METAMAGIC_NONE);
+
+/**
+ * Adds damage to all arcane spells based on the number of dice
+ */
+int SpellDamagePerDice(object oCaster, int nDice);
+
+int IsSpellDamageElemental(int nDamageType);
+
+// Get altered damage type for energy sub feats.
+//      nDamageType - The DAMAGE_TYPE_xxx constant of the damage. All types other
+//          than elemental damage types are ignored.
+//      oCaster - caster object.
+// moved from spinc_common, possibly somewhat redundant
+int PRCGetElementalDamageType(int nDamageType, object oCaster = OBJECT_SELF);
+
+//  Adds the bonus damage from both Spell Betrayal and Spellstrike together
+int ApplySpellBetrayalStrikeDamage(object oTarget, object oCaster, int bShowTextString = TRUE);
+
+// wrapper for DecrementRemainingSpellUses, works for newspellbook 'fake' spells too
+void PRCDecrementRemainingSpellUses(object oCreature, int nSpell);
+
+/**
+ * Determines and applies the alignment shift for using spells/powers with the
+ * [Evil] descriptor.  The amount of adjustment is equal to the square root of
+ * the caster's distance from pure evil.
+ * In other words, the amount of shift is higher the farther the caster is from
+ * pure evil, with the extremes being 10 points of shift at pure good and 0
+ * points of shift at pure evil.
+ *
+ * Does nothing if the PRC_SPELL_ALIGNMENT_SHIFT switch is not set.
+ *
+ * @param oPC The caster whose alignment to adjust
+ */
+//void SPEvilShift(object oPC);
+
+/**
+ * Determines and applies the alignment shift for using spells/powers with the
+ * [Good] descriptor.  The amount of adjustment is equal to the square root of
+ * the caster's distance from pure good.
+ * In other words, the amount of shift is higher the farther the caster is from
+ * pure good, with the extremes being 10 points of shift at pure evil and 0
+ * points of shift at pure good.
+ *
+ * Does nothing if the PRC_SPELL_ALIGNMENT_SHIFT switch is not set.
+ *
+ * @param oPC The caster whose alignment to adjust
+ */
+//void SPGoodShift(object oPC);
+
+/**
+ * Applies the corruption cost for Corrupt spells.
+ *
+ * @param oPC      The caster of the Corrupt spell
+ * @param oTarget  The target of the spell.
+ *                 Not used for anything, should probably remove - Ornedan
+ * @param nAbility ABILITY_* of the ability to apply the cost to
+ * @param nCost    The amount of stat damage or drain to apply
+ * @param bDrain   If this is TRUE, the cost is applied as ability drain.
+ *                 If FALSE, as ability damage.
+ */
+void DoCorruptionCost(object oPC, int nAbility, int nCost, int bDrain);
+
+// This function is used in the spellscripts
+// It functions as Evasion for Fortitude and Will partial saves
+// This means the "partial" section is ignored
+// nSavingThrow takes either SAVING_THROW_WILL or SAVING_THROW_FORT
+int GetHasMettle(object oTarget, int nSavingThrow = SAVING_THROW_WILL);
+
+// Applies all of the effects needed to set a creature incorporeal
+// You need to set the creature incorporeal in the feat/spell/effect itself if using nPermanent = TRUE
+// nSuperOrEx: 0 is normal, 1 is Supernatural, 2 is Extraordinary
+void SetIncorporeal(object oTarget, float fDuration, int nSuperOrEx, int nPermanent = FALSE);
+
+// Test for incorporeallity of the target
+// useful for targetting loops when incorporeal creatures
+// wouldnt be affected
+int GetIsIncorporeal(object oTarget);
+
+/** Tests if a creature is living. Should be called on creatures.
+ *  Dead and not-alive creatures return FALSE
+ *  Returns FALSE for non-creature objects.
+ */
+int PRCGetIsAliveCreature(object oTarget);
+
+// Gets the total number of HD of controlled undead
+// i.e from Animate Dead, Ghoul Gauntlet or similar
+// Dominated undead from Turn Undead do not count
+int GetControlledUndeadTotalHD(object oPC = OBJECT_SELF);
+
+// Gets the total number of HD of controlled evil outsiders
+// i.e from call dretch, call lemure, or similar
+// Dominated outsiders from Turn Undead etc do not count
+int GetControlledFiendTotalHD(object oPC = OBJECT_SELF);
+
+// Gets the total number of HD of controlled good outsiders
+// i.e from call favoured servants
+// Dominated outsiders from Turn Undead etc do not count
+int GetControlledCelestialTotalHD(object oPC = OBJECT_SELF);
+
+/**
+ * Multisummon code, to be run before the summoning effect is applied.
+ * Normally, this will only perform the multisummon trick of setting
+ * pre-existing summons indestructable if PRC_MULTISUMMON is set.
+ *
+ * @param oPC          The creature casting the summoning spell
+ * @param bOverride    If this is set, ignores the value of PRC_MULTISUMMON switch
+ */
+void MultisummonPreSummon(object oPC = OBJECT_SELF, int bOverride = FALSE);
+
+/**
+ * Sets up all of the AoE's variables, but only if they aren't already set.
+ *
+ * This sets many things that would have been checked against GetAreaOfEffectCreator()
+ * as local ints making it so the AoE can now function entirely independantly of its caster.
+ * - The only problem is that this will never be called until the AoE does a heartbeat or
+ * something.
+ *
+ * Since some functions (ie PRCGetLastSpellcastClass() can not work outside of the spell script
+ * sometimes SetAllAoEInts() was storing incorrect vaules for 'new spellbook' classes.
+ * I modified the function and moved it to main spell script, so it should work correctly now. - x
+ *
+ * @param SpellID       Spell ID to store on the AoE.
+ * @param oAoE          AoE object to store the variables on
+ * @param nBaseSaveDC   save DC to store on the AoE
+ * @param SpecDispel    Stored on the AoE (dunno what it's for)
+ * @param nCasterLevel  Caster level to store on the AoE. If default used, gets
+ *                      caster level from the AoE creator.
+ */
+void SetAllAoEInts(int SpellID, object oAoE, int nBaseSaveDC, int SpecDispel = 0 , int nCasterLevel = 0);
+
+// * Applies the effects of FEAT_AUGMENT_SUMMON to summoned creatures.
+void AugmentSummonedCreature(string sResRef);
+
+// -----------------
+// BEGIN SPELLSWORD
+// -----------------
+
+//This function returns 1 only if the object oTarget is the object
+//the weapon hit when it channeled the spell sSpell or if there is no
+//channeling at all
+int ChannelChecker(string sSpell, object oTarget);
+
+//If a spell is being channeled, we store its target and its name
+void StoreSpellVariables(string sString,int nDuration);
+
+//Replacement for The MaximizeOrEmpower function
+int PRCMaximizeOrEmpower(int nDice, int nNumberOfDice, int nMeta, int nBonus = 0);
+
+//This checks if the spell is channeled and if there are multiple spells
+//channeled, which one is it. Then it checks in either case if the spell
+//has the metamagic feat the function gets and returns TRUE or FALSE accordingly
+//int CheckMetaMagic(int nMeta,int nMMagic);
+//not needed now there is PRCGetMetaMagicFeat()
+
+//wrapper for biowares GetMetaMagicFeat()
+//used for spellsword and items
+//      bClearFeatFlags   - clear metamagic feat info (sudden meta, divine meta etc.)- set it to FALSE if you're
+//                          going to use PRCGetMetaMagicFeat() more than once for a single spell
+//                          (ie. first in spellhook code, next in spell script)
+int PRCGetMetaMagicFeat(object oCaster = OBJECT_SELF, int bClearFeatFlags = TRUE);
+
+// This function rolls damage and applies metamagic feats to the damage.
+//      nDamageType - The DAMAGE_TYPE_xxx constant for the damage, or -1 for no
+//          a non-damaging effect.
+//      nDice - number of dice to roll.
+//      nDieSize - size of dice, i.e. d4, d6, d8, etc.
+//      nBonusPerDie - Amount of bonus damage per die.
+//      nBonus - Amount of overall bonus damage.
+//      nMetaMagic - metamagic constant, if -1 GetMetaMagic() is called.
+//      returns - the damage rolled with metamagic applied.
+int PRCGetMetaMagicDamage(int nDamageType, int nDice, int nDieSize,
+    int nBonusPerDie = 0, int nBonus = 0, int nMetaMagic = -1);
+
+// Function to save the school of the currently cast spell in a variable.  This should be
+// called at the beginning of the script to set the spell school (passing the school) and
+// once at the end of the script (with no arguments) to delete the variable.
+//  nSchool - SPELL_SCHOOL_xxx constant to set, if general then the variable is
+//      deleted.
+// moved from spinc_common and renamed
+void PRCSetSchool(int nSchool = SPELL_SCHOOL_GENERAL);
+
+/**
+ * Signals a spell has been cast. Acts as a wrapper to fire EVENT_SPELL_CAST_AT
+ * via SignalEvent()
+ * @param oTarget   Target of the spell.
+ * @param bHostile  TRUE if the spell is a hostile act.
+ * @param nSpellID  Spell ID or -1 if PRCGetSpellId() should be used.
+ * @param oCaster   Object doing the casting.
+ */
+void PRCSignalSpellEvent(object oTarget, int bHostile = TRUE, int nSpellID = -1, object oCaster = OBJECT_SELF);
+
+//GetFirstObjectInShape wrapper for changing the AOE of the channeled spells (Spellsword Channel Spell)
+object MyFirstObjectInShape(int nShape, float fSize, location lTarget, int bLineOfSight=FALSE, int nObjectFilter=OBJECT_TYPE_CREATURE, vector vOrigin=[0.0,0.0,0.0]);
+
+//GetNextObjectInShape wrapper for changing the AOE of the channeled spells (Spellsword Channel Spell)
+object MyNextObjectInShape(int nShape, float fSize, location lTarget, int bLineOfSight=FALSE, int nObjectFilter=OBJECT_TYPE_CREATURE, vector vOrigin=[0.0,0.0,0.0]);
+
+// * Kovi. removes any effects from this type of spell
+// * i.e., used in Mage Armor to remove any previous
+// * mage armors
+void PRCRemoveEffectsFromSpell(object oTarget, int SpellID);
+
+// * Get Scaled Effect
+effect PRCGetScaledEffect(effect eStandard, object oTarget);
+
+// * Searchs through a persons effects and removes all those of a specific type.
+void PRCRemoveSpecificEffect(int nEffectTypeID, object oTarget);
+
+// * Returns true if Target is a humanoid
+int PRCAmIAHumanoid(object oTarget);
+
+// * Get Difficulty Duration
+int PRCGetScaledDuration(int nActualDuration, object oTarget);
+
+// * Will pass back a linked effect for all the protection from alignment spells.  The power represents the multiplier of strength.
+// * That is instead of +3 AC and +2 Saves a  power of 2 will yield +6 AC and +4 Saves.
+effect PRCCreateProtectionFromAlignmentLink(int nAlignment, int nPower = 1);
+
+// * Returns the time in seconds that the effect should be delayed before application.
+float PRCGetSpellEffectDelay(location SpellTargetLocation, object oTarget);
+
+// * This is a wrapper for how Petrify will work in Expansion Pack 1
+// * Scripts affected: flesh to stone, breath petrification, gaze petrification, touch petrification
+// * nPower : This is the Hit Dice of a Monster using Gaze, Breath or Touch OR it is the Caster Spell of
+// *   a spellcaster
+// * nFortSaveDC: pass in this number from the spell script
+void PRCDoPetrification(int nPower, object oSource, object oTarget, int nSpellID, int nFortSaveDC);
+
+int PRCGetDelayedSpellEffectsExpired(int nSpell_ID, object oTarget, object oCaster);
+
+int PRCGetSpellUsesLeft(int nRealSpellID, object oCreature = OBJECT_SELF);
+// -----------------
+// END SPELLSWORD
+// -----------------
+
+// Functions mostly only useful within the scope of this include
+int BWSavingThrow(int nSavingThrow, object oTarget, int nDC, int nSaveType = SAVING_THROW_TYPE_NONE, object oSaveVersus = OBJECT_SELF, float fDelay = 0.0);
+
+// This function holds all functions that are supposed to run before the actual
+// spellscript gets run. If this functions returns FALSE, the spell is aborted
+// and the spellscript will not run
+int X2PreSpellCastCode();
+
+//////////////////////////////////////////////////
+/*                 Constants                    */
+//////////////////////////////////////////////////
+
+// this could also be put into in prc_inc_switches
+const string PRC_SAVEDC_OVERRIDE = "PRC_SAVEDC_OVERRIDE";
+
+const int  TYPE_ARCANE   = -1;
+const int  TYPE_DIVINE   = -2;
+
+
+//Changed to use CLASS_TYPE_* instead
+//const int  TYPE_SORCERER = 2;
+//const int  TYPE_WIZARD   = 3;
+//const int  TYPE_BARD     = 4;
+//const int  TYPE_CLERIC   = 11;
+//const int  TYPE_DRUID    = 12;
+//const int  TYPE_RANGER   = 13;
+//const int  TYPE_PALADIN  = 14;
+
+//////////////////////////////////////////////////
+/*                  Includes                    */
+//////////////////////////////////////////////////
+
+//#include "inc_abil_damage"
+//#include "prc_inc_castlvl"
+//#include "lookup_2da_spell"
+
+// ** THIS ORDER IS IMPORTANT **
+
+//#include "inc_lookups"	// access via prc_inc_core
+#include "inc_newspellbook"
+
+//#include "prc_inc_core"  // Compiler won't allow access via inc_newspellbook
+
+#include "inc_vfx_const"
+#include "spinc_necro_cyst"
+#include "true_utter_const"
+//#include "shd_myst_const"
+//#include "prc_spellhook"
+#include "prc_inc_sneak"
+#include "prcsp_engine"
+//#include "prc_inc_descrptr"
+#include "inc_item_props"
+
+
+//////////////////////////////////////////////////
+/*             Function definitions             */
+//////////////////////////////////////////////////
+
+
+int GetPrCAdjustedClassLevel(int nClass, object oCaster = OBJECT_SELF)
+{
+    int iTemp;
+    // is it arcane, divine or neither?
+    if(GetIsArcaneClass(nClass, oCaster) && nClass != CLASS_TYPE_SUBLIME_CHORD)
+    {
+        if (GetPrimaryArcaneClass(oCaster) == nClass) // adjust for any PrCs
+            iTemp = GetArcanePRCLevels(oCaster);
+    }
+    else if(GetIsDivineClass(nClass, oCaster))
+    {
+        if (GetPrimaryDivineClass(oCaster) == nClass) // adjust for any PrCs
+            iTemp = GetDivinePRCLevels(oCaster);
+    }
+    else // a non-caster class or a PrC
+    {
+        return 0;
+    }
+    // add the caster class levels
+    return iTemp += GetLevelByClass(nClass, oCaster);
+}
+
+int GetPrCAdjustedCasterLevel(int nClass, object oCaster = OBJECT_SELF, int bAdjustForPractisedSpellcaster = TRUE)
+{
+    int iTemp;
+    iTemp = GetPrCAdjustedClassLevel(nClass, oCaster);
+    iTemp = iTemp / GetCasterLevelModifier(nClass);
+    if (bAdjustForPractisedSpellcaster)
+        iTemp += PracticedSpellcasting(oCaster, nClass, iTemp);
+    return iTemp;
+}
+
+int GetPrCAdjustedCasterLevelByType(int nClassType, object oCaster = OBJECT_SELF, int bAdjustForPractisedSpellcaster = TRUE)
+{
+	int nClassLvl;
+	int nClass1, nClass2, nClass3, nClass4, nClass5, nClass6, nClass7, nClass8;
+	int nClass1Lvl, nClass2Lvl, nClass3Lvl, nClass4Lvl, nClass5Lvl, nClass6Lvl, nClass7Lvl, nClass8Lvl;
+		
+    nClass1 = GetClassByPosition(1, oCaster);
+    nClass2 = GetClassByPosition(2, oCaster);
+    nClass3 = GetClassByPosition(3, oCaster);
+    nClass4 = GetClassByPosition(4, oCaster);
+    nClass5 = GetClassByPosition(5, oCaster);
+    nClass6 = GetClassByPosition(6, oCaster);
+    nClass7 = GetClassByPosition(7, oCaster);
+    nClass8 = GetClassByPosition(8, oCaster);
+	
+    if(nClassType == TYPE_ARCANE && (GetFirstArcaneClassPosition(oCaster) > 0))
+    {
+        if (GetIsArcaneClass(nClass1, oCaster)) nClass1Lvl = GetPrCAdjustedCasterLevel(nClass1, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsArcaneClass(nClass2, oCaster)) nClass2Lvl = GetPrCAdjustedCasterLevel(nClass2, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsArcaneClass(nClass3, oCaster)) nClass3Lvl = GetPrCAdjustedCasterLevel(nClass3, oCaster, bAdjustForPractisedSpellcaster);
+		if (GetIsArcaneClass(nClass4, oCaster)) nClass4Lvl = GetPrCAdjustedCasterLevel(nClass4, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsArcaneClass(nClass5, oCaster)) nClass5Lvl = GetPrCAdjustedCasterLevel(nClass5, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsArcaneClass(nClass6, oCaster)) nClass6Lvl = GetPrCAdjustedCasterLevel(nClass6, oCaster, bAdjustForPractisedSpellcaster);
+		if (GetIsArcaneClass(nClass7, oCaster)) nClass7Lvl = GetPrCAdjustedCasterLevel(nClass7, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsArcaneClass(nClass8, oCaster)) nClass8Lvl = GetPrCAdjustedCasterLevel(nClass8, oCaster, bAdjustForPractisedSpellcaster);
+    }
+    else if (nClassType == TYPE_DIVINE && (GetFirstDivineClassPosition(oCaster) > 0))
+    {
+        if (GetIsDivineClass(nClass1, oCaster)) nClass1Lvl = GetPrCAdjustedCasterLevel(nClass1, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsDivineClass(nClass2, oCaster)) nClass2Lvl = GetPrCAdjustedCasterLevel(nClass2, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsDivineClass(nClass3, oCaster)) nClass3Lvl = GetPrCAdjustedCasterLevel(nClass3, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsDivineClass(nClass4, oCaster)) nClass4Lvl = GetPrCAdjustedCasterLevel(nClass4, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsDivineClass(nClass5, oCaster)) nClass5Lvl = GetPrCAdjustedCasterLevel(nClass5, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsDivineClass(nClass6, oCaster)) nClass6Lvl = GetPrCAdjustedCasterLevel(nClass6, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsDivineClass(nClass7, oCaster)) nClass7Lvl = GetPrCAdjustedCasterLevel(nClass7, oCaster, bAdjustForPractisedSpellcaster);
+        if (GetIsDivineClass(nClass8, oCaster)) nClass8Lvl = GetPrCAdjustedCasterLevel(nClass8, oCaster, bAdjustForPractisedSpellcaster);		
+    }
+    int nHighest = nClass1Lvl;
+    if (nClass2Lvl > nHighest) nHighest = nClass2Lvl;
+    if (nClass3Lvl > nHighest) nHighest = nClass3Lvl;
+	if (nClass4Lvl > nHighest) nHighest = nClass4Lvl;
+    if (nClass5Lvl > nHighest) nHighest = nClass5Lvl;
+    if (nClass6Lvl > nHighest) nHighest = nClass6Lvl;
+    if (nClass7Lvl > nHighest) nHighest = nClass7Lvl;
+    if (nClass8Lvl > nHighest) nHighest = nClass8Lvl;	
+	return nHighest;
+}
+
+int GetLevelByTypeArcaneFeats(object oCaster = OBJECT_SELF, int iSpellID = -1)
+{
+    int iFirstArcane = GetPrimaryArcaneClass(oCaster);
+    int iBest = 0;
+    int iClass1 = GetClassByPosition(1, oCaster);
+    int iClass2 = GetClassByPosition(2, oCaster);
+    int iClass3 = GetClassByPosition(3, oCaster);
+    int iClass4 = GetClassByPosition(4, oCaster);
+    int iClass5 = GetClassByPosition(5, oCaster);
+    int iClass6 = GetClassByPosition(6, oCaster);
+    int iClass7 = GetClassByPosition(7, oCaster);
+    int iClass8 = GetClassByPosition(8, oCaster);
+	
+    int iClass1Lev = GetLevelByPosition(1, oCaster);
+    int iClass2Lev = GetLevelByPosition(2, oCaster);
+    int iClass3Lev = GetLevelByPosition(3, oCaster);
+    int iClass4Lev = GetLevelByPosition(4, oCaster);
+    int iClass5Lev = GetLevelByPosition(5, oCaster);
+    int iClass6Lev = GetLevelByPosition(6, oCaster);
+    int iClass7Lev = GetLevelByPosition(7, oCaster);
+    int iClass8Lev = GetLevelByPosition(8, oCaster);
+
+    if (iSpellID = -1) iSpellID = PRCGetSpellId(oCaster);
+
+    int iBoost = ShadowWeave(oCaster, iSpellID) +
+                 FireAdept(oCaster, iSpellID) +
+                 DomainPower(oCaster, iSpellID) +
+                 StormMagic(oCaster) +
+                 CormanthyranMoonMagic(oCaster) +
+                 DraconicPower(oCaster);
+
+    if (iClass1 == CLASS_TYPE_HEXBLADE) iClass1Lev = (iClass1Lev >= 4) ? (iClass1Lev / 2) : 0;
+    if (iClass2 == CLASS_TYPE_HEXBLADE) iClass2Lev = (iClass2Lev >= 4) ? (iClass2Lev / 2) : 0;
+    if (iClass3 == CLASS_TYPE_HEXBLADE) iClass3Lev = (iClass3Lev >= 4) ? (iClass3Lev / 2) : 0;
+    if (iClass4 == CLASS_TYPE_HEXBLADE) iClass4Lev = (iClass4Lev >= 4) ? (iClass4Lev / 2) : 0;
+    if (iClass5 == CLASS_TYPE_HEXBLADE) iClass5Lev = (iClass5Lev >= 4) ? (iClass5Lev / 2) : 0;
+    if (iClass6 == CLASS_TYPE_HEXBLADE) iClass6Lev = (iClass6Lev >= 4) ? (iClass6Lev / 2) : 0;
+    if (iClass7 == CLASS_TYPE_HEXBLADE) iClass7Lev = (iClass7Lev >= 4) ? (iClass7Lev / 2) : 0;
+    if (iClass8 == CLASS_TYPE_HEXBLADE) iClass8Lev = (iClass8Lev >= 4) ? (iClass8Lev / 2) : 0;
+
+    if (iClass1 == iFirstArcane) iClass1Lev += GetArcanePRCLevels(oCaster);
+    if (iClass2 == iFirstArcane) iClass2Lev += GetArcanePRCLevels(oCaster);
+    if (iClass3 == iFirstArcane) iClass3Lev += GetArcanePRCLevels(oCaster);
+	if (iClass1 == iFirstArcane) iClass1Lev += GetArcanePRCLevels(oCaster);
+    if (iClass2 == iFirstArcane) iClass2Lev += GetArcanePRCLevels(oCaster);
+    if (iClass3 == iFirstArcane) iClass3Lev += GetArcanePRCLevels(oCaster);
+    if (iClass1 == iFirstArcane) iClass1Lev += GetArcanePRCLevels(oCaster);
+    if (iClass2 == iFirstArcane) iClass2Lev += GetArcanePRCLevels(oCaster);
+    if (iClass3 == iFirstArcane) iClass3Lev += GetArcanePRCLevels(oCaster);	
+
+    iClass1Lev += iBoost;
+    iClass2Lev += iBoost;
+    iClass3Lev += iBoost;
+    iClass4Lev += iBoost;
+    iClass5Lev += iBoost;
+    iClass6Lev += iBoost;	
+    iClass7Lev += iBoost;
+    iClass8Lev += iBoost;
+
+    iClass1Lev += PracticedSpellcasting(oCaster, iClass1, iClass1Lev);
+    iClass2Lev += PracticedSpellcasting(oCaster, iClass2, iClass2Lev);
+    iClass3Lev += PracticedSpellcasting(oCaster, iClass3, iClass3Lev);
+    iClass4Lev += PracticedSpellcasting(oCaster, iClass4, iClass1Lev);
+    iClass5Lev += PracticedSpellcasting(oCaster, iClass5, iClass2Lev);
+    iClass6Lev += PracticedSpellcasting(oCaster, iClass6, iClass3Lev);
+    iClass7Lev += PracticedSpellcasting(oCaster, iClass7, iClass1Lev);
+    iClass8Lev += PracticedSpellcasting(oCaster, iClass8, iClass2Lev);
+	
+    if (!GetIsArcaneClass(iClass1, oCaster)) iClass1Lev = 0;
+    if (!GetIsArcaneClass(iClass2, oCaster)) iClass2Lev = 0;
+    if (!GetIsArcaneClass(iClass3, oCaster)) iClass3Lev = 0;
+    if (!GetIsArcaneClass(iClass4, oCaster)) iClass4Lev = 0;
+    if (!GetIsArcaneClass(iClass5, oCaster)) iClass5Lev = 0;
+    if (!GetIsArcaneClass(iClass6, oCaster)) iClass6Lev = 0;
+    if (!GetIsArcaneClass(iClass7, oCaster)) iClass7Lev = 0;
+    if (!GetIsArcaneClass(iClass8, oCaster)) iClass8Lev = 0;
+
+    if (iClass1Lev > iBest) iBest = iClass1Lev;
+    if (iClass2Lev > iBest) iBest = iClass2Lev;
+    if (iClass3Lev > iBest) iBest = iClass3Lev;
+    if (iClass4Lev > iBest) iBest = iClass4Lev;
+    if (iClass5Lev > iBest) iBest = iClass5Lev;
+    if (iClass6Lev > iBest) iBest = iClass6Lev;
+    if (iClass7Lev > iBest) iBest = iClass7Lev;
+    if (iClass8Lev > iBest) iBest = iClass8Lev;
+	
+    return iBest;
+}
+
+int GetLevelByTypeDivineFeats(object oCaster = OBJECT_SELF, int iSpellID = -1)
+{
+    int iFirstDivine = GetPrimaryDivineClass(oCaster);
+    int iBest = 0;
+    int iClass1 = GetClassByPosition(1, oCaster);
+    int iClass2 = GetClassByPosition(2, oCaster);
+    int iClass3 = GetClassByPosition(3, oCaster);
+    int iClass4 = GetClassByPosition(4, oCaster);
+    int iClass5 = GetClassByPosition(5, oCaster);
+    int iClass6 = GetClassByPosition(6, oCaster);
+	int iClass7 = GetClassByPosition(7, oCaster);
+    int iClass8 = GetClassByPosition(8, oCaster);
+	
+    int iClass1Lev = GetLevelByPosition(1, oCaster);
+    int iClass2Lev = GetLevelByPosition(2, oCaster);
+    int iClass3Lev = GetLevelByPosition(3, oCaster);
+    int iClass4Lev = GetLevelByPosition(4, oCaster);
+    int iClass5Lev = GetLevelByPosition(5, oCaster);
+    int iClass6Lev = GetLevelByPosition(6, oCaster);
+    int iClass7Lev = GetLevelByPosition(7, oCaster);
+    int iClass8Lev = GetLevelByPosition(8, oCaster);
+	
+    if (iSpellID = -1) iSpellID = PRCGetSpellId(oCaster);
+
+    int iBoost = ShadowWeave(oCaster, iSpellID) +
+                 FireAdept(oCaster, iSpellID) +
+                 DomainPower(oCaster, iSpellID) +
+                 CormanthyranMoonMagic(oCaster) +
+                 StormMagic(oCaster);
+
+    if (iClass1 == CLASS_TYPE_PALADIN
+        || iClass1 == CLASS_TYPE_RANGER
+        || iClass1 == CLASS_TYPE_ANTI_PALADIN)
+        iClass1Lev = iClass1Lev / 2;
+    if (iClass2 == CLASS_TYPE_PALADIN
+        || iClass2 == CLASS_TYPE_RANGER
+        || iClass2 == CLASS_TYPE_ANTI_PALADIN)
+        iClass2Lev = iClass2Lev / 2;
+    if (iClass3 == CLASS_TYPE_PALADIN
+        || iClass3 == CLASS_TYPE_RANGER
+        || iClass3 == CLASS_TYPE_ANTI_PALADIN)
+        iClass3Lev = iClass3Lev / 2;
+    if (iClass4 == CLASS_TYPE_PALADIN
+        || iClass4 == CLASS_TYPE_RANGER
+        || iClass4 == CLASS_TYPE_ANTI_PALADIN)
+        iClass4Lev = iClass4Lev / 2;
+    if (iClass5 == CLASS_TYPE_PALADIN
+        || iClass5 == CLASS_TYPE_RANGER
+        || iClass5 == CLASS_TYPE_ANTI_PALADIN)
+        iClass5Lev = iClass5Lev / 2;
+	if (iClass6 == CLASS_TYPE_PALADIN
+        || iClass6 == CLASS_TYPE_RANGER
+        || iClass6 == CLASS_TYPE_ANTI_PALADIN)
+        iClass6Lev = iClass6Lev / 2;
+    if (iClass7 == CLASS_TYPE_PALADIN
+        || iClass7 == CLASS_TYPE_RANGER
+        || iClass7 == CLASS_TYPE_ANTI_PALADIN)
+        iClass7Lev = iClass7Lev / 2;		
+    if (iClass8 == CLASS_TYPE_PALADIN
+        || iClass8 == CLASS_TYPE_RANGER
+        || iClass8 == CLASS_TYPE_ANTI_PALADIN)
+        iClass8Lev = iClass7Lev / 2;		
+		
+    if (iClass1 == iFirstDivine) iClass1Lev += GetDivinePRCLevels(oCaster);
+    if (iClass2 == iFirstDivine) iClass2Lev += GetDivinePRCLevels(oCaster);
+    if (iClass3 == iFirstDivine) iClass3Lev += GetDivinePRCLevels(oCaster);
+    if (iClass4 == iFirstDivine) iClass4Lev += GetDivinePRCLevels(oCaster);
+    if (iClass5 == iFirstDivine) iClass5Lev += GetDivinePRCLevels(oCaster);
+    if (iClass6 == iFirstDivine) iClass6Lev += GetDivinePRCLevels(oCaster);
+    if (iClass7 == iFirstDivine) iClass7Lev += GetDivinePRCLevels(oCaster);
+    if (iClass8 == iFirstDivine) iClass8Lev += GetDivinePRCLevels(oCaster);
+	
+    iClass1Lev += iBoost;
+    iClass2Lev += iBoost;
+    iClass3Lev += iBoost;
+    iClass4Lev += iBoost;
+    iClass5Lev += iBoost;
+    iClass6Lev += iBoost;
+	iClass7Lev += iBoost;
+    iClass8Lev += iBoost;
+
+    iClass1Lev += PracticedSpellcasting(oCaster, iClass1, iClass1Lev);
+    iClass2Lev += PracticedSpellcasting(oCaster, iClass2, iClass2Lev);
+    iClass3Lev += PracticedSpellcasting(oCaster, iClass3, iClass3Lev);
+    iClass4Lev += PracticedSpellcasting(oCaster, iClass4, iClass4Lev);
+    iClass5Lev += PracticedSpellcasting(oCaster, iClass5, iClass5Lev);
+    iClass6Lev += PracticedSpellcasting(oCaster, iClass6, iClass6Lev);
+	iClass7Lev += PracticedSpellcasting(oCaster, iClass1, iClass7Lev);
+    iClass8Lev += PracticedSpellcasting(oCaster, iClass2, iClass8Lev);
+
+    if (!GetIsDivineClass(iClass1, oCaster)) iClass1Lev = 0;
+    if (!GetIsDivineClass(iClass2, oCaster)) iClass2Lev = 0;
+    if (!GetIsDivineClass(iClass3, oCaster)) iClass3Lev = 0;
+    if (!GetIsDivineClass(iClass4, oCaster)) iClass4Lev = 0;
+    if (!GetIsDivineClass(iClass5, oCaster)) iClass5Lev = 0;
+    if (!GetIsDivineClass(iClass6, oCaster)) iClass6Lev = 0;
+    if (!GetIsDivineClass(iClass7, oCaster)) iClass7Lev = 0;
+    if (!GetIsDivineClass(iClass8, oCaster)) iClass3Lev = 0;
+	
+    if (iClass1Lev > iBest) iBest = iClass1Lev;
+    if (iClass2Lev > iBest) iBest = iClass2Lev;
+    if (iClass3Lev > iBest) iBest = iClass3Lev;
+    if (iClass4Lev > iBest) iBest = iClass4Lev;
+    if (iClass5Lev > iBest) iBest = iClass5Lev;
+    if (iClass6Lev > iBest) iBest = iClass6Lev;
+    if (iClass7Lev > iBest) iBest = iClass7Lev;
+    if (iClass8Lev > iBest) iBest = iClass8Lev;
+
+    return iBest;
+}
+
+// looks up the spell level for the arcane caster classes (Wiz_Sorc, Bard) in spells.2da.
+// Caveat: some onhitcast spells don't have any spell-levels listed for any class
+int GetIsArcaneSpell (int iSpellId)
+{
+    return  Get2DACache("spells", "Wiz_Sorc", iSpellId) != ""
+            || Get2DACache("spells", "Bard", iSpellId) != "";
+}
+
+// looks up the spell level for the divine caster classes (Cleric, Druid, Ranger, Paladin) in spells.2da.
+// Caveat: some onhitcast spells don't have any spell-levels listed for any class
+int GetIsDivineSpell (int iSpellId)
+{
+    return  Get2DACache("spells", "Cleric", iSpellId) != ""
+            || Get2DACache("spells", "Druid", iSpellId) != ""
+            || Get2DACache("spells", "Ranger", iSpellId) != ""
+            || Get2DACache("spells", "Paladin", iSpellId) != "";
+}
+
+int BWSavingThrow(int nSavingThrow, object oTarget, int nDC, int nSaveType = SAVING_THROW_TYPE_NONE, object oSaveVersus = OBJECT_SELF, float fDelay = 0.0)
+{
+    // GZ: sanity checks to prevent wrapping around
+    if      (nDC <   1) nDC = 1;
+    else if (nDC > 255) nDC = 255;
+
+    int bValid = 0;
+    int nEff;
+
+    //some maneuvers allow people to use skill check instead of a save
+    if(nSavingThrow == SAVING_THROW_FORT)
+    {
+        bValid = GetLocalInt(oTarget, "MindOverBody") ?
+                 GetIsSkillSuccessful(oTarget, SKILL_CONCENTRATION, nDC) :
+                 FortitudeSave(oTarget, nDC, nSaveType, oSaveVersus);
+        if(bValid == 1) nEff = VFX_IMP_FORTITUDE_SAVING_THROW_USE;
+    }
+    else if(nSavingThrow == SAVING_THROW_REFLEX)
+    {
+        bValid = GetLocalInt(oTarget, "ActionBeforeThought") ?
+                 GetIsSkillSuccessful(oTarget, SKILL_CONCENTRATION, nDC) :
+                 ReflexSave(oTarget, nDC, nSaveType, oSaveVersus);
+        if(bValid == 1) nEff = VFX_IMP_REFLEX_SAVE_THROW_USE;
+    }
+    else if(nSavingThrow == SAVING_THROW_WILL)
+    {
+        bValid = GetLocalInt(oTarget, "MomentOfPerfectMind") ?
+                 GetIsSkillSuccessful(oTarget, SKILL_CONCENTRATION, nDC) :
+                 WillSave(oTarget, nDC, nSaveType, oSaveVersus);
+        if(bValid == 1) nEff = VFX_IMP_WILL_SAVING_THROW_USE;
+    }
+
+    /*
+        return 0 = FAILED SAVE
+        return 1 = SAVE SUCCESSFUL
+        return 2 = IMMUNE TO WHAT WAS BEING SAVED AGAINST
+    */
+    if(bValid == 0)
+    {
+        int nSpellID = PRCGetSpellId(oSaveVersus);
+        if(nSaveType == SAVING_THROW_TYPE_DEATH
+         || nSpellID == SPELL_WEIRD
+         || nSpellID == SPELL_FINGER_OF_DEATH)
+         //&& nSpellID != SPELL_HORRID_WILTING)
+        {
+            if(fDelay > 0.0f) DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DEATH), oTarget));
+            else                                   ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DEATH), oTarget);
+        }
+    }
+    else //if(bValid == 1 || bValid == 2)
+    {
+        if(bValid == 2) nEff = VFX_IMP_MAGIC_RESISTANCE_USE;
+
+        if(fDelay > 0.0f) DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(nEff), oTarget));
+        else                                   ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(nEff), oTarget);
+    }
+    return bValid;
+}
+
+void PRCBonusDamage(object oTarget, object oCaster = OBJECT_SELF)
+{
+    // Does nothing, left here so files don't need to be edited.
+}
+
+//  Bonus damage to a spell for Spell Betrayal Ability
+int SpellBetrayalDamage(object oTarget, object oCaster)
+{
+     int iDam = 0;
+     int ThrallLevel = GetLevelByClass(CLASS_TYPE_THRALL_OF_GRAZZT_A, oCaster) + GetLevelByClass(CLASS_TYPE_THRALL_OF_GRAZZT_D, oCaster);
+
+     if(ThrallLevel >= 2)
+     {
+          if( GetIsDeniedDexBonusToAC(oTarget, oCaster, TRUE) )
+          {
+               ThrallLevel /= 2;
+               iDam = d6(ThrallLevel);
+          }
+     }
+
+     return iDam;
+}
+
+//  Bonus damage to a spell for Spellstrike Ability
+int SpellStrikeDamage(object oTarget, object oCaster)
+{
+     int iDam = 0;
+     int ThrallLevel = GetLevelByClass(CLASS_TYPE_THRALL_OF_GRAZZT_A, oCaster) + GetLevelByClass(CLASS_TYPE_THRALL_OF_GRAZZT_D, oCaster);
+
+     if(ThrallLevel >= 6)
+     {
+          if( GetIsAOEFlanked(oTarget, oCaster) )
+          {
+               ThrallLevel /= 4;
+               iDam = d6(ThrallLevel);
+          }
+     }
+
+     return iDam;
+}
+
+//  Adds the bonus damage from both Spell Betrayal and Spellstrike together
+int ApplySpellBetrayalStrikeDamage(object oTarget, object oCaster, int bShowTextString = TRUE)
+{
+     int iDam = 0;
+     int iBetrayalDam = SpellBetrayalDamage(oTarget, oCaster);
+     int iStrikeDam = SpellStrikeDamage(oTarget, oCaster);
+     string sMes = "";
+
+     if(iStrikeDam > 0 && iBetrayalDam > 0)  sMes ="*Spellstrike Betrayal Sucess*";
+     else if(iBetrayalDam > 0)               sMes ="*Spell Betrayal Sucess*";
+     else if(iStrikeDam > 0)                 sMes ="*Spellstrike Sucess*";
+
+     if(bShowTextString)      FloatingTextStringOnCreature(sMes, oCaster, TRUE);
+
+     iDam = iBetrayalDam + iStrikeDam;
+
+     // debug code
+     //sMes = "Spell Betrayal / Spellstrike Bonus Damage: " + IntToString(iBetrayalDam) + " + " + IntToString(iStrikeDam) + " = " + IntToString(iDam);
+     //DelayCommand( 1.0, FloatingTextStringOnCreature(sMes, oCaster, TRUE) );
+
+     return iDam;
+}
+
+int SpellDamagePerDice(object oCaster, int nDice)
+{
+	// Arcane only
+	if (!GetIsArcaneClass(PRCGetLastSpellCastClass(oCaster)))
+		return 0;
+
+    int nDam = 0;
+    nDam += GetLocalInt(oCaster, "StrengthFromMagic") * nDice * 2;
+
+	if (DEBUG) DoDebug("SpellDamagePerDice returning "+IntToString(nDam)+" for "+GetName(oCaster));
+
+    return nDam;
+}
+
+int PRCMySavingThrow(int nSavingThrow, object oTarget, int nDC, int nSaveType = SAVING_THROW_TYPE_NONE, object oSaveVersus = OBJECT_SELF, float fDelay = 0.0, int bImmunityCheck = FALSE)
+{
+    int nSpell = PRCGetSpellId(oSaveVersus);
+    int nSpellSchool = GetSpellSchool(nSpell);
+    
+	//If bImmunityCheck == FALSE: returns 0 if failure or immune, 1 if success - same as MySavingThrow
+	//If bImmunityCheck == TRUE:  returns 0 if failure, 1 if success, 2 if immune 
+	
+    // Enigma Helm Crown Bind
+    if (GetIsMeldBound(oTarget, MELD_ENIGMA_HELM) == CHAKRA_CROWN && GetIsOfSubschool(nSpell, SUBSCHOOL_CHARM))
+		return 2;		
+    
+    // Planar Ward
+    if (GetHasSpellEffect(MELD_PLANAR_WARD, oTarget) && (GetIsOfSubschool(nSpell, SUBSCHOOL_CHARM) || GetIsOfSubschool(nSpell, SUBSCHOOL_COMPULSION)))
+    	return 2;
+    	
+    // Chucoclops influence makes you autofail fear saves
+    if (GetHasSpellEffect(VESTIGE_CHUPOCLOPS, oTarget) && !GetLocalInt(oTarget, "PactQuality"+IntToString(VESTIGE_CHUPOCLOPS)) && nSaveType == SAVING_THROW_TYPE_FEAR)
+    	return 1;
+
+    // Iron Mind's Mind Over Body, allows them to treat other saves as will saves up to 3/day.
+    // No point in having it trigger when its a will save.
+    if(nSavingThrow != SAVING_THROW_WILL && GetLocalInt(oTarget, "IronMind_MindOverBody"))
+    {
+        nSavingThrow = SAVING_THROW_WILL;
+        DeleteLocalInt(oTarget, "IronMind_MindOverBody");
+    }
+
+    // Handle the target having Force of Will and being targeted by a psionic power
+    if(nSavingThrow != SAVING_THROW_WILL        &&
+       ((nSpell > 14000 && nSpell < 14360) ||
+        (nSpell > 15350 && nSpell < 15470)
+        )                                       &&
+       GetHasFeat(FEAT_FORCE_OF_WILL, oTarget)  &&
+       !GetLocalInt(oTarget, "ForceOfWillUsed") &&
+       // Only use will save if it's better
+       ((nSavingThrow == SAVING_THROW_FORT ? GetFortitudeSavingThrow(oTarget) : GetReflexSavingThrow(oTarget)) > GetWillSavingThrow(oTarget))
+       )
+    {
+        nSavingThrow = SAVING_THROW_WILL;
+        SetLocalInt(oTarget, "ForceOfWillUsed", TRUE);
+        DelayCommand(6.0f, DeleteLocalInt(oTarget, "ForceOfWillUsed"));
+        // "Force of Will used for this round."
+        FloatingTextStrRefOnCreature(16826670, oTarget, FALSE);
+    }
+
+    //TouchOfDistraction
+    if (GetLocalInt(oTarget, "HasTouchOfDistraction") && (nSavingThrow = SAVING_THROW_REFLEX))
+    {
+        nDC += 2;
+        DeleteLocalInt(oTarget, "HasTouchOfDistraction");
+    }
+    
+    //Diamond Defense
+    if(GetLocalInt(oTarget, "PRC_TOB_DIAMOND_DEFENSE"))
+        nDC -= GetLocalInt(oTarget, "PRC_TOB_DIAMOND_DEFENSE");
+
+    // Master of Nine
+    if(GetLevelByClass(CLASS_TYPE_MASTER_OF_NINE, oSaveVersus) > 2)
+    {
+        int nLastClass = GetLocalInt(oSaveVersus, "PRC_CurrentManeuver_InitiatingClass") - 1;
+        if(nLastClass == CLASS_TYPE_WARBLADE
+        || nLastClass == CLASS_TYPE_SWORDSAGE
+        || nLastClass == CLASS_TYPE_CRUSADER)
+        {
+            // Increases maneuver DCs by 1
+            nDC += 1;
+        }
+    }
+    
+    // Incarnum Resistance
+    if(GetHasFeat(FEAT_INCARNUM_RESISTANCE, oTarget) && nSpell > 18900 && nSpell < 18969)
+    	nDC -= 2;
+
+    // This is done here because it is possible to tell the saving throw type here
+    // it works by lowering the DC rather than adding to the save
+    // same net effect but slightly different numbers
+    if(nSaveType == SAVING_THROW_TYPE_MIND_SPELLS)
+    {
+        //Thayan Knights auto-fail mind spells cast by red wizards
+        if(GetLevelByClass(CLASS_TYPE_RED_WIZARD, oSaveVersus)
+        && GetLevelByClass(CLASS_TYPE_THAYAN_KNIGHT, oTarget))
+            return 0;
+        // Tyranny Domain increases the DC of mind spells by +2.
+        if(GetHasFeat(FEAT_DOMAIN_POWER_TYRANNY, oSaveVersus))
+            nDC += 2;
+        // +2 bonus on saves against mind affecting, done here
+        if(GetLevelByClass(CLASS_TYPE_FIST_DAL_QUOR, oTarget) > 1)
+            nDC -= 2;
+        // Scorpion's Resolve gives a +4 bonus on mind affecting saves
+        if(GetHasFeat(FEAT_SCORPIONS_RESOLVE, oTarget))
+            nDC -= 4;
+        // Warped Mind gives a bonus on mind affecting equal to half aberrant
+        if(GetHasFeat(FEAT_ABERRANT_WARPED_MIND, oTarget))
+            nDC -= GetAberrantFeatCount(oTarget)/2; 
+    }
+    else if(nSaveType == SAVING_THROW_TYPE_FEAR)
+    {
+        // Unnatural Will adds Charisma to saves against fear
+        if(GetHasFeat(FEAT_UNNATURAL_WILL, oTarget))
+            nDC -= GetAbilityModifier(ABILITY_CHARISMA, oTarget);
+        // Krinth have +4 saves against Fear
+        if(GetRacialType(oTarget) == RACIAL_TYPE_KRINTH)
+            nDC -= 4;
+        // Turlemoi/Lashemoi have -4 saves against Fear
+        if(GetRacialType(oTarget) == RACIAL_TYPE_LASHEMOI || GetRacialType(oTarget) == RACIAL_TYPE_TURLEMOI || GetLocalInt(oTarget, "SpeedFromPain") >= 3)
+            nDC += 4;            
+    }    
+    else if(nSaveType == SAVING_THROW_TYPE_NEGATIVE)
+    {
+        // +4 bonus on saves against negative energy, done here
+        if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oTarget) > 8)
+            nDC -= 4;
+        // Jergal's Pact gives a +2 bonus on negative energy saves
+        if(GetHasFeat(FEAT_JERGALS_PACT, oTarget))
+            nDC -= 2;
+    }
+    else if(nSaveType == SAVING_THROW_TYPE_DISEASE)
+    {
+        // Plague Resistant gives a +4 bonus on disease saves
+        if(GetHasFeat(FEAT_PLAGUE_RESISTANT, oTarget))
+            nDC -= 4;
+        // +4/+2 bonus on saves against disease, done here
+        if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oTarget) > 13)
+            nDC -= 4;
+        else if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oTarget) > 3)
+            nDC -= 2;
+    }
+    else if(nSaveType == SAVING_THROW_TYPE_POISON)
+    {
+        // +4/+2 bonus on saves against poison, done here
+        if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oTarget) > 13)
+            nDC -= 4;
+        else if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oTarget) > 3)
+            nDC -= 2;
+        if(GetHasFeat(FEAT_POISON_4, oTarget))
+            nDC -= 4;
+        if(GetHasFeat(FEAT_POISON_3, oTarget))
+            nDC -= 3;
+    	if(GetRacialType(oTarget) == RACIAL_TYPE_EXTAMINAAR && nSavingThrow == SAVING_THROW_FORT)
+        	nDC -= 2; 
+        if(GetRacialType(oTarget) == RACIAL_TYPE_MONGRELFOLK)
+        	nDC -= 1;
+    }
+    else if(nSaveType == SAVING_THROW_TYPE_FIRE)
+    {
+        // Bloodline of Fire gives a +4 bonus on fire saves
+        if(GetHasFeat(FEAT_BLOODLINE_OF_FIRE, oTarget))
+            nDC -= 4;
+        if(GetHasFeat(FEAT_HARD_FIRE, oTarget))
+            nDC -= 1 + (GetHitDice(oTarget) / 5);
+        // +2 vs fire for Halfgiant
+        if(GetHasFeat(FEAT_ACCLIMATED_FIRE, oTarget))
+            nDC -= 2;
+        // +2 vs fire for Heat Endurance feat
+        if(GetHasFeat(FEAT_HEAT_ENDURANCE, oTarget))
+            nDC -= 2;            
+    }
+    else if(nSaveType == SAVING_THROW_TYPE_COLD)
+    {
+        if(GetHasFeat(FEAT_HARD_WATER, oTarget))
+            nDC -= 1 + (GetHitDice(oTarget) / 5);
+        // +2 vs cold for Cold Endurance feat
+        if(GetHasFeat(FEAT_COLD_ENDURANCE, oTarget))
+            nDC -= 2;   
+        // +2 vs cold for Winterhide Shifter trait
+        if(GetHasFeat(FEAT_SHIFTER_WINTERHIDE, oTarget))
+            nDC -= 2;             
+    }
+    else if(nSaveType == SAVING_THROW_TYPE_ELECTRICITY)
+    {
+        if(GetHasFeat(FEAT_HARD_AIR, oTarget))
+            nDC -= 1 + (GetHitDice(oTarget) / 5);
+        else if(GetHasFeat(FEAT_HARD_ELEC, oTarget))
+            nDC -= 2;
+    }
+    else if(nSaveType == SAVING_THROW_TYPE_SONIC)
+    {
+        if(GetHasFeat(FEAT_HARD_AIR, oTarget))
+            nDC -= 1 + (GetHitDice(oTarget) / 5);
+    }
+    else if(nSaveType == SAVING_THROW_TYPE_ACID)
+    {
+        if(GetHasFeat(FEAT_HARD_EARTH, oTarget))
+            nDC -= 1 + (GetHitDice(oTarget) / 5);
+    }
+    
+    // This is done here because it is possible to tell the spell school here
+    // it works by lowering the DC rather than adding to the save
+    // same net effect but slightly different numbers
+    if(nSpellSchool == SPELL_SCHOOL_TRANSMUTATION)
+    {
+        // Full Moon's Trick - +2 vs Transmutation spels
+        if(GetLocalInt(oTarget, "FullMoon_Trans"))
+            nDC -= 2;
+        if(GetLevelByClass(CLASS_TYPE_SAPPHIRE_HIERARCH, oTarget) >= 2)
+            nDC -= 4;            
+    }    
+    
+    // Sapphire Heirarch gets +4 against Chaos and Transmutation effects
+   	if(GetLevelByClass(CLASS_TYPE_SAPPHIRE_HIERARCH, oTarget) >= 2 && GetHasDescriptor(nSpell, DESCRIPTOR_CHAOTIC))
+        nDC -= 4;      
+        
+    // Charming Veil Brow bind grants Essentia bonus on saves against charm and compulsion    
+    if(GetIsOfSubschool(nSpell, SUBSCHOOL_CHARM) || GetIsOfSubschool(nSpell, SUBSCHOOL_COMPULSION))
+    {
+    	if (GetIsMeldBound(oTarget, MELD_CHARMING_VEIL) == CHAKRA_BROW)
+    		nDC -= GetEssentiaInvested(oTarget, MELD_CHARMING_VEIL);
+    }
+    
+    // Krinth get +1 save against Shadow spells
+    if (GetIsOfSubschool(nSpell, SUBSCHOOL_SHADOW) && GetRacialType(oTarget) == RACIAL_TYPE_KRINTH)
+        nDC -= 1;
+
+    //Psionic race save boosts - +1 vs all spells for Xeph
+    if(GetHasFeat(FEAT_XEPH_SPELLHARD, oTarget))
+        nDC -= 1;
+
+    // Apostate - 1/2 HD bonus to resist divine spells
+    if(GetHasFeat(FEAT_APOSTATE, oTarget))
+    {
+        //if divine
+        if(GetIsDivineClass(PRCGetLastSpellCastClass(oSaveVersus)))
+            nDC -= GetHitDice(oTarget) / 2;
+    }
+    
+    // Hammer of Witches - +1 bonus against Arcane spells
+    if(GetIsObjectValid(GetItemPossessedBy(oTarget, "WOL_HammerWitches")))
+    {
+        if(GetIsArcaneClass(PRCGetLastSpellCastClass(oSaveVersus)))
+            nDC -= 1;
+    } 
+    
+    // Cultist of the Shattered Peak - +1 bonus against Arcane spells
+    if(GetLevelByClass(CLASS_TYPE_CULTIST_SHATTERED_PEAK, oTarget))
+    {
+        if(GetIsArcaneClass(PRCGetLastSpellCastClass(oSaveVersus)))
+            nDC -= 1;
+    }     
+
+    //Insightful Divination
+    if(GetLocalInt(oTarget, "Insightful Divination"))
+    {
+        nDC -= GetLocalInt(oTarget, "Insightful Divination");
+        DeleteLocalInt(oTarget, "Insightful Divination");
+    }
+
+    // Phierans Resolve - +4 bonus vs spells with evil descriptor
+    if(GetHasSpellEffect(SPELL_PHIERANS_RESOLVE, oTarget) && GetHasDescriptor(nSpell, DESCRIPTOR_EVIL))
+        nDC -= 4;
+
+    //spell school modificators
+    int nSchool = GetLocalInt(oSaveVersus, "X2_L_LAST_SPELLSCHOOL_VAR");
+    if(nSchool == SPELL_SCHOOL_NECROMANCY)
+    {
+        // Necrotic Cyst penalty on Necromancy spells
+        if(GetPersistantLocalInt(oTarget, NECROTIC_CYST_MARKER))
+            nDC += 2;
+    }
+    else if(nSchool == SPELL_SCHOOL_ILLUSION)
+    {
+        // Piercing Sight gives a +4 bonus on illusion saves
+        if(GetHasFeat(FEAT_PIERCING_SIGHT, oTarget))
+            nDC -= 4;
+        // Adds +2 to Illusion DCs
+        if(GetLocalInt(oSaveVersus, "ShadowTrickster"))
+            nDC += 2;
+    	// Illusion Veil Meld
+    	if(GetHasSpellEffect(MELD_ILLUSION_VEIL, oSaveVersus))
+			nDC += 1;
+    	// Illusion Veil Meld
+    	if(GetHasSpellEffect(MELD_ILLUSION_VEIL, oTarget))
+			nDC -= GetEssentiaInvested(oTarget, MELD_ILLUSION_VEIL);
+		if(GetRacialType(oTarget) == RACIAL_TYPE_MONGRELFOLK)
+			nDC -= 1;
+    }
+    else if(nSchool == SPELL_SCHOOL_ENCHANTMENT)
+    {
+        //check if Unsettling Enchantment applies
+        if(GetHasFeat(FEAT_UNSETTLING_ENCHANTMENT, oSaveVersus) && !GetIsImmune(oTarget, IMMUNITY_TYPE_MIND_SPELLS))
+        {
+            effect eLink = EffectLinkEffects(EffectACDecrease(2), EffectAttackDecrease(2));
+            ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, 6.0);
+        }
+        if(GetRacialType(oTarget) == RACIAL_TYPE_KILLOREN)
+            nDC -= 2;
+        if(GetLocalInt(oTarget, "KillorenAncient"))
+            nDC -= 2;
+		if(GetRacialType(oTarget) == RACIAL_TYPE_MONGRELFOLK)
+			nDC -= 1;            
+    }
+
+    // Hexblade gets a bonus against spells equal to his Charisma (Min +1)
+    if(nSchool && GetLevelByClass(CLASS_TYPE_HEXBLADE, oTarget))
+    {
+        int nHexCha = GetAbilityModifier(ABILITY_CHARISMA, oTarget);
+        if (nHexCha < 1) nHexCha = 1;
+        nDC -= nHexCha;
+    }
+    
+    // Totemist gets a save v magical beasts
+    if(MyPRCGetRacialType(oSaveVersus) == RACIAL_TYPE_MAGICAL_BEAST && GetLevelByClass(CLASS_TYPE_TOTEMIST, oTarget) >= 3)
+        nDC -= 3;   
+
+    int nSaveRoll = BWSavingThrow(nSavingThrow, oTarget, nDC, nSaveType, oSaveVersus, fDelay);
+
+    // If the spell is save immune then the link must be applied in order to get the true immunity
+    // to be resisted.  That is the reason for returing false and not true.  True blocks the
+    // application of effects.
+    if(nSaveRoll == 2 && !bImmunityCheck)
+        return 0;
+
+    // Failed the save - check if we can reroll
+    if(!nSaveRoll)
+    {
+        if(nSaveType == SAVING_THROW_TYPE_MIND_SPELLS)
+        {
+            // Bond Of Loyalty
+            if(GetLocalInt(oTarget, "BondOfLoyalty"))
+            {
+                // Reroll
+                nSaveRoll = BWSavingThrow(nSavingThrow, oTarget, nDC, nSaveType, oSaveVersus, fDelay);
+                DeleteLocalInt(oTarget, "BondOfLoyalty");
+            }
+        }
+        else if(nSaveType == SAVING_THROW_TYPE_FEAR)
+        {
+            // Call To Battle Reroll
+            if(GetLocalInt(oTarget, "CallToBattle"))
+            {
+                // Reroll
+                nSaveRoll = BWSavingThrow(nSavingThrow, oTarget, nDC, nSaveType, oSaveVersus, fDelay);
+                DeleteLocalInt(oTarget, "CallToBattle");
+            }
+        }
+
+        // Second Chance power reroll
+        if(!nSaveRoll && GetLocalInt(oTarget, "PRC_Power_SecondChance_Active") // Second chance is active
+        && !GetLocalInt(oTarget, "PRC_Power_SecondChance_UserForRound"))       // And hasn't yet been used for this round
+        {
+            // Reroll
+            nSaveRoll = BWSavingThrow(nSavingThrow, oTarget, nDC, nSaveType, oSaveVersus, fDelay);
+
+            // Can't use this ability again for a round
+            SetLocalInt(oTarget, "PRC_Power_SecondChance_UserForRound", TRUE);
+            DelayCommand(6.0f, DeleteLocalInt(oTarget, "PRC_Power_SecondChance_UserForRound"));
+        }
+
+        // Zealous Surge Reroll
+        if(!nSaveRoll && GetLocalInt(oTarget, "ZealousSurge"))
+        {
+            // Reroll
+            nSaveRoll = BWSavingThrow(nSavingThrow, oTarget, nDC, nSaveType, oSaveVersus, fDelay);
+
+            // Ability Used
+            DeleteLocalInt(oTarget, "ZealousSurge");
+        }
+        
+        // Balam's Cunning Reroll
+        if(!nSaveRoll && GetLocalInt(oTarget, "BalamCunning"))
+        {
+            // Reroll
+            nSaveRoll = BWSavingThrow(nSavingThrow, oTarget, nDC, nSaveType, oSaveVersus, fDelay);
+
+            // Ability Used
+            DeleteLocalInt(oTarget, "BalamCunning");
+        }        
+
+        if(!nSaveRoll)
+        {
+            if(nSavingThrow == SAVING_THROW_REFLEX)
+            {
+                // Dive for Cover reroll
+                if(GetHasFeat(FEAT_DIVE_FOR_COVER, oTarget))
+                {
+                    // Reroll
+                    nSaveRoll = BWSavingThrow(nSavingThrow, oTarget, nDC, nSaveType, oSaveVersus, fDelay);
+                    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, 6.0);
+                }
+            }
+            // Impetuous Endurance - fortitude or will save
+            else if(GetLevelByClass(CLASS_TYPE_KNIGHT, oTarget) > 16)
+            {
+                // Reroll
+                nSaveRoll = BWSavingThrow(nSavingThrow, oTarget, nDC, nSaveType, oSaveVersus, fDelay);
+            }
+        }
+    }
+    //Serene Guardian Unclouded Mind
+    int nSerene = GetLevelByClass(CLASS_TYPE_SERENE_GUARDIAN, oTarget);
+    //Applies on failed will saves from 9th level on
+    if (nSaveRoll == 1 && nSavingThrow == SAVING_THROW_WILL && nSerene >= 9)
+    {
+        if (GetIsSkillSuccessful(oTarget, SKILL_CONCENTRATION, nDC)) // Concentration check to beat the DC
+            nSaveRoll = 0;
+    }
+    
+    // Iron Mind Barbed Mind ability
+    if(nSaveRoll == 1 && nSaveType == SAVING_THROW_TYPE_MIND_SPELLS)
+    {
+        // Only works in Heavy Armour
+        if(GetLevelByClass(CLASS_TYPE_IRONMIND, oTarget) > 9
+        && GetBaseAC(GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget)) > 5)
+        {
+            // Spell/Power caster takes 1d6 damage and 1 Wisdom damage
+            ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d6(), DAMAGE_TYPE_MAGICAL), oSaveVersus);
+            ApplyAbilityDamage(oSaveVersus, ABILITY_WISDOM, 1, DURATION_TYPE_TEMPORARY, TRUE, -1.0);
+        }
+    }    
+
+    return nSaveRoll;
+}
+
+
+int PRCGetReflexAdjustedDamage(int nDamage, object oTarget, int nDC, int nSaveType = SAVING_THROW_TYPE_NONE, object oSaveVersus = OBJECT_SELF)
+{
+    int nEvasion;
+    if(GetHasFeat(FEAT_IMPROVED_EVASION, oTarget))
+        nEvasion = 2;
+    else if(GetHasFeat(FEAT_EVASION, oTarget))
+        nEvasion = 1;
+    
+    // Grants evasion against dragons, don't override if they've already gotit
+    object oWOL = GetItemPossessedBy(oTarget, "WOL_CrimsonRuination");  
+    if(oWOL != GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget) && MyPRCGetRacialType(oSaveVersus) == RACIAL_TYPE_DRAGON && 1 > nEvasion)
+        nEvasion = 1;
+
+    // This ability removes evasion from the target
+    if(GetLocalInt(oTarget, "TrueConfoundingResistance"))
+    {
+        if(nEvasion)
+            nEvasion -= 1;
+        else
+            nDC += 2;
+    }
+
+    //Get saving throw result
+    int nSaveRoll = PRCMySavingThrow(SAVING_THROW_REFLEX, oTarget, nDC, nSaveType, oSaveVersus);
+
+    //save success
+    if(nSaveRoll)
+        nDamage = nEvasion ? 0 : nDamage / 2;
+    //save failed - check improved evasion
+    else if(nEvasion == 2)
+        nDamage = nDamage / 2;
+
+    return nDamage;
+}
+
+// function for internal use in GetCasterLvl
+
+// caster level for arcane base classes (with practiced spellcaster feats)
+int GetCasterLvlArcane(int iClassType, object oCaster)
+{
+    if (GetPrimaryArcaneClass(oCaster) == iClassType)
+        return GetLevelByTypeArcane(oCaster);
+
+    int iTemp = GetLevelByClass(iClassType, oCaster);
+    iTemp += PracticedSpellcasting(oCaster, iClassType, iTemp);
+    return iTemp;
+}
+
+// caster level for classes with half progression
+int GetCasterLvlArcaneSemi(int iClassType, object oCaster)
+{
+    if (GetPrimaryArcaneClass(oCaster) == iClassType)
+        return GetLevelByTypeArcane(oCaster);
+
+    int iTemp = GetLevelByClass(iClassType, oCaster) / 2;
+    iTemp += PracticedSpellcasting(oCaster, iClassType, iTemp);
+    return iTemp;
+}
+
+// caster level for divine base classes (with practiced spellcaster feats)
+int GetCasterLvlDivine(int iClassType, object oCaster)
+{
+    if (GetPrimaryDivineClass(oCaster) == iClassType)
+        return GetLevelByTypeDivine(oCaster);
+
+    int iTemp = GetLevelByClass(iClassType, oCaster);
+    iTemp += PracticedSpellcasting(oCaster, iClassType, iTemp);
+    return iTemp;
+}
+
+// caster level for classes with half progression
+int GetCasterLvlDivineSemi(int iClassType, object oCaster)
+{
+    if (GetPrimaryDivineClass(oCaster) == iClassType)
+        return GetLevelByTypeDivine(oCaster);
+
+    int iTemp = GetLevelByClass(iClassType, oCaster) / 2;
+    iTemp += PracticedSpellcasting(oCaster, iClassType, iTemp);
+    return iTemp;
+}
+
+int GetCasterLvl(int iTypeSpell, object oCaster = OBJECT_SELF)
+{
+    switch (iTypeSpell)
+    {
+        case TYPE_ARCANE:
+            return GetLevelByTypeArcane(oCaster);
+
+        case TYPE_DIVINE:
+            return GetLevelByTypeDivine(oCaster);
+
+        case CLASS_TYPE_SORCERER:
+        {
+            if (GetPrimaryArcaneClass(oCaster) == CLASS_TYPE_SORCERER)
+                return GetLevelByTypeArcane(oCaster);
+
+            if(!GetLevelByClass(CLASS_TYPE_SORCERER, oCaster))
+            {
+                int iTemp;
+                int nRace = GetRacialType(oCaster);
+
+                //Aranea include outsider HD as sorc
+                if(nRace == RACIAL_TYPE_ARANEA)
+                    iTemp = GetLevelByClass(CLASS_TYPE_SHAPECHANGER, oCaster);
+					
+                //Rakshasa include outsider HD as sorc
+                if(nRace == RACIAL_TYPE_RAKSHASA)
+                    iTemp = GetLevelByClass(CLASS_TYPE_OUTSIDER, oCaster);
+
+                //Drider include aberration HD as sorc
+                if(nRace == RACIAL_TYPE_DRIDER)
+                    iTemp = GetLevelByClass(CLASS_TYPE_ABERRATION, oCaster);
+
+                //Arkamoi + Redspawn include MH HD as sorc
+                if(nRace == RACIAL_TYPE_ARKAMOI) 
+                    iTemp = GetLevelByClass(CLASS_TYPE_MONSTROUS, oCaster);
+                if(nRace == RACIAL_TYPE_REDSPAWN_ARCANISS) 
+                    iTemp = GetLevelByClass(CLASS_TYPE_MONSTROUS, oCaster)*3/4;    
+                if(nRace == RACIAL_TYPE_MARRUTACT) 
+                    iTemp = GetLevelByClass(CLASS_TYPE_MONSTROUS, oCaster)*6/7;                       
+                    
+                iTemp += PracticedSpellcasting(oCaster, CLASS_TYPE_SORCERER, iTemp);
+                iTemp += DraconicPower(oCaster);
+                return iTemp;
+            }
+        }
+        
+        case CLASS_TYPE_BARD:
+        {
+            if (GetPrimaryArcaneClass(oCaster) == CLASS_TYPE_BARD)
+                return GetLevelByTypeArcane(oCaster);
+
+            if(!GetLevelByClass(CLASS_TYPE_BARD, oCaster))
+            {
+                int iTemp;
+                int nRace = GetRacialType(oCaster);
+
+                //Gloura include fey HD as bard
+                if(nRace == RACIAL_TYPE_GLOURA)
+                    iTemp = GetLevelByClass(CLASS_TYPE_FEY, oCaster);   
+                    
+                iTemp += PracticedSpellcasting(oCaster, CLASS_TYPE_BARD, iTemp);
+                iTemp += DraconicPower(oCaster);
+                return iTemp;
+            }
+        }        
+
+        case CLASS_TYPE_ASSASSIN:
+        case CLASS_TYPE_CELEBRANT_SHARESS:
+        case CLASS_TYPE_BEGUILER:
+        case CLASS_TYPE_CULTIST_SHATTERED_PEAK:
+        case CLASS_TYPE_DREAD_NECROMANCER:
+        case CLASS_TYPE_DUSKBLADE:
+        case CLASS_TYPE_SHADOWLORD:
+        case CLASS_TYPE_SUEL_ARCHANAMACH:
+        case CLASS_TYPE_WARMAGE:
+        case CLASS_TYPE_WIZARD:
+            return GetCasterLvlArcane(iTypeSpell, oCaster);
+
+        case CLASS_TYPE_HEXBLADE:
+            return GetCasterLvlArcaneSemi(iTypeSpell, oCaster);
+
+        case CLASS_TYPE_ARCHIVIST:
+        case CLASS_TYPE_BLACKGUARD:
+        case CLASS_TYPE_BLIGHTER:
+        case CLASS_TYPE_CLERIC:
+        case CLASS_TYPE_DRUID:
+        case CLASS_TYPE_FAVOURED_SOUL:
+        case CLASS_TYPE_HEALER:
+        case CLASS_TYPE_KNIGHT_CHALICE:
+        case CLASS_TYPE_KNIGHT_MIDDLECIRCLE:
+        case CLASS_TYPE_NENTYAR_HUNTER:
+        case CLASS_TYPE_OCULAR:
+        case CLASS_TYPE_SHAMAN:
+        case CLASS_TYPE_SLAYER_OF_DOMIEL:
+        case CLASS_TYPE_SOLDIER_OF_LIGHT:
+        case CLASS_TYPE_UR_PRIEST:
+        case CLASS_TYPE_VASSAL:
+            return GetCasterLvlDivine(iTypeSpell, oCaster);
+
+        case CLASS_TYPE_ANTI_PALADIN:
+        case CLASS_TYPE_PALADIN:
+        case CLASS_TYPE_RANGER:
+        case CLASS_TYPE_SOHEI:
+            return GetCasterLvlDivineSemi(iTypeSpell, oCaster);
+    }
+    return 0;
+}
+
+
+////////////////Begin Spellsword//////////////////
+
+void SetAllAoEInts(int SpellID, object oAoE, int nBaseSaveDC, int SpecDispel = 0, int nCasterLevel = 0)
+{
+    if(!GetLocalInt(oAoE, "X2_AoE_BaseSaveDC"))//DC should always be > 0
+    {
+        SetLocalInt(oAoE, "X2_AoE_SpellID", SpellID);
+        SetLocalInt(oAoE, "X2_AoE_BaseSaveDC", nBaseSaveDC);
+        if(SpecDispel) SetLocalInt(oAoE, "X2_AoE_SpecDispel", SpecDispel);
+        if(!nCasterLevel) nCasterLevel = PRCGetCasterLevel();
+        SetLocalInt(oAoE, "X2_AoE_Caster_Level", nCasterLevel);
+        if(GetHasFeat(FEAT_SHADOWWEAVE)) SetLocalInt(oAoE, "X2_AoE_Weave", TRUE);
+    }
+}
+
+//GetNextObjectInShape wrapper for changing the AOE of the channeled spells
+object MyNextObjectInShape(int nShape,
+                           float fSize, location lTarget,
+                           int bLineOfSight = FALSE,
+                           int nObjectFilter = OBJECT_TYPE_CREATURE,
+                           vector vOrigin=[0.0, 0.0, 0.0])
+{
+    object oCaster = OBJECT_SELF;
+
+    // War Wizard of Cormyr's Widen Spell ability
+    float fMulti = GetLocalFloat(oCaster, PRC_SPELL_AREA_SIZE_MULTIPLIER);
+    //if(DEBUG) DoDebug("Original Spell Size: " + FloatToString(fSize)+"\n" + "Widened Multiplier: " + FloatToString(fMulti));
+
+    float fHFInfusion = GetLocalFloat(oCaster, "PRC_HF_Infusion_Wid");
+    if(fHFInfusion > 0.0f)
+    {
+        object oItem = PRCGetSpellCastItem(oCaster);
+        if(GetIsObjectValid(oItem) && GetItemPossessor(oItem) == oCaster)
+        {
+            //Hellfire Infusion - doesn't work on scrolls and potions
+            int nType = GetBaseItemType(oItem);
+            if(nType != BASE_ITEM_POTIONS && nType != BASE_ITEM_ENCHANTED_POTION
+            && nType != BASE_ITEM_SCROLL && nType != BASE_ITEM_ENCHANTED_SCROLL)
+            {
+                fMulti = fHFInfusion;
+                DelayCommand(1.0, DeleteLocalFloat(oCaster, "PRC_HF_Infusion_Wid"));
+            }
+        }
+    }
+
+    if(fMulti > 0.0)
+    {
+        fSize *= fMulti;
+        if(DEBUG) DoDebug("New Spell Size: " + FloatToString(fSize));
+    }
+
+    if(GetLocalInt(oCaster, "spellswd_aoe") == 1)
+    {
+        return OBJECT_INVALID;
+    }
+
+    return GetNextObjectInShape(nShape,fSize,lTarget,bLineOfSight,nObjectFilter,vOrigin);
+}
+
+//GetFirstObjectInShape wrapper for changing the AOE of the channeled spells
+object MyFirstObjectInShape(int nShape,
+                            float fSize, location lTarget,
+                            int bLineOfSight = FALSE,
+                            int nObjectFilter = OBJECT_TYPE_CREATURE,
+                            vector vOrigin=[0.0, 0.0, 0.0])
+{
+    object oCaster = OBJECT_SELF;
+
+    //int on caster for the benefit of spellfire wielder resistance
+    // string sName = "IsAOE_" + IntToString(GetSpellId());
+    string sName = "IsAOE_" + IntToString(PRCGetSpellId(oCaster));
+
+    SetLocalInt(oCaster, sName, 1);
+    DelayCommand(0.1, DeleteLocalInt(oCaster, sName));
+
+    // War Wizard of Cormyr's Widen Spell ability
+    float fMulti = GetLocalFloat(oCaster, PRC_SPELL_AREA_SIZE_MULTIPLIER);
+    //if(DEBUG) DoDebug("Original Spell Size: " + FloatToString(fSize)+"\n" + "Widened Multiplier: " + FloatToString(fMulti));
+
+    float fHFInfusion = GetLocalFloat(oCaster, "PRC_HF_Infusion_Wid");
+    if(fHFInfusion > 0.0f)
+    {
+        object oItem = PRCGetSpellCastItem(oCaster);
+        if(GetIsObjectValid(oItem) && GetItemPossessor(oItem) == oCaster)
+        {
+            //Hellfire Infusion - doesn't work on scrolls and potions
+            int nType = GetBaseItemType(oItem);
+            if(nType != BASE_ITEM_POTIONS && nType != BASE_ITEM_ENCHANTED_POTION
+            && nType != BASE_ITEM_SCROLL && nType != BASE_ITEM_ENCHANTED_SCROLL)
+            {
+                fMulti = fHFInfusion;
+                DelayCommand(1.0, DeleteLocalFloat(oCaster, "PRC_HF_Infusion_Wid"));
+            }
+        }
+    }
+
+    if(fMulti > 0.0)
+    {
+        fSize *= fMulti;
+        if(DEBUG) DoDebug("New Spell Size: " + FloatToString(fSize));
+
+        // This allows it to affect the entire casting
+        DelayCommand(1.0, DeleteLocalFloat(oCaster, PRC_SPELL_AREA_SIZE_MULTIPLIER));
+    }
+
+    if(GetLocalInt(oCaster, "spellswd_aoe") == 1)
+    {
+        return PRCGetSpellTargetObject(oCaster);
+    }
+
+    return GetFirstObjectInShape(nShape,fSize,lTarget,bLineOfSight,nObjectFilter,vOrigin);
+}
+
+
+//This checks if the spell is channeled and if there are multiple spells
+//channeled, which one is it. Then it checks in either case if the spell
+//has the metamagic feat the function gets and returns TRUE or FALSE accordingly
+//Also used by the new spellbooks for the same purpose
+/* replaced by wrapper for GetMetaMagicFeat instead
+   Not necessarily. This may still be a usefule level of abstraction - Ornedan
+   */
+int CheckMetaMagic(int nMeta,int nMMagic)
+{
+    return nMeta & nMMagic;
+}
+
+int PRCGetMetaMagicFeat(object oCaster = OBJECT_SELF, int bClearFeatFlags = TRUE)
+{
+    int nOverride = GetLocalInt(oCaster, PRC_METAMAGIC_OVERRIDE);
+    if(nOverride)
+    {
+        if (DEBUG) DoDebug("PRCGetMetaMagicFeat: found override metamagic = "+IntToString(nOverride)+", original = "+IntToString(GetMetaMagicFeat()));
+        return nOverride;
+    }
+
+    object oItem = PRCGetSpellCastItem(oCaster);
+
+    // we assume that we are casting from an item, if the item is valid and the item belongs to oCaster
+    // however, we cannot be sure because of Bioware's inadequate implementation of GetSpellCastItem
+    if(GetIsObjectValid(oItem) && GetItemPossessor(oItem) == oCaster)
+    {
+        int nFeat;
+
+        //check item for metamagic
+        itemproperty ipTest = GetFirstItemProperty(oItem);
+        while(GetIsItemPropertyValid(ipTest))
+        {
+            if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_CAST_SPELL_METAMAGIC)
+            {
+                int nSubType = GetItemPropertySubType(ipTest);
+                nSubType = StringToInt(Get2DACache("iprp_spells", "SpellIndex", nSubType));
+                if(nSubType == PRCGetSpellId(oCaster))
+                {
+                    int nCostValue = GetItemPropertyCostTableValue(ipTest);
+                    if(nCostValue == -1 && DEBUG)
+                        DoDebug("Problem examining itemproperty");
+                    switch(nCostValue)
+                    {
+                        //bitwise "addition" equivalent to nFeat = (nFeat | nSSFeat)
+                        case 1: nFeat |= METAMAGIC_QUICKEN;  break;
+                        case 2: nFeat |= METAMAGIC_EMPOWER;  break;
+                        case 3: nFeat |= METAMAGIC_EXTEND;   break;
+                        case 4: nFeat |= METAMAGIC_MAXIMIZE; break;
+                        case 5: nFeat |= METAMAGIC_SILENT;   break;
+                        case 6: nFeat |= METAMAGIC_STILL;    break;
+                    }
+                }
+            }
+            ipTest = GetNextItemProperty(oItem);
+        }
+        if (DEBUG) DoDebug("PRCGetMetaMagicFeat: item casting with item = "+GetName(oItem)+", found metamagic = "+IntToString(nFeat));
+
+        //Hellfire Infusion - doesn't work on scrolls and potions
+        int nType = GetBaseItemType(oItem);
+        if(nType != BASE_ITEM_POTIONS && nType != BASE_ITEM_ENCHANTED_POTION
+        && nType != BASE_ITEM_SCROLL && nType != BASE_ITEM_ENCHANTED_SCROLL)
+        {
+            nFeat |= GetLocalInt(oCaster, "PRC_HF_Infusion");
+            if(bClearFeatFlags) DeleteLocalInt(oCaster, "PRC_HF_Infusion");
+        }
+
+        //apply metamagic adjustment (chanell spell)
+        nFeat |= GetLocalInt(oCaster, PRC_METAMAGIC_ADJUSTMENT);
+        return nFeat;
+    }
+
+    if(GetLocalInt(oCaster, "PRC_SPELL_EVENT"))
+    {
+        if (DEBUG) DoDebug("PRCGetMetaMagicFeat: found spell event metamagic = "+IntToString(GetLocalInt(oCaster, "PRC_SPELL_METAMAGIC"))+", original = "+IntToString(GetMetaMagicFeat()));
+        return GetLocalInt(oCaster, "PRC_SPELL_METAMAGIC");
+    }
+
+    int nFeat = GetMetaMagicFeat();
+    if(nFeat == METAMAGIC_ANY)
+        // work around for spontaneous casters (bard or sorcerer) having all metamagic turned on when using ActionCastSpell*
+        nFeat = METAMAGIC_NONE;
+
+    nFeat |= GetLocalInt(oCaster, PRC_METAMAGIC_ADJUSTMENT);
+
+    int nClass = PRCGetLastSpellCastClass(oCaster);
+    // Suel Archanamach's Extend spells they cast on themselves.
+    // Only works for Suel Spells, and not any other caster type they might have
+    // Since this is a spellscript, it assumes OBJECT_SELF is the caster
+    if(nClass == CLASS_TYPE_SUEL_ARCHANAMACH
+    && GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH) >= 3)
+    {
+        // Check that they cast on themselves
+        // if (oCaster == PRCGetSpellTargetObject())
+        if(oCaster == PRCGetSpellTargetObject(oCaster))
+        {
+            // Add extend to the metamagic feat using bitwise math
+            nFeat |= METAMAGIC_EXTEND;
+        }
+    }
+    //Code for the Abjurant Champion. Works similar to the Suel Archamamach but
+    //their extend only works on abjuration spells they cast.
+    if(GetHasFeat(FEAT_EXTENDED_ABJURATION, oCaster)
+    && GetLevelByClass(CLASS_TYPE_ABJURANT_CHAMPION) >= 1)
+    {
+        int nSpellSchool = GetLocalInt(oCaster, "X2_L_LAST_SPELLSCHOOL_VAR");
+        // Check that they cast an abjuration spell
+        if(nSpellSchool == SPELL_SCHOOL_ABJURATION)
+        {
+            // Add extend to the metamagic feat using bitwise math
+            nFeat |= METAMAGIC_EXTEND;
+            if (DEBUG) FloatingTextStringOnCreature("Extended Abjuration Applied", oCaster, FALSE);
+        }
+    }
+    // Magical Contraction, Truenaming Utterance
+    if(GetHasSpellEffect(UTTER_MAGICAL_CONTRACTION_R, oCaster))
+    //(GetLocalInt(oCaster, "TrueMagicalContraction"))
+    {
+        nFeat |= METAMAGIC_EMPOWER;
+    }
+    // Sudden Metamagic
+    int nSuddenMeta = GetLocalInt(oCaster, "SuddenMeta");
+    if(nSuddenMeta)
+    {
+        nFeat |= nSuddenMeta;
+        if(bClearFeatFlags)
+            DeleteLocalInt(oCaster, "SuddenMeta");
+    }
+
+    int nDivMeta = GetLocalInt(oCaster, "DivineMeta");
+    if(nDivMeta)
+    {
+        if(GetIsDivineClass(nClass, oCaster))
+        {
+            nFeat |= nDivMeta;
+            if(bClearFeatFlags)
+                DeleteLocalInt(oCaster, "DivineMeta");
+        }
+    }
+
+    int nSpelldance = GetLocalInt(oCaster, "Spelldance");
+    if(nSpelldance)
+    {
+        nFeat |= nSpelldance;
+        if (DEBUG) FloatingTextStringOnCreature("Metamagic Spelldances applied", oCaster, FALSE);
+    }    
+    
+    int nSpellLevel = PRCGetSpellLevel(oCaster, PRCGetSpellId());
+    if (GetLocalInt(oCaster, "Aradros_Extend")/* && GetIsArcaneClass(nClass, oCaster)*/)
+    {
+        if (DEBUG) DoDebug("PRCGetMetaMagicFeat: GetIsArcaneClass is TRUE");
+        int nHD = GetHitDice(oCaster);
+        if (nHD >= 12 && 6 >= nSpellLevel) 
+        {
+            nFeat |= METAMAGIC_EXTEND;
+            DeleteLocalInt(oCaster, "Aradros_Extend");
+            if (DEBUG) FloatingTextStringOnCreature("Aradros Extend Applied", oCaster, FALSE);
+        }  
+        else if (3 >= nSpellLevel) 
+        {
+            nFeat |= METAMAGIC_EXTEND;
+            DeleteLocalInt(oCaster, "Aradros_Extend");
+            if (DEBUG) FloatingTextStringOnCreature("Aradros Extend Applied", oCaster, FALSE);
+        }        
+    }
+
+    if (DEBUG) DoDebug("PRCGetMetaMagicFeat: nSpellLevel " +IntToString(nSpellLevel)+", PRCGetSpellId " +IntToString(PRCGetSpellId())+", nClass " +IntToString(nClass));
+    if (DEBUG) DoDebug("PRCGetMetaMagicFeat: returning " +IntToString(nFeat));
+    return nFeat;
+}
+
+//Wrapper for The MaximizeOrEmpower function
+int PRCMaximizeOrEmpower(int nDice, int nNumberOfDice, int nMeta, int nBonus = 0)
+{
+    int i, nDamage;
+    for (i = 1; i <= nNumberOfDice; i++)
+    {
+        nDamage = nDamage + Random(nDice) + 1;
+    }
+
+    //Resolve metamagic
+    if(nMeta & METAMAGIC_MAXIMIZE)
+        nDamage = nDice * nNumberOfDice;
+    if(nMeta & METAMAGIC_EMPOWER)
+       nDamage = nDamage + nDamage / 2;
+
+    return nDamage + nBonus;
+}
+
+float PRCGetMetaMagicDuration(float fDuration, int nMeta = -1)
+{
+    if(nMeta == -1) // no metamagic value was passed, so get it here
+        nMeta = PRCGetMetaMagicFeat();
+
+    if(nMeta & METAMAGIC_EXTEND)
+        fDuration *= 2;
+
+    return fDuration;
+}
+
+int PRCGetMetaMagicDamage(int nDamageType, int nDice, int nDieSize,
+    int nBonusPerDie = 0, int nBonus = 0, int nMetaMagic = -1)
+{
+    // If the metamagic argument wasn't given get it.
+    if (-1 == nMetaMagic) nMetaMagic = PRCGetMetaMagicFeat();
+
+    // Roll the damage, applying metamagic.
+    int nDamage = PRCMaximizeOrEmpower(nDieSize, nDice, nMetaMagic, (nBonusPerDie * nDice) + nBonus);
+    return nDamage;
+}
+
+void PRCSetSchool(int nSchool = SPELL_SCHOOL_GENERAL)
+{
+    // Remove the last value in case it is there and set the new value if it is NOT general.
+    if(SPELL_SCHOOL_GENERAL != nSchool)
+        SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", nSchool);
+    else
+        DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
+}
+
+void PRCSignalSpellEvent(object oTarget, int bHostile = TRUE, int nSpellID = -1, object oCaster = OBJECT_SELF)
+{
+    if (-1 == nSpellID) nSpellID = PRCGetSpellId();
+
+    //Fire cast spell at event for the specified target
+    SignalEvent(oTarget, EventSpellCastAt(oCaster, nSpellID, bHostile));
+}
+/*
+void SPEvilShift(object oPC)
+{
+    // Check for alignment shift switch being active
+    if(GetPRCSwitch(PRC_SPELL_ALIGNMENT_SHIFT))
+    {
+        // Amount of adjustment is equal to the square root of your distance from pure evil.
+        // In other words, the amount of shift is higher the farther you are from pure evil, with the
+        // extremes being 10 points of shift at pure good and 0 points of shift at pure evil.
+        AdjustAlignment(oPC, ALIGNMENT_EVIL,  FloatToInt(sqrt(IntToFloat(GetGoodEvilValue(oPC)))), FALSE);
+    }
+}
+
+void SPGoodShift(object oPC)
+{
+    // Check for alignment shift switch being active
+    if(GetPRCSwitch(PRC_SPELL_ALIGNMENT_SHIFT))
+    {
+        // Amount of adjustment is equal to the square root of your distance from pure good.
+        // In other words, the amount of shift is higher the farther you are from pure good, with the
+        // extremes being 10 points of shift at pure evil and 0 points of shift at pure good.
+        AdjustAlignment(oPC, ALIGNMENT_GOOD, FloatToInt(sqrt(IntToFloat(100 - GetGoodEvilValue(oPC)))), FALSE);
+    }
+}*/
+
+void DoCorruptionCost(object oPC, int nAbility, int nCost, int bDrain)
+{
+    // Undead redirect all damage & drain to Charisma, sez http://www.wizards.com/dnd/files/BookVileFAQ12102002.zip
+    if(MyPRCGetRacialType(oPC) == RACIAL_TYPE_UNDEAD)
+        nAbility = ABILITY_CHARISMA;
+
+    //Exalted Raiment
+    if(GetHasSpellEffect(SPELL_EXALTED_RAIMENT, GetItemInSlot(INVENTORY_SLOT_CHEST, oPC)))
+    {
+        nCost -= 1;
+
+        if(nCost < 1)
+            nCost = 1;
+    }
+    
+    if (GetHasFeat(FEAT_FAVORED_ZULKIRS, oPC)) nCost -= 1;
+
+    // Is it ability drain?
+    if(bDrain)
+        ApplyAbilityDamage(oPC, nAbility, nCost, DURATION_TYPE_PERMANENT, TRUE);
+    // Or damage
+    else
+        ApplyAbilityDamage(oPC, nAbility, nCost, DURATION_TYPE_TEMPORARY, TRUE, -1.0f);
+}
+
+void MultisummonPreSummon(object oPC = OBJECT_SELF, int bOverride = FALSE)
+{
+    if(!GetPRCSwitch(PRC_MULTISUMMON) && !bOverride)
+        return;
+    int i=1;
+    int nCount = GetPRCSwitch(PRC_MULTISUMMON);
+    if(bOverride)
+        nCount = bOverride;
+    if(nCount < 0
+        || nCount == 1)
+        nCount = 99;
+    if(nCount > 99)
+        nCount = 99;
+    object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
+    while(GetIsObjectValid(oSummon) && !GetLocalInt(oSummon, "RFSummonedElemental") && i < nCount)
+    {
+        AssignCommand(oSummon, SetIsDestroyable(FALSE, FALSE, FALSE));
+        AssignCommand(oSummon, DelayCommand(0.3, SetIsDestroyable(TRUE, FALSE, FALSE)));
+        i++;
+        oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
+    }
+}
+
+
+//This function returns 1 only if the object oTarget is the object
+//the weapon hit when it channeled the spell sSpell or if there is no
+//channeling at all
+int ChannelChecker(string sSpell, object oTarget)
+{
+    int nSpell = GetLocalInt(GetAreaOfEffectCreator(), sSpell+"channeled");
+    int nTarget = GetLocalInt(oTarget, sSpell+"target");
+    if(nSpell == 1 && nTarget == 1)
+    {
+        return 1;
+    }
+    else if(nSpell != 1 && nTarget != 1)
+    {
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+//If a spell is being channeled, we store its target and its name
+void StoreSpellVariables(string sString,int nDuration)
+{
+    object oCaster = OBJECT_SELF;
+    object oTarget = GetSpellTargetObject();     //using prc version could cause problems
+
+    if(GetLocalInt(oCaster,"spellswd_aoe") == 1)
+    {
+        SetLocalInt(oCaster, sString+"channeled",1);
+        SetLocalInt(oTarget, sString+"target",1);
+    }
+    DelayCommand(RoundsToSeconds(nDuration),DeleteLocalInt(oTarget, sString+"target"));
+    DelayCommand(RoundsToSeconds(nDuration),DeleteLocalInt(oCaster, sString+"channeled"));
+}
+
+effect ChannelingVisual()
+{
+    return EffectVisualEffect(VFX_DUR_SPELLTURNING);
+}
+
+////////////////End Spellsword//////////////////
+
+
+int GetHasMettle(object oTarget, int nSavingThrow = SAVING_THROW_WILL)
+{
+    if(GetLevelByClass(CLASS_TYPE_HEXBLADE, oTarget) >  2) return TRUE;
+    if(GetLevelByClass(CLASS_TYPE_SOHEI, oTarget)    >  8) return TRUE;
+    if(GetLevelByClass(CLASS_TYPE_CRUSADER, oTarget) > 12) return TRUE;
+    if(GetLocalInt(oTarget, "FactotumMettle")) return TRUE;
+
+    if(nSavingThrow = SAVING_THROW_WILL)
+    {
+        // Iron Mind's ability only functions in Heavy Armour
+        if(GetLevelByClass(CLASS_TYPE_IRONMIND, oTarget) > 4
+        && GetBaseAC(GetItemInSlot(INVENTORY_SLOT_CHEST, oTarget)) > 5)
+            return TRUE;
+        // Fill out the line below to add another class with Will mettle
+        // if (GetLevelByClass(CLASS_TYPE_X, oTarget) >= X) return TRUE;
+    }
+    /*else if(nSavingThrow = SAVING_THROW_FORT)
+    {
+        // Add Classes with Fort mettle here
+        // if (GetLevelByClass(CLASS_TYPE_X, oTarget) >= X) return TRUE;
+    }*/
+
+    return FALSE;
+}
+
+void DoCommandSpell(object oCaster, object oTarget, int nSpellId, int nDuration, int nCaster)
+{
+    if(DEBUG) DoDebug("DoCommandSpell: SpellId: " + IntToString(nSpellId));
+    if(DEBUG) DoDebug("Command Spell: Begin");
+    if(nSpellId == SPELL_COMMAND_APPROACH
+    || nSpellId == SPELL_GREATER_COMMAND_APPROACH
+    || nSpellId == 18359 //MYST_VOICE_SHADOW_APPROACH
+    || nSpellId == SPELL_DOA_COMMAND_APPROACH
+    || nSpellId == SPELL_DOA_GREATER_COMMAND_APPROACH)
+    {
+        // Force the target to approach the caster
+        if(DEBUG) DoDebug("Command Spell: Approach");
+        AssignCommand(oTarget, ClearAllActions(TRUE));
+        AssignCommand(oTarget, ActionForceMoveToObject(oCaster, TRUE));
+    }
+    // Creatures that can't be disarmed ignore this
+    else if(nSpellId == SPELL_COMMAND_DROP
+    || nSpellId == SPELL_GREATER_COMMAND_DROP
+    || nSpellId == 18360 //MYST_VOICE_SHADOW_DROP
+    || nSpellId == SPELL_DOA_COMMAND_DROP
+    || nSpellId == SPELL_DOA_GREATER_COMMAND_DROP)
+    {
+        if(GetIsCreatureDisarmable(oTarget) && !GetPRCSwitch(PRC_PNP_DISARM))
+        {
+            // Force the target to drop what its holding
+            if(DEBUG) DoDebug("Command Spell: Drop");
+            AssignCommand(oTarget, ClearAllActions(TRUE));
+            object oTargetWep = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
+			SetDroppableFlag(oTargetWep, TRUE);
+            SetStolenFlag(oTargetWep, FALSE);              
+            AssignCommand(oTarget, ActionPutDownItem(oTargetWep));              
+            /*oTargetWep = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
+			SetDroppableFlag(oTargetWep, TRUE);
+            SetStolenFlag(oTargetWep, FALSE);              
+            AssignCommand(oTarget, ActionPutDownItem(oTargetWep));     */
+        }
+        else
+        {
+            FloatingTextStringOnCreature(GetName(oTarget) + " is not disarmable.", oCaster, FALSE);
+        }
+    }
+    else if(nSpellId == SPELL_COMMAND_FALL
+    || nSpellId == SPELL_GREATER_COMMAND_FALL
+    || nSpellId == 18361 //MYST_VOICE_SHADOW_FALL
+    || nSpellId == SPELL_DOA_COMMAND_FALL
+    || nSpellId == SPELL_DOA_GREATER_COMMAND_FALL)
+    {
+        // Force the target to fall down
+        if(DEBUG) DoDebug("Command Spell: Fall");
+        AssignCommand(oTarget, ClearAllActions(TRUE));
+        SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectKnockdown(), oTarget, RoundsToSeconds(nDuration),TRUE,-1,nCaster);
+    }
+    else if(nSpellId == SPELL_COMMAND_FLEE
+    || nSpellId == SPELL_GREATER_COMMAND_FLEE
+    || nSpellId == 18362 //MYST_VOICE_SHADOW_FLEE
+    || nSpellId == SPELL_DOA_COMMAND_FLEE
+    || nSpellId == SPELL_DOA_GREATER_COMMAND_FLEE)
+    {
+        // Force the target to flee the caster
+        if(DEBUG) DoDebug("Command Spell: Flee");
+        AssignCommand(oTarget, ClearAllActions(TRUE));
+        AssignCommand(oTarget, ActionMoveAwayFromObject(oCaster, TRUE));
+    }
+    else if(nSpellId == SPELL_COMMAND_HALT
+    || nSpellId == SPELL_GREATER_COMMAND_HALT
+    || nSpellId == 18363 //MYST_VOICE_SHADOW_HALT
+    || nSpellId == SPELL_DOA_COMMAND_HALT
+    || nSpellId == SPELL_DOA_GREATER_COMMAND_HALT)
+    {
+        // Force the target to stand still
+        if(DEBUG) DoDebug("Command Spell: Stand");
+        AssignCommand(oTarget, ClearAllActions(TRUE));
+        SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectCutsceneParalyze(), oTarget, RoundsToSeconds(nDuration),TRUE,-1,nCaster);
+    }
+    else // Catch errors here
+    {
+        FloatingTextStringOnCreature("sp_command/sp_greatcommand: Error, Unknown SpellId", oCaster, FALSE);
+    }
+    if(DEBUG) DoDebug("Command Spell: End");
+}
+
+void SetIncorporeal(object oTarget, float fDuration, int nSuperOrEx, int nPermanent = FALSE)
+{
+    if (!GetIsObjectValid(oTarget))
+        return; //No point working 
+    
+    // Immune to non-magical weapons, ignore physical objects
+    effect eIncorporeal = EffectLinkEffects(EffectDamageReduction(100, DAMAGE_POWER_PLUS_ONE, 0), EffectCutsceneGhost());
+           eIncorporeal = EffectLinkEffects(eIncorporeal, EffectDamageImmunityIncrease(DAMAGE_TYPE_BLUDGEONING, 50)); // 50% chance of magical weapons not working. Done as 50% Damage Immunity
+           eIncorporeal = EffectLinkEffects(eIncorporeal, EffectDamageImmunityIncrease(DAMAGE_TYPE_SLASHING, 50));
+           eIncorporeal = EffectLinkEffects(eIncorporeal, EffectDamageImmunityIncrease(DAMAGE_TYPE_PIERCING, 50));
+           eIncorporeal = EffectLinkEffects(eIncorporeal, EffectMissChance(50, MISS_CHANCE_TYPE_VS_MELEE)); // 50% melee miss chance to hit non-incorporeal targets. That's going to be everything
+           eIncorporeal = EffectLinkEffects(eIncorporeal, EffectSkillIncrease(SKILL_MOVE_SILENTLY, 99)); // Cannot be heard
+           eIncorporeal = EffectLinkEffects(eIncorporeal, EffectVisualEffect(VFX_DUR_ETHEREAL_VISAGE)); // Visual effect
+           
+    // No Strength Score, use Dex for melee attacks too
+    int nStr = GetAbilityScore(oTarget, ABILITY_STRENGTH);
+    int nDex = GetAbilityModifier(ABILITY_DEXTERITY, oTarget);
+    int nPen;
+    
+    if (nStr>10)
+    {
+         nPen = nStr - 10; 
+         eIncorporeal = EffectLinkEffects(eIncorporeal, EffectAbilityDecrease(ABILITY_STRENGTH, nPen)); // Reduce Strength to 10
+             
+         object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTarget);
+         if (GetIsObjectValid(oWeapon) && IPGetIsMeleeWeapon(oWeapon))
+         {
+             IPSafeAddItemProperty(oWeapon, ItemPropertyAttackBonus(nDex), fDuration); //Dex has to be done as a melee weapon bonus
+         }
+         oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTarget);
+         if (GetIsObjectValid(oWeapon) && IPGetIsMeleeWeapon(oWeapon))
+         {
+             IPSafeAddItemProperty(oWeapon, ItemPropertyAttackBonus(nDex), fDuration); //Dex has to be done as a melee weapon bonus
+         }  
+         oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oTarget);
+         if (GetIsObjectValid(oWeapon)) // We know these are melee weapons
+         {
+             IPSafeAddItemProperty(oWeapon, ItemPropertyAttackBonus(nDex), fDuration); //Dex has to be done as a melee weapon bonus
+         }
+         oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oTarget);
+         if (GetIsObjectValid(oWeapon)) // We know these are melee weapons
+         {
+             IPSafeAddItemProperty(oWeapon, ItemPropertyAttackBonus(nDex), fDuration); //Dex has to be done as a melee weapon bonus
+         } 
+         oWeapon = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oTarget);
+         if (GetIsObjectValid(oWeapon)) // We know these are melee weapons
+         {
+             IPSafeAddItemProperty(oWeapon, ItemPropertyAttackBonus(nDex), fDuration); //Dex has to be done as a melee weapon bonus
+         }         
+    }    
+    
+    SetLocalInt(oTarget, "Incorporeal", TRUE);
+    if (!nPermanent) DelayCommand(fDuration, DeleteLocalInt(oTarget, "Incorporeal"));
+    
+    if (nSuperOrEx == 1)
+        eIncorporeal = SupernaturalEffect(eIncorporeal);
+    else if (nSuperOrEx == 2)
+        eIncorporeal = ExtraordinaryEffect(eIncorporeal); 
+        
+    if (nPermanent)
+        SPApplyEffectToObject(DURATION_TYPE_PERMANENT, eIncorporeal, oTarget);
+    else   
+        SPApplyEffectToObject(DURATION_TYPE_TEMPORARY, eIncorporeal, oTarget, fDuration, FALSE, -1, -1);
+}
+
+int GetIsIncorporeal(object oTarget)
+{
+    //Check for local int
+    if(GetPersistantLocalInt(oTarget, "Is_Incorporeal"))
+        return TRUE;
+        
+    //Check for local int
+    if(GetLocalInt(oTarget, "Incorporeal"))
+        return TRUE;        
+
+    //check for feat
+    if(GetHasFeat(FEAT_INCORPOREAL, oTarget))
+        return TRUE;
+
+    //base it on appearance
+    int nAppear = GetAppearanceType(oTarget);
+    if(nAppear == APPEARANCE_TYPE_ALLIP
+    || nAppear == APPEARANCE_TYPE_SHADOW
+    || nAppear == APPEARANCE_TYPE_SHADOW_FIEND
+    || nAppear == APPEARANCE_TYPE_SPECTRE
+    || nAppear == APPEARANCE_TYPE_WRAITH)
+        return TRUE;
+
+    //Return value
+    return FALSE;
+}
+
+int GetIsEthereal(object oTarget)
+{
+    return GetPersistantLocalInt(oTarget, "Is_Ethereal")
+         || GetHasFeat(FEAT_ETHEREAL, oTarget);
+}
+
+int PRCGetIsAliveCreature(object oTarget)
+{
+    int bAlive = TRUE;
+    // non-creatures aren't alive
+    if (GetObjectType(oTarget) != OBJECT_TYPE_CREATURE)
+        return FALSE; // night of the living waypoints :p
+
+    int nType = MyPRCGetRacialType(oTarget);
+
+    //Non-living races, excluding warforged
+    if(nType == RACIAL_TYPE_UNDEAD ||
+       (nType == RACIAL_TYPE_CONSTRUCT && !GetIsWarforged(oTarget))) bAlive = FALSE;
+
+    //If they're dead :P
+    if(GetIsDead(oTarget)) bAlive = FALSE;
+
+    //return
+    return bAlive;
+}
+
+int GetControlledUndeadTotalHD(object oPC = OBJECT_SELF)
+{
+    int nTotalHD;
+    int i = 1;
+    object oSummonTest = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
+    while(GetIsObjectValid(oSummonTest))
+    {
+        if(MyPRCGetRacialType(oSummonTest) == RACIAL_TYPE_UNDEAD)
+            nTotalHD += GetHitDice(oSummonTest);
+        if(DEBUG)FloatingTextStringOnCreature(GetName(oSummonTest)+" is summon number "+IntToString(i), oPC);
+        i++;
+        oSummonTest = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
+    }
+    return nTotalHD;
+}
+
+
+int GetControlledFiendTotalHD(object oPC = OBJECT_SELF)
+{
+    int nTotalHD;
+    int i = 1;
+    object oSummonTest = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
+    while(GetIsObjectValid(oSummonTest))
+    {
+        if(MyPRCGetRacialType(oSummonTest) == RACIAL_TYPE_OUTSIDER
+             && GetAlignmentGoodEvil(oSummonTest) == ALIGNMENT_EVIL)
+            nTotalHD += GetHitDice(oSummonTest);
+        if(DEBUG)FloatingTextStringOnCreature(GetName(oSummonTest)+" is summon number "+IntToString(i), oPC);
+        i++;
+        oSummonTest = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
+    }
+    return nTotalHD;
+}
+
+int GetControlledCelestialTotalHD(object oPC = OBJECT_SELF)
+{
+    int nTotalHD;
+    int i = 1;
+    object oSummonTest = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
+    while(GetIsObjectValid(oSummonTest))
+    {
+        if(MyPRCGetRacialType(oSummonTest) == RACIAL_TYPE_OUTSIDER
+             && GetAlignmentGoodEvil(oSummonTest) == ALIGNMENT_GOOD)
+            nTotalHD += GetHitDice(oSummonTest);
+        if(DEBUG)FloatingTextStringOnCreature(GetName(oSummonTest)+" is summon number "+IntToString(i), oPC);
+        i++;
+        oSummonTest = GetAssociate(ASSOCIATE_TYPE_SUMMONED, oPC, i);
+    }
+    return nTotalHD;
+}
+
+
+
+// wrapper for DecrementRemainingSpellUses, works for newspellbook 'fake' spells too
+// should also find and decrement metamagics for newspellbooks
+void PRCDecrementRemainingSpellUses(object oCreature, int nSpell)
+{
+    if (!UseNewSpellBook(oCreature) && GetHasSpell(nSpell, oCreature))
+    {
+        DecrementRemainingSpellUses(oCreature, nSpell);
+        return;
+    }
+
+    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, nSpell);
+        nMeta = RealSpellToSpellbookIDCount(nClass, nSpell);
+        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;
+                }
+                nSpellLevel = StringToInt(Get2DACache(sFile, "Level", j));
+
+                if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
+                {
+                    nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), j);
+                    if(DEBUG) DoDebug("PRCDecrementRemainingSpellUses: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
+                    if(nCount > 0)
+                    {
+                        persistant_array_set_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), j, nCount - 1);
+                        return;
+                    }
+                }
+                else  if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+                {
+                    nCount = persistant_array_get_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel);
+                    if(DEBUG) DoDebug("PRCDecrementRemainingSpellUses: NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
+                    if(nCount > 0)
+                    {
+                        persistant_array_set_int(oCreature, "NewSpellbookMem_" + IntToString(nClass), nSpellLevel, nCount - 1);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+    if(DEBUG) DoDebug("PRCDecrementRemainingSpellUses: Spell " + IntToString(nSpell) + " not found");
+}
+
+//
+//  This function determines if spell damage is elemental
+//
+int IsSpellDamageElemental(int nDamageType)
+{
+    return nDamageType & 2480;// 2480 = (DAMAGE_TYPE_ACID | DAMAGE_TYPE_COLD | DAMAGE_TYPE_ELECTRICAL | DAMAGE_TYPE_FIRE | DAMAGE_TYPE_SONIC)
+}
+
+//
+//  This function converts spell damage into the correct type
+//  TODO: Change the name to consistent (large churn project).
+//
+int ChangedElementalDamage(object oCaster, int nDamageType)
+{
+
+	// None of the stuff here works when items are involved
+	if (GetIsObjectValid(PRCGetSpellCastItem())) return nDamageType;
+	
+    int nNewType;
+
+    //eldritch spellweave
+    if(GetIsObjectValid(GetLocalObject(oCaster, "SPELLWEAVE_TARGET")))
+    {
+        int nEssence = GetLocalInt(oCaster, "BlastEssence");
+
+        if(nEssence == INVOKE_BRIMSTONE_BLAST)
+            nNewType = DAMAGE_TYPE_FIRE;
+
+        else if(nEssence == INVOKE_HELLRIME_BLAST)
+            nNewType = DAMAGE_TYPE_COLD;
+
+        else if(nEssence == INVOKE_UTTERDARK_BLAST)
+            nNewType = DAMAGE_TYPE_NEGATIVE;
+
+        else if(nEssence == INVOKE_VITRIOLIC_BLAST)
+            nNewType = DAMAGE_TYPE_ACID;
+
+        //save new type for other functions
+        if(nNewType)
+            SetLocalInt(oCaster, "archmage_mastery_elements", nNewType);
+    }
+    else
+        // Check if an override is set
+        nNewType = GetLocalInt(oCaster, "archmage_mastery_elements");
+
+    // If so, check if the spell qualifies for a change
+    if (!nNewType || !IsSpellDamageElemental(nDamageType))
+        nNewType = nDamageType;
+
+    return nNewType;
+}
+
+//used in scripts after ChangedElementalDamage() to determine saving throw type
+int ChangedSaveType(int nDamageType)
+{
+    switch(nDamageType)
+    {
+        case DAMAGE_TYPE_ACID:       return SAVING_THROW_TYPE_ACID;
+        case DAMAGE_TYPE_COLD:       return SAVING_THROW_TYPE_COLD;
+        case DAMAGE_TYPE_ELECTRICAL: return SAVING_THROW_TYPE_ELECTRICITY;
+        case DAMAGE_TYPE_FIRE:       return SAVING_THROW_TYPE_FIRE;
+        case DAMAGE_TYPE_SONIC:      return SAVING_THROW_TYPE_SONIC;
+        case DAMAGE_TYPE_DIVINE:     return SAVING_THROW_TYPE_DIVINE;
+        case DAMAGE_TYPE_NEGATIVE:   return SAVING_THROW_TYPE_NEGATIVE;
+        case DAMAGE_TYPE_POSITIVE:   return SAVING_THROW_TYPE_POSITIVE;
+    }
+    return SAVING_THROW_TYPE_NONE;//if it ever gets here, than the function was used incorrectly
+}
+
+// this is possibly used in variations elsewhere
+int PRCGetElementalDamageType(int nDamageType, object oCaster = OBJECT_SELF)
+{
+    switch(nDamageType)
+    {
+        case DAMAGE_TYPE_ACID:
+        case DAMAGE_TYPE_COLD:
+        case DAMAGE_TYPE_ELECTRICAL:
+        case DAMAGE_TYPE_FIRE:
+        case DAMAGE_TYPE_SONIC:
+            nDamageType = ChangedElementalDamage(oCaster, nDamageType);
+    }
+    return nDamageType;
+}
+
+int GetHasBaneMagic(int nRace)
+{
+    switch(nRace)
+    {
+        case RACIAL_TYPE_ABERRATION:         return GetHasFeat(FEAT_BANE_MAGIC_ABERRATION);
+        case RACIAL_TYPE_ANIMAL:             return GetHasFeat(FEAT_BANE_MAGIC_ANIMAL);
+        case RACIAL_TYPE_BEAST:              return GetHasFeat(FEAT_BANE_MAGIC_BEAST);
+        case RACIAL_TYPE_CONSTRUCT:          return GetHasFeat(FEAT_BANE_MAGIC_CONSTRUCT);
+        case RACIAL_TYPE_DRAGON:             return GetHasFeat(FEAT_BANE_MAGIC_DRAGON);
+        case RACIAL_TYPE_DWARF:              return GetHasFeat(FEAT_BANE_MAGIC_DWARF);
+        case RACIAL_TYPE_ELEMENTAL:          return GetHasFeat(FEAT_BANE_MAGIC_ELEMENTAL);
+        case RACIAL_TYPE_ELF:                return GetHasFeat(FEAT_BANE_MAGIC_ELF);
+        case RACIAL_TYPE_FEY:                return GetHasFeat(FEAT_BANE_MAGIC_FEY);
+        case RACIAL_TYPE_GIANT:              return GetHasFeat(FEAT_BANE_MAGIC_GIANT);
+        case RACIAL_TYPE_GNOME:              return GetHasFeat(FEAT_BANE_MAGIC_GNOME);
+        case RACIAL_TYPE_HALFELF:            return GetHasFeat(FEAT_BANE_MAGIC_HALFELF);
+        case RACIAL_TYPE_HALFLING:           return GetHasFeat(FEAT_BANE_MAGIC_HALFLING);
+        case RACIAL_TYPE_HALFORC:            return GetHasFeat(FEAT_BANE_MAGIC_HALFORC);
+        case RACIAL_TYPE_HUMAN:              return GetHasFeat(FEAT_BANE_MAGIC_HUMAN);
+        case RACIAL_TYPE_HUMANOID_GOBLINOID: return GetHasFeat(FEAT_BANE_MAGIC_HUMANOID_GOBLINOID);
+        case RACIAL_TYPE_HUMANOID_MONSTROUS: return GetHasFeat(FEAT_BANE_MAGIC_HUMANOID_MONSTROUS);
+        case RACIAL_TYPE_HUMANOID_ORC:       return GetHasFeat(FEAT_BANE_MAGIC_HUMANOID_ORC);
+        case RACIAL_TYPE_HUMANOID_REPTILIAN: return GetHasFeat(FEAT_BANE_MAGIC_HUMANOID_REPTILIAN);
+        case RACIAL_TYPE_MAGICAL_BEAST:      return GetHasFeat(FEAT_BANE_MAGIC_MAGICAL_BEAST);
+        case RACIAL_TYPE_OUTSIDER:           return GetHasFeat(FEAT_BANE_MAGIC_OUTSIDER);
+        case RACIAL_TYPE_SHAPECHANGER:       return GetHasFeat(FEAT_BANE_MAGIC_SHAPECHANGER);
+        case RACIAL_TYPE_UNDEAD:             return GetHasFeat(FEAT_BANE_MAGIC_UNDEAD);
+        case RACIAL_TYPE_VERMIN:             return GetHasFeat(FEAT_BANE_MAGIC_VERMIN);
+    }
+    return FALSE;
+}
+
+void DoPiercingCold(object oCaster, object oTarget, int nDamageAmount, int nCurrentHP)
+{
+    // Get change in HP from spell damage being applied
+    int nTest = nCurrentHP - GetCurrentHitPoints(oTarget);
+    // If there's no damage resistance, nTest and nDamageAmount should be equal
+    if (nDamageAmount > nTest)
+    {
+        // Apply the difference to ignore resist
+        effect eDam = EffectDamage(nDamageAmount - nTest, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_ENERGY);
+        ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
+        effect eVis = EffectVisualEffect(VFX_IMP_FROST_L);
+        ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget);
+        //FloatingTextStringOnCreature("Piercing Cold Triggered", oCaster, FALSE);
+    }
+}
+
+void BreakDR(object oCaster, object oTarget, int nDamageAmount, int nCurrentHP)
+{
+    // Get change in HP from spell damage being applied
+    int nTest = nCurrentHP - GetCurrentHitPoints(oTarget);
+    // If there's no damage resistance, nTest and nDamageAmount should be equal
+    if (nDamageAmount > nTest)
+    {
+        // Apply the difference to ignore resist
+        effect eDam = EffectDamage(nDamageAmount - nTest, DAMAGE_TYPE_POSITIVE, DAMAGE_POWER_ENERGY);
+        ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
+    }
+}
+
+effect PRCEffectDamage(object oTarget, int nDamageAmount, int nDamageType=DAMAGE_TYPE_MAGICAL, int nDamagePower=DAMAGE_POWER_NORMAL, int nMetaMagic=METAMAGIC_NONE)
+{
+    object oCaster = OBJECT_SELF;
+    
+    // Incorporeal creatures have a 50% chance of not being hurt by damage other than Magical/Divine/Negative
+    if (GetLocalInt(oTarget, "Incorporeal") && nDamageType != DAMAGE_TYPE_MAGICAL && nDamageType != DAMAGE_TYPE_NEGATIVE && nDamageType != DAMAGE_TYPE_DIVINE)
+    {
+        if (d2() == 1) // 50% chance
+        {
+            if (GetIsPC(oTarget))
+                FloatingTextStringOnCreature("Spell missed due to Incorporeality", oTarget, FALSE);
+            effect eEffect;
+            return eEffect; // Null return
+        }
+    }
+	
+	// None of the stuff here works when items are involved
+	if (!GetIsObjectValid(PRCGetSpellCastItem()))
+	{
+    	if(PRCGetLastSpellCastClass(oCaster) == CLASS_TYPE_WARMAGE && !GetLocalInt(oTarget, "WarmageEdgeDelay"))
+    	{
+    	    // Warmage Edge
+    	    nDamageAmount += GetAbilityModifier(ABILITY_INTELLIGENCE);
+    	    if(GetHasFeat(FEAT_TYPE_EXTRA_EDGE))
+    	    {
+    	        // Extra Edge feat.
+    	        nDamageAmount += (GetLevelByClass(CLASS_TYPE_WARMAGE) / 4) + 1;
+    	    }
+    	    SetLocalInt(oTarget, "WarmageEdgeDelay", TRUE);
+    	    DelayCommand(0.25, DeleteLocalInt(oTarget, "WarmageEdgeDelay"));
+    	}
+    	
+    	if(GetHasSpellEffect(MELD_ARCANE_FOCUS, oCaster) && !GetLocalInt(oTarget, "ArcaneFocusDelay"))
+    	{
+    	    nDamageAmount += 1 + GetEssentiaInvested(oCaster, MELD_ARCANE_FOCUS);
+    	    SetLocalInt(oTarget, "ArcaneFocusDelay", TRUE);
+    	    DelayCommand(0.25, DeleteLocalInt(oTarget, "ArcaneFocusDelay"));
+    	    if (DEBUG) DoDebug("ArcaneFocus Damage Applied");
+    	}    
+	
+    	// Thrall of Grazzt damage
+    	nDamageAmount += SpellBetrayalDamage(oTarget, oCaster);
+	
+    	int nRace = MyPRCGetRacialType(oTarget);
+	
+    	//Bane Magic
+    	if(GetHasBaneMagic(nRace))
+    	    nDamageAmount += d6(2);
+	
+    	//Eldritch Spellweave
+    	if(oTarget == GetLocalObject(oCaster, "SPELLWEAVE_TARGET"))
+    	{
+    	    //Bane blast essence is active ;)
+    	    if(nRace == ((GetLocalInt(oCaster, "EssenceData") >>> 16) & 0xFF) - 1)
+    	    {
+    	        DeleteLocalObject(oCaster, "SPELLWEAVE_TARGET");
+    	        nDamageAmount += d6(2);
+    	    }
+    	}
+	
+    	// Piercing Evocation
+    	if(GetHasFeat(FEAT_PIERCING_EVOCATION) && GetLocalInt(oCaster, "X2_L_LAST_SPELLSCHOOL_VAR") == SPELL_SCHOOL_EVOCATION)
+    	{
+    	    // Elemental damage only
+    	    if(IsSpellDamageElemental(nDamageType))
+    	    {
+    	        // Damage magical, max 10 to magical
+    	        if(nDamageAmount > 10)
+    	        {
+    	            nDamageAmount -= 10;
+    	            ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(10), oTarget);
+    	        }
+    	        else
+    	        {
+    	            ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamageAmount), oTarget);
+    	            effect eEffect;
+    	            return eEffect; // Null return
+    	        }
+    	    }
+    	}
+    	
+    	// This is done here so it affects all spells
+    	if(GetLocalInt(oCaster, "Diabolism"))
+    	{
+    	    //FloatingTextStringOnCreature("Diabolism is active", oCaster, FALSE);
+    	    int iDiabolistLevel = GetLevelByClass(CLASS_TYPE_DIABOLIST, oCaster);
+    	    DelayCommand(3.0, DeleteLocalInt(oCaster, "Diabolism"));
+	
+    	    if(iDiabolistLevel)
+    	    {
+    	        int nDice = (iDiabolistLevel + 5) / 5;
+    	        int nDamage = d6(nDice);
+    	        int nDamageType = DAMAGE_TYPE_DIVINE;
+	
+    	        if(GetLocalInt(oCaster, "VileDiabolism"))
+    	        {
+    	            //FloatingTextStringOnCreature("Vile Diabolism is active", oCaster, FALSE);
+    	            nDamage /= 2;
+    	            nDamageType = DAMAGE_TYPE_POSITIVE;
+    	            DeleteLocalInt(oCaster, "VileDiabolism");
+    	        }
+	
+    	        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, nDamageType), oTarget);
+    	        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_LOS_EVIL_10), oTarget);
+    	    }
+    	}    
+    	
+    	// Piercing Cold for the Frost Mage
+    	if (GetLevelByClass(CLASS_TYPE_FROST_MAGE, oCaster) >= 4 && nDamageType == DAMAGE_TYPE_COLD)
+    	{
+    	    int nCurrentHP = GetCurrentHitPoints(oTarget);
+    	    DelayCommand(0.1, DoPiercingCold(oCaster, oTarget, nDamageAmount, nCurrentHP));
+    	}
+    	
+    	// Die DR die
+    	if (GetLocalInt(oCaster, "MoveIgnoreDR"))
+    	{
+    	    int nCurrentHP = GetCurrentHitPoints(oTarget);
+    	    DelayCommand(0.1, BreakDR(oCaster, oTarget, nDamageAmount, nCurrentHP));
+    	}
+    }
+    
+    // Frostrager heals on cold damage when raging. 1 heal for every 2 cold damage.
+    if (GetLocalInt(oTarget, "Frostrage") && nDamageType == DAMAGE_TYPE_COLD)
+    {
+        nDamageAmount /= 2;
+        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectHeal(nDamageAmount), oTarget); 
+        ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_FROST_L), oTarget);
+        
+        FloatingTextStringOnCreature("Absorb Cold healed " + IntToString(nDamageAmount), oTarget, FALSE);
+        effect eEffect;
+        return eEffect; //Doesn't hurt him
+    } 
+    // Phoenix Belt gains fast healing when hit by fire damage
+    if (GetHasSpellEffect(MELD_PHOENIX_BELT, oTarget) && nDamageType == DAMAGE_TYPE_FIRE)
+    {
+    	int nEssentia = GetEssentiaInvested(oTarget, MELD_PHOENIX_BELT);
+    	int nResist = nEssentia * 5;
+        int nDur;
+        if (nDamageAmount >= nResist) nDur = nResist;
+        else nDur = nDamageAmount;
+        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectRegenerate(1, 6.0), oTarget, RoundsToSeconds(nDur+1));
+    }     
+        
+    return EffectDamage(nDamageAmount, nDamageType, nDamagePower);
+}
+
+// * Kovi. removes any effects from this type of spell
+// * i.e., used in Mage Armor to remove any previous
+// * mage armors
+void PRCRemoveEffectsFromSpell(object oTarget, int SpellID)
+{
+    effect eLook = GetFirstEffect(oTarget);
+    while(GetIsEffectValid(eLook))
+    {
+        if(GetEffectSpellId(eLook) == SpellID)
+            RemoveEffect(oTarget, eLook);
+
+        eLook = GetNextEffect(oTarget);
+    }
+}
+
+void PRCRemoveSpecificEffect(int nEffectTypeID, object oTarget)
+{
+    //Search through the valid effects on the target.
+    effect eAOE = GetFirstEffect(oTarget);
+    while (GetIsEffectValid(eAOE))
+    {
+        if (GetEffectType(eAOE) == nEffectTypeID)
+        {
+            //If the effect was created by the spell then remove it
+            RemoveEffect(oTarget, eAOE);
+        }
+        //Get next effect on the target
+        eAOE = GetNextEffect(oTarget);
+    }
+}
+
+effect PRCGetScaledEffect(effect eStandard, object oTarget)
+{
+    int nDiff = GetGameDifficulty();
+    int nEffType = GetEffectType(eStandard);
+
+    if(GetIsPC(oTarget) || GetIsPC(GetMaster(oTarget)))
+    {
+        if(nEffType == EFFECT_TYPE_FRIGHTENED)
+        {
+            if(nDiff == GAME_DIFFICULTY_VERY_EASY)
+            {
+                return EffectAttackDecrease(-2);
+            }
+            else if(nDiff == GAME_DIFFICULTY_EASY)
+            {
+                return EffectAttackDecrease(-4);
+            }
+        }
+        if(nDiff == GAME_DIFFICULTY_VERY_EASY &&
+            (nEffType == EFFECT_TYPE_PARALYZE ||
+             nEffType == EFFECT_TYPE_STUNNED ||
+             nEffType == EFFECT_TYPE_CONFUSED))
+        {
+            return EffectDazed();
+        }
+        if(nEffType == EFFECT_TYPE_CHARMED
+        || nEffType == EFFECT_TYPE_DOMINATED)
+        {
+            return EffectDazed();
+        }
+    }
+    return eStandard;
+}
+
+int PRCAmIAHumanoid(object oTarget)
+{
+    int nRacial = MyPRCGetRacialType(oTarget);
+    if(nRacial == RACIAL_TYPE_DWARF
+    || nRacial == RACIAL_TYPE_HALFELF
+    || nRacial == RACIAL_TYPE_HALFORC
+    || nRacial == RACIAL_TYPE_ELF
+    || nRacial == RACIAL_TYPE_GNOME
+    || nRacial == RACIAL_TYPE_HUMANOID_GOBLINOID
+    || nRacial == RACIAL_TYPE_HALFLING
+    || nRacial == RACIAL_TYPE_HUMAN
+    || nRacial == RACIAL_TYPE_HUMANOID_MONSTROUS
+    || nRacial == RACIAL_TYPE_HUMANOID_ORC
+    || nRacial == RACIAL_TYPE_HUMANOID_REPTILIAN)
+    {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+int PRCGetScaledDuration(int nActualDuration, object oTarget)
+{
+    int nDiff = GetGameDifficulty();
+    int nNew = nActualDuration;
+    if(GetIsPC(oTarget) && nActualDuration > 3)
+    {
+        if(nDiff == GAME_DIFFICULTY_VERY_EASY
+        || nDiff == GAME_DIFFICULTY_EASY)
+        {
+            nNew = nActualDuration / 4;
+        }
+        else if(nDiff == GAME_DIFFICULTY_NORMAL)
+        {
+            nNew = nActualDuration / 2;
+        }
+        if(nNew == 0)
+        {
+            nNew = 1;
+        }
+    }
+    return nNew;
+}
+
+effect PRCCreateProtectionFromAlignmentLink(int nAlignment, int nPower = 1)
+{
+    int nFinal = nPower * 2;
+    int nAlignmentLC;
+    int nAlignmentGE;
+    effect eDur;
+
+    switch(nAlignment)
+    {
+        case ALIGNMENT_LAWFUL:{
+            nAlignmentLC = ALIGNMENT_LAWFUL;
+            nAlignmentGE = ALIGNMENT_ALL;
+            eDur = EffectVisualEffect(VFX_DUR_PROTECTION_EVIL_MINOR);
+            break;}
+        case ALIGNMENT_CHAOTIC:{
+            nAlignmentLC = ALIGNMENT_CHAOTIC;
+            nAlignmentGE = ALIGNMENT_ALL;
+            eDur = EffectVisualEffect(VFX_DUR_PROTECTION_GOOD_MINOR);
+            break;}
+        case ALIGNMENT_GOOD:{
+            nAlignmentLC = ALIGNMENT_ALL;
+            nAlignmentGE = ALIGNMENT_GOOD;
+            eDur = EffectVisualEffect(VFX_DUR_PROTECTION_EVIL_MINOR);
+            break;}
+        case ALIGNMENT_EVIL:{
+            nAlignmentLC = ALIGNMENT_ALL;
+            nAlignmentGE = ALIGNMENT_EVIL;
+            eDur = EffectVisualEffect(VFX_DUR_PROTECTION_GOOD_MINOR);
+            break;}
+    }
+
+    //construct final effect
+    effect eLink = EffectACIncrease(nFinal, AC_DEFLECTION_BONUS);
+           eLink = EffectLinkEffects(eLink, EffectSavingThrowIncrease(SAVING_THROW_ALL, nFinal));
+           eLink = EffectLinkEffects(eLink, EffectImmunity(IMMUNITY_TYPE_MIND_SPELLS));
+           //make it vs alignment
+           eLink = VersusAlignmentEffect(eLink, nAlignmentLC, nAlignmentGE);
+           //add duration vfx
+           eLink = EffectLinkEffects(eLink, EffectVisualEffect(VFX_DUR_CESSATE_POSITIVE));
+           eLink = EffectLinkEffects(eLink, eDur);
+
+    return eLink;
+}
+
+float PRCGetSpellEffectDelay(location SpellTargetLocation, object oTarget)
+{
+    float fDelay = GetDistanceBetweenLocations(SpellTargetLocation, GetLocation(oTarget))/20;
+    return fDelay;
+}
+
+// * returns true if the creature has flesh
+int PRCIsImmuneToPetrification(object oCreature)
+{
+    int nAppearance = GetAppearanceType(oCreature);
+    int bImmune = FALSE;
+    
+	if (GetHasSpellEffect(VESTIGE_HAAGENTI, oCreature) && GetLocalInt(oCreature, "ExploitVestige") != VESTIGE_HAAGENTI_IMMUNE_TRANS) bImmune = TRUE;    
+    
+    switch (nAppearance)
+    {
+        case APPEARANCE_TYPE_BASILISK:
+        case APPEARANCE_TYPE_COCKATRICE:
+        case APPEARANCE_TYPE_MEDUSA:
+        case APPEARANCE_TYPE_ALLIP:
+        case APPEARANCE_TYPE_ELEMENTAL_AIR:
+        case APPEARANCE_TYPE_ELEMENTAL_AIR_ELDER:
+        case APPEARANCE_TYPE_ELEMENTAL_EARTH:
+        case APPEARANCE_TYPE_ELEMENTAL_EARTH_ELDER:
+        case APPEARANCE_TYPE_ELEMENTAL_FIRE:
+        case APPEARANCE_TYPE_ELEMENTAL_FIRE_ELDER:
+        case APPEARANCE_TYPE_ELEMENTAL_WATER:
+        case APPEARANCE_TYPE_ELEMENTAL_WATER_ELDER:
+        case APPEARANCE_TYPE_GOLEM_STONE:
+        case APPEARANCE_TYPE_GOLEM_IRON:
+        case APPEARANCE_TYPE_GOLEM_CLAY:
+        case APPEARANCE_TYPE_GOLEM_BONE:
+        case APPEARANCE_TYPE_GORGON:
+        case APPEARANCE_TYPE_HEURODIS_LICH:
+        case APPEARANCE_TYPE_LANTERN_ARCHON:
+        case APPEARANCE_TYPE_SHADOW:
+        case APPEARANCE_TYPE_SHADOW_FIEND:
+        case APPEARANCE_TYPE_SHIELD_GUARDIAN:
+        case APPEARANCE_TYPE_SKELETAL_DEVOURER:
+        case APPEARANCE_TYPE_SKELETON_CHIEFTAIN:
+        case APPEARANCE_TYPE_SKELETON_COMMON:
+        case APPEARANCE_TYPE_SKELETON_MAGE:
+        case APPEARANCE_TYPE_SKELETON_PRIEST:
+        case APPEARANCE_TYPE_SKELETON_WARRIOR:
+        case APPEARANCE_TYPE_SKELETON_WARRIOR_1:
+        case APPEARANCE_TYPE_SPECTRE:
+        case APPEARANCE_TYPE_WILL_O_WISP:
+        case APPEARANCE_TYPE_WRAITH:
+        case APPEARANCE_TYPE_BAT_HORROR:
+        case 405: // Dracolich:
+        case 415: // Alhoon
+        case 418: // shadow dragon
+        case 420: // mithral golem
+        case 421: // admantium golem
+        case 430: // Demi Lich
+        case 469: // animated chest
+        case 474: // golems
+        case 475: // golems
+        bImmune = TRUE;
+    }
+
+    int nRacialType = MyPRCGetRacialType(oCreature);
+    switch(nRacialType)
+    {
+        case RACIAL_TYPE_ELEMENTAL:
+        case RACIAL_TYPE_CONSTRUCT:
+        case RACIAL_TYPE_OOZE:
+        case RACIAL_TYPE_UNDEAD:
+        bImmune = TRUE;
+    }
+
+    // 01/08/07 Racial feat for petrification immunity
+    if(GetHasFeat(FEAT_IMMUNE_PETRIFICATION)) bImmune = TRUE;
+
+    // 03/07/2005 CraigW - Petrification immunity can also be granted as an item property.
+    if ( ResistSpell(OBJECT_SELF,oCreature) == 2 )
+    {
+        bImmune = TRUE;
+    }
+
+    // * GZ: Sept 2003 - Prevent people from petrifying DM, resulting in GUI even when
+    //                   effect is not successful.
+    if (!GetPlotFlag(oCreature) && GetIsDM(oCreature))
+    {
+       bImmune = FALSE;
+    }
+    return bImmune;
+}
+
+// *  This is a wrapper for how Petrify will work in Expansion Pack 1
+// * Scripts affected: flesh to stone, breath petrification, gaze petrification, touch petrification
+// * nPower : This is the Hit Dice of a Monster using Gaze, Breath or Touch OR it is the Caster Spell of
+// *   a spellcaster
+// * nFortSaveDC: pass in this number from the spell script
+void PRCDoPetrification(int nPower, object oSource, object oTarget, int nSpellID, int nFortSaveDC)
+{
+
+    if(!GetIsReactionTypeFriendly(oTarget))
+    {
+        // * exit if creature is immune to petrification
+        if(PRCIsImmuneToPetrification(oTarget))
+            return;
+
+        float fDifficulty = 0.0;
+        int bIsPC = GetIsPC(oTarget);
+        int bShowPopup = FALSE;
+
+        // * calculate Duration based on difficulty settings
+        int nGameDiff = GetGameDifficulty();
+        switch (nGameDiff)
+        {
+            case GAME_DIFFICULTY_VERY_EASY:
+            case GAME_DIFFICULTY_EASY:
+            case GAME_DIFFICULTY_NORMAL:
+                    fDifficulty = RoundsToSeconds(nPower); // One Round per hit-die or caster level
+                break;
+            case GAME_DIFFICULTY_CORE_RULES:
+            case GAME_DIFFICULTY_DIFFICULT:
+                bShowPopup = TRUE;
+            break;
+        }
+
+        int nSaveDC = nFortSaveDC;
+        effect ePetrify = EffectPetrify();
+
+        effect eDur = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
+
+        effect eLink = EffectLinkEffects(eDur, ePetrify);
+
+            // Let target know the negative spell has been cast
+            SignalEvent(oTarget,
+                        EventSpellCastAt(OBJECT_SELF, nSpellID));
+                        //SpeakString(IntToString(nSpellID));
+
+            // Do a fortitude save check
+            if (!PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nSaveDC))
+            {
+                // Save failed; apply paralyze effect and VFX impact
+
+                /// * The duration is permanent against NPCs but only temporary against PCs
+                if (bIsPC == TRUE)
+                {
+                    if (bShowPopup == TRUE)
+                    {
+                        // * under hardcore rules or higher, this is an instant death
+                        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget);
+                        //only pop up death panel if switch is not set
+                        if(!GetPRCSwitch(PRC_NO_PETRIFY_GUI))
+                        DelayCommand(2.75, PopUpDeathGUIPanel(oTarget, FALSE , TRUE, 40579));
+                        //run the PRC Ondeath code
+                        //no way to run the normal module ondeath code too
+                        //so a execute script has been added for builders to take advantage of
+                        DelayCommand(2.75, ExecuteScript("prc_ondeath", oTarget));
+                        DelayCommand(2.75, ExecuteScript("prc_pw_petrific", oTarget));
+                        // if in hardcore, treat the player as an NPC
+                        bIsPC = FALSE;
+                        //fDifficulty = TurnsToSeconds(nPower); // One turn per hit-die
+                    }
+                    else
+                        ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oTarget, fDifficulty);
+                }
+                else
+                {
+                    ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oTarget);
+                }
+                // April 2003: Clearing actions to kick them out of conversation when petrified
+                AssignCommand(oTarget, ClearAllActions(TRUE));
+            }
+    }
+
+}
+
+//------------------------------------------------------------------------------
+// GZ: 2003-Oct-15
+// A different approach for timing these spells that has the positive side
+// effects of making the spell dispellable as well.
+// I am using the VFX applied by the spell to track the remaining duration
+// instead of adding the remaining runtime on the stack
+//
+// This function returns FALSE if a delayed Spell effect from nSpell_ID has
+// expired. See x2_s0_bigby4.nss for details
+//------------------------------------------------------------------------------
+int PRCGetDelayedSpellEffectsExpired(int nSpell_ID, object oTarget, object oCaster)
+{
+
+    if (!GetHasSpellEffect(nSpell_ID,oTarget) )
+    {
+        DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID));
+        return TRUE;
+    }
+
+    //--------------------------------------------------------------------------
+    // GZ: 2003-Oct-15
+    // If the caster is dead or no longer there, cancel the spell, as it is
+    // directed
+    //--------------------------------------------------------------------------
+    if( !GetIsObjectValid(oCaster))
+    {
+        GZPRCRemoveSpellEffects(nSpell_ID, oTarget);
+        DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID));
+        return TRUE;
+    }
+
+    if (GetIsDead(oCaster))
+    {
+        DeleteLocalInt(oTarget,"XP2_L_SPELL_SAVE_DC_" + IntToString (nSpell_ID));
+        GZPRCRemoveSpellEffects(nSpell_ID, oTarget);
+        return TRUE;
+    }
+
+    return FALSE;
+
+}
+
+// Much similar to PRCGetHasSpell, but used for JPM to get spells left not counting metamagic
+int PRCGetSpellUsesLeft(int nRealSpellID, object oCreature = OBJECT_SELF)
+{
+    if(!PRCGetIsRealSpellKnown(nRealSpellID, oCreature))
+        return 0;
+    int nUses = GetHasSpell(nRealSpellID, oCreature);
+
+    int nClass, nSpellbookID, nCount, 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);
+        if (nSpellbookID != -1)
+        {   //non-spellbook classes should return -1
+                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(Prepared Caster): 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(Spontaneous Caster): NewSpellbookMem_" + IntToString(nClass) + "[" + IntToString(j) + "] = " + IntToString(nCount));
+                    if(nCount > 0)
+                    {
+                        nUses += nCount;
+                    }
+                }
+        }
+    }
+
+    if(DEBUG) DoDebug("PRCGetHasSpell: RealSpellID = " + IntToString(nRealSpellID) + ", Uses = " + IntToString(nUses));
+    return nUses;
+}
+
+// * Applies the effects of FEAT_AUGMENT_SUMMON to summoned creatures.
+void AugmentSummonedCreature(string sResRef)
+{
+    if(GetHasFeat(FEAT_AUGMENT_SUMMON))
+    {
+        int i = 1;
+        object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF);
+        while(GetIsObjectValid(oSummon))
+        {
+            if(GetResRef(oSummon) == sResRef && !GetLocalInt(oSummon, "Augmented"))
+            {
+                effect eLink = EffectAbilityIncrease(ABILITY_STRENGTH, 4);
+                       eLink = EffectLinkEffects(eLink, EffectAbilityIncrease(ABILITY_CONSTITUTION, 4));
+                       eLink = SupernaturalEffect(eLink);
+    
+                ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oSummon);
+                SetLocalInt(oSummon, "Augmented", TRUE);
+            }
+            i++;
+            oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i);
+        }
+    }
+    if(sResRef == "prc_sum_treant")
+    {
+        int i = 1;
+        object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF);
+        while(GetIsObjectValid(oSummon))
+        {
+            if(GetResRef(oSummon) == sResRef)
+            {
+                ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectVisualEffect(VFX_DUR_PROT_BARKSKIN), oSummon);
+            }
+            i++;
+            oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i);
+        }
+    }    
+    if(GetHasFeat(FEAT_BECKON_THE_FROZEN))
+    {
+        int i = 1;
+        object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF);
+        while(GetIsObjectValid(oSummon))
+        {
+            if(GetResRef(oSummon) == sResRef && !GetLocalInt(oSummon, "BeckonTheFrozen"))
+            {
+                effect eLink = EffectVisualEffect(VFX_DUR_ELEMENTAL_SHIELD);
+                eLink = EffectLinkEffects(eLink, EffectDamageImmunityDecrease(DAMAGE_TYPE_FIRE, 50));
+                eLink = EffectLinkEffects(eLink, EffectDamageImmunityIncrease(DAMAGE_TYPE_COLD, 100));
+                eLink = SupernaturalEffect(eLink);
+    
+                ApplyEffectToObject(DURATION_TYPE_PERMANENT, eLink, oSummon);
+                SetLocalInt(oSummon, "BeckonTheFrozen", TRUE);
+            }
+            i++;
+            oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i);
+        }
+    }    
+}    
+
+object GetAreaOfEffectObject(location lTarget, string sTag, object oCaster = OBJECT_SELF)
+{
+    object oAoE = GetFirstObjectInShape(SHAPE_SPHERE, 1.0f, lTarget, FALSE, OBJECT_TYPE_AREA_OF_EFFECT);
+    while(GetIsObjectValid(oAoE))
+    {
+        if((GetAreaOfEffectCreator(oAoE) == oCaster) //was created by oCaster
+        && GetTag(oAoE) == sTag                      //has required tag
+        && !GetLocalInt(oAoE, "X2_AoE_BaseSaveDC")) //and wasn't setup before
+        {
+            return oAoE;
+        }
+        oAoE = GetNextObjectInShape(SHAPE_SPHERE, 1.0f, lTarget, FALSE, OBJECT_TYPE_AREA_OF_EFFECT);
+    }
+    return OBJECT_INVALID;
+}
+
+string GetAreaOfEffectTag(int nAoE)
+{
+    return Get2DACache("vfx_persistent", "LABEL", nAoE);
+}
+
+int CheckTurnUndeadUses(object oPC, int nUses)
+{
+    int i;
+    while(i < nUses)
+    {
+        if(GetHasFeat(FEAT_TURN_UNDEAD, oPC))
+        {
+            DecrementRemainingFeatUses(oPC, FEAT_TURN_UNDEAD);
+            i++;
+        }
+        else
+            break;
+    }
+    if(i < nUses)
+    {
+        while(i)
+        {
+            IncrementRemainingFeatUses(oPC, FEAT_TURN_UNDEAD);
+            i--;
+        }
+        return FALSE;
+    }
+    return TRUE;
+}
+
+// this will execute the prespellcastcode, whose full functionality is incoded in X2PreSpellCastCode2(),
+// as a script, to save loading time for spells scripts and reduce memory usage of NWN
+// the prespellcode takes up roughly 250 kByte compiled code, meaning that every spell script that
+// calls it directly as a function (e.g.: X2PreSpellCastCode2) will be between 100 kByte to 250 kByte
+// larger, than a spell script calling the prespellcode via ExecuteScript (e.g. X2PreSpellCastCode)
+// Although ExecuteScript is slightly slower than a direct function call, quite likely overall performance is
+// increased, because for every new spell 100-250 kByte less code need to be loaded into memory
+// and NWN has more free memory available to keep more spells scripts (and other crucial scripts)
+//in RAM
+
+int X2PreSpellCastCode()
+{
+    object oCaster = OBJECT_SELF;
+
+        // SetLocalInt(oCaster, "PSCC_Ret", 0);
+        ExecuteScript("prc_prespell", oCaster);
+
+        int nReturn = GetLocalInt(oCaster, "PSCC_Ret");
+        // DeleteLocalInt(oCaster, "PSCC_Ret");
+
+        return nReturn;
+}	
+
+//:: Test Void
+//void main (){}
\ No newline at end of file
diff --git a/trunk/include/prc_shifter_info.nss b/trunk/include/prc_shifter_info.nss
new file mode 100644
index 00000000..e5f715d3
--- /dev/null
+++ b/trunk/include/prc_shifter_info.nss
@@ -0,0 +1,1436 @@
+
+//:: Updated for .35 by Jaysyn 2023/03/10
+
+#include "prc_inc_function"
+#include "inc_nwnx_funcs"
+
+//:: Test Void
+//void main (){}
+
+
+const int DEBUG_NATURAL_AC_CALCULATION = FALSE;
+int MAX_BONUS = GetPRCSwitch(PRC_PNP_SHIFTER_BONUS);
+const int MAX_PENALTY = 10;
+int NWNX_STR_LIMIT = 100 - MAX_BONUS;
+
+struct _prc_inc_ability_info_struct{
+    int nTemplateSTR;
+    int nTemplateDEX;
+    int nTemplateCON;
+
+    int nShifterSTR;
+    int nShifterDEX;
+    int nShifterCON;
+
+    int nDeltaSTR;
+    int nDeltaDEX;
+    int nDeltaCON;
+
+    int nItemSTR;
+    int nItemDEX;
+    int nItemCON;
+
+    int nExtraSTR;
+    int nExtraDEX;
+    int nExtraCON;
+    
+    int nItemDeltaSTR;
+    int nItemDeltaDEX;
+    int nItemDeltaCON;
+};
+
+//TODO: also count item penalties?
+struct _prc_inc_ability_info_struct _prc_inc_CountItemAbilities(object oCreature)
+{
+    struct _prc_inc_ability_info_struct rInfoStruct;
+    rInfoStruct.nItemSTR = 0;
+    rInfoStruct.nItemDEX = 0;
+    rInfoStruct.nItemCON = 0;
+    
+    object oItem;
+    itemproperty iProperty;
+    int nSlot;
+    for(nSlot = 0; nSlot < NUM_INVENTORY_SLOTS; nSlot++)
+    {
+        switch (nSlot)
+        {
+            case INVENTORY_SLOT_CARMOUR:
+            case INVENTORY_SLOT_CWEAPON_R:
+            case INVENTORY_SLOT_CWEAPON_L:
+            case INVENTORY_SLOT_CWEAPON_B:
+                break;
+            
+            default:
+            {
+                oItem = GetItemInSlot(nSlot, oCreature);
+                if (GetIsObjectValid(oItem))
+                {
+                    iProperty = GetFirstItemProperty(oItem);
+                    while (GetIsItemPropertyValid(iProperty))
+                    {
+                        if (GetItemPropertyType(iProperty) == ITEM_PROPERTY_ABILITY_BONUS &&
+                            GetItemPropertyDurationType(iProperty) == DURATION_TYPE_PERMANENT 
+                           )
+                        {
+                            int nSubType = GetItemPropertySubType(iProperty);
+                            int nCostTableValue = GetItemPropertyCostTableValue(iProperty);
+                            if (nSubType == IP_CONST_ABILITY_STR)
+                                rInfoStruct.nItemSTR += nCostTableValue;
+                            else if (nSubType == IP_CONST_ABILITY_DEX)
+                                rInfoStruct.nItemDEX += nCostTableValue;
+                            else if (nSubType == IP_CONST_ABILITY_CON)
+                                rInfoStruct.nItemCON += nCostTableValue;
+                        }
+                        // Next item property.
+                        iProperty = GetNextItemProperty(oItem);
+                    }
+                }
+            }
+        }
+    }
+    return rInfoStruct;
+}
+
+struct _prc_inc_ability_info_struct _prc_inc_shifter_GetAbilityInfo(object oTemplate, object oShifter)
+{
+    int bFuncs = GetPRCSwitch(PRC_NWNX_FUNCS);
+
+    //Initialize with item ability bonuses
+
+    struct _prc_inc_ability_info_struct rInfoStruct = _prc_inc_CountItemAbilities(oShifter);
+    
+    //Get template creature abilities
+    
+    rInfoStruct.nTemplateSTR = GetAbilityScore(oTemplate, ABILITY_STRENGTH, TRUE);
+    rInfoStruct.nTemplateDEX = GetAbilityScore(oTemplate, ABILITY_DEXTERITY, TRUE);
+    rInfoStruct.nTemplateCON = GetAbilityScore(oTemplate, ABILITY_CONSTITUTION, TRUE);
+    //TODO: merge in "Ability Bonus: Strength" from item property from template hide here (not too important, as not many templates use this)
+    //TODO: merge in "Ability Bonus: Dexterity" from item property from template hide here (not too important, as not many templates use this)
+    //TODO: merge in "Ability Bonus: Constitution" from item property from template hide here (not too important, as not many templates use this)
+    
+    //Calculate how they compare to the shifter's abilities
+
+    rInfoStruct.nShifterSTR = GetAbilityScore(oShifter, ABILITY_STRENGTH, TRUE);
+    rInfoStruct.nShifterDEX = GetAbilityScore(oShifter, ABILITY_DEXTERITY, TRUE);
+    rInfoStruct.nShifterCON = GetAbilityScore(oShifter, ABILITY_CONSTITUTION, TRUE);
+
+    rInfoStruct.nDeltaSTR = rInfoStruct.nTemplateSTR - rInfoStruct.nShifterSTR;
+    rInfoStruct.nDeltaDEX = rInfoStruct.nTemplateDEX - rInfoStruct.nShifterDEX;
+    rInfoStruct.nDeltaCON = rInfoStruct.nTemplateCON - rInfoStruct.nShifterCON;
+    
+    //Handle stat boosting items
+    if (rInfoStruct.nItemSTR > MAX_BONUS)
+        rInfoStruct.nItemSTR = MAX_BONUS;
+    else if (rInfoStruct.nItemSTR < -MAX_PENALTY)
+        rInfoStruct.nItemSTR = -MAX_PENALTY;
+
+    if (rInfoStruct.nItemDEX > MAX_BONUS)
+        rInfoStruct.nItemDEX = MAX_BONUS;
+    else if (rInfoStruct.nItemDEX < -MAX_PENALTY)
+        rInfoStruct.nItemDEX = -MAX_PENALTY;
+
+    if (rInfoStruct.nItemCON > MAX_BONUS)
+        rInfoStruct.nItemCON = MAX_BONUS;
+    else if (rInfoStruct.nItemCON < -MAX_PENALTY)
+        rInfoStruct.nItemCON = -MAX_PENALTY;
+        
+    //Handle changes that exceed bonus or penalty caps
+
+    rInfoStruct.nItemDeltaSTR = rInfoStruct.nDeltaSTR + rInfoStruct.nItemSTR;
+    if (bFuncs)
+    {
+        //NWNX boosts aren't capped, so we don't need to handle caps, generally speaking. 
+        rInfoStruct.nExtraSTR = 0; 
+
+        //However, due to a Bioware issue, if STR, including bonuses, goes greater than 100,
+        //the amount of weight the PC can carry drops to 0. So, cap STR to make sure this doesn't happen.
+
+        if (rInfoStruct.nTemplateSTR > NWNX_STR_LIMIT)
+        {
+            rInfoStruct.nExtraSTR = rInfoStruct.nTemplateSTR - NWNX_STR_LIMIT;
+            rInfoStruct.nTemplateSTR = NWNX_STR_LIMIT;
+            rInfoStruct.nDeltaSTR = rInfoStruct.nTemplateSTR - rInfoStruct.nShifterSTR;
+        }
+    }
+    else if (rInfoStruct.nItemDeltaSTR > MAX_BONUS)
+        rInfoStruct.nExtraSTR = rInfoStruct.nItemDeltaSTR - MAX_BONUS;
+    else if(rInfoStruct.nItemDeltaSTR < -MAX_PENALTY)
+        rInfoStruct.nExtraSTR = rInfoStruct.nItemDeltaSTR + MAX_PENALTY;
+        
+    rInfoStruct.nItemDeltaDEX = rInfoStruct.nDeltaDEX + rInfoStruct.nItemDEX;
+    if (bFuncs)
+        rInfoStruct.nExtraDEX = 0; //NWNX boosts aren't capped, so we don't need to handle caps
+    else if (rInfoStruct.nItemDeltaDEX > MAX_BONUS)
+        rInfoStruct.nExtraDEX = rInfoStruct.nItemDeltaDEX - MAX_BONUS;
+    else if(rInfoStruct.nItemDeltaDEX < -MAX_PENALTY)
+        rInfoStruct.nExtraDEX = rInfoStruct.nItemDeltaDEX + MAX_PENALTY;
+        
+    rInfoStruct.nItemDeltaCON = rInfoStruct.nDeltaCON + rInfoStruct.nItemCON;
+    if (bFuncs)
+        rInfoStruct.nExtraCON = 0; //NWNX boosts aren't capped, so we don't need to handle caps
+    else if (rInfoStruct.nItemDeltaCON > MAX_BONUS)
+        rInfoStruct.nExtraCON = rInfoStruct.nItemDeltaCON - MAX_BONUS;
+    else if(rInfoStruct.nItemDeltaCON < -MAX_PENALTY)
+        rInfoStruct.nExtraCON = rInfoStruct.nItemDeltaCON + MAX_PENALTY;
+
+    return rInfoStruct;
+}
+
+int _prc_inc_GetItemACBonus(object oItem)
+{
+    int nArmorBonus = 0;
+    itemproperty iProp = GetFirstItemProperty(oItem);
+    while(GetIsItemPropertyValid(iProp))
+    {
+        if(GetItemPropertyType(iProp) == ITEM_PROPERTY_AC_BONUS && GetItemPropertyDurationType(iProp) == DURATION_TYPE_PERMANENT)
+            nArmorBonus = max(nArmorBonus, GetItemPropertyCostTableValue(iProp)); //TODO: pick the biggest? the first? stack them?
+        iProp = GetNextItemProperty(oItem);
+    }    
+    return nArmorBonus;
+}
+
+int _prc_inc_GetArmorMaxDEXBonus(object oArmor, int nMaxDexACBonus = 100)
+{
+    if (GetIsObjectValid(oArmor))
+    {
+        int nArmorAC = GetItemACValue(oArmor) - _prc_inc_GetItemACBonus(oArmor); //Exclude magical AC bonus to figure out armor type
+        switch(nArmorAC)
+        {
+            //TODO: CAN THESE BE LOOKED UP IN A 2DA OR SOMEWHERE?
+            case 8: case 7: case 6:
+                nMaxDexACBonus = 1; break;
+            case 5:
+                nMaxDexACBonus = 2; break;
+            case 4: case 3:
+                nMaxDexACBonus = 4; break;
+            case 2:
+                nMaxDexACBonus = 6; break;
+            case 1:
+                nMaxDexACBonus = 8; break;
+        }
+    }
+    return nMaxDexACBonus;
+}
+
+struct _prc_inc_ac_info_struct{
+    int nArmorBase;
+    int nArmorBonus;
+
+    int nShieldBase;
+    int nShieldBonus;
+    
+    int nDodgeBonus;
+    int nNaturalBonus;
+    int nDeflectionBonus;
+    
+    int nDEXBonus;
+};
+
+struct _prc_inc_ac_info_struct _prc_inc_ACInfo(object oTemplate)
+{
+    struct _prc_inc_ac_info_struct ac_info;
+    
+    object oArmorItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oTemplate);
+    ac_info.nArmorBonus = _prc_inc_GetItemACBonus(oArmorItem);
+    ac_info.nArmorBase = GetItemACValue(oArmorItem) - ac_info.nArmorBonus;
+    
+    ac_info.nDodgeBonus = GetItemACValue(GetItemInSlot(INVENTORY_SLOT_BOOTS, oTemplate));
+    ac_info.nNaturalBonus = GetItemACValue(GetItemInSlot(INVENTORY_SLOT_NECK, oTemplate));
+
+    ac_info.nDeflectionBonus = GetItemACValue(GetItemInSlot(INVENTORY_SLOT_HEAD, oTemplate));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_CLOAK, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_LEFTRING, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_BELT, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_ARROWS, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_BULLETS, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_BOLTS, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oTemplate)));
+    ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(GetItemInSlot(INVENTORY_SLOT_CARMOUR, oTemplate)));
+
+    object oOffHandItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oTemplate);
+    ac_info.nShieldBase = 0;
+    ac_info.nShieldBonus = 0;
+    switch (GetBaseItemType(oOffHandItem))
+    {
+        case BASE_ITEM_SMALLSHIELD:
+            ac_info.nShieldBase = 1;
+            ac_info.nShieldBonus = GetItemACValue(oOffHandItem) - ac_info.nShieldBase;
+            break;
+        case BASE_ITEM_LARGESHIELD:
+            ac_info.nShieldBase = 2;
+            ac_info.nShieldBonus = GetItemACValue(oOffHandItem) - ac_info.nShieldBase;
+            break;
+        case BASE_ITEM_TOWERSHIELD:
+            ac_info.nShieldBase = 3;
+            ac_info.nShieldBonus = GetItemACValue(oOffHandItem) - ac_info.nShieldBase;
+            break;
+        default: //A weapon
+            ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(oOffHandItem));
+            break;
+    }
+    
+    object oArmsItem = GetItemInSlot(INVENTORY_SLOT_ARMS, oTemplate);
+    switch (GetBaseItemType(oArmsItem))
+    {
+        case BASE_ITEM_BRACER:
+            ac_info.nShieldBonus = max(ac_info.nShieldBonus, GetItemACValue(oArmsItem));
+            break;
+        case BASE_ITEM_GLOVES:
+        default:
+            ac_info.nDeflectionBonus = max(ac_info.nDeflectionBonus, GetItemACValue(oArmsItem));
+            break;
+    }
+    
+    if (ac_info.nArmorBonus > 20)
+        ac_info.nArmorBonus = 20;
+    if (ac_info.nDodgeBonus > 20)
+        ac_info.nDodgeBonus = 20;
+    if (ac_info.nNaturalBonus > 20)
+        ac_info.nNaturalBonus = 20;
+    if (ac_info.nDeflectionBonus > 20)
+        ac_info.nDeflectionBonus = 20;
+    if (ac_info.nShieldBonus > 20)
+        ac_info.nShieldBonus = 20;
+        
+    ac_info.nDEXBonus = min(GetAbilityModifier(ABILITY_DEXTERITY, oTemplate), _prc_inc_GetArmorMaxDEXBonus(oArmorItem));
+    //TODO: make sure this isn't < 0?
+    
+    return ac_info;
+}
+
+//Estimate natural AC of the creature oTemplate
+int _prc_inc_CreatureNaturalAC(object oTemplate)
+{
+    struct _prc_inc_ac_info_struct ac_info = _prc_inc_ACInfo(oTemplate);
+
+    //TODO: GetAC(oTemplate) often returns an AC different (usually higher) than the combat debugging log indicates it should be.
+        //Note that combat debugging doesn't report DEX bonus, Monk WIS bonus, etc.; where does this come in?
+    int nNaturalAC = GetAC(oTemplate)
+                   - 10                           // Adjust for base AC
+                   - ac_info.nDEXBonus               // And Dex bonus
+                   - ac_info.nArmorBase           // Etc...
+                   - ac_info.nArmorBonus
+                   - ac_info.nDodgeBonus
+                   - ac_info.nNaturalBonus
+                   - ac_info.nDeflectionBonus
+                   - ac_info.nShieldBase
+                   - ac_info.nShieldBonus;
+    
+    //TODO:
+        //Subtract +4 Dodge bonus if template has Haste?
+        //Subtract +1 AC / each 5 points of the Tumble skill?
+        //Subtract Monk AC from level progression?
+        //Subtract WIS AC if Monk/Ninja, etc.?
+        //Make sure nNaturalAC is not < 0 (it was for me once using the old method of calculation, which is why I created this new one)
+    
+    if (DEBUG_NATURAL_AC_CALCULATION || DEBUG)
+    {
+        DoDebug("_prc_inc_CreatureNaturalAC: total ac: " + IntToString(GetAC(oTemplate)));
+        DoDebug("_prc_inc_CreatureNaturalAC: base ac: " + IntToString(10));
+        DoDebug("_prc_inc_CreatureNaturalAC: armor base ac: " + IntToString(ac_info.nArmorBase));
+        DoDebug("_prc_inc_CreatureNaturalAC: armor bonus ac: " + IntToString(ac_info.nArmorBonus));
+        DoDebug("_prc_inc_CreatureNaturalAC: shield base ac: " + IntToString(ac_info.nShieldBase));
+        DoDebug("_prc_inc_CreatureNaturalAC: shield bonus ac: " + IntToString(ac_info.nShieldBonus));
+        DoDebug("_prc_inc_CreatureNaturalAC: dodge bonus ac: " + IntToString(ac_info.nDodgeBonus));
+        DoDebug("_prc_inc_CreatureNaturalAC: natural bonus ac: " + IntToString(ac_info.nNaturalBonus));
+        DoDebug("_prc_inc_CreatureNaturalAC: deflection bonus ac: " + IntToString(ac_info.nDeflectionBonus));
+        DoDebug("_prc_inc_CreatureNaturalAC: dex ac: " + IntToString(ac_info.nDEXBonus));
+        DoDebug("_prc_inc_CreatureNaturalAC: calculated natural ac: " + IntToString(nNaturalAC));
+    }
+        
+    //TODO: combat debugging shows actual natural AC (as well as other type); compare with that to debug.
+    
+    return nNaturalAC;
+}
+
+int _prc_inc_GetFeatDeathAttackLevel(int nFeat)
+{
+    switch(nFeat)
+    {
+        case FEAT_PRESTIGE_DEATH_ATTACK_1: return 1;
+        case FEAT_PRESTIGE_DEATH_ATTACK_2: return 2;
+        case FEAT_PRESTIGE_DEATH_ATTACK_3: return 3;
+        case FEAT_PRESTIGE_DEATH_ATTACK_4: return 4;
+        case FEAT_PRESTIGE_DEATH_ATTACK_5: return 5;
+        case FEAT_PRESTIGE_DEATH_ATTACK_6: return 6;
+        case FEAT_PRESTIGE_DEATH_ATTACK_7: return 7;
+        case FEAT_PRESTIGE_DEATH_ATTACK_8: return 8;
+        case FEAT_PRESTIGE_DEATH_ATTACK_9: return 9;
+        case FEAT_PRESTIGE_DEATH_ATTACK_10: return 10;
+        case FEAT_PRESTIGE_DEATH_ATTACK_11: return 11;
+        case FEAT_PRESTIGE_DEATH_ATTACK_12: return 12;
+        case FEAT_PRESTIGE_DEATH_ATTACK_13: return 13;
+        case FEAT_PRESTIGE_DEATH_ATTACK_14: return 14;
+        case FEAT_PRESTIGE_DEATH_ATTACK_15: return 15;
+        case FEAT_PRESTIGE_DEATH_ATTACK_16: return 16;
+        case FEAT_PRESTIGE_DEATH_ATTACK_17: return 17;
+        case FEAT_PRESTIGE_DEATH_ATTACK_18: return 18;
+        case FEAT_PRESTIGE_DEATH_ATTACK_19: return 19;
+        case FEAT_PRESTIGE_DEATH_ATTACK_20: return 20;
+    }
+    return 0;
+}
+
+int _prc_inc_GetHasFeat(object oTemplate, int nFeat)
+{
+    //If oTemplate has the feat FEAT_SNEAK_ATTACK_10, GetHasFeat() always says
+    //it has FEAT_PRESTIGE_DEATH_ATTACK_1 through FEAT_PRESTIGE_DEATH_ATTACK_20,
+    //whether it actually does or not. Work around this as follows:
+    int nSuppress=0;
+    int FEAT_SNEAK_ATTACK_10 = 353;    
+    if(GetHasFeat(FEAT_SNEAK_ATTACK_10, oTemplate))
+    {
+        int nFeatDeathAttackLevel = _prc_inc_GetFeatDeathAttackLevel(nFeat);
+        if(nFeatDeathAttackLevel)
+        {
+            int nActualDeathAttackLevel = 0;
+            nActualDeathAttackLevel += (GetLevelByClass(CLASS_TYPE_ASSASSIN, oTemplate) + 1) / 2;
+            //TODO: Add other classes here? OR use GetTotalSneakAttackDice(), etc. from prc_inc_sneak instead?
+            if(nFeatDeathAttackLevel > nActualDeathAttackLevel)
+                nSuppress = 1;
+        }
+    }
+
+    return GetHasFeat(nFeat, oTemplate) && !nSuppress;
+}
+
+int _prc_inc_shifting_GetIsCreatureHarmless(object oTemplate)
+{
+    return GetChallengeRating(oTemplate) < 1.0;
+}
+
+int _prc_inc_shifting_CharacterLevelRequirement(object oTemplate)
+{
+    return GetPRCSwitch(PNP_SHFT_USECR) ? FloatToInt(GetChallengeRating(oTemplate)) : GetHitDice(oTemplate);
+}
+
+int _prc_inc_shifting_ShifterLevelRequirement(object oTemplate)
+{
+    int nRacialType = MyPRCGetRacialType(oTemplate);
+    int nSize = PRCGetCreatureSize(oTemplate);
+    int nLevelRequired = 0;
+
+    // Size tests
+    if(nSize >= CREATURE_SIZE_HUGE)
+        nLevelRequired = max(nLevelRequired, 7);
+    if(nSize == CREATURE_SIZE_LARGE)
+        nLevelRequired = max(nLevelRequired, 3);
+    if(nSize == CREATURE_SIZE_MEDIUM)
+        nLevelRequired = max(nLevelRequired, 1);
+    if(nSize == CREATURE_SIZE_SMALL)
+        nLevelRequired = max(nLevelRequired, 1);
+    if(nSize <= CREATURE_SIZE_TINY)
+        nLevelRequired = max(nLevelRequired, 3);
+
+    // Type tests
+    if(nRacialType == RACIAL_TYPE_OUTSIDER)
+        nLevelRequired = max(nLevelRequired, 9);
+    if(nRacialType == RACIAL_TYPE_ELEMENTAL)
+        nLevelRequired = max(nLevelRequired, 9);
+    if(nRacialType == RACIAL_TYPE_CONSTRUCT)
+        nLevelRequired = max(nLevelRequired, 8);
+    if(nRacialType == RACIAL_TYPE_UNDEAD)
+        nLevelRequired = max(nLevelRequired, 8);
+    if(nRacialType == RACIAL_TYPE_DRAGON)
+        nLevelRequired = max(nLevelRequired, 7);
+    if(nRacialType == RACIAL_TYPE_ABERRATION)
+        nLevelRequired = max(nLevelRequired, 6);
+    if(nRacialType == RACIAL_TYPE_OOZE)
+        nLevelRequired = max(nLevelRequired, 6);
+    if(nRacialType == RACIAL_TYPE_MAGICAL_BEAST)
+        nLevelRequired = max(nLevelRequired, 5);
+    if(nRacialType == RACIAL_TYPE_GIANT)
+        nLevelRequired = max(nLevelRequired, 4);
+    if(nRacialType == RACIAL_TYPE_VERMIN)
+        nLevelRequired = max(nLevelRequired, 4);
+    if(nRacialType == RACIAL_TYPE_BEAST)
+        nLevelRequired = max(nLevelRequired, 3);
+    if(nRacialType == RACIAL_TYPE_ANIMAL)
+        nLevelRequired = max(nLevelRequired, 2);
+    if(nRacialType == RACIAL_TYPE_HUMANOID_MONSTROUS)
+        nLevelRequired = max(nLevelRequired, 2);
+    if(nRacialType == RACIAL_TYPE_DWARF              ||
+       nRacialType == RACIAL_TYPE_ELF                ||
+       nRacialType == RACIAL_TYPE_GNOME              ||
+       nRacialType == RACIAL_TYPE_HUMAN              ||
+       nRacialType == RACIAL_TYPE_HALFORC            ||
+       nRacialType == RACIAL_TYPE_HALFELF            ||
+       nRacialType == RACIAL_TYPE_HALFLING           ||
+       nRacialType == RACIAL_TYPE_HUMANOID_ORC       ||
+       nRacialType == RACIAL_TYPE_HUMANOID_REPTILIAN
+       )
+        nLevelRequired = max(nLevelRequired, 1);
+        
+    return nLevelRequired;
+}
+
+int _prc_inc_shifting_GetCanFormCast(object oTemplate)
+{
+    int nRacialType = MyPRCGetRacialType(oTemplate);
+
+    // Need to have hands, and the ability to speak
+
+    switch (nRacialType)
+    {
+        case RACIAL_TYPE_ABERRATION:
+        case RACIAL_TYPE_ANIMAL:
+        case RACIAL_TYPE_BEAST:
+        case RACIAL_TYPE_MAGICAL_BEAST:
+        case RACIAL_TYPE_VERMIN:
+        case RACIAL_TYPE_OOZE:
+//        case RACIAL_TYPE_PLANT:
+            // These forms can't cast spells
+            return FALSE;
+        case RACIAL_TYPE_DWARF:
+        case RACIAL_TYPE_ELF:
+        case RACIAL_TYPE_GNOME:
+        case RACIAL_TYPE_HALFLING:
+        case RACIAL_TYPE_HALFELF:
+        case RACIAL_TYPE_HALFORC:
+        case RACIAL_TYPE_HUMAN:
+        case RACIAL_TYPE_CONSTRUCT:
+        case RACIAL_TYPE_DRAGON:
+        case RACIAL_TYPE_HUMANOID_GOBLINOID:
+        case RACIAL_TYPE_HUMANOID_MONSTROUS:
+        case RACIAL_TYPE_HUMANOID_ORC:
+        case RACIAL_TYPE_HUMANOID_REPTILIAN:
+        case RACIAL_TYPE_ELEMENTAL:
+        case RACIAL_TYPE_FEY:
+        case RACIAL_TYPE_GIANT:
+        case RACIAL_TYPE_OUTSIDER:
+        case RACIAL_TYPE_SHAPECHANGER:
+        case RACIAL_TYPE_UNDEAD:
+            // Break and go return TRUE at the end of the function
+            break;
+
+        default:{
+            if(DEBUG) DoDebug("prc_inc_shifting: _GetCanFormCast(): Unknown racial type: " + IntToString(nRacialType));
+        }
+    }
+
+    return TRUE;
+}
+
+string _prc_inc_AbilityTypeString(int nAbilityType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_abilities", "Name", nAbilityType)));
+}
+
+string _prc_inc_AlignmentGroupString(int nAlignmentGroup)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_aligngrp", "Name", nAlignmentGroup)));
+}
+
+string _prc_inc_BonusFeatTypeString(int nBonusFeatType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_feats", "Name", nBonusFeatType)));
+}
+
+string _prc_inc_ClassTypeString(int nClassType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("classes", "Name", nClassType)));
+}
+
+string _prc_inc_CostTableEntryString(int nCostTable, int nCostTableValue)
+{
+    string sCostTableName = Get2DACache("iprp_costtable", "Name", nCostTable);
+    if(sCostTableName == "" || sCostTableName == "****")
+        return "??? (" + IntToString(nCostTable) + " / " + IntToString(nCostTableValue) + ")";
+    string sCostTableEntry = Get2DACache(sCostTableName, "Name", nCostTableValue);
+    if(sCostTableEntry == "" || sCostTableEntry == "****")
+        return "??? (" + sCostTableName + " / " + IntToString(nCostTableValue) + ")";
+    return GetStringByStrRef(StringToInt(sCostTableEntry));
+}
+
+string _prc_inc_DamageTypeString(int nDamageType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_damagetype", "Name", nDamageType)));
+}
+
+string _prc_inc_ImmunityTypeString(int nImmunityType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_immunity", "Name", nImmunityType)));
+}
+
+string _prc_inc_OnHitSpellTypeString(int nOnHitSpellType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_onhitspell", "Name", nOnHitSpellType)));
+}
+
+string _prc_inc_OnHitTypeString(int nOnHitSpellType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_onhit", "Name", nOnHitSpellType)));
+}
+
+string _prc_inc_OnMonsterHitTypeString(int nOnMonsterHitType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_monsterhit", "Name", nOnMonsterHitType)));
+}
+
+string _prc_inc_SavingThrowElementTypeString(int nSavingThrowType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_saveelement", "Name", nSavingThrowType)));
+}
+
+string _prc_inc_SavingThrowTypeString(int nSavingThrowType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_savingthrow", "Name", nSavingThrowType)));
+}
+
+string _prc_inc_SkillTypeString(int nSkillType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("skills", "Name", nSkillType)));
+}
+
+string _prc_inc_SpecialWalkTypeString(int nWalkType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_walk", "Name", nWalkType)));
+}
+
+string _prc_inc_SpellSchoolTypeString(int nSpellSchoolType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_spellshl", "Name", nSpellSchoolType)));
+}
+
+string _prc_inc_SpellTypeString(int nOnHitSpellType)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("iprp_spells", "Name", nOnHitSpellType)));
+}
+
+string _prc_inc_VisualEffectString(int nVisualEffect)
+{
+    //TODO: Look up in 2da (which one?)
+    switch(nVisualEffect)
+    {
+        case ITEM_VISUAL_ACID:
+            return "Acid";
+        case ITEM_VISUAL_COLD:
+            return "Cold";
+        case ITEM_VISUAL_ELECTRICAL:
+            return "Electrical";
+        case ITEM_VISUAL_FIRE:
+            return "Fire";
+        case ITEM_VISUAL_SONIC:
+            return "Sonic";
+        case ITEM_VISUAL_HOLY:
+            return "Holy";
+        case ITEM_VISUAL_EVIL:
+            return "Evil";
+    }
+    return "???";
+}
+
+string _prc_inc_ItemPropertyString(itemproperty iprop)
+{
+    int nType = GetItemPropertyType(iprop);
+    int nSubType = GetItemPropertySubType(iprop);
+    int nDurationType = GetItemPropertyDurationType(iprop);
+    int nParam1 = GetItemPropertyParam1(iprop);
+    int nParam1Value = GetItemPropertyParam1Value(iprop);
+    int nCostTable = GetItemPropertyCostTable(iprop);
+    int nCostTableValue = GetItemPropertyCostTableValue(iprop);
+    string sType = IntToString(nType);
+    string sSubType = IntToString(nSubType);
+    string sDurationType = IntToString(nDurationType);
+    string sParam1 = IntToString(nParam1);
+    string sParam1Value = IntToString(nParam1Value);
+    string sCostTable = IntToString(nCostTable);
+    string sCostTableValue = IntToString(nCostTableValue);
+    string sResult = 
+        "Typ: " + sType + "; " 
+        + "SubTyp: " + sSubType + "; "
+        + "DurTyp: " + sDurationType + "; "
+        + "Parm: " + sParam1 + "; "
+        + "ParmVal: " + sParam1Value + "; "
+        + "CTab: " + sCostTable + "; "
+        + "CVal: " + sCostTableValue;
+    string sTypeName = GetStringByStrRef(StringToInt(Get2DACache("itempropdef", "Name", nType)));
+    switch (nType)
+    {
+        //TODO: these are all the possible cases; need to handle more of them.
+        //DONE case ITEM_PROPERTY_ABILITY_BONUS:
+        //DONE case ITEM_PROPERTY_AC_BONUS:
+        // case ITEM_PROPERTY_AC_BONUS_VS_ALIGNMENT_GROUP:
+        // case ITEM_PROPERTY_AC_BONUS_VS_DAMAGE_TYPE:
+        // case ITEM_PROPERTY_AC_BONUS_VS_RACIAL_GROUP:
+        // case ITEM_PROPERTY_AC_BONUS_VS_SPECIFIC_ALIGNMENT:
+        //DONE case ITEM_PROPERTY_ENHANCEMENT_BONUS:
+        //DONE case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP:
+        // case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_RACIAL_GROUP:
+        // case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_SPECIFIC_ALIGNEMENT: 
+        // case ITEM_PROPERTY_DECREASED_ENHANCEMENT_MODIFIER
+        //DONE case ITEM_PROPERTY_BASE_ITEM_WEIGHT_REDUCTION
+        //DONE case ITEM_PROPERTY_BONUS_FEAT:
+        // case ITEM_PROPERTY_BONUS_SPELL_SLOT_OF_LEVEL_N:
+        //DONE case ITEM_PROPERTY_CAST_SPELL:
+        //DONE case ITEM_PROPERTY_DAMAGE_BONUS:
+        //DONE case ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP:
+        //case ITEM_PROPERTY_DAMAGE_BONUS_VS_RACIAL_GROUP:
+        //case ITEM_PROPERTY_DAMAGE_BONUS_VS_SPECIFIC_ALIGNMENT:
+        //DONE case ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE:
+        // case ITEM_PROPERTY_DECREASED_DAMAGE:
+        //DONE case ITEM_PROPERTY_DAMAGE_REDUCTION:
+        //DONE case ITEM_PROPERTY_DAMAGE_RESISTANCE:
+        //DONE case ITEM_PROPERTY_DAMAGE_VULNERABILITY:
+        //DONE case ITEM_PROPERTY_DARKVISION:
+        //DONE case ITEM_PROPERTY_DECREASED_ABILITY_SCORE:
+        // case ITEM_PROPERTY_DECREASED_AC:
+        // case ITEM_PROPERTY_DECREASED_SKILL_MODIFIER: //TODO: e.g. S1-Tomb of Horrors: DesertDragon
+        // case ITEM_PROPERTY_ENHANCED_CONTAINER_REDUCED_WEIGHT:
+        //DONE case ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE:
+        // case ITEM_PROPERTY_EXTRA_RANGED_DAMAGE_TYPE:
+        //DONE case ITEM_PROPERTY_HASTE:
+        // case ITEM_PROPERTY_HOLY_AVENGER:
+        //DONE case ITEM_PROPERTY_IMMUNITY_MISCELLANEOUS:
+        //DONE case ITEM_PROPERTY_IMPROVED_EVASION:
+        //DONE case ITEM_PROPERTY_SPELL_RESISTANCE:
+        //DONE case ITEM_PROPERTY_SAVING_THROW_BONUS:
+        //DONE case ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC:
+        //DONE case ITEM_PROPERTY_KEEN:
+        //DONE case ITEM_PROPERTY_LIGHT:
+        // case ITEM_PROPERTY_MIGHTY:
+        // case ITEM_PROPERTY_MIND_BLANK:
+        // case ITEM_PROPERTY_NO_DAMAGE:
+        //DONE case ITEM_PROPERTY_ON_HIT_PROPERTIES:
+        //DONE case ITEM_PROPERTY_DECREASED_SAVING_THROWS:
+        //DONE case ITEM_PROPERTY_DECREASED_SAVING_THROWS_SPECIFIC:
+        //DONE case ITEM_PROPERTY_REGENERATION:
+        //DONE case ITEM_PROPERTY_SKILL_BONUS:
+        //DONE case ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL:
+        //DONE case ITEM_PROPERTY_IMMUNITY_SPELL_SCHOOL:
+        // case ITEM_PROPERTY_THIEVES_TOOLS:
+        //DONE case ITEM_PROPERTY_ATTACK_BONUS:
+        //DONE case ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP:
+        // case ITEM_PROPERTY_ATTACK_BONUS_VS_RACIAL_GROUP:
+        // case ITEM_PROPERTY_ATTACK_BONUS_VS_SPECIFIC_ALIGNMENT:
+        // case ITEM_PROPERTY_DECREASED_ATTACK_MODIFIER:
+        // case ITEM_PROPERTY_UNLIMITED_AMMUNITION:
+        // case ITEM_PROPERTY_USE_LIMITATION_ALIGNMENT_GROUP:
+        // case ITEM_PROPERTY_USE_LIMITATION_CLASS:
+        // case ITEM_PROPERTY_USE_LIMITATION_RACIAL_TYPE:
+        // case ITEM_PROPERTY_USE_LIMITATION_SPECIFIC_ALIGNMENT:
+        // case ITEM_PROPERTY_USE_LIMITATION_TILESET:
+        //DONE case ITEM_PROPERTY_REGENERATION_VAMPIRIC:
+        // case ITEM_PROPERTY_TRAP:
+        //DONE case ITEM_PROPERTY_TRUE_SEEING:
+        //DONE case ITEM_PROPERTY_ON_MONSTER_HIT:
+        //DONE case ITEM_PROPERTY_TURN_RESISTANCE:
+        //DONE case ITEM_PROPERTY_MASSIVE_CRITICALS:
+        //DONE case ITEM_PROPERTY_FREEDOM_OF_MOVEMENT:
+        //DONE case ITEM_PROPERTY_MONSTER_DAMAGE:
+        //DONE case ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL:
+        //DONE case ITEM_PROPERTY_SPECIAL_WALK:
+        // case ITEM_PROPERTY_HEALERS_KIT:
+        // case ITEM_PROPERTY_WEIGHT_INCREASE:
+        //DONE case ITEM_PROPERTY_ONHITCASTSPELL:
+        //DONE case ITEM_PROPERTY_VISUALEFFECT:
+        // case ITEM_PROPERTY_ARCANE_SPELL_FAILURE:
+        
+        //Completely ignore
+        case ITEM_PROPERTY_BASE_ITEM_WEIGHT_REDUCTION:
+            return "";
+
+        //Property name only
+        case ITEM_PROPERTY_DARKVISION:
+        case ITEM_PROPERTY_FREEDOM_OF_MOVEMENT:
+        case ITEM_PROPERTY_HASTE:
+        case ITEM_PROPERTY_IMPROVED_EVASION:
+        case ITEM_PROPERTY_KEEN:
+        case ITEM_PROPERTY_TRUE_SEEING:
+            return sTypeName;
+
+        //Interpret cost table information
+        case ITEM_PROPERTY_AC_BONUS:
+        case ITEM_PROPERTY_ATTACK_BONUS:
+        case ITEM_PROPERTY_ENHANCEMENT_BONUS:
+        case ITEM_PROPERTY_IMMUNITY_SPECIFIC_SPELL:
+        case ITEM_PROPERTY_IMMUNITY_SPELLS_BY_LEVEL:
+        case ITEM_PROPERTY_LIGHT:
+        case ITEM_PROPERTY_MASSIVE_CRITICALS:
+        case ITEM_PROPERTY_MONSTER_DAMAGE:
+        case ITEM_PROPERTY_REGENERATION:
+        case ITEM_PROPERTY_SPELL_RESISTANCE:
+        case ITEM_PROPERTY_TURN_RESISTANCE:
+            return sTypeName + ": " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+        
+        //Interpret cost table information; interpret subtype as damage type
+        case ITEM_PROPERTY_DAMAGE_BONUS:
+        case ITEM_PROPERTY_DAMAGE_RESISTANCE:
+        case ITEM_PROPERTY_DAMAGE_VULNERABILITY:
+        case ITEM_PROPERTY_IMMUNITY_DAMAGE_TYPE:
+            return sTypeName + ": " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue) + " " + _prc_inc_DamageTypeString(nSubType);
+
+        //Interpret cost table information; interpret subtype as racial group
+        case ITEM_PROPERTY_ATTACK_BONUS_VS_ALIGNMENT_GROUP:
+        case ITEM_PROPERTY_ENHANCEMENT_BONUS_VS_ALIGNMENT_GROUP:
+            return sTypeName + ": " + _prc_inc_AlignmentGroupString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+
+        //Special handling
+        case ITEM_PROPERTY_ABILITY_BONUS:
+        case ITEM_PROPERTY_DECREASED_ABILITY_SCORE:
+            return sTypeName + ": " + _prc_inc_AbilityTypeString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+        case ITEM_PROPERTY_BONUS_FEAT:
+            return sTypeName + ": " + _prc_inc_BonusFeatTypeString(nSubType);
+        case ITEM_PROPERTY_CAST_SPELL:
+            return sTypeName + ": " + _prc_inc_SpellTypeString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+        case ITEM_PROPERTY_DAMAGE_BONUS_VS_ALIGNMENT_GROUP:
+            return sTypeName + ": " + _prc_inc_AlignmentGroupString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue) + " " + _prc_inc_DamageTypeString(nParam1Value);
+        case ITEM_PROPERTY_DAMAGE_REDUCTION:
+            return sTypeName + ": " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue) + " / " + IntToString(StringToInt(sSubType)+1);
+        case ITEM_PROPERTY_EXTRA_MELEE_DAMAGE_TYPE:
+        case ITEM_PROPERTY_EXTRA_RANGED_DAMAGE_TYPE:
+            return sTypeName + ": " + _prc_inc_DamageTypeString(nSubType);
+        case ITEM_PROPERTY_IMMUNITY_MISCELLANEOUS:
+            return sTypeName + ": " + _prc_inc_ImmunityTypeString(nSubType);
+        case ITEM_PROPERTY_IMMUNITY_SPELL_SCHOOL:
+            return sTypeName + ": " + _prc_inc_SpellSchoolTypeString(nSubType);
+        case ITEM_PROPERTY_ON_HIT_PROPERTIES:
+            return sTypeName + ": " + _prc_inc_OnHitTypeString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+        case ITEM_PROPERTY_ONHITCASTSPELL:
+            return sTypeName + ": " + _prc_inc_OnHitSpellTypeString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+        case ITEM_PROPERTY_ON_MONSTER_HIT:
+            return sTypeName + ": " + _prc_inc_OnMonsterHitTypeString(nSubType) + " " + IntToString(nCostTableValue+1);
+        case ITEM_PROPERTY_SKILL_BONUS:
+            return sTypeName + ": " + _prc_inc_SkillTypeString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+        case ITEM_PROPERTY_SPECIAL_WALK:
+            return sTypeName + ": " + _prc_inc_SpecialWalkTypeString(nSubType);            
+        case ITEM_PROPERTY_REGENERATION_VAMPIRIC:
+            return sTypeName + ": " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+        case ITEM_PROPERTY_VISUALEFFECT:
+            return sTypeName + ": " + _prc_inc_VisualEffectString(nSubType);
+
+        case ITEM_PROPERTY_DECREASED_SAVING_THROWS_SPECIFIC:
+        case ITEM_PROPERTY_SAVING_THROW_BONUS_SPECIFIC:
+            return sTypeName + ": " + _prc_inc_SavingThrowTypeString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+
+        case ITEM_PROPERTY_DECREASED_SAVING_THROWS:
+        case ITEM_PROPERTY_SAVING_THROW_BONUS:
+            return sTypeName + ": " + _prc_inc_SavingThrowElementTypeString(nSubType) + " " + _prc_inc_CostTableEntryString(nCostTable, nCostTableValue);
+    }
+    return sTypeName + " (" + sResult + ")";
+}
+
+string _prc_inc_EffectString(effect eEffect)
+{
+    int nType = GetEffectType(eEffect);
+    int nSubType = GetEffectSubType(eEffect);
+    int nDurationType = GetEffectDurationType(eEffect);
+    int nSpellId = GetEffectSpellId(eEffect);
+    string sType = IntToString(nType);
+    string sSubType = IntToString(nSubType);
+    string sDurationType = IntToString(nDurationType);
+    string sSpellId = IntToString(nSpellId);
+
+    //Decode type if possible
+    //TODO: look up in 2da (which one?) instead of having a big switch statement
+    switch (nType)
+    {
+        case EFFECT_TYPE_INVALIDEFFECT               : sType = "EFFECT_TYPE_INVALIDEFFECT"; break;
+        case EFFECT_TYPE_DAMAGE_RESISTANCE           : sType = "EFFECT_TYPE_DAMAGE_RESISTANCE"; break;
+        //case EFFECT_TYPE_ABILITY_BONUS             : sType = "EFFECT_TYPE_ABILITY_BONUS"; break;
+        case EFFECT_TYPE_REGENERATE                  : sType = "EFFECT_TYPE_REGENERATE"; break;
+        //case EFFECT_TYPE_SAVING_THROW_BONUS        : sType = "EFFECT_TYPE_SAVING_THROW_BONUS"; break;
+        //case EFFECT_TYPE_MODIFY_AC                 : sType = "EFFECT_TYPE_MODIFY_AC"; break;
+        //case EFFECT_TYPE_ATTACK_BONUS              : sType = "EFFECT_TYPE_ATTACK_BONUS"; break;
+        case EFFECT_TYPE_DAMAGE_REDUCTION            : sType = "EFFECT_TYPE_DAMAGE_REDUCTION"; break;
+        //case EFFECT_TYPE_DAMAGE_BONUS              : sType = "EFFECT_TYPE_DAMAGE_BONUS"; break;
+        case EFFECT_TYPE_TEMPORARY_HITPOINTS         : sType = "EFFECT_TYPE_TEMPORARY_HITPOINTS"; break;
+        //case EFFECT_TYPE_DAMAGE_IMMUNITY           : sType = "EFFECT_TYPE_DAMAGE_IMMUNITY"; break;
+        case EFFECT_TYPE_ENTANGLE                    : sType = "EFFECT_TYPE_ENTANGLE"; break;
+        case EFFECT_TYPE_INVULNERABLE                : sType = "EFFECT_TYPE_INVULNERABLE"; break;
+        case EFFECT_TYPE_DEAF                        : sType = "EFFECT_TYPE_DEAF"; break;
+        case EFFECT_TYPE_RESURRECTION                : sType = "EFFECT_TYPE_RESURRECTION"; break;
+        case EFFECT_TYPE_IMMUNITY                    : sType = "EFFECT_TYPE_IMMUNITY"; break;
+        //case EFFECT_TYPE_BLIND                     : sType = "EFFECT_TYPE_BLIND"; break;
+        case EFFECT_TYPE_ENEMY_ATTACK_BONUS          : sType = "EFFECT_TYPE_ENEMY_ATTACK_BONUS"; break;
+        case EFFECT_TYPE_ARCANE_SPELL_FAILURE        : sType = "EFFECT_TYPE_ARCANE_SPELL_FAILURE"; break;
+        //case EFFECT_TYPE_MOVEMENT_SPEED            : sType = "EFFECT_TYPE_MOVEMENT_SPEED"; break;
+        case EFFECT_TYPE_AREA_OF_EFFECT              : sType = "EFFECT_TYPE_AREA_OF_EFFECT"; break;
+        case EFFECT_TYPE_BEAM                        : sType = "EFFECT_TYPE_BEAM"; break;
+        //case EFFECT_TYPE_SPELL_RESISTANCE          : sType = "EFFECT_TYPE_SPELL_RESISTANCE"; break;
+        case EFFECT_TYPE_CHARMED                     : sType = "EFFECT_TYPE_CHARMED"; break;
+        case EFFECT_TYPE_CONFUSED                    : sType = "EFFECT_TYPE_CONFUSED"; break;
+        case EFFECT_TYPE_FRIGHTENED                  : sType = "EFFECT_TYPE_FRIGHTENED"; break;
+        case EFFECT_TYPE_DOMINATED                   : sType = "EFFECT_TYPE_DOMINATED"; break;
+        case EFFECT_TYPE_PARALYZE                    : sType = "EFFECT_TYPE_PARALYZE"; break;
+        case EFFECT_TYPE_DAZED                       : sType = "EFFECT_TYPE_DAZED"; break;
+        case EFFECT_TYPE_STUNNED                     : sType = "EFFECT_TYPE_STUNNED"; break;
+        case EFFECT_TYPE_SLEEP                       : sType = "EFFECT_TYPE_SLEEP"; break;
+        case EFFECT_TYPE_POISON                      : sType = "EFFECT_TYPE_POISON"; break;
+        case EFFECT_TYPE_DISEASE                     : sType = "EFFECT_TYPE_DISEASE"; break;
+        case EFFECT_TYPE_CURSE                       : sType = "EFFECT_TYPE_CURSE"; break;
+        case EFFECT_TYPE_SILENCE                     : sType = "EFFECT_TYPE_SILENCE"; break;
+        case EFFECT_TYPE_TURNED                      : sType = "EFFECT_TYPE_TURNED"; break;
+        case EFFECT_TYPE_HASTE                       : sType = "EFFECT_TYPE_HASTE"; break;
+        case EFFECT_TYPE_SLOW                        : sType = "EFFECT_TYPE_SLOW"; break;
+        case EFFECT_TYPE_ABILITY_INCREASE            : sType = "EFFECT_TYPE_ABILITY_INCREASE"; break;
+        case EFFECT_TYPE_ABILITY_DECREASE            : sType = "EFFECT_TYPE_ABILITY_DECREASE"; break;
+        case EFFECT_TYPE_ATTACK_INCREASE             : sType = "EFFECT_TYPE_ATTACK_INCREASE"; break;
+        case EFFECT_TYPE_ATTACK_DECREASE             : sType = "EFFECT_TYPE_ATTACK_DECREASE"; break;
+        case EFFECT_TYPE_DAMAGE_INCREASE             : sType = "EFFECT_TYPE_DAMAGE_INCREASE"; break;
+        case EFFECT_TYPE_DAMAGE_DECREASE             : sType = "EFFECT_TYPE_DAMAGE_DECREASE"; break;
+        case EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE    : sType = "EFFECT_TYPE_DAMAGE_IMMUNITY_INCREASE"; break;
+        case EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE    : sType = "EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE"; break;
+        case EFFECT_TYPE_AC_INCREASE                 : sType = "EFFECT_TYPE_AC_INCREASE"; break;
+        case EFFECT_TYPE_AC_DECREASE                 : sType = "EFFECT_TYPE_AC_DECREASE"; break;
+        case EFFECT_TYPE_MOVEMENT_SPEED_INCREASE     : sType = "EFFECT_TYPE_MOVEMENT_SPEED_INCREASE"; break;
+        case EFFECT_TYPE_MOVEMENT_SPEED_DECREASE     : sType = "EFFECT_TYPE_MOVEMENT_SPEED_DECREASE"; break;
+        case EFFECT_TYPE_SAVING_THROW_INCREASE       : sType = "EFFECT_TYPE_SAVING_THROW_INCREASE"; break;
+        case EFFECT_TYPE_SAVING_THROW_DECREASE       : sType = "EFFECT_TYPE_SAVING_THROW_DECREASE"; break;
+        case EFFECT_TYPE_SPELL_RESISTANCE_INCREASE   : sType = "EFFECT_TYPE_SPELL_RESISTANCE_INCREASE"; break;
+        case EFFECT_TYPE_SPELL_RESISTANCE_DECREASE   : sType = "EFFECT_TYPE_SPELL_RESISTANCE_DECREASE"; break;
+        case EFFECT_TYPE_SKILL_INCREASE              : sType = "EFFECT_TYPE_SKILL_INCREASE"; break;
+        case EFFECT_TYPE_SKILL_DECREASE              : sType = "EFFECT_TYPE_SKILL_DECREASE"; break;
+        case EFFECT_TYPE_INVISIBILITY                : sType = "EFFECT_TYPE_INVISIBILITY"; break;
+        case EFFECT_TYPE_IMPROVEDINVISIBILITY        : sType = "EFFECT_TYPE_IMPROVEDINVISIBILITY"; break;
+        case EFFECT_TYPE_DARKNESS                    : sType = "EFFECT_TYPE_DARKNESS"; break;
+        case EFFECT_TYPE_DISPELMAGICALL              : sType = "EFFECT_TYPE_DISPELMAGICALL"; break;
+        case EFFECT_TYPE_ELEMENTALSHIELD             : sType = "EFFECT_TYPE_ELEMENTALSHIELD"; break;
+        case EFFECT_TYPE_NEGATIVELEVEL               : sType = "EFFECT_TYPE_NEGATIVELEVEL"; break;
+        case EFFECT_TYPE_POLYMORPH                   : sType = "EFFECT_TYPE_POLYMORPH"; break;
+        case EFFECT_TYPE_SANCTUARY                   : sType = "EFFECT_TYPE_SANCTUARY"; break;
+        case EFFECT_TYPE_TRUESEEING                  : sType = "EFFECT_TYPE_TRUESEEING"; break;
+        case EFFECT_TYPE_SEEINVISIBLE                : sType = "EFFECT_TYPE_SEEINVISIBLE"; break;
+        case EFFECT_TYPE_TIMESTOP                    : sType = "EFFECT_TYPE_TIMESTOP"; break;
+        case EFFECT_TYPE_BLINDNESS                   : sType = "EFFECT_TYPE_BLINDNESS"; break;
+        case EFFECT_TYPE_SPELLLEVELABSORPTION        : sType = "EFFECT_TYPE_SPELLLEVELABSORPTION"; break;
+        case EFFECT_TYPE_DISPELMAGICBEST             : sType = "EFFECT_TYPE_DISPELMAGICBEST"; break;
+        case EFFECT_TYPE_ULTRAVISION                 : sType = "EFFECT_TYPE_ULTRAVISION"; break;
+        case EFFECT_TYPE_MISS_CHANCE                 : sType = "EFFECT_TYPE_MISS_CHANCE"; break;
+        case EFFECT_TYPE_CONCEALMENT                 : sType = "EFFECT_TYPE_CONCEALMENT"; break;
+        case EFFECT_TYPE_SPELL_IMMUNITY              : sType = "EFFECT_TYPE_SPELL_IMMUNITY"; break;
+        case EFFECT_TYPE_VISUALEFFECT                : sType = "EFFECT_TYPE_VISUALEFFECT"; break;
+        case EFFECT_TYPE_DISAPPEARAPPEAR             : sType = "EFFECT_TYPE_DISAPPEARAPPEAR"; break;
+        case EFFECT_TYPE_SWARM                       : sType = "EFFECT_TYPE_SWARM"; break;
+        case EFFECT_TYPE_TURN_RESISTANCE_DECREASE    : sType = "EFFECT_TYPE_TURN_RESISTANCE_DECREASE"; break;
+        case EFFECT_TYPE_TURN_RESISTANCE_INCREASE    : sType = "EFFECT_TYPE_TURN_RESISTANCE_INCREASE"; break;
+        case EFFECT_TYPE_PETRIFY                     : sType = "EFFECT_TYPE_PETRIFY"; break;
+        case EFFECT_TYPE_CUTSCENE_PARALYZE           : sType = "EFFECT_TYPE_CUTSCENE_PARALYZE"; break;
+        case EFFECT_TYPE_ETHEREAL                    : sType = "EFFECT_TYPE_ETHEREAL"; break;
+        case EFFECT_TYPE_SPELL_FAILURE               : sType = "EFFECT_TYPE_SPELL_FAILURE"; break;
+        case EFFECT_TYPE_CUTSCENEGHOST               : sType = "EFFECT_TYPE_CUTSCENEGHOST"; break;
+        case EFFECT_TYPE_CUTSCENEIMMOBILIZE          : sType = "EFFECT_TYPE_CUTSCENEIMMOBILIZE"; break;
+    }
+
+    //Decode subtype if possible
+    //TODO: look up in 2da (which one?) instead of having a switch statement
+    switch (nSubType)
+    {
+        case SUBTYPE_MAGICAL                         : sSubType = "SUBTYPE_MAGICAL"; break;
+        case SUBTYPE_SUPERNATURAL                    : sSubType = "SUBTYPE_SUPERNATURAL"; break;
+        case SUBTYPE_EXTRAORDINARY                   : sSubType = "SUBTYPE_EXTRAORDINARY"; break;
+    }
+
+    //Decode duration type if possible
+    //TODO: look up in 2da (which one?) instead of having a switch statement
+    switch (nDurationType)
+    {
+        case DURATION_TYPE_INSTANT                   : sDurationType = "DURATION_TYPE_INSTANT"; break;
+        case DURATION_TYPE_TEMPORARY                 : sDurationType = "DURATION_TYPE_TEMPORARY"; break;
+        case DURATION_TYPE_PERMANENT                 : sDurationType = "DURATION_TYPE_PERMANENT"; break;
+    }
+    
+    string sResult = 
+        "EFFECT Type: " + sType + "; " 
+        + "SubType: " + sSubType + "; "
+        + "DurationType: " + sDurationType + "; "
+        + "SpellId: " + sSpellId;
+
+    return sResult;
+}
+
+void _prc_inc_PrintShapeInfo(object oPC, string sMessage)
+{
+    if(!GetLocalInt(oPC, "PRC_SuppressChatPrint"))
+        SendMessageToPC(oPC, sMessage); //Send to chat window in game
+    if(GetLocalInt(oPC, "PRC_EnableLogPrint"))
+        PrintString(sMessage); //Write to log file for reference
+}
+
+void _prc_inc_PrintClassInfo(string sPrefix, object oPC, object oTemplate, int nClassType)
+{
+    if (nClassType != CLASS_TYPE_INVALID)
+    {
+        int nLevel = GetLevelByClass(nClassType, oTemplate);
+        string sClassName = _prc_inc_ClassTypeString(nClassType);
+        _prc_inc_PrintShapeInfo(oPC, sPrefix + sClassName + " (" + IntToString(nLevel) + ")");
+    }
+}
+
+void _prc_inc_PrintItemProperty(string sPrefix, object oPC, itemproperty iProp, int bIncludeTemp = FALSE)
+{
+    int nDurationType = GetItemPropertyDurationType(iProp);
+    if(nDurationType == DURATION_TYPE_PERMANENT || (bIncludeTemp && nDurationType == DURATION_TYPE_TEMPORARY))
+    {
+        string sPropString = _prc_inc_ItemPropertyString(iProp);
+        if(sPropString != "")
+        {
+            if (nDurationType == DURATION_TYPE_TEMPORARY)
+                sPropString = GetStringByStrRef(57473+0x01000000) + sPropString; //"TEMPORARY: "
+            _prc_inc_PrintShapeInfo(oPC, sPrefix + sPropString);
+        }
+    }    
+}
+
+void _prc_inc_PrintAllItemProperties(string sPrefix, object oPC, object oItem, int bIncludeTemp = FALSE)
+{
+    itemproperty iProp = GetFirstItemProperty(oItem);
+    while(GetIsItemPropertyValid(iProp))
+    {
+        _prc_inc_PrintItemProperty(sPrefix, oPC, iProp, bIncludeTemp);
+        iProp = GetNextItemProperty(oItem);
+    }
+}
+
+void _prc_inc_PrintEffect(string sPrefix, object oPC, effect eEffect)
+{
+    if (GetEffectType(eEffect) == EFFECT_TYPE_INVALIDEFFECT)
+    {
+        //An effect with type EFFECT_TYPE_INVALID is added for each item property
+        //They are also added for a couple of other things (Knockdown, summons, etc.)
+        //Just skip these
+    }
+    else
+    {
+        string sEffectString = _prc_inc_EffectString(eEffect);
+        if(sEffectString != "")
+            _prc_inc_PrintShapeInfo(oPC, sPrefix + sEffectString);
+    }    
+}
+
+void _prc_inc_PrintAllEffects(string sPrefix, object oPC, object oItem)
+{
+    effect eEffect = GetFirstEffect(oItem);
+    while(GetIsEffectValid(eEffect))
+    {
+        _prc_inc_PrintEffect(sPrefix, oPC, eEffect);
+        eEffect = GetNextEffect(oItem);
+    }
+}
+
+//NOTE: THIS FUNCTION HAS A LOT OF CODE IN COMMON WITH _prc_inc_shifting_CreateShifterActiveAbilitiesItem
+//TODO: PUT SOME OF IT IN A SHARED FUNCTION THAT THEY BOTH CALL
+void _prc_inc_shifting_PrintShifterActiveAbilities(object oPC, object oTemplate)
+{
+    string sPrefix = GetStringByStrRef(57437+0x01000000); //"Epic Wildshape Spell-Like Abilities:"
+    _prc_inc_PrintShapeInfo(oPC, "=== " + sPrefix);
+    
+    int bPrinted = FALSE;
+
+    object oTemplateHide = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oTemplate);
+    itemproperty iProp = GetFirstItemProperty(oTemplateHide);
+    while(GetIsItemPropertyValid(iProp))
+    {
+        if(GetItemPropertyDurationType(iProp) == DURATION_TYPE_PERMANENT && GetItemPropertyType(iProp) == ITEM_PROPERTY_CAST_SPELL)
+        {
+            _prc_inc_PrintItemProperty("===    ", oPC, iProp);
+            bPrinted = TRUE;
+        }
+        iProp = GetNextItemProperty(oTemplateHide);
+    }
+
+    // Loop over shifter_abilitie.2da
+    string sNumUses;
+    int nSpell, nNumUses, nProps;
+    int i = 0;
+    while(nSpell = StringToInt(Get2DACache("shifter_abilitie", "Spell", i)))
+    {
+        // See if the template has this spell
+        if(GetHasSpell(nSpell, oTemplate))
+        {
+            // Determine the number of uses from the 2da
+            sNumUses = Get2DACache("shifter_abilitie", "IPCSpellNumUses", i);
+            if(sNumUses == "1_USE_PER_DAY")
+                nNumUses = IP_CONST_CASTSPELL_NUMUSES_1_USE_PER_DAY;
+            else if(sNumUses == "2_USES_PER_DAY")
+                nNumUses = IP_CONST_CASTSPELL_NUMUSES_2_USES_PER_DAY;
+            else if(sNumUses == "3_USES_PER_DAY")
+                nNumUses = IP_CONST_CASTSPELL_NUMUSES_3_USES_PER_DAY;
+            else if(sNumUses == "4_USES_PER_DAY")
+                nNumUses = IP_CONST_CASTSPELL_NUMUSES_4_USES_PER_DAY;
+            else if(sNumUses == "5_USES_PER_DAY")
+                nNumUses = IP_CONST_CASTSPELL_NUMUSES_5_USES_PER_DAY;
+            else if(sNumUses == "UNLIMITED_USE")
+                nNumUses = IP_CONST_CASTSPELL_NUMUSES_UNLIMITED_USE;
+            else{
+                if(DEBUG) DoDebug("prc_inc_shifting: _prc_inc_shifting_PrintShifterActiveAbilities(): Unknown IPCSpellNumUses in shifter_abilitie.2da line " + IntToString(i) + ": " + sNumUses);
+                nNumUses = -1;
+            }
+
+            // Create the itemproperty and print it
+            iProp = ItemPropertyCastSpell(StringToInt(Get2DACache("shifter_abilitie", "IPSpell", i)), nNumUses);
+            _prc_inc_PrintItemProperty("===    ", oPC, iProp);
+            bPrinted = TRUE;
+            //TODO: DESTROY iProp?
+
+            // Increment property counter
+            nProps += 1;
+        }
+
+        // Increment loop counter
+        i += 1;
+    }
+    
+    if(!bPrinted)
+        _prc_inc_PrintShapeInfo(oPC, "===   " + GetStringByStrRef(57481+0x01000000)); //"None"
+}
+
+void _prc_inc_shifting_PrintFeats(object oPC, object oTemplate, int nStartIndex, int nLimitIndex)
+{
+    //Loop over shifter_feats.2da
+    string sFeat;
+    int i = nStartIndex;
+    while((i < nLimitIndex) && (sFeat = Get2DACache("shifter_feats", "Feat", i)) != "")
+    {
+        if (_prc_inc_GetHasFeat(oTemplate, StringToInt(sFeat)))
+        {
+            string sFeatName = GetStringByStrRef(StringToInt(Get2DACache("feat", "Feat", StringToInt(sFeat))));
+            _prc_inc_PrintShapeInfo(oPC, "=== " + sFeatName);
+        }
+        i += 1;
+    }
+}
+
+void _prc_inc_PrintNaturalAC(object oPC, object oTemplate)
+{
+    _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(57435+0x01000000) + " " + IntToString(_prc_inc_CreatureNaturalAC(oTemplate))); //Natural AC of form
+}
+
+//TODO: TLK Entries
+void _prc_inc_PrintDebugItem(object oPC, string oItemType, object oItem)
+{
+    if (GetIsObjectValid(oItem))
+    {
+        _prc_inc_PrintShapeInfo(oPC, "====================================");
+        _prc_inc_PrintShapeInfo(oPC, "====== " + oItemType);
+        _prc_inc_PrintShapeInfo(oPC, "======  NAME: " + GetName(oItem));
+        _prc_inc_PrintShapeInfo(oPC, "======  RESREF: " + GetResRef(oItem));
+        _prc_inc_PrintShapeInfo(oPC, "======  ITEM PROPERTIES ======");
+        _prc_inc_PrintAllItemProperties("=== ", oPC, oItem, TRUE);
+        _prc_inc_PrintShapeInfo(oPC, "======  EFFECTS ======");
+        _prc_inc_PrintAllEffects("=== ", oPC, oItem);
+        _prc_inc_PrintShapeInfo(oPC, "======  OTHER ======");
+        if (GetObjectType(oItem) == OBJECT_TYPE_CREATURE)
+        {
+            _prc_inc_PrintClassInfo("=== ", oPC, oItem, GetClassByPosition(1, oItem));
+            _prc_inc_PrintClassInfo("=== ", oPC, oItem, GetClassByPosition(2, oItem));
+            _prc_inc_PrintClassInfo("=== ", oPC, oItem, GetClassByPosition(3, oItem));
+            _prc_inc_PrintClassInfo("=== ", oPC, oItem, GetClassByPosition(4, oItem));
+            _prc_inc_PrintClassInfo("=== ", oPC, oItem, GetClassByPosition(5, oItem));
+            _prc_inc_PrintClassInfo("=== ", oPC, oItem, GetClassByPosition(6, oItem));
+            _prc_inc_PrintClassInfo("=== ", oPC, oItem, GetClassByPosition(7, oItem));
+            _prc_inc_PrintClassInfo("=== ", oPC, oItem, GetClassByPosition(8, oItem));
+			
+            _prc_inc_PrintShapeInfo(oPC, "------");
+
+            _prc_inc_PrintShapeInfo(oPC, "======  Main hand weapon: " + (GetIsWeaponEffective(oItem, FALSE) ? "Effective" : "Ineffective"));
+            _prc_inc_PrintShapeInfo(oPC, "======  Off hand weapon: " + (GetIsWeaponEffective(oItem, TRUE) ? "Effective" : "Ineffective"));
+            _prc_inc_PrintShapeInfo(oPC, "======  Immortal: " + (GetImmortal(oItem) ? "Yes" : "No"));
+            _prc_inc_PrintShapeInfo(oPC, "------");
+                
+            _prc_inc_PrintShapeInfo(oPC, "======  Level: " + IntToString(GetHitDice(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "======  CR: " + FloatToString(GetChallengeRating(oItem), 4, 1));
+            _prc_inc_PrintShapeInfo(oPC, "======  Caster Level: " + IntToString(GetCasterLevel(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "======  XP: " + IntToString(GetXP(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "======  Alignment: " + IntToString(GetLawChaosValue(oItem)) + " / " + IntToString(GetGoodEvilValue(oItem)));
+                //TODO:
+                // int GetAlignmentLawChaos(object oCreature);
+                // int GetAlignmentGoodEvil(object oCreature);
+            _prc_inc_PrintShapeInfo(oPC, "------");
+
+            _prc_inc_PrintShapeInfo(oPC, "======  BAB: " + IntToString(GetBaseAttackBonus(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "======  HP: " + IntToString(GetCurrentHitPoints(oItem)) + " / " + IntToString(GetMaxHitPoints(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "======  AC: " + IntToString(GetAC(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "======  SR: " + IntToString(GetSpellResistance(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "------");
+
+            //TODO: look up names in 2da/TLK?
+            _prc_inc_PrintShapeInfo(oPC, "======  STR: " + IntToString(GetAbilityScore(oItem, ABILITY_STRENGTH)) + " (" + IntToString(GetAbilityModifier(ABILITY_STRENGTH, oItem)) + ")");
+            _prc_inc_PrintShapeInfo(oPC, "======  DEX: " + IntToString(GetAbilityScore(oItem, ABILITY_DEXTERITY)) + " (" + IntToString(GetAbilityModifier(ABILITY_DEXTERITY, oItem)) + ")");
+            _prc_inc_PrintShapeInfo(oPC, "======  CON: " + IntToString(GetAbilityScore(oItem, ABILITY_CONSTITUTION)) + " (" + IntToString(GetAbilityModifier(ABILITY_CONSTITUTION, oItem)) + ")");
+            _prc_inc_PrintShapeInfo(oPC, "======  INT: " + IntToString(GetAbilityScore(oItem, ABILITY_INTELLIGENCE)) + " (" + IntToString(GetAbilityModifier(ABILITY_INTELLIGENCE, oItem)) + ")");
+            _prc_inc_PrintShapeInfo(oPC, "======  WIS: " + IntToString(GetAbilityScore(oItem, ABILITY_WISDOM)) + " (" + IntToString(GetAbilityModifier(ABILITY_WISDOM, oItem)) + ")");
+            _prc_inc_PrintShapeInfo(oPC, "======  CHA: " + IntToString(GetAbilityScore(oItem, ABILITY_CHARISMA)) + " (" + IntToString(GetAbilityModifier(ABILITY_CHARISMA, oItem)) + ")");
+            _prc_inc_PrintShapeInfo(oPC, "------");
+
+            //TODO: look up names in 2da/TLK?
+            _prc_inc_PrintShapeInfo(oPC, "======  Fortitude: " + IntToString(GetFortitudeSavingThrow(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "======  Will: " + IntToString(GetWillSavingThrow(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "======  Reflex: " + IntToString(GetReflexSavingThrow(oItem)));
+            _prc_inc_PrintShapeInfo(oPC, "------");
+
+            int i = 0;
+            string sSkillName;
+            while((sSkillName = Get2DACache("skills", "Name", i)) != "")
+            {
+                sSkillName = GetStringByStrRef(StringToInt(sSkillName));
+                _prc_inc_PrintShapeInfo(oPC, "======  " + sSkillName + ": " + IntToString(GetSkillRank(i, oItem)));
+                i += 1;
+            }
+            _prc_inc_PrintShapeInfo(oPC, "------");
+
+            _prc_inc_PrintShapeInfo(oPC, "======  Gender: " + IntToString(GetGender(oItem))); //TODO: look up values in 2da?
+            _prc_inc_PrintShapeInfo(oPC, "======  Size: " + IntToString(GetCreatureSize(oItem))); //TODO: look up values in 2da?
+            _prc_inc_PrintShapeInfo(oPC, "======  Race: " + IntToString(GetRacialType(oItem))); //TODO: look up values in 2da?
+            _prc_inc_PrintShapeInfo(oPC, "======  Speed: " + IntToString(GetMovementRate(oItem))); //TODO: look up values in 2da?
+            _prc_inc_PrintShapeInfo(oPC, "======  Dead: " + (GetIsDead(oItem) ? "Yes" : "No"));
+            _prc_inc_PrintShapeInfo(oPC, "======  Tag: " + GetTag(oItem));
+            _prc_inc_PrintShapeInfo(oPC, "======  Object Type: " + IntToString(GetObjectType(oItem))); //TODO: look up values in 2da?
+
+            //TODO?:
+                //int GetGold(object oTarget=OBJECT_SELF);
+                //location GetLocalLocation(object oObject, string sVarName);
+                    // vector GetPositionFromLocation(location lLocation);
+                    // object GetAreaFromLocation(location lLocation);
+                    // float GetFacingFromLocation(location lLocation);
+                //int GetCommandable(object oTarget=OBJECT_SELF);
+                //int GetIsListening(object oObject);
+                //int GetReputation(object oSource, object oTarget);
+                //location GetLocation(object oObject);
+                //int GetIsPC(object oCreature);
+                // int GetIsEnemy(object oTarget, object oSource=OBJECT_SELF);
+                // int GetIsFriend(object oTarget, object oSource=OBJECT_SELF);
+                // int GetIsNeutral(object oTarget, object oSource=OBJECT_SELF);
+                // int GetStealthMode(object oCreature);
+                // int GetDetectMode(object oCreature);
+                // int GetDefensiveCastingMode(object oCreature);
+                // int GetAppearanceType(object oCreature);
+                // int GetWeight(object oTarget=OBJECT_SELF); //Gets the weight of an item, or the total carried weight of a creature in tenths of pounds (as per the baseitems.2da).
+                // int GetAILevel(object oTarget=OBJECT_SELF);
+                // int GetActionMode(object oCreature, int nMode); 
+                // int GetArcaneSpellFailure(object oCreature); 
+                // int GetLootable( object oCreature );
+                // int GetIsCreatureDisarmable(object oCreature);
+                // string GetDeity(object oCreature);
+                // string GetSubRace(object oTarget);
+                // int GetAge(object oCreature);
+                //int GetPlotFlag(object oTarget=OBJECT_SELF);
+        }
+        else
+            _prc_inc_PrintShapeInfo(oPC, "======  AC: " + IntToString(GetItemACValue(oItem)));
+        _prc_inc_PrintShapeInfo(oPC, "====================================");
+    }    
+}
+
+//TODO: TLK Entries
+void _prc_inc_ShapePrintDebug(object oPC, object oTarget, int bForceLogPrint)
+{
+    int nSaveValue = GetLocalInt(oPC, "PRC_EnableLogPrint");
+    if (bForceLogPrint)
+        SetLocalInt(oPC, "PRC_EnableLogPrint", TRUE);
+    
+    DelayCommand(0.0, _prc_inc_PrintDebugItem(oPC, "CREATURE", oTarget));
+    DelayCommand(0.0, _prc_inc_PrintDebugItem(oPC, "CREATURE SKIN", GetItemInSlot(INVENTORY_SLOT_CARMOUR, oTarget)));
+    DelayCommand(0.0, _prc_inc_PrintDebugItem(oPC, "RIGHT CREATURE WEAPON", GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oTarget)));
+    DelayCommand(0.0, _prc_inc_PrintDebugItem(oPC, "LEFT CREATURE WEAPON", GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oTarget)));
+    DelayCommand(0.0, _prc_inc_PrintDebugItem(oPC, "SPECIAL CREATURE WEAPON", GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oTarget)));
+
+    int nSlot;
+    for(nSlot = 0; nSlot < NUM_INVENTORY_SLOTS; nSlot++)
+    {
+        switch (nSlot)
+        {
+            case INVENTORY_SLOT_CARMOUR:
+            case INVENTORY_SLOT_CWEAPON_R:
+            case INVENTORY_SLOT_CWEAPON_L:
+            case INVENTORY_SLOT_CWEAPON_B:
+                break;
+            
+            default:
+                DelayCommand(0.0, _prc_inc_PrintDebugItem(oPC, "INVENTORY ITEM " + IntToString(nSlot) + ": ", GetItemInSlot(nSlot, oTarget)));
+        }
+    }
+
+    if (bForceLogPrint)
+        DelayCommand(0.1, SetLocalInt(oPC, "PRC_EnableLogPrint", nSaveValue));
+}
+
+//TODO: Add nShifterType parameter so that only applicable information is printed?
+void _prc_inc_PrintShape(object oPC, object oTemplate, int bForceLogPrint)
+{
+    int nSaveValue = GetLocalInt(oPC, "PRC_EnableLogPrint");
+    if (bForceLogPrint)
+        SetLocalInt(oPC, "PRC_EnableLogPrint", TRUE);
+    
+    _prc_inc_PrintShapeInfo(oPC, "=================================================");
+    
+    //Basic information
+    
+    _prc_inc_PrintShapeInfo(oPC, "=== " + GetName(oTemplate));
+    _prc_inc_PrintShapeInfo(oPC, "=== " + GetResRef(oTemplate));
+    _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef((StringToInt(Get2DACache("racialtypes", "Name", MyPRCGetRacialType(oTemplate))))));
+    _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(57420+0x01000000) + IntToString(_prc_inc_shifting_ShifterLevelRequirement(oTemplate))); //"Required Shifter Level: "
+    _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(57421+0x01000000) + IntToString(_prc_inc_shifting_CharacterLevelRequirement(oTemplate))); //"Required Character Level: "
+    _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(57436+0x01000000) + FloatToString(GetChallengeRating(oTemplate), 4, 1)); //"Challenge Rating: "
+
+    _prc_inc_PrintShapeInfo(oPC, "==========");
+
+    _prc_inc_PrintClassInfo("=== ", oPC, oTemplate, GetClassByPosition(1, oTemplate));
+    _prc_inc_PrintClassInfo("=== ", oPC, oTemplate, GetClassByPosition(2, oTemplate));
+    _prc_inc_PrintClassInfo("=== ", oPC, oTemplate, GetClassByPosition(3, oTemplate));
+    _prc_inc_PrintClassInfo("=== ", oPC, oTemplate, GetClassByPosition(4, oTemplate));
+    _prc_inc_PrintClassInfo("=== ", oPC, oTemplate, GetClassByPosition(5, oTemplate));
+    _prc_inc_PrintClassInfo("=== ", oPC, oTemplate, GetClassByPosition(6, oTemplate));
+    _prc_inc_PrintClassInfo("=== ", oPC, oTemplate, GetClassByPosition(7, oTemplate));
+    _prc_inc_PrintClassInfo("=== ", oPC, oTemplate, GetClassByPosition(8, oTemplate));
+	
+    _prc_inc_PrintShapeInfo(oPC, "==========");
+
+    //Harmlessly invisible?
+
+    if(_prc_inc_shifting_GetIsCreatureHarmless(oTemplate))
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(57424+0x01000000)); //"Harmlessly Invisible"
+        
+    //Able to cast spells without Natural Spell?
+
+    if(!_prc_inc_shifting_GetCanFormCast(oTemplate) && !GetHasFeat(FEAT_PRESTIGE_SHIFTER_NATURALSPELL, oTemplate))
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(57477+0x01000000)); //"Cannot cast spells"
+    else
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(57476+0x01000000)); //"Can cast spells"
+
+    //Natural AC
+
+    _prc_inc_PrintNaturalAC(oPC, oTemplate);
+
+    //STR, DEX, CON
+    
+    struct _prc_inc_ability_info_struct rInfoStruct = _prc_inc_shifter_GetAbilityInfo(oTemplate, oPC);
+
+    //Extra information related to STR, DEX, CON
+
+    string sExtra, sBonusOrPenalty = GetStringByStrRef(57427+0x01000000);
+    sExtra = " (" + sBonusOrPenalty + (rInfoStruct.nDeltaSTR>=0?"+":"") + IntToString(rInfoStruct.nDeltaSTR) + ")";
+    _prc_inc_PrintShapeInfo(oPC, "=== " + _prc_inc_AbilityTypeString(0) + " " + IntToString(rInfoStruct.nTemplateSTR) + sExtra);
+    sExtra = " (" + sBonusOrPenalty + (rInfoStruct.nDeltaDEX>=0?"+":"") + IntToString(rInfoStruct.nDeltaDEX) + ")";
+    _prc_inc_PrintShapeInfo(oPC, "=== " + _prc_inc_AbilityTypeString(1) + " " + IntToString(rInfoStruct.nTemplateDEX) + sExtra);
+    sExtra = " (" + sBonusOrPenalty + (rInfoStruct.nDeltaCON>=0?"+":"") + IntToString(rInfoStruct.nDeltaCON) + ")";
+    _prc_inc_PrintShapeInfo(oPC, "=== " + _prc_inc_AbilityTypeString(2) + " " + IntToString(rInfoStruct.nTemplateCON) + sExtra);    
+
+    _prc_inc_PrintShapeInfo(oPC, "------");
+
+    int i = 0;
+    string sSkillName;
+    string sSTRBasedSkills, sDEXBasedSkills, sCONBasedSkills;
+    while((sSkillName = Get2DACache("skills", "Name", i)) != "")
+    {
+        sSkillName = GetStringByStrRef(StringToInt(sSkillName));
+        string sSkillKeyAbility = Get2DACache("skills", "KeyAbility", i);
+        if (sSkillKeyAbility == "STR")
+            sSTRBasedSkills += sSkillName + ", ";
+        else if (sSkillKeyAbility == "DEX")
+            sDEXBasedSkills += sSkillName + ", ";
+        else if (sSkillKeyAbility == "CON")
+            sCONBasedSkills += sSkillName + ", ";
+        i += 1;
+    }
+    if (GetStringLength(sSTRBasedSkills))
+        sSTRBasedSkills = GetStringLeft(sSTRBasedSkills, GetStringLength(sSTRBasedSkills) - 2); //Remove the final ", "
+    if (GetStringLength(sDEXBasedSkills))
+        sDEXBasedSkills = GetStringLeft(sDEXBasedSkills, GetStringLength(sDEXBasedSkills) - 2); //Remove the final ", "
+    if (GetStringLength(sCONBasedSkills))
+        sCONBasedSkills = GetStringLeft(sCONBasedSkills, GetStringLength(sCONBasedSkills) - 2); //Remove the final ", "
+
+    int nSTRBonus = rInfoStruct.nExtraSTR / 2;
+    if (nSTRBonus > 0)
+    {
+        //TODO: cap AB bonus
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60544+0x01000000) + " +" + IntToString(nSTRBonus)); //Attack increase from STR increase
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60546+0x01000000) + " +" + IntToString(nSTRBonus)); //Damage increase from STR increase
+        _prc_inc_PrintShapeInfo(oPC, "=== " + ReplaceString(GetStringByStrRef(60528+0x01000000), "%(SKILLS)", sSTRBasedSkills) + " +" + IntToString(nSTRBonus)); //Skill bonus from STR increase
+    }
+    else if (nSTRBonus < 0)
+    {
+        //TODO: cap AB penalty--at what?
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60545+0x01000000) + " " + IntToString(nSTRBonus)); //Attack decrease from STR decrease
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60547+0x01000000) + " " + IntToString(nSTRBonus)); //Damage decrease from STR decrease
+        _prc_inc_PrintShapeInfo(oPC, "=== " + ReplaceString(GetStringByStrRef(60529+0x01000000), "%(SKILLS)", sSTRBasedSkills) + " " + IntToString(nSTRBonus)); //Skill penalty from STR decrease
+    }
+
+    int nDEXBonus = rInfoStruct.nExtraDEX / 2;
+    if (nDEXBonus > 0)
+    {
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60548+0x01000000) + " +" + IntToString(nDEXBonus)); //AC increase from DEX increase
+        _prc_inc_PrintShapeInfo(oPC, "=== " + ReplaceString(GetStringByStrRef(60530+0x01000000), "%(SKILLS)", sDEXBasedSkills) + " +" + IntToString(nDEXBonus)); //Skill bonus from DEX increase
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60531+0x01000000) + " +" + IntToString(nDEXBonus)); //Saving throw bonus from DEX increase
+    }
+    else if (nDEXBonus < 0)
+    {
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60549+0x01000000) + " " + IntToString(nDEXBonus)); //AC decrease from DEX increase
+        _prc_inc_PrintShapeInfo(oPC, "=== " + ReplaceString(GetStringByStrRef(60532+0x01000000), "%(SKILLS)", sDEXBasedSkills) + " " + IntToString(nDEXBonus)); //Skill penalty from DEX decrease
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60533+0x01000000) + " " + IntToString(nDEXBonus)); //Saving throw penalty from DEX decrease
+    }
+
+    int nCONBonus = rInfoStruct.nExtraCON / 2;
+    if (nCONBonus > 0)
+    {
+        _prc_inc_PrintShapeInfo(oPC, "=== " + ReplaceString(GetStringByStrRef(60534+0x01000000), "%(SKILLS)", sCONBasedSkills) + " +" + IntToString(nCONBonus)); //Skill bonus from CON increase
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60535+0x01000000) + " +" + IntToString(nCONBonus)); //Saving throw bonus from CON increase
+        int tempHP = rInfoStruct.nExtraCON * GetHitDice(oPC);
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(57431+0x01000000) + " " + IntToString(tempHP)); //Temporary HP from CON increase
+    }
+    else if (nCONBonus < 0)
+    {
+        _prc_inc_PrintShapeInfo(oPC, "=== " + ReplaceString(GetStringByStrRef(60536+0x01000000), "%(SKILLS)", sCONBasedSkills) + " " + IntToString(nCONBonus)); //Skill penalty from CON decrease
+        _prc_inc_PrintShapeInfo(oPC, "=== " + GetStringByStrRef(60537+0x01000000) + " " + IntToString(nCONBonus)); //Saving throw penalty from CON decrease
+    }
+
+    _prc_inc_PrintShapeInfo(oPC, "==========");
+        
+    //Hide and creature weapon properties
+
+    object oTemplateCWpR = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R, oTemplate);
+    object oTemplateCWpL = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L, oTemplate);
+    object oTemplateCWpB = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B, oTemplate);
+    object oTemplateHide = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oTemplate);
+
+    if(GetIsObjectValid(oTemplateCWpR))
+    {
+        string sPrefix = GetStringByStrRef(57432+0x01000000); //"Right Creature Weapon:"
+        _prc_inc_PrintShapeInfo(oPC, "=== " + sPrefix);
+        _prc_inc_PrintAllItemProperties("===    ", oPC, oTemplateCWpR);
+    }
+
+    if(GetIsObjectValid(oTemplateCWpL))
+    {
+        string sPrefix = GetStringByStrRef(57433+0x01000000); //"Left Creature Weapon:"
+        _prc_inc_PrintShapeInfo(oPC, "=== " + sPrefix);
+        _prc_inc_PrintAllItemProperties("===    ", oPC, oTemplateCWpL);
+    }
+
+    if(GetIsObjectValid(oTemplateCWpB))
+    {
+        string sPrefix = GetStringByStrRef(57434+0x01000000); //"Special Attack Creature Weapon:"
+        _prc_inc_PrintShapeInfo(oPC, "=== " + sPrefix);
+        _prc_inc_PrintAllItemProperties("===    ", oPC, oTemplateCWpB);
+    }
+
+    if(GetIsObjectValid(oTemplateHide))
+        _prc_inc_PrintAllItemProperties("=== ", oPC, oTemplateHide);
+        
+    //Spell-like abilities
+        
+    _prc_inc_shifting_PrintShifterActiveAbilities(oPC, oTemplate);
+    
+    //Feats
+
+    i = 0;
+    string sFeat;
+    int CHUNK_SIZE = 25; //50 was too big, so use 25
+
+    while((sFeat = Get2DACache("shifter_feats", "Feat", i)) != "")
+    {
+        DelayCommand(0.0f, _prc_inc_shifting_PrintFeats(oPC, oTemplate, i, i+CHUNK_SIZE));
+        i += CHUNK_SIZE;
+    }
+    DelayCommand(0.0f, _prc_inc_PrintShapeInfo(oPC, "================================================="));
+
+    if (bForceLogPrint)
+        DelayCommand(0.1, SetLocalInt(oPC, "PRC_EnableLogPrint", nSaveValue));
+
+    if (GetLocalInt(oPC, "prc_shifter_debug"))
+        DelayCommand(0.2f, _prc_inc_ShapePrintDebug(oPC, oTemplate, bForceLogPrint));
+}
diff --git a/trunk/include/psi_inc_core.nss b/trunk/include/psi_inc_core.nss
new file mode 100644
index 00000000..ff94e44f
--- /dev/null
+++ b/trunk/include/psi_inc_core.nss
@@ -0,0 +1,1312 @@
+//::///////////////////////////////////////////////
+//:: Psionics include: Psionic Core Files
+//:: psi_inc_core
+//::///////////////////////////////////////////////
+/** @file
+    Core functions removed from
+	
+	psi_inc_psifunc
+	psi_inc_focus (depreciated)
+	
+	as they are required by many of the other psi groups
+
+    @author Ornedan/ElgarL
+    @date   Created - 2005.11.10/23.07.2010
+ */
+//:://////////////////////////////////////////////
+//:://////////////////////////////////////////////
+
+//:: Updated for .35 by Jaysyn 2023/03/10
+
+//////////////////////////////////////////////////
+/*                 Constants                    */
+//////////////////////////////////////////////////
+
+// Included here to provide the values for the constants below
+#include "prc_class_const"
+
+const int POWER_LIST_PSION          = CLASS_TYPE_PSION;
+const int POWER_LIST_WILDER         = CLASS_TYPE_WILDER;
+const int POWER_LIST_PSYWAR         = CLASS_TYPE_PSYWAR;
+const int POWER_LIST_PSYROG         = CLASS_TYPE_PSYCHIC_ROGUE;
+const int POWER_LIST_FIST_OF_ZUOKEN = CLASS_TYPE_FIST_OF_ZUOKEN;
+const int POWER_LIST_WARMIND        = CLASS_TYPE_WARMIND;
+
+#include "psi_inc_const"
+
+//:: Test Main
+//void main (){}
+
+//////////////////////////////////////////////////
+/*             Function prototypes              */
+//////////////////////////////////////////////////
+
+/**
+ * Attempts to use psionic focus. If the creature was focused, it
+ * loses the focus. If it has Epic Psionic Focus feats, it will
+ * be able to use the focus for a number of times equal to the
+ * number of those feats it has during the next 0.5s
+ *
+ * @param oUser Creature expending it's psionic focus
+ * @return      TRUE if the creature was psionically focus or had
+ *              Epic Psionic Focus uses remaining. FALSE otherwise.
+ */
+int UsePsionicFocus(object oUser = OBJECT_SELF);
+
+/**
+ * Sets psionic focus active and triggers feats dependant
+ * on it.
+ *
+ * Feats currently keyed to activity of psionic focus:
+ *  Psionic Dodge
+ *  Speed of Thought
+ *
+ * @param oGainee Creature gaining psionic focus.
+ */
+void GainPsionicFocus(object oGainee = OBJECT_SELF);
+
+/**
+ * Gets the number of psionic focus uses the creature has available
+ * to it at this moment. If the creature is psionically focused,
+ * the number equal to GetPsionicFocusUsesPerExpenditure(), otherwise
+ * it is however many focus uses the creature still has remaining of
+ * that number.
+ *
+ * @param oCreature Creaute whose psionic focus use count to evaluate
+ * @return          The total number of times UsePsionicFocus() will
+ *                  return TRUE if called at this moment.
+ */
+int GetPsionicFocusesAvailable(object oCreature = OBJECT_SELF);
+
+/**
+ * Calculates the number of times a creature may use it's psionic focus when expending it.
+ * Base is 1.
+ * In addition, 1 more use for each Epic Psionic Focus feat the creature has.
+ *
+ * @param oCreature Creaute whose psionic focus use count to evaluate
+ * @return          The total number of times UsePsionicFocus() will return
+ *                  TRUE for a single expending of psionic focus.
+ */
+int GetPsionicFocusUsesPerExpenditure(object oCreature = OBJECT_SELF);
+
+/**
+ * Sets the given creature's psionic focus off and deactivates all feats keyed to it.
+ *
+ * @param oLoser Creature losing it's psionic focus
+ */
+void LosePsionicFocus(object oLoser = OBJECT_SELF);
+
+/**
+ * Checks whether the given creature is psionically focused.
+ *
+ * @param oCreature Creature whose psionic focus's state to examine
+ * @return          TRUE if the creature is psionically focused, FALSE
+ *                  otherwise.
+ */
+int GetIsPsionicallyFocused(object oCreature = OBJECT_SELF);
+
+/**
+ * Determines the number of feats that would use psionic focus
+ * when triggered the given creature has active.
+ *
+ * Currently accounts for:
+ *  Talented
+ *  Power Specialization
+ *  Power Penetration
+ *  Psionic Endowment
+ *  Chain Power
+ *  Empower Power
+ *  Extend Power
+ *  Maximize Power
+ *  Split Psionic Ray
+ *  Twin Power
+ *  Widen Power
+ *  Quicken Power
+ *
+ * @param oCreature Creature whose feats to examine
+ * @return          How many of the listed feats are active
+ */
+int GetPsionicFocusUsingFeatsActive(object oCreature = OBJECT_SELF);
+
+/**
+ * Calculates the DC of the power being currently manifested.
+ * Base value is 10 + power level + ability modifier in manifesting stat
+ *
+ * WARNING: Return value is not defined when a power is not being manifested.
+ *
+ */
+int GetManifesterDC(object oManifester = OBJECT_SELF);
+
+/**
+ * Determines the spell school matching a discipline according to the
+ * standard transparency rules.
+ * Disciplines which have no matching spell school are matched with
+ * SPELL_SCHOOL_GENERAL.
+ *
+ * @param nDiscipline Discipline to find matching spell school for
+ * @return            SPELL_SCHOOL_* of the match
+ */
+int DisciplineToSpellSchool(int nDiscipline);
+
+/**
+ * Determines the discipline matching a spell school according to the
+ * standard transparency rules.
+ * Spell schools that have no matching disciplines are matched with
+ * DISCIPLINE_NONE.
+ *
+ * @param nSpellSchool Spell schools to find matching discipline for
+ * @return             DISCIPLINE_* of the match
+ */
+int SpellSchoolToDiscipline(int nSpellSchool);
+
+/**
+ * Determines the discipline of a power, using the School column of spells.2da.
+ *
+ * @param nSpellID The spellID of the power to determine the discipline of
+ * @return         DISCIPLINE_* constant. DISCIPLINE_NONE if the power's
+ *                 School designation does not match any of the discipline's.
+ */
+int GetPowerDiscipline(int nSpellID);
+
+/**
+ * Determines whether a given power is a power of the Telepahty discipline.
+ *
+ * @param nSpellID The spells.2da row of the power. If left to default,
+ *                 PRCGetSpellId() is used.
+ * @return         TRUE if the power's discipline is Telepathy, FALSE otherwise
+ */
+int GetIsTelepathyPower(int nSpellID = -1);
+
+/**
+ * Checks whether the PC possesses the feats the given feat has as it's
+ * prerequisites. Possession of a feat is checked using GetHasFeat().
+ *
+ *
+ * @param nFeat The feat for which determine the possession of prerequisites
+ * @param oPC   The creature whose feats to check
+ * @return      TRUE if the PC possesses the prerequisite feats AND does not
+ *              already posses nFeat, FALSE otherwise.
+ */
+int CheckPowerPrereqs(int nFeat, object oPC);
+
+/**
+ * Determines the manifester's level in regards to manifester checks to overcome
+ * spell resistance.
+ *
+ * WARNING: Return value is not defined when a power is not being manifested.
+ *
+ * @param oManifester A creature manifesting a power at the moment
+ * @return            The creature's manifester level, adjusted to account for
+ *                    modifiers that affect spell resistance checks.
+ */
+int GetPsiPenetration(object oManifester = OBJECT_SELF);
+
+/**
+ * Determines whether a given creature possesses the Psionic subtype.
+ * Ways of possessing the subtype:
+ * - Being of a naturally psionic race
+ * - Having class levels in a psionic class
+ * - Possessing the Wild Talent feat
+ *
+ * @param oCreature Creature to test
+ * @return          TRUE if the creature is psionic, FALSE otherwise.
+ */
+int GetIsPsionicCharacter(object oCreature);
+
+/**
+ * Creates the creature weapon for powers like Bite of the Wolf and Claws of the
+ * Beast. If a creature weapon of the correct type is already present, it is
+ * used instead of a new one.
+ *
+ * Preserving existing weapons may cause problems, if so, make the function instead delete the old object - Ornedan
+ *
+ * @param oCreature     Creatue whose creature weapons to mess with.
+ * @param sResRef       Resref of the creature weapon. Assumed to be one of the
+ *                      PRC creature weapons, so this considered to is also be
+ *                      the tag.
+ * @param nIventorySlot Inventory slot where the creature weapon is to be equipped.
+ * @param fDuration     If a new weapon is created, it will be destroyed after
+ *                      this duration.
+ *
+ * @return              The newly created creature weapon. Or an existing weapon,
+ *                      if there was one.
+ */
+object GetPsionicCreatureWeapon(object oCreature, string sResRef, int nInventorySlot, float fDuration);
+
+/**
+ * Applies modifications to a power's damage that depend on some property
+ * of the target.
+ * Currently accounts for:
+ *  - Mental Resistance
+ *  - Greater Power Specialization
+ *  - Intellect Fortress
+ *
+ * @param oTarget     A creature being dealt damage by a power
+ * @param oManifester The creature manifesting the damaging power
+ * @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 oManifester, int nDamage,
+                                     int bIsHitPointDamage = TRUE, int bIsEnergyDamage = FALSE);
+
+/**
+ * Gets the manifester level adjustment from the Practiced Manifester feats.
+ *
+ * @param oManifester           The creature to check
+ * @param iManifestingClass     The CLASS_TYPE* that the power was cast by.
+ * @param iManifestingLevels    The manifester level for the power calculated so far 
+ *                              ie. BEFORE Practiced Manifester.
+ */
+int PracticedManifesting(object oManifester, int iManifestingClass, int iManifestingLevels);
+
+/**
+ * Determines the given creature's manifester level. If a class is specified,
+ * then returns the manifester level for that class. Otherwise, returns
+ * the manifester level for the currently active manifestation.
+ *
+ * @param oManifester    The creature whose manifester level to determine
+ * @param nSpecificClass The class to determine the creature's manifester
+ *                       level in.
+ *                       DEFAULT: CLASS_TYPE_INVALID, which means the creature's
+ *                       manifester level in regards to an ongoing manifestation
+ *                       is determined instead.
+ * @param nMaxPowerLevel For learning powers. Practiced Manifester is breaking things otherwise.
+ * @return               The manifester level
+ */
+int GetManifesterLevel(object oManifester, int nSpecificClass = CLASS_TYPE_INVALID, int nMaxPowerLevel = FALSE);
+
+/**
+ * Determines the given creature's highest undmodified manifester level among it's
+ * manifesting classes.
+ *
+ * @param oCreature Creature whose highest manifester level to determine
+ * @return          The highest unmodified manifester level the creature can have
+ */
+int GetHighestManifesterLevel(object oCreature);
+
+/**
+ * Gets the level of the power being currently manifested.
+ * WARNING: Return value is not defined when a power is not being manifested.
+ *
+ * @param oManifester The creature currently manifesting a power
+ * @return            The level of the power being manifested
+ */
+int GetPowerLevel(object oManifester);
+
+/**
+ * Determines a creature's ability score in the manifesting ability of a given
+ * class.
+ *
+ * @param oManifester Creature whose ability score to get
+ * @param nClass      CLASS_TYPE_* constant of a manifesting class
+ */
+int GetAbilityScoreOfClass(object oManifester, int nClass);
+
+/**
+ * Determines from what class's power list the currently being manifested
+ * power is manifested from.
+ *
+ * @param oManifester A creature manifesting a power at this moment
+ * @return            CLASS_TYPE_* constant of the class
+ */
+int GetManifestingClass(object oManifester = OBJECT_SELF);
+
+/**
+ * Determines the manifesting ability of a class.
+ *
+ * @param nClass CLASS_TYPE_* constant of the class to determine the manifesting stat of
+ * @return       ABILITY_* of the manifesting stat. ABILITY_CHARISMA for non-manifester
+ *               classes.
+ */
+int GetAbilityOfClass(int nClass);
+
+/**
+ * Determines which of the character's classes is their highest or first psionic
+ * manifesting class, if any. This is the one which gains manifester level raise
+ * benefits from prestige classes.
+ *
+ * @param oCreature Creature whose classes to test
+ * @return          CLASS_TYPE_* of the first psionic manifesting class,
+ *                  CLASS_TYPE_INVALID if the creature does not posses any.
+ */
+int GetPrimaryPsionicClass(object oCreature = OBJECT_SELF);
+
+/**
+ * Calculates how many manifester levels are gained by a given creature from
+ * it's levels in prestige classes.
+ *
+ * @param oCreature Creature to calculate added manifester levels for
+ * @return          The number of manifester levels gained
+ */
+int GetPsionicPRCLevels(object oCreature);
+
+/**
+ * Determines the position of a creature's first psionic manifesting class, if any.
+ *
+ * @param oCreature Creature whose classes to test
+ * @return          The position of the first psionic class {1, 2, 3} or 0 if
+ *                  the creature possesses no levels in psionic classes.
+ */
+int GetFirstPsionicClassPosition(object oCreature = OBJECT_SELF);
+
+/**
+ * Determines whether a given class is a psionic class or not. A psionic
+ * class is defined as one that gives base manifesting.
+ *
+ * @param nClass CLASS_TYPE_* of the class to test
+ * @return       TRUE if the class is a psionic class, FALSE otherwise
+ */
+int GetIsPsionicClass(int nClass);
+
+/**
+ * Gets the amount of manifester levels the given creature is Wild Surging by.
+ *
+ * @param oManifester The creature to test
+ * @return            The number of manifester levels added by Wild Surge. 0 if
+ *                    Wild Surge is not active.
+ */
+int GetWildSurge(object oManifester);
+
+/**
+ * Gets the highest power level the creature should know
+ *
+ * @param oManifester The creature to test
+ * @return            Power level.
+ */
+int GetMaxPowerLevel(object oManifester);
+
+//////////////////////////////////////////////////
+/*                  Includes                    */
+//////////////////////////////////////////////////
+
+#include "prc_inc_unarmed"
+						
+//////////////////////////////////////////////////
+/*          Global Structures                   */
+//////////////////////////////////////////////////
+
+// These are used in psi_inc_psifunc and psi_inc_augment
+
+/**
+ * A structure that contains common data used during power manifestation.
+ */
+struct manifestation{
+    /* Generic stuff */
+    /// The creature manifesting the power
+    object oManifester;
+    /// Whether the manifestation is successfull or not
+    int bCanManifest;
+    /// How much Power Points the manifestation costs
+    int nPPCost;
+    /// How many psionic focus uses the manifester would have remaining at a particular point in the manifestation
+    int nPsiFocUsesRemain;
+    /// The creature's manifester level in regards to this power
+    int nManifesterLevel;
+    /// The power's spell ID
+    int nSpellID;
+
+    /* Augmentation */
+    /// How many times the first augmentation option of the power is used
+    int nTimesAugOptUsed_1;
+    /// How many times the second augmentation option of the power is used
+    int nTimesAugOptUsed_2;
+    /// How many times the third augmentation option of the power is used
+    int nTimesAugOptUsed_3;
+    /// How many times the fourth augmentation option of the power is used
+    int nTimesAugOptUsed_4;
+    /// How many times the fifth augmentation option of the power is used
+    int nTimesAugOptUsed_5;
+    /// How many times the PP used for augmentation triggered the generic augmentation of the power
+    int nTimesGenericAugUsed;
+
+    /* Metapsionics */
+    /// Whether Chain Power was used with this manifestation
+    int bChain;
+    /// Whether Empower Power was used with this manifestation
+    int bEmpower;
+    /// Whether Extend Power was used with this manifestation
+    int bExtend;
+    /// Whether Maximize Power was used with this manifestation
+    int bMaximize;
+    /// Whether Split Psionic Ray was used with this manifestation
+    int bSplit;
+    /// Whether Twin Power was used with this manifestation
+    int bTwin;
+    /// Whether Widen Power was used with this manifestation
+    int bWiden;
+    /// Whether Quicken Power was used with this manifestation
+    int bQuicken;
+};
+
+//////////////////////////////////////////////////
+/*             Function definitions             */
+//////////////////////////////////////////////////
+
+
+
+/*					Begin PSI FOCUS					*/
+//////////////////////////////////////////////////////
+
+int UsePsionicFocus(object oUser = OBJECT_SELF)
+{
+    int bToReturn = FALSE;
+    // This does not expend your psionic focus, but rather the item's
+    if (GetLocalInt(oUser, "SimpleBow_Focus"))
+    {
+        DeleteLocalInt(oUser, "SimpleBow_Focus");
+        return TRUE;
+    }
+    // Next, check if we have focus on
+    else if(GetLocalInt(oUser, PSIONIC_FOCUS))
+    {
+        SetLocalInt(oUser, "PsionicFocusUses", GetPsionicFocusUsesPerExpenditure(oUser) - 1);
+        DelayCommand(0.5f, DeleteLocalInt(oUser, "PsionicFocusUses"));
+        SendMessageToPCByStrRef(oUser, 16826414); // "You have used your Psionic Focus"
+
+        bToReturn = TRUE;
+    }
+    // We don't. Check if there are uses remaining
+    else if(GetLocalInt(oUser, "PsionicFocusUses"))
+    {
+        SetLocalInt(oUser, "PsionicFocusUses", GetLocalInt(oUser, "PsionicFocusUses") - 1);
+
+        bToReturn = TRUE;
+    }
+
+    // Lose focus if it was used
+    if(bToReturn) LosePsionicFocus(oUser);
+
+    return bToReturn;
+}
+
+void GainPsionicFocus(object oGainee = OBJECT_SELF)
+{
+    SetLocalInt(oGainee, PSIONIC_FOCUS, TRUE);
+
+    // Speed Of Thought
+    if(GetHasFeat(FEAT_SPEED_OF_THOUGHT, oGainee))
+    {
+        // Check for heavy armor before adding the bonus now
+        if(GetBaseAC(GetItemInSlot(INVENTORY_SLOT_CHEST, oGainee)) < 6)
+            AssignCommand(oGainee, ActionCastSpellAtObject(SPELL_FEAT_SPEED_OF_THOUGHT_BONUS, oGainee, METAMAGIC_NONE, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE));
+
+        // Schedule a script to remove the bonus should they equip heavy armor
+        AddEventScript(oGainee, EVENT_ONPLAYEREQUIPITEM, "psi_spdfthgt_oeq", TRUE, FALSE);
+        // Schedule another script to add the bonus back if the unequip the armor
+        AddEventScript(oGainee, EVENT_ONPLAYERUNEQUIPITEM, "psi_spdfthgt_ueq", TRUE, FALSE);
+    }
+    // Psionic Dodge
+    if(GetHasFeat(FEAT_PSIONIC_DODGE, oGainee))
+        SetCompositeBonus(GetPCSkin(oGainee), "PsionicDodge", 1, ITEM_PROPERTY_AC_BONUS);
+
+    //Strength of Two - Kalashtar racial feat
+    if(GetHasFeat(FEAT_STRENGTH_OF_TWO, oGainee))
+    {
+        SetCompositeBonus(GetPCSkin(oGainee), "StrengthOfTwo", 1, ITEM_PROPERTY_SAVING_THROW_BONUS, SAVING_THROW_WILL);
+    }
+    // Danger Sense abilities for Psychic Rogue
+    if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oGainee) >= 5)
+        ExecuteScript("psi_psyrog_dngr", oGainee);
+    if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oGainee) >= 7) // Uncanny Dodge
+        IPSafeAddItemProperty(GetPCSkin(oGainee), PRCItemPropertyBonusFeat(IP_CONST_FEAT_UNCANNY_DODGE1), HoursToSeconds(24), X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); 
+    if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oGainee) >= 9) // Improved Uncanny Dodge
+        IPSafeAddItemProperty(GetPCSkin(oGainee), PRCItemPropertyBonusFeat(IP_CONST_FEAT_UNCANNY_DODGE2), HoursToSeconds(24), X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE); 
+    if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_1d6, oGainee))
+    {
+        int nPsySneak = 1;
+        if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_2d6, oGainee))
+            nPsySneak += 2;
+        if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_3d6, oGainee))
+            nPsySneak += 3; 
+        
+        SetLocalInt(oGainee, "PsyRogueSneak",nPsySneak);
+        DelayCommand(0.1, ExecuteScript("prc_sneak_att", oGainee));
+    }    
+}
+
+int GetPsionicFocusesAvailable(object oCreature = OBJECT_SELF)
+{
+    // If the creature has a psionic focus active, return the maximum
+    if(GetLocalInt(oCreature, PSIONIC_FOCUS))
+        return GetPsionicFocusUsesPerExpenditure(oCreature);
+    // Otherwise, return the amount currently remaining
+    else
+        return GetLocalInt(oCreature, "PsionicFocusUses");
+}
+
+int GetPsionicFocusUsesPerExpenditure(object oCreature = OBJECT_SELF)
+{
+    int nFocusUses = 1;
+    int i;
+    for(i = FEAT_EPIC_PSIONIC_FOCUS_1; i <= FEAT_EPIC_PSIONIC_FOCUS_10; i++)
+        if(GetHasFeat(i, oCreature)) nFocusUses++;
+
+    return nFocusUses;
+}
+
+void LosePsionicFocus(object oLoser = OBJECT_SELF)
+{
+    // Only remove focus if it's present
+    if(GetLocalInt(oLoser, PSIONIC_FOCUS))
+    {
+        SetLocalInt(oLoser, PSIONIC_FOCUS, FALSE);
+
+        // Loss of Speed of Thought effects
+        PRCRemoveSpellEffects(SPELL_FEAT_SPEED_OF_THOUGHT_BONUS, oLoser, oLoser);
+        RemoveEventScript(oLoser, EVENT_ONPLAYEREQUIPITEM, "psi_spdfthgt_oeq", TRUE);
+        RemoveEventScript(oLoser, EVENT_ONPLAYERUNEQUIPITEM, "psi_spdfthgt_ueq", TRUE);
+        // Loss of Psionic Dodge effects
+        SetCompositeBonus(GetPCSkin(oLoser), "PsionicDodge", 0, ITEM_PROPERTY_AC_BONUS);
+        // Loss of Strength of Two effects
+        SetCompositeBonus(GetPCSkin(oLoser), "StrengthOfTwo", 0, ITEM_PROPERTY_SAVING_THROW_BONUS, SAVING_THROW_WILL);
+        
+        if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oLoser) >= 5)
+            PRCRemoveSpellEffects(POWER_DANGERSENSE, oLoser, oLoser);   
+        if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oLoser) >= 7)            
+            RemoveItemProperty(GetPCSkin(oLoser), ItemPropertyBonusFeat(IP_CONST_FEAT_UNCANNY_DODGE1));
+        if(GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE, oLoser) >= 9)            
+            RemoveItemProperty(GetPCSkin(oLoser), ItemPropertyBonusFeat(IP_CONST_FEAT_UNCANNY_DODGE2));
+
+        // Inform oLoser about the event
+        FloatingTextStrRefOnCreature(16826415, oLoser, FALSE); // "You have lost your Psionic Focus"
+        if(GetHasFeat(FEAT_PSY_SNEAK_ATTACK_1d6, oLoser))
+        {
+            DeleteLocalInt(oLoser, "PsyRogueSneak");
+            DelayCommand(0.1, ExecuteScript("prc_sneak_att", oLoser));
+        }        
+    }
+}
+
+int GetIsPsionicallyFocused(object oCreature = OBJECT_SELF)
+{
+    return GetLocalInt(oCreature, PSIONIC_FOCUS);
+}
+
+int GetPsionicFocusUsingFeatsActive(object oCreature = OBJECT_SELF)
+{
+    int nFeats;
+
+    if(GetLocalInt(oCreature, "TalentedActive"))            nFeats++;
+    if(GetLocalInt(oCreature, "PowerSpecializationActive")) nFeats++;
+    if(GetLocalInt(oCreature, "PowerPenetrationActive"))    nFeats++;
+    if(GetLocalInt(oCreature, "PsionicEndowmentActive"))    nFeats++;
+
+    if(GetLocalInt(oCreature, METAPSIONIC_CHAIN_VAR))       nFeats++;
+    if(GetLocalInt(oCreature, METAPSIONIC_EMPOWER_VAR))     nFeats++;
+    if(GetLocalInt(oCreature, METAPSIONIC_EXTEND_VAR))      nFeats++;
+    if(GetLocalInt(oCreature, METAPSIONIC_MAXIMIZE_VAR))    nFeats++;
+    if(GetLocalInt(oCreature, METAPSIONIC_SPLIT_VAR))       nFeats++;
+    if(GetLocalInt(oCreature, METAPSIONIC_TWIN_VAR))        nFeats++;
+    if(GetLocalInt(oCreature, METAPSIONIC_WIDEN_VAR))       nFeats++;
+    if(GetLocalInt(oCreature, METAPSIONIC_QUICKEN_VAR))     nFeats++;
+
+    return nFeats;
+}
+
+//////////////////////////////////////////////////////
+/*					END PSI FOCUS					*/
+//////////////////////////////////////////////////////
+
+int GetManifesterDC(object oManifester = OBJECT_SELF)
+{
+    int nClass = GetManifestingClass(oManifester);
+    int nDC = 10;
+    nDC += GetPowerLevel(oManifester);
+    nDC += GetAbilityModifier(GetAbilityOfClass(nClass), oManifester);
+
+    // Stuff that applies only to powers, not psi-like abilities goes inside
+    if(!GetLocalInt(oManifester, PRC_IS_PSILIKE))
+    {
+        if (GetLocalInt(oManifester, "PsionicEndowmentActive") == TRUE && UsePsionicFocus(oManifester))
+        {
+            nDC += GetHasFeat(FEAT_GREATER_PSIONIC_ENDOWMENT, oManifester) ? 4 : 2;
+        }
+    }
+
+    // Needed to do some adjustments here.
+    object oTarget = PRCGetSpellTargetObject();
+    int nPower     = PRCGetSpellId();
+
+    // Other DC adjustments
+    // Soul Manifester
+    nDC += Soulcaster(oManifester, PRCGetSpellId());
+    // Charming Veil meld
+    if(GetHasSpellEffect(MELD_CHARMING_VEIL, oManifester) && (GetIsOfSubschool(nPower, SUBSCHOOL_CHARM) || GetIsOfSubschool(nPower, SUBSCHOOL_COMPULSION))) nDC += GetEssentiaInvested(oManifester, MELD_CHARMING_VEIL)+1;
+    // Soul Eater
+    nDC += (GetLocalInt(oManifester, "PRC_SoulEater_HasDrained") && GetLevelByClass(CLASS_TYPE_SOUL_EATER, oManifester) >= 10) ? 2 : 0;
+    // Closed Mind
+    if(GetHasFeat(FEAT_CLOSED_MIND, oTarget)) nDC -= 2;
+    // Strong Mind
+    if(GetHasFeat(FEAT_STRONG_MIND, oTarget)) nDC -= 3;
+    // Fist of Dal Quor
+    if(GetLevelByClass(CLASS_TYPE_FIST_DAL_QUOR, oTarget) >= 4) nDC -= 2;
+
+    return nDC;
+}
+
+int DisciplineToSpellSchool(int nDiscipline)
+{
+    int nSpellSchool = SPELL_SCHOOL_GENERAL;
+
+    switch(nDiscipline)
+    {
+        case DISCIPLINE_CLAIRSENTIENCE:   nSpellSchool = SPELL_SCHOOL_DIVINATION;    break;
+        case DISCIPLINE_METACREATIVITY:   nSpellSchool = SPELL_SCHOOL_CONJURATION;   break;
+        case DISCIPLINE_PSYCHOKINESIS:    nSpellSchool = SPELL_SCHOOL_EVOCATION;     break;
+        case DISCIPLINE_PSYCHOMETABOLISM: nSpellSchool = SPELL_SCHOOL_TRANSMUTATION; break;
+        case DISCIPLINE_TELEPATHY:        nSpellSchool = SPELL_SCHOOL_ENCHANTMENT;   break;
+
+        default: nSpellSchool = SPELL_SCHOOL_GENERAL; break;
+    }
+
+    return nSpellSchool;
+}
+
+int SpellSchoolToDiscipline(int nSpellSchool)
+{
+    int nDiscipline = DISCIPLINE_NONE;
+
+    switch(nSpellSchool)
+    {
+        case SPELL_SCHOOL_GENERAL:       nDiscipline = DISCIPLINE_NONE;             break;
+        case SPELL_SCHOOL_ABJURATION:    nDiscipline = DISCIPLINE_NONE;             break;
+        case SPELL_SCHOOL_CONJURATION:   nDiscipline = DISCIPLINE_METACREATIVITY;   break;
+        case SPELL_SCHOOL_DIVINATION:    nDiscipline = DISCIPLINE_CLAIRSENTIENCE;   break;
+        case SPELL_SCHOOL_ENCHANTMENT:   nDiscipline = DISCIPLINE_TELEPATHY;        break;
+        case SPELL_SCHOOL_EVOCATION:     nDiscipline = DISCIPLINE_PSYCHOKINESIS;    break;
+        case SPELL_SCHOOL_ILLUSION:      nDiscipline = DISCIPLINE_NONE;             break;
+        case SPELL_SCHOOL_NECROMANCY:    nDiscipline = DISCIPLINE_NONE;             break;
+        case SPELL_SCHOOL_TRANSMUTATION: nDiscipline = DISCIPLINE_PSYCHOMETABOLISM; break;
+
+        default: nDiscipline = DISCIPLINE_NONE;
+    }
+
+    return nDiscipline;
+}
+
+int GetPowerDiscipline(int nSpellID)
+{
+    string sSpellSchool = Get2DACache("spells", "School", nSpellID);//lookup_spell_school(nSpellID);
+    int nDiscipline;
+
+    if      (sSpellSchool == "A") nDiscipline = DISCIPLINE_NONE;
+    else if (sSpellSchool == "C") nDiscipline = DISCIPLINE_METACREATIVITY;
+    else if (sSpellSchool == "D") nDiscipline = DISCIPLINE_CLAIRSENTIENCE;
+    else if (sSpellSchool == "E") nDiscipline = DISCIPLINE_TELEPATHY;
+    else if (sSpellSchool == "V") nDiscipline = DISCIPLINE_PSYCHOKINESIS;
+    else if (sSpellSchool == "I") nDiscipline = DISCIPLINE_NONE;
+    else if (sSpellSchool == "N") nDiscipline = DISCIPLINE_NONE;
+    else if (sSpellSchool == "T") nDiscipline = DISCIPLINE_PSYCHOMETABOLISM;
+    else if (sSpellSchool == "G") nDiscipline = DISCIPLINE_PSYCHOPORTATION;
+
+    return nDiscipline;
+}
+
+int GetIsTelepathyPower(int nSpellID = -1)
+{
+    if(nSpellID == -1) nSpellID = PRCGetSpellId();
+
+    return GetPowerDiscipline(nSpellID) == DISCIPLINE_TELEPATHY;
+}
+
+int CheckPowerPrereqs(int nFeat, object oPC)
+{
+    // Having the power already automatically disqualifies one from taking it again
+    if(GetHasFeat(nFeat, oPC))
+    return FALSE;
+    // We assume that the 2da is correctly formatted, and as such, a prereq slot only contains
+    // data if the previous slots in order also contains data.
+    // ie, no PREREQFEAT2 if PREREQFEAT1 is empty
+    if(Get2DACache("feat", "PREREQFEAT1", nFeat) != "")
+    {
+        if(!GetHasFeat(StringToInt(Get2DACache("feat", "PREREQFEAT1", nFeat)), oPC))
+        return FALSE;
+        if(Get2DACache("feat", "PREREQFEAT2", nFeat) != ""
+        && !GetHasFeat(StringToInt(Get2DACache("feat", "PREREQFEAT2", nFeat)), oPC))
+        return FALSE;
+    }
+
+    if(Get2DACache("feat", "OrReqFeat0", nFeat) != "")
+    {
+        if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat0", nFeat)), oPC))
+            return FALSE;
+        if(Get2DACache("feat", "OrReqFeat1", nFeat) != "")
+        {
+            if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat1", nFeat)), oPC))
+                return FALSE;
+            if(Get2DACache("feat", "OrReqFeat2", nFeat) != "")
+            {
+                if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat2", nFeat)), oPC))
+                    return FALSE;
+                if(Get2DACache("feat", "OrReqFeat3", nFeat) != "")
+                {
+                    if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat3", nFeat)), oPC))
+                        return FALSE;
+                    if(Get2DACache("feat", "OrReqFeat4", nFeat) != "")
+                    {
+                        if(!GetHasFeat(StringToInt(Get2DACache("feat", "OrReqFeat4", nFeat)), oPC))
+                            return FALSE;
+    }   }   }   }   }
+
+    //if youve reached this far then return TRUE
+    return TRUE;
+}
+
+int GetPsiPenetration(object oManifester = OBJECT_SELF)
+{
+    int nPen = GetManifesterLevel(oManifester);
+
+    // The stuff inside applies only to normal manifestation, not psi-like abilities
+    if(!GetLocalInt(oManifester, PRC_IS_PSILIKE))
+    {
+        // Check for Power Pen feats being used
+        if(GetLocalInt(oManifester, "PowerPenetrationActive") == TRUE && UsePsionicFocus(oManifester))
+        {
+            nPen += GetHasFeat(FEAT_GREATER_POWER_PENETRATION, oManifester) ? 8 : 4;
+        }
+    }
+
+    return nPen;
+}
+
+int GetIsPsionicCharacter(object oCreature)
+{
+    return !!(GetLevelByClass(CLASS_TYPE_PSION,          oCreature) ||
+              GetLevelByClass(CLASS_TYPE_PSYWAR,         oCreature) ||
+              GetLevelByClass(CLASS_TYPE_PSYCHIC_ROGUE,  oCreature) ||
+              GetLevelByClass(CLASS_TYPE_WILDER,         oCreature) ||
+              GetLevelByClass(CLASS_TYPE_FIST_OF_ZUOKEN, oCreature) ||
+              GetLevelByClass(CLASS_TYPE_WARMIND,        oCreature) ||
+              GetHasFeat(FEAT_WILD_TALENT,               oCreature) ||
+              GetHasFeat(FEAT_KALASHTAR_PP,              oCreature) ||
+              GetHasFeat(FEAT_NATPSIONIC_1,              oCreature) ||
+              GetHasFeat(FEAT_NATPSIONIC_2,              oCreature) ||
+              GetHasFeat(FEAT_NATPSIONIC_3,              oCreature)
+              // Racial psionicity signifying feats go here
+             );
+}
+
+void LocalCleanExtraFists(object oCreature)
+{
+    int iIsCWeap, iIsEquip;
+
+    object oClean = GetFirstItemInInventory(oCreature);
+
+    while (GetIsObjectValid(oClean))
+    {
+        iIsCWeap = GetIsPRCCreatureWeapon(oClean);
+
+        iIsEquip = oClean == GetItemInSlot(INVENTORY_SLOT_CWEAPON_L) ||
+                   oClean == GetItemInSlot(INVENTORY_SLOT_CWEAPON_R) ||
+                   oClean == GetItemInSlot(INVENTORY_SLOT_CWEAPON_B);
+
+        if (iIsCWeap && !iIsEquip)
+        {
+            DestroyObject(oClean);
+        }
+
+        oClean = GetNextItemInInventory(oCreature);
+    }
+}
+object GetPsionicCreatureWeapon(object oCreature, string sResRef, int nInventorySlot, float fDuration)
+{
+    int bCreatedWeapon = FALSE;
+    object oCWeapon = GetItemInSlot(nInventorySlot, oCreature);
+
+    RemoveUnarmedAttackEffects(oCreature);
+    // Make sure they can actually equip them
+    UnarmedFeats(oCreature);
+
+    // Determine if a creature weapon of the proper type already exists in the slot
+    if(!GetIsObjectValid(oCWeapon)                                       ||
+       GetStringUpperCase(GetTag(oCWeapon)) != GetStringUpperCase(sResRef) // Hack: The resref's and tags of the PRC creature weapons are the same
+       )
+    {
+        if (GetHasItem(oCreature, sResRef))
+        {
+            oCWeapon = GetItemPossessedBy(oCreature, sResRef);
+            SetIdentified(oCWeapon, TRUE);
+            //AssignCommand(oCreature, ActionEquipItem(oCWeapon, INVENTORY_SLOT_CWEAPON_L));
+            ForceEquip(oCreature, oCWeapon, nInventorySlot);
+        }
+        else
+        {
+            oCWeapon = CreateItemOnObject(sResRef, oCreature);
+            SetIdentified(oCWeapon, TRUE);
+            //AssignCommand(oCreature, ActionEquipItem(oCWeapon, INVENTORY_SLOT_CWEAPON_L));
+            ForceEquip(oCreature, oCWeapon, nInventorySlot);
+            bCreatedWeapon = TRUE;
+        }
+    }
+
+
+    // Clean up the mess of extra fists made on taking first level.
+    DelayCommand(6.0f, LocalCleanExtraFists(oCreature));
+
+    // Weapon finesse or intuitive attack?
+    SetLocalInt(oCreature, "UsingCreature", TRUE);
+    ExecuteScript("prc_intuiatk", oCreature);
+    DelayCommand(1.0f, DeleteLocalInt(oCreature, "UsingCreature"));
+
+    // Add OnHitCast: Unique if necessary
+    if(GetHasFeat(FEAT_REND, oCreature))
+        IPSafeAddItemProperty(oCWeapon, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 0.0f, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+
+    // This adds creature weapon finesse
+    ApplyUnarmedAttackEffects(oCreature);
+
+    // Destroy the weapon if it was created by this function
+    if(bCreatedWeapon)
+        DestroyObject(oCWeapon, (fDuration + 6.0));
+
+    return oCWeapon;
+}
+
+int GetTargetSpecificChangesToDamage(object oTarget, object oManifester, int nDamage,
+                                     int bIsHitPointDamage = TRUE, int bIsEnergyDamage = FALSE)
+{
+    // Greater Power Specialization - +2 damage on all HP-damaging powers when target is within 30ft
+    if(bIsHitPointDamage                                                &&
+       GetHasFeat(FEAT_GREATER_POWER_SPECIALIZATION, oManifester)       &&
+       GetDistanceBetween(oTarget, oManifester) <= FeetToMeters(30.0f)
+       )
+            nDamage += 2;
+    // Intellect Fortress - Halve damage dealt by powers that allow PR. Goes before DR (-like) reductions
+    if(GetLocalInt(oTarget, "PRC_Power_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;
+    
+    if (GetIsMeldBound(oManifester, MELD_PSYCHIC_FOCUS) == CHAKRA_THROAT && nDamage > 0 && !GetLocalInt(oManifester, "PsychicFocusMeld") && bIsHitPointDamage)
+    {
+    	SetLocalInt(oManifester, "PsychicFocusMeld", TRUE);
+    	DelayCommand(6.0, DeleteLocalInt(oManifester, "PsychicFocusMeld"));
+       	int nClass = GetMeldShapedClass(oManifester, MELD_PSYCHIC_FOCUS);
+		int nDC = GetMeldshaperDC(oManifester, nClass, MELD_PSYCHIC_FOCUS);
+    	if(PRCMySavingThrow(SAVING_THROW_FORT, oTarget, nDC, SAVING_THROW_TYPE_NONE))
+    		ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDazed(), oTarget, 6.0);
+    }
+
+    return nDamage;
+}
+
+int PracticedManifesting(object oManifester, int iManifestingClass, int iManifestingLevels)
+{
+    int nFeat;
+    int iAdjustment = GetHitDice(oManifester) - iManifestingLevels;
+    iAdjustment = iAdjustment > 4 ? 4 : iAdjustment < 0 ? 0 : iAdjustment;
+
+    switch(iManifestingClass)
+    {
+        case CLASS_TYPE_PSION:          nFeat = FEAT_PRACTICED_MANIFESTER_PSION;          break;
+        case CLASS_TYPE_PSYWAR:         nFeat = FEAT_PRACTICED_MANIFESTER_PSYWAR;         break;
+        case CLASS_TYPE_PSYCHIC_ROGUE:  nFeat = FEAT_PRACTICED_MANIFESTER_PSYROG;         break;
+        case CLASS_TYPE_WILDER:         nFeat = FEAT_PRACTICED_MANIFESTER_WILDER;         break;
+        case CLASS_TYPE_WARMIND:        nFeat = FEAT_PRACTICED_MANIFESTER_WARMIND;        break;
+        case CLASS_TYPE_FIST_OF_ZUOKEN: nFeat = FEAT_PRACTICED_MANIFESTER_FIST_OF_ZUOKEN; break;
+        default: nFeat = -1;
+    }
+
+    if(GetHasFeat(nFeat, oManifester))
+        return iAdjustment;
+
+    return 0;
+}
+
+int GetManifesterLevel(object oManifester, int nSpecificClass = CLASS_TYPE_INVALID, int nMaxPowerLevel = FALSE)
+{
+    int nLevel;
+    int nAdjust = GetLocalInt(oManifester, PRC_CASTERLEVEL_ADJUSTMENT);
+    nAdjust -= GetLocalInt(oManifester, "WoLManifPenalty");
+
+    // The function user needs to know the character's manifester level in a specific class
+    // instead of whatever the character last manifested a power as
+    if(nSpecificClass != CLASS_TYPE_INVALID)
+    {
+        if(GetIsPsionicClass(nSpecificClass))
+        {
+            nLevel = GetLevelByClass(nSpecificClass, oManifester);
+            // Add levels from +ML PrCs only for the first manifesting class
+            if(nSpecificClass == GetPrimaryPsionicClass(oManifester))
+                nLevel += GetPsionicPRCLevels(oManifester);
+                
+			// Psionic vestiges are tucked in here to override things.
+			// This assumes that there will never be a psion with this spell effect manifesting things
+            if (nSpecificClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ARETE, oManifester) && !nMaxPowerLevel)
+            {
+            	nLevel = GetLocalInt(oManifester, "AretePsion");
+            	nMaxPowerLevel = TRUE;
+            }  
+            if (nSpecificClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_THETRIAD, oManifester) && !nMaxPowerLevel)
+            {
+            	nLevel = GetLocalInt(oManifester, "TheTriadPsion");
+            	nMaxPowerLevel = TRUE;
+            }
+            if (nSpecificClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ABYSM, oManifester) && !nMaxPowerLevel)
+            {
+            	nLevel = GetLocalInt(oManifester, "AbysmPsion");
+            	nMaxPowerLevel = TRUE;
+            }            
+                
+            // This is for learning powers, we need to ignore some adjustments    
+            if (nMaxPowerLevel) return nLevel;   
+
+            nLevel += PracticedManifesting(oManifester, nSpecificClass, nLevel); //gotta be the last one
+
+            return nLevel + nAdjust;
+        }
+        // A character's manifester level gained from non-manifesting classes is always a nice, round zero
+        else
+            return 0;
+    }
+
+    // Item Spells
+    if(GetItemPossessor(GetSpellCastItem()) == oManifester)
+    {
+        if(DEBUG) SendMessageToPC(oManifester, "Item casting at level " + IntToString(GetCasterLevel(oManifester)));
+
+        return GetCasterLevel(oManifester) + nAdjust;
+    }
+
+    // For when you want to assign the caster level.
+    else if(GetLocalInt(oManifester, PRC_CASTERLEVEL_OVERRIDE) != 0)
+    {
+        if(DEBUG) SendMessageToPC(oManifester, "Forced-level manifesting at level " + IntToString(GetCasterLevel(oManifester)));
+
+        DelayCommand(1.0, DeleteLocalInt(oManifester, PRC_CASTERLEVEL_OVERRIDE));
+        nLevel = GetLocalInt(oManifester, PRC_CASTERLEVEL_OVERRIDE);
+    }
+    else if(GetManifestingClass(oManifester) != CLASS_TYPE_INVALID)
+    {
+        //Gets the manifesting class
+        int nManifestingClass = GetManifestingClass(oManifester);
+//        if(DEBUG) DoDebug("Manifesting class: " + IntToString(nManifestingClass), oManifester);
+        nLevel = GetLevelByClass(nManifestingClass, oManifester);
+        // Add levels from +ML PrCs only for the first manifesting class
+        nLevel += nManifestingClass == GetPrimaryPsionicClass(oManifester) ? GetPsionicPRCLevels(oManifester) : 0;
+        
+		// Psionic vestiges are tucked in here to override things.
+		// This assumes that there will never be a psion with this spell effect manifesting things
+        if (nManifestingClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ARETE, oManifester) && !nMaxPowerLevel)
+        {
+        	nLevel = GetLocalInt(oManifester, "AretePsion");
+        	nMaxPowerLevel = TRUE;
+        }  
+        if (nManifestingClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_THETRIAD, oManifester) && !nMaxPowerLevel)
+        {
+        	nLevel = GetLocalInt(oManifester, "TheTriadPsion");
+        	nMaxPowerLevel = TRUE;
+        }        
+        if (nManifestingClass == CLASS_TYPE_PSION && GetHasSpellEffect(VESTIGE_ABYSM, oManifester) && !nMaxPowerLevel)
+        {
+        	nLevel = GetLocalInt(oManifester, "AbysmPsion");
+        	nMaxPowerLevel = TRUE;
+        }         
+        
+        // This is for learning powers, we need to ignore some adjustments    
+        if (nMaxPowerLevel) return nLevel;   
+
+        nLevel += PracticedManifesting(oManifester, nManifestingClass, nLevel); //gotta be the last one
+//        if(DEBUG) DoDebug("Level gotten via GetLevelByClass: " + IntToString(nLevel), oManifester);
+    }
+    
+    // If you have a primary psionic class and no manifester level yet, get levels based on that
+    if (GetPrimaryPsionicClass(oManifester) && nLevel == 0) 
+    {
+    	int nClass = GetPrimaryPsionicClass(oManifester);
+    	nLevel = GetLevelByClass(nClass, oManifester);
+        nLevel += GetPsionicPRCLevels(oManifester);
+        nLevel += PracticedManifesting(oManifester, nClass, nLevel); //gotta be the last one
+    }
+
+    // If everything else fails, you are not a manifester
+    if(nLevel == 0)
+    {
+        if(DEBUG)             DoDebug("Failed to get manifester level for creature " + DebugObject2Str(oManifester) + ", using first class slot");
+        //else WriteTimestampedLogEntry("Failed to get manifester level for creature " + DebugObject2Str(oManifester) + ", using first class slot");
+
+        return 0;
+    }
+
+
+    // The bonuses inside only apply to normal manifestation
+    if(!GetLocalInt(oManifester, PRC_IS_PSILIKE))
+    {
+        //Adding wild surge
+        int nSurge = GetWildSurge(oManifester);
+        if (nSurge > 0) nLevel += nSurge;
+
+        // Adding overchannel
+        int nOverchannel = GetLocalInt(oManifester, PRC_OVERCHANNEL);
+        if(nOverchannel > 0) nLevel += nOverchannel;
+        
+        // Adding Soul Manifester
+        nLevel += Soulcaster(oManifester, PRCGetSpellId());
+    }
+
+    nLevel += nAdjust;
+
+    // This spam is technically no longer necessary once the manifester level getting mechanism has been confirmed to work
+//    if(DEBUG) FloatingTextStringOnCreature("Manifester Level: " + IntToString(nLevel), oManifester, FALSE);
+
+    return nLevel;
+}
+
+int GetHighestManifesterLevel(object oCreature)
+{
+	int n = 0;
+	int nHighest;
+	int nTemp;
+	
+    while(n <= 8)
+	{
+		if(GetClassByPosition(n, oCreature) != CLASS_TYPE_INVALID)
+		{
+			nTemp = GetManifesterLevel(oCreature, GetClassByPosition(n, oCreature));
+			
+			if(nTemp > nHighest) 
+				nHighest = nTemp;
+		}
+	n++;
+
+	}
+	
+	return nHighest;
+}
+
+/* int GetHighestManifesterLevel(object oCreature)
+{
+    return max(max(GetClassByPosition(1, oCreature) != CLASS_TYPE_INVALID ? GetManifesterLevel(oCreature, GetClassByPosition(1, oCreature)) : 0,
+                   GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID ? GetManifesterLevel(oCreature, GetClassByPosition(2, oCreature)) : 0
+                   ),
+               GetClassByPosition(3, oCreature) != CLASS_TYPE_INVALID ? GetManifesterLevel(oCreature, GetClassByPosition(3, oCreature)) : 0
+               );
+} */
+
+int GetPowerLevel(object oManifester)
+{
+    return GetLocalInt(oManifester, PRC_POWER_LEVEL);
+}
+
+int GetAbilityScoreOfClass(object oManifester, int nClass)
+{
+    return GetAbilityScore(oManifester, GetAbilityOfClass(nClass));
+}
+
+int GetManifestingClass(object oManifester = OBJECT_SELF)
+{
+    return GetLocalInt(oManifester, PRC_MANIFESTING_CLASS) - 1;
+}
+
+int GetAbilityOfClass(int nClass)
+{
+    switch(nClass)
+    {
+        case CLASS_TYPE_DIAMOND_DRAGON:
+        case CLASS_TYPE_PSION:
+        case CLASS_TYPE_PSYCHIC_ROGUE:
+            return ABILITY_INTELLIGENCE;
+        case CLASS_TYPE_PSYWAR:
+        case CLASS_TYPE_FIST_OF_ZUOKEN:
+        case CLASS_TYPE_WARMIND:
+            return ABILITY_WISDOM;
+        case CLASS_TYPE_WILDER:
+            return ABILITY_CHARISMA;
+    }
+
+    // If there's no class, it's racial. Use Charisma
+    return ABILITY_CHARISMA;
+}
+
+int GetPrimaryPsionicClass(object oCreature = OBJECT_SELF)
+{
+    int nClass;
+
+    if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE))
+    {
+        int iPsionicPos = GetFirstPsionicClassPosition(oCreature);
+        if (!iPsionicPos) return CLASS_TYPE_INVALID; // no Psionic casting class
+
+        nClass = GetClassByPosition(iPsionicPos, 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(GetIsPsionicClass(nClass1)) nClass1Lvl = GetLevelByClass(nClass1, oCreature);
+        if(GetIsPsionicClass(nClass2)) nClass2Lvl = GetLevelByClass(nClass2, oCreature);
+        if(GetIsPsionicClass(nClass3)) nClass3Lvl = GetLevelByClass(nClass3, oCreature);		
+        if(GetIsPsionicClass(nClass4)) nClass4Lvl = GetLevelByClass(nClass4, oCreature);
+        if(GetIsPsionicClass(nClass5)) nClass5Lvl = GetLevelByClass(nClass5, oCreature);
+        if(GetIsPsionicClass(nClass6)) nClass6Lvl = GetLevelByClass(nClass6, oCreature);
+        if(GetIsPsionicClass(nClass7)) nClass7Lvl = GetLevelByClass(nClass7, oCreature);
+        if(GetIsPsionicClass(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 GetPsionicPRCLevels(object oCreature)
+{
+    int nLevel = 0;
+
+    // Cerebremancer and Psychic Theurge add manifester levels on each level
+    nLevel += GetLevelByClass(CLASS_TYPE_CEREBREMANCER, oCreature);
+    nLevel += GetLevelByClass(CLASS_TYPE_PSYCHIC_THEURGE, oCreature);
+    if (GetFirstPsionicClassPosition(oCreature)) nLevel += GetLevelByClass(CLASS_TYPE_SOULCASTER, oCreature);
+
+    // No manifester level boost at level 1 and 10 for Thrallherd
+    if(GetLevelByClass(CLASS_TYPE_THRALLHERD, oCreature))
+    {
+        nLevel += GetLevelByClass(CLASS_TYPE_THRALLHERD, oCreature) - 1;
+        if(GetLevelByClass(CLASS_TYPE_THRALLHERD, oCreature) >= 10) nLevel -= 1;
+    }
+    // No manifester level boost at levels 2, 5 and 8 for Shadow Mind
+    if(GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature))
+    {
+        nLevel += GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature);
+        if(GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature) >= 2) nLevel -= 1;
+        if(GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature) >= 5) nLevel -= 1;
+        if(GetLevelByClass(CLASS_TYPE_SHADOWMIND, oCreature) >= 8) nLevel -= 1;
+    }
+    // No manifester level boost at level 1 and 6 for Iron Mind
+    if(GetLevelByClass(CLASS_TYPE_IRONMIND, oCreature))
+    {
+        nLevel += GetLevelByClass(CLASS_TYPE_IRONMIND, oCreature) - 1;
+        if(GetLevelByClass(CLASS_TYPE_IRONMIND, oCreature) >= 6) nLevel -= 1;
+    }
+    // No manifester level boost at level 1 and 6 for Diamond Dragon
+    if(GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oCreature))
+    {
+        nLevel += GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oCreature) - 1;
+        if(GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oCreature) >= 6) nLevel -= 1;
+    }
+    // No manifester level boost at level 1 for Sanctified Mind
+    if(GetLevelByClass(CLASS_TYPE_SANCTIFIED_MIND, oCreature))
+    {
+        nLevel += GetLevelByClass(CLASS_TYPE_SANCTIFIED_MIND, oCreature) - 1;
+    }
+
+    return nLevel;
+}
+
+int GetFirstPsionicClassPosition(object oCreature = OBJECT_SELF)
+{
+    if (GetIsPsionicClass(GetClassByPosition(1, oCreature)))
+        return 1;
+    if (GetIsPsionicClass(GetClassByPosition(2, oCreature)))
+        return 2;
+    if (GetIsPsionicClass(GetClassByPosition(3, oCreature)))
+        return 3;
+    if (GetIsPsionicClass(GetClassByPosition(4, oCreature)))
+        return 4;
+    if (GetIsPsionicClass(GetClassByPosition(5, oCreature)))
+        return 5;
+    if (GetIsPsionicClass(GetClassByPosition(6, oCreature)))
+        return 6;
+    if (GetIsPsionicClass(GetClassByPosition(7, oCreature)))
+        return 7;
+    if (GetIsPsionicClass(GetClassByPosition(8, oCreature)))
+        return 8;
+	
+    return 0;
+}
+
+int GetIsPsionicClass(int nClass)
+{
+    return (nClass==CLASS_TYPE_PSION
+          || nClass==CLASS_TYPE_PSYWAR
+          || nClass==CLASS_TYPE_PSYCHIC_ROGUE
+          || nClass==CLASS_TYPE_WILDER
+          || nClass==CLASS_TYPE_FIST_OF_ZUOKEN
+          || nClass==CLASS_TYPE_WARMIND
+            );
+}
+
+int GetWildSurge(object oManifester)
+{
+    int nWildSurge = GetLocalInt(oManifester, PRC_IS_PSILIKE) ?
+                      0 :                                       // Wild Surge does not apply to psi-like abilities
+                      GetLocalInt(oManifester, PRC_WILD_SURGE);
+
+    if(DEBUG) DoDebug("GetWildSurge():\n"
+                    + "oManifester = " + DebugObject2Str(oManifester) + "\n"
+                    + "nWildSurge = " + IntToString(nWildSurge) + "\n"
+                      );
+
+    return nWildSurge;
+}
+
+int GetMaxPowerLevel(object oManifester)
+{
+	int nClass = GetPrimaryPsionicClass(oManifester);
+    string sFile = GetAMSKnownFileName(nClass);
+    int nLevel = GetHighestManifesterLevel(oManifester);
+    int nMax = StringToInt(Get2DACache(sFile, "MaxPowerLevel", nLevel));
+    if (DEBUG) DoDebug("GetMaxPowerLevel is "+IntToString(nMax));
+    return nMax;
+}
\ No newline at end of file
diff --git a/trunk/include/shd_inc_shdfunc.nss b/trunk/include/shd_inc_shdfunc.nss
new file mode 100644
index 00000000..ce4d0590
--- /dev/null
+++ b/trunk/include/shd_inc_shdfunc.nss
@@ -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;
+}
\ No newline at end of file
diff --git a/trunk/include/tob_inc_recovery.nss b/trunk/include/tob_inc_recovery.nss
new file mode 100644
index 00000000..9517730f
--- /dev/null
+++ b/trunk/include/tob_inc_recovery.nss
@@ -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"));
+}
\ No newline at end of file
diff --git a/trunk/include/tob_inc_tobfunc.nss b/trunk/include/tob_inc_tobfunc.nss
new file mode 100644
index 00000000..04230160
--- /dev/null
+++ b/trunk/include/tob_inc_tobfunc.nss
@@ -0,0 +1,1261 @@
+//::///////////////////////////////////////////////
+//:: Tome of Battle include: Miscellaneous
+//:: tob_inc_tobfunc
+//::///////////////////////////////////////////////
+/** @file
+    Defines various functions and other stuff that
+    do something related to the Tome of Battle implementation.
+
+    Also acts as inclusion nexus for the general
+    tome of battle includes. In other words, don't include
+    them directly in your scripts, instead include this.
+
+    @author Stratovarius
+    @date   Created - 2007.3.19
+*/
+//:://////////////////////////////////////////////
+//:://////////////////////////////////////////////
+
+//:: Updated for .35 by Jaysyn 2023/03/11
+
+//:: Test Void
+//void main (){}
+
+//////////////////////////////////////////////////
+/*                 Constants                    */
+//////////////////////////////////////////////////
+
+const int DISCIPLINE_DESERT_WIND    =   1;
+const int DISCIPLINE_DEVOTED_SPIRIT =   2;
+const int DISCIPLINE_DIAMOND_MIND   =   4;
+const int DISCIPLINE_IRON_HEART     =   8;
+const int DISCIPLINE_SETTING_SUN    =  16;
+const int DISCIPLINE_SHADOW_HAND    =  32;
+const int DISCIPLINE_STONE_DRAGON   =  64;
+const int DISCIPLINE_TIGER_CLAW     = 128;
+const int DISCIPLINE_WHITE_RAVEN    = 256;
+
+const string PRC_INITIATING_CLASS        = "PRC_CurrentManeuver_InitiatingClass";
+const string PRC_MANEUVER_LEVEL          = "PRC_CurrentManeuver_Level";
+
+const int MANEUVER_TYPE_STANCE            = 1;
+const int MANEUVER_TYPE_STRIKE            = 2;
+const int MANEUVER_TYPE_COUNTER           = 3;
+const int MANEUVER_TYPE_BOOST             = 4;
+//global constant (strike & counter & boost)
+const int MANEUVER_TYPE_MANEUVER          = 5;
+
+//////////////////////////////////////////////////
+/*             Function prototypes              */
+//////////////////////////////////////////////////
+
+/**
+ * Determines from what class's maneuver list the currently being initiated
+ * maneuver is initiated from.
+ *
+ * @param oInitiator A creature initiating a maneuver at this moment
+ * @return            CLASS_TYPE_* constant of the class
+ */
+int GetInitiatingClass(object oInitiator = OBJECT_SELF);
+
+/**
+ * Determines the given creature's Initiator level. If a class is specified,
+ * then returns the Initiator level for that class. Otherwise, returns
+ * the Initiator level for the currently active maneuver.
+ *
+ * @param oInitiator   The creature whose Initiator level to determine
+ * @param nSpecificClass The class to determine the creature's Initiator
+ *                       level in.
+ *                       DEFAULT: CLASS_TYPE_INVALID, which means the creature's
+ *                       Initiator level in regards to an ongoing maneuver
+ *                       is determined instead.
+ * @return               The Initiator level
+ */
+int GetInitiatorLevel(object oInitiator = OBJECT_SELF, int nSpecificClass = CLASS_TYPE_INVALID);
+
+/**
+ * Determines whether a given creature uses BladeMagic.
+ * Requires either levels in a BladeMagic-related class or
+ * natural BladeMagic ability based on race.
+ *
+ * @param oCreature Creature to test
+ * @return          TRUE if the creature can use BladeMagics, FALSE otherwise.
+ */
+int GetIsBladeMagicUser(object oCreature);
+
+/**
+ * Determines the given creature's highest undmodified Initiator level among it's
+ * initiating classes.
+ *
+ * @param oCreature Creature whose highest Initiator level to determine
+ * @return          The highest unmodified Initiator level the creature can have
+ */
+int GetHighestInitiatorLevel(object oCreature);
+
+/**
+ * Determines whether a given class is a BladeMagic-related class or not.
+ *
+ * @param nClass CLASS_TYPE_* of the class to test
+ * @return       TRUE if the class is a BladeMagic-related class, FALSE otherwise
+ */
+int GetIsBladeMagicClass(int nClass);
+
+/**
+ * Gets the level of the maneuver being currently initiated or the level
+ * of the maneuver ID passed to it.
+ *
+ * @param oInitiator The creature currently initiating a maneuver
+ * @return            The level of the maneuver being initiated
+ */
+int GetManeuverLevel(object oInitiator, int nMoveId = 0);
+
+/**
+ * Returns the type of the maneuver
+ *
+ * @param nSpellId        SpellId of the maneuver
+ */
+int GetManeuverType(int nSpellId);
+
+/**
+ * Returns the name of the maneuver
+ *
+ * @param nSpellId        SpellId of the maneuver
+ */
+string GetManeuverName(int nSpellId);
+
+/**
+ * Returns the name of the Discipline
+ *
+ * @param nDiscipline        DISCIPLINE_* to name
+ */
+string GetDisciplineName(int nDiscipline);
+
+/**
+ * Returns the Discipline the maneuver is in
+ * @param nMoveId    maneuver to check
+ *
+ * @return           DISCIPLINE_*
+ */
+int GetDisciplineByManeuver(int nMoveId);
+
+/**
+ * Returns true or false if the initiator has the Discipline
+ * @param oInitiator    Person to check
+ * @param nDiscipline   Discipline to check
+ *
+ * @return           TRUE or FALSE
+ */
+int TOBGetHasDiscipline(object oInitiator, int nDiscipline);
+
+/**
+ * Returns true or false if the swordsage has Discipline
+ * focus in the chosen discipline
+ * @param oInitiator    Person to check
+ * @param nDiscipline   Discipline to check
+ *
+ * @return           TRUE or FALSE
+ */
+int TOBGetHasDisciplineFocus(object oInitiator, int nDiscipline);
+
+/**
+ * Calculates how many initiator levels are gained by a given creature from
+ * it's levels in prestige classes.
+ *
+ * @param oCreature Creature to calculate added initiator levels for
+ * @return          The number of initiator levels gained
+ */
+int GetBladeMagicPRCLevels(object oInitiator);
+
+/**
+ * Determines which of the character's classes is their highest or first blade magic
+ * initiating class, if any. This is the one which gains initiator level raise benefits
+ * from prestige classes.
+ *
+ * @param oCreature Creature whose classes to test
+ * @return          CLASS_TYPE_* of the first blade magic initiating class,
+ *                  CLASS_TYPE_INVALID if the creature does not possess any.
+ */
+int GetPrimaryBladeMagicClass(object oCreature = OBJECT_SELF);
+
+/**
+ * Determines the position of a creature's first blade magic initiating class, if any.
+ *
+ * @param oCreature Creature whose classes to test
+ * @return          The position of the first blade magic class {1, 2, 3} or 0 if
+ *                  the creature possesses no levels in blade magic classes.
+ */
+int GetFirstBladeMagicClassPosition(object oCreature = OBJECT_SELF);
+
+/**
+ * Checks whether the PC has the prereqs for the maneuver
+ *
+ * @param nClass The class that is trying to learn the feat
+ * @param nFeat The maneuver's FeatId
+ * @param oPC   The creature whose feats to check
+ * @return      TRUE if the PC possesses the prerequisite feats AND does not
+ *              already posses nFeat, FALSE otherwise.
+ */
+int CheckManeuverPrereqs(int nClass, int nPrereqs, int nDiscipline, object oPC);
+
+/**
+ * Checks whether the maneuver is supernatural or not
+ * Mainly used to check for AMF areas.
+ * Mostly from Swordsage maneuvers
+ *
+ * @param nMoveId The Maneuver to Check
+ * @return        TRUE if Maneuver is (Su), else FALSE
+ */
+int GetIsManeuverSupernatural(int nMoveId);
+
+/**
+ * Checks whether the initiator has an active stance
+ *
+ * @param oInitiator The Initiator
+ * @return        The SpellId or FALSE
+ */
+int GetHasActiveStance(object oInitiator);
+
+/**
+ * Clears spell effects for Stances
+ * Will NOT clear nDontClearMove
+ *
+ * @param oInitiator The Initiator
+ * @param nDontClearMove A single Stance not to clear
+ */
+void ClearStances(object oInitiator, int nDontClearMove);
+
+/**
+ * Marks a stance active via local ints
+ *
+ * @param oInitiator The Initiator
+ * @param nStance    The stance to mark active
+ */
+void MarkStanceActive(object oInitiator, int nStance);
+
+/**
+ * This will take an effect that is supposed to be based on size
+ * And use vs racial effects to approximate it
+ *
+ * @param oInitiator The Initiator
+ * @param eEffect    The effect to scale
+ * @param nSize      0 affects creature one size or more smaller.
+ *                   1 affects creatures one size or more larger
+ */
+effect VersusSizeEffect(object oInitiator, effect eEffect, int nSize);
+
+/**
+ * Checks every 6 seconds whether an adept has moved too far for a stance
+ * Or whether the adept has moved far enough to get a bonus from a stance
+ *
+ * @param oPC        The Initiator
+ * @param nMoveId    The stance
+ * @param fFeet      The distance to check
+ */
+void InitiatorMovementCheck(object oPC, int nMoveId, float fFeet = 10.0);
+
+/**
+ * Checks whether the maneuver is a stance
+ *
+ * @param nMoveId    The Maneuver
+ * @return           TRUE or FALSE
+ */
+int GetIsStance(int nMoveId);
+
+/**
+ * Sets up everything for the Damage boosts (xd6 + IL fire damage)
+ * That the Desert Wind discipline has.
+ *
+ * @param oPC      The PC
+ */
+void DoDesertWindBoost(object oPC);
+
+/**
+ * Determines which PC in the area is weakest, and
+ * returns that PC.
+ *
+ * @param oPC      The PC
+ * @param fDistance The distance to check in feet
+ * @return         The Target
+ */
+object GetCrusaderHealTarget(object oPC, float fDistance);
+
+/**
+ * Returns true or false if the swordsage has Insightful Strike in the chosen discipline
+ * @param oInitiator    Person to check
+ *
+ * @return              TRUE or FALSE
+ */
+int GetHasInsightfulStrike(object oInitiator);
+
+/**
+ * Returns true or false if the swordsage has Defensive Stance
+ * ONLY CALL THIS FROM WITHIN STANCES
+ * @param oInitiator    Person to check
+ * @param nDiscipline   DISCIPLINE_ constant of the school of the maneuver.
+ *
+ * @return              TRUE or FALSE
+ */
+int GetHasDefensiveStance(object oInitiator, int nDiscipline);
+
+/**
+ * Returns true if it is a weapon of the appropriate discipline
+ * @param oWeapon       Weapon to check
+ * @param nDiscipline   DISCIPLINE_ constant of the school of the maneuver.
+ *
+ * @return              TRUE or FALSE
+ */
+int GetIsDisciplineWeapon(object oWeapon, int nDiscipline);
+
+/**
+ * Returns a numerical bonus to attacks for use in strikes
+ * @param oInitiator    Person to check
+ * @param nDiscipline   DISCIPLINE_ constant of the school of the maneuver.
+ * @param nClass        CLASS_TYPE_ constant
+ *
+ * @return              Bonus total
+ */
+int TOBSituationalAttackBonuses(object oInitiator, int nDiscipline, int nClass = CLASS_TYPE_INVALID);
+
+/**
+ * Returns the skill for the named discipline
+ * @param nDiscipline   DISCIPLINE_ constant
+ *
+ * @return              Discipline skill
+ */
+int GetDisciplineSkill(int nDiscipline);
+
+/**
+ * Returns the discipline for the Blade Meditation feat
+ * @param oInitiator    Person to check
+ *
+ * @return              DISCIPLINE_ constant
+ */
+int BladeMeditationFeat(object oInitiator);
+
+/**
+ * Returns 1 if feat and maneuver match
+ * @param oInitiator    Person to check
+ * @param nMoveId       Maneuver to check
+ *
+ * @return              1 or -1
+ */
+int BladeMeditationDamage(object oInitiator, int nMoveId);
+
+//////////////////////////////////////////////////
+/*                  Includes                    */
+//////////////////////////////////////////////////
+
+#include "tob_move_const"
+#include "prc_alterations"
+#include "tob_inc_moveknwn"
+
+//////////////////////////////////////////////////
+/*             Internal functions               */
+//////////////////////////////////////////////////
+
+
+int _CheckPrereqsByDiscipline(object oPC, int nDiscipline, int nCount = 1)
+{
+    int nPrereqCount = GetManeuverCountByDiscipline(oPC, nDiscipline, MANEUVER_TYPE_MANEUVER)
+                      + GetManeuverCountByDiscipline(oPC, nDiscipline, MANEUVER_TYPE_STANCE);
+
+    if(nPrereqCount >= nCount)
+        return nPrereqCount;
+
+    return 0;
+}
+
+void _RecursiveStanceCheck(object oPC, object oTestWP, int nMoveId, float fFeet = 10.0)
+{
+    // Seeing if this works better
+    string sWPTag = "PRC_BMWP_" + GetName(oPC) + IntToString(nMoveId);
+    oTestWP = GetWaypointByTag(sWPTag);
+    // Distance moved in the last round
+    float fDist = FeetToMeters(GetDistanceBetween(oPC, oTestWP));
+    // Giving them a little extra distance because of NWN's dance of death
+    float fCheck = FeetToMeters(fFeet);
+    if(DEBUG) DoDebug("_RecursiveStanceCheck: fDist: " + FloatToString(fDist));
+    if(DEBUG) DoDebug("_RecursiveStanceCheck: fCheck: " + FloatToString(fCheck));
+    if(DEBUG) DoDebug("_RecursiveStanceCheck: nMoveId: " + IntToString(nMoveId));
+
+
+    // Moved the distance
+    if (fDist >= fCheck)
+    {
+        if(DEBUG) DoDebug("_RecursiveStanceCheck: fDist > fCheck");
+        // Stances that clean up
+        if (nMoveId == MOVE_SD_STONEFOOT_STANCE)
+        {
+                PRCRemoveEffectsFromSpell(oPC, nMoveId);
+                if(DEBUG) DoDebug("_RecursiveStanceCheck: Moved too far, cancelling stances.");
+                // Clean up the test WP as well
+                DestroyObject(oTestWP);
+        }
+        // Stances that clean up
+        else if (nMoveId == MOVE_MOUNTAIN_FORTRESS)
+        {
+                PRCRemoveEffectsFromSpell(oPC, nMoveId);
+                if(DEBUG) DoDebug("_RecursiveStanceCheck: Moved too far, cancelling stances.");
+                // Clean up the test WP as well
+                DestroyObject(oTestWP);
+        }
+        // Stances that clean up
+        else if (nMoveId == MOVE_SD_ROOT_MOUNTAIN)
+        {
+                PRCRemoveEffectsFromSpell(oPC, nMoveId);
+                if(DEBUG) DoDebug("_RecursiveStanceCheck: Moved too far, cancelling stances.");
+                // Clean up the test WP as well
+                DestroyObject(oTestWP);
+        }
+        else if (nMoveId == MOVE_SH_CHILD_SHADOW)
+        {
+                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, SupernaturalEffect(EffectConcealment(20)), oPC, 6.0);
+                if(DEBUG) DoDebug("_RecursiveStanceCheck: Applying bonuses.");
+                // Clean up the test WP
+                DestroyObject(oTestWP);
+                // Create waypoint for the movement for next round
+                CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oPC), FALSE, sWPTag);
+        }
+        else if (nMoveId == MOVE_IH_ABSOLUTE_STEEL)
+        {
+                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, ExtraordinaryEffect(EffectACIncrease(2)), oPC, 6.0);
+                if(DEBUG) DoDebug("_RecursiveStanceCheck: Applying bonuses.");
+                // Clean up the test WP
+                DestroyObject(oTestWP);
+                // Create waypoint for the movement for next round
+                CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oPC), FALSE, sWPTag);
+        }
+
+        else if (nMoveId == MOVE_SD_GIANTS_STANCE)
+        {
+                DeleteLocalInt(oPC, "DWGiantsStance");
+                DeleteLocalInt(oPC, "PRC_Power_Expansion_SizeIncrease");
+                PRCRemoveEffectsFromSpell(oPC, nMoveId);
+                DestroyObject(oTestWP);
+        }
+
+        else if (nMoveId == MOVE_IH_DANCING_BLADE_FORM)
+        {
+                DeleteLocalInt(oPC, "DWDancingBladeForm");
+                DestroyObject(oTestWP);
+        }
+
+    }
+    // If they still have the spell, keep going
+    if (GetHasSpellEffect(nMoveId, oPC))
+    {
+        DelayCommand(6.0, _RecursiveStanceCheck(oPC, oTestWP, nMoveId));
+        if(DEBUG) DoDebug("_RecursiveStanceCheck: DelayCommand(6.0, _RecursiveStanceCheck(oPC, oTestWP, nMoveId)).");
+    }
+
+    if(DEBUG) DoDebug("_RecursiveStanceCheck: Exiting");
+}
+
+int _AllowedDiscipline(object oInitiator, int nClass, int nDiscipline)
+{
+    //maneuver choice for prestige classes is restricted only to those disciplines
+    int nOverride = GetPersistantLocalInt(oInitiator, "AllowedDisciplines");
+    if(nOverride == 0)
+    {
+        switch(nClass)
+        {
+            case CLASS_TYPE_CRUSADER:  nOverride = 322; break;//DISCIPLINE_DEVOTED_SPIRIT + DISCIPLINE_STONE_DRAGON + DISCIPLINE_WHITE_RAVEN
+            case CLASS_TYPE_SWORDSAGE: nOverride = 245; break;//DISCIPLINE_DESERT_WIND + DISCIPLINE_DIAMOND_MIND + DISCIPLINE_SETTING_SUN + DISCIPLINE_SHADOW_HAND + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW
+            case CLASS_TYPE_WARBLADE:  nOverride = 460; break;//DISCIPLINE_DIAMOND_MIND + DISCIPLINE_IRON_HEART + DISCIPLINE_STONE_DRAGON + DISCIPLINE_TIGER_CLAW + DISCIPLINE_WHITE_RAVEN
+        }
+    }
+    return nOverride & nDiscipline;
+}
+
+//////////////////////////////////////////////////
+/*             Function definitions             */
+//////////////////////////////////////////////////
+
+int GetInitiatingClass(object oInitiator = OBJECT_SELF)
+{
+    return GetLocalInt(oInitiator, PRC_INITIATING_CLASS) - 1;
+}
+
+int GetInitiatorLevel(object oInitiator = OBJECT_SELF, int nSpecificClass = CLASS_TYPE_INVALID)
+{
+    int nAdjust = GetLocalInt(oInitiator, PRC_CASTERLEVEL_ADJUSTMENT);
+    int nLevel = GetLocalInt(oInitiator, PRC_CASTERLEVEL_OVERRIDE);
+
+    // For when you want to assign the caster level.
+    if(nLevel)
+    {
+        if(DEBUG) SendMessageToPC(oInitiator, "GetInitiatorLevel(): Forced-level initiating at level " + IntToString(nLevel));
+        //DelayCommand(1.0, DeleteLocalInt(oInitiator, PRC_CASTERLEVEL_OVERRIDE));
+        return nLevel + nAdjust;
+    }
+
+    int nTotalHD = GetHitDice(oInitiator);
+
+    // The function user needs to know the character's Initiator level in a specific class
+    // instead of whatever the character last initiated a maneuver as
+    if(nSpecificClass != CLASS_TYPE_INVALID)
+    {
+        if(GetIsBladeMagicClass(nSpecificClass))
+        {
+            // Initiator level is class level + 1/2 levels in all other classes
+            // See ToB p39
+            // Max level is therefor the level plus 1/2 of remaining levels
+            // Prestige classes are stuck in here
+            int nClassLevel = GetLevelByClass(nSpecificClass, oInitiator);
+            if(nClassLevel)
+            {
+                nClassLevel += GetBladeMagicPRCLevels(oInitiator);
+                nLevel = nClassLevel + ((nTotalHD - nClassLevel)/2);
+            }
+        }
+    }
+    else if(GetInitiatingClass(oInitiator) != -1)
+    {
+        int nClassLevel = GetLevelByClass(GetInitiatingClass(oInitiator), oInitiator);
+        nClassLevel += GetBladeMagicPRCLevels(oInitiator);
+        nLevel = nClassLevel + ((nTotalHD - nClassLevel)/2);
+    }
+
+    // A character with no initiator levels has an init level of 1/2 HD (min 1)
+    if(!nLevel)
+        nLevel = max(1, nTotalHD/2);
+
+    // This spam is technically no longer necessary once the Initiator level getting mechanism has been confirmed to work
+//    if(DEBUG) FloatingTextStringOnCreature("Initiator Level: " + IntToString(nLevel), oInitiator, FALSE);
+
+    return nLevel + nAdjust;
+}
+
+int GetIsBladeMagicUser(object oCreature)
+{
+    return !!(GetLevelByClass(CLASS_TYPE_CRUSADER, oCreature)
+            || GetLevelByClass(CLASS_TYPE_SWORDSAGE, oCreature)
+            || GetLevelByClass(CLASS_TYPE_WARBLADE, oCreature));
+}
+
+int GetHighestInitiatorLevel(object oCreature)
+{
+	int n = 0;
+	int nHighest;
+	int nTemp;
+	
+    while(n <= 8)
+	{
+		if(GetClassByPosition(n, oCreature) != CLASS_TYPE_INVALID)
+		{
+			nTemp = GetInitiatorLevel(oCreature, GetClassByPosition(n, oCreature));
+			
+			if(nTemp > nHighest) 
+				nHighest = nTemp;
+		}
+	n++;
+
+	}
+	
+	return nHighest;
+}
+
+/* int GetHighestInitiatorLevel(object oCreature)
+{
+    return max(max(GetClassByPosition(1, oCreature) != CLASS_TYPE_INVALID ? GetInitiatorLevel(oCreature, GetClassByPosition(1, oCreature)) : 0,
+                   GetClassByPosition(2, oCreature) != CLASS_TYPE_INVALID ? GetInitiatorLevel(oCreature, GetClassByPosition(2, oCreature)) : 0
+                   ),
+               GetClassByPosition(3, oCreature) != CLASS_TYPE_INVALID ? GetInitiatorLevel(oCreature, GetClassByPosition(3, oCreature)) : 0
+               );
+} */
+
+int GetIsBladeMagicClass(int nClass)
+{
+    return nClass == CLASS_TYPE_CRUSADER
+         || nClass == CLASS_TYPE_SWORDSAGE
+         || nClass == CLASS_TYPE_WARBLADE;
+}
+
+int GetManeuverLevel(object oInitiator, int nMoveId = 0)
+{
+    int nLevel = GetLocalInt(oInitiator, PRC_MANEUVER_LEVEL);
+    if (nLevel > 0) return nLevel;
+    else if (nMoveId > 0) return StringToInt(lookup_spell_innate(nMoveId));
+    
+    return 0;
+}
+
+string GetManeuverName(int nSpellId)
+{
+    return GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellId)));
+}
+
+int GetManeuverType(int nSpellId)
+{
+    return StringToInt(GetStringRight(Get2DACache("spells", "MetaMagic", nSpellId), 1));
+}
+
+int GetIsStance(int nMoveId)
+{
+    return GetManeuverType(nMoveId) == MANEUVER_TYPE_STANCE;
+}
+
+string GetDisciplineName(int nDiscipline)
+{
+    int nStrRef;
+    switch(nDiscipline)
+    {
+        case DISCIPLINE_DESERT_WIND:    nStrRef = 16829714; break;
+        case DISCIPLINE_DEVOTED_SPIRIT: nStrRef = 16829715; break;
+        case DISCIPLINE_DIAMOND_MIND:   nStrRef = 16829716; break;
+        case DISCIPLINE_IRON_HEART:     nStrRef = 16829717; break;
+        case DISCIPLINE_SETTING_SUN:    nStrRef = 16829718; break;
+        case DISCIPLINE_SHADOW_HAND:    nStrRef = 16829719; break;
+        case DISCIPLINE_STONE_DRAGON:   nStrRef = 16829720; break;
+        case DISCIPLINE_TIGER_CLAW:     nStrRef = 16829721; break;
+        case DISCIPLINE_WHITE_RAVEN:    nStrRef = 16829722; break;
+    }
+    return GetStringByStrRef(nStrRef);
+}
+
+int GetDisciplineByManeuver(int nMoveId)
+{
+    string sSpellSchool = Get2DACache("spells", "School", nMoveId);
+    int nDiscipline;
+
+    if      (sSpellSchool == "A") nDiscipline = DISCIPLINE_DEVOTED_SPIRIT;
+    else if (sSpellSchool == "C") nDiscipline = DISCIPLINE_SETTING_SUN;
+    else if (sSpellSchool == "D") nDiscipline = DISCIPLINE_IRON_HEART;
+    else if (sSpellSchool == "E") nDiscipline = DISCIPLINE_DIAMOND_MIND;
+    else if (sSpellSchool == "V") nDiscipline = DISCIPLINE_DESERT_WIND;
+    else if (sSpellSchool == "I") nDiscipline = DISCIPLINE_SHADOW_HAND;
+    else if (sSpellSchool == "N") nDiscipline = DISCIPLINE_WHITE_RAVEN;
+    else if (sSpellSchool == "T") nDiscipline = DISCIPLINE_TIGER_CLAW;
+    else if (sSpellSchool == "G") nDiscipline = DISCIPLINE_STONE_DRAGON;
+
+    return nDiscipline;
+}
+
+int GetBladeMagicPRCLevels(object oInitiator)
+{
+    int nLevel = GetLevelByClass(CLASS_TYPE_DEEPSTONE_SENTINEL, oInitiator)
+               + GetLevelByClass(CLASS_TYPE_BLOODCLAW_MASTER,   oInitiator)
+               + GetLevelByClass(CLASS_TYPE_RUBY_VINDICATOR,    oInitiator)
+               + GetLevelByClass(CLASS_TYPE_JADE_PHOENIX_MAGE,  oInitiator)
+               + GetLevelByClass(CLASS_TYPE_MASTER_OF_NINE,     oInitiator)
+               + GetLevelByClass(CLASS_TYPE_ETERNAL_BLADE,      oInitiator)
+               + GetLevelByClass(CLASS_TYPE_SHADOW_SUN_NINJA,   oInitiator);
+
+    return nLevel;
+}
+
+int GetPrimaryBladeMagicClass(object oCreature = OBJECT_SELF)
+{
+    int nClass = CLASS_TYPE_INVALID;
+
+    if(GetPRCSwitch(PRC_CASTERLEVEL_FIRST_CLASS_RULE))
+    {
+        int nBladeMagicPos = GetFirstBladeMagicClassPosition(oCreature);
+        if (!nBladeMagicPos) return CLASS_TYPE_INVALID; // no Blade Magic initiating class
+
+        nClass = GetClassByPosition(nBladeMagicPos, oCreature);
+    }
+    else
+    {
+        /*int i, nLevel, nTest, nTestLevel;
+        for(i = 1; i < 4; i++)
+        {
+            nTest = GetClassByPosition(i, oCreature);
+            if(GetIsBladeMagicClass(nTest))
+            {
+                nTestLevel = GetLevelByClass(nTest, oCreature);
+                if(nTestLevel > nLevel)
+                {
+                    nClass = nTest;
+                    nLevel = nTestLevel;
+                }
+            }
+        }*/
+        
+        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(GetIsBladeMagicClass(nClass1)) nClass1Lvl = GetLevelByClass(nClass1, oCreature);
+        if(GetIsBladeMagicClass(nClass2)) nClass2Lvl = GetLevelByClass(nClass2, oCreature);
+        if(GetIsBladeMagicClass(nClass3)) nClass3Lvl = GetLevelByClass(nClass3, oCreature);
+        if(GetIsBladeMagicClass(nClass4)) nClass4Lvl = GetLevelByClass(nClass4, oCreature);
+        if(GetIsBladeMagicClass(nClass5)) nClass5Lvl = GetLevelByClass(nClass5, oCreature);
+        if(GetIsBladeMagicClass(nClass6)) nClass6Lvl = GetLevelByClass(nClass6, oCreature);
+        if(GetIsBladeMagicClass(nClass7)) nClass7Lvl = GetLevelByClass(nClass7, oCreature);
+        if(GetIsBladeMagicClass(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 GetFirstBladeMagicClassPosition(object oCreature = OBJECT_SELF)
+{
+    if (GetIsBladeMagicClass(GetClassByPosition(1, oCreature)))
+        return 1;
+    if (GetIsBladeMagicClass(GetClassByPosition(2, oCreature)))
+        return 2;
+    if (GetIsBladeMagicClass(GetClassByPosition(3, oCreature)))
+        return 3;
+    if (GetIsBladeMagicClass(GetClassByPosition(4, oCreature)))
+        return 4;
+    if (GetIsBladeMagicClass(GetClassByPosition(5, oCreature)))
+        return 5;
+    if (GetIsBladeMagicClass(GetClassByPosition(6, oCreature)))
+        return 6;
+    if (GetIsBladeMagicClass(GetClassByPosition(7, oCreature)))
+        return 7;
+    if (GetIsBladeMagicClass(GetClassByPosition(8, oCreature)))
+        return 8;	
+	
+    return 0;
+}
+
+int CheckManeuverPrereqs(int nClass, int nPrereqs, int nDiscipline, object oPC)
+{
+    // Checking to see what the name of the feat is, and the row number
+    /*if (DEBUG)
+    {
+        DoDebug("CheckManeuverPrereqs: nFeat: " + IntToString(nFeat));
+        string sFeatName = GetStringByStrRef(StringToInt(Get2DACache("feat", "FEAT", nFeat)));
+        DoDebug("CheckManeuverPrereqs: sFeatName: " + sFeatName);
+    }*/
+
+    // Prestige classes can only access certain disciplines
+    if(!_AllowedDiscipline(oPC, nClass, nDiscipline))
+        return FALSE;
+
+    // If this maneuver has a prereq, check for it
+    if(nPrereqs)
+        // if it returns false, exit, otherwise they can take the maneuver
+        return _CheckPrereqsByDiscipline(oPC, nDiscipline, nPrereqs);
+
+    // if you've reached this far then return TRUE
+    return TRUE;
+}
+
+int GetIsManeuverSupernatural(int nMoveId)
+{
+    if(nMoveId == MOVE_DW_BLISTERING_FLOURISH
+    || nMoveId == MOVE_DW_BURNING_BLADE
+    || nMoveId == MOVE_DW_BURNING_BRAND
+    || nMoveId == MOVE_DW_DEATH_MARK
+    || nMoveId == MOVE_DW_DISTRACTING_EMBER
+    || nMoveId == MOVE_DW_DRAGONS_FLAME
+    || nMoveId == MOVE_DW_FAN_FLAMES
+    || nMoveId == MOVE_DW_FIERY_ASSAULT
+    || nMoveId == MOVE_DW_FIRE_RIPOSTE
+    || nMoveId == MOVE_DW_FIRESNAKE
+    || nMoveId == MOVE_DW_FLAMES_BLESSING
+    || nMoveId == MOVE_DW_HATCHLINGS_FLAME
+    || nMoveId == MOVE_DW_HOLOCAUST_CLOAK
+    || nMoveId == MOVE_DW_INFERNO_BLADE
+    || nMoveId == MOVE_DW_INFERNO_BLAST
+    || nMoveId == MOVE_DW_LEAPING_FLAME
+    || nMoveId == MOVE_DW_LINGERING_INFERNO
+    || nMoveId == MOVE_DW_RING_FIRE
+    || nMoveId == MOVE_DW_RISING_PHOENIX
+    || nMoveId == MOVE_DW_SALAMANDER_CHARGE
+    || nMoveId == MOVE_DW_SEARING_BLADE
+    || nMoveId == MOVE_DW_SEARING_CHARGE
+    || nMoveId == MOVE_DW_WYRMS_FLAME
+    || nMoveId == MOVE_SH_BALANCE_SKY
+    || nMoveId == MOVE_SH_CHILD_SHADOW
+    || nMoveId == MOVE_SH_CLINGING_SHADOW
+    || nMoveId == MOVE_SH_CLOAK_DECEPTION
+    || nMoveId == MOVE_SH_ENERVATING_SHADOW
+    || nMoveId == MOVE_SH_FIVE_SHADOW_CREEPING
+    || nMoveId == MOVE_SH_GHOST_BLADE
+    || nMoveId == MOVE_SH_OBSCURING_SHADOW_VEIL
+    || nMoveId == MOVE_SH_SHADOW_BLADE_TECH
+    || nMoveId == MOVE_SH_SHADOW_GARROTTE
+    || nMoveId == MOVE_SH_SHADOW_NOOSE
+    || nMoveId == MOVE_SH_STRENGTH_DRAINING)
+        return TRUE;
+
+    // If nothing returns TRUE, fail
+    return FALSE;
+}
+
+int GetHasActiveStance(object oInitiator)
+{
+    int nStance = GetLocalInt(oInitiator, "TOBStanceOne");
+    if(GetHasSpellEffect(nStance, oInitiator))
+        return nStance;
+
+    nStance = GetLocalInt(oInitiator, "TOBStanceTwo");
+    if(GetHasSpellEffect(nStance, oInitiator))
+        return nStance;
+
+    return FALSE;
+}
+
+void RemoveStance(object oInitiator, int nStance)
+{
+    PRCRemoveEffectsFromSpell(oInitiator, nStance);
+
+    //stances with special handling goes here
+    if(nStance == MOVE_DS_AURA_CHAOS)
+        DeleteLocalInt(oInitiator, "DSChaos");
+    else if(nStance == MOVE_DS_PERFECT_ORDER)
+        DeleteLocalInt(oInitiator, "DSPerfectOrder");
+    else if(nStance == MOVE_DW_RISING_PHOENIX)
+        RemoveItemProperty(GetPCSkin(oInitiator), ItemPropertyBonusFeat(IP_CONST_FEAT_RISING_PHOENIX));
+    else if(nStance == MOVE_SH_ASSASSINS_STANCE)
+    {
+        DelayCommand(0.1, ExecuteScript("prc_sneak_att", oInitiator));
+        if (DEBUG) DoDebug("Cleaning assassin's stance");
+    }    
+    else if(nStance == MOVE_MYSTIC_PHOENIX || nStance == MOVE_MYSTIC_PHOENIX_AUG)
+    {
+        if(DEBUG) DoDebug("Removing Mystic Phoenix Stance");
+        DeleteLocalInt(oInitiator, "ToB_JPM_MystP");
+    }
+    else if(nStance == MOVE_FIREBIRD_STANCE || nStance == MOVE_FIREBIRD_STANCE_AUG)
+    {
+        if(DEBUG) DoDebug("Removing Firebird Stance");
+        DeleteLocalInt(oInitiator, "ToB_JPM_FireB");
+    }
+    else if(nStance == MOVE_CHILD_SL_STANCE)
+    {
+        DeleteLocalInt(oInitiator, "SSN_CHILDSL_SETP");
+        RemoveEventScript(oInitiator, EVENT_ONHEARTBEAT, "tob_ssn_childsl", TRUE, FALSE);
+    }
+}
+
+void ClearStances(object oInitiator, int nDontClearMove)
+{
+    // Clears spell effects, will not clear DontClearMove
+    // This is used to allow Warblades to have two stances.
+    int nStance = GetLocalInt(oInitiator, "TOBStanceOne");
+    if(GetHasSpellEffect(nStance, oInitiator) && nStance != nDontClearMove)
+    {
+        RemoveStance(oInitiator, nStance);
+        DeleteLocalInt(oInitiator, "TOBStanceOne");
+    }
+
+    nStance = GetLocalInt(oInitiator, "TOBStanceTwo");
+    if(GetHasSpellEffect(nStance, oInitiator) && nStance != nDontClearMove)
+    {
+        RemoveStance(oInitiator, nStance);
+        DeleteLocalInt(oInitiator, "TOBStanceTwo");
+    }
+}
+
+void MarkStanceActive(object oInitiator, int nStance)
+{
+    // If the first stance is active, use second
+    // This should only be called with the first active when it is legal to have two stances
+    if(GetLocalInt(oInitiator, "TOBStanceOne") > 0) SetLocalInt(oInitiator, "TOBStanceTwo", nStance);
+    else SetLocalInt(oInitiator, "TOBStanceOne", nStance);
+}
+
+effect VersusSizeEffect(object oInitiator, effect eEffect, int nSize)
+{
+    // Right now this only deals with medium and small PCs
+    int nPCSize = PRCGetCreatureSize(oInitiator);
+    effect eLink;
+    // Creatures larger than PC
+    if (nSize == 1)
+    {
+        eLink = VersusRacialTypeEffect(eEffect, RACIAL_TYPE_ABERRATION);
+        eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_CONSTRUCT));
+        eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_DRAGON));
+        eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_ELEMENTAL));
+        eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_GIANT));
+        eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_OUTSIDER));
+        if (nPCSize == CREATURE_SIZE_SMALL)
+        {
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_ANIMAL));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_BEAST));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_DWARF));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_ELF));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_HALFELF));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_HALFORC));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_HUMAN));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_HUMANOID_GOBLINOID));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_HUMANOID_MONSTROUS));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_HUMANOID_ORC));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_HUMANOID_REPTILIAN));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_MAGICAL_BEAST));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_OOZE));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_SHAPECHANGER));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_UNDEAD));
+        }
+    }// Smaller
+    if (nSize == 0)
+    {
+        eLink = VersusRacialTypeEffect(eEffect, RACIAL_TYPE_FEY);
+        eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_VERMIN));
+        if (nPCSize == CREATURE_SIZE_MEDIUM)
+        {
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_GNOME));
+            eLink = EffectLinkEffects(eLink, VersusRacialTypeEffect(eEffect, RACIAL_TYPE_HALFLING));
+        }
+    }
+
+    return eLink;
+}
+
+void InitiatorMovementCheck(object oPC, int nMoveId, float fFeet = 10.0)
+{
+    // Check to see if the WP is valid
+    string sWPTag = "PRC_BMWP_" + GetName(oPC) + IntToString(nMoveId);
+    object oTestWP = GetWaypointByTag(sWPTag);
+    if (!GetIsObjectValid(oTestWP))
+    {
+        // Create waypoint for the movement
+        CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001", GetLocation(oPC), FALSE, sWPTag);
+        if(DEBUG) DoDebug("InitiatorMovementCheck: WP for " + DebugObject2Str(oPC) + " didn't exist, creating. Tag: " + sWPTag);
+    }
+    // Start the recursive HB check for movement
+    // Seeing if this solves some of the issues with it
+    DelayCommand(2.0, _RecursiveStanceCheck(oPC, oTestWP, nMoveId, fFeet));
+}
+
+void DoDesertWindBoost(object oPC)
+{
+    if(DEBUG) DoDebug("DoDesertWindBoost running");
+    
+    object oItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
+    if (IPGetIsMeleeWeapon(oItem))
+    {
+        effect eVis = EffectLinkEffects(EffectVisualEffect(VFX_IMP_FLAME_M), EffectVisualEffect(VFX_IMP_PULSE_FIRE));
+        SPApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oPC);    
+        // Add eventhook to the item
+        AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_dw_onhit", TRUE, FALSE);
+        DelayCommand(6.0, RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_dw_onhit", TRUE, FALSE));
+        // Add the OnHit and vfx
+        IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 6.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+        IPSafeAddItemProperty(oItem, ItemPropertyVisualEffect(ITEM_VISUAL_FIRE), 6.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+        SetLocalInt(oPC, "DesertWindBoost", PRCGetSpellId());
+        DelayCommand(6.0, DeleteLocalInt(oPC, "DesertWindBoost"));        
+    }
+    oItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
+    if (IPGetIsMeleeWeapon(oItem))
+    {
+        // Add eventhook to the item
+        AddEventScript(oItem, EVENT_ITEM_ONHIT, "tob_dw_onhit", TRUE, FALSE);
+        DelayCommand(6.0, RemoveEventScript(oItem, EVENT_ITEM_ONHIT, "tob_dw_onhit", TRUE, FALSE));
+        // Add the OnHit and vfx
+        IPSafeAddItemProperty(oItem, ItemPropertyOnHitCastSpell(IP_CONST_ONHIT_CASTSPELL_ONHIT_UNIQUEPOWER, 1), 6.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+        IPSafeAddItemProperty(oItem, ItemPropertyVisualEffect(ITEM_VISUAL_FIRE), 6.0, X2_IP_ADDPROP_POLICY_KEEP_EXISTING, FALSE, FALSE);
+    }    
+}
+
+object GetCrusaderHealTarget(object oPC, float fDistance)
+{
+    object oReturn;
+    int nTest, nCurrentMin = 100;
+    location lTarget = GetLocation(oPC);
+    object oTest = MyFirstObjectInShape(SHAPE_SPHERE, fDistance, lTarget);
+    while(GetIsObjectValid(oTest))
+    {
+        if(GetIsFriend(oTest, oPC))
+        {
+            nTest = (GetCurrentHitPoints(oTest) * 100) / GetMaxHitPoints(oTest);
+            // Check HP vs current biggest loss
+            if(nTest < nCurrentMin && GetCurrentHitPoints(oTest) > 0 && !GetIsDead(oTest))
+            {
+                 nCurrentMin = nTest;
+                 oReturn = oTest;
+            }
+        }
+        //Get the next target in the specified area around the caster
+        oTest = MyNextObjectInShape(SHAPE_SPHERE, fDistance, lTarget);
+    }
+    if(DEBUG) DoDebug("GetCrusaderHealTarget: oReturn " + GetName(oReturn));
+    return oReturn;
+}
+
+int GetHasInsightfulStrike(object oInitiator)
+{
+    int nDiscToCheck = GetDisciplineByManeuver(PRCGetSpellId());
+    int nFeat;
+    switch(nDiscToCheck)
+    {
+        case DISCIPLINE_DESERT_WIND:  nFeat = FEAT_SS_DF_IS_DW; break;
+        case DISCIPLINE_DIAMOND_MIND: nFeat = FEAT_SS_DF_IS_DM; break;
+        case DISCIPLINE_SETTING_SUN:  nFeat = FEAT_SS_DF_IS_SS; break;
+        case DISCIPLINE_SHADOW_HAND:  nFeat = FEAT_SS_DF_IS_SH; break;
+        case DISCIPLINE_STONE_DRAGON: nFeat = FEAT_SS_DF_IS_SD; break;
+        case DISCIPLINE_TIGER_CLAW:   nFeat = FEAT_SS_DF_IS_TC; break;
+    }
+    if(GetHasFeat(nFeat, oInitiator))
+        return TRUE;
+
+    return FALSE;
+}
+
+int GetHasDefensiveStance(object oInitiator, int nDiscipline)
+{
+    // Because this is only called from inside the proper stances
+    // Its just a check to see if they should link in the save boost.
+    int nFeat;
+    switch(nDiscipline)
+    {
+        case DISCIPLINE_DESERT_WIND:  nFeat = FEAT_SS_DF_DS_DW; break;
+        case DISCIPLINE_DIAMOND_MIND: nFeat = FEAT_SS_DF_DS_DM; break;
+        case DISCIPLINE_SETTING_SUN:  nFeat = FEAT_SS_DF_DS_SS; break;
+        case DISCIPLINE_SHADOW_HAND:  nFeat = FEAT_SS_DF_DS_SH; break;
+        case DISCIPLINE_STONE_DRAGON: nFeat = FEAT_SS_DF_DS_SD; break;
+        case DISCIPLINE_TIGER_CLAW:   nFeat = FEAT_SS_DF_DS_TC; break;
+    }
+    if(GetHasFeat(nFeat, oInitiator))
+        return TRUE;
+
+    return FALSE;
+}
+
+int TOBGetHasDiscipline(object oInitiator, int nDiscipline)
+{
+    switch(nDiscipline)
+    {
+        case DISCIPLINE_DEVOTED_SPIRIT: return GetLevelByClass(CLASS_TYPE_CRUSADER, oInitiator);
+        case DISCIPLINE_DESERT_WIND:
+        case DISCIPLINE_SETTING_SUN:
+        case DISCIPLINE_SHADOW_HAND:    return GetLevelByClass(CLASS_TYPE_SWORDSAGE, oInitiator);
+        case DISCIPLINE_IRON_HEART:     return GetLevelByClass(CLASS_TYPE_WARBLADE, oInitiator);
+        case DISCIPLINE_DIAMOND_MIND:
+        case DISCIPLINE_TIGER_CLAW:     return GetLevelByClass(CLASS_TYPE_SWORDSAGE, oInitiator) || GetLevelByClass(CLASS_TYPE_WARBLADE, oInitiator);
+        case DISCIPLINE_WHITE_RAVEN:    return GetLevelByClass(CLASS_TYPE_CRUSADER, oInitiator) || GetLevelByClass(CLASS_TYPE_WARBLADE, oInitiator);
+        case DISCIPLINE_STONE_DRAGON:   return GetLevelByClass(CLASS_TYPE_CRUSADER, oInitiator) || GetLevelByClass(CLASS_TYPE_SWORDSAGE, oInitiator) || GetLevelByClass(CLASS_TYPE_WARBLADE, oInitiator);
+    }
+    return FALSE;
+}
+
+int TOBGetHasDisciplineFocus(object oInitiator, int nDiscipline)
+{
+    int nFeat1, nFeat2, nFeat3;
+    switch(nDiscipline)
+    {
+        case DISCIPLINE_DESERT_WIND:  nFeat1 = FEAT_SS_DF_DS_DW; nFeat2 = FEAT_SS_DF_IS_DW; nFeat3 = FEAT_SS_DF_WF_DW; break;
+        case DISCIPLINE_DIAMOND_MIND: nFeat1 = FEAT_SS_DF_DS_DM; nFeat2 = FEAT_SS_DF_IS_DM; nFeat3 = FEAT_SS_DF_WF_DM; break;
+        case DISCIPLINE_SETTING_SUN:  nFeat1 = FEAT_SS_DF_DS_SS; nFeat2 = FEAT_SS_DF_IS_SS; nFeat3 = FEAT_SS_DF_WF_SS; break;
+        case DISCIPLINE_SHADOW_HAND:  nFeat1 = FEAT_SS_DF_DS_SH; nFeat2 = FEAT_SS_DF_IS_SH; nFeat3 = FEAT_SS_DF_WF_SH; break;
+        case DISCIPLINE_STONE_DRAGON: nFeat1 = FEAT_SS_DF_DS_SD; nFeat2 = FEAT_SS_DF_IS_SD; nFeat3 = FEAT_SS_DF_WF_SD; break;
+        case DISCIPLINE_TIGER_CLAW:   nFeat1 = FEAT_SS_DF_DS_TC; nFeat2 = FEAT_SS_DF_IS_TC; nFeat3 = FEAT_SS_DF_WF_TC; break;
+    }
+    if(GetHasFeat(nFeat1, oInitiator) || GetHasFeat(nFeat2, oInitiator) || GetHasFeat(nFeat3, oInitiator))
+        return TRUE;
+
+    // If none of those trigger.
+    return FALSE;
+}
+
+int GetIsDisciplineWeapon(object oWeapon, int nDiscipline)
+{
+    int nType = GetBaseItemType(oWeapon);
+    if(nDiscipline == DISCIPLINE_DESERT_WIND)
+    {
+        if(nType == BASE_ITEM_SCIMITAR
+        || nType == BASE_ITEM_LIGHTMACE
+        || nType == BASE_ITEM_SHORTSPEAR
+        || nType == BASE_ITEM_LIGHT_PICK
+        || nType == BASE_ITEM_FALCHION)
+            return TRUE;
+    }
+    else if(nDiscipline == DISCIPLINE_DEVOTED_SPIRIT)
+    {
+        if(nType == BASE_ITEM_LONGSWORD
+        || nType == BASE_ITEM_HEAVYFLAIL
+        || nType == BASE_ITEM_MAUL
+        || nType == BASE_ITEM_FALCHION)
+            return TRUE;
+    }
+    else if(nDiscipline == DISCIPLINE_DIAMOND_MIND)
+    {
+        if(nType == BASE_ITEM_BASTARDSWORD
+        || nType == BASE_ITEM_KATANA
+        || nType == BASE_ITEM_SHORTSPEAR
+        || nType == BASE_ITEM_RAPIER)
+            return TRUE;
+    }
+    else if(nDiscipline == DISCIPLINE_IRON_HEART)
+    {
+        if(nType == BASE_ITEM_BASTARDSWORD
+        || nType == BASE_ITEM_KATANA
+        || nType == BASE_ITEM_LONGSWORD
+        || nType == BASE_ITEM_TWOBLADEDSWORD
+        || nType == BASE_ITEM_DWARVENWARAXE)
+            return TRUE;
+    }
+    else if(nDiscipline == DISCIPLINE_SETTING_SUN)
+    {
+        // Invalid is empty handed / Unarmed strike
+        if(nType == BASE_ITEM_INVALID
+        || nType == BASE_ITEM_QUARTERSTAFF
+        || nType == BASE_ITEM_SHORTSWORD
+        || nType == BASE_ITEM_NUNCHAKU)
+            return TRUE;
+    }
+    else if(nDiscipline == DISCIPLINE_SHADOW_HAND)
+    {
+        // Invalid is empty handed / Unarmed strike
+        if(nType == BASE_ITEM_DAGGER
+        || nType == BASE_ITEM_INVALID
+        || nType == BASE_ITEM_SHORTSWORD
+        || nType == BASE_ITEM_SAI)
+            return TRUE;
+    }
+    else if(nDiscipline == DISCIPLINE_STONE_DRAGON)
+    {
+        // Invalid is empty handed / Unarmed strike
+        if(nType == BASE_ITEM_GREATAXE
+        || nType == BASE_ITEM_INVALID
+        || nType == BASE_ITEM_GREATSWORD
+        || nType == BASE_ITEM_HEAVY_MACE)
+            return TRUE;
+    }
+    else if(nDiscipline == DISCIPLINE_TIGER_CLAW)
+    {
+        // Invalid is empty handed / Unarmed strike
+        if(nType == BASE_ITEM_KUKRI
+        || nType == BASE_ITEM_KAMA
+        || nType == BASE_ITEM_HANDAXE
+        || nType == BASE_ITEM_GREATAXE
+        || nType == BASE_ITEM_INVALID)
+            return TRUE;
+    }
+    else if(nDiscipline == DISCIPLINE_WHITE_RAVEN)
+    {
+        if(nType == BASE_ITEM_BATTLEAXE
+        || nType == BASE_ITEM_LONGSWORD
+        || nType == BASE_ITEM_HALBERD
+        || nType == BASE_ITEM_WARHAMMER
+        || nType == BASE_ITEM_GREATSWORD)
+            return TRUE;
+    }
+
+    // If none of those trigger.
+    return FALSE;
+}
+
+int TOBSituationalAttackBonuses(object oInitiator, int nDiscipline, int nClass = CLASS_TYPE_INVALID)
+{
+    int nBonus = 0;
+    if(GetLevelByClass(CLASS_TYPE_BLOODCLAW_MASTER, oInitiator) >= 4
+    && nDiscipline == DISCIPLINE_TIGER_CLAW)
+        nBonus += 1;
+
+    return nBonus;
+}
+
+int GetDisciplineSkill(int nDiscipline)
+{
+    if(nDiscipline == DISCIPLINE_DESERT_WIND)
+    {
+            return SKILL_TUMBLE;
+    }
+    else if(nDiscipline == DISCIPLINE_DEVOTED_SPIRIT)
+    {
+            return SKILL_INTIMIDATE;
+    }
+    else if(nDiscipline == DISCIPLINE_DIAMOND_MIND)
+    {
+            return SKILL_CONCENTRATION;
+    }
+    else if(nDiscipline == DISCIPLINE_IRON_HEART)
+    {
+            return SKILL_BALANCE;
+    }
+    else if(nDiscipline == DISCIPLINE_SETTING_SUN)
+    {
+            return SKILL_SENSE_MOTIVE;
+    }
+    else if(nDiscipline == DISCIPLINE_SHADOW_HAND)
+    {
+            return SKILL_HIDE;
+    }
+    else if(nDiscipline == DISCIPLINE_STONE_DRAGON)
+    {
+            return SKILL_BALANCE;
+    }
+    else if(nDiscipline == DISCIPLINE_TIGER_CLAW)
+    {
+            return SKILL_JUMP;
+    }
+    else if(nDiscipline == DISCIPLINE_WHITE_RAVEN)
+    {
+            return SKILL_PERSUADE;
+    }
+
+    // If none of those trigger.
+    return -1;    
+}
+
+int BladeMeditationFeat(object oInitiator)
+{
+         if(GetHasFeat(FEAT_BLADE_MEDITATION_DESERT_WIND   , oInitiator)) return DISCIPLINE_DESERT_WIND   ;
+    else if(GetHasFeat(FEAT_BLADE_MEDITATION_DEVOTED_SPIRIT, oInitiator)) return DISCIPLINE_DEVOTED_SPIRIT;
+    else if(GetHasFeat(FEAT_BLADE_MEDITATION_DIAMOND_MIND  , oInitiator)) return DISCIPLINE_DIAMOND_MIND  ;
+    else if(GetHasFeat(FEAT_BLADE_MEDITATION_IRON_HEART    , oInitiator)) return DISCIPLINE_IRON_HEART    ;
+    else if(GetHasFeat(FEAT_BLADE_MEDITATION_SETTING_SUN   , oInitiator)) return DISCIPLINE_SETTING_SUN   ;
+    else if(GetHasFeat(FEAT_BLADE_MEDITATION_SHADOW_HAND   , oInitiator)) return DISCIPLINE_SHADOW_HAND   ;
+    else if(GetHasFeat(FEAT_BLADE_MEDITATION_STONE_DRAGON  , oInitiator)) return DISCIPLINE_STONE_DRAGON  ;
+    else if(GetHasFeat(FEAT_BLADE_MEDITATION_TIGER_CLAW    , oInitiator)) return DISCIPLINE_TIGER_CLAW    ;
+    else if(GetHasFeat(FEAT_BLADE_MEDITATION_WHITE_RAVEN   , oInitiator)) return DISCIPLINE_WHITE_RAVEN   ;
+    
+    return -1;
+}
+
+int BladeMeditationDamage(object oInitiator, int nMoveId)
+{
+    int nDisc = BladeMeditationFeat(oInitiator);
+    object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oInitiator);
+    if (nDisc == GetDisciplineByManeuver(nMoveId) && GetIsDisciplineWeapon(oWeapon, nDisc))
+        return 1;
+        
+    return -1;
+}
\ No newline at end of file
diff --git a/trunk/include/true_inc_trufunc.nss b/trunk/include/true_inc_trufunc.nss
new file mode 100644
index 00000000..f60ee313
--- /dev/null
+++ b/trunk/include/true_inc_trufunc.nss
@@ -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;
+}
\ No newline at end of file