Inheritance: BaseWand
Exemple #1
0
        public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface,
            List<XmlSpawner.SpawnPositionInfo> spawnpositioning, Mobile triggermob, Point3D location, Map map, XmlGumpCallback gumpcallback, out string status_str)
        {
            status_str = null;

            if (typeName == null || TheSpawn == null || substitutedtypeName == null)
                return false;

            XmlSpawner spawner = invoker as XmlSpawner;

            // check for any special keywords that might appear in the type such as SET, GIVE, or TAKE

            if (IsTypeKeyword(typeName))
            {
                typeKeyword kw = (typeKeyword)typeKeywordHash[typeName];

                switch (kw)
                {
                    case typeKeyword.SET:
                        {
                            // the syntax is SET/prop/value/prop2/value...
                            // check for the SET,itemname[,itemtype]/prop/value form is used
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            string[] keywordargs = ParseString(arglist[0], 3, ",");

                            if (keywordargs.Length > 1)
                            {
                                string typestr = null;
                                if (keywordargs.Length > 2)
                                {
                                    typestr = keywordargs[2];
                                }

                                // is the itemname a serialno?
                                object setitem = null;
                                if (keywordargs[1].StartsWith("0x"))
                                {
                                    int serial = -1;
                                    try
                                    {
                                        serial = Convert.ToInt32(keywordargs[1], 16);
                                    }
                                    catch
                                    {
                                    }
                                    if (serial >= 0)
                                        setitem = World.FindEntity(serial);
                                }
                                else
                                {
                                    // just look it up by name
                                    setitem = FindItemByName(spawner, keywordargs[1], typestr);
                                }

                                if (setitem == null)
                                {
                                    status_str = "cant find unique item :" + keywordargs[1];
                                    return false;
                                }
                                else
                                {
                                    ApplyObjectStringProperties(spawner, substitutedtypeName, setitem, triggermob, invoker, out status_str);
                                }
                            }
                            else if (spawner != null)
                            {
                                ApplyObjectStringProperties(spawner, substitutedtypeName, spawner.SetItem, triggermob, invoker, out status_str);
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETONMOB:
                        {
                            // the syntax is SETONMOB,mobname[,mobtype]/prop/value/prop2/value...
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            Mobile mob = null;
                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                if (keywordargs.Length > 1)
                                {
                                    string typestr = null;
                                    if (keywordargs.Length > 2)
                                    {
                                        typestr = keywordargs[2];
                                    }

                                    mob = FindMobileByName(spawner, keywordargs[1], typestr);

                                    if (mob == null)
                                    {
                                        status_str = String.Format("named mob '{0}' not found", keywordargs[1]);
                                    }
                                }
                                else
                                {
                                    status_str = "missing mob name in SETONMOB";
                                }
                            }
                            if (mob != null)
                            {
                                ApplyObjectStringProperties(spawner, substitutedtypeName, mob, triggermob, invoker, out status_str);
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETONTHIS:
                        {
                            // the syntax is SETONTHIS/prop/value/prop2/value...
                            //string [] arglist = ParseString(substitutedtypeName,3,"/");
                            if (invoker != null)
                            {
                                ApplyObjectStringProperties(spawner, substitutedtypeName, invoker, triggermob, invoker, out status_str);
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETONTRIGMOB:
                        {
                            // the syntax is SETONTRIGMOB/prop/value/prop2/value...
                            ApplyObjectStringProperties(spawner, substitutedtypeName, triggermob, triggermob, invoker, out status_str);
                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETACCOUNTTAG:
                        {
                            // the syntax is SETACCOUNTTAG,tagname/value
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 2);

                            if (arglist.Length > 1)
                            {
                                string[] objstr = ParseString(arglist[0], 2, ",");

                                if (objstr.Length < 2)
                                {
                                    status_str = "missing tagname in SETACCOUNTTAG";
                                    return false;
                                }

                                string tagname = objstr[1];
                                string tagval = arglist[1];

                                // set the tag value
                                // get the value of the account tag from the triggering mob
                                if (triggermob != null && !triggermob.Deleted)
                                {
                                    Account acct = triggermob.Account as Account;
                                    if (acct != null)
                                    {
                                        acct.SetTag(tagname, tagval);
                                    }
                                }
                            }
                            else
                            {
                                status_str = "no value assigned to SETACCOUNTTAG";
                                return false;
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETVAR:
                        {
                            // the syntax is SETVAR,varname/value
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 2);

                            if (arglist.Length > 1)
                            {
                                string[] objstr = ParseString(arglist[0], 2, ",");

                                if (objstr.Length < 2)
                                {
                                    status_str = "missing varname in SETVAR";
                                    return false;
                                }

                                string varname = objstr[1];
                                string varval = arglist[1];

                                // find the xmllocalvariable attachment with that name
                                XmlLocalVariable a = (XmlLocalVariable)XmlAttach.FindAttachment(invoker, typeof(XmlLocalVariable), varname);

                                if (a == null)
                                {
                                    // doesnt already exist so add it
                                    XmlAttach.AttachTo(invoker, new XmlLocalVariable(varname, varval));
                                }
                                else
                                {
                                    a.Data = varval;
                                }
                            }
                            else
                            {
                                status_str = "no value assigned to SETVAR";
                                return false;
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETONNEARBY:
                        {
                            // the syntax is SETONNEARBY,range,name[,type][,searchcontainers][,proptest]/prop/value/prop/value...
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            string typestr = null;
                            string targetname = null;
                            string proptest = null;
                            int range = -1;
                            bool searchcontainers = false;

                            if (arglist.Length > 0)
                            {
                                string[] objstr = ParseString(arglist[0], 6, ",");
                                if (objstr.Length < 3)
                                {
                                    status_str = "missing range or name in SETONNEARBY";
                                    return false;
                                }

                                try
                                {
                                    range = int.Parse(objstr[1]);
                                }
                                catch
                                {
                                }

                                if (range < 0)
                                {
                                    status_str = "invalid range in SETONNEARBY";
                                    return false;
                                }

                                targetname = objstr[2];

                                if (objstr.Length > 3)
                                {
                                    typestr = objstr[3];
                                }

                                if (objstr.Length > 4)
                                {
                                    try
                                    {
                                        searchcontainers = bool.Parse(objstr[4]);
                                    }
                                    catch
                                    {
                                    }
                                }

                                if (objstr.Length > 5)
                                {
                                    proptest = objstr[5];
                                }
                            }
                            else
                            {
                                status_str = "missing args to SETONNEARBY";
                                return false;
                            }

                            Type targettype = null;
                            if (typestr != null)
                            {
                                targettype = SpawnerType.GetType(typestr);
                            }
                            ArrayList nearbylist = GetNearbyObjects(invoker, targetname, targettype, typestr, range, searchcontainers, proptest);

                            // apply the properties to everything on the list
                            foreach (object nearbyobj in nearbylist)
                            {
                                ApplyObjectStringProperties(spawner, substitutedtypeName, nearbyobj, triggermob, invoker, out status_str);
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETONPETS:
                        {
                            // the syntax is SETONPETS,range/prop/value/prop/value...
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            string typestr = "BaseCreature";
                            string targetname = null;
                            int range = -1;
                            bool searchcontainers = false;

                            if (arglist.Length > 0)
                            {
                                string[] objstr = ParseString(arglist[0], 2, ",");
                                if (objstr.Length < 2)
                                {
                                    status_str = "missing range or name in SETONPETS";
                                    return false;
                                }

                                try
                                {
                                    range = int.Parse(objstr[1]);
                                }
                                catch
                                {
                                }

                                if (range < 0)
                                {
                                    status_str = "invalid range in SETONPETS";
                                    return false;
                                }
                            }
                            else
                            {
                                status_str = "missing args to SETONPETS";
                                return false;
                            }

                            Type targettype = null;

                            if (typestr != null)
                            {
                                targettype = SpawnerType.GetType(typestr);
                            }

                            // get all of the nearby pets
                            ArrayList nearbylist = GetNearbyObjects(triggermob, targetname, targettype, typestr, range, searchcontainers, null);

                            // apply the properties to everything on the list
                            foreach (object nearbyobj in nearbylist)
                            {
                                // is this a pet of the triggering mob
                                BaseCreature pet = nearbyobj as BaseCreature;

                                if (pet != null && pet.Controlled && pet.ControlMaster == triggermob)
                                {
                                    ApplyObjectStringProperties(spawner, substitutedtypeName, nearbyobj, triggermob, invoker, out status_str);
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }

                    case typeKeyword.SETONCARRIED:
                        {
                            // the syntax is SETONCARRIED,itemname[,itemtype][,equippedonly]/prop/value/prop2/value...
                            // or SETONCARRIED,itemname[,itemtype]/prop/value
                            // first find the carried item
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            string typestr = null;
                            string itemname = null;
                            bool equippedonly = false;

                            if (arglist.Length > 0)
                            {
                                string[] objstr = ParseString(arglist[0], 4, ",");
                                if (objstr.Length < 2)
                                {
                                    status_str = "missing itemname in SETONCARRIED";
                                    return false;
                                }

                                itemname = objstr[1];

                                if (objstr.Length > 2)
                                {
                                    typestr = objstr[2];
                                }

                                if (objstr.Length > 3)
                                {
                                    if (objstr[3].ToLower() == "equippedonly")
                                    {
                                        equippedonly = true;
                                    }
                                    else
                                    {
                                        try
                                        {
                                            equippedonly = bool.Parse(objstr[3]);
                                        }
                                        catch
                                        {
                                        }
                                    }
                                }
                            }
                            else
                            {
                                status_str = "missing args to SETONCARRIED";
                                return false;
                            }

                            Item testitem = SearchMobileForItem(triggermob, ParseObjectType(itemname), typestr, false, equippedonly);

                            ApplyObjectStringProperties(spawner, substitutedtypeName, testitem, triggermob, invoker, out status_str);

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETONSPAWN:
                        {
                            // the syntax is SETONSPAWN[,spawnername],subgroup/prop/value/prop2/value...
                            // or SETONSPAWN[,spawnername],subgroup/prop/value
                            // first find the spawn
                            int subgroup = -1;
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            XmlSpawner targetspawner = spawner;
                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                if (keywordargs.Length < 2)
                                {
                                    status_str = "missing subgroup in SETONSPAWN";
                                    return false;
                                }
                                else
                                {
                                    string subgroupstr = keywordargs[1];
                                    string spawnerstr = null;
                                    if (keywordargs.Length > 2)
                                    {
                                        spawnerstr = keywordargs[1];
                                        subgroupstr = keywordargs[2];
                                    }
                                    if (spawnerstr != null)
                                    {
                                        targetspawner = FindSpawnerByName(spawner, spawnerstr);
                                    }
                                    try
                                    {
                                        subgroup = int.Parse(subgroupstr);
                                    }
                                    catch
                                    {
                                    }
                                }
                            }
                            if (subgroup == -1)
                            {
                                status_str = "invalid subgroup in SETONSPAWN";
                                return false;
                            }

                            ArrayList spawnedlist = XmlSpawner.GetSpawnedList(targetspawner, subgroup);
                            if (spawnedlist == null)
                                return true;
                            foreach (object targetobj in spawnedlist)
                            {
                                if (targetobj == null)
                                    return true;

                                // dont apply it to keyword tags
                                if (targetobj is KeywordTag)
                                    continue;

                                // set the properties on the target object
                                ApplyObjectStringProperties(spawner, substitutedtypeName, targetobj, triggermob, spawner, out status_str);
                            }
                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETONSPAWNENTRY:
                        {
                            // the syntax is SETONSPAWNENTRY[,spawnername],entrystring/prop/value/prop2/value...
                            // find the spawn entry
                            string entrystring = null;
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            XmlSpawner targetspawner = spawner;

                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                if (keywordargs.Length < 2)
                                {
                                    status_str = "missing entrystring in SETONSPAWNENTRY";
                                    return false;
                                }
                                else
                                {
                                    entrystring = keywordargs[1];
                                    string spawnerstr = null;
                                    if (keywordargs.Length > 2)
                                    {
                                        spawnerstr = keywordargs[1];
                                        entrystring = keywordargs[2];
                                    }
                                    if (spawnerstr != null)
                                    {
                                        targetspawner = FindSpawnerByName(spawner, spawnerstr);
                                    }
                                }
                            }
                            if (entrystring == null || entrystring.Length == 0)
                            {
                                status_str = "invalid entrystring in SETONSPAWNENTRY";
                                return false;
                            }

                            int entryindex = -1;
                            // is the entrystring a number?
                            if (entrystring[0] >= '0' && entrystring[0] <= '9')
                            {
                                try
                                {
                                    entryindex = int.Parse(entrystring);
                                }
                                catch
                                {
                                }
                            }

                            if (targetspawner == null || targetspawner.SpawnObjects == null)
                                return true;

                            for (int i = 0; i < targetspawner.SpawnObjects.Length; i++)
                            {
                                XmlSpawner.SpawnObject targetobj = targetspawner.SpawnObjects[i];

                                // is this references by entrystring or entryindex?
                                if ((entryindex == i) ||
                                    (entryindex == -1 && targetobj != null && targetobj.TypeName != null && targetobj.TypeName.IndexOf(entrystring) >= 0))
                                {
                                    // set the properties on the spawn entry object
                                    ApplyObjectStringProperties(spawner, substitutedtypeName, targetobj, triggermob, spawner, out status_str);
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SETONPARENT:
                        {
                            // the syntax is SETONPARENT/prop/value/prop2/value...
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);

                            if (invoker != null && (invoker is Item))
                            {
                                ApplyObjectStringProperties(spawner, substitutedtypeName, ((Item)invoker).Parent, triggermob, invoker, out status_str);
                            }
                            else if (invoker != null && (invoker is XmlAttachment))
                            {
                                ApplyObjectStringProperties(spawner, substitutedtypeName, ((XmlAttachment)invoker).Attached, triggermob, invoker, out status_str);
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.GIVE:
                        {
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);

                            string remainder;
                            if (arglist.Length > 1)
                            {
                                // check for any special keywords such as the additem option or the subproperty specification
                                // note this will be an arg to some property
                                string[] keywordargs = ParseString(arglist[0], 2, ",");
                                AddItemToTarget(spawner, triggermob, keywordargs, arglist, triggermob, invoker, false, out remainder, out status_str);
                            }
                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.TAKE:
                        {
                            // syntax TAKE[,prob[,quantity[,true,[type]]]]/itemname
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            string targetName;
                            string typestr = null;
                            if (arglist.Length > 1)
                            {
                                targetName = arglist[1];
                            }
                            else
                            {
                                status_str = "invalid TAKE specification";
                                return false;
                            }
                            string[] keywordargs = ParseString(arglist[0], 5, ",");
                            double drop_probability = 1;
                            int quantity = 0;
                            bool banksearch = false;
                            Item savedItem = null;
                            if (keywordargs.Length > 1)
                            {
                                bool converterror = false;
                                try
                                {
                                    drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture);
                                }
                                catch
                                {
                                    status_str = "Invalid TAKE probability : " + arglist[1];
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                            }
                            if (keywordargs.Length > 2)
                            {
                                bool converterror = false;
                                try
                                {
                                    quantity = int.Parse(keywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid TAKE quantity : " + arglist[1];
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                            }
                            if (keywordargs.Length > 3)
                            {
                                bool converterror = false;
                                try
                                {
                                    banksearch = bool.Parse(keywordargs[3]);
                                }
                                catch
                                {
                                    status_str = "Invalid TAKE bankflag : " + arglist[1];
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                            }
                            if (keywordargs.Length > 4)
                            {
                                typestr = keywordargs[4];
                            }
                            if (drop_probability == 1 || Utility.RandomDouble() < drop_probability)
                            {
                                // search the trigger mob for the named item
                                Item itemTarget = SearchMobileForItem(triggermob, targetName, typestr, banksearch);

                                // found the item so get rid of it
                                if (itemTarget != null)
                                {
                                    // if a quantity was specified and the item is stackable, then try to take the quantity
                                    if (quantity > 0 && itemTarget.Stackable)
                                    {
                                        // create a copy of the stacked item to be saved
                                        //savedItem = itemTarget.Dupe(0);
                                        savedItem = Mobile.LiftItemDupe(itemTarget, itemTarget.Amount);
                                        if (savedItem != null)
                                        {
                                            savedItem.Internalize();
                                        }

                                        int totaltaken = 0;

                                        int remaining = itemTarget.Amount - quantity;
                                        if (remaining <= 0)
                                        {
                                            int taken = itemTarget.Amount;
                                            totaltaken += taken;

                                            itemTarget.Delete();
                                            while (remaining < 0)
                                            {
                                                quantity -= taken;
                                                // if didnt get the full amount then keep looking for other stacks
                                                itemTarget = SearchMobileForItem(triggermob, targetName, typestr, banksearch);
                                                if (itemTarget == null)
                                                    break;

                                                remaining = itemTarget.Amount - quantity;

                                                if (remaining <= 0)
                                                {
                                                    taken = itemTarget.Amount;
                                                    totaltaken += taken;

                                                    itemTarget.Delete();
                                                }
                                                else
                                                {
                                                    totaltaken += quantity;
                                                    itemTarget.Amount = remaining;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            totaltaken = quantity;
                                            itemTarget.Amount = remaining;
                                        }

                                        if (savedItem != null)
                                        {
                                            savedItem.Amount = totaltaken;
                                        }
                                    }
                                    else
                                    {
                                        // dont save quest holders
                                        if (itemTarget is XmlQuestBook || itemTarget is IXmlQuest)
                                        {
                                            itemTarget.Delete();
                                        }
                                        else
                                            savedItem = itemTarget;
                                    }

                                    // if the saved item was being held then release it otherwise the player can take it back
                                    if (triggermob != null && triggermob.Holding == savedItem)
                                    {
                                        triggermob.Holding = null;
                                    }

                                    XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(invoker, typeof(XmlSaveItem), "Taken");

                                    if (si == null)
                                    {
                                        XmlAttach.AttachTo(invoker, new XmlSaveItem("Taken", savedItem, triggermob));
                                    }
                                    else
                                    {
                                        si.SavedItem = savedItem;
                                        si.WasOwnedBy = triggermob;
                                    }
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.TAKEBYTYPE:
                        {
                            // syntax TAKEBYTYPE[,prob[,quantity[,true]]]/itemtype
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            string targetName;
                            if (arglist.Length > 1)
                            {
                                targetName = arglist[1];
                            }
                            else
                            {
                                status_str = "invalid TAKEBYTYPE specification";
                                return false;
                            }
                            string[] keywordargs = ParseString(arglist[0], 4, ",");
                            double drop_probability = 1;
                            int quantity = 0;
                            bool banksearch = false;
                            Item savedItem = null;

                            if (keywordargs.Length > 1)
                            {
                                bool converterror = false;
                                try
                                {
                                    drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture);
                                }
                                catch
                                {
                                    status_str = "Invalid TAKEBYTYPE probability : " + arglist[1];
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                            }
                            if (keywordargs.Length > 2)
                            {
                                bool converterror = false;
                                try
                                {
                                    quantity = int.Parse(keywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid TAKEBYTYPE quantity : " + arglist[1];
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                            }
                            if (keywordargs.Length > 3)
                            {
                                bool converterror = false;
                                try
                                {
                                    banksearch = bool.Parse(keywordargs[3]);
                                }
                                catch
                                {
                                    status_str = "Invalid TAKEBYTYPE bankflag : " + arglist[1];
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                            }
                            if (drop_probability == 1 || Utility.RandomDouble() < drop_probability)
                            {
                                // search the trigger mob for the named item
                                Item itemTarget = SearchMobileForItemType(triggermob, targetName, banksearch);

                                // found the item so get rid of it
                                if (itemTarget != null)
                                {
                                    // if a quantity was specified and the item is stackable, then try to take the quantity
                                    if (quantity > 0 && itemTarget.Stackable)
                                    {
                                        // create a copy of the stacked item to be saved
                                        //savedItem = itemTarget.Dupe(0);
                                        savedItem = Mobile.LiftItemDupe(itemTarget, itemTarget.Amount);
                                        if (savedItem != null)
                                        {
                                            savedItem.Internalize();
                                        }

                                        int totaltaken = 0;

                                        int remaining = itemTarget.Amount - quantity;
                                        if (remaining <= 0)
                                        {
                                            int taken = itemTarget.Amount;
                                            totaltaken += taken;

                                            itemTarget.Delete();

                                            while (remaining < 0)
                                            {
                                                quantity -= taken;
                                                // if didnt get the full amount then keep looking for other stacks
                                                itemTarget = SearchMobileForItemType(triggermob, targetName, banksearch);

                                                if (itemTarget == null)
                                                    break;

                                                remaining = itemTarget.Amount - quantity;
                                                if (remaining <= 0)
                                                {
                                                    taken = itemTarget.Amount;
                                                    totaltaken += taken;

                                                    itemTarget.Delete();
                                                }
                                                else
                                                {
                                                    totaltaken += quantity;
                                                    itemTarget.Amount = remaining;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            totaltaken = quantity;
                                            itemTarget.Amount = remaining;
                                        }

                                        if (savedItem != null)
                                        {
                                            savedItem.Amount = totaltaken;
                                        }
                                    }
                                    else
                                    {
                                        // dont save quest holders
                                        if (itemTarget is XmlQuestBook || itemTarget is XmlQuestHolder || itemTarget is XmlQuestToken)
                                        {
                                            itemTarget.Delete();
                                        }
                                        else
                                            savedItem = itemTarget;
                                    }
                                }

                                // is there an existing xmlsaveitem attachment

                                XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(invoker, typeof(XmlSaveItem), "Taken");

                                if (si == null)
                                {
                                    XmlAttach.AttachTo(invoker, new XmlSaveItem("Taken", savedItem, triggermob));
                                }
                                else
                                {
                                    si.SavedItem = savedItem;
                                    si.WasOwnedBy = triggermob;
                                }
                            }
                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.GUMP:
                        {
                            // the syntax is GUMP,title,type/string
                            // can alternatively accept a gump constructor name
                            // GUMP,title,type,constructorname/string
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            string gumpText;
                            if (arglist.Length > 1)
                            {
                                gumpText = arglist[1];
                            }
                            else
                            {
                                status_str = "invalid GUMP specification";
                                return false;
                            }

                            string[] gumpkeywordargs = ParseString(arglist[0], 4, ",");
                            string gumpTitle = "";
                            int gumpNumber = 0; // 0=simple text gump, 1=yes/no gump, 2=reply gump, 3=quest gump

                            if (gumpkeywordargs.Length > 2)
                            {
                                gumpTitle = gumpkeywordargs[1];
                                bool converterror = false;
                                try
                                {
                                    gumpNumber = int.Parse(gumpkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid GUMP args";
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                            }
                            else
                            {
                                status_str = "invalid GUMP specification";
                                return false;
                            }
                            string gumptypestr = "XmlSimpleGump"; // default gump constructor

                            if (gumpkeywordargs.Length > 3)
                            {
                                // get the gump constructor type
                                gumptypestr = gumpkeywordargs[3].Trim();
                            }
                            Type type = null;
                            if (gumptypestr != null)
                            {
                                try
                                {
                                    type = SpawnerType.GetType(gumptypestr);
                                }
                                catch
                                {
                                }
                            }
                            if (type == null)
                            {
                                status_str = "invalid GUMP constructor : " + gumptypestr;
                                return false;
                            }

                            // prepare the keyword tag for the gump
                            KeywordTag newtag = new KeywordTag(substitutedtypeName, spawner, 1);
                            if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile))
                            {
                                object newgump = null;
                                object[] gumpargs = new object[7];
                                gumpargs[0] = invoker;
                                gumpargs[1] = gumpText;
                                gumpargs[2] = gumpTitle;
                                gumpargs[3] = gumpNumber;
                                gumpargs[4] = newtag;
                                gumpargs[5] = triggermob;
                                gumpargs[6] = gumpcallback;

                                //spawner.TriggerMob.SendGump( new XmlSimpleGump(this, gumpText,gumpTitle, gumpType ));
                                try
                                {
                                    newgump = Activator.CreateInstance(type, gumpargs);
                                }
                                catch
                                {
                                    status_str = "Error in creating gump type : " + gumptypestr;
                                    newtag.Delete();
                                    return false;
                                }
                                if (newgump != null)
                                {
                                    if (newgump is Gump)
                                    {
                                        triggermob.SendGump((Gump)newgump);
                                    }
                                    else if (newgump is Item)
                                    {
                                        ((Item)newgump).Delete();
                                        status_str = gumptypestr + " is not a Gump type";
                                        newtag.Delete();
                                        return false;
                                    }
                                    else if (newgump is Mobile)
                                    {
                                        ((Mobile)newgump).Delete();
                                        status_str = gumptypestr + " is not a Gump type";
                                        newtag.Delete();
                                        return false;
                                    }
                                    else
                                    {
                                        status_str = gumptypestr + " is not a Gump type";
                                        newtag.Delete();
                                        return false;
                                    }
                                }
                            }
                            TheSpawn.SpawnedObjects.Add(newtag);

                            break;
                        }
                    case typeKeyword.BROWSER:
                        {
                            // the syntax is BROWSER/url
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 2);
                            string url;

                            if (arglist.Length > 1)
                            {
                                if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@')
                                {
                                    url = arglist[1].Substring(1);
                                }
                                else
                                    url = arglist[1];
                            }
                            else
                            {
                                status_str = "invalid BROWSER specification";
                                return false;
                            }

                            if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile))
                            {
                                triggermob.LaunchBrowser(url);
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SENDMSG:
                        {
                            // the syntax is SENDMSG[,hue]/string
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            // check for literal
                            string msgText;
                            int hue = 0x3B2;
                            int font = 3;

                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 2, ",");
                                if (keywordargs.Length > 1)
                                {
                                    try
                                    {
                                        hue = int.Parse(keywordargs[1]);
                                    }
                                    catch
                                    {
                                        status_str = "invalid hue arg to SENDMSG";
                                    }
                                }
                            }
                            if (arglist.Length > 1)
                            {
                                if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@')
                                {
                                    arglist = ParseSlashArgs(substitutedtypeName, 2);
                                    msgText = arglist[1].Substring(1);
                                }
                                else
                                    msgText = arglist[1];
                            }
                            else
                            {
                                status_str = "invalid SENDMSG specification";
                                return false;
                            }
                            if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile))
                            {
                                //triggermob.SendMessage(msgText);
                                triggermob.Send(new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "ENU", "System", msgText));
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SENDASCIIMSG:
                        {
                            // the syntax is SENDASCIIMSG[,hue][,font#]/string
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            // check for literal
                            string msgText;
                            int hue = 0x3B2;
                            int font = 3;

                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                if (keywordargs.Length > 1)
                                {
                                    try
                                    {
                                        hue = int.Parse(keywordargs[1]);
                                    }
                                    catch
                                    {
                                        status_str = "invalid hue arg to SENDASCIIMSG";
                                    }
                                }
                                if (keywordargs.Length > 2)
                                {
                                    try
                                    {
                                        font = int.Parse(keywordargs[2]);
                                    }
                                    catch
                                    {
                                        status_str = "invalid font arg to SENDASCIIMSG";
                                    }
                                }
                            }
                            if (arglist.Length > 1)
                            {
                                if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@')
                                {
                                    arglist = ParseSlashArgs(substitutedtypeName, 2);
                                    msgText = arglist[1].Substring(1);
                                }
                                else
                                    msgText = arglist[1];
                            }
                            else
                            {
                                status_str = "invalid SENDASCIIMSG specification";
                                return false;
                            }
                            if (triggermob != null && !triggermob.Deleted && (triggermob is PlayerMobile))
                            {
                                triggermob.Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", msgText));
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.WAITUNTIL:
                        {
                            // the syntax is WAITUNTIL[,delay][,timeout][/condition][/thendogroup]
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 4);
                            double delay = 0;
                            double timeout = 0;
                            string condition = null;
                            int gotogroup = -1;
                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                if (keywordargs.Length > 1)
                                {
                                    try
                                    {
                                        delay = double.Parse(keywordargs[1]);
                                    }
                                    catch
                                    {
                                        status_str = "invalid delay arg to WAITUNTIL";
                                    }
                                }
                                if (keywordargs.Length > 2)
                                {
                                    try
                                    {
                                        timeout = double.Parse(keywordargs[2]);
                                    }
                                    catch
                                    {
                                        status_str = "invalid timeout arg to WAITUNTIL";
                                    }
                                }
                            }
                            if (arglist.Length > 1)
                            {
                                condition = arglist[1];
                            }
                            if (arglist.Length > 2)
                            {
                                try
                                {
                                    gotogroup = int.Parse(arglist[2]);
                                }
                                catch
                                {
                                    status_str = "invalid goto arg to WAITUNTIL";
                                }
                            }
                            if (status_str != null)
                            {
                                return false;
                            }
                            // suppress sequential advancement
                            //spawner.HoldSequence = true;

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner, TimeSpan.FromMinutes(delay), TimeSpan.FromMinutes(timeout), condition, gotogroup));

                            break;
                        }
                    case typeKeyword.WHILE:
                        {
                            // the syntax is WHILE/condition/dogroup
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 4);
                            string condition = null;
                            int gotogroup = -1;
                            if (arglist.Length < 3)
                            {
                                status_str = "insufficient args to WHILE";
                            }
                            else
                            {
                                condition = arglist[1];
                                try
                                {
                                    gotogroup = int.Parse(arglist[2]);
                                }
                                catch
                                {
                                    status_str = "invalid dogroup arg to WHILE";
                                }
                            }
                            if (status_str != null)
                            {
                                return false;
                            }
                            // test the condition
                            if (TestItemProperty(spawner, spawner, condition, triggermob, out status_str))
                            {
                                // try to spawn the dogroup
                                if (spawner != null && !spawner.Deleted)
                                {
                                    if (gotogroup >= 0)
                                    {
                                        // spawn the subgroup
                                        spawner.SpawnSubGroup(gotogroup);
                                        // advance the sequence to that group
                                        //spawner.SequentialSpawn = gotogroup;
                                    }
                                    // and suppress sequential advancement
                                    spawner.HoldSequence = true;
                                }
                            }
                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.IF:
                        {
                            // the syntax is IF/condition/thengroup [/elsegroup]
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 5);
                            string condition = null;
                            int thengroup = -1;
                            int elsegroup = -1;
                            if (arglist.Length < 3)
                            {
                                status_str = "insufficient args to IF";
                            }
                            else
                            {
                                condition = arglist[1];
                                try
                                {
                                    thengroup = int.Parse(arglist[2]);
                                }
                                catch
                                {
                                    status_str = "invalid thengroup arg to IF";
                                }
                            }
                            if (arglist.Length > 3)
                            {
                                try
                                {
                                    elsegroup = int.Parse(arglist[3]);
                                }
                                catch
                                {
                                    status_str = "invalid elsegroup arg to IF";
                                }
                            }

                            if (status_str != null)
                            {
                                return false;
                            }

                            // test the condition
                            if (TestItemProperty(spawner, spawner, condition, triggermob, out status_str))
                            {
                                // try to spawn the thengroup
                                if (thengroup >= 0 && spawner != null && !spawner.Deleted)
                                {
                                    // spawn the subgroup
                                    spawner.SpawnSubGroup(thengroup);
                                    // advance the sequence to that group
                                    //spawner.SequentialSpawn = thengroup;
                                }
                                // and suppress sequential advancement
                                //spawner.HoldSequence = true;
                            }
                            else
                            {
                                // try to spawn the elsegroup
                                if (elsegroup >= 0 && spawner != null && !spawner.Deleted)
                                {
                                    // spawn the subgroup
                                    spawner.SpawnSubGroup(elsegroup);
                                    // advance the sequence to that group
                                    //spawner.SequentialSpawn = elsegroup;
                                }
                                // and suppress sequential advancement
                                //spawner.HoldSequence = true;
                            }
                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.DESPAWN:
                        {
                            // the syntax is DESPAWN[,spawnername],subgroup
                            // first find the spawner and group
                            int subgroup = -1;
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            XmlSpawner targetspawner = spawner;
                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                if (keywordargs.Length < 2)
                                {
                                    status_str = "missing subgroup in DESPAWN";
                                    return false;
                                }
                                else
                                {
                                    string subgroupstr = keywordargs[1];
                                    string spawnerstr = null;
                                    if (keywordargs.Length > 2)
                                    {
                                        spawnerstr = keywordargs[1];
                                        subgroupstr = keywordargs[2];
                                    }
                                    if (spawnerstr != null)
                                    {
                                        targetspawner = FindSpawnerByName(spawner, spawnerstr);
                                    }
                                    try
                                    {
                                        subgroup = int.Parse(subgroupstr);
                                    }
                                    catch
                                    {
                                    }
                                }
                            }
                            if (subgroup == -1)
                            {
                                status_str = "invalid subgroup in DESPAWN";
                                return false;
                            }

                            if (targetspawner != null)
                            {
                                targetspawner.ClearSubgroup(subgroup);
                            }
                            else
                            {
                                status_str = "invalid spawner in DESPAWN";
                                return false;
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SPAWN:
                        {
                            // the syntax is SPAWN[,spawnername],subgroup
                            // first find the spawner and group
                            int subgroup = -1;
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            XmlSpawner targetspawner = spawner;
                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                if (keywordargs.Length < 2)
                                {
                                    status_str = "missing subgroup in SPAWN";
                                    return false;
                                }
                                else
                                {
                                    string subgroupstr = keywordargs[1];
                                    string spawnerstr = null;
                                    if (keywordargs.Length > 2)
                                    {
                                        spawnerstr = keywordargs[1];
                                        subgroupstr = keywordargs[2];
                                    }
                                    if (spawnerstr != null)
                                    {
                                        targetspawner = FindSpawnerByName(spawner, spawnerstr);
                                    }
                                    try
                                    {
                                        subgroup = int.Parse(subgroupstr);
                                    }
                                    catch
                                    {
                                    }
                                }
                            }
                            if (subgroup == -1)
                            {
                                status_str = "invalid subgroup in SPAWN";
                                return false;
                            }

                            if (targetspawner != null)
                            {
                                if (spawner != targetspawner)
                                {
                                    // allow spawning of other spawners to be forced and ignore the normal loop protection
                                    targetspawner.SpawnSubGroup(subgroup, false, true);
                                }
                                else
                                {
                                    targetspawner.SpawnSubGroup(subgroup);
                                }
                            }
                            else
                            {
                                status_str = "invalid spawner in SPAWN";
                                return false;
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.GOTO:
                        {
                            // the syntax is GOTO/subgroup
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            int group = -1;
                            if (arglist.Length < 2)
                            {
                                status_str = "insufficient args to GOTO";
                            }
                            else
                            {
                                try
                                {
                                    group = int.Parse(arglist[1]);
                                }
                                catch
                                {
                                    status_str = "invalid subgroup arg to GOTO";
                                }
                            }
                            if (status_str != null)
                            {
                                return false;
                            }

                            // move the sequence to the specified subgroup
                            if (group >= 0 && spawner != null && !spawner.Deleted)
                            {
                                // note, this will activate sequential spawning if it wasnt already set
                                spawner.SequentialSpawn = group;

                                // and suppress sequential advancement so that the specified group is the next to spawn
                                spawner.HoldSequence = true;
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner, 2));

                            break;
                        }
                    case typeKeyword.COMMAND:
                        {
                            // the syntax is COMMAND/commandstring
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            if (arglist.Length > 0)
                            {
                                // mod to use a dummy char to issue commands
                                if (CommandMobileName != null)
                                {
                                    Mobile dummy = FindMobileByName(spawner, CommandMobileName, "Mobile");
                                    if (dummy != null)
                                    {
                                        CommandSystem.Handle(dummy, String.Format("{0}{1}", CommandSystem.Prefix, arglist[1]));
                                    }
                                }
                                else if (triggermob != null && !triggermob.Deleted)
                                {
                                    CommandSystem.Handle(triggermob, String.Format("{0}{1}", CommandSystem.Prefix, arglist[1]));
                                }
                            }
                            else
                            {
                                status_str = "insufficient args to COMMAND";
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.MUSIC:
                        {
                            // the syntax is MUSIC,name,range
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            if (arglist.Length > 0)
                            {
                                SendMusicToPlayers(arglist[0], triggermob, invoker, out status_str);
                                if (status_str != null)
                                {
                                    return false;
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.SOUND:
                        {
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);

                            if (arglist.Length > 0)
                            {
                                // Syntax is SOUND,soundnumber
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                int sound = -1;
                                // try to get the soundnumber argument
                                if (keywordargs.Length < 2)
                                {
                                    status_str = "Missing sound number";
                                }
                                else
                                {
                                    try
                                    {
                                        sound = int.Parse(keywordargs[1]);
                                    }
                                    catch
                                    {
                                        status_str = "Improper sound number format";
                                    }
                                }
                                if (sound >= 0 && invoker is IEntity)
                                {
                                    Effects.PlaySound(((IEntity)invoker).Location, ((IEntity)invoker).Map, sound);
                                }
                                if (status_str != null)
                                {
                                    return false;
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                        //
                        //  MEFFECT keyword
                        //
                    case typeKeyword.MEFFECT:
                        {
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 9, ",");

                                if (keywordargs.Length < 9)
                                {
                                    status_str = "Missing args";
                                }
                                else
                                {
                                    int effect = -1;
                                    int duration = 0;
                                    int speed = 1;
                                    Point3D eloc1 = new Point3D(0, 0, 0);
                                    Point3D eloc2 = new Point3D(0, 0, 0);
                                    Map emap = Map.Internal;

                                    // syntax is MEFFECT,itemid,speed,x,y,z,x2,y2,z2

                                    // try to get the effect argument

                                    try
                                    {
                                        effect = int.Parse(keywordargs[1]);
                                    }
                                    catch
                                    {
                                        status_str = "Improper effect number format";
                                    }

                                    try
                                    {
                                        speed = int.Parse(keywordargs[2]);
                                    }
                                    catch
                                    {
                                        status_str = "Improper effect speed format";
                                    }

                                    int x = 0;
                                    int y = 0;
                                    int z = 0;
                                    try
                                    {
                                        x = int.Parse(keywordargs[3]);
                                        y = int.Parse(keywordargs[4]);
                                        z = int.Parse(keywordargs[5]);
                                    }
                                    catch
                                    {
                                        status_str = "Improper effect location format";
                                    }
                                    eloc1 = new Point3D(x, y, z);

                                    try
                                    {
                                        x = int.Parse(keywordargs[6]);
                                        y = int.Parse(keywordargs[7]);
                                        z = int.Parse(keywordargs[8]);
                                    }
                                    catch
                                    {
                                        status_str = "Improper effect location format";
                                    }
                                    eloc2 = new Point3D(x, y, z);

                                    if (effect >= 0 && emap != Map.Internal)
                                    {
                                        Effects.SendPacket(eloc1, emap, new HuedEffect(EffectType.Moving, -1, -1, effect, eloc1, eloc2, speed, duration, false, false, 0, 0));
                                    }
                                }
                                if (status_str != null)
                                {
                                    return false;
                                }
                            }
                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
                            break;
                        }
                    case typeKeyword.EFFECT:
                        {
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            if (spawner == null || spawner.Deleted)
                                return false;
                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 6, ",");
                                int effect = -1;
                                int duration = 1;
                                // syntax is EFFECT,itemid,duration[,x,y,z] or EFFECT,itemid,duration[,trigmob]
                                // try to get the effect argument
                                // some interesting effects are explosion(14013,15), sparkle(14155,15), explosion2(14000,13)
                                if (keywordargs.Length < 3)
                                {
                                    status_str = "Missing effect number and duration";
                                }
                                else
                                {
                                    try
                                    {
                                        effect = int.Parse(keywordargs[1]);
                                    }
                                    catch
                                    {
                                        status_str = "Improper effect number format";
                                    }
                                    try
                                    {
                                        duration = int.Parse(keywordargs[2]);
                                    }
                                    catch
                                    {
                                        status_str = "Improper effect duration format";
                                    }
                                }
                                // by default just use the spawner location
                                Point3D eloc = spawner.Location;
                                Map emap = spawner.Map;
                                if (keywordargs.Length > 3)
                                {
                                    // is this applied to the trig mob or to a location?
                                    if (keywordargs.Length > 5)
                                    {
                                        int x = spawner.Location.X;
                                        int y = spawner.Location.Y;
                                        int z = spawner.Location.Z;
                                        try
                                        {
                                            x = int.Parse(keywordargs[3]);
                                            y = int.Parse(keywordargs[4]);
                                            z = int.Parse(keywordargs[5]);
                                        }
                                        catch
                                        {
                                            status_str = "Improper effect location format";
                                        }
                                        eloc = new Point3D(x, y, z);
                                    }
                                }
                                if (status_str != null)
                                {
                                    return false;
                                }
                                if (effect >= 0)
                                {
                                    Effects.SendLocationEffect(eloc, emap, effect, duration);
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.POISON:
                        {
                            // the syntax is POISON,name,range
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            if (arglist.Length > 0)
                            {
                                ApplyPoisonToPlayers(arglist[0], triggermob, invoker, out status_str);
                                if (status_str != null)
                                {
                                    return false;
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.DAMAGE:
                        {
                            // the syntax is DAMAGE,damage,phys,fire,cold,pois,energy[,range]
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            if (arglist.Length > 0)
                            {
                                ApplyDamageToPlayers(arglist[0], triggermob, invoker, out status_str);
                                if (status_str != null)
                                {
                                    return false;
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.RESURRECT:
                        {
                            // the syntax is RESURRECT[,range][,PETS]
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            if (arglist.Length > 0)
                            {
                                ResurrectPlayers(arglist[0], triggermob, invoker, out status_str);
                                if (status_str != null)
                                {
                                    return false;
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.CAST:
                        {
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);
                            // Syntax is CAST,spellnumber[,arg] or CAST,spellname[,arg]
                            string[] keywordargs = ParseString(arglist[0], 3, ",");
                            int spellnumber = 0;
                            bool hasnumber = true;
                            // try it as spellnumber
                            if (keywordargs.Length > 1)
                            {
                                try
                                {
                                    spellnumber = int.Parse(keywordargs[1]);
                                }
                                catch
                                {
                                    hasnumber = false;
                                }
                            }
                            else
                            {
                                status_str = "invalid CAST specification";
                                // note that returning true means that Spawn will assume that it worked and will not try to recast
                                return true;
                            }
                            // call this with the 3 argument version that includes the bodytype arg
                            int keywordarg2 = 0;
                            if (keywordargs.Length > 2)
                            {
                                try
                                {
                                    keywordarg2 = int.Parse(keywordargs[2]);
                                }
                                catch
                                {
                                }
                            }

                            Spell spell = null;

                            // the trigger mob will cast the spells

                            Mobile caster = triggermob;
                            if (caster == null)
                            {
                                // note that returning true means that Spawn will assume that it worked and will not try to recast
                                return true;
                            }

                            // make the placeholder wand to avoid reagent and mana use
                            BaseWand cwand = new ClumsyWand();
                            cwand.Parent = caster;

                            if (hasnumber)
                            {
                                spell = SpellRegistry.NewSpell(spellnumber, caster, cwand);
                            }
                            else
                            {
                                spell = SpellRegistry.NewSpell(keywordargs[1], caster, cwand);
                            }
                            if (spell != null)
                            {
                                bool casterror = false;
                                try
                                {
                                    // deal with the 3 types of spells, mob targeted, location targeted, and self targeted
                                    // dont go through all of the warm up stuff, get right to the casting
                                    spell.State = SpellState.Sequencing;

                                    Type spelltype = spell.GetType();
                                    // deal with any special cases here
                                    if (spelltype == typeof(Server.Spells.Seventh.PolymorphSpell))
                                    {
                                        if (keywordarg2 == 0)
                                        {
                                            // this is invalid so dont cast
                                            throw (new ArgumentNullException());
                                        }
                                        object[] polyargs = new object[3];
                                        polyargs[0] = caster;
                                        polyargs[1] = cwand;
                                        polyargs[2] = keywordarg2;
                                        spell = (Spell)Activator.CreateInstance(spelltype, polyargs);

                                        if (spell == null)
                                        {
                                            throw (new ArgumentNullException());
                                        }
                                        spell.State = SpellState.Sequencing;
                                    }
                                    MethodInfo spelltargetmethod = null;

                                    // get the targeting method from the spell
                                    // note, the precedence is important as the target call should override oncast if it is present
                                    if (spelltype != null && (spelltargetmethod = spelltype.GetMethod("Target")) != null)
                                    {
                                    }
                                    // if it doesnt have it then check for self targeted types
                                    else if (spelltype != null && (spelltargetmethod = spelltype.GetMethod("OnCast")) != null)
                                    {
                                    }
                                    else
                                    {
                                        throw (new ArgumentNullException());
                                    }
                                    // Get the parameters for the target method.
                                    ParameterInfo[] spelltargetparms = spelltargetmethod.GetParameters();
                                    // target will have one parm
                                    // selftarg will have none
                                    object[] targetargs = null;
                                    // check the parameters
                                    if (spelltargetparms != null && spelltargetparms.Length > 0)
                                    {
                                        if (spelltargetparms[0].ParameterType == typeof(Server.Mobile))
                                        {
                                            // set the target parameter
                                            targetargs = new object[1];
                                            targetargs[0] = triggermob;
                                        }
                                        else if (spelltargetparms[0].ParameterType == typeof(Server.IPoint3D))
                                        {
                                            // set the target parameter
                                            targetargs = new object[1];
                                            // pick a random point around the caster
                                            int range = keywordarg2;
                                            if (range == 0)
                                                range = 1;
                                            int randx = Utility.RandomMinMax(-range, range);
                                            int randy = Utility.RandomMinMax(-range, range);
                                            if (randx == 0 && randy == 0)
                                                randx = 1;
                                            targetargs[0] = new Point3D(triggermob.Location.X + randx,
                                                triggermob.Location.Y + randy,
                                                triggermob.Location.Z);
                                        }
                                        else
                                        {
                                            // dont handle any other types of args
                                            throw (new ArgumentNullException());
                                        }
                                    }
                                    // set the spell on the caster
                                    caster.Spell = spell;
                                    // invoke the spell method with the appropriate args
                                    spelltargetmethod.Invoke(spell, targetargs);

                                    // get rid of the placeholder wand
                                    if (cwand != null && !cwand.Deleted)
                                        cwand.Delete();
                                }
                                catch
                                {
                                    status_str = "bad spell call : " + spell.Name;
                                    casterror = true;
                                    // get rid of the placeholder wand
                                    if (cwand != null && !cwand.Deleted)
                                        cwand.Delete();
                                }

                                if (casterror)
                                    return true;
                            }
                            else
                            {
                                status_str = "spell invalid or disabled : " + keywordargs[1];
                                //return true;
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));
                            // note that returning true means that Spawn assume that it worked and will not try to recast
                            break;
                        }
                    case typeKeyword.BCAST:
                        {
                            // syntax is BCAST[,hue][,font]/message
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);

                            int hue = 0x482;
                            int font = -1;

                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 3, ",");
                                if (keywordargs.Length > 1)
                                {
                                    try
                                    {
                                        hue = int.Parse(keywordargs[1]);
                                    }
                                    catch
                                    {
                                        status_str = "invalid hue arg to BCAST";
                                    }
                                }
                                if (keywordargs.Length > 2)
                                {
                                    try
                                    {
                                        font = int.Parse(keywordargs[2]);
                                    }
                                    catch
                                    {
                                        status_str = "invalid font arg to BCAST";
                                    }
                                }
                            }

                            if (arglist.Length > 1)
                            {
                                string msg = arglist[1];
                                if (arglist[1] != null && arglist[1].Length > 0 && arglist[1][0] == '@')
                                {
                                    arglist = ParseSlashArgs(substitutedtypeName, 2);
                                    msg = arglist[1].Substring(1);
                                }
                                if (font >= 0)
                                {
                                    // broadcast an ascii message to all players
                                    BroadcastAsciiMessage(AccessLevel.Player, hue, font, msg);
                                }
                                else
                                {
                                    // standard unicode message format
                                    CommandHandlers.BroadcastMessage(AccessLevel.Player, hue, msg);
                                }
                            }
                            else
                            {
                                status_str = "missing msg arg in BCAST";
                                return false;
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    case typeKeyword.BSOUND:
                        {
                            // syntax is BSOUND,soundid
                            string[] arglist = ParseSlashArgs(substitutedtypeName, 3);

                            int soundid = -1;

                            if (arglist.Length > 0)
                            {
                                string[] keywordargs = ParseString(arglist[0], 2, ",");
                                if (keywordargs.Length > 1)
                                {
                                    try
                                    {
                                        soundid = int.Parse(keywordargs[1]);
                                    }
                                    catch
                                    {
                                        status_str = "invalid soundid arg to BSOUND";
                                    }
                                }

                                if (soundid >= 0)
                                {
                                    // broadcast a sound to all players
                                    BroadcastSound(AccessLevel.Player, soundid);
                                }
                            }

                            TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner));

                            break;
                        }
                    default:
                        {
                            status_str = "unrecognized keyword";
                            // should never get here
                            break;
                        }
                }
                // indicate successful keyword spawn
                return true;
            }
            else if (IsSpecialItemKeyword(typeName))
            {
                // these are special keyword item drops
                string[] arglist = ParseSlashArgs(substitutedtypeName, 2);
                string itemtypestr = arglist[0];
                string baseitemtype = typeName;

                // itemtypestr will have the form keyword[,x[,y]]
                string[] itemkeywordargs = ParseString(itemtypestr, 3, ",");

                // deal with the special keywords
                itemKeyword kw = (itemKeyword)itemKeywordHash[baseitemtype];

                switch (kw)
                {
                    case itemKeyword.ARMOR:
                        {
                            // syntax is ARMOR,min,max
                            //get the min,max
                            if (itemkeywordargs.Length == 3)
                            {
                                int min = 0;
                                int max = 0;
                                bool converterror = false;
                                try
                                {
                                    min = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid ARMOR args : " + itemtypestr;
                                    converterror = true;
                                }
                                try
                                {
                                    max = int.Parse(itemkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid ARMOR args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                Item item = MagicArmor(min, max, false, false);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "ARMOR takes 2 args : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.WEAPON:
                        {
                            // syntax is WEAPON,min,max
                            //get the min,max
                            if (itemkeywordargs.Length == 3)
                            {
                                int min = 0;
                                int max = 0;
                                bool converterror = false;
                                try
                                {
                                    min = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid WEAPON args : " + itemtypestr;
                                    converterror = true;
                                }
                                try
                                {
                                    max = int.Parse(itemkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid WEAPON args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                Item item = MagicWeapon(min, max, false);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "WEAPON takes 2 args : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.JARMOR:
                        {
                            // syntax is JARMOR,min,max
                            //get the min,max
                            if (itemkeywordargs.Length == 3)
                            {
                                int min = 0;
                                int max = 0;
                                bool converterror = false;
                                try
                                {
                                    min = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid JARMOR args : " + itemtypestr;
                                    converterror = true;
                                }
                                try
                                {
                                    max = int.Parse(itemkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid JARMOR args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                Item item = MagicArmor(min, max, true, true);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "JARMOR takes 2 args : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.JWEAPON:
                        {
                            // syntax is JWEAPON,min,max
                            //get the min,max
                            if (itemkeywordargs.Length == 3)
                            {
                                int min = 0;
                                int max = 0;
                                bool converterror = false;
                                try
                                {
                                    min = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid JWEAPON args : " + itemtypestr;
                                    converterror = true;
                                }
                                try
                                {
                                    max = int.Parse(itemkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid JWEAPON args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                Item item = MagicWeapon(min, max, true);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "JWEAPON takes 2 args : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.SARMOR:
                        {
                            // syntax is SARMOR,min,max
                            //get the min,max
                            if (itemkeywordargs.Length == 3)
                            {
                                int min = 0;
                                int max = 0;
                                bool converterror = false;
                                try
                                {
                                    min = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid SARMOR args : " + itemtypestr;
                                    converterror = true;
                                }
                                try
                                {
                                    max = int.Parse(itemkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid SARMOR args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                Item item = MagicArmor(min, max, false, true);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "SARMOR takes 2 args : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.SHIELD:
                        {
                            // syntax is SHIELD,min,max
                            //get the min,max
                            if (itemkeywordargs.Length == 3)
                            {
                                int min = 0;
                                int max = 0;
                                bool converterror = false;
                                try
                                {
                                    min = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid SHIELD args : " + itemtypestr;
                                    converterror = true;
                                }
                                try
                                {
                                    max = int.Parse(itemkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid SHIELD args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                Item item = MagicShield(min, max);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "SHIELD takes 2 args : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.JEWELRY:
                        {
                            // syntax is JEWELRY,min,max
                            //get the min,max
                            if (itemkeywordargs.Length == 3)
                            {
                                int min = 0;
                                int max = 0;
                                bool converterror = false;
                                try
                                {
                                    min = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid JEWELRY args : " + itemtypestr;
                                    converterror = true;
                                }
                                try
                                {
                                    max = int.Parse(itemkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid JEWELRY args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                Item item = MagicJewelry(min, max);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "JEWELRY takes 2 args : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.ITEM:
                        {
                            // syntax is ITEM,serial
                            if (itemkeywordargs.Length == 2)
                            {
                                int serial = -1;
                                bool converterror = false;
                                try
                                {
                                    serial = Convert.ToInt32(itemkeywordargs[1], 16);
                                }
                                catch
                                {
                                    status_str = "Invalid ITEM args : " + itemtypestr;
                                    converterror = true;
                                }

                                if (converterror)
                                    return false;

                                Item item = World.FindItem(serial);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "ITEM takes 1 arg : " + itemtypestr;
                                return false;
                            }

                            break;
                        }
                    case itemKeyword.SCROLL:
                        {
                            // syntax is SCROLL,mincircle,maxcircle
                            //get the min,max
                            if (itemkeywordargs.Length == 3)
                            {
                                int minCircle = 0;
                                int maxCircle = 0;
                                bool converterror = false;
                                try
                                {
                                    minCircle = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid SCROLL args : " + itemtypestr;
                                    converterror = true;
                                }
                                try
                                {
                                    maxCircle = int.Parse(itemkeywordargs[2]);
                                }
                                catch
                                {
                                    status_str = "Invalid SCROLL args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                int circle = Utility.RandomMinMax(minCircle, maxCircle);
                                int min = (circle - 1) * 8;
                                Item item = Loot.RandomScroll(min, min + 7, SpellbookType.Regular);
                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "SCROLL takes 2 args : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.LOOT:
                        {
                            // syntax is LOOT,methodname
                            if (itemkeywordargs.Length == 2)
                            {
                                Item item = null;

                                // look up the method
                                Type ltype = typeof(Loot);
                                if (ltype != null)
                                {
                                    MethodInfo method = null;

                                    try
                                    {
                                        // get the zero arg method with the specified name
                                        method = ltype.GetMethod(itemkeywordargs[1], new Type[0]);
                                    }
                                    catch
                                    {
                                    }

                                    if (method != null && method.IsStatic)
                                    {
                                        ParameterInfo[] pinfo = method.GetParameters();
                                        // check to make sure the method for this object has the right args
                                        if (pinfo.Length == 0)
                                        {
                                            // method must be public static with no arguments returning an Item class object
                                            try
                                            {
                                                item = method.Invoke(null, null) as Item;
                                            }
                                            catch
                                            {
                                            }
                                        }
                                        else
                                        {
                                            status_str = "LOOT method must be zero arg : " + itemtypestr;
                                            return false;
                                        }
                                    }
                                    else
                                    {
                                        status_str = "LOOT no valid method found : " + itemtypestr;
                                        return false;
                                    }
                                }

                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "LOOT takes 1 arg : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.POTION:
                        {
                            // syntax is POTION
                            Item item = Loot.RandomPotion();
                            if (item != null)
                            {
                                AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                            }
                            break;
                        }
                    case itemKeyword.TAKEN:
                        {
                            // syntax is TAKEN
                            // find the XmlSaveItem attachment
                            Item item = GetTaken(invoker);

                            if (item != null)
                            {
                                AddSpawnItem(spawner, invoker, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                            }
                            break;
                        }
                    case itemKeyword.GIVEN:
                        {
                            // syntax is GIVEN
                            // find the XmlSaveItem attachment
                            Item item = GetGiven(invoker);

                            if (item != null)
                            {
                                AddSpawnItem(spawner, invoker, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                            }
                            break;
                        }

                    case itemKeyword.NECROSCROLL:
                        {
                            // syntax is NECROSCROLL,index
                            if (itemkeywordargs.Length == 2)
                            {
                                int necroindex = 0;
                                bool converterror = false;
                                try
                                {
                                    necroindex = int.Parse(itemkeywordargs[1]);
                                }
                                catch
                                {
                                    status_str = "Invalid NECROSCROLL args : " + itemtypestr;
                                    converterror = true;
                                }
                                if (converterror)
                                    return false;
                                if (Core.AOS)
                                {
                                    Item item = Loot.Construct(Loot.NecromancyScrollTypes, necroindex);
                                    if (item != null)
                                    {
                                        AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                    }
                                }
                            }
                            else
                            {
                                status_str = "NECROSCROLL takes 1 arg : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    case itemKeyword.MULTIADDON:
                        {
                            // syntax is MULTIADDON,filename
                            if (itemkeywordargs.Length == 2)
                            {
                                string filename = itemkeywordargs[1];

                                // read in the multi.txt file

                                Item item = XmlSpawnerAddon.ReadMultiFile(filename, out status_str);

                                if (item != null)
                                {
                                    AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str);
                                }
                            }
                            else
                            {
                                status_str = "MULTIADDON takes 1 arg : " + itemtypestr;
                                return false;
                            }
                            break;
                        }
                    default:
                        {
                            status_str = "unrecognized keyword";
                            // should never get here
                            break;
                        }
                }

                return true;
            }
            else
            {
                // should never get here
                status_str = "unrecognized keyword";
                return false;
            }
        }
		public override void OnResponse( NetState sender, RelayInfo info )
		{
			Container pack = sender.Mobile.Backpack;

			if ( pack == null )
			{
				sender.Mobile.SendMessage( 1192, "You need a backpack." );
				return;
			}

			int items = 0;
			BaseCustomWand wand = null;
			BaseWand magewand = null;

			switch( (Buttons)info.ButtonID )
			{
				case Buttons.MainMenu:
				{
					if ( sender.Mobile.HasGump( typeof( SpellBindingGump ) ) )
						sender.Mobile.CloseGump( typeof( SpellBindingGump ) );

					sender.Mobile.SendGump( new SpellBindingGump() );
					break;
				}
				case Buttons.Magery:
				{
					if ( sender.Mobile.HasGump( typeof( SpellBindingGump ) ) )
						sender.Mobile.CloseGump( typeof( SpellBindingGump ) );

					sender.Mobile.SendGump( new SpellBindingGump( Buttons.Magery ) );
					break;
				}
				case Buttons.Necromancy:
				{
					if ( sender.Mobile.HasGump( typeof( SpellBindingGump ) ) )
						sender.Mobile.CloseGump( typeof( SpellBindingGump ) );

					sender.Mobile.SendGump( new SpellBindingGump( Buttons.Necromancy ) );
					break;
				}
				case Buttons.Chivalry:
				{
					if ( sender.Mobile.HasGump( typeof( SpellBindingGump ) ) )
						sender.Mobile.CloseGump( typeof( SpellBindingGump ) );

					sender.Mobile.SendGump( new SpellBindingGump( Buttons.Chivalry ) );
					break;
				}
				case Buttons.Golems:
				{
					if ( sender.Mobile.HasGump( typeof( SpellBindingGump ) ) )
						sender.Mobile.CloseGump( typeof( SpellBindingGump ) );

					sender.Mobile.SendGump( new SpellBindingGump( Buttons.Golems ) );
					break;
				}

				#region Magery
				case Buttons.Clumsy:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( Bloodmoss ),
							typeof( Nightshade ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand = new ClumsyWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.Feeble:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( Ginseng ),
							typeof( Nightshade ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand = new FeebleWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.Fireball:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( BlackPearl ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand = new FireballWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.GreaterHeal:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( Garlic ),
							typeof( Ginseng ),
							typeof( MandrakeRoot ),
							typeof( SpidersSilk ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 50, 50, 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand = new GreaterHealWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.Harm:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( Nightshade ),
							typeof( SpidersSilk ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand = new HarmWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.Identification:
				{
					sender.Mobile.SendMessage( 1192, "The Spell Binders of Tolaria have not concentrated on this area of work yet." );
					goto case Buttons.Magery;
				}
				case Buttons.Lightning:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( MandrakeRoot ),
							typeof( SulfurousAsh ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand = new LightningWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.MagicArrow:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( SulfurousAsh ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand= new MagicArrowWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.ManaDrain:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( BlackPearl ),
							typeof( MandrakeRoot ),
							typeof( SpidersSilk ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 50, 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand = new ManaDrainWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.Weakness:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( Garlic ),
							typeof( Nightshade ),
							typeof( ArcaneGem )
						},
						new int[]{ 50, 50, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || items != -1 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & 100 mana.<br>" + 
							"Items: An Arcane Gem." + 
							"Regents: 50 of the regents the spell requires." );
						goto case Buttons.Magery;
					}

					magewand = new WeaknessWand();
					magewand.Crafter = sender.Mobile;
					pack.DropItem( magewand );
					goto case Buttons.Magery;
				}
				case Buttons.MarkRune:
				{
					sender.Mobile.SendMessage( 1192, "The Spell Binders of Tolaria have not concentrated on this area of work yet." );
					goto case Buttons.Magery;
				}
				case Buttons.ArcaneGem: 
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( BlackPearl ),
							typeof( Bloodmoss ),
							typeof( Garlic ),
							typeof( Ginseng ),
							typeof( MandrakeRoot ),
							typeof( Nightshade ),
							typeof( SpidersSilk ),
							typeof( SulfurousAsh )
						},
						new int[]{ 10, 10, 10, 10, 10, 10, 10, 10 } );

					if ( sender.Mobile.Skills[SkillName.ItemID].Base < 100.0 || items != -1 || sender.Mobile.Mana < 25 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: ItemID 100.0+ & 25 mana.<br>" + 
							"Regents: 10 of all magery regents." );
						goto case Buttons.Magery;
					}
					sender.Mobile.SendMessage( 1192, "The Spell Binders of Tolaria have not concentrated on this area of work yet." );
					goto case Buttons.Magery;
				}
				#endregion

				#region Necromancy
				case Buttons.PainSpike:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( GnarledStaff ),
							typeof( ArcaneGem ),
							typeof( GraveDust ),
							typeof( PigIron )
						},
						new int[]{ 1, 1, 20, 20 } );

					if ( sender.Mobile.Skills[SkillName.Necromancy].Base < 40.0 || items != -1 || sender.Mobile.Mana < 24 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Necromancy 40.0+ & 25 mana.<br>" + 
							"Items: An Arcane Gem, a Gnarled Staff (enchantments will be removed).<br>" + 
							"Regents: 20 each of Grave Dust, Pig Iron." );
						goto case Buttons.Necromancy;
					}

					sender.Mobile.Mana -= 25;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new PainSpikeStaff();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Necromancy;
				}
				case Buttons.BloodOath:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( GnarledStaff ),
							typeof( ArcaneGem ),
							typeof( DaemonBlood )
						},
						new int[]{ 1, 1, 20 } );

					if ( sender.Mobile.Skills[SkillName.Necromancy].Base < 40.0 || items != -1 || sender.Mobile.Mana < 64 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Necromancy 40.0+ & 25 mana.<br>" + 
							"Items: An Arcane Gem, a Gnarled Staff (enchantments will be removed).<br>" + 
							"Regents: 20 Daemon Blood." );
						goto case Buttons.Necromancy;
					}

					sender.Mobile.Mana -= 65;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new BloodOathStaff();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Necromancy;
				}
				case Buttons.CorpseSkin:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( GnarledStaff ),
							typeof( ArcaneGem ),
							typeof( BatWing ),
							typeof( GraveDust )
						},
						new int[]{ 1, 1, 20, 20 } );

					if ( sender.Mobile.Skills[SkillName.Necromancy].Base < 40.0 || items != -1 || sender.Mobile.Mana < 54 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Necromancy 40.0+ & 25 mana.<br>" + 
							"Items: An Arcane Gem, a Gnarled Staff (enchantments will be removed).<br>" + 
							"Regents: 20 each of Bat Wing, Grave Dust." );
						goto case Buttons.Necromancy;
					}

					sender.Mobile.Mana -= 55;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new CorpseSkinStaff();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Necromancy;
				}
				case Buttons.EvilOmen:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( GnarledStaff ),
							typeof( ArcaneGem ),
							typeof( BatWing ),
							typeof( NoxCrystal )
						},
						new int[]{ 1, 1, 20, 20 } );

					if ( sender.Mobile.Skills[SkillName.Necromancy].Base < 40.0 || items != -1 || sender.Mobile.Mana < 54 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Necromancy 40.0+ & 25 mana.<br>" + 
							"Items: An Arcane Gem, a Gnarled Staff (enchantments will be removed).<br>" + 
							"Regents: 20 of each Bat Wing, Nox Crystal." );
						goto case Buttons.Necromancy;
					}

					sender.Mobile.Mana -= 55;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new EvilOmenStaff();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Necromancy;
				}
				case Buttons.AnimateDead:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( GnarledStaff ),
							typeof( ArcaneGem ),
							typeof( GraveDust ),
							typeof( DaemonBlood )
						},
						new int[]{ 1, 2, 20, 20 } );

					if ( sender.Mobile.Skills[SkillName.Necromancy].Base < 60.0 || items != -1 || sender.Mobile.Mana < 114 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Necromancy 40.0+ & 25 mana.<br>" + 
							"Items: 2 Arcane Gems, a Gnarled Staff (enchantments will be removed).<br>" + 
							"Regents: 20 of each Grave Dust, Daemon Blood." );
						goto case Buttons.Necromancy;
					}

					sender.Mobile.Mana -= 115;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new AnimateDeadStaff();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Necromancy;
				}
				#endregion

				#region Chivalry
				case Buttons.CleanseByFire:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( Mace ),
						},
						new int[]{ 1, 1 } );

					if ( sender.Mobile.Skills[SkillName.Chivalry].Base < 25.0 || items != -1 || sender.Mobile.TithingPoints < 50 || sender.Mobile.Mana < 50 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Chivalry 25.0+ & 50 mana.<br>" + 
							"Items: Arcane Gem, a Mace (enchantments will be removed).<br>" + 
							"Tithing: 50." );
						goto case Buttons.Chivalry;
					}

					sender.Mobile.Mana -= 50;
					sender.Mobile.TithingPoints -= 50;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new CleanseByFireMace();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Chivalry;
				}
				case Buttons.CloseWounds:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( WarMace ),
						},
						new int[]{ 1, 1 } );

					if ( sender.Mobile.Skills[SkillName.Chivalry].Base < 20.0 || items != -1 || sender.Mobile.TithingPoints < 50 || sender.Mobile.Mana < 50 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Chivalry 20.0+ & 50 mana.<br>" + 
							"Items: Arcane Gem, a War Mace (enchantments will be removed).<br>" + 
							"Tithing: 50." );
						goto case Buttons.Chivalry;
					}

					sender.Mobile.Mana -= 50;
					sender.Mobile.TithingPoints -= 50;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new CloseWoundsWarMace();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Chivalry;
				}
				case Buttons.ConsecrateWeapon:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( HammerPick ),
						},
						new int[]{ 1, 1 } );

					if ( sender.Mobile.Skills[SkillName.Chivalry].Base < 35.0 || items != -1 || sender.Mobile.TithingPoints < 50 || sender.Mobile.Mana < 50 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Chivalry 35.0+ & 50 mana.<br>" + 
							"Items: Arcane Gem, a Hammer Pick (enchantments will be removed).<br>" + 
							"Tithing: 50." );
						goto case Buttons.Chivalry;
					}

					sender.Mobile.Mana -= 50;
					sender.Mobile.TithingPoints -= 50;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new ConsecrateWeaponHammerPick();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Chivalry;
				}
				case Buttons.RemoveCurse:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( Scepter ),
						},
						new int[]{ 1, 1 } );

					if ( sender.Mobile.Skills[SkillName.Chivalry].Base < 25.0 || items != -1 || sender.Mobile.TithingPoints < 50 || sender.Mobile.Mana < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Chivalry 25.0+ & 100 mana.<br>" + 
							"Items: Arcane Gem, a Sceptor (enchantments will be removed).<br>" + 
							"Tithing: 50." );
						goto case Buttons.Chivalry;
					}

					sender.Mobile.Mana -= 100;
					sender.Mobile.TithingPoints -= 50;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new RemoveCurseScepter();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Chivalry;
				}
				case Buttons.DivineFury:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( WarHammer ),
						},
						new int[]{ 1, 1 } );

					if ( sender.Mobile.Skills[SkillName.Chivalry].Base < 45.0 || 
						items != -1 || 
						sender.Mobile.TithingPoints < 50 || 
						sender.Mobile.Mana < 75 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Chivalry 45.0+ & 75 mana.<br>" +
							"Items: Arcane Gem, a War Hammer (enchantments will be removed).<br>" + 
							"Tithing: 50." );
						goto case Buttons.Chivalry;
					}

					sender.Mobile.Mana -= 75;
					sender.Mobile.TithingPoints -= 50;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					wand = new DivineFuryWarHammer();
					wand.Crafter = sender.Mobile;
					pack.DropItem( wand );
					goto case Buttons.Chivalry;
				}
				#endregion

				#region Golems
				case Buttons.BloodGolem:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( PowerCrystal ),
							typeof( Garlic ),
							typeof( Ginseng ),
							typeof( MandrakeRoot ),
							typeof( SpidersSilk ),
							typeof( Head ),
							typeof( LeftArm ),
							typeof( RightArm ),
							typeof( LeftLeg ),
							typeof( RightLeg )
						},
						new int[]{ 3, 1, 50, 50, 50, 50, 1, 1, 1, 1, 1 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 50.0 || sender.Mobile.Skills[SkillName.Necromancy].Base < 50.0 || items != -1 || sender.Mobile.Mana < 74 || sender.Mobile.Hits < 100 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 50.0+ & Necromancy 50.0+ & 75 mana.<br>" + 
							"Items: 3 Arcane Gems, Power Crystal, All the flesh parts from a humanoid corpse.<br>" + 
							"Regents: 50 each of Garlic, Ginsing, Mandrake Root, Spider's Silk." + 
							"Special: 100 Hit Points." );
						goto case Buttons.Golems;
					}

					sender.Mobile.Hits -= 100;
					sender.Mobile.Mana -= 75;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					pack.DropItem( new GolemItem( GolemType.Blood ) );
					goto case Buttons.Golems;
				}
				case Buttons.ClayGolem:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( PowerCrystal ),
							typeof( FertileDirt ),
							typeof( Bloodmoss ),
							typeof( GraveDust ),
							typeof( NoxCrystal ),
							typeof( SpidersSilk ),
						},
						new int[]{ 2, 1, 4, 50, 50, 50, 50 } );

					if ( items == -1 )
					{
						Item[] itemlist = pack.FindItemsByType( typeof( Pitcher ) );

						if ( itemlist.Length == 0 )
							items = 0;

						Pitcher p = null;
						int found = 0;

						for ( int i = 0; i < itemlist.Length; i++ )
						{
							p = (Pitcher)itemlist[i];

							if ( p.IsFull && p.Content == BeverageType.Water )
								found++;
						}

						if ( found < 4 )
							items = 0;
					}

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 75.0 || sender.Mobile.Skills[SkillName.Necromancy].Base < 75.0 || items != -1 || sender.Mobile.Mana < 99 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 75.0+ & Necromancy 75.0+ & 100 mana<br>" + 
							"Items: 2 Arcane Gems, Power Crystal, 4 Fertile Dirt, 4 Pitchers full of water.<br>" + 
							"Regents: 50 each of Bloodmoss, Grave Dust, Nox Crystal, Spider's Silk." );
						goto case Buttons.Golems;
					}

					sender.Mobile.Mana -= 100;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					pack.DropItem( new GolemItem( GolemType.Clay ) );
					goto case Buttons.Golems;
				}
				case Buttons.IronGolem:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( PowerCrystal ),
							typeof( BatWing ),
							typeof( Nightshade ),
							typeof( PigIron )
						},
						new int[]{ 4, 2, 50, 50, 100 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 100.0 || sender.Mobile.Skills[SkillName.Necromancy].Base < 100.0 || items != -1 || sender.Mobile.Mana < 124 )
					{
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 100.0+ & Necromancy 100.0+ & 125 mana.<br>" + 
							"Items: 4 Arcane Gems, 2 Power Crystals.<br>" + 
							"Regents: 50 each of Bat Wing, Nightshade & 100 Pig Iron.<br>" + 
							"Special: Armor or Weapon (consumed on use)" );
						goto case Buttons.Golems;
					}

					sender.Mobile.Mana -= 125;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					pack.DropItem( new GolemItem( GolemType.Iron ) );
					goto case Buttons.Golems;
				}
				case Buttons.FireGolem:
				{
					items = pack.ConsumeTotal(
						new Type[]
						{
							typeof( ArcaneGem ),
							typeof( PowerCrystal ),
							typeof( BlackPearl ),
							typeof( DaemonBlood ),
							typeof( MandrakeRoot ),
							typeof( SulfurousAsh ),
						},
						new int[]{ 5, 2, 50, 50, 50, 200 } );

					if ( sender.Mobile.Skills[SkillName.Magery].Base < 115.0 || sender.Mobile.Skills[SkillName.Necromancy].Base < 115.0 || items != -1 || sender.Mobile.Mana < 149 )
					{
						
						SendFailedGump( sender.Mobile, 
							"Skill Required: Magery 115.0+ & Necromancy 115.0+ & 150 mana." + 
							"Items: 5 Arcane Gems, 2 Power Crystals, 200 Sulfurous Ash" + 
							"Regents: 50 each of Black Peral, Daemon Blood, Mandrake Root & 200 Sulfurous Ash" + 
							"Special: Armor or Weapon" );
						goto case Buttons.Golems;
					}

					sender.Mobile.Mana -= 150;
					sender.Mobile.SendMessage( 1192, "You bound the spell to the item." );
					pack.DropItem( new GolemItem( GolemType.Fire ) );
					goto case Buttons.Golems;
				}
				#endregion
			}
		}