public static int NewStaff(CLRScriptBase script, int maxValue)
        {
            #region Check if collections need to be loaded. Load them if so
            if (FireSpells[IP_CONST_CASTSPELL_BURNING_HANDS_2] == 0)
            {
                FireSpells = convertToStaffPrice(FireSpells);
                ColdSpells = convertToStaffPrice(ColdSpells);
                AcidSpells = convertToStaffPrice(AcidSpells);
                ElectricSpells = convertToStaffPrice(ElectricSpells);
                SoundSpells = convertToStaffPrice(SoundSpells);
                PhysicalAttackSpells = convertToStaffPrice(PhysicalAttackSpells);
                ForceSpells = convertToStaffPrice(ForceSpells);
                MoraleSpells = convertToStaffPrice(MoraleSpells);
                AntimoraleSpells = convertToStaffPrice(AntimoraleSpells);
                MindControlSpells = convertToStaffPrice(MindControlSpells);
                PerceptionSpells = convertToStaffPrice(PerceptionSpells);
                PhysicalSpells = convertToStaffPrice(PhysicalSpells);
                MentalSpells = convertToStaffPrice(MentalSpells);
                Transmutations = convertToStaffPrice(Transmutations);
                AntiMagicSpells = convertToStaffPrice(AntiMagicSpells);
                IllusionSpells = convertToStaffPrice(IllusionSpells);
                DeathSpells = convertToStaffPrice(DeathSpells);
                EvilSpells = convertToStaffPrice(EvilSpells);
                GoodSpells = convertToStaffPrice(GoodSpells);
                ProtectionSpells = convertToStaffPrice(ProtectionSpells);
                HealingSpells = convertToStaffPrice(HealingSpells);
                SummonSpells = convertToStaffPrice(SummonSpells);
            }
            #endregion

            Dictionary<int, int> currentAvailableSpells = new Dictionary<int,int>();
            List<string> possibleNames = new List<string>();
            #region Get Starting Collections
            switch (Generation.rand.Next(22))
            {
                case 0:
                    copyDictionary(FireSpells, currentAvailableSpells);
                    copyList(FireNames, possibleNames);
                    break;
                case 1:
                    copyDictionary(ColdSpells, currentAvailableSpells);
                    copyList(ColdNames, possibleNames);
                    break;
                case 2:
                    copyDictionary(AcidSpells, currentAvailableSpells);
                    copyList(AcidNames, possibleNames);
                    break;
                case 3:
                    copyDictionary(ElectricSpells, currentAvailableSpells);
                    copyList(ElectricNames, possibleNames);
                    break;
                case 4:
                    copyDictionary(SoundSpells, currentAvailableSpells);
                    copyList(SoundNames, possibleNames);
                    break;
                case 5:
                    copyDictionary(PhysicalAttackSpells, currentAvailableSpells);
                    copyList(PhysicalAttackNames, possibleNames);
                    break;
                case 6:
                    copyDictionary(ForceSpells, currentAvailableSpells);
                    copyList(ForceNames, possibleNames);
                    break;
                case 7: 
                    copyDictionary(MoraleSpells, currentAvailableSpells);
                    copyList(MoraleNames, possibleNames);
                    break;
                case 8:
                    copyDictionary(AntimoraleSpells, currentAvailableSpells);
                    copyList(AntimoraleNames, possibleNames);
                    break;
                case 9:
                    copyDictionary(MindControlSpells, currentAvailableSpells);
                    copyList(MindControlNames, possibleNames);
                    break;
                case 10:
                    copyDictionary(PerceptionSpells, currentAvailableSpells);
                    copyList(PerceptionNames, possibleNames);
                    break;
                case 11:
                    copyDictionary(PhysicalSpells, currentAvailableSpells);
                    copyList(PhysicalNames, possibleNames);
                    break;
                case 12:
                    copyDictionary(MentalSpells, currentAvailableSpells);
                    copyList(MentalNames, possibleNames);
                    break;
                case 13:
                    copyDictionary(Transmutations, currentAvailableSpells);
                    copyList(TransmutNames, possibleNames);
                    break;
                case 14:
                    copyDictionary(AntiMagicSpells, currentAvailableSpells);
                    copyList(AntiMagicNames, possibleNames);
                    break;
                case 15:
                    copyDictionary(IllusionSpells, currentAvailableSpells);
                    copyList(IllusionNames, possibleNames);
                    break;
                case 16:
                    copyDictionary(DeathSpells, currentAvailableSpells);
                    copyList(DeathNames, possibleNames);
                    break;
                case 17:
                    copyDictionary(EvilSpells, currentAvailableSpells);
                    copyList(EvilNames, possibleNames);
                    break;
                case 18:
                    copyDictionary(GoodSpells, currentAvailableSpells);
                    copyList(GoodNames, possibleNames);
                    break;
                case 19:
                    copyDictionary(ProtectionSpells, currentAvailableSpells);
                    copyList(ProtectionNames, possibleNames);
                    break;
                case 20:
                    copyDictionary(HealingSpells, currentAvailableSpells);
                    copyList(HealingNames, possibleNames);
                    break;
                case 21:
                    copyDictionary(SummonSpells, currentAvailableSpells);
                    copyList(SummonNames, possibleNames);
                    break;
            }
            if (currentAvailableSpells.Count == 0 || possibleNames.Count == 0)
            {
                return 0;
            }
            #endregion

            #region Select Spells from Collections Based on Price
            Dictionary<int, int> SelectedSpells = new Dictionary<int, int>();
            List<int> SelectedPrices = new List<int>();
            int currentCharges = 5;
            int maxSpellValue = maxValue;
            while (true)
            {
                List<int> spellsToRemove = new List<int>();
                foreach (int spell in currentAvailableSpells.Keys)
                {
                    if (((currentAvailableSpells[spell] * 50) / currentCharges) > maxValue ||
                        currentAvailableSpells[spell] > maxSpellValue)
                    {
                        spellsToRemove.Add(spell);
                    }
                }
                foreach (int spell in spellsToRemove)
                {
                    currentAvailableSpells.Remove(spell);
                }
                if (currentAvailableSpells.Count == 0)
                {
                    if(SelectedSpells.Count == 0)
                    {
                        return 0;
                    }
                    else
                    {
                        break;
                    }
                }
                List<int> spellOptions = new List<int>();
                foreach (int key in currentAvailableSpells.Keys)
                {
                    spellOptions.Add(key);
                }
                int spellSelection = spellOptions[Generation.rand.Next(spellOptions.Count)];
                switch (currentCharges)
                {
                    case 1:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 50);
                        currentCharges--;
                        break;
                    case 2:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_2_CHARGES_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 25);
                        maxSpellValue = currentAvailableSpells[spellSelection] - 1;
                        maxValue -= currentAvailableSpells[spellSelection] * 25;
                        currentCharges--;
                        break;
                    case 3:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_3_CHARGES_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 16);
                        maxSpellValue = currentAvailableSpells[spellSelection] - 1;
                        maxValue -= currentAvailableSpells[spellSelection] * 16;
                        currentCharges--;
                        break;
                    case 4:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_4_CHARGES_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 12);
                        maxSpellValue = currentAvailableSpells[spellSelection] - 1;
                        maxValue -= currentAvailableSpells[spellSelection] * 12;
                        currentCharges--;
                        break;
                    case 5:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_5_CHARGES_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 10);
                        maxSpellValue = currentAvailableSpells[spellSelection] - 1;
                        maxValue -= currentAvailableSpells[spellSelection] * 10;
                        currentCharges--;
                        break;
                }
                if (currentCharges == 0)
                {
                    break;
                }
            }
            #endregion

            #region Sum Predicted Values of Properties
            SelectedPrices.Sort();
            int value = SelectedPrices[0];
            if (SelectedPrices.Count > 1)
            {
                value += (SelectedPrices[1] * 3 / 4);
            }
            if (SelectedPrices.Count > 2)
            {
                value += (SelectedPrices[2] / 2);
            }
            if (SelectedPrices.Count > 3)
            {
                value += (SelectedPrices[3] / 2);
            }
            if (SelectedPrices.Count > 4)
            {
                value += (SelectedPrices[4] / 2);
            }
            #endregion

            #region Build the Actual Staff
            uint staff = script.CreateItemOnObject(GenerateWeapon.WeaponResrefs[BASE_ITEM_QUARTERSTAFF], script.OBJECT_SELF, 1, "", FALSE);
            script.SetItemCharges(staff, 50);
            List<int> classRestrictions = new List<int>();
            foreach (KeyValuePair<int, int> Spell in SelectedSpells)
            {
                script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyCastSpell(Spell.Key, Spell.Value), staff, 0.0f);
                if (ALFA.Shared.Modules.InfoStore.IPCastSpells[Spell.Key].Spell.BardLevel >= 0 &&
                    !classRestrictions.Contains(IP_CONST_CLASS_BARD))
                {
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_BARD), staff, 0.0f);
                    classRestrictions.Add(IP_CONST_CLASS_BARD);
                }
                if (ALFA.Shared.Modules.InfoStore.IPCastSpells[Spell.Key].Spell.ClericLevel >= 0 &&
                    !classRestrictions.Contains(IP_CONST_CLASS_CLERIC))
                {
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_CLERIC), staff, 0.0f);
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_FAVORED_SOUL), staff, 0.0f);
                    classRestrictions.Add(IP_CONST_CLASS_CLERIC);
                }
                if (ALFA.Shared.Modules.InfoStore.IPCastSpells[Spell.Key].Spell.DruidLevel >= 0 &&
                    !classRestrictions.Contains(IP_CONST_CLASS_DRUID))
                {
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_DRUID), staff, 0.0f);
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_SPIRIT_SHAMAN), staff, 0.0f);
                    classRestrictions.Add(IP_CONST_CLASS_DRUID);
                }
                if (ALFA.Shared.Modules.InfoStore.IPCastSpells[Spell.Key].Spell.WizardLevel >= 0 &&
                    !classRestrictions.Contains(IP_CONST_CLASS_WIZARD))
                {
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_WIZARD), staff, 0.0f);
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_SORCERER), staff, 0.0f);
                    classRestrictions.Add(IP_CONST_CLASS_WIZARD);
                }
                if (ALFA.Shared.Modules.InfoStore.IPCastSpells[Spell.Key].Spell.PaladinLevel >= 0 &&
                    !classRestrictions.Contains(IP_CONST_CLASS_PALADIN))
                {
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_PALADIN), staff, 0.0f);
                    classRestrictions.Add(IP_CONST_CLASS_PALADIN);
                }
                if (ALFA.Shared.Modules.InfoStore.IPCastSpells[Spell.Key].Spell.RangerLevel >= 0 &&
                    !classRestrictions.Contains(IP_CONST_CLASS_RANGER))
                {
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(IP_CONST_CLASS_RANGER), staff, 0.0f);
                    classRestrictions.Add(IP_CONST_CLASS_RANGER);
                }
            }
            script.SetFirstName(staff, String.Format(possibleNames[Generation.rand.Next(possibleNames.Count)], "Staff"));
            Pricing.CalculatePrice(script, staff);
            #endregion
            return value;
        }
        public static int NewWand(CLRScriptBase script, int maxValue)
        {
            if (maxValue < 375)
            {
                return 0;
            }
            int wandValue = 0;
            uint scrollSource = OBJECT_INVALID;
            if (maxValue >= 21000)
            {
                switch (Generation.rand.Next(5))
                {
                    case 0:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level4Scrolls[Generation.rand.Next(GenerateScroll.Level4Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 21000;
                        break;
                    case 1:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level3Scrolls[Generation.rand.Next(GenerateScroll.Level3Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 11250;
                        break;
                    case 2:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level2Scrolls[Generation.rand.Next(GenerateScroll.Level2Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 4500;
                        break;
                    case 3:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level1Scrolls[Generation.rand.Next(GenerateScroll.Level1Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 750;
                        break;
                    case 4:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level0Scrolls[Generation.rand.Next(GenerateScroll.Level0Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 375;
                        break;
                }
            }
            else if (maxValue >= 11250)
            {
                switch (Generation.rand.Next(4))
                {
                    case 0:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level3Scrolls[Generation.rand.Next(GenerateScroll.Level3Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 11250;
                        break;
                    case 1:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level2Scrolls[Generation.rand.Next(GenerateScroll.Level2Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 4500;
                        break;
                    case 2:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level1Scrolls[Generation.rand.Next(GenerateScroll.Level1Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 750;
                        break;
                    case 3:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level0Scrolls[Generation.rand.Next(GenerateScroll.Level0Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 375;
                        break;
                }
            }
            else if (maxValue >= 4500)
            {
                switch (Generation.rand.Next(3))
                {
                    case 0:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level2Scrolls[Generation.rand.Next(GenerateScroll.Level2Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 4500;
                        break;
                    case 1:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level1Scrolls[Generation.rand.Next(GenerateScroll.Level1Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 750;
                        break;
                    case 2:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level0Scrolls[Generation.rand.Next(GenerateScroll.Level0Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 375;
                        break;
                }
            }
            else if (maxValue >= 750)
            {
                switch (Generation.rand.Next(2))
                {
                    case 0:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level1Scrolls[Generation.rand.Next(GenerateScroll.Level1Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 750;
                        break;
                    case 1:
                        wandNumber++;
                        scrollSource = script.CreateItemOnObject(GenerateScroll.Level0Scrolls[Generation.rand.Next(GenerateScroll.Level0Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                        wandValue = 375;
                        break;
                }
            }
            else if (maxValue >= 375)
            {
                wandNumber++;
                scrollSource = script.CreateItemOnObject(GenerateScroll.Level0Scrolls[Generation.rand.Next(GenerateScroll.Level0Scrolls.Count)], script.OBJECT_SELF, 1, "soonwand" + wandNumber.ToString(), FALSE);
                wandValue = 375;
            }

            uint wandItem = script.CreateItemOnObject(wandResRef, script.OBJECT_SELF, 1, script.GetTag(scrollSource) + wandNumber.ToString(), FALSE);
            script.SetItemCharges(wandItem, 50);
            string wandName = script.GetFirstName(scrollSource);
            wandName.Replace("Scroll", "Wand");
            script.SetFirstName(wandItem, wandName);
            foreach (NWItemProperty prop in script.GetItemPropertiesOnItem(scrollSource))
            {
                if (script.GetItemPropertyType(prop) == ITEM_PROPERTY_CAST_SPELL)
                {
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyCastSpell(script.GetItemPropertySubType(prop), IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE), wandItem, 0.0f);
                }
                else if (script.GetItemPropertyType(prop) == ITEM_PROPERTY_USE_LIMITATION_CLASS)
                {
                    script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyLimitUseByClass(script.GetItemPropertySubType(prop)), wandItem, 0.0f);
                }
            }
            script.DestroyObject(scrollSource, 0.0f, FALSE);
            return wandValue;
        }
        public static int NewRod(CLRScriptBase script, int maxValue)
        {
            #region Check if collections need to be loaded. Load them if so
            if (FireSpells.Count == 0)
            {
                convertToRodPrice(GenerateStaff.FireSpells, FireSpells);
                convertToRodPrice(GenerateStaff.ColdSpells, ColdSpells);
                convertToRodPrice(GenerateStaff.AcidSpells, AcidSpells);
                convertToRodPrice(GenerateStaff.ElectricSpells, ElectricSpells);
                convertToRodPrice(GenerateStaff.SoundSpells, SoundSpells);
                convertToRodPrice(GenerateStaff.PhysicalAttackSpells, PhysicalAttackSpells);
                convertToRodPrice(GenerateStaff.ForceSpells, ForceSpells);
                convertToRodPrice(GenerateStaff.MoraleSpells, MoraleSpells);
                convertToRodPrice(GenerateStaff.AntimoraleSpells, AntimoraleSpells);
                convertToRodPrice(GenerateStaff.MindControlSpells, MindControlSpells);
                convertToRodPrice(GenerateStaff.PerceptionSpells, PerceptionSpells);
                convertToRodPrice(GenerateStaff.PhysicalSpells, PhysicalSpells);
                convertToRodPrice(GenerateStaff.MentalSpells, MentalSpells);
                convertToRodPrice(GenerateStaff.Transmutations, Transmutations);
                convertToRodPrice(GenerateStaff.AntiMagicSpells, AntiMagicSpells);
                convertToRodPrice(GenerateStaff.IllusionSpells, IllusionSpells);
                convertToRodPrice(GenerateStaff.DeathSpells, DeathSpells);
                convertToRodPrice(GenerateStaff.EvilSpells, EvilSpells);
                convertToRodPrice(GenerateStaff.GoodSpells, GoodSpells);
                convertToRodPrice(GenerateStaff.ProtectionSpells, ProtectionSpells);
                convertToRodPrice(GenerateStaff.HealingSpells, HealingSpells);
                convertToRodPrice(GenerateStaff.SummonSpells, SummonSpells);
            }
            #endregion

            Dictionary<int, int> currentAvailableSpells = new Dictionary<int,int>();
            List<string> possibleNames = new List<string>();
            #region Get Starting Collections
            switch (Generation.rand.Next(22))
            {
                case 0:
                    GenerateStaff.copyDictionary(FireSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.FireNames, possibleNames);
                    break;
                case 1:
                    GenerateStaff.copyDictionary(ColdSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.ColdNames, possibleNames);
                    break;
                case 2:
                    GenerateStaff.copyDictionary(AcidSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.AcidNames, possibleNames);
                    break;
                case 3:
                    GenerateStaff.copyDictionary(ElectricSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.ElectricNames, possibleNames);
                    break;
                case 4:
                    GenerateStaff.copyDictionary(SoundSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.SoundNames, possibleNames);
                    break;
                case 5:
                    GenerateStaff.copyDictionary(PhysicalAttackSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.PhysicalAttackNames, possibleNames);
                    break;
                case 6:
                    GenerateStaff.copyDictionary(ForceSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.ForceNames, possibleNames);
                    break;
                case 7: 
                    GenerateStaff.copyDictionary(MoraleSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.MoraleNames, possibleNames);
                    break;
                case 8:
                    GenerateStaff.copyDictionary(AntimoraleSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.AntimoraleNames, possibleNames);
                    break;
                case 9:
                    GenerateStaff.copyDictionary(MindControlSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.MindControlNames, possibleNames);
                    break;
                case 10:
                    GenerateStaff.copyDictionary(PerceptionSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.PerceptionNames, possibleNames);
                    break;
                case 11:
                    GenerateStaff.copyDictionary(PhysicalSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.PhysicalNames, possibleNames);
                    break;
                case 12:
                    GenerateStaff.copyDictionary(MentalSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.MentalNames, possibleNames);
                    break;
                case 13:
                    GenerateStaff.copyDictionary(Transmutations, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.TransmutNames, possibleNames);
                    break;
                case 14:
                    GenerateStaff.copyDictionary(AntiMagicSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.AntiMagicNames, possibleNames);
                    break;
                case 15:
                    GenerateStaff.copyDictionary(IllusionSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.IllusionNames, possibleNames);
                    break;
                case 16:
                    GenerateStaff.copyDictionary(DeathSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.DeathNames, possibleNames);
                    break;
                case 17:
                    GenerateStaff.copyDictionary(EvilSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.EvilNames, possibleNames);
                    break;
                case 18:
                    GenerateStaff.copyDictionary(GoodSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.GoodNames, possibleNames);
                    break;
                case 19:
                    GenerateStaff.copyDictionary(ProtectionSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.ProtectionNames, possibleNames);
                    break;
                case 20:
                    GenerateStaff.copyDictionary(HealingSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.HealingNames, possibleNames);
                    break;
                case 21:
                    GenerateStaff.copyDictionary(SummonSpells, currentAvailableSpells);
                    GenerateStaff.copyList(GenerateStaff.SummonNames, possibleNames);
                    break;
            }
            if (currentAvailableSpells.Count == 0 || possibleNames.Count == 0)
            {
                return 0;
            }
            #endregion

            #region Select Spells from Collections Based on Price
            Dictionary<int, int> SelectedSpells = new Dictionary<int, int>();
            List<int> SelectedPrices = new List<int>();
            int currentCharges = 5;
            int maxSpellValue = maxValue;
            while (true)
            {
                List<int> spellsToRemove = new List<int>();
                foreach (int spell in currentAvailableSpells.Keys)
                {
                    if (((currentAvailableSpells[spell] * 50) / currentCharges) > maxValue ||
                        currentAvailableSpells[spell] > maxSpellValue)
                    {
                        spellsToRemove.Add(spell);
                    }
                }
                foreach (int spell in spellsToRemove)
                {
                    currentAvailableSpells.Remove(spell);
                }
                if (currentAvailableSpells.Count == 0)
                {
                    if(SelectedSpells.Count == 0)
                    {
                        return 0;
                    }
                    else
                    {
                        break;
                    }
                }
                List<int> spellOptions = new List<int>();
                foreach (int key in currentAvailableSpells.Keys)
                {
                    spellOptions.Add(key);
                }
                int spellSelection = spellOptions[Generation.rand.Next(spellOptions.Count)];
                switch (currentCharges)
                {
                    case 1:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_1_CHARGE_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 50);
                        currentCharges--;
                        break;
                    case 2:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_2_CHARGES_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 25);
                        maxSpellValue = currentAvailableSpells[spellSelection] - 1;
                        maxValue -= currentAvailableSpells[spellSelection] * 25;
                        currentCharges--;
                        break;
                    case 3:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_3_CHARGES_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 16);
                        maxSpellValue = currentAvailableSpells[spellSelection] - 1;
                        maxValue -= currentAvailableSpells[spellSelection] * 16;
                        currentCharges--;
                        break;
                    case 4:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_4_CHARGES_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 12);
                        maxSpellValue = currentAvailableSpells[spellSelection] - 1;
                        maxValue -= currentAvailableSpells[spellSelection] * 12;
                        currentCharges--;
                        break;
                    case 5:
                        SelectedSpells.Add(spellSelection, IP_CONST_CASTSPELL_NUMUSES_5_CHARGES_PER_USE);
                        SelectedPrices.Add(currentAvailableSpells[spellSelection] * 10);
                        maxSpellValue = currentAvailableSpells[spellSelection] - 1;
                        maxValue -= currentAvailableSpells[spellSelection] * 10;
                        currentCharges--;
                        break;
                }
                if (currentCharges == 0)
                {
                    break;
                }
            }
            #endregion

            #region Sum Predicted Values of Properties
            SelectedPrices.Sort();
            int value = SelectedPrices[0];
            if (SelectedPrices.Count > 1)
            {
                value += (SelectedPrices[1] * 3 / 4);
            }
            if (SelectedPrices.Count > 2)
            {
                value += (SelectedPrices[2] / 2);
            }
            if (SelectedPrices.Count > 3)
            {
                value += (SelectedPrices[3] / 2);
            }
            if (SelectedPrices.Count > 4)
            {
                value += (SelectedPrices[4] / 2);
            }
            #endregion

            #region Build the Actual Staff
            uint staff = script.CreateItemOnObject(GenerateWeapon.WeaponResrefs[BASE_ITEM_LIGHTMACE], script.OBJECT_SELF, 1, "", FALSE);
            script.SetItemCharges(staff, 50);
            foreach (KeyValuePair<int, int> Spell in SelectedSpells)
            {
                script.AddItemProperty(DURATION_TYPE_PERMANENT, script.ItemPropertyCastSpell(Spell.Key, Spell.Value), staff, 0.0f);
            }
            script.SetFirstName(staff, String.Format(possibleNames[Generation.rand.Next(possibleNames.Count)], "Rod"));
            Pricing.CalculatePrice(script, staff);
            #endregion
            return value;
        }