diff --git a/hakbuilder.json b/hakbuilder.json
index 63fb85df3..02cb22ea7 100644
--- a/hakbuilder.json
+++ b/hakbuilder.json
@@ -103,9 +103,14 @@
       "CompileModels": false
     },
 	{
-      "Name":  tmd19a_deepcave",
+      "Name":  "tmd19a_deepcave",
       "Path": "./tmd19a_deepcave/",
       "CompileModels": false
+    },
+	{
+      "Name":  "nwnds_scripts",
+      "Path": "./nwnds_scripts/",
+      "CompileModels": false
     },
   ]
 }
\ No newline at end of file
diff --git a/nwnds_scripts/inv_et_grblst.ncs b/nwnds_scripts/inv_et_grblst.ncs
new file mode 100644
index 000000000..2c5343134
Binary files /dev/null and b/nwnds_scripts/inv_et_grblst.ncs differ
diff --git a/nwnds_scripts/inv_et_grblst.nss b/nwnds_scripts/inv_et_grblst.nss
new file mode 100644
index 000000000..993835319
--- /dev/null
+++ b/nwnds_scripts/inv_et_grblst.nss
@@ -0,0 +1,313 @@
+//:://////////////////////////////////////////////
+//:: prc_et_grblast.nss
+//:://////////////////////////////////////////////
+/** @file
+    Spell selection for eldritch theurge's greatreach blast ability
+    Handles the dynamic convo *and* the quickselects
+*/
+//:://////////////////////////////////////////////
+//:://////////////////////////////////////////////
+
+#include "prc_sp_func"
+#include "inc_dynconv"
+#include "inv_inc_invfunc"
+//#include "inc_newspellbook"
+
+/* Constant defintions */
+const int STAGE_ENTRY = 0;
+const int STAGE_SLOT  = 1;
+const int STAGE_LVL0  = 10;
+const int STAGE_LVL9  = 20;
+
+/* Aid functions */
+void PopulateList(object oPC, int nLevel, int nClass)
+{
+    int i = 0, MaxValue = 0, nSpellID, nChoice = 1;
+    if(nClass == CLASS_TYPE_WIZARD
+	|| nClass == CLASS_TYPE_DEFILER //NWN Dark Sun Class
+    || (nClass == CLASS_TYPE_SORCERER && GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK)))
+    {
+        string sFile = "cls_spell_sorc";
+        object oToken = GetObjectByTag("SpellLvl_9_Level_" + IntToString(nLevel));
+        MaxValue = array_get_size(oToken, "Lkup");
+        //DoDebug("ET PopulateList: nClass = "+IntToString(nClass));
+        //DoDebug("ET PopulateList: nLevel = "+IntToString(nLevel));
+        //DoDebug("ET PopulateList: MaxValue = "+IntToString(MaxValue));
+        while(i < MaxValue)
+        {
+            nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", array_get_int(oToken, "Lkup", i)));
+            if(GetHasSpell(nSpellID, oPC))
+            {
+                if(IsTouchSpell(nSpellID))
+                {
+                    string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                    AddChoice(sName, nChoice, oPC);
+                    SetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                    SetLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice), -1);
+                    nChoice++;
+                }
+            }
+            i++;
+        }
+    }
+    else if(nClass == CLASS_TYPE_BARD && GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK))
+    {
+        string sFile = "cls_spell_bard";
+        object oToken = GetObjectByTag("SpellLvl_1_Level_" + IntToString(nLevel));
+        MaxValue = array_get_size(oToken, "Lkup");
+        //DoDebug("ET PopulateList: MaxValue = "+IntToString(MaxValue));
+        while(i < MaxValue)
+        {
+            nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", array_get_int(oToken, "Lkup", i)));
+            if(GetHasSpell(nSpellID, oPC))
+            {
+                if(IsTouchSpell(nSpellID))
+                {
+                    string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                    AddChoice(sName, nChoice, oPC);
+                    SetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                    SetLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice), -1);
+                    nChoice++;
+                }
+            }
+            i++;
+        }
+    }
+    else
+    {
+        string sFile = GetFileForClass(nClass);
+        string sArray = "NewSpellbookMem_" + IntToString(nClass);
+        // if we ever add another arcane caster with prepared spellbook
+        // uncomment all following lines
+        //int nSpellbookType = GetSpellbookTypeForClass(nClass);
+        //if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+        {
+            int nCount = persistant_array_get_int(oPC, sArray, nLevel);
+            //DoDebug("ET PopulateList: nCount = "+IntToString(nCount));
+            if(nCount)
+            {
+                MaxValue = persistant_array_get_size(oPC, "Spellbook"+IntToString(nClass));
+                while(i < MaxValue)
+                {
+                    int nNewSpellbookID = persistant_array_get_int(oPC, "Spellbook"+IntToString(nClass), i);
+                    if(nLevel == StringToInt(Get2DACache(sFile, "Level", nNewSpellbookID))
+                    && GetHasFeat(StringToInt(Get2DACache(sFile, "FeatID", nNewSpellbookID)), oPC))
+                    {
+                        int nRealSpell = StringToInt(Get2DACache(sFile, "RealSpellID", nNewSpellbookID));
+                        if(IsTouchSpell(nRealSpell))
+                        {
+                            string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell)));
+                            AddChoice(sName, nChoice, oPC);
+                            SetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice), nLevel);
+                            SetLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice), nRealSpell);
+                            SetLocalString(oPC, "ET_CLASS_ARRAY_" + IntToString(nChoice), sArray);
+                            nChoice++;
+                        }
+                    }
+                    i++;
+                }
+            }
+        }
+        /*else if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
+        {
+            string sArrayIDX = "SpellbookIDX" + IntToString(nLevel) + "_" + IntToString(nClass);
+            MaxValue = persistant_array_get_size(oPC, sArrayIDX);
+            while(i < MaxValue)
+            {
+                int nNewSpellbookID = persistant_array_get_int(oPC, sArrayIDX, i);
+                int nCount = persistant_array_get_int(oPC, sArray, nNewSpellbookID);
+                if(nCount)
+                {
+                    int nRealSpell = StringToInt(Get2DACache(sFile, "RealSpellID", nNewSpellbookID));
+                    string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell)));
+                    AddChoice(sName, nChoice, oPC);
+                    SetLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice), nNewSpellbookID);
+                    SetLocalInt(oPC, "EF_REAL_SPELL_CHOICE_" + IntToString(nChoice), nRealSpell);
+                    SetLocalString(oPC, "EF_CLASS_ARRAY_" + IntToString(nChoice), sArray);
+                    nChoice++;
+                }
+                i++;
+            }
+        }*/
+    }
+
+    SetDefaultTokens();
+    DeleteLocalInt(oPC, "DynConv_Waiting");
+    FloatingTextStringOnCreature("*Done*", oPC, FALSE);
+}
+
+void main()
+{
+    object oPC = OBJECT_SELF;
+    int nID = GetSpellId();
+    int nValue = GetLocalInt(GetPCSpeaker(), DYNCONV_VARIABLE);
+
+    //SendMessageToPC(oPC, "inv_et_grblst.nss:" + IntToString(nID) + " nVal:"+ IntToString(nValue));
+    if (nValue != 0) {
+        // do conversation
+        oPC = GetPCSpeaker();
+        /* Get the value of the local variable set by the conversation script calling
+         * this script. Values:
+         * DYNCONV_ABORTED     Conversation aborted
+         * DYNCONV_EXITED      Conversation exited via the exit node
+         * DYNCONV_SETUP_STAGE System's reply turn
+         * 0                   Error - something else called the script
+         * Other               The user made a choice
+         */
+        // The stage is used to determine the active conversation node.
+        // 0 is the entry node.
+        int nStage = GetStage(oPC);
+
+        if(nValue == DYNCONV_SETUP_STAGE)
+        {
+            // Check if this stage is marked as already set up
+            // This stops list duplication when scrolling
+            if(!GetIsStageSetUp(nStage, oPC))
+            {
+                // variable named nStage determines the current conversation node
+                // Function SetHeader to set the text displayed to the PC
+                // Function AddChoice to add a response option for the PC. The responses are show in order added
+                if(nStage == STAGE_ENTRY)
+                {
+                    SetHeader("Select Spell Level:");
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell1")) AddChoice(GetStringByStrRef(690),  1, oPC);//"Level 1"
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell2")) AddChoice(GetStringByStrRef(725),  2, oPC);//"Level 2"
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell3")) AddChoice(GetStringByStrRef(687),  3, oPC);//"Level 3"
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell4")) AddChoice(GetStringByStrRef(684),  4, oPC);//"Level 4"
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell5")) AddChoice(GetStringByStrRef(1026), 5, oPC);//"Level 5"
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell6")) AddChoice(GetStringByStrRef(1014), 6, oPC);//"Level 6"
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell7")) AddChoice(GetStringByStrRef(2214), 7, oPC);//"Level 7"
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell8")) AddChoice(GetStringByStrRef(2215), 8, oPC);//"Level 8"
+                    if(!GetLocalInt(oPC, "PRC_ArcSpell9")) AddChoice(GetStringByStrRef(2216), 9, oPC);//"Level 9"
+                    MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
+                    SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
+                }
+                else if (nStage >= STAGE_LVL0 && nStage <= STAGE_LVL9)
+                {
+                    // Set the header
+                    SetHeader("Select Spell:");
+                    int nLevel = nStage - STAGE_LVL0;
+                    SetLocalInt(oPC, "DynConv_Waiting", TRUE);
+
+                    PopulateList(oPC, nLevel, GetETArcaneClass(oPC));
+
+                    MarkStageSetUp(nStage, oPC);
+                }
+                else if (nStage = STAGE_SLOT)
+                {
+                    SetHeader("Select QuickSlot:");
+                    AddChoice("Slot 1", 1, oPC);
+                    AddChoice("Slot 2", 2, oPC);
+                    AddChoice("Slot 3", 3, oPC);
+                    AddChoice("Slot 4", 4, oPC);
+                    MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
+                    SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
+                }
+
+            //add more stages for more nodes with Else If clauses
+            }
+
+            // Do token setup
+            SetupTokens();
+        }
+        // End of conversation cleanup
+        // Abort conversation cleanup.
+        else if(nValue == DYNCONV_EXITED
+              || nValue == DYNCONV_ABORTED)
+        {
+            int nChoice = 1;
+            while(GetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice)))
+            {
+                DeleteLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice));
+                DeleteLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+                DeleteLocalString(oPC, "ET_CLASS_ARRAY_" + IntToString(nChoice));
+                nChoice++;
+            }
+            DeleteLocalInt(oPC, "ET_SPELL_ID");
+            DeleteLocalInt(oPC, "ET_REAL_SPELL_ID");
+            DeleteLocalString(oPC, "ET_CLASS_ARRAY_ID");
+            DeleteLocalInt(oPC, "ET_SPELL_LEVEL_CHOICE");
+        }
+        // Handle PC responses
+        else
+        {
+            // variable named nChoice is the value of the player's choice as stored when building the choice list
+            // variable named nStage determines the current conversation node
+            int nChoice = GetChoice(oPC);
+            if(nStage == STAGE_ENTRY)
+            {
+                int nLevel = nChoice;
+                SetLocalInt(oPC, "ET_SPELL_LEVEL_CHOICE", nLevel);
+                nStage = STAGE_LVL0 + nChoice;
+                // Move to another stage based on response, for example
+                //nStage = STAGE_QUUX;
+            }
+            else if (nStage >= STAGE_LVL0 && nStage <= STAGE_LVL9)
+            {
+                MarkStageNotSetUp(nStage, oPC);
+                int nSpell = GetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice));
+                int nRealSpell = GetLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+                string sArray = GetLocalString(oPC, "ET_CLASS_ARRAY_" + IntToString(nChoice));
+
+                SetLocalInt(oPC, "ET_SPELL_ID", nSpell);
+                SetLocalInt(oPC, "ET_REAL_SPELL_ID", nRealSpell);
+                SetLocalString(oPC, "ET_CLASS_ARRAY_ID", sArray);
+
+                nStage = STAGE_SLOT;
+            }
+            else if (nStage = STAGE_SLOT)
+            {
+                int nSpell = GetLocalInt(oPC, "ET_SPELL_ID");
+                int nRealSpell = GetLocalInt(oPC, "ET_REAL_SPELL_ID");
+                string sArray = GetLocalString(oPC, "ET_CLASS_ARRAY_ID");
+                int nLevel = GetLocalInt(oPC, "ET_SPELL_LEVEL_CHOICE");
+                SetLocalInt(oPC, "ET_GR_SPELL_QUICK" + IntToString(nChoice), nSpell);
+                SetLocalInt(oPC, "ET_GR_REAL_SPELL_QUICK" + IntToString(nChoice), nRealSpell);
+                SetLocalString(oPC, "ET_GR_SPELL_QUICK" + IntToString(nChoice), sArray);
+                SetLocalInt(oPC, "ET_GR_SPELL_QUICK" + IntToString(nChoice) + "LVL", nLevel);
+
+                nStage = STAGE_ENTRY;
+            }
+            // Store the stage value. If it has been changed, this clears out the choices
+            SetStage(nStage, oPC);
+        }
+    }
+    else if(nID == INVOKE_GR_SPELL_SELECT_CONVO)
+    {
+        DelayCommand(0.5, StartDynamicConversation("inv_et_grblst", oPC, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, FALSE, oPC));
+    }
+    else
+    {
+        string sSlotNo;
+        switch(nID)
+        {
+            case INVOKE_GR_SPELL_SELECT_QUICK1: sSlotNo = "1"; break;
+            case INVOKE_GR_SPELL_SELECT_QUICK2: sSlotNo = "2"; break;
+            case INVOKE_GR_SPELL_SELECT_QUICK3: sSlotNo = "3"; break;
+            case INVOKE_GR_SPELL_SELECT_QUICK4: sSlotNo = "4"; break;
+        }
+
+        if(sSlotNo == "")
+            return;
+
+        int nSpell = GetLocalInt(oPC, "ET_GR_SPELL_QUICK"+sSlotNo);
+        int nLevel = GetLocalInt(oPC, "ET_GR_SPELL_QUICK"+sSlotNo+"LVL");
+        int nRealSpell = GetLocalInt(oPC, "ET_GR_REAL_SPELL_QUICK"+sSlotNo);
+        if(nRealSpell == -1) nRealSpell = nSpell;
+        string sArray = GetLocalString(oPC, "ET_GR_SPELL_QUICK"+sSlotNo);
+        int nUses = sArray == "" ? GetHasSpell(nSpell, oPC) : persistant_array_get_int(oPC, sArray, nSpell);
+        if(nUses)
+        {
+            SetLocalInt(oPC, "ET_SPELL_CURRENT", (nSpell+1));
+            SetLocalInt(oPC, "ET_SPELL_CURRENT_LVL", nLevel);
+            SetLocalInt(oPC, "ET_REAL_SPELL_CURRENT", nRealSpell);
+            SetLocalString(oPC, "ET_SPELL_CURRENT", sArray);
+            FloatingTextStringOnCreature("*Greatreach Blast: " + GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell))) + "*", oPC, FALSE);
+            FloatingTextStringOnCreature("*You have " + IntToString(nUses) + " uses left*", oPC, FALSE);
+        }
+        else
+        {
+            FloatingTextStringOnCreature("No uses or preperations left for selected spell!", oPC, FALSE);
+        }
+    }
+}
diff --git a/nwnds_scripts/inv_et_spellblst.ncs b/nwnds_scripts/inv_et_spellblst.ncs
new file mode 100644
index 000000000..1c1f2b6c4
Binary files /dev/null and b/nwnds_scripts/inv_et_spellblst.ncs differ
diff --git a/nwnds_scripts/inv_et_spellblst.nss b/nwnds_scripts/inv_et_spellblst.nss
new file mode 100644
index 000000000..f8828caef
--- /dev/null
+++ b/nwnds_scripts/inv_et_spellblst.nss
@@ -0,0 +1,247 @@
+//:://////////////////////////////////////////////
+//:: inv_et_spellblst.nss
+//:://////////////////////////////////////////////
+/** @file
+    Spell selection for eldritch theurge's spellblast ability
+    Handles the dynamic convo *and* the quickselects
+*/
+//:://////////////////////////////////////////////
+//:://////////////////////////////////////////////
+
+#include "inv_invoc_const"
+#include "inc_dynconv"
+#include "inv_inc_invfunc"
+
+/* Constant defintions */
+const int STAGE_ENTRY = 0;
+const int STAGE_SLOT  = 1;
+
+/* Aid functions */
+
+void PopulateList(object oPC, int nClass)
+{
+    string sFile = "et_spellblast";
+    int MaxValue = StringToInt(Get2DACache(sFile, "Label", 0));
+
+    int i = 1, nSpellID, nChoice = 1;
+    if(nClass == CLASS_TYPE_WIZARD
+	|| nClass == CLASS_TYPE_DEFILER
+    || (nClass == CLASS_TYPE_SORCERER && GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK))
+    || (nClass == CLASS_TYPE_BARD && GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK)))
+    {
+        while(i < MaxValue)
+        {
+            nSpellID = StringToInt(Get2DACache(sFile, "SpellID", i));
+            if(GetHasSpell(nSpellID, oPC))
+            {
+                string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                AddChoice(sName, nChoice, oPC);
+                SetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                SetLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice), -1);
+                nChoice++;
+            }
+            i++;
+        }
+    }
+    else
+    {
+        string sClassFile = GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED ? "":
+                            GetFileForClass(nClass);
+        string sArray = "NewSpellbookMem_" + IntToString(nClass);
+        int nSpellbookID, nLevel, nCount;
+        while(i < MaxValue)
+        {
+            nSpellID = StringToInt(Get2DACache(sFile, "SpellID", i));
+            nSpellbookID = RealSpellToSpellbookID(nClass, nSpellID);
+DoDebug(Get2DACache(sFile, "Label", i)+" = "+IntToString(nSpellbookID));
+            if(nSpellbookID != -1)
+            {
+            /*  // if we ever add another arcane caster with prepared spellbook
+                // uncomment all following lines
+                if(sClassFile == "")
+                {
+                    nCount = persistant_array_get_int(oPC, sArray, nSpellbookID);
+                    if(nCount)
+                    {
+                        string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                        AddChoice(sName, nChoice, oPC);
+                        SetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice), nSpellbookID);
+                        SetLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                        SetLocalString(oPC, "ET_CLASS_ARRAY_" + IntToString(nChoice), sArray);
+                        nChoice++;
+                    }
+                }
+                else*/
+                {
+                    if(GetHasFeat(StringToInt(Get2DACache(sClassFile, "FeatID", nSpellbookID)), oPC))
+                    {
+                        nLevel = StringToInt(Get2DACache(sClassFile, "Level", nSpellbookID));
+                        nCount = persistant_array_get_int(oPC, sArray, nLevel);
+                        if(nCount)
+                        {
+                            string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                            AddChoice(sName, nChoice, oPC);
+                            SetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice), nLevel);
+                            SetLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                            SetLocalString(oPC, "ET_CLASS_ARRAY_" + IntToString(nChoice), sArray);
+                            nChoice++;
+                        }
+                    }
+                }
+            }
+            i++;
+        }
+    }
+
+    SetDefaultTokens();
+    DeleteLocalInt(oPC, "DynConv_Waiting");
+    FloatingTextStringOnCreature("*Done*", oPC, FALSE);
+}
+
+void main()
+{
+    object oPC = OBJECT_SELF;
+    int nID = GetSpellId();
+    int nValue = GetLocalInt(GetPCSpeaker(), DYNCONV_VARIABLE);
+
+    //SendMessageToPC(oPC, "inv_et_spellblst:" + IntToString(nID) + " nVal:"+ IntToString(nValue));
+    if (nValue != 0) {
+        // do conversation
+        oPC = GetPCSpeaker();
+        /* Get the value of the local variable set by the conversation script calling
+         * this script. Values:
+         * DYNCONV_ABORTED     Conversation aborted
+         * DYNCONV_EXITED      Conversation exited via the exit node
+         * DYNCONV_SETUP_STAGE System's reply turn
+         * 0                   Error - something else called the script
+         * Other               The user made a choice
+         */
+        // The stage is used to determine the active conversation node.
+        // 0 is the entry node.
+        int nStage = GetStage(oPC);
+
+        if(nValue == DYNCONV_SETUP_STAGE)
+        {
+            // Check if this stage is marked as already set up
+            // This stops list duplication when scrolling
+            if(!GetIsStageSetUp(nStage, oPC))
+            {
+                // variable named nStage determines the current conversation node
+                // Function SetHeader to set the text displayed to the PC
+                // Function AddChoice to add a response option for the PC. The responses are show in order added
+                if(nStage == STAGE_ENTRY)
+                {
+                    // Set the header
+                    SetHeader("Select Spell:");
+                    SetLocalInt(oPC, "DynConv_Waiting", TRUE);
+
+                    PopulateList(oPC, GetETArcaneClass(oPC));
+
+                    MarkStageSetUp(nStage, oPC);
+                }
+                else if (nStage = STAGE_SLOT)
+                {
+                    SetHeader("Select QuickSlot:");
+                    AddChoice("Slot 1", 1, oPC);
+                    AddChoice("Slot 2", 2, oPC);
+                    AddChoice("Slot 3", 3, oPC);
+                    AddChoice("Slot 4", 4, oPC);
+                    MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
+                    SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
+                }
+
+            //add more stages for more nodes with Else If clauses
+            }
+
+            // Do token setup
+            SetupTokens();
+        }
+        // Abort conversation cleanup.
+        // NOTE: This section is only run when the conversation is aborted
+        // while aborting is allowed. When it isn't, the dynconvo infrastructure
+        // handles restoring the conversation in a transparent manner
+        else if(nValue == DYNCONV_ABORTED
+              || nValue == DYNCONV_EXITED)
+        {
+            int nChoice = 1;
+            while(GetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice)))
+            {
+                DeleteLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice));
+                DeleteLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+                DeleteLocalString(oPC, "ET_CLASS_ARRAY_" + IntToString(nChoice));
+                nChoice++;
+            }
+            DeleteLocalInt(oPC, "ET_SPELL_ID");
+            DeleteLocalInt(oPC, "ET_REAL_SPELL_ID");
+            DeleteLocalString(oPC, "ET_CLASS_ARRAY_ID");
+            DeleteLocalInt(oPC, "ET_SPELL_LEVEL_CHOICE");
+        }
+        // Handle PC responses
+        else
+        {
+            // variable named nChoice is the value of the player's choice as stored when building the choice list
+            // variable named nStage determines the current conversation node
+            int nChoice = GetChoice(oPC);
+            if(nStage == STAGE_ENTRY)
+            {
+                MarkStageNotSetUp(nStage, oPC);
+                int nSpell = GetLocalInt(oPC, "ET_SPELL_CHOICE_" + IntToString(nChoice));
+                int nRealSpell = GetLocalInt(oPC, "ET_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+                string sArray = GetLocalString(oPC, "ET_CLASS_ARRAY_" + IntToString(nChoice));
+
+                SetLocalInt(oPC, "ET_SPELL_ID", nSpell);
+                SetLocalInt(oPC, "ET_REAL_SPELL_ID", nRealSpell);
+                SetLocalString(oPC, "ET_CLASS_ARRAY_ID", sArray);
+
+                nStage = STAGE_SLOT;
+            }
+            else if (nStage = STAGE_SLOT)
+            {
+                MarkStageNotSetUp(nStage, oPC);
+                int nSpell = GetLocalInt(oPC, "ET_SPELL_ID");
+                int nRealSpell = GetLocalInt(oPC, "ET_REAL_SPELL_ID");
+                string sArray = GetLocalString(oPC, "ET_CLASS_ARRAY_ID");
+                int nLevel = GetLocalInt(oPC, "ET_SPELL_LEVEL_CHOICE");
+                SetLocalInt(oPC, "ET_SPELL_QUICK" + IntToString(nChoice), nSpell);
+                SetLocalInt(oPC, "ET_REAL_SPELL_QUICK" + IntToString(nChoice), nRealSpell);
+                SetLocalString(oPC, "ET_SPELL_QUICK" + IntToString(nChoice), sArray);
+                SetLocalInt(oPC, "ET_SPELL_QUICK" + IntToString(nChoice) + "LVL", nLevel);
+
+                nStage = STAGE_ENTRY;
+            }
+            // Store the stage value. If it has been changed, this clears out the choices
+            SetStage(nStage, oPC);
+        }
+    }
+    else if(nID == INVOKE_SB_SPELL_SELECT_CONVO)
+    {
+        DelayCommand(0.5, StartDynamicConversation("inv_et_spellblst", oPC, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, FALSE, oPC));
+    }
+    else
+    {
+        string sSlotNo;
+        switch(nID)
+        {
+            case INVOKE_SB_SPELL_SELECT_QUICK1: sSlotNo = "1"; break;
+            case INVOKE_SB_SPELL_SELECT_QUICK2: sSlotNo = "2"; break;
+            case INVOKE_SB_SPELL_SELECT_QUICK3: sSlotNo = "3"; break;
+            case INVOKE_SB_SPELL_SELECT_QUICK4: sSlotNo = "4"; break;
+        }
+
+        if(sSlotNo == "")
+            return;
+
+        int nSpell = GetLocalInt(oPC, "ET_SPELL_QUICK"+sSlotNo);
+        int nLevel = GetLocalInt(oPC, "ET_SPELL_QUICK"+sSlotNo+"LVL");
+        int nRealSpell = GetLocalInt(oPC, "ET_REAL_SPELL_QUICK"+sSlotNo);
+        if(nRealSpell == -1) nRealSpell = nSpell;
+        string sArray = GetLocalString(oPC, "ET_SPELL_QUICK"+sSlotNo);
+        SetLocalInt(oPC, "ET_SPELL_CURRENT", (nSpell+1));
+        SetLocalInt(oPC, "ET_SPELL_CURRENT_LVL", nLevel);
+        SetLocalInt(oPC, "ET_REAL_SPELL_CURRENT", nRealSpell);
+        SetLocalString(oPC, "ET_SPELL_CURRENT", sArray);
+        int nUses = sArray == "" ? GetHasSpell(nSpell, oPC) : persistant_array_get_int(oPC, sArray, nSpell);
+        FloatingTextStringOnCreature("*Spellblast: " + GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell))) + "*", oPC, FALSE);
+        FloatingTextStringOnCreature("*You have " + IntToString(nUses) + " uses left*", oPC, FALSE);
+    }
+}
diff --git a/nwnds_scripts/nw_s2_familiar.ncs b/nwnds_scripts/nw_s2_familiar.ncs
new file mode 100644
index 000000000..63bbd5f89
Binary files /dev/null and b/nwnds_scripts/nw_s2_familiar.ncs differ
diff --git a/nwnds_scripts/nw_s2_familiar.nss b/nwnds_scripts/nw_s2_familiar.nss
new file mode 100644
index 000000000..c5fa27466
--- /dev/null
+++ b/nwnds_scripts/nw_s2_familiar.nss
@@ -0,0 +1,343 @@
+//::///////////////////////////////////////////////
+//:: Summon Familiar
+//:: NW_S2_Familiar
+//:: Copyright (c) 2001 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+    This spell summons an Arcane casters familiar
+*/
+//:://////////////////////////////////////////////
+//:: Created By: Preston Watamaniuk
+//:: Created On: Sept 27, 2001
+//:://////////////////////////////////////////////
+
+#include "prc_class_const"
+#include "inc_dynconv"
+//#include "inc_dispel"
+#include "prc_inc_assoc"
+#include "prc_inc_template"
+
+
+const int PACKAGE_ELEMENTAL_STR = PACKAGE_ELEMENTAL;
+const int PACKAGE_ELEMENTAL_DEX = PACKAGE_FEY;
+
+void BondedSummoner(object oPC);
+void SummonPnPFamiliar(object oPC, int nType);
+void SummonPRCFamiliar(object oPC);
+void DreadNecro(object oPC);
+void MasterShadow(object oPC);
+
+void main()
+{
+    object oPC = OBJECT_SELF;
+    
+    if(GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oPC))
+    {
+        //handles summoning of shadow familiar
+        MasterShadow(oPC);
+    }
+    else if(GetLevelByClass(CLASS_TYPE_BONDED_SUMMONNER, oPC))
+    {
+        //handles summoning of elemental familiar
+        BondedSummoner(oPC);
+    }
+    else if(GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC) > 6)
+    {
+        //handles dread necromancer familiar
+        DreadNecro(oPC);
+    }
+    else if(GetLevelByClass(CLASS_TYPE_CELEBRANT_SHARESS, oPC))
+    {
+        //It's a PnP Cat familiar
+        SummonPnPFamiliar(oPC, 6);
+    }    
+    else if(GetPRCSwitch(PRC_PNP_FAMILIARS))
+    {
+        //handles summoning of pnp familiar
+        SummonPnPFamiliar(oPC, -1);
+    }
+    else if(GetPRCSwitch(PRC_FAMILIARS)//the switch is set
+    || (!GetLevelByClass(CLASS_TYPE_WIZARD, oPC) || !GetLevelByClass(CLASS_TYPE_DEFILER, oPC)
+    &&  !GetLevelByClass(CLASS_TYPE_SORCERER, oPC)))//or no bio-ware familiar
+    {
+        //handles summoning of familiars for PRC classes (witch, hexblade)
+        SummonPRCFamiliar(oPC);
+    }
+    else
+        //summon bio-ware familiar
+        SummonFamiliar();
+
+    object oFam;
+    int i;
+    int bDiabol = GetLevelByClass(CLASS_TYPE_DIABOLIST, oPC) >= 2;
+    int bPseudonat = GetHasFeat(FEAT_PSEUDONATURAL_FAMILIAR, oPC);
+    for(i = 1; i <= 5; i++)
+    {
+        oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, i);
+
+        if(bDiabol && GetAppearanceType(oFam) != APPEARANCE_TYPE_IMP)
+            DestroyAssociate(oFam);
+
+        if(bPseudonat)
+        {
+            object oFamSkin = GetPCSkin(oFam);
+            ApplyPseudonatural(oFam, oFamSkin);
+        }
+    }
+}
+
+void BondedSummoner(object oPC)
+{
+    object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_BONDED_FAMILIAR);
+
+    //remove previously summoned familiar
+    if(GetIsObjectValid(oFam))
+        DestroyAssociate(oFam);
+
+    string sResRef, sElem;
+    int nPackage;
+    if(GetHasFeat(FEAT_BONDED_AIR, oPC))
+    {
+        sElem = "air";
+        nPackage = PACKAGE_ELEMENTAL_DEX;
+    }
+    else if(GetHasFeat(FEAT_BONDED_EARTH, oPC))
+    {
+        sElem = "earth";
+        nPackage = PACKAGE_ELEMENTAL_STR;
+    }
+    else if(GetHasFeat(FEAT_BONDED_FIRE, oPC))
+    {
+        sElem = "fire";
+        nPackage = PACKAGE_ELEMENTAL_DEX;
+    }
+    else if(GetHasFeat(FEAT_BONDED_WATER, oPC))
+    {
+        sElem = "water";
+        nPackage = PACKAGE_ELEMENTAL_STR;
+    }
+
+    int nLevel = GetLevelByClass(CLASS_TYPE_BONDED_SUMMONNER, oPC);
+
+    switch(nLevel)
+    {
+        case 1:
+        case 2: sResRef = "x1_s_"+sElem+"small"; break;//this is the 4HD version in the SRD, which is medium
+        case 3:
+        case 4: sResRef = "prc_s_"+sElem+"large"; break;
+        case 5:
+        case 6: sResRef = "nw_s_"+sElem+"huge"; break;
+        case 7:
+        case 8: sResRef = "nw_s_"+sElem+"great"; break;
+        case 9:
+        case 10: sResRef = "nw_s_"+sElem+"elder"; break;
+    }
+
+    oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sResRef, PRCGetSpellTargetLocation(), NPC_BONDED_FAMILIAR);
+    AddAssociate(oPC, oFam);
+
+    //set its name
+    string sName = GetFamiliarName(oPC);
+    if(sName == "")
+        sName = GetName(oPC)+ "'s Familiar";
+    SetName(oFam, sName);
+    //apply bonus based on level
+    int nArcaneLevel = GetPrCAdjustedCasterLevelByType(TYPE_ARCANE) + nLevel/2;
+    object oSkin = GetPCSkin(oFam);
+    //in all cases
+    IPSafeAddItemProperty(oSkin, PRCItemPropertyBonusFeat(ITEM_PROPERTY_IMPROVED_EVASION));
+    //9+ levels
+    if(nArcaneLevel >= 9)
+        IPSafeAddItemProperty(oSkin, ItemPropertyBonusSpellResistance(GetSRByValue(nArcaneLevel+5)));
+    //11+ levels
+    if(nArcaneLevel >= 11)
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(EffectMovementSpeedIncrease(30)), oFam);
+    //add their ondeath special
+    AddEventScript(oFam, EVENT_NPC_ONDEATH, "prc_bond_death");
+
+    /*int nAdjustLevel = nArcaneLevel - GetHitDice(oFam);
+    int n;
+    for(n = 1; nAdjustLevel >= n; n++)
+        LevelUpHenchman(oFam, CLASS_TYPE_INVALID, TRUE, nPackage);*/
+
+    //set it so the spell-share detects it
+    SetLocalObject(oPC, "Familiar", oFam);
+}
+
+void DreadNecro(object oPC)
+{
+    object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_DN_FAMILIAR);
+
+    //remove previously summoned familiar
+    if(GetIsObjectValid(oFam))
+        DestroyAssociate(oFam);
+
+    int bPnP = GetPRCSwitch(PRC_PNP_FAMILIARS);
+    int nAlign = GetAlignmentLawChaos(oPC);
+    string sResRef;
+    if(bPnP)
+    {
+        sResRef = nAlign == ALIGNMENT_LAWFUL ? "prc_pnpfam_imp" : nAlign == ALIGNMENT_CHAOTIC ? "prc_pnpfam_qust" : "prc_pnpfam_varg";
+    }
+    else
+    {
+        int nDNLevel = GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC);
+        string sTemp = nDNLevel < 10 ? "0"+IntToString(nDNLevel) : IntToString(nDNLevel);
+        sResRef = nAlign == ALIGNMENT_LAWFUL ? "NW_FM_IMP"+sTemp : nAlign == ALIGNMENT_CHAOTIC ? "NW_FM_QUAS"+sTemp : "X2_FM_EYE0"+sTemp;
+    }
+
+    oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sResRef, PRCGetSpellTargetLocation(), NPC_DN_FAMILIAR);
+
+    //add the familiar as a henchman
+    AddAssociate(oPC, oFam);
+
+    //set its name
+    string sName = GetFamiliarName(oPC);
+    if(sName == "")
+        sName = GetName(oPC)+ "'s Familiar";
+    SetName(oFam, sName);
+
+    if(bPnP) ApplyPnPFamiliarProperties(oPC, oFam);
+}
+
+void SummonPnPFamiliar(object oPC, int nType)
+{
+    IncrementRemainingFeatUses(oPC, FEAT_SUMMON_FAMILIAR);
+
+    //check if already has a familiar
+    object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_PNP_FAMILIAR);
+    object oFamToken = GetItemPossessedBy(oPC, "prc_pnp_familiar");
+
+    int nFamiliarType;
+    
+    if (nType > 0)
+    	nFamiliarType = nType;
+    else
+    	nFamiliarType = GetPersistantLocalInt(oPC, "PnPFamiliarType");
+    if(!nFamiliarType)
+    {
+        StartDynamicConversation("prc_pnp_fam_conv", oPC, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, TRUE, oPC);
+        return;
+    }
+
+    if(GetIsObjectValid(oFam))
+    {
+        //reapply familiar bonuses
+        PRCRemoveEffectsFromSpell(oFam, 318);//318 = summon familiar
+    }
+    else
+    {
+        if(GetIsObjectValid(oFamToken))
+        {
+            DestroyObject(oFamToken, 0.1f);
+        }
+        //spawn the familiar
+        string sResRef = Get2DACache("prc_familiar", "BASERESREF", nFamiliarType);
+        oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sResRef, PRCGetSpellTargetLocation(), NPC_PNP_FAMILIAR);
+
+        //set its name
+        string sName = GetFamiliarName(oPC);
+        if(sName == "")
+            sName = GetName(oPC)+ "'s Familiar";
+        SetName(oFam, sName);
+
+        //add the familiar as a henchman
+        AddAssociate(oPC, oFam);
+    }
+
+    //this is the masters bonus
+    effect eBonus = GetMasterBonus(nFamiliarType);
+    eBonus = SupernaturalEffect(eBonus);
+    if(!GetHasFeatEffect(FEAT_SUMMON_FAMILIAR, oPC))
+    {
+        ApplyEffectToObject(DURATION_TYPE_PERMANENT, eBonus, oPC);
+        CheckIsValidFamiliar(oPC, eBonus);
+    }
+
+    ApplyPnPFamiliarProperties(oPC, oFam);
+    if (GetHasFeat(FEAT_SHADOW_FAMILIAR, oPC)) ApplyTemplateToObject(TEMPLATE_DARK, oFam);
+}
+
+void SummonPRCFamiliar(object oPC)
+{
+    object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_HENCHMAN_COMPANION);
+
+    //remove previously summoned familiar
+    if(GetIsObjectValid(oFam))
+        DestroyAssociate(oFam);
+
+    int nFamiliarType = GetPersistantLocalInt(oPC, "FamiliarType");
+    if(!nFamiliarType)
+    {
+        StartDynamicConversation("prc_pnp_fam_conv", oPC, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, TRUE, oPC);
+        IncrementRemainingFeatUses(oPC, FEAT_SUMMON_FAMILIAR);
+        return;
+    }
+    else
+        nFamiliarType--;
+
+    int nFamLevel = GetLevelByClass(CLASS_TYPE_WIZARD);
+	nFamLevel = max(nFamLevel, GetLevelByClass(CLASS_TYPE_DEFILER)); // NWN Dark Sun class
+    nFamLevel = max(nFamLevel, GetLevelByClass(CLASS_TYPE_SORCERER));
+    nFamLevel = max(nFamLevel, GetLevelByClass(CLASS_TYPE_WITCH));
+    nFamLevel = max(nFamLevel, GetLevelByClass(CLASS_TYPE_HEXBLADE));
+    nFamLevel += GetLevelByClass(CLASS_TYPE_ALIENIST);
+    if (GetHasFeat(FEAT_SHADOW_FAMILIAR, oPC)) nFamLevel = GetLevelByTypeArcane(oPC) + GetShadowcasterLevel(oPC); // For the purpose of determining familiar abilities that depend on your arcane caster level, your levels in all classes that allow you to cast mysteries or arcane spells stack
+    
+    string sTemp = Get2DACache("hen_familiar", "BASERESREF", nFamiliarType);
+    string sResRef = nFamLevel < 10 ? sTemp+"0"+IntToString(nFamLevel) : sTemp+IntToString(nFamLevel);
+
+    //spawn the familiar
+    oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sResRef, PRCGetSpellTargetLocation(), NPC_HENCHMAN_COMPANION);
+    AddAssociate(oPC, oFam);
+    
+    if (GetHasFeat(FEAT_SHADOW_FAMILIAR, oPC)) ApplyTemplateToObject(TEMPLATE_DARK, oFam);
+
+    //set its name
+    string sName = GetFamiliarName(oPC);
+    if(sName == "")
+        sName = GetName(oPC)+ "'s Familiar";
+    SetName(oFam, sName);
+}
+
+void MasterShadow(object oPC)
+{
+    object oFam = GetAssociateNPC(ASSOCIATE_TYPE_FAMILIAR, oPC, NPC_MS_ELEMENTAL);
+
+    //remove previously summoned familiar
+    if(GetIsObjectValid(oFam))
+        DestroyAssociate(oFam);
+        
+    int nLevel = GetLevelByClass(CLASS_TYPE_MASTER_OF_SHADOW, oPC);
+    string sShadow = "shd_shdelem_med";
+    if (nLevel >= 10)
+        sShadow = "shd_shdelem_med4";
+    else if (nLevel >= 7)
+        sShadow = "shd_shdelem_med3";
+    else if (nLevel >= 4)
+        sShadow = "shd_shdelem_med2";        
+       
+    oFam = CreateLocalNPC(oPC, ASSOCIATE_TYPE_FAMILIAR, sShadow, PRCGetSpellTargetLocation(), NPC_MS_ELEMENTAL);
+    AddAssociate(oPC, oFam);  
+    //set its name
+    string sName = GetFamiliarName(oPC);
+    if(sName == "")
+        sName = GetName(oPC)+ "'s Shadow Elemental";
+    SetName(oFam, sName);    
+
+    itemproperty ipIP;
+    object oSkin = GetPCSkin(oFam);
+    if (nLevel >= 10)
+        ipIP =ItemPropertyDamageImmunity(IP_CONST_DAMAGETYPE_COLD,IP_CONST_DAMAGEIMMUNITY_100_PERCENT);
+    else if (nLevel >= 6)
+        ipIP =ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD, IP_CONST_DAMAGERESIST_20); 
+    else if (nLevel >= 4)
+        ipIP =ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD, IP_CONST_DAMAGERESIST_10);            
+    else if (nLevel >= 2)
+        ipIP =ItemPropertyDamageResistance(IP_CONST_DAMAGETYPE_COLD, IP_CONST_DAMAGERESIST_5); 
+        
+    IPSafeAddItemProperty(oSkin, ipIP, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE);        
+        
+    if (nLevel >= 3) // Grow to size large
+        SetCreatureAppearanceType(oFam, APPEARANCE_TYPE_SHADOW_FIEND);
+}    
\ No newline at end of file
diff --git a/nwnds_scripts/prc_amagsys_gain.ncs b/nwnds_scripts/prc_amagsys_gain.ncs
new file mode 100644
index 000000000..f91269a67
Binary files /dev/null and b/nwnds_scripts/prc_amagsys_gain.ncs differ
diff --git a/nwnds_scripts/prc_amagsys_gain.nss b/nwnds_scripts/prc_amagsys_gain.nss
new file mode 100644
index 000000000..77b418bdb
--- /dev/null
+++ b/nwnds_scripts/prc_amagsys_gain.nss
@@ -0,0 +1,556 @@
+//:://////////////////////////////////////////////
+//:: Alternate magic system gain evaluation script
+//:: prc_amagsys_gain
+//:://////////////////////////////////////////////
+/** @file
+    This file determines if the given character
+    has gained new spells / powers / utterances /
+    whathaveyou since the last time it was run.
+    If so, it starts the relevant selection
+    conversations.
+
+    Add new classes to their respective magic
+    user type block, or if such doesn't exist
+    yet for the system the class belongs to,
+    make a new block for them at the end of main().
+
+
+    @author Ornedan
+    @date   Created - 2006.12.14
+ */
+//:://////////////////////////////////////////////
+//:://////////////////////////////////////////////
+
+#include "inc_dynconv"
+#include "psi_inc_psifunc"
+#include "inc_newspellbook"
+#include "true_inc_trufunc"
+#include "tob_inc_tobfunc"
+#include "shd_inc_shdfunc"
+#include "inv_inc_invfunc"
+
+//////////////////////////////////////////////////
+/*             Function prototypes              */
+//////////////////////////////////////////////////
+
+void CheckSpellbooks(object oPC);
+void CheckPsionics(object oPC);
+void CheckInvocations(object oPC);
+void CheckToB(object oPC);
+void CheckShadow(object oPC);
+void CheckTruenaming(object oPC);
+int CheckMissingPowers(object oPC, int nClass);
+int CheckMissingSpells(object oPC, int nClass, int nMinLevel, int nMaxLevel);
+int CheckMissingUtterances(object oPC, int nClass, int nLexicon);
+int CheckMissingManeuvers(object oPC, int nClass);
+int CheckMissingMysteries(object oPC, int nClass);
+int CheckMissingInvocations(object oPC, int nClass);
+void AMSCompatibilityCheck(object oPC);
+
+//////////////////////////////////////////////////
+/*             Function definitions             */
+//////////////////////////////////////////////////
+
+void main()
+{
+    object oPC = OBJECT_SELF;
+
+    // Sanity checks - Shifted or polymorphed characters may have their hide fucked up, and might be missing access to their hide-feats
+    // @todo Shifting probably doesn't do this anymore, could be ditchable - Ornedan, 20061214
+    if(GetLocalInt(oPC, "nPCShifted"))
+        return;
+    effect eTest = GetFirstEffect(oPC);
+    while(GetIsEffectValid(eTest))
+    {
+        if(GetEffectType(eTest) == EFFECT_TYPE_POLYMORPH)
+            return;
+        eTest = GetNextEffect(oPC);
+    }
+
+    DelayCommand(0.0f, CheckSpellbooks(oPC));
+}
+
+// Handle new spellbooks
+void CheckSpellbooks(object oPC)
+{
+    if(!GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK) && CheckMissingSpells(oPC, CLASS_TYPE_BARD, 0, 6))
+        return;
+    if(!GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK) && CheckMissingSpells(oPC, CLASS_TYPE_SORCERER, 0, 9))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_SUEL_ARCHANAMACH, 1, 5))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_FAVOURED_SOUL, 0, 9))
+        return;
+//    if(CheckMissingSpells(oPC, CLASS_TYPE_MYSTIC, 0, 9))
+//        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_WARMAGE, 0, 9))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_DREAD_NECROMANCER, 1, 9))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_HEXBLADE, 1, 4))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_DUSKBLADE, 0, 5))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_JUSTICEWW, 1, 4))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_KNIGHT_WEAVE, 1, 6))
+        return;        
+//    if(CheckMissingSpells(oPC, CLASS_TYPE_WITCH, 0, 9))
+//        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_SUBLIME_CHORD, 4, 9))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_ARCHIVIST, 0, 9))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_BEGUILER, 0, 9))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_HARPER, 1, 3))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_TEMPLAR, 0, 9))
+//        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_ASSASSIN, 1, 4))
+        return;
+    if(CheckMissingSpells(oPC, CLASS_TYPE_CELEBRANT_SHARESS, 1, 4))
+        return;
+
+    DelayCommand(0.0f, CheckPsionics(oPC));
+}
+
+// Handle psionics
+void CheckPsionics(object oPC)
+{
+    if(CheckMissingPowers(oPC, CLASS_TYPE_PSION))
+        return;
+    if(CheckMissingPowers(oPC, CLASS_TYPE_WILDER))
+        return;
+    if(CheckMissingPowers(oPC, CLASS_TYPE_PSYWAR))
+        return;
+    if(CheckMissingPowers(oPC, CLASS_TYPE_PSYCHIC_ROGUE))
+        return;        
+    if(CheckMissingPowers(oPC, CLASS_TYPE_FIST_OF_ZUOKEN))
+        return;
+    if(CheckMissingPowers(oPC, CLASS_TYPE_WARMIND))
+        return;
+    //expanded knowledge
+    if(CheckMissingPowers(oPC, -1))
+        return;
+    //epic expanded knowledge
+    if(CheckMissingPowers(oPC, -2))
+        return;
+
+    DelayCommand(0.0f, CheckInvocations(oPC));
+}
+
+// Handle Invocations
+void CheckInvocations(object oPC)
+{
+    if(CheckMissingInvocations(oPC, CLASS_TYPE_DRAGONFIRE_ADEPT))
+        return;
+    if(CheckMissingInvocations(oPC, CLASS_TYPE_WARLOCK))
+        return;
+    if(CheckMissingInvocations(oPC, CLASS_TYPE_DRAGON_SHAMAN))
+        return;
+    //extra invocations
+    if(CheckMissingInvocations(oPC, CLASS_TYPE_INVALID))
+        return;
+    //epic extra invocations
+    if(CheckMissingInvocations(oPC, -2))
+        return;
+
+    DelayCommand(0.0f, CheckToB(oPC));
+}
+
+// Handle Tome of Battle
+void CheckToB(object oPC)
+{
+    if(CheckMissingManeuvers(oPC, CLASS_TYPE_CRUSADER))
+        return;
+    if(CheckMissingManeuvers(oPC, CLASS_TYPE_SWORDSAGE))
+        return;
+    if(CheckMissingManeuvers(oPC, CLASS_TYPE_WARBLADE))
+        return;
+
+    DelayCommand(0.0f, CheckShadow(oPC));
+}
+
+// Handle Shadowcasting
+void CheckShadow(object oPC)
+{
+    if(CheckMissingMysteries(oPC, CLASS_TYPE_SHADOWCASTER))
+        return;
+    if(CheckMissingMysteries(oPC, CLASS_TYPE_SHADOWSMITH))
+        return;
+
+    DelayCommand(0.0f, CheckTruenaming(oPC));
+}
+
+// Handle Truenaming - Three different Lexicons to check
+void CheckTruenaming(object oPC)
+{
+    if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_EVOLVING_MIND))
+        return;
+    if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_CRAFTED_TOOL))
+        return;
+    if(CheckMissingUtterances(oPC, CLASS_TYPE_TRUENAMER, LEXICON_PERFECTED_MAP))
+        return;
+
+    if(!GetIsDM(oPC))
+        DelayCommand(0.0f, AMSCompatibilityCheck(oPC));
+}
+
+int CheckMissingPowers(object oPC, int nClass)
+{
+    int nLevel = GetLevelByClass(nClass, oPC);
+    if(!nLevel && nClass != -1 && nClass != -2)
+        return FALSE;
+    else if(nClass == -1 && !GetHasFeat(FEAT_EXPANDED_KNOWLEDGE_1))
+        return FALSE;
+    else if(nClass == -2 && !GetHasFeat(FEAT_EPIC_EXPANDED_KNOWLEDGE_1))
+        return FALSE;
+
+    int nCurrentPowers = GetPowerCount(oPC, nClass);
+    int nMaxPowers = GetMaxPowerCount(oPC, nClass);
+
+    if(nCurrentPowers < nMaxPowers)
+    {
+        // Mark the class for which the PC is to gain powers and start the conversation
+        SetLocalInt(oPC, "nClass", nClass);
+        StartDynamicConversation("psi_powconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+
+        return TRUE;
+    }
+    return FALSE;
+}
+
+int CheckMissingInvocations(object oPC, int nClass)
+{
+    int nLevel = GetLevelByClass(nClass, oPC);
+    if(!nLevel && (nClass == CLASS_TYPE_DRAGONFIRE_ADEPT || nClass == CLASS_TYPE_WARLOCK || nClass == CLASS_TYPE_DRAGON_SHAMAN))
+        return FALSE;
+    else if(nClass == CLASS_TYPE_INVALID && !GetHasFeat(FEAT_EXTRA_INVOCATION_I))
+               return FALSE;
+    else if(nClass == -2 && !GetHasFeat(FEAT_EPIC_EXTRA_INVOCATION_I))
+               return FALSE;
+
+    int nCurrentInvocations = GetInvocationCount(oPC, nClass);
+    if(DEBUG) DoDebug("Current Invocations: " + IntToString(nCurrentInvocations));
+    int nMaxInvocations = GetMaxInvocationCount(oPC, nClass);
+    if(DEBUG) DoDebug("Max Invocations: " + IntToString(nMaxInvocations));
+
+    if(nCurrentInvocations < nMaxInvocations)
+    {
+        // Mark the class for which the PC is to gain invocations and start the conversation
+        SetLocalInt(oPC, "nClass", nClass);
+        StartDynamicConversation("inv_invokeconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+
+        return TRUE;
+    }
+    return FALSE;
+}
+
+void AddSpellsForLevel(int nClass, int nLevel)
+{
+    object oPC = OBJECT_SELF;
+    object oSkin = GetPCSkin(oPC);
+    object oToken = GetHideToken(oPC);
+    string sFile = GetFileForClass(nClass);
+    string sSpellbook;
+    int nSpellbookType = GetSpellbookTypeForClass(nClass);
+    if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+        sSpellbook = "Spellbook"+IntToString(nClass);
+    else
+        sSpellbook = "Spellbook_Known_"+IntToString(nClass)+"_"+IntToString(nLevel);
+
+    // Create spells known persistant array  if it is missing
+    int nSize = array_get_size(oToken, sSpellbook);
+    if (nSize < 0)
+    {
+        array_create(oToken, sSpellbook);
+        nSize = 0;
+    }
+
+    //check for learnable spells
+    object oToken_Class = GetObjectByTag("SpellLvl_" + IntToString(nClass) + "_Level_" + IntToString(nLevel));
+    int nSpells_Total = array_get_size(oToken_Class, "Lkup");
+    int i;
+    for(i = 0; i < nSpells_Total; i++)
+    {
+        int nSpellbookID = array_get_int(oToken_Class, "Lkup", i);
+        if(Get2DAString(sFile, "AL", nSpellbookID) != "1")
+        {
+            array_set_int(oToken, sSpellbook, nSize, nSpellbookID);
+            nSize++;
+            if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+            {
+                int nIPFeatID = StringToInt(Get2DACache(sFile, "IPFeatID", nSpellbookID));
+                int nFeatID = StringToInt(Get2DACache(sFile, "FeatID", nSpellbookID));
+                AddSpellUse(oPC, nSpellbookID, nClass, sFile, "NewSpellbookMem_" + IntToString(nClass), nSpellbookType, oSkin, nFeatID, nIPFeatID);
+            }
+        }
+    }
+}
+
+int CheckMissingSpells(object oPC, int nClass, int nMinLevel, int nMaxLevel)
+{
+    int nLevel;
+    //Raks cast as sorcs
+    if(nClass == CLASS_TYPE_SORCERER && GetRacialType(oPC) == RACIAL_TYPE_RAKSHASA)
+        nLevel = GetLevelByClass(CLASS_TYPE_OUTSIDER, oPC);
+//    else if(nClass == CLASS_TYPE_SORCERER && GetRacialType(oPC) == RACIAL_TYPE_BOZAK) //Bozaks cast as sorcs
+//        nLevel = GetLevelByClass(CLASS_TYPE_DRAGON, oPC);
+    else if(nClass == CLASS_TYPE_SORCERER && GetRacialType(oPC) == RACIAL_TYPE_DRIDER) //Driders cast as sorcs
+        nLevel = GetLevelByClass(CLASS_TYPE_ABERRATION, oPC);
+    else    
+        nLevel = nClass == CLASS_TYPE_SUBLIME_CHORD ? GetLevelByClass(nClass, oPC) : GetSpellslotLevel(nClass, oPC);
+
+    if (DEBUG) DoDebug("CheckMissingSpells 1 Class: " + IntToString(nClass));
+    if (DEBUG) DoDebug("CheckMissingSpells 1 Level: " + IntToString(nLevel));
+
+    if(!nLevel)
+        return FALSE;
+    if(nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER)
+    {
+        if((GetLevelByClass(nClass, oPC) == nLevel) //no PrC
+            && !(GetHasFeat(FEAT_DRACONIC_GRACE, oPC) || GetHasFeat(FEAT_DRACONIC_BREATH, oPC))) //no Draconic feats that apply
+            return FALSE;
+    }
+    else if(nClass == CLASS_TYPE_ARCHIVIST)
+    {
+        int nLastGainLevel = GetPersistantLocalInt(oPC, "LastSpellGainLevel");
+        nLevel = GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC);
+
+        if(nLastGainLevel < nLevel)
+        {
+            if(nLevel == 1)
+            {
+                //count the number of available at 1st level spells
+                int nSpellsAvailable = 3 + GetAbilityModifier(ABILITY_INTELLIGENCE, oPC);
+                SetLocalInt(oPC, "LrnLvlUp", nSpellsAvailable);
+            }
+            else if(nLevel > 1)
+                //add additional 2 spells form cleric list
+                SetLocalInt(oPC, "LrnLvlUp", 2);
+
+            SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_ARCHIVIST);
+            SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
+            StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, TRUE, FALSE, oPC);
+
+            return TRUE;
+        }
+        //add cleric spells known for level 0
+        else if(persistant_array_get_size(oPC, "Spellbook_Known_"+IntToString(CLASS_TYPE_ARCHIVIST)+"_0") < 5)  // TODO: replace with GetSpellKnownCurrentCount
+        {
+            ActionDoCommand(AddSpellsForLevel(CLASS_TYPE_ARCHIVIST, 0));
+        }
+        else
+            return FALSE;
+    }
+    
+    if (DEBUG) DoDebug("CheckMissingSpells 2 Class: " + IntToString(nClass));
+    if (DEBUG) DoDebug("CheckMissingSpells 2 Level: " + IntToString(nLevel));
+     
+    int i;
+    for(i = nMinLevel; i <= nMaxLevel; i++)
+    {
+        int nMaxSpells = GetSpellKnownMaxCount(nLevel, i, nClass, oPC);
+        if(nMaxSpells > 0)
+        {
+            int nCurrentSpells = GetSpellKnownCurrentCount(oPC, i, nClass);
+            int nSpellsAvailable = GetSpellUnknownCurrentCount(oPC, i, nClass);
+
+            if(nCurrentSpells < nMaxSpells && nSpellsAvailable > 0)
+            {
+                if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS && bKnowsAllClassSpells(nClass))
+                {
+                    ActionDoCommand(AddSpellsForLevel(nClass, i));
+                }
+                else
+                {
+                    // Mark the class for which the PC is to gain powers and start the conversation
+                    SetLocalInt(oPC, "SpellGainClass", nClass);
+                    SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
+                    SetLocalInt(oPC, "SpellbookMaxSpelllevel", nMaxLevel);
+                    StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+
+                    return TRUE;
+                }
+            }
+        }
+    }
+    //Advanced Learning check
+    nLevel = GetLevelByClass(nClass, oPC);
+    int nALSpells = GetPersistantLocalInt(oPC, "AdvancedLearning_"+IntToString(nClass));
+    if(nClass == CLASS_TYPE_BEGUILER && nALSpells < (nLevel+1)/4)//one every 4 levels starting at 3.
+    {
+        // Mark the class for which the PC is to gain powers and start the conversation
+        SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_BEGUILER);
+        SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
+        SetLocalInt(oPC, "AdvancedLearning", 1);
+        StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+        return TRUE;
+    }
+    else if(nClass == CLASS_TYPE_DREAD_NECROMANCER && nALSpells < nLevel/4)//one every 4 levels
+    {
+        // Mark the class for which the PC is to gain powers and start the conversation
+        SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_DREAD_NECROMANCER);
+        SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
+        SetLocalInt(oPC, "AdvancedLearning", 1);
+        StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+        return TRUE;
+    }
+    else if(nClass == CLASS_TYPE_WARMAGE)
+    {
+        if((nLevel >= 40 && nALSpells < 9) ||// :/
+           (nLevel >= 36 && nLevel < 40 && nALSpells < 8) ||
+           (nLevel >= 32 && nLevel < 36 && nALSpells < 7) ||
+           (nLevel >= 28 && nLevel < 32 && nALSpells < 6) ||
+           (nLevel >= 24 && nLevel < 28 && nALSpells < 5) ||
+           (nLevel >= 16 && nLevel < 24 && nALSpells < 4) ||
+           (nLevel >= 11 && nLevel < 16 && nALSpells < 3) ||
+           (nLevel >= 6  && nLevel < 11 && nALSpells < 2) ||
+           (nLevel >= 3  && nLevel < 6  && nALSpells < 1))
+        {
+            // Mark the class for which the PC is to gain powers and start the conversation
+            SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_WARMAGE);
+            SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
+            SetLocalInt(oPC, "AdvancedLearning", 1);
+            StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+            return TRUE;
+        }
+    }
+    else if(nClass == CLASS_TYPE_NIGHTSTALKER && nALSpells < (nLevel+1)/6)//one every 6 levels starting at 5th
+    {
+        // Mark the class for which the PC is to gain powers and start the conversation
+        SetLocalInt(oPC, "SpellGainClass", CLASS_TYPE_NIGHTSTALKER);
+        SetLocalInt(oPC, "SpellbookMinSpelllevel", nMinLevel);
+        SetLocalInt(oPC, "AdvancedLearning", 1);
+        StartDynamicConversation("prc_s_spellgain", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+int CheckMissingUtterances(object oPC, int nClass, int nLexicon)
+{
+    int nLevel = GetLevelByClass(nClass, oPC);
+    if(!nLevel)
+        return FALSE;
+
+    int nCurrentUtterances = GetUtteranceCount(oPC, nClass, nLexicon);
+    int nMaxUtterances = GetMaxUtteranceCount(oPC, nClass, nLexicon);
+    if(DEBUG) DoDebug("CheckMissingUtterances(" + IntToString(nClass) + ", " + IntToString(nLexicon) + ", " + GetName(oPC) + ") = " + IntToString(nCurrentUtterances) + ", " + IntToString(nMaxUtterances));
+
+    if(nCurrentUtterances < nMaxUtterances)
+    {
+        // Mark the class for which the PC is to gain Utterances and start the conversation
+        SetLocalInt(oPC, "nClass", nClass);
+        StartDynamicConversation("true_utterconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+
+        return TRUE;
+    }
+    return FALSE;
+}
+
+int CheckMissingManeuvers(object oPC, int nClass)
+{
+    int nLevel = GetLevelByClass(nClass, oPC);
+    if(!nLevel)
+        return FALSE;
+
+    int nCurrentManeuvers = GetManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER);
+    int nMaxManeuvers = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_MANEUVER);
+    int nCurrentStances = GetManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE);
+    int nMaxStances = GetMaxManeuverCount(oPC, nClass, MANEUVER_TYPE_STANCE);
+
+    if(nCurrentManeuvers < nMaxManeuvers || nCurrentStances < nMaxStances)
+    {
+        // Mark the class for which the PC is to gain powers and start the conversation
+        SetLocalInt(oPC, "nClass", nClass);
+        StartDynamicConversation("tob_moveconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+
+        return TRUE;
+    }
+    return FALSE;
+}
+
+int CheckMissingMysteries(object oPC, int nClass)
+{
+    int nLevel = GetLevelByClass(nClass, oPC);
+    if(!nLevel)
+        return FALSE;
+
+    int nCurrentMysteries = GetMysteryCount(oPC, nClass);
+    int nMaxMysteries = GetMaxMysteryCount(oPC, nClass);
+
+    if(nCurrentMysteries < nMaxMysteries)
+    {
+        // Mark the class for which the PC is to gain powers and start the conversation
+        SetLocalInt(oPC, "nClass", nClass);
+        StartDynamicConversation("shd_mystconv", oPC, DYNCONV_EXIT_NOT_ALLOWED, FALSE, TRUE, oPC);
+
+        return TRUE;
+    }
+    return FALSE;
+}
+
+//AMS Compatibility functions - xwarren:
+void CopyAMSArray(object oHideToken, object oAMSToken, int nClass, string sArray, int nMin, int nMax, int nLoopSize = 100)
+{
+    string sFile = GetFileForClass(nClass);
+    int i = nMin;
+    while(i < nMin + nLoopSize && i < nMax)
+    {
+        int nSpellbookID = array_get_int(oHideToken, sArray, i);
+        int nSpell = StringToInt(Get2DACache(sFile, "RealSpellID", nSpellbookID));
+        if(DEBUG) DoDebug("Copying spell "+IntToString(nSpell));
+        array_set_int(oAMSToken, sArray, i, nSpell);
+        i++;
+    }
+    if(i < nMax)
+        DelayCommand(0.0, CopyAMSArray(oHideToken, oAMSToken, nClass, sArray, i, nMax));
+}
+
+void DoBuckUpAMS(object oPC, int nClass, string sSpellbook, object oHideToken, object oAMSToken)
+{
+    if(DEBUG) DoDebug("Creating buck-up copy of "+sSpellbook);
+    if(array_exists(oAMSToken, sSpellbook))
+        array_delete(oAMSToken, sSpellbook);
+    array_create(oAMSToken, sSpellbook);
+    int nSize = array_get_size(oHideToken, sSpellbook);
+    DelayCommand(0.0, CopyAMSArray(oHideToken, oAMSToken, nClass, sSpellbook, 0, nSize));
+}
+
+void AMSCompatibilityCheck(object oPC)
+{
+    //Get an extra hide token with amagsys info
+    object oAMSToken = GetHideToken(oPC, TRUE);
+    object oHideToken = GetHideToken(oPC);
+
+    int i;
+    for(i = 1; i <= 3; i++)
+    {
+        int nClass = GetClassByPosition(i, oPC);
+        string sSpellbook;
+        int nSpellbookType = GetSpellbookTypeForClass(nClass);
+        if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+        {
+            sSpellbook = "Spellbook"+IntToString(nClass);
+            int nSize1 = array_get_size(oHideToken, sSpellbook);
+            int nSize2 = array_get_size(oAMSToken, sSpellbook);
+            if(nSize1 > nSize2)
+                DelayCommand(0.1f, DoBuckUpAMS(oPC, nClass, sSpellbook, oHideToken, oAMSToken));
+        }
+        else if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
+        {
+            int j;
+            for(j = 0; j <= 9; j++)
+            {
+                sSpellbook = "Spellbook_Known_"+IntToString(nClass)+"_"+IntToString(j);
+                int nSize1 = array_get_size(oHideToken, sSpellbook);
+                int nSize2 = array_get_size(oAMSToken, sSpellbook);
+                if(nSize1 > nSize2)
+                    DelayCommand(0.1f, DoBuckUpAMS(oPC, nClass, sSpellbook, oHideToken, oAMSToken));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/nwnds_scripts/prc_cbtmed_spnhl.ncs b/nwnds_scripts/prc_cbtmed_spnhl.ncs
new file mode 100644
index 000000000..c92fcc877
Binary files /dev/null and b/nwnds_scripts/prc_cbtmed_spnhl.ncs differ
diff --git a/nwnds_scripts/prc_cbtmed_spnhl.nss b/nwnds_scripts/prc_cbtmed_spnhl.nss
new file mode 100644
index 000000000..f056f0678
--- /dev/null
+++ b/nwnds_scripts/prc_cbtmed_spnhl.nss
@@ -0,0 +1,116 @@
+/* Combat Medic spontaneous heal ability
+ *
+ * Created July 17 2005
+ * Author: GaiaWerewolf
+ */
+#include "prc_inc_spells"
+#include "prc_getbest_inc"
+
+int GetSpontaneousHealBurnableSpell(object oCaster)
+{
+    int nBurnableSpell = -1;
+
+    nBurnableSpell = GetBestL6Spell(oCaster, nBurnableSpell);
+    if(nBurnableSpell == -1)
+        nBurnableSpell = GetBestL7Spell(oCaster, nBurnableSpell);
+    if(nBurnableSpell == -1)
+        nBurnableSpell = GetBestL8Spell(oCaster, nBurnableSpell);
+    if(nBurnableSpell == -1)
+        nBurnableSpell = GetBestL9Spell(oCaster, nBurnableSpell);
+
+    return nBurnableSpell;
+}
+
+void main()
+{
+    //Declare our standard variables
+    object oCaster = OBJECT_SELF;
+    int nCasterLvl = GetLevelByTypeDivineFeats(oCaster, SPELL_HEAL);//character is most likely divine caster
+    int nArcane = GetPrimaryArcaneClass(oCaster);
+    if(nArcane == CLASS_TYPE_BARD || nArcane == CLASS_TYPE_WITCH)//but we check arcane classes just in case
+    {
+        int nTest = GetLevelByTypeArcaneFeats(oCaster, SPELL_HEAL);
+        if(nTest > nCasterLvl)
+            nCasterLvl = nTest;
+    }
+
+    int nClass, nLevel, i;
+    int nBurnableSpell = -1;
+    int bBioCastersLoopDone = 0;//will prevent running 'GetBestSpell' loops twice
+
+    for(i = 1; i <= 3; i++)
+    {
+        nClass = GetClassByPosition(i, oCaster);
+
+        if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS)
+        {
+            for(nLevel = 6; nLevel < 10; nLevel++)
+            {
+                nBurnableSpell = persistant_array_get_int(oCaster, "NewSpellbookMem_" + IntToString(nClass), nLevel);
+                if(nBurnableSpell > 0)
+                    break;
+            }
+
+            if(nBurnableSpell > 0)
+            {
+                SetLocalInt(oCaster, "DomainCast", -1);
+                SetLocalInt(oCaster, "NSB_Class", nClass);
+                SetLocalInt(oCaster, "NSB_SpellLevel", nLevel);
+                ActionCastSpell(SPELL_HEAL, nCasterLvl, 16 + GetAbilityModifier(ABILITY_WISDOM, oCaster), 0, METAMAGIC_NONE, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, FALSE);
+                return;
+            }
+        }
+        else if(GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_PREPARED)
+        {
+            string sFile = GetFileForClass(nClass);
+            string sArrayIDX, sArray = "NewSpellbookMem_" + IntToString(nClass);
+            int nSpellbookID, nSpellLevel, MaxValue;
+
+            for(nLevel = 6; nLevel < 10; nLevel++)
+            {
+                sArrayIDX = "SpellbookIDX" + IntToString(nLevel) + "_" + IntToString(nClass);
+                MaxValue = persistant_array_get_size(oCaster, sArrayIDX);
+                int j = 0;
+                while(j < MaxValue)
+                {
+                    nSpellbookID = persistant_array_get_int(oCaster, sArrayIDX, j);
+                    nSpellLevel = StringToInt(Get2DACache(sFile, "Level", nSpellbookID));
+                    if(nSpellLevel > 5)
+                    {
+                        nBurnableSpell = persistant_array_get_int(oCaster, sArray, nSpellbookID);
+                        if(nBurnableSpell > 0)//escape while loop
+                            break;
+                    }
+                    j++;
+                }
+                if(nBurnableSpell > 0)//escape for loop
+                    break;
+            }
+
+            if(nBurnableSpell > 0)
+            {
+                SetLocalInt(oCaster, "DomainCast", -1);
+                SetLocalInt(oCaster, "NSB_Class", nClass);
+                SetLocalInt(oCaster, "NSB_SpellbookID", nSpellbookID);
+                ActionCastSpell(SPELL_HEAL, nCasterLvl, 16 + GetAbilityModifier(ABILITY_WISDOM, oCaster), 0, METAMAGIC_NONE, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, FALSE);
+                return;
+            }
+        }
+        if(((nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_SORCERER) && persistant_array_get_size(oCaster, "Spellbook" + IntToString(nClass)) != -1) ||//bard/sorcerer *not* using new spellbooks
+             nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_DRUID || nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_DEFILER)//other bioware casters with 6+ spell levels
+        {
+            nBurnableSpell = bBioCastersLoopDone ? -1: GetSpontaneousHealBurnableSpell(oCaster);
+            bBioCastersLoopDone = 1;
+            if(nBurnableSpell != -1)
+            {
+                SetLocalInt(oCaster, "DomainCast", -1);
+                SetLocalInt(oCaster, "Domain_BurnableSpell", nBurnableSpell + 1);
+                ActionCastSpell(SPELL_HEAL, nCasterLvl, 16 + GetAbilityModifier(ABILITY_WISDOM, oCaster), 0, METAMAGIC_NONE, CLASS_TYPE_INVALID, 0, 0, OBJECT_INVALID, FALSE);
+                return;
+            }
+        }
+    }
+
+    //if we got here - there's no burnable spells left
+    FloatingTextStringOnCreature("You have no spells left to trade for a spontaneous heal.", oCaster, FALSE);
+}
\ No newline at end of file
diff --git a/nwnds_scripts/prc_ccc_make_pc.ncs b/nwnds_scripts/prc_ccc_make_pc.ncs
new file mode 100644
index 000000000..19c876944
Binary files /dev/null and b/nwnds_scripts/prc_ccc_make_pc.ncs differ
diff --git a/nwnds_scripts/prc_ccc_make_pc.nss b/nwnds_scripts/prc_ccc_make_pc.nss
new file mode 100644
index 000000000..352b1886c
--- /dev/null
+++ b/nwnds_scripts/prc_ccc_make_pc.nss
@@ -0,0 +1,252 @@
+#include "prc_alterations"
+#include "inc_letocommands"
+#include "prc_racial_const"
+#include "ccc_inc_convo"
+// #include "inc_encrypt"
+#include "prc_class_const"
+
+void main()
+{
+    //define some varaibles
+    object oPC = OBJECT_SELF;
+    int i;
+    //get some stored data
+    int         nStr =              GetLocalInt(oPC, "Str");
+    int         nDex =              GetLocalInt(oPC, "Dex");
+    int         nCon =              GetLocalInt(oPC, "Con");
+    int         nInt =              GetLocalInt(oPC, "Int");
+    int         nWis =              GetLocalInt(oPC, "Wis");
+    int         nCha =              GetLocalInt(oPC, "Cha");
+
+    int         nRace =             GetLocalInt(oPC, "Race");
+
+    int         nClass =            GetLocalInt(oPC, "Class");
+    int         nHitPoints =        GetLocalInt(oPC, "HitPoints");
+
+    int         nSex =              GetLocalInt(oPC, "Gender");
+
+    int         nOrder =            GetLocalInt(oPC, "LawfulChaotic");
+    int         nMoral =            GetLocalInt(oPC, "GoodEvil");
+    
+    int         nSkillPointsSaved=  GetLocalInt(oPC, "SavedSkillPoints");
+
+
+    int         nFamiliar =         GetLocalInt(oPC, "Familiar");
+
+    int         nAnimalCompanion =  GetLocalInt(oPC, "Companion");
+
+    int         nDomain1 =          GetLocalInt(oPC, "Domain1");
+    int         nDomain2 =          GetLocalInt(oPC, "Domain2");
+
+    int         nSchool =           GetLocalInt(oPC, "School");
+    
+    int         nSpellsPerDay0 =    GetLocalInt(oPC, "SpellsPerDay0");
+    int         nSpellsPerDay1 =    GetLocalInt(oPC, "SpellsPerDay1");
+
+
+    int         nVoiceset =         GetLocalInt(oPC, "Soundset");
+    int         nSkin =             GetLocalInt(oPC, "Skin");
+    int         nHair =             GetLocalInt(oPC, "Hair");
+    int         nTattooColour1 =    GetLocalInt(oPC, "TattooColour1");
+    int         nTattooColour2 =    GetLocalInt(oPC, "TattooColour2");
+
+
+    //clear existing stuff
+    string sScript;
+    sScript += LetoDelete("FeatList");
+    sScript += LetoDelete("ClassList");
+    sScript += LetoDelete("LvlStatList");
+    sScript += LetoDelete("SkillList");
+    sScript += LetoAdd("FeatList", "", "list");
+    sScript += LetoAdd("ClassList", "", "list");
+    sScript += LetoAdd("LvlStatList", "", "list");
+    sScript += LetoAdd("SkillList", "", "list");
+
+    //Sex
+    sScript += SetGender(nSex);
+
+    //Race
+    sScript += SetRace(nRace);
+
+    //Class
+    sScript += LetoAdd("ClassList/Class", IntToString(nClass), "int");
+    sScript += LetoAdd("ClassList/[0]/ClassLevel", "1", "short");
+    sScript += LetoAdd("LvlStatList/LvlStatClass", IntToString(nClass), "byte");
+    sScript += LetoAdd("LvlStatList/[0]/EpicLevel", "0", "byte");
+    sScript += LetoAdd("LvlStatList/[0]/LvlStatHitDie", IntToString(nHitPoints), "byte");
+    sScript += LetoAdd("LvlStatList/[0]/FeatList", "", "list");
+    sScript += LetoAdd("LvlStatList/[0]/SkillList", "", "list");
+
+    //Alignment
+    sScript += LetoSet("LawfulChaotic", IntToString(nOrder), "byte");
+    sScript += LetoSet("GoodEvil", IntToString(nMoral), "byte");
+
+    //Familiar
+    //has a random name
+    if((nClass == CLASS_TYPE_WIZARD ||
+        nClass == CLASS_TYPE_DEFILER ||
+        nClass == CLASS_TYPE_SORCERER)
+            && !GetPRCSwitch(PRC_PNP_FAMILIARS))
+    {
+        sScript += LetoSet("FamiliarType", IntToString(nFamiliar), "int");
+        if(GetFamiliarName(oPC) == "")
+            sScript += LetoSet("FamiliarName", RandomName(NAME_FAMILIAR), "string");
+    }
+
+    //Animal Companion
+    //has a random name
+    if(nClass == CLASS_TYPE_DRUID)
+    {
+        sScript += LetoSet("CompanionType", IntToString(nAnimalCompanion), "int");
+        if(GetAnimalCompanionName(oPC) == "")
+            sScript += LetoSet("CompanionName", RandomName(NAME_ANIMAL), "string");
+    }
+
+    //Domains
+    if(nClass == CLASS_TYPE_CLERIC)
+    {
+        // fix for air domain being 0
+        if (nDomain1 == -1)
+            nDomain1 = 0;
+        if (nDomain2 == -1)
+            nDomain2 = 0;
+        sScript += LetoAdd("ClassList/[0]/Domain1", IntToString(nDomain1), "byte");
+        sScript += LetoAdd("ClassList/[0]/Domain2", IntToString(nDomain2), "byte");
+    }
+
+    //Ability Scores
+    sScript += SetAbility(ABILITY_STRENGTH, nStr);
+    sScript += SetAbility(ABILITY_DEXTERITY, nDex);
+    sScript += SetAbility(ABILITY_CONSTITUTION, nCon);
+    sScript += SetAbility(ABILITY_INTELLIGENCE, nInt);
+    sScript += SetAbility(ABILITY_WISDOM, nWis);
+    sScript += SetAbility(ABILITY_CHARISMA, nCha);
+
+    //Feats
+    //Make sure the list exists
+    //Populate the list from array
+    for(i=0;i<array_get_size(oPC, "Feats"); i++)
+    {
+        string si = IntToString(i);
+        int nFeatID =array_get_int(oPC, "Feats", i);
+        if(nFeatID != 0)
+        {
+            if(nFeatID == -1)//alertness fix
+                nFeatID = 0;
+            DoDebug("Feat array positon "+IntToString(i)+" is "+IntToString(nFeatID));
+            sScript += LetoAdd("FeatList/Feat", IntToString(nFeatID), "word");
+            sScript += LetoAdd("LvlStatList/[0]/FeatList/Feat", IntToString(nFeatID), "word");
+        }
+    }
+
+    //Skills
+    for (i=0;i<=GetPRCSwitch(FILE_END_SKILLS);i++)
+    {
+        sScript += LetoAdd("SkillList/Rank", IntToString(array_get_int(oPC, "Skills", i)), "byte");
+        sScript += LetoAdd("LvlStatList/[_]/SkillList/Rank", IntToString(array_get_int(oPC, "Skills", i)), "byte");
+    }
+    sScript += LetoAdd("SkillPoints", IntToString(nSkillPointsSaved), "word");
+    sScript += LetoAdd("LvlStatList/[_]/SkillPoints", IntToString(nSkillPointsSaved), "word");
+    
+    // saved skill points - this is set regardless to stop the skill point exploit
+    sScript += LetoSet("SkillPoints", IntToString(nSkillPointsSaved), "word");
+
+    //Spells
+    if(nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_DEFILER) // NWN Dark Sun class
+    {
+        sScript += LetoAdd("ClassList/[_]/KnownList0", "", "list");
+        sScript += LetoAdd("ClassList/[_]/KnownList1", "", "list");
+        sScript += LetoAdd("LvlStatList/[_]/KnownList0", "", "list");
+        sScript += LetoAdd("LvlStatList/[_]/KnownList1", "", "list");
+        for (i=0;i<array_get_size(oPC, "SpellLvl0");i++)
+        {
+            sScript += LetoAdd("ClassList/[_]/KnownList0/Spell", IntToString(array_get_int(oPC, "SpellLvl0", i)), "word");
+            sScript += LetoAdd("LvlStatList/[_]/KnownList0/Spell", IntToString(array_get_int(oPC, "SpellLvl0", i)), "word");
+        }
+        for (i=0;i<array_get_size(oPC, "SpellLvl1");i++)
+        {
+            sScript += LetoAdd("ClassList/[_]/KnownList1/Spell", IntToString(array_get_int(oPC, "SpellLvl1", i)), "word");
+            sScript += LetoAdd("LvlStatList/[_]/KnownList1/Spell", IntToString(array_get_int(oPC, "SpellLvl1", i)), "word");
+        }
+        //throw spellschoool in here too
+        if(GetPRCSwitch(PRC_PNP_SPELL_SCHOOLS))
+            sScript += LetoAdd("ClassList/[_]/School", IntToString(9), "byte");
+        else
+            sScript += LetoAdd("ClassList/[_]/School", IntToString(nSchool), "byte");
+    }
+    else if (nClass == CLASS_TYPE_BARD)
+    {
+        sScript += LetoAdd("ClassList/[_]/KnownList0", "", "list");
+        sScript += LetoAdd("ClassList/[_]/SpellsPerDayList", "", "list");
+        sScript += LetoAdd("LvlStatList/[_]/KnownList0", "", "list");
+        for (i=0;i<array_get_size(oPC, "SpellLvl0");i++)
+        {
+            sScript += LetoAdd("ClassList/[_]/KnownList0/Spell", IntToString(array_get_int(oPC, "SpellLvl0", i)), "word");
+            sScript += LetoAdd("LvlStatList/[_]/KnownList0/Spell", IntToString(array_get_int(oPC, "SpellLvl0", i)), "word");
+        }
+        //spells per day
+        sScript += LetoAdd("ClassList/[_]/SpellsPerDayList/NumSpellsLeft", IntToString(nSpellsPerDay0), "word");
+    }
+    else if (nClass == CLASS_TYPE_SORCERER)
+    {
+        sScript += LetoAdd("ClassList/[_]/KnownList0", "", "list");
+        sScript += LetoAdd("ClassList/[_]/KnownList1", "", "list");
+        sScript += LetoAdd("ClassList/[_]/SpellsPerDayList", "", "list");
+        sScript += LetoAdd("LvlStatList/[_]/KnownList0", "", "list");
+        sScript += LetoAdd("LvlStatList/[_]/KnownList1", "", "list");
+        for (i=0;i<array_get_size(oPC, "SpellLvl0");i++)
+        {
+            sScript += LetoAdd("ClassList/[_]/KnownList0/Spell", IntToString(array_get_int(oPC, "SpellLvl0", i)), "word");
+            sScript += LetoAdd("LvlStatList/[_]/KnownList0/Spell", IntToString(array_get_int(oPC, "SpellLvl0", i)), "word");
+        }
+        for (i=0;i<array_get_size(oPC, "SpellLvl1");i++)
+        {
+            sScript += LetoAdd("ClassList/[_]/KnownList1/Spell", IntToString(array_get_int(oPC, "SpellLvl1", i)), "word");
+            sScript += LetoAdd("LvlStatList/[_]/KnownList1/Spell", IntToString(array_get_int(oPC, "SpellLvl1", i)), "word");
+        }
+        //spells per day
+        sScript += LetoAdd("ClassList/[_]/SpellsPerDayList/NumSpellsLeft", IntToString(nSpellsPerDay0), "word");
+        sScript += LetoAdd("ClassList/[_]/SpellsPerDayList/NumSpellsLeft", IntToString(nSpellsPerDay1), "word");
+    }
+
+    //Appearance stuff
+
+    if(nVoiceset != -1) //keep existing voiceset
+        sScript += LetoSet("SoundSetFile", IntToString(nVoiceset), "word");
+    if(nSkin != -1) // keep existing skin colour
+        sScript += SetSkinColor(nSkin);
+    if(nHair != -1) // keep existing hair colour
+        sScript += SetHairColor(nHair);
+    if (nTattooColour1 != -1)
+        sScript += SetTattooColor(nTattooColour1, 1);
+    if (nTattooColour2 != -1)
+        sScript += SetTattooColor(nTattooColour2, 2);
+    
+    sScript += LetoSet("Tag", Encrypt(oPC), "string");
+    //give an XP so the XP switch works
+    SetXP(oPC, 1);
+
+    SetLocalInt(oPC, "StopRotatingCamera", TRUE);
+    SetCutsceneMode(oPC, FALSE);
+    // clean up local variables
+    DoCleanup();
+    object oClone = GetLocalObject(oPC, "Clone");
+    AssignCommand(oClone, SetIsDestroyable(TRUE));
+    DestroyObject(oClone);
+    //do anti-hacker stuff
+    SetPlotFlag(oPC, FALSE);
+    SetImmortal(oPC, FALSE);
+    AssignCommand(oPC, SetIsDestroyable(TRUE));
+    // removes the cutscene paralysis and invisibility
+    ForceRest(oPC);
+    // let the convoCC be used by someone else
+    DeleteLocalObject(GetModule(), "ccc_active_pc");
+    // Here's where the custom PW script is run if the switch is set
+    if(GetPRCSwitch(PRC_CONVOCC_CUSTOM_EXIT_SCRIPT))
+    {
+        ExecuteScript("ccc_custom_exit", oPC);
+    }
+    StackedLetoScript(sScript);
+
+    RunStackedLetoScriptOnObject(oPC, "OBJECT", "SPAWN");
+}
diff --git a/nwnds_scripts/prc_ef_spell.ncs b/nwnds_scripts/prc_ef_spell.ncs
new file mode 100644
index 000000000..939627c13
Binary files /dev/null and b/nwnds_scripts/prc_ef_spell.ncs differ
diff --git a/nwnds_scripts/prc_ef_spell.nss b/nwnds_scripts/prc_ef_spell.nss
new file mode 100644
index 000000000..bf554252c
--- /dev/null
+++ b/nwnds_scripts/prc_ef_spell.nss
@@ -0,0 +1,331 @@
+//:://////////////////////////////////////////////
+//:: Spell selection for enleightened fist's  arcane fist/rejuvenation abilities
+//:: prc_ef_spell.nss
+//:://////////////////////////////////////////////
+/** @file
+    Spell selection for enleightened fist's  arcane fist/rejuvenation abilities
+    Handles the dynamic convo *and* the quickselects
+
+    @author HackyKid
+    @date   Created  - yyyy.mm.dd
+*/
+//:://////////////////////////////////////////////
+//:://////////////////////////////////////////////
+
+#include "prc_spell_const"
+#include "inc_dynconv"
+#include "inc_newspellbook"
+
+/* Constant defintions */
+const int STAGE_ENTRY = 0;
+const int STAGE_SLOT  = 1;
+const int STAGE_LVL0  = 10;
+const int STAGE_LVL9  = 20;
+
+/* Aid functions */
+void PopulateList(object oPC, int nLevel, int iClass, int nChoice)
+{
+    if(!GetLocalInt(oPC, "DynConv_Waiting"))
+        return;
+
+    int nClass = GetClassByPosition(iClass);
+    if(GetIsArcaneClass(nClass))
+    {
+        int i = 0, MaxValue = 0, nSpellID;
+        if(nClass == CLASS_TYPE_WIZARD
+		|| nClass == CLASS_TYPE_DEFILER // NWN Dark Sun class
+        || (nClass == CLASS_TYPE_SORCERER && GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK)))
+        {
+            string sFile = "cls_spell_sorc";
+            object oToken = GetObjectByTag("SpellLvl_9_Level_" + IntToString(nLevel));
+            MaxValue = array_get_size(oToken, "Lkup");
+            //DoDebug("EF PopulateList: nClass = "+IntToString(nClass));
+            //DoDebug("EF PopulateList: nLevel = "+IntToString(nLevel));
+            //DoDebug("EF PopulateList: MaxValue = "+IntToString(MaxValue));
+            while(i < MaxValue)
+            {
+                nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", array_get_int(oToken, "Lkup", i)));
+                if(GetHasSpell(nSpellID, oPC))
+                {
+                    string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                    AddChoice(sName, nChoice, oPC);
+                    SetLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                    SetLocalInt(oPC, "EF_REAL_SPELL_CHOICE_" + IntToString(nChoice), -1);
+                    nChoice++;
+                }
+                i++;
+            }
+        }
+        else if(nClass == CLASS_TYPE_BARD && GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK))
+        {
+            string sFile = "cls_spell_bard";
+            object oToken = GetObjectByTag("SpellLvl_1_Level_" + IntToString(nLevel));
+            MaxValue = array_get_size(oToken, "Lkup");
+            //DoDebug("EF PopulateList: MaxValue = "+IntToString(MaxValue));
+            while(i < MaxValue)
+            {
+                nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", array_get_int(oToken, "Lkup", i)));
+                if(GetHasSpell(nSpellID, oPC))
+                {
+                    string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                    AddChoice(sName, nChoice, oPC);
+                    SetLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                    SetLocalInt(oPC, "EF_REAL_SPELL_CHOICE_" + IntToString(nChoice), -1);
+                    nChoice++;
+                }
+                i++;
+            }
+        }
+        else
+        {
+            string sFile = GetFileForClass(nClass);
+            string sArray = "NewSpellbookMem_" + IntToString(nClass);
+            // if we ever add another arcane caster with prepared spellbook
+            // uncomment all following lines
+            //int nSpellbookType = GetSpellbookTypeForClass(nClass);
+            //if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+            {
+                int nCount = persistant_array_get_int(oPC, sArray, nLevel);
+                //DoDebug("EF PopulateList: nCount = "+IntToString(nCount));
+                if(nCount)
+                {
+                    MaxValue = persistant_array_get_size(oPC, "Spellbook"+IntToString(nClass));
+                    while(i < MaxValue)
+                    {
+                        int nNewSpellbookID = persistant_array_get_int(oPC, "Spellbook"+IntToString(nClass), i);
+                        if(nLevel == StringToInt(Get2DACache(sFile, "Level", nNewSpellbookID))
+                        && GetHasFeat(StringToInt(Get2DACache(sFile, "FeatID", nNewSpellbookID)), oPC))
+                        {
+                            int nRealSpell = StringToInt(Get2DACache(sFile, "SpellID", nNewSpellbookID));
+                            string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell)));
+                            AddChoice(sName, nChoice, oPC);
+                            SetLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice), nLevel);
+                            SetLocalInt(oPC, "EF_REAL_SPELL_CHOICE_" + IntToString(nChoice), nRealSpell);
+                            SetLocalString(oPC, "EF_CLASS_ARRAY_" + IntToString(nChoice), sArray);
+                            nChoice++;
+                        }
+                        i++;
+                    }
+                }
+            }
+            /*else if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
+            {
+                string sArrayIDX = "SpellbookIDX" + IntToString(nLevel) + "_" + IntToString(nClass);
+                MaxValue = persistant_array_get_size(oPC, sArrayIDX);
+                while(i < MaxValue)
+                {
+                    int nNewSpellbookID = persistant_array_get_int(oPC, sArrayIDX, i);
+                    int nCount = persistant_array_get_int(oPC, sArray, nNewSpellbookID);
+                    if(nCount
+                    && GetHasFeat(StringToInt(Get2DACache(sFile, "FeatID", nNewSpellbookID)), oPC))
+                    {
+                        int nRealSpell = StringToInt(Get2DACache(sFile, "RealSpellID", nNewSpellbookID));
+                        string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell)));
+                        AddChoice(sName, nChoice, oPC);
+                        SetLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice), nNewSpellbookID);
+                        SetLocalInt(oPC, "EF_REAL_SPELL_CHOICE_" + IntToString(nChoice), nRealSpell);
+                        SetLocalString(oPC, "EF_CLASS_ARRAY_" + IntToString(nChoice), sArray);
+                        nChoice++;
+                    }
+                    i++;
+                }
+            }*/
+        }
+    }
+
+    if(iClass == 3)
+    {
+        SetDefaultTokens();
+        DeleteLocalInt(oPC, "DynConv_Waiting");
+        FloatingTextStringOnCreature("*Done*", oPC, FALSE);
+        return;
+    }
+
+    DelayCommand(0.01, PopulateList(oPC, nLevel, iClass + 1, nChoice));
+}
+
+void main()
+{
+    object oPC = OBJECT_SELF;
+    int nID = GetSpellId();
+    int nValue = GetLocalInt(GetPCSpeaker(), DYNCONV_VARIABLE);
+
+    //SendMessageToPC(oPC, "prc_ef_spell:" + IntToString(nID) + " nVal:"+ IntToString(nValue));
+    if (nValue != 0) {
+        // do conversation
+        oPC = GetPCSpeaker();
+        /* Get the value of the local variable set by the conversation script calling
+         * this script. Values:
+         * DYNCONV_ABORTED     Conversation aborted
+         * DYNCONV_EXITED      Conversation exited via the exit node
+         * DYNCONV_SETUP_STAGE System's reply turn
+         * 0                   Error - something else called the script
+         * Other               The user made a choice
+         */
+        // The stage is used to determine the active conversation node.
+        // 0 is the entry node.
+        int nStage = GetStage(oPC);
+
+        if(nValue == DYNCONV_SETUP_STAGE)
+        {
+            // Check if this stage is marked as already set up
+            // This stops list duplication when scrolling
+            if(!GetIsStageSetUp(nStage, oPC))
+            {
+                // variable named nStage determines the current conversation node
+                // Function SetHeader to set the text displayed to the PC
+                // Function AddChoice to add a response option for the PC. The responses are show in order added
+                if(nStage == STAGE_ENTRY)
+                {
+                    SetHeader("Select Spell Level:");
+                    AddChoice(GetStringByStrRef(690),  1, oPC);//"Level 1"
+                    AddChoice(GetStringByStrRef(725),  2, oPC);//"Level 2"
+                    AddChoice(GetStringByStrRef(687),  3, oPC);//"Level 3"
+                    AddChoice(GetStringByStrRef(684),  4, oPC);//"Level 4"
+                    AddChoice(GetStringByStrRef(1026), 5, oPC);//"Level 5"
+                    AddChoice(GetStringByStrRef(1014), 6, oPC);//"Level 6"
+                    AddChoice(GetStringByStrRef(2214), 7, oPC);//"Level 7"
+                    AddChoice(GetStringByStrRef(2215), 8, oPC);//"Level 8"
+                    AddChoice(GetStringByStrRef(2216), 9, oPC);//"Level 9"
+                    MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
+                    SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
+                }
+                else if (nStage >= STAGE_LVL0 && nStage <= STAGE_LVL9)
+                {
+                    // Set the header
+                    SetHeader("Select Spell:");
+                    int nLevel = nStage - STAGE_LVL0;
+                    SetLocalInt(oPC, "DynConv_Waiting", TRUE);
+
+                    PopulateList(oPC, nLevel, 1, 1);
+
+                    MarkStageSetUp(nStage, oPC);
+                }
+                else if (nStage = STAGE_SLOT)
+                {
+                    SetHeader("Select QuickSlot:");
+                    AddChoice("Slot 1", 1, oPC);
+                    AddChoice("Slot 2", 2, oPC);
+                    AddChoice("Slot 3", 3, oPC);
+                    AddChoice("Slot 4", 4, oPC);
+                    MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
+                    SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
+                }
+
+            //add more stages for more nodes with Else If clauses
+            }
+
+            // Do token setup
+            SetupTokens();
+        }
+        // End of conversation cleanup
+        else if(nValue == DYNCONV_EXITED)
+        {
+            int nChoice = 1;
+            while(GetLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice)))
+            {
+                DeleteLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice));
+                DeleteLocalInt(oPC, "EF_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+                DeleteLocalString(oPC, "EF_CLASS_ARRAY_" + IntToString(nChoice));
+                nChoice++;
+            }
+            DeleteLocalInt(oPC, "EF_SPELL_ID");
+            DeleteLocalInt(oPC, "EF_REAL_SPELL_ID");
+            DeleteLocalString(oPC, "EF_CLASS_ARRAY_ID");
+            DeleteLocalInt(oPC, "EF_SPELL_LEVEL_CHOICE");
+        }
+        // Abort conversation cleanup.
+        // NOTE: This section is only run when the conversation is aborted
+        // while aborting is allowed. When it isn't, the dynconvo infrastructure
+        // handles restoring the conversation in a transparent manner
+        else if(nValue == DYNCONV_ABORTED)
+        {
+            int nChoice = 1;
+            while(GetLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice)))
+            {
+                DeleteLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice));
+                DeleteLocalInt(oPC, "EF_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+                DeleteLocalString(oPC, "EF_CLASS_ARRAY_" + IntToString(nChoice));
+                nChoice++;
+            }
+            DeleteLocalInt(oPC, "EF_SPELL_ID");
+            DeleteLocalInt(oPC, "EF_REAL_SPELL_ID");
+            DeleteLocalString(oPC, "EF_CLASS_ARRAY_ID");
+            DeleteLocalInt(oPC, "EF_SPELL_LEVEL_CHOICE");
+        }
+        // Handle PC responses
+        else
+        {
+            // variable named nChoice is the value of the player's choice as stored when building the choice list
+            // variable named nStage determines the current conversation node
+            int nChoice = GetChoice(oPC);
+            if(nStage == STAGE_ENTRY)
+            {
+                int nLevel = nChoice;
+                SetLocalInt(oPC, "EF_SPELL_LEVEL_CHOICE", nLevel);
+                nStage = STAGE_LVL0 + nChoice;
+                // Move to another stage based on response, for example
+                //nStage = STAGE_QUUX;
+            }
+            else if (nStage >= STAGE_LVL0 && nStage <= STAGE_LVL9)
+            {
+                MarkStageNotSetUp(nStage, oPC);
+                int nSpell = GetLocalInt(oPC, "EF_SPELL_CHOICE_" + IntToString(nChoice));
+                int nRealSpell = GetLocalInt(oPC, "EF_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+                string sArray = GetLocalString(oPC, "EF_CLASS_ARRAY_" + IntToString(nChoice));
+
+                SetLocalInt(oPC, "EF_SPELL_ID", nSpell);
+                SetLocalInt(oPC, "EF_REAL_SPELL_ID", nRealSpell);
+                SetLocalString(oPC, "EF_CLASS_ARRAY_ID", sArray);
+
+                nStage = STAGE_SLOT;
+            }
+            else if (nStage = STAGE_SLOT)
+            {
+                int nSpell = GetLocalInt(oPC, "EF_SPELL_ID");
+                int nRealSpell = GetLocalInt(oPC, "EF_REAL_SPELL_ID");
+                string sArray = GetLocalString(oPC, "EF_CLASS_ARRAY_ID");
+                int nLevel = GetLocalInt(oPC, "EF_SPELL_LEVEL_CHOICE");
+                SetLocalInt(oPC, "EF_SPELL_QUICK" + IntToString(nChoice), nSpell);
+                SetLocalInt(oPC, "EF_REAL_SPELL_QUICK" + IntToString(nChoice), nRealSpell);
+                SetLocalString(oPC, "EF_SPELL_QUICK" + IntToString(nChoice), sArray);
+                SetLocalInt(oPC, "EF_SPELL_QUICK" + IntToString(nChoice) + "LVL", nLevel);
+
+                nStage = STAGE_ENTRY;
+            }
+            // Store the stage value. If it has been changed, this clears out the choices
+            SetStage(nStage, oPC);
+        }
+    }
+    else if (nID == SPELL_EF_SPELL_SELECT_CONVO)
+    {
+        DelayCommand(0.5, StartDynamicConversation("prc_ef_spell", oPC, DYNCONV_EXIT_ALLOWED_SHOW_CHOICE, TRUE, FALSE, oPC));
+    }
+    else
+    {
+        string sSlotNo;
+        switch(nID)
+        {
+            case SPELL_EF_SPELL_SELECT_QUICK1: sSlotNo = "1"; break;
+            case SPELL_EF_SPELL_SELECT_QUICK2: sSlotNo = "2"; break;
+            case SPELL_EF_SPELL_SELECT_QUICK3: sSlotNo = "3"; break;
+            case SPELL_EF_SPELL_SELECT_QUICK4: sSlotNo = "4"; break;
+        }
+
+        if(sSlotNo == "")
+            return;
+
+        int nSpell = GetLocalInt(oPC, "EF_SPELL_QUICK"+sSlotNo);
+        int nLevel = GetLocalInt(oPC, "EF_SPELL_QUICK"+sSlotNo+"LVL");
+        int nRealSpell = GetLocalInt(oPC, "EF_REAL_SPELL_QUICK"+sSlotNo);
+        if(nRealSpell == -1) nRealSpell = nSpell;
+        string sArray = GetLocalString(oPC, "EF_SPELL_QUICK"+sSlotNo);
+        SetLocalInt(oPC, "EF_SPELL_CURRENT", nSpell);
+        SetLocalInt(oPC, "EF_SPELL_CURRENT_LVL", nLevel);
+        SetLocalInt(oPC, "EF_REAL_SPELL_CURRENT", nRealSpell);
+        SetLocalString(oPC, "EF_SPELL_CURRENT", sArray);
+        int nUses = sArray == "" ? GetHasSpell(nSpell, oPC) : persistant_array_get_int(oPC, sArray, nSpell);
+        FloatingTextStringOnCreature("*Selected Spell: " + GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell))) + "*", oPC, FALSE);
+        FloatingTextStringOnCreature("*You have " + IntToString(nUses) + " uses left*", oPC, FALSE);
+    }
+}
diff --git a/nwnds_scripts/prc_nwnx_funcs.ncs b/nwnds_scripts/prc_nwnx_funcs.ncs
new file mode 100644
index 000000000..64bb07846
Binary files /dev/null and b/nwnds_scripts/prc_nwnx_funcs.ncs differ
diff --git a/nwnds_scripts/prc_nwnx_funcs.nss b/nwnds_scripts/prc_nwnx_funcs.nss
new file mode 100644
index 000000000..d7a51d2c6
--- /dev/null
+++ b/nwnds_scripts/prc_nwnx_funcs.nss
@@ -0,0 +1,445 @@
+//::///////////////////////////////////////////////
+//:: Script for nwnx_funcs plugin
+//:: prc_nwnx_funcs.nss
+//:://////////////////////////////////////////////
+//:: This script is executed only if PRC code detects
+//:: nwnx_funcs plugin.
+//::
+//:: It will apply permanent stat modifications
+//:: for PRC classes.
+//:://////////////////////////////////////////////
+//:: Created By: xwarren
+//:: Created On: 12/05/2010
+//:://////////////////////////////////////////////
+
+#include "prc_inc_template"
+#include "inc_nwnx_funcs"
+
+void main()
+{
+    object oPC = OBJECT_SELF;
+    int nBonus, nClassLvl, iTest, nDiff;
+
+    //Warchief
+    nClassLvl = GetLevelByClass(CLASS_TYPE_WARCHIEF, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_WarchiefCha");
+    if(nClassLvl || iTest)
+    {
+        if     (nClassLvl > 1 && nClassLvl < 6) nBonus = 2;
+        else if(nClassLvl > 5 && nClassLvl < 10) nBonus = 4;
+        else if(nClassLvl > 9) nBonus = 6;
+
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_WarchiefCha", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CHARISMA, nDiff);
+        }
+    }
+
+    //Mighty Contender of Kord
+    nClassLvl = GetLevelByClass(CLASS_TYPE_MIGHTY_CONTENDER_KORD, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_MightyContenderStr");
+    if(nClassLvl || iTest)
+    {
+        nBonus = 0;
+        if (nClassLvl >= 9) nBonus = 2;
+        else if (nClassLvl >= 5) nBonus = 1;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_MightyContenderStr", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_STRENGTH, nDiff);
+        }
+    }
+
+    //Heartwarder
+    nClassLvl = GetLevelByClass(CLASS_TYPE_HEARTWARDER, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_HeartWardCha");
+    if(nClassLvl || iTest)
+    {
+        nBonus = (nClassLvl + 1) / 2;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_HeartWardCha", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CHARISMA, nDiff);
+        }
+    }
+    /*iTest = GetPersistantLocalInt(oPC, "NWNX_HeartWardSkill");
+    if(nClassLvl || iTest)
+    {
+        nBonus = GetHasFeat(FEAT_HEART_PASSION, oPC) ? 2 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_HeartWardSkill", nBonus);
+            PRC_Funcs_ModSkill(oPC, SKILL_ANIMAL_EMPATHY, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_PERFORM, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_PERSUADE, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_TAUNT, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_USE_MAGIC_DEVICE, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_BLUFF, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_INTIMIDATE, nDiff);
+        }
+    }*/
+
+    //Acolyte of the Skin
+    nClassLvl = GetLevelByClass(CLASS_TYPE_ACOLYTE, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_AcolyteDex");
+    if(nClassLvl || iTest)
+    {
+        nBonus = GetHasFeat(FEAT_WEAR_FIEND, oPC) * 2;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_AcolyteDex", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_DEXTERITY, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_AcolyteInt");
+    if(nClassLvl || iTest)
+    {
+        nBonus = (GetHasFeat(FEAT_EPIC_INT_1, oPC)
+                + GetHasFeat(FEAT_EPIC_INT_2, oPC)) * 2;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_AcolyteInt", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_INTELLIGENCE, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_AcolyteCon");
+    if(nClassLvl || iTest)
+    {
+        nBonus = (GetHasFeat(FEAT_SKIN_ADAPTION, oPC)
+                + GetHasFeat(FEAT_EPIC_CON_1, oPC)
+                + GetHasFeat(FEAT_EPIC_CON_2, oPC)
+                + GetHasFeat(FEAT_EPIC_CON_3, oPC)) * 2;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_AcolyteCon", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CONSTITUTION, nDiff);
+        }
+    }
+
+    //Alienist
+    nClassLvl = GetLevelByClass(CLASS_TYPE_ALIENIST, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_AlienistWis");
+    if(nClassLvl || iTest)
+    {
+        nBonus = GetHasFeat(FEAT_ALIEN_BLESSING, oPC) ? -2 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_AlienistWis", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_WISDOM, nDiff);
+        }
+    }
+
+    //Diamond Dragon
+    nClassLvl = GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DiaDragStr");
+    if(nClassLvl || iTest)
+    {
+        nBonus = GetHasFeat(FEAT_DRAGON_AUGMENT_STR_1, oPC)
+               + GetHasFeat(FEAT_DRAGON_AUGMENT_STR_2, oPC)
+               + GetHasFeat(FEAT_DRAGON_AUGMENT_STR_3, oPC);
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DiaDragStr", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_STRENGTH, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DiaDragDex");
+    if(nClassLvl || iTest)
+    {
+        nBonus = GetHasFeat(FEAT_DRAGON_AUGMENT_DEX_1, oPC)
+               + GetHasFeat(FEAT_DRAGON_AUGMENT_DEX_2, oPC)
+               + GetHasFeat(FEAT_DRAGON_AUGMENT_DEX_3, oPC);
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DiaDragDex", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_DEXTERITY, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DiaDragCon");
+    if(nClassLvl || iTest)
+    {
+        nBonus = GetHasFeat(FEAT_DRAGON_AUGMENT_CON_1, oPC)
+               + GetHasFeat(FEAT_DRAGON_AUGMENT_CON_2, oPC)
+               + GetHasFeat(FEAT_DRAGON_AUGMENT_CON_3, oPC);
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DiaDragCon", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CONSTITUTION, nDiff);
+        }
+    }
+
+    //Disciple of Baalzebul
+    nClassLvl = GetLevelByClass(CLASS_TYPE_DISC_BAALZEBUL, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_KingofLies");
+    if(nClassLvl || iTest)
+    {
+        nBonus = GetHasFeat(FEAT_KING_LIES, oPC) ? 4 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_KingofLies", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CHARISMA, nDiff);
+        }
+    }
+
+    //Oozemaster
+    nClassLvl = GetLevelByClass(CLASS_TYPE_OOZEMASTER, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_OozemasterCha");
+    if(nClassLvl || iTest)
+    {
+        nBonus = (nClassLvl / 2) * -1;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_OozemasterCha", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CHARISMA, nDiff);
+        }
+    }
+
+    //Swift Wing
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DragonicSurgeStr");
+    nBonus = GetHasFeat(FEAT_DRACONIC_SURGE_STR, oPC);
+    if(nBonus || iTest)
+    {
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DragonicSurgeStr", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_STRENGTH, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DragonicSurgeDex");
+    nBonus = GetHasFeat(FEAT_DRACONIC_SURGE_DEX, oPC);
+    if(nBonus || iTest)
+    {
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DragonicSurgeDex", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_DEXTERITY, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DragonicSurgeCon");
+    nBonus = GetHasFeat(FEAT_DRACONIC_SURGE_CON, oPC);
+    if(nBonus || iTest)
+    {
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DragonicSurgeCon", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CONSTITUTION, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DragonicSurgeInt");
+    nBonus = GetHasFeat(FEAT_DRACONIC_SURGE_INT, oPC);
+    if(nBonus || iTest)
+    {
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DragonicSurgeInt", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_INTELLIGENCE, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DragonicSurgeWis");
+    nBonus = GetHasFeat(FEAT_DRACONIC_SURGE_WIS, oPC);
+    if(nBonus || iTest)
+    {
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DragonicSurgeWis", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_WISDOM, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DragonicSurgeCha");
+    nBonus = GetHasFeat(FEAT_DRACONIC_SURGE_CHA, oPC);
+    if(nBonus || iTest)
+    {
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DragonicSurgeCha", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CHARISMA, nDiff);
+        }
+    }
+
+    //Dragon Devotee
+    nClassLvl = GetLevelByClass(CLASS_TYPE_DRAGON_DEVOTEE, oPC);
+    int nDragDisc = GetLevelByClass(CLASS_TYPE_DRAGON_DISCIPLE, oPC);
+    int nHalfDrag = GetHasTemplate(TEMPLATE_HALF_DRAGON);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DraDevCha");
+    if(nClassLvl || iTest)
+    {
+        nBonus = nDragDisc < 10 && !nHalfDrag ? 2 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DraDevCha", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CHARISMA, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DraDevCon");
+    if(nClassLvl || iTest)
+    {
+        nBonus = nClassLvl > 2 && nDragDisc < 7 && !nHalfDrag ? 2 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DraDevCon", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CONSTITUTION, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_DraDevStr");
+    if(nClassLvl || iTest)
+    {
+        nBonus = nClassLvl > 4 && nDragDisc < 2 && !nHalfDrag ? 2 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_DraDevStr", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_STRENGTH, nDiff);
+        }
+    }
+
+    //Baelnorn
+    nClassLvl = GetLevelByClass(CLASS_TYPE_BAELNORN, oPC);
+    iTest = GetPersistantLocalInt(oPC, "NWNX_BaelnornCha");
+    if(nClassLvl || iTest)
+    {
+        nBonus = nClassLvl >= 4 ? 2 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_BaelnornCha", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CHARISMA, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_BaelnornWis");
+    if(nClassLvl || iTest)
+    {
+        nBonus = nClassLvl >= 3 ? 2 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_BaelnornWis", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_WISDOM, nDiff);
+        }
+    }
+    iTest = GetPersistantLocalInt(oPC, "NWNX_BaelnornInt");
+    if(nClassLvl || iTest)
+    {
+        nBonus = nClassLvl >= 1 ? 2 : 0;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_BaelnornInt", nBonus);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_INTELLIGENCE, nDiff);
+        }
+    }
+    /*iTest = GetPersistantLocalInt(oPC, "NWNX_BaelnornSkill");
+    if(nClassLvl || iTest)
+    {
+        nBonus = nClassLvl * 2;
+        nDiff = nBonus - iTest;
+        if(nDiff != 0)
+        {
+            SetPersistantLocalInt(oPC, "NWNX_BaelnornSkill", nBonus);
+            PRC_Funcs_ModSkill(oPC, SKILL_SPOT, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_HIDE, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_LISTEN, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_MOVE_SILENTLY, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_SEARCH, nDiff);
+            PRC_Funcs_ModSkill(oPC, SKILL_PERSUADE, nDiff);
+        }
+    }*/
+    if(GetPersistantLocalInt(oPC, "EpicSpell_TransVital"))
+    {
+        if(!GetPersistantLocalInt(oPC, "NWNX_TransVital"))
+        {
+            SetPersistantLocalInt(oPC, "NWNX_TransVital", 1);
+            PRC_Funcs_ModAbilityScore(oPC, ABILITY_CONSTITUTION, 5);
+        }
+    }
+    if(GetAlignmentGoodEvil(oPC) == ALIGNMENT_EVIL)
+    {
+        if(GetHasFeat(FEAT_VILE_DEFORM_OBESE, oPC) && !GetHasFeat(FEAT_VILE_DEFORM_GAUNT, oPC))
+        {
+            if(!GetPersistantLocalInt(oPC, "NWNX_DeformObese"))
+            {
+                SetPersistantLocalInt(oPC, "NWNX_DeformObese", 1);
+                PRC_Funcs_ModAbilityScore(oPC, ABILITY_CONSTITUTION, 2);
+                PRC_Funcs_ModAbilityScore(oPC, ABILITY_DEXTERITY, -2);
+            }
+        }
+        if(GetHasFeat(FEAT_VILE_DEFORM_GAUNT, oPC) && !GetHasFeat(FEAT_VILE_DEFORM_OBESE, oPC))
+        {
+            if(!GetPersistantLocalInt(oPC, "NWNX_DeformGaunt"))
+            {
+                SetPersistantLocalInt(oPC, "NWNX_DeformGaunt", 1);
+                PRC_Funcs_ModAbilityScore(oPC, ABILITY_DEXTERITY, 2);
+                PRC_Funcs_ModAbilityScore(oPC, ABILITY_CONSTITUTION, -2);
+            }
+        }
+    }
+
+    //Mystics with Sun domain get Turn Undead feat
+    /*if(GetLevelByClass(CLASS_TYPE_MYSTIC, oPC) && GetHasFeat(FEAT_BONUS_DOMAIN_SUN, oPC))
+    {
+        if(!PRC_Funcs_GetFeatKnown(oPC, FEAT_TURN_UNDEAD))
+            PRC_Funcs_AddFeat(oPC, FEAT_TURN_UNDEAD);
+    }*/
+    
+    //Inherent Bonuses to abilities
+    if(GetPersistantLocalInt(oPC, "PRC_InherentBonus"))
+    {
+        int i;
+        string sAbi;
+        for(i = 0; i < 6; i++)
+        {
+            sAbi = IntToString(i);
+            nBonus = GetPersistantLocalInt(oPC, "PRC_InherentBonus_"+sAbi);
+            iTest = GetPersistantLocalInt(oPC, "NWNX_InherentBonus_"+sAbi);
+            nDiff = nBonus - iTest;
+            if(nDiff != 0)
+            {
+                SetPersistantLocalInt(oPC, "NWNX_InherentBonus_"+sAbi, nBonus);
+                PRC_Funcs_ModAbilityScore(oPC, i, nDiff);
+            }
+        }
+    }
+
+    //PRC PnP Spell Schools
+    if(GetPRCSwitch(PRC_PNP_SPELL_SCHOOLS)
+    && GetLevelByClass(CLASS_TYPE_WIZARD, oPC) || GetLevelByClass(CLASS_TYPE_DEFILER, oPC)) // NWN Dark Sun class
+    {
+        if(GetHasFeat(2274, oPC)
+        || GetHasFeat(2276, oPC)
+        || GetHasFeat(2277, oPC)
+        || GetHasFeat(2278, oPC)
+        || GetHasFeat(2279, oPC)
+        || GetHasFeat(2280, oPC)
+        || GetHasFeat(2281, oPC))
+        {
+            //set school to PnP school
+            PRC_Funcs_SetWizardSpecialization(oPC, 9);
+        }
+        else if(GetHasFeat(2273, oPC))
+        {
+            //set school to generalist
+            PRC_Funcs_SetWizardSpecialization(oPC, 0);
+        }
+    }
+}
\ No newline at end of file
diff --git a/nwnds_scripts/prc_onaquire.ncs b/nwnds_scripts/prc_onaquire.ncs
new file mode 100644
index 000000000..eac5f7a66
Binary files /dev/null and b/nwnds_scripts/prc_onaquire.ncs differ
diff --git a/nwnds_scripts/prc_onaquire.nss b/nwnds_scripts/prc_onaquire.nss
new file mode 100644
index 000000000..05384c0b1
--- /dev/null
+++ b/nwnds_scripts/prc_onaquire.nss
@@ -0,0 +1,342 @@
+//::///////////////////////////////////////////////
+//:: OnAcquireItem eventscript
+//:: prc_onaquire
+//:://////////////////////////////////////////////
+#include "prc_alterations"
+#include "prc_craft_inc"
+//#include "psi_inc_manifest"
+
+void AntiMagicFieldCheck(object oItem, object oCreature)
+{
+    int nIP = array_get_size(oItem, "PRC_NPF_ItemList");
+    if(GetHasSpellEffect(SPELL_ANTIMAGIC_FIELD, oCreature)
+    || GetHasSpellEffect(POWER_NULL_PSIONICS_FIELD, oCreature))
+    {
+        if(nIP)
+            // itemproperty list already exists - do nothing
+            return;
+
+        //remove ips
+        string sIP;
+        int nIpCount;
+        persistant_array_create(oCreature, "PRC_NPF_ItemList"); //stores object strings
+        itemproperty ip = GetFirstItemProperty(oItem);
+        while(GetIsItemPropertyValid(ip))
+        {
+            if(GetItemPropertyDurationType(ip) == DURATION_TYPE_PERMANENT)
+            {   //only store the permanent ones as underscore delimited strings
+                sIP = IntToString(GetItemPropertyType(ip)) + "_" +
+                      IntToString(GetItemPropertySubType(ip)) + "_" +
+                      IntToString(GetItemPropertyCostTableValue(ip)) + "_" +
+                      IntToString(GetItemPropertyParam1Value(ip));
+                if(DEBUG) DoDebug("StoreItemprops: " + GetName(oCreature) + ", " + ObjectToString(oItem) + ", " + sIP);
+                array_set_string(oCreature, "PRC_NPF_ItemList", nIpCount++, sIP);
+            }
+            RemoveItemProperty(oItem, ip);
+            ip = GetNextItemProperty(oItem);
+        }
+    }
+    else
+    {
+        if(!nIP)
+            // itemproperty list not found!
+            return;
+
+        //restore ips
+        struct ipstruct iptemp;
+        itemproperty ip;
+        string sIP;
+        int i;
+        
+        for(i = 0; i < nIP; i++)
+        {
+            sIP = array_get_string(oItem, "PRC_NPF_ItemList", i);
+            iptemp = GetIpStructFromString(sIP);
+            ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
+            IPSafeAddItemProperty(oItem, ip, 0.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING);
+            if(DEBUG) DoDebug("RetoreItemprops: " + GetName(GetItemPossessor(oItem)) + ", " + ObjectToString(oItem) + ", " + sIP);
+        }
+        array_delete(oItem, "PRC_NPF_ItemList");
+    }
+}
+
+void UpdateIPs(object oItem)
+{
+    // Has lookup finished yet?
+    if(GetXP(GetObjectByTag("Bioware2DACache")) & 0x01)
+    {
+        int bAddRestrictions = FALSE;
+        int nSpellID;
+
+        //Set the AMS version of last update
+        SetLocalString(oItem, "sb_ver", AMS_VERSION);
+
+        //remove all class restrictions and mark the spell
+        itemproperty ipTest = GetFirstItemProperty(oItem);
+        while(GetIsItemPropertyValid(ipTest))
+        {
+            if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_USE_LIMITATION_CLASS)
+            {
+                //the scroll/wand had a use limitation
+                RemoveItemProperty(oItem, ipTest);
+                bAddRestrictions = TRUE;
+            }
+            else if(GetItemPropertyType(ipTest) == ITEM_PROPERTY_CAST_SPELL)
+            {
+                nSpellID = StringToInt(Get2DACache("iprp_spells", "SpellIndex", GetItemPropertySubType(ipTest)));
+            }
+            ipTest = GetNextItemProperty(oItem);
+        }
+        if(bAddRestrictions)
+        {
+            int i, nClass, bAdd;
+            for(i = 0; i < 36; i++)
+            {
+                bAdd = FALSE;
+                switch(i)
+                {
+                    case  0: nClass = CLASS_TYPE_BARD; break;
+                    case  1: nClass = CLASS_TYPE_CLERIC; break;
+                    case  2: nClass = CLASS_TYPE_DRUID; break;
+                    case  3: nClass = CLASS_TYPE_PALADIN; break;
+                    case  4: nClass = CLASS_TYPE_RANGER; break;
+                    case  5: nClass = CLASS_TYPE_SORCERER; break;
+                    case  6: nClass = CLASS_TYPE_WIZARD; break;
+                    case  7: nClass = CLASS_TYPE_HARPER; break;
+                    case  8: nClass = CLASS_TYPE_ASSASSIN; break;
+                    case  9: nClass = CLASS_TYPE_BLACKGUARD; break;
+                    case 10: nClass = CLASS_TYPE_OCULAR; break;
+                    case 11: nClass = CLASS_TYPE_HEXBLADE; break;
+                    case 12: nClass = CLASS_TYPE_DUSKBLADE; break;
+                    case 13: nClass = CLASS_TYPE_HEALER; break;
+                    case 14: nClass = CLASS_TYPE_BEGUILER; break;
+                    case 15: nClass = CLASS_TYPE_KNIGHT_CHALICE; break;
+                    case 16: nClass = CLASS_TYPE_VIGILANT; break;
+                    case 17: nClass = CLASS_TYPE_VASSAL; break;
+                    case 18: nClass = CLASS_TYPE_SUBLIME_CHORD; break;
+                    case 19: nClass = CLASS_TYPE_ANTI_PALADIN; break;
+                    case 20: nClass = CLASS_TYPE_SOLDIER_OF_LIGHT; break;
+                    case 21: nClass = CLASS_TYPE_SHADOWLORD; break;
+                    case 22: nClass = CLASS_TYPE_JUSTICEWW; break;
+                    case 23: nClass = CLASS_TYPE_KNIGHT_MIDDLECIRCLE; break;
+                    case 24: nClass = CLASS_TYPE_DREAD_NECROMANCER; break;
+                    case 25: nClass = CLASS_TYPE_MYSTIC; break;
+                    case 26: nClass = CLASS_TYPE_ARCHIVIST; break;
+                    case 27: nClass = CLASS_TYPE_WITCH; break;
+                    case 28: nClass = CLASS_TYPE_SHAMAN; break;
+                    case 29: nClass = CLASS_TYPE_SLAYER_OF_DOMIEL; break;
+                    case 30: nClass = CLASS_TYPE_SUEL_ARCHANAMACH; break;
+                    case 31: nClass = CLASS_TYPE_FAVOURED_SOUL; break;
+                    case 32: nClass = CLASS_TYPE_SHUGENJA; break;
+                    case 33: nClass = CLASS_TYPE_SOHEI; break;
+                    case 34: nClass = CLASS_TYPE_WARMAGE; break;
+                    case 35: nClass = CLASS_TYPE_TEMPLAR; break;
+					case 36: nClass = CLASS_TYPE_DEFILER; break;
+                }
+
+                if(nClass == CLASS_TYPE_DRUID)
+                    bAdd = Get2DACache("Spells", "Druid", nSpellID) == "" ? FALSE : TRUE;
+                else if(nClass == CLASS_TYPE_PALADIN)
+                    bAdd = Get2DACache("Spells", "Paladin", nSpellID) == "" ? FALSE : TRUE;
+                else if(nClass == CLASS_TYPE_RANGER)
+                    bAdd = Get2DACache("Spells", "Ranger", nSpellID) == "" ? FALSE : TRUE;
+                else if(nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_DEFILER)
+                    bAdd = RealSpellToSpellbookID(CLASS_TYPE_SORCERER, nSpellID) == -1 ? FALSE : TRUE;
+                else if(nClass == CLASS_TYPE_CLERIC)
+                    bAdd = RealSpellToSpellbookID(CLASS_TYPE_MYSTIC, nSpellID) == -1 ? FALSE : TRUE;
+                else
+                    bAdd = RealSpellToSpellbookID(nClass, nSpellID) == -1 ? FALSE : TRUE;
+
+                if(bAdd)
+                    AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyLimitUseByClass(nClass), oItem);
+            }
+        }
+    }
+    else // Nope, try again later
+    {
+        DelayCommand(0.2f, UpdateIPs(oItem));
+    }
+}
+
+void main()
+{
+    // Find out the relevant objects
+    object oCreature = GetModuleItemAcquiredBy();
+    object oItem     = GetModuleItemAcquired();
+    string sTag = GetTag(oItem);
+
+    // Do not run for some of the PRC special items
+    if(sTag == "PRC_MANIFTOKEN"
+    || sTag == "HideToken"
+    || GetResRef(oItem) == "base_prc_skin")
+        return;
+
+    //if(DEBUG) DoDebug("Running OnAcquireItem, creature = '" + GetName(oCreature) + "' is PC: " + DebugBool2String(GetIsPC(oCreature)) + "; Item = '" + GetName(oItem) + "' - '" + GetTag(oItem) + "'");
+
+    AntiMagicFieldCheck(oItem, oCreature);
+
+    int nItemType = GetBaseItemType(oItem);
+
+    //fix for all-beige 1.67 -> 1.68 cloaks
+    //gives them a random color
+    if(nItemType == BASE_ITEM_CLOAK)
+    {
+        if(!GetPRCSwitch(PRC_DYNAMIC_CLOAK_AUTOCOLOUR_DISABLE) && !GetLocalInt(oItem, "CloakDone"))
+        {
+            //&& GetItemAppearance(oItem, ITEM_APPR_TYPE_SIMPLE_MODEL, 0) == 1
+            if(GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_CLOTH1) == 0
+            && GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_CLOTH2) == 0
+            && GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_LEATHER1) == 0
+            && GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_LEATHER2) == 0
+            && GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_METAL1) == 0
+            && GetItemAppearance(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_METAL2) == 0)
+            {
+                //pre-1.68 boring bland cloak, colorise it :)
+                //move it to temporary storage first
+                object oChest = GetObjectByTag("HEARTOFCHAOS");
+                DestroyObject(oItem);
+                oItem = CopyItem(oItem, oChest, TRUE);
+                //set appearance
+                //doesnt work yet should do for 1.69
+                //DestroyObject(oItem);
+                //oItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_SIMPLE_MODEL, 0, Random(14)+1, TRUE);
+                //set colors
+                DestroyObject(oItem);
+                oItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_CLOTH1, Random(176), TRUE);
+                DestroyObject(oItem);
+                oItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_CLOTH2, Random(176), TRUE);
+                DestroyObject(oItem);
+                oItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_LEATHER1, Random(176), TRUE);
+                DestroyObject(oItem);
+                oItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_LEATHER2, Random(176), TRUE);
+                DestroyObject(oItem);
+                oItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_METAL1, Random(176), TRUE);
+                DestroyObject(oItem);
+                oItem = CopyItemAndModify(oItem, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_METAL2, Random(176), TRUE);
+                //move it back
+                DestroyObject(oItem);
+                oItem = CopyItem(oItem, oCreature, TRUE);
+                //mark it as set just to be sure
+                SetLocalInt(oItem, "CloakDone", TRUE);
+            }
+        }
+    }
+
+    // This is a resource hog. To work around, we assume that it's not going to cause noticeable issues if
+    // racial restrictions are only ever expanded when a PC is involved
+    if(GetIsPC(oCreature) || GetIsPC(GetMaster(oCreature)) || GetPRCSwitch(PRC_NPC_FORCE_RACE_ACQUIRE))
+        ExecuteScript("race_ev_aquire", OBJECT_SELF);
+
+    // Creatures not related to PCs skip this block, contents are irrelevant for them
+    if(GetIsPC(oCreature) || GetIsPC(GetMaster(oCreature)))
+    {
+        if(GetPRCSwitch(PRC_AUTO_IDENTIFY_ON_ACQUIRE))
+        {
+            if(!GetIdentified(oItem))
+            {
+                int nLore = GetSkillRank(SKILL_LORE, oCreature);
+                int nMax = StringToInt(Get2DACache("SkillVsItemCost", "DeviceCostMax", nLore));
+                if(nMax == 0)
+                    nMax = 120000000;
+                // Check for the value of the item first.
+                SetIdentified(oItem, TRUE);
+                int nGP = GetGoldPieceValue(oItem);
+                // If oPC has enough Lore skill to ID the item, then do so.
+                if(nMax >= nGP)
+                {
+                    string sName = GetName(oItem);
+                    if(sName != "")
+                        SendMessageToPC(oCreature, GetStringByStrRef(16826224) + " " + sName + " " + GetStringByStrRef(16826225));
+                }
+                else
+                    SetIdentified(oItem, FALSE);
+            }
+        }
+
+        if(nItemType == BASE_ITEM_MAGICWAND
+        || nItemType == BASE_ITEM_ENCHANTED_WAND
+        || nItemType == BASE_ITEM_SCROLL
+        || nItemType == BASE_ITEM_SPELLSCROLL
+        || nItemType == BASE_ITEM_ENCHANTED_SCROLL)
+        {
+            if(!GetPRCSwitch(PRC_SCROLL_AUTOUPDATE_RESTR_DISABLE)
+            && GetLocalString(oItem, "sb_ver") != AMS_VERSION //different Alternate Magic System versions - update IPs
+            && !GetLocalInt(oItem, "ip_lock")) //IPs of wand/scroll were locked in toolset or by script
+            {
+                DelayCommand(1.0f, UpdateIPs(oItem));//delayed to reduce lag and prevent TMIs
+            }
+        }
+
+        //rest kits
+        if(GetPRCSwitch(PRC_SUPPLY_BASED_REST))
+            ExecuteScript("sbr_onaquire", OBJECT_SELF);
+
+        //PRC Companion
+        //DOA visible dyepot items
+        /*if(GetPRCSwitch(MARKER_PRC_COMPANION))
+        {
+            if(GetBaseItemType(oItem) == BASE_ITEM_MISCSMALL)
+            {
+                //x2_it_dyec23
+                string sTag = GetTag(oItem);
+                if(GetStringLeft(sTag, 9) == "x2_it_dye")
+                {
+                    //get the color
+                    //taken from x2_s3_dyearmour
+                    // GZ@2006/03/26: Added new color palette support. Note: Will only work
+                    //                if craig updates the in engine functions as well.
+                    int nColor     =  0;
+                    // See if we find a valid int between 0 and 127 in the last three letters
+                    // of the tag, use it as color
+                    int nTest      =  StringToInt(GetStringRight(sTag,3));
+                    if (nTest > 0 &&
+                        nTest < 175 )//magic number, bad!
+                        nColor = nTest;
+                    else //otherwise, use last two letters, as per legacy HotU
+                        nColor = StringToInt(GetStringRight(sTag,2));
+
+                    //use limbo for crafting in
+                    object oLimbo = GetObjectByTag("HEARTOFCHAOS");
+                    //create the new one with the same tag as the old
+                    object oDye = CreateItemOnObject("prccompdye", oLimbo, 1, sTag);
+                    //ensure old one is cleaned up
+                    DestroyObject(oItem);
+                    //if its a metalic dye, modify it to use model 2
+                    if(GetStringRight(GetStringLeft(sTag, 10), 1) == "m")
+                    {
+                        DestroyObject(oDye);
+                        oDye = CopyItemAndModify(oDye, ITEM_APPR_TYPE_SIMPLE_MODEL, 0, 2);
+                        //metal dye color
+                        DestroyObject(oDye);
+                        oDye = CopyItemAndModify(oDye, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_METAL1, nColor);
+                    }
+                    else
+                    {
+                        //standard dye
+                        DestroyObject(oDye);
+                        //cloth and leather use same palettee
+                        oDye = CopyItemAndModify(oDye, ITEM_APPR_TYPE_ARMOR_COLOR, ITEM_APPR_ARMOR_COLOR_LEATHER1, nColor);
+                    }
+                    //copy the itemprops to cast the dye "spell"
+                    itemproperty ipTest = GetFirstItemProperty(oItem);
+                    while(GetIsItemPropertyValid(ipTest))
+                    {
+                        AddItemProperty(DURATION_TYPE_PERMANENT, ipTest, oDye);
+                        ipTest = GetNextItemProperty(oItem);
+                    }
+                    //move it back to the player
+                    CopyItem(oDye, oCreature);
+                    DestroyObject(oDye);
+                }
+            }
+        }*/
+    }// end if - PC or associate of PC
+
+    // Execute scripts hooked to this event for the creature and item triggering it
+    ExecuteAllScriptsHookedToEvent(oCreature, EVENT_ONACQUIREITEM);
+    ExecuteAllScriptsHookedToEvent(oItem, EVENT_ITEM_ONACQUIREITEM);
+
+    // Tag-based scripting hook for PRC items
+    SetUserDefinedItemEventNumber(X2_ITEM_EVENT_ACQUIRE);
+    ExecuteScript("is_"+sTag, OBJECT_SELF);
+}
\ No newline at end of file
diff --git a/nwnds_scripts/prc_prereq.ncs b/nwnds_scripts/prc_prereq.ncs
new file mode 100644
index 000000000..dbf241aea
Binary files /dev/null and b/nwnds_scripts/prc_prereq.ncs differ
diff --git a/nwnds_scripts/prc_prereq.nss b/nwnds_scripts/prc_prereq.nss
new file mode 100644
index 000000000..33941485b
--- /dev/null
+++ b/nwnds_scripts/prc_prereq.nss
@@ -0,0 +1,1426 @@
+//::///////////////////////////////////////////////
+//:: PRC Prerequisites
+//:: prc_prereq.nss
+//:://////////////////////////////////////////////
+//:: Check to see what classes a PC is capable of taking.
+//:://////////////////////////////////////////////
+//:: Created By: Stratovarius.
+//:: Created On: July 3rd, 2004
+//:://////////////////////////////////////////////
+
+#include "inc_epicspells"
+#include "prc_inc_sneak"
+#include "psi_inc_psifunc"
+#include "tob_inc_tobfunc"
+#include "shd_inc_shdfunc"
+#include "inc_newspellbook"
+#include "prc_allow_const"
+#include "inv_inc_invfunc"
+#include "prc_inc_template"
+#include "moi_inc_moifunc"
+#include "bnd_inc_bndfunc"
+
+/*
+AlignRestrict flags in classes.2da:
+0x01 - no neutral
+0x02 - no lawful
+0x04 - no chaotic
+0x08 - no good
+0x10 - no evil
+
+AlignRstrctType:
+0x01 - law/chaos
+0x02 - good/evil
+*/
+// Some alignment restrictions can't be setup properly in classes.2da
+// ie. for Soldier of Light the closest thing to NG requirement is 0x16 0x3
+// which will allow only NG and TN alignments.
+// To disable True Neutral Soldiers of Light a Script Var 'PRC_ExAlignTN'
+// was added to cls_pres_sol.2da.
+void reqAlignment(object oPC)
+{
+    string sAling = "PRC_ExAlign";
+    DeleteLocalInt(oPC, sAling+"LG");
+    DeleteLocalInt(oPC, sAling+"LN");
+    DeleteLocalInt(oPC, sAling+"LE");
+    DeleteLocalInt(oPC, sAling+"NG");
+    DeleteLocalInt(oPC, sAling+"TN");
+    DeleteLocalInt(oPC, sAling+"NE");
+    DeleteLocalInt(oPC, sAling+"CG");
+    DeleteLocalInt(oPC, sAling+"CN");
+    DeleteLocalInt(oPC, sAling+"CE");
+
+    int nGoodEvil = GetAlignmentGoodEvil(oPC);
+    int nLawChaos = GetAlignmentLawChaos(oPC);
+
+    if(nGoodEvil == ALIGNMENT_GOOD)
+    {
+        if(nLawChaos == ALIGNMENT_LAWFUL)
+            SetLocalInt(oPC, sAling+"LG", 1);
+        else if(nLawChaos == ALIGNMENT_NEUTRAL)
+            SetLocalInt(oPC, sAling+"NG", 1);
+        else// if(nLawChaos == ALIGNMENT_CHAOTIC)
+            SetLocalInt(oPC, sAling+"CG", 1);
+    }
+    else if(nGoodEvil == ALIGNMENT_NEUTRAL)
+    {
+        if(nLawChaos == ALIGNMENT_LAWFUL)
+            SetLocalInt(oPC, sAling+"LN", 1);
+        else if(nLawChaos == ALIGNMENT_NEUTRAL)
+            SetLocalInt(oPC, sAling+"TN", 1);
+        else// if(nLawChaos == ALIGNMENT_CHAOTIC)
+            SetLocalInt(oPC, sAling+"CN", 1);
+    }
+    else// if(nGoodEvil == ALIGNMENT_EVIL)
+    {
+        if(nLawChaos == ALIGNMENT_LAWFUL)
+            SetLocalInt(oPC, sAling+"LE", 1);
+        else if(nLawChaos == ALIGNMENT_NEUTRAL)
+            SetLocalInt(oPC, sAling+"NE", 1);
+        else// if(nLawChaos == ALIGNMENT_CHAOTIC)
+            SetLocalInt(oPC, sAling+"CE", 1);
+    }
+}
+
+//for requirements that Skirmish or Sneak Attack apply to
+void reqSpecialAttack(object oPC)
+{
+    int iSneak = GetTotalSneakAttackDice(oPC);
+    int nLevel = GetLevelByClass(CLASS_TYPE_SCOUT, oPC);
+    int iCount;
+    string sVariable1, sVariable2;
+
+    //Skirmish
+    int nDice = (nLevel + 3) / 4;
+    for (iCount = 1; iCount <= 30; iCount++)
+    {
+        sVariable1 = "PRC_SkirmishLevel" + IntToString(iCount);
+        sVariable2 = "PRC_SplAtkLevel" + IntToString(iCount);
+        if (nDice >= iCount)
+        {
+            SetLocalInt(oPC, sVariable1, 0);
+            SetLocalInt(oPC, sVariable2, 0);
+        }
+    }
+    //Sneak Attack
+    for (iCount = 1; iCount <= 30; iCount++)
+    {
+        sVariable1 = "PRC_SneakLevel" + IntToString(iCount);
+        sVariable2 = "PRC_SplAtkLevel" + IntToString(iCount);
+        if (iSneak >= iCount)
+        {
+            SetLocalInt(oPC, sVariable1, 0);
+            SetLocalInt(oPC, sVariable2, 0);
+        }
+    }
+}
+
+void reqGender()
+{
+    int nGender = GetGender(OBJECT_SELF);
+
+    SetLocalInt(OBJECT_SELF, "PRC_Female", 1);
+    SetLocalInt(OBJECT_SELF, "PRC_Male", 1);
+
+    if (nGender == GENDER_FEMALE)
+        DeleteLocalInt(OBJECT_SELF, "PRC_Female");
+    else if (nGender == GENDER_MALE)
+        DeleteLocalInt(OBJECT_SELF, "PRC_Male");
+}
+
+void Kord(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqKord", 1);
+
+    if (GetFortitudeSavingThrow(oPC) >= 6)
+    {
+        SetLocalInt(oPC, "PRC_PrereqKord", 0);
+    }
+}
+
+void Purifier(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqPurifier", 1);
+
+    if (GetWillSavingThrow(oPC) >= 5)
+    {
+        SetLocalInt(oPC, "PRC_PrereqPurifier", 0);
+    }
+}
+
+void Dragonheart(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqDragonheart", 1);
+    
+    int nClassSlot = 1;
+    while(nClassSlot <= 3)
+    {
+        int nClass = GetClassByPosition(nClassSlot, oPC);
+        nClassSlot += 1;
+        if(GetIsArcaneClass(nClass) && GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS)
+            SetLocalInt(oPC, "PRC_PrereqDragonheart", 0); 
+    }        
+}
+
+void Cultist(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqCultist", 1);
+
+	// Can't be arcane
+	if(!GetIsArcaneClass(GetClassByPosition(1, oPC)) && (!GetIsArcaneClass(GetClassByPosition(2, oPC)) || GetClassByPosition(2, oPC) == CLASS_TYPE_CULTIST_SHATTERED_PEAK))
+		SetLocalInt(oPC, "PRC_PrereqCultist", 0);       
+}
+
+void Shifter(object oPC, int iArcSpell, int iDivSpell)
+{
+     //This function checks if the Pnp Shifter requirement "You must be able to assume an alternate form" is met.
+
+     SetLocalInt(oPC, "PRC_PrereqShift", 1);
+
+     //This used to check for Cleric class, animal domain, and divine spell level 5.
+     //I've eliminated the Cleric class check--any class with the animal domain should qualify--
+     //and changed it to check for divine spell level 9 instead of 5, since it isn't until level 9
+     //that the PRC Animal domain gains the Shapechange spell, which is what qualifies it for PnP Shifter.
+     //(The Bioware implementation of the Animal domain gives Polymorph Self at spell level 5).
+     if (GetHasFeat(FEAT_ANIMAL_DOMAIN_POWER) && iDivSpell >= 9)
+     {
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+
+     //Sorcerer (if it uses the old spellbook) and Wizard (which always does) need special checks
+     if ((GetLevelByClass(CLASS_TYPE_SORCERER) && !UseNewSpellBook(oPC)) || GetLevelByClass(CLASS_TYPE_WIZARD) || GetLevelByClass(CLASS_TYPE_DEFILER))
+     {
+        if(GetHasSpell(SPELL_POLYMORPH_SELF, oPC))
+        {
+            // done this way as it's the only way to see if a bioware spellcaster knows the spell
+            // actually checks if they have at least one use left
+            SetLocalInt(oPC, "PRC_PrereqShift", 0);
+            return;
+        }
+     }
+
+     //Ranger also needs special check since it also uses the old spellbook. It gains Polymorph Self at spell level 4.
+     if (GetLevelByClass(CLASS_TYPE_RANGER) && iDivSpell >= 4)
+     {
+          SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+
+     //Any class that has Polymorph Self spell qualifies
+     if (PRCGetIsRealSpellKnown(SPELL_POLYMORPH_SELF, oPC))
+     {
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+
+     //Warlock doesn't normally qualify for PnP Shifter since it doesn't cast spells, 
+     //but these invocations from Warlock meets the alternate form qualification
+     //if another class provides the level 3 spells
+     if(GetHasInvocation(INVOKE_MASK_OF_FLESH, oPC)
+     || GetHasInvocation(INVOKE_HUMANOID_SHAPE, oPC)
+     || GetHasInvocation(INVOKE_SPIDER_SHAPE, oPC)
+     || GetHasInvocation(INVOKE_HELLSPAWNED_GRACE, oPC))
+     {
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+
+     //These classes have appropriate alternate forms
+     if (GetLevelByClass(CLASS_TYPE_DRUID) >= 5)
+     {
+         //Wild Shape qualifies
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+     if (GetLevelByClass(CLASS_TYPE_INITIATE_DRACONIC) >= 10)
+     {
+         //Dragon Shape qualifies
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+     if (GetLevelByClass(CLASS_TYPE_NINJA_SPY) >= 7)
+     {
+         //Thousand Faces qualifies
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+     if (GetLevelByClass(CLASS_TYPE_WEREWOLF) >= 1)
+     {
+         //Alternate Form, Wolf qualifies
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+     if (GetLevelByClass(CLASS_TYPE_BONDED_SUMMONNER) >= 10)
+     {
+         //Elemental Form qualifies
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+     //This is not strictly necessary because Witch gains Polymorph Self
+     //at an earlier level, but add it here anyway for completeness:
+     if (GetLevelByClass(CLASS_TYPE_WITCH) >= 13)
+     {
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+
+     int nRace = GetRacialType(oPC);
+     //These races have appropriate alternate forms
+     if(nRace == RACIAL_TYPE_PURE_YUAN
+     || nRace == RACIAL_TYPE_ABOM_YUAN
+     || nRace == RACIAL_TYPE_PIXIE
+     || nRace == RACIAL_TYPE_RAKSHASA
+     || nRace == RACIAL_TYPE_FEYRI
+     || nRace == RACIAL_TYPE_HOUND_ARCHON
+     || nRace == RACIAL_TYPE_IRDA
+     || nRace == RACIAL_TYPE_ZAKYA_RAKSHASA
+     || nRace == RACIAL_TYPE_CHANGELING
+     || nRace == RACIAL_TYPE_SHIFTER
+     // not counted since it is just "disguise self" and not alter self or shape change
+     //||nRace == RACIAL_TYPE_DEEP_GNOME
+     || nRace == RACIAL_TYPE_NAZTHARUNE_RAKSHASA)
+     {
+         SetLocalInt(oPC, "PRC_PrereqShift", 0);
+     }
+}
+
+void Tempest()
+{
+     SetLocalInt(OBJECT_SELF, "PRC_PrereqTemp", 1);
+
+     if(((GetHasFeat(FEAT_AMBIDEXTERITY) || GetPRCSwitch(PRC_35_TWO_WEAPON_FIGHTING)) && GetHasFeat(FEAT_TWO_WEAPON_FIGHTING))
+     ||  GetHasFeat(FEAT_RANGER_DUAL))
+         DeleteLocalInt(OBJECT_SELF, "PRC_PrereqTemp");
+}
+
+void KOTC(object oPC)
+{
+     SetLocalInt(oPC, "PRC_PrereqKOTC", 1);
+
+     // to check if PC can cast protection from evil
+     if(GetLevelByClass(CLASS_TYPE_CLERIC))
+         DeleteLocalInt(oPC, "PRC_PrereqKOTC");
+
+     if(GetLevelByClass(CLASS_TYPE_PALADIN) > 3)
+     {
+        if(GetAbilityScore(oPC, ABILITY_WISDOM) > 11
+        || GetLevelByClass(CLASS_TYPE_PALADIN) > 5)
+        {
+            DeleteLocalInt(oPC, "PRC_PrereqKOTC");
+            return;
+        }
+     }
+     if(PRCGetIsRealSpellKnown(SPELL_PROTECTION_FROM_EVIL, oPC))
+     {
+         DeleteLocalInt(oPC, "PRC_PrereqKOTC");
+     }
+}
+
+void Shadowlord(object oPC, int iArcSpell)
+{
+    SetLocalInt(oPC, "PRC_PrereqTelflam", 1);
+
+    if(iArcSpell > 3                                   //ability to cast Level 4 Arcane Spells
+    || GetLevelByClass(CLASS_TYPE_SHADOWDANCER, oPC)   //at least 1 lvl of shadowdancer
+    || GetPersistantLocalInt(oPC, "shadowwalkerstok")) //a token proving a donation of 10,000 gold to the Telflamm Guild
+  //|| GetHasItem(oPC, "shadowwalkerstok"))
+    {
+        SetLocalInt(oPC, "PRC_PrereqTelflam", 0);
+    }
+}
+
+//taken out of master at arms because i wanted to use the code in Eternal Blade prereq too
+int WeaponFocusCount(object oPC)
+{
+    int iWF;
+
+    // Calculate the total number of Weapon Focus feats the character has
+    iWF = GetHasFeat(FEAT_WEAPON_FOCUS_BASTARD_SWORD,oPC)   +GetHasFeat(FEAT_WEAPON_FOCUS_BATTLE_AXE,oPC)  +GetHasFeat(FEAT_WEAPON_FOCUS_CLUB,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_DAGGER,oPC)          +GetHasFeat(FEAT_WEAPON_FOCUS_DART,oPC)        +GetHasFeat(FEAT_WEAPON_FOCUS_DIRE_MACE,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_DOUBLE_AXE,oPC)      +GetHasFeat(FEAT_WEAPON_FOCUS_DWAXE,oPC)       +GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_AXE,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_GREAT_SWORD,oPC)     +GetHasFeat(FEAT_WEAPON_FOCUS_HALBERD,oPC)     +GetHasFeat(FEAT_WEAPON_FOCUS_HAND_AXE,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_CROSSBOW,oPC)  +GetHasFeat(FEAT_WEAPON_FOCUS_HEAVY_FLAIL,oPC) +GetHasFeat(FEAT_WEAPON_FOCUS_KAMA,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_TWO_BLADED_SWORD,oPC)+GetHasFeat(FEAT_WEAPON_FOCUS_LONG_SWORD,oPC)  +GetHasFeat(FEAT_WEAPON_FOCUS_RAPIER,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_KATANA,oPC)          +GetHasFeat(FEAT_WEAPON_FOCUS_KUKRI,oPC)       +GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_CROSSBOW,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_FLAIL,oPC)     +GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_HAMMER,oPC)+GetHasFeat(FEAT_WEAPON_FOCUS_LIGHT_MACE,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_LONGBOW,oPC)         +GetHasFeat(FEAT_WEAPON_FOCUS_MORNING_STAR,oPC)+GetHasFeat(FEAT_WEAPON_FOCUS_SCIMITAR,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_SCYTHE,oPC)          +GetHasFeat(FEAT_WEAPON_FOCUS_SHORT_SWORD,oPC) +GetHasFeat(FEAT_WEAPON_FOCUS_SHORTBOW,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_SHURIKEN,oPC)        +GetHasFeat(FEAT_WEAPON_FOCUS_SICKLE,oPC)      +GetHasFeat(FEAT_WEAPON_FOCUS_SLING,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_SPEAR,oPC)           +GetHasFeat(FEAT_WEAPON_FOCUS_STAFF,oPC)       +GetHasFeat(FEAT_WEAPON_FOCUS_THROWING_AXE,oPC)+
+          GetHasFeat(FEAT_WEAPON_FOCUS_WAR_HAMMER,oPC)      +GetHasFeat(FEAT_WEAPON_FOCUS_MINDBLADE, oPC)  +GetHasFeat(FEAT_WEAPON_FOCUS_WHIP,oPC); //why was whip commented out?
+
+    // If they are a soulknife, their WF Mindblade might be counting twice due to how it is implemented, so account for it if necessary
+    if(GetStringLeft(GetTag(GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC)), 14) == "prc_sk_mblade_" ||
+       GetStringLeft(GetTag(GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC)), 14) == "prc_sk_mblade_")
+        iWF--;
+
+    return iWF;
+}
+
+void DemiLich(object oPC)
+{
+    DeleteLocalInt(oPC, "PRC_DemiLich");
+    
+    if (!GetIsEpicSpellcaster(oPC) && GetLevelByClass(CLASS_TYPE_LICH) > 3)
+         SetLocalInt(oPC, "PRC_DemiLich", 1); // Need to be an epic caster to take demilich
+
+    if(GetPRCSwitch(PRC_DISABLE_DEMILICH) && GetLevelByClass(CLASS_TYPE_LICH) > 3)
+    {
+        SetLocalInt(oPC, "PRC_DemiLich", 1); // This is here because it'll always turn things off
+    }
+}
+
+void reqDomains()
+{
+    //Black Flame Zealot
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqBFZ", 1);
+    if(GetHasFeat(FEAT_FIRE_DOMAIN_POWER)
+     + GetHasFeat(FEAT_DESTRUCTION_DOMAIN_POWER)
+     + GetHasFeat(FEAT_DOMAIN_POWER_RENEWAL) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqBFZ");
+
+    //Brimstone Speaker
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqBrimstone", 1);
+    if(GetHasFeat(FEAT_FIRE_DOMAIN_POWER)
+    || GetHasFeat(FEAT_GOOD_DOMAIN_POWER))
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqBrimstone");
+
+    //Shining Blade of Heironeous
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqSBHeir", 1);
+    if (GetHasFeat(FEAT_WAR_DOMAIN_POWER)
+    && GetHasFeat(FEAT_GOOD_DOMAIN_POWER))
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqSBHeir");
+
+    //Eye of Gruumsh
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqEOG", 1);
+    if(GetHasFeat(FEAT_WAR_DOMAIN_POWER)
+     + GetHasFeat(FEAT_STRENGTH_DOMAIN_POWER)
+     + GetHasFeat(FEAT_EVIL_DOMAIN_POWER) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqEOG");
+
+    //Stormlord
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqStormL", 1);
+    if(GetHasFeat(FEAT_FIRE_DOMAIN_POWER)
+     + GetHasFeat(FEAT_DESTRUCTION_DOMAIN_POWER)
+     + GetHasFeat(FEAT_EVIL_DOMAIN_POWER)
+     + GetHasFeat(FEAT_DOMAIN_POWER_STORM) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqStormL");
+
+    //Battleguard of Tempus
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqTempus", 1);
+    if(GetHasFeat(FEAT_PROTECTION_DOMAIN_POWER)
+     + GetHasFeat(FEAT_STRENGTH_DOMAIN_POWER) >= 1
+    && GetHasFeat(FEAT_WAR_DOMAIN_POWER))
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqTempus");
+
+    //Heartwarder
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqHeartW", 1);
+    if(GetHasFeat(FEAT_GOOD_DOMAIN_POWER)
+     + GetHasFeat(FEAT_PROTECTION_DOMAIN_POWER)
+     + GetHasFeat(FEAT_DOMAIN_POWER_CHARM) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqHeartW");
+
+    //Talontar Blightlord
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqBlightL", 1);
+    if(GetHasFeat(FEAT_DESTRUCTION_DOMAIN_POWER)
+    && GetHasFeat(FEAT_EVIL_DOMAIN_POWER))
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqBlightL");
+
+    //Shadow Adept
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqShadAd", 1);
+    if(GetHasFeat(FEAT_EVIL_DOMAIN_POWER)
+     + GetHasFeat(FEAT_KNOWLEDGE_DOMAIN_POWER)
+     + GetHasFeat(FEAT_DARKNESS_DOMAIN) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqShadAd");
+
+    //Thrall of Graz'zt
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqTOG", 1);
+    if(GetHasFeat(FEAT_EVIL_DOMAIN_POWER)
+    && GetHasFeat(FEAT_DARKNESS_DOMAIN))
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqTOG");
+
+    //Champion of Corellon
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqCoC", 1);
+    if(GetHasFeat(FEAT_DOMAIN_POWER_ELF)
+    //+ GetHasFeat(FEAT_DOMAIN_POWER_CHAOS)    //chaos domain not yet implemented
+     + GetHasFeat(FEAT_GOOD_DOMAIN_POWER)
+     + GetHasFeat(FEAT_MAGIC_DOMAIN_POWER)
+     + GetHasFeat(FEAT_PROTECTION_DOMAIN_POWER)
+     + GetHasFeat(FEAT_WAR_DOMAIN_POWER) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqCoC");
+
+    //Morninglord of Lathander
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqMornLord", 1);
+    if(GetHasFeat(FEAT_GOOD_DOMAIN_POWER)
+     + GetHasFeat(FEAT_PROTECTION_DOMAIN_POWER)
+     + GetHasFeat(FEAT_STRENGTH_DOMAIN_POWER)
+     + GetHasFeat(FEAT_SUN_DOMAIN_POWER)
+     + GetHasFeat(FEAT_DOMAIN_POWER_NOBILITY)
+     + GetHasFeat(FEAT_DOMAIN_POWER_RENEWAL) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqMornLord");
+
+    //Favored of Milil
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqFoM", 1);
+    if(GetHasFeat(FEAT_GOOD_DOMAIN_POWER)
+     + GetHasFeat(FEAT_DOMAIN_POWER_NOBILITY)
+     + GetHasFeat(FEAT_DOMAIN_POWER_CHARM)
+     + GetHasFeat(FEAT_KNOWLEDGE_DOMAIN_POWER) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqFoM");
+
+    //Soldier of Light
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqSOL", 1);
+    if(GetHasFeat(FEAT_GOOD_DOMAIN_POWER)
+     + GetHasFeat(FEAT_HEALING_DOMAIN_POWER)
+     + GetHasFeat(FEAT_LUCK_DOMAIN_POWER)
+     + GetHasFeat(FEAT_PROTECTION_DOMAIN_POWER)
+     + GetHasFeat(FEAT_SUN_DOMAIN_POWER)
+     + GetHasFeat(FEAT_KNOWLEDGE_DOMAIN_POWER) >= 2)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqSOL");
+}
+
+
+void WWolf(object oPC)
+{
+    //If not a natural lycanthrope or not already leveled in werewolf, prevent the player from taking the werewolf class
+    if (!GetHasFeat(FEAT_TRUE_LYCANTHROPE, oPC) || GetLevelByClass(CLASS_TYPE_WEREWOLF, oPC) < 1)
+    {
+        SetLocalInt(oPC, "PRC_PrereqWWolf", 1);
+    }
+
+    if (GetHasFeat(FEAT_TRUE_LYCANTHROPE, oPC))
+    {
+        SetLocalInt(oPC, "PRC_PrereqWWolf", 0);
+    }
+}
+
+void Maester(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqMaester", 1);
+
+    // Base Ranks Only
+    if(GetSkillRank(SKILL_CRAFT_ARMOR,  oPC, TRUE) > 7
+    || GetSkillRank(SKILL_CRAFT_TRAP,   oPC, TRUE) > 7
+    || GetSkillRank(SKILL_CRAFT_WEAPON, oPC, TRUE) > 7)
+    {
+        // At least two crafting feats
+        if(GetItemCreationFeatCount() > 1)
+        {
+            //check for arcane caster levels
+            if(!GetLocalInt(oPC, "PRC_ArcSpell3") || GetInvokerLevel(oPC) > 4)
+                SetLocalInt(oPC, "PRC_PrereqMaester", 0);
+        }
+    }
+}
+
+void reqCombatMedic(object oPC)
+{
+    /* The combat medic can only be taken if the player is able to cast Cure Light Wounds.
+     * Base classes:
+     * With druids and clerics, that's no problem - they get it at first level. Paladins and
+     * rangers are a bit more complicated, due to their bonus spells and later spell gains.
+     */
+
+    SetLocalInt(oPC, "PRC_PrereqCbtMed", 1);
+
+    //check PRC classes
+    if(PRCGetIsRealSpellKnown(SPELL_CURE_LIGHT_WOUNDS, oPC))
+    {
+        SetLocalInt(oPC, "PRC_PrereqCbtMed", 0);
+        return;
+    }
+
+    //check bioware classes
+    int iWis = GetLocalInt(GetPCSkin(oPC), "PRC_trueWIS");
+    if(iWis > 10)
+    {
+        if(GetLevelByClass(CLASS_TYPE_CLERIC)
+        || GetLevelByClass(CLASS_TYPE_DRUID)
+        || GetLevelByClass(CLASS_TYPE_PALADIN) >= 6
+        || GetLevelByClass(CLASS_TYPE_RANGER) >= 6
+        || (iWis > 11 && GetLevelByClass(CLASS_TYPE_PALADIN) >= 4)
+        || (iWis > 11 && GetLevelByClass(CLASS_TYPE_RANGER) >= 4))
+            SetLocalInt(oPC, "PRC_PrereqCbtMed", 0);
+    }
+}
+
+void RedWizard(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqRedWiz", 1);
+
+    int iFeat;
+    int iFocus;
+
+    iFocus = GetHasFeat(FEAT_RW_TF_ABJ, oPC)
+           + GetHasFeat(FEAT_RW_TF_CON, oPC)
+           + GetHasFeat(FEAT_RW_TF_DIV, oPC)
+           + GetHasFeat(FEAT_RW_TF_ENC, oPC)
+           + GetHasFeat(FEAT_RW_TF_EVO, oPC)
+           + GetHasFeat(FEAT_RW_TF_ILL, oPC)
+           + GetHasFeat(FEAT_RW_TF_NEC, oPC)
+           + GetHasFeat(FEAT_RW_TF_TRS, oPC);
+    // Metamagic or Item Creation feats
+    iFeat = GetItemCreationFeatCount()
+          + GetHasFeat(FEAT_EMPOWER_SPELL, oPC)
+          + GetHasFeat(FEAT_EXTEND_SPELL, oPC)
+          + GetHasFeat(FEAT_MAXIMIZE_SPELL, oPC)
+          + GetHasFeat(FEAT_QUICKEN_SPELL, oPC)
+          + GetHasFeat(FEAT_SILENCE_SPELL, oPC)
+          + GetHasFeat(FEAT_STILL_SPELL, oPC)
+          + GetHasFeat(FEAT_SUDDEN_EMPOWER, oPC)
+          + GetHasFeat(FEAT_SUDDEN_MAXIMIZE, oPC)
+          + GetHasFeat(FEAT_SUDDEN_EXTEND, oPC)
+          + GetHasFeat(FEAT_SUDDEN_WIDEN, oPC);
+
+
+    // At least two arcane feats, one tattoo focus
+    if (iFeat > 2 && iFocus == 1)
+    {
+        SetLocalInt(oPC, "PRC_PrereqRedWiz", 0);
+    }
+}
+
+void WildMageReq(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PresWildMageReq", 1);
+
+    int iFeat =  GetHasFeat(FEAT_EMPOWER_SPELL, oPC)
+          + GetHasFeat(FEAT_EXTEND_SPELL, oPC)
+          + GetHasFeat(FEAT_MAXIMIZE_SPELL, oPC)
+          + GetHasFeat(FEAT_QUICKEN_SPELL, oPC)
+          + GetHasFeat(FEAT_SILENCE_SPELL, oPC)
+          + GetHasFeat(FEAT_STILL_SPELL, oPC)
+          + GetHasFeat(FEAT_SUDDEN_EMPOWER, oPC)
+          + GetHasFeat(FEAT_SUDDEN_MAXIMIZE, oPC)
+          + GetHasFeat(FEAT_SUDDEN_EXTEND, oPC)
+          + GetHasFeat(FEAT_SUDDEN_WIDEN, oPC);
+
+    // At least one metamagic feat
+    if (iFeat)
+        SetLocalInt(oPC, "PRC_PresWildMageReq", 0);
+}
+
+void DalQuor(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqDalQuor", 1);
+
+    // Psionic feats
+    if(GetHasFeat(FEAT_COMBAT_MANIFESTATION        , oPC)
+    || GetHasFeat(FEAT_MENTAL_LEAP                 , oPC)
+    || GetHasFeat(FEAT_NARROW_MIND                 , oPC)
+    || GetHasFeat(FEAT_POWER_PENETRATION           , oPC)
+    || GetHasFeat(FEAT_GREATER_POWER_PENETRATION   , oPC)
+    || GetHasFeat(FEAT_POWER_SPECIALIZATION        , oPC)
+    || GetHasFeat(FEAT_GREATER_POWER_SPECIALIZATION, oPC)
+    || GetHasFeat(FEAT_PSIONIC_DODGE               , oPC)
+    || GetHasFeat(FEAT_PSIONIC_ENDOWMENT           , oPC)
+    || GetHasFeat(FEAT_GREATER_PSIONIC_ENDOWMENT   , oPC)
+    || GetHasFeat(FEAT_PSIONIC_FIST                , oPC)
+    || GetHasFeat(FEAT_GREATER_PSIONIC_FIST        , oPC)
+    || GetHasFeat(FEAT_PSIONIC_WEAPON              , oPC)
+    || GetHasFeat(FEAT_GREATER_PSIONIC_WEAPON      , oPC)
+    || GetHasFeat(FEAT_PSIONIC_SHOT                , oPC)
+    || GetHasFeat(FEAT_GREATER_PSIONIC_SHOT        , oPC)
+    || GetHasFeat(FEAT_OVERCHANNEL                 , oPC)
+    || GetHasFeat(FEAT_PSIONIC_MEDITATION          , oPC)
+    || GetHasFeat(FEAT_RAPID_METABOLISM            , oPC)
+    || GetHasFeat(FEAT_TALENTED                    , oPC)
+    || GetHasFeat(FEAT_UNAVOIDABLE_STRIKE          , oPC)
+    || GetHasFeat(FEAT_WILD_TALENT                 , oPC)
+    || GetHasFeat(FEAT_WOUNDING_ATTACK             , oPC)
+    || GetHasFeat(FEAT_BOOST_CONSTRUCT             , oPC)
+    || GetHasFeat(FEAT_SPEED_OF_THOUGHT            , oPC)
+    || GetHasFeat(FEAT_PSIONIC_TALENT_1            , oPC)
+    || GetHasFeat(FEAT_METAMORPHIC_TRANSFER_1      , oPC)
+    || GetHasFeat(FEAT_DEEP_IMPACT                 , oPC)
+    || GetHasFeat(FEAT_FELL_SHOT                   , oPC)
+    || GetHasFeat(FEAT_EXPANDED_KNOWLEDGE_1        , oPC)
+    || GetHasFeat(FEAT_INVEST_ARMOUR               , oPC))
+        // At least one psionic feat
+        SetLocalInt(oPC, "PRC_PrereqDalQuor", 0);
+}
+
+void Thrallherd(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqThrallherd", 1);
+
+    // Technically, you must be able to manifest mindlink, and the only class that can do so is a Telepath Psion
+    // Thus, this restriction.
+    if(GetHasFeat(FEAT_PSION_DIS_TELEPATH, oPC))
+    {
+        // @todo Replace with some mechanism that is not dependent on power enumeration. Maybe a set of variables that tell how many powers of each discipline a character knows <- requires hooking to power gain / loss
+        if(GetHasPower(POWER_CHARMPERSON, oPC)
+        || GetHasPower(POWER_AVERSION, oPC)
+        || GetHasPower(POWER_BRAINLOCK, oPC)
+        || GetHasPower(POWER_CRISISBREATH, oPC)
+        || GetHasPower(POWER_EMPATHICTRANSFERHOSTILE, oPC)
+        || GetHasPower(POWER_DOMINATE, oPC)
+        || GetHasPower(POWER_CRISISLIFE, oPC)
+        || GetHasPower(POWER_PSYCHICCHIR_REPAIR, oPC))
+        {
+            SetLocalInt(oPC, "PRC_PrereqThrallherd", 0);
+        }
+    }
+}
+
+void Shadowmind(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqShadowmind", 1);
+
+    if(GetHasPower(POWER_CONCEALAMORPHA, oPC))
+        SetLocalInt(oPC, "PRC_PrereqShadowmind", 0);
+}
+
+void SoulEater(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqSoulEater", 1);
+
+    int nRace = MyPRCGetRacialType(oPC);
+    if(nRace == RACIAL_TYPE_ABERRATION
+    || nRace == RACIAL_TYPE_ANIMAL
+    || nRace == RACIAL_TYPE_BEAST
+    || nRace == RACIAL_TYPE_DRAGON
+    || nRace == RACIAL_TYPE_HUMANOID_MONSTROUS
+    || nRace == RACIAL_TYPE_MAGICAL_BEAST
+    || nRace == RACIAL_TYPE_OUTSIDER
+    || nRace == RACIAL_TYPE_FEY
+    || nRace == RACIAL_TYPE_GIANT
+    || nRace == RACIAL_TYPE_ELEMENTAL)
+        SetLocalInt(oPC, "PRC_PrereqSoulEater", 0);
+}
+
+void RacialHD(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqAberration", 1);
+    SetLocalInt(oPC, "PRC_PrereqAnimal", 1);
+    SetLocalInt(oPC, "PRC_PrereqConstruct", 1);
+    SetLocalInt(oPC, "PRC_PrereqHumanoid", 1);
+    SetLocalInt(oPC, "PRC_PrereqMonstrous", 1);
+    SetLocalInt(oPC, "PRC_PrereqEle", 1);
+    SetLocalInt(oPC, "PRC_PrereqFey", 1);
+    SetLocalInt(oPC, "PRC_PrereqDragon", 1);
+    SetLocalInt(oPC, "PRC_PrereqUndead", 1);
+    SetLocalInt(oPC, "PRC_PrereqBeast", 1);
+    SetLocalInt(oPC, "PRC_PrereqGiant", 1);
+    SetLocalInt(oPC, "PRC_PrereqMagicalBeast", 1);
+    SetLocalInt(oPC, "PRC_PrereqOutsider", 1);
+    SetLocalInt(oPC, "PRC_PrereqShapechanger", 1);
+    SetLocalInt(oPC, "PRC_PrereqVermin", 1);
+    SetLocalInt(oPC, "PRC_PrereqPlant", 1);
+    if(GetPRCSwitch(PRC_XP_USE_SIMPLE_RACIAL_HD))
+    {
+        int nRealRace = GetRacialType(oPC);
+        int nRacialHD = StringToInt(Get2DACache("ECL", "RaceHD", nRealRace));
+        int nRacialClass = StringToInt(Get2DACache("ECL", "RaceClass", nRealRace));
+        if(nRacialHD && GetLevelByClass(nRacialClass, oPC) < nRacialHD)
+        {
+            switch(nRacialClass)
+            {
+                case CLASS_TYPE_ABERRATION: SetLocalInt(oPC, "PRC_PrereqAberration", 0); break;
+                case CLASS_TYPE_ANIMAL: SetLocalInt(oPC, "PRC_PrereqAnmal", 0); break;
+                case CLASS_TYPE_CONSTRUCT: SetLocalInt(oPC, "PRC_PrereqConstruct", 0); break;
+                case CLASS_TYPE_HUMANOID: SetLocalInt(oPC, "PRC_PrereqHumanoid", 0); break;
+                case CLASS_TYPE_MONSTROUS: SetLocalInt(oPC, "PRC_PrereqMonstrous", 0); break;
+                case CLASS_TYPE_ELEMENTAL: SetLocalInt(oPC, "PRC_PrereqEle", 0); break;
+                case CLASS_TYPE_FEY: SetLocalInt(oPC, "PRC_PrereqFey", 0); break;
+                case CLASS_TYPE_DRAGON: SetLocalInt(oPC, "PRC_PrereqDragon", 0); break;
+                case CLASS_TYPE_UNDEAD: SetLocalInt(oPC, "PRC_PrereqUndead", 0); break;
+                case CLASS_TYPE_BEAST: SetLocalInt(oPC, "PRC_PrereqBeast", 0); break;
+                case CLASS_TYPE_GIANT: SetLocalInt(oPC, "PRC_PrereqGiant", 0); break;
+                case CLASS_TYPE_MAGICAL_BEAST: SetLocalInt(oPC, "PRC_PrereqMagicalBeast", 0); break;
+                case CLASS_TYPE_OUTSIDER: SetLocalInt(oPC, "PRC_PrereqOutsider", 0); break;
+                case CLASS_TYPE_SHAPECHANGER: SetLocalInt(oPC, "PRC_PrereqShapechanger", 0); break;
+                case CLASS_TYPE_VERMIN: SetLocalInt(oPC, "PRC_PrereqVermin", 0); break;
+                case CLASS_TYPE_PLANT: SetLocalInt(oPC, "PRC_PrereqPlant", 0); break;
+                default: SetLocalInt(oPC, "NoRace", 0);
+            }
+        }
+    }
+}
+
+void Virtuoso(object oPC)
+{   //Needs 6 ranks of Persuade OR 6 ranks of Intimidate
+    SetLocalInt(oPC, "PRC_PrereqVirtuoso", 1);
+    if((GetSkillRank(SKILL_PERSUADE, oPC) >= 6) || (GetSkillRank(SKILL_INTIMIDATE, oPC) >= 6))
+        SetLocalInt(oPC, "PRC_PrereqVirtuoso", 0);
+}
+
+void FistRaziel(object oPC)
+{
+    /* The fist of Raziel can only be taken if the player is able to cast Divine Favor.
+     * Base classes:
+     * Cleric gets it at level 1. Paladin at level 4 (with wis > 11) to 6 (wis == 11)
+     */
+
+    SetLocalInt(oPC, "PRC_PrereqFistRaz", 1);
+    object oSkin = GetPCSkin(oPC);
+    int iWis = GetLocalInt(oSkin, "PRC_trueWIS");
+    // hard code it to work for Bioware classes
+    if (GetLevelByClass(CLASS_TYPE_CLERIC))
+    {
+        SetLocalInt(oPC, "PRC_PrereqFistRaz", 0);
+        return;
+    }
+
+    if (GetLevelByClass(CLASS_TYPE_PALADIN))
+    {
+        if(iWis > 11 && GetLevelByClass(CLASS_TYPE_PALADIN) >= 4)
+        {
+            SetLocalInt(oPC, "PRC_PrereqFistRaz", 0);
+            return;
+        }
+        else if (GetLevelByClass(CLASS_TYPE_PALADIN) >= 6)
+        {
+            SetLocalInt(oPC, "PRC_PrereqFistRaz", 0);
+            return;
+        }
+    }
+
+    if (PRCGetIsRealSpellKnown(SPELL_DIVINE_FAVOR, oPC))
+    {
+        SetLocalInt(oPC, "PRC_PrereqFistRaz", 0);
+        return;
+    }
+
+}
+
+void Pyro(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqPyro", 1);
+    if(GetIsPsionicCharacter(oPC))
+        SetLocalInt(oPC, "PRC_PrereqPyro", 0);
+}
+
+void Suel()
+{
+    SetLocalInt(OBJECT_SELF, "PRC_PrereqSuelWeap", 1);
+
+              //martial weapon proficiences
+    int nProf = GetHasFeat(FEAT_WEAPON_PROFICIENCY_SHORTSWORD)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_LONGSWORD)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_BATTLEAXE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_WARHAMMER)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_LONGBOW)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_LIGHT_FLAIL)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_HALBERD)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_SHORTBOW)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_GREATSWORD)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_GREATAXE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_HEAVY_FLAIL)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_LIGHT_HAMMER)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_HANDAXE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_RAPIER)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_SCIMITAR)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_THROWING_AXE);
+              //exotic weapon proficiences
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_BASTARD_SWORD)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_TWO_BLADED_SWORD)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_BATTLEAXE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_DIRE_MACE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_DOUBLE_AXE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_KAMA)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_KUKRI)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_KATANA)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_SCYTHE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_SHURIKEN)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_DWARVEN_WARAXE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_WHIP)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELVEN_THINBLADE)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_RAPIER)
+              + GetHasFeat(FEAT_WEAPON_PROFICIENCY_ELVEN_COURTBLADE);
+
+    if(nProf > 3)
+        DeleteLocalInt(OBJECT_SELF, "PRC_PrereqSuelWeap");
+}
+
+void TomeOfBattle(object oPC = OBJECT_SELF)
+{
+    // Deepstone Sentinel
+    SetLocalInt(oPC, "PRC_PrereqDeepSt", 1);
+    // Needs two Stone Dragon maneuvers
+    int nMove = GetManeuverCountByDiscipline(oPC, DISCIPLINE_STONE_DRAGON, MANEUVER_TYPE_MANEUVER);
+    // Needs one Stone Dragon Stance
+    int nStance = GetManeuverCountByDiscipline(oPC, DISCIPLINE_STONE_DRAGON, MANEUVER_TYPE_STANCE);
+    if(nMove > 1 && nStance)
+        SetLocalInt(oPC, "PRC_PrereqDeepSt", 0);
+
+    // Bloodclaw Master
+    SetLocalInt(oPC, "PRC_PrereqBloodclaw", 1);
+    // Needs three Tiger Claw maneuvers
+    if(_CheckPrereqsByDiscipline(oPC, DISCIPLINE_TIGER_CLAW, 3))
+        SetLocalInt(oPC, "PRC_PrereqBloodclaw", 0);
+
+    // Ruby Knight Vindicator
+    SetLocalInt(oPC, "PRC_PrereqRubyKnight", 1);
+    // Needs one Devoted Spirit maneuver
+    nMove = GetManeuverCountByDiscipline(oPC, DISCIPLINE_DEVOTED_SPIRIT, MANEUVER_TYPE_MANEUVER);
+    // Needs one Devoted Spirit stance
+    nStance = GetManeuverCountByDiscipline(oPC, DISCIPLINE_DEVOTED_SPIRIT, MANEUVER_TYPE_STANCE);
+    // If it's a cleric, needs to have Death, Law and Magic as domains.
+    int nDomain = TRUE;
+    if(GetLevelByClass(CLASS_TYPE_CLERIC, oPC))
+    {
+        nDomain = GetHasFeat(FEAT_DEATH_DOMAIN_POWER, oPC)
+                + GetHasFeat(FEAT_MAGIC_DOMAIN_POWER, oPC)
+                //+ GetHasFeat(FEAT_LAW_DOMAIN_POWER, oPC)
+                > 1;
+    }
+    if(nMove && nStance && nDomain)
+        SetLocalInt(oPC, "PRC_PrereqRubyKnight", 0);
+
+    // Jade Phoenix Mage
+    SetLocalInt(oPC, "PRC_PrereqJPM", 1);
+    // Skip the rest of not an arcane caster
+    if(GetLocalInt(oPC, "PRC_ArcSpell2") == 0)
+    {
+        int nUser;
+        int nMove = 0;
+        int nStance = 0;
+        int nType;
+
+        // Only need first blade magic class.  Can't take a second and Jade Phoenix and meet requirements.
+        nUser = GetPrimaryBladeMagicClass(oPC);
+
+        // If inv_inc_moveknwn can be included here, GetManeuverCount() can be used in place of GetPersistantLocalInt()
+        // the following is pulled from the function
+
+        nType = MANEUVER_TYPE_MANEUVER;
+        nMove += GetPersistantLocalInt(oPC, "PRC_ManeuverList_" + IntToString(nUser) + IntToString(nType) + "_TotalKnown");
+
+        nType = MANEUVER_TYPE_STANCE;
+        nStance += GetPersistantLocalInt(oPC, "PRC_ManeuverList_" + IntToString(nUser) + IntToString(nType) + "_TotalKnown");
+
+        if (nMove >= 2 && nStance >= 1)
+            SetLocalInt(oPC, "PRC_PrereqJPM", 0);
+    }
+
+    //Master of Nine
+    SetLocalInt(oPC, "PRC_PrereqMoNine", 1);
+    // Needs 6 maneuvers, so check the persistent locals
+    int i, nCount, nSkills;
+    for(i = 1; i <= 256; i <<= 1)
+    {
+        // Loop over all disciplines, and total up how many he knows
+        if(_CheckPrereqsByDiscipline(oPC, i))
+            nCount++;
+    }
+
+    // Base ranks only
+    if(GetSkillRank(SKILL_TUMBLE, oPC, TRUE) >= 10) nSkills += 1;
+    if(GetSkillRank(SKILL_INTIMIDATE, oPC, TRUE) >= 10) nSkills += 1;
+    if(GetSkillRank(SKILL_CONCENTRATION, oPC, TRUE) >= 10) nSkills += 1;
+    if(GetSkillRank(SKILL_BALANCE, oPC, TRUE) >= 10) nSkills += 1;
+    if(GetSkillRank(SKILL_SENSE_MOTIVE, oPC, TRUE) >= 10) nSkills += 1;
+    if(GetSkillRank(SKILL_HIDE, oPC, TRUE) >= 10) nSkills += 1;
+    if(GetSkillRank(SKILL_JUMP, oPC, TRUE) >= 10) nSkills += 1;
+    if(GetSkillRank(SKILL_PERSUADE, oPC, TRUE) >= 10) nSkills += 1;
+
+    if(nCount >= 6 && nSkills >= 4)
+        SetLocalInt(oPC, "PRC_PrereqMoNine", 0);
+
+    //Eternal Blade
+    SetLocalInt(oPC, "PRC_PrereqETBL", 1);
+
+    int iWF = WeaponFocusCount(oPC);
+    nCount = _CheckPrereqsByDiscipline(oPC, DISCIPLINE_DEVOTED_SPIRIT)
+                + _CheckPrereqsByDiscipline(oPC, DISCIPLINE_DIAMOND_MIND);
+
+    if(nCount >= 2 && iWF >= 1)
+        SetLocalInt(oPC, "PRC_PrereqETBL", 0);
+
+    //Shadow Sun Ninja
+    SetLocalInt(oPC, "PRC_PrereqSSN", 1);
+
+    int nLv2 = GetPersistantLocalInt(oPC, "ShadowSunNinjaLv2Req");
+    int nSS = _CheckPrereqsByDiscipline(oPC, DISCIPLINE_SETTING_SUN);
+    int nSH = _CheckPrereqsByDiscipline(oPC, DISCIPLINE_SHADOW_HAND);
+
+    // We have at least one 2nd level Shadow Hand or Setting Sun maneuver
+    // And at least one of each Shadow Hand and Setting Sun maneuvers
+    if(nLv2 && nSS && nSH && (nSS >= 2 || nSH >= 2))
+        SetLocalInt(oPC, "PRC_PrereqSSN", 0);
+}
+
+void AOTS(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqAOTS", 1);
+    int iArcane = GetLocalInt(oPC, "PRC_ArcSpell3");
+    if(iArcane == 0 || GetInvokerLevel(oPC) >= 5)
+        SetLocalInt(oPC, "PRC_PrereqAOTS", 0);
+}
+
+void EnlF(object oPC)
+{
+     SetLocalInt(oPC, "PRC_PrereqEnlF", 1);
+     int iArcane = GetLocalInt(oPC, "PRC_ArcSpell2");
+     if(iArcane == 0 || GetInvokerLevel(oPC) >= 3)
+         SetLocalInt(oPC, "PRC_PrereqEnlF", 0);
+}
+
+void LichPrereq(object oPC)
+{
+     SetLocalInt(oPC, "PRC_PrereqLich", 1);
+     if(PRCAmIAHumanoid(oPC) || GetLevelByClass(CLASS_TYPE_LICH, oPC) >= 4)
+         SetLocalInt(oPC, "PRC_PrereqLich", 0);
+}
+
+void DragDisciple(object oPC)
+{
+    int bRace = FALSE;
+    int bSpells = FALSE;
+    SetLocalInt(oPC, "PRC_PrereqDrDis", 1);
+
+    //Any nondragon (cannot already be a half-dragon)
+    int nRace = GetRacialType(oPC);
+    if(!GetHasTemplate(TEMPLATE_HALF_DRAGON, oPC)
+    && nRace != RACIAL_TYPE_BAAZ
+    && nRace != RACIAL_TYPE_BOZAK
+    && nRace != RACIAL_TYPE_KAPAK)
+        bRace = TRUE;
+
+    // Ability to cast arcane spells without preparation
+    // (dragon blooded feat eliminates that requirement)
+    if(GetHasFeat(DRAGON_BLOODED, oPC))
+        bSpells = TRUE;
+    else if(GetLevelByClass(CLASS_TYPE_ASSASSIN, oPC)
+    || GetLevelByClass(CLASS_TYPE_BARD, oPC)
+    || GetLevelByClass(CLASS_TYPE_BEGUILER, oPC)
+    || GetLevelByClass(CLASS_TYPE_DREAD_NECROMANCER, oPC)
+    || GetLevelByClass(CLASS_TYPE_DUSKBLADE, oPC)
+    || GetLevelByClass(CLASS_TYPE_HEXBLADE, oPC)
+    || GetLevelByClass(CLASS_TYPE_SORCERER, oPC)
+    || GetLevelByClass(CLASS_TYPE_SUEL_ARCHANAMACH, oPC)
+    || GetLevelByClass(CLASS_TYPE_WARMAGE, oPC)
+    || GetLevelByClass(CLASS_TYPE_WITCH, oPC))
+    {
+        if(!GetLocalInt(oPC, "PRC_ArcSpell0")
+        || !GetLocalInt(oPC, "PRC_ArcSpell1"))
+              bSpells = TRUE;
+    }
+
+    if(bRace && bSpells)
+        SetLocalInt(oPC, "PRC_PrereqDrDis", 0);
+}
+
+void WarlockPrCs(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqHFWar", 1);
+    SetLocalInt(oPC, "PRC_PrereqEDisc", 1);
+    SetLocalInt(oPC, "PRC_PrereqETheurg", 1);
+
+    if(GetHasInvocation(INVOKE_BRIMSTONE_BLAST, oPC)
+    || GetHasInvocation(INVOKE_HELLRIME_BLAST, oPC))
+    {
+        SetLocalInt(oPC, "PRC_PrereqHFWar", 0);
+    }
+
+    //currently there are only 2 invocation using classes
+    //all start with least invocations so this should be accurate
+    if(GetIsInvocationUser(oPC))
+    {
+        SetLocalInt(oPC, "PRC_PrereqEDisc", 0);
+
+        if(GetBlastDamageDices(oPC, GetInvokerLevel(oPC, CLASS_TYPE_WARLOCK)) > 1)
+        {
+            SetLocalInt(oPC, "PRC_PrereqETheurg", 0);
+        }
+    }
+}
+
+void Shadowbane(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqShadowbane", 1);
+    if(GetLevelByClass(CLASS_TYPE_CLERIC, oPC) || 
+       GetLevelByClass(CLASS_TYPE_ARCHIVIST, oPC) || 
+       GetLevelByClass(CLASS_TYPE_PALADIN, oPC) ||
+       GetLevelByClass(CLASS_TYPE_KNIGHT_CHALICE, oPC) ||
+       GetLevelByClass(CLASS_TYPE_SOLDIER_OF_LIGHT, oPC) ||
+       GetLevelByClass(CLASS_TYPE_SHAMAN, oPC) ||
+       GetLevelByClass(CLASS_TYPE_SLAYER_OF_DOMIEL, oPC))
+        SetLocalInt(oPC, "PRC_PrereqShadowbane", 0);
+}
+
+void KnightWeave(object oPC)
+{
+    int bSpontCaster = FALSE;
+    //make sure user is a spontaneous arcane caster
+    int i;
+    for(i = 1; i <= 3; i++)
+    {
+        int nClass = GetClassByPosition(i, oPC);
+        if((GetSpellbookTypeForClass(nClass) == SPELLBOOK_TYPE_SPONTANEOUS) && GetMaxSpellLevelForCasterLevel(nClass, GetLevelByTypeArcane(oPC)) >= 3)
+              bSpontCaster = TRUE;
+              
+        //if (DEBUG) DoDebug("Knight of the Weave: Spellbook Type "+IntToString(GetSpellbookTypeForClass(nClass))+", MaxSpellLevel "+IntToString(GetMaxSpellLevelForCasterLevel(nClass, GetLevelByTypeArcane(oPC)))+", BAB "+IntToString(GetBaseAttackBonus(oPC)));      
+    }
+    
+    SetLocalInt(oPC, "PRC_PrereqKnightWeave", 1);
+    if((GetBaseAttackBonus(oPC) >= 5 || bSpontCaster) && !GetHasFeat(FEAT_SHADOWWEAVE, oPC)) // Shadow weave not allowed
+        SetLocalInt(oPC, "PRC_PrereqKnightWeave", 0);
+}
+
+void Incarnate(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqIncarnate", 1);
+    if(IncarnateAlignment(oPC) && (PRCGetIsAliveCreature(oPC) || GetHasFeat(FEAT_UNDEAD_MELDSHAPER, oPC)))
+        SetLocalInt(oPC, "PRC_PrereqIncarnate", 0);
+}
+
+void Spinemeld(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqSpinemeld", 1);
+    SetLocalInt(oPC, "PRC_PrereqUmbral", 1);
+    SetLocalInt(oPC, "PRC_PrereqIncandescent", 1);
+    if(GetTotalEssentia(oPC))
+    {
+        SetLocalInt(oPC, "PRC_PrereqSpinemeld", 0);    
+        SetLocalInt(oPC, "PRC_PrereqUmbral", 0);
+        SetLocalInt(oPC, "PRC_PrereqIncandescent", 0);
+    }    
+    //FloatingTextStringOnCreature("PRC_PrereqSpinemeld is "+IntToString(GetLocalInt(oPC, "PRC_PrereqSpinemeld"))+" GetBAB is "+IntToString(GetBaseAttackBonus(oPC))+" GetLawChaos is "+IntToString(GetAlignmentLawChaos(oPC))+" GetRace is "+IntToString(GetRacialType(oPC)), oPC, FALSE);    
+}
+
+void SapphireHierarch(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqSapphire", 1);
+    if(GetTotalEssentia(oPC) >= 3 &&/* GetHasFeat(FEAT_LAW_DOMAIN_POWER, oPC) &&*/ GetTotalSoulmeldCount(oPC) >= 3)
+        SetLocalInt(oPC, "PRC_PrereqSapphire", 0);    
+}
+
+void SoulcasterReq(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqSoulcaster", 1);
+    if( GetMaxBindCount(oPC, GetPrimaryIncarnumClass(oPC)) >= 1 && GetTotalSoulmeldCount(oPC) >= 3 &&
+    ((!GetLocalInt(oPC, "PRC_PsiPower2") && GetHasFeat(FEAT_AZURE_TALENT, oPC)) ||
+    (!GetLocalInt(oPC, "PRC_ArcSpell2") && GetHasFeat(FEAT_INCARNUM_SPELLSHAPING))))
+        SetLocalInt(oPC, "PRC_PrereqSoulcaster", 0);    
+}
+
+void Ironsoul(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqIronsoul", 1);
+    if(GetTotalSoulmeldCount(oPC) >= 1)
+        SetLocalInt(oPC, "PRC_PrereqIronsoul", 0);    
+}
+
+void Necrocarnum(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqNecrocarnum", 1);
+    if(GetTotalSoulmeldCount(oPC) && GetCanBindChakra(oPC, CHAKRA_CROWN) && GetCanBindChakra(oPC, CHAKRA_FEET) && GetCanBindChakra(oPC, CHAKRA_HANDS))
+        SetLocalInt(oPC, "PRC_PrereqNecrocarnum", 0);    
+}
+
+void Witchborn(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqWitchborn", 1);
+    // Can't be arcane at all, Meldshaper level 6th
+    if(GetPrimaryArcaneClass(oPC) == CLASS_TYPE_INVALID && GetHighestMeldshaperLevel(oPC) >= 6)
+        SetLocalInt(oPC, "PRC_PrereqWitchborn", 0);    
+}
+
+void AbChamp(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqAbjCha", 1);
+    if(GetHasFeat(FEAT_COMBAT_CASTING, oPC))
+        SetLocalInt(oPC, "PRC_PrereqAbjCha", 0);    
+}
+
+void AnimaMageReq(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqAnimaMage", 1);
+
+    int iFeat = GetHasFeat(FEAT_EMPOWER_SPELL, oPC)
+          + GetHasFeat(FEAT_EXTEND_SPELL, oPC)
+          + GetHasFeat(FEAT_MAXIMIZE_SPELL, oPC)
+          + GetHasFeat(FEAT_QUICKEN_SPELL, oPC)
+          + GetHasFeat(FEAT_SILENCE_SPELL, oPC)
+          + GetHasFeat(FEAT_STILL_SPELL, oPC);
+
+    // At least one metamagic feat, 2nd level vestiges from Binder class
+    if (iFeat && GetMaxVestigeLevel(oPC) >= 2 && GetLevelByClass(CLASS_TYPE_BINDER, oPC))
+        SetLocalInt(oPC, "PRC_PrereqAnimaMage", 0);
+}
+
+void TenebrousReq(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqTenebrous", 1);
+	int nDomain = FALSE;
+    if(GetHasFeat(FEAT_DEATH_DOMAIN_POWER)
+     + GetHasFeat(FEAT_TRICKERY_DOMAIN_POWER)
+     + GetHasFeat(FEAT_EVIL_DOMAIN_POWER) >= 2)
+     	nDomain = TRUE;
+
+	// Tenebrous grants turn undead, so it actually meets that requirement.
+
+    // 4th level vestiges from Binder class
+    if ((nDomain || !GetLevelByClass(CLASS_TYPE_CLERIC, oPC)) && GetMaxVestigeLevel(oPC) >= 4 && GetLevelByClass(CLASS_TYPE_BINDER, oPC))
+        SetLocalInt(oPC, "PRC_PrereqTenebrous", 0);
+}
+
+void ScionReq(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqScion", 1);
+	int nCheck = FALSE;
+    int nRace = MyPRCGetRacialType(oPC);
+    if(nRace == RACIAL_TYPE_HUMAN
+    || nRace == RACIAL_TYPE_HALFORC
+    || nRace == RACIAL_TYPE_HALFELF)
+     	nCheck = TRUE;
+
+    // 5th level vestiges from Binder class
+    if (nCheck && GetMaxVestigeLevel(oPC) >= 5 && GetLevelByClass(CLASS_TYPE_BINDER, oPC))
+        SetLocalInt(oPC, "PRC_PrereqScion", 0);
+}
+
+void DragonDevotee(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqDragonDevotee", 1);
+
+    if(MyPRCGetRacialType(oPC) != RACIAL_TYPE_DRAGON)
+        SetLocalInt(oPC, "PRC_PrereqDragonDevotee", 0);
+}
+
+void UrPriest(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqUrPriest", 1);
+
+    if (GetWillSavingThrow(oPC) >= 3 && GetFortitudeSavingThrow(oPC) >= 3)
+    {
+        SetLocalInt(oPC, "PRC_PrereqUrPriest", 0);
+    }
+}
+
+void Ocular(object oPC)
+{
+    SetLocalInt(oPC, "PRC_PrereqOcular", 1);
+
+    if (GetFortitudeSavingThrow(oPC) >= 4)
+    {
+        SetLocalInt(oPC, "PRC_PrereqOcular", 0);
+    }
+}
+
+void main()
+{
+    //Declare Major Variables
+    object oPC = OBJECT_SELF;
+    object oSkin = GetPCSkin(oPC);
+
+    // Initialize all the variables.
+    string sVariable, sCount;
+    int iCount;
+    for (iCount = 0; iCount <= 9; iCount++)
+    {
+       sCount = IntToString(iCount);
+
+       sVariable = "PRC_AllSpell" + sCount;
+       SetLocalInt(oPC, sVariable, 1);
+
+       sVariable = "PRC_ArcSpell" + sCount;
+       SetLocalInt(oPC, sVariable, 1);
+
+       sVariable = "PRC_DivSpell" + sCount;
+       SetLocalInt(oPC, sVariable, 1);
+
+       sVariable = "PRC_PsiPower" + sCount;
+       SetLocalInt(oPC, sVariable, 1);
+       
+        sVariable = "PRC_MystLevel" + sCount;
+       SetLocalInt(oPC, sVariable, 1);       
+    }
+
+    for (iCount = 1; iCount <= 30; iCount++)
+    {
+       sCount = IntToString(iCount);
+
+       sVariable = "PRC_SneakLevel" + sCount;
+       SetLocalInt(oPC, sVariable, 1);
+
+       sVariable = "PRC_SkirmishLevel" + sCount;
+       SetLocalInt(oPC, sVariable, 1);
+
+       sVariable = "PRC_SplAtkLevel" + sCount;
+       SetLocalInt(oPC, sVariable, 1);
+    }
+
+     // Find the spell levels.
+    int iCha = GetLocalInt(oSkin, "PRC_trueCHA") - 10;
+    int iWis = GetLocalInt(oSkin, "PRC_trueWIS") - 10;
+    int iInt = GetLocalInt(oSkin, "PRC_trueINT") - 10;
+    int nArcHighest;
+    int nDivHighest;
+    int nPsiHighest;
+    int bFirstArcClassFound, bFirstDivClassFound, bFirstPsiClassFound, bFirstShdClassFound;
+    //for(i=1;i<3;i++)
+    int nSpellLevel;
+    int nClassSlot = 1;
+    while(nClassSlot <= 3)
+    {
+        int nClass = GetClassByPosition(nClassSlot, oPC);
+        nClassSlot += 1;
+        if(GetIsDivineClass(nClass))
+        {
+            int nLevel = GetLevelByClass(nClass, oPC);
+            if (!bFirstDivClassFound &&
+                GetPrimaryDivineClass(oPC) == nClass)
+            {
+                nLevel += GetDivinePRCLevels(oPC);
+                bFirstDivClassFound = TRUE;
+            }
+            int nAbility = GetAbilityScoreForClass(nClass, oPC);
+
+            for(nSpellLevel = 0; nSpellLevel <= 9; nSpellLevel++)
+            {
+                int nSlots = GetSlotCount(nLevel, nSpellLevel, nAbility, nClass);
+                if(nSlots > 0)
+                {
+                    SetLocalInt(oPC, "PRC_AllSpell"+IntToString(nSpellLevel), 0);
+                    SetLocalInt(oPC, "PRC_DivSpell"+IntToString(nSpellLevel), 0);
+                    if(nSpellLevel > nDivHighest)
+                        nDivHighest = nSpellLevel;
+                }
+            }
+        }
+        else if(GetIsArcaneClass(nClass))
+        {
+            int nLevel = GetLevelByClass(nClass, oPC);
+            if (!bFirstArcClassFound &&
+                GetPrimaryArcaneClass(oPC) == nClass)
+            {
+                nLevel += GetArcanePRCLevels(oPC);
+                bFirstArcClassFound = TRUE;
+            }
+            int nAbility = GetAbilityScoreForClass(nClass, oPC);
+
+            for(nSpellLevel = 0; nSpellLevel <= 9; nSpellLevel++)
+            {
+                int nSlots = GetSlotCount(nLevel, nSpellLevel, nAbility, nClass);
+                if(nSlots > 0)
+                {
+                    SetLocalInt(oPC, "PRC_AllSpell"+IntToString(nSpellLevel), 0);
+                    SetLocalInt(oPC, "PRC_ArcSpell"+IntToString(nSpellLevel), 0);
+                    if(nSpellLevel > nArcHighest)
+                        nArcHighest = nSpellLevel;
+                }
+            }
+        }
+        else if(GetIsPsionicClass(nClass))
+        {
+            int nLevel = GetLevelByClass(nClass, oPC);
+            if (!bFirstPsiClassFound &&
+                GetPrimaryPsionicClass(oPC) == nClass)
+            {
+                nLevel += GetPsionicPRCLevels(oPC);
+                bFirstPsiClassFound = TRUE;
+            }
+            int nAbility = GetAbilityScoreForClass(nClass, oPC);
+            string sPsiFile = GetAMSKnownFileName(nClass);
+            int nMaxLevel = StringToInt(Get2DACache(sPsiFile, "MaxPowerLevel", nLevel));
+
+            int nPsiHighest = min(nMaxLevel, nAbility - 10);
+
+            for(nSpellLevel = 1; nSpellLevel <= nPsiHighest; nSpellLevel++)
+            {
+                SetLocalInt(oPC, "PRC_PsiPower"+IntToString(nSpellLevel), 0);
+                //if(DEBUG) DoDebug("Psionics power level Prereq Variable " + IntToString(nSpellLevel) +": " + IntToString(GetLocalInt(oPC, "PRC_PsiPower"+IntToString(nSpellLevel))), oPC);
+            }
+        }
+        else if(GetIsShadowMagicClass(nClass))
+        {
+            int nLevel = GetLevelByClass(nClass, oPC);
+            if (!bFirstShdClassFound &&
+                GetPrimaryShadowMagicClass(oPC) == nClass)
+            {
+                nLevel += GetShadowMagicPRCLevels(oPC);
+                bFirstShdClassFound = TRUE;
+            }
+            int nAbility = GetAbilityScoreForClass(nClass, oPC);
+            string sShdFile = GetAMSKnownFileName(nClass);
+
+            int nShdHighest = max(GetMaxMysteryLevelLearnable(oPC, nClass, 1), GetMaxMysteryLevelLearnable(oPC, nClass, 2));
+                nShdHighest = max(nShdHighest, GetMaxMysteryLevelLearnable(oPC, nClass, 3));
+
+            for(nSpellLevel = 1; nSpellLevel <= nShdHighest; nSpellLevel++)
+            {
+                SetLocalInt(oPC, "PRC_MystLevel"+IntToString(nSpellLevel), 0);
+                //if(DEBUG) DoDebug("Shadowcasting mystery level Prereq Variable " + IntToString(nSpellLevel) +": " + IntToString(GetLocalInt(oPC, "PRC_MystLevel"+IntToString(nSpellLevel))), oPC);
+            }
+        }        
+    }// end while - loop over all 3 class slots
+
+    // special alignment requirements
+    reqAlignment(oPC);
+    // special gender requirements
+    reqGender();
+    // Find the sneak attack/skirmish capacity.
+    reqSpecialAttack(oPC);
+
+    // Cleric domain requirements
+    if(GetLevelByClass(CLASS_TYPE_CLERIC))
+        reqDomains();
+
+    // Special requirements for several classes.
+    Tempest();
+    KOTC(oPC);
+    RedWizard(oPC);
+    Shadowlord(oPC, nArcHighest);
+    Shifter(oPC, nArcHighest, nDivHighest);
+    DemiLich(oPC);
+    WWolf(oPC);
+    Kord(oPC);
+    Maester(oPC);
+    reqCombatMedic(oPC);
+    Thrallherd(oPC);
+    Shadowmind(oPC);
+    SoulEater(oPC);
+    RacialHD(oPC);
+    Virtuoso(oPC);
+    LichPrereq(oPC);
+    DalQuor(oPC);
+    Pyro(oPC);
+    Suel();
+    TomeOfBattle(oPC);
+    AOTS(oPC);
+    EnlF(oPC);
+    DragDisciple(oPC);
+    WarlockPrCs(oPC);
+    Purifier(oPC);
+    Shadowbane(oPC);
+    WildMageReq(oPC);
+    KnightWeave(oPC);
+    Dragonheart(oPC);
+    Cultist(oPC);
+    Incarnate(oPC);
+    Spinemeld(oPC);
+    SapphireHierarch(oPC);
+    SoulcasterReq(oPC);
+    Ironsoul(oPC);
+    AbChamp(oPC);
+    Necrocarnum(oPC);
+    Witchborn(oPC);
+    AnimaMageReq(oPC);
+    TenebrousReq(oPC);
+    ScionReq(oPC);
+    DragonDevotee(oPC);
+    UrPriest(oPC);
+    Ocular(oPC);
+    // Truly massive debug message flood if activated.
+ /*   
+    if (DEBUG)
+    {
+        string sPRC_AllSpell;
+        string sPRC_ArcSpell;
+        string sPRC_DivSpell;
+        string sPRC_PsiPower;
+        string sPRC_ShdMyst;
+        for (iCount = 1; iCount <= 9; iCount++)
+        {
+           sPRC_AllSpell = "PRC_AllSpell" + IntToString(iCount);
+           sPRC_ArcSpell = "PRC_ArcSpell" + IntToString(iCount);
+           sPRC_DivSpell = "PRC_DivSpell" + IntToString(iCount);
+           sPRC_PsiPower = "PRC_PsiPower" + IntToString(iCount);
+           sPRC_ShdMyst = "PRC_MystLevel" + IntToString(iCount);
+           SendMessageToPC(oPC, sPRC_AllSpell + " is " + IntToString(GetLocalInt(oPC, sPRC_AllSpell)) + ". " +
+                                sPRC_ArcSpell + " is " + IntToString(GetLocalInt(oPC, sPRC_ArcSpell)) + ". " +
+                                sPRC_DivSpell + " is " + IntToString(GetLocalInt(oPC, sPRC_DivSpell)) + ". " +
+                                sPRC_PsiPower + " is " + IntToString(GetLocalInt(oPC, sPRC_PsiPower)) + ". " +
+                                sPRC_ShdMyst + " is " + IntToString(GetLocalInt(oPC, sPRC_ShdMyst)) + ".");
+        }
+        for (iCount = 1; iCount <= 30; iCount++)
+        {
+           sVariable = "PRC_SneakLevel" + IntToString(iCount);
+           SendMessageToPC(oPC, sVariable + " is " + IntToString(GetLocalInt(oPC, sVariable)) + ".");
+        }
+        
+    }*/
+}
diff --git a/nwnds_scripts/prc_rest.ncs b/nwnds_scripts/prc_rest.ncs
new file mode 100644
index 000000000..712bb1799
Binary files /dev/null and b/nwnds_scripts/prc_rest.ncs differ
diff --git a/nwnds_scripts/prc_rest.nss b/nwnds_scripts/prc_rest.nss
new file mode 100644
index 000000000..2c9224f9e
--- /dev/null
+++ b/nwnds_scripts/prc_rest.nss
@@ -0,0 +1,395 @@
+//::///////////////////////////////////////////////
+//:: OnPlayerRest eventscript
+//:: prc_rest
+//:://////////////////////////////////////////////
+/*
+    Hooked NPC's into this via prc_npc_rested - 06.03.2004, Ornedan
+*/
+
+#include "prc_inc_function"
+#include "psi_inc_psifunc"
+#include "prc_sp_func"
+#include "prc_inc_domain"
+#include "true_inc_trufunc"
+#include "inv_inc_invfunc"
+#include "inc_epicspells"
+#include "prc_inc_scry"
+#include "prc_inc_dragsham"
+#include "prc_inc_wpnrest"
+#include "inc_dynconv"
+#include "prc_inc_util"
+#include "shd_inc_myst"
+#include "prc_inc_template"
+
+void PrcFeats(object oPC)
+{
+    if(DEBUG) DoDebug("prc_rest: Evaluating PC feats for " + DebugObject2Str(oPC));
+
+    SetLocalInt(oPC,"ONREST",1);
+    object oSkin = GetPCSkin(oPC);
+    DelayCommand(0.0, ScrubPCSkin(oPC, oSkin));
+    DelayCommand(0.1, FeatSpecialUsePerDay(oPC));
+    DelayCommand(0.2, DeletePRCLocalInts(oSkin));
+    DelayCommand(0.3, DeletePRCLocalIntsT(oPC));
+    DelayCommand(0.4, EvalPRCFeats(oPC));
+    DelayCommand(0.4, DoWeaponsEquip(oPC));
+    DelayCommand(1.0, DeleteLocalInt(oPC,"ONREST"));
+}
+
+void RestCancelled(object oPC)
+{
+    if(GetPRCSwitch(PRC_PNP_REST_HEALING))
+    {
+        int nHP = GetLocalInt(oPC, "PnP_Rest_InitialHP");
+        //cancelled, dont heal anything
+        //nHP += GetHitDice(oPC);
+        int nCurrentHP = GetCurrentHitPoints(oPC);
+        int nDamage = nCurrentHP-nHP;
+        //check its a positive number
+        if(nDamage > 0)
+        {
+            //DelayCommand(1.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_PLUS_TWENTY), oPC));
+            SetCurrentHitPoints(oPC, nCurrentHP - nDamage);
+        }    
+    }
+    if(DEBUG) DoDebug("prc_rest: Rest cancelled for " + DebugObject2Str(oPC));
+    DelayCommand(1.0,PrcFeats(oPC));
+    // Execute scripts hooked to this event for the player triggering it
+    ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONPLAYERREST_CANCELLED);
+}
+
+void RestFinished(object oPC)
+{
+    int nGeneration = PRC_NextGeneration(GetLocalInt(oPC, PRC_Rest_Generation));
+    if (DEBUG > 1) DoDebug("Rest Generation: " + IntToString(nGeneration));
+    SetLocalInt(oPC, PRC_Rest_Generation, nGeneration);
+
+    if(DEBUG) DoDebug("prc_rest: Rest finished for for " + DebugObject2Str(oPC));
+    //Restore Power Points for Psionics
+    ExecuteScript("prc_psi_ppoints", oPC);
+    ExecuteScript("tob_evnt_recover", oPC);
+    DelayCommand(0.0, BonusDomainRest(oPC));
+    DelayCommand(0.0, ClearLawLocalVars(oPC));
+    DelayCommand(0.0, ClearMystLocalVars(oPC));
+    DelayCommand(0.0, ClearLegacyUses(oPC));
+    DelayCommand(0.1, ClearInvocationLocalVars(oPC));
+
+    // To heal up enslaved creatures...
+    object oSlave = GetLocalObject(oPC, "EnslavedCreature");
+    if (GetIsObjectValid(oSlave) && !GetIsDead(oSlave) && !GetIsInCombat(oSlave))
+            AssignCommand(oSlave, ActionRest());
+            //ForceRest(oSlave);
+
+    if (GetIsEpicSpellcaster(oPC)) {
+        FloatingTextStringOnCreature("*You feel refreshed*", oPC, FALSE);
+        ReplenishSlots(oPC);
+    }
+
+    if (GetHasFeat(FEAT_SF_CODE,oPC))
+        DelayCommand(0.1, RemoveSpecificProperty(GetPCSkin(oPC),ITEM_PROPERTY_BONUS_FEAT,IP_CONST_FEAT_SF_CODE));
+
+    // begin flurry of swords array
+    if (GetLevelByClass(CLASS_TYPE_ARCANE_DUELIST, oPC))
+    {
+        DeleteLocalInt(oPC, "FLURRY_TARGET_NUMBER");
+
+        int i;
+        for (i = 0 ; i < 10 ; i++)
+        {
+            string sName = "FLURRY_TARGET_" + IntToString(i);
+            SetLocalObject(oPC, sName, OBJECT_INVALID);
+        }
+    }
+    // end flurry or swords array
+
+    //Check for leftover Diamond Dragon appendages
+    if (GetLevelByClass(CLASS_TYPE_DIAMOND_DRAGON, oPC))
+    {
+        if(GetPersistantLocalInt(oPC, "ChannelingTail"))
+        {
+            SetPersistantLocalInt(oPC, "ChannelingTail", FALSE);
+            SetCreatureTailType(CREATURE_TAIL_TYPE_NONE, oPC);
+        }
+        if(GetPersistantLocalInt(oPC, "ChannelingWings"))
+        {
+            SetPersistantLocalInt(oPC, "ChannelingWings", FALSE);
+            SetCreatureWingType(CREATURE_WING_TYPE_NONE, oPC);
+        }
+    }
+
+    if(GetPRCSwitch(PRC_PNP_REST_HEALING))
+    {
+        int nHP = GetLocalInt(oPC, "PnP_Rest_InitialHP");
+        int nOldMax = GetLocalInt(oPC, "PnP_Rest_InitialMax");
+        if(DEBUG) DoDebug("prc_rest: Finished HPs for " + DebugObject2Str(oPC)+"n/n/"+" nCurrent: "+IntToString(nHP)+" nMax: "+IntToString(nOldMax));
+        //only heal HP if not undead and not a construct
+        if(MyPRCGetRacialType(oPC) != RACIAL_TYPE_UNDEAD && MyPRCGetRacialType(oPC) != RACIAL_TYPE_CONSTRUCT)
+            nHP = GetMaxHitPoints(oPC) - nOldMax + nHP + GetHitDice(oPC);
+        int nCurrentHP = GetCurrentHitPoints(oPC);
+        int nDamage = nCurrentHP-nHP;
+        //check its a positive number
+        if(nDamage > 0)
+        {
+            //DelayCommand(1.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_PLUS_TWENTY), oPC));
+            SetCurrentHitPoints(oPC, nCurrentHP - nDamage);
+        }  
+        // We've finished rest, clean up
+        DeleteLocalInt(oPC, "PnP_Rest_InitialHP");
+        DeleteLocalInt(oPC, "PnP_Rest_InitialMax");
+    }
+
+    int nSpellCount = GetPRCSwitch(PRC_DISABLE_SPELL_COUNT);
+    int i;
+    string sMessage;
+    for(i=1;i<nSpellCount;i++)
+    {   //WARNING! WILL DO BAD THINGS TO SPONTANEOUS CASTERS AFFECTED
+        int nSpell = GetPRCSwitch(PRC_DISABLE_SPELL_+IntToString(i));
+        int nMessage;
+        while(PRCGetHasSpell(nSpell, oPC))
+        {
+            if(!nMessage)
+            {
+                sMessage += "You cannot use "+GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpell)))+" in this module.\n";
+                nMessage = TRUE;
+            }
+            PRCDecrementRemainingSpellUses(oPC, nSpell);
+        }
+    }
+    if(sMessage != "")
+        FloatingTextStringOnCreature(sMessage, oPC, TRUE);
+
+    //Clear Battle Fortitude lock
+    DeleteLocalInt(oPC, "BattleFortitude");
+    DeleteLocalInt(oPC, "ArmouredStealth");
+    
+    //Clear Spelldancing
+    DeleteLocalInt(oPC, "SpelldanceFatigue");
+    DeleteLocalInt(oPC, "SpelldanceExhaust");    
+    DeleteLocalInt(oPC, "SpelldanceRounds");  
+    
+    //Clear Killoren
+    DeleteLocalInt(oPC, "KillorenAncient");    
+    DeleteLocalInt(oPC, "KillorenHunter"); 
+    
+    //Clear Earth Smite
+    DeleteLocalInt(oPC, "EarthSmite"); 
+    
+    //Clear Fatigue
+    DeleteLocalInt(oPC, "Fatigued");    
+    DeleteLocalInt(oPC, "HeatstrokeCount");  
+    
+    // Allow Readying
+    DeleteLocalInt(oPC, "ReadyManeuverCru");
+    DeleteLocalInt(oPC, "ReadyManeuverSwd");
+    DeleteLocalInt(oPC, "ReadyManeuverWar");
+    
+    // Rest Ranged Recall
+    DeleteLocalInt(oPC, "RangedRecall");  
+    
+    // Animal Affinity
+    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_STRENGTH));
+    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_DEXTERITY));
+    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_CONSTITUTION));
+    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_WISDOM));
+    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_INTELLIGENCE));
+    DeleteLocalInt(oPC, "AnimalAffin"+IntToString(ABILITY_CHARISMA));
+
+    if(GetHasFeat(FEAT_WEAPON_APTITUDE, oPC))
+    {
+        FloatingTextStringOnCreature(GetStringByStrRef(16837723), oPC, FALSE);
+        SetLocalInt(oPC, "PRC_WEAPON_APTITUDE_APPLIED", 0);
+    }
+
+    //DelayCommand(1.0,PrcFeats(oPC));
+    PrcFeats(oPC);
+
+    //allow players to recruit a new cohort
+    DeleteLocalInt(oPC, "CohortRecruited");
+
+    //in large parties, sometimes people dont rest
+    //loop over all and forcerest when necessary
+    //assumes NPCs start and finish resting after the PC
+    /*if(!GetIsObjectValid(GetMaster(oPC)))
+    {*/
+        int nType;
+        for(nType = 1; nType < 6; nType++)
+        {
+            int i = 1;
+            object oOldTest;
+            object oTest = GetAssociate(nType, oPC, i);
+            while(GetIsObjectValid(oTest) && oTest != oOldTest)
+            {
+                if(GetCurrentAction(oTest) != ACTION_REST)
+                    AssignCommand(oTest, DelayCommand(0.01, PRCForceRest(oTest)));
+                i++;
+                oOldTest = oTest;
+                oTest = GetAssociate(nType, oPC, i);
+            }
+        }
+    //}
+
+    // New Spellbooks
+    DelayCommand(0.3, CheckNewSpellbooks(oPC));
+    // PnP spellschools
+    if(GetPRCSwitch(PRC_PNP_SPELL_SCHOOLS)
+        && GetLevelByClass(CLASS_TYPE_WIZARD, oPC)|| GetLevelByClass(CLASS_TYPE_DEFILER)) // NWN Dark Sun class
+    {
+        //need to put a check in to make sure the player
+        //memorized one spell of their specialized
+        //school for each spell level
+        //also need to remove spells of prohibited schools
+    }
+
+    //Reset potions brewed
+    DeleteLocalInt(oPC, "PRC_POTIONS_BREWED");
+
+    //Reset scry on familiar uses
+    DeleteLocalInt(oPC, "Scry_Familiar");
+
+    //for Touch of Vitality point resetting
+    ResetTouchOfVitality(oPC);
+
+    //Lahm's finger darts - recover lost fingers
+    SetPersistantLocalInt(oPC, "FINGERS_LEFT_HAND", 6);
+    SetPersistantLocalInt(oPC, "FINGERS_RIGHT_HAND", 6);
+    SetPersistantLocalInt(oPC, "LEFT_HAND_USELESS", FALSE);
+    SetPersistantLocalInt(oPC, "RIGHT_HAND_USELESS", FALSE);
+
+    //DelayCommand(6.0f, ExecuteScript("prc_trueappear", oPC));
+
+    //skip time forward if applicable
+    DelayCommand(0.4, AdvanceTimeForPlayer(oPC, HoursToSeconds(8)));
+    
+    int nRest = GetPRCSwitch(PRC_PNP_REST_LIMIT);
+    if(nRest > 0 || nRest < 0)    
+    {
+        int nDelay = nRest * GetHitDice(oPC);
+        if (nRest == -1) nDelay = 24; 
+        else if (nRest == -2) nDelay = 16;     
+      
+        SetLocalInt(oPC, "RestTimer", TRUE);
+        DelayCommand(HoursToSeconds(nDelay), DeleteLocalInt(oPC, "RestTimer"));
+        DelayCommand(HoursToSeconds(nDelay), FloatingTextStringOnCreature("You may now rest again.", oPC, FALSE));
+        FloatingTextStringOnCreature("You may rest again in "+IntToString(nDelay)+" hours.", oPC, FALSE);
+    }    
+
+    // Execute scripts hooked to this event for the player triggering it
+    ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONPLAYERREST_FINISHED);
+}
+
+void RestStarted(object oPC)
+{
+    if(DEBUG) DoDebug("prc_rest: Rest started for " + DebugObject2Str(oPC));
+
+    // Scrying cleanup
+    if (GetIsScrying(oPC))
+    {
+        object oCopy = GetLocalObject(oPC, "Scry_Copy");
+        DoScryEnd(oPC, oCopy);
+    }
+    
+    int nRest = GetPRCSwitch(PRC_PNP_REST_LIMIT);
+    if(nRest > 0 || nRest < 0)    
+    {
+        int nDelay = nRest * GetHitDice(oPC);
+        if (nRest == -1) nDelay = 24; 
+        else if (nRest == -2) nDelay = 16;     
+        
+        if(GetLocalInt(oPC, "RestTimer"))
+        {
+            AssignCommand(oPC, ClearAllActions());
+            FloatingTextStringOnCreature("You may not rest yet. You may rest once every "+IntToString(nDelay)+" hours.", oPC, FALSE);
+        }
+    }
+    
+    // Clean up Crown of Might
+    object oCrown = GetItemPossessedBy(oPC, "prc_crown_might");
+    if (GetIsObjectValid(oCrown)) DestroyObject(oCrown);
+    oCrown = GetItemPossessedBy(oPC, "prc_crown_prot");
+    if (GetIsObjectValid(oCrown)) DestroyObject(oCrown);    
+
+    if (GetLevelByClass(CLASS_TYPE_DRUNKEN_MASTER, oPC)){
+        SetLocalInt(oPC, "DRUNKEN_MASTER_IS_IN_DRUNKEN_RAGE", 0);
+        SetLocalInt(oPC, "DRUNKEN_MASTER_IS_DRUNK_LIKE_A_DEMON", 0);
+    }
+    /* Left here in case the multisummon trick is ever broken. In that case, use this to make Astral Constructs get unsummoned properly
+    if(GetHasFeat(whatever feat determines if the PC can manifest Astral Construct here)){
+        int i = 1;
+        object oCheck = GetHenchman(oPC, i);
+        while(oCheck != OBJECT_INVALID){
+            if(GetStringLeft(GetTag(oCheck), 14) == "psi_astral_con")
+                DoDespawn(oCheck);
+            i++;
+            oCheck = GetHenchman(oPC, i);
+        }
+    }
+    */
+
+    if (GetIsPC(oPC)) SetLocalInt(oPC, "PnP_Rest_InitialHP", GetCurrentHitPoints(oPC));
+    SetLocalInt(oPC, "PnP_Rest_InitialMax", GetMaxHitPoints(oPC));
+    if(DEBUG) DoDebug("prc_rest: HPs for " + DebugObject2Str(oPC)+"n/n/"+" nCurrent: "+IntToString(GetCurrentHitPoints(oPC))+" nMax: "+IntToString(GetMaxHitPoints(oPC)));
+    // Remove Psionic Focus
+    if(GetIsPsionicallyFocused(oPC))
+    {
+        LosePsionicFocus(oPC);
+    }
+    DeleteLocalInt(oPC, PRC_SPELL_CHARGE_COUNT);
+    DeleteLocalInt(oPC, PRC_SPELL_CHARGE_SPELLID);
+    DeleteLocalObject(oPC, PRC_SPELL_CONC_TARGET);
+    if(GetLocalInt(oPC, PRC_SPELL_HOLD)) FloatingTextStringOnCreature("*Normal Casting*", oPC);
+    DeleteLocalInt(oPC, PRC_SPELL_HOLD);
+    DeleteLocalInt(oPC, PRC_SPELL_METAMAGIC);
+    DeleteLocalManifestation(oPC, PRC_POWER_HOLD_MANIFESTATION);
+    DeleteLocalMystery(oPC, "MYST_HOLD_MYST");
+    // run the prereq check here
+    ExecuteScript("prc_prereq", oPC);
+    // Execute scripts hooked to this event for the player triggering it
+    ExecuteAllScriptsHookedToEvent(oPC, EVENT_ONPLAYERREST_STARTED);
+}
+
+void main()
+{
+    object oPC = GetLastBeingRested();
+
+    if(DEBUG) DoDebug("prc_rest: Running for " + DebugObject2Str(oPC));
+    if(DEBUG) DoDebug("prc_rest Void Main: HPs for " + DebugObject2Str(oPC) +" nCurrent: "+IntToString(GetCurrentHitPoints(oPC)));
+
+    // return here for DMs as they don't need all this stuff
+    if(GetIsDM(oPC))
+        return;
+
+    //rest kits
+    if(GetPRCSwitch(PRC_SUPPLY_BASED_REST))
+        ExecuteScript("sbr_onrest", OBJECT_SELF);
+
+    // Handle the PRCForceRest() wrapper
+    if(GetLocalInt(oPC, "PRC_ForceRested"))
+    {
+        if(DEBUG) DoDebug("prc_rest: Handling forced rest");
+        RestStarted(oPC);
+        // A minor delay to break the script association and to lessen TMI chances
+        DelayCommand(0.1f, RestFinished(oPC));
+        // Clear the flag
+        DeleteLocalInt(oPC, "PRC_ForceRested");
+    }
+    else
+    {
+        switch(MyGetLastRestEventType()){
+            case REST_EVENTTYPE_REST_CANCELLED:{
+                RestCancelled(oPC);
+                break;
+            }
+            case REST_EVENTTYPE_REST_STARTED:{
+                RestStarted(oPC);
+                break;
+            }
+            case REST_EVENTTYPE_REST_FINISHED:{
+                RestFinished(oPC);
+                break;
+            }
+            case REST_EVENTTYPE_REST_INVALID:{
+                break;
+            }
+        }
+    }
+}
diff --git a/nwnds_scripts/tob_jpm_spellcon.ncs b/nwnds_scripts/tob_jpm_spellcon.ncs
new file mode 100644
index 000000000..5a1ff1183
Binary files /dev/null and b/nwnds_scripts/tob_jpm_spellcon.ncs differ
diff --git a/nwnds_scripts/tob_jpm_spellcon.nss b/nwnds_scripts/tob_jpm_spellcon.nss
new file mode 100644
index 000000000..5cc78e1b3
--- /dev/null
+++ b/nwnds_scripts/tob_jpm_spellcon.nss
@@ -0,0 +1,305 @@
+//:://////////////////////////////////////////////
+//:: Spell selection conversation for the Jade Phoenix Mage's abilities
+//:: tob_jpm_spellconv.nss
+//:://////////////////////////////////////////////
+/** @file
+    Spell selection for Jade Phoenix Mage's abilities
+    Handles the dynamic convo *and* the quickselects
+
+    @author Stratovaris
+    @date   Created  - yyyy.mm.dd
+*/
+//:://////////////////////////////////////////////
+//:://////////////////////////////////////////////
+
+#include "prc_spell_const"
+#include "inc_dynconv"
+#include "inc_newspellbook"
+////#include "prc_alterations"
+
+
+#include "prc_inc_castlvl"
+/* Constant defintions */
+const int STAGE_ENTRY = 0;
+const int STAGE_SLOT  = 1;
+const int STAGE_LVL0  = 10;
+const int STAGE_LVL9  = 20;
+
+void PopulateList(object oPC, int nLevel, int iClass, int nChoice)
+{
+    if(!GetLocalInt(oPC, "DynConv_Waiting"))
+        return;
+
+    //SendMessageToPC(oPC, "*Tick* *" + IntToString(iClass) + "*");
+
+    int nClass = GetClassByPosition(iClass);
+    if(GetIsArcaneClass(nClass))
+    {
+        int i = 0, MaxValue = 0, nSpellID;
+        if(nClass == CLASS_TYPE_WIZARD
+		|| nClass == CLASS_TYPE_DEFILER
+        || (nClass == CLASS_TYPE_SORCERER && GetPRCSwitch(PRC_SORC_DISALLOW_NEWSPELLBOOK)))
+        {
+            string sFile = "cls_spell_sorc";
+            object oToken = GetObjectByTag("SpellLvl_9_Level_" + IntToString(nLevel));
+            MaxValue = array_get_size(oToken, "Lkup");
+            //DoDebug("JPM PopulateList: nClass = "+IntToString(nClass));
+            //DoDebug("JPM PopulateList: nLevel = "+IntToString(nLevel));
+            //DoDebug("JPM PopulateList: MaxValue = "+IntToString(MaxValue));
+            while(i < MaxValue)
+            {
+                nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", array_get_int(oToken, "Lkup", i)));
+                if(GetHasSpell(nSpellID, oPC))
+                {
+                    string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                    AddChoice(sName, nChoice, oPC);
+                    SetLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                    SetLocalInt(oPC, "JPM_REAL_SPELL_CHOICE_" + IntToString(nChoice), -1);
+                    nChoice++;
+                }
+                i++;
+            }
+        }
+        else if(nClass == CLASS_TYPE_BARD && GetPRCSwitch(PRC_BARD_DISALLOW_NEWSPELLBOOK))
+        {
+            string sFile = "cls_spell_bard";
+            object oToken = GetObjectByTag("SpellLvl_1_Level_" + IntToString(nLevel));
+            MaxValue = array_get_size(oToken, "Lkup");
+            //DoDebug("JPM PopulateList: MaxValue = "+IntToString(MaxValue));
+            while(i < MaxValue)
+            {
+                nSpellID = StringToInt(Get2DACache(sFile, "RealSpellID", array_get_int(oToken, "Lkup", i)));
+                if(GetHasSpell(nSpellID, oPC))
+                {
+                    string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nSpellID)));
+                    AddChoice(sName, nChoice, oPC);
+                    SetLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice), nSpellID);
+                    SetLocalInt(oPC, "JPM_REAL_SPELL_CHOICE_" + IntToString(nChoice), -1);
+                    nChoice++;
+                }
+                i++;
+            }
+        }
+        else
+        {
+            string sFile = GetFileForClass(nClass);
+            string sArray = "NewSpellbookMem_" + IntToString(nClass);
+            // if we ever add another arcane caster with prepared spellbook
+            // uncomment all following lines
+            //int nSpellbookType = GetSpellbookTypeForClass(nClass);
+            //if(nSpellbookType == SPELLBOOK_TYPE_SPONTANEOUS)
+            {
+                int nCount = persistant_array_get_int(oPC, sArray, nLevel);
+                //DoDebug("JPM PopulateList: nCount = "+IntToString(nCount));
+                if(nCount)
+                {
+                    MaxValue = persistant_array_get_size(oPC, "Spellbook"+IntToString(nClass));
+                    while(i < MaxValue)
+                    {
+                        int nNewSpellbookID = persistant_array_get_int(oPC, "Spellbook"+IntToString(nClass), i);
+                        if(nLevel == StringToInt(Get2DACache(sFile, "Level", nNewSpellbookID))
+                        && GetHasFeat(StringToInt(Get2DACache(sFile, "FeatID", nNewSpellbookID)), oPC))
+                        {
+                            int nRealSpell = StringToInt(Get2DACache(sFile, "SpellID", nNewSpellbookID));
+                            string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell)));
+                            AddChoice(sName, nChoice, oPC);
+                            SetLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice), nLevel);
+                            SetLocalInt(oPC, "JPM_REAL_SPELL_CHOICE_" + IntToString(nChoice), nRealSpell);
+                            SetLocalString(oPC, "JPM_CLASS_ARRAY_" + IntToString(nChoice), sArray);
+                            nChoice++;
+                        }
+                        i++;
+                    }
+                }
+            }
+            /*else if(nSpellbookType == SPELLBOOK_TYPE_PREPARED)
+            {
+                string sArrayIDX = "SpellbookIDX" + IntToString(nLevel) + "_" + IntToString(nClass);
+                MaxValue = persistant_array_get_size(oPC, sArrayIDX);
+                while(i < MaxValue)
+                {
+                    int nNewSpellbookID = persistant_array_get_int(oPC, sArrayIDX, i);
+                    int nCount = persistant_array_get_int(oPC, sArray, nNewSpellbookID);
+                    if(nCount
+                    && GetHasFeat(StringToInt(Get2DACache(sFile, "FeatID", nNewSpellbookID)), oPC))
+                    {
+                        int nRealSpell = StringToInt(Get2DACache(sFile, "RealSpellID", nNewSpellbookID));
+                        string sName = GetStringByStrRef(StringToInt(Get2DACache("spells", "Name", nRealSpell)));
+                        AddChoice(sName, nChoice, oPC);
+                        SetLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice), nNewSpellbookID);
+                        SetLocalInt(oPC, "JPM_REAL_SPELL_CHOICE_" + IntToString(nChoice), nRealSpell);
+                        SetLocalString(oPC, "JPM_CLASS_ARRAY_" + IntToString(nChoice), sArray);
+                        nChoice++;
+                    }
+                    i++;
+                }
+            }*/
+        }
+    }
+
+    if(iClass == 3)
+    {
+        SetDefaultTokens();
+        DeleteLocalInt(oPC, "DynConv_Waiting");
+        FloatingTextStringOnCreature("*Done*", oPC, FALSE);
+        return;
+    }
+
+    DelayCommand(0.01, PopulateList(oPC, nLevel, iClass + 1, nChoice));
+}
+
+void main()
+{
+    object oPC = GetPCSpeaker();
+    int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
+    int nStage = GetStage(oPC);
+
+    // Check which of the conversation scripts called the scripts
+    if(nValue == 0) // All of them set the DynConv_Var to non-zero value, so something is wrong -> abort
+        return;
+
+    // Check if this stage is marked as already set up
+    // This stops list duplication when scrolling
+    //SendMessageToPC(OBJECT_SELF, "prc_jpm_spellconv:" + IntToString(nID) + " nVal:"+ IntToString(nValue));
+    /* Get the value of the local variable set by the conversation script calling
+     * this script. Values:
+     * DYNCONV_ABORTED     Conversation aborted
+     * DYNCONV_EXITED      Conversation exited via the exit node
+     * DYNCONV_SETUP_STAGE System's reply turn
+     * 0                   Error - something else called the script
+     * Other               The user made a choice
+     */
+    // The stage is used to determine the active conversation node.
+    // 0 is the entry node.
+
+
+    if(nValue == DYNCONV_SETUP_STAGE)
+    {
+        // Check if this stage is marked as already set up
+        // This stops list duplication when scrolling
+        if(!GetIsStageSetUp(nStage, oPC))
+        {
+            // variable named nStage determines the current conversation node
+            // Function SetHeader to set the text displayed to the PC
+            // Function AddChoice to add a response option for the PC. The responses are show in order added
+            if(nStage == STAGE_ENTRY)
+            {
+                SetHeader("Select Spell Level:");
+                AddChoice(GetStringByStrRef(690),  1, oPC);//"Level 1"
+                AddChoice(GetStringByStrRef(725),  2, oPC);//"Level 2"
+                AddChoice(GetStringByStrRef(687),  3, oPC);//"Level 3"
+                AddChoice(GetStringByStrRef(684),  4, oPC);//"Level 4"
+                AddChoice(GetStringByStrRef(1026), 5, oPC);//"Level 5"
+                AddChoice(GetStringByStrRef(1014), 6, oPC);//"Level 6"
+                AddChoice(GetStringByStrRef(2214), 7, oPC);//"Level 7"
+                AddChoice(GetStringByStrRef(2215), 8, oPC);//"Level 8"
+                AddChoice(GetStringByStrRef(2216), 9, oPC);//"Level 9"
+                MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
+                SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
+            }
+            else if (nStage >= STAGE_LVL0 && nStage <= STAGE_LVL9)
+            {
+                // Set the header
+                SetHeader("Select Spell:");
+                int nLevel = nStage - STAGE_LVL0;
+                SetLocalInt(oPC, "DynConv_Waiting", TRUE);
+
+                PopulateList(oPC, nLevel, 1, 1);
+
+                MarkStageSetUp(nStage, oPC);
+            }
+            else if (nStage = STAGE_SLOT)
+            {
+                SetHeader("Select QuickSlot:");
+                AddChoice("Slot 1", 1, oPC);
+                AddChoice("Slot 2", 2, oPC);
+                AddChoice("Slot 3", 3, oPC);
+                AddChoice("Slot 4", 4, oPC);
+                MarkStageSetUp(nStage, oPC); // This prevents the setup being run for this stage again until MarkStageNotSetUp is called for it
+                SetDefaultTokens(); // Set the next, previous, exit and wait tokens to default values
+            }
+        //add more stages for more nodes with Else If clauses
+        }
+        // Do token setup
+        SetupTokens();
+    }
+    // End of conversation cleanup
+    else if(nValue == DYNCONV_EXITED)
+    {
+        int nChoice = 1;
+        while(GetLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice)))
+        {
+            DeleteLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice));
+            DeleteLocalInt(oPC, "JPM_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+            DeleteLocalString(oPC, "JPM_CLASS_ARRAY_" + IntToString(nChoice));
+            nChoice++;
+        }
+        DeleteLocalInt(oPC, "JPM_SPELL_ID");
+        DeleteLocalInt(oPC, "JPM_REAL_SPELL_ID");
+        DeleteLocalString(oPC, "JPM_CLASS_ARRAY_ID");
+        DeleteLocalInt(oPC, "JPM_SPELL_LEVEL_CHOICE");
+    }
+    // Abort conversation cleanup.
+    // NOTE: This section is only run when the conversation is aborted
+    // while aborting is allowed. When it isn't, the dynconvo infrastructure
+    // handles restoring the conversation in a transparent manner
+    else if(nValue == DYNCONV_ABORTED)
+    {
+        int nChoice = 1;
+        while (GetLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice)))
+        {
+            DeleteLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice));
+            DeleteLocalInt(oPC, "JPM_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+            DeleteLocalString(oPC, "JPM_CLASS_ARRAY_" + IntToString(nChoice));
+            nChoice++;
+        }
+        DeleteLocalInt(oPC, "JPM_SPELL_ID");
+        DeleteLocalInt(oPC, "JPM_REAL_SPELL_ID");
+        DeleteLocalString(oPC, "JPM_CLASS_ARRAY_ID");
+        DeleteLocalInt(oPC, "JPM_SPELL_LEVEL_CHOICE");
+    }
+    // Handle PC responses
+    else
+    {
+        // variable named nChoice is the value of the player's choice as stored when building the choice list
+        // variable named nStage determines the current conversation node
+        int nChoice = GetChoice(oPC);
+        if(nStage == STAGE_ENTRY)
+        {
+            int nLevel = nChoice;
+            SetLocalInt(oPC, "JPM_SPELL_LEVEL_CHOICE", nLevel);
+            nStage = STAGE_LVL0 + nLevel;
+            // Move to another stage based on response, for example
+            //nStage = STAGE_QUUX;
+        }
+        else if (nStage >= STAGE_LVL0 && nStage <= STAGE_LVL9)
+        {
+            MarkStageNotSetUp(nStage, oPC);
+            int nSpell = GetLocalInt(oPC, "JPM_SPELL_CHOICE_" + IntToString(nChoice));
+            int nRealSpell = GetLocalInt(oPC, "JPM_REAL_SPELL_CHOICE_" + IntToString(nChoice));
+            string sArray = GetLocalString(oPC, "JPM_CLASS_ARRAY_" + IntToString(nChoice));
+
+            SetLocalInt(oPC, "JPM_SPELL_ID", nSpell);
+            SetLocalInt(oPC, "JPM_REAL_SPELL_ID", nRealSpell);
+            SetLocalString(oPC, "JPM_CLASS_ARRAY_ID", sArray);
+
+            nStage = STAGE_SLOT;
+        }
+        else if (nStage = STAGE_SLOT)
+        {
+            int nSpell = GetLocalInt(oPC, "JPM_SPELL_ID");
+            int nRealSpell = GetLocalInt(oPC, "JPM_REAL_SPELL_ID");
+            string sArray = GetLocalString(oPC, "JPM_CLASS_ARRAY_ID");
+            int nLevel = GetLocalInt(oPC, "JPM_SPELL_LEVEL_CHOICE");
+
+            if(DEBUG) DoDebug("tob_jpm_spellconv: nSpell value = " + IntToString(nSpell));
+            SetLocalInt(oPC, "JPM_SPELL_QUICK" + IntToString(nChoice), nSpell);
+            SetLocalInt(oPC, "JPM_REAL_SPELL_QUICK" + IntToString(nChoice), nRealSpell);
+            SetLocalString(oPC, "JPM_SPELL_QUICK" + IntToString(nChoice), sArray);
+            SetLocalInt(oPC, "JPM_SPELL_QUICK" + IntToString(nChoice) + "LVL", nLevel);
+            nStage = STAGE_ENTRY;
+        }
+        // Store the stage value. If it has been changed, this clears out the choices
+        SetStage(nStage, oPC);
+    }
+}
\ No newline at end of file
diff --git a/nwnds_scripts/x2_pc_umdcheck.ncs b/nwnds_scripts/x2_pc_umdcheck.ncs
new file mode 100644
index 000000000..e508398b5
Binary files /dev/null and b/nwnds_scripts/x2_pc_umdcheck.ncs differ
diff --git a/nwnds_scripts/x2_pc_umdcheck.nss b/nwnds_scripts/x2_pc_umdcheck.nss
new file mode 100644
index 000000000..f45bfaf95
--- /dev/null
+++ b/nwnds_scripts/x2_pc_umdcheck.nss
@@ -0,0 +1,163 @@
+//------------------------------------------------------------------------------
+/*
+Use Magic Device Check.
+Simple use magic device check to prevent abuse of
+the engine level implementation of use magic device
+This function is not supposed to mirror the 3E use
+magic device mechanics.
+
+Returns TRUE if the Spell is allowed to be
+cast, either because the character is allowed
+to cast it or he has won the required UMD check
+
+returns TRUE if
+   ... spell not cast by an item
+   ... item is not a scroll (may be extended)
+   ... caster has levels in wiz, bard, sorc
+   ... caster is no rogue and has no UMD skill
+   ... caster has memorized this spell
+   ... the property corresponding to the spell does not exist (2da inconsistency)
+
+   ... a UMD check against 25+InnateLevel of the spell is won
+
+Note: I am not using the effective level of the spell for DC calculation but
+      instead the lowest possible effective level. This is by design to allow
+      rogues to use most low level scrolls in the game (i.e. light scrolls have
+      an effective level 5 but a lowest effective level of 1 and we want low level
+      rogues to cast these spells..)
+
+      Setting a Local Interger called X2_SWITCH_CLASSIC_UMD (TRUE) on the Module
+      will result in this function to return TRUE all the time
+
+      User's can change this default implementation by modifing this file
+*/
+//------------------------------------------------------------------------------
+
+#include "prc_inc_spells"
+
+int DoCastingClassCheck(object oCaster, int nSpellID, int nClass)
+{
+    string sClass;
+    switch(nClass)
+    {
+        case CLASS_TYPE_CLERIC:  sClass = "Cleric";   break;
+        case CLASS_TYPE_DRUID:   sClass = "Druid";    break;
+        case CLASS_TYPE_PALADIN: sClass = "Paladin";  break;
+        case CLASS_TYPE_RANGER:  sClass = "Ranger";   break;
+        case CLASS_TYPE_WIZARD:  sClass = "Wiz_Sorc"; break;
+		case CLASS_TYPE_DEFILER: sClass = "Wiz_Sorc"; break;
+    }
+    if(sClass == "")
+        return RealSpellToSpellbookID(nClass, nSpellID) != -1;
+    else
+        return Get2DACache("Spells", sClass, nSpellID) != "";
+}
+
+int UMD_CheckCastingClass(object oCaster, int nSpellID)
+{
+    int i;
+    for(i = 1; i < 4; i++)
+    {
+        if(DoCastingClassCheck(oCaster, nSpellID, GetClassByPosition(i, oCaster)))
+            return TRUE;
+    }
+    return FALSE;
+}
+
+int X2_UMD()
+{
+    if(!GetModuleSwitchValue(MODULE_SWITCH_ENABLE_UMD_SCROLLS))
+        return TRUE;
+
+    object oItem = PRCGetSpellCastItem();
+    if(!GetIsObjectValid(oItem))
+        return TRUE; // Spell not cast by item, UMD not required
+
+    // -------------------------------------------------------------------------
+    // Only Scrolls are subject to our default UMD Check
+    // -------------------------------------------------------------------------
+    if(GetBaseItemType(oItem) != BASE_ITEM_SPELLSCROLL)
+        return TRUE; // spell not cast from a scroll
+
+    // -------------------------------------------------------------------------
+    // Ignore scrolls that have no use limitations (i.e. raise dead)
+    // -------------------------------------------------------------------------
+    if(!IPGetHasUseLimitation(oItem))
+        return TRUE;
+
+    object oCaster = OBJECT_SELF;
+    int nSpellID = PRCGetSpellId();
+
+    // -------------------------------------------------------------------------
+    // Check if caster has levels in class that can cast given spell
+    // -------------------------------------------------------------------------
+    if(UMD_CheckCastingClass(oCaster, nSpellID))
+        return TRUE;
+
+    // -------------------------------------------------------------------------
+    // If the caster used the item and has no UMD Skill and is not a rogue
+    // thus we assume he must be allowed to use it because the engine
+    // prevents people that are not capable of using an item from using it....
+    // -------------------------------------------------------------------------
+    if(!GetHasSkill(SKILL_USE_MAGIC_DEVICE, oCaster)
+    && !GetLevelByClass(CLASS_TYPE_ROGUE, oCaster)
+    && !GetLevelByClass(CLASS_TYPE_ASSASSIN, oCaster)
+    && !GetLevelByClass(CLASS_TYPE_SHADOWDANCER, oCaster))
+    {
+        // ---------------------------------------------------------------------
+        //SpeakString("I have no UMD, thus I can cast the spell... ");
+        // ---------------------------------------------------------------------
+        return TRUE;
+    }
+
+    if(Get2DACache("des_crft_spells", "IPRP_SpellIndex", nSpellID) == "")
+    {
+        WriteTimestampedLogEntry("***X2UseMagicDevice (Warning): Found no property matching SpellID "+ IntToString(nSpellID));
+        return TRUE;
+    }
+
+    // -------------------------------------------------------------------------
+    //I am using des_crft_spells.2da Innate Level column here, not (as would be correct)
+    //the IPPR_Spells.2da InnateLvl column, because some of the scrolls in
+    //the game (i.e. light) would not be useable (DC 30+)
+    // -------------------------------------------------------------------------
+    int nInnateLevel = StringToInt(Get2DACache("des_crft_spells","Level",nSpellID));
+    int nSkill = SKILL_USE_MAGIC_DEVICE;
+    //int nSkillRanks = GetSkillRank(SKILL_USE_MAGIC_DEVICE, oCaster);
+    if(GetLevelByClass(CLASS_TYPE_ARTIFICER, oCaster))
+        nInnateLevel -= 2;  //only scrolls are being checked, and arti gets scribe scroll at level 1, this instead of +2 to skill
+
+    // -------------------------------------------------------------------------
+    // Base DC for casting a spell from a scroll is 25+SpellLevel
+    // We do not have a way to check for misshaps here but GetIsSkillSuccessful
+    // does not return the required information
+    // -------------------------------------------------------------------------
+    if(GetPRCIsSkillSuccessful(oCaster, nSkill, 25+ nInnateLevel, (GetHasFeat(FEAT_DECEIVE_ITEM, oCaster) || GetHasFeat(FEAT_SKILL_MASTERY_ARTIFICER, oCaster)) ? 10 : -1))
+    {
+        return TRUE;
+    }
+    else
+    {
+        effect ePuff =  EffectVisualEffect(VFX_IMP_MAGIC_RESISTANCE_USE);
+        ApplyEffectToObject(DURATION_TYPE_INSTANT,ePuff,oCaster);
+        return FALSE;
+    }
+}
+
+void main()
+{
+    //--------------------------------------------------------------------------
+    // Reset
+    //--------------------------------------------------------------------------
+    if(GetLocalInt(GetModule(),"X2_L_STOP_EXPERTISE_ABUSE"))
+    {
+         SetActionMode(OBJECT_SELF, ACTION_MODE_EXPERTISE, FALSE);
+         SetActionMode(OBJECT_SELF, ACTION_MODE_IMPROVED_EXPERTISE, FALSE);
+    }
+
+    //--------------------------------------------------------------------------
+    // Do use magic device check
+    //--------------------------------------------------------------------------
+    int nRet = X2_UMD();
+    SetExecutedScriptReturnValue(nRet);
+}
\ No newline at end of file
diff --git a/nwnds_scripts/x2_s0_blckblde.ncs b/nwnds_scripts/x2_s0_blckblde.ncs
new file mode 100644
index 000000000..9a93f0118
Binary files /dev/null and b/nwnds_scripts/x2_s0_blckblde.ncs differ
diff --git a/nwnds_scripts/x2_s0_blckblde.nss b/nwnds_scripts/x2_s0_blckblde.nss
new file mode 100644
index 000000000..3dd06c8f5
--- /dev/null
+++ b/nwnds_scripts/x2_s0_blckblde.nss
@@ -0,0 +1,220 @@
+//::///////////////////////////////////////////////
+//:: Black Blade of Disaster
+//:: X2_S0_BlckBlde
+//:: Copyright (c) 2001 Bioware Corp.
+//:://////////////////////////////////////////////
+/*
+    Summons a greatsword to battle for the caster
+*/
+//:://////////////////////////////////////////////
+//:: Created By: Andrew Nobbs
+//:: Created On: Nov 26, 2002
+//:://////////////////////////////////////////////
+//:: Last Updated By: Georg Zoeller, July 28 - 2003
+
+//:: modified by mr_bumpkin Dec 4, 2003 for prc stuff
+
+#include "inc_utility"
+#include "prc_inc_spells"
+#include "prc_inc_sp_tch"
+#include "prc_add_spell_dc"
+
+void DoPnPAttack(object oSummon)
+{
+    object oTarget = GetAttackTarget(oSummon);
+    if(GetIsObjectValid(oTarget)
+        && GetDistanceBetween(oTarget, oSummon) < 5.0)
+    {
+        int nAttackResult = PRCDoMeleeTouchAttack(oTarget);;
+        if(nAttackResult)
+        {
+            //hit or critical hit
+            //touch attacks are only crit on 20
+            //BBoD is crit on 18-20
+            //so 2/20ths of attacks that hit, but not crit, will be turned into crits
+            if(nAttackResult == 1 & d20(1)>=19)
+                nAttackResult = 2;
+            int nDamage = d12(2);
+            if(nAttackResult == 2)
+                nDamage *=2; //critical doubles damage
+            //its magical damage because the description is unclear
+            AssignCommand(oSummon, ApplyEffectToObject(
+                DURATION_TYPE_INSTANT, PRCEffectDamage(oTarget, nDamage,
+                    DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_PLUS_FIVE), oTarget));
+        }
+        if(nAttackResult == 2)
+        {
+            //critical hit
+            //cast disintegrate
+            int nLevel = GetLocalInt(oSummon, "BBoD_Level");
+
+            SetLocalInt(oSummon, PRC_CASTERLEVEL_OVERRIDE, nLevel);
+            // Make sure this variable gets deleted as quickly as possible in case it's added in error.
+            AssignCommand(oSummon, DelayCommand(1.0, DeleteLocalInt(oSummon, PRC_CASTERLEVEL_OVERRIDE)));
+
+            // Make SR check
+           if (!PRCDoResistSpell(OBJECT_SELF, oTarget))
+           {
+                // Generate the RTA beam.
+                AssignCommand(oSummon, SPApplyEffectToObject(DURATION_TYPE_TEMPORARY,
+                EffectBeam(VFX_BEAM_DISINTEGRATE, OBJECT_SELF, BODY_NODE_HAND), oTarget, 1.0,FALSE));
+
+                // Fort save or die time, but we implement death by doing massive damage
+                // since disintegrate works on constructs, undead, etc.  At some point EffectDie()
+                // should be tested to see if it works on non-living targets, and if it does it should
+                // be used instead.
+                // Test done. Result: It does kill them.
+                int nDamage = 9999;
+                if (PRCMySavingThrow(SAVING_THROW_FORT, oTarget, PRCGetSaveDC(oTarget,OBJECT_SELF), SAVING_THROW_TYPE_SPELL))
+                {
+                     nDamage = PRCGetMetaMagicDamage(DAMAGE_TYPE_MAGICAL, 1 == nAttackResult ? 5 : 10, 6);
+                }
+                else
+                {
+                     // If FB passes saving throw it survives, else it dies
+                     //DeathlessFrenzyCheck(oTarget);
+
+                     // For targets with > 9999 HP. Uncomment if you have such in your module and would like Disintegrate
+                     // to be sure to blast them
+                     //DelayCommand(0.30, SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oTarget));
+                }
+
+                // Apply damage effect and VFX impact, and if the target is dead then apply
+                // the fancy rune circle too.
+                if (nDamage >= GetCurrentHitPoints (oTarget))
+                     DelayCommand(0.25, SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_2), oTarget));
+                //DelayCommand(0.25, SPApplyEffectToObject(DURATION_TYPE_INSTANT, PRCEffectDamage(oTarget, nDamage, DAMAGE_TYPE_MAGICAL), oTarget));
+                DelayCommand(0.25, SPApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_MAGBLUE), oTarget));
+                ApplyTouchAttackDamage(OBJECT_SELF, oTarget, nAttackResult, nDamage, DAMAGE_TYPE_MAGICAL);
+           }
+
+        }
+    }
+    if(GetIsObjectValid(oSummon))
+        DelayCommand(6.0, DoPnPAttack(oSummon));
+}
+
+//Creates the weapon that the creature will be using.
+void spellsCreateItemForSummoned()
+{
+    //Declare major variables
+    int nStat;
+
+    // cast from scroll, we just assume +5 ability modifier
+    if (GetSpellCastItem() != OBJECT_INVALID)
+    {
+        nStat = 5;
+    }
+     else
+    {
+        int nClass = PRCGetLastSpellCastClass();
+        int nLevel = GetLevelByClass(nClass);
+
+        int nStat;
+
+        int nCha =  GetAbilityModifier(ABILITY_CHARISMA,OBJECT_SELF);
+        int nInt =  GetAbilityModifier(ABILITY_INTELLIGENCE,OBJECT_SELF);
+
+        if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_DEFILER)
+        {
+            nStat = nInt;
+        }
+        else
+        {
+            nStat = nCha;
+        }
+
+        if (nStat >20)
+        {
+            nStat =20;
+        }
+
+        if (nStat <1)
+        {
+           nStat = 0;
+        }
+    }
+    int i = 1;
+    object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i);
+    while(GetIsObjectValid(oSummon))
+    {
+        oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF, i);
+        i++;
+    }
+    // Make the blade require concentration
+    SetLocalInt(oSummon,"X2_L_CREATURE_NEEDS_CONCENTRATION",TRUE);
+    object oWeapon;
+    //Create item on the creature, epuip it and add properties.
+    oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,oSummon);
+    if (nStat > 0 && !GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER))
+    {
+        IPSetWeaponEnhancementBonus(oWeapon, nStat);
+    }
+    SetDroppableFlag(oWeapon, FALSE);
+    SetPlotFlag (oSummon,TRUE);
+
+    if(GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER))
+    {
+        itemproperty ipTest = GetFirstItemProperty(oWeapon);
+        while(GetIsItemPropertyValid(ipTest))
+        {
+            ipTest = GetNextItemProperty(oWeapon);
+        }
+        itemproperty ipNoDam = ItemPropertyNoDamage();
+        AddItemProperty(DURATION_TYPE_PERMANENT, ipNoDam, oWeapon);
+        itemproperty ipVFX = ItemPropertyVisualEffect(ITEM_VISUAL_ELECTRICAL);
+        AddItemProperty(DURATION_TYPE_PERMANENT, ipVFX, oWeapon);
+        //store the level on the summon
+        SetLocalInt(oSummon, "BBoD_Level", GetLocalInt(OBJECT_SELF, "BBoD_Level"));
+        DeleteLocalInt(OBJECT_SELF, "BBoD_Level");
+        //attacks are handled through a pseudoHB
+        DoPnPAttack(oSummon);
+    }
+}
+
+void main()
+{
+DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
+SetLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR", SPELL_SCHOOL_CONJURATION);
+/*
+  Spellcast Hook Code
+  Added 2003-07-07 by Georg Zoeller
+  If you want to make changes to all spells,
+  check x2_inc_spellhook.nss to find out more
+
+*/
+
+    if (!X2PreSpellCastCode())
+    {
+    // If code within the PreSpellCastHook (i.e. UMD) reports FALSE, do not run this spell
+        return;
+    }
+
+// End of Spell Cast Hook
+
+
+    //Declare major variables
+    int nMetaMagic = PRCGetMetaMagicFeat();
+    int nDuration = PRCGetCasterLevel(OBJECT_SELF);
+    effect eSummon = EffectSummonCreature("x2_s_bblade");
+    effect eVis = EffectVisualEffect(VFX_FNF_SUMMON_MONSTER_3);
+    //Make metamagic check for extend
+    if ((nMetaMagic & METAMAGIC_EXTEND))
+        nDuration = nDuration *2;//Duration is +100%
+    //Apply the VFX impact and summon effect
+    MultisummonPreSummon();
+    ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, PRCGetSpellTargetLocation());
+
+    float fDuration = RoundsToSeconds(nDuration);
+    if(GetPRCSwitch(PRC_SUMMON_ROUND_PER_LEVEL))
+        fDuration = RoundsToSeconds(nDuration*GetPRCSwitch(PRC_SUMMON_ROUND_PER_LEVEL));
+    ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, PRCGetSpellTargetLocation(), fDuration);
+    DelayCommand(1.5, spellsCreateItemForSummoned());
+    if(GetPRCSwitch(PRC_PNP_BLACK_BLADE_OF_DISASTER))
+    {
+        SetLocalInt(OBJECT_SELF, "BBoD_Level", PRCGetCasterLevel(OBJECT_SELF));
+    }
+
+DeleteLocalInt(OBJECT_SELF, "X2_L_LAST_SPELLSCHOOL_VAR");
+// Erasing the variable used to store the spell's spell school
+}