using System; using System.Data; using System.IO; using System.Collections.Generic; using Server; using Server.Items; using Server.Network; using Server.Gumps; using Server.Targeting; using System.Reflection; using Server.Commands; using Server.Commands.Generic; using CPA = Server.CommandPropertyAttribute; using System.Xml; using Server.Spells; using System.Text; using System.Globalization; using Server.Accounting; using Server.Engines.XmlSpawner2; namespace Server.Mobiles { public delegate void XmlGumpCallback(Mobile from, object invoker, string response); public class BaseXmlSpawner { #region Initialization private static List ProtectedPropertiesList = new List(); private class ProtectedProperty { public Type ObjectType; public string Name; public ProtectedProperty(Type type, string name) { ObjectType = type; Name = name; } } public static bool IsProtected(Type type, string property) { if (type == null || property == null) return false; // search through the protected list for a matching entry foreach (ProtectedProperty p in ProtectedPropertiesList) { if ((p.ObjectType == type || type.IsSubclassOf(p.ObjectType)) && (property.ToLower() == p.Name.ToLower())) { return true; } } return false; } public static void Initialize() { // register restricted properties that cannot be set by the spawner ProtectedPropertiesList.Add(new ProtectedProperty(typeof(Mobile), "accesslevel")); ProtectedPropertiesList.Add(new ProtectedProperty(typeof(Item), "stafflevel")); //fill the list //InitializeHash(); } #endregion #region Type support [Flags] public enum KeywordFlags { HoldSpawn = 0x01, HoldSequence = 0x02, Serialize = 0x04, Defrag = 0x08, } public class TypeInfo { public List plist = new List(); // hold propertyinfo list public Type t; } // ------------------------------------------------------------- // Modified from Beta-36 Properties.cs code // ------------------------------------------------------------- private static Type typeofTimeSpan = typeof(TimeSpan); private static Type typeofParsable = typeof(ParsableAttribute); private static Type typeofCustomEnum = typeof(CustomEnumAttribute); private static bool IsParsable(Type t) { return (t == typeofTimeSpan || t.IsDefined(typeofParsable, false)); } private static Type[] m_ParseTypes = new Type[] { typeof(string) }; private static object[] m_ParseParams = new object[1]; private static object Parse(object o, Type t, string value) { MethodInfo method = t.GetMethod("Parse", m_ParseTypes); m_ParseParams[0] = value; return method.Invoke(o, m_ParseParams); } private static Type[] m_NumericTypes = new Type[] { typeof( Byte ), typeof( SByte ), typeof( Int16 ), typeof( UInt16 ), typeof( Int32 ), typeof( UInt32 ), typeof( Int64 ), typeof( UInt64 ), typeof( Server.Serial ) }; public static bool IsNumeric(Type t) { return (Array.IndexOf(m_NumericTypes, t) >= 0); } private static Type typeofType = typeof(Type); private static bool IsType(Type t) { return (t == typeofType); } private static Type typeofChar = typeof(Char); private static bool IsChar(Type t) { return (t == typeofChar); } private static Type typeofString = typeof(String); private static bool IsString(Type t) { return (t == typeofString); } private static bool IsEnum(Type t) { return t.IsEnum; } private static bool IsCustomEnum(Type t) { return t.IsDefined(typeofCustomEnum, false); } // ------------------------------------------------------------- // End modified Beta-36 Properties.cs code // ------------------------------------------------------------- public static string ParsedType(Type type) { if (type == null) return null; string s = type.ToString(); if (s == null) return null; string[] args = s.Split(Type.Delimiter); if (args != null && args.Length > 0) { return args[args.Length - 1]; } else { return null; } } public static bool CheckType(object o, string typename) { if (typename == null || o == null) return false; // test the type Type objecttype = o.GetType(); Type targettype = null; targettype = SpawnerType.GetType(typename); if (objecttype != null && targettype != null && (objecttype.Equals(targettype) || objecttype.IsSubclassOf(targettype))) { return true; } return false; } private enum typeKeyword { SET, SETVAR, SETONTRIGMOB, SETONCARRIED, SETONSPAWN, SETONSPAWNENTRY, SETONNEARBY, SETONPETS, SETONMOB, SETONTHIS, SETONPARENT, SETACCOUNTTAG, FOREACH, GIVE, TAKEGIVE, TAKE, GUMP, TAKEBYTYPE, BROWSER, SENDMSG, SENDASCIIMSG, MUSIC, RESURRECT, POISON, DAMAGE, EFFECT, MEFFECT, SOUND, WAITUNTIL, WHILE, IF, GOTO, CAST, BCAST, BSOUND, COMMAND, SPAWN, DESPAWN } private enum typemodKeyword { MUSIC, POISON, DAMAGE, EFFECT, BOLTEFFECT, MEFFECT, PEFFECT, SOUND, SAY, SPEECH, ANIMATE, OFFSET, ADD, MSG, ASCIIMSG, SENDMSG, SENDASCIIMSG, BCAST, EQUIP, UNEQUIP, DELETE, KILL, ATTACH, FACETO, SETVALUE, FLASH, PRIVMSG } private enum itemKeyword { ARMOR, WEAPON, JARMOR, JWEAPON, SHIELD, SARMOR, LOOT, JEWELRY, POTION, SCROLL, NECROSCROLL, LOOTPACK, TAKEN, GIVEN, ITEM, MULTIADDON, RANDOMITEM } private enum valueKeyword { GET, GETVAR, GETONMOB, GETONCARRIED, GETONTRIGMOB, GETONNEARBY, GETONSPAWN, GETONPARENT, GETONTHIS, GETONTAKEN, GETONGIVEN, GETFROMFILE, GETACCOUNTTAG, AMOUNTCARRIED, RND, RNDBOOL, RNDLIST, RNDSTRLIST, TRIGSKILL, PLAYERSINRANGE, MY, RANDNAME } private enum valuemodKeyword { GET, GETONMOB, GETVAR, GETONCARRIED, GETONTRIGMOB, GETONNEARBY, GETONSPAWN, GETONPARENT, GETONTHIS, GETONTAKEN, GETONGIVEN, GETFROMFILE, GETACCOUNTTAG, AMOUNTCARRIED, RND, RNDBOOL, RNDLIST, RNDSTRLIST, MUL, INC, MOB, TRIGMOB, MY, TRIGSKILL, PLAYERSINRANGE, RANDNAME } #endregion #region Static variable declarations // name of mobile used to issue commands via the COMMAND keyword. The accesslevel of the mobile will determine // the accesslevel of commands that can be issued. // if this is null, then COMMANDS can only be issued when triggered by players of the appropriate accesslevel private static string CommandMobileName = null; private static Dictionary typeKeywordHash = new Dictionary(); private static Dictionary typemodKeywordHash = new Dictionary(); private static Dictionary valueKeywordHash = new Dictionary(); private static Dictionary valuemodKeywordHash = new Dictionary(); private static Dictionary itemKeywordHash = new Dictionary(); private static char[] slashdelim = new char[1] { '/' }; private static char[] commadelim = new char[1] { ',' }; private static char[] spacedelim = new char[1] { ' ' }; private static char[] semicolondelim = new char[1] { ';' }; private static char[] literalend = new char[1] { '§' }; #endregion #region Keywords public static bool IsValueKeyword(string str) { if (string.IsNullOrEmpty(str) || !char.IsUpper(str[0])) return false; //if (valueKeywordHash == null) InitializeHash(); return valueKeywordHash.ContainsKey(str); } public static bool IsValuemodKeyword(string str) { if (string.IsNullOrEmpty(str) || !char.IsUpper(str[0])) return false; //if (valuemodKeywordHash == null) InitializeHash(); return valuemodKeywordHash.ContainsKey(str); } public static bool IsSpecialItemKeyword(string typeName) { if (string.IsNullOrEmpty(typeName) || !char.IsUpper(typeName[0])) return false; //if (itemKeywordHash == null) InitializeHash(); return itemKeywordHash.ContainsKey(typeName); } public static bool IsTypeKeyword(string typeName) { if (string.IsNullOrEmpty(typeName) || !char.IsUpper(typeName[0])) return false; //if (typeKeywordHash == null) InitializeHash(); return (typeKeywordHash.ContainsKey(typeName)); } public static bool IsTypemodKeyword(string typeName) { if (string.IsNullOrEmpty(typeName) || !char.IsUpper(typeName[0])) return false; //if (typemodKeywordHash == null) InitializeHash(); return (typemodKeywordHash.ContainsKey(typeName)); } public static bool IsTypeOrItemKeyword(string typeName) { if (string.IsNullOrEmpty(typeName) || !Char.IsUpper(typeName[0])) return false; //if (typeKeywordHash == null || itemKeywordHash == null) InitializeHash(); return (typeKeywordHash.ContainsKey(typeName) || itemKeywordHash.ContainsKey(typeName)); } private static void AddTypeKeyword(string name) { typeKeywordHash.Add(name, (typeKeyword)Enum.Parse(typeof(typeKeyword), name)); } private static void AddTypemodKeyword(string name) { typemodKeywordHash.Add(name, (typemodKeyword)Enum.Parse(typeof(typemodKeyword), name)); } private static void AddValueKeyword(string name) { valueKeywordHash.Add(name, (valueKeyword)Enum.Parse(typeof(valueKeyword), name)); } private static void AddValuemodKeyword(string name) { valuemodKeywordHash.Add(name, (valuemodKeyword)Enum.Parse(typeof(valuemodKeyword), name)); } private static void AddItemKeyword(string name) { itemKeywordHash.Add(name, (itemKeyword)Enum.Parse(typeof(itemKeyword), name)); } public static void RemoveKeyword(string name) { if (name == null) return; name = name.Trim().ToUpper(); //if (IsTypeKeyword(name)) //{ typeKeywordHash.Remove(name); //} //if (IsTypemodKeyword(name)) //{ typemodKeywordHash.Remove(name); //} //if (IsValueKeyword(name)) //{ valueKeywordHash.Remove(name); //} //if (IsValuemodKeyword(name)) //{ valuemodKeywordHash.Remove(name); //} //if (IsSpecialItemKeyword(name)) //{ itemKeywordHash.Remove(name); //} } public static void Configure() { // set up the keyword hash tables // already set at startup time /*typeKeywordHash = new Hashtable(); typemodKeywordHash = new Hashtable(); itemKeywordHash = new Hashtable(); valueKeywordHash = new Hashtable(); valuemodKeywordHash = new Hashtable();*/ // Type keywords // spawned as primary objects AddTypeKeyword("SET"); AddTypeKeyword("SETVAR"); AddTypeKeyword("SETONTRIGMOB"); AddTypeKeyword("SETONCARRIED"); AddTypeKeyword("SETONNEARBY"); AddTypeKeyword("SETONPETS"); AddTypeKeyword("SETONSPAWN"); AddTypeKeyword("SETONSPAWNENTRY"); AddTypeKeyword("SETONMOB"); AddTypeKeyword("SETONTHIS"); AddTypeKeyword("SETONPARENT"); AddTypeKeyword("SETACCOUNTTAG"); AddTypeKeyword("FOREACH"); AddTypeKeyword("GIVE"); AddTypeKeyword("TAKEGIVE"); AddTypeKeyword("TAKE"); AddTypeKeyword("GUMP"); AddTypeKeyword("TAKEBYTYPE"); AddTypeKeyword("BROWSER"); AddTypeKeyword("SENDMSG"); AddTypeKeyword("SENDASCIIMSG"); AddTypeKeyword("RESURRECT"); AddTypeKeyword("POISON"); AddTypeKeyword("DAMAGE"); AddTypeKeyword("SOUND"); AddTypeKeyword("EFFECT"); AddTypeKeyword("MEFFECT"); AddTypeKeyword("MUSIC"); AddTypeKeyword("WAITUNTIL"); AddTypeKeyword("WHILE"); AddTypeKeyword("IF"); AddTypeKeyword("GOTO"); AddTypeKeyword("CAST"); AddTypeKeyword("BCAST"); AddTypeKeyword("BSOUND"); AddTypeKeyword("COMMAND"); AddTypeKeyword("SPAWN"); AddTypeKeyword("DESPAWN"); // Typemod keywords // used in place of properties as modifiers of the primary object type AddTypemodKeyword("MUSIC"); AddTypemodKeyword("SOUND"); AddTypemodKeyword("POISON"); AddTypemodKeyword("DAMAGE"); AddTypemodKeyword("EFFECT"); AddTypemodKeyword("BOLTEFFECT"); AddTypemodKeyword("MEFFECT"); AddTypemodKeyword("PEFFECT"); AddTypemodKeyword("SAY"); AddTypemodKeyword("SPEECH"); AddTypemodKeyword("ANIMATE"); AddTypemodKeyword("OFFSET"); AddTypemodKeyword("MSG"); AddTypemodKeyword("ASCIIMSG"); AddTypemodKeyword("SENDMSG"); AddTypemodKeyword("SENDASCIIMSG"); AddTypemodKeyword("BCAST"); AddTypemodKeyword("ADD"); AddTypemodKeyword("EQUIP"); AddTypemodKeyword("UNEQUIP"); AddTypemodKeyword("DELETE"); AddTypemodKeyword("KILL"); AddTypemodKeyword("ATTACH"); AddTypemodKeyword("FACETO"); AddTypemodKeyword("SETVALUE"); AddTypemodKeyword("FLASH"); AddTypemodKeyword("PRIVMSG"); // Value keywords // used in property tests AddValueKeyword("RND"); AddValueKeyword("RNDBOOL"); AddValueKeyword("RNDLIST"); AddValueKeyword("RNDSTRLIST"); AddValueKeyword("MY"); AddValueKeyword("GET"); AddValueKeyword("GETVAR"); AddValueKeyword("GETONMOB"); AddValueKeyword("GETONCARRIED"); AddValueKeyword("AMOUNTCARRIED"); AddValueKeyword("GETONTRIGMOB"); AddValueKeyword("GETONNEARBY"); AddValueKeyword("GETONSPAWN"); AddValueKeyword("GETONPARENT"); AddValueKeyword("GETONTHIS"); AddValueKeyword("GETONTAKEN"); AddValueKeyword("GETONGIVEN"); AddValueKeyword("GETFROMFILE"); AddValueKeyword("GETACCOUNTTAG"); AddValueKeyword("RANDNAME"); AddValueKeyword("TRIGSKILL"); AddValueKeyword("PLAYERSINRANGE"); // Valuemod keywords // used as values in property assignments AddValuemodKeyword("RND"); AddValuemodKeyword("RNDBOOL"); AddValuemodKeyword("RNDLIST"); AddValuemodKeyword("RNDSTRLIST"); AddValuemodKeyword("MY"); AddValuemodKeyword("GET"); AddValuemodKeyword("GETVAR"); AddValuemodKeyword("GETONMOB"); AddValuemodKeyword("GETONCARRIED"); AddValuemodKeyword("AMOUNTCARRIED"); AddValuemodKeyword("GETONTRIGMOB"); AddValuemodKeyword("GETONNEARBY"); AddValuemodKeyword("GETONSPAWN"); AddValuemodKeyword("GETONPARENT"); AddValuemodKeyword("GETONTHIS"); AddValuemodKeyword("GETONTAKEN"); AddValuemodKeyword("GETONGIVEN"); AddValuemodKeyword("GETFROMFILE"); AddValuemodKeyword("GETACCOUNTTAG"); AddValuemodKeyword("MUL"); AddValuemodKeyword("INC"); AddValuemodKeyword("MOB"); AddValuemodKeyword("TRIGMOB"); AddValuemodKeyword("RANDNAME"); AddValuemodKeyword("TRIGSKILL"); AddValuemodKeyword("PLAYERSINRANGE"); // Item keywords // these can be spawned like type keywords, or added to containers like items AddItemKeyword("ARMOR"); AddItemKeyword("WEAPON"); AddItemKeyword("JARMOR"); AddItemKeyword("LOOT"); AddItemKeyword("JWEAPON"); AddItemKeyword("SARMOR"); AddItemKeyword("SHIELD"); AddItemKeyword("JEWELRY"); AddItemKeyword("POTION"); AddItemKeyword("SCROLL"); AddItemKeyword("NECROSCROLL"); AddItemKeyword("LOOTPACK"); AddItemKeyword("TAKEN"); AddItemKeyword("GIVEN"); AddItemKeyword("ITEM"); AddItemKeyword("MULTIADDON"); AddItemKeyword("RANDOMITEM"); } #endregion #region KeywordTag public class KeywordTag { public KeywordFlags Flags; public int Type; private Timer m_Timer; public DateTime m_End; public DateTime m_TimeoutEnd; public TimeSpan m_Delay; public TimeSpan m_Timeout; private XmlSpawner m_Spawner; public string m_Condition; public int m_Goto; public bool Deleted = false; public int Serial = -1; public Mobile m_TrigMob; public string Typename; public KeywordTag(string typename, XmlSpawner spawner) : this(typename, spawner, -1) { } public KeywordTag(string typename, XmlSpawner spawner, int type) : this(typename, spawner, type, TimeSpan.Zero, TimeSpan.Zero, null, -1) { } public KeywordTag(string typename, XmlSpawner spawner, TimeSpan delay, string condition, int gotogroup) : this(typename, spawner, 0, delay, TimeSpan.Zero, condition, gotogroup) { } public KeywordTag(string typename, XmlSpawner spawner, TimeSpan delay, TimeSpan timeout, string condition, int gotogroup) : this(typename, spawner, 0, delay, timeout, condition, gotogroup) { } public KeywordTag(string typename, XmlSpawner spawner, int type, TimeSpan delay, TimeSpan timeout, string condition, int gotogroup) { Type = type; m_Delay = delay; m_Timeout = timeout; m_TimeoutEnd = DateTime.UtcNow + timeout; m_Spawner = spawner; m_Condition = condition; m_Goto = gotogroup; Typename = typename; // add the tag to the list if (spawner != null && !spawner.Deleted) { m_TrigMob = spawner.TriggerMob; if (spawner.m_KeywordTagList == null) { spawner.m_KeywordTagList = new List(); } // calculate the serial index of the new tag by adding one to the last one if there is one, otherwise just reset to 0 if (spawner.m_KeywordTagList.Count > 0) Serial = spawner.m_KeywordTagList[spawner.m_KeywordTagList.Count - 1].Serial + 1; else Serial = 0; spawner.m_KeywordTagList.Add(this); switch (type) { case 0: // WAIT timer type // start up the timer DoTimer(delay, m_Delay, condition, gotogroup); // and put spawning on hold until it is done //spawner.OnHold = true; Flags |= KeywordFlags.HoldSpawn; Flags |= KeywordFlags.Serialize; break; case 1: // GUMP type break; case 2: // GOTO type Flags |= KeywordFlags.HoldSequence; Flags |= KeywordFlags.Serialize; break; default: // dont do anything for other types Flags |= KeywordFlags.Defrag; break; } } } public void Delete() { // release any hold on spawning that might have been in place //if(m_Spawner != null && !m_Spawner.Deleted && Type == 0) //{ //m_Spawner.OnHold = false; //m_Spawner.HoldSequence = false; //} // and stop all timers if (m_Timer != null && Type == 0) { m_Timer.Stop(); } this.Deleted = true; // and remove it from the list RemoveFromTagList(m_Spawner, this); } private void DoTimer(TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup) { m_End = DateTime.UtcNow + delay; if (m_Timer != null) m_Timer.Stop(); m_Timer = new KeywordTimer(m_Spawner, this, delay, repeatdelay, condition, gotogroup); m_Timer.Start(); } public void Serialize(GenericWriter writer) { writer.Write((int)1); // version // Version 1 writer.Write((int)Flags); // Version 0 writer.Write(m_Spawner); writer.Write(Type); writer.Write(Serial); if (Type == 0) { // save any timer information writer.Write(m_End - DateTime.UtcNow); writer.Write(m_Delay); writer.Write(m_Condition); writer.Write(m_Goto); writer.Write(m_TimeoutEnd - DateTime.UtcNow); writer.Write(m_Timeout); writer.Write(m_TrigMob); } } public void Deserialize(GenericReader reader) { int version = reader.ReadInt(); switch (version) { case 1: Flags = (KeywordFlags)reader.ReadInt(); goto case 0; case 0: m_Spawner = (XmlSpawner)reader.ReadItem(); Type = reader.ReadInt(); Serial = reader.ReadInt(); if (Type == 0) { // get any timer info TimeSpan delay = reader.ReadTimeSpan(); m_Delay = reader.ReadTimeSpan(); m_Condition = reader.ReadString(); m_Goto = reader.ReadInt(); TimeSpan timeoutdelay = reader.ReadTimeSpan(); m_TimeoutEnd = DateTime.UtcNow + timeoutdelay; m_Timeout = reader.ReadTimeSpan(); m_TrigMob = reader.ReadMobile(); this.DoTimer(delay, m_Delay, m_Condition, m_Goto); } break; } } // added the timer that begins on spawning tmp keywords private class KeywordTimer : Timer { private KeywordTag m_Tag; private XmlSpawner m_Spawner; private string m_Condition; private int m_Goto; private TimeSpan m_Repeatdelay; public KeywordTimer(XmlSpawner spawner, KeywordTag tag, TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup) : base(delay) { Priority = TimerPriority.OneSecond; m_Tag = tag; m_Spawner = spawner; m_Condition = condition; m_Goto = gotogroup; m_Repeatdelay = repeatdelay; } protected override void OnTick() { // if a condition is available then test it if (m_Condition != null && m_Condition.Length > 0 && m_Spawner != null && m_Spawner.Running) { // if the test is valid then terminate the timer string status_str; Mobile trigmob = null; if (m_Spawner != null && !m_Spawner.Deleted) { trigmob = m_Spawner.TriggerMob; } if (TestItemProperty(m_Spawner, m_Spawner, m_Condition, trigmob, out status_str)) { // release the hold on spawning //m_Spawner.OnHold = false; // spawn the designated subgroup if specified if (m_Goto >= 0 && m_Spawner != null && !m_Spawner.Deleted) { // set the trigmob to the mob that originally triggered the wait keyword if (m_Tag != null) m_Spawner.TriggerMob = m_Tag.m_TrigMob; // spawn the subgroup m_Spawner.SpawnSubGroup(m_Goto, 0); // advance sequential spawning to that group //m_Spawner.SequentialSpawn = m_Goto; } // get rid of the temporary tag if (m_Tag != null && !m_Tag.Deleted) { m_Tag.Delete(); } } else { // otherwise restart it and keep on holding if (m_Tag != null && !m_Tag.Deleted) { //if(m_Tag.m_Timeout > TimeSpan.Zero) // check the timeout if applicable if (m_Tag.m_Timeout > TimeSpan.Zero && m_Tag.m_TimeoutEnd < DateTime.UtcNow) { // release the hold on spawning and delete the tag m_Tag.Delete(); //m_Spawner.OnHold = false; } else { m_Tag.DoTimer(m_Repeatdelay, m_Repeatdelay, m_Condition, m_Goto); } } } } else { // and terminate the timer if (m_Tag != null && !m_Tag.Deleted) { m_Tag.Delete(); } // release the hold on spawning //m_Spawner.OnHold = false; } } } } public static string TagInfo(KeywordTag tag) { if (tag != null) return (String.Format("{0} : type={1} cond={2} go={3} del={4} end={5}", tag.Typename, tag.Type, tag.m_Condition, tag.m_Goto, tag.m_Delay, tag.m_End)); else return null; } public static void RemoveFromTagList(XmlSpawner spawner, KeywordTag tag) { for (int i = 0; i < spawner.m_KeywordTagList.Count; i++) { if (tag == spawner.m_KeywordTagList[i]) { spawner.m_KeywordTagList.RemoveAt(i); break; } } } public static KeywordTag GetFromTagList(XmlSpawner spawner, int serial) { for (int i = 0; i < spawner.m_KeywordTagList.Count; i++) { if (serial == spawner.m_KeywordTagList[i].Serial) { return spawner.m_KeywordTagList[i]; } } return (null); } #endregion #region Property parsing methods // ------------------------------------------------------------- // Begin modified code from Beta-36 Properties.cs // Added support for nested attribute and array access // ------------------------------------------------------------- private static string InternalGetValue(object o, PropertyInfo p, int index) { Type type = p.PropertyType; object value = null; if (type.IsPrimitive) { value = p.GetValue(o, null); } else if ((type.GetInterface("IList") != null) && index >= 0) { try { object arrayvalue = p.GetValue(o, null); value = ((IList)arrayvalue)[index]; } catch { } } else { value = p.GetValue(o, null); } string toString; if (value == null) toString = "(-null-)"; else if (IsNumeric(type)) toString = String.Format("{0} (0x{0:X})", value); else if (IsChar(type)) toString = String.Format("'{0}' ({1} [0x{1:X}])", value, (int)value); else if (IsString(type)) toString = String.Format("\"{0}\"", value); else toString = value.ToString(); return String.Format("{0} = {1}", p.Name, toString); } public static bool IsItem(Type type) { return (type != null && (type == typeof(Item) || type.IsSubclassOf(typeof(Item)))); } public static bool IsMobile(Type type) { return (type != null && (type == typeof(Mobile) || type.IsSubclassOf(typeof(Mobile)))); } public static string ConstructFromString(PropertyInfo p, Type type, object obj, string value, ref object constructed) { object toSet; if (value == "(-null-)" && !type.IsValueType) value = null; if (IsEnum(type)) { try { toSet = Enum.Parse(type, value, true); } catch { return "That is not a valid enumeration member."; } } else if (IsCustomEnum(type)) { try { MethodInfo info = p.PropertyType.GetMethod("Parse", new Type[] { typeof(string) }); if (info != null) toSet = info.Invoke(null, new object[] { value }); else if (p.PropertyType == typeof(Enum) || p.PropertyType.IsSubclassOf(typeof(Enum))) toSet = Enum.Parse(p.PropertyType, value, false); else toSet = null; if (toSet == null) return "That is not a valid custom enumeration member."; } catch { return "That is not a valid custom enumeration member."; } } else if (IsType(type)) { try { toSet = ScriptCompiler.FindTypeByName(value); if (toSet == null) return "No type with that name was found."; } catch { return "No type with that name was found."; } } else if (IsParsable(type)) { try { toSet = Parse(obj, type, value); } catch { return "That is not properly formatted."; } } else if (value == null) { toSet = null; } else if (value.StartsWith("0x") && IsNumeric(type)) { try { toSet = Convert.ChangeType(Convert.ToUInt64(value.Substring(2), 16), type); } catch { return "That is not properly formatted. not convertible."; } } else if (value.StartsWith("0x") && (IsItem(type) || IsMobile(type))) { try { // parse out the mobile or item name from the value string int ispace = value.IndexOf(' '); string valstr = value.Substring(2); if (ispace > 0) { valstr = value.Substring(2, ispace - 2); } toSet = World.FindEntity(Convert.ToInt32(valstr, 16)); // now check to make sure the object returned is consistent with the type if (!((toSet is Mobile && IsMobile(type)) || (toSet is Item && IsItem(type)))) { return "Item/Mobile type mismatch. cannot assign."; } } catch { return "That is not properly formatted. not convertible."; } } else if ((type.GetInterface("IList") != null)) { try { object arrayvalue = p.GetValue(obj, null); object po = ((IList)arrayvalue)[0]; Type atype = po.GetType(); toSet = Parse(obj, atype, value); } catch { return "That is not properly formatted."; } } else { try { toSet = Convert.ChangeType(value, type); } catch { return "That is not properly formatted."; } } constructed = toSet; return null; } public static string InternalSetValue(Mobile from, object o, PropertyInfo p, string value, bool shouldLog, int index) { object toSet = null; Type ptype = p.PropertyType; string result = ConstructFromString(p, p.PropertyType, o, value, ref toSet); if (result != null) return result; try { if (shouldLog) CommandLogging.LogChangeProperty(from, o, p.Name, value); if (ptype.IsPrimitive) { p.SetValue(o, toSet, null); } else if ((ptype.GetInterface("IList") != null) && index >= 0) { try { object arrayvalue = p.GetValue(o, null); ((IList)arrayvalue)[index] = toSet; } catch { } } else { p.SetValue(o, toSet, null); } return "Property has been set."; } catch (Exception e) { Console.WriteLine(e.ToString()); return "An exception was caught, the property may not be set."; } } // set property values with support for nested attributes public static string SetPropertyValue(XmlSpawner spawner, object o, string name, string value) { if (o == null) { return "Null object"; } Type ptype = null; object po = null; Type type = o.GetType(); PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); // parse the strings of the form property.attribute into two parts // first get the property string[] arglist = ParseString(name, 2, "."); string propname = arglist[0]; string[] keywordargs = ParseString(propname, 4, ","); // check for special keywords if (keywordargs[0] == "ATTACHMENT") { if (keywordargs.Length < 4) { return "Invalid ATTACHMENT format"; } // syntax is ATTACHMENT,type,name,propname string apropname = keywordargs[3]; string aname = keywordargs[2]; Type attachtype = SpawnerType.GetType(keywordargs[1]); // allow empty string specifications to be used to indicate a null string which will match any name if (aname == "") aname = null; List attachments = XmlAttach.FindAttachments(o, attachtype, aname); if (attachments != null && attachments.Count > 0) { // change the object, object type, and propname to refer to the attachment o = attachments[0]; propname = apropname; if (o == null) { return "Null object"; } type = o.GetType(); props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); } else return "Attachment not found"; } else if (keywordargs[0] == "SKILL") { if (keywordargs.Length < 2) { return "Invalid SKILL format"; } SkillName skillname; #if Framework_4_0 if(Enum.TryParse(keywordargs[1], true, out skillname)) #else if(TryParse(keywordargs[1], true, out skillname)) #endif { if(o is Mobile) { Skill skill = ((Mobile)o).Skills[skillname]; double d; if(double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) { skill.Base = d; return "Property has been set."; } else return "Invalid double number"; } else return "Object is not mobile"; } else return "Invalid SKILL reference."; } else if (keywordargs[0] == "STEALABLE") { if (o is Item) { bool b; if(bool.TryParse(value, out b)) { ItemFlags.SetStealable((Item)o, b); return "Property has been set."; } else return "Invalid Stealable assignment."; } else return "Object is not an item"; } // do a bit of parsing to handle array references string[] arraystring = propname.Split('['); int index = 0; if (arraystring.Length > 1) { // parse the property name from the indexing propname = arraystring[0]; // then parse to get the index value string[] arrayvalue = arraystring[1].Split(']'); if (arrayvalue.Length > 0) { int.TryParse(arraystring[0], out index); } } if (arglist.Length == 2) { PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); if (plookup != null) { //if ( !plookup.CanWrite ) //return "Property is read only."; if (BaseXmlSpawner.IsProtected(type, propname)) return "Property is protected."; ptype = plookup.PropertyType; po = plookup.GetValue(o, null); // now set the nested attribute using the new property list return (SetPropertyValue(spawner, po, arglist[1], value)); } else { // is a nested property with attributes so first get the property foreach (PropertyInfo p in props) { if (Insensitive.Equals(p.Name, propname)) { //CPA pattr = Properties.GetCPA( p ); //if ( pattr == null ) //return "Property not found."; //if ( !p.CanWrite ) //return "Property is read only."; if (BaseXmlSpawner.IsProtected(type, propname)) return "Property is protected."; ptype = p.PropertyType; po = p.GetValue(o, null); // now set the nested attribute using the new property list return (SetPropertyValue(spawner, po, arglist[1], value)); } } } } else { // its just a simple single property PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); if (plookup != null) { if (!plookup.CanWrite) return "Property is read only."; if (BaseXmlSpawner.IsProtected(type, propname)) return "Property is protected."; string returnvalue = InternalSetValue(null, o, plookup, value, false, index); return returnvalue; } else { // note, looping through all of the props turns out to be a significant performance bottleneck // good place for optimization foreach (PropertyInfo p in props) { if (Insensitive.Equals(p.Name, propname)) { if (!p.CanWrite) return "Property is read only."; if (BaseXmlSpawner.IsProtected(type, propname)) return "Property is protected."; string returnvalue = InternalSetValue(null, o, p, value, false, index); return returnvalue; } } } } return "Property not found."; } public static string SetPropertyObject(XmlSpawner spawner, object o, string name, object value) { if (o == null) { return "Null object"; } Type ptype = null; object po = null; Type type = o.GetType(); PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); // parse the strings of the form property.attribute into two parts // first get the property string[] arglist = ParseString(name, 2, "."); if (arglist.Length == 2) { // is a nested property with attributes so first get the property // use the lookup table for optimization if possible PropertyInfo plookup = LookupPropertyInfo(spawner, type, arglist[0]); if (plookup != null) { //if ( !plookup.CanWrite ) //return "Property is read only."; if (BaseXmlSpawner.IsProtected(type, arglist[0])) return "Property is protected."; ptype = plookup.PropertyType; po = plookup.GetValue(o, null); // now set the nested attribute using the new property list return (SetPropertyObject(spawner, po, arglist[1], value)); } else { foreach (PropertyInfo p in props) { if (Insensitive.Equals(p.Name, arglist[0])) { //if ( !p.CanWrite ) //return "Property is read only."; if (BaseXmlSpawner.IsProtected(type, arglist[0])) return "Property is protected."; ptype = p.PropertyType; po = p.GetValue(o, null); // now set the nested attribute using the new property list return (SetPropertyObject(spawner, po, arglist[1], value)); } } } } else { // its just a simple single property // use the lookup table for optimization if possible PropertyInfo plookup = LookupPropertyInfo(spawner, type, name); if (plookup != null) { if (!plookup.CanWrite) return "Property is read only."; if (BaseXmlSpawner.IsProtected(type, name)) return "Property is protected."; if (plookup.PropertyType == typeof(Server.Mobile)) { plookup.SetValue(o, value, null); return "Property has been set."; } else { return "Property is not of type Mobile."; } } else { foreach (PropertyInfo p in props) { if (Insensitive.Equals(p.Name, name)) { if (!p.CanWrite) return "Property is read only."; if (BaseXmlSpawner.IsProtected(type, name)) return "Property is protected."; if (p.PropertyType == typeof(Server.Mobile)) { p.SetValue(o, value, null); return "Property has been set."; } else { return "Property is not of type Mobile."; } } } } } return "Property not found."; } public static string GetBasicPropertyValue(object o, string propname, out Type ptype) { ptype = null; if (o == null || propname == null) return null; Type type = o.GetType(); PropertyInfo[] props = type.GetProperties(); foreach (PropertyInfo p in props) { if (Insensitive.Equals(p.Name, propname)) { if (!p.CanRead) return null; ptype = p.PropertyType; string value = InternalGetValue(o, p, -1); return ParseGetValue(value, ptype); } } return null; } public static string GetPropertyValue(XmlSpawner spawner, object o, string name, out Type ptype) { ptype = null; if (o == null || name == null) return null; Type type = o.GetType(); object po = null; PropertyInfo[] props = null; try { props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); } catch { Console.WriteLine("GetProperties error with type {0}", type); return null; } // parse the strings of the form property.attribute into two parts // first get the property string[] arglist = ParseString(name, 2, "."); string propname = arglist[0]; // parse up to 4 comma separated args for special keyword properties string[] keywordargs = ParseString(propname, 4, ","); // check for special keywords if (keywordargs[0] == "ATTACHMENT") { // syntax is ATTACHMENT,type,name,property if (keywordargs.Length < 4) { return "Invalid ATTACHMENT format"; } string apropname = keywordargs[3]; string aname = keywordargs[2]; Type attachtype = SpawnerType.GetType(keywordargs[1]); // allow empty string specifications to be used to indicate a null string which will match any name if (aname == "") aname = null; List attachments = XmlAttach.FindAttachments(o, attachtype, aname); if (attachments != null && attachments.Count > 0) { string getvalue = GetPropertyValue(spawner, attachments[0], apropname, out ptype); return getvalue; } else return "Attachment not found"; } else if (keywordargs[0] == "SKILL") { // syntax is SKILL,skillname if (keywordargs.Length < 2) { return "Invalid SKILL format"; } SkillName skillname; #if Framework_4_0 if(Enum.TryParse(keywordargs[1], true, out skillname)) #else if(TryParse(keywordargs[1], true, out skillname)) #endif { if (o is Mobile) { Skill skill = ((Mobile)o).Skills[skillname]; ptype = skill.Value.GetType(); return String.Format("{0} = {1}", skillname, skill.Value); } else return "Object is not mobile"; } else { return "Skill not found."; } } else if (keywordargs[0] == "SERIAL") { bool found = true; try { if (o is Mobile) { ptype = ((Mobile)o).Serial.GetType(); return String.Format("Serial = {0}", ((Mobile)o).Serial); } else if (o is Item) { ptype = ((Item)o).Serial.GetType(); return String.Format("Serial = {0}", ((Item)o).Serial); } else return "Object is not item/mobile"; } catch { found = false; } if (!found) return "Serial not found."; } else if (keywordargs[0] == "TYPE") { ptype = typeof(Type); return String.Format("Type = {0}", o.GetType().Name); } else if (keywordargs[0] == "STEALABLE") { bool found = true; try { if (o is Item) { ptype = typeof(bool); return String.Format("Stealable = {0}", ItemFlags.GetStealable((Item)o)); } else return "Object is not an item"; } catch { found = false; } if (!found) return "Stealable flag not found."; } // do a bit of parsing to handle array references string[] arraystring = arglist[0].Split('['); int index = -1; if (arraystring.Length > 1) { // parse the property name from the indexing propname = arraystring[0]; // then parse to get the index value string[] arrayvalue = arraystring[1].Split(']'); if (arrayvalue.Length > 0) { if(!int.TryParse(arrayvalue[0], out index)) index=-1; } } if (arglist.Length == 2) { // use the lookup table for optimization if possible PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); if (plookup != null) { if (!plookup.CanRead) return "Property is write only."; //if ( BaseXmlSpawner.IsProtected(type, propname) ) //return "Property is protected."; ptype = plookup.PropertyType; if (ptype.IsPrimitive) { po = plookup.GetValue(o, null); } else if ((ptype.GetInterface("IList") != null) && index >= 0) { try { object arrayvalue = plookup.GetValue(o, null); po = ((IList)arrayvalue)[index]; } catch { } } else { po = plookup.GetValue(o, null); } // now set the nested attribute using the new property list return (GetPropertyValue(spawner, po, arglist[1], out ptype)); } else { // is a nested property with attributes so first get the property foreach (PropertyInfo p in props) { //if ( Insensitive.Equals( p.Name, arglist[0] ) ) if (Insensitive.Equals(p.Name, propname)) { if (!p.CanRead) return "Property is write only."; //if ( BaseXmlSpawner.IsProtected(type, propname) ) //return "Property is protected."; ptype = p.PropertyType; if (ptype.IsPrimitive) { po = p.GetValue(o, null); } else if ((ptype.GetInterface("IList") != null) && index >= 0) { try { object arrayvalue = p.GetValue(o, null); po = ((IList)arrayvalue)[index]; } catch { } } else { po = p.GetValue(o, null); } // now set the nested attribute using the new property list return (GetPropertyValue(spawner, po, arglist[1], out ptype)); } } } } else { // use the lookup table for optimization if possible PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); if (plookup != null) { if (!plookup.CanRead) return "Property is write only."; ptype = plookup.PropertyType; return InternalGetValue(o, plookup, index); } else { // its just a simple single property foreach (PropertyInfo p in props) { //if ( Insensitive.Equals( p.Name, name ) ) if (Insensitive.Equals(p.Name, propname)) { if (!p.CanRead) return "Property is write only."; ptype = p.PropertyType; return InternalGetValue(o, p, index); } } } } return "Property not found."; } // ------------------------------------------------------------- // End modified Beta-36 Properties.cs code // ------------------------------------------------------------- public static string ApplyToProperty(XmlSpawner spawner, object getobject, object setobject, string getpropertystring, string setpropertystring) { Type ptype; string getvalue = GetPropertyValue(spawner, getobject, getpropertystring, out ptype); if (getvalue == null) { return "Null object or property"; } if (ptype == null) { return getvalue; } string value2 = ParseGetValue(getvalue, ptype); if (value2 != null) { // set the property value using returned get value as the the value string result = SetPropertyValue(spawner, setobject, setpropertystring, value2); // see if it was successful if (result != "Property has been set.") { return setpropertystring + " : " + result; } } return null; } // added in arg parsing to handle object property setting public static bool ApplyObjectStringProperties(XmlSpawner spawner, string str, object o, Mobile trigmob, object refobject, out string status_str) { status_str = null; if (str == null || str.Length <= 0 || o == null) return false; // object strings will be of the form "object/modifier" where the modifier string is of the form "propname/value/propname/value/..." // some keywords do not have value arguments so the modifier could take the form "propname/propname/value/..." // this is handled by parsing into both forms // make sure the string is properly terminated to assure proper parsing of any final keywords bool terminated = false; str = str.Trim(); if (str[str.Length - 1] != '/') { str += "/"; terminated = true; } string[] arglist; arglist = ParseSlashArgs(str, 2); string remainder = null; // place the modifier section of the string in remainder if (arglist.Length > 1) remainder = arglist[1]; bool no_error = true; // process the modifier string if there is anything while (arglist.Length > 1) { // place into arglist the parsed modifier up to this point // arglist[0] will contain the propname // arglist[1] will contain the value // arglist[2] will contain the reset of the modifier arglist = ParseSlashArgs(remainder, 3); // singlearglist will contain the propname and the remainder // for those keywords that do not have value args string[] singlearglist = ParseSlashArgs(remainder, 2); if (arglist.Length > 1) { // handle value keywords that may take comma args // itemarglist[1] will contain arg2/arg3/arg4>/arg5 // additemstr should have the full list of args /arg5 if they are there. In the case of /arg1/ADD/arg2 // it will just have arg2 string[] groupedarglist = ParseString(arglist[1], 2, "["); // take that argument list that should like like arg2/ag3/arg4>/arg5 // need to find the matching ">" string[] groupargs = null; string groupargstring = null; if (groupedarglist.Length > 1) { groupargs = ParseToMatchingParen(groupedarglist[1], '[', ']'); // and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4 groupargstring = groupargs[0]; } // need to handle comma args that may be grouped with the () such as the (ATTACHMENT,args) arg //string[] value_keywordargs = ParseString(groupedarglist[0],10,","); string[] value_keywordargs = groupedarglist[0].Trim().Split(','); if (groupargstring != null && groupargstring.Length > 0) { if (value_keywordargs != null && value_keywordargs.Length > 0) value_keywordargs[value_keywordargs.Length - 1] = groupargstring; } // handle propname keywords that may take comma args //string[] keywordargs = ParseString(arglist[0],10,","); string[] keywordargs = arglist[0].Trim().Split(','); // this quick optimization can determine whether this is a regular prop/value assignment // since most prop modification strings will use regular propnames and not keywords, it makes sense to check for that first if (value_keywordargs[0].Length > 0 && !Char.IsUpper(value_keywordargs[0][0]) && arglist[0].Length > 0 && !Char.IsUpper(arglist[0][0])) { // all of this code is also included in the keyword candidate tests // this is because regular props can also be entered with uppercase so the lowercase test is not definitive // restricted properties //if(arglist[0].ToLower() == "accesslevel") //{ // status_str = "accesslevel is a protected property"; // if(arglist.Length < 3) break; // remainder = arglist[2]; //} //else { // check for the literal char if (singlearglist[1] != null && singlearglist[1].Length > 0 && singlearglist[1][0] == '@') { //support for literal terminator singlearglist = ParseLiteralTerminator(singlearglist[1]); string lstr = singlearglist[0]; if (terminated && lstr[lstr.Length - 1] == '/') lstr = lstr.Remove(lstr.Length - 1, 1); string result = SetPropertyValue(spawner, o, arglist[0], lstr.Remove(0, 1)); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } if(singlearglist.Length>1 && singlearglist[1] != null) { // if(singlearglist[1].Length>0 && singlearglist[1][0]=='/') // singlearglist[1].Remove(0, 1); remainder = singlearglist[1]; } else { remainder=null; break; } } else { string result = SetPropertyValue(spawner, o, arglist[0], arglist[1]); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } } } else { if (IsValuemodKeyword(value_keywordargs[0])) { valuemodKeyword kw = valuemodKeywordHash[value_keywordargs[0]]; if (kw == valuemodKeyword.RND) { // generate a random number and use it as the property value. Use the format /RND,min,max/ if (value_keywordargs.Length > 2) { // get a random number string randvalue = "0"; int min, max; if(int.TryParse(value_keywordargs[1], out min) && int.TryParse(value_keywordargs[2], out max)) { randvalue=String.Format("{0}", Utility.RandomMinMax(min, max)); } else { status_str = "Invalid RND args : " + arglist[1]; no_error = false; } // set the property value using the random number as the value string result = SetPropertyValue(spawner, o, arglist[0], randvalue); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } else { status_str = "Invalid RND args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.RNDBOOL) { // generate a random bool and use it as the property value. Use the format /RNDBOOL/ string randvalue = Utility.RandomBool().ToString(); // set the property value using the random number as the value string result = SetPropertyValue(spawner, o, arglist[0], randvalue); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.RNDLIST || kw == valuemodKeyword.RNDSTRLIST) { // generate a random number and use it as the property value. Use the format /RNDLIST,val1,val2,.../ if (value_keywordargs.Length > 1) { // compute a random index into the arglist int randindex = Utility.Random(1, value_keywordargs.Length - 1); // assign the list entry as the value string randvalue = value_keywordargs[randindex]; // set the property value string result = SetPropertyValue(spawner, o, arglist[0], randvalue); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } else { status_str = "Invalid " + arglist[0] + " args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.MY) { // syntax is MY,property // note this will be an arg to some property if (value_keywordargs.Length > 1) { string resultstr = ApplyToProperty(spawner, o, o, value_keywordargs[1], arglist[0]); if (resultstr != null) { status_str = "MY error: " + resultstr; no_error = false; } } else { status_str = "Invalid MY args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GET) { // syntax is GET,[itemname -OR- SETITEM][,itemtype],property // or GET,itemname[,itemtype], // note this will be an arg to some property if (value_keywordargs.Length > 2) { string propname = value_keywordargs[2]; string typestr = null; if (value_keywordargs.Length > 3) { propname = value_keywordargs[3]; typestr = value_keywordargs[2]; } // get the current property value //Type ptype; // get target item // is the itemname a serialno? object testitem = null; if (value_keywordargs[1].StartsWith("0x")) { int serial; if(!int.TryParse(value_keywordargs[1].Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out serial)) serial=-1; if (serial >= 0) testitem = World.FindEntity(serial); } else if(value_keywordargs[1]=="SETITEM" && spawner!=null && !spawner.Deleted && spawner.SetItem!=null) { testitem = spawner.SetItem; } else { testitem = FindItemByName(spawner, value_keywordargs[1], typestr); } string resultstr = ApplyToProperty(spawner, testitem, o, propname, arglist[0]); if (resultstr != null) { status_str = "GET error: " + resultstr; no_error = false; } } else if(spawner!=null && value_keywordargs.Length > 0) { string propname = value_keywordargs[0]; string resultstr = ApplyToProperty(spawner, spawner.SetItem, o, propname, arglist[0]); if (resultstr != null) { status_str = "GET error: " + resultstr; no_error = false; } } else { status_str = "Invalid GET args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETVAR) { // syntax is GETVAR,varname if (value_keywordargs.Length > 1) { string varname = value_keywordargs[1]; // look for the xmllocalvariable attachment with the given name XmlLocalVariable var = (XmlLocalVariable)XmlAttach.FindAttachment(refobject, typeof(XmlLocalVariable), varname); if (var != null) { string result = SetPropertyValue(spawner, o, arglist[0], var.Data); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } else { status_str = arglist[0] + " : No such var"; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else { status_str = "Invalid GETVAR args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONMOB) { // syntax is GETONMOB,mobname[,mobtype],property // or GETONMOB,mobname[,mobtype], // note this will be an arg to some property if (value_keywordargs.Length > 2) { //if(trigmob != null && !trigmob.Deleted){ // get the current property value //Type ptype; // get target item string propname = value_keywordargs[2]; string typestr = null; if (value_keywordargs.Length > 3) { propname = value_keywordargs[3]; typestr = value_keywordargs[2]; } Mobile testmobile = FindMobileByName(spawner, value_keywordargs[1], typestr); string resultstr = ApplyToProperty(spawner, testmobile, o, propname, arglist[0]); if (resultstr != null) { status_str = "GETONMOB error: " + resultstr; no_error = false; } } else { status_str = "Invalid GETONMOB args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONCARRIED) { // syntax is GETONCARRIED,itemname[,itemtype][,equippedonly],property // or GETONCARRIED,itemname[,itemtype][,equippedonly], // note this will be an arg to some property if (value_keywordargs.Length > 2) { bool equippedonly = false; if (trigmob != null && !trigmob.Deleted) { string itemname = value_keywordargs[1]; string propname = value_keywordargs[2]; string typestr = null; if (value_keywordargs.Length > 3) { propname = value_keywordargs[3]; typestr = value_keywordargs[2]; } if (value_keywordargs.Length > 4) { propname = value_keywordargs[4]; if (value_keywordargs[3].ToLower() == "equippedonly") { equippedonly = true; } else { if(!bool.TryParse(value_keywordargs[3], out equippedonly)) { status_str = "GETONCARRIED error parsing equippedonly"; no_error = false; } } } // get the current property value //Type ptype; // get target item Item testitem = SearchMobileForItem(trigmob, ParseObjectType(itemname), typestr, false, equippedonly); string resultstr = ApplyToProperty(spawner, testitem, o, propname, arglist[0]); if (resultstr != null) { status_str = "GETONCARRIED error: " + resultstr; no_error = false; } } else { no_error = false; } } else { status_str = "Invalid GETONCARRIED args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONTRIGMOB) { // syntax is GETONTRIGMOB,property // or GETONTRIGMOB, // note this will be an arg to some property if (value_keywordargs.Length > 1) { if (trigmob != null && !trigmob.Deleted) { string resultstr = ApplyToProperty(spawner, trigmob, o, value_keywordargs[1], arglist[0]); if (resultstr != null) { status_str = "GETONTRIGMOB error: " + resultstr; no_error = false; } } else { no_error = false; } } else { status_str = "Invalid GETONTRIGMOB args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONNEARBY) { // syntax is GETONNEARBY,range,name[,type][,searchcontainers],property // or GETONNEARBY,range,name[,type][,searchcontainers],[ATTACHMENT,type,name,property] // note this will be an arg to some property if (value_keywordargs.Length > 3) { string targetname = value_keywordargs[2]; string propname = value_keywordargs[3]; string typestr = null; bool searchcontainers = false; int range; if(!int.TryParse(value_keywordargs[1], out range)) range=-1; if (range < 0) { status_str = "invalid range in GETONNEARBY"; no_error = false; } if (value_keywordargs.Length > 4) { typestr = value_keywordargs[3]; propname = value_keywordargs[4]; } if (value_keywordargs.Length > 5) { if(!bool.TryParse(value_keywordargs[3], out searchcontainers)) { status_str = "invalid searchcontainer bool in GETONNEARBY"; no_error = false; } typestr = value_keywordargs[4]; propname = value_keywordargs[5]; } Type targettype = null; if (typestr != null) { targettype = SpawnerType.GetType(typestr); } if (no_error) { // get all of the nearby objects object relativeto = spawner; if (o is XmlAttachment) { relativeto = ((XmlAttachment)o).AttachedTo; } List nearbylist = GetNearbyObjects(relativeto, targetname, targettype, typestr, range, searchcontainers, null); string resultstr = null; // apply the properties from the first valid thing on the list foreach (object nearbyobj in nearbylist) { resultstr = ApplyToProperty(spawner, nearbyobj, o, propname, arglist[0]); if (resultstr == null) break; } if (resultstr != null) { status_str = "GETONNEARBY error: " + resultstr; no_error = false; } } } else { status_str = "Invalid GETONNEARBY args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONPARENT) { // syntax is GETONPARENT,property // or GETONPARENT, // note this will be an arg to some property if (value_keywordargs.Length > 1) { object parent = null; if (refobject is Item) { parent = ((Item)refobject).Parent; } else if (refobject is XmlAttachment) { parent = ((XmlAttachment)refobject).AttachedTo; } if (parent != null) { string resultstr = ApplyToProperty(spawner, parent, o, value_keywordargs[1], arglist[0]); if (resultstr != null) { status_str = "GETONPARENT error: " + resultstr; no_error = false; } } else { no_error = false; } } else { status_str = "Invalid GETONPARENT args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONTHIS) { // syntax is GETONTHIS,property // or GETONTHIS, // note this will be an arg to some property if (value_keywordargs.Length > 1) { if (refobject != null) { string resultstr = ApplyToProperty(spawner, refobject, o, value_keywordargs[1], arglist[0]); if (resultstr != null) { status_str = "GETONTHIS error: " + resultstr; no_error = false; } } else { no_error = false; } } else { status_str = "Invalid GETONTHIS args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONTAKEN) { // syntax is GETONTAKEN,property // or GETONTAKEN, // note this will be an arg to some property if (value_keywordargs.Length > 1) { // find the taken object Item taken = GetTaken(refobject); if (taken != null) { string resultstr = ApplyToProperty(spawner, taken, o, value_keywordargs[1], arglist[0]); if (resultstr != null) { status_str = "GETONTAKEN error: " + resultstr; no_error = false; } } else { no_error = false; } } else { status_str = "Invalid GETONTAKEN args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONGIVEN) { // syntax is GETONGIVEN,property // or GETONGIVEN, // note this will be an arg to some property if (value_keywordargs.Length > 1) { // find the taken object Item taken = GetGiven(refobject); if (taken != null) { string resultstr = ApplyToProperty(spawner, taken, o, value_keywordargs[1], arglist[0]); if (resultstr != null) { status_str = "GETONGIVEN error: " + resultstr; no_error = false; } } else { no_error = false; } } else { status_str = "Invalid GETONGIVEN args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETONSPAWN) { // syntax is GETONSPAWN[,spawername],subgroup,property // or GETONSPAWN[,spawername],subgroup, // note this will be an arg to some property if (value_keywordargs.Length > 2) { string subgroupstr = value_keywordargs[1]; string propstr = value_keywordargs[2]; string spawnerstr = null; if (value_keywordargs.Length > 3) { spawnerstr = value_keywordargs[1]; subgroupstr = value_keywordargs[2]; propstr = value_keywordargs[3]; } // get the current property value //Type ptype; // get target object int subgroup; if(!int.TryParse(subgroupstr, out subgroup)) subgroup = -1; if (subgroup == -1) { status_str = "Invalid subgroup in GETONSPAWN"; no_error = false; } else { if (spawnerstr != null) { spawner = FindSpawnerByName(spawner, spawnerstr); if (spawner == null) { status_str = "Invalid spawnername in GETONSPAWN"; no_error = false; } } object targetobj = XmlSpawner.GetSpawned(spawner, subgroup); if (targetobj != null) { string resultstr = ApplyToProperty(spawner, targetobj, o, propstr, arglist[0]); if (resultstr != null) { status_str = "GETONSPAWN error: " + resultstr; no_error = false; } } else { no_error = false; } } } else { status_str = "Invalid GETONSPAWN args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETFROMFILE) { // syntax is GETFROMFILE,filename if (value_keywordargs.Length > 1) { string filename = value_keywordargs[1]; string filestring = null; // read in the string from the file if (System.IO.File.Exists(filename) == true) { try { // Create an instance of StreamReader to read from a file. // The using statement also closes the StreamReader. using (StreamReader sr = new StreamReader(filename)) { string line; // Read and display lines from the file until the end of // the file is reached. while ((line = sr.ReadLine()) != null) { filestring += line; } sr.Close(); } } catch { status_str = "GETFROMFILE error: " + filename; no_error = false; } // set the property value string result = SetPropertyValue(spawner, o, arglist[0], filestring); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } } else { status_str = "Invalid GETFROMFILE args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.GETACCOUNTTAG) { // syntax is GETACCOUNTTAG,tagname if (value_keywordargs.Length > 1) { string tagname = value_keywordargs[1]; string tagvalue = null; // get the value of the account tag from the triggering mob if (trigmob != null && !trigmob.Deleted) { Account acct = trigmob.Account as Account; if (acct != null) { tagvalue = acct.GetTag(tagname); } } else { no_error = false; } if (tagvalue != null) { // set the property value string result = SetPropertyValue(spawner, o, arglist[0], tagvalue); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } else { status_str = "Invalid GETACCOUNTTAG tagname : " + tagname; no_error = false; } } else { status_str = "Invalid GETACCOUNTTAG args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.MUL) { // increment the property value by the amount. Use the format propname/MUL,min,max/ or propname/MUL,value if (value_keywordargs.Length > 1) { // get a random number string incvalue = "0"; if (value_keywordargs.Length > 2) { double d0, d1; if(double.TryParse(value_keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out d0) && double.TryParse(value_keywordargs[2], NumberStyles.Any, CultureInfo.InvariantCulture, out d1)) { incvalue = String.Format("{0}", Utility.RandomMinMax((int)(10000*d0), (int)(10000*d1)) / 10000.0); } else{ status_str = "Invalid MUL args : " + arglist[1]; no_error = false; } } else { incvalue = value_keywordargs[1]; } // get the current property value Type ptype; string tmpvalue = GetPropertyValue(spawner, o, arglist[0], out ptype); // see if it was successful if (ptype == null) { status_str = String.Format("Cant find {0}", arglist[0]); no_error = false; } else { string currentvalue = "0"; try { string[] arglist2 = ParseString(tmpvalue, 2, "="); string[] arglist3 = ParseString(arglist2[1], 2, " "); currentvalue = arglist3[0].Trim(); } catch { } string tmpstr = currentvalue; // should use the actual ptype info to do the multiplication. Maybe later. double d0,d1; if(double.TryParse(currentvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out d0) && double.TryParse(incvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out d1)) { tmpstr = ((int)(d0*d1)).ToString(); } else{ status_str = "Invalid MUL args : " + arglist[1]; no_error = false; } // set the property value using the incremented value string result = SetPropertyValue(spawner, o, arglist[0], tmpstr); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } } else { status_str = "Invalid MUL args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.INC) { // increment the property value by the amount. Use the format propname/INC,min,max/ or propname/INC,value if (value_keywordargs.Length > 1) { // get a random number string incvalue = "0"; if (value_keywordargs.Length > 2) { int min,max; if(int.TryParse(value_keywordargs[1], out min) && int.TryParse(value_keywordargs[2], out max)) { incvalue = String.Format("{0}", Utility.RandomMinMax(min, max)); } else{ status_str = "Invalid INC args : " + arglist[1]; no_error = false; } } else { incvalue = value_keywordargs[1]; } // get the current property value Type ptype; string tmpvalue = GetPropertyValue(spawner, o, arglist[0], out ptype); // see if it was successful if (ptype == null) { status_str = String.Format("Cant find {0}", arglist[0]); no_error = false; } else { string currentvalue = "0"; try { string[] arglist2 = ParseString(tmpvalue, 2, "="); string[] arglist3 = ParseString(arglist2[1], 2, " "); currentvalue = arglist3[0].Trim(); } catch { } string tmpstr = currentvalue; // should use the actual ptype info to do the addition. Maybe later. double d0,d1; if(double.TryParse(currentvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out d0) && double.TryParse(incvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out d1)) { tmpstr=((int)(d0+d1)).ToString(); } else { status_str = "Invalid INC args : " + arglist[1]; no_error = false; } // set the property value using the incremented value string result = SetPropertyValue(spawner, o, arglist[0], tmpstr); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } } else { status_str = "Invalid INC args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.MOB) { // lookup the mob id based on the name. format is /MOB,name[,type]/ if (value_keywordargs.Length > 1) { string typestr = null; if (value_keywordargs.Length > 2) { typestr = value_keywordargs[2]; } // lookup the name Mobile mob_id = null; try { mob_id = FindMobileByName(spawner, value_keywordargs[1], typestr); // the format of this will be 0xvalue "name" } catch { status_str = "Invalid MOB args : " + arglist[1]; no_error = false; } // set the property value using this format (M) id name string result = SetPropertyObject(spawner, o, arglist[0], mob_id); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } else { no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.TRIGMOB) { string result = SetPropertyObject(spawner, o, arglist[0], trigmob); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.AMOUNTCARRIED) { // syntax is AMOUNTCARRIED,itemtype[[,banksearch],itemname] int amount = 0; if (value_keywordargs.Length > 1) { string typestr = value_keywordargs[1], namestr="*"; bool banksearch = false; if(value_keywordargs.Length > 2) { if(!bool.TryParse(value_keywordargs[2], out banksearch)) { status_str = "Invalid AMOUNTCARRIED banksearch boolean : " + arglist[1]; no_error = false; } else if(value_keywordargs.Length > 3) { namestr=value_keywordargs[3]; } } // get the list of items being carried of the specified type Type targetType = SpawnerType.GetType(typestr); if (targetType != null && trigmob != null && trigmob.Backpack != null) { Item[] items = trigmob.Backpack.FindItemsByType( targetType, true ); for ( int i = 0; i < items.Length; ++i ) { if(CheckNameMatch(namestr, items[i].Name)) amount += items[i].Amount; } if(banksearch && trigmob.BankBox!=null) { items = trigmob.BankBox.FindItemsByType( targetType, true ); for ( int i = 0; i < items.Length; ++i ) { if(CheckNameMatch(namestr, items[i].Name)) amount += items[i].Amount; } } } string result = SetPropertyValue(spawner, o, arglist[0], amount.ToString()); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } else { status_str = "Invalid AMOUNTCARRIED args : " + arglist[1]; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.PLAYERSINRANGE) { // syntax is PLAYERSINRANGE,range int nplayers = 0; int range = 0; // get the number of players in range if (value_keywordargs.Length > 1) { int.TryParse(value_keywordargs[1], out range); } // count nearby players if (refobject is Item) { IPooledEnumerable ie = ((Item)refobject).GetMobilesInRange(range); foreach (Mobile p in ie ) { if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++; } ie.Free(); } else if (refobject is Mobile) { IPooledEnumerable ie = ((Mobile)refobject).GetMobilesInRange(range); foreach (Mobile p in ie) { if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++; } ie.Free(); } string result = SetPropertyValue(spawner, o, arglist[0], nplayers.ToString()); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.TRIGSKILL) { if (value_keywordargs.Length > 1) { if (spawner != null && spawner.TriggerSkill != null) { string skillstr = null; // syntax is TRIGSKILL,name|value|cap|base if (value_keywordargs[1].ToLower() == "name") { skillstr = spawner.TriggerSkill.Name; } else if (value_keywordargs[1].ToLower() == "value") { skillstr = spawner.TriggerSkill.Value.ToString(); } else if (value_keywordargs[1].ToLower() == "cap") { skillstr = spawner.TriggerSkill.Cap.ToString(); } else if (value_keywordargs[1].ToLower() == "base") { skillstr = spawner.TriggerSkill.Base.ToString(); } string result = SetPropertyValue(spawner, o, arglist[0], skillstr); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == valuemodKeyword.RANDNAME) { if (value_keywordargs.Length > 1) { string result = SetPropertyValue(spawner, o, arglist[0], NameList.RandomName(value_keywordargs[1])); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } } else { no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } } else if (IsTypemodKeyword(keywordargs[0])) { typemodKeyword kw = typemodKeywordHash[keywordargs[0]]; if (kw == typemodKeyword.MUSIC) { SendMusicToPlayers(arglist[0], trigmob, refobject, out status_str); if (status_str != null) { no_error = false; } if (arglist.Length < 2) break; remainder = singlearglist[1]; } // // SOUND keyword // else if (kw == typemodKeyword.SOUND) { int sound = -1; // try to get the soundnumber argument if (keywordargs.Length < 2) { status_str = "Missing sound number"; no_error = false; } else { if(!int.TryParse(keywordargs[1], out sound)) { status_str = "Improper sound number format"; no_error = false; } } try { if (sound >= 0 && o is IEntity) { Effects.PlaySound(((IEntity)o).Location, ((IEntity)o).Map, sound); } } catch { } if (arglist.Length < 2) break; remainder = singlearglist[1]; } // // EFFECT keyword // else if (kw == typemodKeyword.EFFECT) { int effect = -1; int duration = 1; // syntax is EFFECT,itemid,duration,[x,y,z] // try to get the effect argument if (keywordargs.Length < 2) { status_str = "Missing effect number"; no_error = false; } else { if(!int.TryParse(keywordargs[1], out effect)) { status_str = "Improper effect number format"; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out duration)) { status_str = "Improper effect duration format"; no_error = false; } } // by default just use the spawn location Point3D eloc; Map emap = Map.Internal; if (o is Mobile) { eloc = ((Mobile)o).Location; emap = ((Mobile)o).Map; } else if (o is Item) { eloc = ((Item)o).Location; emap = ((Item)o).Map; } else { // should never get here eloc = new Point3D(0, 0, 0); } if (keywordargs.Length > 3) { // is this applied to the trig mob or to a location? if (keywordargs.Length > 5) { int x=0; int y=0; int z=0; if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z)) { status_str = "Improper effect location format"; } eloc = new Point3D(x, y, z); } } if (effect >= 0 && emap != Map.Internal) { Effects.SendLocationEffect(eloc, emap, effect, duration); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } // // BOLTEFFECT keyword // else if (kw == typemodKeyword.BOLTEFFECT) { int sound = 0x29; int hue = 0; // syntax is BOLTEFFECT[,sound[,hue]] // try to get the effect argument if (keywordargs.Length > 1) { if(!int.TryParse(keywordargs[1], out sound)) { status_str = "Improper sound id"; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out hue)) { status_str = "Improper hue"; no_error = false; } } if (o is IEntity) { SendBoltEffect((IEntity)o, sound, hue); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } // // MEFFECT keyword // else if (kw == typemodKeyword.MEFFECT) { 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; bool hasloc = false; // syntax is MEFFECT,itemid[,speed][,x,y,z][,x2,y2,z2] // try to get the effect argument if (keywordargs.Length < 2) { status_str = "Missing effect number"; no_error = false; } else { if(!int.TryParse(keywordargs[1], out effect)) { status_str = "Improper effect number format"; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out speed)) { status_str = "Improper effect speed format"; no_error = false; } } // by default just use the spawn location if (o is Mobile) { eloc2 = ((Mobile)o).Location; emap = ((Mobile)o).Map; } else if (o is Item) { eloc2 = ((Item)o).Location; emap = ((Item)o).Map; } if (keywordargs.Length > 8) { int x=0; int y=0; int z=0; if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z)) { status_str = "Improper effect location format"; } eloc1 = new Point3D(x, y, z); x=y=z=0; if(!int.TryParse(keywordargs[6], out x) || !int.TryParse(keywordargs[7], out y) || !int.TryParse(keywordargs[8], out z)) { status_str = "Improper effect location format"; } eloc2 = new Point3D(x, y, z); hasloc = true; } else if (keywordargs.Length > 5) { int x = 0; int y = 0; int z = 0; if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z)) { status_str = "Improper effect location format"; } eloc1 = new Point3D(x, y, z); hasloc = true; } if (effect >= 0 && hasloc && emap != Map.Internal) { Effects.SendPacket(eloc1, emap, new HuedEffect(EffectType.Moving, -1, -1, effect, eloc1, eloc2, speed, duration, false, false, 0, 0)); } else if (effect >= 0 && refobject is IEntity && o is IEntity) { //Effects.SendLocationEffect(eloc, emap, effect, duration); //public static void SendMovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes ) Effects.SendMovingEffect((IEntity)refobject, (IEntity)o, effect, speed, duration, false, false); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } // // PEFFECT keyword // else if (kw == typemodKeyword.PEFFECT) { int effect = -1; int duration = 1; // syntax is PEFFECT,itemid,duration,[x,y,z] // try to get the effect argument if (keywordargs.Length < 2) { status_str = "Missing effect number"; no_error = false; } else { if(!int.TryParse(keywordargs[1], out effect)) { status_str = "Improper effect number format"; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out duration)) { status_str = "Improper effect duration format"; no_error = false; } } // by default just use the spawn location Point3D eloc; Map emap = Map.Internal; if (o is Mobile) { eloc = ((Mobile)o).Location; emap = ((Mobile)o).Map; } else if (o is Item) { eloc = ((Item)o).Location; emap = ((Item)o).Map; } else { // should never get here eloc = new Point3D(0, 0, 0); } if (keywordargs.Length > 3) { // is this applied to the trig mob or to a location? if (keywordargs.Length > 5) { int x = 0; int y = 0; int z = 0; if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z)) { status_str = "Improper effect location format"; } eloc = new Point3D(x, y, z); } } if (effect >= 0 && emap != Map.Internal) { Effects.SendLocationEffect(eloc, emap, effect, duration); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } // // POISON keyword // else if (kw == typemodKeyword.POISON) { ApplyPoisonToPlayers(arglist[0], o as Mobile, o, out status_str); //ApplyPoisonToPlayers(arglist[0], trigmob, refobject, out status_str); if (status_str != null) { no_error = false; } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.DAMAGE) { // the syntax is DAMAGE,damage,phys,fire,cold,pois,energy[,range][,playeronly] ApplyDamageToPlayers(arglist[0], o as Mobile, o, out status_str); //ApplyDamageToPlayers(arglist[0], trigmob, refobject, out status_str); if (status_str != null) { no_error = false; } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.ADD) { no_error = AddItemToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, false, out remainder, out status_str); } else if (kw == typemodKeyword.EQUIP) { no_error = AddItemToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, true, out remainder, out status_str); } else if (kw == typemodKeyword.DELETE) { if (o is Item) { ((Item)o).Delete(); } else if (o is Mobile) { if (!((Mobile)o).Player) { ((Mobile)o).Delete(); } } else if (o is XmlAttachment) { ((XmlAttachment)o).Delete(); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.KILL) { if (o is Mobile) { ((Mobile)o).Kill(); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.UNEQUIP) { // syntax is UNEQUIP,layer[,delete] Layer layer = Layer.Invalid; bool remove = false; if (keywordargs.Length > 1) { #if Framework_4_0 if(!Enum.TryParse(keywordargs[1], true, out layer)) #else if(!TryParse(keywordargs[1], true, out layer)) #endif { status_str = "Invalid layer"; } } if (keywordargs.Length > 2) { if (keywordargs[2] == "delete") { remove = true; } else bool.TryParse(keywordargs[2], out remove); } if (o is Mobile && layer != Layer.Invalid) { Mobile m = (Mobile)o; // go through all of the items on the mobile List packlist = m.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = (Item)packlist[i]; // check the layer // if it matches then unequip it if (item.Layer == layer) { if (remove) { item.Delete(); } else { m.AddToBackpack(item); } } } } if (status_str != null) { no_error = false; } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.ATTACH) { no_error = AddAttachmentToTarget(spawner, o, keywordargs, arglist, trigmob, refobject, out remainder, out status_str); } else if (kw == typemodKeyword.MSG) { // syntax is MSG[,probability][,hue] // if the object is a mobile then display a msg over the mob or item double drop_probability = 1; int hue = 0x3b2; if (keywordargs.Length > 1) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out hue)) { status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; } } if (hue < 0) hue = 0; if (o is Mobile || o is Item) { string msgstr = arglist[1]; // test the drop probability if (Utility.RandomDouble() < drop_probability) { if (o is Mobile) ((Mobile)o).PublicOverheadMessage(MessageType.Regular, hue, false, msgstr); else if (o is Item) ((Item)o).PublicOverheadMessage(MessageType.Regular, hue, false, msgstr); } } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == typemodKeyword.ASCIIMSG) { // syntax is ASCIIMSG[,probability][,hue][,font] // if the object is a mobile then display a msg over the mob or item double drop_probability = 1; int hue = 0x3b2; int font = 3; if (keywordargs.Length > 1) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out hue)) { status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 3) { if(!int.TryParse(keywordargs[3], out font)) { status_str = "Invalid MSG font : " + arglist[1]; no_error = false; } } if (hue < 0) hue = 0; if (font < 0) font = 0; if (o is Mobile || o is Item) { string msgstr = arglist[1]; // test the drop probability if (Utility.RandomDouble() < drop_probability) { if (o is Mobile) PublicOverheadMobileMessage((Mobile)o, MessageType.Regular, hue, font, msgstr, true); else if (o is Item) PublicOverheadItemMessage((Item)o, MessageType.Regular, hue, font, msgstr); } } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == typemodKeyword.SENDMSG) { // syntax is SENDMSG[,probability][,hue]/msg // if the object is a mobile then display a msg over the mob or item double drop_probability = 1; int hue = 0x3b2; int font = 3; if (keywordargs.Length > 1) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out hue)) { status_str = "Invalid SENDMSG hue : " + arglist[1]; no_error = false; } } if (hue < 0) hue = 0; if (o is Mobile) { string msgstr = arglist[1]; // test the drop probability if (Utility.RandomDouble() < drop_probability) { ((Mobile)o).Send(new UnicodeMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "ENU", "System", msgstr)); } } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == typemodKeyword.SENDASCIIMSG) { // syntax is SENDASCIIMSG[,probability][,hue][,font] // if the object is a mobile then display a msg over the mob or item double drop_probability = 1; int hue = 0x3b2; int font = 3; if (keywordargs.Length > 1) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out hue)) { status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 3) { if(!int.TryParse(keywordargs[3], out font)) { status_str = "Invalid MSG font : " + arglist[1]; no_error = false; } } if (hue < 0) hue = 0; if (font < 0) font = 0; if (o is Mobile) { string msgstr = arglist[1]; // test the drop probability if (Utility.RandomDouble() < drop_probability) { ((Mobile)o).Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", msgstr)); } } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == typemodKeyword.SAY) { // if the object is a mobile then display a msg over the mob double drop_probability = 1; if (keywordargs.Length > 1) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid say probability : " + arglist[1]; no_error = false; } } if (o is Mobile) { string msgstr = arglist[1]; // test the drop probability if (Utility.RandomDouble() < drop_probability) { ((Mobile)o).Say(msgstr); } } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == typemodKeyword.SPEECH) { // syntax is SPEECH[,probability][,keywordnumber] // if the object is a mobile then have it speak with optional keyword arg double drop_probability = 1; if (keywordargs.Length > 1) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid speech probability : " + arglist[1]; no_error = false; } } int keyword_number = -1; if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out keyword_number)) { status_str = "Invalid keyword number : " + arglist[1]; no_error = false; } } if (o is Mobile) { string msgstr = arglist[1]; // test the drop probability if (Utility.RandomDouble() < drop_probability) { int[] keywordarray = new int[] { }; if (keyword_number >= 0) { keywordarray = new int[] { keyword_number }; } ((Mobile)o).DoSpeech(msgstr, keywordarray, MessageType.Regular, 0x3B2); } } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == typemodKeyword.OFFSET) { // syntax is OFFSET,x,y[,z] // shift the location of the object by the specified amount int xoffset = 0; int yoffset = 0; int zoffset = 0; if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[1], out xoffset) || !int.TryParse(keywordargs[2], out yoffset)) { status_str = "Invalid xy offset : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 3) { if(!int.TryParse(keywordargs[3], out zoffset)) { status_str = "Invalid zoffset : " + arglist[1]; no_error = false; } } if (o is Mobile) { Point3D loc = ((Mobile)o).Location; ((Mobile)o).Location = new Point3D(loc.X + xoffset, loc.Y + yoffset, loc.Z + zoffset); } else if (o is Item) { Point3D loc = ((Item)o).Location; ((Item)o).Location = new Point3D(loc.X + xoffset, loc.Y + yoffset, loc.Z + zoffset); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.ANIMATE) { // syntax is ANIMATE,action[,framecount][,repeatcount][,forward true/false][,repeat true/false][delay] // Animate( int action, int frameCount, int repeatCount, bool forward, bool repeat, int delay ) int action=-1; int framecount = 7; int repeatcount = 1; bool forward = true; bool repeat = false; int delay = 0; if (keywordargs.Length > 1) { if(!int.TryParse(keywordargs[1], out action)) { status_str = "Invalid action : " + arglist[1]; no_error = false; action=-1; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out framecount)) { status_str = "Invalid framecount : " + arglist[1]; no_error = false; framecount=7; } } if (keywordargs.Length > 3) { if(!int.TryParse(keywordargs[3], out repeatcount)) { status_str = "Invalid repeatcount : " + arglist[1]; no_error = false; repeatcount=1; } } if (keywordargs.Length > 4) { if(!bool.TryParse(keywordargs[4], out forward)) { status_str = "Invalid forward : " + arglist[1]; no_error = false; forward=true; } } if (keywordargs.Length > 5) { if(!bool.TryParse(keywordargs[5], out repeat)) { status_str = "Invalid repeat : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 6) { if(!int.TryParse(keywordargs[6], out delay)) { status_str = "Invalid delay : " + arglist[1]; no_error = false; } } if (o is Mobile && action >= 0) { ((Mobile)o).Animate(action, framecount, repeatcount, forward, repeat, delay); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.FACETO) { // the mobile will turn to the direction coordinates // syntax is FACETO,x,y if (o is Mobile) { Mobile m=(Mobile)o; int dx=m.X, dy=m.Y; if (keywordargs.Length > 2) { Int32.TryParse(keywordargs[1], out dx); Int32.TryParse(keywordargs[2], out dy); } m.Direction = m.GetDirectionTo(dx,dy); } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.SETVALUE) { // syntax is SETVALUE,varname,value,duration - it's a wrapper for xmlvalue if (keywordargs.Length > 3) { int val; double duration; int.TryParse(keywordargs[2], out val); double.TryParse(keywordargs[3], NumberStyles.Any, CultureInfo.InvariantCulture, out duration); XmlValue x = (XmlValue)XmlAttach.FindAttachment(o, typeof(XmlValue), keywordargs[1]); if(x!=null) { x.Value+=val; x.Expiration=TimeSpan.FromMinutes(duration); } else { XmlAttach.AttachTo(o, new XmlValue(keywordargs[1], val, duration)); } } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.FLASH) { //the mobile, only player, will get a flash effect //syntax is FLASH,int (from 1 to 5) // 1 is fade to black // 2 is fade to white // 3 is light flash // 4 is light to black flash // 5 is black flash if(o is PlayerMobile) { PlayerMobile m=(PlayerMobile)o; if(m.NetState!=null && m.NetState.Running) { short flash=0; if(short.TryParse(keywordargs[1], out flash) && flash>0 && flash<6) { ScreenEffect se = new ScreenEffect((ScreenEffectType)(flash-1)); if(se!=null) { Packet.Acquire(se); m.Send(se); } Packet.Release(se); } } } if (arglist.Length < 2) break; remainder = singlearglist[1]; } else if (kw == typemodKeyword.PRIVMSG) { // syntax is PRIVMSG[,probability][,hue] // if the object is a mobile actively connected display the message double drop_probability = 1; int hue = 0x3b2; if (keywordargs.Length > 1) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid msg probability : " + arglist[1]; no_error = false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out hue)) { status_str = "Invalid MSG hue : " + arglist[1]; no_error = false; } } if (hue < 0) hue = 0; if (o is Mobile) { string msgstr = arglist[1]; // test the drop probability if (Utility.RandomDouble() < drop_probability) { Mobile mob = (Mobile)o; mob.PrivateOverheadMessage(MessageType.Regular, hue, false, msgstr, mob.NetState); } } if (arglist.Length < 3) break; remainder = arglist[2]; } else if (kw == typemodKeyword.BCAST) { // syntax is BCAST[,hue][,font]/message int hue = 0x482; int font = -1; // default unicode messages if (keywordargs.Length > 1) { if(!int.TryParse(keywordargs[1], out hue)) { status_str = "Invalid hue : " + arglist[1]; no_error = false; hue=0x482; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out font)) { status_str = "Invalid font : " + arglist[1]; no_error = false; font=-1; } } if (font >= 0) { // broadcast an ascii message to all players BroadcastAsciiMessage(AccessLevel.Player, hue, font, arglist[1]); } else { // broadcast a message to all players CommandHandlers.BroadcastMessage(AccessLevel.Player, hue, arglist[1]); } if (arglist.Length < 3) break; remainder = arglist[2]; } } //else // check for protected properties // if(arglist[0].ToLower() == "accesslevel") //{ // status_str = "accesslevel is a protected property"; // if(arglist.Length < 3) break; // remainder = arglist[2]; //} else { // check for the literal char if (singlearglist[1] != null && singlearglist[1].Length > 0 && singlearglist[1][0] == '@') { //support for literal terminator singlearglist = ParseLiteralTerminator(singlearglist[1]); string lstr = singlearglist[0]; if (terminated && lstr[lstr.Length - 1] == '/') lstr = lstr.Remove(lstr.Length - 1, 1); string result = SetPropertyValue(spawner, o, arglist[0], lstr.Remove(0, 1)); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } if(singlearglist.Length>1 && singlearglist[1] != null) { // if(singlearglist[1].Length>0 && singlearglist[1][0]=='/') // singlearglist[1].Remove(0, 1); remainder = singlearglist[1]; } else { remainder=null; break; } } else { string result = SetPropertyValue(spawner, o, arglist[0], arglist[1]); // see if it was successful if (result != "Property has been set.") { status_str = arglist[0] + " : " + result; no_error = false; } if (arglist.Length < 3) break; remainder = arglist[2]; } } } } } return (no_error); } #endregion #region Property testing public static bool TestMobProperty(XmlSpawner spawner, Mobile mobile, string testString, Mobile trigmob, out string status_str) { status_str = null; // now make sure the mobile itself is there if (mobile == null || mobile.Deleted) { return false; } bool testreturn = CheckPropertyString(spawner, mobile, testString, trigmob, out status_str); return testreturn; } public static bool TestItemProperty(XmlSpawner spawner, Item ObjectPropertyItem, string testString, Mobile trigmob, out string status_str) { status_str = null; // now make sure the item itself is there if (ObjectPropertyItem == null || ObjectPropertyItem.Deleted) { status_str = "Trigger Object not found"; return false; } bool testreturn = CheckPropertyString(spawner, ObjectPropertyItem, testString, trigmob, out status_str); return testreturn; } public static PropertyInfo LookupPropertyInfo(XmlSpawner spawner, Type type, string propname) { if (spawner == null || type == null || propname == null) return null; // look up the info in the current list if (spawner.PropertyInfoList == null) spawner.PropertyInfoList = new List(); PropertyInfo pinfo = null; TypeInfo tinfo = null; foreach (TypeInfo to in spawner.PropertyInfoList) { // check the type if (to.t == type) { // found it tinfo = to; // now search the property list foreach (PropertyInfo p in to.plist) { if (Insensitive.Equals(p.Name, propname)) { pinfo = p; } } } } // did we find the property? if (pinfo != null) { return pinfo; } else { // if it cant be found, then do the full search and add it to the list PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo p in props) { if (Insensitive.Equals(p.Name, propname)) { // did we find the type at least? if (tinfo == null) { // if not then add the type to the list tinfo = new TypeInfo(); tinfo.t = type; spawner.PropertyInfoList.Add(tinfo); } // and add the property to the tinfo property list tinfo.plist.Add(p); return p; } } } return null; } public static string ParseForKeywords(XmlSpawner spawner, object o, string valstr, Mobile trigmob, bool literal, out Type ptype) { ptype = null; if (valstr == null || valstr.Length <= 0) return null; string str = valstr.Trim(); // look for keywords // need to handle the case of nested arglists like arg,arg, // handle value keywords that may take comma args // itemarglist[1] will contain arg2/arg3/arg4>/arg5 // additemstr should have the full list of args /arg5 if they are there. In the case of /arg1/ADD/arg2 // it will just have arg2 string[] groupedarglist = ParseString(str, 2, "["); // take that argument list that should like like arg2/ag3/arg4>/arg5 // need to find the matching ">" string[] groupargs = null; string groupargstring = null; if (groupedarglist.Length > 1) { groupargs = ParseToMatchingParen(groupedarglist[1], '[', ']'); // and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4 groupargstring = groupargs[0]; } // need to handle comma args that may be grouped with the () such as the (ATTACHMENT,args) arg //string[] arglist = ParseString(groupedarglist[0],4,","); string[] arglist = groupedarglist[0].Trim().Split(','); if (groupargstring != null && groupargstring.Length > 0) { if (arglist != null && arglist.Length > 0) arglist[arglist.Length - 1] = groupargstring; } string pname = arglist[0].Trim(); char startc = str[0]; // first see whether it is a standard numeric value if ((startc == '.') || (startc == '-') || (startc == '+') || (startc >= '0' && startc <= '9')) { // determine the type if (str.IndexOf(".") >= 0) { ptype = typeof(Double); } else { ptype = typeof(Int32); } return str; } else // or a string if (startc == '"' || startc == '(') { ptype = typeof(String); return str; } else // or an enum if (startc == '#') { ptype = typeof(String); return str.Substring(1); } // or a bool else if ((str.ToLower()) == "true" || (str.ToLower() == "false")) { ptype = typeof(Boolean); return str; } // then look for a keyword else if (IsValueKeyword(pname)) { valueKeyword kw = valueKeywordHash[pname]; //if(pname == "GETONMOB" && arglist.Length > 2) if ((kw == valueKeyword.GETONMOB) && arglist.Length > 2) { // syntax is GETONMOB,mobname[,mobtype],property string propname = arglist[2]; string typestr = null; if (arglist.Length > 3) { typestr = arglist[2]; propname = arglist[3]; } Mobile testmobile = FindMobileByName(spawner, arglist[1], typestr); string getvalue = GetPropertyValue(spawner, testmobile, propname, out ptype); return ParseGetValue(getvalue, ptype); } else if ((kw == valueKeyword.GET) && arglist.Length > 2) { // syntax is GET,[itemname -OR- SETITEM][,itemtype],property string propname = arglist[2]; string typestr = null; if (arglist.Length > 3) { typestr = arglist[2]; propname = arglist[3]; } // is the itemname a serialno? object testitem = null; if (arglist[1].StartsWith("0x")) { int serial; if(!int.TryParse(arglist[1].Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out serial)) serial=-1; if (serial >= 0) testitem = World.FindEntity(serial); } else if(arglist[1]=="SETITEM" && spawner!=null && !spawner.Deleted && spawner.SetItem!=null) { testitem = spawner.SetItem; } else { testitem = FindItemByName(spawner, arglist[1], typestr); } string getvalue = GetPropertyValue(spawner, testitem, propname, out ptype); return ParseGetValue(getvalue, ptype); } else if ((kw == valueKeyword.GETONCARRIED) && arglist.Length > 2) { // syntax is GETONCARRIED,itemname[,itemtype][,equippedonly],property string propname = arglist[2]; string typestr = null; bool equippedonly = false; // if the itemtype arg has been specified then check it if (arglist.Length > 3) { propname = arglist[3]; typestr = arglist[2]; } if (arglist.Length > 4) { propname = arglist[4]; if (arglist[3].ToLower() == "equippedonly") { equippedonly = true; } else { bool.TryParse(arglist[3], out equippedonly); } } Item testitem = SearchMobileForItem(trigmob, ParseObjectType(arglist[1]), typestr, false, equippedonly); string getvalue = GetPropertyValue(spawner, testitem, propname, out ptype); return ParseGetValue(getvalue, ptype); } else if ((kw == valueKeyword.GETONNEARBY) && arglist.Length > 3) { // syntax is GETONNEARBY,range,name[,type][,searchcontainers],property // or GETONNEARBY,range,name[,type][,searchcontainers],[ATTACHMENT,type,name,property] string targetname = arglist[2]; string propname = arglist[3]; string typestr = null; bool searchcontainers = false; int range; if(!int.TryParse(arglist[1], out range)) range = -1; if (arglist.Length > 4) { typestr = arglist[3]; propname = arglist[4]; } if (arglist.Length > 5) { bool.TryParse(arglist[4], out searchcontainers); propname = arglist[5]; } Type targettype = null; if (typestr != null) { targettype = SpawnerType.GetType(typestr); } if (range >= 0) { // get all of the nearby objects object relativeto = spawner; if (o is XmlAttachment) { relativeto = ((XmlAttachment)o).AttachedTo; } List nearbylist = GetNearbyObjects(relativeto, targetname, targettype, typestr, range, searchcontainers, null); // apply the properties from the first valid thing on the list foreach (object nearbyobj in nearbylist) { string getvalue = GetPropertyValue(spawner, nearbyobj, propname, out ptype); return ParseGetValue(getvalue, ptype); } } else return null; } else if ((kw == valueKeyword.GETONTRIGMOB) && arglist.Length > 1) { // syntax is GETONTRIGMOB,property string getvalue = GetPropertyValue(spawner, trigmob, arglist[1], out ptype); return ParseGetValue(getvalue, ptype); } else if ((kw == valueKeyword.GETVAR) && arglist.Length > 1) { // syntax is GETVAR,varname string varname = arglist[1]; if (o is XmlAttachment) o = ((XmlAttachment)o).AttachedTo; // look for the xmllocalvariable attachment with the given name XmlLocalVariable var = (XmlLocalVariable)XmlAttach.FindAttachment(o, typeof(XmlLocalVariable), varname); if (var != null) { return var.Data; } else { return null; } } else if ((kw == valueKeyword.GETONPARENT) && arglist.Length > 1) { // syntax is GETONPARENT,property string getvalue = null; if (o is Item) { getvalue = GetPropertyValue(spawner, ((Item)o).Parent, arglist[1], out ptype); } else if (o is XmlAttachment) { getvalue = GetPropertyValue(spawner, ((XmlAttachment)o).AttachedTo, arglist[1], out ptype); } return ParseGetValue(getvalue, ptype); } else if ((kw == valueKeyword.GETONGIVEN) && arglist.Length > 1) { // syntax is GETONGIVEN,property Item taken = null; if (o is XmlAttachment) { taken = GetGiven(((XmlAttachment)o).AttachedTo); } else { taken = GetGiven(o); } string getvalue = GetPropertyValue(spawner, taken, arglist[1], out ptype); return ParseGetValue(getvalue, ptype); } else if ((kw == valueKeyword.GETONTAKEN) && arglist.Length > 1) { // syntax is GETONTAKEN,property Item taken = null; if (o is XmlAttachment) { taken = GetTaken(((XmlAttachment)o).AttachedTo); } else { taken = GetTaken(o); } string getvalue = GetPropertyValue(spawner, taken, arglist[1], out ptype); return ParseGetValue(getvalue, ptype); } else if ((kw == valueKeyword.GETONTHIS) && arglist.Length > 1) { // syntax is GETONTHIS,property string getvalue = GetPropertyValue(spawner, o, arglist[1], out ptype); return ParseGetValue(getvalue, ptype); } else if ((kw == valueKeyword.GETONSPAWN) && arglist.Length > 2) { // syntax is GETONSPAWN[,spawnername],subgroup,property // get the target from the spawn list string subgroupstr = arglist[1]; string propstr = arglist[2]; string spawnerstr = null; if (arglist.Length > 3) { spawnerstr = arglist[1]; subgroupstr = arglist[2]; propstr = arglist[3]; } int subgroup; if(!int.TryParse(subgroupstr, out subgroup)) subgroup = -1; if (subgroup == -1) return null; if (spawnerstr != null) { spawner = FindSpawnerByName(spawner, spawnerstr); } // check for the special COUNT property keyword if (propstr == "COUNT") { ptype = typeof(int); // get all of the currently active spawns with the specified subgroup List so = XmlSpawner.GetSpawnedList(spawner, subgroup); if (so == null) return "0"; // and return the count return so.Count.ToString(); } else { object targetobj = XmlSpawner.GetSpawned(spawner, subgroup); if (targetobj == null) return null; string getvalue = GetPropertyValue(spawner, targetobj, propstr, out ptype); return ParseGetValue(getvalue, ptype); } } else if ((kw == valueKeyword.GETFROMFILE) && arglist.Length > 1) { // syntax is GETFROMFILE,filename ptype = typeof(string); string filename = arglist[1]; string filestring = null; // read in the string from the file if (System.IO.File.Exists(filename) == true) { try { // Create an instance of StreamReader to read from a file. // The using statement also closes the StreamReader. using (StreamReader sr = new StreamReader(filename)) { string line; // Read and display lines from the file until the end of // the file is reached. while ((line = sr.ReadLine()) != null) { filestring += line; } sr.Close(); } } catch { } } return filestring; } else if ((kw == valueKeyword.GETACCOUNTTAG) && arglist.Length > 1) { // syntax is GETACCOUNTTAG,tagname ptype = typeof(string); string tagname = arglist[1]; string tagvalue = null; // get the value of the account tag from the triggering mob if (trigmob != null && !trigmob.Deleted) { Account acct = trigmob.Account as Account; if (acct != null) { tagvalue = '"' + acct.GetTag(tagname) + '"'; } } return tagvalue; } else if ((kw == valueKeyword.RND) && arglist.Length > 2) { // syntax is RND,min,max string randvalue = "0"; ptype = typeof(Int32); int min,max; if(int.TryParse(arglist[1], out min) && int.TryParse(arglist[2], out max)) randvalue=string.Format("{0}", Utility.RandomMinMax(min, max)); // return the random number as the value return randvalue; } else if ((kw == valueKeyword.RNDBOOL)) { // syntax is RNDBOOL ptype = typeof(bool); // return the random number as the value return Utility.RandomBool().ToString(); } else if ((kw == valueKeyword.RNDLIST) && arglist.Length > 1) { // syntax is RNDLIST,val1,val2,... ptype = typeof(Int32); // compute a random index into the arglist int randindex = Utility.Random(1, arglist.Length - 1); // return the list entry as the value return arglist[randindex]; } else if ((kw == valueKeyword.RNDSTRLIST) && arglist.Length > 1) { // syntax is RNDSTRLIST,val1,val2,... ptype = typeof(string); // compute a random index into the arglist int randindex = Utility.Random(1, arglist.Length - 1); if(trigmob!=null) { if(arglist[randindex].Contains("$TRIGNAME")) arglist[randindex]=arglist[randindex].Replace("$TRIGNAME", trigmob.Name); } // return the list entry as the value return arglist[randindex]; } else if ((kw == valueKeyword.AMOUNTCARRIED) && arglist.Length > 1) { // syntax is AMOUNTCARRIED,itemtype[,banksearch[,itemname]] ptype = typeof(Int32); int amount = 0; string typestr = arglist[1]; if (typestr != null) { string namestr="*"; bool banksearch = false; if(arglist.Length > 2) { if(!bool.TryParse(arglist[2], out banksearch) && arglist[2].ToLowerInvariant() != "banksearch") { return null; } else if(arglist.Length > 3) { namestr=arglist[3]; } } // get the list of items being carried of the specified type Type targetType = SpawnerType.GetType(typestr); if (targetType != null && trigmob != null && trigmob.Backpack != null) { Item[] items = trigmob.Backpack.FindItemsByType( targetType, true ); for ( int i = 0; i < items.Length; ++i ) { if(CheckNameMatch(namestr, items[i].Name)) amount += items[i].Amount; } if(banksearch && trigmob.BankBox!=null) { items = trigmob.BankBox.FindItemsByType( targetType, true ); for ( int i = 0; i < items.Length; ++i ) { if(CheckNameMatch(namestr, items[i].Name)) amount += items[i].Amount; } } } } return amount.ToString(); } else if ((kw == valueKeyword.PLAYERSINRANGE) && arglist.Length > 1) { // syntax is PLAYERSINRANGE,range ptype = typeof(Int32); int nplayers = 0; int range; // get the number of players in range int.TryParse(arglist[1], out range); // count nearby players if(spawner!=null && spawner.SpawnRegion!=null && range<0) { foreach(Mobile p in spawner.SpawnRegion.GetPlayers()) { if (p.AccessLevel <= spawner.TriggerAccessLevel) nplayers++; } } else if (o is Item) { IPooledEnumerable ie = ((Item)o).GetMobilesInRange(range); foreach (Mobile p in ie) { if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++; } ie.Free(); } else if (o is Mobile) { IPooledEnumerable ie = ((Mobile)o).GetMobilesInRange(range); foreach (Mobile p in ie) { if (p.Player && p.AccessLevel == AccessLevel.Player) nplayers++; } ie.Free(); } return nplayers.ToString(); } else if ((kw == valueKeyword.TRIGSKILL) && arglist.Length > 1) { if (spawner != null && spawner.TriggerSkill != null) { // syntax is TRIGSKILL,name|value|cap|base if (arglist[1].ToLower() == "name") { ptype = typeof(string); return spawner.TriggerSkill.Name; } else if (arglist[1].ToLower() == "value") { ptype = typeof(double); return spawner.TriggerSkill.Value.ToString(); } else if (arglist[1].ToLower() == "cap") { ptype = typeof(double); return spawner.TriggerSkill.Cap.ToString(); } else if (arglist[1].ToLower() == "base") { ptype = typeof(double); return spawner.TriggerSkill.Base.ToString(); } } return null; } if ((kw == valueKeyword.RANDNAME) && arglist.Length > 1) { // syntax is RANDNAME,nametype return NameList.RandomName(arglist[1]); } else { // an invalid keyword format will be passed as literal return str; } } else if (literal) { ptype = typeof(String); return str; } else { // otherwise treat it as a property name string result = GetPropertyValue(spawner, o, pname, out ptype); return ParseGetValue(result, ptype); } } public static string ParseGetValue(string str, Type ptype) { // the results of getPropertyValue takes the form // propname = value // or // propname = value (hexvalue) if (str == null) return null; // find the separator string[] arglist = str.Split("=".ToCharArray(), 2); if (arglist.Length > 1) { if (IsNumeric(ptype)) { // parse the value portion and get rid of the possible (hexvalue) portion of the string string[] arglist2 = arglist[1].Trim().Split(" ".ToCharArray(), 2); return arglist2[0]; } else { // for everything else // pass on as is return arglist[1].Trim(); } } else { return null; } } public static bool CheckSubstitutedPropertyString(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str) { string substitutedtest = ApplySubstitution(spawner, o, trigmob, testString); return CheckPropertyString(spawner, o, substitutedtest, trigmob, out status_str); } public static bool CheckPropertyString(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str) { status_str = null; if (o == null) return false; if (testString == null || testString.Length < 1) { status_str = "Null property test string"; return false; } // parse the property test string for and(&)/or(|) operators string[] arglist = ParseString(testString, 2, "&|"); if (arglist.Length < 2) { bool returnval = CheckSingleProperty(spawner, o, testString, trigmob, out status_str); // simple conditional test with no and/or operators return returnval; } else { // test each half independently and combine the results bool first = CheckSingleProperty(spawner, o, arglist[0], trigmob, out status_str); // this will recursively parse the property test string with implicit nesting for multiple logical tests of the // form A * B * C * D being grouped as A * (B * (C * D)) bool second = CheckPropertyString(spawner, o, arglist[1], trigmob, out status_str); int andposition = testString.IndexOf("&"); int orposition = testString.IndexOf("|"); // combine them based upon the operator if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition)) { // and operator return (first && second); } else if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition)) { // or operator return (first || second); } else { // should never get here return false; } } } public static bool CheckSingleProperty(XmlSpawner spawner, object o, string testString, Mobile trigmob, out string status_str) { status_str = null; if (o == null || testString == null || testString.Length == 0) return false; //get the prop name and test value // format will be prop=prop, or prop>prop, prop 0 && testString[0] == '~') { invertreturn = true; testString = testString.Substring(1, testString.Length - 1); } string[] arglist = ParseString(testString, 2, "=> 0) { hasequal = true; } else if (testString.IndexOf("!") > 0) { hasnotequals = true; } else if (testString.IndexOf(">") > 0) { hasgreaterthan = true; } else if (testString.IndexOf("<") > 0) { haslessthan = true; } // does it have a valid operator? if (!hasequal && !hasgreaterthan && !haslessthan && !hasnotequals) return false; Type ptype1; Type ptype2; string value1 = ParseForKeywords(spawner, o, arglist[0].Trim(), trigmob, false, out ptype1); // see if it was successful if (ptype1 == null) { status_str = arglist[0] + " : " + value1; return invertreturn; //return false; } string value2 = ParseForKeywords(spawner, o, arglist[1].Trim(), trigmob, false, out ptype2); // see if it was successful if (ptype2 == null) { status_str = arglist[1] + " : " + value2; return invertreturn; //return false; } // look for hex numeric specifications int base1 = 10; int base2 = 10; if (IsNumeric(ptype1) && !string.IsNullOrEmpty(value1) && value1.StartsWith("0x")) { base1 = 16; } if (IsNumeric(ptype2) && !string.IsNullOrEmpty(value2) && value2.StartsWith("0x")) { base2 = 16; } // and do the type dependent comparisons if (ptype2 == typeof(TimeSpan) || ptype1 == typeof(TimeSpan)) { if (hasequal) { TimeSpan ts1,ts2; if(TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2)) { if(ts1==ts2) return !invertreturn; } else { status_str = "invalid timespan comparison : {0}" + testString; } } else if (hasnotequals) { TimeSpan ts1,ts2; if(TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2)) { if(ts1!=ts2) return !invertreturn; } else { status_str = "invalid timespan comparison : {0}" + testString; } } else if (hasgreaterthan) { TimeSpan ts1,ts2; if(TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2)) { if(ts1>ts2) return !invertreturn; } else { status_str = "invalid timespan comparison : {0}" + testString; } } else if (haslessthan) { TimeSpan ts1,ts2; if(TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2)) { if(ts1dt2) return !invertreturn; } else { status_str = "invalid DateTime comparison : {0}" + testString; } } else if (haslessthan) { DateTime dt1,dt2; if(DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) { if(dt1 Convert.ToInt64(value2, base2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } else if (haslessthan) { try { if (Convert.ToInt64(value1, base1) < Convert.ToInt64(value2, base2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } } else if ((ptype2 == typeof(double)) && IsNumeric(ptype1)) { //TODO: howto convert correctly with int64.tryparse? if (hasequal) { try { if (Convert.ToInt64(value1, base1) == double.Parse(value2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } else if (hasnotequals) { try { if (Convert.ToInt64(value1, base1) != double.Parse(value2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } else if (hasgreaterthan) { try { if (Convert.ToInt64(value1, base1) > double.Parse(value2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } else if (haslessthan) { try { if (Convert.ToInt64(value1, base1) < double.Parse(value2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } } else if ((ptype1 == typeof(double)) && IsNumeric(ptype2)) { //TODO: howto convert correctly with int64.tryparse? if (hasequal) { try { if (double.Parse(value1) == Convert.ToInt64(value2, base2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } else if (hasnotequals) { try { if (double.Parse(value1) != Convert.ToInt64(value2, base2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } else if (hasgreaterthan) { try { if (double.Parse(value1) > Convert.ToInt64(value2, base2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } else if (haslessthan) { try { if (double.Parse(value1) < Convert.ToInt64(value2, base2)) return !invertreturn; } catch { status_str = "invalid int comparison : {0}" + testString; } } } else if ((ptype1 == typeof(double)) && (ptype2 == typeof(double))) { double val1=0,val2=0; if (hasequal) { if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2)) { if(val1==val2) return !invertreturn; } else { status_str = "invalid int comparison : {0}" + testString; } } else if (hasnotequals) { if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2)) { if(val1!=val2) return !invertreturn; } else { status_str = "invalid int comparison : {0}" + testString; } } else if (hasgreaterthan) { if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2)) { if(val1>val2) return !invertreturn; } else { status_str = "invalid int comparison : {0}" + testString; } } else if (haslessthan) { if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2)) { if(val1val2) return !invertreturn; } else{ status_str = "invalid double comparison : {0}" + testString; } } else if (haslessthan) { if(double.TryParse(value1, NumberStyles.Any, CultureInfo.InvariantCulture, out val1) && double.TryParse(value2, NumberStyles.Any, CultureInfo.InvariantCulture, out val2)) { if(val1 nearbylist, string proptest) { string status_str; if (source != null && source.Items != null && nearbylist != null) { foreach (Item i in source.Items) { // check the type and name Type itemtype = i.GetType(); if (!i.Deleted && CheckNameMatch(targetname, i.Name) && (typestr == null || (itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype))))) { if (proptest == null || CheckPropertyString(null, i, proptest, null, out status_str)) nearbylist.Add(i); } if (i is Container) { GetItemsIn(i, targetname, targettype, typestr, ref nearbylist, proptest); } } } } private static List GetNearbyObjects(object invoker, string targetname, Type targettype, string typestr, int range, bool searchcontainers, string proptest) { IPooledEnumerable itemlist = null; IPooledEnumerable mobilelist = null; List nearbylist = new List(); string status_str; // get nearby items if (targettype == null || targettype == typeof(Item) || targettype.IsSubclassOf(typeof(Item))) { if (invoker is Item) { itemlist = ((Item)invoker).GetItemsInRange(range); } else if (invoker is Mobile) { itemlist = ((Mobile)invoker).GetItemsInRange(range); } if (itemlist != null) { foreach (Item i in itemlist) { // check the type and name Type itemtype = i.GetType(); if (searchcontainers) { if (i is Container) GetItemsIn(i, targetname, targettype, typestr, ref nearbylist, proptest); } else if (!i.Deleted && CheckNameMatch(targetname, i.Name) && (typestr == null || (itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype))))) { if (proptest == null || CheckPropertyString(null, i, proptest, null, out status_str)) nearbylist.Add(i); } } itemlist.Free(); } } // get nearby mobiles if (targettype == null || targettype == typeof(Mobile) || targettype.IsSubclassOf(typeof(Mobile))) { if (invoker is Item) { mobilelist = ((Item)invoker).GetMobilesInRange(range); } else if (invoker is Mobile) { mobilelist = ((Mobile)invoker).GetMobilesInRange(range); } if (mobilelist != null) { foreach (Mobile m in mobilelist) { // check the type and name Type mobtype = m.GetType(); if (!m.Deleted && CheckNameMatch(targetname, m.Name) && (typestr == null || (mobtype != null && targettype != null && (mobtype.Equals(targettype) || mobtype.IsSubclassOf(targettype))))) { if (proptest == null || CheckPropertyString(null, m, proptest, null, out status_str)) nearbylist.Add(m); } } mobilelist.Free(); } } return nearbylist; } public static Item SearchMobileForItem(Mobile m, string targetName, string typeStr, bool searchbank) { return SearchMobileForItem(m, targetName, typeStr, searchbank, false); } public static Item SearchMobileForItem(Mobile m, string targetName, string typeStr, bool searchbank, bool equippedonly) { if (m != null && !m.Deleted) { // go through all of the items in the pack List packlist = m.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = packlist[i]; // dont search bank boxes if (item is BankBox && !searchbank && !equippedonly) continue; // recursively search containers if (item != null && !item.Deleted) { if (item is Container && !equippedonly) { Item itemTarget = SearchPackForItem((Container)item, targetName, typeStr); if (itemTarget != null) return itemTarget; } // test the item name against the trigger string // if a typestring has been specified then check against that as well if (CheckNameMatch(targetName, item.Name)) { if ((typeStr == null || CheckType(item, typeStr))) { //found it return item; } } } } // now check any item that might be held Item held = m.Holding; if (held != null && !held.Deleted && !equippedonly) { if (held is Container) { Item itemTarget = SearchPackForItem((Container)held, targetName, typeStr); if (itemTarget != null) return itemTarget; } // test the item name against the trigger string if (CheckNameMatch(targetName, held.Name)) { if (typeStr == null || CheckType(held, typeStr)) { //found it return held; } } } } return null; } public static List SearchMobileForItems(Mobile m, string targetName, string typeStr, bool searchbank, bool equippedonly) { List itemlist = new List(); if (m != null && !m.Deleted) { // go through all of the items in the pack List packlist = m.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = packlist[i]; // dont search bank boxes if (item is BankBox && (!searchbank || equippedonly)) continue; // recursively search containers if (item != null && !item.Deleted) { if (item is Container && !equippedonly) { itemlist.AddRange(SearchPackForItems((Container)item, targetName, typeStr)); } // test the item name against the trigger string // if a typestring has been specified then check against that as well else if (CheckNameMatch(targetName, item.Name)) { if ((typeStr == null || CheckType(item, typeStr))) { //found it itemlist.Add(item); } } } } // now check any item that might be held Item held = m.Holding; if (held != null && !held.Deleted && !equippedonly) { if (held is Container) { itemlist.AddRange(SearchPackForItems((Container)held, targetName, typeStr)); } // test the item name against the trigger string else if (CheckNameMatch(targetName, held.Name)) { if (typeStr == null || CheckType(held, typeStr)) { //found it itemlist.Add(held); } } } } return itemlist; } public static Item SearchPackForItemType(Container pack, string targetName) { if (pack != null && !pack.Deleted && targetName != null && targetName.Length > 0) { Type targetType = SpawnerType.GetType(targetName); // go through all of the items in the pack List packlist = pack.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = (Item)packlist[i]; if (item != null && !item.Deleted) { if (item is Container) { Item itemTarget = SearchPackForItemType((Container)item, targetName); if (itemTarget != null) return itemTarget; } // test the item name against the trigger string if (item.GetType() == targetType) { //found it return item; } } } } return null; } public static Item SearchMobileForItemType(Mobile m, string targetName, bool searchbank) { if (m != null && !m.Deleted && targetName != null && targetName.Length > 0) { Type targetType = SpawnerType.GetType(targetName); // go through all of the items in the pack List packlist = m.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = (Item)packlist[i]; // dont search bank boxes if (item is BankBox && !searchbank) continue; // recursively search containers if (item != null && !item.Deleted) { if (item is Container) { Item itemTarget = SearchPackForItemType((Container)item, targetName); if (itemTarget != null) return itemTarget; } // test the item type against the trigger string if ((item.GetType() == targetType)) { //found it return item; } } } // now check any item that might be held Item held = m.Holding; if (held != null && !held.Deleted) { if (held is Container) { Item itemTarget = SearchPackForItemType((Container)held, targetName); if (itemTarget != null) return itemTarget; } // test the item name against the trigger string if (held.GetType() == targetType) { //found it return held; } } } return null; } public static Item SearchPackForItem(Container pack, string targetName, string typestr) { if (pack != null && !pack.Deleted) { Type targettype = null; if (typestr != null) { targettype = SpawnerType.GetType(typestr); } // go through all of the items in the pack List packlist = pack.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = (Item)packlist[i]; if (item != null && !item.Deleted) { if (item is Container) { Item itemTarget = SearchPackForItem((Container)item, targetName, typestr); if (itemTarget != null) return itemTarget; } // test the item name against the trigger string if (CheckNameMatch(targetName, item.Name)) { if (targettype == null || (item.GetType().Equals(targettype) || item.GetType().IsSubclassOf(targettype))) { //found it return item; } } } } } return null; } public static List SearchPackForItems(Container pack, string targetName, string typestr) { List itemlist = new List(); if (pack != null && !pack.Deleted) { Type targettype = null; if (typestr != null) { targettype = SpawnerType.GetType(typestr); } // go through all of the items in the pack List packlist = pack.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = (Item)packlist[i]; if (item != null && !item.Deleted) { if (item is Container) { itemlist.AddRange(SearchPackForItems((Container)item, targetName, typestr)); } // test the item name against the trigger string since it's not a container else if (CheckNameMatch(targetName, item.Name)) { if (targettype == null || (item.GetType().Equals(targettype) || item.GetType().IsSubclassOf(targettype))) { //found it itemlist.Add(item); } } } } } return itemlist; } public static List SearchPackListForItemType(Container pack, string targetName, List itemlist) { if (pack != null && !pack.Deleted && targetName != null && targetName.Length > 0) { Type targetType = SpawnerType.GetType(targetName); if (targetType == null) return null; // go through all of the items in the pack List packlist = pack.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = packlist[i]; if (item != null && !item.Deleted && item is Container) { itemlist = SearchPackListForItemType((Container)item, targetName, itemlist); } // test the item name against the trigger string if (item != null && !item.Deleted && (item.GetType().IsSubclassOf(targetType) || item.GetType().Equals(targetType))) { //found it itemlist.Add(item); } } } return itemlist; } public static List FindItemListByType(Mobile m, string targetName, bool searchbank) { List itemlist = new List(); if (m != null && !m.Deleted && targetName != null && targetName.Length > 0) { Type targetType = SpawnerType.GetType(targetName); // go through all of the items on the mobile List packlist = m.Items; for (int i = 0; i < packlist.Count; ++i) { Item item = packlist[i]; // dont search bank boxes if (item is BankBox && !searchbank) continue; // recursively search containers if (item != null && !item.Deleted) { if (item is Container) { itemlist = SearchPackListForItemType((Container)item, targetName, itemlist); } // test the item name against the trigger string if (item.GetType().IsSubclassOf(targetType) || item.GetType().Equals(targetType)) { //found it // add the item to the list itemlist.Add(item); } } } // now check any item that might be held Item held = m.Holding; if (held != null && !held.Deleted) { if (held is Container) { itemlist = SearchPackListForItemType((Container)held, targetName, itemlist); } // test the item name against the trigger string if (held.GetType().IsSubclassOf(targetType) || held.GetType().Equals(targetType)) { //found it // add the item to the list itemlist.Add(held); } } } return itemlist; } public static bool CheckForNotCarried(Mobile m, string objectivestr) { if (m == null || objectivestr == null) return true; // parse the objective string that might be of the form 'obj &| obj &| obj ...' string[] arglist = ParseString(objectivestr, 2, "&|"); if (arglist.Length < 2) { // simple test with no and/or operators return SingleCheckForNotCarried(m, objectivestr); } else { // test each half independently and combine the results bool first = SingleCheckForNotCarried(m, arglist[0]); // this will recursively parse the property test string with implicit nesting for multiple logical tests of the // form A * B * C * D being grouped as A * (B * (C * D)) bool second = CheckForNotCarried(m, arglist[1]); int andposition = objectivestr.IndexOf("&"); int orposition = objectivestr.IndexOf("|"); // for the & operator // notrigger if // notcarrying A | notcarrying B // people will actually think of it as not(carrying A | carrying B) // which is // notrigger if // notcarrying A && notcarrying B // similarly for the & operator // combine them based upon the operator if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition)) { // and operator (see explanation above) return (first || second); } else if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition)) { // or operator (see explanation above) return (first && second); } else { // should never get here return false; } } } public static bool SingleCheckForNotCarried(Mobile m, string objectivestr) { if (m == null || objectivestr == null) return true; bool has_no_such_item = true; // check to see whether there is an objective specification as well. The format is name[,type][,EQUIPPED][,objective,objective,...] string[] objstr = ParseString(objectivestr, 8, ","); string itemname = objstr[0]; // check for attachment keyword if (itemname == "ATTACHMENT") { // syntax is ATTACHMENT,name,type if (objstr.Length > 1) { string aname = objstr[1]; Type atype = null; if (objstr.Length > 2) { atype = SpawnerType.GetType(objstr[2]); } // try to find the attachment on the mob if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) return false; else return true; } else return true; } bool equippedonly = false; string typestr = null; int objoffset = 1; // is there a type specification? while (objoffset < objstr.Length) { if (objstr[objoffset] != null && objstr[objoffset].Length > 0) { char startc = objstr[objoffset][0]; if (startc >= '0' && startc <= '9') { // this is the start of the numeric objective specifications break; } else if (objstr[objoffset] == "EQUIPPED") { equippedonly = true; } else { // treat as a type specification if it does not begin with a numeric char // and is not the EQUIPPED keyword typestr = objstr[objoffset]; } } objoffset++; } // look for the item Item testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly); // found the item if (testitem != null) { // check to see if it is a quest token item. If so, then check validity, otherwise just finding it is enough if (testitem is IXmlQuest && ((IXmlQuest)testitem).IsValid) { IXmlQuest token = (IXmlQuest)testitem; if (objstr.Length > objoffset) { has_no_such_item = true; // get any objectives and test for them. If any of the required conditions are true, then block trigger for (int n = objoffset; n < objstr.Length; n++) { int x=0; if(int.TryParse(objstr[n], out x)) { switch (x - objoffset + 1) { case 1: if (token.Completed1) has_no_such_item = false; break; case 2: if (token.Completed2) has_no_such_item = false; break; case 3: if (token.Completed3) has_no_such_item = false; break; case 4: if (token.Completed4) has_no_such_item = false; break; case 5: if (token.Completed5) has_no_such_item = false; break; } } } } else has_no_such_item = false; } else { // is the equippedonly flag set? If so then see if the item is equipped if ((equippedonly && testitem.Parent == m) || !equippedonly) has_no_such_item = false; } } return has_no_such_item; } public static bool CheckForCarried(Mobile m, string objectivestr) { if (m == null || objectivestr == null) return true; // parse the objective string that might be of the form 'obj &| obj &| obj ...' string[] arglist = ParseString(objectivestr, 2, "&|"); if (arglist.Length < 2) { // simple test with no and/or operators return SingleCheckForCarried(m, objectivestr); } else { // test each half independently and combine the results bool first = SingleCheckForCarried(m, arglist[0]); // this will recursively parse the property test string with implicit nesting for multiple logical tests of the // form A * B * C * D being grouped as A * (B * (C * D)) bool second = CheckForCarried(m, arglist[1]); int andposition = objectivestr.IndexOf("&"); int orposition = objectivestr.IndexOf("|"); // combine them based upon the operator if ((andposition > 0 && orposition <= 0) || (andposition > 0 && andposition < orposition)) { // and operator return (first && second); } else if ((orposition > 0 && andposition <= 0) || (orposition > 0 && orposition < andposition)) { // or operator return (first || second); } else { // should never get here return false; } } } public static bool SingleCheckForCarried(Mobile m, string objectivestr) { if (m == null || objectivestr == null) return false; bool has_valid_item = false; // check to see whether there is an objective specification as well. The format is name[,type][,EQUIPPED][,objective,objective,...] string[] objstr = ParseString(objectivestr, 8, ","); string itemname = objstr[0]; // check for attachment keyword if (itemname == "ATTACHMENT") { // syntax is ATTACHMENT,name,type if (objstr.Length > 1) { string aname = objstr[1]; Type atype = null; if (objstr.Length > 2) { atype = SpawnerType.GetType(objstr[2]); } // try to find the attachment on the mob if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) return true; else return false; } else return false; } bool equippedonly = false; string typestr = null; int objoffset = 1; // is there a type specification? while (objoffset < objstr.Length) { if (objstr[objoffset] != null && objstr[objoffset].Length > 0) { char startc = objstr[objoffset][0]; if (startc >= '0' && startc <= '9') { // this is the start of the numeric objective specifications break; } else if (objstr[objoffset].ToLowerInvariant() == "equipped") { equippedonly = true; } else { // treat as a type specification if it does not begin with a numeric char // and is not the EQUIPPED keyword typestr = objstr[objoffset]; } } objoffset++; } Item testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly); // found the item if (testitem != null) { // check to see if it is a quest token item. If so, then check validity, otherwise just finding it is enough if (testitem is IXmlQuest) { IXmlQuest token = (IXmlQuest)testitem; if (token.IsValid) { if (objstr.Length > objoffset) { has_valid_item = true; // get any objectives and test for them. If any of the required conditions are false, then dont trigger for (int n = objoffset; n < objstr.Length; n++) { int x=0; if(int.TryParse(objstr[n], out x)) { switch (x - objoffset + 1) { case 1: if (!token.Completed1) has_valid_item = false; break; case 2: if (!token.Completed2) has_valid_item = false; break; case 3: if (!token.Completed3) has_valid_item = false; break; case 4: if (!token.Completed4) has_valid_item = false; break; case 5: if (!token.Completed5) has_valid_item = false; break; } } } } else // if an objective list has not been specified then just a valid item is enough has_valid_item = true; } } else { // is the equippedonly flag set? If so then see if the item is equipped if ((equippedonly && testitem.Parent == m) || !equippedonly) has_valid_item = true; } } return has_valid_item; } public static Item FindItemByName(XmlSpawner fromspawner, string name, string typestr) { if (name == null) return null; int count = 0; Item founditem = FindInRecentItemSearchList(fromspawner, name, typestr); if (founditem != null) { return founditem; } Type targettype = null; if (typestr != null) { targettype = SpawnerType.GetType(typestr); } // search through all items in the world and find the first one with a matching name foreach (Item item in World.Items.Values) { Type itemtype = item.GetType(); if (!item.Deleted && (name.Length == 0 || String.Compare(item.Name, name, true) == 0)) { if (typestr == null || (itemtype != null && targettype != null && (itemtype.Equals(targettype) || itemtype.IsSubclassOf(targettype)))) { founditem = item; count++; // added the break in to return the first match instead of forcing uniqueness (overrides the count test) break; } } //if(count > 1) break; } // if a unique item is found then success if (count == 1) { // add this to the recent search list AddToRecentItemSearchList(fromspawner, founditem); return (founditem); } else return null; } public static Mobile FindMobileByName(XmlSpawner fromspawner, string name, string typestr) { if (name == null) return null; int count = 0; Mobile foundmobile = FindInRecentMobileSearchList(fromspawner, name, typestr); if (foundmobile != null) return foundmobile; Type targettype = null; if (typestr != null) { targettype = SpawnerType.GetType(typestr); } // search through all mobiles in the world and find one with a matching name foreach (Mobile mobile in World.Mobiles.Values) { Type mobtype = mobile.GetType(); if (!mobile.Deleted && ((name.Length == 0 || String.Compare(mobile.Name, name, true) == 0)) && (typestr == null || (mobtype != null && targettype != null && (mobtype.Equals(targettype) || mobtype.IsSubclassOf(targettype))))) { foundmobile = mobile; count++; // added the break in to return the first match instead of forcing uniqueness (overrides the count test) break; } //if(count > 1) break; } // if a unique item is found then success if (count == 1) { // add this to the recent search list AddToRecentMobileSearchList(fromspawner, foundmobile); return (foundmobile); } else return null; } public static XmlSpawner FindSpawnerByName(XmlSpawner fromspawner, string name) { if (name==null) return null; if (name.StartsWith("0x")) { int serial = -1; try { serial = Convert.ToInt32(name, 16); } catch { } return World.FindEntity(serial) as XmlSpawner; } else { // do a quick search through the recent search list to see if it is there XmlSpawner foundspawner = FindInRecentSpawnerSearchList(fromspawner, name); if (foundspawner != null) return foundspawner; int count=0; // search through all xmlspawners in the world and find one with a matching name foreach (Item item in World.Items.Values) { if (item is XmlSpawner) { XmlSpawner spawner = (XmlSpawner)item; if (!spawner.Deleted && (String.Compare(spawner.Name, name, true) == 0)) { foundspawner = spawner; count++; // added the break in to return the first match instead of forcing uniqueness (overrides the count test) break; } //if(count > 1) break; } } // if a unique item is found then success if (count == 1) { // add this to the recent search list AddToRecentSpawnerSearchList(fromspawner, foundspawner); return (foundspawner); } else return null; } } public static void AddToRecentSpawnerSearchList(XmlSpawner spawner, XmlSpawner target) { if (spawner == null || target == null) return; if (spawner.RecentSpawnerSearchList == null) { spawner.RecentSpawnerSearchList = new List(); } spawner.RecentSpawnerSearchList.Add(target); // check the length and truncate if it gets too long if (spawner.RecentSpawnerSearchList.Count > 100) { spawner.RecentSpawnerSearchList.RemoveAt(0); } } public static XmlSpawner FindInRecentSpawnerSearchList(XmlSpawner spawner, string name) { if (spawner == null || name == null || spawner.RecentSpawnerSearchList == null) return null; List deletelist = null; XmlSpawner foundspawner = null; foreach (XmlSpawner s in spawner.RecentSpawnerSearchList) { if (s.Deleted) { // clean it up if (deletelist == null) deletelist = new List(); deletelist.Add(s); } else if (String.Compare(s.Name, name, true) == 0) { foundspawner = s; break; } } if (deletelist != null) { foreach (XmlSpawner i in deletelist) spawner.RecentSpawnerSearchList.Remove(i); } return (foundspawner); } public static void AddToRecentItemSearchList(XmlSpawner spawner, Item target) { if (spawner == null || target == null) return; if (spawner.RecentItemSearchList == null) { spawner.RecentItemSearchList = new List(); } spawner.RecentItemSearchList.Add(target); // check the length and truncate if it gets too long if (spawner.RecentItemSearchList.Count > 100) { spawner.RecentItemSearchList.RemoveAt(0); } } public static Item FindInRecentItemSearchList(XmlSpawner spawner, string name, string typestr) { if (spawner == null || name == null || spawner.RecentItemSearchList == null) return null; List deletelist = null; Item founditem = null; Type targettype = null; if (typestr != null) { targettype = SpawnerType.GetType(typestr); } foreach (Item item in spawner.RecentItemSearchList) { if (item.Deleted) { // clean it up if (deletelist == null) deletelist = new List(); deletelist.Add(item); } else if (name.Length == 0 || String.Compare(item.Name, name, true) == 0) { if (typestr == null || (item.GetType() != null && targettype != null && (item.GetType().Equals(targettype) || item.GetType().IsSubclassOf(targettype)))) { founditem = item; break; } } } if (deletelist != null) { foreach (Item i in deletelist) spawner.RecentItemSearchList.Remove(i); } return (founditem); } public static void AddToRecentMobileSearchList(XmlSpawner spawner, Mobile target) { if (spawner == null || target == null) return; if (spawner.RecentMobileSearchList == null) { spawner.RecentMobileSearchList = new List(); } spawner.RecentMobileSearchList.Add(target); // check the length and truncate if it gets too long if (spawner.RecentMobileSearchList.Count > 100) { spawner.RecentMobileSearchList.RemoveAt(0); } } public static Mobile FindInRecentMobileSearchList(XmlSpawner spawner, string name, string typestr) { if (spawner == null || name == null || spawner.RecentMobileSearchList == null) return null; List deletelist = null; Mobile foundmobile = null; Type targettype = null; if (typestr != null) { targettype = SpawnerType.GetType(typestr); } foreach (Mobile m in spawner.RecentMobileSearchList) { if (m.Deleted) { // clean it up if (deletelist == null) deletelist = new List(); deletelist.Add(m); } else if (name.Length == 0 || String.Compare(m.Name, name, true) == 0) { if (typestr == null || (m.GetType() != null && targettype != null && (m.GetType().Equals(targettype) || m.GetType().IsSubclassOf(targettype)))) { foundmobile = m; break; } } } if (deletelist != null) { foreach (Mobile i in deletelist) spawner.RecentMobileSearchList.Remove(i); } return (foundmobile); } #endregion #region Add object methods public static bool AddAttachmentToTarget(XmlSpawner spawner, object o, string[] keywordargs, string[] arglist, Mobile trigmob, object refobject, out string remainder, out string status_str) { remainder = ""; status_str = null; if (o == null || keywordargs == null || arglist == null) return false; // Use the format /ATTACH,drop_probability/attachmenttype,name[,args]/ // or /ATTACH,drop_probability// double drop_probability = 1; if (keywordargs.Length > 1) { bool converterror = false; try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } catch { status_str = "Invalid drop probability : " + arglist[1]; converterror = true; } if (converterror) return false; } // o is the object to which the attachment will be attached // handle the nested item property specification using <> string attachargstring = null; // attachtypestr will be the actual attachment type to be created. In the simple form it will be arglist[1] // for the string /arg1/ATTACH/arg2/arg3/arg4/arg5 arglist [0] will contain ATTACH , arglist[1] will be arg2, // and arglist[2] will be arg3/arg4/arg5 // if nested property specs // arglist[1] will be /arg5 // the drop probability will be in probargs string[] probargs = ParseString(arglist[0], 2, ","); string attachtypestr = arglist[1]; // get the argument list after the < if any , note for the string /arg1/ATTACH//arg5 arglist [0] will contain ATTACH // arglist[1] will be /arg5 // but note arglist[1] could also be // remainder will have ATTACH//arg5 // // can also deal with nested cases of ATTACH/> and ATTACH//ADD/> although there is no clear // reason why this syntax should be used at this time string addattachstr = arglist[1]; if (arglist.Length > 2) addattachstr = arglist[1] + "/" + arglist[2]; // check to see if the first char is a "<" if (addattachstr.IndexOf("<") == 0) { // attacharglist[1] will contain arg2/arg3/arg4>/arg5 // addattachstr should have the full list of args /arg5 if they are there. In the case of /arg1/ADD/arg2 // it will just have arg2 string[] attacharglist = ParseString(addattachstr, 2, "<"); // take that argument list that should like like arg2/ag3/arg4>/arg5 // need to find the matching ">" //string[] attachargs = ParseString(attacharglist[1],2,">"); string[] attachargs = ParseToMatchingParen(attacharglist[1], '<', '>'); // and get the first part of the string without the > so attachargs[0] should be arg2/ag3/arg4 attachargstring = attachargs[0]; // and attachargs[1] should be the remainder if (attachargs.Length > 1) { // but have to get rid of any trailing / that might be after the > string[] trailstr = ParseSlashArgs(attachargs[1], 2); if (trailstr.Length > 1) remainder = trailstr[1]; else remainder = attachargs[1]; } else remainder = ""; // get the type info by pulling out the first arg in attachargstring string[] tempattacharg = ParseSlashArgs(attachargstring, 2); // and get the type info from it attachtypestr = tempattacharg[0]; } else { // otherwise its just a regular case with arglist[2] containing the rest of the arguments if (arglist.Length > 2) remainder = arglist[2]; else remainder = ""; } // test the drop probability if (Utility.RandomDouble() >= drop_probability) return true; Type type = null; if (attachtypestr != null) { type = SpawnerType.GetType(ParseObjectType(attachtypestr)); } // if so then create it if (type != null && type.IsSubclassOf(typeof(XmlAttachment))) { object newo = XmlSpawner.CreateObject(type, attachtypestr, false, true); if (newo is XmlAttachment) { XmlAttachment attachment = (XmlAttachment)newo; // could call applyobjectstringproperties on a nested propertylist here to set attachment attributes if (attachargstring != null) { ApplyObjectStringProperties(spawner, attachargstring, attachment, trigmob, refobject, out status_str); } // add the attachment to the target if (!XmlAttach.AttachTo(spawner, o, attachment)) { status_str = String.Format("Attachment {0} not added", attachtypestr); return false; } } else { status_str = "Invalid ATTACH. No such attachment : " + attachtypestr; return false; } } else { status_str = "Invalid ATTACH. No such attachment : " + attachtypestr; return false; } return true; } public static bool AddItemToTarget(XmlSpawner spawner, object o, string[] keywordargs, string[] arglist, Mobile trigmob, object refobject, bool equip, out string remainder, out string status_str) { remainder = ""; status_str = null; if (o == null || keywordargs == null || arglist == null) return false; // if the object is a mobile then add the item in the next arg to its pack. Use the format /ADD,drop_probability/itemtype/ // or /ADD,drop_probability// double drop_probability = 1; if (keywordargs.Length > 1) { bool converterror = false; try { drop_probability = Convert.ToDouble(keywordargs[1], CultureInfo.InvariantCulture); } catch { status_str = "Invalid drop probability : " + arglist[1]; converterror = true; } if (converterror) return false; } Mobile m = null; if (o is Mobile || (o is Container)) { Container pack = null; if (o is Mobile) { m = (Mobile)o; if (!m.Deleted) { pack = m.Backpack; // auto add a pack if the mob doesnt have one if (pack == null) { pack = new Backpack(); m.AddItem(pack); } } } else { pack = o as Container; } if (pack != null) { // handle the nested item property specification using <> string itemargstring = null; // itemtypestr will be the actual item type to be created. In the simple form it will be arglist[1] // for the string /arg1/ADD/arg2/arg3/arg4/arg5 arglist [0] will contain ADD , arglist[1] will be arg2, // and arglist[2] will be arg3/arg4/arg5 // if nested property specs // arglist[1] will be /arg5 // the drop probability will be in probargs string[] probargs = ParseCommaArgs(arglist[0], 2); string itemtypestr = arglist[1]; // get the argument list after the < if any , note for the string /arg1/ADD//arg5 arglist [0] will contain ADD // arglist[1] will be /arg5 // but note arglist[1] could also be // remainder will have ADD//arg5 // // also need to deal with nested cases of ADD/> and ADD//ADD> string additemstr = arglist[1]; if (arglist.Length > 2) additemstr = arglist[1] + "/" + arglist[2]; // check to see if the first char is a "<" if (additemstr.IndexOf("<") == 0) { // itemarglist[1] will contain arg2/arg3/arg4>/arg5 // additemstr should have the full list of args /arg5 if they are there. In the case of /arg1/ADD/arg2 // it will just have arg2 string[] itemarglist = ParseString(additemstr, 2, "<"); // take that argument list that should like like arg2/ag3/arg4>/arg5 // need to find the matching ">" //string[] itemargs = ParseString(itemarglist[1],2,">"); string[] itemargs = ParseToMatchingParen(itemarglist[1], '<', '>'); // and get the first part of the string without the > so itemargs[0] should be arg2/ag3/arg4 itemargstring = itemargs[0]; // and itemargs[1] should be the remainder if (itemargs.Length > 1) { // but have to get rid of any trailing / that might be after the > string[] trailstr = ParseSlashArgs(itemargs[1], 2); if (trailstr.Length > 1) remainder = trailstr[1]; else remainder = itemargs[1]; } else remainder = ""; // get the type info by pulling out the first arg in itemargstring string[] tempitemarg = ParseSlashArgs(itemargstring, 2); // and get the type info from it itemtypestr = tempitemarg[0]; } else { // otherwise its just a regular case with arglist[2] containing the rest of the arguments if (arglist.Length > 2) remainder = arglist[2]; else remainder = ""; } // test the drop probability if (Utility.RandomDouble() >= drop_probability) return true; // is it a valid item specification? string baseitemtype = ParseObjectType(itemtypestr); #region itemKeyword if (IsSpecialItemKeyword(baseitemtype)) { // itemtypestr will have the form keyword[,x[,y]] string[] itemkeywordargs = ParseCommaArgs(itemtypestr, 3); itemKeyword kw = itemKeywordHash[baseitemtype]; switch (kw) { // deal with the special keywords 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) { if (equip && m != null) { if (!m.EquipItem(item)) pack.DropItem(item); } else { pack.DropItem(item); } // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, 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) { if (equip && m != null) { if (!m.EquipItem(item)) pack.DropItem(item); } else pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "WEAPON 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) { if (equip && m != null) { if (!m.EquipItem(item)) pack.DropItem(item); } else pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "JEWELRY 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) { if (equip && m != null) { if (!m.EquipItem(item)) pack.DropItem(item); } else pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "SHIELD 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) { if (equip && m != null) { if (!m.EquipItem(item)) pack.DropItem(item); } else pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "JARMOR 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) { if (equip && m != null) { if (!m.EquipItem(item)) pack.DropItem(item); } else pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "SARMOR 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) { if (equip && m != null) { if (!m.EquipItem(item)) pack.DropItem(item); } else pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "JWEAPON takes 2 args : " + 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; if(!int.TryParse(itemkeywordargs[1], out minCircle)) { status_str = "Invalid SCROLL args : " + itemtypestr; return false; } if(!int.TryParse(itemkeywordargs[2], out maxCircle)) { status_str = "Invalid SCROLL args : " + itemtypestr; 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) { pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "SCROLL takes 2 args : " + itemtypestr; return false; } break; } case itemKeyword.POTION: { // syntax is POTION Item item = Loot.RandomPotion(); if (item != null) { pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } break; } case itemKeyword.TAKEN: { // syntax is TAKEN Item item = GetTaken(refobject); if (item != null) { pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } break; } case itemKeyword.GIVEN: { // syntax is GIVEN Item item = GetGiven(refobject); if (item != null) { pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } 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) { pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "ITEM takes 1 arg : " + 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) { pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } else { status_str = "LOOT takes 1 arg : " + itemtypestr; return false; } break; } case itemKeyword.NECROSCROLL: { // syntax is NECROSCROLL,index if (itemkeywordargs.Length == 2) { int index = 0; if(!int.TryParse(itemkeywordargs[1], out index)) { status_str = "Invalid NECROSCROLL args : " + itemtypestr; return false; } if (Core.AOS) { Item item = Loot.Construct(Loot.NecromancyScrollTypes, index); if (item != null) { pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } } } else { status_str = "NECROSCROLL takes 1 arg : " + itemtypestr; return false; } break; } case itemKeyword.LOOTPACK: { // syntax is LOOTPACK,type if (itemkeywordargs.Length == 2) { LootPack lootpack = null; string loottype = itemkeywordargs[1]; if (loottype.ToLower() == "poor") { lootpack = LootPack.Poor; } else if (loottype.ToLower() == "meager") { lootpack = LootPack.Meager; } else if (loottype.ToLower() == "average") { lootpack = LootPack.Average; } else if (loottype.ToLower() == "rich") { lootpack = LootPack.Rich; } else if (loottype.ToLower() == "filthyrich") { lootpack = LootPack.FilthyRich; } else if (loottype.ToLower() == "ultrarich") { lootpack = LootPack.UltraRich; } else if (loottype.ToLower() == "superboss") { lootpack = LootPack.SuperBoss; } else { status_str = "Invalid LOOTPACK type: " + loottype; return false; } int m_KillersLuck = 0; if (trigmob != null) { m_KillersLuck = LootPack.GetLuckChanceForKiller(trigmob); } bool converterror = false; try { // generate the nospawn component of the lootpack lootpack.Generate(m, pack, false, m_KillersLuck); // generate the spawn component (basically gold) requires a mobile and wont work in containers // because Generate does a test for TryDropItem for stackables which requires a valid mob argument, // any stackable generated in a container will fail // so just test for a valid mobile and only do the atspawn generate for them. if (m != null) lootpack.Generate(m, pack, true, m_KillersLuck); } catch { status_str = "Unable to add LOOTPACK"; converterror = true; } if (converterror) return false; } else { status_str = "LOOTPACK takes 1 arg : " + itemtypestr; return false; } break; } } } #endregion else { Type type = SpawnerType.GetType(ParseObjectType(itemtypestr)); // if so then create it if (type != null) { object newo = XmlSpawner.CreateObject(type, itemtypestr); if (newo is Item) { Item item = newo as Item; if (equip && m != null) { if (!m.EquipItem(item)) pack.DropItem(item); } else pack.DropItem(item); // could call applyobjectstringproperties on a nested propertylist here to set item attributes if (itemargstring != null) { ApplyObjectStringProperties(spawner, itemargstring, item, trigmob, refobject, out status_str); } } else { status_str = "Invalid ADD. No such item : " + itemtypestr; if (newo is BaseCreature) ((BaseCreature)newo).Delete(); return false; } } else { status_str = "Invalid ADD. No such item : " + itemtypestr; return false; } } } else { status_str = "Invalid ADD. mobile has no pack."; if (arglist.Length < 3) return false; remainder = arglist[2]; return false; } } else { status_str = "Invalid ADD. must be mobile or container."; if (arglist.Length < 3) return false; remainder = arglist[2]; return false; } return true; } #endregion #region String parsing methods public static string ApplySubstitution(XmlSpawner spawner, object o, Mobile trigmob, string typeName) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); // go through the string looking for instances of {keyword} string remaining = typeName; while (remaining != null && remaining.Length > 0) { int startindex = remaining.IndexOf('{'); if (startindex == -1 || startindex + 1 >= remaining.Length) { // if there are no more delimiters then append the remainder and finish sb.Append(remaining); break; } // might be a substitution, check for keywords int endindex = remaining.Substring(startindex + 1).IndexOf("}"); // if the ending delimiter cannot be found then just append and finish if (endindex == -1) { sb.Append(remaining); break; } // get the string up to the delimiter string firstpart = remaining.Substring(0, startindex); sb.Append(firstpart); string keypart = remaining.Substring(startindex + 1, endindex); // try to evaluate and then substitute the arg Type ptype; string value = ParseForKeywords(spawner, o, keypart.Trim(), trigmob, true, out ptype); // trim off the " from strings if (value != null) { value = value.Trim('"'); } // replace the parsed value for the keyword sb.Append(value); // continue processing the rest of the string if (endindex + startindex + 2 >= remaining.Length) break; remaining = remaining.Substring(endindex + startindex + 2, remaining.Length - endindex - startindex - 2); } return sb.ToString(); } public static string ParseObjectType(string str) { string[] arglist = ParseSlashArgs(str, 2); if (arglist != null && arglist.Length > 0) { // parse out any arguments of the form typename,arg,arg,.. string[] typeargs = ParseCommaArgs(arglist[0], 2); if (typeargs.Length > 1) { return (typeargs[0]); } return arglist[0]; } else return null; } public static string[] ParseObjectArgs(string str) { string[] arglist = ParseSlashArgs(str, 2); if (arglist.Length > 0) { string itemtypestring = arglist[0]; // parse out any arguments of the form typename,arg,arg,.. // find the first arg if it is there string[] typeargs = null; int argstart = 0; if (itemtypestring != null && itemtypestring.Length > 0) argstart = itemtypestring.IndexOf(",") + 1; if (argstart > 1 && argstart < itemtypestring.Length) { typeargs = ParseCommaArgs(itemtypestring.Substring(argstart), 15); } return (typeargs); } else return null; } // take a string of the form str-opendelim-str-closedelim-str-closedelimstr public static string[] ParseToMatchingParen(string str, char opendelim, char closedelim) { int nopen = 1; int nclose = 0; int splitpoint = str.Length; for (int i = 0; i < str.Length; i++) { // walk through the string until a matching close delimstr is found if (str[i] == opendelim) nopen++; if (str[i] == closedelim) nclose++; if (nopen == nclose) { splitpoint = i; break; } } string[] args = new string[2]; // allow missing closing delimiters at the end of the line, basically just treat eol as a closing delim args[0] = str.Substring(0, splitpoint); args[1] = ""; if (splitpoint + 1 < str.Length) { args[1] = str.Substring(splitpoint + 1, str.Length - splitpoint - 1); } return args; } public static string[] ParseString(string str, int nitems, string delimstr) { if (str == null || delimstr == null) return null; char[] delims = delimstr.ToCharArray(); string[] args = null; str = str.Trim(); args = str.Split(delims, nitems); return args; } public static string[] ParseSlashArgs(string str, int nitems) { if (str == null) return null; string[] args = null; str = str.Trim(); // this supports strings that may have special html formatting in them that use the / if (str.IndexOf("= 0 || str.IndexOf("/>") >= 0) { // or use indexof to do it with more context control List tmparray = new List(); // find the next slash char int index = 0; int preindex = 0; int searchindex = 0; int length = str.Length; while (index >= 0 && searchindex < length && tmparray.Count < nitems - 1) { index = str.IndexOf('/', searchindex); if (index >= 0) { // check the char before it and after it to ignore if ((index > 0 && str[index - 1] == '<') || (index < length - 1 && str[index + 1] == '>')) { // skip it searchindex = index + 1; } else { // split it tmparray.Add(str.Substring(preindex, index - preindex)); preindex = index + 1; searchindex = preindex; } } } // is there still room for more args? if (tmparray.Count <= nitems - 1 && preindex < length) { // searched past the end and didnt find anything tmparray.Add(str.Substring(preindex, length - preindex)); } // turn tmparray into a string[] args = new string[tmparray.Count]; tmparray.CopyTo(args); } else { // just use split to do it with no context control args = str.Split(slashdelim, nitems); } return args; } public static string[] ParseSpaceArgs(string str, int nitems) { if (str == null) return null; string[] args = null; str = str.Trim(); args = str.Split(spacedelim, nitems); return args; } public static string[] ParseCommaArgs(string str, int nitems) { if (str == null) return null; string[] args = null; str = str.Trim(); args = str.Split(commadelim, nitems); return args; } public static string[] ParseLiteralTerminator(string str) { if (str == null) return null; string[] args = null; str = str.Trim(); args = str.Split(literalend, 2); return args; } public static string[] ParseSemicolonArgs(string str, int nitems) { if (str == null) return null; string[] args = null; str = str.Trim(); args = str.Split(semicolondelim, nitems); return args; } public static string[] SplitString(string str, string separator) { if (str == null || separator == null) return null; int lastindex = 0; int index = 0; List strargs = new List(); while (index >= 0) { // go through the string and find the first instance of the separator index = str.IndexOf(separator); if (index < 0) { // no separator so its the end of the string strargs.Add(str); break; } string arg = str.Substring(lastindex, index); strargs.Add(arg); str = str.Substring(index + separator.Length, str.Length - (index + separator.Length)); } // now make the string args string[] args = new string[strargs.Count]; for (int i = 0; i < strargs.Count; i++) { args[i] = strargs[i]; } return args; } #endregion #region Keyword support methods public static void BroadcastAsciiMessage(AccessLevel ac, int hue, int font, string message) { foreach (NetState state in NetState.Instances) { Mobile m = state.Mobile; if (m != null && m.AccessLevel >= ac) //m.SendMessage(hue, message); m.Send(new AsciiMessage(Serial.MinusOne, -1, MessageType.Regular, hue, font, "System", message)); } } public static void BroadcastSound(AccessLevel ac, int soundid) { foreach (NetState state in NetState.Instances) { Mobile m = state.Mobile; if (m != null && m.AccessLevel >= ac) { m.ProcessDelta(); state.Send(new PlaySound(soundid, m.Location)); } } } public static void PublicOverheadMobileMessage(Mobile mob, MessageType type, int hue, int font, string text, bool noLineOfSight) { if (mob != null && mob.Map != null) { Packet p = null; IPooledEnumerable eable = mob.Map.GetClientsInRange(mob.Location); foreach (NetState state in eable) { if (state.Mobile.CanSee(mob) && (noLineOfSight || state.Mobile.InLOS(mob))) { if (p == null) { p = new AsciiMessage(mob.Serial, mob.Body, type, hue, font, mob.Name, text); p.Acquire(); } state.Send(p); } } Packet.Release(p); eable.Free(); } } public static void PublicOverheadItemMessage(Item item, MessageType type, int hue, int font, string text) { if (item != null && item.Map != null) { Packet p = null; Point3D worldLoc = item.GetWorldLocation(); IPooledEnumerable eable = item.Map.GetClientsInRange(worldLoc, item.GetMaxUpdateRange()); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(item) && m.InRange(worldLoc, item.GetUpdateRange(m))) { if (p == null) { p = new AsciiMessage(item.Serial, item.ItemID, type, hue, font, item.Name, text); p.Acquire(); } state.Send(p); } } Packet.Release(p); eable.Free(); } } public static Item GetTaken(object o) { // find the XmlSaveItem attachment XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(o, typeof(XmlSaveItem), "Taken"); if (si != null) { return si.SavedItem; } return null; } public static Item GetGiven(object o) { // find the XmlSaveItem attachment XmlSaveItem si = (XmlSaveItem)XmlAttach.FindAttachment(o, typeof(XmlSaveItem), "Given"); if (si != null) { return si.SavedItem; } return null; } // modified from 1.0.0 core packet.cs public sealed class XmlPlayMusic : Packet { public XmlPlayMusic(short number) : base(0x6D, 3) { UnderlyingStream.Write(number); } } // ------------------------------------------------------------- // Begin modified code from Beta-36 Basecreature.cs // ------------------------------------------------------------- public static Item MagicJewelry(int minLevel, int maxLevel) { BaseCreature.Cap(ref minLevel, 0, 5); BaseCreature.Cap(ref maxLevel, 0, 5); if (Core.AOS) { Item item = Loot.RandomJewelry(); if (item == null) return null; int attributeCount, min, max; BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); if (item is BaseJewel) BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max); return item; } else { Item jewel = Loot.RandomJewelry(); return jewel; } } public static Item MagicArmor(int minLevel, int maxLevel, bool jewel, bool shield) { BaseCreature.Cap(ref minLevel, 0, 5); BaseCreature.Cap(ref maxLevel, 0, 5); if (Core.AOS) { Item item = null; if (jewel) item = Loot.RandomArmorOrShieldOrJewelry(); else if (shield) item = Loot.RandomArmorOrShield(); else item = Loot.RandomArmor(); if (item == null) return null; int attributeCount, min, max; BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); if (item is BaseArmor) BaseRunicTool.ApplyAttributesTo((BaseArmor)item, attributeCount, min, max); else if (item is BaseJewel) BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max); return item; } else { BaseArmor armor = Loot.RandomArmorOrShield(); if (armor == null) return null; armor.ProtectionLevel = (ArmorProtectionLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); armor.Durability = (ArmorDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); return armor; } } public static Item MagicShield(int minLevel, int maxLevel) { BaseCreature.Cap(ref minLevel, 0, 5); BaseCreature.Cap(ref maxLevel, 0, 5); if (Core.AOS) { Item item = Loot.RandomShield(); if (item == null) return null; int attributeCount, min, max; BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); if (item is BaseArmor) BaseRunicTool.ApplyAttributesTo((BaseArmor)item, attributeCount, min, max); return item; } else { BaseArmor armor = Loot.RandomShield(); if (armor == null) return null; armor.ProtectionLevel = (ArmorProtectionLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); armor.Durability = (ArmorDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); return armor; } } public static Item MagicWeapon(int minLevel, int maxLevel, bool jewel) { BaseCreature.Cap(ref minLevel, 0, 5); BaseCreature.Cap(ref maxLevel, 0, 5); if (Core.AOS) { Item item = null; if (jewel) item = Loot.RandomWeaponOrJewelry(); else item = Loot.RandomWeapon(); if (item == null) return null; int attributeCount, min, max; BaseCreature.GetRandomAOSStats(minLevel, maxLevel, out attributeCount, out min, out max); if (item is BaseWeapon) BaseRunicTool.ApplyAttributesTo((BaseWeapon)item, attributeCount, min, max); else if (item is BaseJewel) BaseRunicTool.ApplyAttributesTo((BaseJewel)item, attributeCount, min, max); return item; } else { BaseWeapon weapon = Loot.RandomWeapon(); if (weapon == null) return null; if (0.05 > Utility.RandomDouble()) weapon.Slayer = SlayerName.Silver; weapon.DamageLevel = (WeaponDamageLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); weapon.AccuracyLevel = (WeaponAccuracyLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); weapon.DurabilityLevel = (WeaponDurabilityLevel)BaseCreature.RandomMinMaxScaled(minLevel, maxLevel); return weapon; } } // ------------------------------------------------------------- // End modified code from Beta-36 Basecreature.cs // ------------------------------------------------------------- public static void SendMusicToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str) { status_str = null; Item refitem = null; Mobile refmob = null; if (refobject is Item) { refitem = (Item)refobject; } else if (refobject is Mobile) { refmob = (Mobile)refobject; } // look for the other args string[] musicstr = ParseString(arglist, 3, ","); int range = 0; if (musicstr.Length < 2) { status_str = "missing musicname in MUSIC"; } if (musicstr.Length > 2) { // get the range arg if(!int.TryParse(musicstr[2], out range)) status_str = "bad range arg in MUSIC"; } if ((range > 0) || (triggermob != null && !triggermob.Deleted)) { // send the music to all players within range if range is > 0 if (range > 0) { IPooledEnumerable rangelist = null; if (refitem != null && !refitem.Deleted) { rangelist = refitem.GetClientsInRange(range); } else if (refmob != null && !refmob.Deleted) { rangelist = refmob.GetClientsInRange(range); } if (rangelist != null) { foreach (NetState p in rangelist) { if (p != null) { // stop any ongoing music p.Send(PlayMusic.InvalidInstance); // and play the new music short musicnumber = -1; if(!short.TryParse(musicstr[1], out musicnumber)) musicnumber = -1; if (musicnumber == -1) { MusicName music; #if Framework_4_0 if(Enum.TryParse(musicstr[1], true, out music)) #else if(TryParse(musicstr[1], true, out music)) #endif p.Send(PlayMusic.GetInstance(music)); } else { p.Send(new XmlPlayMusic(musicnumber)); } } } rangelist.Free(); } } else { // just send it to the mob who triggered // stop any ongoing music triggermob.Send(PlayMusic.InvalidInstance); // and play the new music //triggermob.Send(PlayMusic.GetInstance((MusicName)Enum.Parse(typeof(MusicName), musicstr[1], true))); //m_mob_who_triggered.Region.Music = (MusicName)Enum.Parse(typeof(MusicName), musicstr[1]); // and play the new music short musicnumber = -1; if(!short.TryParse(musicstr[1], out musicnumber)) musicnumber = -1; if (musicnumber == -1) { MusicName music; #if Framework_4_0 if(Enum.TryParse(musicstr[1], true, out music)) #else if(TryParse(musicstr[1], true, out music)) #endif triggermob.Send(PlayMusic.GetInstance(music)); } else { triggermob.Send(new XmlPlayMusic(musicnumber)); } } } } public static void ResurrectPlayers(string arglist, Mobile triggermob, object refobject, out string status_str) { status_str = null; Item refitem = null; Mobile refmob = null; if (refobject is Item) { refitem = (Item)refobject; } else if (refobject is Mobile) { refmob = (Mobile)refobject; } // syntax is RESURRECT[,range][,PETS] // look for the range arg string[] str = ParseString(arglist, 3, ","); int range = 0; bool petres = false; if (str.Length > 1) { if(!int.TryParse(str[1], out range)) status_str = "bad range arg in RESURRECT"; } if (str.Length > 2) { // get the range arg if (str[2].ToLower() == "pets") petres = true; else bool.TryParse(str[2], out petres); } try { if ((range > 0) || (triggermob != null && !triggermob.Deleted)) { // resurrect all players within range if range is > 0 if (range > 0) { IPooledEnumerable rangelist = null; if (refitem != null && !refitem.Deleted) { rangelist = refitem.GetMobilesInRange(range); } else if (refmob != null && !refmob.Deleted) { rangelist = refmob.GetMobilesInRange(range); } if (rangelist != null) { foreach (Mobile p in rangelist) { if (!petres && p is PlayerMobile && p.Body.IsGhost) { p.Resurrect(); } else if (petres && p is BaseCreature && ((BaseCreature)p).ControlMaster == triggermob && ((BaseCreature)p).Controlled && ((BaseCreature)p).IsDeadPet) { ((BaseCreature)p).ResurrectPet(); } } rangelist.Free(); } } else { // just send it to the mob who triggered if (triggermob.Body.IsGhost) triggermob.Resurrect(); } } } catch { } } public static void ApplyPoisonToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str) { status_str = null; Item refitem = null; Mobile refmob = null; if (refobject is Item) { refitem = (Item)refobject; } else if (refobject is Mobile) { refmob = (Mobile)refobject; } // look for the other args string[] str = ParseString(arglist, 4, ","); bool playeronly = false; int range = 0; if (str.Length < 2) { status_str = "missing poisontype in POISON"; } if (str.Length > 2) { // get the range arg if(!int.TryParse(str[2], out range)) status_str = "bad range arg in POISON"; } if (str.Length > 3) { if(str[3].ToLower() == "playeronly") playeronly = true; else bool.TryParse(str[3], out playeronly); } try { if ((range > 0) || (triggermob != null && !triggermob.Deleted)) { // apply the poison to all players within range if range is > 0 if (range > 0) { IPooledEnumerable rangelist = null; if (refitem != null && !refitem.Deleted) { rangelist = refitem.GetMobilesInRange(range); } else if (refmob != null && !refmob.Deleted) { rangelist = refmob.GetMobilesInRange(range); } if (rangelist != null) { foreach (Mobile p in rangelist) { if (p is PlayerMobile || !playeronly) p.ApplyPoison(p, Poison.Parse(str[1])); } rangelist.Free(); } } else { // just apply it to the mob who triggered triggermob.ApplyPoison(triggermob, Poison.Parse(str[1])); } } } catch { } } public static void ApplyDamageToPlayers(string arglist, Mobile triggermob, object refobject, out string status_str) { status_str = null; Item refitem = null; Mobile refmob = null; if (refobject is Item) { refitem = (Item)refobject; } else if (refobject is Mobile) { refmob = (Mobile)refobject; } // look for the other args. Syntax is DAMAGE,damage,phys,fire,cold,pois,energy[,range][,playeronly] string[] str = ParseString(arglist, 9, ","); bool playeronly = false; int range = -1; int damage=0, phys=0, fire=0, cold=0, pois=0, ener=0; if(str.Length < 3) { // we consider all the damage as physical if(str.Length > 1 && int.TryParse(str[1], out damage)) phys = 100; else status_str = "bad damage arg in DAMAGE"; } else if(str.Length < 7) { status_str = "missing damage args in DAMAGE"; } else if(!int.TryParse(str[1], out damage) | !int.TryParse(str[2], out phys) | !int.TryParse(str[3], out fire) | !int.TryParse(str[4], out cold) | !int.TryParse(str[5], out pois) | !int.TryParse(str[6], out ener)) { status_str = "bad damage args in DAMAGE"; } if (str.Length > 7) { // get the range arg if(!int.TryParse(str[7], out range)) { range = -1; status_str = "bad range arg in DAMAGE"; } } if (str.Length > 8) { if(str[8].ToLower() == "playeronly") playeronly = true; else bool.TryParse(str[8], out playeronly); } try { if (range >= 0 || (triggermob != null && !triggermob.Deleted)) { // apply the poison to all players within range if range is > 0 if (range >= 0) { IPooledEnumerable rangelist = null; if (refitem != null && !refitem.Deleted) { rangelist = refitem.GetMobilesInRange(range); } else if (refmob != null && !refmob.Deleted) { rangelist = refmob.GetMobilesInRange(range); } if (rangelist != null) { foreach (Mobile p in rangelist) { if (p is PlayerMobile || !playeronly) AOS.Damage(p, damage, phys, fire, cold, pois, ener); } rangelist.Free(); } } else { // just apply it to the mob who triggered AOS.Damage(triggermob, damage, phys, fire, cold, pois, ener); } } } catch { } } public static void SendBoltEffect(IEntity e, int sound, int hue) { Map map = e.Map; if (map == null) return; if (e is Item) ((Item)e).ProcessDelta(); else if (e is Mobile) ((Mobile)e).ProcessDelta(); Packet preEffect = null, boltEffect = null, playSound = null; IPooledEnumerable eable = map.GetClientsInRange(e.Location); foreach (NetState state in eable) { if (Effects.SendParticlesTo(state)) { if (preEffect == null) preEffect = Packet.Acquire(new TargetParticleEffect(e, 0, 10, 5, 0, 0, 5031, 3, 0)); state.Send(preEffect); } if (boltEffect == null) boltEffect = Packet.Acquire(new BoltEffect(e, hue)); state.Send(boltEffect); if (sound > 0) { if (playSound == null) playSound = Packet.Acquire(new PlaySound(sound, e)); state.Send(playSound); } } Packet.Release(preEffect); Packet.Release(boltEffect); Packet.Release(playSound); eable.Free(); } public static void ExecuteActions(Mobile mob, object attachedto, string actions) { if (actions == null || actions.Length <= 0) return; // execute any action associated with it // allow for multiple action strings on a single line separated by a semicolon string[] args = actions.Split(';'); for (int j = 0; j < args.Length; j++) { ExecuteAction(mob, attachedto, args[j]); } } public static void ExecuteAction(Mobile trigmob, object attachedto, string action) { Point3D loc = Point3D.Zero; Map map = null; if (attachedto is IEntity) { loc = ((IEntity)attachedto).Location; map = ((IEntity)attachedto).Map; } if (action == null || action.Length <= 0 || attachedto == null || map == null) return; string status_str = null; Server.Mobiles.XmlSpawner.SpawnObject TheSpawn = new Server.Mobiles.XmlSpawner.SpawnObject(null, 0); TheSpawn.TypeName = action; string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, attachedto, trigmob, action); string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) { BaseXmlSpawner.SpawnTypeKeyword(attachedto, TheSpawn, typeName, substitutedtypeName, true, trigmob, loc, map, out status_str); } else { // its a regular type descriptor so find out what it is Type type = SpawnerType.GetType(typeName); try { string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); object o = Server.Mobiles.XmlSpawner.CreateObject(type, arglist[0]); if (o == null) { status_str = "invalid type specification: " + arglist[0]; } else if (o is Mobile) { Mobile m = (Mobile)o; if (m is BaseCreature) { BaseCreature c = (BaseCreature)m; c.Home = loc; // Spawners location is the home point } m.Location = loc; m.Map = map; BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, m, trigmob, attachedto, out status_str); } else if (o is Item) { Item item = (Item)o; BaseXmlSpawner.AddSpawnItem(null, attachedto, TheSpawn, item, loc, map, trigmob, false, substitutedtypeName, out status_str); } } catch { } } } #endregion #region Spawn methods public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, string propertyString, out string status_str) { AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, false, out status_str); } public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, string propertyString, out string status_str) { AddSpawnItem(spawner, invoker, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, false, out status_str); } public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, string propertyString, bool smartspawn, out string status_str) { AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, null, propertyString, smartspawn, out status_str); } public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, List spawnpositioning, string propertyString, out string status_str) { AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, false, out status_str); } public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, List spawnpositioning, string propertyString, out string status_str) { AddSpawnItem(spawner, invoker, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, false, out status_str); } public static void AddSpawnItem(XmlSpawner spawner, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, List spawnpositioning, string propertyString, bool smartspawn, out string status_str) { AddSpawnItem(spawner, spawner, theSpawn, item, location, map, trigmob, requiresurface, spawnpositioning, propertyString, smartspawn, out status_str); } public static void AddSpawnItem(XmlSpawner spawner, object invoker, XmlSpawner.SpawnObject theSpawn, Item item, Point3D location, Map map, Mobile trigmob, bool requiresurface, List spawnpositioning, string propertyString, bool smartspawn, out string status_str) { status_str = null; if (item == null || theSpawn == null) return; // add the item to the spawned list theSpawn.SpawnedObjects.Add(item); item.Spawner = spawner; if (spawner != null) { // this is being called by a spawner so use spawner information for placement if (!spawner.Deleted) { // set the item amount if (spawner.StackAmount > 1 && item.Stackable) { item.Amount = spawner.StackAmount; } // if this is in any container such as a pack then add to the container. if (spawner.Parent is Container) { Container c = (Container)spawner.Parent; Point3D loc = spawner.Location; if (!smartspawn) { item.OnBeforeSpawn(loc, map); } item.Location = loc; // check to see whether we drop or add the item based on the spawnrange // this will distribute multiple items around the spawn point, and allow precise // placement of single spawns at the spawn point if (spawner.SpawnRange > 0) c.DropItem(item); else c.AddItem(item); } else { // if the spawn entry is in a subgroup and has a packrange, then get the packcoord Point3D packcoord = Point3D.Zero; if (theSpawn.PackRange >= 0 && theSpawn.SubGroup > 0) { packcoord = spawner.GetPackCoord(theSpawn.SubGroup); } Point3D loc = spawner.GetSpawnPosition(requiresurface, theSpawn.PackRange, packcoord, spawnpositioning); if (!smartspawn) { item.OnBeforeSpawn(loc, map); } // standard placement for all items in the world item.MoveToWorld(loc, map); } } else { // if the spawner has already been deleted then delete the item since it cannot be cleaned up by spawner deletion any longer item.Delete(); return; } } else { if (!smartspawn) { item.OnBeforeSpawn(location, map); } // use the location and map info passed in // this allows AddSpawnItem to be called by objects other than spawners as long as they pass in a valid SpawnObject item.MoveToWorld(location, map); } // clear the taken flag on all newly spawned items ItemFlags.SetTaken(item, false); if (!smartspawn) { item.OnAfterSpawn(); } // apply the parsed arguments from the typestring using setcommand // be sure to do this after setting map and location so that errors dont place the mob on the internal map BaseXmlSpawner.ApplyObjectStringProperties(spawner, propertyString, item, trigmob, spawner, out status_str); // if the object has an OnAfterSpawnAndModify method, then invoke it //InvokeOnAfterSpawnAndModify(item); } /* // hash table for optimizing OnAfterSpawnAndModify method invocation private static Hashtable OnAfterSpawnAndModifyMethodHash; public static void InvokeOnAfterSpawnAndModify(object o) { if(o == null) return; // try looking this up in the lookup table if(OnAfterSpawnAndModifyMethodHash == null) { OnAfterSpawnAndModifyMethodHash = new Hashtable(); } MethodInfo minfo = null; if(!OnAfterSpawnAndModifyMethodHash.Contains(o.GetType())) { // not found so look it up the long way minfo = o.GetType().GetMethod("OnAfterSpawnAndModify"); if(minfo != null) { ParameterInfo [] pinfo = minfo.GetParameters(); // check to make sure the OnSpawned method for this object has the right args if(pinfo.Length != 0) { minfo = null; } } OnAfterSpawnAndModifyMethodHash.Add(o.GetType(),minfo); } else { // look it up in the hash table minfo = (MethodInfo) OnAfterSpawnAndModifyMethodHash[o.GetType()]; } try{ if(minfo != null) { minfo.Invoke(o, null); } } catch {} } */ public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface, Mobile triggermob, Point3D location, Map map, out string status_str) { return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, null, triggermob, location, map, null, out status_str, 0); } public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface, Mobile triggermob, Point3D location, Map map, XmlGumpCallback gumpcallback, out string status_str, byte loops) { return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, null, triggermob, location, map, gumpcallback, out status_str, loops); } public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface, List spawnpositioning, Mobile triggermob, Point3D location, Map map, out string status_str, byte loops) { return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, requiresurface, spawnpositioning, triggermob, location, map, null, out status_str, loops); } public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, bool requiresurface, List spawnpositioning, Mobile triggermob, Point3D location, Map map, XmlGumpCallback gumpcallback, out string status_str, byte loops) { 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 #region typeKeyword if (IsTypeKeyword(typeName)) { typeKeyword kw = typeKeywordHash[typeName]; switch (kw) { case typeKeyword.SET: { // the syntax is SET/prop/value/prop2/value... // check for the SET,itemname or serialno[,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[,proptest=value]/prop/value/prop2/value2/prop3/value3/.. //string [] arglist = ParseString(substitutedtypeName,3,"/"); string[] arglist = ParseSlashArgs(substitutedtypeName, 3); string proptest = null; if(arglist.Length > 0) { string[] objstr = ParseString(arglist[0], 2, ","); if (objstr.Length > 1) { proptest = objstr[1]; } } else { status_str = "missing args to SETONTHIS"; return false; } if(invoker != null && (proptest == null || CheckPropertyString(null, invoker, proptest, null, out status_str))) { 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.FOREACH: { // the syntax is FOREACH,objecttype[,name][,range]/action string[] arglist = ParseSlashArgs(substitutedtypeName, 2); if(arglist.Length > 1) { string[] objstr = ParseString(arglist[0], 4, ","); if (objstr.Length < 2) { status_str = "missing objecttype in FOREACH"; return false; } Type objecttype = SpawnerType.GetType(objstr[1]); if(objecttype != null) { int range = -1; string objectname = "*"; if(objstr.Length > 2) { objectname = objstr[2]; if(objstr.Length > 3 && !int.TryParse(objstr[3], out range)) range = -1; } if((spawner==null || spawner.Deleted) && range<0) { status_str = "invalid range outside of spawner in FOREACH"; return false; } string remaining = arglist[1]; if(typeof(Mobile).IsAssignableFrom(objecttype)) { List mobs = new List(); if(spawner!=null) { if(spawner.SpawnRegion!=null && spawner.HasRegionPoints(spawner.SpawnRegion)) { foreach(Mobile m in spawner.SpawnRegion.GetMobiles()) { if(objecttype.IsAssignableFrom(m.GetType()) && CheckNameMatch(objectname, m.Name)) mobs.Add(m); } } else { foreach(Mobile m in map.GetMobilesInBounds(spawner.SpawnerBounds)) { if(objecttype.IsAssignableFrom(m.GetType()) && CheckNameMatch(objectname, m.Name)) { mobs.Add(m); } } } } else if(invoker!=null && invoker is IEntity) { IPooledEnumerable eable = map.GetMobilesInRange(((IEntity)invoker).Location, range); foreach(Mobile m in eable) { if(objecttype.IsAssignableFrom(m.GetType()) && CheckNameMatch(objectname, m.Name)) mobs.Add(m); } eable.Free(); } for(int x = mobs.Count - 1; x>=0; --x) { if(mobs[x].AccessLevel < AccessLevel.Counselor) ApplyObjectStringProperties(spawner, substitutedtypeName, mobs[x], mobs[x], invoker, out status_str); } } else if(typeof(Item).IsAssignableFrom(objecttype)) { List items = new List(); if(spawner!=null) { if(spawner.SpawnRegion!=null && spawner.HasRegionPoints(spawner.SpawnRegion)) { foreach(Item i in GetItems(spawner.SpawnRegion)) { if(objecttype.IsAssignableFrom(i.GetType()) && CheckNameMatch(objectname, i.Name)) items.Add(i); } } else { foreach(Item i in map.GetItemsInBounds(spawner.SpawnerBounds)) { if(objecttype.IsAssignableFrom(i.GetType()) && CheckNameMatch(objectname, i.Name)) items.Add(i); } } } else if(invoker!=null && invoker is IEntity) { foreach(Item i in map.GetItemsInRange(((IEntity)invoker).Location, range)) { if(objecttype.IsAssignableFrom(i.GetType()) && CheckNameMatch(objectname, i.Name)) items.Add(i); } } for(int x = items.Count - 1; x>=0; --x) ApplyObjectStringProperties(spawner, substitutedtypeName, items[x], triggermob, invoker, out status_str); } else { status_str = "invalid TYPE specified in FOREACH"; return false; } } else { status_str = "invalid TYPE specified in FOREACH"; 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; } if(!int.TryParse(objstr[1], out range)) range=-1; 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) { bool.TryParse(objstr[4], out searchcontainers); } 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); } List 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[,name]/prop/value/prop/value... string[] arglist = ParseSlashArgs(substitutedtypeName, 3); string typestr = "BaseCreature"; string targetname = "*"; int range = -1; bool searchcontainers = false; if (arglist.Length > 0) { string[] objstr = ParseString(arglist[0], 3, ","); if (objstr.Length < 2) { status_str = "missing range in SETONPETS"; return false; } if(!int.TryParse(objstr[1], out range)) range=-1; if (range < 0) { status_str = "invalid range in SETONPETS"; return false; } if(objstr.Length > 2) targetname = objstr[2]; } 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 List 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 { bool.TryParse(objstr[3], out equippedonly); } } } 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); } if(!int.TryParse(subgroupstr, out subgroup)) subgroup=-1; } } if (subgroup == -1) { status_str = "invalid subgroup in SETONSPAWN"; return false; } List 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') { if(!int.TryParse(entrystring, out entryindex)) entryindex=-1; } 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.TAKEGIVE: { // syntax TAKEGIVE[,quantity[,true*,[type]]]/itemnametotake/GIVE/itemtypetogive *search in banca string[] arglist = ParseSlashArgs(substitutedtypeName, 5); string[] givelist = null; string targetName; string typestr = null; if (arglist.Length < 4) { status_str = "invalid TAKEGIVE specification"; return false; } else { givelist = new string[arglist.Length - 2]; targetName = arglist[1]; Array.Copy(arglist, 2, givelist, 0, arglist.Length -2); } string[] keywordargs = ParseString(arglist[0], 4, ","); string[] givekeywordargs = ParseString(givelist[0], 2, ","); int quantity = 0; bool banksearch = false; bool success = false; List toRemove = new List(); if (keywordargs.Length > 1) { if(!int.TryParse(keywordargs[1], out quantity)) { status_str = "Invalid TAKE quantity : " + arglist[1]; return false; } } if (keywordargs.Length > 2) { if(!bool.TryParse(keywordargs[2], out banksearch)) { status_str = "Invalid TAKE bankflag : " + arglist[1]; return false; } } if (keywordargs.Length > 3) { typestr = keywordargs[3]; } // 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) { List itemlist = SearchMobileForItems(triggermob, targetName, typestr, banksearch, false); itemlist.Reverse(); int totaltaken = 0; int totake = quantity; int remaining=0; int taken=0; foreach(Item it in itemlist) { remaining = it.Amount - quantity; if(remaining <= 0) { taken = it.Amount; totaltaken += taken; toRemove.Add(it); quantity -= taken; } else { totaltaken += quantity; it.Amount = remaining; break; } } if(totaltaken>=totake) { for(int i=toRemove.Count - 1; i>=0; --i) toRemove[i].Delete(); success=true; } } else//non stackable, we have to find them all { // dont save quest holders if (itemTarget is XmlQuestBook || itemTarget is IXmlQuest || quantity<=1) { toRemove.Add(itemTarget); } else { List itemlist = SearchMobileForItems(triggermob, targetName, typestr, banksearch, false); itemlist.Reverse(); for(int i=itemlist.Count - 1, totake=quantity;i>=0 && totake>0;--i, --totake) { toRemove.Add(itemlist[i]); } } if(toRemove.Count>=quantity) { for(int i=toRemove.Count - 1; i>=0; --i) toRemove[i].Delete(); success=true; } } string remainder; if(success) AddItemToTarget(spawner, triggermob, givekeywordargs, givelist, triggermob, invoker, false, out remainder, out status_str); } TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); break; } case typeKeyword.GIVE: { //syntax is GIVE[,probability (0.01=1% 1=100%)]/itemtypetogive 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) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid TAKE probability : " + arglist[1]; return false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out quantity)) { status_str = "Invalid TAKE quantity : " + arglist[1]; return false; } } if (keywordargs.Length > 3) { if(!bool.TryParse(keywordargs[3], out banksearch)) { status_str = "Invalid TAKE bankflag : " + arglist[1]; 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) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out drop_probability)) { status_str = "Invalid TAKEBYTYPE probability : " + arglist[1]; return false; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out quantity)) { status_str = "Invalid TAKEBYTYPE quantity : " + arglist[1]; return false; } } if (keywordargs.Length > 3) { if(!bool.TryParse(keywordargs[3], out banksearch)) { status_str = "Invalid TAKEBYTYPE bankflag : " + arglist[1]; 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, 2); 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, 4=multiple option gump (free) if (gumpkeywordargs.Length > 2) { gumpTitle = gumpkeywordargs[1]; if(!int.TryParse(gumpkeywordargs[2], out gumpNumber)) { status_str = "Invalid GUMP args"; 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 = SpawnerType.GetType(gumptypestr);; 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], 3, ","); if (keywordargs.Length > 1) { if(!int.TryParse(keywordargs[1], out hue)) { hue=0x3B2; status_str = "invalid hue arg to SENDMSG"; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out font)) { font = 3; 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 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) { if(!int.TryParse(keywordargs[1], out hue)) { hue = 0x3B2; status_str = "invalid hue arg to SENDASCIIMSG"; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out font)) { font = 3; 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) { if(!double.TryParse(keywordargs[1], NumberStyles.Any, CultureInfo.InvariantCulture, out delay)) status_str = "invalid delay arg to WAITUNTIL"; } if (keywordargs.Length > 2) { if (!double.TryParse(keywordargs[2], NumberStyles.Any, CultureInfo.InvariantCulture, out timeout)) status_str = "invalid timeout arg to WAITUNTIL"; } } if (arglist.Length > 1) { condition = arglist[1]; } if (arglist.Length > 2) { if(!int.TryParse(arglist[2], out gotogroup)) { status_str = "invalid goto arg to WAITUNTIL"; gotogroup = -1; } } 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]; if(!int.TryParse(arglist[2], out gotogroup)) { status_str = "invalid dogroup arg to WHILE"; gotogroup = -1; } } 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) { if(loops>=XmlSpawner.MaxLoops) { status_str = "recursive looping stop in WHILE"; return false; } // spawn the subgroup spawner.SpawnSubGroup(gotogroup, (byte)(loops+1)); // 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]; if(!int.TryParse(arglist[2], out thengroup)) { status_str = "invalid thengroup arg to IF"; thengroup=-1; } } if (arglist.Length > 3) { if(!int.TryParse(arglist[3], out elsegroup)) { status_str = "invalid elsegroup arg to IF"; elsegroup = -1; } } 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 if(loops>=XmlSpawner.MaxLoops) { status_str = "recursive looping stop in IF"; return false; } spawner.SpawnSubGroup(thengroup, (byte)(loops+1)); // 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 if(loops>=XmlSpawner.MaxLoops) { status_str = "recursive looping stop in IF"; return false; } spawner.SpawnSubGroup(elsegroup, (byte)(loops+1)); // 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); } if(!int.TryParse(subgroupstr, out subgroup)) subgroup = -1; } } 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); } if(!int.TryParse(subgroupstr, out subgroup)) subgroup = -1; } } 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 if(loops>=XmlSpawner.MaxLoops) //preventing looping from spawner to spawner, via recursive linked method calls { status_str = "recursive looping stop in SPAWN"; return false; } targetspawner.SpawnSubGroup(subgroup, false, true, (byte)(loops+1)); } else { if(loops>=XmlSpawner.MaxLoops) { status_str = "recursive looping stop in SPAWN"; return false; } targetspawner.SpawnSubGroup(subgroup, (byte)(loops+1)); } } 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 { if(!int.TryParse(arglist[1], out group)) { status_str = "invalid subgroup arg to GOTO"; group=-1; } } 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 { if(!int.TryParse(keywordargs[1], out sound)) { status_str = "Improper sound number format"; sound=-1; } } 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; int duration = 0; int speed; 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 if(!int.TryParse(keywordargs[1], out effect)) { status_str = "Improper effect number format"; effect=-1; } if(!int.TryParse(keywordargs[2], out speed)) { status_str = "Improper effect speed format"; speed=1; } int x=0,y=0,z=0; if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z)) status_str = "Improper effect location format"; eloc1 = new Point3D(x, y, z); if(!int.TryParse(keywordargs[6], out x) || !int.TryParse(keywordargs[7], out y) || !int.TryParse(keywordargs[8], out z)) 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 { if(!int.TryParse(keywordargs[1], out effect)) { status_str = "Improper effect number format"; effect=-1; } if(!int.TryParse(keywordargs[2], out duration)) { status_str = "Improper effect duration format"; duration=1; } } // 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, y, z; if(!int.TryParse(keywordargs[3], out x) || !int.TryParse(keywordargs[4], out y) || !int.TryParse(keywordargs[5], out z)) { status_str = "Improper effect location format"; x=spawner.Location.X; y=spawner.Location.Y; z=spawner.Location.Z; } 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][,playeronly] 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) { hasnumber=int.TryParse(keywordargs[1], out spellnumber); } 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) { int.TryParse(keywordargs[2], out keywordarg2); } 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) { if(!int.TryParse(keywordargs[1], out hue)) { status_str = "invalid hue arg to BCAST"; hue = 0x482; } } if (keywordargs.Length > 2) { if(!int.TryParse(keywordargs[2], out font)) { status_str = "invalid font arg to BCAST"; font=-1; } } } 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) { if(!int.TryParse(keywordargs[1], out soundid)) { status_str = "invalid soundid arg to BSOUND"; soundid=-1; } } 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; } #endregion #region itemKeyword 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, 6, ","); itemKeyword kw = itemKeywordHash[typeName]; // deal with the special keywords switch (kw) { case itemKeyword.ARMOR: { // syntax is ARMOR,min,max //get the min,max if (itemkeywordargs.Length == 3) { int min = 0; int max = 0; if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max)) { status_str = "Invalid ARMOR args : " + itemtypestr; 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; if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max)) { status_str = "Invalid WEAPON args : " + itemtypestr; 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; if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max)) { status_str = "Invalid JARMOR args : " + itemtypestr; 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; if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max)) { status_str = "Invalid JWEAPON args : " + itemtypestr; 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; if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max)) { status_str = "Invalid SARMOR args : " + itemtypestr; 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; if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max)) { status_str = "Invalid SHIELD args : " + itemtypestr; 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; if(!int.TryParse(itemkeywordargs[1], out min) || !int.TryParse(itemkeywordargs[2], out max)) { status_str = "Invalid JEWELRY args : " + itemtypestr; 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; if(!int.TryParse(itemkeywordargs[1], out minCircle) || !int.TryParse(itemkeywordargs[2], out maxCircle)) { status_str = "Invalid SCROLL args : " + itemtypestr; 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; if(!int.TryParse(itemkeywordargs[1], out necroindex)) { status_str = "Invalid NECROSCROLL args : " + itemtypestr; return false; } 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; } case itemKeyword.RANDOMITEM: { // syntax is RANDOMITEM,[basebudget,][prefix,][suffix,][rawluck,][artifact] int basebudget = 0; ReforgedPrefix prefix = ReforgedPrefix.None; ReforgedSuffix suffix = ReforgedSuffix.None; int killersluck = 0; bool converterror = false; if (itemkeywordargs.Length > 1) { try { basebudget = int.Parse(itemkeywordargs[1]); } catch { status_str = "Invalid RANDOMITEM args : " + itemtypestr; converterror = true; } } else basebudget = Utility.RandomMinMax(100, 700); if (converterror) return false; if (itemkeywordargs.Length > 2) { try { prefix = (ReforgedPrefix)Enum.Parse(typeof(ReforgedPrefix), itemkeywordargs[2], true); } catch { status_str = "Invalid RANDOMITEM args : " + itemtypestr; converterror = true; } } if (converterror) return false; if (itemkeywordargs.Length > 3) { try { suffix = (ReforgedSuffix)Enum.Parse(typeof(ReforgedSuffix), itemkeywordargs[3], true); } catch { status_str = "Invalid RANDOMITEM args : " + itemtypestr; converterror = true; } } if (converterror) return false; int rawluck = triggermob != null ? triggermob is PlayerMobile ? ((PlayerMobile)triggermob).RealLuck : triggermob.Luck : 0; bool artifact = false; if (rawluck == 0 && itemkeywordargs.Length > 4) { try { rawluck = int.Parse(itemkeywordargs[4]); } catch { status_str = "Invalid RANDOMITEM args : " + itemtypestr; converterror = true; } } if (rawluck > 0) { killersluck = LootPack.GetLuckChance(rawluck); } if (itemkeywordargs.Length > 5) { string arty = itemkeywordargs[5]; if (arty != null && arty.ToLower() == "true") { artifact = true; } } if (basebudget < 100) basebudget = 100; Item root = spawner; if (spawner != null && spawner.RootParent is Item) root = spawner.RootParent as Item; Item item = Loot.RandomArmorOrShieldOrWeaponOrJewelry(LootPackEntry.IsInTokuno(root), LootPackEntry.IsMondain(root), LootPackEntry.IsStygian(root)); if (item != null) { if (artifact) { RunicReforging.GenerateRandomArtifactItem(item, rawluck, basebudget, prefix, suffix); } else { RunicReforging.GenerateRandomItem(item, triggermob, basebudget, killersluck, prefix, suffix); } AddSpawnItem(spawner, TheSpawn, item, location, map, triggermob, requiresurface, spawnpositioning, substitutedtypeName, out status_str); } break; } default: { status_str = "unrecognized keyword"; // should never get here break; } } return true; } #endregion else { // should never get here status_str = "unrecognized keyword"; return false; } } #endregion #region Specials by Fwiffo public static List GetItems(Region r) { List list = new List(); if(r==null) return list; Sector[] sectors = r.Sectors; if ( sectors != null ) { for ( int i = 0; i < sectors.Length; i++ ) { Sector sector = sectors[i]; foreach ( Item item in sector.Items ) { if ( Region.Find( item.Location, item.Map).IsPartOf(r) ) list.Add( item ); } } } return list; } /// /// Converts the string representation of the name value of one or more enumerated constants to an equivalent enumerated object. A parameter specifies whether the operation is case-sensitive (default: false). The return value indicates whether the conversion succeeded. /// /// The string representation of the enumeration name or underlying value to convert. /// result: if the method returns true, it's a TEnum whose value is represented by value. Otherwise uninitialized parameter. /// true if the value parameter was converted successfully; otherwise, false. /// TEnum is not an enumeration type. public static bool TryParse(string tocheck, out TEnum result) where TEnum : struct, IConvertible { return TryParse(tocheck, false, out result); } /// /// Converts the string representation of the name value of one or more enumerated constants to an equivalent enumerated object. A parameter specifies whether the operation is case-sensitive. The return value indicates whether the conversion succeeded. /// /// The string representation of the enumeration name or underlying value to convert. /// If this parameter is set to true it will ignore case of string tocheck, otherwise it will check case. /// result: if the method returns true, it's a TEnum whose value is represented by value. Otherwise uninitialized parameter. /// true if the value parameter was converted successfully; otherwise, false. /// TEnum is not an enumeration type. public static bool TryParse(string tocheck, bool ignorecase, out TEnum result) where TEnum : struct, IConvertible { bool boolean = (tocheck == null ? false : Enum.IsDefined(typeof(TEnum), tocheck)); result = (boolean ? (TEnum)Enum.Parse(typeof(TEnum), tocheck) : default(TEnum)); return boolean; } #endregion } }