From 13c3e5263991c8635035407a39684471e1375673 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:39:57 -0700 Subject: [PATCH 1/8] Adds xmlspawner --- .../Engines/XMLSpawner/BaseXmlSpawner.cs | 3982 +++++ .../Engines/XMLSpawner/ExceptionLogging.cs | 74 + .../UOContent/Engines/XMLSpawner/ItemFlags.cs | 134 + .../Engines/XMLSpawner/SpawnerExporter.cs | 283 + .../XMLSpawner/XmlPropsGumps/XmlPropsGump.cs | 721 + .../XmlPropsGumps/XmlSetCustomEnumGump.cs | 47 + .../XMLSpawner/XmlPropsGumps/XmlSetGump.cs | 250 + .../XmlPropsGumps/XmlSetListOptionGump.cs | 196 + .../XmlPropsGumps/XmlSetObjectGump.cs | 302 + .../XmlPropsGumps/XmlSetObjectTarget.cs | 72 + .../XmlPropsGumps/XmlSetPoint2DGump.cs | 235 + .../XmlPropsGumps/XmlSetPoint3DGump.cs | 241 + .../XmlPropsGumps/XmlSetTimeSpanGump.cs | 240 + .../Engines/XMLSpawner/XmlSpawner.cs | 12776 ++++++++++++++++ .../Engines/XMLSpawner/XmlSpawnerGumps.cs | 1331 ++ .../XMLSpawner/XmlSpawnerSkillCheck.cs | 296 + .../Engines/XMLSpawner/XmlTextEntryBook.cs | 80 + .../Engines/XMLSpawner/XmlUtils/WriteMulti.cs | 468 + .../Engines/XMLSpawner/XmlUtils/XmlAdd.cs | 1774 +++ .../XmlUtils/XmlCategorizedAddGump.cs | 477 + .../Engines/XMLSpawner/XmlUtils/XmlEdit.cs | 1420 ++ .../Engines/XMLSpawner/XmlUtils/XmlFind.cs | 2367 +++ .../XmlUtils/XmlPartialCategorizedAddGump.cs | 266 + 23 files changed, 28032 insertions(+) create mode 100644 Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/ExceptionLogging.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetCustomEnumGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetListOptionGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectTarget.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint2DGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint3DGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetTimeSpanGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlTextEntryBook.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlCategorizedAddGump.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlEdit.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs create mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlPartialCategorizedAddGump.cs diff --git a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs new file mode 100644 index 000000000..9866f8f57 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs @@ -0,0 +1,3982 @@ +using Server.Commands; +using Server.Items; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using Server.Engines.XmlSpawner2; + +namespace Server.Mobiles; + +public delegate void XmlGumpCallback(Mobile from, object invoker, string response); +public class BaseXmlSpawner +{ + + [Flags] + public enum KeywordFlags + { + HoldSpawn = 0x01, + HoldSequence = 0x02, + Serialize = 0x04, + Defrag = 0x08 + } + + public class TypeInfo + { + public List plist = new(); // hold propertyinfo list + public Type t; + } + + private static readonly Type typeofTimeSpan = typeof(TimeSpan); + private static readonly Type typeofParsable = typeof(ParsableAttribute); + private static readonly Type typeofCustomEnum = typeof(CustomEnumAttribute); + + private static bool IsParsable(Type t) => t == typeofTimeSpan || t.IsDefined(typeofParsable, false); + + private static readonly Type[] m_ParseTypes = { typeof(string) }; + private static readonly 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 readonly Type[] m_NumericTypes = + { + typeof(byte), typeof(sbyte), + typeof(short), typeof(ushort), + typeof(int), typeof(uint), + typeof(long), typeof(ulong), typeof(Serial) + }; + + public static bool IsNumeric(Type t) => Array.IndexOf(m_NumericTypes, t) >= 0; + + private static readonly Type typeofType = typeof(Type); + + private static bool IsType(Type t) => t == typeofType; + + private static readonly Type typeofChar = typeof(char); + + private static bool IsChar(Type t) => t == typeofChar; + + private static readonly Type typeofString = typeof(string); + + private static bool IsString(Type t) => t == typeofString; + + private static bool IsEnum(Type t) => t.IsEnum; + + private static bool IsCustomEnum(Type t) => t.IsDefined(typeofCustomEnum, false); + + private enum typeKeyword + { + SET, + GOTO, + COMMAND, + SPAWN, + DESPAWN + } + + private enum typemodKeyword + { + // Preparing for removal. + } + + private enum valueKeyword + { + PLAYERSINRANGE, + RANDNAME + } + + private enum valuemodKeyword + { + INC, + MOB, + TRIGMOB, + PLAYERSINRANGE + } + + // 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 readonly string CommandMobileName = null; + + private static readonly Dictionary typeKeywordHash = new(); + private static readonly Dictionary typemodKeywordHash = new(); + private static readonly Dictionary valueKeywordHash = new(); + private static readonly Dictionary valuemodKeywordHash = new(); + + private static readonly char[] slashdelim = { '/' }; + private static readonly char[] commadelim = { ',' }; + private static readonly char[] semicolondelim = { ';' }; + private static readonly char[] literalend = { 'ยง' }; + + public static bool IsValueKeyword(string str) + { + if (string.IsNullOrEmpty(str) || !char.IsUpper(str[0])) + { + return false; + } + + return valueKeywordHash.ContainsKey(str); + } + + public static bool IsValuemodKeyword(string str) + { + if (string.IsNullOrEmpty(str) || !char.IsUpper(str[0])) + { + return false; + } + + return valuemodKeywordHash.ContainsKey(str); + } + + public static bool IsTypeKeyword(string typeName) + { + if (string.IsNullOrEmpty(typeName) || !char.IsUpper(typeName[0])) + { + return false; + } + + return typeKeywordHash.ContainsKey(typeName); + } + + public static bool IsTypeOrItemKeyword(string typeName) + { + if (string.IsNullOrEmpty(typeName) || !char.IsUpper(typeName[0])) + { + return false; + } + + return typeKeywordHash.ContainsKey(typeName); + } + + public static void RemoveKeyword(string name) + { + if (name == null) + { + return; + } + + name = name.Trim().ToUpper(); + + typeKeywordHash.Remove(name); + + typemodKeywordHash.Remove(name); + + valueKeywordHash.Remove(name); + + valuemodKeywordHash.Remove(name); + } + + 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; + 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, 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); + 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() + { + // and stop all timers + if (m_Timer != null && Type == 0) + { + m_Timer.Stop(); + } + + 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(IGenericWriter writer) + { + writer.Write(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(IGenericReader reader) + { + + int version = reader.ReadInt(); + switch (version) + { + case 1: + { + Flags = (KeywordFlags)reader.ReadInt(); + goto case 0; + } + case 0: + { + m_Spawner = reader.ReadEntity(); + 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.ReadEntity(); + + DoTimer(delay, m_Delay, m_Condition, m_Goto); + } + break; + } + } + } + + // added the timer that begins on spawning tmp keywords + private class KeywordTimer : Timer + { + private readonly KeywordTag m_Tag; + private readonly XmlSpawner m_Spawner; + private readonly string m_Condition; + private readonly int m_Goto; + private TimeSpan m_Repeatdelay; + + public KeywordTimer(XmlSpawner spawner, KeywordTag tag, TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup) + : base(delay) + { + 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 (!string.IsNullOrEmpty(m_Condition) && m_Spawner != null && m_Spawner.Running) + { + // if the test is valid then terminate the timer + string status_str; + + if (TestItemProperty(m_Spawner, m_Spawner, m_Condition, out status_str)) + { + // 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); + } + + // 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) + { + // 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(); + } + 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(); + } + } + } + } + } + + public static string TagInfo(KeywordTag tag) + { + if (tag != null) + { + return $"{tag.Typename} : type={tag.Type} cond={tag.m_Condition} go={tag.m_Goto} del={tag.m_Delay} end={tag.m_End}"; + } + + 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; + } + + 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 = $"\"{value}\""; + } + else + { + toString = value.ToString(); + } + + return $"{p.Name} = {toString}"; + } + + public static bool IsItem(Type type) => type != null && (type == typeof(Item) || type.IsSubclassOf(typeof(Item))); + + public static bool IsMobile(Type type) => 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[] { 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 = AssemblyHandler.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((Serial)Convert.ToUInt32(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 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]; + + // 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); + + object po; + if (plookup != null) + { + po = plookup.GetValue(o, null); + + // now set the nested attribute using the new property list + return SetPropertyValue(spawner, po, arglist[1], value); + } + + // is a nested property with attributes so first get the property + foreach (PropertyInfo p in props) + { + if (p.Name.InsensitiveEquals(propname)) + { + 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."; + } + + string returnvalue = InternalSetValue(null, o, plookup, value, false, index); + + return returnvalue; + } + // 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 (p.Name.InsensitiveEquals(propname)) + { + if (!p.CanWrite) + { + return "Property is read only."; + } + + 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 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]); + + object po; + if (plookup != null) + { + po = plookup.GetValue(o, null); + + // now set the nested attribute using the new property list + return SetPropertyObject(spawner, po, arglist[1], value); + } + + foreach (PropertyInfo p in props) + { + if (p.Name.InsensitiveEquals(arglist[0])) + { + 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 (plookup.PropertyType == typeof(Mobile)) + { + plookup.SetValue(o, value, null); + + return "Property has been set."; + } + + return "Property is not of type Mobile."; + } + + foreach (PropertyInfo p in props) + { + if (p.Name.InsensitiveEquals(name)) + { + + if (!p.CanWrite) + { + return "Property is read only."; + } + + if (p.PropertyType == typeof(Mobile)) + { + p.SetValue(o, value, null); + + return "Property has been set."; + } + + return "Property is not of type Mobile."; + } + } + } + + return "Property not found."; + } + + 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; + 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, ","); + + if (keywordargs[0] == "SERIAL") + { + try + { + if (o is Mobile mobile) + { + ptype = mobile.Serial.GetType(); + + return $"Serial = {mobile.Serial}"; + } + + if (o is Item item) + { + ptype = item.Serial.GetType(); + + return $"Serial = {item.Serial}"; + } + + return "Object is not item/mobile"; + } + + catch { return "Serial not found."; } + } + + if (keywordargs[0] == "TYPE") + { + ptype = typeof(Type); + + return $"Type = {o.GetType().Name}"; + + } + + // 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."; + } + + 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); + } + + // is a nested property with attributes so first get the property + foreach (PropertyInfo p in props) + { + //if (Insensitive.Equals(p.Name, arglist[0])) + if (p.Name.InsensitiveEquals(propname)) + { + if (!p.CanRead) + { + return "Property is write only."; + } + + 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); + } + + // its just a simple single property + foreach (PropertyInfo p in props) + { + //if (Insensitive.Equals(p.Name, name)) + if (p.Name.InsensitiveEquals(propname)) + { + if (!p.CanRead) + { + return "Property is write only."; + } + + ptype = p.PropertyType; + + return InternalGetValue(o, p, index); + } + } + } + + return "Property not found."; + } + + // 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; + } + + var 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, "["); + string groupargstring = null; + if (groupedarglist.Length > 1) + { + // take that argument list that should like like arg2/ag3/arg4>/arg5 + // need to find the matching ">" + + string[] 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 (!string.IsNullOrEmpty(groupargstring)) + { + + if (value_keywordargs != null && value_keywordargs.Length > 0) + { + value_keywordargs[value_keywordargs.Length - 1] = groupargstring; + } + } + + // 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 + { + // 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) + { + remainder = singlearglist[1]; + } + else + { + 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.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 = $"{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 = $"Cant find {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.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 item) + { + IPooledEnumerable ie = item.GetMobilesInRange(range); + foreach (Mobile p in ie) + { + if (p.Player && p.AccessLevel == AccessLevel.Player) + { + nplayers++; + } + } + ie.Free(); + } + else if (refobject is Mobile mobile) + { + IPooledEnumerable ie = mobile.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 + { + // 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) + { + remainder = singlearglist[1]; + } + else + { + 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; + } + + public static bool TestMobProperty(XmlSpawner spawner, Mobile mobile, string testString, 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, out status_str); + + return testreturn; + } + + public static bool TestItemProperty(XmlSpawner spawner, Item ObjectPropertyItem, string testString, out string status_str) + { + // 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, 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 (p.Name.InsensitiveEquals(propname)) + { + pinfo = p; + } + } + } + } + + // did we find the property? + if (pinfo != null) + { + return pinfo; + } + // 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 (p.Name.InsensitiveEquals(propname)) + { + // did we find the type at least? + if (tinfo == null) + { + // if not then add the type to the list + tinfo = new TypeInfo + { + 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, 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, "["); + string groupargstring = null; + if (groupedarglist.Length > 1) + { + // take that argument list that should like like arg2/ag3/arg4>/arg5 + // need to find the matching ">" + + string[] 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 = groupedarglist[0].Trim().Split(','); + + if (!string.IsNullOrEmpty(groupargstring) && 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 + ptype = str.IndexOf(".") >= 0 ? typeof(double) : typeof(int); + + return str; + } + + if (startc == '"' || startc == '(') + { + ptype = typeof(string); + return str; + } + + if (startc == '#') + { + ptype = typeof(string); + return str.Substring(1); + } + // or a bool + + if (str.ToLower() == "true" || str.ToLower() == "false") + { + ptype = typeof(bool); + return str; + } + // then look for a keyword + + if (IsValueKeyword(pname)) + { + valueKeyword kw = valueKeywordHash[pname]; + + if (kw == valueKeyword.PLAYERSINRANGE && arglist.Length > 1) + { + // syntax is PLAYERSINRANGE,range + + ptype = typeof(int); + + int nplayers = 0; + int range; + // get the number of players in range + int.TryParse(arglist[1], out range); + + // count nearby players + if (spawner?.SpawnRegion != null && range < 0) + { + foreach (Mobile p in spawner.SpawnRegion.GetPlayers()) + { + if (p.AccessLevel <= spawner.TriggerAccessLevel) + { + nplayers++; + } + } + } + else if (o is Item item) + { + IPooledEnumerable ie = item.GetMobilesInRange(range); + foreach (Mobile p in ie) + { + if (p.Player && p.AccessLevel == AccessLevel.Player) + { + nplayers++; + } + } + ie.Free(); + } + else if (o is Mobile mobile) + { + IPooledEnumerable ie = mobile.GetMobilesInRange(range); + foreach (Mobile p in ie) + { + if (p.Player && p.AccessLevel == AccessLevel.Player) + { + nplayers++; + } + } + ie.Free(); + } + + return nplayers.ToString(); + } + if (kw == valueKeyword.RANDNAME && arglist.Length > 1) + { + // syntax is RANDNAME,nametype + return NameList.RandomName(arglist[1]); + } + + // an invalid keyword format will be passed as literal + return str; + } + + if (literal) + { + ptype = typeof(string); + return str; + } + + // 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]; + } + + // for everything else + // pass on as is + return arglist[1].Trim(); + } + + return null; + } + + public static bool CheckPropertyString(XmlSpawner spawner, object o, string testString, out string status_str) + { + status_str = null; + + if (o == null) + { + return false; + } + + if (string.IsNullOrEmpty(testString)) + { + 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, out status_str); + + // simple conditional test with no and/or operators + return returnval; + } + + // test each half independently and combine the results + bool first = CheckSingleProperty(spawner, o, arglist[0], 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], 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; + } + + if (orposition > 0 && andposition <= 0 || orposition > 0 && orposition < andposition) + { + // or operator + return first || second; + } + + // should never get here + return false; + } + + public static bool CheckSingleProperty(XmlSpawner spawner, object o, string testString, 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(), 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(), 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 + { + 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 + // and do the type dependent comparisons + if (ptype2 == typeof(DateTime) || ptype1 == typeof(DateTime)) + { + if (hasequal) + { + DateTime dt1, dt2; + if (DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) + { + if (dt1 == dt2) + { + return !invertreturn; + } + } + else + { + status_str = $"invalid DateTime comparison : {{0}}{testString}"; + } + } + else if (hasnotequals) + { + DateTime dt1, dt2; + if (DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) + { + if (dt1 != dt2) + { + return !invertreturn; + } + } + else + { + status_str = $"invalid DateTime comparison : {{0}}{testString}"; + } + } + else if (hasgreaterthan) + { + DateTime dt1, dt2; + if (DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) + { + if (dt1 > dt2) + { + return !invertreturn; + } + } + else + { + status_str = $"invalid DateTime comparison : {{0}}{testString}"; + } + } + else + { + DateTime dt1, dt2; + if (DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) + { + if (dt1 < dt2) + { + return !invertreturn; + } + } + else + { + status_str = $"invalid DateTime comparison : {{0}}{testString}"; + } + } + } + else if (IsNumeric(ptype2) && IsNumeric(ptype1)) + { + if (hasequal) + { + try + { + if (Convert.ToInt64(value1, base1) == Convert.ToInt64(value2, base2)) + { + return !invertreturn; + } + } + catch + { + status_str = $"invalid int comparison : {{0}}{testString}"; + } + } + else if (hasnotequals) + { + try + { + if (Convert.ToInt64(value1, base1) != Convert.ToInt64(value2, base2)) + { + return !invertreturn; + } + } + catch + { + status_str = $"invalid int comparison : {{0}}{testString}"; + } + } + else if (hasgreaterthan) + { + try + { + if (Convert.ToInt64(value1, base1) > Convert.ToInt64(value2, base2)) + { + return !invertreturn; + } + } + catch { status_str = $"invalid int comparison : {{0}}{testString}"; } + } + else + { + 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)) + { + 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 + { + 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)) + { + 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 + { + 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; + double val2; + 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 (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 (ptype2 == typeof(bool) && ptype1 == typeof(bool)) + { + bool val1, val2; + if (hasequal) + { + if (bool.TryParse(value1, out val1) && bool.TryParse(value2, out val2)) + { + if (val1 == val2) + { + return !invertreturn; + } + } + else { status_str = $"invalid bool comparison : {{0}}{testString}"; } + } + else if (hasnotequals) + { + if (bool.TryParse(value1, out val1) && bool.TryParse(value2, out val2)) + { + if (val1 != val2) + { + return !invertreturn; + } + } + else { status_str = $"invalid bool comparison : {{0}}{testString}"; } + } + } + else if (ptype2 == typeof(double) || ptype2 == typeof(double)) + { + double val1; + double val2; + 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 double 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 double 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 double comparison : {{0}}{testString}"; } + } + else + { + 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 double comparison : {{0}}{testString}"; } + } + } + else + { + // by default just do a string comparison + if (hasequal) + { + if (value1 == value2) + { + return !invertreturn; + } + } + else + if (hasnotequals) + { + if (value1 != value2) + { + return !invertreturn; + } + } + } + return invertreturn; + } + + public static Item SearchMobileForItem(Mobile m, string targetName, string typeStr, bool searchbank) => 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 container && !equippedonly) + { + Item itemTarget = SearchPackForItem(container, 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 container) + { + Item itemTarget = SearchPackForItem(container, 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 Item SearchPackForItem(Container pack, string targetName, string typestr) + { + if (pack != null && !pack.Deleted) + { + Type targettype = null; + + if (typestr != null) + { + targettype = AssemblyHandler.FindTypeByName(typestr); + } + + // 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) + { + + if (item is Container container) + { + Item itemTarget = SearchPackForItem(container, 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; + } + private static bool CheckNameMatch(string targetname, string name) => + // a "*" targetname will match anything + // a null or empty targetname will match a null name + // otherwise the strings must match + targetname == "*" || name == targetname || targetname != null && targetname.Length == 0 && name == 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; + + try + { + targettype = AssemblyHandler.FindTypeByName(typename); + } + catch { } + + if (objecttype != null && targettype != null && (objecttype.Equals(targettype) || objecttype.IsSubclassOf(targettype))) + { + return true; + + } + + return false; + + } + 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); + } + + // 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; + } + + if (orposition > 0 && andposition <= 0 || orposition > 0 && orposition < andposition) + { + // or operator + return first || second; + } + // 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) + { + try + { + atype = AssemblyHandler.FindTypeByName(objstr[2]); + } + catch { } + } + // try to find the attachment on the mob + if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) + { + return true; + } + + return false; + } + + 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; + } + + 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++; + } + + + 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 token) + { + 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++) + { + try + { + switch (int.Parse(objstr[n]) - 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; + } + } + } + catch { } + } + } + 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 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); + } + + // 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; + } + + if (orposition > 0 && andposition <= 0 || orposition > 0 && orposition < andposition) + { + // or operator (see explanation above) + return first && second; + } + // 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) + { + try + { + atype = AssemblyHandler.FindTypeByName(objstr[2]); + } + catch { } + } + + // try to find the attachment on the mob + if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) + { + return false; + } + + return true; + } + + 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; + } + + 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 token && token.IsValid) + { + 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++) + { + try + { + switch (int.Parse(objstr[n]) - 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; + } + } + } + catch { } + } + } + 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 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 = AssemblyHandler.FindTypeByName(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 || + 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) // if a unique item is found then success + { + // add this to the recent search list + AddToRecentItemSearchList(fromspawner, founditem); + + return founditem; + } + + 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 = AssemblyHandler.FindTypeByName(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 || + 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 a unique item is found then success + if (count == 1) + { + // add this to the recent search list + AddToRecentMobileSearchList(fromspawner, foundmobile); + + return foundmobile; + } + + return null; + } + + public static XmlSpawner FindSpawnerByName(XmlSpawner fromspawner, string name) + { + if (name == null) + { + return null; + } + + if (name.StartsWith("0x")) + { + uint serial; + try + { + serial = Convert.ToUInt32(name, 16); + return World.FindEntity((Serial)serial); + } + catch { } + } + + // 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 spawner) + { + 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 a unique item is found then success + if (count == 1) + { + // add this to the recent search list + AddToRecentSpawnerSearchList(fromspawner, foundspawner); + + return foundspawner; + } + + 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 = AssemblyHandler.FindTypeByName(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 || + 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 = AssemblyHandler.FindTypeByName(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 || + 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; + } + + public static string ApplySubstitution(XmlSpawner spawner, object o, string typeName) + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + // go through the string looking for instances of {keyword} + string remaining = typeName; + + while (!string.IsNullOrEmpty(remaining)) + { + + 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(), 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]; + } + + 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 (!string.IsNullOrEmpty(itemtypestring)) + { + argstart = itemtypestring.IndexOf(",") + 1; + } + + if (argstart > 1 && argstart < itemtypestring.Length) + { + typeargs = ParseCommaArgs(itemtypestring.Substring(argstart), 15); + } + return typeargs; + + } + + 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(); + str = str.Trim(); + string[] args = str.Split(delims, nitems); + + return args; + } + + public static string[] ParseSlashArgs(string str, int nitems) + { + if (str == null) + { + return null; + } + + str = str.Trim(); + + + string[] args; + // 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[] ParseCommaArgs(string str, int nitems) + { + if (str == null) + { + return null; + } + + str = str.Trim(); + + string[] args = str.Split(commadelim, nitems); + return args; + } + + public static string[] ParseLiteralTerminator(string str) + { + if (str == null) + { + return null; + } + + str = str.Trim(); + + string[] args = str.Split(literalend, 2); + return args; + } + + public static string[] ParseSemicolonArgs(string str, int nitems) + { + if (str == null) + { + return null; + } + + str = str.Trim(); + + string[] 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; + List strargs = new List(); + while (true) + { + // go through the string and find the first instance of the separator + var 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; + } + + 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, + 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 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) + { + parent.DropItem(item); + } + else + { + parent.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 + ApplyObjectStringProperties(spawner, propertyString, item, trigmob, spawner, out status_str); + } + + public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, + Mobile triggermob, Map map, out string status_str) => + SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, + triggermob, map, out status_str, 0); + + public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, Mobile triggermob, Map map, 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 + 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")) + { + uint serial; + try + { + serial = Convert.ToUInt32(keywordargs[1], 16); + setitem = World.FindEntity((Serial)serial); + } + catch { } + } + 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; + } + + 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.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; + } + + 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; + } + + 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, $"{CommandSystem.Prefix}{arglist[1]}"); + } + } + else + if (triggermob != null && !triggermob.Deleted) + { + CommandSystem.Handle(triggermob, $"{CommandSystem.Prefix}{arglist[1]}"); + } + } + else + { + status_str = "insufficient args to COMMAND"; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + default: + { + status_str = "unrecognized keyword"; + // should never get here + break; + } + } + // indicate successful keyword spawn + return true; + } + + // should never get here + status_str = "unrecognized keyword"; + return false; + } + + 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; + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/ExceptionLogging.cs b/Projects/UOContent/Engines/XMLSpawner/ExceptionLogging.cs new file mode 100644 index 000000000..a60a4017d --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/ExceptionLogging.cs @@ -0,0 +1,74 @@ +using System; +using System.IO; + +namespace Server.Diagnostics; + +// TODO: Replace this with serilog +public class ExceptionLogging +{ + public static string LogDirectory { get; set; } + + private static StreamWriter _Output; + + public static StreamWriter Output + { + get + { + if (_Output == null) + { + _Output = new StreamWriter(Path.Combine(LogDirectory, $"{Core.Now.ToLongDateString()}.log"), true) + { + AutoFlush = true + }; + + _Output.WriteLine("##############################"); + _Output.WriteLine("Exception log started on {0}", Core.Now); + _Output.WriteLine(); + } + + return _Output; + } + } + + static ExceptionLogging() + { + var directory = Path.Combine(Core.BaseDirectory, "Logs/Exceptions"); + + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + LogDirectory = directory; + } + + public static void LogException(Exception e) + { + Utility.PushColor(ConsoleColor.Red); + Console.WriteLine("Caught Exception:"); + Utility.PopColor(); + + Utility.PushColor(ConsoleColor.DarkRed); + Console.WriteLine(e); + Utility.PopColor(); + + Output.WriteLine("Exception Caught: {0}", Core.Now); + Output.WriteLine(e); + Output.WriteLine(); + } + + public static void LogException(Exception e, string arg) + { + Utility.PushColor(ConsoleColor.Red); + Console.WriteLine("Caught Exception: {0}", arg); + Utility.PopColor(); + + Utility.PushColor(ConsoleColor.DarkRed); + Console.WriteLine(e); + Utility.PopColor(); + + Output.WriteLine("Exception Caught: {0}", Core.Now); + Output.WriteLine(e); + Output.WriteLine(); + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs b/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs new file mode 100644 index 000000000..ce893bfcf --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs @@ -0,0 +1,134 @@ +using System; +using Server.Targeting; + +namespace Server.Items; + +public partial class ItemFlags +{ + private const int StealableFlag = 0x00200000; + private const int TakenFlag = 0x00100000; + + public static void SetStealable(Item target, bool value) + { + target?.SetSavedFlag(StealableFlag, value); + } + public static bool GetStealable(Item target) => target != null && target.GetSavedFlag(StealableFlag); + + public static void SetTaken(Item target, bool value) + { + target?.SetSavedFlag(TakenFlag, value); + } + public static bool GetTaken(Item target) => target != null && target.GetSavedFlag(TakenFlag); + + [Usage("Flag flagfield")] + [Description("Gets the state of the specified SavedFlag on any item")] + public static void GetFlag_OnCommand(CommandEventArgs e) + { + int flag=0; + bool error = false; + if (e.Arguments.Length > 0) + { + if (e.Arguments[0].StartsWith("0x")) + { + try{flag = Convert.ToInt32(e.Arguments[0].Substring(2), 16); } catch { error = true;} + } else + { + try{flag = int.Parse(e.Arguments[0]); } catch { error = true;} + } + + } + if (!error) + { + e.Mobile.Target = new GetFlagTarget(e,flag); + } else + { + try{ + e.Mobile.SendMessage(33,"Flag: Bad flagfield argument"); + } catch {} + } + } + + private class GetFlagTarget : Target + { + private CommandEventArgs m_e; + private int m_flag; + + public GetFlagTarget(CommandEventArgs e, int flag) : base (30, false, TargetFlags.None) + { + m_e = e; + m_flag = flag; + } + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Item item) + { + bool state = item.GetSavedFlag(m_flag); + + from.SendMessage("Flag (0x{0:X}) = {1}",m_flag,state); + } else + { + from.SendMessage("Must target an Item"); + } + } + } + + + [Usage("Stealable [true/false]")] + [Description("Sets/gets the stealable flag on any item")] + public static void SetStealable_OnCommand(CommandEventArgs e) + { + bool state = false; + bool error = false; + if (e.Arguments.Length > 0) + { + try + { + state = bool.Parse(e.Arguments[0]); + } + catch + { + error = true; + } + } + if (!error) + { + e.Mobile.Target = new SetStealableTarget(e, state); + } + + } + + private class SetStealableTarget : Target + { + private CommandEventArgs m_e; + private bool m_state; + private bool set; + + public SetStealableTarget(CommandEventArgs e, bool state) : base (30, false, TargetFlags.None) + { + m_e = e; + m_state = state; + if (e.Arguments.Length > 0) + { + set = true; + } + } + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Item item) + { + if (set) + { + SetStealable(item, m_state); + } + + bool state = GetStealable(item); + + from.SendMessage("Stealable = {0}",state); + + } else + { + from.SendMessage("Must target an Item"); + } + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs b/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs new file mode 100644 index 000000000..d5fa8d955 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs @@ -0,0 +1,283 @@ +using Server.Commands.Generic; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using Server.Engines.Spawners; + +/* +** Sno's distro spawner importer/exporter +** +** [exportspawner filename - Saves distro spawners to XML to 'Saves/Spawners/filename' +** +** [importspawner filename - Restores distro spawners from 'Saves/Spawners/filename'. Note, this command does not check for +** duplication, so if you run it more than once you will end up with multiple spawners. +** +** These spawns can also be imported back in as XmlSpawners by using the '[xmlimportspawners Saves/Spawners/filename' command. +*/ + +namespace Server.Mobiles; + +public class SpawnerExporter +{ + public static void Initialize() + { + TargetCommands.Register(new ExportSpawnerCommand()); + CommandSystem.Register("ImportSpawners", AccessLevel.Administrator, ImportSpawners_OnCommand); + } + + public class ExportSpawnerCommand : BaseCommand + { + public ExportSpawnerCommand() + { + AccessLevel = AccessLevel.Administrator; + Supports = CommandSupport.Area | CommandSupport.Region | CommandSupport.Global | CommandSupport.Multi | CommandSupport.Single; + Commands = new[] { "ExportSpawner" }; + ObjectTypes = ObjectTypes.Items; + Usage = "ExportSpawner "; + Description = "Exports all Spawner objects to the specified filename."; + ListOptimized = true; + } + + public override void ExecuteList(CommandEventArgs e, List list) + { + string filename = e.GetString(0); + + ArrayList spawners = new ArrayList(); + + for (int i = 0; i < list.Count; ++i) + { + if (list[i] is Spawner) + { + Spawner spawner = (Spawner)list[i]; + if (!spawner.Deleted && spawner.Map != Map.Internal && spawner.Parent == null) + { + spawners.Add(spawner); + } + } + } + + AddResponse($"{spawners.Count.ToString()} spawners exported to Saves/Spawners/{filename}."); + + ExportSpawners(spawners, filename); + } + + public override bool ValidateArgs(BaseCommandImplementor impl, CommandEventArgs e) + { + if (e.Arguments.Length >= 1) + { + return true; + } + + e.Mobile.SendMessage($"Usage: {Usage}"); + return false; + } + + private void ExportSpawners(ArrayList spawners, string filename) + { + if (spawners.Count == 0) + { + return; + } + + if (!Directory.Exists("Saves/Spawners")) + { + Directory.CreateDirectory("Saves/Spawners"); + } + + string filePath = Path.Combine("Saves/Spawners", filename); + + using (StreamWriter op = new StreamWriter(filePath)) + { + XmlTextWriter xml = new XmlTextWriter(op) + { + Formatting = Formatting.Indented, + IndentChar = '\t', + Indentation = 1 + }; + + xml.WriteStartDocument(true); + + xml.WriteStartElement("spawners"); + + xml.WriteAttributeString("count", spawners.Count.ToString()); + + foreach (Spawner spawner in spawners) + { + ExportSpawner(spawner, xml); + } + + xml.WriteEndElement(); + + xml.Close(); + } + } + + private void ExportSpawner(Spawner spawner, XmlWriter xml) + { + xml.WriteStartElement("spawner"); + + xml.WriteStartElement("count"); + xml.WriteString(spawner.Count.ToString()); + xml.WriteEndElement(); + + xml.WriteStartElement("group"); + xml.WriteString(spawner.Group.ToString()); + xml.WriteEndElement(); + + xml.WriteStartElement("homerange"); + xml.WriteString(spawner.HomeRange.ToString()); + xml.WriteEndElement(); + + xml.WriteStartElement("walkingrange"); + xml.WriteString(spawner.WalkingRange.ToString()); + xml.WriteEndElement(); + + xml.WriteStartElement("maxdelay"); + xml.WriteString(spawner.MaxDelay.ToString()); + xml.WriteEndElement(); + + xml.WriteStartElement("mindelay"); + xml.WriteString(spawner.MinDelay.ToString()); + xml.WriteEndElement(); + + xml.WriteStartElement("team"); + xml.WriteString(spawner.Team.ToString()); + xml.WriteEndElement(); + + xml.WriteStartElement("creaturesname"); + foreach (var entry in spawner.Entries) + { + xml.WriteStartElement("creaturename"); + xml.WriteString(entry.SpawnedName); + xml.WriteEndElement(); + } + xml.WriteEndElement(); + + // Item properties + + xml.WriteStartElement("name"); + xml.WriteString(spawner.Name); + xml.WriteEndElement(); + + xml.WriteStartElement("location"); + xml.WriteString(spawner.Location.ToString()); + xml.WriteEndElement(); + + xml.WriteStartElement("map"); + xml.WriteString(spawner.Map.ToString()); + xml.WriteEndElement(); + + xml.WriteEndElement(); + } + } + + [Usage("ImportSpawners")] + [Description("Recreates Spawner items from the specified file.")] + public static void ImportSpawners_OnCommand(CommandEventArgs e) + { + if (e.Arguments.Length >= 1) + { + string filename = e.GetString(0); + string filePath = Path.Combine("Saves/Spawners", filename); + + if (File.Exists(filePath)) + { + XmlDocument doc = new XmlDocument(); + doc.Load(filePath); + + XmlElement root = doc["spawners"]; + + int successes = 0, failures = 0; + + foreach (XmlElement spawner in root.GetElementsByTagName("spawner")) + { + try + { + ImportSpawner(spawner); + successes++; + } + catch (Exception ex) + { + failures++; + Diagnostics.ExceptionLogging.LogException(ex); + } + } + + e.Mobile.SendMessage("{0} spawners loaded successfully from {1}, {2} failures.", successes, filePath, failures); + } + else + { + e.Mobile.SendMessage("File {0} does not exist.", filePath); + } + } + else + { + e.Mobile.SendMessage("Usage: [ImportSpawners "); + } + } + + private static string GetText(XmlNode node, string defaultValue) + { + if (node == null) + { + return defaultValue; + } + + return node.InnerText; + } + + private static void ImportSpawner(XmlNode node) + { + int count = int.Parse(GetText(node["count"], "1")); + int homeRange = int.Parse(GetText(node["homerange"], "4")); + + int walkingRange = int.Parse(GetText(node["walkingrange"], "-1")); + + int team = int.Parse(GetText(node["team"], "0")); + + bool group = bool.Parse(GetText(node["group"], "False")); + TimeSpan maxDelay = TimeSpan.Parse(GetText(node["maxdelay"], "10:00")); + TimeSpan minDelay = TimeSpan.Parse(GetText(node["mindelay"], "05:00")); + IEnumerable creaturesName = LoadCreaturesName(node["creaturesname"]); + + string name = GetText(node["name"], "Spawner"); + Point3D location = Point3D.Parse(GetText(node["location"], "Error")); + Map map = Map.Parse(GetText(node["map"], "Error")); + + Spawner spawner = new Spawner(count, minDelay, maxDelay, team, homeRange, creaturesName.ToArray()); + if (walkingRange >= 0) + { + spawner.WalkingRange = walkingRange; + } + + spawner.Name = name; + spawner.MoveToWorld(location, map); + if (spawner.Map == Map.Internal) + { + spawner.Delete(); + throw new Exception("Spawner created on Internal map."); + } + spawner.Respawn(); + } + + private static IEnumerable LoadCreaturesName(XmlElement node) + { + List names = new List(); + + if (node != null) + { + foreach (XmlElement ele in node.GetElementsByTagName("creaturename")) + { + if (ele != null) + { + names.Add(ele.InnerText); + } + } + } + + return names; + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs new file mode 100644 index 000000000..29e451244 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs @@ -0,0 +1,721 @@ +using Server.Commands.Generic; +using Server.Network; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using CPA = Server.CommandPropertyAttribute; +/* +** modified properties gumps taken from RC0 properties gump scripts to support the special XmlSpawner properties gump +*/ + +namespace Server.Gumps; + +public class XmlPropertiesGump : Gump +{ + private readonly ArrayList m_List; + private int m_Page; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int NameWidth = 103; + private static readonly int ValueWidth = 82; + + private static readonly int EntryCount = 66; + private static readonly int ColumnEntryCount = 22; + + private static readonly int TypeWidth = NameWidth + OffsetSize + ValueWidth; + + private static readonly int TotalWidth = OffsetSize + NameWidth + OffsetSize + ValueWidth + OffsetSize + SetWidth + OffsetSize; + + public XmlPropertiesGump(Mobile mobile, object o) : base(GumpOffsetX, GumpOffsetY) + { + m_Mobile = mobile; + m_Object = o; + m_List = BuildList(); + + Initialize(0); + } + + public XmlPropertiesGump(Mobile mobile, object o, Stack stack, StackEntry parent) : base(GumpOffsetX, GumpOffsetY) + { + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_List = BuildList(); + + if (parent != null) + { + if (m_Stack == null) + { + m_Stack = new Stack(); + } + + m_Stack.Push(parent); + } + + Initialize(0); + } + + public XmlPropertiesGump(Mobile mobile, object o, Stack stack, ArrayList list, int page) : base(GumpOffsetX, GumpOffsetY) + { + m_Mobile = mobile; + m_Object = o; + m_List = list; + m_Stack = stack; + + Initialize(page); + } + + private void Initialize(int page) + { + m_Page = page; + + int count = m_List.Count - page * EntryCount; + + if (count < 0) + { + count = 0; + } + else if (count > EntryCount) + { + count = EntryCount; + } + + int lastIndex = page * EntryCount + count - 1; + + if (lastIndex >= 0 && lastIndex < m_List.Count && m_List[lastIndex] == null) + { + --count; + } + + int totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (ColumnEntryCount + 1); + + AddPage(0); + + AddBackground(0, 0, TotalWidth * 3 + BorderSize * 2, BorderSize + totalHeight + BorderSize, BackGumpID); + AddImageTiled(BorderSize, BorderSize + EntryHeight, (TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0)) * 3, totalHeight - EntryHeight, OffsetGumpID); + + int x = BorderSize + OffsetSize; + int y = BorderSize; + + if (m_Object is Item item) + { + AddLabelCropped(x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, TextHue, item.Name); + } + + int propcount = 0; + for (int i = 0, index = page * EntryCount; i <= count && index < m_List.Count; ++i, ++index) + { + // do the multi column display + int column = propcount / ColumnEntryCount; + if (propcount % ColumnEntryCount == 0) + { + y = BorderSize; + } + + x = BorderSize + OffsetSize + column * (ValueWidth + NameWidth + OffsetSize * 2 + SetOffsetX + SetWidth); + y += EntryHeight + OffsetSize; + + object o = m_List[index]; + + if (o == null) + { + AddImageTiled(x - OffsetSize, y, TotalWidth, EntryHeight, BackGumpID + 4); + propcount++; + } + else if (o is PropertyInfo prop) + { + propcount++; + + // look for the default value of the equivalent property in the XmlSpawnerDefaults.DefaultEntry class + + int huemodifier = TextHue; + Mobiles.XmlSpawnerDefaults.DefaultEntry de = new Mobiles.XmlSpawnerDefaults.DefaultEntry(); + Type ftype = de.GetType(); + + var finfo = ftype.GetField(prop.Name); + + // is there an equivalent default field? + if (finfo != null) + { + // see if the value is different from the default + if (ValueToString(finfo.GetValue(de)) != ValueToString(prop)) + { + huemodifier = 68; + } + } + + AddImageTiled(x, y, NameWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, NameWidth - TextOffsetX, EntryHeight, huemodifier, prop.Name); + x += NameWidth + OffsetSize; + AddImageTiled(x, y, ValueWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, huemodifier, ValueToString(prop)); + x += ValueWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + CPA cpa = GetCPA(prop); + + if (prop.CanWrite && cpa != null && m_Mobile.AccessLevel >= cpa.WriteLevel) + { + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3); + } + } + } + } + + public static string[] m_BoolNames = { "True", "False" }; + public static object[] m_BoolValues = { true, false }; + + public static string[] m_PoisonNames = { "None", "Lesser", "Regular", "Greater", "Deadly", "Lethal" }; + public static object[] m_PoisonValues = { null, Poison.Lesser, Poison.Regular, Poison.Greater, Poison.Deadly, Poison.Lethal }; + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = state.Mobile; + + if (!BaseCommand.IsAccessible(from, m_Object)) + { + from.SendMessage("You may no longer access their properties."); + return; + } + + switch (info.ButtonID) + { + case 0: // Closed + { + if (m_Stack != null && m_Stack.Count > 0) + { + StackEntry entry = m_Stack.Pop(); + from.SendGump(new XmlPropertiesGump(from, entry.m_Object, m_Stack, null)); + } + + break; + } + case 1: // Previous + { + if (m_Page > 0) + { + from.SendGump(new XmlPropertiesGump(from, m_Object, m_Stack, m_List, m_Page - 1)); + } + + break; + } + case 2: // Next + { + if ((m_Page + 1) * EntryCount < m_List.Count) + { + from.SendGump(new XmlPropertiesGump(from, m_Object, m_Stack, m_List, m_Page + 1)); + } + + break; + } + default: + { + int index = m_Page * EntryCount + (info.ButtonID - 3); + + if (index >= 0 && index < m_List.Count) + { + PropertyInfo prop = m_List[index] as PropertyInfo; + + if (prop == null) + { + return; + } + + CPA attr = GetCPA(prop); + + if (!prop.CanWrite || attr == null || from.AccessLevel < attr.WriteLevel) + { + return; + } + + Type type = prop.PropertyType; + + if (IsType(type, typeofMobile) || IsType(type, typeofItem)) + { + from.SendGump(new XmlSetObjectGump(prop, from, m_Object, m_Stack, type, m_Page, m_List)); + } + else if (IsType(type, typeofType)) + { + from.Target = new XmlSetObjectTarget(prop, from, m_Object, m_Stack, type, m_Page, m_List); + } + else if (IsType(type, typeofPoint3D)) + { + from.SendGump(new XmlSetPoint3DGump(prop, from, m_Object, m_Stack, m_Page, m_List)); + } + else if (IsType(type, typeofPoint2D)) + { + from.SendGump(new XmlSetPoint2DGump(prop, from, m_Object, m_Stack, m_Page, m_List)); + } + else if (IsType(type, typeofTimeSpan)) + { + from.SendGump(new XmlSetTimeSpanGump(prop, from, m_Object, m_Stack, m_Page, m_List)); + } + else if (IsCustomEnum(type)) + { + from.SendGump(new XmlSetCustomEnumGump(prop, from, m_Object, m_Stack, m_Page, m_List, GetCustomEnumNames(type))); + } + else if (IsType(type, typeofEnum)) + { + from.SendGump(new XmlSetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, Enum.GetNames(type), GetObjects(Enum.GetValues(type)))); + } + else if (IsType(type, typeofBool)) + { + from.SendGump(new XmlSetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, m_BoolNames, m_BoolValues)); + } + else if (IsType(type, typeofString) || IsType(type, typeofReal) || IsType(type, typeofNumeric)) + { + from.SendGump(new XmlSetGump(prop, from, m_Object, m_Stack, m_Page, m_List)); + } + else if (IsType(type, typeofPoison)) + { + from.SendGump(new XmlSetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, m_PoisonNames, m_PoisonValues)); + } + else if (IsType(type, typeofMap)) + { + from.SendGump(new XmlSetListOptionGump(prop, from, m_Object, m_Stack, m_Page, m_List, Map.GetMapNames(), Map.GetMapValues())); + } + else if (IsType(type, typeofSkills) && m_Object is Mobile mobile) + { + from.SendGump(new XmlPropertiesGump(from, mobile, m_Stack, m_List, m_Page)); + from.SendGump(new SkillsGump(from, mobile)); + } + else if (HasAttribute(type, typeofPropertyObject, true)) + { + object obj = prop.GetValue(m_Object, null); + + from.SendGump(obj != null + ? new XmlPropertiesGump(from, obj, m_Stack, + new StackEntry(m_Object, prop)) + : new XmlPropertiesGump(from, m_Object, m_Stack, m_List, m_Page)); + } + } + + break; + } + } + } + + private static object[] GetObjects(Array a) + { + object[] list = new object[a.Length]; + + for (int i = 0; i < list.Length; ++i) + { + list[i] = a.GetValue(i); + } + + return list; + } + + private static bool IsCustomEnum(Type type) => type.IsDefined(typeofCustomEnum, false); + + private static string[] GetCustomEnumNames(Type type) + { + object[] attrs = type.GetCustomAttributes(typeofCustomEnum, false); + + if (attrs.Length == 0) + { + return new string[0]; + } + + CustomEnumAttribute ce = attrs[0] as CustomEnumAttribute; + + if (ce == null) + { + return new string[0]; + } + + return ce.Names; + } + + private static bool HasAttribute(Type type, Type check, bool inherit) + { + object[] objs = type.GetCustomAttributes(check, inherit); + + return objs.Length > 0; + } + + private static bool IsType(Type type, Type check) => type == check || type.IsSubclassOf(check); + + private static bool IsType(Type type, Type[] check) + { + for (int i = 0; i < check.Length; ++i) + { + if (IsType(type, check[i])) + { + return true; + } + } + + return false; + } + + private static readonly Type typeofMobile = typeof(Mobile); + private static readonly Type typeofItem = typeof(Item); + private static readonly Type typeofType = typeof(Type); + private static readonly Type typeofPoint3D = typeof(Point3D); + private static readonly Type typeofPoint2D = typeof(Point2D); + private static readonly Type typeofTimeSpan = typeof(TimeSpan); + private static readonly Type typeofCustomEnum = typeof(CustomEnumAttribute); + private static readonly Type typeofEnum = typeof(Enum); + private static readonly Type typeofBool = typeof(bool); + private static readonly Type typeofString = typeof(string); + private static readonly Type typeofPoison = typeof(Poison); + private static readonly Type typeofMap = typeof(Map); + private static readonly Type typeofSkills = typeof(Skills); + private static readonly Type typeofPropertyObject = typeof(PropertyObjectAttribute); + private static readonly Type typeofNoSort = typeof(NoSortAttribute); + + private static readonly Type[] typeofReal = + { + typeof(float), + typeof(double) + }; + + private static readonly Type[] typeofNumeric = + { + typeof(byte), + typeof(short), + typeof(int), + typeof(long), + typeof(sbyte), + typeof(ushort), + typeof(uint), + typeof(ulong) + }; + + private string ValueToString(PropertyInfo prop) => ValueToString(m_Object, prop); + + public static string ValueToString(object obj, PropertyInfo prop) + { + try + { + return ValueToString(prop.GetValue(obj, null)); + } + catch (Exception e) + { + return $"!{e.GetType()}!"; + } + } + + public static string ValueToString(object o) + { + if (o == null) + { + return "-null-"; + } + + if (o is string s1) + { + return $"\"{s1}\""; + } + + if (o is bool) + { + return o.ToString(); + } + + if (o is char c) + { + return $"0x{(int)c:X} '{c}'"; + } + + if (o is Serial s) + { + if (s.IsValid) + { + if (s.IsItem) + { + return $"(I) 0x{s.Value:X}"; + } + if (s.IsMobile) + { + return $"(M) 0x{s.Value:X}"; + } + } + + return $"(?) 0x{s.Value:X}"; + } + + if (o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong) + { + return string.Format("{0} (0x{0:X})", o); + } + + if (o is double) + { + return o.ToString(); + } + + if (o is Mobile mobile) + { + return $"(M) 0x{mobile.Serial.Value:X} \"{mobile.Name}\""; + } + + if (o is Item item) + { + return $"(I) 0x{item.Serial:X}"; + } + + if (o is Type type) + { + return type.Name; + } + + return o.ToString(); + } + + private ArrayList BuildList() + { + Type type = m_Object.GetType(); + + PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + + ArrayList groups = GetGroups(type, props); + ArrayList list = new ArrayList(); + + for (int i = 0; i < groups.Count; ++i) + { + DictionaryEntry de = (DictionaryEntry)groups[i]; + ArrayList groupList = (ArrayList)de.Value; + + if (!HasAttribute((Type)de.Key, typeofNoSort, false)) + { + groupList.Sort(PropertySorter.Instance); + } + + if (i != 0) + { + list.Add(null); + } + + list.Add(de.Key); + list.AddRange(groupList); + } + + return list; + } + + private static readonly Type typeofCPA = typeof(CPA); + private static readonly Type typeofObject = typeof(object); + + private static CPA GetCPA(PropertyInfo prop) + { + object[] attrs = prop.GetCustomAttributes(typeofCPA, false); + + if (attrs.Length > 0) + { + return attrs[0] as CPA; + } + + return null; + } + + private ArrayList GetGroups(Type objectType, PropertyInfo[] props) + { + Hashtable groups = new Hashtable(); + + for (int i = 0; i < props.Length; ++i) + { + PropertyInfo prop = props[i]; + + if (prop.CanRead) + { + CPA attr = GetCPA(prop); + + if (attr != null && m_Mobile.AccessLevel >= attr.ReadLevel) + { + Type type = prop.DeclaringType; + + while (true) + { + Type baseType = type.BaseType; + + if (baseType == null || baseType == typeofObject) + { + break; + } + + if (baseType.GetProperty(prop.Name, prop.PropertyType) != null) + { + type = baseType; + } + else + { + break; + } + } + + ArrayList list = (ArrayList)groups[type]; + + if (list == null) + { + groups[type] = list = new ArrayList(); + } + + list.Add(prop); + } + } + } + + ArrayList sorted = new ArrayList(groups); + + sorted.Sort(new GroupComparer(objectType)); + + return sorted; + } + + public static object GetObjectFromString(Type t, string s) + { + if (t == typeof(string)) + { + return s; + } + + if (t == typeof(byte) || t == typeof(sbyte) || t == typeof(short) || t == typeof(ushort) || t == typeof(int) || t == typeof(uint) || t == typeof(long) || t == typeof(ulong)) + { + if (s.StartsWith("0x")) + { + if (t == typeof(ulong) || t == typeof(uint) || t == typeof(ushort) || t == typeof(byte)) + { + return Convert.ChangeType(Convert.ToUInt64(s.Substring(2), 16), t); + } + + return Convert.ChangeType(Convert.ToInt64(s.Substring(2), 16), t); + } + + return Convert.ChangeType(s, t); + } + + if (t == typeof(double) || t == typeof(float)) + { + return Convert.ChangeType(s, t); + } + if (t.IsDefined(typeof(ParsableAttribute), false)) + { + MethodInfo parseMethod = t.GetMethod("Parse", new[] { typeof(string) }); + + return parseMethod.Invoke(null, new object[] { s }); + } + + throw new Exception("bad"); + } + + private class PropertySorter : IComparer + { + public static readonly PropertySorter Instance = new(); + + private PropertySorter() + { + } + + public int Compare(object x, object y) + { + if (x == null && y == null) + { + return 0; + } + + if (x == null) + { + return -1; + } + + if (y == null) + { + return 1; + } + + PropertyInfo a = x as PropertyInfo; + PropertyInfo b = y as PropertyInfo; + + if (a == null || b == null) + { + throw new ArgumentException(); + } + + return a.Name.CompareTo(b.Name); + } + } + + private class GroupComparer : IComparer + { + private readonly Type m_Start; + + public GroupComparer(Type start) => m_Start = start; + + private static readonly Type typeofObject = typeof(object); + + private int GetDistance(Type type) + { + Type current = m_Start; + + int dist; + + for (dist = 0; current != null && current != typeofObject && current != type; ++dist) + { + current = current.BaseType; + } + + return dist; + } + + public int Compare(object x, object y) + { + if (x == null && y == null) + { + return 0; + } + + if (x == null) + { + return -1; + } + + if (y == null) + { + return 1; + } + + if (!(x is DictionaryEntry de1) || !(y is DictionaryEntry de2)) + { + throw new ArgumentException(); + } + + Type a = (Type)de1.Key; + Type b = (Type)de2.Key; + + return GetDistance(a).CompareTo(GetDistance(b)); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetCustomEnumGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetCustomEnumGump.cs new file mode 100644 index 000000000..a45d8f1da --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetCustomEnumGump.cs @@ -0,0 +1,47 @@ +using Server.Commands; +using Server.Network; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlSetCustomEnumGump : XmlSetListOptionGump +{ + private readonly string[] m_Names; + public XmlSetCustomEnumGump(PropertyInfo prop, Mobile mobile, object o, Stack stack, int propspage, ArrayList list, string[] names) : base(prop, mobile, o, stack, propspage, list, names, null) + { + m_Names = names; + } + + public override void OnResponse(NetState sender, RelayInfo relayInfo) + { + int index = relayInfo.ButtonID - 1; + + if (index >= 0 && index < m_Names.Length) + { + try + { + MethodInfo info = m_Property.PropertyType.GetMethod("Parse", new[] { typeof(string) }); + + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, m_Names[index]); + + if (info != null) + { + m_Property.SetValue(m_Object, info.Invoke(null, new object[] { m_Names[index] }), null); + } + else if (m_Property.PropertyType == typeof(Enum) || m_Property.PropertyType.IsSubclassOf(typeof(Enum))) + { + m_Property.SetValue(m_Object, Enum.Parse(m_Property.PropertyType, m_Names[index], false), null); + } + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetGump.cs new file mode 100644 index 000000000..e3decf23f --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetGump.cs @@ -0,0 +1,250 @@ +using Server.Commands; +using Server.HuePickers; +using Server.Network; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlSetGump : Gump +{ + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly int m_Page; + private readonly ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + 2 * (EntryHeight + OffsetSize); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlSetGump(PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list) : base(GumpOffsetX, GumpOffsetY) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + bool canNull = !prop.PropertyType.IsValueType; + bool canDye = prop.IsDefined(typeof(HueAttribute), false); + + int xextend = 0; + if (prop.PropertyType == typeof(string)) + { + xextend = 300; + } + + object val = prop.GetValue(m_Object, null); + + var initialText = val == null ? "" : val.ToString(); + + AddPage(0); + + AddBackground(0, 0, BackWidth + xextend, BackHeight + (canNull ? EntryHeight + OffsetSize : 0) + (canDye ? EntryHeight + OffsetSize : 0), BackGumpID); + AddImageTiled(BorderSize, BorderSize, TotalWidth + xextend - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight + (canNull ? EntryHeight + OffsetSize : 0) + (canDye ? EntryHeight + OffsetSize : 0), OffsetGumpID); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled(x, y, EntryWidth + xextend, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth + xextend - TextOffsetX, EntryHeight, TextHue, prop.Name); + x += EntryWidth + xextend + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth + xextend, EntryHeight, EntryGumpID); + AddTextEntry(x + TextOffsetX, y, EntryWidth + xextend - TextOffsetX, EntryHeight, TextHue, 0, initialText); + x += EntryWidth + xextend + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); + + if (canNull) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth + xextend, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth + xextend - TextOffsetX, EntryHeight, TextHue, "Null"); + x += EntryWidth + xextend + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2); + } + + if (canDye) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth + xextend, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth + xextend - TextOffsetX, EntryHeight, TextHue, "Hue Picker"); + x += EntryWidth + xextend + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3); + } + } + + private class InternalPicker : HuePicker + { + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly int m_Page; + private readonly ArrayList m_List; + + public InternalPicker(PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list) : base(((IHued)o).HuedItemID) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + public override void OnResponse(int hue) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, hue.ToString()); + m_Property.SetValue(m_Object, hue, null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + object toSet; + bool shouldSet, shouldSend = true; + + switch (info.ButtonID) + { + case 1: + { + TextRelay text = info.GetTextEntry(0); + + if (text != null) + { + try + { + toSet = XmlPropertiesGump.GetObjectFromString(m_Property.PropertyType, text.Text); + shouldSet = true; + } + catch + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage("Bad format"); + } + } + else + { + toSet = null; + shouldSet = false; + } + + break; + } + case 2: // Null + { + toSet = null; + shouldSet = true; + + break; + } + case 3: // Hue Picker + { + toSet = null; + shouldSet = false; + shouldSend = false; + + m_Mobile.SendHuePicker(new InternalPicker(m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List)); + + break; + } + default: + { + toSet = null; + shouldSet = false; + + break; + } + } + + if (shouldSet) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, toSet == null ? "(null)" : toSet.ToString()); + m_Property.SetValue(m_Object, toSet, null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + if (shouldSend) + { + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetListOptionGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetListOptionGump.cs new file mode 100644 index 000000000..ab7e061a1 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetListOptionGump.cs @@ -0,0 +1,196 @@ +using Server.Commands; +using Server.Network; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlSetListOptionGump : Gump +{ + protected PropertyInfo m_Property; + protected Mobile m_Mobile; + protected object m_Object; + protected Stack m_Stack; + protected int m_Page; + protected ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + private static readonly int EntryCount = 13; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + + private static readonly bool PrevLabel = OldStyle, NextLabel = OldStyle; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private static readonly int PrevLabelOffsetY = 0; + + private static readonly int NextLabelOffsetX = -29; + private static readonly int NextLabelOffsetY = 0; + + protected object[] m_Values; + + public XmlSetListOptionGump(PropertyInfo prop, Mobile mobile, object o, Stack stack, int propspage, ArrayList list, string[] names, object[] values) : base(GumpOffsetX, GumpOffsetY) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = propspage; + m_List = list; + + m_Values = values; + + int pages = (names.Length + EntryCount - 1) / EntryCount; + int index = 0; + + for (int page = 1; page <= pages; ++page) + { + AddPage(page); + + int start = (page - 1) * EntryCount; + int count = names.Length - start; + + if (count > EntryCount) + { + count = EntryCount; + } + + int totalHeight = OffsetSize + (count + 2) * (EntryHeight + OffsetSize); + int backHeight = BorderSize + totalHeight + BorderSize; + + AddBackground(0, 0, BackWidth, backHeight, BackGumpID); + AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID); + + + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + int emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4 - (OldStyle ? SetWidth + OffsetSize : 0); + + AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); + + if (page > 1) + { + AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 0, GumpButtonType.Page, page - 1); + + if (PrevLabel) + { + AddLabel(x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous"); + } + } + + x += PrevWidth + OffsetSize; + + if (!OldStyle) + { + AddImageTiled(x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, HeaderGumpID); + } + + x += emptyWidth + OffsetSize; + + if (!OldStyle) + { + AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); + } + + if (page < pages) + { + AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 0, GumpButtonType.Page, page + 1); + + if (NextLabel) + { + AddLabel(x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next"); + } + } + + + + AddRect(0, prop.Name, 0); + + for (int i = 0; i < count; ++i) + { + AddRect(i + 1, names[index], ++index); + } + } + } + + private void AddRect(int index, string str, int button) + { + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize + (index + 1) * (EntryHeight + OffsetSize); + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, str); + + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + if (button != 0) + { + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, button); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + int index = info.ButtonID - 1; + + if (index >= 0 && index < m_Values.Length) + { + try + { + object toSet = m_Values[index]; + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, toSet == null ? "(-null-)" : toSet.ToString()); + m_Property.SetValue(m_Object, toSet, null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs new file mode 100644 index 000000000..d0230e414 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs @@ -0,0 +1,302 @@ +using Server.Commands; +using Server.Commands.Generic; +using Server.Network; +using Server.Prompts; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlSetObjectGump : Gump +{ + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly Type m_Type; + private readonly int m_Page; + private readonly ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + 5 * (EntryHeight + OffsetSize); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlSetObjectGump(PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list) : base(GumpOffsetX, GumpOffsetY) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + + string initialText = XmlPropertiesGump.ValueToString(o, prop); + + AddPage(0); + + AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); + AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, initialText); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Change by Serial"); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Nullify"); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "View Properties"); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 4); + } + + private class InternalPrompt : Prompt + { + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly Type m_Type; + private readonly int m_Page; + private readonly ArrayList m_List; + + public InternalPrompt(PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + } + + public override void OnCancel(Mobile from) + { + m_Mobile.SendGump(new XmlSetObjectGump(m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List)); + } + + public override void OnResponse(Mobile from, string text) + { + object toSet; + bool shouldSet; + + try + { + var serial = Utility.ToUInt32(text); + toSet = World.FindEntity((Serial)serial); + + if (toSet == null) + { + shouldSet = false; + m_Mobile.SendMessage("No object with that serial was found."); + } + else if (!m_Type.IsInstanceOfType(toSet)) + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage("The object with that serial could not be assigned to a property of type : {0}", m_Type.Name); + } + else + { + shouldSet = true; + } + } + catch + { + toSet = null; + shouldSet = false; + m_Mobile.SendMessage("Bad format"); + } + + if (shouldSet) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, toSet.ToString()); + m_Property.SetValue(m_Object, toSet, null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + m_Mobile.SendGump(new XmlSetObjectGump(m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List)); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + bool shouldSet, shouldSend = true; + object viewProps = null; + + switch (info.ButtonID) + { + case 0: // closed + { + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + shouldSet = false; + shouldSend = false; + + break; + } + case 1: // Change by Target + { + m_Mobile.Target = new XmlSetObjectTarget(m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List); + shouldSet = false; + shouldSend = false; + break; + } + case 2: // Change by Serial + { + shouldSet = false; + shouldSend = false; + m_Mobile.SendMessage("Enter the serial you wish to find:"); + m_Mobile.Prompt = new InternalPrompt(m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List); + + break; + } + case 3: // Nullify + { + shouldSet = true; + break; + } + case 4: // View Properties + { + shouldSet = false; + + object obj = m_Property.GetValue(m_Object, null); + + if (obj == null) + { + m_Mobile.SendMessage("The property is null and so you cannot view its properties."); + } + else if (!BaseCommand.IsAccessible(m_Mobile, obj)) + { + m_Mobile.SendMessage("You may not view their properties."); + } + else + { + viewProps = obj; + } + + break; + } + default: + { + shouldSet = false; + break; + } + } + + if (shouldSet) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, "(null)"); + m_Property.SetValue(m_Object, null, null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + if (shouldSend) + { + m_Mobile.SendGump(new XmlSetObjectGump(m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List)); + } + + if (viewProps != null) + { + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, viewProps)); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectTarget.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectTarget.cs new file mode 100644 index 000000000..9c6393b40 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectTarget.cs @@ -0,0 +1,72 @@ +using Server.Commands; +using Server.Items; +using Server.Targeting; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlSetObjectTarget : Target +{ + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly Type m_Type; + private readonly int m_Page; + private readonly ArrayList m_List; + + public XmlSetObjectTarget(PropertyInfo prop, Mobile mobile, object o, Stack stack, Type type, int page, ArrayList list) : base(-1, false, TargetFlags.None) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Type = type; + m_Page = page; + m_List = list; + } + + protected override void OnTarget(Mobile from, object targeted) + { + try + { + if (m_Type == typeof(Type)) + { + targeted = targeted.GetType(); + } + else if ((m_Type == typeof(BaseAddon) || m_Type.IsAssignableFrom(typeof(BaseAddon))) && targeted is AddonComponent component) + { + targeted = component.Addon; + } + + if (m_Type.IsInstanceOfType(targeted)) + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, targeted.ToString()); + m_Property.SetValue(m_Object, targeted, null); + } + else + { + m_Mobile.SendMessage("That cannot be assigned to a property of type : {0}", m_Type.Name); + } + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + protected override void OnTargetFinish(Mobile from) + { + if (m_Type == typeof(Type)) + { + from.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } + else + { + from.SendGump(new XmlSetObjectGump(m_Property, m_Mobile, m_Object, m_Stack, m_Type, m_Page, m_List)); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint2DGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint2DGump.cs new file mode 100644 index 000000000..eb5f634cb --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint2DGump.cs @@ -0,0 +1,235 @@ +using Server.Commands; +using Server.Network; +using Server.Targeting; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlSetPoint2DGump : Gump +{ + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly int m_Page; + private readonly ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int CoordWidth = 105; + private static readonly int EntryWidth = CoordWidth + OffsetSize + CoordWidth; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + 4 * (EntryHeight + OffsetSize); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlSetPoint2DGump(PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list) : base(GumpOffsetX, GumpOffsetY) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + Point2D p = (Point2D)prop.GetValue(o, null); + + AddPage(0); + + AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); + AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Use your location"); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Target a location"); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, CoordWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "X:"); + AddTextEntry(x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 0, p.X.ToString()); + x += CoordWidth + OffsetSize; + + AddImageTiled(x, y, CoordWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Y:"); + AddTextEntry(x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 1, p.Y.ToString()); + x += CoordWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3); + } + + private class InternalTarget : Target + { + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly int m_Page; + private readonly ArrayList m_List; + + public InternalTarget(PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list) : base(-1, true, TargetFlags.None) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + protected override void OnTarget(Mobile from, object targeted) + { + IPoint3D p = targeted as IPoint3D; + + if (p != null) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, new Point2D(p.X, p.Y).ToString()); + m_Property.SetValue(m_Object, new Point2D(p.X, p.Y), null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + } + + protected override void OnTargetFinish(Mobile from) + { + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Point2D toSet; + bool shouldSet, shouldSend; + + switch (info.ButtonID) + { + case 1: // Current location + { + toSet = new Point2D(m_Mobile.X, m_Mobile.Y); + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // Pick location + { + m_Mobile.Target = new InternalTarget(m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List); + + toSet = Point2D.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 3: // Use values + { + TextRelay x = info.GetTextEntry(0); + TextRelay y = info.GetTextEntry(1); + + toSet = new Point2D(x == null ? 0 : Utility.ToInt32(x.Text), y == null ? 0 : Utility.ToInt32(y.Text)); + shouldSet = true; + shouldSend = true; + + break; + } + default: + { + toSet = Point2D.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if (shouldSet) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, toSet.ToString()); + m_Property.SetValue(m_Object, toSet, null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + if (shouldSend) + { + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint3DGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint3DGump.cs new file mode 100644 index 000000000..b0fa3c0a3 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint3DGump.cs @@ -0,0 +1,241 @@ +using Server.Commands; +using Server.Network; +using Server.Targeting; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlSetPoint3DGump : Gump +{ + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly int m_Page; + private readonly ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int CoordWidth = 70; + private static readonly int EntryWidth = CoordWidth + OffsetSize + CoordWidth + OffsetSize + CoordWidth; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + 4 * (EntryHeight + OffsetSize); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlSetPoint3DGump(PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list) : base(GumpOffsetX, GumpOffsetY) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + Point3D p = (Point3D)prop.GetValue(o, null); + + AddPage(0); + + AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); + AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Use your location"); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 1); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, "Target a location"); + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 2); + + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + AddImageTiled(x, y, CoordWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "X:"); + AddTextEntry(x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 0, p.X.ToString()); + x += CoordWidth + OffsetSize; + + AddImageTiled(x, y, CoordWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Y:"); + AddTextEntry(x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 1, p.Y.ToString()); + x += CoordWidth + OffsetSize; + + AddImageTiled(x, y, CoordWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, CoordWidth - TextOffsetX, EntryHeight, TextHue, "Z:"); + AddTextEntry(x + 16, y, CoordWidth - 16, EntryHeight, TextHue, 2, p.Z.ToString()); + x += CoordWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, 3); + } + + private class InternalTarget : Target + { + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly int m_Page; + private readonly ArrayList m_List; + + public InternalTarget(PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list) : base(-1, true, TargetFlags.None) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + } + + protected override void OnTarget(Mobile from, object targeted) + { + IPoint3D p = targeted as IPoint3D; + + if (p != null) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, new Point3D(p).ToString()); + m_Property.SetValue(m_Object, new Point3D(p), null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + } + + protected override void OnTargetFinish(Mobile from) + { + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + Point3D toSet; + bool shouldSet, shouldSend; + + switch (info.ButtonID) + { + case 1: // Current location + { + toSet = m_Mobile.Location; + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // Pick location + { + m_Mobile.Target = new InternalTarget(m_Property, m_Mobile, m_Object, m_Stack, m_Page, m_List); + + toSet = Point3D.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 3: // Use values + { + TextRelay x = info.GetTextEntry(0); + TextRelay y = info.GetTextEntry(1); + TextRelay z = info.GetTextEntry(2); + + toSet = new Point3D(x == null ? 0 : Utility.ToInt32(x.Text), y == null ? 0 : Utility.ToInt32(y.Text), z == null ? 0 : Utility.ToInt32(z.Text)); + shouldSet = true; + shouldSend = true; + + break; + } + default: + { + toSet = Point3D.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if (shouldSet) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, toSet.ToString()); + m_Property.SetValue(m_Object, toSet, null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + if (shouldSend) + { + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetTimeSpanGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetTimeSpanGump.cs new file mode 100644 index 000000000..2e1c45a6e --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetTimeSpanGump.cs @@ -0,0 +1,240 @@ +using Server.Commands; +using Server.Network; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlSetTimeSpanGump : Gump +{ + private readonly PropertyInfo m_Property; + private readonly Mobile m_Mobile; + private readonly object m_Object; + private readonly Stack m_Stack; + private readonly int m_Page; + private readonly ArrayList m_List; + + public static readonly bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = PropsConfig.EntryHeight; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly int EntryWidth = 212; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + private static readonly int TotalHeight = OffsetSize + 7 * (EntryHeight + OffsetSize); + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize; + + public XmlSetTimeSpanGump(PropertyInfo prop, Mobile mobile, object o, Stack stack, int page, ArrayList list) : base(GumpOffsetX, GumpOffsetY) + { + m_Property = prop; + m_Mobile = mobile; + m_Object = o; + m_Stack = stack; + m_Page = page; + m_List = list; + + TimeSpan ts = (TimeSpan)prop.GetValue(o, null); + + AddPage(0); + + AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); + AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID); + + AddRect(0, prop.Name, 0, -1); + AddRect(1, ts.ToString(), 0, -1); + AddRect(2, "Zero", 1, -1); + AddRect(3, "From H:M:S", 2, -1); + AddRect(4, "H:", 3, 0); + AddRect(5, "M:", 4, 1); + AddRect(6, "S:", 5, 2); + } + + private void AddRect(int index, string str, int button, int text) + { + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize + index * (EntryHeight + OffsetSize); + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, str); + + if (text != -1) + { + AddTextEntry(x + 16 + TextOffsetX, y, EntryWidth - TextOffsetX - 16, EntryHeight, TextHue, text, ""); + } + + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + if (button != 0) + { + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, button); + } + } + + public override void OnResponse(NetState sender, RelayInfo info) + { + TimeSpan toSet; + bool shouldSet, shouldSend; + + TextRelay h = info.GetTextEntry(0); + TextRelay m = info.GetTextEntry(1); + TextRelay s = info.GetTextEntry(2); + + switch (info.ButtonID) + { + case 1: // Zero + { + toSet = TimeSpan.Zero; + shouldSet = true; + shouldSend = true; + + break; + } + case 2: // From H:M:S + { + if (h != null && m != null && s != null) + { + try + { + toSet = TimeSpan.Parse($"{h.Text}:{m.Text}:{s.Text}"); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 3: // From H + { + if (h != null) + { + try + { + toSet = TimeSpan.FromHours(Utility.ToDouble(h.Text)); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 4: // From M + { + if (m != null) + { + try + { + toSet = TimeSpan.FromMinutes(Utility.ToDouble(m.Text)); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + case 5: // From S + { + if (s != null) + { + try + { + toSet = TimeSpan.FromSeconds(Utility.ToDouble(s.Text)); + shouldSet = true; + shouldSend = true; + + break; + } + catch + { + } + } + + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = false; + + break; + } + default: + { + toSet = TimeSpan.Zero; + shouldSet = false; + shouldSend = true; + + break; + } + } + + if (shouldSet) + { + try + { + CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, toSet.ToString()); + m_Property.SetValue(m_Object, toSet, null); + } + catch + { + m_Mobile.SendMessage("An exception was caught. The property may not have changed."); + } + } + + if (shouldSend) + { + m_Mobile.SendGump(new XmlPropertiesGump(m_Mobile, m_Object, m_Stack, m_List, m_Page)); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs new file mode 100644 index 000000000..abb16a41c --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs @@ -0,0 +1,12776 @@ +using Server.Accounting; +using Server.Commands; +using Server.Commands.Generic; +using Server.ContextMenus; +using Server.Items; +using Server.Network; +using Server.Targeting; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Xml; +using Server.Engines.Spawners; + +namespace Server.Mobiles; + +public class XmlSpawner : Item, ISpawner +{ + public enum TODModeType { Realtime, Gametime } + + public enum SpawnPositionType { Random, RowFill, ColFill, Perimeter, Player, Waypoint, RelXY, DeltaLocation, Location, Wet, Tiles, NoTiles, ItemID, NoItemID } + + public class SpawnPositionInfo + { + public SpawnPositionType positionType; + public Mobile trigMob; + public string[] positionArgs; + + public SpawnPositionInfo(SpawnPositionType positiontype, Mobile trigmob, string[] positionargs) + { + positionType = positiontype; + trigMob = trigmob; + positionArgs = positionargs; + } + } + + public class MovementInfo + { + public Mobile trigMob; + public Point3D trigLocation = Point3D.Zero; + + public MovementInfo(Mobile m) + { + trigMob = m; + if (m != null) + { + trigLocation = m.Location; + } + } + } + + public const string Version = "5.0"; // RUADUCK's EDIT + public const byte MaxLoops = 10; //maximum number of recursive calls from spawner to itself. this is to prevent stack overflow from xmlspawner scripting + private const int ShowBoundsItemId = 14089; // 14089 Fire Column // 3555 Campfire // 8708 Skull Pole + private const string SpawnDataSetName = "Spawns"; + private const string SpawnTablePointName = "Points"; + private const int SpawnFitSize = 16; // Normal wall/door height for a mobile is 20 to walk through + private static int BaseItemId = 0x1F1C; // Purple Magic Crystal + private static int ShowItemId = 0x3E57; // ships mast + private static int defaultTriggerSound = 0x1F4; // click and sparkle sound by default (0x1F4) , click sound (0x3A4) + public static string XmlSpawnDir = "XmlSpawner"; // default directory for saving/loading .xml files with [xmlload [xmlsave + private const int MaxSmartSectorListSize = 1024; // maximum sector list size for use in smart spawning. This gives a 512x512 tile range. + + private static string defwaypointname; // default waypoint name will get assigned in Initialize + private const string XmlTableName = "Properties"; + private const string XmlDataSetName = "XmlSpawner"; + public static AccessLevel DiskAccessLevel = AccessLevel.Administrator; // minimum access level required by commands that can access the disk such as XmlLoad, XmlSave, and the Save function of XmlEdit +#if (RESTRICTConstructible) + public static AccessLevel ConstructibleAccessLevel = AccessLevel.GameMaster; // only allow spawning of objects that have Constructible access restrictions at this level or lower. Must define RESTRICTConstructible to enable this. +#endif + private static int MaxMoveCheck = 10; // limit number of players that can be checked for triggering in a single OnMovement tick + + // specifies the level at which smartspawning will be triggered. Players with AccessLevel above this will not trigger smartspawning unless unhidden. + public static AccessLevel SmartSpawnAccessLevel = AccessLevel.Player; + + // define the default values used in making spawners + private static TimeSpan defMinDelay = TimeSpan.FromMinutes(5); + private static TimeSpan defMaxDelay = TimeSpan.FromMinutes(10); + private static TimeSpan defMinRefractory = TimeSpan.FromMinutes(0); + private static TimeSpan defMaxRefractory = TimeSpan.FromMinutes(0); + private static TimeSpan defTODStart = TimeSpan.FromMinutes(0); + private static TimeSpan defTODEnd = TimeSpan.FromMinutes(0); + private static TimeSpan defDuration = TimeSpan.FromMinutes(0); + private static TimeSpan defDespawnTime = TimeSpan.FromHours(0); + private static bool defIsGroup; + private static int defTeam; + private static int defProximityTriggerSound = defaultTriggerSound; + private static int defAmount = 1; + private static bool defRelativeHome = true; + private static int defSpawnRange = 5; + private static int defHomeRange = 5; + private static double defTriggerProbability = 1; + private static int defProximityRange = -1; + private static readonly int defKillReset = 1; + private static TODModeType defTODMode = TODModeType.Realtime; + + private static Timer m_GlobalSectorTimer; + private static bool SmartSpawningSystemEnabled; + + private static WarnTimer2 m_WarnTimer; + + // hash table for optimizing HoldSmartSpawning method invocation + private static Dictionary holdSmartSpawningHash; + + public static int seccount; + + // sector hashtable for each map + private static readonly Dictionary>[] GlobalSectorTable = new Dictionary>[6]; + + private string m_Name = string.Empty; + private string m_UniqueId = string.Empty; + private bool m_PlayerCreated; + private bool m_HomeRangeIsRelative; + private int m_Team; + private int m_HomeRange; + // added a amount parameter for stacked item spawns + private int m_StackAmount; + // this is actually redundant with the width height spec for spawning area + // just an easier way of specifying it + private int m_SpawnRange; + private int m_Count; + private TimeSpan m_MinDelay; + private TimeSpan m_MaxDelay; + // added a duration parameter for time-limited spawns + private TimeSpan m_Duration; + public List m_SpawnObjects = new(); // List of objects to spawn + private DateTime m_End; + private DateTime m_RefractEnd; + private DateTime m_DurEnd; + private SpawnerTimer m_Timer; + private InternalTimer m_DurTimer; + private InternalTimer3 m_RefractoryTimer; + private bool m_Running; + private bool m_Group; + private int m_X; + private int m_Y; + private int m_Width; + private int m_Height; + private WayPoint m_WayPoint; + + private Static m_ShowContainerStatic; + private bool m_proximityActivated; + private bool m_refractActivated; + private bool m_durActivated; + private TimeSpan m_TODStart; + private TimeSpan m_TODEnd; + // time after proximity activation when the spawn cannot be reactivated + private TimeSpan m_MinRefractory; + private TimeSpan m_MaxRefractory; + private string m_ItemTriggerName; + private string m_NoItemTriggerName; + private Item m_ObjectPropertyItem; + private string m_ObjectPropertyName; + public string status_str; + public int m_killcount; + // added proximity range sensor + private int m_ProximityRange; + // sound played when a proximity triggered spawner is tripped by a player + // set this to zero if you dont want to hear anything + private int m_ProximityTriggerSound; + private string m_ProximityTriggerMessage; + private string m_SpeechTrigger; + private bool m_speechTriggerActivated; + private string m_MobPropertyName; + private string m_MobTriggerName; + private string m_PlayerPropertyName; + private double m_TriggerProbability = defTriggerProbability; + private Mobile m_mob_who_triggered; + private Item m_SetPropertyItem; + + private bool m_skipped; + private int m_KillReset = defKillReset; // number of spawn ticks that pass without kills before killcount gets reset to zero + private int m_spawncheck; + private TODModeType m_TODMode = TODModeType.Realtime; + private string m_GumpState; + private bool m_ExternalTriggering; + private bool m_ExternalTrigger; + private int m_SequentialSpawning = -1; // off by default + private DateTime m_SeqEnd; + private Region m_Region; // 2004.02.08 :: Omega Red + private string m_RegionName = string.Empty; // 2004.02.08 :: Omega Red + private AccessLevel m_TriggerAccessLevel = AccessLevel.Player; + + public List m_TextEntryBook; + private XmlSpawnerGump m_SpawnerGump; + + private bool m_AllowGhostTriggering; + private bool m_AllowNPCTriggering; + private string m_ConfigFile; + private bool m_OnHold; + private bool m_HoldSequence; + private bool m_SpawnOnTrigger; + + private List m_MovementList; + private MovementTimer m_MovementTimer; + internal List m_KeywordTagList = new(); + + public List RecentSpawnerSearchList = null; + public List RecentItemSearchList = null; + public List RecentMobileSearchList = null; + private TimeSpan m_DespawnTime; + + private string m_SkillTrigger; + private SkillName m_skill_that_triggered; + private bool m_FreeRun; // override for all other triggering modes + + private Map currentmap; + + public bool m_IsInactivated; + private bool m_SmartSpawning; + private SectorTimer m_SectorTimer; + + private List m_ShowBoundsItems = new(); + + public List PropertyInfoList = null; // used to optimize property info lookup used by set and get property methods. + + private Dictionary> spawnPositionWayTable; // used to optimize #waypoint lookup + + private bool inrespawn; + + private List sectorList; + + private bool m_DisableGlobalAutoReset; + + private Point3D mostRecentSpawnPosition = Point3D.Zero; + + // does not decay + public override bool Decays => false; + // is not counted in the normal item count + public override bool IsVirtualItem => true; + + private bool m_skillTriggerActivated; + private SkillName m_SkillTriggerName; + private double m_SkillTriggerMin; + private double m_SkillTriggerMax; + private int m_SkillTriggerSuccess; + + public bool DebugThis { get; set; } = false; + + public int MovingPlayerCount { get; set; } + + public int FastestPlayerSpeed { get; set; } + + public int NearbyPlayerCount + { + get + { + int count = 0; + if (ProximityRange >= 0) + { + IPooledEnumerable eable = GetMobilesInRange(ProximityRange); + foreach (Mobile m in eable) + { + if (m != null && m.Player) + { + count++; + } + } + + eable.Free(); + } + return count; + } + } + + public Point3D MostRecentSpawnPosition + { + get => mostRecentSpawnPosition; + set => mostRecentSpawnPosition = value; + } + + public TimeSpan GameTOD + { + get + { + int hours; + int minutes; + + Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); + return new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0).TimeOfDay; + } + } + + public TimeSpan RealTOD => DateTime.UtcNow.TimeOfDay; + + public int RealDay => DateTime.UtcNow.Day; + + public int RealMonth => DateTime.UtcNow.Month; + + public DayOfWeek RealDayOfWeek => DateTime.UtcNow.DayOfWeek; + + public MoonPhase MoonPhase => Clock.GetMoonPhase(Map, Location.X, Location.Y); + + public XmlSpawnerGump SpawnerGump + { + get => m_SpawnerGump; + set => m_SpawnerGump = value; + } + + public bool DisableGlobalAutoReset { get => m_DisableGlobalAutoReset; + set => m_DisableGlobalAutoReset = value; + } + + public bool DoDefrag + { + get => false; + set + { + if (value) + { + Defrag(true); + } + } + } + + private readonly bool sectorIsActive = false; + private bool UseSectorActivate; + + public bool SingleSector => UseSectorActivate; + + public bool InActivationRange(Sector s1, Sector s2) + { + // check to see if the sectors are within +- 2 of one another + if (s1 == null || s2 == null) + { + return false; + } + + return Math.Abs(s1.X - s2.X) < 3 && Math.Abs(s1.Y - s2.Y) < 3; + } + + public bool HasDamagedOrDistantSpawns + { + get + { + Sector ssec = Map.GetSector(Location); + // go through the spawn lists + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + + if (o is BaseCreature creature) + { + // if the mob is damaged or outside of smartspawning detection range then return true + if (creature.Hits < creature.HitsMax || creature.Mana < creature.ManaMax || creature.Stam < creature.StamMax || creature.Map != Map) + { + return true; + } + + // if the spawn moves into a sector that is not activatable from a sector on the sector list then dont smartspawn + if (creature.Map != null && creature.Map != Map.Internal) + { + Sector bsec = creature.Map.GetSector(creature.Location); + + if (UseSectorActivate) + { + // is it in activatable range of the sector the spawner is in + if (!InActivationRange(bsec, ssec)) + { + return true; + } + } + else + { + bool outofsec = true; + + if (sectorList != null) + { + foreach (Sector s in sectorList) + { + // is the creatures sector within activation range of any of the sectors in the list + if (InActivationRange(bsec, s)) + { + outofsec = false; + break; + } + } + } + + if (outofsec) + { + return true; + } + } + } + } + } + } + + return false; + } + } + + private static int totalSectorsMonitored; + + public bool HasActiveSectors + { + get + { + if (!SmartSpawning || Map == null || Map == Map.Internal) + { + return false; + } + + // is this a region spawner? + if (m_Region != null) + { + var players = m_Region.GetPlayers(); + + if (players == null || players.Count == 0) + { + return false; + } + + // confirm that players with the proper access level are present + foreach (Mobile m in players) + { + if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden)) + { + return true; + } + } + return false; + } + // is this a single sector spawner? + if (UseSectorActivate) + { + return sectorIsActive; + } + + // if there is no sector list made for this spawner then create one. + if (sectorList == null) + { + Point3D loc = Location; + sectorList = new List(); + + // is this container held? + if (Parent != null) + { + if (RootParent is Mobile mobile) + { + loc = ((Mobile)RootParent).Location; + } + else + if (RootParent is Item item) + { + loc = ((Item)RootParent).Location; + } + } + + // find the max detection range by examining both spawnrange + // note, sectors will activate when within +-2 sectors + int bufferzone = 2 * Map.SectorSize; + int x1 = m_X - bufferzone; + int width = m_Width + 2 * bufferzone; + int y1 = m_Y - bufferzone; + int height = m_Height + 2 * bufferzone; + + // go through all of the sectors within the SpawnRange of the spawner to see if any are active + for (int x = x1; x <= x1 + width; x += Map.SectorSize) + { + for (int y = y1; y <= y1 + height; y += Map.SectorSize) + { + Sector s = Map.GetSector(new Point3D(x, y, loc.Z)); + + if (s == null) + { + continue; + } + + // dont add any redundant sectors + bool duplicate = false; + foreach (Sector olds in sectorList) + { + if (olds == s) + { + duplicate = true; + break; + } + } + if (!duplicate) + { + sectorList.Add(s); + + if (GlobalSectorTable[Map.MapID] == null) + { + GlobalSectorTable[Map.MapID] = new Dictionary>(); + } + + // add this sector and the spawner associated with it to the global sector table + List spawnerlist; + if (GlobalSectorTable[Map.MapID].TryGetValue(s, out spawnerlist)) //.Contains(s)) + { + //List spawnerlist = GlobalSectorTable[Map.MapID][s]; + if (spawnerlist == null) + { + //GlobalSectorTable[Map.MapID].Remove(s); + spawnerlist = new List(); + //GlobalSectorTable[Map.MapID].Add(s, spawnerlist); + GlobalSectorTable[Map.MapID][s] = spawnerlist; + } + + if (!spawnerlist.Contains(this)) + { + spawnerlist.Add(this); + + } + } + else + { + spawnerlist = new List(); + spawnerlist.Add(this); + // add a new entry to the table + GlobalSectorTable[Map.MapID][s] = spawnerlist; + } + + totalSectorsMonitored++; + + // add some sanity checking here + if (sectorList.Count > MaxSmartSectorListSize) + { + SmartSpawning = false; + + // log it + try + { + Console.WriteLine("SmartSpawning disabled at {0} {1} : Range too large.", loc, Map); + + using (StreamWriter op = new StreamWriter("badspawn.log", true)) + { + op.WriteLine("{0} SmartSpawning disabled at {1} {2} : Range too large.", DateTime.UtcNow, loc, Map); + op.WriteLine(); + } + } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + + return true; + } + } + } + } + + UseSectorActivate = false; + } + + _TraceStart(2); + // go through the sectorlist and see if any of the sectors are active + + foreach (Sector s in sectorList) + { + if (s != null && s.Active && s.Clients != null && s.Clients.Count > 0) + { + // confirm that players with the proper access level are present + foreach (NetState ns in s.Clients) + { + var m = ns.Mobile; + if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden)) + { + return true; + } + } + _TraceEnd(2); + } + seccount++; + } + _TraceEnd(2); + return false; + } + } + + public int SecCount => seccount; + + public bool IsInactivated + { + get => m_IsInactivated; + set => m_IsInactivated = value; + } + + public int ActiveSectorCount + { + get + { + if (sectorList != null) + { + return sectorList.Count; + } + + return 0; + } + } + + public bool PlayerCreated + { + get => m_PlayerCreated; + set => m_PlayerCreated = value; + } + + public bool OnHold + { + get + { + if (m_OnHold) + { + return true; + } + + // determine whether there are any keywordtags with the hold flag + if (m_KeywordTagList == null || m_KeywordTagList.Count == 0) + { + return false; + } + + foreach (BaseXmlSpawner.KeywordTag sot in m_KeywordTagList) + { + // check for any keyword tag with the holdspawn flag + if (sot != null && !sot.Deleted && (sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSpawn) != 0) + { + return true; + } + } + // no hold flags were set + return false; + } + set => m_OnHold = value; + } + + public string AddSpawn + { + get => null; + set + { + if (!string.IsNullOrEmpty(value)) + { + string str = value.Trim(); + string typestr = BaseXmlSpawner.ParseObjectType(str); + + Type type = AssemblyHandler.FindTypeByName(typestr); + + if (type != null) + { + m_SpawnObjects.Add(new SpawnObject(str, 1)); + } + else + { + // check for special keywords + if (typestr != null && (BaseXmlSpawner.IsTypeOrItemKeyword(typestr) || typestr.IndexOf("{") != -1 || typestr.StartsWith("*") || typestr.StartsWith("#"))) + { + m_SpawnObjects.Add(new SpawnObject(str, 1)); + } + else + { + status_str = string.Format("{0} is not a valid type name.", str); + } + } + InvalidateProperties(); + } + } + } + + public string UniqueId => m_UniqueId; + + // does not perform a defrag, so less accurate but can be used while looping through world object enums + public int SafeCurrentCount => SafeTotalSpawnedObjects; + + public bool FreeRun + { + get => m_FreeRun; + set => m_FreeRun = value; + } + + public bool CanFreeSpawn + { + get + { + // allow free spawning if proximity sensing is off and if all of the potential free-spawning triggers are disabled + if (Running && m_ProximityRange == -1 && + string.IsNullOrEmpty(m_ObjectPropertyName) && + (string.IsNullOrEmpty(m_MobPropertyName) || + m_MobTriggerName == null || m_MobTriggerName.Length == 0) && + !m_ExternalTriggering) + { + return true; + } + + return false; + } + } + + public SpawnObject[] SpawnObjects + { + get => m_SpawnObjects.ToArray(); + set + { + if (value != null && value.Length > 0) + { + + foreach (SpawnObject so in value) + { + if (so == null) + { + continue; + } + + bool AlreadyInList = false; + + // Check if the new array has an existing spawn object + foreach (SpawnObject TheSpawn in m_SpawnObjects) + { + if (TheSpawn.TypeName.ToUpper() == so.TypeName.ToUpper()) + { + AlreadyInList = true; + break; + } + } + + // Does this item need to be added + if (!AlreadyInList) + { + // This is a new spawn object so add it to the array (deep copy) + m_SpawnObjects.Add(new SpawnObject(so.TypeName, so.ActualMaxCount, so.SubGroup, so.SequentialResetTime, so.SequentialResetTo, so.KillsNeeded, + so.RestrictKillsToSubgroup, so.ClearOnAdvance, so.MinDelay, so.MaxDelay, so.SpawnsPerTick, so.PackRange)); + } + } + + if (SpawnObjects.Length < 1) + { + Stop(); + } + + InvalidateProperties(); + } + } + } + + public bool HoldSequence + { + get + { + // check to see if any keyword tags have the holdsequence flag set, or whether the spawner holdsequence flag is set + if (m_HoldSequence) + { + return true; + } + + // determine whether there are any keywordtags with the hold flag + if (m_KeywordTagList == null || m_KeywordTagList.Count == 0) + { + return false; + } + + foreach (BaseXmlSpawner.KeywordTag sot in m_KeywordTagList) + { + // check for any keyword tag with the holdsequence flag + if (sot != null && !sot.Deleted && (sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSequence) != 0) + { + return true; + } + } + + // no hold flags were set + return false; + } + + set => m_HoldSequence = value; + } + + public bool CanSpawn + { + get + { + if (OnHold) + { + return false; + } + + if (m_Group) + { + if (TotalSpawnedObjects <= 0) + { + return true; + } + + return false; + } + + if (IsFull) + { + return false; + } + + return true; + } + } + + // test for a full spawner + public bool IsFull + { + get + { + int nobj = TotalSpawnedObjects; + + return nobj >= m_Count || nobj >= TotalSpawnObjectCount; + } + } + + // this can be used in loops over world objects since it will not defrag and potentially modify the world object lists + public int SafeTotalSpawnedObjects + { + get + { + if (m_SpawnObjects == null) + { + return 0; + } + + int count = 0; + + foreach (SpawnObject so in m_SpawnObjects) + { + count += so.SpawnedObjects.Count; + } + + return count; + } + } + + public int TotalSpawnedObjects + { + get + { + if (m_SpawnObjects == null) + { + return 0; + } + + // defrag so that accurately reflects currently active spawns + Defrag(true); + + int count = 0; + + foreach (SpawnObject so in m_SpawnObjects) + { + count += so.SpawnedObjects.Count; + } + + return count; + } + } + + public bool isEmpty() + { + if (m_SpawnObjects == null) + { + return true; + } + + foreach (SpawnObject so in m_SpawnObjects) + { + if (so.SpawnedObjects != null && so.SpawnedObjects.Count > 0) + { + if (so.SpawnedObjects[0] is Mobile) + { + return false; + } + } + + } + return true; + } + + public int TotalSpawnObjectCount + { + get + { + int count = 0; + + foreach (SpawnObject so in m_SpawnObjects) + { + count += so.MaxCount; + } + + return count; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool GumpReset + { + + set + { + if (value) + { + m_SpawnerGump = null; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Region SpawnRegion + { + get => m_Region; + set + { + // force a re-update of the smart spawning sector list the next time it is accessed + ResetSectorList(); + + m_Region = value; + + m_RegionName = m_Region?.Name; + } + } + + // 2004.02.08 :: Omega Red + [CommandProperty(AccessLevel.GameMaster)] + public string RegionName + { + get => m_RegionName; + set + { + // force a re-update of the smart spawning sector list the next time it is accessed + ResetSectorList(); + + m_RegionName = value; + + if (string.IsNullOrEmpty(value)) + { + m_Region = null; + return; + } + + if (Region.Regions.Count == 0) // after world load, before region load + { + return; + } + + foreach (Region region in Region.Regions) + { + if (string.Compare(region.Name, m_RegionName, true) == 0) + { + m_Region = region; + m_RegionName = region.Name; + //InvalidateProperties(); + return; + } + } + status_str = $"invalid region: {value}"; + m_Region = null; + } + } + + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D X1_Y1 + { + get => new(m_X, m_Y, Z); + set + { + // X1 and Y1 will initiate region specification + m_Width = 0; + m_Height = 0; + m_X = value.X; + m_Y = value.Y; + + // reset the sector list + ResetSectorList(); + + m_SpawnRange = 0; + + if (ShowBounds) + { + ShowBounds = false; + ShowBounds = true; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Point3D X2_Y2 + { + get => new(m_X + m_Width, m_Y + m_Height, Z); + set + { + int X2; + int Y2; + + int OriginalX2 = m_X + m_Width; + int OriginalY2 = m_Y + m_Height; + + // reset the sector list + ResetSectorList(); + + // now determine based upon the entered coordinate values what the lower left corner is + // lower left will be the min x and min y + // upper right will be max x max y + if (value.X < OriginalX2) + { + // ok, this is the proper x value for the lower left + m_X = value.X; + X2 = OriginalX2; + } + else + { + m_X = OriginalX2; + X2 = value.X; + } + + if (value.Y < OriginalY2) + { + // ok, this is the proper y value for the lower left + m_Y = value.Y; + Y2 = OriginalY2; + } + else + { + m_Y = OriginalY2; + Y2 = value.Y; + } + + m_Width = X2 - m_X; + m_Height = Y2 - m_Y; + + if (m_Width == m_Height) + { + m_SpawnRange = m_Width / 2; + } + else + { + m_SpawnRange = -1; + } + + if (m_HomeRangeIsRelative == false) + { + int NewHomeRange = m_Width > m_Height ? m_Height : m_Width; + m_HomeRange = NewHomeRange > 0 ? NewHomeRange : 0; + } + + //original test was for less than 1, changed it to less than zero (zero is a valid width, its the default in fact) + // Stop the spawner if the width or height is less than 1 + if (m_Width < 0 || m_Height < 0) + { + Running = false; + } + + InvalidateProperties(); + + if (ShowBounds) + { + ShowBounds = false; + ShowBounds = true; + } + } + } + + // added the spawnrange property. It sets both the XY and width/height parameters automatically. + // also doesnt mess with homerange like XY does + [CommandProperty(AccessLevel.GameMaster)] + public int SpawnRange + { + get => m_SpawnRange; + set + { + if (value < 0) + { + return; + } + + // reset the sector list + ResetSectorList(); + + m_SpawnRange = value; + m_Width = m_SpawnRange * 2; + m_Height = m_SpawnRange * 2; + + // dont set the bounding box locations if the initial location is 0,0 since this occurs when the item is just being made + // because m_X and m_Y are restored on loading, it creates problems with OnLocationChange which has to avoid applying translational + // adjustments to newly placed spawners (because the actual m_X and m_Y is associated with the original location, not the 0,0 location) + // basically, before placement, dont set m_X or m_Y to anything that needs to be adjusted later on + + if (Location.X == 0 && Location.Y == 0) + { + return; + } + + m_X = Location.X - m_SpawnRange; + m_Y = Location.Y - m_SpawnRange; + + if (ShowBounds) + { + ShowBounds = false; + ShowBounds = true; + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ShowBounds + { + get => m_ShowBoundsItems != null && m_ShowBoundsItems.Count > 0; + set + { + if (value && ShowBounds == false) + { + if (m_ShowBoundsItems == null) + { + m_ShowBoundsItems = new List(); + } + + // Boundary lines + int ValidX1 = m_X; + int ValidX2 = m_X + m_Width; + int ValidY1 = m_Y; + int ValidY2 = m_Y + m_Height; + + for (int x = 0; x <= m_Width; x++) + { + int NewX = m_X + x; + for (int y = 0; y <= m_Height; y++) + { + int NewY = m_Y + y; + + if (NewX == ValidX1 || NewX == ValidX2 || NewX == ValidY1 || NewX == ValidY2 || NewY == ValidX1 || NewY == ValidX2 || NewY == ValidY1 || NewY == ValidY2) + { + // Add an object to show the spawn area + Static s = new Static(ShowBoundsItemId) + { + Visible = false + }; + s.MoveToWorld(new Point3D(NewX, NewY, Z), Map); + m_ShowBoundsItems.Add(s); + } + } + } + } + + if (value == false && m_ShowBoundsItems != null) + { + // Remove all of the items from the array + foreach (Static s in m_ShowBoundsItems) + { + s.Delete(); + } + + m_ShowBoundsItems.Clear(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxCount + { + get => m_Count; + set + { + m_Count = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int CurrentCount => TotalSpawnedObjects; + + [CommandProperty(AccessLevel.GameMaster)] + public WayPoint WayPoint + { + get => m_WayPoint; + set => m_WayPoint = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ExternalTriggering + { + get => m_ExternalTriggering; + set => m_ExternalTriggering = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool ExtTrigState + { + get => m_ExternalTrigger; + set => m_ExternalTrigger = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Running + { + get => m_Running; + set + { + // Don't start the spawner unless the height and width are valid + if (value && m_Width >= 0 && m_Height >= 0) + { + Start(); + } + else + { + Stop(); + } + + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int HomeRange + { + get => m_HomeRange; + set { m_HomeRange = value; InvalidateProperties(); } + } + + public Region Region { get; } + + [CommandProperty(AccessLevel.GameMaster)] + public bool HomeRangeIsRelative + { + get => m_HomeRangeIsRelative; + set => m_HomeRangeIsRelative = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int Team + { + get => m_Team; + set { m_Team = value; InvalidateProperties(); } + } + [CommandProperty(AccessLevel.GameMaster)] + public int StackAmount + { + get => m_StackAmount; + set => m_StackAmount = value; + } + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan MinDelay + { + get => m_MinDelay; + set + { + m_MinDelay = value; + // reset the spawn timer + DoTimer(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan MaxDelay + { + get => m_MaxDelay; + set + { + m_MaxDelay = value; + // reset the spawn timer + DoTimer(); + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int KillCount + { + get => m_killcount; + set => m_killcount = value; + } + [CommandProperty(AccessLevel.GameMaster)] + public int KillReset + { + get => m_KillReset; + set => m_KillReset = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public double TriggerProbability + { + get => m_TriggerProbability; + set => m_TriggerProbability = value; + } + + //added refractory period support + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan RefractMin + { + get => m_MinRefractory; + set => m_MinRefractory = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan RefractMax + { + get => m_MaxRefractory; + set => m_MaxRefractory = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan RefractoryOver + { + get + { + if (m_refractActivated) + { + return m_RefractEnd - DateTime.UtcNow; + } + + return TimeSpan.FromSeconds(0); + } + set => DoTimer3(value); + } + + [CommandProperty(AccessLevel.GameMaster)] + public string SetItemName + { + get + { + if (m_SetPropertyItem == null || m_SetPropertyItem.Deleted) + { + return null; + } + + return m_SetPropertyItem.Name; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item SetItem + { + get => m_SetPropertyItem; + set => m_SetPropertyItem = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public string MobTriggerProp + { + get => m_MobPropertyName; + set => m_MobPropertyName = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public string MobTriggerName + { + get => m_MobTriggerName; + set => m_MobTriggerName = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile MobTriggerId + { + get + { + if (m_MobTriggerName == null) + { + return null; + } + + // try to parse out the type information if it has also been saved + string[] typeargs = m_MobTriggerName.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = m_MobTriggerName; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + return BaseXmlSpawner.FindMobileByName(this, namestr, typestr); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string PlayerTriggerProp + { + get => m_PlayerPropertyName; + set => m_PlayerPropertyName = value; + } + + // time of day activation + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan TODStart + { + get => m_TODStart; + set => m_TODStart = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan TODEnd + { + get => m_TODEnd; + set => m_TODEnd = value; + } + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan TOD + { + get + { + if (m_TODMode == TODModeType.Gametime) + { + int hours; + int minutes; + Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); + return new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0).TimeOfDay; + } + + return DateTime.UtcNow.TimeOfDay; + } + + } + + [CommandProperty(AccessLevel.GameMaster)] + public TODModeType TODMode + { + get => m_TODMode; + set => m_TODMode = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool TODInRange + { + get + { + if (m_TODStart == m_TODEnd) + { + return true; + } + + DateTime now; + + if (m_TODMode == TODModeType.Gametime) + { + int hours; + int minutes; + Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); + now = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0); + } + else + { + // calculate the time window + now = DateTime.UtcNow; + } + var day_start = new DateTime(now.Year, now.Month, now.Day); + // calculate the starting TOD window by adding the TODStart to day_start + var TOD_start = day_start + m_TODStart; + var TOD_end = day_start + m_TODEnd; + + // handle the case when TODstart is before midnight and end is after + + if (TOD_start > TOD_end) + { + if (now > TOD_start || now < TOD_end) + { + return true; + } + + return false; + } + + if (now > TOD_start && now < TOD_end) + { + return true; + } + + return false; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan DespawnTime + { + get => m_DespawnTime; + set => m_DespawnTime = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan Duration + { + get => m_Duration; + set + { + m_Duration = value; + InvalidateProperties(); + } + } + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan DurationOver + { + get + { + if (m_durActivated) + { + return m_DurEnd - DateTime.UtcNow; + } + + return TimeSpan.FromSeconds(0); + } + set => DoTimer2(value); + } + // proximity range parameter + [CommandProperty(AccessLevel.GameMaster)] + public int ProximityRange + { + get => m_ProximityRange; + set + { + m_ProximityRange = value; + InvalidateProperties(); + } + } + + + // proximity range activated? + [CommandProperty(AccessLevel.GameMaster)] + public bool ProximityActivated + { + get => m_proximityActivated; + set + { + + if (AllowTriggering) + { + ActivateTrigger(); + } + + m_proximityActivated = value; + + } + } + + // proximity trigger sound parameter + [CommandProperty(AccessLevel.GameMaster)] + public int ProximitySound + { + get => m_ProximityTriggerSound; + set => m_ProximityTriggerSound = value; + } + + // proximity trigger message parameter + [CommandProperty(AccessLevel.GameMaster)] + public string ProximityMsg + { + get => m_ProximityTriggerMessage; + set => m_ProximityTriggerMessage = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public string SpeechTrigger + { + get => m_SpeechTrigger; + set => m_SpeechTrigger = value; + } + + public string SkillTrigger + { + get => m_SkillTrigger; + set => m_SkillTrigger = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NextSpawn + { + get + { + if (m_Running) + { + return m_End - DateTime.UtcNow; + } + + return TimeSpan.FromSeconds(0); + } + set + { + Start(); + DoTimer(value); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool SpawnOnTrigger + { + get => m_SpawnOnTrigger; + set => m_SpawnOnTrigger = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool Group + { + get => m_Group; + set { m_Group = value; InvalidateProperties(); } + } + + [CommandProperty(AccessLevel.GameMaster)] + public string GumpState + { + get => m_GumpState; + set => m_GumpState = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public int SequentialSpawn + { + get => m_SequentialSpawning; + set => m_SequentialSpawning = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public TimeSpan NextSeqReset + { + get + { + if (m_Running && m_SeqEnd - DateTime.UtcNow > TimeSpan.Zero) + { + return m_SeqEnd - DateTime.UtcNow; + } + + return TimeSpan.FromSeconds(0); + } + set => m_SeqEnd = DateTime.UtcNow + value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public AccessLevel TriggerAccessLevel + { + get => m_TriggerAccessLevel; + set => m_TriggerAccessLevel = value; + } + + + [CommandProperty(AccessLevel.GameMaster)] + public bool DoRespawn + { + get => false; + set + { + // need to determine whether this is being set by the spawner during processing of a respawn entry + // if so then dont do it, otherwise you will infinitely recurse and crash with a stack overflow + if (value && !inrespawn) + { + TryRespawn(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool DoReset + { + get => false; + set { if (value) + { + Reset(); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowGhostTrig + { + get => m_AllowGhostTriggering; + set => m_AllowGhostTriggering = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool AllowNPCTrig + { + get => m_AllowNPCTriggering; + set => m_AllowNPCTriggering = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public string ConfigFile + { + get => m_ConfigFile; + set => m_ConfigFile = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool LoadConfig + { + get => false; + set { if (value) + { + LoadXmlConfig(ConfigFile); + } + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Mobile TriggerMob + { + get => m_mob_who_triggered; + set => m_mob_who_triggered = value; + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool SmartSpawning + { + get => m_SmartSpawning; + set + { + m_SmartSpawning = value; + + if (m_SmartSpawning) + { + // if any spawner is smartspawning, then the smartspawning system is enabled + SmartSpawningSystemEnabled = true; + // check to see if the global sector timer is running + if (m_GlobalSectorTimer == null || !m_GlobalSectorTimer.Running) + { + // start the global smartspawning timer + DoGlobalSectorTimer(TimeSpan.FromSeconds(1)); + } + } + + //IsInactivated = false; + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public bool IsEmpty => isEmpty(); + + public Guid Guid { get; } + public bool UnlinkOnTaming => true; + + [CommandProperty(AccessLevel.Developer)] + public bool ReturnOnDeactivate { get; set; } + + public Point3D HomeLocation => Location; + public int Range => HomeRange; + + public virtual void GetSpawnProperties(ISpawnable spawn, IPropertyList list) + { } + + public virtual void GetSpawnContextEntries(ISpawnable spawn, Mobile user, List list) + { } + + public void Remove(ISpawnable spawn) + { + if (m_SpawnObjects == null) + { + return; + } + + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + if (so.SpawnedObjects[i] == spawn) + { + so.SpawnedObjects.Remove(spawn); + if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup) + { + if (so.SubGroup == SequentialSpawn) + { + m_killcount++; + } + } + else + { + m_killcount++; + } + + return; + } + } + } + } + + public void RestoreISpawner() + { + // restore the Spawner assignments to all spawned objects + if (m_SpawnObjects == null) + { + return; + } + + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + if (o is Item item) + { + item.Spawner = this; + } + else if (o is Mobile mobile) + { + mobile.Spawner = this; + } + } + } + } + + public override void OnAfterDuped(Item newItem) + { + ((XmlSpawner)newItem).Running = false; // automatically turn off duped spawners + + base.OnAfterDuped(newItem); + } + + public override void OnMapChange() + { + base.OnMapChange(); + + currentmap = Map; + + ResetSectorList(); // reset the sector list for smart spawning + } + + public override void OnDoubleClick(Mobile from) + { + if (from == null || from.Deleted || from.AccessLevel < AccessLevel.GameMaster || m_SpawnerGump != null && SomeOneHasGumpOpen) + { + return; + } + + DeleteTextEntryBook(); // clear any text entry books that might still be around + + int x = 0; + int y = 0; + + Account acct = from.Account as Account; // read the text entries for default values + + if (acct != null) + { + XmlSpawnerDefaults.DefaultEntry defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); + if (defs != null) + { + x = defs.SpawnerGumpX; + y = defs.SpawnerGumpY; + } + } + + XmlSpawnerGump g = new XmlSpawnerGump(this, x, y, 0, 0, 0); + from.SendGump(g); + } + + public override void GetProperties(IPropertyList list) + { + base.GetProperties(list); + + list.Add(m_Running ? 1060742 : 1060743); // Active - Inactive + + // add whitespace to the beginning to avoid any problem with names that begin with # and are interpreted as cliloc ids + list.Add(1042971, $" {Name}"); // ~1_val~ + list.Add(1060656, m_Count.ToString()); // amount to make: ~1_val~ + list.Add(1061169, m_HomeRange.ToString()); // range ~1_val~ + + int nlist_items = 6; + + if (m_Group) + { + list.Add(1060658 + 6 - nlist_items, $"{"group"}\t{m_Group}"); // ~1_val~: ~2_val~ + nlist_items--; + } + + if (m_Team != 0) + { + list.Add(1060658 + 6 - nlist_items, $"{"team"}\t{m_Team}"); // ~1_val~: ~2_val~ + nlist_items--; + } + + list.Add(1060658 + 6 - nlist_items, $"{"speed"}\t{m_MinDelay} to {m_MaxDelay}"); // ~1_val~: ~2_val~ + nlist_items--; + + // display the duration parameter in the prop gump if it is non-zero + if (m_Duration > TimeSpan.FromMinutes(0)) + { + list.Add(1060658 + 6 - nlist_items, $"{"Duration"}\t{m_Duration}"); + nlist_items--; + } + + // display the proximity range parameter in the prop gump if it is active + if (m_ProximityRange != -1) + { + list.Add(1060658 + 6 - nlist_items, $"{"ProximityRange"}\t{m_ProximityRange}"); + nlist_items--; + } + + if (m_SpawnObjects != null) + { + for (int i = 0; i < nlist_items && i < m_SpawnObjects.Count; ++i) + { + string typename = m_SpawnObjects[i].TypeName; + if (typename != null && typename.Length > 20) + { + typename = typename[..20]; + } + + typename = $" {typename}"; + + list.Add(1060658 + (6 - nlist_items) + i, $"{typename}\t{m_SpawnObjects[i].SpawnedObjects.Count}"); + } + } + } + + public override void OnDelete() + { + base.OnDelete(); + + if (ShowBounds) + { + ShowBounds = false; + } + + RemoveSpawnObjects(); + + // remove any text entry books that might still be attached to the spawner + DeleteTextEntryBook(); + + if (m_Timer != null) + { + m_Timer.Stop(); + } + + if (m_DurTimer != null) + { + m_DurTimer.Stop(); + } + + if (m_RefractoryTimer != null) + { + m_RefractoryTimer.Stop(); + } + + // if statics were added for marking container held spawners, delete them + if (m_ShowContainerStatic != null && !m_ShowContainerStatic.Deleted) + { + m_ShowContainerStatic.Delete(); + } + } + + static bool IgnoreLocationChange; + public override void OnLocationChange(Point3D oldLocation) + { + if (IgnoreLocationChange) + { + IgnoreLocationChange = false; + return; + } + + + // calculate the positional shift + if (oldLocation.X > 0 && oldLocation.Y > 0) + { + int diffx = X - oldLocation.X; + int diffy = Y - oldLocation.Y; + m_X += diffx; + m_Y += diffy; + } + else + { + // Keep the original dimensions the same (Width, Height), + // just recalculate the new top left corner + m_X = X - m_Width / 2; + m_Y = Y - m_Height / 2; + } + + // reset the sector list for smart spawning + ResetSectorList(); + + // Check if the spawner is showing its bounds + if (ShowBounds) + { + ShowBounds = false; + ShowBounds = true; + } + } + + public bool SomeOneHasGumpOpen + { + get + { + // go through all online mobiles and see if any have xmlspawner gumps open + var states = TcpServer.Instances; + + foreach (var ns in states) + { + var m = ns.Mobile; + if (m != null && m.HasGump()) + { + return true; + } + } + + return false; + } + } + + + public static void SpawnerGumpCallback(Mobile from, object invoker, string response) + { + // assign the response to the gumpstate + if (invoker is XmlSpawner xs) + { + xs.GumpState = response; + } + } + + public void DeleteTextEntryBook() + { + if (m_TextEntryBook != null) + { + foreach (XmlTextEntryBook s in m_TextEntryBook) + { + s.Delete(); + } + + m_TextEntryBook = null; + } + } + + private static bool IsConstructible(ConstructorInfo ctor) => ctor.IsDefined(typeof(ConstructibleAttribute), false); + + public static int ConvertToInt(string value) + { + if (value.StartsWith("0x")) + { + return Convert.ToInt32(value.Substring(2), 16); + } + + return Convert.ToInt32(value); + } + + public static void ExecuteAction(object attachedto, Mobile trigmob, string action) + { + Point3D loc = Point3D.Zero; + Map map = null; + if (attachedto is IEntity entity) + { + loc = entity.Location; + map = entity.Map; + } + + if (action == null || action.Length <= 0 || attachedto == null || map == null) + { + return; + } + + SpawnObject TheSpawn = new SpawnObject(null, 0) + { + TypeName = action + }; + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, attachedto, action); + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + + string status_str; + if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) + { + BaseXmlSpawner.SpawnTypeKeyword(attachedto, TheSpawn, typeName, substitutedtypeName, trigmob, map, out status_str); + } + else + { + // its a regular type descriptor so find out what it is + Type type = AssemblyHandler.FindTypeByName(typeName); + try + { + string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + object o = CreateObject(type, arglist[0]); + + if (o == null) + { + status_str = $"invalid type specification: {arglist[0]}"; + } + else + if (o is Mobile mobile) + { + if (mobile is BaseCreature creature) + { + creature.Home = loc; // Spawners location is the home point + } + + mobile.Location = loc; + mobile.Map = map; + + BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, mobile, trigmob, attachedto, out status_str); + } + else + if (o is Item item) + { + BaseXmlSpawner.AddSpawnItem(null, attachedto, TheSpawn, item, loc, map, trigmob, false, substitutedtypeName, out status_str); + } + } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + } + } + + private static void RemoveFromSectorTable(Sector s, XmlSpawner spawner) + { + if (s == null || s.Owner == null || s.Owner == Map.Internal || GlobalSectorTable[s.Owner.MapID] == null) + { + return; + } + + // find the sector + List spawnerlist; + if (GlobalSectorTable[s.Owner.MapID].TryGetValue(s, out spawnerlist) && spawnerlist != null) + { + //List spawnerlist = GlobalSectorTable[s.Owner.MapID][s]; + if (spawnerlist.Contains(spawner)) + { + spawnerlist.Remove(spawner); + } + } + } + + private void ResetSectorList() + { + // remove the global sector entries + if (sectorList != null) + { + foreach (Sector s in sectorList) + { + RemoveFromSectorTable(s, this); + + } + } + sectorList = null; + UseSectorActivate = false; + + // force an update of the sector list + bool sectorrefresh = HasActiveSectors; + } + + public void LoadXmlConfig(string filename) + { + if (filename == null || filename.Length <= 0) + { + return; + } + + // Check if the file exists + if (File.Exists(filename)) + { + FileStream fs = null; + try + { + fs = File.Open(filename, FileMode.Open, FileAccess.Read); + } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + + if (fs == null) + { + status_str = string.Format("Unable to open {0} for loading", filename); + return; + } + + // Create the data set + DataSet ds = new DataSet(XmlDataSetName); + + // Read in the file + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch { fileerror = true; } + // close the file + fs.Close(); + if (fileerror) + { + Console.WriteLine("XmlSpawner: Error in XML config file '{0}'", filename); + return; + } + + // Check that at least a single table was loaded + if (ds.Tables.Count > 0) + { + if (ds.Tables[XmlTableName] != null && ds.Tables[XmlTableName].Rows.Count > 0) + { + foreach (DataRow dr in ds.Tables[XmlTableName].Rows) + { + string strEntry = null; + bool boolEntry = true; + double doubleEntry = 0; + int intEntry = 0; + + var valid_entry = true; + try { strEntry = (string)dr["Name"]; } + catch { valid_entry = false; } + if (valid_entry) { Name = strEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["X"]); } + catch { valid_entry = false; } + if (valid_entry) { m_X = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Y"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Y = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Width"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Width = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Height"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Height = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["CentreX"]); } + catch { valid_entry = false; } + if (valid_entry) { X = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["CentreY"]); } + catch { valid_entry = false; } + if (valid_entry) { Y = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["CentreZ"]); } + catch { valid_entry = false; } + if (valid_entry) { Z = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["SequentialSpawning"]); } + catch { valid_entry = false; } + if (valid_entry) { m_SequentialSpawning = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["ProximityRange"]); } + catch { valid_entry = false; } + if (valid_entry) { m_ProximityRange = intEntry; } + + valid_entry = true; + try { strEntry = (string)dr["ProximityTriggerMessage"]; } + catch { valid_entry = false; } + if (valid_entry) { m_ProximityTriggerMessage = strEntry; } + + valid_entry = true; + try { strEntry = (string)dr["SpeechTrigger"]; } + catch { valid_entry = false; } + if (valid_entry) { m_SpeechTrigger = strEntry; } + + valid_entry = true; + try { strEntry = (string)dr["SkillTrigger"]; } + catch { valid_entry = false; } + if (valid_entry) { m_SkillTrigger = strEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["ProximityTriggerSound"]); } + catch { valid_entry = false; } + if (valid_entry) { m_ProximityTriggerSound = intEntry; } + + valid_entry = true; + try { strEntry = (string)dr["ItemTriggerName"]; } + catch { valid_entry = false; } + if (valid_entry) { m_ItemTriggerName = strEntry; } + + valid_entry = true; + try { strEntry = (string)dr["NoItemTriggerName"]; } + catch { valid_entry = false; } + if (valid_entry) { m_NoItemTriggerName = strEntry; } + + // check for the delayinsec entry + bool delayinsec = false; + try { delayinsec = bool.Parse((string)dr["DelayInSec"]); } + catch { } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["MinDelay"]); } + catch { valid_entry = false; } + if (valid_entry) + { + m_MinDelay = delayinsec ? TimeSpan.FromSeconds(doubleEntry) : TimeSpan.FromMinutes(doubleEntry); + } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["MaxDelay"]); } + catch { valid_entry = false; } + if (valid_entry) + { + m_MaxDelay = delayinsec ? TimeSpan.FromSeconds(doubleEntry) : TimeSpan.FromMinutes(doubleEntry); + } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["Duration"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Duration = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["DespawnTime"]); } + catch { valid_entry = false; } + if (valid_entry) { m_DespawnTime = TimeSpan.FromHours(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["MinRefractory"]); } + catch { valid_entry = false; } + if (valid_entry) { m_MinRefractory = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["MaxRefractory"]); } + catch { valid_entry = false; } + if (valid_entry) { m_MaxRefractory = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["TODStart"]); } + catch { valid_entry = false; } + if (valid_entry) { m_TODStart = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["TODEnd"]); } + catch { valid_entry = false; } + if (valid_entry) { m_TODEnd = TimeSpan.FromMinutes(doubleEntry); } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["TODMode"]); } + catch { valid_entry = false; } + if (valid_entry) { m_TODMode = (TODModeType)intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Amount"]); } + catch { valid_entry = false; } + if (valid_entry) { m_StackAmount = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["MaxCount"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Count = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Range"]); } + catch { valid_entry = false; } + if (valid_entry) { m_HomeRange = intEntry; } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["Team"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Team = intEntry; } + + valid_entry = true; + try { strEntry = (string)dr["WayPoint"]; } + catch { valid_entry = false; } + if (valid_entry) { m_WayPoint = GetWaypoint(strEntry); } + + valid_entry = true; + try { intEntry = int.Parse((string)dr["KillReset"]); } + catch { valid_entry = false; } + if (valid_entry) { m_KillReset = intEntry; } + + valid_entry = true; + try { doubleEntry = double.Parse((string)dr["TriggerProbability"]); } + catch { valid_entry = false; } + if (valid_entry) { m_TriggerProbability = doubleEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["ExternalTriggering"]); } + catch { valid_entry = false; } + if (valid_entry) { m_ExternalTriggering = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["IsGroup"]); } + catch { valid_entry = false; } + if (valid_entry) { m_Group = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["IsHomeRangeRelative"]); } + catch { valid_entry = false; } + if (valid_entry) { m_HomeRangeIsRelative = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["AllowGhostTriggering"]); } + catch { valid_entry = false; } + if (valid_entry) { m_AllowGhostTriggering = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["AllowNPCTriggering"]); } + catch { valid_entry = false; } + if (valid_entry) { m_AllowNPCTriggering = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["SpawnOnTrigger"]); } + catch { valid_entry = false; } + if (valid_entry) { m_SpawnOnTrigger = boolEntry; } + + valid_entry = true; + try { boolEntry = bool.Parse((string)dr["SmartSpawning"]); } + catch { valid_entry = false; } + if (valid_entry) { m_SmartSpawning = boolEntry; } + + valid_entry = true; + try { strEntry = (string)dr["RegionName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + RegionName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["PlayerPropertyName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + m_PlayerPropertyName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["MobPropertyName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + m_MobPropertyName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["MobTriggerName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + m_MobTriggerName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["ObjectPropertyName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + m_ObjectPropertyName = strEntry; + } + + valid_entry = true; + try { strEntry = (string)dr["ObjectPropertyItemName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + string[] typeargs = strEntry.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = strEntry; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(this, namestr, typestr); + } + + valid_entry = true; + try { strEntry = (string)dr["SetPropertyItemName"]; } + catch { valid_entry = false; } + if (valid_entry) + { + string[] typeargs = strEntry.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = strEntry; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + m_SetPropertyItem = BaseXmlSpawner.FindItemByName(this, namestr, typestr); + } + + valid_entry = true; + try { strEntry = (string)dr["Name"]; } + catch { valid_entry = false; } + if (valid_entry) { Name = strEntry; } + + valid_entry = true; + try { strEntry = (string)dr["Map"]; } + catch { valid_entry = false; } + if (valid_entry) + { + // Convert the xml map value to a real map object + try + { + Map = Map.Parse(strEntry); + } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + } + + // try loading the new spawn specifications first + SpawnObject[] Spawns = new SpawnObject[0]; + bool havenew = true; + valid_entry = true; + try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); } + catch { havenew = false; } + if (!havenew) + { + // try loading the new spawn specifications + try { Spawns = SpawnObject.LoadSpawnObjectsFromString((string)dr["Objects"]); } + catch { valid_entry = false; } + // can only have one of these defined + } + if (valid_entry) + { + + // clear existing spawns + RemoveSpawnObjects(); + + // Create the new array of spawned objects + m_SpawnObjects = new List(); + + // Assign the list of objects to spawn + SpawnObjects = Spawns; + } + } + } + } + } + } + + public void ReportStatus() + { + if (PropertyInfoList != null) + { + Console.WriteLine("PropertyInfoList: {0}", PropertyInfoList.Count); + foreach (BaseXmlSpawner.TypeInfo to in PropertyInfoList) + { + Console.WriteLine("\t{0}", to.t); + foreach (PropertyInfo p in to.plist) + { + Console.WriteLine("\t\t{0}", p); + } + } + } + + ShowTagList(this); + int count = 0; + Console.WriteLine("Registered SkillsTotal = {0}", count); + } + +#if (TRACE) + + readonly string setname1 = _traceName[1] = "XmlFind"; + readonly string setname2 = _traceName[2] = "HasSector"; + readonly string setname4 = _traceName[4] = "AttachSpeech"; + readonly string setname5 = _traceName[5] = "HasHold"; + readonly string setname8 = _traceName[8] = "OnTick"; + readonly string setname9 = _traceName[9] = "Defrag"; + readonly string setname10 = _traceName[10] = "Respawn"; + readonly string setname11 = _traceName[11] = "SetProp"; + readonly string setname12 = _traceName[12] = "AttachMovement"; + readonly string setname13 = _traceName[13] = "ActiveSector"; + readonly string setname15 = _traceName[15] = "DistroTick"; + readonly string setname16 = _traceName[16] = "GetScaledFaction"; + readonly string setname17 = _traceName[17] = "FactionOnKill"; + readonly string setname18 = _traceName[18] = "CheckAcquire"; + + + private const int MaxTraces = 20; + private static readonly DateTime[] _traceStart = new DateTime[MaxTraces]; + public static TimeSpan[] _traceTotal = new TimeSpan[MaxTraces]; + public static string[] _traceName = new string[MaxTraces]; + public static int[] _traceCount = new int[MaxTraces]; + private static DateTime _traceStartTime = DateTime.UtcNow; + private static double _startProcessTime; + + public static void _TraceStart(int index) + { + if (index < MaxTraces) + { + _traceStart[index] = DateTime.UtcNow; + //_traceStart[index] = Process.GetCurrentProcess().UserProcessorTime; + } + } + public static void _TraceEnd(int index) + { + if (index < MaxTraces) + { + _traceTotal[index] = _traceTotal[index].Add(DateTime.UtcNow - _traceStart[index]); + //XmlSpawner._traceTotal[index] = XmlSpawner._traceTotal[index].Add(Process.GetCurrentProcess().UserProcessorTime - _traceStart[index]); + _traceCount[index]++; + } + } +#else + public static void _TraceStart(int index) { } + public static void _TraceEnd(int index) { } +#endif + + private bool ValidPlayerTrig(Mobile m) + { + if (m == null || m.Deleted) + { + return false; + } + + return (m.Player || m_AllowNPCTriggering) && m.AccessLevel <= TriggerAccessLevel && (!m.Body.IsGhost && !m_AllowGhostTriggering || m.Body.IsGhost && m_AllowGhostTriggering); + } + + private bool AllowTriggering => m_Running && !m_refractActivated && TODInRange && CanSpawn; + + private void ActivateTrigger() + { + DoTimer(); // reset the timer + + // start the refractory timer to set proximity activated to false, thus enabling another activation + if (m_MaxRefractory > TimeSpan.FromMinutes(0)) + { + int minSeconds = (int)m_MinRefractory.TotalSeconds; + int maxSeconds = (int)m_MaxRefractory.TotalSeconds; + + DoTimer3(TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds))); + } + + // if the spawnontrigger flag is set, then spawn immediately + if (m_SpawnOnTrigger) + { + NextSpawn = TimeSpan.Zero; + ResetNextSpawnTimes(); + } + + // reset speech triggering if it was set + m_speechTriggerActivated = false; + } + + public void CheckTriggers(Mobile m, Skill s, bool hasproximity) + { + if (AllowTriggering && !m_proximityActivated) // only proximity trigger when no spawns have already been triggered + { + bool needs_speech_trigger = false; + bool needs_player_trigger = false; + bool has_player_trigger = false; + + m_skipped = false; + + // test for the various triggering options in the order of increasing computational demand. No point checking a high demand test + // if a low demand one has already failed. + + // check for external triggering + if (m_ExternalTriggering && !m_ExternalTrigger) + { + return; + } + + // if speech triggering is set then test for successful activation + if (!string.IsNullOrEmpty(m_SpeechTrigger)) + { + needs_speech_trigger = true; + } + // check to see if we have to continue + if (needs_speech_trigger && !m_speechTriggerActivated) + { + return; + } + + // if player property triggering is set then look for the mob and test properties + if (!string.IsNullOrEmpty(m_PlayerPropertyName)) + { + needs_player_trigger = true; + string status_str; + + if (BaseXmlSpawner.TestMobProperty(this, m, m_PlayerPropertyName, out status_str)) + { + has_player_trigger = true; + } + + if (!string.IsNullOrEmpty(status_str)) + { + this.status_str = status_str; + } + } + + // check to see if we have to continue + if (needs_player_trigger && !has_player_trigger) + { + return; + } + + // if this was called without being proximity triggered then check to see that the non-movement triggers were enabled. + if (!hasproximity && !m_ExternalTriggering) + { + return; + } + + // all of the necessary trigger conditions have been met so go ahead and trigger + // after you make the probability check + + if (Utility.RandomDouble() < m_TriggerProbability) + { + // play a sound indicating the spawner has been triggered + if (m_ProximityTriggerSound > 0 && m != null && !m.Deleted) + { + m.PlaySound(m_ProximityTriggerSound); + } + + // display the trigger message + if (!string.IsNullOrEmpty(m_ProximityTriggerMessage) && m != null && !m.Deleted) + { + m.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, m_ProximityTriggerMessage); + } + + // enable spawning at the next ontick + // this will also start the refractory timer and send the triggering indicators + ProximityActivated = true; + + // keep track of who triggered this + m_mob_who_triggered = m; + } + else + { + m_skipped = true; + + // reset speech triggering if it was set + m_speechTriggerActivated = false; + } + } + } + public bool HandlesOnSkillUse => m_Running && m_SkillTrigger != null && m_SkillTrigger.Length > 0; + + // this is the handler for skill use + public void OnSkillUse(Mobile m, Skill skill, bool success) + { + + if (m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(m) && CanSpawn && !m_refractActivated && TODInRange) + { + + if (!Utility.InRange(m.Location, Location, m_ProximityRange)) + { + return; + } + + m_skillTriggerActivated = false; + + // check the skill trigger conditions, Skillname[+/-][,min,max] + if (m_SkillTrigger != null && skill.SkillName == m_SkillTriggerName && + (m_SkillTriggerMin < 0 || skill.Value >= m_SkillTriggerMin) && + (m_SkillTriggerMax < 0 || skill.Value <= m_SkillTriggerMax) && + (m_SkillTriggerSuccess == 3 || m_SkillTriggerSuccess == 1 && success || m_SkillTriggerSuccess == 2 && !success)) + { + // have a skill trigger so flag it and test it + m_skillTriggerActivated = true; + + CheckTriggers(m, skill, true); + } + } + } + public override bool HandlesOnSpeech => m_Running && !string.IsNullOrEmpty(m_SpeechTrigger); + + public override void OnSpeech(SpeechEventArgs e) + { + if (m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(e.Mobile) && CanSpawn && !m_refractActivated && TODInRange) + { + m_speechTriggerActivated = false; + + if (!Utility.InRange(e.Mobile.Location, Location, m_ProximityRange)) + { + return; + } + + if (m_SpeechTrigger != null && e.Speech.ToLower().IndexOf(m_SpeechTrigger.ToLower()) >= 0) + { + e.Handled = true; + + // found the speech trigger so flag it for testing in the onmovement handler where the other proximity features are tested + m_speechTriggerActivated = true; + + CheckTriggers(e.Mobile, null, true); + } + } + } + + public override bool HandlesOnMovement => m_Running && m_ProximityRange >= 0; + + public void AddToMovementList(Mobile m) + { + // go through the list and check for redundancy + if (m_MovementList == null) + { + m_MovementList = new List(); + } + + // check to see if the movement timer is running + if (m_MovementTimer == null || !m_MovementTimer.Running) + { + DoMovementTimer(TimeSpan.FromSeconds(1)); + } + + bool add = true; + + foreach (MovementInfo moveinfo in m_MovementList) + { + Mobile mtrig = moveinfo.trigMob; + if (mtrig == m) + { + add = false; + break; + } + } + + // wasnt on the list so add it + if (add) + { + + // is the list at max throttling length? + if (m_MovementList.Count > MaxMoveCheck) + { + // replace a random entry in the current list with this one + m_MovementList[Utility.Random(m_MovementList.Count)] = new MovementInfo(m); + } + else + { + + m_MovementList.Add(new MovementInfo(m)); + } + } + } + + public void DoMovementTimer(TimeSpan delay) + { + if (m_MovementTimer != null) + { + m_MovementTimer.Stop(); + } + + m_MovementTimer = new MovementTimer(this, delay); + + m_MovementTimer.Start(); + } + + private class MovementTimer : Timer + { + private readonly XmlSpawner m_Spawner; + + public MovementTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_Spawner = spawner; + + protected override void OnTick() + { + // check everyone on the movement list then clear the list + if (m_Spawner != null && !m_Spawner.Deleted) + { + if (m_Spawner.m_Running && !m_Spawner.m_proximityActivated && !m_Spawner.m_refractActivated && m_Spawner.TODInRange && m_Spawner.CanSpawn) + { + int count = 0; + int maxspeed = 0; + foreach (MovementInfo moveinfo in m_Spawner.m_MovementList) + { + Mobile m = moveinfo.trigMob; + if (m == null) + { + continue; + } + + // additional throttling in here by limiting number of mobs that can be checked in a single ontick + count++; + if (count > MaxMoveCheck) + { + break; + } + + int speed = (int)GetDistance(m.Location, moveinfo.trigLocation); + if (speed > maxspeed) + { + maxspeed = speed; + } + + m_Spawner.CheckTriggers(m, null, true); + } + + m_Spawner.MovingPlayerCount = m_Spawner.m_MovementList.Count; + m_Spawner.FastestPlayerSpeed = maxspeed; + + } + m_Spawner.m_MovementList.Clear(); + } + } + } + + public static double GetDistance(Point3D p1, Point3D p2) + { + int xDelta = p1.X - p2.X; + int yDelta = p1.Y - p2.Y; + + return Math.Sqrt(xDelta * xDelta + yDelta * yDelta); + } + + public override void OnMovement(Mobile m, Point3D oldLocation) + { + if (m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(m) && CanSpawn) + { + // check to see if player is within range of the spawner + if (Parent == null && Utility.InRange(m.Location, Location, m_ProximityRange)) + { + // add some throttling code here. + // add the player to a list that gets cleared every few seconds, checking for redundancy then trigger off of the list instead of off of + // the actual movement stream + + AddToMovementList(m); + } + else + { + // clear any speech triggering + m_speechTriggerActivated = false; + } + } + base.OnMovement(m, oldLocation); + } + + public static bool AssignSettings(string argname, string value) + { + switch (argname) + { + case "XmlSpawnDir": + { + XmlSpawnDir = value; + break; + } + case "DiskAccessLevel": + { + DiskAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); + break; + } + case "SmartSpawnAccessLevel": + { + SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); + break; + } + case "defaultTriggerSound": + { + defaultTriggerSound = ConvertToInt(value); + defProximityTriggerSound = defaultTriggerSound; + break; + } + case "BaseItemId": + { + BaseItemId = ConvertToInt(value); + break; + } + case "ShowItemId": + { + ShowItemId = ConvertToInt(value); + break; + } + case "MaxMoveCheck": + { + MaxMoveCheck = ConvertToInt(value); + break; + } + case "defMinDelay": + { + defMinDelay = TimeSpan.FromMinutes(ConvertToInt(value)); + break; + } + case "defMaxDelay": + { + defMaxDelay = TimeSpan.FromMinutes(ConvertToInt(value)); + break; + } + case "defRelativeHome": + { + defRelativeHome = bool.Parse(value); + break; + } + case "defSpawnRange": + { + defSpawnRange = ConvertToInt(value); + break; + } + case "defHomeRange": + { + defHomeRange = ConvertToInt(value); + break; + } + case "BlockKeyword": + { + // parse the keyword list and remove them from the keyword hashtables + string[] keywordlist = value.Split(','); + + if (keywordlist.Length > 0) + { + for (int i = 0; i < keywordlist.Length; i++) + { + BaseXmlSpawner.RemoveKeyword(keywordlist[i]); + } + } + + break; + } + case "BlockCommand": + case "ChangeCommand": + { + // delay processing of these settings until after all commands have been registered in their Initialize methods + Timer.DelayCall(TimeSpan.Zero, DelayedAssignSettings, argname, value); + break; + } + default: + { + return false; + } + } + + return true; + } + + private static void DelayedAssignSettings(string argname, string value) + { + switch (argname) + { + case "BlockCommand": + { + // delay processing of this until after all commands have been registered in their Initialize methods + // parse the command list and remove them from the command hashtables + // the syntax is "commandname, commandname, etc." + string[] keywordlist = value.Split(','); + + if (keywordlist.Length > 0) + { + for (int i = 0; i < keywordlist.Length; i++) + { + string commandname = keywordlist[i].Trim().ToLower(); + try + { + CommandSystem.Entries.Remove(commandname); + } + catch + { + Console.WriteLine("{0}: invalid command {1}", argname, commandname); + } + } + } + break; + } + case "ChangeCommand": + { + // delay processing of this until after all commands have been registered in their Initialize methods + // parse the command list and rehash them into the command hashtables + // the syntax is "oldname:newname[:accesslevel], oldname:newname[:accesslevel], etc." + string[] keywordlist = value.Split(','); + + if (keywordlist.Length > 0) + { + for (int i = 0; i < keywordlist.Length; i++) + { + string[] namelist = keywordlist[i].Split(':'); + if (namelist.Length > 1) + { + string oldname = namelist[0].Trim().ToLower(); + string newname = namelist[1].Trim(); + + if (newname.Length == 0) + { + newname = oldname; + } + + AccessLevel access = AccessLevel.Player; + bool validaccess = false; + if (namelist.Length > 2) + { + // get the new accesslevel + try + { + access = (AccessLevel)Enum.Parse(typeof(AccessLevel), namelist[2].Trim(), true); + validaccess = true; + } + catch + { + Console.WriteLine("{0}: invalid accesslevel {1} for {2}", argname, namelist[2], newname); + } + } + // find the command entry for the old name + CommandEntry e = null; + try + { + e = CommandSystem.Entries[oldname]; + } + catch + { + Console.WriteLine("{0}: invalid command {1}", argname, oldname); + } + if (e != null) + { + if (!validaccess) + { + // use the old accesslevel + access = e.AccessLevel; + } + // remove the old command entry + CommandSystem.Entries.Remove(oldname); + // register the new command using the old handler + CommandSystem.Register(newname, access, e.Handler); + } + + // also look in the targetcommands list and adjust name and accesslevel there + foreach (BaseCommand b in TargetCommands.AllCommands) + { + if (b.Commands != null) + { + for (int j = 0; j < b.Commands.Length; j++) + { + string commandname = b.Commands[j]; + if (commandname.ToLower() == oldname) + { + // modify the basecommand with the new name and access + b.Commands[j] = newname; + if (validaccess) + { + b.AccessLevel = access; + } + + // re-register it in the implementors hashtable + List impls = BaseCommandImplementor.Implementors; + + for (int k = 0; k < impls.Count; ++k) + { + BaseCommandImplementor impl = impls[k]; + + if ((b.Supports & impl.SupportRequirement) != 0) + { + try + { + impl.Commands.Remove(commandname); + } + catch (Exception ex) + { + Diagnostics.ExceptionLogging.LogException(ex); + } + impl.Register(b); + } + } + + break; + } + } + } + } + } + } + } + break; + } + } + } + + public delegate bool AssignSettingsHandler(string argname, string value); + + // load in settings from the xmlspawner2.cfg file in the Data directory + public static void LoadSettings(AssignSettingsHandler settingshandler, string section) + { + // Check if the file exists + string path = Path.Combine(Core.BaseDirectory, "Data/xmlspawner.cfg"); + + if (!File.Exists(path)) + { + return; + } + + Console.WriteLine("Loading {0} configuration", section); + using (StreamReader ip = new StreamReader(path)) + { + string line; + string currentsection = null; + int nsettings = 0; + + while ((line = ip.ReadLine()) != null) + { + line = line.Trim(); + + // skip comments + if (line.Length == 0 || line.StartsWith("#")) + { + continue; + } + + if (line.StartsWith("[")) + { + // parse the section name + string[] args = line.Split("[]".ToCharArray(), 3); + if (args.Length > 2) + { + currentsection = args[1].Trim(); + } + } + + // only process the matching classname section + if (currentsection != section) + { + continue; + } + + string[] split = line.Split('='); + + if (split.Length >= 2) + { + string argname = split[0].Trim(); + string value = split[1].Trim(); + + if (argname.Length == 0 || value.Length == 0) + { + continue; + } + + try + { + if (settingshandler(argname, value)) + { + nsettings++; + } + else + { + Console.WriteLine("'{0}' setting is invalid in section [{1}]", argname, currentsection); + } + } + catch (Exception e) + { + Console.WriteLine("Config error '{0}'='{1}'", argname, value); + Console.WriteLine("Error: {0}", e.Message); + Diagnostics.ExceptionLogging.LogException(e); + } + } + } + + if (nsettings > 0) + { + Console.WriteLine("{0} settings processed", nsettings); + } + } + } + + public static void Initialize() + { + LoadSettings(AssignSettings, "XmlSpawner"); + + // initialize the default waypoint name + WayPoint tmpwaypoint = new WayPoint(); + defwaypointname = tmpwaypoint.Name; + tmpwaypoint.Delete(); + + int count = 0; + int regional = 0; + + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner spawner) + { + count++; + + if (!string.IsNullOrEmpty(spawner.RegionName)) + { + spawner.RegionName = spawner.RegionName; // invoke set(RegionName) + regional++; + } + + // check for smart spawning and restart timers after deser if needed + // note, HasActiveSectors will recalculate the sector list and UseSectorActivate property + bool recalc_sectors = spawner.HasActiveSectors; + + spawner.RestoreISpawner(); + } + } + + // start the global smartspawning timer + if (SmartSpawningSystemEnabled) + { + DoGlobalSectorTimer(TimeSpan.FromSeconds(1)); + } + + // standard commands + CommandSystem.Register("XmlSpawnerShowAll", AccessLevel.Administrator, ShowSpawnPoints_OnCommand); + CommandSystem.Register("XmlSpawnerHideAll", AccessLevel.Administrator, HideSpawnPoints_OnCommand); + CommandSystem.Register("XmlSpawnerWipe", AccessLevel.Administrator, Wipe_OnCommand); + CommandSystem.Register("XmlSpawnerWipeAll", AccessLevel.Administrator, WipeAll_OnCommand); + CommandSystem.Register("XmlSpawnerLoad", DiskAccessLevel, Load_OnCommand); + CommandSystem.Register("XmlSpawnerSave", DiskAccessLevel, Save_OnCommand); + CommandSystem.Register("XmlSpawnerSaveAll", DiskAccessLevel, SaveAll_OnCommand); + CommandSystem.Register("XmlSpawnerRespawn", AccessLevel.Seer, Respawn_OnCommand); + CommandSystem.Register("XmlSpawnerRespawnAll", AccessLevel.Seer, RespawnAll_OnCommand); + + CommandSystem.Register("XmlShow", AccessLevel.Administrator, ShowSpawnPoints_OnCommand); + CommandSystem.Register("XmlHide", AccessLevel.Administrator, HideSpawnPoints_OnCommand); + CommandSystem.Register("XmlHome", AccessLevel.GameMaster, XmlHome_OnCommand); + CommandSystem.Register("XmlUnLoad", DiskAccessLevel, UnLoad_OnCommand); + CommandSystem.Register("XmlSpawnerUnLoad", DiskAccessLevel, UnLoad_OnCommand); + CommandSystem.Register("XmlLoad", DiskAccessLevel, Load_OnCommand); + CommandSystem.Register("XmlLoadHere", DiskAccessLevel, LoadHere_OnCommand); + CommandSystem.Register("XmlNewLoad", DiskAccessLevel, NewLoad_OnCommand); + CommandSystem.Register("XmlNewLoadHere", DiskAccessLevel, NewLoadHere_OnCommand); + CommandSystem.Register("XmlSave", DiskAccessLevel, Save_OnCommand); + CommandSystem.Register("XmlSaveAll", DiskAccessLevel, SaveAll_OnCommand); + CommandSystem.Register("XmlSaveOld", DiskAccessLevel, SaveOld_OnCommand); + CommandSystem.Register("XmlImportSpawners", DiskAccessLevel, XmlImportSpawners_OnCommand); + CommandSystem.Register("XmlImportMSF", DiskAccessLevel, XmlImportMSF_OnCommand); + CommandSystem.Register("XmlImportMap", DiskAccessLevel, XmlImportMap_OnCommand); + CommandSystem.Register("XmlDefaults", AccessLevel.Administrator, XmlDefaults_OnCommand); + CommandSystem.Register("XmlGet", AccessLevel.GameMaster, XmlGetValue_OnCommand); + CommandSystem.Register("OptimalSmartSpawning", AccessLevel.Administrator, OptimalSmartSpawning_OnCommand); + CommandSystem.Register("SmartStat", AccessLevel.GameMaster, SmartStat_OnCommand); + CommandSystem.Register("XmlGo", AccessLevel.GameMaster, SpawnEditorGo_OnCommand); + + TargetCommands.Register(new XmlSetCommand()); + TargetCommands.Register(new XmlSaveSingle()); + +#if (TRACE) + CommandSystem.Register("XmlMake", AccessLevel.Administrator, XmlMake_OnCommand); + CommandSystem.Register("XmlTrace", AccessLevel.Administrator, XmlTrace_OnCommand); + CommandSystem.Register("XmlResetTrace", AccessLevel.Administrator, XmlResetTrace_OnCommand); +#endif + + } + + [Usage("XmlGet property")] + [Description("Returns value of the property on the targeted object.")] + public static void XmlGetValue_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new GetValueTarget(e); + } + private class GetValueTarget : Target + { + private readonly CommandEventArgs m_e; + public GetValueTarget(CommandEventArgs e) + : base(30, false, TargetFlags.None) => + m_e = e; + + protected override void OnTarget(Mobile from, object targeted) + { + string pname = m_e.GetString(0); + Type ptype; + string result = BaseXmlSpawner.GetPropertyValue(null, targeted, pname, out ptype); + + // see if it was successful + if (ptype == null) + { + return; + } + from.SendMessage("{0}", result); + + } + } + + public class XmlSetCommand : BaseCommand + { + public XmlSetCommand() + { + AccessLevel = AccessLevel.Administrator; + Supports = CommandSupport.All; + Commands = new[] { "XmlSet" }; + ObjectTypes = ObjectTypes.Both; + Usage = "XmlSet "; + Description = "Sets a property value by name of a targeted object. Provides access to all public properties."; + } + + public override void Execute(CommandEventArgs e, object obj) + { + if (e.Length >= 2) + { + string result = BaseXmlSpawner.SetPropertyValue(null, obj, e.GetString(0), e.GetString(1)); + + if (result == "Property has been set.") + { + AddResponse(result); + } + else + { + LogFailure(result); + } + } + else + { + LogFailure("Format: XmlSet "); + } + } + } + + [Usage("TagList property")] + [Description("Lists the keyword taglist for a spawner")] + public static void ShowTagList_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new TagListTarget(e); + } + + private class TagListTarget : Target + { + private readonly CommandEventArgs m_e; + + public TagListTarget(CommandEventArgs e) + : base(30, false, TargetFlags.None) => + m_e = e; + + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is XmlSpawner spawner) + { + spawner.ShowTagList(spawner); + } + } + } + + public void ShowTagList(XmlSpawner spawner) + { + int count = 0; + Console.WriteLine("{0} tags", spawner.m_KeywordTagList.Count); + foreach (BaseXmlSpawner.KeywordTag tag in spawner.m_KeywordTagList) + { + count++; + Console.WriteLine("tag {0} : {1}", count, BaseXmlSpawner.TagInfo(tag)); + } + } + + + // added in targeting for the [xmlhome command + private class XmlHomeTarget : Target + { + private readonly CommandEventArgs m_e; + public XmlHomeTarget(CommandEventArgs e) + : base(30, false, TargetFlags.None) => + m_e = e; + + protected override void OnTarget(Mobile from, object targeted) + { + XmlSpawner spawner = null; + + if (targeted is XmlSpawner xmlSpawner) + { + if (m_e.GetString(0) == "status") + { + xmlSpawner.ReportStatus(); + return; + } + } + + + if (targeted is Mobile mobile) + { + spawner = mobile.Spawner as XmlSpawner; + } + else + if (targeted is Item item) + { + spawner = item.Spawner as XmlSpawner; + } + + if (spawner == null) + { + from.SendMessage("Unable to find spawner for this object"); + return; + } + + // check to make sure it is still on the spawner + foreach (SpawnObject so in spawner.m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + + if (o == targeted) + { + from.SendMessage("{0}, {1}, {2}", spawner.X, spawner.Y, spawner.Z); + + if (m_e.GetString(0) == "go") + { + // make sure the spawner is not in a container. + if (spawner.Parent == null) + { + from.Location = new Point3D(spawner.Location); + from.Map = spawner.Map; + } + else + { + from.SendMessage("Spawner is in a container"); + } + } + else + if (m_e.GetString(0) == "send") + { + // make sure the spawner is not in a container. + if (spawner.Parent == null) + { + if (o is Item item) + { + item.Location = new Point3D(spawner.Location); + item.Map = spawner.Map; + } + if (o is Mobile mobile1) + { + mobile1.Location = new Point3D(spawner.Location); + mobile1.Map = spawner.Map; + } + } + else + { + from.SendMessage("Spawner is in a container"); + } + } + else if (m_e.GetString(0) == "gump") + { + spawner.OnDoubleClick(from); + } + + return; + } + } + } + } + } + + [Usage("XmlHome [go][gump][send]")] + [Description("Returns the coordinates of the spawner for the targeted object. Args: 'go' teleports to spawner, 'gump' opens spawner gump, 'send' sends mob home")] + public static void XmlHome_OnCommand(CommandEventArgs e) + { + e.Mobile.Target = new XmlHomeTarget(e); + } + + private static void XmlSaveDefaults(string filePath, Mobile m) + { + + if (string.IsNullOrEmpty(filePath)) + { + return; + } + + using (StreamWriter op = new StreamWriter(filePath)) + { + XmlTextWriter xml = new XmlTextWriter(op) + { + Formatting = Formatting.Indented, + IndentChar = '\t', + Indentation = 1 + }; + + xml.WriteStartDocument(true); + + xml.WriteStartElement("XmlDefaults"); + + xml.WriteStartElement("defProximityRange"); + xml.WriteString(defProximityRange.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTriggerProbability"); + xml.WriteString(defTriggerProbability.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defProximityTriggerSound"); + xml.WriteString(defProximityTriggerSound.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defMinRefractory"); + xml.WriteString(defMinRefractory.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defMaxRefractory"); + xml.WriteString(defMaxRefractory.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTODStart"); + xml.WriteString(defTODStart.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTODEnd"); + xml.WriteString(defTODEnd.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defStackAmount"); + xml.WriteString(defAmount.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defDuration"); + xml.WriteString(defDuration.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defIsGroup"); + xml.WriteString(defIsGroup.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTeam"); + xml.WriteString(defTeam.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defRelativeHome"); + xml.WriteString(defRelativeHome.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defSpawnRange"); + xml.WriteString(defSpawnRange.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defHomeRange"); + xml.WriteString(defHomeRange.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defMinDelay"); + xml.WriteString(defMinDelay.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defMaxDelay"); + xml.WriteString(defMaxDelay.ToString()); + xml.WriteEndElement(); + xml.WriteStartElement("defTODMode"); + xml.WriteString(defTODMode.ToString()); + xml.WriteEndElement(); + + xml.WriteEndElement(); + + xml.Close(); + } + m.SendMessage("defaults saved to {0}", filePath); + } + + public static void XmlLoadDefaults(string filePath, Mobile m) + { + if (m == null || m.Deleted) + { + return; + } + + if (!string.IsNullOrEmpty(filePath)) + { + + if (File.Exists(filePath)) + { + XmlDocument doc = new XmlDocument(); + doc.Load(filePath); + + XmlElement root = doc["XmlDefaults"]; + LoadDefaults(root); + m.SendMessage("defaults loaded successfully from {0}", filePath); + } + else + { + m.SendMessage("File {0} does not exist.", filePath); + } + } + } + + private static void LoadDefaults(XmlElement node) + { + + try { defProximityRange = int.Parse(node["defProximityRange"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defTriggerProbability = double.Parse(node["defTriggerProbability"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defProximityTriggerSound = int.Parse(node["defProximityTriggerSound"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defMinRefractory = TimeSpan.Parse(node["defMinRefractory"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defMaxRefractory = TimeSpan.Parse(node["defMaxRefractory"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defTODStart = TimeSpan.Parse(node["defTODStart"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defTODEnd = TimeSpan.Parse(node["defTODEnd"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defAmount = int.Parse(node["defStackAmount"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defDuration = TimeSpan.Parse(node["defDuration"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defIsGroup = bool.Parse(node["defIsGroup"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defTeam = int.Parse(node["defTeam"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defRelativeHome = bool.Parse(node["defRelativeHome"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defSpawnRange = int.Parse(node["defSpawnRange"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defHomeRange = int.Parse(node["defHomeRange"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defMinDelay = TimeSpan.Parse(node["defMinDelay"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + try { defMaxDelay = TimeSpan.Parse(node["defMaxDelay"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + int todmode = 0; + try { todmode = int.Parse(node["defTODMode"].InnerText); } + catch (Exception e) + { + Diagnostics.ExceptionLogging.LogException(e); + } + switch (todmode) + { + case (int)TODModeType.Realtime: + { + defTODMode = TODModeType.Realtime; + break; + } + case (int)TODModeType.Gametime: + { + defTODMode = TODModeType.Gametime; + break; + } + } + } + + [Usage("XmlDefaults [defaultpropertyname value]")] + [Description("Returns or changes the default settings of the spawner.")] + public static void XmlDefaults_OnCommand(CommandEventArgs e) + { + Mobile m = e.Mobile; + if (m == null || m.Deleted) + { + return; + } + + if (e.Arguments.Length >= 1) + { + // leave open the possibility of just requesting display of a single property + if (e.Arguments.Length == 2) + { + if (e.Arguments[0].ToLower() == "save") + { + XmlSaveDefaults(e.Arguments[1], m); + } + else if (e.Arguments[0].ToLower() == "load") + { + XmlLoadDefaults(e.Arguments[1], m); + } + else if (e.Arguments[0].ToLower() == "maxdelay") + { + try + { + defMaxDelay = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("MaxDelay = {0}", defMaxDelay); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "mindelay") + { + try + { + defMinDelay = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("MinDelay = {0}", defMinDelay); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "spawnrange") + { + try + { + defSpawnRange = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("SpawnRange = {0}", defSpawnRange); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "homerange") + { + try + { + defHomeRange = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("HomeRange = {0}", defHomeRange); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "relativehome") + { + try + { + defRelativeHome = Convert.ToBoolean(e.Arguments[1]); + m.SendMessage("RelativeHome = {0}", defRelativeHome); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "proximitytriggersound") + { + try + { + defProximityTriggerSound = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("ProximityTriggerSound = {0}", defProximityTriggerSound); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "proximityrange") + { + try + { + defProximityRange = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("ProximityRange = {0}", defProximityRange); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "triggerprobability") + { + try + { + defTriggerProbability = Convert.ToDouble(e.Arguments[1]); + m.SendMessage("TriggerProbability = {0}", defTriggerProbability); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "todstart") + { + try + { + defTODStart = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("TODStart = {0}", defTODStart); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "todend") + { + try + { + defTODEnd = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("TODEnd = {0}", defTODEnd); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "stackamount") + { + try + { + defAmount = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("StackAmount = {0}", defAmount); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "duration") + { + try + { + defDuration = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("Duration = {0}", defDuration); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "group") + { + try + { + defIsGroup = Convert.ToBoolean(e.Arguments[1]); + m.SendMessage("Group = {0}", defIsGroup); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "team") + { + try + { + defTeam = Convert.ToInt32(e.Arguments[1]); + m.SendMessage("Team = {0}", defTeam); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "todmode") + { + try + { + int todmode = Convert.ToInt32(e.Arguments[1]); + switch (todmode) + { + case (int)TODModeType.Gametime: + { + defTODMode = TODModeType.Gametime; + break; + } + case (int)TODModeType.Realtime: + { + defTODMode = TODModeType.Realtime; + break; + } + } + m.SendMessage("TODMode = {0}", defTODMode); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "maxrefractory") + { + try + { + defMaxRefractory = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("MaxRefractory = {0}", defMaxRefractory); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else if (e.Arguments[0].ToLower() == "minrefractory") + { + try + { + defMinRefractory = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); + m.SendMessage("MinRefractory = {0}", defMinRefractory); + } + catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + } + else + { + m.SendMessage("{0} : no such default value.", e.Arguments[0]); + } + } + + } + else + { + // just display the values + m.SendMessage("TriggerProbability = {0}", defTriggerProbability); + m.SendMessage("ProximityRange = {0}", defProximityRange); + m.SendMessage("ProximityTriggerSound = {0}", defProximityTriggerSound); + m.SendMessage("MinRefractory = {0}", defMinRefractory); + m.SendMessage("MaxRefractory = {0}", defMaxRefractory); + m.SendMessage("TODStart = {0}", defTODStart); + m.SendMessage("TODEnd = {0}", defTODEnd); + m.SendMessage("TODMode = {0}", defTODMode); + m.SendMessage("StackAmount = {0}", defAmount); + m.SendMessage("Duration = {0}", defDuration); + m.SendMessage("Group = {0}", defIsGroup); + m.SendMessage("Team = {0}", defTeam); + m.SendMessage("RelativeHome = {0}", defRelativeHome); + m.SendMessage("SpawnRange = {0}", defSpawnRange); + m.SendMessage("HomeRange = {0}", defHomeRange); + m.SendMessage("MinDelay = {0}", defMinDelay); + m.SendMessage("MaxDelay = {0}", defMaxDelay); + } + } + + [Usage("XmlSpawnerShowAll")] + [Aliases("XmlShow")] + [Description("Makes all XmlSpawner objects movable and also changes the item id to a blue ships mast for easy identification.")] + public static void ShowSpawnPoints_OnCommand(CommandEventArgs e) + { + List ToShow = new List(); + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner) + { + //turned off visibility. Admins will still see masts but players will not. + item.Visible = false; // set the spawn item visibility + item.Movable = false; // Make the spawn item movable + item.Hue = 88; // Bright blue colour so its easy to spot + item.ItemID = ShowItemId; // Ship Mast (Very tall, easy to see if beneath other objects) + + // find container-held spawners to be marked with an external static + if (item.Parent != null && item.RootParent is Container) + { + ToShow.Add(item); + } + } + } + + // place the statics + foreach (XmlSpawner xml_item in ToShow) + { + // does the spawner already have a static attached to it? could happen if two showall commands are issued in a row. + // if so then dont add another + if ((xml_item.m_ShowContainerStatic == null || xml_item.m_ShowContainerStatic.Deleted) && xml_item.RootParent is Container rootItem) + { + // calculate a world location for the static. Position it just above the container + int x = rootItem.Location.X; + int y = rootItem.Location.Y; + int z = rootItem.Location.Z + 10; + + Static s = new Static(ShowItemId) + { + Visible = false + }; + s.MoveToWorld(new Point3D(x, y, z), rootItem.Map); + + xml_item.m_ShowContainerStatic = s; + } + + } + } + + [Usage("XmlSpawnerHideAll")] + [Aliases("XmlHide")] + [Description("Makes all XmlSpawner objects invisible and unmovable returns the object id to the default.")] + public static void HideSpawnPoints_OnCommand(CommandEventArgs e) + { + List ToDelete = new List(); + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner xmlItem) + { + xmlItem.Visible = false; + xmlItem.Movable = false; + xmlItem.Hue = 0; + xmlItem.ItemID = BaseItemId; + + // get rid of the external static marker for container-held spawners + // check anything that might have been tagged with a container static + if (xmlItem.m_ShowContainerStatic != null && !xmlItem.m_ShowContainerStatic.Deleted) + { + ToDelete.Add(xmlItem); + } + } + } + foreach (XmlSpawner xml_item in ToDelete) + { + if (xml_item.m_ShowContainerStatic != null && !xml_item.m_ShowContainerStatic.Deleted) + { + xml_item.m_ShowContainerStatic.Delete(); + } + } + } + + [Usage("XmlGo | [z]")] + [Description("Go command used with spawn editor, takes the name of the map as the first parameter.")] + private static void SpawnEditorGo_OnCommand(CommandEventArgs e) + { + if (e == null) + { + return; + } + + Mobile from = e.Mobile; + + // Make sure a map name was given at least + if (from != null && e.Length >= 1) + { + string MapName = e.Arguments[0]; + + // Get the map + Map NewMap; + // Convert the xml map value to a real map object + if (string.Compare(MapName, Map.Trammel.Name, true) == 0) + { + NewMap = Map.Trammel; + } + else if (string.Compare(MapName, Map.Felucca.Name, true) == 0) + { + NewMap = Map.Felucca; + } + else if (string.Compare(MapName, Map.Ilshenar.Name, true) == 0) + { + NewMap = Map.Ilshenar; + } + else if (string.Compare(MapName, Map.Malas.Name, true) == 0) + { + NewMap = Map.Malas; + } + else if (string.Compare(MapName, Map.Tokuno.Name, true) == 0) + { + NewMap = Map.Tokuno; + } + else + { + from.SendMessage("Map '{0}' does not exist!", MapName); + return; + } + + // Now that the map has been determined, continue + // Check if the request is to simply change maps + if (e.Length == 1) + { + // Map Change ONLY + from.Map = NewMap; + } + else if (e.Length == 3) + { + // Map & X Y ONLY + if (NewMap != null) + { + int x = e.GetInt32(1); + int y = e.GetInt32(2); + int z = NewMap.GetAverageZ(x, y); + from.Map = NewMap; + from.Location = new Point3D(x, y, z); + } + } + else if (e.Length == 4) + { + // Map & X Y Z + from.Map = NewMap; + from.Location = new Point3D(e.GetInt32(1), e.GetInt32(2), e.GetInt32(3)); + } + else + { + from.SendMessage("Format: XmlGo | [z]"); + } + } + } + + [Usage("SmartStat [accesslevel Player/Counselor/GameMaster/Seer/Administrator]")] + [Description("Returns the spawn reduction due to SmartSpawning.")] + public static void SmartStat_OnCommand(CommandEventArgs e) + { + if (e == null || e.Mobile == null) + { + return; + } + + if (e.Arguments.Length > 1 && e.Arguments[0].ToLower() == "accesslevel" && e.Mobile.AccessLevel >= AccessLevel.Administrator) + { + try + { + SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), e.Arguments[1], true); + } + catch (Exception ex) { Diagnostics.ExceptionLogging.LogException(ex); } + } + // handle the + // number of spawners + int count = 0; + // number of actual spawns + int currentcount = 0; + int smartcount = 0; + int inactivecount = 0; + // maximum possible spawns + int totalcount = 0; + int maxcount = 0; + // maximum possible of spawns that are currently inactivated + int savings = 0; + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner spawner) + { + if (spawner.Deleted) + { + continue; + } + + totalcount += spawner.MaxCount; + // get the current count without defragging + currentcount += spawner.SafeCurrentCount; + count++; + + // check to see if smartspawning is set + if (spawner.SmartSpawning) + { + smartcount++; + maxcount += spawner.MaxCount; + } + + if (spawner.IsInactivated) + { + inactivecount++; + savings += spawner.MaxCount; + } + } + } + + int percent = 0; + + int maxpercent = 0; + if (totalcount > 0) + { + percent = 100 * savings / totalcount; + maxpercent = 100 * maxcount / totalcount; + } + + e.Mobile.SendMessage( + "Smartspawning access level is {10}\n" + + "--------------------------------\n" + + "{0} XmlSpawners\n" + + "{1} are configured for SmartSpawning\n" + + "{2} are currently inactivated\n" + + "{9} sectors being monitored\n" + + "Maximum possible spawn count is {3}\n" + + "Maximum possible spawn reduction is {4}\n" + + "Current spawn count is {5}\n" + + "Current spawn reduction is {6}\n" + + "Maximum possible savings is {7}%\n" + + "Current savings is {8}%", + count, smartcount, inactivecount, totalcount, maxcount, currentcount, savings, maxpercent, + percent, totalSectorsMonitored, SmartSpawnAccessLevel); + } + + [Usage("OptimalSmartSpawning [max spawn/homerange diff]")] + [Description("Activates SmartSpawning on XmlSpawners that are well-suited for use of this feature.")] + public static void OptimalSmartSpawning_OnCommand(CommandEventArgs e) + { + int maxdiff = 1; + if (e.Arguments.Length > 0) + { + try + { + maxdiff = int.Parse(e.Arguments[0]); + } + catch (Exception ex) + { + Diagnostics.ExceptionLogging.LogException(ex); + } + } + int count = 0; + int maxcount = 0; + foreach (Item item in World.Items.Values) + { + if (item is XmlSpawner spawner) + { + // determine whether this spawner is a good candidate + + if (spawner.Deleted) + { + continue; + } + + // ignore spawners in towns + //if (Region.Find(spawner.Location, spawner.Map) is Regions.TownRegion) continue; + + // dont bother setting it on triggered spawners + if (spawner.ProximityRange >= 0) + { + continue; + } + + // check the relative spawnrange and homerange. Dont set it on spawners with a larger homerange than spawnrange + int width = spawner.m_Width; + int height = spawner.m_Height; + + if (spawner.HomeRange * 2 > width + maxdiff * 2 || spawner.HomeRange * 2 > height + maxdiff * 2 && spawner.m_Region != null) + { + continue; + } + + int nso = 0; + + if (spawner.m_SpawnObjects != null) + { + nso = spawner.m_SpawnObjects.Count; + } + + // empty spawner so skip it + if (nso == 0) + { + continue; + } + + bool skipit = false; + + // check the spawn types + for (int i = 0; i < nso; ++i) + { + SpawnObject so = spawner.m_SpawnObjects[i]; + + if (so == null) + { + continue; + } + + string typestr = so.TypeName; + + Type type = AssemblyHandler.FindTypeByName(typestr); + + // if it has basevendors on it or invalid types, then skip it + if (typestr == null || type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor))) || + type == null && !BaseXmlSpawner.IsTypeOrItemKeyword(typestr) && typestr.IndexOf('{') == -1 && !typestr.StartsWith("*") && !typestr.StartsWith("#")) + { + skipit = true; + break; + } + } + + if (!skipit) + { + count++; + spawner.SmartSpawning = true; + maxcount += spawner.MaxCount; + } + } + } + + e.Mobile.SendMessage("Configured {0} XmlSpawners for SmartSpawning using maxdiff of {1}", count, maxdiff); + e.Mobile.SendMessage("Estimated item/mob reduction is {0}", maxcount); + } + + [Usage("XmlSpawnerWipe [SpawnerPrefixFilter]")] + [Description("Removes all XmlSpawner objects from the current map.")] + public static void Wipe_OnCommand(CommandEventArgs e) + { + WipeSpawners(e, false); + } + + [Usage("XmlSpawnerWipeAll [SpawnerPrefixFilter]")] + [Description("Removes all XmlSpawner objects from the entire world.")] + public static void WipeAll_OnCommand(CommandEventArgs e) + { + WipeSpawners(e, true); + } + + public static void XmlUnLoadFromFile(string filename, string SpawnerPrefix, Mobile from, out int processedmaps, out int processedspawners) + { + + processedmaps = 0; + processedspawners = 0; + if (filename == null || filename.Length <= 0) + { + return; + } + + int total_processed_maps = 0; + int total_processed_spawners = 0; + + // Check if the file exists + if (File.Exists(filename)) + { + FileStream fs = null; + try + { + fs = File.Open(filename, FileMode.Open, FileAccess.Read); + } + catch { } + + if (fs == null) + { + if (from != null) + { + from.SendMessage("Unable to open {0} for unloading", filename); + } + + return; + } + + XmlUnLoadFromStream(fs, filename, SpawnerPrefix, from, out processedmaps, out processedspawners); + + } + else + // check to see if it is a directory + if (Directory.Exists(filename)) + { + // if so then import all of the .xml files in the directory + string[] files = null; + try + { + files = Directory.GetFiles(filename, "*.xml"); + } + catch { } + if (files != null && files.Length > 0) + { + if (from != null) + { + from.SendMessage("UnLoading {0} .xml files from directory {1}", files.Length, filename); + } + + foreach (string file in files) + { + XmlUnLoadFromFile(file, SpawnerPrefix, from, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + // recursively search subdirectories for more .xml files + string[] dirs = null; + try + { + dirs = Directory.GetDirectories(filename); + } + catch { } + if (dirs != null && dirs.Length > 0) + { + foreach (string dir in dirs) + { + XmlUnLoadFromFile(dir, SpawnerPrefix, from, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + if (from != null) + { + from.SendMessage("UnLoaded a total of {0} .xml files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + } + + processedmaps = total_processed_maps; + processedspawners = total_processed_spawners; + } + else + { + if (from != null) + { + from.SendMessage("{0} does not exist", filename); + } + } + + } + + public static void XmlUnLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + + if (fs == null) + { + return; + } + + int TotalCount = 0; + int TrammelCount = 0; + int FeluccaCount = 0; + int IlshenarCount = 0; + int MalasCount = 0; + int TokunoCount = 0; + int OtherCount = 0; + int bad_spawner_count = 0; + int spawners_deleted = 0; + + if (from != null) + { + from.SendMessage(string.Format("UnLoading {0} objects{1} from file {2}.", + "XmlSpawner", !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty, filename)); + } + + // Create the data set + DataSet ds = new DataSet(SpawnDataSetName); + + // Read in the file + //ds.ReadXml(e.Arguments[0].ToString()); + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch + { + if (from != null) + { + from.SendMessage(33, "Error reading xml file {0}", filename); + } + + fileerror = true; + } + // close the file + fs.Close(); + if (fileerror) + { + return; + } + + // Check that at least a single table was loaded + if (ds.Tables.Count > 0) + { + // Add each spawn point to the current map + if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + { + foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) + { + // load in the spawner info. Certain fields are required and therefore cannot be ignored + // the exception handler for those will flag bad_spawner and the result will be logged + + // Each row makes up a single spawner + string SpawnName = "Spawner"; + try { SpawnName = (string)dr["Name"]; } + catch { } + + // Check if there is any spawner name criteria specified on the unload + if (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || SpawnName.StartsWith(SpawnerPrefix)) + { + bool bad_spawner = false; + // Try load the GUID (might not work so create a new GUID) + Guid SpawnId = Guid.NewGuid(); + try { SpawnId = new Guid((string)dr["UniqueId"]); } + catch { bad_spawner = true; } + // have to have a GUID or no point in continuing + if (bad_spawner) + { + bad_spawner_count++; + continue; + } + // Get the map (default to the mobiles map) + Map SpawnMap = Map.Internal; + string XmlMapName = SpawnMap.Name; + + // Try to get the "map" field, but in case it doesn't exist, catch and discard the exception + try { XmlMapName = (string)dr["Map"]; } + catch { } + + // Convert the xml map value to a real map object + if (string.Compare(XmlMapName, Map.Trammel.Name, true) == 0 || XmlMapName == "Trammel") + { + SpawnMap = Map.Trammel; + TrammelCount++; + } + else if (string.Compare(XmlMapName, Map.Felucca.Name, true) == 0 || XmlMapName == "Felucca") + { + SpawnMap = Map.Felucca; + FeluccaCount++; + } + else if (string.Compare(XmlMapName, Map.Ilshenar.Name, true) == 0 || XmlMapName == "Ilshenar") + { + SpawnMap = Map.Ilshenar; + IlshenarCount++; + } + else if (string.Compare(XmlMapName, Map.Malas.Name, true) == 0 || XmlMapName == "Malas") + { + SpawnMap = Map.Malas; + MalasCount++; + } + else if (string.Compare(XmlMapName, Map.Tokuno.Name, true) == 0 || XmlMapName == "Tokuno") + { + SpawnMap = Map.Tokuno; + TokunoCount++; + } + else + { + try + { + SpawnMap = Map.Parse(XmlMapName); + } + catch { } + OtherCount++; + } + + // Check if this spawner already exists + XmlSpawner OldSpawner = null; + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner checkXmlSpawner) + { + // Check if the spawners GUID is the same as the one being unloaded + // and that the spawners map is the same as the one being unloaded + if (checkXmlSpawner.UniqueId == SpawnId.ToString() + /*&& (CheckXmlSpawner.Map == SpawnMap)*/) + { + OldSpawner = checkXmlSpawner; + if (OldSpawner != null) + { + spawners_deleted++; + OldSpawner.Delete(); + } + + break; + } + } + } + } + + TotalCount++; + } + } + } + + try + { + fs.Close(); + } + catch { } + + if (from != null) + { + from.SendMessage("{0}/{8} spawner(s) were unloaded using file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6}, Other={7}].", + spawners_deleted, filename, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount, TotalCount); + } + + if (bad_spawner_count > 0) + { + if (from != null) + { + from.SendMessage(33, "{0} bad spawners detected.", bad_spawner_count); + } + } + + processedmaps = 1; + processedspawners = TotalCount; + } + + [Usage("XmlSpawnerUnLoad [SpawnerPrefixFilter]")] + [Aliases("XmlUnload")] + [Description("UnLoads XmlSpawner objects from the proper map as defined in the file supplied.")] + public static void UnLoad_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + // Spawner unload criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (load criteria) + if (e.Arguments.Length > 1) + { + SpawnerPrefix = e.Arguments[1]; + } + + string filename = LocateFile(e.Arguments[0]); + int processedmaps; + int processedspawners; + XmlUnLoadFromFile(filename, SpawnerPrefix, e.Mobile, out processedmaps, out processedspawners); + } + else + { + e.Mobile.SendMessage("Usage: {0} ", e.Command); + } + } + else + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + } + + [Usage("XmlImportMap ")] + [Description("Loads spawner definitions from a .map file")] + public static void XmlImportMap_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = e.Arguments[0]; + + int processedmaps; + int processedspawners; + XmlImportMap(filename, e.Mobile, out processedmaps, out processedspawners); + } + else + { + e.Mobile.SendMessage("Usage: {0} ", e.Command); + } + } + else + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + } + + public static void XmlImportMap(string filename, Mobile from, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + int total_processed_maps = 0; + int total_processed_spawners = 0; + if (filename == null || filename.Length <= 0 || from == null || from.Deleted) + { + return; + } + + // Check if the file exists + if (File.Exists(filename)) + { + int spawnercount = 0; + int badspawnercount = 0; + int linenumber = 0; + // default is no map override, use the map spec from each spawn line + int overridemap = -1; + double overridemintime = -1; + double overridemaxtime = -1; + bool newformat = false; + 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) + { + // the old format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1 + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount + // * | typename:typename:... |s1 |s2 |s3 |s4 |s5 | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount | maxcount1 | maxcount2 | maxcount3 | maxcount4 | maxcount5 + // where s1-5 are additional spawn type entries with their own maxcounts + // the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1 + + linenumber++; + // is this the new format? + string[] args; + if (line.IndexOf('|') >= 0) + { + args = line.Trim().Split('|'); + newformat = true; + } + else + { + args = line.Trim().Split(' '); + } + + // determine the format of this line and parse accordingly + if (newformat) + { + ParseNewMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime); + } + else + { + ParseOldMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime); + } + + } + sr.Close(); + } + } + catch (Exception e) + { + // Let the user know what went wrong. + from.SendMessage("The file could not be read: {0}", e.Message); + } + from.SendMessage("Imported {0} spawners from {1}", spawnercount, filename); + from.SendMessage("{0} bad spawners detected", badspawnercount); + processedmaps = 1; + processedspawners = spawnercount; + } + else + // check to see if it is a directory + if (Directory.Exists(filename)) + { + // if so then import all of the .map files in the directory + string[] files = null; + try + { + files = Directory.GetFiles(filename, "*.map"); + } + catch { } + if (files != null && files.Length > 0) + { + from.SendMessage("Importing {0} .map files from directory {1}", files.Length, filename); + foreach (string file in files) + { + XmlImportMap(file, from, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + // recursively search subdirectories for more .map files + string[] dirs = null; + try + { + dirs = Directory.GetDirectories(filename); + } + catch { } + if (dirs != null && dirs.Length > 0) + { + foreach (string dir in dirs) + { + XmlImportMap(dir, from, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + from.SendMessage("Imported a total of {0} .map files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + processedmaps = total_processed_maps; + processedspawners = total_processed_spawners; + } + else + { + from.SendMessage("{0} does not exist", filename); + } + } + + private static void ParseNewMapFormat(Mobile from, string filename, string line, string[] args, int linenumber, ref int spawnercount, ref int badspawnercount, ref int overridemap, ref double overridemintime, ref double overridemaxtime) + { + // format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1 + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount + // or + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange spawnid maxcount + // ## are comments + // overridemap mapnumber + // map 0 is tram+fel + // map 1 is fel + // map 2 is tram + // map 3 is ilsh + // map 4 is mal + // map 5 is tokuno + // + // * | typename:typename:... | | | | | | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount1 | maxcount2 | maxcount2 | maxcount3 | maxcount4 | maxcount5 | maxcount6 + // the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1 + + if (args == null || from == null) + { + return; + } + + // look for the override keyword + if (args.Length == 2 && args[0].ToLower() == "overridemap") + { + try + { + overridemap = int.Parse(args[1]); + } + catch { } + } + else + if (args.Length == 2 && args[0].ToLower() == "overridemintime") + { + try + { + overridemintime = double.Parse(args[1]); + } + catch { } + } + else + if (args.Length == 2 && args[0].ToLower() == "overridemaxtime") + { + try + { + overridemaxtime = double.Parse(args[1]); + } + catch { } + } + else + // look for a spawn spec line + if (args.Length > 0 && args[0] == "*") + { + + bool badspawn = false; + int x = 0; + int y = 0; + int z = 0; + int map = 0; + double mindelay = 0; + double maxdelay = 0; + int homerange = 0; + int spawnrange = 0; + string[][] typenames = new string[6][]; + + int[] maxcount = new int[6]; + + // parse the main args + + try + { + // get the list of spawns + for (int k = 0; k < 6; k++) + { + typenames[k] = args[k + 1].Split(':'); + } + + x = int.Parse(args[7]); + y = int.Parse(args[8]); + z = int.Parse(args[9]); + map = int.Parse(args[10]); + mindelay = double.Parse(args[11]); + maxdelay = double.Parse(args[12]); + homerange = int.Parse(args[13]); + spawnrange = int.Parse(args[14]); + int spawnid = int.Parse(args[15]); + + for (int k = 0; k < 6; k++) + { + maxcount[k] = int.Parse(args[k + 16]); + } + } + catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + + // compute the total number of spawns + int totalspawns = 0; + int totalmaxcount = 0; + + for (int k = 0; k < 6; k++) + { + if (typenames[k] == null) + { + continue; + } + + for (int i = 0; i < typenames[k].Length; i++) + { + if (typenames[k][i] == null || typenames[k][i].Length == 0) + { + continue; + } + + totalspawns++; + } + + totalmaxcount += maxcount[k]; + } + + // apply min/maxdelay overrides + if (overridemintime != -1) + { + mindelay = overridemintime; + } + if (overridemaxtime != -1) + { + maxdelay = overridemaxtime; + } + if (mindelay > maxdelay) + { + maxdelay = mindelay; + } + + if (!badspawn && totalspawns > 0) + { + // everything seems ok so go ahead and make the spawner + // check for map override + if (overridemap >= 0) + { + map = overridemap; + } + + Map spawnmap = Map.Internal; + switch (map) + { + case 0: + { + spawnmap = Map.Felucca; + // note it also does trammel + break; + } + case 1: + { + spawnmap = Map.Felucca; + break; + } + case 2: + { + spawnmap = Map.Trammel; + break; + } + case 3: + { + spawnmap = Map.Ilshenar; + break; + } + case 4: + { + spawnmap = Map.Malas; + break; + } + case 5: + { + spawnmap = Map.Tokuno; + break; + } + } + + if (!IsValidMapLocation(x, y, spawnmap)) + { + // invalid so dont spawn it + badspawnercount++; + from.SendMessage("Invalid map/location at line {0}", linenumber); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + + // allow it to make an xmlspawner instead + // first add all of the creatures on the list + SpawnObject[] so = new SpawnObject[totalspawns]; + int count = 0; + bool hasvendor = true; + for (int k = 0; k < 6; k++) + { + if (typenames[k] == null) + { + continue; + } + + for (int i = 0; i < typenames[k].Length; i++) + { + if (typenames[k][i] == null || typenames[k][i].Length == 0 || count > totalspawns) + { + continue; + } + + so[count++] = new SpawnObject(typenames[k][i], maxcount[k]); + + // check the type to see if there are vendors on it + Type type = AssemblyHandler.FindTypeByName(typenames[k][i]); + + // check for vendor-only spawners which get special spawnrange treatment + if (type != null && type != typeof(BaseVendor) && !type.IsSubclassOf(typeof(BaseVendor))) + { + hasvendor = false; + } + + } + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + + // and give it a name based on the spawner count and file + string spawnername = string.Format("{0}#{1}", Path.GetFileNameWithoutExtension(filename), spawnercount); + + // Create the new xml spawner + XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount, + TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, + TimeSpan.FromHours(0), null, false, null); + + spawner.SpawnRange = hasvendor ? 0 : spawnrange; + + spawner.m_PlayerCreated = true; + + spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); + if (spawner.Map == Map.Internal) + { + badspawnercount++; + spawner.Delete(); + from.SendMessage("Invalid map at line {0}", linenumber); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + spawnercount++; + // handle the special case of map 0 that also needs to do trammel + if (map == 0) + { + spawnmap = Map.Trammel; + // assign it a unique id + SpawnId = Guid.NewGuid(); + // Create the new xml spawner + spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount, + TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, + TimeSpan.FromHours(0), null, false, null) + { + SpawnRange = spawnrange, + m_PlayerCreated = true + }; + + spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); + if (spawner.Map == Map.Internal) + { + badspawnercount++; + spawner.Delete(); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + spawnercount++; + } + } + else + { + badspawnercount++; + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + } + } + } + + private static void ParseOldMapFormat(Mobile from, string filename, string line, string[] args, int linenumber, ref int spawnercount, ref int badspawnercount, ref int overridemap, ref double overridemintime, ref double overridemaxtime) + { + // format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1 + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount + // or + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange spawnid maxcount + // ## are comments + // overridemap mapnumber + // map 0 is tram+fel + // map 1 is fel + // map 2 is tram + // map 3 is ilsh + // map 4 is mal + // map 5 is tokuno + // + // * | typename:typename:... | | | | | | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount | maxcount2 | maxcount2 | maxcount3 | maxcount4 | maxcount5 + // the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1 + + if (args == null || from == null) + { + return; + } + + // look for the override keyword + if (args.Length == 2 && args[0].ToLower() == "overridemap") + { + try + { + overridemap = int.Parse(args[1]); + } + catch { } + } + else + if (args.Length == 2 && args[0].ToLower() == "overridemintime") + { + try + { + overridemintime = double.Parse(args[1]); + } + catch { } + } + else + if (args.Length == 2 && args[0].ToLower() == "overridemaxtime") + { + try + { + overridemaxtime = double.Parse(args[1]); + } + catch { } + } + else + // look for a spawn spec line + if (args.Length > 0 && args[0] == "*") + { + bool badspawn = false; + int x = 0; + int y = 0; + int z = 0; + int map = 0; + double mindelay = 0; + double maxdelay = 0; + int homerange = 0; + int spawnrange = 0; + int maxcount = 0; + string[] typenames = null; + if (args.Length != 11 && args.Length != 12) + { + badspawn = true; + from.SendMessage("Invalid arg count {1} at line {0}", linenumber, args.Length); + } + else + { + // get the list of spawns + typenames = args[1].Split(':'); + // parse the rest of the args + + if (args.Length == 11) + { + + try + { + x = int.Parse(args[2]); + y = int.Parse(args[3]); + z = int.Parse(args[4]); + map = int.Parse(args[5]); + mindelay = double.Parse(args[6]); + maxdelay = double.Parse(args[7]); + homerange = int.Parse(args[8]); + spawnrange = int.Parse(args[9]); + maxcount = int.Parse(args[10]); + + } + catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + } + else + if (args.Length == 12) + { + + try + { + x = int.Parse(args[2]); + y = int.Parse(args[3]); + z = int.Parse(args[4]); + map = int.Parse(args[5]); + mindelay = double.Parse(args[6]); + maxdelay = double.Parse(args[7]); + homerange = int.Parse(args[8]); + spawnrange = int.Parse(args[9]); + int spawnid = int.Parse(args[10]); + maxcount = int.Parse(args[11]); + + } + catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + } + } + + + // apply mi/maxdelay overrides + if (overridemintime != -1) + { + mindelay = overridemintime; + } + if (overridemaxtime != -1) + { + maxdelay = overridemaxtime; + } + if (mindelay > maxdelay) + { + maxdelay = mindelay; + } + + if (!badspawn && typenames.Length > 0) + { + // everything seems ok so go ahead and make the spawner + // check for map override + if (overridemap >= 0) + { + map = overridemap; + } + + Map spawnmap = Map.Internal; + switch (map) + { + case 0: + { + spawnmap = Map.Felucca; + // note it also does trammel + break; + } + case 1: + { + spawnmap = Map.Felucca; + break; + } + case 2: + { + spawnmap = Map.Trammel; + break; + } + case 3: + { + spawnmap = Map.Ilshenar; + break; + } + case 4: + { + spawnmap = Map.Malas; + break; + } + case 5: + { + spawnmap = Map.Tokuno; + break; + } + } + + if (!IsValidMapLocation(x, y, spawnmap)) + { + // invalid so dont spawn it + badspawnercount++; + from.SendMessage("Invalid map/location at line {0}", linenumber); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + + // allow it to make an xmlspawner instead + // first add all of the creatures on the list + SpawnObject[] so = new SpawnObject[typenames.Length]; + + bool hasvendor = true; + for (int i = 0; i < typenames.Length; i++) + { + so[i] = new SpawnObject(typenames[i], maxcount); + + // check the type to see if there are vendors on it + Type type = AssemblyHandler.FindTypeByName(typenames[i]); + + // check for vendor-only spawners which get special spawnrange treatment + if (type != null && type != typeof(BaseVendor) && !type.IsSubclassOf(typeof(BaseVendor))) + { + hasvendor = false; + } + + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + + // and give it a name based on the spawner count and file + string spawnername = string.Format("{0}#{1}", Path.GetFileNameWithoutExtension(filename), spawnercount); + + // Create the new xml spawner + XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount, + TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, + TimeSpan.FromHours(0), null, false, null); + + spawner.SpawnRange = hasvendor ? 0 : spawnrange; + + spawner.m_PlayerCreated = true; + + spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); + if (spawner.Map == Map.Internal) + { + badspawnercount++; + spawner.Delete(); + from.SendMessage("Invalid map at line {0}", linenumber); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + spawnercount++; + // handle the special case of map 0 that also needs to do trammel + if (map == 0) + { + spawnmap = Map.Trammel; + // assign it a unique id + SpawnId = Guid.NewGuid(); + // Create the new xml spawner + spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount, + TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, + TimeSpan.FromHours(0), null, false, null) + { + SpawnRange = spawnrange, + m_PlayerCreated = true + }; + + spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); + if (spawner.Map == Map.Internal) + { + badspawnercount++; + spawner.Delete(); + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + return; + } + spawnercount++; + } + } + else + { + badspawnercount++; + from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + } + } + } + + [Usage("XmlImportSpawners filename")] + [Description("Loads xml files created by Sno's xml exporter as xmlspawners.")] + public static void XmlImportSpawners_OnCommand(CommandEventArgs e) + { + if (e.Arguments.Length >= 1) + { + string filename = e.GetString(0); + string filePath = Path.Combine("Saves/Spawners", filename); + if (File.Exists(filePath)) + { + XmlDocument doc = new XmlDocument(); + try + { + doc.Load(filePath); + } + catch + { + e.Mobile.SendMessage("unable to load file {0}.", filePath); + return; + } + + XmlElement root = doc["spawners"]; + int successes = 0, failures = 0; + if (root?.GetElementsByTagName("spawner") != null) + { + foreach (XmlElement spawner in root.GetElementsByTagName("spawner")) + { + try + { + ImportSpawner(spawner, e.Mobile); + successes++; + } + catch (Exception ex) { e.Mobile.SendMessage(33, "{0} {1}", ex.Message, spawner.InnerText); failures++; } + } + } + e.Mobile.SendMessage("{0} spawners loaded successfully from {1}, {2} failures.", successes, filePath, failures); + } + else + { + e.Mobile.SendMessage("File {0} does not exist.", filePath); + } + } + else + { + e.Mobile.SendMessage("Usage: [XmlImportSpawners "); + } + } + + private static string GetText(XmlElement node, string defaultValue) + { + if (node == null) + { + return defaultValue; + } + + return node.InnerText; + } + + private static void ImportSpawner(XmlElement node, Mobile from) + { + int count = int.Parse(GetText(node["count"], "1")); + int homeRange = int.Parse(GetText(node["homerange"], "4")); + int walkingRange = int.Parse(GetText(node["walkingrange"], "-1")); + // width of the spawning area + int spawnwidth = homeRange * 2; + if (walkingRange >= 0) + { + spawnwidth = walkingRange * 2; + } + + int team = int.Parse(GetText(node["team"], "0")); + bool group = bool.Parse(GetText(node["group"], "False")); + TimeSpan maxDelay = TimeSpan.Parse(GetText(node["maxdelay"], "10:00")); + TimeSpan minDelay = TimeSpan.Parse(GetText(node["mindelay"], "05:00")); + List creaturesName = LoadCreaturesName(node["creaturesname"]); + string name = GetText(node["name"], "Spawner"); + Point3D location = Point3D.Parse(GetText(node["location"], "Error")); + Map map = Map.Parse(GetText(node["map"], "Error")); + + // allow it to make an xmlspawner instead + // first add all of the creatures on the list + SpawnObject[] so = new SpawnObject[creaturesName.Count]; + + bool hasvendor = false; + + for (int i = 0; i < creaturesName.Count; i++) + { + so[i] = new SpawnObject(creaturesName[i], count); + // check the type to see if there are vendors on it + Type type = AssemblyHandler.FindTypeByName(creaturesName[i]); + + // if it has basevendors on it or invalid types, then skip it + if (type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor)))) + { + hasvendor = true; + } + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + + // Create the new xml spawner + XmlSpawner spawner = new XmlSpawner(SpawnId, location.X, location.Y, spawnwidth, spawnwidth, name, count, + minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); + + spawner.SpawnRange = hasvendor ? 0 : homeRange; + spawner.m_PlayerCreated = true; + + spawner.MoveToWorld(location, map); + if (!IsValidMapLocation(location, spawner.Map)) + { + spawner.Delete(); + throw new Exception("Invalid spawner location."); + } + } + + private static List LoadCreaturesName(XmlElement node) + { + List names = new List(); + + if (node != null) + { + foreach (XmlElement ele in node.GetElementsByTagName("creaturename")) + { + if (ele != null) + { + names.Add(ele.InnerText); + } + } + } + return names; + } + + [Usage("XmlImportMSF filename")] + [Description("Loads msf files created by Morxeton's megaspawner as xmlspawners.")] + public static void XmlImportMSF_OnCommand(CommandEventArgs e) + { + if (e.Arguments.Length >= 1) + { + /* + // I'm not sure what the default location for .msf files is + string filename = e.GetString(0); + string filePath = Path.Combine("Data/Megaspawner", filename); + */ + string filePath = e.GetString(0); + if (File.Exists(filePath)) + { + XmlDocument doc = new XmlDocument(); + doc.Load(filePath); + XmlElement root = doc["MegaSpawners"]; + if (root != null) + { + int successes = 0, failures = 0; + foreach (XmlElement spawner in root.GetElementsByTagName("MegaSpawner")) + { + + try + { + ImportMegaSpawner(e.Mobile, spawner); + successes++; + } + catch (Exception ex) { e.Mobile.SendMessage(33, "{0} {1}", ex.Message, spawner.InnerText); failures++; } + } + e.Mobile.SendMessage("{0} megaspawners loaded successfully from {1}, {2} failures.", successes, filePath, failures); + } + else + { + e.Mobile.SendMessage("Invalid .msf file. No MegaSpawners node found"); + } + } + else + { + e.Mobile.SendMessage("File {0} does not exist.", filePath); + } + } + else + { + e.Mobile.SendMessage("Usage: [XmlImportMSF "); + } + } + + private static void ImportMegaSpawner(Mobile from, XmlElement node) + { + string name = GetText(node["Name"], "MegaSpawner"); + bool running = bool.Parse(GetText(node["Active"], "True")); + Point3D location = Point3D.Parse(GetText(node["Location"], "Error")); + Map map = Map.Parse(GetText(node["Map"], "Error")); + + + int team = 0; + bool group = false; + int maxcount = 0; // default maxcount of the spawner + int homeRange = 4; // default homerange + int spawnRange = 4; // default homerange + TimeSpan maxDelay = TimeSpan.FromMinutes(10); + TimeSpan minDelay = TimeSpan.FromMinutes(5); + + XmlElement listnode = node["EntryLists"]; + + int nentries = 0; + SpawnObject[] so = null; + + + if (listnode != null) + { + // get the number of entries + if (listnode.HasAttributes) + { + XmlAttributeCollection attr = listnode.Attributes; + + nentries = int.Parse(attr.GetNamedItem("count").Value); + } + if (nentries > 0) + { + so = new SpawnObject[nentries]; + + int entrycount = 0; + bool diff = false; + foreach (XmlElement entrynode in listnode.GetElementsByTagName("EntryList")) + { + // go through each entry and add a spawn object for it + if (entrynode != null) + { + if (entrycount == 0) + { + // get the spawner defaults from the first entry + // dont handle the individually specified entry attributes + group = bool.Parse(GetText(entrynode["GroupSpawn"], "False")); + maxDelay = TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MaxDelay"], "10:00"))); + minDelay = TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MinDelay"], "05:00"))); + homeRange = int.Parse(GetText(entrynode["WalkRange"], "10")); + spawnRange = int.Parse(GetText(entrynode["SpawnRange"], "4")); + } + else + { + // just check for consistency with other entries and report discrepancies + if (group != bool.Parse(GetText(entrynode["GroupSpawn"], "False"))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual group entry difference: {0} vs {1}", + GetText(entrynode["GroupSpawn"], "False"), group); + + } + } + catch { } + } + if (minDelay != TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MinDelay"], "05:00")))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual mindelay entry difference: {0} vs {1}", + GetText(entrynode["MinDelay"], "05:00"), minDelay); + + } + } + catch { } + } + if (maxDelay != TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MaxDelay"], "10:00")))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual maxdelay entry difference: {0} vs {1}", + GetText(entrynode["MaxDelay"], "10:00"), maxDelay); + + } + } + catch { } + } + if (homeRange != int.Parse(GetText(entrynode["WalkRange"], "10"))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual homerange entry difference: {0} vs {1}", + GetText(entrynode["WalkRange"], "10"), homeRange); + + } + } + catch { } + } + if (spawnRange != int.Parse(GetText(entrynode["SpawnRange"], "4"))) + { + diff = true; + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("MSFimport : individual spawnrange entry difference: {0} vs {1}", + GetText(entrynode["SpawnRange"], "4"), spawnRange); + + } + } + catch { } + } + } + + // these apply to individual entries + int amount = int.Parse(GetText(entrynode["Amount"], "1")); + string entryname = GetText(entrynode["EntryType"], ""); + + // keep track of the maxcount for the spawner by adding the individual amounts + maxcount += amount; + + // add the creature entry + so[entrycount] = new SpawnObject(entryname, amount); + + entrycount++; + if (entrycount > nentries) + { + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("{0} MSFImport Error; inconsistent entry count {1} {2}", DateTime.UtcNow, location, map); + op.WriteLine(); + } + } + catch { } + from.SendMessage("Inconsistent entry count detected at {0} {1}.", location, map); + break; + } + + } + } + if (diff) + { + from.SendMessage("Individual entry setting detected at {0} {1}.", location, map); + // log it + try + { + using (StreamWriter op = new StreamWriter("badimport.log", true)) + { + op.WriteLine("{0} MSFImport: Individual entry setting differences listed above from spawner at {1} {2}", DateTime.UtcNow, location, map); + op.WriteLine(); + } + } + catch { } + } + } + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + // Create the new xml spawner + XmlSpawner spawner = new XmlSpawner(SpawnId, location.X, location.Y, 0, 0, name, maxcount, + minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, + team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), + TimeSpan.FromMinutes(0), null, null, null, null, null, + null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null) + { + SpawnRange = spawnRange, + m_PlayerCreated = true + }; + + // Try to find a valid Z height if required (Z == -999) + + if (location.Z == -999) + { + int NewZ = map.GetAverageZ(location.X, location.Y); + + if (map.CanFit(location.X, location.Y, NewZ, SpawnFitSize) == false) + { + for (int x = 1; x <= 39; x++) + { + if (map.CanFit(location.X, location.Y, NewZ + x, SpawnFitSize)) + { + NewZ += x; + break; + } + } + } + location.Z = NewZ; + } + + spawner.MoveToWorld(location, map); + + if (!IsValidMapLocation(location, spawner.Map)) + { + spawner.Delete(); + throw new Exception("Invalid spawner location."); + } + } + + + + public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + int total_processed_maps = 0; + int total_processed_spawners = 0; + + if (filename == null || filename.Length <= 0) + { + return; + } + + // Check if the file exists + if (File.Exists(filename)) + { + FileStream fs = null; + try + { + fs = File.Open(filename, FileMode.Open, FileAccess.Read); + } + catch { } + + if (fs == null) + { + if (from != null) + { + from.SendMessage("Unable to open {0} for loading", filename); + } + + return; + } + + // load the file + XmlLoadFromStream(fs, filename, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + + } + else if (Directory.Exists(filename)) + { + // if so then load all of the .xml files in the directory + string[] files = null; + try + { + files = Directory.GetFiles(filename, "*.xml"); + } + catch { } + if (files != null && files.Length > 0) + { + if (from != null) + { + from.SendMessage("Loading {0} .xml files from directory {1}", files.Length, filename); + } + + foreach (string file in files) + { + XmlLoadFromFile(file, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + // recursively search subdirectories for more .xml files + string[] dirs = null; + try + { + dirs = Directory.GetDirectories(filename); + } + catch { } + if (dirs != null && dirs.Length > 0) + { + foreach (string dir in dirs) + { + XmlLoadFromFile(dir, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + total_processed_maps += processedmaps; + total_processed_spawners += processedspawners; + } + } + if (from != null) + { + from.SendMessage("Loaded a total of {0} .xml files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + } + + processedmaps = total_processed_maps; + processedspawners = total_processed_spawners; + } + else + { + if (from != null) + { + from.SendMessage("{0} does not exist", filename); + } + } + + } + + public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Mobile from, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) + { + processedmaps = 0; + processedspawners = 0; + + if (from == null) + { + return; + } + + XmlLoadFromFile(filename, SpawnerPrefix, from, from.Location, from.Map, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + } + + public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) + { + XmlLoadFromFile(filename, SpawnerPrefix, null, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); + + } + + public static void XmlLoadFromFile(string filename, string SpawnerPrefix, bool loadnew, out int processedmaps, out int processedspawners) + { + XmlLoadFromFile(filename, SpawnerPrefix, null, Point3D.Zero, Map.Internal, false, 0, loadnew, out processedmaps, out processedspawners); + + } + + + public static void XmlLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) + { + XmlLoadFromStream(fs, filename, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners, false); + } + + public static void XmlLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners, bool verbose) + { + processedmaps = 0; + processedspawners = 0; + + if (fs == null) + { + return; + } + + // assign an id that will be used to distinguish the newly loaded spawners by appending it to their name + Guid newloadid = Guid.NewGuid(); + + int TotalCount = 0; + int TrammelCount = 0; + int FeluccaCount = 0; + int IlshenarCount = 0; + int MalasCount = 0; + int TokunoCount = 0; + int OtherCount = 0; + bool questionable_spawner = false; + bool bad_spawner = false; + int badcount = 0; + int questionablecount = 0; + + int failedobjectitemcount = 0; + int failedsetitemcount = 0; + int relativex = -1; + int relativey = -1; + int relativez = 0; + Map relativemap = null; + + if (from != null) + { + from.SendMessage($"Loading {"XmlSpawner"} objects{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} from file {filename}."); + } + + // Create the data set + DataSet ds = new DataSet(SpawnDataSetName); + + // Read in the file + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch + { + if (from != null) + { + from.SendMessage(33, "Error reading xml file {0}", filename); + } + + fileerror = true; + } + // close the file + fs.Close(); + if (fileerror) + { + return; + } + + // Check that at least a single table was loaded + if (ds.Tables.Count > 0) + { + // Add each spawn point to the current map + if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + { + foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) + { + // load in the spawner info. Certain fields are required and therefore cannot be ignored + // the exception handler for those will flag bad_spawner and the result will be logged + + // Each row makes up a single spawner + string SpawnName = "Spawner"; + try { SpawnName = (string)dr["Name"]; } + catch { questionable_spawner = true; } + + if (loadnew) + { + // append the new id to the name + SpawnName = string.Format("{0}-{1}", SpawnName, newloadid); + } + + // Check if there is any spawner name criteria specified on the load + if (string.IsNullOrEmpty(SpawnerPrefix) || SpawnName.StartsWith(SpawnerPrefix)) + { + // Try load the GUID (might not work so create a new GUID) + Guid SpawnId = Guid.NewGuid(); + if (!loadnew) + { + try { SpawnId = new Guid((string)dr["UniqueId"]); } + catch { } + } + else + { + // change the dataset guid to the newly created one when new loading + try + { + dr["UniqueId"] = SpawnId; + } + catch { Console.WriteLine("unable to set UniqueId"); } + } + + int SpawnCentreX = fromloc.X; + int SpawnCentreY = fromloc.Y; + int SpawnCentreZ = fromloc.Z; + + try { SpawnCentreX = int.Parse((string)dr["CentreX"]); } + catch { bad_spawner = true; } + try { SpawnCentreY = int.Parse((string)dr["CentreY"]); } + catch { bad_spawner = true; } + try { SpawnCentreZ = int.Parse((string)dr["CentreZ"]); } + catch { bad_spawner = true; } + + int SpawnX = SpawnCentreX; + int SpawnY = SpawnCentreY; + int SpawnWidth = 0; + int SpawnHeight = 0; + try { SpawnX = int.Parse((string)dr["X"]); } + catch { questionable_spawner = true; } + try { SpawnY = int.Parse((string)dr["Y"]); } + catch { questionable_spawner = true; } + try { SpawnWidth = int.Parse((string)dr["Width"]); } + catch { questionable_spawner = true; } + try { SpawnHeight = int.Parse((string)dr["Height"]); } + catch { questionable_spawner = true; } + + // Try load the InContainer (default to false) + bool InContainer = false; + int ContainerX = 0; + int ContainerY = 0; + int ContainerZ = 0; + try { InContainer = bool.Parse((string)dr["InContainer"]); } + catch { } + if (InContainer) + { + try { ContainerX = int.Parse((string)dr["ContainerX"]); } + catch { } + try { ContainerY = int.Parse((string)dr["ContainerY"]); } + catch { } + try { ContainerZ = int.Parse((string)dr["ContainerZ"]); } + catch { } + } + + // Get the map (default to the mobiles map) if the relative distance is too great, then use the defined map + + Map SpawnMap = frommap; + + string XmlMapName = frommap.Name; + + //if (!loadrelative && !loadnew) + { + // Try to get the "map" field, but in case it doesn't exist, catch and discard the exception + try { XmlMapName = (string)dr["Map"]; } + catch { questionable_spawner = true; } + + // Convert the xml map value to a real map object + if (string.Compare(XmlMapName, Map.Trammel.Name, true) == 0 || XmlMapName == "Trammel") + { + SpawnMap = Map.Trammel; + TrammelCount++; + } + else if (string.Compare(XmlMapName, Map.Felucca.Name, true) == 0 || XmlMapName == "Felucca") + { + SpawnMap = Map.Felucca; + FeluccaCount++; + } + else if (string.Compare(XmlMapName, Map.Ilshenar.Name, true) == 0 || XmlMapName == "Ilshenar") + { + SpawnMap = Map.Ilshenar; + IlshenarCount++; + } + else if (string.Compare(XmlMapName, Map.Malas.Name, true) == 0 || XmlMapName == "Malas") + { + SpawnMap = Map.Malas; + MalasCount++; + } + else if (string.Compare(XmlMapName, Map.Tokuno.Name, true) == 0 || XmlMapName == "Tokuno") + { + SpawnMap = Map.Tokuno; + TokunoCount++; + } + else + { + try + { + SpawnMap = Map.Parse(XmlMapName); + } + catch { } + OtherCount++; + } + } + + // test to see whether the distance between the relative center point and the spawner is too great. If so then dont do relative + if (relativex == -1 && relativey == -1) + { + // the first xml entry in the file will determine the origin + relativex = SpawnCentreX; + relativey = SpawnCentreY; + relativez = SpawnCentreZ; + + // and also the relative map to relocate from + relativemap = SpawnMap; + } + + int SpawnRelZ = 0; + int OrigZ = SpawnCentreZ; + if (loadrelative && Math.Abs(relativex - SpawnCentreX) <= maxrange && Math.Abs(relativey - SpawnCentreY) <= maxrange + && SpawnMap == relativemap) + { + // its within range so shift it + SpawnCentreX -= relativex - fromloc.X; + SpawnCentreY -= relativey - fromloc.Y; + SpawnX -= relativex - fromloc.X; + SpawnY -= relativey - fromloc.Y; + // force it to autosearch for Z when it places it but hold onto relative Z info just in case it can be placed there + SpawnRelZ = relativez - fromloc.Z; + SpawnCentreZ = short.MinValue; + } + + // if relative loading has been specified, see if the loaded map is the same as the relativemap and relocate. + // if it doesnt match then just leave it + if (loadrelative && relativemap == SpawnMap) + { + SpawnMap = frommap; + } + + + if (SpawnMap == Map.Internal) + { + bad_spawner = true; + } + + // Try load the IsRelativeHomeRange (default to true) + bool SpawnIsRelativeHomeRange = true; + try { SpawnIsRelativeHomeRange = bool.Parse((string)dr["IsHomeRangeRelative"]); } + catch { } + + + int SpawnHomeRange = 5; + try { SpawnHomeRange = int.Parse((string)dr["Range"]); } + catch { questionable_spawner = true; } + int SpawnMaxCount = 1; + try { SpawnMaxCount = int.Parse((string)dr["MaxCount"]); } + catch { questionable_spawner = true; } + + //deal with double format for delay. default is the old minute format + bool delay_in_sec = false; + try { delay_in_sec = bool.Parse((string)dr["DelayInSec"]); } + catch { } + TimeSpan SpawnMinDelay = TimeSpan.FromMinutes(5); + TimeSpan SpawnMaxDelay = TimeSpan.FromMinutes(10); + + + if (delay_in_sec) + { + try { SpawnMinDelay = TimeSpan.FromSeconds(int.Parse((string)dr["MinDelay"])); } + catch { } + try { SpawnMaxDelay = TimeSpan.FromSeconds(int.Parse((string)dr["MaxDelay"])); } + catch { } + } + else + { + try { SpawnMinDelay = TimeSpan.FromMinutes(int.Parse((string)dr["MinDelay"])); } + catch { } + try { SpawnMaxDelay = TimeSpan.FromMinutes(int.Parse((string)dr["MaxDelay"])); } + catch { } + } + TimeSpan SpawnMinRefractory = TimeSpan.FromMinutes(0); + try { SpawnMinRefractory = TimeSpan.FromMinutes(double.Parse((string)dr["MinRefractory"])); } + catch { } + + TimeSpan SpawnMaxRefractory = TimeSpan.FromMinutes(0); + try { SpawnMaxRefractory = TimeSpan.FromMinutes(double.Parse((string)dr["MaxRefractory"])); } + catch { } + + TimeSpan SpawnTODStart = TimeSpan.FromMinutes(0); + try { SpawnTODStart = TimeSpan.FromMinutes(double.Parse((string)dr["TODStart"])); } + catch { } + + TimeSpan SpawnTODEnd = TimeSpan.FromMinutes(0); + try { SpawnTODEnd = TimeSpan.FromMinutes(double.Parse((string)dr["TODEnd"])); } + catch { } + + int todmode = (int)TODModeType.Realtime; + TODModeType SpawnTODMode = TODModeType.Realtime; + try { todmode = int.Parse((string)dr["TODMode"]); } + catch { } + switch (todmode) + { + case (int)TODModeType.Gametime: + { + SpawnTODMode = TODModeType.Gametime; + break; + } + case (int)TODModeType.Realtime: + { + SpawnTODMode = TODModeType.Realtime; + break; + } + } + + int SpawnKillReset = defKillReset; + try { SpawnKillReset = int.Parse((string)dr["KillReset"]); } + catch { } + + string SpawnProximityMessage = null; + // proximity message + try { SpawnProximityMessage = (string)dr["ProximityTriggerMessage"]; } + catch { } + + string SpawnItemTriggerName = null; + try { SpawnItemTriggerName = (string)dr["ItemTriggerName"]; } + catch { } + + string SpawnNoItemTriggerName = null; + try { SpawnNoItemTriggerName = (string)dr["NoItemTriggerName"]; } + catch { } + + string SpawnSpeechTrigger = null; + try { SpawnSpeechTrigger = (string)dr["SpeechTrigger"]; } + catch { } + + string SpawnSkillTrigger = null; + try { SpawnSkillTrigger = (string)dr["SkillTrigger"]; } + catch { } + + string SpawnMobTriggerName = null; + try { SpawnMobTriggerName = (string)dr["MobTriggerName"]; } + catch { } + string SpawnMobPropertyName = null; + try { SpawnMobPropertyName = (string)dr["MobPropertyName"]; } + catch { } + string SpawnPlayerPropertyName = null; + try { SpawnPlayerPropertyName = (string)dr["PlayerPropertyName"]; } + catch { } + + double SpawnTriggerProbability = 1; + try { SpawnTriggerProbability = double.Parse((string)dr["TriggerProbability"]); } + catch { } + + int SpawnSequentialSpawning = -1; + try { SpawnSequentialSpawning = int.Parse((string)dr["SequentialSpawning"]); } + catch { } + + string SpawnRegionName = null; + try { SpawnRegionName = (string)dr["RegionName"]; } + catch { } + + string SpawnConfigFile = null; + try { SpawnConfigFile = (string)dr["ConfigFile"]; } + catch { } + + bool SpawnAllowGhost = false; + try { SpawnAllowGhost = bool.Parse((string)dr["AllowGhostTriggering"]); } + catch { } + + bool SpawnAllowNPC = false; + try { SpawnAllowNPC = bool.Parse((string)dr["AllowNPCTriggering"]); } + catch { } + + bool SpawnSpawnOnTrigger = false; + try { SpawnSpawnOnTrigger = bool.Parse((string)dr["SpawnOnTrigger"]); } + catch { } + + bool SpawnSmartSpawning = false; + try { SpawnSmartSpawning = bool.Parse((string)dr["SmartSpawning"]); } + catch { } + + bool TickReset = false; + try { TickReset = bool.Parse((string)dr["TickReset"]); } + catch { } + + string SpawnObjectPropertyName = null; + try { SpawnObjectPropertyName = (string)dr["ObjectPropertyName"]; } + catch { } + + // we will assign this during the self-reference resolution pass + Item SpawnSetPropertyItem = null; + + // we will assign this during the self-reference resolution pass + Item SpawnObjectPropertyItem = null; + + // read the duration parameter from the xml file + // but older files wont have it so deal with that condition and set it to the default of "0", i.e. infinite duration + // Try to get the "Duration" field, but in case it doesn't exist, catch and discard the exception + TimeSpan SpawnDuration = TimeSpan.FromMinutes(0); + try { SpawnDuration = TimeSpan.FromMinutes(double.Parse((string)dr["Duration"])); } + catch { } + + TimeSpan SpawnDespawnTime = TimeSpan.FromHours(0); + try { SpawnDespawnTime = TimeSpan.FromHours(double.Parse((string)dr["DespawnTime"])); } + catch { } + int SpawnProximityRange = -1; + // Try to get the "ProximityRange" field, but in case it doesn't exist, catch and discard the exception + try { SpawnProximityRange = int.Parse((string)dr["ProximityRange"]); } + catch { } + + int SpawnProximityTriggerSound = 0; + // Try to get the "ProximityTriggerSound" field, but in case it doesn't exist, catch and discard the exception + try { SpawnProximityTriggerSound = int.Parse((string)dr["ProximityTriggerSound"]); } + catch { } + + int SpawnAmount = 1; + try { SpawnAmount = int.Parse((string)dr["Amount"]); } + catch { } + + bool SpawnExternalTriggering = false; + try { SpawnExternalTriggering = bool.Parse((string)dr["ExternalTriggering"]); } + catch { } + + string waypointstr = null; + try { waypointstr = (string)dr["Waypoint"]; } + catch { } + + WayPoint SpawnWaypoint = GetWaypoint(waypointstr); + + int SpawnTeam = 0; + try { SpawnTeam = int.Parse((string)dr["Team"]); } + catch { questionable_spawner = true; } + bool SpawnIsGroup = false; + try { SpawnIsGroup = bool.Parse((string)dr["IsGroup"]); } + catch { questionable_spawner = true; } + bool SpawnIsRunning = false; + try { SpawnIsRunning = bool.Parse((string)dr["IsRunning"]); } + catch { questionable_spawner = true; } + // try loading the new spawn specifications first + SpawnObject[] Spawns = new SpawnObject[0]; + bool havenew = true; + try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); } + catch { havenew = false; } + if (!havenew) + { + // try loading the new spawn specifications + try { Spawns = SpawnObject.LoadSpawnObjectsFromString((string)dr["Objects"]); } + catch { questionable_spawner = true; } + // can only have one of these defined + } + + // do a check on the location of the spawner + if (!IsValidMapLocation(SpawnCentreX, SpawnCentreY, SpawnMap)) + { + if (from != null) + { + from.SendMessage(33, "Invalid location '{0}' at [{1} {2}] in {3}", + SpawnName, SpawnCentreX, SpawnCentreY, XmlMapName); + } + + bad_spawner = true; + } + + // Check if this spawner already exists + XmlSpawner OldSpawner = null; + bool found_container = false; + bool found_spawner = false; + Container spawn_container = null; + if (!bad_spawner) + { + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner checkXmlSpawner) + { + // Check if the spawners GUID is the same as the one being loaded + // and that the spawners map is the same as the one being loaded + if (checkXmlSpawner.UniqueId == SpawnId.ToString() + /* && (CheckXmlSpawner.Map == SpawnMap || loadrelative)*/) + { + OldSpawner = checkXmlSpawner; + found_spawner = true; + } + } + + //look for containers with the spawn coordinates if the incontainer flag is set + if (InContainer && !found_container && i is Container container && SpawnCentreX == container.Location.X && SpawnCentreY == container.Location.Y && + (SpawnCentreZ == container.Location.Z || SpawnCentreZ == short.MinValue)) + { + // assume this is the container that the spawner was in + found_container = true; + spawn_container = container; + } + // ok we can break if we have handled both the spawner and any containers + if (found_spawner && (found_container || !InContainer)) + { + break; + } + } + } + + // test to see whether the spawner specification was valid, bad, or questionable + if (bad_spawner) + { + badcount++; + if (from != null) + { + from.SendMessage(33, "Invalid spawner"); + } + + // log it + long fileposition = -1; + try { fileposition = fs.Position; } + catch { } + try + { + using (StreamWriter op = new StreamWriter("badxml.log", true)) + { + op.WriteLine("# Invalid spawner : {0}: Fileposition {1} {2}", DateTime.UtcNow, fileposition, filename); + op.WriteLine(); + } + } + catch { } + } + else + if (questionable_spawner) + { + questionablecount++; + if (from != null) + { + from.SendMessage(33, "Questionable spawner '{0}' at [{1} {2}] in {3}", + SpawnName, SpawnCentreX, SpawnCentreY, XmlMapName); + } + + // log it + long fileposition = -1; + try { fileposition = fs.Position; } + catch { } + try + { + using (StreamWriter op = new StreamWriter("badxml.log", true)) + { + op.WriteLine("# Questionable spawner : {0}: Format: X Y Z Map SpawnerName Fileposition Xmlfile", DateTime.UtcNow); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", SpawnCentreX, SpawnCentreY, SpawnCentreZ, XmlMapName, SpawnName, fileposition, filename); + op.WriteLine(); + } + } + catch { } + } + if (!bad_spawner) + { + // Delete the old spawner if it exists + if (OldSpawner != null) + { + OldSpawner.Delete(); + } + + // Create the new spawner + XmlSpawner TheSpawn = new XmlSpawner(SpawnId, SpawnX, SpawnY, SpawnWidth, SpawnHeight, SpawnName, SpawnMaxCount, + SpawnMinDelay, SpawnMaxDelay, SpawnDuration, SpawnProximityRange, SpawnProximityTriggerSound, SpawnAmount, + SpawnTeam, SpawnHomeRange, SpawnIsRelativeHomeRange, Spawns, SpawnMinRefractory, SpawnMaxRefractory, SpawnTODStart, + SpawnTODEnd, SpawnObjectPropertyItem, SpawnObjectPropertyName, SpawnProximityMessage, SpawnItemTriggerName, SpawnNoItemTriggerName, + SpawnSpeechTrigger, SpawnMobTriggerName, SpawnMobPropertyName, SpawnPlayerPropertyName, SpawnTriggerProbability, + SpawnSetPropertyItem, SpawnIsGroup, SpawnTODMode, SpawnKillReset, SpawnExternalTriggering, SpawnSequentialSpawning, + SpawnRegionName, SpawnAllowGhost, SpawnAllowNPC, SpawnSpawnOnTrigger, SpawnConfigFile, SpawnDespawnTime, SpawnSkillTrigger, SpawnSmartSpawning, SpawnWaypoint) + { + m_DisableGlobalAutoReset = TickReset + }; + + // Try to find a valid Z height if required (SpawnCentreZ = short.MinValue) + int NewZ = 0; + + // Check if relative loading is set. If so then try loading at the z-offset position first with no surface requirement, then try auto + /*if (loadrelative && SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, OrigZ - SpawnRelZ, SpawnFitSize,true, false,false)) */ + + if (loadrelative && HasTileSurface(SpawnMap, SpawnCentreX, SpawnCentreY, OrigZ - SpawnRelZ)) + { + NewZ = OrigZ - SpawnRelZ; + } + else if (SpawnCentreZ == short.MinValue) + { + NewZ = SpawnMap.GetAverageZ(SpawnCentreX, SpawnCentreY); + + if (SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, NewZ, SpawnFitSize) == false) + { + for (int x = 1; x <= 39; x++) + { + if (SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, NewZ + x, SpawnFitSize)) + { + NewZ += x; + break; + } + } + } + } + else + { + // This spawn point already has a defined Z location, so use it + NewZ = SpawnCentreZ; + } + + // if this is a container held spawner, drop it in the container + if (found_container && spawn_container != null && !spawn_container.Deleted) + { + TheSpawn.Location = new Point3D(ContainerX, ContainerY, ContainerZ); + spawn_container.AddItem(TheSpawn); + } + else + { + // disable the X_Y adjustments in OnLocationChange + IgnoreLocationChange = true; + TheSpawn.MoveToWorld(new Point3D(SpawnCentreX, SpawnCentreY, NewZ), SpawnMap); + } + + // reset the spawner + TheSpawn.Reset(); + TheSpawn.Running = SpawnIsRunning; + + // update subgroup-specific next spawn times + TheSpawn.NextSpawn = TimeSpan.Zero; + TheSpawn.ResetNextSpawnTimes(); + + + // Send a message to the client that the spawner is created + if (from != null && verbose) + { + from.SendMessage(188, "Created '{0}' in {1} at {2}", TheSpawn.Name, TheSpawn.Map.Name, TheSpawn.Location.ToString()); + } + + // Do a total respawn + //TheSpawn.Respawn(); + + // Increment the count + TotalCount++; + } + bad_spawner = false; + questionable_spawner = false; + } + } + } + + if (from != null) + { + from.SendMessage("Resolving spawner self references"); + } + + if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + { + foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) + { + // Try load the GUID + bool badid = false; + Guid SpawnId = Guid.NewGuid(); + try { SpawnId = new Guid((string)dr["UniqueId"]); } + catch { badid = true; } + if (badid) + { + continue; + } + + // Get the map + Map SpawnMap = frommap; + string XmlMapName = frommap.Name; + + if (!loadrelative) + { + try { XmlMapName = (string)dr["Map"]; } + catch { } + + // Convert the xml map value to a real map object + try + { + SpawnMap = Map.Parse(XmlMapName); + } + catch { } + } + + bool found_spawner = false; + XmlSpawner OldSpawner = null; + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner checkXmlSpawner) + { + // Check if the spawners GUID is the same as the one being loaded + // and that the spawners map is the same as the one being loaded + if (checkXmlSpawner.UniqueId == SpawnId.ToString() + /* && (CheckXmlSpawner.Map == SpawnMap || loadrelative) */) + { + OldSpawner = checkXmlSpawner; + found_spawner = true; + } + } + + if (found_spawner) + { + break; + } + } + + if (found_spawner && OldSpawner != null && !OldSpawner.Deleted) + { + // resolve item name references since they may have referred to spawners that were just created + string setObjectName = null; + try { setObjectName = (string)dr["SetPropertyItemName"]; } + catch { } + if (!string.IsNullOrEmpty(setObjectName)) + { + // try to parse out the type information if it has also been saved + string[] typeargs = setObjectName.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = setObjectName; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + + // if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid + if (loadnew) + { + string tmpsetObjectName = string.Format("{0}-{1}", namestr, newloadid); + OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, tmpsetObjectName, typestr); + } + // if this fails then try the original + if (OldSpawner.m_SetPropertyItem == null) + { + OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, namestr, typestr); + } + if (OldSpawner.m_SetPropertyItem == null) + { + failedsetitemcount++; + if (from != null) + { + from.SendMessage(33, "Failed to initialize SetItemProperty Object '{0}' on ' '{1}' at [{2} {3}] in {4}", + setObjectName, OldSpawner.Name, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Map); + } + + // log it + try + { + using (StreamWriter op = new StreamWriter("badxml.log", true)) + { + op.WriteLine("# Failed SetItemProperty Object initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", + DateTime.UtcNow); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", + setObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); + op.WriteLine(); + } + } + catch { } + } + } + + string triggerObjectName = null; + try { triggerObjectName = (string)dr["ObjectPropertyItemName"]; } + catch { } + + if (!string.IsNullOrEmpty(triggerObjectName)) + { + string[] typeargs = triggerObjectName.Split(",".ToCharArray(), 2); + string typestr = null; + string namestr = triggerObjectName; + + if (typeargs.Length > 1) + { + namestr = typeargs[0]; + typestr = typeargs[1]; + } + + // if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid + if (loadnew) + { + string tmptriggerObjectName = string.Format("{0}-{1}", namestr, newloadid); + OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, tmptriggerObjectName, typestr); + } + // if this fails then try the original + if (OldSpawner.m_ObjectPropertyItem == null) + { + OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, namestr, typestr); + } + if (OldSpawner.m_ObjectPropertyItem == null) + { + failedobjectitemcount++; + if (from != null) + { + from.SendMessage(33, "Failed to initialize TriggerObject '{0}' on ' '{1}' at [{2} {3}] in {4}", + triggerObjectName, OldSpawner.Name, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Map); + } + + // log it + try + { + using (StreamWriter op = new StreamWriter("badxml.log", true)) + { + op.WriteLine("# Failed TriggerObject initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", + DateTime.UtcNow); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", + triggerObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); + op.WriteLine(); + } + } + catch { } + } + } + } + } + } + } + + // close the file + try + { + fs.Close(); + } + catch { } + + if (from != null) + { + from.SendMessage("{0} spawner(s) were created from file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6} Other={7}].", + TotalCount, filename, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount); + } + + if (failedobjectitemcount > 0) + { + if (from != null) + { + from.SendMessage(33, "Failed to initialize TriggerObjects in {0} spawners. Saved to 'badxml.log'", failedobjectitemcount); + } + } + if (failedsetitemcount > 0) + { + if (from != null) + { + from.SendMessage(33, "Failed to initialize SetItemProperty Objects in {0} spawners. Saved to 'badxml.log'", failedsetitemcount); + } + } + if (badcount > 0) + { + if (from != null) + { + from.SendMessage(33, "{0} bad spawners detected. Saved to 'badxml.log'", badcount); + } + } + if (questionablecount > 0) + { + if (from != null) + { + from.SendMessage(33, "{0} questionable spawners detected. Saved to 'badxml.log'", questionablecount); + } + } + processedmaps = 1; + processedspawners = TotalCount; + + } + + public static string LocateFile(string filename) + { + bool found = false; + + string dirname = null; + + if (Directory.Exists(XmlSpawnDir)) + { + // get it from the defaults directory if it exists + dirname = string.Format("{0}/{1}", XmlSpawnDir, filename); + found = File.Exists(dirname) || Directory.Exists(dirname); + } + + if (!found) + { + // otherwise just get it from the main installation dir + dirname = filename; + } + + return dirname; + } + + [Usage("XmlNewLoad [SpawnerPrefixFilter]")] + [Description("Loads new XmlSpawner objects with new GUIDs (no replacement) into the current map of the player.")] + public static void NewLoad_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = LocateFile(e.Arguments[0]); + + // Spawner load criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (load criteria) + if (e.Arguments.Length > 1) + { + SpawnerPrefix = e.Arguments[1]; + } + + int processedmaps; + int processedspawners; + + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, false, 0, true, out processedmaps, out processedspawners); + } + else + { + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + } + } + else + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + } + + [Usage("XmlLoad [SpawnerPrefixFilter]")] + [Description("Loads XmlSpawner objects (replacing existing spawners with matching GUIDs) into the proper map as defined in the file supplied.")] + public static void Load_OnCommand(CommandEventArgs e) + { + var m = e.Mobile; + + if (m == null || m.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = LocateFile(e.Arguments[0]); + + // Spawner load criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (load criteria) + if (e.Arguments.Length > 1) + { + SpawnerPrefix = e.Arguments[1]; + } + + int processedmaps; + int processedspawners; + + XmlLoadFromFile(filename, SpawnerPrefix, m, false, 0, false, out processedmaps, out processedspawners); + } + else if (m != null) + { + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + } + } + else + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + } + + [Usage("XmlNewLoadHere [SpawnerPrefixFilter][-maxrange range]")] + [Description("Loads new XmlSpawner objects with new GUIDs (no replacement) to the current map and location of the player. Spawners beyond maxrange (default=48 tiles) are not moved relative to the player")] + public static void NewLoadHere_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = LocateFile(e.Arguments[0]); + + // Spawner load criteria (if any) + string SpawnerPrefix = string.Empty; + bool badargs = false; + int maxrange = 48; + + // Check if there is an argument provided (load criteria) + try + { + // Check if there is an argument provided (load criteria) + for (int nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++) + { + // is it a maxrange option? + if (e.Arguments[nxtarg].ToLower() == "-maxrange") + { + maxrange = int.Parse(e.Arguments[++nxtarg]); + } + else + { + SpawnerPrefix = e.Arguments[nxtarg]; + } + } + } + catch { e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); badargs = true; } + + if (!badargs) + { + int processedmaps; + int processedspawners; + + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, true, out processedmaps, out processedspawners); + } + } + else + { + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); + } + } + else + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + } + + [Usage("XmlLoadHere [SpawnerPrefixFilter][-maxrange range]")] + [Description("Loads XmlSpawner objects to the current map and location of the player. Spawners beyond maxrange (default=48 tiles) are not moved relative to the player")] + public static void LoadHere_OnCommand(CommandEventArgs e) + { + if (e.Mobile.AccessLevel >= DiskAccessLevel) + { + if (e.Arguments.Length >= 1) + { + string filename = LocateFile(e.Arguments[0]); + + // Spawner load criteria (if any) + string SpawnerPrefix = string.Empty; + bool badargs = false; + int maxrange = 48; + + try + { + // Check if there is an argument provided (load criteria) + for (int nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++) + { + // is it a maxrange option? + if (e.Arguments[nxtarg].ToLower() == "-maxrange") + { + maxrange = int.Parse(e.Arguments[++nxtarg]); + } + else + { + SpawnerPrefix = e.Arguments[nxtarg]; + } + } + } + catch { e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); badargs = true; } + + if (!badargs) + { + int processedmaps; + int processedspawners; + + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, false, out processedmaps, out processedspawners); + } + } + else + { + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); + } + } + else + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + } + + [Usage("XmlSaveOld [SpawnerPrefixFilter]")] + [Description("Saves all XmlSpawner objects from the current map into the file supplied in the old xmlspawner format.")] + public static void SaveOld_OnCommand(CommandEventArgs e) + { + SaveSpawns(e, false, true); + } + + [Usage("XmlSpawnerSave [SpawnerPrefixFilter]")] + [Description("Saves all XmlSpawner objects from the current map into the file supplied.")] + public static void Save_OnCommand(CommandEventArgs e) + { + SaveSpawns(e, false, false); + } + + [Usage("XmlSpawnerSaveAll [SpawnerPrefixFilter]")] + [Description("Saves ALL XmlSpawner objects from the entire world into the file supplied.")] + public static void SaveAll_OnCommand(CommandEventArgs e) + { + SaveSpawns(e, true, false); + } + + public class XmlSaveSingle : BaseCommand + { + public XmlSaveSingle() + { + AccessLevel = DiskAccessLevel; + Supports = CommandSupport.Single; + Commands = new[] { "XmlSaveSingle" }; + ObjectTypes = ObjectTypes.Items; + Usage = "XmlSaveSingle "; + Description = "Saves single xmlspawner to specified file."; + } + + public override void Execute(CommandEventArgs e, object obj) + { + if (e == null || e.Mobile == null || e.Arguments == null) + { + return; + } + + if (e.Arguments.Length < 1) + { + e.Mobile.SendMessage("Usage: {0} (without spaces!!)", e.Command); + return; + } + + string filename = e.Arguments[0]; + + XmlSpawner xmlspawner = obj as XmlSpawner; + + if (xmlspawner == null) + { + e.Mobile.SendMessage("You can select only XmlSpawner objects!"); + return; + } + + Mobile m = e.Mobile; + + CommandLogging.WriteLine(m, "{0} {1} Saving XmlSpawner {2} on file {3}", m.AccessLevel, CommandLogging.Format(m), CommandLogging.Format(xmlspawner), CommandLogging.Format(filename)); + SaveSpawns(m, xmlspawner, filename); + } + } + + private static void SaveSpawns(Mobile m, XmlSpawner xmlspawner, string filename) + { + if (m.AccessLevel < DiskAccessLevel) + { + m.SendMessage("You do not have rights to perform this command."); + return; + } + + string dirname; + + if (Directory.Exists(XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = string.Format("{0}/{1}", XmlSpawnDir, filename); + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + m.SendMessage("Saving object in folder {0} - file {1} - spawner {2}.", dirname, filename, xmlspawner); + + List saveslist = new List(1); + saveslist.Add(xmlspawner); + SaveSpawnList(m, saveslist, dirname, false, true); + } + + private static void SaveSpawns(CommandEventArgs e, bool SaveAllMaps, bool oldformat) + { + if (e == null || e.Mobile == null || e.Arguments == null || e.Arguments.Length < 1) + { + return; + } + + if (e.Mobile.AccessLevel < DiskAccessLevel) + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + return; + } + + if (e.Arguments != null && e.Arguments.Length < 1) + { + e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + return; + } + + // Spawner save criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (save criteria) + if (e.Arguments.Length > 1) + { + SpawnerPrefix = e.Arguments[1]; + } + + string filename = e.Arguments[0]; + + string dirname; + if (Directory.Exists(XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = string.Format("{0}/{1}", XmlSpawnDir, filename); + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + if (SaveAllMaps) + { + e.Mobile.SendMessage(string.Format("Saving {0} objects{1} to file {2} from {3}.", "XmlSpawner", + !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty, dirname, e.Mobile.Map)); + } + else + { + e.Mobile.SendMessage(string.Format("Saving {0} obejcts{1} to file {2} from the entire world.", "XmlSpawner", + !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty, dirname)); + } + + + List saveslist = new List(); + + // Add each spawn point to the list + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner spawner && !spawner.Deleted && (SaveAllMaps || spawner.Map == e.Mobile.Map) + //check for mob carried spawners and ignore them + && !(spawner.RootParent is Mobile) + && (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || spawner.Name != null && spawner.Name.StartsWith(SpawnerPrefix))) + { + saveslist.Add(spawner); + } + } + + // save the list + SaveSpawnList(e.Mobile, saveslist, dirname, oldformat, true); + } + + public static bool SaveSpawnList(List savelist, Stream stream) => SaveSpawnList(null, savelist, null, stream, false, false); + + public static bool SaveSpawnList(Mobile from, List savelist, string dirname, bool oldformat, bool verbose) + { + if (string.IsNullOrEmpty(dirname)) + { + return false; + } + + + bool save_ok = true; + FileStream fs = null; + + try + { + // Create the FileStream to write with. + fs = new FileStream(dirname, FileMode.Create); + } + catch + { + if (from != null) + { + from.SendMessage("Error creating file {0}", dirname); + } + + save_ok = false; + } + + // so far so good + if (save_ok) + { + save_ok = SaveSpawnList(from, savelist, dirname, fs, oldformat, verbose); + } + + if (!save_ok && from != null) + { + from.SendMessage("Unable to complete save operation."); + } + + return save_ok; + } + + + public static bool SaveSpawnList(Mobile from, List savelist, string dirname, Stream stream, bool oldformat, bool verbose) + { + if (savelist == null || stream == null) + { + return false; + } + + int TotalCount = 0; + int TrammelCount = 0; + int FeluccaCount = 0; + int IlshenarCount = 0; + int MalasCount = 0; + int TokunoCount = 0; + int OtherCount = 0; + + + // Create the data set + DataSet ds = new DataSet(SpawnDataSetName); + + // Load the data set up + ds.Tables.Add(SpawnTablePointName); + + // Create spawn point schema + ds.Tables[SpawnTablePointName].Columns.Add("Name"); + ds.Tables[SpawnTablePointName].Columns.Add("UniqueId"); + ds.Tables[SpawnTablePointName].Columns.Add("Map"); + ds.Tables[SpawnTablePointName].Columns.Add("X"); + ds.Tables[SpawnTablePointName].Columns.Add("Y"); + ds.Tables[SpawnTablePointName].Columns.Add("Width"); + ds.Tables[SpawnTablePointName].Columns.Add("Height"); + ds.Tables[SpawnTablePointName].Columns.Add("CentreX"); + ds.Tables[SpawnTablePointName].Columns.Add("CentreY"); + ds.Tables[SpawnTablePointName].Columns.Add("CentreZ"); + ds.Tables[SpawnTablePointName].Columns.Add("Range"); + ds.Tables[SpawnTablePointName].Columns.Add("MaxCount"); + ds.Tables[SpawnTablePointName].Columns.Add("MinDelay"); + ds.Tables[SpawnTablePointName].Columns.Add("MaxDelay"); + // deal with the double format for delay. old format stored them as minutes in int format. that meant that short delays were lost + // proper solution would simply be to store as doubles, but older progs still assume int format (like spawneditor) + // so this is the solution. add a flag and do it both ways. + ds.Tables[SpawnTablePointName].Columns.Add("DelayInSec"); + + // add the duration and proximity range and sound parameters, and in container flag and coords inside the container + ds.Tables[SpawnTablePointName].Columns.Add("Duration"); + ds.Tables[SpawnTablePointName].Columns.Add("DespawnTime"); + ds.Tables[SpawnTablePointName].Columns.Add("ProximityRange"); + ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerSound"); + ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerMessage"); + ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyName"); + ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyItemName"); + ds.Tables[SpawnTablePointName].Columns.Add("SetPropertyItemName"); + ds.Tables[SpawnTablePointName].Columns.Add("ItemTriggerName"); + ds.Tables[SpawnTablePointName].Columns.Add("NoItemTriggerName"); + ds.Tables[SpawnTablePointName].Columns.Add("MobTriggerName"); + ds.Tables[SpawnTablePointName].Columns.Add("MobPropertyName"); + ds.Tables[SpawnTablePointName].Columns.Add("PlayerPropertyName"); + ds.Tables[SpawnTablePointName].Columns.Add("TriggerProbability"); + ds.Tables[SpawnTablePointName].Columns.Add("SpeechTrigger"); + ds.Tables[SpawnTablePointName].Columns.Add("SkillTrigger"); + ds.Tables[SpawnTablePointName].Columns.Add("InContainer"); + ds.Tables[SpawnTablePointName].Columns.Add("ContainerX"); + ds.Tables[SpawnTablePointName].Columns.Add("ContainerY"); + ds.Tables[SpawnTablePointName].Columns.Add("ContainerZ"); + ds.Tables[SpawnTablePointName].Columns.Add("MinRefractory"); + ds.Tables[SpawnTablePointName].Columns.Add("MaxRefractory"); + ds.Tables[SpawnTablePointName].Columns.Add("TODStart"); + ds.Tables[SpawnTablePointName].Columns.Add("TODEnd"); + ds.Tables[SpawnTablePointName].Columns.Add("TODMode"); + ds.Tables[SpawnTablePointName].Columns.Add("KillReset"); + ds.Tables[SpawnTablePointName].Columns.Add("ExternalTriggering"); + ds.Tables[SpawnTablePointName].Columns.Add("SequentialSpawning"); + ds.Tables[SpawnTablePointName].Columns.Add("RegionName"); + ds.Tables[SpawnTablePointName].Columns.Add("AllowGhostTriggering"); + ds.Tables[SpawnTablePointName].Columns.Add("AllowNPCTriggering"); + ds.Tables[SpawnTablePointName].Columns.Add("SpawnOnTrigger"); + ds.Tables[SpawnTablePointName].Columns.Add("ConfigFile"); + ds.Tables[SpawnTablePointName].Columns.Add("SmartSpawning"); + ds.Tables[SpawnTablePointName].Columns.Add("TickReset"); + + ds.Tables[SpawnTablePointName].Columns.Add("WayPoint"); + ds.Tables[SpawnTablePointName].Columns.Add("Team"); + // amount for stacked item spawns + ds.Tables[SpawnTablePointName].Columns.Add("Amount"); + ds.Tables[SpawnTablePointName].Columns.Add("IsGroup"); + ds.Tables[SpawnTablePointName].Columns.Add("IsRunning"); + ds.Tables[SpawnTablePointName].Columns.Add("IsHomeRangeRelative"); + ds.Tables[SpawnTablePointName].Columns.Add(oldformat ? "Objects" : "Objects2"); + + // Always export sorted by UUID to help diffs + savelist.Sort((a, b) => + { + return a.UniqueId.CompareTo(b.UniqueId); + }); + + // Add each spawn point to the new table + foreach (XmlSpawner sp in savelist) + { + if (sp == null || sp.Map == null || sp.Deleted) + { + continue; + } + + if (verbose && from != null) + // Send a message to the client that the spawner is being saved + { + from.SendMessage(68, "Saving '{0}' in {1} at {2}", sp.Name, sp.Map.Name, sp.Location.ToString()); + } + + // Create a new data row + DataRow dr = ds.Tables[SpawnTablePointName].NewRow(); + + // Populate the data + dr["Name"] = sp.Name; + + // Set the unqiue id + dr["UniqueId"] = sp.m_UniqueId; + + // Get the map name + dr["Map"] = sp.Map.Name; + + // Convert the xml map value to a real map object + if (string.Compare(sp.Map.Name, Map.Trammel.Name, true) == 0) + { + TrammelCount++; + } + else if (string.Compare(sp.Map.Name, Map.Felucca.Name, true) == 0) + { + FeluccaCount++; + } + else if (string.Compare(sp.Map.Name, Map.Ilshenar.Name, true) == 0) + { + IlshenarCount++; + } + else if (string.Compare(sp.Map.Name, Map.Malas.Name, true) == 0) + { + MalasCount++; + } + else if (string.Compare(sp.Map.Name, Map.Tokuno.Name, true) == 0) + { + TokunoCount++; + } + else + { + OtherCount++; + } + + dr["X"] = sp.m_X; + dr["Y"] = sp.m_Y; + dr["Width"] = sp.m_Width; + dr["Height"] = sp.m_Height; + + // check to see if this is in a container + if (sp.RootParent is Container container) + { + dr["CentreX"] = container.Location.X; + dr["CentreY"] = container.Location.Y; + dr["CentreZ"] = container.Location.Z; + dr["ContainerX"] = sp.Location.X; + dr["ContainerY"] = sp.Location.Y; + dr["ContainerZ"] = sp.Location.Z; + dr["InContainer"] = true; + } + else + { + dr["CentreX"] = sp.Location.X; + dr["CentreY"] = sp.Location.Y; + dr["CentreZ"] = sp.Location.Z; + //dr["ContainerX"] = 0; + //dr["ContainerY"] = 0; + //dr["ContainerZ"] = 0; + dr["InContainer"] = false; + } + dr["Range"] = sp.m_HomeRange; + dr["MaxCount"] = sp.m_Count; + + // need to deal with the fact that the old xmlspawner xml format only saved delays in minutes as ints, so shorter spawn times + // are lost + // flag it then on reading it can be properly handled and still + // maintain backward compatibility with older xml files + if ((int)sp.m_MinDelay.TotalSeconds - 60 * (int)sp.m_MinDelay.TotalMinutes > 0 || + (int)sp.m_MaxDelay.TotalSeconds - 60 * (int)sp.m_MaxDelay.TotalMinutes > 0) + { + dr["DelayInSec"] = true; + dr["MinDelay"] = (int)sp.m_MinDelay.TotalSeconds; + dr["MaxDelay"] = (int)sp.m_MaxDelay.TotalSeconds; + } + else + { + dr["DelayInSec"] = false; + dr["MinDelay"] = (int)sp.m_MinDelay.TotalMinutes; + dr["MaxDelay"] = (int)sp.m_MaxDelay.TotalMinutes; + } + + // additional parameters + dr["TODStart"] = sp.m_TODStart.TotalMinutes; + dr["TODEnd"] = sp.m_TODEnd.TotalMinutes; + dr["TODMode"] = (int)sp.m_TODMode; + dr["KillReset"] = sp.m_KillReset; + dr["MinRefractory"] = sp.m_MinRefractory.TotalMinutes; + dr["MaxRefractory"] = sp.m_MaxRefractory.TotalMinutes; + dr["Duration"] = sp.m_Duration.TotalMinutes; + dr["DespawnTime"] = sp.m_DespawnTime.TotalHours; + dr["ExternalTriggering"] = sp.m_ExternalTriggering; + + dr["ProximityRange"] = sp.m_ProximityRange; + dr["ProximityTriggerSound"] = sp.m_ProximityTriggerSound; + dr["ProximityTriggerMessage"] = sp.m_ProximityTriggerMessage; + if (sp.m_ObjectPropertyItem != null && !sp.m_ObjectPropertyItem.Deleted) + { + dr["ObjectPropertyItemName"] = string.Format("{0},{1}", sp.m_ObjectPropertyItem.Name, + sp.m_ObjectPropertyItem.GetType().Name); + } + else + { + dr["ObjectPropertyItemName"] = null; + } + + dr["ObjectPropertyName"] = sp.m_ObjectPropertyName; + if (sp.m_SetPropertyItem != null && !sp.m_SetPropertyItem.Deleted) + { + dr["SetPropertyItemName"] = string.Format("{0},{1}", sp.m_SetPropertyItem.Name, + sp.m_SetPropertyItem.GetType().Name); + } + else + { + dr["SetPropertyItemName"] = null; + } + + dr["ItemTriggerName"] = sp.m_ItemTriggerName; + dr["NoItemTriggerName"] = sp.m_NoItemTriggerName; + dr["MobTriggerName"] = sp.m_MobTriggerName; + dr["MobPropertyName"] = sp.m_MobPropertyName; + dr["PlayerPropertyName"] = sp.m_PlayerPropertyName; + dr["TriggerProbability"] = sp.m_TriggerProbability; + dr["SequentialSpawning"] = sp.m_SequentialSpawning; + dr["RegionName"] = sp.m_RegionName; + dr["AllowGhostTriggering"] = sp.m_AllowGhostTriggering; + dr["AllowNPCTriggering"] = sp.m_AllowNPCTriggering; + dr["SpawnOnTrigger"] = sp.m_SpawnOnTrigger; + dr["ConfigFile"] = sp.m_ConfigFile; + dr["SmartSpawning"] = sp.m_SmartSpawning; + dr["TickReset"] = sp.m_DisableGlobalAutoReset; + + dr["SpeechTrigger"] = sp.m_SpeechTrigger; + dr["SkillTrigger"] = sp.m_SkillTrigger; + dr["Amount"] = sp.m_StackAmount; + dr["Team"] = sp.m_Team; + + // assign the waypoint based on the waypoint name if it deviates from the default waypoint name, otherwise do it by serial + string waystr = null; + if (sp.m_WayPoint != null) + { + if (sp.m_WayPoint.Name != defwaypointname && !string.IsNullOrEmpty(sp.m_WayPoint.Name)) + { + waystr = sp.m_WayPoint.Name; + } + else + { + waystr = string.Format("SERIAL,{0}", sp.m_WayPoint.Serial); + } + } + dr["WayPoint"] = waystr; + + dr["IsGroup"] = sp.m_Group; + dr["IsRunning"] = sp.m_Running; + dr["IsHomeRangeRelative"] = sp.m_HomeRangeIsRelative; + if (oldformat) + { + dr["Objects"] = sp.GetSerializedObjectList(); + } + else + { + dr["Objects2"] = sp.GetSerializedObjectList2(); + } + + // Add the row the the table + ds.Tables[SpawnTablePointName].Rows.Add(dr); + + // Increment the count + TotalCount++; + } + + // Write out the file + bool file_error = false; + if (TotalCount > 0) + { + try + { + ds.WriteXml(stream); + } + catch { file_error = true; } + + if (file_error) + { + return false; + } + } + + try + { + stream.Close(); + } + catch { } + // Indicate how many spawners were written + if (from != null) + { + from.SendMessage("{0} spawner(s) were saved to file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6}, Other={7}].", + TotalCount, dirname, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount); + } + return true; + + } + + private static void WipeSpawners(CommandEventArgs e, bool WipeAll) + { + if (e == null || e.Mobile == null) + { + return; + } + + if (e.Mobile.AccessLevel >= AccessLevel.Administrator) + { + // Spawner delete criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (delete criteria) + if (e.Arguments != null && e.Arguments.Length > 0) + { + SpawnerPrefix = e.Arguments[0]; + } + + if (WipeAll) + { + e.Mobile.SendMessage("Removing ALL XmlSpawner objects from the world{0}.", !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" + : string.Empty); + } + else + { + e.Mobile.SendMessage("Removing ALL XmlSpawner objects from {0}{1}.", e.Mobile.Map, !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" + : string.Empty); + } + + // Delete Xml spawner's in the world based on the mobiles current map + int Count = 0; + List ToDelete = new List(); + foreach (Item i in World.Items.Values) + { + if (i is XmlSpawner && (WipeAll || i.Map == e.Mobile.Map) && i.Deleted == false) + { + // Check if there is a delete condition + if (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || i.Name.StartsWith(SpawnerPrefix)) + { + // Send a message to the client that the spawner is being deleted + //e.Mobile.SendMessage(33, "Removing '{0}' in {1} at {2}", i.Name, i.Map.Name, i.Location.ToString()); + + ToDelete.Add(i); + Count++; + } + } + } + + // Delete the items in the array list + foreach (Item i in ToDelete) + { + i.Delete(); + } + + if (WipeAll) + { + e.Mobile.SendMessage("Removed {0} XmlSpawner objects from the world.", Count); + } + else + { + e.Mobile.SendMessage("Removed {0} XmlSpawner objects from {1}.", Count, e.Mobile.Map); + } + } + else + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + } + + + [Usage("XmlSpawnerRespawn [SpawnerPrefixFilter]")] + [Description("Respawns all XmlSpawner objects from the current map.")] + public static void Respawn_OnCommand(CommandEventArgs e) + { + RespawnSpawners(e, false); + } + + [Usage("XmlSpawnerRespawnAll [SpawnerPrefixFilter]")] + [Description("Respawns all XmlSpawner objects from the entire world.")] + public static void RespawnAll_OnCommand(CommandEventArgs e) + { + RespawnSpawners(e, true); + } + + private static void RespawnSpawners(CommandEventArgs e, bool RespawnAll) + { + if (e == null || e.Mobile == null) + { + return; + } + + if (e.Mobile.AccessLevel >= AccessLevel.Administrator) + { + // Spawner Respawn criteria (if any) + string SpawnerPrefix = string.Empty; + + // Check if there is an argument provided (respawn criteria) + if (e.Arguments != null && e.Arguments.Length > 0) + { + SpawnerPrefix = e.Arguments[0]; + } + + if (RespawnAll) + { + e.Mobile.SendMessage("Respawning ALL XmlSpawner objects from the world{0}.", !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" + : string.Empty); + } + else + { + e.Mobile.SendMessage("Respawning ALL XmlSpawner objects from {0}{1}.", e.Mobile.Map, !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" + : string.Empty); + } + + // Respawn Xml spawner's in the world based on the mobiles current map + int Count = 0; + List ToRespawn = new List(); + foreach (Item i in World.Items.Values) + { + try + { + + if (i is XmlSpawner && (RespawnAll || i.Map == e.Mobile.Map) && i.Deleted == false) + { + // Check if there is a respawn condition + if (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || i.Name != null && i.Name.StartsWith(SpawnerPrefix)) + { + ToRespawn.Add(i); + Count++; + } + } + } + catch (Exception ex) { Console.WriteLine("Error attempting to add {0}, {1}", i, ex.Message); } + } + // Respawn the items in the array list + foreach (Item i in ToRespawn) + { + + // Send a message to the client that the spawner is being respawned + e.Mobile.SendMessage(33, "Respawning '{0}' in {1} at {2}", i.Name, i.Map.Name, i.Location.ToString()); + XmlSpawner CheckXmlSpawner = (XmlSpawner)i; + CheckXmlSpawner.TryRespawn(); + } + + if (RespawnAll) + { + e.Mobile.SendMessage("Respawned {0} XmlSpawner objects from the world.", Count); + } + else + { + e.Mobile.SendMessage("Respawned {0} XmlSpawner objects from {1}.", Count, e.Mobile.Map); + } + } + else + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + } + } + +#if (TRACE) + public static void XmlMake_OnCommand(CommandEventArgs e) + { + + if (e.Arguments.Length > 0) + { + int count = 0; + try + { + count = Convert.ToInt32(e.Arguments[0], 10); + } + catch (Exception ex) { Diagnostics.ExceptionLogging.LogException(ex); } + + for (int i = 0; i < count; i++) + { + if (e.Arguments.Length > 2) + { + Spawner x = new Spawner(10, 1, 1, 0, 2, e.Arguments[1]); + x.Location = new Point3D(5400 + Utility.Random(700), 1090 + Utility.Random(180), 0); + x.Map = Map.Trammel; + } + else + if (e.Arguments.Length > 1) + { + XmlSpawner x = new XmlSpawner(10, 1, 1, 0, 2, e.Arguments[1]); + x.Location = new Point3D(5400 + Utility.Random(700), 1090 + Utility.Random(180), 0); + x.Map = Map.Trammel; + //x.MinDelay = TimeSpan.FromSeconds(1); + //x.MaxDelay = TimeSpan.FromSeconds(1); + //x.ProximityRange = 0; + } + } + if (e.Arguments.Length > 2) + { + e.Mobile.SendMessage("Created {0} Spawner objects.", count); + } + else + { + e.Mobile.SendMessage("Created {0} XmlSpawner objects.", count); + } + + + } + } + + public static void XmlTrace_OnCommand() + { + XmlTrace_OnCommand(null); + } + + public static void XmlTrace_OnCommand(CommandEventArgs e) + { + Process currentprocess = Process.GetCurrentProcess(); + TimeSpan runningtime = DateTime.UtcNow - _traceStartTime; + double processtime = currentprocess.UserProcessorTime.TotalMilliseconds - _startProcessTime; + double sysload = 0; + + if (runningtime.TotalMilliseconds > 0) + { + sysload = processtime / runningtime.TotalMilliseconds; + } + + Console.WriteLine("______________"); + Console.WriteLine("Active Traces:"); + Console.WriteLine("Running Time = {0}", runningtime); + Console.WriteLine("Adjusted Process Time = {0:####.####} secs", processtime / 1000); + Console.WriteLine("Processor Time = {0} ({1:p3} avg sys load)", currentprocess.UserProcessorTime, sysload); + + for (int i = 0; i < MaxTraces; i++) + { + if (_traceCount[i] > 0) + { + double load = 0; + if (processtime > 0) + { + load = _traceTotal[i].TotalMilliseconds / processtime; + } + Console.WriteLine("{0} ({4}) {1,21} / {2} calls = {3:####.####} ms/call, {5:p3}", + i, _traceTotal[i], _traceCount[i], _traceTotal[i].TotalMilliseconds / _traceCount[i], + _traceName[i], load); + } + } + } + + public static void XmlResetTrace_OnCommand(CommandEventArgs e) + { + + if (e.Arguments.Length >= 0) + { + for (int i = 0; i < MaxTraces; i++) + { + _traceCount[i] = 0; + _traceTotal[i] = TimeSpan.Zero; + } + _traceStartTime = DateTime.UtcNow; + + Process currentprocess = Process.GetCurrentProcess(); + _startProcessTime = currentprocess.UserProcessorTime.TotalMilliseconds; + + Console.WriteLine("Traces reset"); + } + } +#endif + + [Constructible] + public XmlSpawner() + : base(BaseItemId) + { + m_PlayerCreated = true; + m_UniqueId = Guid.NewGuid().ToString(); + SpawnRange = defSpawnRange; + + InitSpawn(0, 0, m_Width, m_Height, string.Empty, 0, defMinDelay, defMaxDelay, defDuration, + defProximityRange, defProximityTriggerSound, defAmount, defTeam, defHomeRange, defRelativeHome, new SpawnObject[0], defMinRefractory, defMaxRefractory, + defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode, + defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); + } + + [Constructible] + public XmlSpawner(int amount, int minDelay, int maxDelay, int team, int homeRange, string creatureName) + : base(BaseItemId) + { + m_PlayerCreated = true; + m_UniqueId = Guid.NewGuid().ToString(); + SpawnRange = homeRange; + SpawnObject[] so = new SpawnObject[1]; + so[0] = new SpawnObject(creatureName, amount); + + InitSpawn(0, 0, m_Width, m_Height, string.Empty, amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), defDuration, + defProximityRange, defProximityTriggerSound, defAmount, team, homeRange, defRelativeHome, so, defMinRefractory, defMaxRefractory, + defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode, + defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); + } + + [Constructible] + public XmlSpawner(int amount, int minDelay, int maxDelay, int team, int homeRange, int spawnRange, string creatureName) + : base(BaseItemId) + { + m_PlayerCreated = true; + m_UniqueId = Guid.NewGuid().ToString(); + SpawnRange = spawnRange; + SpawnObject[] so = new SpawnObject[1]; + so[0] = new SpawnObject(creatureName, amount); + + InitSpawn(0, 0, m_Width, m_Height, string.Empty, amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), defDuration, + defProximityRange, defProximityTriggerSound, defAmount, team, homeRange, defRelativeHome, so, defMinRefractory, defMaxRefractory, + defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode, + defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); + } + + [Constructible] + public XmlSpawner(string creatureName) + : base(BaseItemId) + { + m_PlayerCreated = true; + m_UniqueId = Guid.NewGuid().ToString(); + SpawnObject[] so = new SpawnObject[1]; + so[0] = new SpawnObject(creatureName, 1); + SpawnRange = defSpawnRange; + + InitSpawn(0, 0, m_Width, m_Height, string.Empty, 1, defMinDelay, defMaxDelay, defDuration, + defProximityRange, defProximityTriggerSound, defAmount, defTeam, defHomeRange, defRelativeHome, so, defMinRefractory, defMaxRefractory, + defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode, + defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); + } + + public XmlSpawner(Guid uniqueId, int x, int y, int width, int height, string name, int maxCount, TimeSpan minDelay, TimeSpan maxDelay, TimeSpan duration, + int proximityRange, int proximityTriggerSound, int amount, int team, int homeRange, bool isRelativeHomeRange, SpawnObject[] spawnObjects, + TimeSpan minRefractory, TimeSpan maxRefractory, TimeSpan todstart, TimeSpan todend, Item objectPropertyItem, string objectPropertyName, string proximityMessage, + string itemTriggerName, string noitemTriggerName, string speechTrigger, string mobTriggerName, string mobPropertyName, string playerPropertyName, double triggerProbability, + Item setPropertyItem, bool isGroup, TODModeType todMode, int killReset, bool externalTriggering, int sequentialSpawning, string regionName, + bool allowghost, bool allownpc, bool spawnontrigger, string configfile, TimeSpan despawnTime, string skillTrigger, bool smartSpawning, WayPoint wayPoint) + : base(BaseItemId) + { + m_UniqueId = uniqueId.ToString(); + InitSpawn(x, y, width, height, name, maxCount, minDelay, maxDelay, duration, + proximityRange, proximityTriggerSound, amount, team, homeRange, isRelativeHomeRange, spawnObjects, minRefractory, maxRefractory, todstart, todend, + objectPropertyItem, objectPropertyName, proximityMessage, itemTriggerName, noitemTriggerName, speechTrigger, mobTriggerName, mobPropertyName, playerPropertyName, + triggerProbability, setPropertyItem, isGroup, todMode, killReset, externalTriggering, sequentialSpawning, regionName, allowghost, allownpc, spawnontrigger, configfile, + despawnTime, skillTrigger, smartSpawning, wayPoint); + } + + + public void InitSpawn(int x, int y, int width, int height, string name, int maxCount, TimeSpan minDelay, TimeSpan maxDelay, TimeSpan duration, + int proximityRange, int proximityTriggerSound, int amount, int team, int homeRange, bool isRelativeHomeRange, SpawnObject[] objectsToSpawn, + TimeSpan minRefractory, TimeSpan maxRefractory, TimeSpan todstart, TimeSpan todend, Item objectPropertyItem, string objectPropertyName, string proximityMessage, + string itemTriggerName, string noitemTriggerName, string speechTrigger, string mobTriggerName, string mobPropertyName, string playerPropertyName, double triggerProbability, + Item setPropertyItem, bool isGroup, TODModeType todMode, int killReset, bool externalTriggering, int sequentialSpawning, string regionName, bool allowghost, bool allownpc, bool spawnontrigger, + string configfile, TimeSpan despawnTime, string skillTrigger, bool smartSpawning, WayPoint wayPoint) + { + + Visible = false; + Movable = false; + m_X = x; + m_Y = y; + m_Width = width; + m_Height = height; + + // init spawn range if compatible + if (width == height) + { + m_SpawnRange = width / 2; + } + else + { + m_SpawnRange = -1; + } + + m_Running = true; + m_Group = isGroup; + + Name = !string.IsNullOrEmpty(name) ? name : "Spawner"; + + m_MinDelay = minDelay; + m_MaxDelay = maxDelay; + + // duration and proximity range parameter + m_MinRefractory = minRefractory; + m_MaxRefractory = maxRefractory; + m_TODStart = todstart; + m_TODEnd = todend; + m_TODMode = todMode; + m_KillReset = killReset; + m_Duration = duration; + m_DespawnTime = despawnTime; + m_ProximityRange = proximityRange; + m_ProximityTriggerSound = proximityTriggerSound; + m_proximityActivated = false; + m_durActivated = false; + m_refractActivated = false; + m_Count = maxCount; + m_Team = team; + m_StackAmount = amount; + m_HomeRange = homeRange; + m_HomeRangeIsRelative = isRelativeHomeRange; + m_ObjectPropertyItem = objectPropertyItem; + m_ObjectPropertyName = objectPropertyName; + m_ProximityTriggerMessage = proximityMessage; + m_ItemTriggerName = itemTriggerName; + m_NoItemTriggerName = noitemTriggerName; + m_SpeechTrigger = speechTrigger; + SkillTrigger = skillTrigger; // note this will register the skill as well + m_MobTriggerName = mobTriggerName; + m_MobPropertyName = mobPropertyName; + m_PlayerPropertyName = playerPropertyName; + m_TriggerProbability = triggerProbability; + m_SetPropertyItem = setPropertyItem; + m_ExternalTriggering = externalTriggering; + m_ExternalTrigger = false; + m_SequentialSpawning = sequentialSpawning; + RegionName = regionName; + m_AllowGhostTriggering = allowghost; + m_AllowNPCTriggering = allownpc; + m_SpawnOnTrigger = spawnontrigger; + m_SmartSpawning = smartSpawning; + ConfigFile = configfile; + m_WayPoint = wayPoint; + + // set the totalitem property to -1 so that it doesnt show up in the item count of containers + //TotalItems = -1; + //UpdateTotal(this, TotalType.Items, -1); + + // Create the array of spawned objects + m_SpawnObjects = new List(); + + // Assign the list of objects to spawn + SpawnObjects = objectsToSpawn; + + // Kick off the process + DoTimer(TimeSpan.FromSeconds(1)); + } + + public XmlSpawner(Serial serial) + : base(serial) + { + } + + public void Defrag(bool killtest) + { + if (m_SpawnObjects == null) + { + return; + } + + bool removed = false; + int total_removed = 0; + + List deleteilist = new List(); + List deletemlist = new List(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + + if (o is Item item) + { + bool despawned = false; + // check to see if the despawn time has elapsed. If so, then delete it if it hasnt been picked up or stolen. + if (DespawnTime.TotalHours > 0 && !item.Deleted && item.LastMoved < DateTime.UtcNow - DespawnTime && item.Parent == Parent + && (!ItemFlags.GetTaken(item) || item.Parent != null && item.Parent == Parent)) // can despawn if just moved within the same container + { + //item.Delete(); + deleteilist.Add(item); + despawned = true; + } + + // Check if the items has been deleted or + // if something else now owns the item (picked it up for example) + // also check the stolen/placed in container flag. If any of those are true then the spawner doesnt own it any more so take it off the list. + // the stolen/container flag prevents spawns from being left on the list when players take them and lock them back down on the ground. + // If you have made the changes to stealing.cs and container.cs described in xmlspawner2.txt then just uncomment the line below to + // enable this check + if (item.Deleted || despawned || item.Parent != Parent // different container + || ItemFlags.GetTaken(item) && (item.Parent == null || item.Parent != Parent)) // taken and in the world, or a different container + { + so.SpawnedObjects.Remove(item); + x--; + removed = true; + // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if + // the object is in the current subgroup before adding to the total + if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup) + { + if (so.SubGroup == SequentialSpawn) + { + total_removed++; + } + } + else + { + // just add it + total_removed++; + } + } + } + else if (o is Mobile mobile) + { + bool despawned = false; + // check to see if the despawn time has elapsed. If so, and the sector is not active then delete it. + if (DespawnTime.TotalHours > 0 && !mobile.Deleted && mobile.Created < DateTime.UtcNow - DespawnTime + && mobile.Map != null && mobile.Map != Map.Internal && !mobile.Map.GetSector(mobile.Location).Active) + { + //m.Delete(); + deletemlist.Add(mobile); + despawned = true; + } + + if (mobile.Deleted || despawned) + { + // Remove the delete mobile from the list + so.SpawnedObjects.Remove(mobile); + x--; + removed = true; + // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if + // the object is in the current subgroup before adding to the total + if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup) + { + if (so.SubGroup == SequentialSpawn) + { + total_removed++; + } + } + else + { + // just add it + total_removed++; + } + } + else if (mobile is BaseCreature creature) + { + // Check if the creature has been tamed or previously tamed and released + // and if it is, remove it from the list of spawns + if (creature.Controlled || creature.IsStabled || creature.Owners != null && creature.Owners.Count > 0) + { + so.SpawnedObjects.Remove(mobile); + x--; + removed = true; + // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if + // the object is in the current subgroup before adding to the total + if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup) + { + if (so.SubGroup == SequentialSpawn) + { + total_removed++; + } + } + else + { + // just add it + total_removed++; + } + } + } + } + else + if (o is BaseXmlSpawner.KeywordTag tag) + { + if (tag.Deleted) + { + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + } + else + { + // Don't know what this is, so remove it + Console.WriteLine("removing unknown {0} from spawnlist", so); + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + } + } + + DeleteFromList(deleteilist, deletemlist); + + // Check if anything has been removed + if (removed) + { + InvalidateProperties(); + } + + // increment the killcount based upon the number of items that were removed from the spawnlist (i.e. were spawned but now are gone, presumed killed) + if (killtest) + { + m_killcount += total_removed; + } + } + + // special defrag pass to remove GOTO keyword tags + public void ClearGOTOTags() + { + if (m_SpawnObjects == null) + { + return; + } + + List ToDelete = new List(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (o is BaseXmlSpawner.KeywordTag sot) + { + // clear the tags except for gump and delay tags + if (sot.Type == 2) + { + ToDelete.Add(sot); + so.SpawnedObjects.Remove(o); + x--; + } + + } + } + } + + for (int x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) + { + BaseXmlSpawner.KeywordTag i = ToDelete[x]; + if (i != null && !i.Deleted) + { + i.Delete(); + } + } + } + + // special defrag pass to remove spawn object tags, which are placeholders for the special keyword spawn spec entries + public void ClearTags(bool all) + { + if (m_SpawnObjects == null) + { + return; + } + + bool removed = false; + List ToDelete = new List(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (o is BaseXmlSpawner.KeywordTag sot) + { + // clear the tags except for gump and delay tags + if (all || (sot.Flags & BaseXmlSpawner.KeywordFlags.Defrag) != 0) + { + ToDelete.Add(sot); + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + + } + } + } + + for (int x = ToDelete.Count - 1; x >= 0; --x) //each (BaseXmlSpawner.KeywordTag i in ToDelete) + { + BaseXmlSpawner.KeywordTag i = ToDelete[x]; + if (i != null && !i.Deleted) + { + i.Delete(); + } + } + + // full clear of the taglist + if (all) + { + m_KeywordTagList.Clear(); + } + + // Check if anything has been removed + if (removed) + { + InvalidateProperties(); + } + } + + public void DeleteGumpTags() + { + if (m_SpawnObjects == null) + { + return; + } + + bool removed = false; + List ToDelete = new List(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (o is BaseXmlSpawner.KeywordTag sot) + { + // clear the gump tags + if (sot.Type == 1) + { + ToDelete.Add(sot); + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + } + } + } + + for (int x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) + { + BaseXmlSpawner.KeywordTag i = ToDelete[x]; + if (i != null && !i.Deleted) + { + i.Delete(); + } + } + + // Check if anything has been removed + if (removed) + { + InvalidateProperties(); + } + } + + public void DeleteTag(BaseXmlSpawner.KeywordTag tag) + { + if (m_SpawnObjects == null) + { + return; + } + + bool removed = false; + List ToDelete = new List(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (o is BaseXmlSpawner.KeywordTag sot) + { + // clear the matching tags + if (sot == tag) + { + ToDelete.Add(sot); + so.SpawnedObjects.Remove(o); + x--; + removed = true; + } + } + } + } + + for (int x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) + { + BaseXmlSpawner.KeywordTag i = ToDelete[x]; + if (i != null && !i.Deleted) + { + i.Delete(); + } + } + + // Check if anything has been removed + if (removed) + { + InvalidateProperties(); + } + } + + private int SubGroupCount(int sgroup) + { + if (m_SpawnObjects == null) + { + return 0; + } + + int nsub = 0; + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = m_SpawnObjects[i]; + + if (s.SubGroup == sgroup) + { + nsub++; + } + } + + return nsub; + } + + private int RandomAvailableSpawnIndex() => + // get spawn indices randomly from all available spawns independent of group + RandomAvailableSpawnIndex(-1); + + // get spawn indices randomly from all available spawns of a group + private int RandomAvailableSpawnIndex(int sgroup) + { + if (m_SpawnObjects == null) + { + return -1; + } + + int maxrange = 0; + List sgrouplist = null; + int totalcount = 0; + // make a pass to determine which subgroups are available for spawning + // by finding any subgroups that do not have available spawns + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = m_SpawnObjects[i]; + if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) + { + continue; + } + + totalcount += s.SpawnedObjects.Count; + if (s.SubGroup > 0 && s.SpawnedObjects.Count >= s.MaxCount) + { + // this subgroup is not available so add it to the list + if (sgrouplist == null) + { + sgrouplist = new List(); + } + sgrouplist.Add(s.SubGroup); + } + } + + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = m_SpawnObjects[i]; + + if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) + { + continue; + } + + if (s.MaxCount > s.SpawnedObjects.Count && (sgroup < 0 || sgroup == s.SubGroup) + && (sgrouplist == null || !sgrouplist.Contains(s.SubGroup)) && (s.SubGroup <= 0 || SubGroupCount(s.SubGroup) + totalcount <= MaxCount)) + { + // keep track of the number of spawn objects that are not at max (hence available for spawning) + // this will be used to compute the probabilistic weighting function based on the relative + // maxcounts of each entry + maxrange += s.MaxCount; + s.Available = true; + } + else + { + s.Available = false; + } + } + // now generate a random number over the available spawnobjects + // but only if the entire subgroup is available for spawning + // note, subgroup zero is exempt from this check. + if (maxrange > 0) + { + int randindex = Utility.Random(maxrange); + + // and map it into the avail spawns + int currentrange = 0; + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = m_SpawnObjects[i]; + if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) + { + continue; + } + + // keep track of the number of spawn objects that are not at max (hence available for spawning) + if (s.Available) + { + // check to see if the random value maps into the range of the current index + if (randindex >= currentrange && randindex < currentrange + s.MaxCount) + { + return i; + } + + currentrange += s.MaxCount; + } + } + + // should never get here + return -1; + } + + // no spawns are available + return -1; + } + + // get spawn indices randomly from all available spawns of a group + private int RandomSpawnIndex(int sgroup) + { + if (m_SpawnObjects == null) + { + return -1; + } + + int avail = 0; + int maxrange = 0; + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = m_SpawnObjects[i]; + + // keep track of the number of spawn objects that are not at max (hence available for spawning) + if (sgroup < 0 || sgroup == s.SubGroup) + { + avail++; + maxrange += s.MaxCount; + } + } + // now generate a random number over the available spawnobjects + if (avail > 0 && maxrange > 0) + { + int randindex = Utility.Random(maxrange); + + // and map it into the avail spawns + int currentrange = 0; + + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject s = m_SpawnObjects[i]; + + // keep track of the number of spawn objects that are not at max (hence available for spawning) + if (sgroup < 0 || sgroup == s.SubGroup) + { + if (randindex >= currentrange && randindex < currentrange + s.MaxCount) + { + return i; + } + + currentrange += s.MaxCount; + } + } + + // should never get here + return -1; + } + + // no spawns are available + return -1; + } + + // return the next subgroup in the sequence. + public int NextSequentialIndex(int sgroup) + { + if (m_SpawnObjects == null || m_SpawnObjects.Count == 0) + { + return 0; + } + + int finddirection = 1; + int largergroup = -1; + + //find the next subgroup that is greater than the current one + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject s = m_SpawnObjects[j]; + if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) + { + continue; + } + + int thisgroup = s.SubGroup; + + // start off by finding a subgroup that is larger + if (finddirection == 1) + { + if (thisgroup > sgroup) + { + largergroup = thisgroup; + + // then work backward to find the group that is less than this but still larger than the current + finddirection = -1; + } + } + else + { + if (thisgroup > sgroup && thisgroup < largergroup) + { + largergroup = thisgroup; + + finddirection = -1; + } + } + } + + // if couldnt find one larger, then it is time to wraparound + if (largergroup < 0 && sgroup >= 0) + { + return NextSequentialIndex(-1); + } + + return largergroup; + } + + // returns the spawn index of a spawn entry in the current sequential subgroup + public int GetCurrentAvailableSequentialSpawnIndex(int sgroup) + { + if (sgroup < 0) + { + return -1; + } + + if (m_SpawnObjects == null) + { + return -1; + } + + if (sgroup == 0) + { + return RandomAvailableSpawnIndex(0); + } + + //return the first instance of a spawn object that is an available member of the requested subgroup + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject s = m_SpawnObjects[j]; + + if (s.SubGroup == sgroup && s.MaxCount > s.SpawnedObjects.Count) + { + return j; + } + } + // failed to find any spawn entry of the requested subgroup + return -1; + } + + // returns the spawn index of a spawn entry in the current sequential subgroup + public int GetCurrentSequentialSpawnIndex(int sgroup) + { + if (sgroup < 0) + { + return -1; + } + + if (m_SpawnObjects == null) + { + return -1; + } + + if (sgroup == 0) + { + return RandomSpawnIndex(0); + } + + //return the first instance of a spawn object that is an available member of the requested subgroup + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + if (m_SpawnObjects[j].SubGroup == sgroup) + { + return j; + } + } + // failed to find any spawn entry of the requested subgroup + return -1; + } + + private void SeqResetTo(int sgroup) + { + // check the SequentialResetTo on the subgroup + // cant do resets on subgroup 0 + if (sgroup == 0) + { + return; + } + + // this will get the index of the first spawn entry in the subgroup + // it will have the subgroup timer settings + int spawnindex = GetCurrentSequentialSpawnIndex(sgroup); + + if (spawnindex >= 0) + { + // if it is greater than zero then initiate reset + SpawnObject s = m_SpawnObjects[spawnindex]; + m_SequentialSpawning = s.SequentialResetTo; + + InitiateSequentialReset(sgroup); + + // clear the spawns + //RemoveSpawnObjects(); + ClearSubgroup(s.SubGroup); + + // and reset the kill count + KillCount = 0; + } + } + + private bool CheckForSequentialReset() + { + // check the SequentialResetTime on the subgroup + // cant do resets on subgroup 0 + if (m_SequentialSpawning == 0) + { + return false; + } + + // this will get the index of the first spawn entry in the subgroup + // it will have the subgroup timer settings + int spawnindex = GetCurrentSequentialSpawnIndex(m_SequentialSpawning); + + if (spawnindex >= 0) + { + // check the reset time on it + SpawnObject s = m_SpawnObjects[spawnindex]; + // if it is greater than zero then resetting is possible + if (s.SequentialResetTime > 0) + { + // so check the reset timer + if (NextSeqReset <= TimeSpan.Zero) + { + // it has expired so time to reset + return true; + } + } + } + return false; + } + + private void InitiateSequentialReset(int sgroup) + { + // check the SequentialResetTime on the subgroup + // cant do resets on subgroup 0 + if (sgroup == 0) + { + return; + } + + // this will get the index of the first spawn entry in the subgroup + // it will have the subgroup timer settings + int spawnindex = GetCurrentSequentialSpawnIndex(sgroup); + + if (spawnindex >= 0) + { + // if it is greater than zero then initiate reset + SpawnObject s = m_SpawnObjects[spawnindex]; + NextSeqReset = TimeSpan.FromMinutes(s.SequentialResetTime); + } + } + + + public void ResetSequential() + { + // go back to the lowest level + if (m_SequentialSpawning >= 0) + { + m_SequentialSpawning = NextSequentialIndex(-1); + } + + // reset the nextspawn times + ResetNextSpawnTimes(); + + // and reset the kill count + KillCount = 0; + } + + public bool AdvanceSequential() + { + // check for a sequence hold + + if (HoldSequence) + { + return false; + } + + // check for triggering + if (!((m_proximityActivated || CanFreeSpawn) && TODInRange)) + { + return false; + } + + // if kills needed is greater than zero then check the killcount as well + int spawnindex = GetCurrentSequentialSpawnIndex(m_SequentialSpawning); + + int killsneeded = 0; + int subgroup = -1; + bool clearedobjects = false; + + if (spawnindex >= 0) + { + SpawnObject s = m_SpawnObjects[spawnindex]; + subgroup = s.SubGroup; + killsneeded = s.KillsNeeded; + } + + // advance the sequential spawn index if it is enabled and kills needed have been satisfied + if (m_SequentialSpawning >= 0 && (killsneeded == 0 || KillCount >= killsneeded)) + { + m_SequentialSpawning = NextSequentialIndex(m_SequentialSpawning); + + // set the sequential reset based on the current sequence state + // this will be checked in the spawner OnTick to determine whether to Reset the sequential state + InitiateSequentialReset(m_SequentialSpawning); + + // clear the spawns if there is a killcount on the level + if (killsneeded >= 0) + { + ClearSubgroup(subgroup); + clearedobjects = true; + } + + // and reset the kill count + KillCount = 0; + } + + // returning true will indicate that all spawns have been cleared and therefore a new spawn can be initiated in the same OnTick + return clearedobjects; + } + + int killcount_held; + + public void OnTick() + { + _TraceStart(8); + // start up the timer again for the next Ontick + DoTimer(); + + // reset the protection against runaway looping + ClearSpawnedThisTick = true; + + // if regional spawning is enabled, update the region in case new regions were added after the initialization pass + CheckRegionAssignment = true; + + // reset the killcount whenever a spawntick goes by in which it could have spawned, ie the spawner is full, or proximity triggered + // spawns were not activated. Note that killcount gets incremented within Defrag whenever a spawn is that had been generated is removed from the active list. + // Check the count before and then after the spawn passes. + // if the spawner is still refractory then dont do a reset of the killcount. + //int startcount = this.m_killcount; + int startcount = killcount_held; + if (!m_skipped) + { + killcount_held = m_killcount; + } + + // killcount will be updated in Defrag + Defrag(true); + + // remove any keyword tags that were made + // note, tags only last a single ontick except for WAIT type + ClearTags(false); + + if (!m_DisableGlobalAutoReset && startcount == m_killcount && !m_refractActivated && !m_skipped) + { + m_spawncheck--; + } + m_skipped = false; + + // allow for some slack in the killcount reset by resetting after a certain number of spawn ticks without kills pass + if (m_spawncheck <= 0) + { + m_killcount = 0; + m_spawncheck = m_KillReset; // wait for 1 spawn ticks to pass before resetting. This can be set to anything you like + } + + // check for smart spawning + if (SmartSpawning && IsFull && !HasActiveSectors && !HasDamagedOrDistantSpawns /*&& !HasHoldSmartSpawning */) + { + IsInactivated = true; + // for multiple sector spawning ranges use the sector timer, otherwise just rely on OnSectorActivate to detect sector activation + //if (!UseSectorActivate) + //DoSectorTimer(TimeSpan.FromSeconds(1)); + + SmartRemoveSpawnObjects(); + + } + + // dont process spawn ticks while inactivated if smart spawning is enabled + if (SmartSpawning && IsInactivated) + { + _TraceEnd(8); + return; + } + + IsInactivated = false; + + // check to see if spawning is on hold due to a WAIT keyword + if (!OnHold) + { + // look for triggers that are not player activated. + if (m_ProximityRange == -1 && CanSpawn) + { + CheckTriggers(null, null, false); + } + + // check for proximity triggers without movement activation + if (m_ProximityRange >= 0 && CanSpawn) + { + // check all nearby players + IPooledEnumerable eable = GetMobilesInRange(m_ProximityRange); + foreach (Mobile p in eable) + { + if (ValidPlayerTrig(p)) + { + CheckTriggers(p, null, true); + } + } + + eable.Free(); + } + + if (m_Group) + { + // check the seq reset time on the current subgroup + // if the reset time is greater than zero then check the timer + // if it has expired then reset the sequential subgroup + // only do this if it can actually spawn + if (CheckForSequentialReset()) + { + // it has expired so reset the sequential spawn level + SeqResetTo(m_SequentialSpawning); + + bool triedtospawn = TryRespawn(); + + if (triedtospawn) + { + ClearGOTOTags(); + } + + // dont advance if the spawn isnt triggered after resetting + if (!triedtospawn) + { + HoldSequence = true; + } + } + else if (TotalSpawnedObjects <= 0) + { + + // advance the sequential spawn index if it is enabled + AdvanceSequential(); + + //bool hadhold = HoldSequence; + + //HoldSequence = false; + + bool triedtospawn = TryRespawn(); + + if (triedtospawn) + { + ClearGOTOTags(); + } + + //if (!triedtospawn) HoldSequence = hadhold; + } + } + else + { + + if (CheckForSequentialReset()) + { + // it has expired so reset the sequential spawn level + SeqResetTo(m_SequentialSpawning); + + // dont advance if the spawn isnt triggered after resetting + HoldSequence = true; + } + else + { + // advance the sequence before spawning + AdvanceSequential(); + } + + // keep track of the hold flag before trying to spawn in case no spawn attempt is made + //bool hadhold = HoldSequence; + + // clear the hold flag to see if any of the spawned entries try to set it + //HoldSequence = false; + + // try to spawn. If spawning conditions such as triggering or TOD are not met, then it returns false + bool triedtospawn = Spawn(false, 0); + + if (triedtospawn) + { + ClearGOTOTags(); + } + // this will maintain any sequential holds if spawning was suppressed due to triggering + + if (!FreeRun) + { + m_mob_who_triggered = null; + } + + } + + // remove any keyword tags that were made except for WAIT type + ClearTags(false); + + + // and clear triggering flags + if (!OnHold && !FreeRun) + { + m_proximityActivated = false; + } + } + + if (FreeRun && SpawnOnTrigger && m_proximityActivated) + { + // if it is in free run and was triggered, then just keep spawning as though it was triggered immediately + NextSpawn = TimeSpan.Zero; + ResetNextSpawnTimes(); + } + + + //this.m_ExternalTrigger = false; + // if it is out of the TOD range then delete the spawns + if (!TODInRange) + { + RemoveSpawnObjects(); + + ResetAllFlags(); + } + _TraceEnd(8); + + } + + public bool ClearSpawnedThisTick + { + set + { + if (m_SpawnObjects == null || value == false) + { + return; + } + + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject sobj = m_SpawnObjects[i]; + if (sobj != null) + { + sobj.SpawnedThisTick = false; + } + } + } + } + + // select and spawn something + // return false if it cannot spawn, e.g. there is nothing to spawn or it is a triggerable spawner and has not been triggered + public bool Spawn(bool smartspawn, byte loops) + { + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0 && (m_proximityActivated || CanFreeSpawn) && TODInRange) + { + m_HoldSequence = false; + + // if the spawner is full then dont bother + if (IsFull) + { + ResetProximityActivated(); + return true; + } + + // Pick a spawn object to spawn + int SpawnIndex; + + // see if sequential spawning has been selected + SpawnIndex = m_SequentialSpawning >= 0 ? GetCurrentAvailableSequentialSpawnIndex(m_SequentialSpawning) : RandomAvailableSpawnIndex(); + + // no spawns are available so no point in continuing + if (SpawnIndex < 0) + { + ResetProximityActivated(); + return true; + } + + SpawnObject sobj = m_SpawnObjects[SpawnIndex]; + int sgroup = sobj.SubGroup; + + // if this is part of a non-zero group, then spawn all of the group members as well + if (sgroup != 0) + { + SpawnSubGroup(sgroup, smartspawn, loops); + } + else + { + // Found a valid spawn object so spawn it and see if it successful + if (Spawn(SpawnIndex, smartspawn, sobj.SpawnsPerTick, loops)) + { + if (!smartspawn) + { + RefreshNextSpawnTime(sobj); + } + } + } + + ResetProximityActivated(); + return true; + } + + ResetProximityActivated(); + return false; + } + + // spawn an individual entry by index up to count times + public bool Spawn(int index, bool smartspawn, int count, int packrange, Point3D packcoord, bool ignoreloopprotection, byte loops) + { + if (m_SpawnObjects == null || index >= m_SpawnObjects.Count) + { + return false; + } + + bool didspawn = false; + + SpawnObject so = m_SpawnObjects[index]; + + if (so == null) + { + return false; + } + + Defrag(false); + + // make sure you dont go over the individual entry maxcount + int somax = so.MaxCount; + int socnt = so.SpawnedObjects.Count; + int nspawn = so.SpawnsPerTick; + int scnt = SafeCurrentCount; + + for (int k = 0; k < nspawn && k + socnt < somax && k + scnt < MaxCount; k++) + { + if (packrange >= 0 && so.SubGroup > 0 && packcoord == Point3D.Zero) + { + packcoord = GetPackCoord(so.SubGroup); + } + if (Spawn(index, smartspawn, packrange, packcoord, ignoreloopprotection, loops)) + { + // if any of the attempts were successful then flag it as having spawned + didspawn = true; + } + } + + return didspawn; + } + + // spawn an individual entry by index up to count times + public bool Spawn(int index, bool smartspawn, int count, byte loops) => Spawn(index, smartspawn, count, false, loops); + + // spawn an individual entry by index up to count times + public bool Spawn(int index, bool smartspawn, int count, bool ignoreloopprotection, byte loops) => Spawn(index, smartspawn, count, -1, Point3D.Zero, ignoreloopprotection, loops); + + // spawn an individual entry by spawn object + public void Spawn(string SpawnObjectTypeName, bool smartspawn, int packrange, Point3D packcoord, byte loops) + { + if (m_SpawnObjects == null) + { + return; + } + + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + if (m_SpawnObjects[i].TypeName.ToUpper() == SpawnObjectTypeName.ToUpper()) + { + + if (Spawn(i, smartspawn, packrange, packcoord, loops)) + { + RefreshNextSpawnTime(m_SpawnObjects[i]); + } + break; + } + } + } + + // spawn an individual entry by index + public void Spawn(string SpawnObjectTypeName, bool smartspawn, byte loops) + { + Spawn(SpawnObjectTypeName, smartspawn, -1, Point3D.Zero, loops); + } + + // spawn an individual entry by index + public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, byte loops) => Spawn(index, smartspawn, packrange, packcoord, false, loops); + + // spawn an individual entry by index + public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, bool ignoreloopprotection, byte loops) + { + Map map = Map; + + // Make sure everything is ok to spawn an object + if (map == null || + map == Map.Internal || + m_SpawnObjects == null || + m_SpawnObjects.Count == 0 || + index < 0 || + index >= m_SpawnObjects.Count + ) + { + return false; + } + + // Remove any spawns that don't belong to the spawner any more. + Defrag(false); + + // Get the spawn object at the required index + SpawnObject TheSpawn = m_SpawnObjects[index]; + + // Check if the object retrieved is a valid SpawnObject + if (TheSpawn != null) + { + // dont allow an entry to be spawned more than once per tick + // this protects against runaway recursive looping + if (TheSpawn.SpawnedThisTick && !ignoreloopprotection) + { + return false; + } + + // check the nextspawn time to see if it is available + if (TheSpawn.NextSpawn > DateTime.UtcNow) + { + return false; + } + + int CurrentCreatureMax = TheSpawn.MaxCount; + int CurrentCreatureCount = TheSpawn.SpawnedObjects.Count; + + // Check that the current object to be spawned has not reached its maximum allowed + // and make sure that the maximum spawner count has not been exceeded as well + if (CurrentCreatureCount >= CurrentCreatureMax || + TotalSpawnedObjects >= m_Count) + { + return false; + } + + // check for string substitions + string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(this, this, TheSpawn.TypeName); + + // random positioning is the default + List spawnpositioning = null; + + // require valid surfaces by default + bool requiresurface = true; + + // parse the # function specification for the entry + while (substitutedtypeName.StartsWith("#")) + { + string[] args = BaseXmlSpawner.ParseSemicolonArgs(substitutedtypeName, 2); + + if (args.Length > 0) + { + if (spawnpositioning == null) + { + spawnpositioning = new List(); + } + // parse any comma args + string[] keyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 10); + + if (keyvalueargs.Length > 0) + { + + switch (keyvalueargs[0]) + { + case "#NOITEMID": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoItemID, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#ITEMID": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ItemID, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#NOTILES": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoTiles, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#TILES": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Tiles, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#WET": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Wet, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#XFILL": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RowFill, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#YFILL": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ColFill, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#EDGE": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Perimeter, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#PLAYER": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Player, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#WAYPOINT": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Waypoint, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#RELXY": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RelXY, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#DXY": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.DeltaLocation, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#XY": + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Location, m_mob_who_triggered, keyvalueargs)); + break; + } + case "#CONDITION": + { + // test the specified condition string + // syntax is #CONDITION,proptest + // reparse with only one arg after the comma, this allows property tests that use commas as well + string[] ckeyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 2); + if (ckeyvalueargs.Length > 1) + { + // dont spawn if it fails the test + if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out status_str)) + { + return false; + } + } + else + { + status_str = $"invalid #CONDITION specification: {args[0]}"; + } + break; + } + default: + { + status_str = $"invalid # specification: {args[0]}"; + break; + } + } + } + } + + // get the rest of the spawn entry + substitutedtypeName = args.Length > 1 ? args[1].Trim() : string.Empty; + } + + + if (substitutedtypeName.StartsWith("*")) + { + requiresurface = false; + substitutedtypeName = substitutedtypeName.TrimStart('*'); + } + + TheSpawn.RequireSurface = requiresurface; + + string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + + if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) + { + string status_str = null; + + bool completedtypespawn = BaseXmlSpawner.SpawnTypeKeyword(this, TheSpawn, typeName, substitutedtypeName, + m_mob_who_triggered, Map, out status_str, loops); + + if (status_str != null) + { + this.status_str = status_str; + } + + if (completedtypespawn) + { + // successfully spawned the keyword + // note that returning true means that Spawn will assume that it worked and will not try to respawn something else + // added the duration timer that begins on spawning + DoTimer2(m_Duration); + + InvalidateProperties(); + + return true; + } + + return false; + } + + // its a regular type descriptor so find out what it is + Type type = AssemblyHandler.FindTypeByName(typeName); + + // dont try to spawn invalid types, or Mobile type spawns in containers + if (type != null && !(Parent != null && (type == typeof(Mobile) || type.IsSubclassOf(typeof(Mobile))))) + { + + string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + + object o = CreateObject(type, arglist[0]); + + if (o == null) + { + status_str = $"invalid type specification: {arglist[0]}"; + return true; + } + try + { + if (o is Mobile mob) + { + // if this is in any container such as a pack the xyz values are invalid as map coords so dont spawn the mob + if (Parent is Container) + { + mob.Delete(); + + return true; + } + + // add the mobile to the spawned list + TheSpawn.SpawnedObjects.Add(mob); + + mob.Spawner = this; + + var loc = GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, mob); + + if (!smartspawn) + { + mob.OnBeforeSpawn(loc, map); + } + + mob.MoveToWorld(loc, map); + + if (mob is BaseCreature mobile) + { + mobile.RangeHome = m_HomeRange; + mobile.CurrentWayPoint = m_WayPoint; + + if (m_Team > 0) + { + mobile.Team = m_Team; + } + + // Check if this spawner uses absolute (from spawnER location) + // or relative (from spawnED location) as the mobiles home point + mobile.Home = m_HomeRangeIsRelative ? mobile.Location : Location; + } + + // if the object has an OnSpawned method, then invoke it + if (!smartspawn) + { + mob.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 + string status_str; + + BaseXmlSpawner.ApplyObjectStringProperties(this, substitutedtypeName, mob, m_mob_who_triggered, this, out status_str); + + if (status_str != null) + { + this.status_str = status_str; + } + + InvalidateProperties(); + + // added the duration timer that begins on spawning + DoTimer2(m_Duration); + + return true; + } + + if (o is Item item) + { + string status_str; + + BaseXmlSpawner.AddSpawnItem(this, TheSpawn, item, Location, map, m_mob_who_triggered, requiresurface, spawnpositioning, substitutedtypeName, smartspawn, out status_str); + + if (status_str != null) + { + this.status_str = status_str; + } + + InvalidateProperties(); + + // added the duration timer that begins on spawning + DoTimer2(m_Duration); + + return true; + } + } + catch (Exception ex) { Console.WriteLine("When spawning {0}, {1}", o, ex); } + } + else + { + status_str = $"invalid type specification: {typeName}"; + return true; + } + } + return false; + } + + public bool SpawnSubGroup(int sgroup, byte loops) => SpawnSubGroup(sgroup, false, loops); + + public bool SpawnSubGroup(int sgroup, bool smartspawn, byte loops) => SpawnSubGroup(sgroup, false, false, loops); + + public bool SpawnSubGroup(int sgroup, bool smartspawn, bool ignoreloopprotection, byte loops) + { + if (m_SpawnObjects == null) + { + return false; + } + + if (sgroup >= 0) + { + bool didspawn = false; + Point3D packcoord = Point3D.Zero; + + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject so = m_SpawnObjects[j]; + + if (so != null && so.SubGroup == sgroup) + { + // find the first subgroup spawn to determine the packspawning reference coordinates + if (so.PackRange >= 0 && packcoord == Point3D.Zero) + { + packcoord = GetPackCoord(sgroup); + } + + // get the SpawnsPerTick count and spawn up to that number + bool success = Spawn(j, smartspawn, so.SpawnsPerTick, so.PackRange, packcoord, ignoreloopprotection, loops); + + if (success) + { + didspawn = true; + } + + if (success && !smartspawn) + { + RefreshNextSpawnTime(so); + } + } + } + + // success if any of the subgroup spawned + if (didspawn) + { + return true; + } + } + return false; + } + + public Point3D GetPackCoord(int sgroup) + { + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + SpawnObject so = m_SpawnObjects[j]; + + if (so != null && so.SubGroup == sgroup && so.SpawnedObjects.Count > 0 && so.PackRange >= 0) + { + // if pack spawning is enabled for this subgroup, then get the + // the origin for pack spawning using the first existing pack spawn + // in the subgroup + + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + if (o is Item item) + { + return item.Location; + } + + if (o is Mobile mobile) + { + return mobile.Location; + } + } + } + } + + return Point3D.Zero; + } + + + //used by the reset button in the gump + public void ResetAllFlags() + { + m_proximityActivated = false; + m_ExternalTrigger = false; + m_durActivated = false; + m_refractActivated = false; + m_mob_who_triggered = null; + m_killcount = 0; + m_GumpState = null; + FreeRun = false; + } + + public bool BringHome + { + set { if (value) + { + BringToHome(); + } + } + } + + public void BringToHome() + { + if (m_SpawnObjects == null) + { + return; + } + + Defrag(false); + + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + if (o is Mobile mobile) + { + mobile.Map = Map; + mobile.Location = new Point3D(Location); + } + else if (o is Item item) + { + item.MoveToWorld(Location, Map); + } + } + } + } + + public bool CheckRegionAssignment + { + get => false; + set + { + if (value) + { + // see if a region definition needs updating + if (m_Region == null && m_RegionName != null && RegionName != string.Empty) + { + RegionName = RegionName; + + if (SpawnRegion != null) + { + // clear the status if successful + status_str = null; + } + } + } + } + } + + public void Start() + { + if (m_Running == false) + { + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + { + m_Running = true; + DoTimer(); + } + } + } + + public void Stop() + { + if (m_Running) + { + // turn off all timers + if (m_Timer != null) + { + m_Timer.Stop(); + } + + if (m_DurTimer != null) + { + m_DurTimer.Stop(); + } + + if (m_RefractoryTimer != null) + { + m_RefractoryTimer.Stop(); + } + + m_Running = false; + m_proximityActivated = false; + m_ExternalTrigger = false; + m_mob_who_triggered = null; + } + } + + public void Reset() + { + Stop(); + // reset the protection against runaway looping + ClearSpawnedThisTick = true; + RemoveSpawnObjects(); + ClearTags(true); + ResetAllFlags(); + status_str = ""; + m_killcount = 0; + OnHold = false; + mostRecentSpawnPosition = Point3D.Zero; + spawnPositionWayTable = null; + // dont advance before the next spawn + HoldSequence = true; + IsInactivated = false; + ResetSequential(); + } + + public void Respawn() + { + TryRespawn(); + } + + public bool TryRespawn() + { + inrespawn = true; + IsInactivated = false; + + // reset the protection against runaway looping + ClearSpawnedThisTick = true; + + // Delete all currently spawned objects + RemoveSpawnObjects(); + + // added the explicit start. Previously it relied on the automatic start that occurred when the spawnobject list was updated. + Start(); + + ResetNextSpawnTimes(); + + // Respawn all objects up to the spawners current maximum allowed + // note that by default, for proximity sensing, the spawner will only trigger once, but for respawns allow them all + bool keepProximityActivated = m_proximityActivated; + + bool triedtospawn = false; + + // attempt to spawn up to the MaxCount of the spawner + for (int x = 0; x < m_Count; x++) + { + triedtospawn = Spawn(false, 0); + + if (x < m_Count - 1 || OnHold) + { + m_proximityActivated = keepProximityActivated; + } + } + if (!FreeRun) + { + m_mob_who_triggered = null; + } + + ClearTags(true); + + inrespawn = false; + + return triedtospawn; + } + + // used to optimize smartspawning use of hasholdsmartspawning + public void SmartRespawn() + { + inrespawn = true; + IsInactivated = false; + + // reset the protection against runaway looping + ClearSpawnedThisTick = true; + + // Delete all currently spawned objects + SmartRemoveSpawnObjects(); + + // added the explicit start. Previously it relied on the automatic start that occurred when the spawnobject list was updated. + Start(); + + ResetNextSpawnTimes(); + + // Respawn all objects up to the spawners current maximum allowed + // note that by default, for proximity sensing, the spawner will only trigger once, but for respawns allow them all + bool keepProximityActivated = m_proximityActivated; + + // attempt to spawn up to the MaxCount of the spawner + for (int x = 0; x < m_Count; x++) + { + Spawn(true, 0); + + if (x < m_Count - 1 || OnHold) + { + m_proximityActivated = keepProximityActivated; + } + } + + if (!FreeRun) + { + m_mob_who_triggered = null; + } + + ClearTags(true); + + inrespawn = false; + } + + + public void SortSpawns() + { + if (m_SpawnObjects == null) + { + return; + } + + // establish the entry order + int count = 0; + + foreach (SpawnObject so in m_SpawnObjects) + { + so.EntryOrder = count++; + } + + m_SpawnObjects.Sort(new SubgroupSorter()); + } + + private class SubgroupSorter : IComparer + { + public int Compare(SpawnObject a, SpawnObject b) + { + if (a.SubGroup == b.SubGroup) + { + // use the entry order as the secondary sort factor + return a.EntryOrder - b.EntryOrder; + } + + return a.SubGroup - b.SubGroup; + } + } + + public static SpawnObject GetSpawnObject(XmlSpawner spawner, int sgroup) + { + if (spawner == null || spawner.m_SpawnObjects == null) + { + return null; + } + + for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + { + // find the first entry with matching subgroup id + if (spawner.m_SpawnObjects[i].SubGroup == sgroup) + { + return spawner.m_SpawnObjects[i]; + } + } + return null; + } + + public static object GetSpawned(XmlSpawner spawner, int sgroup) + { + if (spawner == null || spawner.m_SpawnObjects == null) + { + return null; + } + + for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + { + // find the first entry with matching subgroup id + if (spawner.m_SpawnObjects[i].SubGroup == sgroup) + { + // find the first spawned object in the entry + if (spawner.m_SpawnObjects[i].SpawnedObjects.Count > 0) + { + return spawner.m_SpawnObjects[i].SpawnedObjects[0]; + } + } + } + return null; + } + + public static List GetSpawnedList(XmlSpawner spawner, int sgroup) + { + List newlist = new List(); + + if (spawner == null || spawner.m_SpawnObjects == null) + { + return null; + } + + for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + { + // find the first entry with matching subgroup id + if (spawner.m_SpawnObjects[i].SubGroup == sgroup) + { + // find the first spawned object in the entry + + if (spawner.m_SpawnObjects[i].SpawnedObjects.Count > 0) + { + for (int j = 0; j < spawner.m_SpawnObjects[i].SpawnedObjects.Count; j++) + { + newlist.Add(spawner.m_SpawnObjects[i].SpawnedObjects[j]); + } + } + } + } + return newlist; + } + + public bool HasSubGroups() + { + if (m_SpawnObjects == null) + { + return false; + } + + for (int j = 0; j < m_SpawnObjects.Count; j++) + { + if (m_SpawnObjects[j].SubGroup > 0) + { + return true; + } + } + + return false; + } + + private void ResetProximityActivated() + { + // dont reset triggering if free run mode has been selected + if (!FreeRun) + { + m_proximityActivated = false; + } + } + + public bool HasIndividualSpawnTimes() + { + + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + { + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject so = m_SpawnObjects[i]; + + if (so.MinDelay != -1 || so.MaxDelay != -1) + { + return true; + } + } + } + return false; + } + + private void ResetNextSpawnTimes() + { + + if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + { + for (int i = 0; i < m_SpawnObjects.Count; i++) + { + SpawnObject so = m_SpawnObjects[i]; + + so.NextSpawn = DateTime.UtcNow; + } + } + } + + public void RefreshNextSpawnTime(SpawnObject so) + { + if (so == null) + { + return; + } + + int mind = (int)(so.MinDelay * 60); + int maxd = (int)(so.MaxDelay * 60); + if (mind < 0 || maxd < 0) + { + so.NextSpawn = DateTime.UtcNow; + } + else + { + + TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(mind, maxd)); + + so.NextSpawn = DateTime.UtcNow + delay; + } + + } + + public static bool IsValidMapLocation(int X, int Y, Map map) + { + if (map == null || map == Map.Internal) + { + return false; + } + + // check the location relative to the current map to make sure it is valid + if (X < 0 || X > map.Width || Y < 0 || Y > map.Height) + { + return false; + } + return true; + } + public static bool IsValidMapLocation(Point3D location, Map map) + { + if (map == null || map == Map.Internal) + { + return false; + } + + // check the location relative to the current map to make sure it is valid + if (location.X < 0 || location.X > map.Width || location.Y < 0 || location.Y > map.Height) + { + return false; + } + return true; + } + public static bool IsValidMapLocation(Point2D location, Map map) + { + if (map == null || map == Map.Internal) + { + return false; + } + + // check the location relative to the current map to make sure it is valid + if (location.X < 0 || location.X > map.Width || location.Y < 0 || location.Y > map.Height) + { + return false; + } + return true; + } + + private static WayPoint GetWaypoint(string waypointstr) + { + WayPoint waypoint = null; + + // try parsing the waypoint name to determine the waypoint. object syntax is "SERIAL,sernumber" or "waypointname" + if (!string.IsNullOrEmpty(waypointstr)) + { + string[] wayargs = BaseXmlSpawner.ParseString(waypointstr, 2, ","); + if (wayargs != null && wayargs.Length > 0) + { + // is this a SERIAL specification? + if (wayargs[0] == "SERIAL") + { + + // look it up by serial + if (wayargs.Length > 1) + { + uint sernum; + try + { + sernum = (uint)Convert.ToUInt64(wayargs[1][2..], 16); + IEntity e = World.FindEntity((Serial)sernum); + + if (e is WayPoint point) + { + waypoint = point; + } + } + catch { } + } + } + else + { + // just look it up by name + Item wayitem = BaseXmlSpawner.FindItemByName(null, wayargs[0], "WayPoint"); + if (wayitem is WayPoint point) + { + waypoint = point; + } + } + } + } + + return waypoint; + } + + private static bool HasTileSurface(Map map, int X, int Y, int Z) + { + if (map == null) + { + return false; + } + + StaticTile[] tiles = map.Tiles.GetStaticTiles(X, Y, true); + + if (tiles == null) + { + return false; + } + + // go through the tiles and see if any are at the Z location + foreach (StaticTile o in tiles) + { + StaticTile i = o; + + if (i.Z + i.Height == Z) + { + return true; + } + } + + return false; + } + + private bool CheckHoldSmartSpawning(object o) + { + if (o == null) + { + return false; + } + + // try looking this up in the lookup table + if (holdSmartSpawningHash == null) + { + holdSmartSpawningHash = new Dictionary(); + } + PropertyInfo prop; + if (!holdSmartSpawningHash.TryGetValue(o.GetType(), out prop)) + { + prop = o.GetType().GetProperty("HoldSmartSpawning"); + // check to make sure the HoldSmartSpawning property for this object has the right type + if (prop != null && (!prop.CanRead || prop.PropertyType != typeof(bool))) + { + prop = null; + } + + holdSmartSpawningHash[o.GetType()] = prop; + } + + if (prop != null) + { + try + { + return (bool)prop.GetValue(o, null); + } + catch { } + } + + return false; + } + + public bool HasHoldSmartSpawning + { + get + { + // go through the spawn lists + foreach (SpawnObject so in m_SpawnObjects) + { + for (int x = 0; x < so.SpawnedObjects.Count; x++) + { + object o = so.SpawnedObjects[x]; + if (CheckHoldSmartSpawning(o)) + { + return true; + } + } + } + + return false; + } + } + + // if a non-null mob argument is passed, then check the canswim and cantwalk props to determine valid placement + public bool CanFit(int x, int y, int z, int height, bool checkBlocksFit, bool checkMobiles, bool requireSurface, Mobile mob) + { + Map map = Map; + + if (DebugThis) + { + Console.WriteLine("CanFit mob {0}, map={1}", mob, map); + } + if (map == null || map == Map.Internal) + { + return false; + } + + if (x < 0 || y < 0 || x >= map.Width || y >= map.Height) + { + return false; + } + + bool hasSurface = false; + bool checkmob = false; + bool canswim = false; + bool cantwalk = false; + + if (mob != null) + { + checkmob = true; + canswim = mob.CanSwim; + cantwalk = mob.CantWalk; + } + if (DebugThis) + { + Console.WriteLine("fitting mob {0} checkmob={1} swim={2} walk={3}", mob, checkmob, canswim, cantwalk); + } + LandTile lt = map.Tiles.GetLandTile(x, y); + + bool surface; + bool wet = false; + + map.GetAverageZ(x, y, out var lowZ, out var avgZ, out var topZ); + TileFlag landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; + + if (DebugThis) + { + Console.WriteLine("landtile at {0},{1},{2} lowZ={3} avgZ={4} topZ={5}", x, y, z, lowZ, avgZ, topZ); + } + + var impassable = (landFlags & TileFlag.Impassable) != 0; + if (checkmob) + { + wet = (landFlags & TileFlag.Wet) != 0; + // dont allow wateronly creatures on land + if (cantwalk && !wet) + { + impassable = true; + } + + // allow water creatures on water + if (canswim && wet) + { + impassable = false; + } + } + + if (impassable && avgZ > z && z + height > lowZ) + { + return false; + } + + if (!impassable && z == avgZ && !lt.Ignored) + { + hasSurface = true; + } + + if (DebugThis) + { + Console.WriteLine("landtile at {0},{1},{2} wet={3} impassable={4} hassurface={5}", x, y, z, wet, impassable, hasSurface); + } + + StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y, true); + + for (int i = 0; i < staticTiles.Length; ++i) + { + ItemData id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; + surface = id.Surface; + impassable = id.Impassable; + if (checkmob) + { + wet = (id.Flags & TileFlag.Wet) != 0; + // dont allow wateronly creatures on land + if (cantwalk && !wet) + { + impassable = true; + } + + // allow water creatures on water + if (canswim && wet) + { + surface = true; + impassable = false; + } + } + + if ((surface || impassable) && staticTiles[i].Z + id.CalcHeight > z && z + height > staticTiles[i].Z) + { + return false; + } + + if (surface && !impassable && z == staticTiles[i].Z + id.CalcHeight) + { + hasSurface = true; + } + } + if (DebugThis) + { + Console.WriteLine("statics hassurface={0}", hasSurface); + } + + Sector sector = map.GetSector(x, y); + List items = sector.Items; + List mobs = sector.Mobiles; + + for (int i = 0; i < items.Count; ++i) + { + Item item = items[i]; + + if (item.ItemID < 0x4000 && item.AtWorldPoint(x, y)) + { + ItemData id = item.ItemData; + surface = id.Surface; + impassable = id.Impassable; + if (checkmob) + { + wet = (id.Flags & TileFlag.Wet) != 0; + // dont allow wateronly creatures on land + if (cantwalk && !wet) + { + impassable = true; + } + + // allow water creatures on water + if (canswim && wet) + { + surface = true; + impassable = false; + } + } + + if ((surface || impassable || checkBlocksFit && item.BlocksFit) && item.Z + id.CalcHeight > z && z + height > item.Z) + { + return false; + } + + if (surface && !impassable && !item.Movable && z == item.Z + id.CalcHeight) + { + hasSurface = true; + } + } + } + + if (DebugThis) + { + Console.WriteLine("items hassurface={0}", hasSurface); + } + + if (checkMobiles) + { + for (int i = 0; i < mobs.Count; ++i) + { + Mobile m = mobs[i]; + + if (m.Location.X == x && m.Location.Y == y && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + { + if (m.Z + 16 > z && z + height > m.Z) + { + return false; + } + } + } + } + + if (DebugThis) + { + Console.WriteLine("return requiresurface={0} hassurface={1}", requireSurface, hasSurface); + } + + return !requireSurface || hasSurface; + } + + public bool CanSpawnMobile(int x, int y, int z, Mobile mob) + { + if (DebugThis) + { + Console.WriteLine("CanSpawnMobile mob {0}", mob); + } + + return Region.Find(new Point3D(x, y, z), Map).AllowSpawn() && Map.CanFit(x, y, z, 16); + } + + public static bool HasRegionPoints(Region r) => r != null && r.Area.Length > 0; + + public Rectangle2D SpawnerBounds => new(m_X, m_Y, m_Width + 1, m_Height + 1); + + private void FindTileLocations(ref List locations, Map map, int startx, int starty, int width, int height, List includetilelist, List excludetilelist, TileFlag tileflag, bool checkitems, int spawnerZ) + { + if (width < 0 || height < 0 || map == null) + { + return; + } + + if (locations == null) + { + locations = new List(); + } + + bool includetile; + bool excludetile; + + for (int x = startx; x <= startx + width; x++) + { + for (int y = starty; y <= starty + height; y++) + { + bool allok = false; + Point3D p = Point3D.Zero; + // go through all of the tiles at the location and find those that are in the allowed tiles list + LandTile ltile = map.Tiles.GetLandTile(x, y); + TileFlag lflags = TileData.LandTable[ltile.ID & TileData.MaxLandValue].Flags; + + // check the land tile + if (includetilelist != null && includetilelist.Count > 0) + { + includetile = includetilelist.Contains(ltile.ID & TileData.MaxLandValue); + } + else + { + includetile = true; + } + + // non-excluded tiles must also be passable + if (excludetilelist != null && excludetilelist.Count > 0) + { + // also require the tile to be passable + excludetile = (lflags & TileFlag.Impassable) != 0 || excludetilelist.Contains(ltile.ID & TileData.MaxLandValue); + } + else + { + excludetile = false; + } + + if (includetile && !excludetile && (lflags & tileflag) == tileflag) + { + p = new Point3D(x, y, ltile.Z + ltile.Height); + allok = true; + } + + StaticTile[] statictiles = map.Tiles.GetStaticTiles(x, y, true); + + // check the static tiles + for (int i = 0; i < statictiles.Length; ++i) + { + StaticTile stile = statictiles[i]; + TileFlag sflags = TileData.ItemTable[stile.ID & TileData.MaxItemValue].Flags; + + if (includetilelist != null && includetilelist.Count > 0) + { + includetile = includetilelist.Contains(stile.ID & TileData.MaxItemValue); + } + else + { + includetile = true; + } + + // non-excluded tiles must also be passable + if (excludetilelist != null && excludetilelist.Count > 0) + { + excludetile = (sflags & TileFlag.Impassable) != 0 || excludetilelist.Contains(stile.ID & TileData.MaxItemValue); + } + else + { + excludetile = false; + } + + if (includetile && !excludetile && (sflags & tileflag) == tileflag) + { + //Console.WriteLine("found statictile {0}/{1} at {2},{3},{4}", stile.ID, stile.ID & 0x3fff, x, y, stile.Z + stile.Height); + if (p == Point3D.Zero) + { + p = new Point3D(x, y, stile.Z + stile.Height); + } + else if (!allok && p.Z - spawnerZ > Math.Abs(stile.Z - spawnerZ)) + { + p = new Point3D(x, y, stile.Z + stile.Height); + } + else if (Math.Abs(ltile.Z - spawnerZ) > Math.Abs(stile.Z - spawnerZ)) //maggiore distanza rispetto allo statico dallo spawner + { + p = new Point3D(x, y, stile.Z + stile.Height); + } + + allok = true; + //locations.Add(new Point3D(x, y, stile.Z + stile.Height)); + //break; + } + } + + if (checkitems) + { + IPooledEnumerable itemslist = map.GetItemsInRange(new Point3D(x, y, 0), 0); + + // check the itemsid + foreach (Item i in itemslist) + { + if (i.ItemData.Impassable) + { + excludetile = true; + } + + TileFlag iflags = TileData.ItemTable[i.ItemID & TileData.MaxItemValue].Flags; + if (includetilelist != null && includetilelist.Count > 0) + { + includetile = includetilelist.Contains(i.ItemID & TileData.MaxItemValue); + } + else + { + includetile = true; + } + + if (excludetilelist != null && excludetilelist.Count > 0) + { + excludetile = excludetilelist.Contains(i.ItemID & TileData.MaxItemValue); + } + else + { + excludetile = false; + } + + if (includetile && !excludetile && (iflags & tileflag) == tileflag) + { + p = new Point3D(x, y, i.Z + i.ItemData.Height); + allok = true; + } + } + + itemslist.Free(); + } + + if (allok && !excludetile) + { + locations.Add(p); + } + } + } + } + + private void FindRegionTileLocations(ref List locations, Region r, List includetilelist, List excludetilelist, TileFlag tileflag, bool checkitems, int spawnerZ) + { + if (r == null || r.Area == null) + { + return; + } + + int count = r.Area.Length; + + if (locations == null) + { + locations = new List(); + } + + // calculate fields of all rectangles (for probability calculating) + for (int n = 0; n < count; n++) + { + Rectangle3D ra = r.Area[n]; + int sx = ra.Start.X; + int sy = ra.Start.Y; + int w = ra.Width; + int h = ra.Height; + + // find all of the valid tile locations in the area + FindTileLocations(ref locations, r.Map, sx, sy, w, h, includetilelist, excludetilelist, tileflag, checkitems, spawnerZ); + } + } + + public Point2D GetRandomRegionPoint(Region r) + { + int count = r.Area.Length; + + int[] FieldArray = new int[count]; + int total = 0; + + // calculate fields of all rectangles (for probability calculating) + for (int i = 0; i < count; i++) + { + Rectangle3D ra = r.Area[i]; + total += FieldArray[i] = ra.Width * ra.Height; + } + + int sum = 0; + int rnd = 0; + if (total > 0) + { + rnd = Utility.Random(total); + } + + int x = 0; + int y = 0; + for (int i = 0; i < count; i++) + { + sum += FieldArray[i]; + if (sum > rnd) + { + Rectangle3D r3d = r.Area[i]; + if (r3d.Width >= 0) + { + x = r3d.Start.X + Utility.Random(r3d.Width); + } + + if (r3d.Height >= 0) + { + y = r3d.Start.Y + Utility.Random(r3d.Height); + } + + break; + } + } + + return new Point2D(x, y); + } + + public Point3D GetSpawnPosition(ISpawnable spawned, Map map) => GetSpawnPosition(true, spawned as Mobile); + + // used for getting non-mobile spawn positions + public Point3D GetSpawnPosition(bool requiresurface) => + // no pack spawning + GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, null); + + // used for getting mobile spawn positions + public Point3D GetSpawnPosition(bool requiresurface, Mobile mob) => + // no pack spawning + GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, mob); + + // used for getting non-mobile spawn positions + public Point3D GetSpawnPosition( + bool requiresurface, + int packrange, + Point3D packcoord, + List spawnpositioning + ) => GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, null); + + public Point3D GetSpawnPosition(bool requiresurface, int packrange, Point3D packcoord, List spawnpositioning, Mobile mob) + { + Map map = Map; + + if (map == null) + { + return Location; + } + + // random positioning by default + SpawnPositionType positioning = SpawnPositionType.Random; + Mobile trigmob = null; + List includetilelist = null; + List excludetilelist = null; + bool checkitems = false; + // restrictions on tile flags + TileFlag tileflag = TileFlag.None; + List locations = null; + + int fillinc = 1; + int positionrange = 0; + string prefix = null; + List WayList = null; + int xinc = 0; + int yinc = 0; + int zinc = 0; + if (spawnpositioning != null) + { + foreach (SpawnPositionInfo s in spawnpositioning) + { + if (s == null) + { + continue; + } + + trigmob = s.trigMob; + string[] positionargs = s.positionArgs; + + // parse the possible args to the spawn position control keywords + switch (s.positionType) + { + case SpawnPositionType.Wet: + { + // syntax Wet + // find all of the wet tiles + tileflag |= TileFlag.Wet; + requiresurface = false; + break; + } + case SpawnPositionType.ItemID: + { + checkitems = true; + goto case SpawnPositionType.Tiles; + } + case SpawnPositionType.NoItemID: + { + checkitems = true; + goto case SpawnPositionType.NoTiles; + } + case SpawnPositionType.Tiles: + { + // syntax Tiles,start[,end] + // get the tiles in the range + requiresurface = false; + int start = -1; + int end = -1; + if (positionargs != null && positionargs.Length > 1) + { + try + { + start = int.Parse(positionargs[1]); + } + catch { } + } + if (positionargs != null && positionargs.Length > 2) + { + try + { + end = int.Parse(positionargs[2]); + } + catch { } + } + if (includetilelist == null) + { + includetilelist = new List(); + } + + // add the tiles to the list + if (start > -1 && end < 0) + { + includetilelist.Add(start); + } + else + if (start > -1 && end > -1) + { + for (int j = start; j <= end; j++) + { + includetilelist.Add(j); + } + } + break; + } + case SpawnPositionType.NoTiles: + { + // syntax Tiles,start[,end] + // get the tiles in the range + requiresurface = false; + int start = -1; + int end = -1; + if (positionargs != null && positionargs.Length > 1) + { + try + { + start = int.Parse(positionargs[1]); + } + catch { } + } + if (positionargs != null && positionargs.Length > 2) + { + try + { + end = int.Parse(positionargs[2]); + } + catch { } + } + if (excludetilelist == null) + { + excludetilelist = new List(); + } + + // add the tiles to the list + if (start > -1 && end < 0) + { + excludetilelist.Add(start); + } + else + if (start > -1 && end > -1) + { + for (int j = start; j <= end; j++) + { + excludetilelist.Add(j); + } + } + break; + } + case SpawnPositionType.RowFill: + case SpawnPositionType.ColFill: + case SpawnPositionType.Perimeter: + { + // syntax XFILL[,inc] + // syntax YFILL[,inc] + // syntax EDGE[,inc] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) + { + try + { + fillinc = int.Parse(positionargs[1]); + } + catch { } + } + break; + } + case SpawnPositionType.RelXY: + case SpawnPositionType.DeltaLocation: + case SpawnPositionType.Location: + { + // syntax RELXY,xinc,yinc[,zinc] + // syntax XY,x,y[,z] + // syntax DXY,dx,dy[,dz] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 2) + { + try + { + xinc = int.Parse(positionargs[1]); + yinc = int.Parse(positionargs[2]); + } + catch { } + } + if (positionargs != null && positionargs.Length > 3) + { + try + { + zinc = int.Parse(positionargs[3]); + } + catch { } + } + break; + } + case SpawnPositionType.Waypoint: + { + // syntax WAYPOINT,prefix[,range] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) + { + prefix = positionargs[1]; + } + + if (positionargs != null && positionargs.Length > 2) + { + try + { + positionrange = int.Parse(positionargs[2]); + } + catch { } + } + + // find a list of items that match the waypoint prefix + if (prefix != null) + { + // see if there is an existing hashtable for the waypoint lists + if (spawnPositionWayTable == null) + { + spawnPositionWayTable = new Dictionary>(); + } + + // no existing list so create a new one + if (!spawnPositionWayTable.TryGetValue(prefix, out WayList) || WayList == null) + { + WayList = new List(); + + foreach (Item i in World.Items.Values) + { + if (i is WayPoint && !string.IsNullOrEmpty(i.Name) && i.Map == Map && i.Name == prefix) + { + // add it to the list of items + WayList.Add(i); + } + } + // add the new list to the local table + spawnPositionWayTable[prefix] = WayList; + } + } + break; + } + case SpawnPositionType.Player: + { + // syntax PLAYER[,range] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) + { + try + { + positionrange = int.Parse(positionargs[1]); + } + catch { } + } + break; + } + } + } + } + + // precalculate tile locations if they have been specified + if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) + { + if (m_Region != null && HasRegionPoints(m_Region)) + { + FindRegionTileLocations(ref locations, m_Region, includetilelist, excludetilelist, tileflag, checkitems, Z); + } + else if (positioning == SpawnPositionType.Random) + { + FindTileLocations(ref locations, Map, m_X, m_Y, m_Width, m_Height, includetilelist, excludetilelist, tileflag, checkitems, Z); + } + } + + // Try 10 times to find a Spawnable location. + // trace profiling indicates that this is a major bottleneck + for (int i = 0; i < 10; i++) + { + int x = X; + int y = Y; + int z = Z; + + int defaultZ = Z; + if (packrange >= 0 && packcoord != Point3D.Zero) + { + defaultZ = packcoord.Z; + } + + if (packrange >= 0 && packcoord != Point3D.Zero) + { + // find a random coord relative to the packcoord + x = packcoord.X - packrange + Utility.Random(packrange * 2 + 1); + y = packcoord.Y - packrange + Utility.Random(packrange * 2 + 1); + } + else if (m_Region != null && HasRegionPoints(m_Region)) + { + // if region spawning is selected then use that to find an x,y loc instead of the spawn box + + if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) + { + // use the precalculated tile locations + if (locations != null && locations.Count > 0) + { + Point3D p = locations[Utility.Random(locations.Count)]; + x = p.X; + y = p.Y; + defaultZ = p.Z; + } + } + else + { + Point2D p = GetRandomRegionPoint(m_Region); + x = p.X; + y = p.Y; + } + } + else + { + switch (positioning) + { + case SpawnPositionType.Random: + { + if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) + { + + if (locations != null && locations.Count > 0) + { + Point3D p = locations[Utility.Random(locations.Count)]; + x = p.X; + y = p.Y; + defaultZ = p.Z; + } + } + else + { + + if (m_Width > 0) + { + x = m_X + Utility.Random(m_Width + 1); + } + + if (m_Height > 0) + { + y = m_Y + Utility.Random(m_Height + 1); + } + } + break; + } + + case SpawnPositionType.RelXY: + { + x = mostRecentSpawnPosition.X + xinc; + y = mostRecentSpawnPosition.Y + yinc; + defaultZ = mostRecentSpawnPosition.Z + zinc; + break; + } + + case SpawnPositionType.DeltaLocation: + { + x = X + xinc; + y = Y + yinc; + defaultZ = Z + zinc; + break; + } + + case SpawnPositionType.Location: + { + x = xinc; + y = yinc; + defaultZ = zinc; + break; + } + + case SpawnPositionType.RowFill: + { + x = mostRecentSpawnPosition.X + fillinc; + y = mostRecentSpawnPosition.Y; + + if (x < m_X) + { + x = m_X; + } + + if (y < m_Y) + { + y = m_Y; + } + + if (x > m_X + m_Width) + { + x = m_X + (x - m_X - m_Width - 1); + y++; + } + + if (y > m_Y + m_Height) + { + y = m_Y; + } + + break; + } + + case SpawnPositionType.ColFill: + { + x = mostRecentSpawnPosition.X; + y = mostRecentSpawnPosition.Y + fillinc; + + if (x < m_X) + { + x = m_X; + } + + if (y < m_Y) + { + y = m_Y; + } + + if (y > m_Y + m_Height) + { + y = m_Y + (y - m_Y - m_Height - 1); + x++; + } + + if (x > m_X + m_Width) + { + x = m_X; + } + + break; + } + + case SpawnPositionType.Perimeter: + { + x = mostRecentSpawnPosition.X; + y = mostRecentSpawnPosition.Y; + + // if the point is not on the perimeter, reset it to the corner + if (x != m_X && x != m_X + m_Width && y != m_Y && y != m_Y + m_Height) + { + x = m_X; + y = m_Y; + } + + if (y == m_Y && x < m_X + m_Width) + { + x += fillinc; + } + else + if (y == m_Y + m_Height && x > m_X) + { + x -= fillinc; + } + else + if (x == m_X && y > m_Y) + { + y -= fillinc; + } + else + if (x == m_X + m_Width && y < m_Y + m_Height) + { + y += fillinc; + } + + if (x > m_X + m_Width) + { + x = m_X + m_Width; + } + + if (y > m_Y + m_Height) + { + y = m_Y + m_Height; + } + + if (x < m_X) + { + x = m_X; + } + + if (y < m_Y) + { + y = m_Y; + } + + break; + } + + case SpawnPositionType.Player: + { + if (trigmob != null) + { + x = trigmob.Location.X; + y = trigmob.Location.Y; + if (positionrange > 0) + { + x += Utility.Random(positionrange * 2 + 1) - positionrange; + y += Utility.Random(positionrange * 2 + 1) - positionrange; + } + } + break; + } + + case SpawnPositionType.Waypoint: + { + // pick an item randomly from the waylist + if (WayList != null && WayList.Count > 0) + { + int index = Utility.Random(WayList.Count); + Item waypoint = WayList[index]; + if (waypoint != null) + { + x = waypoint.Location.X; + y = waypoint.Location.Y; + defaultZ = waypoint.Location.Z; + if (positionrange > 0) + { + x += Utility.Random(positionrange * 2 + 1) - positionrange; + y += Utility.Random(positionrange * 2 + 1) - positionrange; + } + } + } + + break; + } + } + + mostRecentSpawnPosition = new Point3D(x, y, defaultZ); + } + + // skip invalid points + if (x < 0 || y < 0 || x == 0 && y == 0) + { + continue; + } + + // try to find a valid spawn location using the z coord of the spawner + // relax the normal surface requirement for mobiles if the flag is set + var fit = requiresurface ? CanSpawnMobile(x, y, defaultZ, mob) : Map.CanFit(x, y, defaultZ, SpawnFitSize, true, false, false); + + // if that fails then try to find a valid z coord + if (fit) + { + return new Point3D(x, y, defaultZ); + } + + z = Map.GetAverageZ(x, y); + + fit = requiresurface ? CanSpawnMobile(x, y, z, mob) : Map.CanFit(x, y, z, SpawnFitSize, true, false, false); + + if (fit) + { + return new Point3D(x, y, z); + } + } + + if (packrange >= 0 && packcoord != Point3D.Zero) + { + return packcoord; + } + + return Location; + } + + public int GetCreatureMax(int index) + { + Defrag(false); + + if (m_SpawnObjects == null) + { + return 0; + } + + return m_SpawnObjects[index].MaxCount; + } + + private void DeleteFromList(List list) + { + if (list == null) + { + return; + } + + foreach (object o in list) + { + if (o is Item item) + { + item.Delete(); + } + else if (o is Mobile mobile) + { + mobile.Delete(); + } + } + } + + private void DeleteFromList(List listi, List listm) + { + if (listi != null) + { + int i = listi.Count; + + while (--i >= 0) + { + if (i < listi.Count && listi[i] != null) + { + try + { + listi[i].Delete(); + } + catch + { } + } + } + + listi.Clear(); + } + + if (listm != null) + { + int i = listm.Count; + + while (--i >= 0) + { + if (i < listm.Count && listm[i] != null) + { + try + { + listm[i].Delete(); + } + catch + { } + } + } + + listm.Clear(); + } + } + + public void RemoveSpawnObjects() + { + if (m_SpawnObjects == null) + { + return; + } + + Defrag(false); + + ClearTags(true); + List deletelist = new List(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + if (o is Item || o is Mobile) + { + deletelist.Add(o); + } + } + } + + DeleteFromList(deletelist); + + // Defrag again + Defrag(false); + } + + + public void RemoveSpawnObjects(SpawnObject so) + { + if (so == null) + { + return; + } + + Defrag(false); + + List deletelist = new List(); + + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + if (o is Item || o is Mobile) + { + deletelist.Add(o); + } + } + + DeleteFromList(deletelist); + + // Defrag again + Defrag(false); + } + + public void ClearSubgroup(int subgroup) + { + if (m_SpawnObjects == null) + { + return; + } + + Defrag(false); + + ClearTags(true); + List deletelist = new List(); + foreach (SpawnObject so in m_SpawnObjects) + { + if (so.SubGroup != subgroup || !so.ClearOnAdvance) + { + continue; + } + + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + if (o is Item || o is Mobile) + { + deletelist.Add(o); + } + } + } + + DeleteFromList(deletelist); + + // Defrag again + Defrag(false); + } + + + // used to optimize smart spawning by removing all objects except those that have hold smartspawning + public void SmartRemoveSpawnObjects() + { + if (m_SpawnObjects == null) + { + return; + } + + Defrag(false); + + ClearTags(true); + List deletelist = new List(); + foreach (SpawnObject so in m_SpawnObjects) + { + for (int i = 0; i < so.SpawnedObjects.Count; ++i) + { + object o = so.SpawnedObjects[i]; + + // new optimization for smart spawning to remove all objects except those with hold smartspawning enabled + if (CheckHoldSmartSpawning(o)) + { + continue; + } + + if (o is Item || o is Mobile) + { + deletelist.Add(o); + } + } + } + + DeleteFromList(deletelist); + + // Defrag again + Defrag(false); + } + + public void AddSpawnObject(string SpawnObjectName) + { + if (m_SpawnObjects == null) + { + return; + } + + Defrag(false); + + // Find the spawn object and increment its count by one + foreach (SpawnObject so in m_SpawnObjects) + { + if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper()) + { + // Add one to the total count + m_Count++; + + // Increment the max count for the current creature + so.ActualMaxCount++; + + //only spawn them immediately if the spawner is running + if (Running) + { + Spawn(SpawnObjectName, false, 0); + } + } + } + + InvalidateProperties(); + } + + public void DeleteSpawnObject(Mobile from, string SpawnObjectName) + { + bool WasRunning = m_Running; + + try + { + // Stop spawning for a moment + Stop(); + + // Clean up any spawns marked as deleted + Defrag(false); + + // Keep a reference to the spawn object + SpawnObject TheSpawn = null; + + // Find the spawn object and increment its count by one + foreach (SpawnObject so in m_SpawnObjects) + { + if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper()) + { + // Set the spawn + TheSpawn = so; + break; + } + } + + // Was the spawn object found + if (TheSpawn != null) + { + bool delete_this_entry = false; + + // Decrement the max count for the current creature + TheSpawn.ActualMaxCount--; + + // Make sure the spawn count does not go negative + if (TheSpawn.MaxCount < 0) + { + TheSpawn.MaxCount = 0; + delete_this_entry = true; + } + + if (!delete_this_entry) + { + // Subtract one to the total count + m_Count--; + } + + // Make sure the count does not go negative + if (m_Count < 0) + { + m_Count = 0; + + } + + List deletelist = new List(); + + // Remove any spawns over the count + while (TheSpawn.SpawnedObjects != null && TheSpawn.SpawnedObjects.Count > 0 && TheSpawn.SpawnedObjects.Count > TheSpawn.MaxCount) + { + object o = TheSpawn.SpawnedObjects[0]; + + // Delete the object + if (o is Item || o is Mobile) + { + deletelist.Add(o); + } + + TheSpawn.SpawnedObjects.Remove(o); + } + + DeleteFromList(deletelist); + + // Check if the spawn object should be removed + if (delete_this_entry) + { + m_SpawnObjects.Remove(TheSpawn); + if (from != null) + { + CommandLogging.WriteLine(from, "{0} {1} removed from XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7}", from.AccessLevel, CommandLogging.Format(from), Serial, Name, GetWorldLocation().X, GetWorldLocation().Y, Map, SpawnObjectName); + } + } + } + + InvalidateProperties(); + } + finally + { + if (WasRunning) + { + Start(); + } + } + } + + public void RemoveSpawnObject(SpawnObject so) + { + if (m_SpawnObjects.Contains(so)) + { + m_SpawnObjects.Remove(so); + } + } + + public static object CreateObject(Type type, string itemtypestring) => CreateObject(type, itemtypestring, true); + + public static object CreateObject(Type type, string itemtypestring, bool requireConstructible) + { + // look for constructor arguments to be passed to it with the syntax type,arg1,arg2,.../ + string[] typewordargs = BaseXmlSpawner.ParseObjectArgs(itemtypestring); + + return CreateObject(type, typewordargs, requireConstructible); + } + + public static object CreateObject(Type type, string[] typewordargs, bool requireConstructible) + { + if (type == null) + { + return null; + } + + object o = null; + + int typearglen = 0; + if (typewordargs != null) + { + typearglen = typewordargs.Length; + } + + // ok, there are args in the typename, so we need to invoke the proper constructor + ConstructorInfo[] ctors = type.GetConstructors(); + + // go through all the constructors for this type + for (int i = 0; i < ctors.Length; ++i) + { + ConstructorInfo ctor = ctors[i]; + + // if requireConstructible is true, then allow either condition +#if (RESTRICTConstructible) + if (!(requireConstructible && Add.IsConstructible(ctor,requester))) + continue; +#else + if (!(requireConstructible && IsConstructible(ctor))) + { + continue; + } +#endif + + // check the parameter list of the constructor + ParameterInfo[] paramList = ctor.GetParameters(); + + // and compare with the argument list provided + if (typearglen == paramList.Length) + { + // this is a constructor that takes args and matches the number of args passed in to CreateObject + if (paramList.Length > 0) + { + object[] paramValues = null; + + try + { + paramValues = Add.ParseValues(paramList, typewordargs); + } + catch { } + + if (paramValues == null) + { + continue; + } + + // ok, have a match on args, so try to construct it + try + { + o = Activator.CreateInstance(type, paramValues); + } + catch { } + } + else + { + // zero argument constructor + try + { + o = Activator.CreateInstance(type); + } + catch { } + } + + // successfully constructed the object, otherwise try another matching constructor + if (o != null) + { + break; + } + } + } + + return o; + } + + private static void DoGlobalSectorTimer(TimeSpan delay) + { + if (m_GlobalSectorTimer != null) + { + m_GlobalSectorTimer.Stop(); + } + + m_GlobalSectorTimer = new GlobalSectorTimer(delay); + + m_GlobalSectorTimer.Start(); + } + + private class GlobalSectorTimer : Timer + { + + public GlobalSectorTimer(TimeSpan delay) : base(delay, delay) + { + } + + protected override void OnTick() + { + // check the sectors + + // check all active players + foreach (NetState state in TcpServer.Instances) + { + Mobile m = state.Mobile; + + if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden)) + { + // activate any spawner in the sector they are in + if (m.Map != null && m.Map != Map.Internal) + { + Sector s = m.Map.GetSector(m.Location); + + if (s != null && GlobalSectorTable[m.Map.MapID] != null) + { + + List spawnerlist; // = GlobalSectorTable[m.Map.MapID][s]; + if (GlobalSectorTable[m.Map.MapID].TryGetValue(s, out spawnerlist) && spawnerlist != null) + { + foreach (XmlSpawner spawner in spawnerlist) + { + + if (spawner != null && !spawner.Deleted && spawner.Running && spawner.SmartSpawning && spawner.IsInactivated) + { + spawner.SmartRespawn(); + } + } + } + } + } + } + } + } + } + + public void DoSectorTimer(TimeSpan delay) + { + if (m_SectorTimer != null) + { + m_SectorTimer.Stop(); + } + + m_SectorTimer = new SectorTimer(this, delay); + + m_SectorTimer.Start(); + } + + private class SectorTimer : Timer + { + private readonly XmlSpawner m_Spawner; + + public SectorTimer(XmlSpawner spawner, TimeSpan delay) : base(delay, delay) => m_Spawner = spawner; + + protected override void OnTick() + { + // check the sectors + if (m_Spawner != null && !m_Spawner.Deleted && m_Spawner.Running && m_Spawner.IsInactivated) + { + if (m_Spawner.SmartSpawning) + { + if (m_Spawner.HasActiveSectors) + { + Stop(); + + m_Spawner.SmartRespawn(); + } + } + else + { + Stop(); + + m_Spawner.IsInactivated = false; + } + } + else + { + Stop(); + + } + } + } + + private class WarnTimer2 : Timer + { + private readonly List m_List; + + private class WarnEntry2 + { + public Point3D m_Point; + public Map m_Map; + public string m_Name; + + public WarnEntry2(Point3D p, Map map, string name) + { + m_Point = p; + m_Map = map; + m_Name = name; + } + } + + public WarnTimer2() + : base(TimeSpan.FromSeconds(1.0)) + { + m_List = new List(); + Start(); + } + + public void Add(Point3D p, Map map, string name) + { + m_List.Add(new WarnEntry2(p, map, name)); + } + + protected override void OnTick() + { + try + { + Console.WriteLine("Warning: {0} bad spawns detected, logged: 'badspawn.log'", m_List.Count); + + using (StreamWriter op = new StreamWriter("badspawn.log", true)) + { + op.WriteLine("# Bad spawns : {0}", DateTime.UtcNow); + op.WriteLine("# Format: X Y Z F Name"); + op.WriteLine(); + + foreach (WarnEntry2 e in m_List) + { + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", e.m_Point.X, e.m_Point.Y, e.m_Point.Z, e.m_Map, e.m_Name); + } + + op.WriteLine(); + op.WriteLine(); + } + } + catch + { } + } + } + + public void DoTimer() + { + if (!m_Running) + { + return; + } + + int minSeconds = (int)m_MinDelay.TotalSeconds; + int maxSeconds = (int)m_MaxDelay.TotalSeconds; + + TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds)); + DoTimer(delay); + } + + public void DoTimer(TimeSpan delay) + { + if (!m_Running) + { + return; + } + + m_End = DateTime.UtcNow + delay; + + if (m_Timer != null) + { + m_Timer.Stop(); + } + + m_Timer = new SpawnerTimer(this, delay); + m_Timer.Start(); + } + + public void DoTimer2(TimeSpan delay) + { + m_DurEnd = DateTime.UtcNow + delay; + if (m_Duration > TimeSpan.FromMinutes(0) || m_durActivated) + { + if (m_DurTimer != null) + { + m_DurTimer.Stop(); + } + + m_DurTimer = new InternalTimer(this, delay); + m_DurTimer.Start(); + m_durActivated = true; + } + } + + public void DoTimer3(TimeSpan delay) + { + m_RefractEnd = DateTime.UtcNow + delay; + m_refractActivated = true; + + if (m_RefractoryTimer != null) + { + m_RefractoryTimer.Stop(); + } + + m_RefractoryTimer = new InternalTimer3(this, delay); + m_RefractoryTimer.Start(); + } + + // added the duration timer that begins on spawning + private class InternalTimer : Timer + { + private readonly XmlSpawner m_spawner; + + public InternalTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_spawner = spawner; + + protected override void OnTick() + { + if (m_spawner != null && !m_spawner.Deleted) + { + m_spawner.RemoveSpawnObjects(); + m_spawner.m_durActivated = false; + } + + } + } + + private class SpawnerTimer : Timer + { + private readonly XmlSpawner m_Spawner; + + public SpawnerTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_Spawner = spawner; + + protected override void OnTick() + { + if (m_Spawner != null && !m_Spawner.Deleted) + { + m_Spawner.OnTick(); + } + } + } + + // added the refractory timer that begins on proximity triggering + private class InternalTimer3 : Timer + { + private readonly XmlSpawner m_spawner; + + public InternalTimer3(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_spawner = spawner; + + protected override void OnTick() + { + if (m_spawner != null && !m_spawner.Deleted) + { + // reenable triggering + m_spawner.m_refractActivated = false; + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(32); // version + // version 31 + writer.Write(m_DisableGlobalAutoReset); + // Version 30 + writer.Write(m_AllowNPCTriggering); + + // Version 29 + if (m_SpawnObjects != null) + { + writer.Write(m_SpawnObjects.Count); + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + // Write the spawns per tick value + writer.Write(m_SpawnObjects[i].SpawnsPerTick); + } + } + else + { + // empty spawner + writer.Write(0); + } + + // Version 28 + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + // Write the pack range value + writer.Write(m_SpawnObjects[i].PackRange); + } + } + + + // Version 27 + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + // Write the disable spawn flag + writer.Write(m_SpawnObjects[i].Disabled); + } + } + + // Version 26 + writer.Write(m_SpawnOnTrigger); + + // Version 24 + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + SpawnObject so = m_SpawnObjects[i]; + // Write the restrict kills flag + writer.Write(so.RestrictKillsToSubgroup); + // Write the clear on advance flag + writer.Write(so.ClearOnAdvance); + // Write the mindelay + writer.Write(so.MinDelay); + // Write the maxdelay + writer.Write(so.MaxDelay); + // write the next spawn time for the subgrop + writer.WriteDeltaTime(so.NextSpawn); + + } + } + + if (m_ShowBoundsItems != null && m_ShowBoundsItems.Count > 0) + { + writer.Write(true); + writer.Write(m_ShowBoundsItems); + } + else + { + // empty showbounds item list + writer.Write(false); + } + + // Version 23 + writer.Write(IsInactivated); + writer.Write(m_SmartSpawning); + // Version 22 + writer.Write(m_SkillTrigger); + writer.Write((int)m_skill_that_triggered); + writer.Write(m_FreeRun); + writer.Write(m_mob_who_triggered); + // Version 21 + writer.Write(m_DespawnTime); + // Version 20 + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + // Write the requiresurface flag + writer.Write(m_SpawnObjects[i].RequireSurface); + } + } + // Version 19 + writer.Write(m_ConfigFile); + writer.Write(m_OnHold); + writer.Write(m_HoldSequence); + // compute the number of tags to save + int tagcount = 0; + for (int i = 0; i < m_KeywordTagList.Count; i++) + { + // only save WAIT type keywords or other keywords that have the save flag set + if ((m_KeywordTagList[i].Flags & BaseXmlSpawner.KeywordFlags.Serialize) != 0) + { + tagcount++; + } + } + writer.Write(tagcount); + // and write them out + for (int i = 0; i < m_KeywordTagList.Count; i++) + { + if ((m_KeywordTagList[i].Flags & BaseXmlSpawner.KeywordFlags.Serialize) != 0) + { + m_KeywordTagList[i].Serialize(writer); + } + } + // Version 18 + writer.Write(m_AllowGhostTriggering); + // Version 17 + // removed in version 25 + //writer.Write(m_TextEntryBook); + // Version 16 + writer.Write(m_SequentialSpawning); + // write out the remaining time until sequential reset + writer.Write(NextSeqReset); + // Write the spawn object list + if (m_SpawnObjects != null) + { + for (int i = 0; i < m_SpawnObjects.Count; ++i) + { + SpawnObject so = m_SpawnObjects[i]; + // Write the subgroup and sequential reset time + writer.Write(so.SubGroup); + writer.Write(so.SequentialResetTime); + writer.Write(so.SequentialResetTo); + writer.Write(so.KillsNeeded); + } + } + writer.Write(m_RegionName); + + // Version 15 + writer.Write(m_ExternalTriggering); + writer.Write(m_ExternalTrigger); + + // Version 14 + writer.Write(m_NoItemTriggerName); + + // Version 13 + writer.Write(m_GumpState); + + // Version 12 + int todtype = (int)m_TODMode; + writer.Write(todtype); + + // Version 11 + writer.Write(m_KillReset); + writer.Write(m_skipped); + writer.Write(m_spawncheck); + + // Version 10 + writer.Write(m_SetPropertyItem); + + // Version 9 + writer.Write(m_TriggerProbability); + + // Version 8 + writer.Write(m_MobPropertyName); + writer.Write(m_MobTriggerName); + writer.Write(m_PlayerPropertyName); + + // Version 7 + writer.Write(m_SpeechTrigger); + + // Version 6 + writer.Write(m_ItemTriggerName); + + // Version 5 + writer.Write(m_ProximityTriggerMessage); + writer.Write(m_ObjectPropertyItem); + writer.Write(m_ObjectPropertyName); + writer.Write(m_killcount); + + // Version 4 + writer.Write(m_ProximityRange); + writer.Write(m_ProximityTriggerSound); + writer.Write(m_proximityActivated); + writer.Write(m_durActivated); + writer.Write(m_refractActivated); + writer.Write(m_StackAmount); + writer.Write(m_TODStart); + writer.Write(m_TODEnd); + writer.Write(m_MinRefractory); + writer.Write(m_MaxRefractory); + if (m_refractActivated) + { + writer.Write(m_RefractEnd - DateTime.UtcNow); + } + + if (m_durActivated) + { + writer.Write(m_DurEnd - DateTime.UtcNow); + } + + // Version 3 + writer.Write(m_ShowContainerStatic); + // Version 2 + writer.Write(m_Duration); + + // Version 1 + writer.Write(m_UniqueId); + writer.Write(m_HomeRangeIsRelative); + + // Version 0 + writer.Write(m_Name); + writer.Write(m_X); + writer.Write(m_Y); + writer.Write(m_Width); + writer.Write(m_Height); + writer.Write(m_WayPoint); + writer.Write(m_Group); + writer.Write(m_MinDelay); + writer.Write(m_MaxDelay); + writer.Write(m_Count); + writer.Write(m_Team); + writer.Write(m_HomeRange); + writer.Write(m_Running); + + if (m_Running) + { + writer.Write(m_End - DateTime.UtcNow); + } + + // Write the spawn object list + int nso = 0; + if (m_SpawnObjects != null) + { + nso = m_SpawnObjects.Count; + } + + writer.Write(nso); + for (int i = 0; i < nso; ++i) + { + SpawnObject so = m_SpawnObjects[i]; + + // Write the type and maximum count + writer.Write(so.TypeName); + writer.Write(so.ActualMaxCount); + + // Write the spawned object information + writer.Write(so.SpawnedObjects.Count); + for (int x = 0; x < so.SpawnedObjects.Count; ++x) + { + object o = so.SpawnedObjects[x]; + + if (o is Item item) + { + writer.Write(item); + } + else if (o is Mobile mobile) + { + writer.Write(mobile); + } + else + { + // if this is a keyword tag then add some more info + if (o is BaseXmlSpawner.KeywordTag tag) + { + writer.Write(-1 * tag.Serial - 2); + } + else + { + writer.Write(Serial.MinusOne); + } + } + } + } + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + int version = reader.ReadInt(); + bool haveproximityrange = false; + bool hasnewobjectinfo = false; + int tmpSpawnListSize = 0; + List tmpSubGroup = null; + List tmpSequentialResetTime = null; + List tmpSequentialResetTo = null; + List tmpKillsNeeded = null; + List tmpRequireSurface = null; + List tmpRestrictKillsToSubgroup = null; + List tmpClearOnAdvance = null; + List tmpMinDelay = null; + List tmpMaxDelay = null; + List tmpNextSpawn = null; + List tmpDisableSpawn = null; + List tmpPackRange = null; + List tmpSpawnsPer = null; + + switch (version) + { + case 32: + case 31: + { + m_DisableGlobalAutoReset = reader.ReadBool(); + goto case 30; + } + case 30: + { + m_AllowNPCTriggering = reader.ReadBool(); + goto case 29; + } + case 29: + { + tmpSpawnListSize = reader.ReadInt(); + tmpSpawnsPer = new List(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + int spawnsper = reader.ReadInt(); + + tmpSpawnsPer.Add(spawnsper); + + } + goto case 28; + } + case 28: + { + tmpPackRange = new List(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + int packrange = reader.ReadInt(); + + tmpPackRange.Add(packrange); + + } + goto case 27; + } + case 27: + { + tmpDisableSpawn = new List(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + bool disablespawn = reader.ReadBool(); + + tmpDisableSpawn.Add(disablespawn); + + } + goto case 26; + } + case 26: + { + m_SpawnOnTrigger = reader.ReadBool(); + + if (version < 32) + { + // Delete First & Last Modified + reader.ReadDateTime(); + reader.ReadDateTime(); + } + goto case 25; + } + case 25: + { + goto case 24; + } + case 24: + { + tmpRestrictKillsToSubgroup = new List(tmpSpawnListSize); + tmpClearOnAdvance = new List(tmpSpawnListSize); + tmpMinDelay = new List(tmpSpawnListSize); + tmpMaxDelay = new List(tmpSpawnListSize); + tmpNextSpawn = new List(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + bool restrictkills = reader.ReadBool(); + bool clearadvance = reader.ReadBool(); + double mind = reader.ReadDouble(); + double maxd = reader.ReadDouble(); + DateTime nextspawn = reader.ReadDeltaTime(); + + tmpRestrictKillsToSubgroup.Add(restrictkills); + tmpClearOnAdvance.Add(clearadvance); + tmpMinDelay.Add(mind); + tmpMaxDelay.Add(maxd); + tmpNextSpawn.Add(nextspawn); + } + + bool hasitems = reader.ReadBool(); + + if (hasitems) + { + m_ShowBoundsItems = reader.ReadEntityList(); + } + goto case 23; + } + case 23: + { + IsInactivated = reader.ReadBool(); + SmartSpawning = reader.ReadBool(); + + goto case 22; + } + case 22: + { + SkillTrigger = reader.ReadString(); // note this will also register the skill + m_skill_that_triggered = (SkillName)reader.ReadInt(); + m_FreeRun = reader.ReadBool(); + m_mob_who_triggered = reader.ReadEntity(); + goto case 21; + } + case 21: + { + m_DespawnTime = reader.ReadTimeSpan(); + goto case 20; + } + case 20: + { + tmpRequireSurface = new List(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + bool requiresurface = reader.ReadBool(); + tmpRequireSurface.Add(requiresurface); + } + goto case 19; + } + case 19: + { + m_ConfigFile = reader.ReadString(); + m_OnHold = reader.ReadBool(); + m_HoldSequence = reader.ReadBool(); + + if (version < 32) + { + // // Delete First & Last Modified By + // // Delete First & Last Modified By + reader.ReadString(); + reader.ReadString(); + } + + // deserialize the keyword tag list + int tagcount = reader.ReadInt(); + m_KeywordTagList = new List(tagcount); + for (int i = 0; i < tagcount; i++) + { + BaseXmlSpawner.KeywordTag tag = new BaseXmlSpawner.KeywordTag(null, this); + tag.Deserialize(reader); + } + goto case 18; + } + case 18: + { + m_AllowGhostTriggering = reader.ReadBool(); + goto case 17; + } + case 17: + { + goto case 16; + } + case 16: + { + hasnewobjectinfo = true; + m_SequentialSpawning = reader.ReadInt(); + TimeSpan seqdelay = reader.ReadTimeSpan(); + m_SeqEnd = DateTime.UtcNow + seqdelay; + + tmpSubGroup = new List(tmpSpawnListSize); + tmpSequentialResetTime = new List(tmpSpawnListSize); + tmpSequentialResetTo = new List(tmpSpawnListSize); + tmpKillsNeeded = new List(tmpSpawnListSize); + for (int i = 0; i < tmpSpawnListSize; ++i) + { + int subgroup = reader.ReadInt(); + double resettime = reader.ReadDouble(); + int resetto = reader.ReadInt(); + int killsneeded = reader.ReadInt(); + tmpSubGroup.Add(subgroup); + tmpSequentialResetTime.Add(resettime); + tmpSequentialResetTo.Add(resetto); + tmpKillsNeeded.Add(killsneeded); + } + m_RegionName = reader.ReadString(); + goto case 15; + } + case 15: + { + m_ExternalTriggering = reader.ReadBool(); + m_ExternalTrigger = reader.ReadBool(); + goto case 14; + } + case 14: + { + m_NoItemTriggerName = reader.ReadString(); + goto case 13; + } + case 13: + { + m_GumpState = reader.ReadString(); + goto case 12; + } + case 12: + { + int todtype = reader.ReadInt(); + switch (todtype) + { + case (int)TODModeType.Gametime: + { + m_TODMode = TODModeType.Gametime; + break; + } + case (int)TODModeType.Realtime: + { + m_TODMode = TODModeType.Realtime; + break; + } + } + goto case 11; + } + case 11: + { + m_KillReset = reader.ReadInt(); + m_skipped = reader.ReadBool(); + m_spawncheck = reader.ReadInt(); + goto case 10; + } + case 10: + { + m_SetPropertyItem = reader.ReadEntity(); + goto case 9; + } + case 9: + { + m_TriggerProbability = reader.ReadDouble(); + goto case 8; + } + case 8: + { + m_MobPropertyName = reader.ReadString(); + m_MobTriggerName = reader.ReadString(); + m_PlayerPropertyName = reader.ReadString(); + goto case 7; + } + case 7: + { + m_SpeechTrigger = reader.ReadString(); + goto case 6; + } + case 6: + { + m_ItemTriggerName = reader.ReadString(); + goto case 5; + } + case 5: + { + m_ProximityTriggerMessage = reader.ReadString(); + m_ObjectPropertyItem = reader.ReadEntity(); + m_ObjectPropertyName = reader.ReadString(); + m_killcount = reader.ReadInt(); + goto case 4; + } + case 4: + { + haveproximityrange = true; + m_ProximityRange = reader.ReadInt(); + m_ProximityTriggerSound = reader.ReadInt(); + m_proximityActivated = reader.ReadBool(); + m_durActivated = reader.ReadBool(); + m_refractActivated = reader.ReadBool(); + m_StackAmount = reader.ReadInt(); + m_TODStart = reader.ReadTimeSpan(); + m_TODEnd = reader.ReadTimeSpan(); + m_MinRefractory = reader.ReadTimeSpan(); + m_MaxRefractory = reader.ReadTimeSpan(); + if (m_refractActivated) + { + TimeSpan delay = reader.ReadTimeSpan(); + DoTimer3(delay); + } + if (m_durActivated) + { + TimeSpan delay = reader.ReadTimeSpan(); + DoTimer2(delay); + } + goto case 3; + } + case 3: + { + m_ShowContainerStatic = reader.ReadEntity() ; + goto case 2; + } + case 2: + { + m_Duration = reader.ReadTimeSpan(); + goto case 1; + } + case 1: + { + m_UniqueId = reader.ReadString(); + m_HomeRangeIsRelative = reader.ReadBool(); + goto case 0; + } + case 0: + { + m_Name = reader.ReadString(); + // backward compatibility with old name storage + if (!string.IsNullOrEmpty(m_Name)) + { + Name = m_Name; + } + + m_X = reader.ReadInt(); + m_Y = reader.ReadInt(); + m_Width = reader.ReadInt(); + m_Height = reader.ReadInt(); + //we HAVE to check if the area is even or if coordinates point to the original spawner, otherwise it's custom area! + if (m_Width == m_Height && m_Width % 2 == 0 && m_X + m_Width / 2 == X && m_Y + m_Height / 2 == Y) + { + m_SpawnRange = m_Width / 2; + } + else + { + m_SpawnRange = -1; + } + + if (!haveproximityrange) + { + m_ProximityRange = -1; + } + m_WayPoint = reader.ReadEntity(); + m_Group = reader.ReadBool(); + m_MinDelay = reader.ReadTimeSpan(); + m_MaxDelay = reader.ReadTimeSpan(); + m_Count = reader.ReadInt(); + m_Team = reader.ReadInt(); + m_HomeRange = reader.ReadInt(); + m_Running = reader.ReadBool(); + + if (m_Running) + { + TimeSpan delay = reader.ReadTimeSpan(); + DoTimer(delay); + } + + // Read in the size of the spawn object list + int SpawnListSize = reader.ReadInt(); + m_SpawnObjects = new List(SpawnListSize); + for (int i = 0; i < SpawnListSize; ++i) + { + string TypeName = reader.ReadString(); + int TypeMaxCount = reader.ReadInt(); + + SpawnObject TheSpawnObject = new SpawnObject(TypeName, TypeMaxCount); + + m_SpawnObjects.Add(TheSpawnObject); + + string typeName = BaseXmlSpawner.ParseObjectType(TypeName); + + if (typeName == null || AssemblyHandler.FindTypeByName(typeName) == null && + !BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && typeName.IndexOf('{') == -1 && !typeName.StartsWith("*") && !typeName.StartsWith("#")) + { + if (m_WarnTimer == null) + { + m_WarnTimer = new WarnTimer2(); + } + + m_WarnTimer.Add(Location, Map, TypeName); + + status_str = $"invalid type: {typeName}"; + } + + // Read in the number of spawns already + int SpawnedCount = reader.ReadInt(); + + TheSpawnObject.SpawnedObjects = new List(SpawnedCount); + + for (int x = 0; x < SpawnedCount; ++x) + { + int serial = reader.ReadInt(); + if (serial < -1) + { + // minusone is reserved for unknown types by default + // minustwo on is used for referencing keyword tags + int tagserial = -1 * (serial + 2); + // get the tag with that serial and add it + BaseXmlSpawner.KeywordTag t = BaseXmlSpawner.GetFromTagList(this, tagserial); + if (t != null) + { + TheSpawnObject.SpawnedObjects.Add(t); + } + } + else + { + IEntity e = World.FindEntity((Serial)(uint)serial); + + if (e != null) + { + TheSpawnObject.SpawnedObjects.Add(e); + } + } + } + } + // now have to reintegrate the later version spawnobject information into the earlier version desered objects + if (hasnewobjectinfo && tmpSpawnListSize == SpawnListSize) + { + for (int i = 0; i < SpawnListSize; ++i) + { + SpawnObject so = m_SpawnObjects[i]; + + so.SubGroup = tmpSubGroup[i]; + so.SequentialResetTime = tmpSequentialResetTime[i]; + so.SequentialResetTo = tmpSequentialResetTo[i]; + so.KillsNeeded = tmpKillsNeeded[i]; + if (version > 19) + { + so.RequireSurface = tmpRequireSurface[i]; + } + + bool restrictkills = false; + bool clearadvance = true; + double mind = -1; + double maxd = -1; + DateTime nextspawn = DateTime.MinValue; + if (version > 23) + { + restrictkills = tmpRestrictKillsToSubgroup[i]; + clearadvance = tmpClearOnAdvance[i]; + mind = tmpMinDelay[i]; + maxd = tmpMaxDelay[i]; + nextspawn = tmpNextSpawn[i]; + } + so.RestrictKillsToSubgroup = restrictkills; + so.ClearOnAdvance = clearadvance; + so.MinDelay = mind; + so.MaxDelay = maxd; + so.NextSpawn = nextspawn; + + bool disablespawn = false; + if (version > 26) + { + disablespawn = tmpDisableSpawn[i]; + } + so.Disabled = disablespawn; + + int packrange = -1; + if (version > 27) + { + packrange = tmpPackRange[i]; + } + so.PackRange = packrange; + + int spawnsper = 1; + if (version > 28) + { + spawnsper = tmpSpawnsPer[i]; + } + so.SpawnsPerTick = spawnsper; + + } + } + + break; + } + } + if (m_RegionName != null) + { + Timer.DelayCall(delegate { if (!Deleted && m_RegionName != null) + { + RegionName = m_RegionName; + } + }); + } + } + + internal string GetSerializedObjectList() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + foreach (SpawnObject so in m_SpawnObjects) + { + if (sb.Length > 0) + { + sb.Append(':'); // ':' Separates multiple object types + } + + sb.AppendFormat("{0}={1}", so.TypeName, so.ActualMaxCount); // '=' separates object name from maximum amount + } + + return sb.ToString(); + } + + internal string GetSerializedObjectList2() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + + foreach (SpawnObject so in m_SpawnObjects) + { + if (sb.Length > 0) + { + sb.Append(":OBJ="); // Separates multiple object types + } + + sb.AppendFormat("{0}:MX={1}:SB={2}:RT={3}:TO={4}:KL={5}:RK={6}:CA={7}:DN={8}:DX={9}:SP={10}:PR={11}", + so.TypeName, so.ActualMaxCount, so.SubGroup, so.SequentialResetTime, so.SequentialResetTo, so.KillsNeeded, + so.RestrictKillsToSubgroup ? 1 : 0, so.ClearOnAdvance ? 1 : 0, so.MinDelay, so.MaxDelay, so.SpawnsPerTick, so.PackRange); + } + + return sb.ToString(); + } + + public class SpawnObject + { + private int m_MaxCount; + + // temporary variable used to calculate weighted spawn probabilities + public bool Available; + + public List SpawnedObjects; + public string[] PropertyArgs; + public double SequentialResetTime; + public int EntryOrder; // used for sorting + public bool RequireSurface = true; + public DateTime NextSpawn; + public bool SpawnedThisTick; + + // these are externally accessible to the SETONSPAWNENTRY keyword + public string TypeName { get; set; } + + public int MaxCount + { + get + { + if (Disabled) + { + return 0; + } + + return m_MaxCount; + } + set => m_MaxCount = value; + } + public int ActualMaxCount + { + get => m_MaxCount; + set => m_MaxCount = value; + } + public int SubGroup { get; set; } + public int SpawnsPerTick { get; set; } = 1; + public int SequentialResetTo { get; set; } + public int KillsNeeded { get; set; } + public bool RestrictKillsToSubgroup { get; set; } + public bool ClearOnAdvance { get; set; } = true; + public double MinDelay { get; set; } = -1; + public double MaxDelay { get; set; } = -1; + public bool Disabled { get; set; } + public bool Ignore { get; set; } = false; + public int PackRange { get; set; } = -1; + + // command loggable constructor + public SpawnObject(Mobile from, XmlSpawner spawner, string name, int maxamount) + { + + if (from != null && spawner != null) + { + bool found = false; + // go through the current spawner objects and see if this is a new entry + if (spawner.m_SpawnObjects != null) + { + for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + { + SpawnObject s = spawner.m_SpawnObjects[i]; + if (s != null && s.TypeName == name) + { + found = true; + break; + } + } + } + + if (!found) + { + CommandLogging.WriteLine(from, "{0} {1} added to XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7}", from.AccessLevel, CommandLogging.Format(from), spawner.Serial, spawner.Name, spawner.GetWorldLocation().X, spawner.GetWorldLocation().Y, spawner.Map, name); + } + } + + TypeName = name; + MaxCount = maxamount; + SubGroup = 0; + SequentialResetTime = 0; + SequentialResetTo = 0; + KillsNeeded = 0; + RestrictKillsToSubgroup = false; + ClearOnAdvance = true; + SpawnedObjects = new List(); + } + + public SpawnObject(string name, int maxamount) + { + TypeName = name; + MaxCount = maxamount; + SubGroup = 0; + SequentialResetTime = 0; + SequentialResetTo = 0; + KillsNeeded = 0; + RestrictKillsToSubgroup = false; + ClearOnAdvance = true; + SpawnedObjects = new List(); + } + + public SpawnObject(string name, int maxamount, int subgroup, double sequentialresettime, int sequentialresetto, int killsneeded, + bool restrictkills, bool clearadvance, double mindelay, double maxdelay, int spawnsper, int packrange) + { + TypeName = name; + MaxCount = maxamount; + SubGroup = subgroup; + SequentialResetTime = sequentialresettime; + SequentialResetTo = sequentialresetto; + KillsNeeded = killsneeded; + RestrictKillsToSubgroup = restrictkills; + ClearOnAdvance = clearadvance; + MinDelay = mindelay; + MaxDelay = maxdelay; + SpawnsPerTick = spawnsper; + PackRange = packrange; + SpawnedObjects = new List(); + } + + internal static string GetParm(string str, string separator) + { + // find the parm separator in the string + // then look for the termination at the ':' or end of string + // and return the stuff between + string[] arg = BaseXmlSpawner.SplitString(str, separator); + //should be 2 args + if (arg.Length > 1) + { + // look for the end of parm terminator (could also be eol) + string[] parm = arg[1].Split(':'); + if (parm.Length > 0) + { + return parm[0]; + } + } + return null; + } + + internal static SpawnObject[] LoadSpawnObjectsFromString(string ObjectList) + { + // Clear the spawn object list + List NewSpawnObjects = new List(); + + if (!string.IsNullOrEmpty(ObjectList)) + { + // Split the string based on the object separator first ':' + string[] SpawnObjectList = ObjectList.Split(':'); + + // Parse each item in the array + foreach (string s in SpawnObjectList) + { + // Split the single spawn object item by the max count '=' + string[] SpawnObjectDetails = s.Split('='); + + // Should be two entries + if (SpawnObjectDetails.Length == 2) + { + // Validate the information + + // Make sure the spawn object name part has a valid length + if (SpawnObjectDetails[0].Length > 0) + { + // Make sure the max count part has a valid length + if (SpawnObjectDetails[1].Length > 0) + { + int maxCount = 1; + + try + { + maxCount = int.Parse(SpawnObjectDetails[1]); + } + catch (Exception) + { // Something went wrong, leave the default amount } + } + + // Create the spawn object and store it in the array list + SpawnObject so = new SpawnObject(SpawnObjectDetails[0], maxCount); + NewSpawnObjects.Add(so); + } + } + } + } + } + + return NewSpawnObjects.ToArray(); + } + + internal static SpawnObject[] LoadSpawnObjectsFromString2(string ObjectList) + { + // Clear the spawn object list + List NewSpawnObjects = new List(); + + // spawn object definitions will take the form typestring:MX=int:SB=int:RT=double:TO=int:KL=int + // or typestring:MX=int:SB=int:RT=double:TO=int:KL=int:OBJ=typestring... + if (!string.IsNullOrEmpty(ObjectList)) + { + string[] SpawnObjectList = BaseXmlSpawner.SplitString(ObjectList, ":OBJ="); + + // Parse each item in the array + foreach (string s in SpawnObjectList) + { + // at this point each spawn string will take the form typestring:MX=int:SB=int:RT=double:TO=int:KL=int + // Split the single spawn object item by the max count to get the typename and the remaining parms + string[] SpawnObjectDetails = BaseXmlSpawner.SplitString(s, ":MX="); + + // Should be two entries + if (SpawnObjectDetails.Length == 2) + { + // Validate the information + + // Make sure the spawn object name part has a valid length + if (SpawnObjectDetails[0].Length > 0) + { + // Make sure the parm part has a valid length + if (SpawnObjectDetails[1].Length > 0) + { + // now parse out the parms + // MaxCount + string parmstr = GetParm(s, ":MX="); + int maxCount = 1; + try { maxCount = int.Parse(parmstr); } + catch { } + + // SubGroup + parmstr = GetParm(s, ":SB="); + + int subGroup = 0; + try { subGroup = int.Parse(parmstr); } + catch { } + + // SequentialSpawnResetTime + parmstr = GetParm(s, ":RT="); + double resetTime = 0; + try { resetTime = double.Parse(parmstr); } + catch { } + + // SequentialSpawnResetTo + parmstr = GetParm(s, ":TO="); + int resetTo = 0; + try { resetTo = int.Parse(parmstr); } + catch { } + + // KillsNeeded + parmstr = GetParm(s, ":KL="); + int killsNeeded = 0; + try { killsNeeded = int.Parse(parmstr); } + catch { } + + // RestrictKills + parmstr = GetParm(s, ":RK="); + bool restrictKills = false; + if (parmstr != null) + { + try { restrictKills = int.Parse(parmstr) == 1; } + catch { } + } + + // ClearOnAdvance + parmstr = GetParm(s, ":CA="); + bool clearAdvance = true; + // if kills needed is zero, then set CA to false by default. This maintains consistency with the + // previous default behavior for old spawn specs that havent specified CA + if (killsNeeded == 0) + { + clearAdvance = false; + } + + if (parmstr != null) + { + try { clearAdvance = int.Parse(parmstr) == 1; } + catch { } + } + + // MinDelay + parmstr = GetParm(s, ":DN="); + double minD = -1; + try { minD = double.Parse(parmstr); } + catch { } + + // MaxDelay + parmstr = GetParm(s, ":DX="); + double maxD = -1; + try { maxD = double.Parse(parmstr); } + catch { } + + // SpawnsPerTick + parmstr = GetParm(s, ":SP="); + int spawnsPer = 1; + try { spawnsPer = int.Parse(parmstr); } + catch { } + + // PackRange + parmstr = GetParm(s, ":PR="); + int packRange = -1; + try { packRange = int.Parse(parmstr); } + catch { } + + // Create the spawn object and store it in the array list + SpawnObject so = new SpawnObject(SpawnObjectDetails[0], maxCount, subGroup, resetTime, resetTo, killsNeeded, + restrictKills, clearAdvance, minD, maxD, spawnsPer, packRange); + + NewSpawnObjects.Add(so); + } + } + } + } + } + + return NewSpawnObjects.ToArray(); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs new file mode 100644 index 000000000..832509a37 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs @@ -0,0 +1,1331 @@ +#define NEWPROPSGUMP +#define BOOKTEXTENTRY +using Server.Commands; +using Server.Gumps; +using Server.Items; +using Server.Network; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Server.Mobiles; + +public class TextEntryGump : Gump +{ + private readonly XmlSpawner m_Spawner; + private readonly int m_index; + private readonly XmlSpawnerGump m_SpawnerGump; + + public TextEntryGump(XmlSpawner spawner, XmlSpawnerGump spawnergump, int index, int X, int Y) + : base(X, Y) + { + if (spawner == null || spawner.Deleted) + { + return; + } + + m_Spawner = spawner; + m_index = index; + m_SpawnerGump = spawnergump; + + AddPage(0); + + AddBackground(20, 0, 220, 354, 5054); + AddAlphaRegion(20, 0, 220, 354); + AddImageTiled(23, 5, 214, 270, 0x52); + AddImageTiled(24, 6, 213, 261, 0xBBC); + + string label = $"{spawner.Name} entry {index}"; + AddLabel(28, 10, 0x384, label); + + // OK button + AddButton(25, 325, 0xFB7, 0xFB9, 1); + // Close button + AddButton(205, 325, 0xFB1, 0xFB3, 0); + // Edit button + AddButton(100, 325, 0xEF, 0xEE, 2); + string str = null; + if (index < m_Spawner.SpawnObjects.Length) + { + str = m_Spawner.SpawnObjects[index].TypeName; + } + // main text entry area + AddTextEntry(35, 30, 200, 251, 0, 0, str); + + // editing text entry areas + // background for text entry area + AddImageTiled(23, 275, 214, 23, 0x52); + AddImageTiled(24, 276, 213, 21, 0xBBC); + AddImageTiled(23, 300, 214, 23, 0x52); + AddImageTiled(24, 301, 213, 21, 0xBBC); + + AddTextEntry(35, 275, 200, 21, 0, 1, null); + AddTextEntry(35, 300, 200, 21, 0, 2, null); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state?.Mobile == null) + { + return; + } + + if (m_Spawner == null || m_Spawner.Deleted) + { + return; + } + + bool update_entry = false; + bool edit_entry = false; + + switch (info.ButtonID) + { + case 0: // Close + { + break; + } + case 1: // Okay + { + update_entry = true; + break; + } + case 2: // Edit + { + edit_entry = true; + break; + } + default: + { + update_entry = true; + break; + } + } + if (edit_entry) + { + // get the old text + TextRelay entry = info.GetTextEntry(1); + string oldtext = entry.Text; + // get the new text + entry = info.GetTextEntry(2); + string newtext = entry.Text; + // make the substitution + entry = info.GetTextEntry(0); + string origtext = entry.Text; + if (origtext != null && oldtext != null && newtext != null) + { + try + { + int firstindex = origtext.IndexOf(oldtext); + if (firstindex >= 0) + { + + + int secondindex = firstindex + oldtext.Length; + + int lastindex = origtext.Length - 1; + + string editedtext; + if (firstindex > 0) + { + editedtext = origtext.Substring(0, firstindex) + newtext + origtext.Substring(secondindex, lastindex - secondindex + 1); + } + else + { + editedtext = newtext + origtext.Substring(secondindex, lastindex - secondindex + 1); + } + + if (m_index < m_Spawner.SpawnObjects.Length) + { + m_Spawner.SpawnObjects[m_index].TypeName = editedtext; + } + else + { + // Update the creature list + m_Spawner.SpawnObjects = m_SpawnerGump.CreateArray(info, state.Mobile); + } + } + } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + + } + // open a new text entry gump + state.Mobile.SendGump(new TextEntryGump(m_Spawner, m_SpawnerGump, m_index, X, Y)); + return; + } + if (update_entry) + { + TextRelay entry = info.GetTextEntry(0); + if (m_index < m_Spawner.SpawnObjects.Length) + { + m_Spawner.SpawnObjects[m_index].TypeName = entry.Text; + } + else + { + // Update the creature list + m_Spawner.SpawnObjects = m_SpawnerGump.CreateArray(info, state.Mobile); + } + } + + // open a new spawner gump + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, X, Y, m_SpawnerGump.m_ShowGump, m_SpawnerGump.xoffset, m_SpawnerGump.page)); + } +} + +public class XmlSpawnerGump : Gump +{ + private static int nclicks; + public XmlSpawner m_Spawner; + public const int MaxSpawnEntries = 60; + private const int MaxEntriesPerPage = 15; + public int m_ShowGump; + public int xoffset; + public int initial_maxcount; + public int page; + public ReplacementEntry Rentry; + + public class ReplacementEntry + { + public string Typename; + public int Index; + public int Color; + } + + public XmlSpawnerGump(XmlSpawner spawner, int X, int Y, int extension, int textextension, int newpage) + : this(spawner, X, Y, extension, textextension, newpage, null) + { + } + + public XmlSpawnerGump(XmlSpawner spawner, int X, int Y, int extension, int textextension, int newpage, ReplacementEntry rentry) + : base(X, Y) + { + if (spawner == null || spawner.Deleted) + { + return; + } + + m_Spawner = spawner; + spawner.SpawnerGump = this; + xoffset = textextension; + initial_maxcount = spawner.MaxCount; + page = newpage; + Rentry = rentry; + + AddPage(0); + + // automatically change the gump depending on whether sequential spawning and/or subgroups are activated + + if (spawner.SequentialSpawn >= 0 || spawner.HasSubGroups() || spawner.HasIndividualSpawnTimes()) + { + // show the fully extended gump with subgroups and reset timer info + m_ShowGump = 2; + } + + if (extension > 0) + { + m_ShowGump = extension; + } + if (extension < 0) + { + m_ShowGump = 0; + } + + // if the expanded gump toggle has been activated then override the auto settings. + if (m_ShowGump > 1) + { + AddBackground(0, 0, 670 + xoffset + 30, 474, 5054); + AddAlphaRegion(0, 0, 670 + xoffset + 30, 474); + } + else + if (m_ShowGump > 0) + { + AddBackground(0, 0, 335 + xoffset, 474, 5054); + AddAlphaRegion(0, 0, 335 + xoffset, 474); + } + else + { + AddBackground(0, 0, 305 + xoffset, 474, 5054); + AddAlphaRegion(0, 0, 305 + xoffset, 474); + } + + // spawner name area + AddImageTiled(3, 5, 227, 23, 0x52); + AddImageTiled(4, 6, 225, 21, 0xBBC); + AddTextEntry(6, 5, 222, 21, 0, 999, spawner.Name); // changed from color 50 + + AddButton(5, 450, 0xFAE, 0xFAF, 4); + AddLabel(38, 450, 0x384, "Goto"); + + //AddButton(5, 428, 0xFB7, 0xFB9, 1, GumpButtonType.Reply, 0); + AddButton(5, 428, 0xFAE, 0xFAF, 1); + AddLabel(38, 428, 0x384, "Help"); + + AddButton(71, 428, 0xFB4, 0xFB6, 2); + AddLabel(104, 428, 0x384, "Bring Home"); + AddButton(71, 450, 0xFA8, 0xFAA, 3); + AddLabel(104, 450, 0x384, "Respawn"); + + // Props button + AddButton(168, 428, 0xFAB, 0xFAD, 9999); + AddLabel(201, 428, 0x384, "Props"); + + // Sort button + AddButton(168, 450, 0xFAB, 0xFAD, 702); + AddLabel(201, 450, 0x384, "Sort"); + + // Reset button + AddButton(71, 406, 0xFA2, 0xFA3, 701); + AddLabel(104, 406, 0x384, "Reset"); + + // Refresh button + AddButton(168, 406, 0xFBD, 0xFBE, 9998); + AddLabel(201, 406, 0x384, "Refresh"); + + AddButton(280, 395, m_Spawner.DisableGlobalAutoReset ? 0xD3 : 0xD2, + m_Spawner.DisableGlobalAutoReset ? 0xD2 : 0xD3, 9997); + AddLabel(263, 410, m_Spawner.DisableGlobalAutoReset ? 68 : 33, "Disable"); + AddLabel(247, 424, m_Spawner.DisableGlobalAutoReset ? 68 : 33, "TickReset"); + + // add run status display + if (m_Spawner.Running) + { + AddButton(5, 399, 0x2A4E, 0x2A3A, 700); + AddLabel(38, 406, 0x384, "On"); + } + else + { + AddButton(5, 399, 0x2A62, 0x2A3A, 700); + AddLabel(38, 406, 0x384, "Off"); + } + + // Add sequential spawn state + if (m_Spawner.SequentialSpawn >= 0) + { + AddLabel(15, 365, 33, $"{m_Spawner.SequentialSpawn}"); + } + + // Add Current / Max count labels + AddLabel(231 + xoffset, 9, 68, "Count"); + AddLabel(270 + xoffset, 9, 33, "Max"); + + if (m_ShowGump > 0) + { + // Add subgroup label + AddLabel(334 + xoffset, 9, 68, "Sub"); + } + if (m_ShowGump > 1) + { + // Add entry field labels + AddLabel(303 + xoffset, 9, 68, "Per"); + AddLabel(329 + xoffset + 30, 9, 68, "Reset"); + AddLabel(368 + xoffset + 30, 9, 68, "To"); + AddLabel(392 + xoffset + 30, 9, 68, "Kills"); + AddLabel(432 + xoffset + 30, 9, 68, "MinD"); + AddLabel(472 + xoffset + 30, 9, 68, "MaxD"); + AddLabel(515 + xoffset + 30, 9, 68, "Rng"); + AddLabel(545 + xoffset + 30, 9, 68, "RK"); + AddLabel(565 + xoffset + 30, 9, 68, "Clr"); + AddLabel(590 + xoffset + 30, 9, 68, "NextSpawn"); + } + + // add area for spawner max + AddLabel(180 + xoffset, 365, 50, "Spawner"); + AddImageTiled(267 + xoffset, 365, 35, 23, 0x52); + AddImageTiled(268 + xoffset, 365, 32, 21, 0xBBC); + AddTextEntry(273 + xoffset, 365, 33, 33, 33, 300, m_Spawner.MaxCount.ToString()); + + // add area for spawner count + AddImageTiled(231 + xoffset, 365, 35, 23, 0x52); + AddImageTiled(232 + xoffset, 365, 32, 21, 0xBBC); + AddLabel(233 + xoffset, 365, 68, m_Spawner.CurrentCount.ToString()); + + // add the status string + AddTextEntry(38, 384, 235, 33, 33, 900, m_Spawner.status_str); + // add the page buttons + for (int i = 0; i < MaxSpawnEntries / MaxEntriesPerPage; i++) + { + //AddButton(38+i*30, 365, 2206, 2206, 0, GumpButtonType.Page, 1+i); + AddButton(38 + i * 25, 365, 0x8B1 + i, 0x8B1 + i, 4000 + i); + } + + // add gump extension button + if (m_ShowGump > 1) + { + AddButton(645 + xoffset + 30, 450, 0x15E3, 0x15E7, 200); + } + else + if (m_ShowGump > 0) + { + AddButton(315 + xoffset, 450, 0x15E1, 0x15E5, 200); + } + else + { + AddButton(285 + xoffset, 450, 0x15E1, 0x15E5, 200); + } + + // add the textentry extender button + if (xoffset > 0) + { + AddButton(160, 365, 0x15E3, 0x15E7, 201); + } + else + { + AddButton(160, 365, 0x15E1, 0x15E5, 201); + } + + + for (int i = 0; i < MaxSpawnEntries; i++) + { + if (page != i / MaxEntriesPerPage) + { + continue; + } + + string str = string.Empty; + int texthue = 0; + int background = 0xBBC; + + if (i % MaxEntriesPerPage == 0) + { + //AddPage(page+1); + // add highlighted page button + AddImageTiled(35 + page * 25, 363, 25, 25, 0xBBC); + AddImage(38 + page * 25, 365, 0x8B1 + page); + } + + if (i < m_Spawner.SpawnObjects.Length) + { + // disable button + + if (m_Spawner.SpawnObjects[i].Disabled) + { + // change the background for the spawn text entry if disabled + background = 0x23F4; + AddButton(2, 22 * (i % MaxEntriesPerPage) + 34, 0x82C, 0x82C, 6000 + i); + } + else + { + AddButton(2, 22 * (i % MaxEntriesPerPage) + 36, 0x837, 0x837, 6000 + i); + } + } + + bool hasreplacement = false; + + // check for replacement entries + if (Rentry != null && Rentry.Index == i) + { + hasreplacement = true; + str = Rentry.Typename; + background = Rentry.Color; + // replacement is one time only. + Rentry = null; + } + + // increment/decrement buttons + AddButton(15, 22 * (i % MaxEntriesPerPage) + 34, 0x15E0, 0x15E4, 6 + i * 2); + AddButton(30, 22 * (i % MaxEntriesPerPage) + 34, 0x15E2, 0x15E6, 7 + i * 2); + + // categorization gump button + AddButton(171 + xoffset - 18, 22 * (i % MaxEntriesPerPage) + 34, 0x15E1, 0x15E5, 5000 + i); + + // goto spawn button + AddButton(171 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 0xFAE, 0xFAF, 1300 + i); + + // text entry gump button + AddButton(200 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 0xFAB, 0xFAD, 800 + i); + + // background for text entry area + AddImageTiled(48, 22 * (i % MaxEntriesPerPage) + 30, 133 + xoffset - 25, 23, 0x52); + AddImageTiled(49, 22 * (i % MaxEntriesPerPage) + 31, 131 + xoffset - 25, 21, background); + + if (i < m_Spawner.SpawnObjects.Length) + { + if (!hasreplacement) + { + str = m_Spawner.SpawnObjects[i].TypeName; + } + + int count = m_Spawner.SpawnObjects[i].SpawnedObjects.Count; + int max = m_Spawner.SpawnObjects[i].ActualMaxCount; + int subgrp = m_Spawner.SpawnObjects[i].SubGroup; + int spawnsper = m_Spawner.SpawnObjects[i].SpawnsPerTick; + + texthue = subgrp * 11; + if (texthue < 0) + { + texthue = 0; + } + + // Add current count + AddImageTiled(231 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 35, 23, 0x52); + AddImageTiled(232 + xoffset, 22 * (i % MaxEntriesPerPage) + 31, 32, 21, 0xBBC); + AddLabel(233 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 68, count.ToString()); + + // Add maximum count + AddImageTiled(267 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 35, 23, 0x52); + AddImageTiled(268 + xoffset, 22 * (i % MaxEntriesPerPage) + 31, 32, 21, 0xBBC); + // AddTextEntry(x,y,w,ht,color,id,str) + AddTextEntry(270 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 30, 30, 33, 500 + i, max.ToString()); + + if (m_ShowGump > 0) + { + // Add subgroup + AddImageTiled(334 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 25, 23, 0x52); + AddImageTiled(335 + xoffset, 22 * (i % MaxEntriesPerPage) + 31, 22, 21, 0xBBC); + AddTextEntry(338 + xoffset, 22 * (i % MaxEntriesPerPage) + 30, 17, 33, texthue, 600 + i, subgrp.ToString()); + } + if (m_ShowGump > 1) + { + // Add subgroup timer fields + string strrst = null; + string strto = null; + string strkill = null; + string strmind = null; + string strmaxd = null; + string strpackrange = null; + string strspawnsper = spawnsper.ToString(); + + if (m_Spawner.SpawnObjects[i].SequentialResetTime > 0 && m_Spawner.SpawnObjects[i].SubGroup > 0) + { + strrst = m_Spawner.SpawnObjects[i].SequentialResetTime.ToString(); + strto = m_Spawner.SpawnObjects[i].SequentialResetTo.ToString(); + } + if (m_Spawner.SpawnObjects[i].KillsNeeded > 0) + { + strkill = m_Spawner.SpawnObjects[i].KillsNeeded.ToString(); + } + + if (m_Spawner.SpawnObjects[i].MinDelay >= 0) + { + strmind = m_Spawner.SpawnObjects[i].MinDelay.ToString(); + } + + if (m_Spawner.SpawnObjects[i].MaxDelay >= 0) + { + strmaxd = m_Spawner.SpawnObjects[i].MaxDelay.ToString(); + } + + if (m_Spawner.SpawnObjects[i].PackRange >= 0) + { + strpackrange = m_Spawner.SpawnObjects[i].PackRange.ToString(); + } + + string strnext; + if (m_Spawner.SpawnObjects[i].NextSpawn > DateTime.UtcNow) + { + // if the next spawn tick of the spawner will occur after the subgroup is available for spawning + // then report the next spawn tick since that is the earliest that the subgroup can actually be spawned + if (DateTime.UtcNow + m_Spawner.NextSpawn > m_Spawner.SpawnObjects[i].NextSpawn) + { + strnext = m_Spawner.NextSpawn.ToString(); + } + else + { + // estimate the earliest the next spawn could occur as the first spawn tick after reaching the subgroup nextspawn + strnext = (m_Spawner.SpawnObjects[i].NextSpawn - DateTime.UtcNow + m_Spawner.NextSpawn).ToString(); + } + } + else + { + strnext = m_Spawner.NextSpawn.ToString(); + } + + int yoff = 22 * (i % MaxEntriesPerPage) + 30; + + // spawns per tick + AddImageTiled(303 + xoffset, yoff, 30, 23, 0x52); + AddImageTiled(304 + xoffset, yoff + 1, 27, 21, 0xBBC); + AddTextEntry(307 + xoffset, yoff, 22, 33, texthue, 1500 + i, strspawnsper); + // reset time + AddImageTiled(329 + xoffset + 30, yoff, 35, 23, 0x52); + AddImageTiled(330 + xoffset + 30, yoff + 1, 32, 21, 0xBBC); + AddTextEntry(333 + xoffset + 30, yoff, 27, 33, texthue, 1000 + i, strrst); + // reset to + AddImageTiled(365 + xoffset + 30, yoff, 26, 23, 0x52); + AddImageTiled(366 + xoffset + 30, yoff + 1, 23, 21, 0xBBC); + AddTextEntry(369 + xoffset + 30, yoff, 18, 33, texthue, 1100 + i, strto); + // kills needed + AddImageTiled(392 + xoffset + 30, yoff, 35, 23, 0x52); + AddImageTiled(393 + xoffset + 30, yoff + 1, 32, 21, 0xBBC); + AddTextEntry(396 + xoffset + 30, yoff, 27, 33, texthue, 1200 + i, strkill); + + // mindelay + AddImageTiled(428 + xoffset + 30, yoff, 41, 23, 0x52); + AddImageTiled(429 + xoffset + 30, yoff + 1, 38, 21, 0xBBC); + AddTextEntry(432 + xoffset + 30, yoff, 33, 33, texthue, 1300 + i, strmind); + + // maxdelay + AddImageTiled(470 + xoffset + 30, yoff, 41, 23, 0x52); + AddImageTiled(471 + xoffset + 30, yoff + 1, 38, 21, 0xBBC); + AddTextEntry(474 + xoffset + 30, yoff, 33, 33, texthue, 1400 + i, strmaxd); + + // packrange + AddImageTiled(512 + xoffset + 30, yoff, 33, 23, 0x52); + AddImageTiled(513 + xoffset + 30, yoff + 1, 30, 21, 0xBBC); + AddTextEntry(516 + xoffset + 30, yoff, 25, 33, texthue, 1600 + i, strpackrange); + + if (m_Spawner.SequentialSpawn >= 0) + { + // restrict kills button + AddButton(545 + xoffset + 30, yoff, m_Spawner.SpawnObjects[i].RestrictKillsToSubgroup ? 0xD3 : 0xD2, + m_Spawner.SpawnObjects[i].RestrictKillsToSubgroup ? 0xD2 : 0xD3, 300 + i); + + //clear on advance button for spawn entries in subgroups that require kills + AddButton(565 + xoffset + 30, yoff, m_Spawner.SpawnObjects[i].ClearOnAdvance ? 0xD3 : 0xD2, + m_Spawner.SpawnObjects[i].ClearOnAdvance ? 0xD2 : 0xD3, 400 + i); + } + + // add the next spawn time + AddLabelCropped(590 + xoffset + 30, yoff, 70, 20, 55, strnext); + } + } + + AddTextEntry(52, 22 * (i % MaxEntriesPerPage) + 31, 119 + xoffset - 25, 21, texthue, i, str); + } + } + + public XmlSpawner.SpawnObject[] CreateArray(RelayInfo info, Mobile from) + { + ArrayList SpawnObjects = new ArrayList(); + + for (int i = 0; i < MaxSpawnEntries; i++) + { + TextRelay te = info.GetTextEntry(i); + + if (te != null) + { + string str = te.Text; + + if (str.Length > 0) + { + str = str.Trim(); +#if (BOOKTEXTENTRY) + if (i < m_Spawner.SpawnObjects.Length) + { + string currenttext = m_Spawner.SpawnObjects[i].TypeName; + if (currenttext != null && currenttext.Length >= 230) + { + str = currenttext; + } + } +#endif + string typestr = BaseXmlSpawner.ParseObjectType(str); + + Type type = AssemblyHandler.FindTypeByName(typestr); + + if (type != null) + { + SpawnObjects.Add(new XmlSpawner.SpawnObject(from, m_Spawner, str, 0)); + } + else + { + // check for special keywords + if (typestr != null && (BaseXmlSpawner.IsTypeOrItemKeyword(typestr) || typestr.IndexOf("{") != -1 || typestr.StartsWith("*") || typestr.StartsWith("#"))) + { + SpawnObjects.Add(new XmlSpawner.SpawnObject(from, m_Spawner, str, 0)); + } + else + { + m_Spawner.status_str = $"{str} is not a valid type name."; + } + //from.SendMessage("{0} is not a valid type name.", str); + } + + } + } + } + + return (XmlSpawner.SpawnObject[])SpawnObjects.ToArray(typeof(XmlSpawner.SpawnObject)); + } + + public void UpdateTypeNames(Mobile from, RelayInfo info) + { + for (int i = 0; i < MaxSpawnEntries; i++) + { + TextRelay te = info.GetTextEntry(i); + + if (te != null) + { + string str = te.Text; + + if (str.Length > 0) + { + str = str.Trim(); + if (i < m_Spawner.SpawnObjects.Length) + { + // check to see if the existing typename is longer than the max textentry buffer + // if it is then dont update it since we will assume that the textentry has truncated the actual string + // that could be longer than the buffer if booktextentry is used + +#if (BOOKTEXTENTRY) + string currentstr = m_Spawner.SpawnObjects[i].TypeName; + if (currentstr != null && currentstr.Length < 230) +#endif + { + if (m_Spawner.SpawnObjects[i].TypeName != str) + { + CommandLogging.WriteLine( + from, + "{0} {1} changed XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7} to {8}", + from.AccessLevel, + CommandLogging.Format(from), + m_Spawner.Serial, + m_Spawner.Name, + m_Spawner.GetWorldLocation().X, + m_Spawner.GetWorldLocation().Y, + m_Spawner.Map, + m_Spawner.SpawnObjects[i].TypeName, + str + ); + + } + + m_Spawner.SpawnObjects[i].TypeName = str; + } + } + } + } + } + } + + public static void RefreshSpawnerGumps(Mobile from) + { + if (from == null) + { + return; + } + + NetState ns = from.NetState; + + if (ns?.Gumps != null) + { + ArrayList refresh = new ArrayList(); + + foreach (Gump g in ns.Gumps) + { + // clear the gump status on the spawner associated with the gump + if (g is XmlSpawnerGump xg && xg.m_Spawner != null) + { + refresh.Add(xg); + } + } + + // close all of the currently opened spawner gumps + from.CloseGump(); + + // reopen the closed gumps from the gump collection + foreach (XmlSpawnerGump g in refresh) + { + // reopen a new gump for the spawner + if (g.m_Spawner != null) + { + // flag the current gump on the spawner as closed + g.m_Spawner.GumpReset = true; + + XmlSpawnerGump xg = new XmlSpawnerGump(g.m_Spawner, g.X, g.Y, g.m_ShowGump, g.xoffset, g.page, g.Rentry); + + from.SendGump(xg); + } + } + } + } + + private static bool ValidGotoObject(Mobile from, object o) + { + if (o is Item i) + { + if (!i.Deleted && i.Map != null && i.Map != Map.Internal) + { + return true; + } + + if (from != null && !from.Deleted) + { + from.SendMessage("{0} is not available", i); + } + } + else if (o is Mobile m) + { + if (!m.Deleted && m.Map != null && m.Map != Map.Internal) + { + return true; + } + + if (from != null && !from.Deleted) + { + from.SendMessage("{0} is not available", m); + } + } + + return false; + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (m_Spawner == null || m_Spawner.Deleted || state == null || info == null) + { + if (m_Spawner != null) + { + m_Spawner.SpawnerGump = null; + } + + return; + } + + // Get the current name + TextRelay tr = info.GetTextEntry(999); + if (tr != null) + { + m_Spawner.Name = tr.Text; + } + + // update typenames of the spawn objects based upon the current text entry strings + UpdateTypeNames(state.Mobile, info); + + // Update the creature list + m_Spawner.SpawnObjects = CreateArray(info, state.Mobile); + + if (m_Spawner.SpawnObjects == null) + { + m_Spawner.SpawnerGump = null; + return; + } + + for (int i = 0; i < m_Spawner.SpawnObjects.Length; i++) + { + if (page != i / MaxEntriesPerPage) + { + continue; + } + + // check the max count entry + TextRelay temcnt = info.GetTextEntry(500 + i); + if (temcnt != null) + { + int maxval = 0; + try { maxval = Convert.ToInt32(temcnt.Text, 10); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (maxval < 0) + { + maxval = 0; + } + + m_Spawner.SpawnObjects[i].MaxCount = maxval; + } + + if (m_ShowGump > 0) + { + // check the subgroup entry + TextRelay tegrp = info.GetTextEntry(600 + i); + if (tegrp != null) + { + int grpval = 0; + try { grpval = Convert.ToInt32(tegrp.Text, 10); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (grpval < 0) + { + grpval = 0; + } + + m_Spawner.SpawnObjects[i].SubGroup = grpval; + } + } + + if (m_ShowGump > 1) + { + // note, while these values can be entered in any spawn entry, they will only be assigned to the subgroup leader + int subgroupindex = m_Spawner.GetCurrentSequentialSpawnIndex(m_Spawner.SpawnObjects[i].SubGroup); + TextRelay tegrp; + + if (subgroupindex >= 0 && subgroupindex < m_Spawner.SpawnObjects.Length) + { + // check the *reset time* entry + tegrp = info.GetTextEntry(1000 + i); + if (tegrp?.Text != null && tegrp.Text.Length > 0) + { + double grpval = 0; + try { grpval = Convert.ToDouble(tegrp.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (grpval < 0) + { + grpval = 0; + } + + m_Spawner.SpawnObjects[i].SequentialResetTime = 0; + + m_Spawner.SpawnObjects[subgroupindex].SequentialResetTime = grpval; + } + // check the *reset to* entry + tegrp = info.GetTextEntry(1100 + i); + if (tegrp?.Text != null && tegrp.Text.Length > 0) + { + int grpval = 0; + try { grpval = Convert.ToInt32(tegrp.Text, 10); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (grpval < 0) + { + grpval = 0; + } + + m_Spawner.SpawnObjects[subgroupindex].SequentialResetTo = grpval; + } + // check the kills entry + tegrp = info.GetTextEntry(1200 + i); + if (tegrp?.Text != null && tegrp.Text.Length > 0) + { + int grpval = 0; + try { grpval = Convert.ToInt32(tegrp.Text, 10); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (grpval < 0) + { + grpval = 0; + } + + m_Spawner.SpawnObjects[subgroupindex].KillsNeeded = grpval; + } + } + + // check the mindelay + tegrp = info.GetTextEntry(1300 + i); + if (tegrp != null) + { + if (!string.IsNullOrEmpty(tegrp.Text)) + { + double grpval = -1; + try { grpval = Convert.ToDouble(tegrp.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (grpval < 0) + { + grpval = -1; + } + + // if this value has changed, then update the next spawn time + if (grpval != m_Spawner.SpawnObjects[i].MinDelay) + { + m_Spawner.SpawnObjects[i].MinDelay = grpval; + m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + } + } + else + { + m_Spawner.SpawnObjects[i].MinDelay = -1; + m_Spawner.SpawnObjects[i].MaxDelay = -1; + m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + } + } + + // check the maxdelay + tegrp = info.GetTextEntry(1400 + i); + if (tegrp != null) + { + if (!string.IsNullOrEmpty(tegrp.Text)) + { + double grpval = -1; + try { grpval = Convert.ToDouble(tegrp.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (grpval < 0) + { + grpval = -1; + } + + // if this value has changed, then update the next spawn time + if (grpval != m_Spawner.SpawnObjects[i].MaxDelay) + { + m_Spawner.SpawnObjects[i].MaxDelay = grpval; + m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + } + } + else + { + m_Spawner.SpawnObjects[i].MinDelay = -1; + m_Spawner.SpawnObjects[i].MaxDelay = -1; + m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + } + } + + // check the spawns per tick + tegrp = info.GetTextEntry(1500 + i); + if (tegrp != null) + { + if (!string.IsNullOrEmpty(tegrp.Text)) + { + int grpval = 1; + try { grpval = int.Parse(tegrp.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (grpval < 0) + { + grpval = 1; + } + + // if this value has changed, then update the next spawn time + if (grpval != m_Spawner.SpawnObjects[i].SpawnsPerTick) + { + m_Spawner.SpawnObjects[i].SpawnsPerTick = grpval; + } + } + else + { + m_Spawner.SpawnObjects[i].SpawnsPerTick = 1; + } + } + + // check the packrange + tegrp = info.GetTextEntry(1600 + i); + if (tegrp != null) + { + if (!string.IsNullOrEmpty(tegrp.Text)) + { + int grpval = 1; + try { grpval = int.Parse(tegrp.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (grpval < 0) + { + grpval = 1; + } + + // if this value has changed, then update + if (grpval != m_Spawner.SpawnObjects[i].PackRange) + { + m_Spawner.SpawnObjects[i].PackRange = grpval; + } + } + else + { + m_Spawner.SpawnObjects[i].PackRange = -1; + } + } + } + } + + // Update the maxcount + TextRelay temax = info.GetTextEntry(300); + if (temax != null) + { + int maxval = 0; + try { maxval = Convert.ToInt32(temax.Text, 10); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (maxval < 0) + { + maxval = 0; + } + + // if the maxcount of the spawner has been altered external to the interface (e.g. via props, or by the running spawner itself + // then that change will override the text entry + if (m_Spawner.MaxCount == initial_maxcount) + { + m_Spawner.MaxCount = maxval; + } + } + + switch (info.ButtonID) + { + case 0: // Close + { + // clear any text entry books + m_Spawner.DeleteTextEntryBook(); + // and reset the gump status + m_Spawner.GumpReset = true; + + return; + } + case 1: // Help + { + break; + } + case 2: // Bring everything home + { + m_Spawner.BringToHome(); + break; + } + case 3: // Complete respawn + { + m_Spawner.TryRespawn(); + //m_Spawner.AdvanceSequential(); + m_Spawner.m_killcount = 0; + break; + } + case 4: // Goto + { + state.Mobile.Location = m_Spawner.Location; + state.Mobile.Map = m_Spawner.Map; + break; + } + case 200: // gump extension + { + state.Mobile.SendGump(m_ShowGump > 1 + ? new XmlSpawnerGump(m_Spawner, X, Y, -1, xoffset, page) + : new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump + 2, xoffset, page)); + return; + } + case 201: // gump text extension + { + state.Mobile.SendGump(xoffset > 0 + ? new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, 0, page) + : new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, 250, page)); + return; + } + case 700: // Start/stop spawner + { + m_Spawner.Running = !m_Spawner.Running; + break; + } + case 701: // Complete reset + { + m_Spawner.Reset(); + break; + } + case 702: // Sort spawns + { + m_Spawner.SortSpawns(); + break; + } + case 900: // empty the status string + { + m_Spawner.status_str = ""; + break; + } + case 9997: + { + m_Spawner.DisableGlobalAutoReset = !m_Spawner.DisableGlobalAutoReset; + break; + } + case 9998: // refresh the gump + { + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page)); + return; + } + case 9999: + { + // Show the props window for the spawner, as well as a new gump + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page)); + + state.Mobile.SendGump(new XmlPropertiesGump(state.Mobile, m_Spawner)); + return; + } + default: + { + // check the restrict kills flag + if (info.ButtonID >= 300 && info.ButtonID < 300 + MaxSpawnEntries) + { + int index = info.ButtonID - 300; + if (index < m_Spawner.SpawnObjects.Length) + { + m_Spawner.SpawnObjects[index].RestrictKillsToSubgroup = !m_Spawner.SpawnObjects[index].RestrictKillsToSubgroup; + } + } + else if (info.ButtonID >= 400 && info.ButtonID < 400 + MaxSpawnEntries) + { + int index = info.ButtonID - 400; + if (index < m_Spawner.SpawnObjects.Length) + { + m_Spawner.SpawnObjects[index].ClearOnAdvance = !m_Spawner.SpawnObjects[index].ClearOnAdvance; + } + } + else if (info.ButtonID >= 800 && info.ButtonID < 800 + MaxSpawnEntries) + { + // open the text entry gump + int index = info.ButtonID - 800; + // open a text entry gump +#if (BOOKTEXTENTRY) + // display a new gump + XmlSpawnerGump newgump = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page); + state.Mobile.SendGump(newgump); + + // is there an existing book associated with the gump? + if (m_Spawner.m_TextEntryBook == null) + { + m_Spawner.m_TextEntryBook = new List(); + } + + object[] args = new object[6]; + + args[0] = m_Spawner; + args[1] = index; + args[2] = X; + args[3] = Y; + args[4] = m_ShowGump; + args[5] = page; + + XmlTextEntryBook book = new XmlTextEntryBook(0, string.Empty, m_Spawner.Name, 20, true); + + m_Spawner.m_TextEntryBook.Add(book); + + book.Title = $"Entry {index}"; + book.Author = m_Spawner.Name; + + // fill the contents of the book with the current text entry data + string text = string.Empty; + if (m_Spawner.SpawnObjects != null && index < m_Spawner.SpawnObjects.Length) + { + text = m_Spawner.SpawnObjects[index].TypeName; + } + book.FillTextEntryBook(text); + + // put the book at the location of the player so that it can be opened, but drop it below visible range + book.Visible = false; + book.Movable = false; + book.MoveToWorld(new Point3D(state.Mobile.Location.X, state.Mobile.Location.Y, state.Mobile.Location.Z - 100), state.Mobile.Map); + + // and open it + book.OnDoubleClick(state.Mobile); + +#else + state.Mobile.SendGump(new TextEntryGump(m_Spawner,this, index, this.X, this.Y)); +#endif + return; + } + else if (info.ButtonID >= 1300 && info.ButtonID < 1300 + MaxSpawnEntries) + { + nclicks++; + // find the location of the spawn at the specified index + int index = info.ButtonID - 1300; + if (index < m_Spawner.SpawnObjects.Length) + { + int scount = m_Spawner.SpawnObjects[index].SpawnedObjects.Count; + if (scount > 0) + { + object so = m_Spawner.SpawnObjects[index].SpawnedObjects[nclicks % scount]; + + if (ValidGotoObject(state.Mobile, so)) + { + IPoint3D o = so as IPoint3D; + + if (o != null) + { + Map m = m_Spawner.Map; + + if (o is Item item) + { + m = item.Map; + } + + if (o is Mobile mobile) + { + m = mobile.Map; + } + + state.Mobile.Location = new Point3D(o); + state.Mobile.Map = m; + } + } + } + } + } + else if (info.ButtonID >= 4000 && info.ButtonID < 4001 + MaxSpawnEntries / MaxEntriesPerPage) + { + // which page + page = info.ButtonID - 4000; + + } + else if (info.ButtonID >= 6000 && info.ButtonID < 6000 + MaxSpawnEntries) + { + int index = info.ButtonID - 6000; + + if (index < m_Spawner.SpawnObjects.Length) + { + m_Spawner.SpawnObjects[index].Disabled = !m_Spawner.SpawnObjects[index].Disabled; + + // clear any current spawns on the disabled entry + if (m_Spawner.SpawnObjects[index].Disabled) + { + m_Spawner.RemoveSpawnObjects(m_Spawner.SpawnObjects[index]); + } + } + } + else if (info.ButtonID >= 5000 && info.ButtonID < 5000 + MaxSpawnEntries) + { + int i = info.ButtonID - 5000; + + string categorystring = null; + string entrystring = null; + + TextRelay te = info.GetTextEntry(i); + + if (te?.Text != null) + { + // get the string + + string[] cargs = te.Text.Split(','); + + // parse out any comma separated args + categorystring = cargs[0]; + + entrystring = te.Text; + } + + if (string.IsNullOrEmpty(categorystring)) + { + + XmlSpawnerGump newg = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page); + state.Mobile.SendGump(newg); + + // if no string has been entered then just use the full categorized add gump + state.Mobile.CloseGump(); + state.Mobile.SendGump(new XmlCategorizedAddGump(state.Mobile, i, newg)); + } + else + { + // use the XmlPartialCategorizedAddGump + state.Mobile.CloseGump(); + + //Type [] types = (Type[])XmlPartialCategorizedAddGump.Match(categorystring).ToArray(typeof(Type)); + ArrayList types = XmlPartialCategorizedAddGump.Match(categorystring); + + + ReplacementEntry re = new ReplacementEntry + { + Typename = entrystring, + Index = i, + Color = 0x1436 + }; + + XmlSpawnerGump newg = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page, re); + + state.Mobile.SendGump(new XmlPartialCategorizedAddGump(state.Mobile, categorystring, 0, types, true, i, newg)); + + state.Mobile.SendGump(newg); + } + + return; + } + else + { + // up and down arrows + int buttonID = info.ButtonID - 6; + int index = buttonID / 2; + int type = buttonID % 2; + + TextRelay entry = info.GetTextEntry(index); + + if (entry != null && entry.Text.Length > 0) + { + string entrystr = entry.Text; + +#if (BOOKTEXTENTRY) + if (index < m_Spawner.SpawnObjects.Length) + { + string str = m_Spawner.SpawnObjects[index].TypeName; + + if (str != null && str.Length >= 230) + { + entrystr = str; + } + } +#endif + if (type == 0) // Add creature + { + m_Spawner.AddSpawnObject(entrystr); + } + else // Remove creatures + { + m_Spawner.DeleteSpawnObject(state.Mobile, entrystr); + + } + } + } + break; + } + } + + state.Mobile.SendGump(new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page, Rentry)); + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs new file mode 100644 index 000000000..314551e44 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs @@ -0,0 +1,296 @@ +using System.Collections; +using Server.Items; +using CPA = Server.CommandPropertyAttribute; +using Server.Misc; + +namespace Server.Mobiles; + +public class XmlSpawnerSkillCheck +{ + // alternate skillcheck hooks to replace those in SkillCheck.cs + public static bool Mobile_SkillCheckLocation(Mobile from, SkillName skillName, double minSkill, double maxSkill) + { + Skill skill = from.Skills[skillName]; + + if (skill == null) + { + return false; + } + + // call the default skillcheck handler + bool success = SkillCheck.Mobile_SkillCheckLocation( from, skillName, minSkill, maxSkill); + + // call the xmlspawner skillcheck handler + CheckSkillUse(from, skill, success); + + return success; + } + + public static bool Mobile_SkillCheckDirectLocation(Mobile from, SkillName skillName, double chance) + { + Skill skill = from.Skills[skillName]; + + if (skill == null) + { + return false; + } + + // call the default skillcheck handler + bool success = SkillCheck.Mobile_SkillCheckDirectLocation( from, skillName, chance); + + // call the xmlspawner skillcheck handler + CheckSkillUse(from, skill, success); + + return success; + } + + public static bool Mobile_SkillCheckTarget(Mobile from, SkillName skillName, object target, double minSkill, double maxSkill) + { + Skill skill = from.Skills[skillName]; + + if (skill == null) + { + return false; + } + + // call the default skillcheck handler + bool success = SkillCheck.Mobile_SkillCheckTarget( from, skillName, target, minSkill, maxSkill); + + // call the xmlspawner skillcheck handler + CheckSkillUse(from, skill, success); + + return success; + } + + public static bool Mobile_SkillCheckDirectTarget(Mobile from, SkillName skillName, object target, double chance) + { + Skill skill = from.Skills[skillName]; + + if (skill == null) + { + return false; + } + + // call the default skillcheck handler + bool success = SkillCheck.Mobile_SkillCheckDirectTarget( from, skillName, target, chance); + + // call the xmlspawner skillcheck handler + CheckSkillUse(from, skill, success); + + return success; + } + + + public class RegisteredSkill + { + public const int MaxSkills = 52; + public const SkillName Invalid = (SkillName)(-1); + + public object target; + public SkillName sid; + + // note the extra skill MaxSkills +1 is used for any unknown skill that falls outside of the known 52 + private static ArrayList[] m_FeluccaSkillList = new ArrayList[MaxSkills+1]; + private static ArrayList[] m_TrammelSkillList = new ArrayList[MaxSkills+1]; + private static ArrayList[] m_MalasSkillList = new ArrayList[MaxSkills+1]; + private static ArrayList[] m_IlshenarSkillList = new ArrayList[MaxSkills+1]; + private static ArrayList[] m_TokunoSkillList = new ArrayList[MaxSkills+1]; + + // primary function that returns the list of objects (spawners) that are associated with a given skillname by map + public static ArrayList TriggerList(SkillName index, Map map) + { + if (map == null || map == Map.Internal) + { + return null; + } + + ArrayList[] maplist; + + // get the list for the specified map + + if (map == Map.Felucca) + { + maplist = m_FeluccaSkillList; + } + else if (map == Map.Ilshenar) + { + maplist = m_IlshenarSkillList; + } + else if (map == Map.Malas) + { + maplist = m_MalasSkillList; + } + else if (map == Map.Trammel) + { + maplist = m_TrammelSkillList; + } + else if (map == Map.Tokuno) + { + maplist = m_TokunoSkillList; + } + else + { + return null; + } + + // is it one of the standard 52 skills + if ((int)index >= 0 && (int)index < MaxSkills) + { + return maplist[(int)index] ??= new ArrayList(); + } + + // otherwise pull it out of the final slot for unknown skills. I dont know of a condition that would lead to + // additional skills being registered but it will support them if they are + return maplist[MaxSkills] ??= new ArrayList(); + } + } + + public static void RegisterSkillTrigger(object o, SkillName s, Map map) + { + if (o == null || s == RegisteredSkill.Invalid) + { + return; + } + + // go through the list and if the spawner is not on it yet, then add it + bool found = false; + + ArrayList skilllist = RegisteredSkill.TriggerList(s, map); + + if (skilllist == null) + { + return; + } + + foreach(RegisteredSkill rs in skilllist) + { + if (rs.target == o && rs.sid == s) + { + found = true; + // dont register a skill if it is already on the list for this spawner + break; + } + } + + // if it hasnt already been added to the list, then add it + if (!found) + { + RegisteredSkill newrs = new RegisteredSkill(); + newrs.target = o; + newrs.sid = s; + + skilllist.Add(newrs); + + } + } + + public static void UnRegisterSkillTrigger(object o, SkillName s, Map map, bool all) + { + if (o == null || s == RegisteredSkill.Invalid) + { + return; + } + + // go through the list and if the spawner is on it regardless of the skill registered, then remove it + if (all) + { + for(int i = 0;i 0) + { + foreach(XmlAttachment a in list) + { + if (a != null && !a.Deleted && a.HandlesOnSkillUse) + { + a.OnSkillUse(m, skill, success); + } + } + } + */ + + // then check for registered skills + ArrayList skilllist = RegisteredSkill.TriggerList(skill.SkillName, m.Map); + + if (skilllist == null) + { + return; + } + + // determine whether there are any registered objects for this skill + foreach(RegisteredSkill rs in skilllist) + { + if (rs.sid == skill.SkillName) + { + // if so then invoke their skill handlers + if (rs.target is XmlSpawner spawner) + { + if (spawner.HandlesOnSkillUse) + { + // call the spawner handler + spawner.OnSkillUse(m, skill, success); + } + } else + if (rs.target is IXmlQuest quest) + { + if (quest.HandlesOnSkillUse) + { + // call the xmlquest handler + quest.OnSkillUse(m, skill, success); + } + } + } + } + } + +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlTextEntryBook.cs b/Projects/UOContent/Engines/XMLSpawner/XmlTextEntryBook.cs new file mode 100644 index 000000000..971d1d6c4 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlTextEntryBook.cs @@ -0,0 +1,80 @@ +namespace Server.Items; + +public class XmlTextEntryBook : BaseBook +{ + public XmlTextEntryBook(int itemID, string title, string author, int pageCount, bool writable) : base(itemID, title, author, pageCount, writable) + { + } + + public XmlTextEntryBook(Serial serial) : base(serial) + { + } + + public void FillTextEntryBook(string text) + { + int pagenum = 0; + int current = 0; + + // break up the text into single line length pieces + while (text != null && current < text.Length) + { + int lineCount = 10; + string[] lines = new string[lineCount]; + + // place the line on the page + for (int i = 0; i < lineCount; i++) + { + if (current < text.Length) + { + // make each line 25 chars long + int length = text.Length - current; + if (length > 20) + { + length = 20; + } + + lines[i] = text.Substring(current, length); + current += length; + } + else + { + // fill up the remaining lines + lines[i] = string.Empty; + } + } + + if (pagenum >= PagesCount) + { + return; + } + + Pages[pagenum].Lines = lines; + pagenum++; + } + // empty the remaining contents + for (int j = pagenum; j < PagesCount; j++) + { + if (Pages[j].Lines.Length > 0) + { + for (int i = 0; i < Pages[j].Lines.Length; i++) + { + Pages[j].Lines[i] = string.Empty; + } + } + } + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + writer.Write(0); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + reader.ReadInt(); + + Delete(); + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs new file mode 100644 index 000000000..8992ed537 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs @@ -0,0 +1,468 @@ +using System.IO; +using System.Collections; +using Server.Items; +using Server.Mobiles; + +namespace Server.Engines.XmlSpawner2; + +public class WriteMulti +{ + private class TileEntry + { + public int ID; + public int X; + public int Y; + public int Z; + + public TileEntry(int id, int x, int y, int z) + { + ID = id; + X = x; + Y = y; + Z = z; + } + } + + public static void Initialize() + { + + CommandSystem.Register("WriteMulti", XmlSpawner.DiskAccessLevel, WriteMulti_OnCommand); + } + + [Usage("WriteMulti [zmin zmax][-noitems][-nostatics][-nomultis][-noaddons][-invisible]")] + [Description("Creates a multi text file from the objects within the targeted area. The min/max z range can also be specified.")] + public static void WriteMulti_OnCommand(CommandEventArgs e) + { + if (e == null || e.Mobile == null) + { + return; + } + + if (e.Mobile.AccessLevel < XmlSpawner.DiskAccessLevel) + { + e.Mobile.SendMessage("You do not have rights to perform this command."); + return; + } + + if (e.Arguments != null && e.Arguments.Length < 1) + { + e.Mobile.SendMessage("Usage: {0} [zmin zmax][-noitems][-nostatics][-nomultis][-noaddons][-invisible]", e.Command); + return; + } + + string filename = e.Arguments[0]; + + int zmin = int.MinValue; + int zmax = int.MinValue; + bool includeitems = true; + bool includestatics = true; + bool includemultis = true; + bool includeaddons = true; + bool includeinvisible = false; + + if (e.Arguments.Length > 1) + { + int index = 1; + while (index < e.Arguments.Length) + { + if (e.Arguments[index] == "-noitems") + { + includeitems = false; + index++; + } + else if (e.Arguments[index] == "-nostatics") + { + includestatics = false; + index++; + } + else if (e.Arguments[index] == "-nomultis") + { + includemultis = false; + index++; + } + else if (e.Arguments[index] == "-noaddons") + { + includeaddons = false; + index++; + } + else if (e.Arguments[index] == "-invisible") + { + includeinvisible = true; + index++; + } + else + { + try + { + zmin = int.Parse(e.Arguments[index++]); + zmax = int.Parse(e.Arguments[index++]); + } + catch + { + e.Mobile.SendMessage("{0} : Invalid zmin zmax arguments", e.Command); + return; + } + } + } + } + + string dirname; + if (Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = $"{XmlSpawner.XmlSpawnDir}/{filename}"; + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + // check to see if the file already exists and can be written to by the owner + if (File.Exists(dirname)) + { + + // check the file + try + { + StreamReader op = new StreamReader(dirname, false); + + if (op == null) + { + e.Mobile.SendMessage("Cannot access file {0}", dirname); + return; + } + + string line = op.ReadLine(); + + op.Close(); + + // check the first line + if (line != null && line.Length > 0) + { + + string[] args = line.Split(" ".ToCharArray(), 3); + if (args == null || args.Length < 3) + { + e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + return; + } + + if (args[2] != e.Mobile.Name) + { + e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + return; + } + } + else + { + e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + return; + } + + } + catch + { + e.Mobile.SendMessage("Cannot overwrite file {0}", dirname); + return; + } + + } + + DefineMultiArea(e.Mobile, dirname, zmin, zmax, includeitems, includestatics, includemultis, includeinvisible, includeaddons); + } + + public static void DefineMultiArea(Mobile m, string dirname, int zmin, int zmax, bool includeitems, bool includestatics, + bool includemultis, bool includeinvisible, bool includeaddons) + { + BoundingBoxPicker.Begin( + m, + (map, start, end) => DefineMultiArea_Callback( + m, + map, + start, + end, + dirname, + zmin, + zmax, + includeitems, + includestatics, + includemultis, + includeinvisible, + includeaddons + ) + ); + } + + private static void DefineMultiArea_Callback( + Mobile from, + Map map, + Point3D start, + Point3D end, + string dirname, + int zmin, + int zmax, + bool includeitems, + bool includestatics, + bool includemultis, + bool includeinvisible, + bool includeaddons + ) + { + if (from != null && map != null) + { + ArrayList itemlist = new ArrayList(); + ArrayList staticlist = new ArrayList(); + ArrayList tilelist = new ArrayList(); + + int sx = start.X > end.X ? end.X : start.X; + int sy = start.Y > end.Y ? end.Y : start.Y; + int ex = start.X < end.X ? end.X : start.X; + int ey = start.Y < end.Y ? end.Y : start.Y; + + // find all of the world-placed items within the specified area + if (includeitems) + { + // make the first pass for items only + IPooledEnumerable eable = map.GetItemsInBounds(new Rectangle2D(sx, sy, ex - sx + 1, ey - sy + 1)); + + foreach (Item item in eable) + { + // is it within the bounding area + if (item.Parent == null && (zmin == int.MinValue || item.Location.Z >= zmin && item.Location.Z <= zmax)) + { + // add the item + if ((includeinvisible || item.Visible) && item.ItemID <= 16383) + { + itemlist.Add(item); + } + } + } + + eable.Free(); + + int searchrange = 100; + + // make the second expanded pass to pick up addon components and multi components + eable = map.GetItemsInBounds(new Rectangle2D(sx - searchrange, sy - searchrange, ex - sy + searchrange * 2 + 1, + ey - sy + searchrange * 2 + 1)); + + foreach (Item item in eable) + { + // is it within the bounding area + if (item.Parent == null) + { + + if (item is BaseAddon addon && includeaddons) + { + // go through all of the addon components + foreach (AddonComponent c in addon.Components) + { + int x = c.X; + int y = c.Y; + int z = c.Z; + + if ((includeinvisible || addon.Visible) && (addon.ItemID <= 16383 || includemultis) && + x >= sx && x <= ex && y >= sy && y <= ey && (zmin == int.MinValue || z >= zmin && z <= zmax)) + { + itemlist.Add(c); + } + } + } + + if (item is BaseMulti multi && includemultis) + { + // go through all of the multi components + MultiComponentList mcl = multi.Components; + if (mcl != null && mcl.List != null) + { + for (int i = 0; i < mcl.List.Length; i++) + { + MultiTileEntry t = mcl.List[i]; + + int x = t.OffsetX + multi.X; + int y = t.OffsetY + multi.Y; + int z = t.OffsetZ + multi.Z; + int itemID = t.ItemId & 0x3FFF; + + if (x >= sx && x <= ex && y >= sy && y <= ey && (zmin == int.MinValue || z >= zmin && z <= zmax)) + { + tilelist.Add(new TileEntry(itemID, x, y, z)); + } + } + + } + } + } + } + + eable.Free(); + } + + // find all of the static tiles within the specified area + if (includestatics) + { + // count the statics + for (int x = sx; x < ex; x++) + { + for (int y = sy; y < ey; y++) + { + StaticTile[] statics = map.Tiles.GetStaticTiles(x, y, false); + + for (int j = 0; j < statics.Length; j++) + { + if (zmin == int.MinValue || statics[j].Z >= zmin && statics[j].Z <= zmax) + { + staticlist.Add(new TileEntry(statics[j].ID & 0x3FFF, x, y, statics[j].Z)); + } + } + } + } + } + + int nstatics = staticlist.Count; + int nitems = itemlist.Count; + int ntiles = tilelist.Count; + + int ntotal = nitems + nstatics + ntiles; + + int ninvisible = 0; + int nmultis = ntiles; + int naddons = 0; + + foreach (Item item in itemlist) + { + int x = item.X - from.X; + int y = item.Y - from.Y; + int z = item.Z - from.Z; + + if (item.ItemID > 16383) + { + nmultis++; + } + if (!item.Visible) + { + ninvisible++; + } + if (item is BaseAddon || item is AddonComponent) + { + naddons++; + } + } + + try + { + // open the file, overwrite any previous contents + StreamWriter op = new StreamWriter(dirname, false); + + if (op != null) + { + // write the header + op.WriteLine("1 version {0}", from.Name); + op.WriteLine("{0} num components", ntotal); + + // write out the items + foreach (Item item in itemlist) + { + + int x = item.X - from.X; + int y = item.Y - from.Y; + int z = item.Z - from.Z; + + if (item.Hue > 0) + { + // format is x y z visible hue + op.WriteLine("{0} {1} {2} {3} {4} {5}", item.ItemID, x, y, z, item.Visible ? 1 : 0, item.Hue); + } + else + { + // format is x y z visible + op.WriteLine("{0} {1} {2} {3} {4}", item.ItemID, x, y, z, item.Visible ? 1 : 0); + } + } + + if (includestatics) + { + foreach (TileEntry s in staticlist) + { + int x = s.X - from.X; + int y = s.Y - from.Y; + int z = s.Z - from.Z; + int ID = s.ID; + op.WriteLine("{0} {1} {2} {3} {4}", ID, x, y, z, 1); + } + } + + if (includemultis) + { + foreach (TileEntry s in tilelist) + { + int x = s.X - from.X; + int y = s.Y - from.Y; + int z = s.Z - from.Z; + int ID = s.ID; + op.WriteLine("{0} {1} {2} {3} {4}", ID, x, y, z, 1); + } + } + } + + op.Close(); + } + catch + { + from.SendMessage("Error writing multi file {0}", dirname); + return; + } + + from.SendMessage(66, "WriteMulti results:"); + + if (includeitems) + { + from.SendMessage(66, "Included {0} items", nitems); + + if (includemultis) + { + from.SendMessage("{0} multis", nmultis); + } + else + { + from.SendMessage(33, "Ignored multis"); + } + + if (includeinvisible) + { + from.SendMessage("{0} invisible", ninvisible); + } + else + { + from.SendMessage(33, "Ignored invisible"); + } + + if (includeaddons) + { + from.SendMessage("{0} addons", naddons); + } + else + { + from.SendMessage(33, "Ignored addons"); + } + + } + else + { + from.SendMessage(33, "Ignored items"); + } + + if (includestatics) + { + from.SendMessage(66, "Included {0} statics", nstatics); + } + else + { + from.SendMessage(33, "Ignored statics"); + } + + from.SendMessage(66, "Saved {0} components to {1}", ntotal, dirname); + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs new file mode 100644 index 000000000..eac9420f2 --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs @@ -0,0 +1,1774 @@ +using Server.Accounting; +using Server.Gumps; +using Server.Items; +using Server.Network; +using Server.Targeting; +using System; +using System.Collections; +using System.Data; +using System.IO; + +namespace Server.Mobiles; + +public class XmlSpawnerDefaults +{ + public class DefaultEntry + { + public string AccountName; + public string PlayerName; + public TimeSpan MinDelay = TimeSpan.FromMinutes(5); + public TimeSpan MaxDelay = TimeSpan.FromMinutes(10); + public TimeSpan RefractMin = TimeSpan.FromMinutes(0); + public TimeSpan RefractMax = TimeSpan.FromMinutes(0); + public TimeSpan TODStart = TimeSpan.FromMinutes(0); + public TimeSpan TODEnd = TimeSpan.FromMinutes(0); + public TimeSpan Duration = TimeSpan.FromMinutes(0); + public TimeSpan DespawnTime = TimeSpan.FromHours(0); + public bool Group; + public int Team; + public int ProximitySound = 0x1F4; + public string SpeechTrigger; + public string SkillTrigger; + public int SequentialSpawn = -1; + public bool HomeRangeIsRelative = true; + public int SpawnRange = 5; + public int HomeRange = 5; + public int ProximityRange = -1; + public XmlSpawner.TODModeType TODMode = XmlSpawner.TODModeType.Realtime; + public int KillReset = 1; + public string SpawnerName = "Spawner"; + public bool AllowGhostTrig; + public bool AllowNPCTrig; + public bool SpawnOnTrigger; + public bool SmartSpawning; + public bool ExternalTriggering; + public string TriggerOnCarried; + public string NoTriggerOnCarried; + public string ProximityMsg; + public double TriggerProbability = 1; + public string PlayerTriggerProp; + public string TriggerObjectProp; + public string DefsExt; + public string[] NameList; + public bool[] SelectionList; + public int AddGumpX = 440; + public int AddGumpY; + public int SpawnerGumpX; + public int SpawnerGumpY; + public int FindGumpX; + public int FindGumpY; + + // these are additional defaults that are not set by XmlAdd but can be used by other routines such as the custom properties gump to determine + // whether properties have been changed from spawner default values + public bool Running = true; + + public bool AutoNumber; + public int AutoNumberValue; + + public XmlAddCAGCategory CurrentCategory; + public int CurrentCategoryPage; + public int CategorySelectionIndex = -1; + + public XmlSpawner LastSpawner; + public Map StartingMap; + public Point3D StartingLoc; + public bool ShowExtension; + + public bool IgnoreUpdate; + } + public static ArrayList DefaultEntryList; + + public static DefaultEntry GetDefaults(string account, string name) + { + // find the default entry corresponding to the account and username + if (DefaultEntryList != null) + { + for (int i = 0; i < DefaultEntryList.Count; i++) + { + DefaultEntry entry = (DefaultEntry)DefaultEntryList[i]; + if (entry != null && string.Compare(entry.PlayerName, name, true) == 0 && string.Compare(entry.AccountName, account, true) == 0) + { + return entry; + } + } + } + // if not found then add one + DefaultEntry newentry = new DefaultEntry + { + PlayerName = name, + AccountName = account + }; + if (DefaultEntryList == null) + { + DefaultEntryList = new ArrayList(); + } + + DefaultEntryList.Add(newentry); + return newentry; + } + + public static void RestoreDefs(DefaultEntry defs) + { + if (defs == null) + { + return; + } + + defs.MinDelay = TimeSpan.FromMinutes(5); + defs.MaxDelay = TimeSpan.FromMinutes(10); + defs.RefractMin = TimeSpan.FromMinutes(0); + defs.RefractMax = TimeSpan.FromMinutes(0); + defs.TODStart = TimeSpan.FromMinutes(0); + defs.TODEnd = TimeSpan.FromMinutes(0); + defs.Duration = TimeSpan.FromMinutes(0); + defs.DespawnTime = TimeSpan.FromHours(0); + defs.Group = false; + defs.Team = 0; + defs.ProximitySound = 0x1F4; + defs.SpeechTrigger = null; + defs.SkillTrigger = null; + defs.SequentialSpawn = -1; + defs.HomeRangeIsRelative = true; + defs.SpawnRange = 5; + defs.HomeRange = 5; + defs.ProximityRange = -1; + defs.TODMode = XmlSpawner.TODModeType.Realtime; + defs.KillReset = 1; + defs.SpawnerName = "Spawner"; + defs.AllowGhostTrig = false; + defs.AllowNPCTrig = false; + defs.SpawnOnTrigger = false; + defs.SmartSpawning = false; + defs.ExternalTriggering = false; + defs.TriggerOnCarried = null; + defs.NoTriggerOnCarried = null; + defs.ProximityMsg = null; + defs.TriggerProbability = 1; + defs.PlayerTriggerProp = null; + defs.TriggerObjectProp = null; + defs.DefsExt = null; + defs.AddGumpX = 440; + defs.AddGumpY = 0; + defs.SpawnerGumpX = 0; + defs.SpawnerGumpY = 0; + defs.FindGumpX = 0; + defs.FindGumpY = 0; + defs.AutoNumber = false; + defs.AutoNumberValue = 0; + + if (defs.SelectionList != null) + { + Array.Clear(defs.SelectionList, 0, defs.SelectionList.Length); + } + + if (defs.NameList != null) + { + Array.Clear(defs.NameList, 0, defs.NameList.Length); + } + } +} + +public class XmlAddGump : Gump +{ + private const int MaxEntries = 40; + private const int MaxEntriesPerColumn = 20; + private const string DefsDataSetName = "Defs"; + private const string DefsTablePointName = "Values"; + private const string DefsDir = "SpawnerDefs"; + + private readonly Mobile m_From; + + public XmlSpawnerDefaults.DefaultEntry defs; + + private string NameListToString() + { + if (defs.NameList == null || defs.NameList.Length == 0) + { + return "0"; + } + + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.AppendFormat("{0}", defs.NameList.Length); + for (int i = 0; i < defs.NameList.Length; i++) + { + sb.AppendFormat(":{0}", defs.NameList[i]); + } + return sb.ToString(); + } + + private string SelectionListToString() + { + if (defs.SelectionList == null || defs.SelectionList.Length == 0) + { + return "0"; + } + + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.AppendFormat("{0}", defs.SelectionList.Length); + for (int i = 0; i < defs.SelectionList.Length; i++) + { + sb.AppendFormat(":{0}", defs.SelectionList[i] ? 1 : 0); + } + return sb.ToString(); + } + + private static string[] StringToNameList(string namelist) + { + string[] newlist = new string[MaxEntries]; + string[] tmplist = namelist.Split(':'); + for (int i = 1; i < tmplist.Length; i++) + { + if (i - 1 >= newlist.Length) + { + break; + } + + newlist[i - 1] = tmplist[i]; + } + return newlist; + } + + private static bool[] StringToSelectionList(string selectionlist) + { + bool[] newlist = new bool[MaxEntries]; + string[] tmplist = selectionlist.Split(':'); + for (int i = 1; i < tmplist.Length; i++) + { + if (i - 1 >= newlist.Length) + { + break; + } + + if (tmplist[i] == "1") + { + newlist[i - 1] = true; + } + else + { + newlist[i - 1] = false; + } + } + return newlist; + } + + private void DoSaveDefs(Mobile from, string filename) + { + if (filename == null || filename.Length <= 0) + { + return; + } + + // Create the data set + DataSet ds = new DataSet(DefsDataSetName); + + // Load the data set up + ds.Tables.Add(DefsTablePointName); + + // Create spawn point schema + //ds.Tables[DefsTablePointName].Columns.Add("AccountName"); + //ds.Tables[DefsTablePointName].Columns.Add("PlayerName"); + ds.Tables[DefsTablePointName].Columns.Add("MinDelay"); + ds.Tables[DefsTablePointName].Columns.Add("MaxDelay"); + ds.Tables[DefsTablePointName].Columns.Add("SpawnRange"); + ds.Tables[DefsTablePointName].Columns.Add("HomeRange"); + ds.Tables[DefsTablePointName].Columns.Add("MinRefractory"); + ds.Tables[DefsTablePointName].Columns.Add("MaxRefractory"); + ds.Tables[DefsTablePointName].Columns.Add("TODStart"); + ds.Tables[DefsTablePointName].Columns.Add("TODEnd"); + ds.Tables[DefsTablePointName].Columns.Add("Duration"); + ds.Tables[DefsTablePointName].Columns.Add("DespawnTime"); + ds.Tables[DefsTablePointName].Columns.Add("RelativeHome"); + ds.Tables[DefsTablePointName].Columns.Add("IsGroup"); + ds.Tables[DefsTablePointName].Columns.Add("Team"); + ds.Tables[DefsTablePointName].Columns.Add("ProximityTriggerSound"); + ds.Tables[DefsTablePointName].Columns.Add("SpeechTrigger"); + ds.Tables[DefsTablePointName].Columns.Add("SkillTrigger"); + ds.Tables[DefsTablePointName].Columns.Add("SequentialSpawn"); + ds.Tables[DefsTablePointName].Columns.Add("ProximityRange"); + ds.Tables[DefsTablePointName].Columns.Add("TODMode"); + ds.Tables[DefsTablePointName].Columns.Add("KillReset"); + ds.Tables[DefsTablePointName].Columns.Add("SpawnerName"); + ds.Tables[DefsTablePointName].Columns.Add("AllowGhost"); + ds.Tables[DefsTablePointName].Columns.Add("AllowNPC"); + ds.Tables[DefsTablePointName].Columns.Add("SpawnOnTrigger"); + ds.Tables[DefsTablePointName].Columns.Add("SmartSpawn"); + ds.Tables[DefsTablePointName].Columns.Add("ExtTrig"); + ds.Tables[DefsTablePointName].Columns.Add("TrigOnCarried"); + ds.Tables[DefsTablePointName].Columns.Add("NoTrigOnCarried"); + ds.Tables[DefsTablePointName].Columns.Add("ProximityMessage"); + ds.Tables[DefsTablePointName].Columns.Add("TrigProb"); + ds.Tables[DefsTablePointName].Columns.Add("PlayerTrigProp"); + ds.Tables[DefsTablePointName].Columns.Add("TrigObjectProp"); + //ds.Tables[DefsTablePointName].Columns.Add("DefsExt"); + ds.Tables[DefsTablePointName].Columns.Add("NameList"); + ds.Tables[DefsTablePointName].Columns.Add("SelectionList"); + ds.Tables[DefsTablePointName].Columns.Add("AddGumpX"); + ds.Tables[DefsTablePointName].Columns.Add("AddGumpY"); + ds.Tables[DefsTablePointName].Columns.Add("SpawnerGumpX"); + ds.Tables[DefsTablePointName].Columns.Add("SpawnerGumpY"); + ds.Tables[DefsTablePointName].Columns.Add("FindGumpX"); + ds.Tables[DefsTablePointName].Columns.Add("FindGumpY"); + ds.Tables[DefsTablePointName].Columns.Add("AutoNumber"); + ds.Tables[DefsTablePointName].Columns.Add("AutoNumberValue"); + + // Create a new data row + DataRow dr = ds.Tables[DefsTablePointName].NewRow(); + + // Populate the data + //dr["AccountName"] = (string)defs.AccountName; + //dr["PlayerName"] = (string)defs.PlayerName; + dr["SpawnerName"] = defs.SpawnerName; + dr["MinDelay"] = defs.MinDelay.TotalMinutes; + dr["MaxDelay"] = defs.MaxDelay.TotalMinutes; + dr["SpawnRange"] = defs.SpawnRange; + dr["HomeRange"] = defs.HomeRange; + dr["RelativeHome"] = defs.HomeRangeIsRelative; + dr["IsGroup"] = defs.Group; + dr["Team"] = defs.Team; + dr["MinRefractory"] = defs.RefractMin.TotalMinutes; + dr["MaxRefractory"] = defs.RefractMax.TotalMinutes; + dr["TODStart"] = defs.TODStart.TotalMinutes; + dr["TODEnd"] = defs.TODEnd.TotalMinutes; + dr["TODMode"] = defs.TODMode; + dr["Duration"] = defs.Duration.TotalMinutes; + dr["DespawnTime"] = defs.Duration.TotalHours; + dr["ProximityRange"] = defs.ProximityRange; + dr["ProximityTriggerSound"] = defs.ProximitySound; + dr["ProximityMessage"] = defs.ProximityMsg; + dr["SpeechTrigger"] = defs.SpeechTrigger; + dr["SkillTrigger"] = defs.SkillTrigger; + dr["SequentialSpawn"] = defs.SequentialSpawn; + dr["KillReset"] = defs.KillReset; + dr["TrigProb"] = defs.TriggerProbability; + dr["AllowGhost"] = defs.AllowGhostTrig; + dr["AllowNPC"] = defs.AllowNPCTrig; + dr["SpawnOnTrigger"] = defs.SpawnOnTrigger; + dr["SmartSpawn"] = defs.SmartSpawning; + dr["ExtTrig"] = defs.ExternalTriggering; + dr["TrigOnCarried"] = defs.TriggerOnCarried; + dr["NoTrigOnCarried"] = defs.NoTriggerOnCarried; + dr["PlayerTrigProp"] = defs.PlayerTriggerProp; + dr["TrigObjectProp"] = defs.TriggerObjectProp; + dr["NameList"] = NameListToString(); + dr["SelectionList"] = SelectionListToString(); + dr["AddGumpX"] = defs.AddGumpX; + dr["AddGumpY"] = defs.AddGumpY; + dr["SpawnerGumpX"] = defs.SpawnerGumpX; + dr["SpawnerGumpY"] = defs.SpawnerGumpY; + dr["FindGumpX"] = defs.FindGumpX; + dr["FindGumpY"] = defs.FindGumpY; + dr["AutoNumber"] = defs.AutoNumber; + dr["AutoNumberValue"] = defs.AutoNumberValue; + + // Add the row the the table + ds.Tables[DefsTablePointName].Rows.Add(dr); + + // Write out the file + bool file_error = false; + + var dirname = Directory.Exists(DefsDir) ? $"{DefsDir}/{filename}.defs" : $"{filename}.defs"; + + try + { + ds.WriteXml(dirname); + } + catch { file_error = true; } + + if (file_error) + { + if (from != null && !from.Deleted) + { + from.SendMessage("Error trying to save to file {0}", dirname); + } + + return; + } + + if (from != null && !from.Deleted) + { + from.SendMessage("Saved defs to file {0}", dirname); + } + } + + private void DoLoadDefs(Mobile from, string filename) + { + if (filename == null || filename.Length <= 0) + { + return; + } + + string dirname; + if (Directory.Exists(DefsDir)) + { + // look for it in the defaults directory + dirname = $"{DefsDir}/{filename}.defs"; + // Check if the file exists + if (File.Exists(dirname) == false) + { + // didnt find it so just look in the main install dir + dirname = $"{filename}.defs"; + } + } + else + { + // look in the main installation dir + dirname = $"{filename}.defs"; + } + // Check if the file exists + if (File.Exists(dirname)) + { + FileStream fs = null; + try + { + fs = File.Open(dirname, FileMode.Open, FileAccess.Read); + } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + + if (fs == null) + { + from.SendMessage("Unable to open {0} for loading", dirname); + return; + } + + // Create the data set + DataSet ds = new DataSet(DefsDataSetName); + + // Read in the file + //ds.ReadXml(e.Arguments[0].ToString()); + bool fileerror = false; + try + { + ds.ReadXml(fs); + } + catch { fileerror = true; } + // close the file + fs.Close(); + if (fileerror) + { + if (from != null && !from.Deleted) + { + from.SendMessage(33, "Error reading defs file {0}", dirname); + } + + return; + } + + // Check that at least a single table was loaded + if (ds.Tables.Count > 0) + { + // Add each spawn point to the current map + if (ds.Tables[DefsTablePointName] != null && ds.Tables[DefsTablePointName].Rows.Count > 0) + { + //foreach(DataRow dr in ds.Tables[DefsTablePointName].Rows){ + DataRow dr = ds.Tables[DefsTablePointName].Rows[0]; + + try { defs.SpawnerName = (string)dr["SpawnerName"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + + double mindelay = defs.MinDelay.TotalMinutes; + try { mindelay = double.Parse((string)dr["MinDelay"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + defs.MinDelay = TimeSpan.FromMinutes(mindelay); + + double maxdelay = defs.MaxDelay.TotalMinutes; + try { maxdelay = double.Parse((string)dr["MaxDelay"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + defs.MaxDelay = TimeSpan.FromMinutes(maxdelay); + + try { defs.SpawnRange = int.Parse((string)dr["SpawnRange"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.HomeRange = int.Parse((string)dr["HomeRange"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.HomeRangeIsRelative = bool.Parse((string)dr["RelativeHome"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.Group = bool.Parse((string)dr["IsGroup"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.Team = int.Parse((string)dr["Team"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + + double minrefract = defs.RefractMin.TotalMinutes; + try { minrefract = double.Parse((string)dr["MinRefractory"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + defs.RefractMin = TimeSpan.FromMinutes(minrefract); + + double maxrefract = defs.RefractMax.TotalMinutes; + try { maxrefract = double.Parse((string)dr["MaxRefractory"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + defs.RefractMax = TimeSpan.FromMinutes(maxrefract); + + double todstart = defs.TODStart.TotalMinutes; + try { todstart = double.Parse((string)dr["TODStart"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + defs.TODStart = TimeSpan.FromMinutes(todstart); + + double todend = defs.TODEnd.TotalMinutes; + try { todend = double.Parse((string)dr["TODEnd"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + defs.TODEnd = TimeSpan.FromMinutes(todend); + + string todmode = null; + try { todmode = (string)dr["TODMode"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + if (todmode != null) + { + if (todmode == "Realtime") + { + defs.TODMode = XmlSpawner.TODModeType.Realtime; + } + else + if (todmode == "Gametime") + { + defs.TODMode = XmlSpawner.TODModeType.Gametime; + } + } + + double duration = defs.Duration.TotalMinutes; + try { duration = double.Parse((string)dr["Duration"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + defs.Duration = TimeSpan.FromMinutes(duration); + + double despawnTime = defs.DespawnTime.TotalHours; + try { despawnTime = double.Parse((string)dr["DespawnTime"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + defs.DespawnTime = TimeSpan.FromHours(despawnTime); + + try { defs.ProximityRange = int.Parse((string)dr["ProximityRange"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.ProximitySound = int.Parse((string)dr["ProximityTriggerSound"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.ProximityMsg = (string)dr["ProximityMessage"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.SpeechTrigger = (string)dr["SpeechTrigger"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.SkillTrigger = (string)dr["SkillTrigger"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.SequentialSpawn = int.Parse((string)dr["SequentialSpawn"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.KillReset = int.Parse((string)dr["KillReset"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.TriggerProbability = double.Parse((string)dr["TrigProb"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.AllowGhostTrig = bool.Parse((string)dr["AllowGhost"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.AllowNPCTrig = bool.Parse((string)dr["AllowNPC"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.SpawnOnTrigger = bool.Parse((string)dr["SpawnOnTrigger"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.SmartSpawning = bool.Parse((string)dr["SmartSpawn"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.ExternalTriggering = bool.Parse((string)dr["ExtTrig"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.TriggerOnCarried = (string)dr["TrigOnCarried"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.NoTriggerOnCarried = (string)dr["NoTrigOnCarried"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.PlayerTriggerProp = (string)dr["PlayerTrigProp"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.TriggerObjectProp = (string)dr["TrigObjectProp"]; } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + + try { defs.NameList = StringToNameList((string)dr["NameList"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.SelectionList = StringToSelectionList((string)dr["SelectionList"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.AddGumpX = int.Parse((string)dr["AddGumpX"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.AddGumpY = int.Parse((string)dr["AddGumpY"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.SpawnerGumpX = int.Parse((string)dr["SpawnerGumpX"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.SpawnerGumpY = int.Parse((string)dr["SpawnerGumpY"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.FindGumpX = int.Parse((string)dr["FindGumpX"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.FindGumpY = int.Parse((string)dr["FindGumpY"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.AutoNumber = bool.Parse((string)dr["AutoNumber"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + try { defs.AutoNumberValue = int.Parse((string)dr["AutoNumberValue"]); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + + if (from != null && !from.Deleted) + { + from.SendMessage("Loaded defs from file {0}", dirname); + } + } + } + } + else + { + if (from != null && !from.Deleted) + { + from.SendMessage(33, "File not found: {0}", dirname); + } + } + } + + public static void Initialize() + { + CommandSystem.Register("XmlAdd", AccessLevel.GameMaster, XmlAdd_OnCommand); + } + + [Usage("XmlAdd [-defaults]")] + [Description("Opens a gump that can add Xmlspawners with specified default settings")] + public static void XmlAdd_OnCommand(CommandEventArgs e) + { + Account acct = e.Mobile.Account as Account; + int x = 440; + int y = 0; + XmlSpawnerDefaults.DefaultEntry defs = null; + if (acct != null) + { + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), e.Mobile.Name); + } + + if (defs != null) + { + x = defs.AddGumpX; + y = defs.AddGumpY; + } + // Check if there is an argument provided (load criteria) + try + { + // Check if there is an argument provided (load criteria) + for (int nxtarg = 0; nxtarg < e.Arguments.Length; nxtarg++) + { + // is it a defaults option? + if (e.Arguments[nxtarg].ToLower() == "-defaults") + { + XmlSpawnerDefaults.RestoreDefs(defs); + if (defs != null) + { + x = defs.AddGumpX; + y = defs.AddGumpY; + } + } + } + } + catch (Exception ex) { Diagnostics.ExceptionLogging.LogException(ex); } + + e.Mobile.SendGump(new XmlAddGump(e.Mobile, e.Mobile.Location, e.Mobile.Map, true, false, x, y)); + + } + + public XmlAddGump(Mobile from, Point3D startloc, Map startmap, bool firststart, bool extension, int gumpx, int gumpy) : base(gumpx, gumpy) + { + if (from == null || from.Deleted) + { + return; + } + + defs = null; + + m_From = from; + + // read the text entries for default values + Account acct = from.Account as Account; + if (acct != null) + { + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); + } + + if (defs == null) + { + return; + } + + if (firststart) + { + defs.StartingMap = from.Map; + defs.StartingLoc = from.Location; + } + else + { + defs.StartingMap = startmap; + defs.StartingLoc = startloc; + } + + defs.IgnoreUpdate = false; + defs.ShowExtension = extension; + + if (defs.SelectionList == null) + { + defs.SelectionList = new bool[MaxEntries]; + } + if (defs.NameList == null) + { + defs.NameList = new string[MaxEntries]; + } + + + // prepare the page + + AddPage(0); + if (defs.ShowExtension) + { + AddBackground(0, 0, 520, 500, 5054); + AddAlphaRegion(0, 0, 520, 500); + } + else + { + AddBackground(0, 0, 200, 500, 5054); + AddAlphaRegion(0, 0, 200, 500); + } + + var y = 3; + var yinc = 20; + // add the min/maxdelay entries + AddImageTiled(5, y, 40, 19, 0xBBC); + AddTextEntry(5, y, 40, 19, 0, 100, defs.MinDelay.TotalMinutes.ToString()); + AddLabel(45, y, 0x384, "MinDelay(m)"); + + AddImageTiled(105, y, 40, 19, 0xBBC); + AddTextEntry(105, y, 40, 19, 0, 101, defs.MaxDelay.TotalMinutes.ToString()); + AddLabel(145, y, 0x384, "MaxDelay(m)"); + + y += yinc; + AddImageTiled(5, y, 40, 19, 0xBBC); + AddTextEntry(5, y, 40, 19, 0, 107, defs.HomeRange.ToString()); + AddLabel(45, y, 0x384, "HomeRng"); + + AddImageTiled(105, y, 40, 19, 0xBBC); + AddTextEntry(105, y, 40, 19, 0, 108, defs.SpawnRange.ToString()); + AddLabel(145, y, 0x384, "SpawnRng"); + + y += yinc; + AddImageTiled(5, y, 40, 19, 0xBBC); + AddTextEntry(5, y, 40, 19, 0, 109, defs.ProximityRange.ToString()); + AddLabel(45, y, 0x384, "ProxRng"); + + AddImageTiled(105, y, 40, 19, 0xBBC); + AddTextEntry(105, y, 40, 19, 0, 110, defs.Team.ToString()); + AddLabel(145, y, 0x384, "Team"); + + y += yinc; + AddImageTiled(5, y, 40, 19, 0xBBC); + AddTextEntry(5, y, 40, 19, 0, 113, defs.KillReset.ToString()); + AddLabel(45, y, 0x384, "KillReset"); + + AddImageTiled(105, y, 40, 19, 0xBBC); + AddTextEntry(105, y, 40, 19, 0, 121, defs.TriggerProbability.ToString()); + AddLabel(145, y, 0x384, "TrigProb"); + + y += yinc; + AddImageTiled(5, y, 40, 19, 0xBBC); + AddTextEntry(5, y, 40, 19, 0, 111, defs.Duration.TotalMinutes.ToString()); + AddLabel(45, y, 0x384, "Duration(m)"); + + AddImageTiled(105, y, 40, 19, 0xBBC); + AddTextEntry(105, y, 40, 19, 0, 112, defs.ProximitySound.ToString()); + AddLabel(145, y, 0x384, "ProxSnd"); + + y += yinc; + AddImageTiled(5, y, 40, 19, 0xBBC); + AddTextEntry(5, y, 40, 19, 0, 102, defs.RefractMin.TotalMinutes.ToString()); + AddLabel(45, y, 0x384, "MinRefr(m)"); + + AddImageTiled(105, y, 40, 19, 0xBBC); + AddTextEntry(105, y, 40, 19, 0, 103, defs.RefractMax.TotalMinutes.ToString()); + AddLabel(145, y, 0x384, "MaxRefr(m)"); + + y += yinc; + AddImageTiled(5, y, 40, 19, 0xBBC); + AddTextEntry(5, y, 40, 19, 0, 104, defs.TODStart.TotalHours.ToString()); + AddLabel(45, y, 0x384, "TODStart(h)"); + + AddImageTiled(105, y, 40, 19, 0xBBC); + AddTextEntry(105, y, 40, 19, 0, 105, defs.TODEnd.TotalHours.ToString()); + AddLabel(145, y, 0x384, "TODEnd(h)"); + + y += yinc; + AddImageTiled(5, y, 40, 19, 0xBBC); + AddTextEntry(5, y, 40, 19, 0, 123, defs.DespawnTime.TotalHours.ToString()); + AddLabel(45, y, 0x384, "Despawn(h)"); + + + // AllowNPC + AddLabel(125, y, 0x384, "AllowNPC"); + AddCheck(105, y, 0xD2, 0xD3, defs.AllowNPCTrig, 312); + + //y = 164; + yinc = 21; + y += yinc; + // TOD + if (defs.TODMode == XmlSpawner.TODModeType.Gametime) + { + AddLabel(25, y, 0x384, "GameTOD"); + } + else + if (defs.TODMode == XmlSpawner.TODModeType.Realtime) + { + AddLabel(25, y, 0x384, "RealTOD"); + } + + AddButton(5, y, 0xD3, 0xD3, 306); + + + // Sequentialspawn + AddLabel(125, y, 0x384, "SeqSpawn"); + AddCheck(105, y, 0xD2, 0xD3, defs.SequentialSpawn == 0, 307); + + y += yinc; + // IsGroup + AddLabel(25, y, 0x384, "Group"); + AddCheck(5, y, 0xD2, 0xD3, defs.Group, 304); + + // HomeRangeRelative + AddLabel(125, y, 0x384, "HomeRngRel"); + AddCheck(105, y, 0xD2, 0xD3, defs.HomeRangeIsRelative, 305); + + y += yinc; + // smart spawning + AddLabel(25, y, 0x384, "SmartSpawn"); + AddCheck(5, y, 0xD2, 0xD3, defs.SmartSpawning, 310); + + // AllowGhost + AddLabel(125, y, 0x384, "AllowGhost"); + AddCheck(105, y, 0xD2, 0xD3, defs.AllowGhostTrig, 309); + + y += yinc; + // ExtTrig + AddLabel(25, y, 0x384, "ExtTrig"); + AddCheck(5, y, 0xD2, 0xD3, defs.ExternalTriggering, 308); + + // SpawnOnTrig + AddLabel(125, y, 0x384, "SpawnOnTrig"); + AddCheck(105, y, 0xD2, 0xD3, defs.SpawnOnTrigger, 311); + + y += yinc; + // AutoNumber + AddLabel(25, y, 0x384, "AutoNumber"); + AddCheck(5, y, 0xD2, 0xD3, defs.AutoNumber, 306); + AddImageTiled(105, y, 80, 19, 0xBBC); + AddTextEntry(105, y, 80, 19, 0, 125, defs.AutoNumberValue.ToString()); + + //y = 270; + yinc = 20; + y += yinc; + // Name + AddImageTiled(5, y, 95, 19, 0xBBC); + AddTextEntry(5, y, 85, 19, 0, 114, defs.SpawnerName); + AddLabel(105, y, 0x384, "SpawnerName"); + + y += yinc; + // speech trigger + AddLabel(105, y, 0x384, "SpeechTrigger"); + AddImageTiled(5, y, 95, 19, 0xBBC); + AddTextEntry(5, y, 85, 19, 0, 106, defs.SpeechTrigger); + + y += yinc; + // skill trigger + AddLabel(105, y, 0x384, "SkillTrigger"); + AddImageTiled(5, y, 95, 19, 0xBBC); + AddTextEntry(5, y, 85, 19, 0, 124, defs.SkillTrigger); + + y += yinc; + AddImageTiled(5, y, 95, 19, 0xBBC); + AddTextEntry(5, y, 85, 19, 0, 117, defs.TriggerOnCarried); + AddLabel(105, y, 0x384, "TrigOnCarried"); + + y += yinc; + AddImageTiled(5, y, 95, 19, 0xBBC); + AddTextEntry(5, y, 85, 19, 0, 118, defs.NoTriggerOnCarried); + AddLabel(105, y, 0x384, "NoTrigOnCarried"); + + y += yinc; + AddImageTiled(5, y, 95, 19, 0xBBC); + AddTextEntry(5, y, 85, 19, 0, 119, defs.ProximityMsg); + AddLabel(105, y, 0x384, "ProximityMsg"); + + y += yinc; + AddImageTiled(5, y, 95, 19, 0xBBC); + AddTextEntry(5, y, 85, 19, 0, 120, defs.PlayerTriggerProp); + AddLabel(105, y, 0x384, "PlayerTrigProp"); + + y += yinc; + AddImageTiled(5, y, 95, 19, 0xBBC); + AddTextEntry(5, y, 85, 19, 0, 122, defs.TriggerObjectProp); + AddLabel(105, y, 0x384, "TrigObjectProp"); + + //y = 429; + yinc = 23; + y += yinc; + // add the RestoreDefs button + AddButton(5, y, 0xFAE, 0xFAF, 117); + AddLabel(35, y, 0x384, "Restore Defs"); + + // add the RestoreDefs button + AddButton(125, y, 0xFAE, 0xFAF, 180); + AddLabel(155, y, 0x384, "Options"); + + y += yinc; + // add the SaveDefs button + AddButton(5, y, 0xFAE, 0xFAF, 115); + AddLabel(35, y, 0x384, "Save"); + + // add the LoadDefs button + AddButton(65, y, 0xFAE, 0xFAF, 116); + AddLabel(95, y, 0x384, "Load"); + + // add the DefsExt entry + AddImageTiled(127, y, 68, 21, 0xBBC); + AddTextEntry(129, y, 64, 21, 0, 115, defs.DefsExt); + + y += yinc; + // add the Add button + AddButton(5, y, 0xFAE, 0xFAF, 100); + AddLabel(35, y, 0x384, "Add"); + + // add the Goto button + AddButton(64, y, 0xFAE, 0xFAF, 1000); + AddLabel(94, y, 0x384, "Goto"); + + // add the Delete button + AddButton(125, y, 0xFAE, 0xFAF, 156); + AddLabel(155, y, 0x384, "Del"); + + // add the Edit button + // add the Find button + + // add gump extension button + if (defs.ShowExtension) + { + AddButton(480, y + 5, 0x15E3, 0x15E7, 200); + } + else + { + AddButton(180, y + 5, 0x15E1, 0x15E5, 200); + } + + if (defs.ShowExtension) + { + AddLabel(300, 5, 0x384, "Spawn Entries"); + // display the clear all toggle + AddButton(475, 5, 0xD2, 0xD3, 3999); + // display the selection entries + for (int i = 0; i < MaxEntries; i++) + { + int xpos = i / MaxEntriesPerColumn * 155; + int ypos = i % MaxEntriesPerColumn * 22 + 30; + + // background for search results area + AddImageTiled(xpos + 205, ypos, 116, 23, 0x52); + + // has this been selected for category info specification? + AddImageTiled(xpos + 206, ypos + 1, 114, 21, i == defs.CategorySelectionIndex ? 0x1436 : 0xBBC); + + bool sel = false; + if (defs.SelectionList != null && i < defs.SelectionList.Length) + { + sel = defs.SelectionList[i]; + } + + int texthue = 0; + if (sel) + { + texthue = 68; + } + + string namestr = null; + if (defs.NameList != null && i < defs.NameList.Length) + { + namestr = defs.NameList[i]; + } + + AddTextEntry(xpos + 208, ypos + 1, 110, 21, texthue, 1000 + i, namestr); + // display the selection button + AddButton(xpos + 320, ypos + 2, sel ? 0xD3 : 0xD2, sel ? 0xD2 : 0xD3, 4000 + i); + // display the info button + AddButton(xpos + 340, ypos + 2, 0x15E1, 0x15E5, 5000 + i); + } + } + } + + private void DoGoTo(Item x) + { + if (m_From == null || m_From.Deleted) + { + return; + } + + if (x == null || x.Deleted || x.Map == null) + { + return; + } + + Point3D itemloc; + + if (x.Parent != null) + { + if (x.RootParent is Container container) + { + itemloc = container.Location; + } + else + { + return; + } + } + else + { + itemloc = x.Location; + } + m_From.Location = itemloc; + m_From.Map = x.Map; + } + + private void DoShowProps(IEntity x) + { + if (m_From == null || m_From.Deleted) + { + return; + } + + if (x == null || x.Deleted || x.Map == null) + { + return; + } + + m_From.SendGump(new PropertiesGump(m_From, x)); + } + + private static void DoShowGump(Mobile from, Item x) + { + if (from == null || from.Deleted) + { + return; + } + + if (x == null || x.Deleted || x.Map == null || x.Map == Map.Internal) + { + return; + } + + x.OnDoubleClick(from); + } + + public static void Refresh(Mobile from) + { + Refresh(from, false); + } + + public static void Refresh(Mobile from, bool ignoreupdate) + { + if (from == null) + { + return; + } + + // read the text entries for default values + XmlSpawnerDefaults.DefaultEntry defs = null; + + Account acct = from.Account as Account; + if (acct != null) + { + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); + } + + if (defs == null) + { + return; + } + + int x = defs.AddGumpX; + int y = defs.AddGumpY; + if (defs.ShowExtension) + { + // shift the starting point + x = defs.AddGumpX - 140; + } + + defs.IgnoreUpdate = ignoreupdate; + + from.CloseGump(); + + defs.IgnoreUpdate = false; + from.SendGump(new XmlAddGump(from, defs.StartingLoc, defs.StartingMap, false, defs.ShowExtension, x, y)); + } + + private class PlaceSpawnerTarget : Target + { + readonly XmlSpawnerDefaults.DefaultEntry defs; + readonly NetState m_state; + + public PlaceSpawnerTarget(NetState state) : base(30, true, TargetFlags.None) + { + if (state?.Mobile == null) + { + return; + } + + // read the text entries for default values + defs = null; + + Account acct = state.Mobile.Account as Account; + if (acct != null) + { + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), state.Mobile.Name); + } + + if (defs == null) + { + return; + } + + m_state = state; + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (from == null) + { + return; + } + + // assign it a unique id + Guid SpawnId = Guid.NewGuid(); + // count the number of entries to be added for maxcount + int maxcount = 0; + for (int i = 0; i < MaxEntries; i++) + { + if (defs.SelectionList != null && i < defs.SelectionList.Length && defs.SelectionList[i] && + defs.NameList != null && i < defs.NameList.Length && defs.NameList[i] != null && defs.NameList[i].Length > 0) + { + maxcount++; + } + } + + // if autonumbering is enabled, name the spawner with the name+number + string sname = defs.SpawnerName; + if (defs.AutoNumber) + { + sname = $"{defs.SpawnerName}#{defs.AutoNumberValue}"; + } + + XmlSpawner spawner = new XmlSpawner(SpawnId, from.Location.X, from.Location.Y, 0, 0, sname, maxcount, + defs.MinDelay, defs.MaxDelay, defs.Duration, defs.ProximityRange, defs.ProximitySound, 1, + defs.Team, defs.HomeRange, defs.HomeRangeIsRelative, new XmlSpawner.SpawnObject[0], defs.RefractMin, defs.RefractMax, + defs.TODStart, defs.TODEnd, null, defs.TriggerObjectProp, defs.ProximityMsg, defs.TriggerOnCarried, defs.NoTriggerOnCarried, + defs.SpeechTrigger, null, null, defs.PlayerTriggerProp, defs.TriggerProbability, null, defs.Group, defs.TODMode, defs.KillReset, defs.ExternalTriggering, + defs.SequentialSpawn, null, defs.AllowGhostTrig, defs.AllowNPCTrig, defs.SpawnOnTrigger, null, defs.DespawnTime, defs.SkillTrigger, defs.SmartSpawning, null) + { + PlayerCreated = true + }; + + // if the object is a container, then place it in the container + if (targeted is Container container) + { + container.DropItem(spawner); + } + else + { + // place the spawner at the targeted location + IPoint3D p = targeted as IPoint3D; + if (p == null) + { + spawner.Delete(); + return; + } + if (p is Item item) + { + p = item.GetWorldTop(); + } + + spawner.MoveToWorld(new Point3D(p), from.Map); + } + + spawner.SpawnRange = defs.SpawnRange; + // add entries from the name list + for (int i = 0; i < MaxEntries; i++) + { + if (defs.SelectionList != null && i < defs.SelectionList.Length && defs.SelectionList[i] && + defs.NameList != null && i < defs.NameList.Length && defs.NameList[i] != null && defs.NameList[i].Length > 0) + { + spawner.AddSpawn = defs.NameList[i]; + } + } + + defs.LastSpawner = spawner; + + if (defs.AutoNumber) + // bump the autonumber + { + defs.AutoNumberValue++; + } + + //from.CloseGump(); + Refresh(m_state.Mobile, true); + + // open the spawner gump + DoShowGump(from, spawner); + } + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state?.Mobile == null) + { + return; + } + + // read the text entries for default values + XmlSpawnerDefaults.DefaultEntry defaults = XmlSpawnerDefaults.GetDefaults(state.Account.ToString(), state.Mobile.Name); + if (defaults.IgnoreUpdate) + { + return; + } + + TextRelay tr = info.GetTextEntry(100); // mindelay + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.MinDelay = TimeSpan.FromMinutes(double.Parse(tr.Text)); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + tr = info.GetTextEntry(101); // maxdelay info + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.MaxDelay = TimeSpan.FromMinutes(double.Parse(tr.Text)); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(102); // min refractory + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.RefractMin = TimeSpan.FromMinutes(double.Parse(tr.Text)); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(103); // max refractory + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.RefractMax = TimeSpan.FromMinutes(double.Parse(tr.Text)); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(104); // TOD start + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.TODStart = TimeSpan.FromHours(double.Parse(tr.Text)); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(105); // TOD end + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.TODEnd = TimeSpan.FromHours(double.Parse(tr.Text)); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(106); // Speech trigger + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) + { + txt = null; + } + + defaults.SpeechTrigger = txt; + } + + tr = info.GetTextEntry(107); // HomeRange + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.HomeRange = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(108); // SpawnRange + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.SpawnRange = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(109); // ProximityRange + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.ProximityRange = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(110); // Team + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.Team = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(111); // Duration + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.Duration = TimeSpan.FromMinutes(double.Parse(tr.Text)); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(112); // ProximitySound + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.ProximitySound = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(113); // Kill reset + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.KillReset = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(114); // Spawner name + if (tr != null) + { + defaults.SpawnerName = tr.Text; + } + + // DefsExt entry + tr = info.GetTextEntry(115); // save def str + if (tr != null) + { + defaults.DefsExt = tr.Text; + } + + tr = info.GetTextEntry(117); // trigger on carried + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) + { + txt = null; + } + + defaults.TriggerOnCarried = txt; + } + + tr = info.GetTextEntry(118); // no trigger on carried + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) + { + txt = null; + } + + defaults.NoTriggerOnCarried = txt; + } + + tr = info.GetTextEntry(119); // proximity message + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) + { + txt = null; + } + + defaults.ProximityMsg = txt; + } + + tr = info.GetTextEntry(120); // player trig prop + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) + { + txt = null; + } + + defaults.PlayerTriggerProp = txt; + } + + tr = info.GetTextEntry(121); // Trigger probability + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.TriggerProbability = double.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(122); // trig object prop + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) + { + txt = null; + } + + defaults.TriggerObjectProp = txt; + } + + tr = info.GetTextEntry(123); // DespawnTime + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.DespawnTime = TimeSpan.FromHours(double.Parse(tr.Text)); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(124); // Skill trigger + if (tr != null) + { + string txt = tr.Text; + if (txt != null && txt.Length == 0) + { + txt = null; + } + + defaults.SkillTrigger = txt; + } + + tr = info.GetTextEntry(125); // AutoNumberValue + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defaults.AutoNumberValue = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + // fill the NameList from the text entries + if (defaults.ShowExtension) + { + for (int i = 0; i < MaxEntries; i++) + { + tr = info.GetTextEntry(1000 + i); + if (defaults.NameList != null && i < defaults.NameList.Length && tr != null) + { + defaults.NameList[i] = tr.Text; + } + } + } + + defaults.Group = info.IsSwitched(304); + defaults.HomeRangeIsRelative = info.IsSwitched(305); + defaults.AutoNumber = info.IsSwitched(306); + defaults.SequentialSpawn = info.IsSwitched(307) ? 0 : -1; + defaults.ExternalTriggering = info.IsSwitched(308); + defaults.AllowGhostTrig = info.IsSwitched(309); + defaults.SpawnOnTrigger = info.IsSwitched(311); + defaults.SmartSpawning = info.IsSwitched(310); + defaults.AllowNPCTrig = info.IsSwitched(312); + + switch (info.ButtonID) + { + case 0: // Close + { + return; + } + case 100: // Add spawner + { + state.Mobile.Target = new PlaceSpawnerTarget(state); + + break; + } + case 115: // SaveDefs + { + string filename; + if (!string.IsNullOrEmpty(defaults.DefsExt)) + { + filename = $"{defaults.AccountName}-{defaults.PlayerName}-{defaults.DefsExt}"; + } + else + { + filename = $"{defaults.AccountName}-{defaults.PlayerName}"; + } + DoSaveDefs(state.Mobile, filename); + break; + } + case 116: // LoadDefs + { + string filename; + if (!string.IsNullOrEmpty(defaults.DefsExt)) + { + filename = $"{defaults.AccountName}-{defaults.PlayerName}-{defaults.DefsExt}"; + } + else + { + filename = $"{defaults.AccountName}-{defaults.PlayerName}"; + } + DoLoadDefs(state.Mobile, filename); + break; + } + case 117: // Restore Defaults + { + state.Mobile.SendMessage("Restoring defaults"); + XmlSpawnerDefaults.RestoreDefs(defaults); + break; + } + case 155: // Return the player to the starting loc + { + m_From.Location = defaults.StartingLoc; + m_From.Map = defaults.StartingMap; + break; + } + case 156: // Delete last spawner + { + if (defaults.LastSpawner == null || defaults.LastSpawner.Deleted) + { + break; + } + + Refresh(state.Mobile); + state.Mobile.SendGump(new XmlAddConfirmDeleteGump(defaults.LastSpawner)); + return; + } + case 157: // Reset last spawner + { + if (defaults.LastSpawner != null && !defaults.LastSpawner.Deleted) + { + defaults.LastSpawner.DoReset = true; + } + + break; + } + case 158: // Respawn last spawner + { + if (defaults.LastSpawner != null && !defaults.LastSpawner.Deleted) + { + defaults.LastSpawner.DoRespawn = true; + } + + break; + } + case 180: // Set Options + { + Refresh(state.Mobile); + state.Mobile.SendGump(new XmlAddOptionsGump(state.Mobile)); + return; + } + case 200: // gump extension + { + defaults.ShowExtension = !defaults.ShowExtension; + break; + } + case 306: // TOD mode + { + defaults.TODMode = defaults.TODMode == XmlSpawner.TODModeType.Realtime ? XmlSpawner.TODModeType.Gametime : XmlSpawner.TODModeType.Realtime; + break; + } + case 1000: // GoTo + { + // then go to it + DoGoTo(defaults.LastSpawner); + break; + } + case 1001: // Show Gump + { + Refresh(state.Mobile); + DoShowGump(state.Mobile, defaults.LastSpawner); + break; + } + case 1002: // Show Props + { + Refresh(state.Mobile); + DoShowProps(defaults.LastSpawner); + break; + } + case 3999: // clear selections + { + // clear the selections + if (defaults.SelectionList != null) + { + Array.Clear(defaults.SelectionList, 0, defaults.SelectionList.Length); + } + + break; + } + case 9998: // refresh the gump + { + break; + } + default: + { + if (info.ButtonID >= 4000 && info.ButtonID < 4000 + MaxEntries) + { + int i = info.ButtonID - 4000; + if (defaults.SelectionList != null && i >= 0 && i < defaults.SelectionList.Length) + { + defaults.SelectionList[i] = !defaults.SelectionList[i]; + } + } + if (info.ButtonID >= 5000 && info.ButtonID < 5000 + MaxEntries) + { + int i = info.ButtonID - 5000; + + defaults.CategorySelectionIndex = i; + XmlAddGump newg = new XmlAddGump(state.Mobile, defaults.StartingLoc, defaults.StartingMap, false, defaults.ShowExtension, 0, 0); + + state.Mobile.SendGump(newg); + + if (defaults.NameList[i] == null || defaults.NameList[i].Length == 0) + { + // if no string has been entered then just use the full categorized add gump + state.Mobile.CloseGump(); + state.Mobile.SendGump(new XmlCategorizedAddGump(state.Mobile, defaults.CurrentCategory, defaults.CurrentCategoryPage, i, newg)); + } + else + { + // use the XmlPartialCategorizedAddGump + state.Mobile.CloseGump(); + + //Type [] types = (Type[])XmlPartialCategorizedAddGump.Match(defs.NameList[i]).ToArray(typeof(Type)); + ArrayList types = XmlPartialCategorizedAddGump.Match(defaults.NameList[i]); + state.Mobile.SendGump(new XmlPartialCategorizedAddGump(state.Mobile, defaults.NameList[i], 0, types, true, i, newg)); + } + + return; + } + + break; + } + } + + Refresh(state.Mobile); + } + + private class XmlAddOptionsGump : Gump + { + public XmlAddOptionsGump(Mobile from) : base(0, 0) + { + // read the text entries for default values + Account acct = from.Account as Account; + XmlSpawnerDefaults.DefaultEntry defs = null; + + if (acct != null) + { + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); + } + + if (defs == null) + { + return; + } + + Closable = true; + Draggable = true; + AddPage(0); + AddBackground(0, 0, 300, 130, 5054); + + AddLabel(20, 5, 0, "Options"); + // add the AddGumpX/Y entries + AddImageTiled(5, 30, 40, 21, 0xBBC); + AddTextEntry(5, 30, 40, 21, 0, 100, defs.AddGumpX.ToString()); + AddLabel(45, 30, 0x384, "AddGumpX"); + + AddImageTiled(135, 30, 40, 21, 0xBBC); + AddTextEntry(135, 30, 40, 21, 0, 101, defs.AddGumpY.ToString()); + AddLabel(175, 30, 0x384, "AddGumpY"); + + // add the SpawnerGumpX/Y entries + AddImageTiled(5, 55, 40, 21, 0xBBC); + AddTextEntry(5, 55, 40, 21, 0, 102, defs.SpawnerGumpX.ToString()); + AddLabel(45, 55, 0x384, "SpawnerGumpX"); + + AddImageTiled(135, 55, 40, 21, 0xBBC); + AddTextEntry(135, 55, 40, 21, 0, 103, defs.SpawnerGumpY.ToString()); + AddLabel(175, 55, 0x384, "SpawnerGumpY"); + + // add the FindGumpX/Y entries + AddImageTiled(5, 80, 40, 21, 0xBBC); + AddTextEntry(5, 80, 40, 21, 0, 104, defs.FindGumpX.ToString()); + AddLabel(45, 80, 0x384, "FindGumpX"); + + AddImageTiled(135, 80, 40, 21, 0xBBC); + AddTextEntry(135, 80, 40, 21, 0, 105, defs.FindGumpY.ToString()); + AddLabel(175, 80, 0x384, "FindGumpY"); + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state?.Mobile == null) + { + return; + } + + // read the text entries for default values + XmlSpawnerDefaults.DefaultEntry defs = XmlSpawnerDefaults.GetDefaults(state.Account.ToString(), state.Mobile.Name); + if (defs == null) + { + return; + } + + TextRelay tr = info.GetTextEntry(100); // AddGumpX + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defs.AddGumpX = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + tr = info.GetTextEntry(101); // AddGumpY info + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defs.AddGumpY = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + tr = info.GetTextEntry(102); // SpawnerGumpX info + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defs.SpawnerGumpX = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + tr = info.GetTextEntry(103); // SpawnerGumpY info + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defs.SpawnerGumpY = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + tr = info.GetTextEntry(104); // FindGumpX info + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defs.FindGumpX = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + tr = info.GetTextEntry(105); // FindGumpY info + if (tr?.Text != null && tr.Text.Length > 0) + { + try { defs.FindGumpY = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + } + } + + private class XmlAddConfirmDeleteGump : Gump + { + private readonly XmlSpawner LastSpawner; + + public XmlAddConfirmDeleteGump(XmlSpawner lastSpawner) : base(0, 0) + { + LastSpawner = lastSpawner; + Closable = false; + Draggable = true; + AddPage(0); + AddBackground(10, 200, 200, 130, 5054); + + AddLabel(20, 225, 33, "Delete Last Spawner?"); + AddRadio(35, 255, 9721, 0x86A, false, 1); // accept/yes radio + AddRadio(135, 255, 9721, 0x86A, true, 2); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff); // No + AddButton(80, 289, 2130, 2129, 3); // Okay button + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state?.Mobile == null) + { + return; + } + + int radiostate = -1; + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch (info.ButtonID) + { + default: + { + if (radiostate == 1 && LastSpawner != null && !LastSpawner.Deleted) + { // accept + // delete it + LastSpawner.Delete(); + } + break; + } + } + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlCategorizedAddGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlCategorizedAddGump.cs new file mode 100644 index 000000000..f8077e55a --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlCategorizedAddGump.cs @@ -0,0 +1,477 @@ +using Server.Mobiles; +using Server.Network; +using System; +using System.Collections; +using System.IO; +using System.Xml; + +namespace Server.Gumps; + +public abstract class XmlAddCAGNode +{ + public abstract string Caption { get; } + public abstract void OnClick(Mobile from, int page, int index, Gump gump); +} + +public class XmlAddCAGObject : XmlAddCAGNode +{ + private readonly Type m_Type; + private readonly XmlAddCAGCategory m_Parent; + + public int ItemID { get; } + + public override string Caption => m_Type == null ? "bad type" : m_Type.Name; + + public override void OnClick(Mobile from, int page, int index, Gump gump) + { + if (m_Type == null) + { + from.SendMessage("That is an invalid type name."); + } + else + { + if (gump is XmlAddGump xmladdgump) + { + //Commands.Handle(from, String.Format("{0}Add {1}", Commands.CommandPrefix, m_Type.Name)); + if (xmladdgump.defs?.NameList != null && index >= 0 && index < xmladdgump.defs.NameList.Length) + { + xmladdgump.defs.NameList[index] = m_Type.Name; + XmlAddGump.Refresh(from, true); + } + from.SendGump(new XmlCategorizedAddGump(from, m_Parent, page, index, xmladdgump)); + } + else if (gump is XmlSpawnerGump spawnerGump) + { + XmlSpawner m_Spawner = spawnerGump.m_Spawner; + + if (m_Spawner != null) + { + XmlSpawnerGump xg = m_Spawner.SpawnerGump; + + if (xg != null) + { + xg.Rentry = new XmlSpawnerGump.ReplacementEntry + { + Typename = m_Type.Name, + Index = index, + Color = 0x1436 + }; + + Timer.DelayCall(TimeSpan.Zero, XmlSpawnerGump.RefreshSpawnerGumps, from); + } + } + } + } + } + + public XmlAddCAGObject(XmlAddCAGCategory parent, XmlReader xml) + { + m_Parent = parent; + + if (xml.MoveToAttribute("type")) + { + m_Type = AssemblyHandler.FindTypeByFullName(xml.Value, false); + } + + if (xml.MoveToAttribute("gfx")) + { + ItemID = XmlConvert.ToInt32(xml.Value); + } + + if (xml.MoveToAttribute("hue")) + { + XmlConvert.ToInt32(xml.Value); + } + } +} + +public class XmlAddCAGCategory : XmlAddCAGNode +{ + private readonly string m_Title; + + public XmlAddCAGNode[] Nodes { get; } + + public XmlAddCAGCategory Parent { get; } + + public override string Caption => m_Title; + + public override void OnClick(Mobile from, int page, int index, Gump gump) + { + from.SendGump(new XmlCategorizedAddGump(from, this, 0, index, gump)); + } + + private XmlAddCAGCategory() + { + m_Title = "no data"; + Nodes = new XmlAddCAGNode[0]; + } + + public XmlAddCAGCategory(XmlAddCAGCategory parent, XmlReader xml) + { + Parent = parent; + + if (xml.MoveToAttribute("title")) + { + m_Title = xml.Value == "Add Menu" ? "XmlAdd Menu" : xml.Value; + } + else + { + m_Title = "empty"; + } + + if (m_Title == "Docked") + { + m_Title = "Docked 2"; + } + + if (xml.IsEmptyElement) + { + Nodes = new XmlAddCAGNode[0]; + } + else + { + ArrayList nodes = new ArrayList(); + + try + { + while (xml.Read() && xml.NodeType != XmlNodeType.EndElement) + { + + if (xml.NodeType == XmlNodeType.Element && xml.Name == "object") + { + nodes.Add(new XmlAddCAGObject(this, xml)); + } + else if (xml.NodeType == XmlNodeType.Element && xml.Name == "category") + { + if (!xml.IsEmptyElement) + { + nodes.Add(new XmlAddCAGCategory(this, xml)); + } + } + else + { + xml.Skip(); + } + } + } + catch (Exception ex) + { + Console.WriteLine("XmlCategorizedAddGump: Corrupted Data/objects.xml file detected. Not all XmlCAG objects loaded. {0}", ex); + } + + Nodes = (XmlAddCAGNode[])nodes.ToArray(typeof(XmlAddCAGNode)); + } + } + + private static XmlAddCAGCategory m_Root; + public static XmlAddCAGCategory Root => m_Root ?? (m_Root = Load("Data/objects.xml")); + + public static XmlAddCAGCategory Load(string path) + { + if (File.Exists(path)) + { + XmlTextReader xml = new XmlTextReader(path) + { + WhitespaceHandling = WhitespaceHandling.None + }; + + while (xml.Read()) + { + if (xml.Name == "category" && xml.NodeType == XmlNodeType.Element) + { + XmlAddCAGCategory cat = new XmlAddCAGCategory(null, xml); + + xml.Close(); + + return cat; + } + } + } + + return new XmlAddCAGCategory(); + } +} + +public class XmlCategorizedAddGump : Gump +{ + public static bool OldStyle = PropsConfig.OldStyle; + + public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX; + public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY; + + public static readonly int TextHue = PropsConfig.TextHue; + public static readonly int TextOffsetX = PropsConfig.TextOffsetX; + + public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID; + public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID; + public static readonly int EntryGumpID = PropsConfig.EntryGumpID; + public static readonly int BackGumpID = PropsConfig.BackGumpID; + public static readonly int SetGumpID = PropsConfig.SetGumpID; + + public static readonly int SetWidth = PropsConfig.SetWidth; + public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/; + public static readonly int SetButtonID1 = PropsConfig.SetButtonID1; + public static readonly int SetButtonID2 = PropsConfig.SetButtonID2; + + public static readonly int PrevWidth = PropsConfig.PrevWidth; + public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/; + public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1; + public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2; + + public static readonly int NextWidth = PropsConfig.NextWidth; + public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY /*+ (((EntryHeight - 20) / 2) / 2)*/; + public static readonly int NextButtonID1 = PropsConfig.NextButtonID1; + public static readonly int NextButtonID2 = PropsConfig.NextButtonID2; + + public static readonly int OffsetSize = PropsConfig.OffsetSize; + + public static readonly int EntryHeight = 24; + public static readonly int BorderSize = PropsConfig.BorderSize; + + private static readonly bool PrevLabel = false, NextLabel = false; + + private static readonly int PrevLabelOffsetX = PrevWidth + 1; + private const int PrevLabelOffsetY = 0; + + private const int NextLabelOffsetX = -29; + private const int NextLabelOffsetY = 0; + + private const int EntryWidth = 180; + private const int EntryCount = 15; + + private static readonly int TotalWidth = OffsetSize + EntryWidth + OffsetSize + SetWidth + OffsetSize; + + private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize; + private readonly Mobile m_Owner; + private readonly XmlAddCAGCategory m_Category; + private int m_Page; + + private readonly int m_Index; + private readonly Gump m_Gump; + + public XmlCategorizedAddGump(Mobile owner, int index, Gump gump) : this(owner, XmlAddCAGCategory.Root, 0, index, gump) + { + } + + public XmlCategorizedAddGump(Mobile owner, XmlAddCAGCategory category, int page, int index, Gump gump) : base(GumpOffsetX, GumpOffsetY) + { + if (category == null) + { + category = XmlAddCAGCategory.Root; + page = 0; + } + + owner.CloseGump(); + + m_Owner = owner; + m_Category = category; + + m_Index = index; + m_Gump = gump; + + if (gump is XmlAddGump xmladdgump) + { + if (xmladdgump.defs != null) + { + xmladdgump.defs.CurrentCategory = category; + xmladdgump.defs.CurrentCategoryPage = page; + } + } + + Initialize(page); + } + + public void Initialize(int page) + { + m_Page = page; + + XmlAddCAGNode[] nodes = m_Category.Nodes; + + int count = nodes.Length - page * EntryCount; + + if (count < 0) + { + count = 0; + } + else if (count > EntryCount) + { + count = EntryCount; + } + + int totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); + + AddPage(0); + + AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); + AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID); + + int x = BorderSize + OffsetSize; + int y = BorderSize + OffsetSize; + + if (OldStyle) + { + AddImageTiled(x, y, TotalWidth - OffsetSize * 3 - SetWidth, EntryHeight, HeaderGumpID); + } + else + { + AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); + } + + if (m_Category.Parent != null) + { + AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1); + + if (PrevLabel) + { + AddLabel(x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous"); + } + } + + x += PrevWidth + OffsetSize; + + int emptyWidth = TotalWidth - PrevWidth * 2 - NextWidth - OffsetSize * 5 - (OldStyle ? SetWidth + OffsetSize : 0); + + if (!OldStyle) + { + AddImageTiled(x - (OldStyle ? OffsetSize : 0), y, emptyWidth + (OldStyle ? OffsetSize * 2 : 0), EntryHeight, EntryGumpID); + } + + AddHtml(x + TextOffsetX, y + (EntryHeight - 20) / 2, emptyWidth - TextOffsetX, EntryHeight, + $"
{m_Category.Caption}
"); + + x += emptyWidth + OffsetSize; + + if (OldStyle) + { + AddImageTiled(x, y, TotalWidth - OffsetSize * 3 - SetWidth, EntryHeight, HeaderGumpID); + } + else + { + AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); + } + + if (page > 0) + { + AddButton(x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 2); + + if (PrevLabel) + { + AddLabel(x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous"); + } + } + + x += PrevWidth + OffsetSize; + + if (!OldStyle) + { + AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID); + } + + if ((page + 1) * EntryCount < nodes.Length) + { + AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 3, GumpButtonType.Reply, 1); + + if (NextLabel) + { + AddLabel(x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next"); + } + } + + for (int i = 0, index = page * EntryCount; i < EntryCount && index < nodes.Length; ++i, ++index) + { + x = BorderSize + OffsetSize; + y += EntryHeight + OffsetSize; + + XmlAddCAGNode node = nodes[index]; + + AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); + AddLabelCropped(x + TextOffsetX, y + (EntryHeight - 20) / 2, EntryWidth - TextOffsetX, EntryHeight, TextHue, node.Caption); + + x += EntryWidth + OffsetSize; + + if (SetGumpID != 0) + { + AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); + } + + AddButton(x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 4); + + if (node is XmlAddCAGObject obj) + { + int itemID = obj.ItemID; + + Rectangle2D bounds = ItemBounds.Table[itemID]; + + if (itemID != 1 && bounds.Height < EntryHeight * 2) + { + if (bounds.Height < EntryHeight) + { + AddItem(x - OffsetSize - 22 - i % 2 * 44 - bounds.Width / 2 - bounds.X, y + EntryHeight / 2 - bounds.Height / 2 - bounds.Y, itemID); + } + else + { + AddItem(x - OffsetSize - 22 - i % 2 * 44 - bounds.Width / 2 - bounds.X, y + EntryHeight - 1 - bounds.Height - bounds.Y, itemID); + } + } + } + } + } + + public override void OnResponse(NetState state, RelayInfo info) + { + Mobile from = m_Owner; + + switch (info.ButtonID) + { + case 0: // Closed + { + return; + } + case 1: // Up + { + if (m_Category.Parent != null) + { + int index = Array.IndexOf(m_Category.Parent.Nodes, m_Category) / EntryCount; + + if (index < 0) + { + index = 0; + } + + from.SendGump(new XmlCategorizedAddGump(from, m_Category.Parent, index, m_Index, m_Gump)); + } + + break; + } + case 2: // Previous + { + if (m_Page > 0) + { + from.SendGump(new XmlCategorizedAddGump(from, m_Category, m_Page - 1, m_Index, m_Gump)); + } + + break; + } + case 3: // Next + { + if ((m_Page + 1) * EntryCount < m_Category.Nodes.Length) + { + from.SendGump(new XmlCategorizedAddGump(from, m_Category, m_Page + 1, m_Index, m_Gump)); + } + + break; + } + default: + { + int index = m_Page * EntryCount + (info.ButtonID - 4); + + if (index >= 0 && index < m_Category.Nodes.Length) + { + m_Category.Nodes[index].OnClick(from, m_Page, m_Index, m_Gump); + } + + break; + } + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlEdit.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlEdit.cs new file mode 100644 index 000000000..e61f7113c --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlEdit.cs @@ -0,0 +1,1420 @@ +using System; +using System.Collections; +using Server.Items; +using Server.Network; +using Server.Gumps; +using Server.Targeting; +using CPA = Server.CommandPropertyAttribute; +using Server.Mobiles; + +/* +** XmlEditNPC +** Version 1.00 +** updated 5/24/05 +** ArteGordon +** +** +*/ + +namespace Server.Engines.XmlSpawner2; + +public class XmlEditDialogGump : Gump +{ + private const int MaxEntries = 8; + private const int MaxEntriesPerPage = 8; + + private Mobile m_From; + private string Name; + private int Selected; + private int DisplayFrom; + private string SaveFilename; + private bool [] m_SelectionList; + private XmlDialog m_Dialog; + + private bool SelectAll; + + private ArrayList m_SearchList; + + public static void Initialize() + { + CommandSystem.Register("XmlEdit", AccessLevel.GameMaster, XmlEditDialog_OnCommand); + } + + [Usage("XmlEdit")] + [Description("Edits XmlDialog entries on an object")] + public static void XmlEditDialog_OnCommand(CommandEventArgs e) + { + if (e == null || e.Mobile == null) + { + return; + } + + // target an object with the xmldialog attachment + e.Mobile.Target = new EditDialogTarget(); + + + } + + private class EditDialogTarget : Target + { + + public EditDialogTarget() : base (30, true, TargetFlags.None) + { + + } + + protected override void OnTarget(Mobile from, object targeted) + { + if (from == null) + { + return; + } + + // does it have an xmldialog attachment? + XmlDialog xd = XmlAttach.FindAttachment(targeted, typeof(XmlDialog)) as XmlDialog; + + if (xd == null) + { + from.SendMessage("Target has no XmlDialog attachment"); + + // TODO: ask whether they would like to add one + from.SendGump(new XmlConfirmAddGump(from, targeted)); + + return; + } + + from.SendGump(new XmlEditDialogGump(from, true, xd, -1, 0, null, false, null, 0, 0)); + } + } + + public class XmlConfirmAddGump : Gump + { + private Mobile m_From; + private object m_Targeted; + + public XmlConfirmAddGump(Mobile from, object targeted) : base (0, 0) + { + if (from == null || targeted == null) + { + return; + } + + m_Targeted = targeted; + m_From = from; + + Closable = false; + Draggable = true; + AddPage(0); + AddBackground(10, 200, 200, 130, 5054); + + AddLabel(20, 210, 68, "Add an XmlDialog to target?"); + + string name = null; + if (targeted is Item item) + { + name = item.Name; + } + else + if (targeted is Mobile mobile) + { + name = mobile.Name; + } + + if (name == null) + { + name = targeted.GetType().Name; + } + AddLabel(20, 230, 0, $"{name}"); + + AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio + AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff); // No + AddButton(80, 289, 2130, 2129, 3); // Okay button + + } + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null) + { + return; + } + + int radiostate = -1; + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch (info.ButtonID) + { + + default: + { + if (radiostate == 1) + { // accept + + // add the attachment + XmlDialog xd = new XmlDialog(); + XmlAttach.AttachTo(state.Mobile, m_Targeted, xd); + + // open the editing gump + state.Mobile.SendGump(new XmlEditDialogGump(state.Mobile, true, xd, -1, 0, null, false, null, 0, 0)); + } + break; + } + } + } + } + + public const int MaxLabelLength = 200; + public string TruncateLabel(string s) + { + if (s == null || s.Length < MaxLabelLength) + { + return s; + } + + return s.Substring(0,MaxLabelLength); + } + + public XmlEditDialogGump(Mobile from, bool firststart, + XmlDialog dialog, int selected, int displayfrom, string savefilename, + bool selectall, bool [] selectionlist, int X, int Y) : base(X,Y) + { + + if (from == null || dialog == null) + { + return; + } + + m_Dialog = dialog; + m_From = from; + + m_SelectionList = selectionlist; + if (m_SelectionList == null) + { + m_SelectionList = new bool[MaxEntries]; + } + SaveFilename = savefilename; + + DisplayFrom = displayfrom; + Selected = selected; + + // fill the list with the XmlDialog entries + m_SearchList = dialog.SpeechEntries; + + // prepare the page + int height = 500; + + + AddPage(0); + + AddBackground(0, 0, 755, height, 5054); + AddAlphaRegion(0, 0, 755, height); + + // add the separators + AddImageTiled(10, 80, 735, 4, 0xBB9); + AddImageTiled(10, height -212, 735, 4, 0xBB9); + AddImageTiled(10, height -60, 735, 4, 0xBB9); + + // add the xmldialog properties + int y = 5; + int w = 140; + int x = 5; + int lw = 0; + // the dialog name + AddImageTiled(x, y, w, 21, 0x23F4); + // get the name of the object this is attached to + + if (m_Dialog.AttachedTo is Item item) + { + Name = item.Name; + } + else + if (m_Dialog.AttachedTo is Mobile mobile) + { + Name = mobile.Name; + } + if (Name == null && m_Dialog.AttachedTo != null) + { + Name = m_Dialog.AttachedTo.GetType().Name; + } + AddLabelCropped(x, y, w, 21, 0, Name); + + + x += w + lw + 20; + w = 40; + lw = 90; + // add the proximity range + AddLabel(x, y, 0x384, "ProximityRange"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 140, m_Dialog.ProximityRange.ToString()); + + x += w + lw + 20; + w = 100; + lw = 60; + // reset time + AddLabel(x, y, 0x384, "ResetTime"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 141, m_Dialog.ResetTime.ToString()); + + x += w + lw + 20; + w = 40; + lw = 65; + // speech pace + AddLabel(x, y, 0x384, "SpeechPace"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 142, m_Dialog.SpeechPace.ToString()); + + x += w + lw + 20; + w = 30; + lw = 55; + // allow ghost triggering + AddLabel(x, y, 0x384, "GhostTrig"); + AddCheck(x+lw, y, 0xD2, 0xD3, m_Dialog.AllowGhostTrig, 260); + + // add the triggeroncarried + y += 27; + w = 600; + x = 10; + lw = 100; + AddLabel(10, y, 0x384, "TrigOnCarried"); + AddImageTiled(x + lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 150, TruncateLabel(m_Dialog.TriggerOnCarried)); + AddButton(720, y, 0xFAB, 0xFAD, 5005); + + // add the notriggeroncarried + y += 22; + w = 600; + x = 10; + lw = 100; + AddLabel(x, y, 0x384, "NoTrigOnCarried"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x + lw, y, w, 21, 0, 151, TruncateLabel(m_Dialog.NoTriggerOnCarried)); + AddButton(720, y, 0xFAB, 0xFAD, 5006); + + y = 88; + // column labels + AddLabel(10, y, 0x384, "Edit"); + AddLabel(45, y, 0x384, "#"); + AddLabel(95, y, 0x384, "ID"); + AddLabel(145, y, 0x384, "Depends"); + AddLabel(195, y, 0x384, "Keywords"); + AddLabel(295, y, 0x384, "Text"); + AddLabel(540, y, 0x384, "Action"); + AddLabel(602, y, 0x384, "Condition"); + AddLabel(664, y, 0x384, "Gump"); + + // display the select-all-displayed toggle + AddButton(730, y, 0xD2, 0xD3, 3999); + + y -= 10; + for (int i = 0; i < MaxEntries; i++) + { + int index = i + DisplayFrom; + if (m_SearchList == null || index >= m_SearchList.Count) + { + break; + } + + int page = i/MaxEntriesPerPage; + if (i%MaxEntriesPerPage == 0) + { + AddPage(page+1); + // add highlighted page button + //AddImageTiled(235+page*25, 448, 25, 25, 0xBBC); + //AddImage(238+page*25, 450, 0x8B1+page); + } + + // background for search results area + AddImageTiled(235, y + 22 * (i%MaxEntriesPerPage) + 30, 386, 23, 0x52); + AddImageTiled(236, y + 22 * (i%MaxEntriesPerPage) + 31, 384, 21, 0xBBC); + + + XmlDialog.SpeechEntry s = (XmlDialog.SpeechEntry)m_SearchList[index]; + + if (s == null) + { + continue; + } + + int texthue = 0; + + bool sel=false; + + if (m_SelectionList != null && i < m_SelectionList.Length) + { + sel = m_SelectionList[i]; + } + + // entries with the selection box checked are highlighted in red + if (sel) + { + texthue = 33; + } + + // the selected entry is highlighted in green + if (i == Selected) + { + texthue = 68; + } + + x = 10; + w = 35; + // add the Edit button for each entry + AddButton(10, y + 22 * (i%MaxEntriesPerPage) + 30, 0xFAE, 0xFAF, 1000+i); + + x += w; + w = 50; + // display the entry number + AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC); + AddLabel(x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.EntryNumber.ToString()); + + x += w; + w = 50; + // display the entry ID + AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4); + AddLabel(x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.ID.ToString()); + + x += w; + w = 50; + // display the entry dependson + AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC ); + AddLabel(x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.DependsOn); + + x += w; + w = 100; + // display the entry keywords + AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4); + AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Keywords)); + + x += w; + w = 245; + // display the entry text + AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC); + AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Text)); + + x += w; + w = 62; + // display the action text + AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4); + AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Action)); + + x += w; + w = 62; + // display the condition text + AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC); + AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Condition)); + + x += w; + w = 62; + // display the gump text + AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4); + AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Gump)); + + // display the selection button + AddButton(730, y + 22 * (i%MaxEntriesPerPage) + 32, sel? 0xD3:0xD2, sel? 0xD2:0xD3, 4000+i); + + } + + + // display the selected entry information for editing + XmlDialog.SpeechEntry sentry = null; + if (Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) + { + sentry = (XmlDialog.SpeechEntry)m_SearchList[Selected+ DisplayFrom]; + } + + if (sentry != null) + { + + y = height - 200; + + // add the entry parameters + lw = 15; + w = 40; + x = 10; + int spacing = 11; + + // entry number + AddLabel(x, y, 0x384, "#"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 200, sentry.EntryNumber.ToString()); + + x += w + lw + spacing; + w = 40; + lw = 17; + // ID number + AddLabel(x, y, 0x384, "ID"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 201, sentry.ID.ToString()); + + x += w + lw + spacing; + w = 40; + lw = 65; + // depends on + AddLabel(x, y, 0x384, "DependsOn"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 202, sentry.DependsOn); + + x += w + lw + spacing; + w = 35; + lw = 57; + // prepause + AddLabel(x, y, 0x384, "PrePause"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 203, sentry.PrePause.ToString()); + + x += w + lw + spacing; + w = 35; + lw = 37; + // pause + AddLabel(x, y, 0x384, "Pause"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 204, sentry.Pause.ToString()); + + x += w + lw + spacing; + w = 37; + lw = 26; + // speech hue + AddLabel(x, y, 0x384, "Hue"); + AddImageTiled(x+lw, y, w, 21, 0xBBC); + AddTextEntry(x+lw, y, w, 21, 0, 205, sentry.SpeechHue.ToString()); + + x += w + lw + spacing; + w = 20; + lw = 52; + // lock conversation + AddLabel(x, y, 0x384, "IgnoreCar"); + AddCheck(x + lw, y, 0xD2, 0xD3, sentry.IgnoreCarried, 252); + + x += w + lw + spacing; + w = 20; + lw = 42; + // lock conversation + AddLabel(x, y, 0x384, "LockOn"); + AddCheck(x+lw, y, 0xD2, 0xD3, sentry.LockConversation, 250); + + x += w + lw + spacing; + w = 20; + lw = 54; + // npctrigger + AddLabel(x, y, 0x384, "AllowNPC"); + AddCheck(x+lw, y, 0xD2, 0xD3, sentry.AllowNPCTrigger, 251); + + + w = 650; + x = 70; + + y += 27; + // add the keyword entry + AddLabel(10, y, 0x384, "Keywords"); + AddImageTiled(x, y, w, 21, 0xBBC); + AddTextEntry(x+1, y, w, 21, 0, 101, sentry.Keywords); + AddButton(720, y, 0xFAB, 0xFAD, 5001); + + y += 22; + // add the text entry + AddLabel(10, y, 0x384, "Text"); + AddImageTiled(x, y, w, 21, 0xBBC); + AddTextEntry(x+1, y, w, 21, 0, 100, sentry.Text); + AddButton(720, y, 0xFAB, 0xFAD, 5000); + + + y += 22; + // add the condition string entry + AddLabel(10, y, 0x384, "Condition"); + AddImageTiled(x, y, w, 21, 0xBBC); + AddTextEntry(x+1, y, w, 21, 0, 102, sentry.Condition); + AddButton(720, y, 0xFAB, 0xFAD, 5002); + + y += 22; + // add the action string entry + AddLabel(10, y, 0x384, "Action"); + AddImageTiled(x, y, w, 21, 0xBBC); + AddTextEntry(x+1, y, w, 21, 0, 103, sentry.Action); + AddButton(720, y, 0xFAB, 0xFAD, 5003); + + y += 22; + // add the gump string entry + AddLabel(10, y, 0x384, "Gump"); + AddImageTiled(x, y, w, 21, 0xBBC); + AddTextEntry(x+1, y, w, 21, 0, 104, sentry.Gump); + AddButton(720, y, 0xFAB, 0xFAD, 5004); + } + + y = height - 50; + + AddLabel(10, y, 0x384, "Config:"); + AddImageTiled(50, y , 120, 19, 0x23F4); + AddLabel(50, y, 0, m_Dialog.ConfigFile); + + if (from.AccessLevel >= XmlSpawner.DiskAccessLevel) + { + + // add the save entry + AddButton(185, y , 0xFA8, 0xFAA, 159); + AddLabel(218, y , 0x384, "Save to file:"); + AddImageTiled(300, y , 180, 19, 0xBBC); + AddTextEntry(300, y, 180, 19, 0, 300, SaveFilename); + } + + // display the item list + if (m_SearchList != null) + { + AddLabel(495, y, 68, $"{m_SearchList.Count} Entries"); + int last = DisplayFrom + MaxEntries < m_SearchList.Count ? DisplayFrom + MaxEntries : m_SearchList.Count; + if (last > 0) + { + AddLabel(595, y, 68, $"Displaying {DisplayFrom}-{last - 1}"); + } + } + + y = height - 25; + + // add run status display + if (m_Dialog.Running) + { + AddButton(10, y-5, 0x2A4E, 0x2A3A, 100); + AddLabel(43, y, 0x384, "On"); + } + else + { + AddButton(10, y-5, 0x2A62, 0x2A3A, 100); + AddLabel(43, y, 0x384, "Off"); + } + + // add the Refresh/Sort button + AddButton(80, y, 0xFAB, 0xFAD, 700); + AddLabel(113, y, 0x384, "Refresh"); + + // add the Add button + AddButton(185, y, 0xFAB, 0xFAD, 155); + AddLabel(218, y, 0x384, "Add"); + + // add the Delete button + AddButton(255, y, 0xFB1, 0xFB3, 156); + AddLabel(283, y, 0x384, "Delete"); + + // add the page buttons + for(int i = 0;i 0) + { + + m_SearchList.Sort(new ListSorter(false)); + + } + } + + private class ListSorter : IComparer + { + private bool Dsort; + public ListSorter(bool descend) => Dsort = descend; + + public int Compare(object x, object y) + { + int xn = 0; + int yn = 0; + + + xn = ((XmlDialog.SpeechEntry)x).EntryNumber; + + yn = ((XmlDialog.SpeechEntry)y).EntryNumber; + + + if (Dsort) + { + return yn - xn; + } + + return xn- yn; + } + } + + + + private void SaveList(Mobile from, string filename) + { + if (m_SearchList == null || m_SelectionList == null) + { + return; + } + + string dirname; + if (System.IO.Directory.Exists(XmlDialog.DefsDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = $"{XmlDialog.DefsDir}/{filename}"; + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + // save it to the file + } + + private XmlEditDialogGump Refresh(NetState state) + { + XmlEditDialogGump g = new XmlEditDialogGump(m_From, false, m_Dialog, Selected, + DisplayFrom, SaveFilename, SelectAll, m_SelectionList, X, Y); + state.Mobile.SendGump(g); + return g; + } + + public static void ProcessXmlEditBookEntry(Mobile from, object[] args, string text) + { + + if (from == null || args == null || args.Length < 6) + { + return; + } + + XmlDialog dialog = (XmlDialog)args[0]; + XmlDialog.SpeechEntry entry = (XmlDialog.SpeechEntry)args[1]; + int textid = (int)args[2]; + int selected = (int)args[3]; + int displayfrom = (int)args[4]; + string savefile = (string)args[5]; + + // place the book text into the entry by type + switch (textid) + { + case 0: // text + { + if (entry != null) + { + entry.Text = text; + } + + break; + } + case 1: // keywords + { + if (entry != null) + { + entry.Keywords = text; + } + + break; + } + case 2: // condition + { + if (entry != null) + { + entry.Condition = text; + } + + break; + } + case 3: // action + { + if (entry != null) + { + entry.Action = text; + } + + break; + } + case 4: // gump + { + if (entry != null) + { + entry.Gump = text; + } + + break; + } + case 5: // trigoncarried + { + if (dialog != null) + { + dialog.TriggerOnCarried = text; + } + + break; + } + case 6: // notrigoncarried + { + if (dialog != null) + { + dialog.NoTriggerOnCarried = text; + } + + break; + } + } + + + from.CloseGump(); + + //from.SendGump(new XmlEditDialogGump(from, false, m_Dialog, selected, displayfrom, savefilename, false, null, X, Y)); + from.SendGump(new XmlEditDialogGump(from, true, dialog, selected, displayfrom, savefile, false, null, 0, 0)); + } + + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state == null || state.Mobile == null || m_Dialog == null) + { + return; + } + + int radiostate = -1; + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + + + + TextRelay tr = info.GetTextEntry(400); // displayfrom info + try + { + DisplayFrom = int.Parse(tr.Text); + } + catch{} + + + tr = info.GetTextEntry(300); // savefilename info + if (tr != null) + { + SaveFilename = tr.Text; + } + + if (m_Dialog != null) + { + tr = info.GetTextEntry(140); // proximity range + if (tr != null) + { + try + { + m_Dialog.ProximityRange = int.Parse(tr.Text); + } + catch{} + } + tr = info.GetTextEntry(141); // reset time + if (tr != null) + { + try + { + m_Dialog.ResetTime = TimeSpan.Parse(tr.Text); + } + catch{} + } + tr = info.GetTextEntry(142); // speech pace + if (tr != null) + { + try + { + m_Dialog.SpeechPace = int.Parse(tr.Text); + } + catch{} + } + + tr = info.GetTextEntry(150); // trig on carried + if (tr != null && (m_Dialog.TriggerOnCarried == null || m_Dialog.TriggerOnCarried.Length < 230)) + { + if (tr.Text != null && tr.Text.Trim().Length > 0) + { + m_Dialog.TriggerOnCarried = tr.Text; + } + else + { + m_Dialog.TriggerOnCarried = null; + } + } + + tr = info.GetTextEntry(151); // notrig on carried + if (tr != null && (m_Dialog.NoTriggerOnCarried == null || m_Dialog.NoTriggerOnCarried.Length < 230)) + { + if (tr.Text != null && tr.Text.Trim().Length > 0) + { + m_Dialog.NoTriggerOnCarried = tr.Text; + } + else + { + m_Dialog.NoTriggerOnCarried = null; + } + } + + m_Dialog.AllowGhostTrig = info.IsSwitched(260); // allow ghost triggering + } + + if (m_SearchList != null && Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) + { + // entry information + XmlDialog.SpeechEntry entry = (XmlDialog.SpeechEntry)m_SearchList[Selected + DisplayFrom]; + + tr = info.GetTextEntry(200); // entry number + if (tr != null) + { + try + { + entry.EntryNumber = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry(201); // entry id + if (tr != null) + { + try + { + entry.ID = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry(202); // depends on + if (tr != null) + { + try + { + entry.DependsOn = tr.Text; + } + catch {} + } + + tr = info.GetTextEntry(203); // prepause + if (tr != null) + { + try + { + entry.PrePause = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry(204); // pause + if (tr != null) + { + try + { + entry.Pause = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry(205); // hue + if (tr != null) + { + try + { + entry.SpeechHue = int.Parse(tr.Text); + } + catch {} + } + + tr = info.GetTextEntry(101); // keywords + if (tr != null && (entry.Keywords == null || entry.Keywords.Length < 230)) + { + if (tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Keywords = tr.Text; + } + else + { + entry.Keywords = null; + } + + } + + tr = info.GetTextEntry(100); // text + if (tr != null && (entry.Text == null || entry.Text.Length < 230)) + { + if (tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Text = tr.Text; + } + else + { + entry.Text = null; + } + } + + tr = info.GetTextEntry(102); // condition + if (tr != null && (entry.Condition == null || entry.Condition.Length < 230)) + { + if (tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Condition = tr.Text; + } + else + { + entry.Condition = null; + } + } + + tr = info.GetTextEntry(103); // action + if (tr != null && (entry.Action == null || entry.Action.Length < 230)) + { + if (tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Action = tr.Text; + } + else + { + entry.Action = null; + } + } + + tr = info.GetTextEntry(104); // gump + if (tr != null && (entry.Gump == null || entry.Gump.Length < 230)) + { + if (tr.Text != null && tr.Text.Trim().Length > 0) + { + entry.Gump = tr.Text; + } + else + { + entry.Gump = null; + } + } + + entry.LockConversation = info.IsSwitched(250); // lock conversation + entry.AllowNPCTrigger = info.IsSwitched(251); // allow npc + entry.IgnoreCarried = info.IsSwitched(252); // ignorecarried + } + + + + switch (info.ButtonID) + { + + case 0: // Close + { + + m_Dialog.DeleteTextEntryBook(); + + return; + } + case 100: // toggle running status + { + + m_Dialog.Running = !m_Dialog.Running; + + break; + } + case 155: // add new entry + { + + if (m_SearchList != null) + { + // find the last entry + int lastentry = 0; + foreach(XmlDialog.SpeechEntry e in m_SearchList) + { + if (e.EntryNumber > lastentry) + { + lastentry = e.EntryNumber; + } + } + lastentry += 10; + XmlDialog.SpeechEntry se = new XmlDialog.SpeechEntry(); + se.EntryNumber = lastentry; + se.ID = lastentry; + m_SearchList.Add(se); + Selected = m_SearchList.Count -1; + } + break; + } + + case 156: // Delete selected entries + { + XmlEditDialogGump g = Refresh(state); + int allcount = 0; + if (m_SearchList != null) + { + allcount = m_SearchList.Count; + } + + state.Mobile.SendGump(new XmlConfirmDeleteGump(state.Mobile, g, m_SearchList, m_SelectionList, DisplayFrom, SelectAll, allcount)); + return; + } + + case 159: // save to a .npc file + { + + // Create a new gump + Refresh(state); + // try to save + m_Dialog.DoSaveNPC(state.Mobile, SaveFilename, true); + + return; + } + + case 201: // forward block + { + // clear the selections + if (m_SelectionList != null && !SelectAll) + { + Array.Clear(m_SelectionList,0,m_SelectionList.Length); + } + + if (m_SearchList != null && DisplayFrom + MaxEntries < m_SearchList.Count) + { + DisplayFrom += MaxEntries; + // clear any selection + Selected = -1; + } + break; + } + case 202: // backward block + { + // clear the selections + if (m_SelectionList != null && !SelectAll) + { + Array.Clear(m_SelectionList,0,m_SelectionList.Length); + } + + DisplayFrom -= MaxEntries; + if (DisplayFrom < 0) + { + DisplayFrom = 0; + } + + // clear any selection + Selected = -1; + break; + } + + case 700: // Sort + { + // clear any selection + Selected = -1; + // clear the selections + if (m_SelectionList != null && !SelectAll) + { + Array.Clear(m_SelectionList,0,m_SelectionList.Length); + } + + SortFindList(); + break; + } + + case 9998: // refresh the gump + { + // clear any selection + Selected = -1; + break; + } + default: + { + + if (info.ButtonID >= 1000 && info.ButtonID < 1000+ MaxEntries) + { + // flag the entry selected + Selected = info.ButtonID - 1000; + } + else + if (info.ButtonID == 3998) + { + + SelectAll = !SelectAll; + + // dont allow individual selection with the selectall button selected + if (m_SelectionList != null) + { + for(int i = 0; i < MaxEntries;i++) + { + if (i < m_SelectionList.Length) + { + // only toggle the selection list entries for things that actually have entries + m_SelectionList[i] = SelectAll; + } + else + { + break; + } + } + } + } + else + if (info.ButtonID == 3999) + { + + // dont allow individual selection with the selectall button selected + if (m_SelectionList != null && m_SearchList != null && !SelectAll) + { + for(int i = 0; i < MaxEntries;i++) + { + if (i < m_SelectionList.Length) + { + // only toggle the selection list entries for things that actually have entries + if (m_SearchList.Count - DisplayFrom > i) + { + m_SelectionList[i] = !m_SelectionList[i]; + } + } + else + { + break; + } + } + } + } + else + if (info.ButtonID >= 4000 && info.ButtonID < 4000+ MaxEntries) + { + int i = info.ButtonID - 4000; + // dont allow individual selection with the selectall button selected + if (m_SelectionList != null && i >= 0 && i < m_SelectionList.Length && !SelectAll) + { + // only toggle the selection list entries for things that actually have entries + if (m_SearchList != null && m_SearchList.Count - DisplayFrom > i) + { + m_SelectionList[i] = !m_SelectionList[i]; + } + } + } + else + if (info.ButtonID >= 5000 && info.ButtonID < 5100) + { + + + // text entry book buttons + int textid = info.ButtonID - 5000; + + // entry information + XmlDialog.SpeechEntry entry = null; + + if (m_SearchList != null && Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) + { + entry = (XmlDialog.SpeechEntry)m_SearchList[Selected + DisplayFrom]; + } + + string text = String.Empty; + string title = String.Empty; + switch (textid) + { + case 0: // text + { + if (entry != null) + { + text = entry.Text; + } + + title = "Text"; + break; + } + case 1: // keywords + { + if (entry != null) + { + text = entry.Keywords; + } + + title = "Keywords"; + break; + } + case 2: // condition + { + if (entry != null) + { + text = entry.Condition; + } + + title = "Condition"; + break; + } + case 3: // action + { + if (entry != null) + { + text = entry.Action; + } + + title = "Action"; + break; + } + case 4: // gump + { + if (entry != null) + { + text = entry.Gump; + } + + title = "Gump"; + break; + } + case 5: // trigoncarried + { + text = m_Dialog.TriggerOnCarried; + title = "TrigOnCarried"; + break; + } + case 6: // notrigoncarried + { + text = m_Dialog.NoTriggerOnCarried; + title = "NoTrigOnCarried"; + break; + } + } + + object [] args = new object[6]; + + args[0] = m_Dialog; + args[1] = entry; + args[2] = textid; + args[3] = Selected; + args[4] = DisplayFrom; + args[5] = SaveFilename; + + XmlTextEntryBook book = new XmlTextEntryBook(0, String.Empty, m_Dialog.Name, 20, true); + //XmlTextEntryBook book = new XmlTextEntryBook(0, String.Empty, m_Dialog.Name, 20, true, new XmlTextEntryBookCallback(ProcessXmlEditBookEntry), args); + if (m_Dialog.m_TextEntryBook == null) + { + m_Dialog.m_TextEntryBook = new ArrayList(); + } + m_Dialog.m_TextEntryBook.Add(book); + + book.Title = title; + book.Author = Name; + + // fill the contents of the book with the current text entry data + book.FillTextEntryBook(text); + + // put the book at the location of the player so that it can be opened, but drop it below visible range + book.Visible = false; + book.Movable = false; + book.MoveToWorld(new Point3D(state.Mobile.Location.X,state.Mobile.Location.Y,state.Mobile.Location.Z-100), state.Mobile.Map); + + // Create a new gump + Refresh(state); + + // and open it + book.OnDoubleClick(state.Mobile); + + return; + + } + break; + } + } + // Create a new gump + Refresh(state); + } + + + public class XmlConfirmDeleteGump : Gump + { + private ArrayList SearchList; + private bool [] SelectedList; + private Mobile From; + private int DisplayFrom; + private bool selectAll; + XmlEditDialogGump m_Gump; + + public XmlConfirmDeleteGump(Mobile from, XmlEditDialogGump gump, ArrayList searchlist, bool [] selectedlist, int displayfrom, bool selectall, int allcount) : base (0, 0) + { + SearchList = searchlist; + SelectedList = selectedlist; + DisplayFrom = displayfrom; + selectAll = selectall; + m_Gump = gump; + From = from; + Closable = false; + Draggable = true; + AddPage(0); + AddBackground(10, 200, 200, 130, 5054); + int count = 0; + if (selectall) + { + count = allcount; + } + else + { + for(int i =0;i 0) + { + radiostate = info.Switches[0]; + } + switch (info.ButtonID) + { + + default: + { + if (radiostate == 1 && SearchList != null && SelectedList != null) + { // accept + ArrayList dlist = new ArrayList(); + for(int i = 0;i < SearchList.Count;i++) + { + int index = i-DisplayFrom; + if (index >= 0 && index < SelectedList.Length && SelectedList[index] || selectAll) + { + object o = SearchList[i]; + // delete the entry; + dlist.Add(o); + } + } + + foreach(object o in dlist) + { + SearchList.Remove(o); + } + + // clear the selections + Array.Clear(SelectedList,0,SelectedList.Length); + + if (m_Gump != null) + { + state.Mobile.CloseGump(); + m_Gump.Refresh(state); + } + } + break; + } + } + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs new file mode 100644 index 000000000..7ad581eba --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs @@ -0,0 +1,2367 @@ +using Server.Accounting; +using Server.Commands; +using Server.Commands.Generic; +using Server.Gumps; +using Server.Items; +using Server.Multis; +using Server.Network; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Server.Engines.Spawners; + +namespace Server.Mobiles; + +public class XmlFindGump : Gump +{ + public class XmlFindThread + { + readonly SearchCriteria m_SearchCriteria; + readonly Mobile m_From; + readonly string m_commandstring; + + public XmlFindThread(Mobile from, SearchCriteria criteria, string commandstring) + { + m_SearchCriteria = criteria; + m_From = from; + m_commandstring = commandstring; + } + + public void XmlFindThreadMain() + { + if (m_From == null) + { + return; + } + + string status_str; + + ArrayList results = Search(m_SearchCriteria, out status_str); + + XmlFindGump gump = new XmlFindGump(m_From, m_From.Location, m_From.Map, true, true, false, + + m_SearchCriteria, + + results, -1, 0, null, m_commandstring, + false, false, false, false, false, false, 0, 0); + + // display the updated gump synched with the main server thread + Core.LoopContext.Post(() => GumpDisplayCallback(m_From, gump, status_str)); + + } + + public void GumpDisplayCallback(Mobile from, XmlFindGump gump, string status_str) + { + if (from != null && !from.Deleted) + { + from.SendGump(gump); + if (status_str != null) + { + from.SendMessage(33, "XmlFind: {0}", status_str); + } + } + } + } + + private const int MaxEntries = 18; + private const int MaxEntriesPerPage = 18; + + public class SearchEntry + { + public bool Selected; + public object Object; + + public SearchEntry(object o) => Object = o; + } + + public class SearchCriteria + { + public bool Dosearchtype; + public bool Dosearchname; + public bool Dosearchrange; + public bool Dosearchregion; + public bool Dosearchspawnentry; + public bool Dosearchspawntype; + public bool Dosearchcondition; + public bool Dosearchfel; + public bool Dosearchtram; + public bool Dosearchmal; + public bool Dosearchilsh; + public bool Dosearchtok; + public bool Dosearchter; + public bool Dosearchint; + public bool Dosearchnull; + public bool Dosearcherr; + public bool Dosearchage; + public bool Dohidevalidint; + public bool Searchagedirection; + public double Searchage; + public int Searchrange; + public string Searchregion; + public string Searchcondition; + public string Searchtype; + public string Searchname; + public string Searchspawnentry; + + public Map Currentmap; + public Point3D Currentloc; + + public SearchCriteria(bool dotype, bool doname, bool dorange, bool doregion, bool doentry, bool doentrytype, bool docondition, bool dofel, bool dotram, + bool domal, bool doilsh, bool dotok, bool doter, bool doint, bool donull, bool doerr, bool doage, bool dohidevalid, + bool agedirection, double age, int range, string region, string condition, string type, string name, string entry + ) + { + Dosearchtype = dotype; + Dosearchname = doname; + Dosearchrange = dorange; + Dosearchregion = doregion; + Dosearchspawnentry = doentry; + Dosearchspawntype = doentrytype; + Dosearchcondition = docondition; + Dosearchfel = dofel; + Dosearchtram = dotram; + Dosearchmal = domal; + Dosearchilsh = doilsh; + Dosearchtok = dotok; + Dosearchter = doter; + Dosearchint = doint; + Dosearchnull = donull; + Dosearcherr = doerr; + Dosearchage = doage; + Dohidevalidint = dohidevalid; + Searchagedirection = agedirection; + Searchage = age; + Searchrange = range; + Searchregion = region; + Searchcondition = condition; + Searchtype = type; + Searchname = name; + Searchspawnentry = entry; + } + + public SearchCriteria() + { + } + } + + private readonly SearchCriteria m_SearchCriteria; + private bool Sorttype; + private bool Sortrange; + private bool Sortname; + private bool Sortmap; + private bool Sortselect; + private readonly Mobile m_From; + private readonly Point3D StartingLoc; + private readonly Map StartingMap; + private bool m_ShowExtension; + private bool Descendingsort; + private int Selected; + private int DisplayFrom; + private string SaveFilename; + private string CommandString; + + private bool SelectAll; + + private ArrayList m_SearchList; + + public static void Initialize() + { + CommandSystem.Register("XmlFind", AccessLevel.GameMaster, XmlFind_OnCommand); + } + + private static bool TestRange(object o, int range, Map currentmap, Point3D currentloc) + { + if (range < 0) + { + return true; + } + + if (o is Item item) + { + if (item.Map != currentmap) + { + return false; + } + + // is the item in a container? + // if so, then check the range of the parent rather than the item + Point3D loc = item.Location; + if (item.Parent != null && item.RootParent != null) + { + if (item.RootParent is Mobile mobile) + { + loc = mobile.Location; + } + else + if (item.RootParent is Container container) + { + loc = container.Location; + } + + } + return Utility.InRange(currentloc, loc, range); + + } + if (o is Mobile mob) + { + if (mob.Map != currentmap) + { + return false; + } + + return Utility.InRange(currentloc, mob.Location, range); + + } + return false; + } + + private static bool TestRegion(object o, string regionname) + { + if (regionname == null) + { + return false; + } + + if (o is Item item) + { + // is the item in a container? + // if so, then check the region of the parent rather than the item + Point3D loc = item.Location; + if (item.Parent != null && item.RootParent != null) + { + if (item.RootParent is Mobile mobile) + { + loc = mobile.Location; + } + else + if (item.RootParent is Container container) + { + loc = container.Location; + } + } + + Region r = Region.Regions.FirstOrDefault(reg => reg.Map == item.Map && !string.IsNullOrEmpty(reg.Name) && string.Equals(reg.Name, regionname, StringComparison.CurrentCultureIgnoreCase)); + + if (r == null) + { + return false; + } + + return r.Contains(loc); + } + + if (o is Mobile mob) + { + Region r = Region.Regions.FirstOrDefault(reg => reg.Map == mob.Map && !string.IsNullOrEmpty(reg.Name) && string.Equals(reg.Name, regionname, StringComparison.CurrentCultureIgnoreCase)); + + if (r == null) + { + return false; + } + + return r.Contains(mob.Location); + + } + + return false; + } + + private static bool TestAge(object o, double age, bool direction) + { + if (age <= 0) + { + return true; + } + + if (o is Mobile mob) + { + if (direction) + { + // true means allow only mobs greater than the age + if (DateTime.UtcNow - mob.Created > TimeSpan.FromHours(age)) + { + return true; + } + } + else + { + // false means allow only mobs less than the age + if (DateTime.UtcNow - mob.Created < TimeSpan.FromHours(age)) + { + return true; + } + } + } + + return false; + } + + private static void IgnoreManagedInternal(object i, ref ArrayList ignoreList) + { + // ignore valid internalized commodity deed items + if (i is CommodityDeed deed && deed.Commodity != null && deed.Commodity.Map == Map.Internal) + { + ignoreList.Add(deed.Commodity); + } + + // ignore valid internalized keyring keys + if (i is KeyRing keyring && keyring.Keys != null) + { + foreach (Key k in keyring.Keys) + { + ignoreList.Add(k); + } + } + + // ignore valid internalized relocatable house items + if (i is BaseHouse house) + { + foreach (RelocatedEntity relEntity in house.RelocatedEntities) + { + if (relEntity.Entity is Item) + { + ignoreList.Add(relEntity.Entity); + } + } + + foreach (VendorInventory inventory in house.VendorInventories) + { + foreach (Item subItem in inventory.Items) + { + ignoreList.Add(subItem); + } + } + } + } + + // test for valid items/mobs on the internal map + private static bool TestValidInternal(object o) + { + if (o is Mobile m) + { + if (m.Map != Map.Internal || m.Account != null || + (m as IMount)?.Rider != null || + m is BaseCreature creature && creature.IsStabled || + m is PlayerVendor && BaseHouse.AllHouses.Any(x => x.InternalizedVendors.Contains(m))) + { + return true; + } + } + else if (o is Item i) + { + // note, in order to test for a vendors display container that contains valid internal map items + if (i.Map != Map.Internal || i.Parent != null || i is Fists or MountItem or EffectItem || i.HeldBy != null || + i is MovingCrate || i.GetType().DeclaringType == typeof(GenericBuyInfo)) + { + return true; + } + + // boat stuffs + if (i is Static && i.Name != null && (i.Name.ToLower() == "weapon pad" || i.Name.ToLower() == "deck")) + { + return true; + } + + // Ship/Vehicle parts + if (i is BaseDockedBoat or BaseBoat or Plank or TillerMan or Hold) + { + return true; + } + + // TODO: Ignores addons, persistence, and other items that are internalized while not in use + } + + return false; + } + + public static ArrayList Search(SearchCriteria criteria, out string status_str) + { + status_str = null; + ArrayList newarray = new ArrayList(); + ArrayList ignoreList = new ArrayList(); + + if (criteria == null) + { + status_str = "Empty search criteria"; + return newarray; + } + + Type targetType = null; + + Map tokunomap = null; + try + { + tokunomap = Map.Parse("Tokuno"); + } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + + // if the type is specified then get the search type + if (criteria.Dosearchtype && criteria.Searchtype != null) + { + targetType = AssemblyHandler.FindTypeByName(criteria.Searchtype); + if (targetType == null) + { + status_str = $"Invalid type: {criteria.Searchtype}"; + return newarray; + } + } + + // do the search through items + + // make a copy so that we dont get enumeration errors if World.Items.Values changes while searching + ArrayList itemarray = null; + + ICollection itemvalues = World.Items.Values; + + lock (itemvalues.SyncRoot) + { + try + { + itemarray = new ArrayList(itemvalues); + } + catch (SystemException e) { status_str = $"Unable to search World.Items: {e.Message}"; } + } + + if (itemarray != null) + { + foreach (Item i in itemarray) + { + bool hastype = false; + bool hasname = false; + bool hasentry = false; + bool hascondition = false; + bool hasrange = false; + bool hasregion = false; + bool hasmap = false; + bool hasspawnerr = false; + bool hasvalidhidden = false; + + if (i == null || i.Deleted) + { + continue; + } + + // this will deal with items that are not on the internal map but hold valid internal items + if (criteria.Dohidevalidint && i.Map != Map.Internal && i.Map != null) + { + IgnoreManagedInternal(i, ref ignoreList); + } + + // check for map + if (i.Map == Map.Felucca && criteria.Dosearchfel || i.Map == Map.Trammel && criteria.Dosearchtram || + i.Map == Map.Malas && criteria.Dosearchmal || i.Map == Map.Ilshenar && criteria.Dosearchilsh || + i.Map == Map.TerMur && criteria.Dosearchter || i.Map == Map.Internal && criteria.Dosearchint || + i.Map == null && criteria.Dosearchnull) + { + hasmap = true; + } + + if (tokunomap != null && i.Map == tokunomap && criteria.Dosearchtok) + { + hasmap = true; + } + + if (!hasmap) + { + continue; + } + + // check for type + if (criteria.Dosearchtype && (i.GetType().IsSubclassOf(targetType) || i.GetType() == targetType)) + { + hastype = true; + } + if (criteria.Dosearchtype && !hastype) + { + continue; + } + + // check for name + if (criteria.Dosearchname && i.Name != null && criteria.Searchname != null && i.Name.ToLower().IndexOf(criteria.Searchname.ToLower()) >= 0) + { + hasname = true; + } + + if (criteria.Dosearchname && !hasname) + { + continue; + } + + // check for valid internal map items + if (criteria.Dohidevalidint && TestValidInternal(i)) + { + hasvalidhidden = true; + + // this will deal with items that are on the internal map and hold valid internal items + IgnoreManagedInternal(i, ref ignoreList); + } + if (criteria.Dohidevalidint && hasvalidhidden) + { + continue; + } + + // check for range + if (criteria.Dosearchrange && TestRange(i, criteria.Searchrange, criteria.Currentmap, criteria.Currentloc)) + { + hasrange = true; + } + if (criteria.Dosearchrange && !hasrange) + { + continue; + } + + // check for region + if (criteria.Dosearchregion && TestRegion(i, criteria.Searchregion)) + { + hasregion = true; + } + if (criteria.Dosearchregion && !hasregion) + { + continue; + } + + // check for condition + if (criteria.Dosearchcondition && criteria.Searchcondition != null) + { + // check the property test + hascondition = BaseXmlSpawner.CheckPropertyString(null, i, criteria.Searchcondition, out status_str); + } + if (criteria.Dosearchcondition && !hascondition) + { + continue; + } + + // check for entry + if (criteria.Dosearchspawnentry) + { + Type targetentrytype = null; + + if (criteria.Dosearchspawntype) + { + targetentrytype = AssemblyHandler.FindTypeByName(criteria.Searchspawnentry.ToLower()); + } + + if (criteria.Searchspawnentry == null || targetentrytype == null && criteria.Dosearchspawntype) + { + hasentry = false; + } + else + { + // see what kind of spawner it is + if (i is XmlSpawner spawner) + { + // search the entries of the spawner + foreach (XmlSpawner.SpawnObject so in spawner.m_SpawnObjects) + { + if (criteria.Dosearchspawntype) + { + // search by entry type + Type type = null; + + if (so.TypeName != null) + { + string[] args = so.TypeName.Split('/'); + string typestr = null; + if (args != null && args.Length > 0) + { + typestr = args[0]; + } + + type = AssemblyHandler.FindTypeByName(typestr); + } + + if (type != null && (type == targetentrytype || type.IsSubclassOf(targetentrytype))) + { + hasentry = true; + break; + } + } + else + { + // search by entry string + if (so.TypeName != null && so.TypeName.ToLower().IndexOf(criteria.Searchspawnentry.ToLower()) >= 0) + { + hasentry = true; + break; + } + } + } + } + else if (i is Spawner spawner1) + { + // search the entries of the spawner + foreach (var entry in spawner1.Entries) + { + string so = entry.SpawnedName; + + if (criteria.Dosearchspawntype) + { + // search by entry type + Type type = null; + + if (so != null) + { + type = AssemblyHandler.FindTypeByName(so); + } + + if (type != null && (type == targetentrytype || type.IsSubclassOf(targetentrytype))) + { + hasentry = true; + break; + } + } + else + { + if (so != null && so.ToLower().IndexOf(criteria.Searchspawnentry.ToLower()) >= 0) + { + hasentry = true; + break; + } + } + } + } + else + { + hasentry = false; + } + } + } + + if (criteria.Dosearchspawnentry && !hasentry) + { + continue; + } + + if (criteria.Dosearcherr && i is XmlSpawner hasSpawn && hasSpawn.status_str != null) + { + hasspawnerr = true; + } + + if (criteria.Dosearcherr && !hasspawnerr) + { + continue; + } + + // satisfied all conditions so add it + newarray.Add(new SearchEntry(i)); + } + } + + // do the search through mobiles + if (!criteria.Dosearcherr) + { + // make a copy so that we dont get enumeration errors if World.Mobiles.Values changes while searching + ArrayList mobilearray = null; + ICollection mobilevalues = World.Mobiles.Values; + lock (mobilevalues.SyncRoot) + { + try + { + mobilearray = new ArrayList(mobilevalues); + } + catch (SystemException e) { status_str = $"Unable to search World.Mobiles: {e.Message}"; } + } + + if (mobilearray != null) + { + foreach (Mobile i in mobilearray) + { + bool hastype = false; + bool hasname = false; + bool hascondition = false; + bool hasrange = false; + bool hasregion = false; + bool hasmap = false; + bool hasage = false; + bool hasvalidhidden = false; + + if (i == null || i.Deleted) + { + continue; + } + + // check for map + if (i.Map == Map.Felucca && criteria.Dosearchfel || i.Map == Map.Trammel && criteria.Dosearchtram || + i.Map == Map.Malas && criteria.Dosearchmal || i.Map == Map.Ilshenar && criteria.Dosearchilsh || + i.Map == Map.TerMur && criteria.Dosearchter || i.Map == Map.Internal && criteria.Dosearchint || + i.Map == null && criteria.Dosearchnull) + { + hasmap = true; + } + + if (tokunomap != null && i.Map == tokunomap && criteria.Dosearchtok) + { + hasmap = true; + } + + if (!hasmap) + { + continue; + } + + // check for range + if (criteria.Dosearchrange && TestRange(i, criteria.Searchrange, criteria.Currentmap, criteria.Currentloc)) + { + hasrange = true; + } + if (criteria.Dosearchrange && !hasrange) + { + continue; + } + + // check for region + if (criteria.Dosearchregion && TestRegion(i, criteria.Searchregion)) + { + hasregion = true; + } + if (criteria.Dosearchregion && !hasregion) + { + continue; + } + + // check for valid internal map mobiles + if (criteria.Dohidevalidint && TestValidInternal(i)) + { + hasvalidhidden = true; + } + if (criteria.Dohidevalidint && hasvalidhidden) + { + continue; + } + + // check for age + if (criteria.Dosearchage && TestAge(i, criteria.Searchage, criteria.Searchagedirection)) + { + hasage = true; + } + if (criteria.Dosearchage && !hasage) + { + continue; + } + + // check for type + if (criteria.Dosearchtype && (i.GetType().IsSubclassOf(targetType) || i.GetType() == targetType)) + { + hastype = true; + } + if (criteria.Dosearchtype && !hastype) + { + continue; + } + + // check for name + if (criteria.Dosearchname && i.Name != null && criteria.Searchname != null && i.Name.ToLower().IndexOf(criteria.Searchname.ToLower()) >= 0) + { + hasname = true; + } + if (criteria.Dosearchname && !hasname) + { + continue; + } + + // check for condition + if (criteria.Dosearchcondition && criteria.Searchcondition != null) + { + // check the property test + hascondition = BaseXmlSpawner.CheckPropertyString(null, i, criteria.Searchcondition, out status_str); + } + if (criteria.Dosearchcondition && !hascondition) + { + continue; + } + + // passed all conditions so add it to the list + + newarray.Add(new SearchEntry(i)); + } + } + } + + ArrayList removelist = new ArrayList(); + for (int i = 0; i < ignoreList.Count; ++i) + { + foreach (SearchEntry se in newarray) + { + if (se.Object == ignoreList[i]) + { + removelist.Add(se); + break; + } + } + } + + foreach (SearchEntry se in removelist) + { + newarray.Remove(se); + } + + return newarray; + } + + [Usage("XmlFind [objecttype] [range]")] + [Description("Finds objects in the world")] + public static void XmlFind_OnCommand(CommandEventArgs e) + { + if (e?.Mobile == null) + { + return; + } + + Account acct = e.Mobile.Account as Account; + int x = 0; + int y = 0; + XmlSpawnerDefaults.DefaultEntry defs = null; + if (acct != null) + { + defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), e.Mobile.Name); + } + + if (defs != null) + { + x = defs.FindGumpX; + y = defs.FindGumpY; + } + + string typename = "Xmlspawner"; + int range = -1; + bool dorange = false; + + if (e.Arguments.Length > 0) + { + typename = e.Arguments[0]; + } + + if (e.Arguments.Length > 1) + { + dorange = true; + try + { + range = int.Parse(e.Arguments[1]); + } + catch + { + dorange = false; + e.Mobile.SendMessage("Invalid range argument {0}", e.Arguments[1]); + } + } + + e.Mobile.SendGump(new XmlFindGump(e.Mobile, e.Mobile.Location, e.Mobile.Map, typename, range, dorange, x, y)); + } + + public XmlFindGump(Mobile from, Point3D startloc, Map startmap, int x, int y) + : this(from, startloc, startmap, null, x, y) + { + } + + public XmlFindGump(Mobile from, Point3D startloc, Map startmap, string type, int x, int y) + : this(from, startloc, startmap, type, -1, false, x, y) + { + } + + public XmlFindGump(Mobile from, Point3D startloc, Map startmap, string type, int range, bool dorange, int x, int y) + : this(from, startloc, startmap, true, false, false, + + new SearchCriteria( + true, // dotype + false, // doname + dorange, // dorange + false, // doregion + false, // doentry + false, // doentrytype + false, // docondition + true, // dofel + true, // dotram + true, // domal + true, // doilsh + true, // dotok + true, // doter + false, // doint + false, // donull + false, // doerr + false, // doage + false, // dohidevalid + true, // agedirection + 0, // age + range, // range + null, // region + null, // condition + type, // type + null, // name + null // entry + ), + + null, -1, 0, null, null, + false, false, false, false, false, false, x, y) + { + } + + public XmlFindGump( + Mobile from, + Point3D startloc, + Map startmap, + bool firststart, + bool extension, + bool descend, + SearchCriteria criteria, + ArrayList searchlist, + int selected, + int displayfrom, + string savefilename, + string commandstring, + bool sorttype, + bool sortname, + bool sortrange, + bool sortmap, + bool sortselect, + bool selectall, + int X, + int Y + ) + : base(X, Y) + { + + StartingMap = startmap; + StartingLoc = startloc; + if (from != null && !from.Deleted) + { + m_From = from; + if (firststart) + { + StartingMap = from.Map; + StartingLoc = from.Location; + } + } + + SaveFilename = savefilename; + CommandString = commandstring; + SelectAll = selectall; + Sorttype = sorttype; + Sortname = sortname; + Sortrange = sortrange; + Sortmap = sortmap; + Sortselect = sortselect; + DisplayFrom = displayfrom; + Selected = selected; + m_ShowExtension = extension; + Descendingsort = descend; + + m_SearchCriteria = criteria ?? new SearchCriteria(); + + m_SearchList = searchlist; + + // prepare the page + const int height = 500; + + AddPage(0); + if (m_ShowExtension) + { + AddBackground(0, 0, 755, height, 5054); + AddAlphaRegion(0, 0, 755, height); + } + else + { + AddBackground(0, 0, 170, height, 5054); + AddAlphaRegion(0, 0, 170, height); + } + + // ---------------- + // SORT section + // ---------------- + int y = 5; + // add the Sort button + AddButton(5, y, 0xFAB, 0xFAD, 700); + AddLabel(38, y, 0x384, "Sort"); + + // add the sort direction button + if (Descendingsort) + { + AddButton(75, y + 3, 0x15E2, 0x15E6, 701); + AddLabel(95, y, 0x384, "descend"); + } + else + { + AddButton(75, y + 3, 0x15E0, 0x15E4, 701); + AddLabel(95, y, 0x384, "ascend"); + } + y += 22; + // add the Sort on type toggle + AddRadio(5, y, 0xD2, 0xD3, Sorttype, 0); + AddLabel(28, y, 0x384, "type"); + + // add the Sort on name toggle + AddRadio(75, y, 0xD2, 0xD3, Sortname, 1); + AddLabel(98, y, 0x384, "name"); + + y += 20; + // add the Sort on range toggle + AddRadio(5, y, 0xD2, 0xD3, Sortrange, 2); + AddLabel(28, y, 0x384, "range"); + + // add the Sort on map toggle + AddRadio(75, y, 0xD2, 0xD3, Sortmap, 4); + AddLabel(98, y, 0x384, "map"); + + y += 20; + // add the Sort on selected toggle + AddRadio(5, y, 0xD2, 0xD3, Sortselect, 5); + AddLabel(28, y, 0x384, "select"); + + // ---------------- + // SEARCH section + // ---------------- + y = 85; + // add the Search button + AddButton(5, y, 0xFA8, 0xFAA, 3); + AddLabel(38, y, 0x384, "Search"); + + y += 20; + // add the map buttons + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchint, 312); + AddLabel(28, y, 0x384, "Int"); + AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchnull, 314); + AddLabel(98, y, 0x384, "Null"); + + y += 20; + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchfel, 308); + AddLabel(28, y, 0x384, "Fel"); + AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtram, 309); + AddLabel(98, y, 0x384, "Tram"); + + y += 20; + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchmal, 310); + AddLabel(28, y, 0x384, "Mal"); + AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchilsh, 311); + AddLabel(98, y, 0x384, "Ilsh"); + + y += 20; + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtok, 318); + AddLabel(28, y, 0x384, "Tok"); + AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchter, 320); + AddLabel(98, y, 0x384, "Ter"); + + y += 20; + // add the hide valid internal map button + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dohidevalidint, 316); + AddLabel(28, y, 0x384, "Hide valid internal"); + + // ---------------- + // FILTER section + // ---------------- + y = height - 295; + + // add the search region entry + AddLabel(28, y, 0x384, "region"); + AddImageTiled(70, y, 68, 19, 0xBBC); + AddTextEntry(70, y, 250, 19, 0, 106, m_SearchCriteria.Searchregion); + // add the toggle to enable search region + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchregion, 319); + + y += 20; + // add the search age entry + AddLabel(28, y, 0x384, "age"); + //AddImageTiled(80, 220, 50, 23, 0x52); + AddImageTiled(70, y, 45, 19, 0xBBC); + AddTextEntry(70, y, 45, 19, 0, 105, m_SearchCriteria.Searchage.ToString()); + AddLabel(117, y, 0x384, "Hrs"); + // add the toggle to enable search age + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchage, 303); + // add the toggle to set the search age test direction + AddCheck(50, y + 2, 0x1467, 0x1468, m_SearchCriteria.Searchagedirection, 302); + + y += 20; + // add the search range entry + AddLabel(28, y, 0x384, "range"); + AddImageTiled(70, y, 45, 19, 0xBBC); + AddTextEntry(70, y, 45, 19, 0, 100, m_SearchCriteria.Searchrange.ToString()); + // add the toggle to enable search range + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchrange, 304); + + y += 20; + // add the search type entry + AddLabel(28, y, 0x384, "type"); + // add the toggle to enable search by type + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtype, 305); + //AddImageTiled(5, 285, 135, 23, 0x52); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 250, 19, 0, 101, m_SearchCriteria.Searchtype); + + y += 41; + // add the search condition entry + AddLabel(28, y, 0x384, "property test"); + // add the toggle to enable search by condition + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchcondition, 315); + //AddImageTiled(5, 285, 135, 23, 0x52); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 500, 19, 0, 104, m_SearchCriteria.Searchcondition); + + y += 41; + // add the search name entry + AddLabel(28, y, 0x384, "name"); + // add the toggle to enable search by name + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchname, 306); + //AddImageTiled(5, 350, 135, 23, 0x52); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 250, 19, 0, 102, m_SearchCriteria.Searchname); + + y += 41; + // add the search spawner entries + AddLabel(28, y, 0x384, "entry"); + // add the toggle to enable search spawner entries + AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchspawnentry, 307); + + // add the search spawner entries by type + AddLabel(88, y, 0x384, "type"); + // add the toggle to enable search spawner entry types + AddCheck(65, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchspawntype, 326); + + //AddImageTiled(5, 415, 135, 23, 0x52); + AddImageTiled(6, y + 20, 132, 19, 0xBBC); + AddTextEntry(6, y + 20, 250, 19, 0, 103, m_SearchCriteria.Searchspawnentry); + + // add the search spawner errors + AddLabel(140, y, 0x384, "err"); + // add the toggle to enable search spawner entries + AddCheck(117, y, 0xD2, 0xD3, m_SearchCriteria.Dosearcherr, 313); + + // add the Show Map button + //AddButton(5, 450, 0xFAB, 0xFAD, 150, GumpButtonType.Reply, 0); + //AddLabel(38, 450, 0x384, "Map"); + + // ---------------- + // CONTROL section + // ---------------- + + y = height - 25; + // add the Return button + AddButton(72, y, 0xFAE, 0xFAF, 155); + AddLabel(105, y, 0x384, "Return"); + + y = height - 25; + // add the Bring button + AddButton(5, y, 0xFAE, 0xFAF, 154); + AddLabel(38, y, 0x384, "Bring"); + + + // add gump extension button + if (m_ShowExtension) + { + AddButton(720, y + 5, 0x15E3, 0x15E7, 200); + } + else + { + AddButton(150, y + 5, 0x15E1, 0x15E5, 200); + } + + if (m_ShowExtension) + { + AddLabel(143, 5, 0x384, "Gump"); + AddLabel(178, 5, 0x384, "Prop"); + AddLabel(210, 5, 0x384, "Goto"); + AddLabel(250, 5, 0x384, "Name"); + AddLabel(365, 5, 0x384, "Type"); + AddLabel(460, 5, 0x384, "Location"); + AddLabel(578, 5, 0x384, "Map"); + AddLabel(650, 5, 0x384, "Owner"); + + // add the Delete button + AddButton(150, y, 0xFB1, 0xFB3, 156); + AddLabel(183, height - 25, 0x384, "Delete"); + + // add the Reset button + AddButton(230, y, 0xFA2, 0xFA3, 157); + AddLabel(263, y, 0x384, "Reset"); + + // add the Respawn button + AddButton(310, y, 0xFA8, 0xFAA, 158); + AddLabel(343, y, 0x384, "Respawn"); + + // add the xmlsave entry + AddButton(150, y - 25, 0xFA8, 0xFAA, 159); + AddLabel(183, y - 25, 0x384, "Save to file:"); + + AddImageTiled(270, y - 25, 180, 19, 0xBBC); + AddTextEntry(270, y - 25, 180, 19, 0, 300, SaveFilename); + + // add the commandstring entry + AddButton(470, y - 25, 0xFA8, 0xFAA, 160); + AddLabel(503, y - 25, 0x384, "Command:"); + + AddImageTiled(560, y - 25, 180, 19, 0xBBC); + AddTextEntry(560, y - 25, 180, 19, 0, 301, CommandString); + + + // add the page buttons + for (int i = 0; i < MaxEntries / MaxEntriesPerPage; i++) + { + //AddButton(38+i*30, 365, 2206, 2206, 0, GumpButtonType.Page, 1+i); + AddButton(418 + i * 25, height - 25, 0x8B1 + i, 0x8B1 + i, 0, GumpButtonType.Page, 1 + i); + } + + // add the advance pageblock buttons + AddButton(415 + 25 * (MaxEntries / MaxEntriesPerPage), height - 25, 0x15E1, 0x15E5, 201); // block forward + AddButton(395, height - 25, 0x15E3, 0x15E7, 202); // block backward + + // add the displayfrom entry + AddLabel(460, y, 0x384, "Display"); + AddImageTiled(500, y, 60, 21, 0xBBC); + AddTextEntry(501, y, 60, 21, 0, 400, DisplayFrom.ToString()); + AddButton(560, y, 0xFAB, 0xFAD, 9998); + + // display the item list + if (m_SearchList != null) + { + AddLabel(180, y - 50, 68, $"Found {m_SearchList.Count} items/mobiles"); + AddLabel(400, y - 50, 68, + $"Displaying {DisplayFrom}-{(DisplayFrom + MaxEntries < m_SearchList.Count ? DisplayFrom + MaxEntries : m_SearchList.Count)}" + ); + + // count the number of selected objects + int count = 0; + foreach (SearchEntry e in m_SearchList) + { + if (e.Selected) + { + count++; + } + } + AddLabel(600, y - 50, 33, $"Selected {count}"); + } + + // display the select-all-displayed toggle + AddButton(730, 5, 0xD2, 0xD3, 3999); + + AddLabel(610, y, 0x384, "Select All"); + // display the select-all toggle + AddButton(670, y, SelectAll ? 0xD3 : 0xD2, SelectAll ? 0xD2 : 0xD3, 3998); + + for (int i = 0; i < MaxEntries; i++) + { + int index = i + DisplayFrom; + if (m_SearchList == null || index >= m_SearchList.Count) + { + break; + } + + SearchEntry e = (SearchEntry)m_SearchList[index]; + + int page = i / MaxEntriesPerPage; + + if (i % MaxEntriesPerPage == 0) + { + AddPage(page + 1); + // add highlighted page button + //AddImageTiled(235+page*25, 448, 25, 25, 0xBBC); + //AddImage(238+page*25, 450, 0x8B1+page); + } + + // background for search results area + AddImageTiled(235, 22 * (i % MaxEntriesPerPage) + 30, 386, 23, 0x52); + AddImageTiled(236, 22 * (i % MaxEntriesPerPage) + 31, 384, 21, 0xBBC); + + // add the Goto button for each entry + AddButton(205, 22 * (i % MaxEntriesPerPage) + 30, 0xFAE, 0xFAF, 1000 + i); + + object o = e.Object; + + // add the Gump button for spawner entries + if (o is XmlSpawner || o is Spawner) + { + AddButton(145, 22 * (i % MaxEntriesPerPage) + 30, 0xFBD, 0xFBE, 2000 + i); + } + + // add the Props button for each entry + AddButton(175, 22 * (i % MaxEntriesPerPage) + 30, 0xFAB, 0xFAD, 3000 + i); + + string namestr = string.Empty; + string typestr = string.Empty; + string locstr = string.Empty; + string mapstr = string.Empty; + string ownstr = string.Empty; + int texthue = 0; + + if (o is Item) + { + Item item = (Item)e.Object; + // change the color if it is in a container + namestr = item.Name; + string str = item.GetType().ToString(); + if (str != null) + { + string[] arglist = str.Split('.'); + typestr = arglist[arglist.Length - 1]; + } + // check for in container + // if so then display parent loc + // change the color for container held items + if (item.Parent != null) + { + if (item.RootParent is Mobile m) + { + texthue = m.Player ? 44 : 24; + locstr = m.Location.ToString(); + ownstr = m.Name; + } + else if (item.RootParent is Container c) + { + texthue = 5; + locstr = c.Location.ToString(); + ownstr = c.Name ?? c.ItemData.Name; + } + } + else + { + locstr = item.Location.ToString(); + } + + if (item.Deleted) + { + mapstr = "Deleted"; + } + else + if (item.Map != null) + { + mapstr = item.Map.ToString(); + } + } + else if (o is Mobile) + { + Mobile mob = (Mobile)e.Object; + // change the color if it is in a container + namestr = mob.Name; + string str = mob.GetType().ToString(); + if (str != null) + { + string[] arglist = str.Split('.'); + typestr = arglist[arglist.Length - 1]; + } + locstr = mob.Location.ToString(); + if (mob.Deleted) + { + mapstr = "Deleted"; + } + else + if (mob.Map != null) + { + mapstr = mob.Map.ToString(); + } + } + + if (e.Selected) + { + texthue = 33; + } + + if (i == Selected) + { + texthue = 68; + } + + // display the name + AddLabelCropped(248, 22 * (i % MaxEntriesPerPage) + 31, 110, 21, texthue, namestr ?? string.Empty); + + // display the type + AddImageTiled(360, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, 0xBBC); + AddLabelCropped(360, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, texthue, typestr); + // display the loc + AddImageTiled(450, 22 * (i % MaxEntriesPerPage) + 31, 137, 21, 0xBBC); + AddLabel(450, 22 * (i % MaxEntriesPerPage) + 31, texthue, locstr); + // display the map + AddImageTiled(571, 22 * (i % MaxEntriesPerPage) + 31, 70, 21, 0xBBC); + AddLabel(571, 22 * (i % MaxEntriesPerPage) + 31, texthue, mapstr); + // display the owner + AddImageTiled(640, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, 0xBBC); + AddLabelCropped(640, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, texthue, ownstr); + + // display the selection button + + AddButton(730, 22 * (i % MaxEntriesPerPage) + 32, e.Selected ? 0xD3 : 0xD2, e.Selected ? 0xD2 : 0xD3, 4000 + i); + } + } + } + + private void DoGoTo(int index) + { + if (m_From == null || m_From.Deleted) + { + return; + } + + if (m_SearchList != null && index < m_SearchList.Count) + { + object o = ((SearchEntry)m_SearchList[index]).Object; + if (o is Item item) + { + Point3D itemloc; + if (item.Parent != null) + { + if (item.RootParent is Mobile mobile) + { + itemloc = mobile.Location; + } + else if (item.RootParent is Container container) + { + itemloc = container.Location; + } + else + { + return; + } + } + else + { + itemloc = item.Location; + } + if (item.Deleted || item.Map == null || item.Map == Map.Internal) + { + return; + } + + m_From.Location = itemloc; + m_From.Map = item.Map; + } + + else if (o is Mobile mob) + { + if (mob.Deleted || mob.Map == null || mob.Map == Map.Internal) + { + return; + } + + m_From.Location = mob.Location; + m_From.Map = mob.Map; + } + } + } + + private void DoShowGump(int index) + { + if (m_From == null || m_From.Deleted) + { + return; + } + + if (m_SearchList != null && index < m_SearchList.Count) + { + object o = ((SearchEntry)m_SearchList[index]).Object; + if (o is XmlSpawner x1) + { + // dont open anything with a null map null item or deleted + if (x1.Deleted || x1.Map == null || x1.Map == Map.Internal) + { + return; + } + + x1.OnDoubleClick(m_From); + } + else if (o is Spawner x2) + { + if (x2.Deleted || x2.Map == null || x2.Map == Map.Internal) + { + return; + } + + x2.OnDoubleClick(m_From); + } + } + } + + private void DoShowProps(int index) + { + if (m_From == null || m_From.Deleted) + { + return; + } + + if (m_SearchList != null && index < m_SearchList.Count) + { + object o = ((SearchEntry)m_SearchList[index]).Object; + if (o is Item x1) + { + if (x1.Deleted) + { + return; + } + + m_From.SendGump(new PropertiesGump(m_From, x1)); + } + else if (o is Mobile x2) + { + if (x2.Deleted) + { + return; + } + + m_From.SendGump(new PropertiesGump(m_From, x2)); + } + } + } + + private void SortFindList() + { + if (m_SearchList != null && m_SearchList.Count > 0) + { + if (Sorttype) + { + m_SearchList.Sort(new ListTypeSorter(Descendingsort)); + } + else if (Sortname) + { + m_SearchList.Sort(new ListNameSorter(Descendingsort)); + } + else if (Sortmap) + { + m_SearchList.Sort(new ListMapSorter(Descendingsort)); + } + else if (Sortrange) + { + m_SearchList.Sort(new ListRangeSorter(m_From, Descendingsort)); + } + else if (Sortselect) + { + m_SearchList.Sort(new ListSelectSorter(Descendingsort)); + } + } + } + + private class ListTypeSorter : IComparer + { + private readonly bool Dsort; + + public ListTypeSorter(bool descend) => Dsort = descend; + + public int Compare(object e1, object e2) + { + string xstr = (e1 as SearchEntry)?.Object?.GetType().Name; + string ystr = (e2 as SearchEntry)?.Object?.GetType().Name; + + if (Dsort) + { + return string.Compare(ystr, xstr, true); + } + + return string.Compare(xstr, ystr, true); + } + } + + private class ListNameSorter : IComparer + { + private readonly bool Dsort; + + public ListNameSorter(bool descend) => Dsort = descend; + + public int Compare(object e1, object e2) + { + string xstr = (e1 as SearchEntry)?.Object switch + { + Item item => item.Name, + Mobile mobile => mobile.Name, + _ => null + }; + + string ystr = (e2 as SearchEntry)?.Object switch + { + Item item => item.Name, + Mobile mobile => mobile.Name, + _ => null + }; + + if (Dsort) + { + return string.Compare(ystr, xstr, true); + } + + return string.Compare(xstr, ystr, true); + } + } + + private class ListMapSorter : IComparer + { + private readonly bool Dsort; + + public ListMapSorter(bool descend) => Dsort = descend; + + public int Compare(object e1, object e2) + { + string xstr = ((e1 as SearchEntry)?.Object as IEntity)?.Map.Name; + string ystr = ((e2 as SearchEntry)?.Object as IEntity)?.Map.Name; + + if (Dsort) + { + return string.Compare(ystr, xstr, true); + } + + return string.Compare(xstr, ystr, true); + } + } + + private class ListRangeSorter : IComparer + { + private readonly Mobile From; + private readonly bool Dsort; + + public ListRangeSorter(Mobile from, bool descend) + { + From = from; + Dsort = descend; + } + + public int Compare(object e1, object e2) + { + if (From == null || From.Deleted) + { + return 0; + } + + IEntity entity1 = (e1 as SearchEntry)?.Object as IEntity; + IEntity entity2 = (e2 as SearchEntry)?.Object as IEntity; + + if (entity1 == null && entity2 == null) + { + return 0; + } + + if (entity1 == null) + { + return Dsort ? 1 : -1; + } + if (entity2 == null) + { + return Dsort ? -1 : 1; + } + + if (entity1.Map != From.Map && entity2.Map != From.Map) + { + return 0; + } + + if (entity1.Map == From.Map && entity2.Map != From.Map) + { + return Dsort ? 1 : -1; + } + + if (entity1.Map != From.Map && entity2.Map == From.Map) + { + return Dsort ? -1 : 1; + } + + if (Dsort) + { + return From.GetDistanceToSqrt(entity2.Location).CompareTo(From.GetDistanceToSqrt(entity1.Location)); + } + + return From.GetDistanceToSqrt(entity1.Location).CompareTo(From.GetDistanceToSqrt(entity2.Location)); + } + } + + private class ListSelectSorter : IComparer + { + private readonly bool Dsort; + + public ListSelectSorter(bool descend) => Dsort = descend; + + public int Compare(object e1, object e2) + { + int x = 0; + int y = 0; + + if (e1 is SearchEntry entry) + { + x = entry.Selected ? 1 : 0; + } + + if (e2 is SearchEntry searchEntry) + { + y = searchEntry.Selected ? 1 : 0; + } + + if (Dsort) + { + return x - y; + } + + return y - x; + } + } + + private void Refresh(NetState state) + { + state.Mobile.SendGump(new XmlFindGump(m_From, StartingLoc, StartingMap, false, m_ShowExtension, Descendingsort, m_SearchCriteria, m_SearchList, Selected, DisplayFrom, SaveFilename, + CommandString, Sorttype, Sortname, Sortrange, + Sortmap, Sortselect, SelectAll, X, Y)); + } + + private void ResetList() + { + if (m_SearchList == null) + { + return; + } + + for (int i = 0; i < m_SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)m_SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is XmlSpawner spawner) + { + spawner.DoReset = true; + } + } + } + } + + private void RespawnList() + { + if (m_SearchList == null) + { + return; + } + + for (int i = 0; i < m_SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)m_SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is XmlSpawner spawner) + { + spawner.DoRespawn = true; + } + } + } + } + + private void SaveList(Mobile from, string filename) + { + if (m_SearchList == null) + { + return; + } + + string dirname; + if (System.IO.Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + { + // put it in the defaults directory if it exists + dirname = $"{XmlSpawner.XmlSpawnDir}/{filename}"; + } + else + { + // otherwise just put it in the main installation dir + dirname = filename; + } + + List savelist = new List(); + + for (int i = 0; i < m_SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)m_SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is XmlSpawner spawner) + { + // add it to the saves list + savelist.Add(spawner); + } + } + } + + // write out the spawners to a file + XmlSpawner.SaveSpawnList(from, savelist, dirname, false, true); + } + + private void ExecuteCommand(Mobile from, string command) + { + if (m_SearchList == null) + { + return; + } + + var executelist = new List(); + + for (int i = 0; i < m_SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)m_SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + // add it to the execute list + executelist.Add(o); + + } + } + + // lookup the command + // and execute it + if (!string.IsNullOrEmpty(command)) + { + string[] args = command.Split(' '); + + if (args.Length > 1) + { + string[] cargs = new string[args.Length - 1]; + for (int i = 0; i < args.Length - 1; i++) + { + cargs[i] = args[i + 1]; + } + + CommandEventArgs e = new CommandEventArgs(from, args[0], command, cargs); + + foreach (BaseCommand c in TargetCommands.AllCommands) + { + // find the matching command + if (string.Equals(c.Commands[0], args[0], StringComparison.CurrentCultureIgnoreCase)) + { + bool flushToLog = false; + + // execute the command on the objects in the list + + if (executelist.Count > 20) + { + CommandLogging.Enabled = false; + } + + c.ExecuteList(e, executelist); + + if (executelist.Count > 20) + { + flushToLog = true; + CommandLogging.Enabled = true; + } + + c.Flush(from, flushToLog); + return; + } + } + from.SendMessage("Invalid command: {0}", args[0]); + } + } + } + + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state?.Mobile == null || m_SearchCriteria == null) + { + return; + } + + int radiostate = -1; + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + + // read the text entries for the search criteria + TextRelay tr = info.GetTextEntry(105); // range info + m_SearchCriteria.Searchage = 0; + if (tr?.Text != null && tr.Text.Length > 0) + { + try { m_SearchCriteria.Searchage = double.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + // read the text entries for the search criteria + tr = info.GetTextEntry(100); // range info + m_SearchCriteria.Searchrange = -1; + if (tr?.Text != null && tr.Text.Length > 0) + { + try { m_SearchCriteria.Searchrange = int.Parse(tr.Text); } + catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } + } + + tr = info.GetTextEntry(101); // type info + if (tr != null) + { + m_SearchCriteria.Searchtype = tr.Text; + } + + tr = info.GetTextEntry(102); // name info + if (tr != null) + { + m_SearchCriteria.Searchname = tr.Text; + } + + tr = info.GetTextEntry(103); // entry info + if (tr != null) + { + m_SearchCriteria.Searchspawnentry = tr.Text; + } + + tr = info.GetTextEntry(104); // condition info + if (tr != null) + { + m_SearchCriteria.Searchcondition = tr.Text; + } + + tr = info.GetTextEntry(106); // region info + if (tr != null) + { + m_SearchCriteria.Searchregion = tr.Text; + } + + + tr = info.GetTextEntry(400); // displayfrom info + if (tr != null) + { + DisplayFrom = Utility.ToInt32(tr.Text); + } + + tr = info.GetTextEntry(300); // savefilename info + if (tr != null) + { + SaveFilename = tr.Text; + } + + tr = info.GetTextEntry(301); // commandstring info + if (tr != null) + { + CommandString = tr.Text; + } + + + // check all of the check boxes + m_SearchCriteria.Searchagedirection = info.IsSwitched(302); + m_SearchCriteria.Dosearchage = info.IsSwitched(303); + m_SearchCriteria.Dosearchrange = info.IsSwitched(304); + m_SearchCriteria.Dosearchtype = info.IsSwitched(305); + m_SearchCriteria.Dosearchname = info.IsSwitched(306); + m_SearchCriteria.Dosearchspawnentry = info.IsSwitched(307); + m_SearchCriteria.Dosearchspawntype = info.IsSwitched(326); + m_SearchCriteria.Dosearcherr = info.IsSwitched(313); + m_SearchCriteria.Dosearchcondition = info.IsSwitched(315); + + m_SearchCriteria.Dosearchint = info.IsSwitched(312); + m_SearchCriteria.Dosearchfel = info.IsSwitched(308); + m_SearchCriteria.Dosearchtram = info.IsSwitched(309); + m_SearchCriteria.Dosearchmal = info.IsSwitched(310); + m_SearchCriteria.Dosearchilsh = info.IsSwitched(311); + m_SearchCriteria.Dosearchtok = info.IsSwitched(318); + m_SearchCriteria.Dosearchter = info.IsSwitched(320); + m_SearchCriteria.Dosearchnull = info.IsSwitched(314); + + m_SearchCriteria.Dohidevalidint = info.IsSwitched(316); + m_SearchCriteria.Dosearchregion = info.IsSwitched(319); + + switch (info.ButtonID) + { + + case 0: // Close + { + return; + } + case 3: // Search + { + // clear any selection + Selected = -1; + + // reset displayfrom + DisplayFrom = 0; + + // do the search + m_SearchCriteria.Currentloc = state.Mobile.Location; + m_SearchCriteria.Currentmap = state.Mobile.Map; + + //m_SearchList = Search(m_SearchCriteria, out status_str); + XmlFindThread tobj = new XmlFindThread(state.Mobile, m_SearchCriteria, CommandString); + Thread find = new Thread(tobj.XmlFindThreadMain) + { + Name = "XmlFind Thread" + }; + find.Start(); + + // turn on gump extension + m_ShowExtension = true; + return; + } + case 4: // SubSearch + { + // do the search + string status_str; + m_SearchList = Search(m_SearchCriteria, out status_str); + break; + } + case 150: // Open the map gump + { + break; + } + case 154: // Bring all selected objects to the current location + { + Refresh(state); + + state.Mobile.SendGump(new XmlConfirmBringGump(m_SearchList)); + return; + } + case 155: // Return the player to the starting loc + { + m_From.Location = StartingLoc; + m_From.Map = StartingMap; + break; + } + case 156: // Delete selected items + { + Refresh(state); + + state.Mobile.SendGump(new XmlConfirmDeleteGump(m_SearchList)); + return; + } + case 157: // Reset selected items + { + ResetList(); + break; + } + case 158: // Respawn selected items + { + RespawnList(); + break; + } + case 159: // xmlsave selected spawners + { + SaveList(state.Mobile, SaveFilename); + break; + } + case 160: // execute the command on the selected items + { + ExecuteCommand(state.Mobile, CommandString); + break; + } + case 200: // gump extension + { + m_ShowExtension = !m_ShowExtension; + break; + } + case 201: // forward block + { + if (m_SearchList != null && DisplayFrom + MaxEntries < m_SearchList.Count) + { + DisplayFrom += MaxEntries; + // clear any selection + Selected = -1; + } + break; + } + case 202: // backward block + { + + DisplayFrom -= MaxEntries; + if (DisplayFrom < 0) + { + DisplayFrom = 0; + } + + // clear any selection + Selected = -1; + break; + } + + case 700: // Sort + { + // clear any selection + Selected = -1; + + Sorttype = false; + Sortname = false; + Sortrange = false; + Sortmap = false; + Sortselect = false; + // read the toggle switches that determine the sort + if (radiostate == 0) // sort by type + { + Sorttype = true; + } + else + if (radiostate == 1) // sort by name + { + Sortname = true; + } + else + if (radiostate == 2) // sort by range + { + Sortrange = true; + } + else + if (radiostate == 4) // sort by entry + { + Sortmap = true; + } + else + if (radiostate == 5) // sort by selected + { + Sortselect = true; + } + + SortFindList(); + break; + } + case 701: // descending sort + { + Descendingsort = !Descendingsort; + break; + } + case 9998: // refresh the gump + { + // clear any selection + Selected = -1; + break; + } + default: + { + + if (info.ButtonID >= 1000 && info.ButtonID < 1000 + MaxEntries) + { + // flag the entry selected + Selected = info.ButtonID - 1000; + // then go to it + DoGoTo(info.ButtonID - 1000 + DisplayFrom); + } + if (info.ButtonID >= 2000 && info.ButtonID < 2000 + MaxEntries) + { + // flag the entry selected + Selected = info.ButtonID - 2000; + // then open the gump + Refresh(state); + DoShowGump(info.ButtonID - 2000 + DisplayFrom); + return; + } + if (info.ButtonID >= 3000 && info.ButtonID < 3000 + MaxEntries) + { + Selected = info.ButtonID - 3000; + // Show the props window + Refresh(state); + DoShowProps(info.ButtonID - 3000 + DisplayFrom); + return; + } + if (info.ButtonID == 3998) + { + SelectAll = !SelectAll; + + if (m_SearchList != null) + { + foreach (SearchEntry e in m_SearchList) + { + e.Selected = SelectAll; + } + } + } + if (info.ButtonID == 3999) + { + // toggle selection of everything currently displayed + if (m_SearchList != null) + { + for (int i = 0; i < MaxEntries; i++) + { + if (i + DisplayFrom < m_SearchList.Count) + { + SearchEntry e = (SearchEntry)m_SearchList[i + DisplayFrom]; + + e.Selected = !e.Selected; + } + else + { + break; + } + } + } + } + if (info.ButtonID >= 4000 && info.ButtonID < 4000 + MaxEntries) + { + int i = info.ButtonID - 4000; + + if (m_SearchList != null && i >= 0 && m_SearchList.Count > i + DisplayFrom) + { + SearchEntry e = (SearchEntry)m_SearchList[i + DisplayFrom]; + + e.Selected = !e.Selected; + } + } + + break; + } + } + + Refresh(state); + } + + public class XmlConfirmBringGump : Gump + { + private readonly ArrayList SearchList; + + public XmlConfirmBringGump(ArrayList searchlist) + : base(0, 0) + { + SearchList = searchlist; + + Closable = false; + Draggable = true; + AddPage(0); + AddBackground(10, 200, 200, 130, 5054); + int count = 0; + + if (SearchList != null) + { + for (int i = 0; i < SearchList.Count; i++) + { + if (((SearchEntry)SearchList[i]).Selected) + { + count++; + } + } + } + + AddLabel(20, 225, 33, $"Bring {count} objects to you?"); + AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio + AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff); // No + AddButton(80, 289, 2130, 2129, 3); // Okay button + + } + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state?.Mobile == null) + { + return; + } + + int radiostate = -1; + + Point3D myloc = state.Mobile.Location; + Map mymap = state.Mobile.Map; + + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch (info.ButtonID) + { + default: + { + if (radiostate == 1 && SearchList != null) + { // accept + for (int i = 0; i < SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is Item item) + { + + item.MoveToWorld(myloc, mymap); + + } + else if (o is Mobile mobile) + { + + mobile.MoveToWorld(myloc, mymap); + + } + } + } + } + break; + } + } + } + } + + public class XmlConfirmDeleteGump : Gump + { + private readonly ArrayList SearchList; + + public XmlConfirmDeleteGump(ArrayList searchlist) + : base(0, 0) + { + SearchList = searchlist; + + Closable = false; + Draggable = true; + AddPage(0); + AddBackground(10, 200, 200, 130, 5054); + int count = 0; + + if (SearchList != null) + { + for (int i = 0; i < SearchList.Count; i++) + { + if (((SearchEntry)SearchList[i]).Selected) + { + count++; + } + } + } + + AddLabel(20, 225, 33, $"Delete {count} objects?"); + AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio + AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio + AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff); // Yes + AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff); // No + AddButton(80, 289, 2130, 2129, 3); // Okay button + + } + public override void OnResponse(NetState state, RelayInfo info) + { + if (info == null || state?.Mobile == null) + { + return; + } + + int radiostate = -1; + if (info.Switches.Length > 0) + { + radiostate = info.Switches[0]; + } + switch (info.ButtonID) + { + + default: + { + if (radiostate == 1 && SearchList != null) + { // accept + for (int i = 0; i < SearchList.Count; i++) + { + SearchEntry e = (SearchEntry)SearchList[i]; + + if (e.Selected) + { + object o = e.Object; + + if (o is Item item) + { + // some objects may not delete gracefully (null map items are particularly error prone) so trap them + try + { + item.Delete(); + } + catch (Exception ex) { Diagnostics.ExceptionLogging.LogException(ex); } + } + else if (o is Mobile mobile && !mobile.Player) + { + try + { + mobile.Delete(); + } + catch (Exception ex) { Diagnostics.ExceptionLogging.LogException(ex); } + } + } + } + } + + break; + } + } + } + } +} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlPartialCategorizedAddGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlPartialCategorizedAddGump.cs new file mode 100644 index 000000000..00de759ff --- /dev/null +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlPartialCategorizedAddGump.cs @@ -0,0 +1,266 @@ +using Server.Mobiles; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace Server.Gumps; + +public class XmlPartialCategorizedAddGump : Gump +{ + private readonly string m_SearchString; + private readonly ArrayList m_SearchResults; + private readonly int m_Page; + private readonly Gump m_Gump; + private readonly int m_EntryIndex; + private readonly XmlSpawner m_Spawner; + + public XmlPartialCategorizedAddGump(Mobile from, string searchString, int page, ArrayList searchResults, bool explicitSearch, int entryindex, Gump gump) : base(50, 50) + { + if (gump is XmlSpawnerGump spawnerGump) + { + // keep track of the spawner for xmlspawnergumps + m_Spawner = spawnerGump.m_Spawner; + } + + // keep track of the gump + m_Gump = gump; + + + m_SearchString = searchString; + m_SearchResults = searchResults; + m_Page = page; + + m_EntryIndex = entryindex; + + from.CloseGump(); + + AddPage(0); + + AddBackground(0, 0, 420, 280, 5054); + + AddImageTiled(10, 10, 400, 20, 2624); + AddAlphaRegion(10, 10, 400, 20); + AddImageTiled(41, 11, 184, 18, 0xBBC); + AddImageTiled(42, 12, 182, 16, 2624); + AddAlphaRegion(42, 12, 182, 16); + + AddButton(10, 9, 4011, 4013, 1); + AddTextEntry(44, 10, 180, 20, 0x480, 0, searchString); + + AddHtmlLocalized(230, 10, 100, 20, 3010005, 0x7FFF); + + AddImageTiled(10, 40, 400, 200, 2624); + AddAlphaRegion(10, 40, 400, 200); + + if (searchResults.Count > 0) + { + for (int i = page * 10; i < (page + 1) * 10 && i < searchResults.Count; ++i) + { + int index = i % 10; + + SearchEntry se = (SearchEntry)searchResults[i]; + + string labelstr = se.EntryType.Name; + + if (se.Parameters.Length > 0) + { + for (int j = 0; j < se.Parameters.Length; j++) + { + labelstr += $", {se.Parameters[j].Name}"; + } + } + + AddLabel(44, 39 + index * 20, 0x480, labelstr); + AddButton(10, 39 + index * 20, 4023, 4025, 4 + i); + } + } + else + { + AddLabel(15, 44, 0x480, explicitSearch ? "Nothing matched your search terms." : "No results to display."); + } + + AddImageTiled(10, 250, 400, 20, 2624); + AddAlphaRegion(10, 250, 400, 20); + + if (m_Page > 0) + { + AddButton(10, 249, 4014, 4016, 2); + } + else + { + AddImage(10, 249, 4014); + } + + AddHtmlLocalized(44, 250, 170, 20, 1061028, m_Page > 0 ? 0x7FFF : 0x5EF7); // Previous page + + if ((m_Page + 1) * 10 < searchResults.Count) + { + AddButton(210, 249, 4005, 4007, 3); + } + else + { + AddImage(210, 249, 4005); + } + + AddHtmlLocalized(244, 250, 170, 20, 1061027, (m_Page + 1) * 10 < searchResults.Count ? 0x7FFF : 0x5EF7); // Next page + } + + private static readonly Type typeofItem = typeof(Item), typeofMobile = typeof(Mobile); + + private class SearchEntry + { + public Type EntryType; + public ParameterInfo[] Parameters; + } + private static void Match(string match, IReadOnlyList types, IList results) + { + if (match.Length == 0) + { + return; + } + + match = match.ToLower(); + + for (int i = 0; i < types.Count; ++i) + { + Type t = types[i]; + + if ((typeofMobile.IsAssignableFrom(t) || typeofItem.IsAssignableFrom(t)) && t.Name.ToLower().IndexOf(match) >= 0 && !results.Contains(t)) + { + ConstructorInfo[] ctors = t.GetConstructors(); + + for (int j = 0; j < ctors.Length; ++j) + { + if (/*ctors[j].GetParameters().Length == 0 && */ ctors[j].IsDefined(typeof(ConstructibleAttribute), false)) + { + SearchEntry s = new SearchEntry + { + EntryType = t, + Parameters = ctors[j].GetParameters() + }; + //results.Add(t); + results.Add(s); + //break; + } + } + } + } + } + + public static ArrayList Match(string match) + { + ArrayList results = new ArrayList(); + Type[] types; + + Assembly[] asms = AssemblyHandler.Assemblies; + + for (int i = 0; i < asms.Length; ++i) + { + types = AssemblyHandler.GetTypeCache(asms[i]).Types; + Match(match, types, results); + } + + types = AssemblyHandler.GetTypeCache(Core.Assembly).Types; + Match(match, types, results); + + results.Sort(new TypeNameComparer()); + + return results; + } + + private class TypeNameComparer : IComparer + { + public int Compare(object x, object y) + { + SearchEntry a = x as SearchEntry; + SearchEntry b = y as SearchEntry; + + return a.EntryType.Name.CompareTo(b.EntryType.Name); + } + } + + + public override void OnResponse(Network.NetState sender, RelayInfo info) + { + Mobile from = sender.Mobile; + + switch (info.ButtonID) + { + case 1: // Search + { + TextRelay te = info.GetTextEntry(0); + string match = te == null ? "" : te.Text.Trim(); + + if (match.Length < 3) + { + from.SendMessage("Invalid search string."); + from.SendGump(new XmlPartialCategorizedAddGump(from, match, m_Page, m_SearchResults, false, m_EntryIndex, m_Gump)); + } + else + { + from.SendGump(new XmlPartialCategorizedAddGump(from, match, 0, Match(match), true, m_EntryIndex, m_Gump)); + } + + break; + } + case 2: // Previous page + { + if (m_Page > 0) + { + from.SendGump(new XmlPartialCategorizedAddGump(from, m_SearchString, m_Page - 1, m_SearchResults, true, m_EntryIndex, m_Gump)); + } + + break; + } + case 3: // Next page + { + if ((m_Page + 1) * 10 < m_SearchResults.Count) + { + from.SendGump(new XmlPartialCategorizedAddGump(from, m_SearchString, m_Page + 1, m_SearchResults, true, m_EntryIndex, m_Gump)); + } + + break; + } + default: + { + int index = info.ButtonID - 4; + + if (index >= 0 && index < m_SearchResults.Count) + { + Type type = ((SearchEntry)m_SearchResults[index]).EntryType; + + if (m_Gump is XmlAddGump mXmlAddGump && type != null) + { + if (mXmlAddGump.defs?.NameList != null && m_EntryIndex >= 0 && m_EntryIndex < mXmlAddGump.defs.NameList.Length) + { + mXmlAddGump.defs.NameList[m_EntryIndex] = type.Name; + XmlAddGump.Refresh(from, true); + } + } + else if (m_Spawner != null && type != null) + { + XmlSpawnerGump xg = m_Spawner.SpawnerGump; + + if (xg != null) + { + + xg.Rentry = new XmlSpawnerGump.ReplacementEntry + { + Typename = type.Name, + Index = m_EntryIndex, + Color = 0x1436 + }; + + Timer.DelayCall(TimeSpan.Zero, XmlSpawnerGump.RefreshSpawnerGumps, from); + //from.CloseGump(); + //from.SendGump(new XmlSpawnerGump(xg.m_Spawner, xg.X, xg.Y, xg.m_ShowGump, xg.xoffset, xg.page, xg.Rentry)); + } + } + } + + break; + } + } + } +} From d984df1c16ec3a42b4a63406c35823935673299b Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:34:48 -0700 Subject: [PATCH 2/8] Fixes SendMessages --- Projects/Server/Main.cs | 4 +- .../Serialization/GenericEntityPersistence.cs | 2 +- .../Server/Serialization/IGenericReader.cs | 2 +- .../Server/Serialization/IGenericWriter.cs | 2 +- Projects/Server/World/EntityPersistence.cs | 2 +- .../Engines/XMLSpawner/BaseXmlSpawner.cs | 202 +-- .../UOContent/Engines/XMLSpawner/ItemFlags.cs | 4 +- .../Engines/XMLSpawner/SpawnerExporter.cs | 4 +- .../XMLSpawner/XmlPropsGumps/XmlPropsGump.cs | 10 +- .../XmlPropsGumps/XmlSetObjectGump.cs | 2 +- .../XmlPropsGumps/XmlSetObjectTarget.cs | 2 +- .../Engines/XMLSpawner/XmlSpawner.cs | 512 +++--- .../Engines/XMLSpawner/XmlSpawnerGumps.cs | 21 +- .../XMLSpawner/XmlSpawnerSkillCheck.cs | 22 +- .../Engines/XMLSpawner/XmlUtils/WriteMulti.cs | 35 +- .../Engines/XMLSpawner/XmlUtils/XmlAdd.cs | 12 +- .../Engines/XMLSpawner/XmlUtils/XmlEdit.cs | 1420 ----------------- .../Engines/XMLSpawner/XmlUtils/XmlFind.cs | 13 +- 18 files changed, 309 insertions(+), 1962 deletions(-) delete mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlEdit.cs diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index d17c45108..43fa92fae 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -164,7 +164,7 @@ public static class Core { // See notes above for _now and why this is a volatile variable. var now = _now; - return now == DateTime.MinValue ? DateTime.UtcNow : now; + return now == DateTime.MinValue ? Core.Now : now; } } @@ -557,7 +557,7 @@ public static class Core while (!Closing) { _tickCount = TickCount; - _now = DateTime.UtcNow; + _now = Core.Now; Mobile.ProcessDeltaQueue(); Item.ProcessDeltaQueue(); diff --git a/Projects/Server/Serialization/GenericEntityPersistence.cs b/Projects/Server/Serialization/GenericEntityPersistence.cs index 49e53979a..005838b51 100644 --- a/Projects/Server/Serialization/GenericEntityPersistence.cs +++ b/Projects/Server/Serialization/GenericEntityPersistence.cs @@ -255,7 +255,7 @@ public class GenericEntityPersistence : Persistence, IGenericEntityPersistenc try { using var op = new StreamWriter("world-save-errors.log", true); - op.WriteLine("{0}\t{1}", DateTime.UtcNow, message); + op.WriteLine("{0}\t{1}", Core.Now, message); op.WriteLine(new StackTrace(2).ToString()); op.WriteLine(); } diff --git a/Projects/Server/Serialization/IGenericReader.cs b/Projects/Server/Serialization/IGenericReader.cs index 31f5c4a7e..815b9f54c 100644 --- a/Projects/Server/Serialization/IGenericReader.cs +++ b/Projects/Server/Serialization/IGenericReader.cs @@ -51,7 +51,7 @@ public interface IGenericReader { long.MinValue => DateTime.MinValue, long.MaxValue => DateTime.MaxValue, - var delta => new DateTime(delta + DateTime.UtcNow.Ticks, DateTimeKind.Utc) + var delta => new DateTime(delta + Core.Now.Ticks, DateTimeKind.Utc) }; } decimal ReadDecimal() => new(stackalloc int[4] { ReadInt(), ReadInt(), ReadInt(), ReadInt() }); diff --git a/Projects/Server/Serialization/IGenericWriter.cs b/Projects/Server/Serialization/IGenericWriter.cs index 6595cb0fa..d512996da 100644 --- a/Projects/Server/Serialization/IGenericWriter.cs +++ b/Projects/Server/Serialization/IGenericWriter.cs @@ -70,7 +70,7 @@ public interface IGenericWriter } // Technically supports negative deltas for times in the past - Write(value.Ticks - DateTime.UtcNow.Ticks); + Write(value.Ticks - Core.Now.Ticks); } void Write(IPAddress value) { diff --git a/Projects/Server/World/EntityPersistence.cs b/Projects/Server/World/EntityPersistence.cs index 8564f0bd0..25e9fe16b 100644 --- a/Projects/Server/World/EntityPersistence.cs +++ b/Projects/Server/World/EntityPersistence.cs @@ -119,7 +119,7 @@ public static class EntityPersistence return map; } - var now = DateTime.UtcNow; + var now = Core.Now; for (int i = 0; i < count; ++i) { diff --git a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs index 9866f8f57..e7a33b48e 100644 --- a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs @@ -28,11 +28,8 @@ public class BaseXmlSpawner } private static readonly Type typeofTimeSpan = typeof(TimeSpan); - private static readonly Type typeofParsable = typeof(ParsableAttribute); private static readonly Type typeofCustomEnum = typeof(CustomEnumAttribute); - private static bool IsParsable(Type t) => t == typeofTimeSpan || t.IsDefined(typeofParsable, false); - private static readonly Type[] m_ParseTypes = { typeof(string) }; private static readonly object[] m_ParseParams = new object[1]; @@ -204,7 +201,7 @@ public class BaseXmlSpawner Type = type; m_Delay = delay; m_Timeout = timeout; - m_TimeoutEnd = DateTime.UtcNow + timeout; + m_TimeoutEnd = Core.Now + timeout; m_Spawner = spawner; m_Condition = condition; m_Goto = gotogroup; @@ -280,7 +277,7 @@ public class BaseXmlSpawner private void DoTimer(TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup) { - m_End = DateTime.UtcNow + delay; + m_End = Core.Now + delay; if (m_Timer != null) { @@ -303,11 +300,11 @@ public class BaseXmlSpawner if (Type == 0) { // save any timer information - writer.Write(m_End - DateTime.UtcNow); + writer.Write(m_End - Core.Now); writer.Write(m_Delay); writer.Write(m_Condition); writer.Write(m_Goto); - writer.Write(m_TimeoutEnd - DateTime.UtcNow); + writer.Write(m_TimeoutEnd - Core.Now); writer.Write(m_Timeout); writer.Write(m_TrigMob); } @@ -337,7 +334,7 @@ public class BaseXmlSpawner m_Goto = reader.ReadInt(); TimeSpan timeoutdelay = reader.ReadTimeSpan(); - m_TimeoutEnd = DateTime.UtcNow + timeoutdelay; + m_TimeoutEnd = Core.Now + timeoutdelay; m_Timeout = reader.ReadTimeSpan(); m_TrigMob = reader.ReadEntity(); @@ -373,9 +370,8 @@ public class BaseXmlSpawner if (!string.IsNullOrEmpty(m_Condition) && m_Spawner != null && m_Spawner.Running) { // if the test is valid then terminate the timer - string status_str; - if (TestItemProperty(m_Spawner, m_Spawner, m_Condition, out status_str)) + if (TestItemProperty(m_Spawner, m_Spawner, m_Condition, out _)) { // spawn the designated subgroup if specified if (m_Goto >= 0 && m_Spawner != null && !m_Spawner.Deleted) @@ -403,7 +399,7 @@ public class BaseXmlSpawner if (m_Tag != null && !m_Tag.Deleted) { // check the timeout if applicable - if (m_Tag.m_Timeout > TimeSpan.Zero && m_Tag.m_TimeoutEnd < DateTime.UtcNow) + if (m_Tag.m_Timeout > TimeSpan.Zero && m_Tag.m_TimeoutEnd < Core.Now) { // release the hold on spawning and delete the tag m_Tag.Delete(); @@ -578,17 +574,6 @@ public class BaseXmlSpawner 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; @@ -2553,11 +2538,6 @@ public class BaseXmlSpawner } catch { } } - // try to find the attachment on the mob - if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) - { - return true; - } return false; } @@ -2603,87 +2583,13 @@ public class BaseXmlSpawner // 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 token) + // is the equippedonly flag set? If so then see if the item is equipped + if (equippedonly && testitem.Parent == m || !equippedonly) { - 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++) - { - try - { - switch (int.Parse(objstr[n]) - 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; - } - } - } - catch { } - } - } - 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; - } + has_valid_item = true; } } + return has_valid_item; } public static bool CheckForNotCarried(Mobile m, string objectivestr) @@ -2767,12 +2673,6 @@ public class BaseXmlSpawner catch { } } - // try to find the attachment on the mob - if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) - { - return false; - } - return true; } @@ -2818,81 +2718,10 @@ public class BaseXmlSpawner // 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 token && token.IsValid) + // is the equippedonly flag set? If so then see if the item is equipped + if (equippedonly && testitem.Parent == m || !equippedonly) { - 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++) - { - try - { - switch (int.Parse(objstr[n]) - 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; - } - } - } - catch { } - } - } - 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; - } + has_no_such_item = false; } } return has_no_such_item; @@ -3296,9 +3125,8 @@ public class BaseXmlSpawner string keypart = remaining.Substring(startindex + 1, endindex); // try to evaluate and then substitute the arg - Type ptype; - string value = ParseForKeywords(spawner, o, keypart.Trim(), true, out ptype); + string value = ParseForKeywords(spawner, o, keypart.Trim(), true, out _); // trim off the " from strings if (value != null) diff --git a/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs b/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs index ce893bfcf..0ed76c387 100644 --- a/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs +++ b/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs @@ -64,7 +64,7 @@ public partial class ItemFlags { bool state = item.GetSavedFlag(m_flag); - from.SendMessage("Flag (0x{0:X}) = {1}",m_flag,state); + from.SendMessage($"Flag (0x{m_flag:X}) = {state}"); } else { from.SendMessage("Must target an Item"); @@ -123,7 +123,7 @@ public partial class ItemFlags bool state = GetStealable(item); - from.SendMessage("Stealable = {0}",state); + from.SendMessage($"Stealable = {state}"); } else { diff --git a/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs b/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs index d5fa8d955..d8df61e43 100644 --- a/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs +++ b/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs @@ -206,11 +206,11 @@ public class SpawnerExporter } } - e.Mobile.SendMessage("{0} spawners loaded successfully from {1}, {2} failures.", successes, filePath, failures); + e.Mobile.SendMessage($"{successes} spawners loaded successfully from {filePath}, {failures} failures."); } else { - e.Mobile.SendMessage("File {0} does not exist.", filePath); + e.Mobile.SendMessage($"File {filePath} does not exist."); } } else diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs index 29e451244..053386ae3 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs @@ -608,10 +608,10 @@ public class XmlPropertiesGump : Gump { if (t == typeof(ulong) || t == typeof(uint) || t == typeof(ushort) || t == typeof(byte)) { - return Convert.ChangeType(Convert.ToUInt64(s.Substring(2), 16), t); + return Convert.ChangeType(Convert.ToUInt64(s[2..], 16), t); } - return Convert.ChangeType(Convert.ToInt64(s.Substring(2), 16), t); + return Convert.ChangeType(Convert.ToInt64(s[2..], 16), t); } return Convert.ChangeType(s, t); @@ -621,12 +621,6 @@ public class XmlPropertiesGump : Gump { return Convert.ChangeType(s, t); } - if (t.IsDefined(typeof(ParsableAttribute), false)) - { - MethodInfo parseMethod = t.GetMethod("Parse", new[] { typeof(string) }); - - return parseMethod.Invoke(null, new object[] { s }); - } throw new Exception("bad"); } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs index d0230e414..b69949db6 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs @@ -181,7 +181,7 @@ public class XmlSetObjectGump : Gump { toSet = null; shouldSet = false; - m_Mobile.SendMessage("The object with that serial could not be assigned to a property of type : {0}", m_Type.Name); + m_Mobile.SendMessage($"The object with that serial could not be assigned to a property of type : {m_Type.Name}"); } else { diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectTarget.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectTarget.cs index 9c6393b40..303c03d69 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectTarget.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectTarget.cs @@ -49,7 +49,7 @@ public class XmlSetObjectTarget : Target } else { - m_Mobile.SendMessage("That cannot be assigned to a property of type : {0}", m_Type.Name); + m_Mobile.SendMessage($"That cannot be assigned to a property of type : {m_Type.Name}"); } } catch diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs index abb16a41c..d0c629154 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs @@ -231,11 +231,11 @@ public class XmlSpawner : Item, ISpawner // is not counted in the normal item count public override bool IsVirtualItem => true; - private bool m_skillTriggerActivated; - private SkillName m_SkillTriggerName; - private double m_SkillTriggerMin; - private double m_SkillTriggerMax; - private int m_SkillTriggerSuccess; + // private bool m_skillTriggerActivated; + // private SkillName m_SkillTriggerName; + // private double m_SkillTriggerMin; + // private double m_SkillTriggerMax; + // private int m_SkillTriggerSuccess; public bool DebugThis { get; set; } = false; @@ -279,17 +279,17 @@ public class XmlSpawner : Item, ISpawner int minutes; Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); - return new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0).TimeOfDay; + return new DateTime(Core.Now.Year, Core.Now.Month, Core.Now.Day, hours, minutes, 0).TimeOfDay; } } - public TimeSpan RealTOD => DateTime.UtcNow.TimeOfDay; + public TimeSpan RealTOD => Core.Now.TimeOfDay; - public int RealDay => DateTime.UtcNow.Day; + public int RealDay => Core.Now.Day; - public int RealMonth => DateTime.UtcNow.Month; + public int RealMonth => Core.Now.Month; - public DayOfWeek RealDayOfWeek => DateTime.UtcNow.DayOfWeek; + public DayOfWeek RealDayOfWeek => Core.Now.DayOfWeek; public MoonPhase MoonPhase => Clock.GetMoonPhase(Map, Location.X, Location.Y); @@ -532,7 +532,7 @@ public class XmlSpawner : Item, ISpawner using (StreamWriter op = new StreamWriter("badspawn.log", true)) { - op.WriteLine("{0} SmartSpawning disabled at {1} {2} : Range too large.", DateTime.UtcNow, loc, Map); + op.WriteLine("{0} SmartSpawning disabled at {1} {2} : Range too large.", Core.Now, loc, Map); op.WriteLine(); } } @@ -656,7 +656,7 @@ public class XmlSpawner : Item, ISpawner } else { - status_str = string.Format("{0} is not a valid type name.", str); + status_str = $"{str} is not a valid type name."; } } InvalidateProperties(); @@ -1304,7 +1304,7 @@ public class XmlSpawner : Item, ISpawner { if (m_refractActivated) { - return m_RefractEnd - DateTime.UtcNow; + return m_RefractEnd - Core.Now; } return TimeSpan.FromSeconds(0); @@ -1402,10 +1402,10 @@ public class XmlSpawner : Item, ISpawner int hours; int minutes; Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); - return new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0).TimeOfDay; + return new DateTime(Core.Now.Year, Core.Now.Month, Core.Now.Day, hours, minutes, 0).TimeOfDay; } - return DateTime.UtcNow.TimeOfDay; + return Core.Now.TimeOfDay; } } @@ -1434,12 +1434,12 @@ public class XmlSpawner : Item, ISpawner int hours; int minutes; Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); - now = new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day, hours, minutes, 0); + now = new DateTime(Core.Now.Year, Core.Now.Month, Core.Now.Day, hours, minutes, 0); } else { // calculate the time window - now = DateTime.UtcNow; + now = Core.Now; } var day_start = new DateTime(now.Year, now.Month, now.Day); // calculate the starting TOD window by adding the TODStart to day_start @@ -1491,7 +1491,7 @@ public class XmlSpawner : Item, ISpawner { if (m_durActivated) { - return m_DurEnd - DateTime.UtcNow; + return m_DurEnd - Core.Now; } return TimeSpan.FromSeconds(0); @@ -1565,7 +1565,7 @@ public class XmlSpawner : Item, ISpawner { if (m_Running) { - return m_End - DateTime.UtcNow; + return m_End - Core.Now; } return TimeSpan.FromSeconds(0); @@ -1610,14 +1610,14 @@ public class XmlSpawner : Item, ISpawner { get { - if (m_Running && m_SeqEnd - DateTime.UtcNow > TimeSpan.Zero) + if (m_Running && m_SeqEnd - Core.Now > TimeSpan.Zero) { - return m_SeqEnd - DateTime.UtcNow; + return m_SeqEnd - Core.Now; } return TimeSpan.FromSeconds(0); } - set => m_SeqEnd = DateTime.UtcNow + value; + set => m_SeqEnd = Core.Now + value; } [CommandProperty(AccessLevel.GameMaster)] @@ -2149,7 +2149,7 @@ public class XmlSpawner : Item, ISpawner if (fs == null) { - status_str = string.Format("Unable to open {0} for loading", filename); + status_str = $"Unable to open {filename} for loading"; return; } @@ -2558,14 +2558,14 @@ public class XmlSpawner : Item, ISpawner public static TimeSpan[] _traceTotal = new TimeSpan[MaxTraces]; public static string[] _traceName = new string[MaxTraces]; public static int[] _traceCount = new int[MaxTraces]; - private static DateTime _traceStartTime = DateTime.UtcNow; + private static DateTime _traceStartTime = Core.Now; private static double _startProcessTime; public static void _TraceStart(int index) { if (index < MaxTraces) { - _traceStart[index] = DateTime.UtcNow; + _traceStart[index] = Core.Now; //_traceStart[index] = Process.GetCurrentProcess().UserProcessorTime; } } @@ -2573,7 +2573,7 @@ public class XmlSpawner : Item, ISpawner { if (index < MaxTraces) { - _traceTotal[index] = _traceTotal[index].Add(DateTime.UtcNow - _traceStart[index]); + _traceTotal[index] = _traceTotal[index].Add(Core.Now - _traceStart[index]); //XmlSpawner._traceTotal[index] = XmlSpawner._traceTotal[index].Add(Process.GetCurrentProcess().UserProcessorTime - _traceStart[index]); _traceCount[index]++; } @@ -2725,19 +2725,19 @@ public class XmlSpawner : Item, ISpawner return; } - m_skillTriggerActivated = false; + // m_skillTriggerActivated = false; // check the skill trigger conditions, Skillname[+/-][,min,max] - if (m_SkillTrigger != null && skill.SkillName == m_SkillTriggerName && - (m_SkillTriggerMin < 0 || skill.Value >= m_SkillTriggerMin) && - (m_SkillTriggerMax < 0 || skill.Value <= m_SkillTriggerMax) && - (m_SkillTriggerSuccess == 3 || m_SkillTriggerSuccess == 1 && success || m_SkillTriggerSuccess == 2 && !success)) - { - // have a skill trigger so flag it and test it - m_skillTriggerActivated = true; - - CheckTriggers(m, skill, true); - } + // if (m_SkillTrigger != null && skill.SkillName == m_SkillTriggerName && + // (m_SkillTriggerMin < 0 || skill.Value >= m_SkillTriggerMin) && + // (m_SkillTriggerMax < 0 || skill.Value <= m_SkillTriggerMax) && + // (m_SkillTriggerSuccess == 3 || m_SkillTriggerSuccess == 1 && success || m_SkillTriggerSuccess == 2 && !success)) + // { + // // have a skill trigger so flag it and test it + // m_skillTriggerActivated = true; + // + // CheckTriggers(m, skill, true); + // } } } public override bool HandlesOnSpeech => m_Running && !string.IsNullOrEmpty(m_SpeechTrigger); @@ -3326,7 +3326,7 @@ public class XmlSpawner : Item, ISpawner { return; } - from.SendMessage("{0}", result); + from.SendMessage($"{result}"); } } @@ -3448,7 +3448,7 @@ public class XmlSpawner : Item, ISpawner if (o == targeted) { - from.SendMessage("{0}, {1}, {2}", spawner.X, spawner.Y, spawner.Z); + from.SendMessage($"{spawner.Location}"); if (m_e.GetString(0) == "go") { @@ -3581,7 +3581,7 @@ public class XmlSpawner : Item, ISpawner xml.Close(); } - m.SendMessage("defaults saved to {0}", filePath); + m.SendMessage($"defaults saved to {filePath}"); } public static void XmlLoadDefaults(string filePath, Mobile m) @@ -3601,11 +3601,11 @@ public class XmlSpawner : Item, ISpawner XmlElement root = doc["XmlDefaults"]; LoadDefaults(root); - m.SendMessage("defaults loaded successfully from {0}", filePath); + m.SendMessage($"defaults loaded successfully from {filePath}"); } else { - m.SendMessage("File {0} does not exist.", filePath); + m.SendMessage($"File {filePath} does not exist."); } } } @@ -3742,126 +3742,126 @@ public class XmlSpawner : Item, ISpawner try { defMaxDelay = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); - m.SendMessage("MaxDelay = {0}", defMaxDelay); + m.SendMessage($"MaxDelay = {defMaxDelay}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "mindelay") { try { defMinDelay = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); - m.SendMessage("MinDelay = {0}", defMinDelay); + m.SendMessage($"MinDelay = {defMinDelay}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "spawnrange") { try { defSpawnRange = Convert.ToInt32(e.Arguments[1]); - m.SendMessage("SpawnRange = {0}", defSpawnRange); + m.SendMessage($"SpawnRange = {defSpawnRange}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "homerange") { try { defHomeRange = Convert.ToInt32(e.Arguments[1]); - m.SendMessage("HomeRange = {0}", defHomeRange); + m.SendMessage($"HomeRange = {defHomeRange}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "relativehome") { try { defRelativeHome = Convert.ToBoolean(e.Arguments[1]); - m.SendMessage("RelativeHome = {0}", defRelativeHome); + m.SendMessage($"RelativeHome = {defRelativeHome}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "proximitytriggersound") { try { defProximityTriggerSound = Convert.ToInt32(e.Arguments[1]); - m.SendMessage("ProximityTriggerSound = {0}", defProximityTriggerSound); + m.SendMessage($"ProximityTriggerSound = {defProximityTriggerSound}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "proximityrange") { try { defProximityRange = Convert.ToInt32(e.Arguments[1]); - m.SendMessage("ProximityRange = {0}", defProximityRange); + m.SendMessage($"ProximityRange = {defProximityRange}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "triggerprobability") { try { defTriggerProbability = Convert.ToDouble(e.Arguments[1]); - m.SendMessage("TriggerProbability = {0}", defTriggerProbability); + m.SendMessage($"TriggerProbability = {defTriggerProbability}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "todstart") { try { defTODStart = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); - m.SendMessage("TODStart = {0}", defTODStart); + m.SendMessage($"TODStart = {defTODStart}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "todend") { try { defTODEnd = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); - m.SendMessage("TODEnd = {0}", defTODEnd); + m.SendMessage($"TODEnd = {defTODEnd}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "stackamount") { try { defAmount = Convert.ToInt32(e.Arguments[1]); - m.SendMessage("StackAmount = {0}", defAmount); + m.SendMessage($"StackAmount = {defAmount}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "duration") { try { defDuration = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); - m.SendMessage("Duration = {0}", defDuration); + m.SendMessage($"Duration = {defDuration}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "group") { try { defIsGroup = Convert.ToBoolean(e.Arguments[1]); - m.SendMessage("Group = {0}", defIsGroup); + m.SendMessage($"Group = {defIsGroup}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "team") { try { defTeam = Convert.ToInt32(e.Arguments[1]); - m.SendMessage("Team = {0}", defTeam); + m.SendMessage($"Team = {defTeam}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "todmode") { @@ -3881,31 +3881,31 @@ public class XmlSpawner : Item, ISpawner break; } } - m.SendMessage("TODMode = {0}", defTODMode); + m.SendMessage($"TODMode = {defTODMode}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "maxrefractory") { try { defMaxRefractory = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); - m.SendMessage("MaxRefractory = {0}", defMaxRefractory); + m.SendMessage($"MaxRefractory = {defMaxRefractory}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else if (e.Arguments[0].ToLower() == "minrefractory") { try { defMinRefractory = TimeSpan.FromMinutes(Convert.ToDouble(e.Arguments[1])); - m.SendMessage("MinRefractory = {0}", defMinRefractory); + m.SendMessage($"MinRefractory = {defMinRefractory}"); } - catch { m.SendMessage("invalid value : {0}", e.Arguments[1]); } + catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } } else { - m.SendMessage("{0} : no such default value.", e.Arguments[0]); + m.SendMessage($"{e.Arguments[0]} : no such default value."); } } @@ -3913,23 +3913,23 @@ public class XmlSpawner : Item, ISpawner else { // just display the values - m.SendMessage("TriggerProbability = {0}", defTriggerProbability); - m.SendMessage("ProximityRange = {0}", defProximityRange); - m.SendMessage("ProximityTriggerSound = {0}", defProximityTriggerSound); - m.SendMessage("MinRefractory = {0}", defMinRefractory); - m.SendMessage("MaxRefractory = {0}", defMaxRefractory); - m.SendMessage("TODStart = {0}", defTODStart); - m.SendMessage("TODEnd = {0}", defTODEnd); - m.SendMessage("TODMode = {0}", defTODMode); - m.SendMessage("StackAmount = {0}", defAmount); - m.SendMessage("Duration = {0}", defDuration); - m.SendMessage("Group = {0}", defIsGroup); - m.SendMessage("Team = {0}", defTeam); - m.SendMessage("RelativeHome = {0}", defRelativeHome); - m.SendMessage("SpawnRange = {0}", defSpawnRange); - m.SendMessage("HomeRange = {0}", defHomeRange); - m.SendMessage("MinDelay = {0}", defMinDelay); - m.SendMessage("MaxDelay = {0}", defMaxDelay); + m.SendMessage($"TriggerProbability = {defTriggerProbability}"); + m.SendMessage($"ProximityRange = {defProximityRange}"); + m.SendMessage($"ProximityTriggerSound = {defProximityTriggerSound}"); + m.SendMessage($"MinRefractory = {defMinRefractory}"); + m.SendMessage($"MaxRefractory = {defMaxRefractory}"); + m.SendMessage($"TODStart = {defTODStart}"); + m.SendMessage($"TODEnd = {defTODEnd}"); + m.SendMessage($"TODMode = {defTODMode}"); + m.SendMessage($"StackAmount = {defAmount}"); + m.SendMessage($"Duration = {defDuration}"); + m.SendMessage($"Group = {defIsGroup}"); + m.SendMessage($"Team = {defTeam}"); + m.SendMessage($"RelativeHome = {defRelativeHome}"); + m.SendMessage($"SpawnRange = {defSpawnRange}"); + m.SendMessage($"HomeRange = {defHomeRange}"); + m.SendMessage($"MinDelay = {defMinDelay}"); + m.SendMessage($"MaxDelay = {defMaxDelay}"); } } @@ -4054,7 +4054,7 @@ public class XmlSpawner : Item, ISpawner } else { - from.SendMessage("Map '{0}' does not exist!", MapName); + from.SendMessage($"Map '{MapName}' does not exist!"); return; } @@ -4157,21 +4157,18 @@ public class XmlSpawner : Item, ISpawner maxpercent = 100 * maxcount / totalcount; } - e.Mobile.SendMessage( - "Smartspawning access level is {10}\n" + - "--------------------------------\n" + - "{0} XmlSpawners\n" + - "{1} are configured for SmartSpawning\n" + - "{2} are currently inactivated\n" + - "{9} sectors being monitored\n" + - "Maximum possible spawn count is {3}\n" + - "Maximum possible spawn reduction is {4}\n" + - "Current spawn count is {5}\n" + - "Current spawn reduction is {6}\n" + - "Maximum possible savings is {7}%\n" + - "Current savings is {8}%", - count, smartcount, inactivecount, totalcount, maxcount, currentcount, savings, maxpercent, - percent, totalSectorsMonitored, SmartSpawnAccessLevel); + e.Mobile.SendMessage($"Smartspawning access level is {SmartSpawnAccessLevel}"); + e.Mobile.SendMessage($"--------------------------------"); + e.Mobile.SendMessage($"{count} XmlSpawners"); + e.Mobile.SendMessage($"{smartcount} are configured for SmartSpawning\n"); + e.Mobile.SendMessage($"{inactivecount} are currently inactivated"); + e.Mobile.SendMessage($"{totalSectorsMonitored} sectors being monitored\n"); + e.Mobile.SendMessage($"Maximum possible spawn count is {totalcount}"); + e.Mobile.SendMessage($"Maximum possible spawn reduction is {maxcount}\n"); + e.Mobile.SendMessage($"Current spawn count is {currentcount}"); + e.Mobile.SendMessage($"Current spawn reduction is {savings}"); + e.Mobile.SendMessage($"Maximum possible savings is {maxpercent}%"); + e.Mobile.SendMessage($"Current savings is {percent}%"); } [Usage("OptimalSmartSpawning [max spawn/homerange diff]")] @@ -4268,8 +4265,8 @@ public class XmlSpawner : Item, ISpawner } } - e.Mobile.SendMessage("Configured {0} XmlSpawners for SmartSpawning using maxdiff of {1}", count, maxdiff); - e.Mobile.SendMessage("Estimated item/mob reduction is {0}", maxcount); + e.Mobile.SendMessage($"Configured {count} XmlSpawners for SmartSpawning using maxdiff of {maxdiff}"); + e.Mobile.SendMessage($"Estimated item/mob reduction is {maxcount}"); } [Usage("XmlSpawnerWipe [SpawnerPrefixFilter]")] @@ -4313,7 +4310,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage("Unable to open {0} for unloading", filename); + from.SendMessage($"Unable to open {filename} for unloading"); } return; @@ -4337,7 +4334,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage("UnLoading {0} .xml files from directory {1}", files.Length, filename); + from.SendMessage($"UnLoading {files.Length} .xml files from directory {filename}"); } foreach (string file in files) @@ -4365,7 +4362,7 @@ public class XmlSpawner : Item, ISpawner } if (from != null) { - from.SendMessage("UnLoaded a total of {0} .xml files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + from.SendMessage($"UnLoaded a total of {total_processed_maps} .xml files and {total_processed_spawners} spawners from directory {filename}"); } processedmaps = total_processed_maps; @@ -4375,7 +4372,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage("{0} does not exist", filename); + from.SendMessage($"{filename} does not exist"); } } @@ -4403,8 +4400,9 @@ public class XmlSpawner : Item, ISpawner if (from != null) { - from.SendMessage(string.Format("UnLoading {0} objects{1} from file {2}.", - "XmlSpawner", !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty, filename)); + from.SendMessage( + $"UnLoading {"XmlSpawner"} objects{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} from file {filename}." + ); } // Create the data set @@ -4421,7 +4419,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage(33, "Error reading xml file {0}", filename); + from.SendMessage(33, $"Error reading xml file {filename}"); } fileerror = true; @@ -4544,15 +4542,16 @@ public class XmlSpawner : Item, ISpawner if (from != null) { - from.SendMessage("{0}/{8} spawner(s) were unloaded using file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6}, Other={7}].", - spawners_deleted, filename, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount, TotalCount); + from.SendMessage( + $"{spawners_deleted}/{TotalCount} spawner(s) were unloaded using file {filename} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}]." + ); } if (bad_spawner_count > 0) { if (from != null) { - from.SendMessage(33, "{0} bad spawners detected.", bad_spawner_count); + from.SendMessage(33, $"{bad_spawner_count} bad spawners detected."); } } @@ -4579,13 +4578,11 @@ public class XmlSpawner : Item, ISpawner } string filename = LocateFile(e.Arguments[0]); - int processedmaps; - int processedspawners; - XmlUnLoadFromFile(filename, SpawnerPrefix, e.Mobile, out processedmaps, out processedspawners); + XmlUnLoadFromFile(filename, SpawnerPrefix, e.Mobile, out _, out _); } else { - e.Mobile.SendMessage("Usage: {0} ", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} "); } } else @@ -4604,13 +4601,11 @@ public class XmlSpawner : Item, ISpawner { string filename = e.Arguments[0]; - int processedmaps; - int processedspawners; - XmlImportMap(filename, e.Mobile, out processedmaps, out processedspawners); + XmlImportMap(filename, e.Mobile, out _, out _); } else { - e.Mobile.SendMessage("Usage: {0} ", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} "); } } else @@ -4688,10 +4683,10 @@ public class XmlSpawner : Item, ISpawner catch (Exception e) { // Let the user know what went wrong. - from.SendMessage("The file could not be read: {0}", e.Message); + from.SendMessage($"The file could not be read: {e.Message}"); } - from.SendMessage("Imported {0} spawners from {1}", spawnercount, filename); - from.SendMessage("{0} bad spawners detected", badspawnercount); + from.SendMessage($"Imported {spawnercount} spawners from {filename}"); + from.SendMessage($"{badspawnercount} bad spawners detected"); processedmaps = 1; processedspawners = spawnercount; } @@ -4708,7 +4703,7 @@ public class XmlSpawner : Item, ISpawner catch { } if (files != null && files.Length > 0) { - from.SendMessage("Importing {0} .map files from directory {1}", files.Length, filename); + from.SendMessage($"Importing {files.Length} .map files from directory {filename}"); foreach (string file in files) { XmlImportMap(file, from, out processedmaps, out processedspawners); @@ -4732,13 +4727,15 @@ public class XmlSpawner : Item, ISpawner total_processed_spawners += processedspawners; } } - from.SendMessage("Imported a total of {0} .map files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + from.SendMessage( + $"Imported a total of {total_processed_maps} .map files and {filename} spawners from directory {total_processed_spawners}" + ); processedmaps = total_processed_maps; processedspawners = total_processed_spawners; } else { - from.SendMessage("{0} does not exist", filename); + from.SendMessage($"{filename} does not exist"); } } @@ -4835,7 +4832,7 @@ public class XmlSpawner : Item, ISpawner maxcount[k] = int.Parse(args[k + 16]); } } - catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + catch { from.SendMessage($"Parsing error at line {linenumber}"); badspawn = true; } // compute the total number of spawns int totalspawns = 0; @@ -4924,8 +4921,8 @@ public class XmlSpawner : Item, ISpawner { // invalid so dont spawn it badspawnercount++; - from.SendMessage("Invalid map/location at line {0}", linenumber); - from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + from.SendMessage($"Invalid map/location at line {linenumber}"); + from.SendMessage($"Bad spawn at line {line}: {line}"); return; } @@ -4966,7 +4963,7 @@ public class XmlSpawner : Item, ISpawner Guid SpawnId = Guid.NewGuid(); // and give it a name based on the spawner count and file - string spawnername = string.Format("{0}#{1}", Path.GetFileNameWithoutExtension(filename), spawnercount); + string spawnername = $"{Path.GetFileNameWithoutExtension(filename)}#{spawnercount}"; // Create the new xml spawner XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount, @@ -4985,8 +4982,8 @@ public class XmlSpawner : Item, ISpawner { badspawnercount++; spawner.Delete(); - from.SendMessage("Invalid map at line {0}", linenumber); - from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + from.SendMessage($"Invalid map at line {linenumber}"); + from.SendMessage($"Bad spawn at line {linenumber}: {line}"); return; } spawnercount++; @@ -5013,7 +5010,7 @@ public class XmlSpawner : Item, ISpawner { badspawnercount++; spawner.Delete(); - from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + from.SendMessage($"Bad spawn at line {linenumber}: {line}"); return; } spawnercount++; @@ -5022,7 +5019,7 @@ public class XmlSpawner : Item, ISpawner else { badspawnercount++; - from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + from.SendMessage($"Bad spawn at line {linenumber}: {line}"); } } } @@ -5095,7 +5092,7 @@ public class XmlSpawner : Item, ISpawner if (args.Length != 11 && args.Length != 12) { badspawn = true; - from.SendMessage("Invalid arg count {1} at line {0}", linenumber, args.Length); + from.SendMessage($"Invalid arg count {args.Length} at line {linenumber}"); } else { @@ -5119,7 +5116,7 @@ public class XmlSpawner : Item, ISpawner maxcount = int.Parse(args[10]); } - catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + catch { from.SendMessage($"Parsing error at line {linenumber}"); badspawn = true; } } else if (args.Length == 12) @@ -5139,7 +5136,7 @@ public class XmlSpawner : Item, ISpawner maxcount = int.Parse(args[11]); } - catch { from.SendMessage("Parsing error at line {0}", linenumber); badspawn = true; } + catch { from.SendMessage($"Parsing error at line {linenumber}"); badspawn = true; } } } @@ -5207,8 +5204,8 @@ public class XmlSpawner : Item, ISpawner { // invalid so dont spawn it badspawnercount++; - from.SendMessage("Invalid map/location at line {0}", linenumber); - from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + from.SendMessage($"Invalid map/location at line {linenumber}"); + from.SendMessage($"Bad spawn at line {linenumber}: {line}"); return; } @@ -5236,7 +5233,7 @@ public class XmlSpawner : Item, ISpawner Guid SpawnId = Guid.NewGuid(); // and give it a name based on the spawner count and file - string spawnername = string.Format("{0}#{1}", Path.GetFileNameWithoutExtension(filename), spawnercount); + string spawnername = $"{Path.GetFileNameWithoutExtension(filename)}#{spawnercount}"; // Create the new xml spawner XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount, @@ -5255,8 +5252,8 @@ public class XmlSpawner : Item, ISpawner { badspawnercount++; spawner.Delete(); - from.SendMessage("Invalid map at line {0}", linenumber); - from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + from.SendMessage($"Invalid map at line {linenumber}"); + from.SendMessage($"Bad spawn at line {linenumber}: {line}"); return; } spawnercount++; @@ -5283,7 +5280,7 @@ public class XmlSpawner : Item, ISpawner { badspawnercount++; spawner.Delete(); - from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + from.SendMessage($"Bad spawn at line {linenumber}: {line}"); return; } spawnercount++; @@ -5292,7 +5289,7 @@ public class XmlSpawner : Item, ISpawner else { badspawnercount++; - from.SendMessage("Bad spawn at line {1}: {0}", line, linenumber); + from.SendMessage($"Bad spawn at line {linenumber}: {line}"); } } } @@ -5314,7 +5311,7 @@ public class XmlSpawner : Item, ISpawner } catch { - e.Mobile.SendMessage("unable to load file {0}.", filePath); + e.Mobile.SendMessage($"unable to load file {filePath}."); return; } @@ -5329,14 +5326,14 @@ public class XmlSpawner : Item, ISpawner ImportSpawner(spawner, e.Mobile); successes++; } - catch (Exception ex) { e.Mobile.SendMessage(33, "{0} {1}", ex.Message, spawner.InnerText); failures++; } + catch (Exception ex) { e.Mobile.SendMessage(33, $"{ex.Message} {spawner.InnerText}"); failures++; } } } - e.Mobile.SendMessage("{0} spawners loaded successfully from {1}, {2} failures.", successes, filePath, failures); + e.Mobile.SendMessage($"{successes} spawners loaded successfully from {filePath}, {failures} failures."); } else { - e.Mobile.SendMessage("File {0} does not exist.", filePath); + e.Mobile.SendMessage($"File {filePath} does not exist."); } } else @@ -5461,9 +5458,9 @@ public class XmlSpawner : Item, ISpawner ImportMegaSpawner(e.Mobile, spawner); successes++; } - catch (Exception ex) { e.Mobile.SendMessage(33, "{0} {1}", ex.Message, spawner.InnerText); failures++; } + catch (Exception ex) { e.Mobile.SendMessage(33, $"{ex.Message} {spawner.InnerText}"); failures++; } } - e.Mobile.SendMessage("{0} megaspawners loaded successfully from {1}, {2} failures.", successes, filePath, failures); + e.Mobile.SendMessage($"{successes} megaspawners loaded successfully from {filePath}, {failures} failures."); } else { @@ -5472,7 +5469,7 @@ public class XmlSpawner : Item, ISpawner } else { - e.Mobile.SendMessage("File {0} does not exist.", filePath); + e.Mobile.SendMessage($"File {filePath} does not exist."); } } else @@ -5631,12 +5628,12 @@ public class XmlSpawner : Item, ISpawner { using (StreamWriter op = new StreamWriter("badimport.log", true)) { - op.WriteLine("{0} MSFImport Error; inconsistent entry count {1} {2}", DateTime.UtcNow, location, map); + op.WriteLine($"{Core.Now} MSFImport Error; inconsistent entry count {location} {map}"); op.WriteLine(); } } catch { } - from.SendMessage("Inconsistent entry count detected at {0} {1}.", location, map); + from.SendMessage($"Inconsistent entry count detected at {location} {map}."); break; } @@ -5644,13 +5641,13 @@ public class XmlSpawner : Item, ISpawner } if (diff) { - from.SendMessage("Individual entry setting detected at {0} {1}.", location, map); + from.SendMessage($"Individual entry setting detected at {location} {map}."); // log it try { using (StreamWriter op = new StreamWriter("badimport.log", true)) { - op.WriteLine("{0} MSFImport: Individual entry setting differences listed above from spawner at {1} {2}", DateTime.UtcNow, location, map); + op.WriteLine($"{Core.Now} MSFImport: Individual entry setting differences listed above from spawner at {location} {map}"); op.WriteLine(); } } @@ -5729,7 +5726,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage("Unable to open {0} for loading", filename); + from.SendMessage($"Unable to open {filename} for loading"); } return; @@ -5752,7 +5749,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage("Loading {0} .xml files from directory {1}", files.Length, filename); + from.SendMessage($"Loading {files.Length} .xml files from directory {filename}"); } foreach (string file in files) @@ -5780,7 +5777,7 @@ public class XmlSpawner : Item, ISpawner } if (from != null) { - from.SendMessage("Loaded a total of {0} .xml files and {2} spawners from directory {1}", total_processed_maps, filename, total_processed_spawners); + from.SendMessage($"Loaded a total of {total_processed_maps} .xml files and {filename} spawners from directory {total_processed_spawners}"); } processedmaps = total_processed_maps; @@ -5790,7 +5787,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage("{0} does not exist", filename); + from.SendMessage($"{filename} does not exist"); } } @@ -5877,7 +5874,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage(33, "Error reading xml file {0}", filename); + from.SendMessage(33, $"Error reading xml file {filename}"); } fileerror = true; @@ -5908,7 +5905,7 @@ public class XmlSpawner : Item, ISpawner if (loadnew) { // append the new id to the name - SpawnName = string.Format("{0}-{1}", SpawnName, newloadid); + SpawnName = $"{SpawnName}-{newloadid}"; } // Check if there is any spawner name criteria specified on the load @@ -6272,8 +6269,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage(33, "Invalid location '{0}' at [{1} {2}] in {3}", - SpawnName, SpawnCentreX, SpawnCentreY, XmlMapName); + from.SendMessage(33, $"Invalid location '{SpawnName}' at [{SpawnCentreX} {SpawnCentreY}] in {XmlMapName}"); } bad_spawner = true; @@ -6333,7 +6329,7 @@ public class XmlSpawner : Item, ISpawner { using (StreamWriter op = new StreamWriter("badxml.log", true)) { - op.WriteLine("# Invalid spawner : {0}: Fileposition {1} {2}", DateTime.UtcNow, fileposition, filename); + op.WriteLine("# Invalid spawner : {0}: Fileposition {1} {2}", Core.Now, fileposition, filename); op.WriteLine(); } } @@ -6345,8 +6341,7 @@ public class XmlSpawner : Item, ISpawner questionablecount++; if (from != null) { - from.SendMessage(33, "Questionable spawner '{0}' at [{1} {2}] in {3}", - SpawnName, SpawnCentreX, SpawnCentreY, XmlMapName); + from.SendMessage(33, $"Questionable spawner '{SpawnName}' at [{SpawnCentreX} {SpawnCentreY}] in {XmlMapName}"); } // log it @@ -6357,7 +6352,7 @@ public class XmlSpawner : Item, ISpawner { using (StreamWriter op = new StreamWriter("badxml.log", true)) { - op.WriteLine("# Questionable spawner : {0}: Format: X Y Z Map SpawnerName Fileposition Xmlfile", DateTime.UtcNow); + op.WriteLine("# Questionable spawner : {0}: Format: X Y Z Map SpawnerName Fileposition Xmlfile", Core.Now); op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", SpawnCentreX, SpawnCentreY, SpawnCentreZ, XmlMapName, SpawnName, fileposition, filename); op.WriteLine(); } @@ -6441,7 +6436,7 @@ public class XmlSpawner : Item, ISpawner // Send a message to the client that the spawner is created if (from != null && verbose) { - from.SendMessage(188, "Created '{0}' in {1} at {2}", TheSpawn.Name, TheSpawn.Map.Name, TheSpawn.Location.ToString()); + from.SendMessage(188, $"Created '{TheSpawn.Name}' in {TheSpawn.Map.Name} at {TheSpawn.Location}"); } // Do a total respawn @@ -6536,7 +6531,7 @@ public class XmlSpawner : Item, ISpawner // if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid if (loadnew) { - string tmpsetObjectName = string.Format("{0}-{1}", namestr, newloadid); + string tmpsetObjectName = $"{namestr}-{newloadid}"; OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, tmpsetObjectName, typestr); } // if this fails then try the original @@ -6549,8 +6544,7 @@ public class XmlSpawner : Item, ISpawner failedsetitemcount++; if (from != null) { - from.SendMessage(33, "Failed to initialize SetItemProperty Object '{0}' on ' '{1}' at [{2} {3}] in {4}", - setObjectName, OldSpawner.Name, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Map); + from.SendMessage(33, $"Failed to initialize SetItemProperty Object '{setObjectName}' on ' '{OldSpawner.Name}' at [{OldSpawner.Location.X} {OldSpawner.Location.Y}] in {OldSpawner.Map}"); } // log it @@ -6559,7 +6553,7 @@ public class XmlSpawner : Item, ISpawner using (StreamWriter op = new StreamWriter("badxml.log", true)) { op.WriteLine("# Failed SetItemProperty Object initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", - DateTime.UtcNow); + Core.Now); op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", setObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); op.WriteLine(); @@ -6588,7 +6582,7 @@ public class XmlSpawner : Item, ISpawner // if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid if (loadnew) { - string tmptriggerObjectName = string.Format("{0}-{1}", namestr, newloadid); + string tmptriggerObjectName = $"{namestr}-{newloadid}"; OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, tmptriggerObjectName, typestr); } // if this fails then try the original @@ -6601,8 +6595,7 @@ public class XmlSpawner : Item, ISpawner failedobjectitemcount++; if (from != null) { - from.SendMessage(33, "Failed to initialize TriggerObject '{0}' on ' '{1}' at [{2} {3}] in {4}", - triggerObjectName, OldSpawner.Name, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Map); + from.SendMessage(33, $"Failed to initialize TriggerObject '{triggerObjectName}' on ' '{OldSpawner.Name}' at [{OldSpawner.Location.X} {OldSpawner.Location.Y}] in {OldSpawner.Map}"); } // log it @@ -6611,7 +6604,7 @@ public class XmlSpawner : Item, ISpawner using (StreamWriter op = new StreamWriter("badxml.log", true)) { op.WriteLine("# Failed TriggerObject initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", - DateTime.UtcNow); + Core.Now); op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", triggerObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); op.WriteLine(); @@ -6634,36 +6627,35 @@ public class XmlSpawner : Item, ISpawner if (from != null) { - from.SendMessage("{0} spawner(s) were created from file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6} Other={7}].", - TotalCount, filename, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount); + from.SendMessage($"{TotalCount} spawner(s) were created from file {filename} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount} Other={OtherCount}]."); } if (failedobjectitemcount > 0) { if (from != null) { - from.SendMessage(33, "Failed to initialize TriggerObjects in {0} spawners. Saved to 'badxml.log'", failedobjectitemcount); + from.SendMessage(33, $"Failed to initialize TriggerObjects in {failedobjectitemcount} spawners. Saved to 'badxml.log'"); } } if (failedsetitemcount > 0) { if (from != null) { - from.SendMessage(33, "Failed to initialize SetItemProperty Objects in {0} spawners. Saved to 'badxml.log'", failedsetitemcount); + from.SendMessage(33, $"Failed to initialize SetItemProperty Objects in {failedsetitemcount} spawners. Saved to 'badxml.log'"); } } if (badcount > 0) { if (from != null) { - from.SendMessage(33, "{0} bad spawners detected. Saved to 'badxml.log'", badcount); + from.SendMessage(33, $"{badcount} bad spawners detected. Saved to 'badxml.log'"); } } if (questionablecount > 0) { if (from != null) { - from.SendMessage(33, "{0} questionable spawners detected. Saved to 'badxml.log'", questionablecount); + from.SendMessage(33, $"{questionablecount} questionable spawners detected. Saved to 'badxml.log'"); } } processedmaps = 1; @@ -6680,7 +6672,7 @@ public class XmlSpawner : Item, ISpawner if (Directory.Exists(XmlSpawnDir)) { // get it from the defaults directory if it exists - dirname = string.Format("{0}/{1}", XmlSpawnDir, filename); + dirname = $"{XmlSpawnDir}/{filename}"; found = File.Exists(dirname) || Directory.Exists(dirname); } @@ -6712,14 +6704,11 @@ public class XmlSpawner : Item, ISpawner SpawnerPrefix = e.Arguments[1]; } - int processedmaps; - int processedspawners; - - XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, false, 0, true, out processedmaps, out processedspawners); + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, false, 0, true, out _, out _); } else { - e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} [SpawnerPrefixFilter]"); } } else @@ -6749,14 +6738,11 @@ public class XmlSpawner : Item, ISpawner SpawnerPrefix = e.Arguments[1]; } - int processedmaps; - int processedspawners; - - XmlLoadFromFile(filename, SpawnerPrefix, m, false, 0, false, out processedmaps, out processedspawners); + XmlLoadFromFile(filename, SpawnerPrefix, m, false, 0, false, out _, out _); } else if (m != null) { - e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} [SpawnerPrefixFilter]"); } } else @@ -6797,19 +6783,16 @@ public class XmlSpawner : Item, ISpawner } } } - catch { e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); badargs = true; } + catch { e.Mobile.SendMessage($"Usage: {e.Command} [SpawnerPrefixFilter][-maxrange range]"); badargs = true; } if (!badargs) { - int processedmaps; - int processedspawners; - - XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, true, out processedmaps, out processedspawners); + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, true, out _, out _); } } else { - e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} [SpawnerPrefixFilter][-maxrange range]"); } } else @@ -6849,19 +6832,16 @@ public class XmlSpawner : Item, ISpawner } } } - catch { e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); badargs = true; } + catch { e.Mobile.SendMessage($"Usage: {e.Command} [SpawnerPrefixFilter][-maxrange range]"); badargs = true; } if (!badargs) { - int processedmaps; - int processedspawners; - - XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, false, out processedmaps, out processedspawners); + XmlLoadFromFile(filename, SpawnerPrefix, e.Mobile, true, maxrange, false, out _, out _); } } else { - e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter][-maxrange range]", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} [SpawnerPrefixFilter][-maxrange range]"); } } else @@ -6912,7 +6892,7 @@ public class XmlSpawner : Item, ISpawner if (e.Arguments.Length < 1) { - e.Mobile.SendMessage("Usage: {0} (without spaces!!)", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} (without spaces!!)"); return; } @@ -6928,7 +6908,7 @@ public class XmlSpawner : Item, ISpawner Mobile m = e.Mobile; - CommandLogging.WriteLine(m, "{0} {1} Saving XmlSpawner {2} on file {3}", m.AccessLevel, CommandLogging.Format(m), CommandLogging.Format(xmlspawner), CommandLogging.Format(filename)); + CommandLogging.WriteLine(m, $"{m.AccessLevel} {CommandLogging.Format(m)} Saving XmlSpawner {CommandLogging.Format(xmlspawner)} on file {CommandLogging.Format(filename)}"); SaveSpawns(m, xmlspawner, filename); } } @@ -6946,7 +6926,7 @@ public class XmlSpawner : Item, ISpawner if (Directory.Exists(XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) { // put it in the defaults directory if it exists - dirname = string.Format("{0}/{1}", XmlSpawnDir, filename); + dirname = $"{XmlSpawnDir}/{filename}"; } else { @@ -6954,7 +6934,7 @@ public class XmlSpawner : Item, ISpawner dirname = filename; } - m.SendMessage("Saving object in folder {0} - file {1} - spawner {2}.", dirname, filename, xmlspawner); + m.SendMessage($"Saving object in folder {dirname} - file {filename} - spawner {xmlspawner}."); List saveslist = new List(1); saveslist.Add(xmlspawner); @@ -6976,7 +6956,7 @@ public class XmlSpawner : Item, ISpawner if (e.Arguments != null && e.Arguments.Length < 1) { - e.Mobile.SendMessage("Usage: {0} [SpawnerPrefixFilter]", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} [SpawnerPrefixFilter]"); return; } @@ -6995,7 +6975,7 @@ public class XmlSpawner : Item, ISpawner if (Directory.Exists(XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) { // put it in the defaults directory if it exists - dirname = string.Format("{0}/{1}", XmlSpawnDir, filename); + dirname = $"{XmlSpawnDir}/{filename}"; } else { @@ -7005,13 +6985,15 @@ public class XmlSpawner : Item, ISpawner if (SaveAllMaps) { - e.Mobile.SendMessage(string.Format("Saving {0} objects{1} to file {2} from {3}.", "XmlSpawner", - !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty, dirname, e.Mobile.Map)); + e.Mobile.SendMessage( + $"Saving XmlSpawner objects{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} to file {dirname} from {e.Mobile.Map}." + ); } else { - e.Mobile.SendMessage(string.Format("Saving {0} obejcts{1} to file {2} from the entire world.", "XmlSpawner", - !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty, dirname)); + e.Mobile.SendMessage( + $"Saving XmlSpawner obejcts{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} to file {dirname} from the entire world." + ); } @@ -7055,7 +7037,7 @@ public class XmlSpawner : Item, ISpawner { if (from != null) { - from.SendMessage("Error creating file {0}", dirname); + from.SendMessage($"Error creating file {dirname}"); } save_ok = false; @@ -7181,7 +7163,7 @@ public class XmlSpawner : Item, ISpawner if (verbose && from != null) // Send a message to the client that the spawner is being saved { - from.SendMessage(68, "Saving '{0}' in {1} at {2}", sp.Name, sp.Map.Name, sp.Location.ToString()); + from.SendMessage(68, $"Saving '{sp.Name}' in {sp.Map.Name} at {sp.Location}"); } // Create a new data row @@ -7285,8 +7267,7 @@ public class XmlSpawner : Item, ISpawner dr["ProximityTriggerMessage"] = sp.m_ProximityTriggerMessage; if (sp.m_ObjectPropertyItem != null && !sp.m_ObjectPropertyItem.Deleted) { - dr["ObjectPropertyItemName"] = string.Format("{0},{1}", sp.m_ObjectPropertyItem.Name, - sp.m_ObjectPropertyItem.GetType().Name); + dr["ObjectPropertyItemName"] = $"{sp.m_ObjectPropertyItem.Name},{sp.m_ObjectPropertyItem.GetType().Name}"; } else { @@ -7296,8 +7277,7 @@ public class XmlSpawner : Item, ISpawner dr["ObjectPropertyName"] = sp.m_ObjectPropertyName; if (sp.m_SetPropertyItem != null && !sp.m_SetPropertyItem.Deleted) { - dr["SetPropertyItemName"] = string.Format("{0},{1}", sp.m_SetPropertyItem.Name, - sp.m_SetPropertyItem.GetType().Name); + dr["SetPropertyItemName"] = $"{sp.m_SetPropertyItem.Name},{sp.m_SetPropertyItem.GetType().Name}"; } else { @@ -7334,7 +7314,7 @@ public class XmlSpawner : Item, ISpawner } else { - waystr = string.Format("SERIAL,{0}", sp.m_WayPoint.Serial); + waystr = $"SERIAL,{sp.m_WayPoint.Serial}"; } } dr["WayPoint"] = waystr; @@ -7382,8 +7362,7 @@ public class XmlSpawner : Item, ISpawner // Indicate how many spawners were written if (from != null) { - from.SendMessage("{0} spawner(s) were saved to file {1} [Trammel={2}, Felucca={3}, Ilshenar={4}, Malas={5}, Tokuno={6}, Other={7}].", - TotalCount, dirname, TrammelCount, FeluccaCount, IlshenarCount, MalasCount, TokunoCount, OtherCount); + from.SendMessage($"{TotalCount} spawner(s) were saved to file {dirname} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}]."); } return true; @@ -7409,13 +7388,11 @@ public class XmlSpawner : Item, ISpawner if (WipeAll) { - e.Mobile.SendMessage("Removing ALL XmlSpawner objects from the world{0}.", !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" - : string.Empty); + e.Mobile.SendMessage($"Removing ALL XmlSpawner objects from the world{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)}."); } else { - e.Mobile.SendMessage("Removing ALL XmlSpawner objects from {0}{1}.", e.Mobile.Map, !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" - : string.Empty); + e.Mobile.SendMessage($"Removing ALL XmlSpawner objects from {e.Mobile.Map}{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)}."); } // Delete Xml spawner's in the world based on the mobiles current map @@ -7445,11 +7422,11 @@ public class XmlSpawner : Item, ISpawner if (WipeAll) { - e.Mobile.SendMessage("Removed {0} XmlSpawner objects from the world.", Count); + e.Mobile.SendMessage($"Removed {Count} XmlSpawner objects from the world."); } else { - e.Mobile.SendMessage("Removed {0} XmlSpawner objects from {1}.", Count, e.Mobile.Map); + e.Mobile.SendMessage($"Removed {Count} XmlSpawner objects from {e.Mobile.Map}."); } } else @@ -7493,13 +7470,11 @@ public class XmlSpawner : Item, ISpawner if (RespawnAll) { - e.Mobile.SendMessage("Respawning ALL XmlSpawner objects from the world{0}.", !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" - : string.Empty); + e.Mobile.SendMessage($"Respawning ALL XmlSpawner objects from the world{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)}."); } else { - e.Mobile.SendMessage("Respawning ALL XmlSpawner objects from {0}{1}.", e.Mobile.Map, !string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" - : string.Empty); + e.Mobile.SendMessage($"Respawning ALL XmlSpawner objects from {e.Mobile.Map}{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)}."); } // Respawn Xml spawner's in the world based on the mobiles current map @@ -7509,7 +7484,6 @@ public class XmlSpawner : Item, ISpawner { try { - if (i is XmlSpawner && (RespawnAll || i.Map == e.Mobile.Map) && i.Deleted == false) { // Check if there is a respawn condition @@ -7527,18 +7501,18 @@ public class XmlSpawner : Item, ISpawner { // Send a message to the client that the spawner is being respawned - e.Mobile.SendMessage(33, "Respawning '{0}' in {1} at {2}", i.Name, i.Map.Name, i.Location.ToString()); + e.Mobile.SendMessage(33, $"Respawning '{i.Name}' in {i.Map.Name} at {i.Location}"); XmlSpawner CheckXmlSpawner = (XmlSpawner)i; CheckXmlSpawner.TryRespawn(); } if (RespawnAll) { - e.Mobile.SendMessage("Respawned {0} XmlSpawner objects from the world.", Count); + e.Mobile.SendMessage($"Respawned {Count} XmlSpawner objects from the world."); } else { - e.Mobile.SendMessage("Respawned {0} XmlSpawner objects from {1}.", Count, e.Mobile.Map); + e.Mobile.SendMessage($"Respawned {Count} XmlSpawner objects from {e.Mobile.Map}."); } } else @@ -7581,11 +7555,11 @@ public class XmlSpawner : Item, ISpawner } if (e.Arguments.Length > 2) { - e.Mobile.SendMessage("Created {0} Spawner objects.", count); + e.Mobile.SendMessage($"Created {count} Spawner objects."); } else { - e.Mobile.SendMessage("Created {0} XmlSpawner objects.", count); + e.Mobile.SendMessage($"Created {count} XmlSpawner objects."); } @@ -7600,7 +7574,7 @@ public class XmlSpawner : Item, ISpawner public static void XmlTrace_OnCommand(CommandEventArgs e) { Process currentprocess = Process.GetCurrentProcess(); - TimeSpan runningtime = DateTime.UtcNow - _traceStartTime; + TimeSpan runningtime = Core.Now - _traceStartTime; double processtime = currentprocess.UserProcessorTime.TotalMilliseconds - _startProcessTime; double sysload = 0; @@ -7641,7 +7615,7 @@ public class XmlSpawner : Item, ISpawner _traceCount[i] = 0; _traceTotal[i] = TimeSpan.Zero; } - _traceStartTime = DateTime.UtcNow; + _traceStartTime = Core.Now; Process currentprocess = Process.GetCurrentProcess(); _startProcessTime = currentprocess.UserProcessorTime.TotalMilliseconds; @@ -7846,7 +7820,7 @@ public class XmlSpawner : Item, ISpawner { bool despawned = false; // check to see if the despawn time has elapsed. If so, then delete it if it hasnt been picked up or stolen. - if (DespawnTime.TotalHours > 0 && !item.Deleted && item.LastMoved < DateTime.UtcNow - DespawnTime && item.Parent == Parent + if (DespawnTime.TotalHours > 0 && !item.Deleted && item.LastMoved < Core.Now - DespawnTime && item.Parent == Parent && (!ItemFlags.GetTaken(item) || item.Parent != null && item.Parent == Parent)) // can despawn if just moved within the same container { //item.Delete(); @@ -7886,7 +7860,7 @@ public class XmlSpawner : Item, ISpawner { bool despawned = false; // check to see if the despawn time has elapsed. If so, and the sector is not active then delete it. - if (DespawnTime.TotalHours > 0 && !mobile.Deleted && mobile.Created < DateTime.UtcNow - DespawnTime + if (DespawnTime.TotalHours > 0 && !mobile.Deleted && mobile.Created < Core.Now - DespawnTime && mobile.Map != null && mobile.Map != Map.Internal && !mobile.Map.GetSector(mobile.Location).Active) { //m.Delete(); @@ -8986,7 +8960,7 @@ public class XmlSpawner : Item, ISpawner } // check the nextspawn time to see if it is available - if (TheSpawn.NextSpawn > DateTime.UtcNow) + if (TheSpawn.NextSpawn > Core.Now) { return false; } @@ -9738,7 +9712,7 @@ public class XmlSpawner : Item, ISpawner { SpawnObject so = m_SpawnObjects[i]; - so.NextSpawn = DateTime.UtcNow; + so.NextSpawn = Core.Now; } } } @@ -9754,14 +9728,14 @@ public class XmlSpawner : Item, ISpawner int maxd = (int)(so.MaxDelay * 60); if (mind < 0 || maxd < 0) { - so.NextSpawn = DateTime.UtcNow; + so.NextSpawn = Core.Now; } else { TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(mind, maxd)); - so.NextSpawn = DateTime.UtcNow + delay; + so.NextSpawn = Core.Now + delay; } } @@ -11258,7 +11232,8 @@ public class XmlSpawner : Item, ISpawner m_SpawnObjects.Remove(TheSpawn); if (from != null) { - CommandLogging.WriteLine(from, "{0} {1} removed from XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7}", from.AccessLevel, CommandLogging.Format(from), Serial, Name, GetWorldLocation().X, GetWorldLocation().Y, Map, SpawnObjectName); + var loc = GetWorldLocation(); + CommandLogging.WriteLine(from, $"{from.AccessLevel} {CommandLogging.Format(from)} removed from XmlSpawner {Serial} '{Name}' [{loc.X}, {loc.Y}] ({Map}) : {SpawnObjectName}"); } } } @@ -11518,7 +11493,7 @@ public class XmlSpawner : Item, ISpawner using (StreamWriter op = new StreamWriter("badspawn.log", true)) { - op.WriteLine("# Bad spawns : {0}", DateTime.UtcNow); + op.WriteLine("# Bad spawns : {0}", Core.Now); op.WriteLine("# Format: X Y Z F Name"); op.WriteLine(); @@ -11557,7 +11532,7 @@ public class XmlSpawner : Item, ISpawner return; } - m_End = DateTime.UtcNow + delay; + m_End = Core.Now + delay; if (m_Timer != null) { @@ -11570,7 +11545,7 @@ public class XmlSpawner : Item, ISpawner public void DoTimer2(TimeSpan delay) { - m_DurEnd = DateTime.UtcNow + delay; + m_DurEnd = Core.Now + delay; if (m_Duration > TimeSpan.FromMinutes(0) || m_durActivated) { if (m_DurTimer != null) @@ -11586,7 +11561,7 @@ public class XmlSpawner : Item, ISpawner public void DoTimer3(TimeSpan delay) { - m_RefractEnd = DateTime.UtcNow + delay; + m_RefractEnd = Core.Now + delay; m_refractActivated = true; if (m_RefractoryTimer != null) @@ -11850,12 +11825,12 @@ public class XmlSpawner : Item, ISpawner writer.Write(m_MaxRefractory); if (m_refractActivated) { - writer.Write(m_RefractEnd - DateTime.UtcNow); + writer.Write(m_RefractEnd - Core.Now); } if (m_durActivated) { - writer.Write(m_DurEnd - DateTime.UtcNow); + writer.Write(m_DurEnd - Core.Now); } // Version 3 @@ -11884,7 +11859,7 @@ public class XmlSpawner : Item, ISpawner if (m_Running) { - writer.Write(m_End - DateTime.UtcNow); + writer.Write(m_End - Core.Now); } // Write the spawn object list @@ -12119,7 +12094,7 @@ public class XmlSpawner : Item, ISpawner hasnewobjectinfo = true; m_SequentialSpawning = reader.ReadInt(); TimeSpan seqdelay = reader.ReadTimeSpan(); - m_SeqEnd = DateTime.UtcNow + seqdelay; + m_SeqEnd = Core.Now + seqdelay; tmpSubGroup = new List(tmpSpawnListSize); tmpSequentialResetTime = new List(tmpSpawnListSize); @@ -12535,7 +12510,8 @@ public class XmlSpawner : Item, ISpawner if (!found) { - CommandLogging.WriteLine(from, "{0} {1} added to XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7}", from.AccessLevel, CommandLogging.Format(from), spawner.Serial, spawner.Name, spawner.GetWorldLocation().X, spawner.GetWorldLocation().Y, spawner.Map, name); + var loc = spawner.GetWorldLocation(); + CommandLogging.WriteLine(from, $"{from.AccessLevel} {CommandLogging.Format(from)} added to XmlSpawner {spawner.Serial} '{spawner.Name}' [{loc.X}, {loc.Y}] ({spawner.Map}) : {name}"); } } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs index 832509a37..a708f2c22 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs @@ -510,18 +510,18 @@ public class XmlSpawnerGump : Gump } string strnext; - if (m_Spawner.SpawnObjects[i].NextSpawn > DateTime.UtcNow) + if (m_Spawner.SpawnObjects[i].NextSpawn > Core.Now) { // if the next spawn tick of the spawner will occur after the subgroup is available for spawning // then report the next spawn tick since that is the earliest that the subgroup can actually be spawned - if (DateTime.UtcNow + m_Spawner.NextSpawn > m_Spawner.SpawnObjects[i].NextSpawn) + if (Core.Now + m_Spawner.NextSpawn > m_Spawner.SpawnObjects[i].NextSpawn) { strnext = m_Spawner.NextSpawn.ToString(); } else { // estimate the earliest the next spawn could occur as the first spawn tick after reaching the subgroup nextspawn - strnext = (m_Spawner.SpawnObjects[i].NextSpawn - DateTime.UtcNow + m_Spawner.NextSpawn).ToString(); + strnext = (m_Spawner.SpawnObjects[i].NextSpawn - Core.Now + m_Spawner.NextSpawn).ToString(); } } else @@ -665,16 +665,7 @@ public class XmlSpawnerGump : Gump { CommandLogging.WriteLine( from, - "{0} {1} changed XmlSpawner {2} '{3}' [{4}, {5}] ({6}) : {7} to {8}", - from.AccessLevel, - CommandLogging.Format(from), - m_Spawner.Serial, - m_Spawner.Name, - m_Spawner.GetWorldLocation().X, - m_Spawner.GetWorldLocation().Y, - m_Spawner.Map, - m_Spawner.SpawnObjects[i].TypeName, - str + $"{from.AccessLevel} {CommandLogging.Format(from)} changed XmlSpawner {m_Spawner.Serial} '{m_Spawner.Name}' [{m_Spawner.GetWorldLocation().X}, {m_Spawner.GetWorldLocation().Y}] ({m_Spawner.Map}) : {m_Spawner.SpawnObjects[i].TypeName} to {str}" ); } @@ -740,7 +731,7 @@ public class XmlSpawnerGump : Gump if (from != null && !from.Deleted) { - from.SendMessage("{0} is not available", i); + from.SendMessage($"{i} is not available"); } } else if (o is Mobile m) @@ -752,7 +743,7 @@ public class XmlSpawnerGump : Gump if (from != null && !from.Deleted) { - from.SendMessage("{0} is not available", m); + from.SendMessage($"{m} is not available"); } } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs index 314551e44..fa1b2b6ed 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs @@ -270,25 +270,11 @@ public class XmlSpawnerSkillCheck // determine whether there are any registered objects for this skill foreach(RegisteredSkill rs in skilllist) { - if (rs.sid == skill.SkillName) + // if so then invoke their skill handlers + // call the spawner handler + if (rs.sid == skill.SkillName && rs.target is XmlSpawner spawner && spawner.HandlesOnSkillUse) { - // if so then invoke their skill handlers - if (rs.target is XmlSpawner spawner) - { - if (spawner.HandlesOnSkillUse) - { - // call the spawner handler - spawner.OnSkillUse(m, skill, success); - } - } else - if (rs.target is IXmlQuest quest) - { - if (quest.HandlesOnSkillUse) - { - // call the xmlquest handler - quest.OnSkillUse(m, skill, success); - } - } + spawner.OnSkillUse(m, skill, success); } } } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs index 8992ed537..ce083ed65 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs @@ -46,7 +46,7 @@ public class WriteMulti if (e.Arguments != null && e.Arguments.Length < 1) { - e.Mobile.SendMessage("Usage: {0} [zmin zmax][-noitems][-nostatics][-nomultis][-noaddons][-invisible]", e.Command); + e.Mobile.SendMessage($"Usage: {e.Command} [zmin zmax][-noitems][-nostatics][-nomultis][-noaddons][-invisible]"); return; } @@ -99,7 +99,7 @@ public class WriteMulti } catch { - e.Mobile.SendMessage("{0} : Invalid zmin zmax arguments", e.Command); + e.Mobile.SendMessage($"{e.Command} : Invalid zmin zmax arguments"); return; } } @@ -126,13 +126,6 @@ public class WriteMulti try { StreamReader op = new StreamReader(dirname, false); - - if (op == null) - { - e.Mobile.SendMessage("Cannot access file {0}", dirname); - return; - } - string line = op.ReadLine(); op.Close(); @@ -142,28 +135,28 @@ public class WriteMulti { string[] args = line.Split(" ".ToCharArray(), 3); - if (args == null || args.Length < 3) + if (args.Length < 3) { - e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + e.Mobile.SendMessage($"Cannot overwrite file {dirname} : not owner"); return; } if (args[2] != e.Mobile.Name) { - e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + e.Mobile.SendMessage($"Cannot overwrite file {dirname} : not owner"); return; } } else { - e.Mobile.SendMessage("Cannot overwrite file {0} : not owner", dirname); + e.Mobile.SendMessage($"Cannot overwrite file {dirname} : not owner"); return; } } catch { - e.Mobile.SendMessage("Cannot overwrite file {0}", dirname); + e.Mobile.SendMessage($"Cannot overwrite file {dirname}"); return; } @@ -410,7 +403,7 @@ public class WriteMulti } catch { - from.SendMessage("Error writing multi file {0}", dirname); + from.SendMessage($"Error writing multi file {dirname}"); return; } @@ -418,11 +411,11 @@ public class WriteMulti if (includeitems) { - from.SendMessage(66, "Included {0} items", nitems); + from.SendMessage(66, $"Included {nitems} items"); if (includemultis) { - from.SendMessage("{0} multis", nmultis); + from.SendMessage($"{nmultis} multis"); } else { @@ -431,7 +424,7 @@ public class WriteMulti if (includeinvisible) { - from.SendMessage("{0} invisible", ninvisible); + from.SendMessage($"{ninvisible} invisible"); } else { @@ -440,7 +433,7 @@ public class WriteMulti if (includeaddons) { - from.SendMessage("{0} addons", naddons); + from.SendMessage($"{naddons} addons"); } else { @@ -455,14 +448,14 @@ public class WriteMulti if (includestatics) { - from.SendMessage(66, "Included {0} statics", nstatics); + from.SendMessage(66, $"Included {nstatics} statics"); } else { from.SendMessage(33, "Ignored statics"); } - from.SendMessage(66, "Saved {0} components to {1}", ntotal, dirname); + from.SendMessage(66, $"Saved {ntotal} components to {dirname}"); } } } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs index eac9420f2..c74c2fa30 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs @@ -378,7 +378,7 @@ public class XmlAddGump : Gump { if (from != null && !from.Deleted) { - from.SendMessage("Error trying to save to file {0}", dirname); + from.SendMessage($"Error trying to save to file {dirname}"); } return; @@ -386,7 +386,7 @@ public class XmlAddGump : Gump if (from != null && !from.Deleted) { - from.SendMessage("Saved defs to file {0}", dirname); + from.SendMessage($"Saved defs to file {dirname}"); } } @@ -426,7 +426,7 @@ public class XmlAddGump : Gump if (fs == null) { - from.SendMessage("Unable to open {0} for loading", dirname); + from.SendMessage($"Unable to open {dirname} for loading"); return; } @@ -447,7 +447,7 @@ public class XmlAddGump : Gump { if (from != null && !from.Deleted) { - from.SendMessage(33, "Error reading defs file {0}", dirname); + from.SendMessage(33, $"Error reading defs file {dirname}"); } return; @@ -590,7 +590,7 @@ public class XmlAddGump : Gump if (from != null && !from.Deleted) { - from.SendMessage("Loaded defs from file {0}", dirname); + from.SendMessage($"Loaded defs from file {dirname}"); } } } @@ -599,7 +599,7 @@ public class XmlAddGump : Gump { if (from != null && !from.Deleted) { - from.SendMessage(33, "File not found: {0}", dirname); + from.SendMessage(33, $"File not found: {dirname}"); } } } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlEdit.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlEdit.cs deleted file mode 100644 index e61f7113c..000000000 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlEdit.cs +++ /dev/null @@ -1,1420 +0,0 @@ -using System; -using System.Collections; -using Server.Items; -using Server.Network; -using Server.Gumps; -using Server.Targeting; -using CPA = Server.CommandPropertyAttribute; -using Server.Mobiles; - -/* -** XmlEditNPC -** Version 1.00 -** updated 5/24/05 -** ArteGordon -** -** -*/ - -namespace Server.Engines.XmlSpawner2; - -public class XmlEditDialogGump : Gump -{ - private const int MaxEntries = 8; - private const int MaxEntriesPerPage = 8; - - private Mobile m_From; - private string Name; - private int Selected; - private int DisplayFrom; - private string SaveFilename; - private bool [] m_SelectionList; - private XmlDialog m_Dialog; - - private bool SelectAll; - - private ArrayList m_SearchList; - - public static void Initialize() - { - CommandSystem.Register("XmlEdit", AccessLevel.GameMaster, XmlEditDialog_OnCommand); - } - - [Usage("XmlEdit")] - [Description("Edits XmlDialog entries on an object")] - public static void XmlEditDialog_OnCommand(CommandEventArgs e) - { - if (e == null || e.Mobile == null) - { - return; - } - - // target an object with the xmldialog attachment - e.Mobile.Target = new EditDialogTarget(); - - - } - - private class EditDialogTarget : Target - { - - public EditDialogTarget() : base (30, true, TargetFlags.None) - { - - } - - protected override void OnTarget(Mobile from, object targeted) - { - if (from == null) - { - return; - } - - // does it have an xmldialog attachment? - XmlDialog xd = XmlAttach.FindAttachment(targeted, typeof(XmlDialog)) as XmlDialog; - - if (xd == null) - { - from.SendMessage("Target has no XmlDialog attachment"); - - // TODO: ask whether they would like to add one - from.SendGump(new XmlConfirmAddGump(from, targeted)); - - return; - } - - from.SendGump(new XmlEditDialogGump(from, true, xd, -1, 0, null, false, null, 0, 0)); - } - } - - public class XmlConfirmAddGump : Gump - { - private Mobile m_From; - private object m_Targeted; - - public XmlConfirmAddGump(Mobile from, object targeted) : base (0, 0) - { - if (from == null || targeted == null) - { - return; - } - - m_Targeted = targeted; - m_From = from; - - Closable = false; - Draggable = true; - AddPage(0); - AddBackground(10, 200, 200, 130, 5054); - - AddLabel(20, 210, 68, "Add an XmlDialog to target?"); - - string name = null; - if (targeted is Item item) - { - name = item.Name; - } - else - if (targeted is Mobile mobile) - { - name = mobile.Name; - } - - if (name == null) - { - name = targeted.GetType().Name; - } - AddLabel(20, 230, 0, $"{name}"); - - AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio - AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio - AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff); // Yes - AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff); // No - AddButton(80, 289, 2130, 2129, 3); // Okay button - - } - public override void OnResponse(NetState state, RelayInfo info) - { - if (info == null || state == null || state.Mobile == null) - { - return; - } - - int radiostate = -1; - if (info.Switches.Length > 0) - { - radiostate = info.Switches[0]; - } - switch (info.ButtonID) - { - - default: - { - if (radiostate == 1) - { // accept - - // add the attachment - XmlDialog xd = new XmlDialog(); - XmlAttach.AttachTo(state.Mobile, m_Targeted, xd); - - // open the editing gump - state.Mobile.SendGump(new XmlEditDialogGump(state.Mobile, true, xd, -1, 0, null, false, null, 0, 0)); - } - break; - } - } - } - } - - public const int MaxLabelLength = 200; - public string TruncateLabel(string s) - { - if (s == null || s.Length < MaxLabelLength) - { - return s; - } - - return s.Substring(0,MaxLabelLength); - } - - public XmlEditDialogGump(Mobile from, bool firststart, - XmlDialog dialog, int selected, int displayfrom, string savefilename, - bool selectall, bool [] selectionlist, int X, int Y) : base(X,Y) - { - - if (from == null || dialog == null) - { - return; - } - - m_Dialog = dialog; - m_From = from; - - m_SelectionList = selectionlist; - if (m_SelectionList == null) - { - m_SelectionList = new bool[MaxEntries]; - } - SaveFilename = savefilename; - - DisplayFrom = displayfrom; - Selected = selected; - - // fill the list with the XmlDialog entries - m_SearchList = dialog.SpeechEntries; - - // prepare the page - int height = 500; - - - AddPage(0); - - AddBackground(0, 0, 755, height, 5054); - AddAlphaRegion(0, 0, 755, height); - - // add the separators - AddImageTiled(10, 80, 735, 4, 0xBB9); - AddImageTiled(10, height -212, 735, 4, 0xBB9); - AddImageTiled(10, height -60, 735, 4, 0xBB9); - - // add the xmldialog properties - int y = 5; - int w = 140; - int x = 5; - int lw = 0; - // the dialog name - AddImageTiled(x, y, w, 21, 0x23F4); - // get the name of the object this is attached to - - if (m_Dialog.AttachedTo is Item item) - { - Name = item.Name; - } - else - if (m_Dialog.AttachedTo is Mobile mobile) - { - Name = mobile.Name; - } - if (Name == null && m_Dialog.AttachedTo != null) - { - Name = m_Dialog.AttachedTo.GetType().Name; - } - AddLabelCropped(x, y, w, 21, 0, Name); - - - x += w + lw + 20; - w = 40; - lw = 90; - // add the proximity range - AddLabel(x, y, 0x384, "ProximityRange"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 140, m_Dialog.ProximityRange.ToString()); - - x += w + lw + 20; - w = 100; - lw = 60; - // reset time - AddLabel(x, y, 0x384, "ResetTime"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 141, m_Dialog.ResetTime.ToString()); - - x += w + lw + 20; - w = 40; - lw = 65; - // speech pace - AddLabel(x, y, 0x384, "SpeechPace"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 142, m_Dialog.SpeechPace.ToString()); - - x += w + lw + 20; - w = 30; - lw = 55; - // allow ghost triggering - AddLabel(x, y, 0x384, "GhostTrig"); - AddCheck(x+lw, y, 0xD2, 0xD3, m_Dialog.AllowGhostTrig, 260); - - // add the triggeroncarried - y += 27; - w = 600; - x = 10; - lw = 100; - AddLabel(10, y, 0x384, "TrigOnCarried"); - AddImageTiled(x + lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 150, TruncateLabel(m_Dialog.TriggerOnCarried)); - AddButton(720, y, 0xFAB, 0xFAD, 5005); - - // add the notriggeroncarried - y += 22; - w = 600; - x = 10; - lw = 100; - AddLabel(x, y, 0x384, "NoTrigOnCarried"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x + lw, y, w, 21, 0, 151, TruncateLabel(m_Dialog.NoTriggerOnCarried)); - AddButton(720, y, 0xFAB, 0xFAD, 5006); - - y = 88; - // column labels - AddLabel(10, y, 0x384, "Edit"); - AddLabel(45, y, 0x384, "#"); - AddLabel(95, y, 0x384, "ID"); - AddLabel(145, y, 0x384, "Depends"); - AddLabel(195, y, 0x384, "Keywords"); - AddLabel(295, y, 0x384, "Text"); - AddLabel(540, y, 0x384, "Action"); - AddLabel(602, y, 0x384, "Condition"); - AddLabel(664, y, 0x384, "Gump"); - - // display the select-all-displayed toggle - AddButton(730, y, 0xD2, 0xD3, 3999); - - y -= 10; - for (int i = 0; i < MaxEntries; i++) - { - int index = i + DisplayFrom; - if (m_SearchList == null || index >= m_SearchList.Count) - { - break; - } - - int page = i/MaxEntriesPerPage; - if (i%MaxEntriesPerPage == 0) - { - AddPage(page+1); - // add highlighted page button - //AddImageTiled(235+page*25, 448, 25, 25, 0xBBC); - //AddImage(238+page*25, 450, 0x8B1+page); - } - - // background for search results area - AddImageTiled(235, y + 22 * (i%MaxEntriesPerPage) + 30, 386, 23, 0x52); - AddImageTiled(236, y + 22 * (i%MaxEntriesPerPage) + 31, 384, 21, 0xBBC); - - - XmlDialog.SpeechEntry s = (XmlDialog.SpeechEntry)m_SearchList[index]; - - if (s == null) - { - continue; - } - - int texthue = 0; - - bool sel=false; - - if (m_SelectionList != null && i < m_SelectionList.Length) - { - sel = m_SelectionList[i]; - } - - // entries with the selection box checked are highlighted in red - if (sel) - { - texthue = 33; - } - - // the selected entry is highlighted in green - if (i == Selected) - { - texthue = 68; - } - - x = 10; - w = 35; - // add the Edit button for each entry - AddButton(10, y + 22 * (i%MaxEntriesPerPage) + 30, 0xFAE, 0xFAF, 1000+i); - - x += w; - w = 50; - // display the entry number - AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC); - AddLabel(x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.EntryNumber.ToString()); - - x += w; - w = 50; - // display the entry ID - AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4); - AddLabel(x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.ID.ToString()); - - x += w; - w = 50; - // display the entry dependson - AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC ); - AddLabel(x, y + 22 * (i%MaxEntriesPerPage) + 31, texthue, s.DependsOn); - - x += w; - w = 100; - // display the entry keywords - AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4); - AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Keywords)); - - x += w; - w = 245; - // display the entry text - AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC); - AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Text)); - - x += w; - w = 62; - // display the action text - AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4); - AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Action)); - - x += w; - w = 62; - // display the condition text - AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0xBBC); - AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Condition)); - - x += w; - w = 62; - // display the gump text - AddImageTiled(x, y + 22 * (i%MaxEntriesPerPage) + 31, w, 21, 0x23F4); - AddLabelCropped(x, y + 22 * (i%MaxEntriesPerPage) + 31, w-5, 21, texthue, TruncateLabel(s.Gump)); - - // display the selection button - AddButton(730, y + 22 * (i%MaxEntriesPerPage) + 32, sel? 0xD3:0xD2, sel? 0xD2:0xD3, 4000+i); - - } - - - // display the selected entry information for editing - XmlDialog.SpeechEntry sentry = null; - if (Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) - { - sentry = (XmlDialog.SpeechEntry)m_SearchList[Selected+ DisplayFrom]; - } - - if (sentry != null) - { - - y = height - 200; - - // add the entry parameters - lw = 15; - w = 40; - x = 10; - int spacing = 11; - - // entry number - AddLabel(x, y, 0x384, "#"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 200, sentry.EntryNumber.ToString()); - - x += w + lw + spacing; - w = 40; - lw = 17; - // ID number - AddLabel(x, y, 0x384, "ID"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 201, sentry.ID.ToString()); - - x += w + lw + spacing; - w = 40; - lw = 65; - // depends on - AddLabel(x, y, 0x384, "DependsOn"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 202, sentry.DependsOn); - - x += w + lw + spacing; - w = 35; - lw = 57; - // prepause - AddLabel(x, y, 0x384, "PrePause"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 203, sentry.PrePause.ToString()); - - x += w + lw + spacing; - w = 35; - lw = 37; - // pause - AddLabel(x, y, 0x384, "Pause"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 204, sentry.Pause.ToString()); - - x += w + lw + spacing; - w = 37; - lw = 26; - // speech hue - AddLabel(x, y, 0x384, "Hue"); - AddImageTiled(x+lw, y, w, 21, 0xBBC); - AddTextEntry(x+lw, y, w, 21, 0, 205, sentry.SpeechHue.ToString()); - - x += w + lw + spacing; - w = 20; - lw = 52; - // lock conversation - AddLabel(x, y, 0x384, "IgnoreCar"); - AddCheck(x + lw, y, 0xD2, 0xD3, sentry.IgnoreCarried, 252); - - x += w + lw + spacing; - w = 20; - lw = 42; - // lock conversation - AddLabel(x, y, 0x384, "LockOn"); - AddCheck(x+lw, y, 0xD2, 0xD3, sentry.LockConversation, 250); - - x += w + lw + spacing; - w = 20; - lw = 54; - // npctrigger - AddLabel(x, y, 0x384, "AllowNPC"); - AddCheck(x+lw, y, 0xD2, 0xD3, sentry.AllowNPCTrigger, 251); - - - w = 650; - x = 70; - - y += 27; - // add the keyword entry - AddLabel(10, y, 0x384, "Keywords"); - AddImageTiled(x, y, w, 21, 0xBBC); - AddTextEntry(x+1, y, w, 21, 0, 101, sentry.Keywords); - AddButton(720, y, 0xFAB, 0xFAD, 5001); - - y += 22; - // add the text entry - AddLabel(10, y, 0x384, "Text"); - AddImageTiled(x, y, w, 21, 0xBBC); - AddTextEntry(x+1, y, w, 21, 0, 100, sentry.Text); - AddButton(720, y, 0xFAB, 0xFAD, 5000); - - - y += 22; - // add the condition string entry - AddLabel(10, y, 0x384, "Condition"); - AddImageTiled(x, y, w, 21, 0xBBC); - AddTextEntry(x+1, y, w, 21, 0, 102, sentry.Condition); - AddButton(720, y, 0xFAB, 0xFAD, 5002); - - y += 22; - // add the action string entry - AddLabel(10, y, 0x384, "Action"); - AddImageTiled(x, y, w, 21, 0xBBC); - AddTextEntry(x+1, y, w, 21, 0, 103, sentry.Action); - AddButton(720, y, 0xFAB, 0xFAD, 5003); - - y += 22; - // add the gump string entry - AddLabel(10, y, 0x384, "Gump"); - AddImageTiled(x, y, w, 21, 0xBBC); - AddTextEntry(x+1, y, w, 21, 0, 104, sentry.Gump); - AddButton(720, y, 0xFAB, 0xFAD, 5004); - } - - y = height - 50; - - AddLabel(10, y, 0x384, "Config:"); - AddImageTiled(50, y , 120, 19, 0x23F4); - AddLabel(50, y, 0, m_Dialog.ConfigFile); - - if (from.AccessLevel >= XmlSpawner.DiskAccessLevel) - { - - // add the save entry - AddButton(185, y , 0xFA8, 0xFAA, 159); - AddLabel(218, y , 0x384, "Save to file:"); - AddImageTiled(300, y , 180, 19, 0xBBC); - AddTextEntry(300, y, 180, 19, 0, 300, SaveFilename); - } - - // display the item list - if (m_SearchList != null) - { - AddLabel(495, y, 68, $"{m_SearchList.Count} Entries"); - int last = DisplayFrom + MaxEntries < m_SearchList.Count ? DisplayFrom + MaxEntries : m_SearchList.Count; - if (last > 0) - { - AddLabel(595, y, 68, $"Displaying {DisplayFrom}-{last - 1}"); - } - } - - y = height - 25; - - // add run status display - if (m_Dialog.Running) - { - AddButton(10, y-5, 0x2A4E, 0x2A3A, 100); - AddLabel(43, y, 0x384, "On"); - } - else - { - AddButton(10, y-5, 0x2A62, 0x2A3A, 100); - AddLabel(43, y, 0x384, "Off"); - } - - // add the Refresh/Sort button - AddButton(80, y, 0xFAB, 0xFAD, 700); - AddLabel(113, y, 0x384, "Refresh"); - - // add the Add button - AddButton(185, y, 0xFAB, 0xFAD, 155); - AddLabel(218, y, 0x384, "Add"); - - // add the Delete button - AddButton(255, y, 0xFB1, 0xFB3, 156); - AddLabel(283, y, 0x384, "Delete"); - - // add the page buttons - for(int i = 0;i 0) - { - - m_SearchList.Sort(new ListSorter(false)); - - } - } - - private class ListSorter : IComparer - { - private bool Dsort; - public ListSorter(bool descend) => Dsort = descend; - - public int Compare(object x, object y) - { - int xn = 0; - int yn = 0; - - - xn = ((XmlDialog.SpeechEntry)x).EntryNumber; - - yn = ((XmlDialog.SpeechEntry)y).EntryNumber; - - - if (Dsort) - { - return yn - xn; - } - - return xn- yn; - } - } - - - - private void SaveList(Mobile from, string filename) - { - if (m_SearchList == null || m_SelectionList == null) - { - return; - } - - string dirname; - if (System.IO.Directory.Exists(XmlDialog.DefsDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) - { - // put it in the defaults directory if it exists - dirname = $"{XmlDialog.DefsDir}/{filename}"; - } - else - { - // otherwise just put it in the main installation dir - dirname = filename; - } - - // save it to the file - } - - private XmlEditDialogGump Refresh(NetState state) - { - XmlEditDialogGump g = new XmlEditDialogGump(m_From, false, m_Dialog, Selected, - DisplayFrom, SaveFilename, SelectAll, m_SelectionList, X, Y); - state.Mobile.SendGump(g); - return g; - } - - public static void ProcessXmlEditBookEntry(Mobile from, object[] args, string text) - { - - if (from == null || args == null || args.Length < 6) - { - return; - } - - XmlDialog dialog = (XmlDialog)args[0]; - XmlDialog.SpeechEntry entry = (XmlDialog.SpeechEntry)args[1]; - int textid = (int)args[2]; - int selected = (int)args[3]; - int displayfrom = (int)args[4]; - string savefile = (string)args[5]; - - // place the book text into the entry by type - switch (textid) - { - case 0: // text - { - if (entry != null) - { - entry.Text = text; - } - - break; - } - case 1: // keywords - { - if (entry != null) - { - entry.Keywords = text; - } - - break; - } - case 2: // condition - { - if (entry != null) - { - entry.Condition = text; - } - - break; - } - case 3: // action - { - if (entry != null) - { - entry.Action = text; - } - - break; - } - case 4: // gump - { - if (entry != null) - { - entry.Gump = text; - } - - break; - } - case 5: // trigoncarried - { - if (dialog != null) - { - dialog.TriggerOnCarried = text; - } - - break; - } - case 6: // notrigoncarried - { - if (dialog != null) - { - dialog.NoTriggerOnCarried = text; - } - - break; - } - } - - - from.CloseGump(); - - //from.SendGump(new XmlEditDialogGump(from, false, m_Dialog, selected, displayfrom, savefilename, false, null, X, Y)); - from.SendGump(new XmlEditDialogGump(from, true, dialog, selected, displayfrom, savefile, false, null, 0, 0)); - } - - - public override void OnResponse(NetState state, RelayInfo info) - { - if (info == null || state == null || state.Mobile == null || m_Dialog == null) - { - return; - } - - int radiostate = -1; - if (info.Switches.Length > 0) - { - radiostate = info.Switches[0]; - } - - - - TextRelay tr = info.GetTextEntry(400); // displayfrom info - try - { - DisplayFrom = int.Parse(tr.Text); - } - catch{} - - - tr = info.GetTextEntry(300); // savefilename info - if (tr != null) - { - SaveFilename = tr.Text; - } - - if (m_Dialog != null) - { - tr = info.GetTextEntry(140); // proximity range - if (tr != null) - { - try - { - m_Dialog.ProximityRange = int.Parse(tr.Text); - } - catch{} - } - tr = info.GetTextEntry(141); // reset time - if (tr != null) - { - try - { - m_Dialog.ResetTime = TimeSpan.Parse(tr.Text); - } - catch{} - } - tr = info.GetTextEntry(142); // speech pace - if (tr != null) - { - try - { - m_Dialog.SpeechPace = int.Parse(tr.Text); - } - catch{} - } - - tr = info.GetTextEntry(150); // trig on carried - if (tr != null && (m_Dialog.TriggerOnCarried == null || m_Dialog.TriggerOnCarried.Length < 230)) - { - if (tr.Text != null && tr.Text.Trim().Length > 0) - { - m_Dialog.TriggerOnCarried = tr.Text; - } - else - { - m_Dialog.TriggerOnCarried = null; - } - } - - tr = info.GetTextEntry(151); // notrig on carried - if (tr != null && (m_Dialog.NoTriggerOnCarried == null || m_Dialog.NoTriggerOnCarried.Length < 230)) - { - if (tr.Text != null && tr.Text.Trim().Length > 0) - { - m_Dialog.NoTriggerOnCarried = tr.Text; - } - else - { - m_Dialog.NoTriggerOnCarried = null; - } - } - - m_Dialog.AllowGhostTrig = info.IsSwitched(260); // allow ghost triggering - } - - if (m_SearchList != null && Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) - { - // entry information - XmlDialog.SpeechEntry entry = (XmlDialog.SpeechEntry)m_SearchList[Selected + DisplayFrom]; - - tr = info.GetTextEntry(200); // entry number - if (tr != null) - { - try - { - entry.EntryNumber = int.Parse(tr.Text); - } - catch {} - } - - tr = info.GetTextEntry(201); // entry id - if (tr != null) - { - try - { - entry.ID = int.Parse(tr.Text); - } - catch {} - } - - tr = info.GetTextEntry(202); // depends on - if (tr != null) - { - try - { - entry.DependsOn = tr.Text; - } - catch {} - } - - tr = info.GetTextEntry(203); // prepause - if (tr != null) - { - try - { - entry.PrePause = int.Parse(tr.Text); - } - catch {} - } - - tr = info.GetTextEntry(204); // pause - if (tr != null) - { - try - { - entry.Pause = int.Parse(tr.Text); - } - catch {} - } - - tr = info.GetTextEntry(205); // hue - if (tr != null) - { - try - { - entry.SpeechHue = int.Parse(tr.Text); - } - catch {} - } - - tr = info.GetTextEntry(101); // keywords - if (tr != null && (entry.Keywords == null || entry.Keywords.Length < 230)) - { - if (tr.Text != null && tr.Text.Trim().Length > 0) - { - entry.Keywords = tr.Text; - } - else - { - entry.Keywords = null; - } - - } - - tr = info.GetTextEntry(100); // text - if (tr != null && (entry.Text == null || entry.Text.Length < 230)) - { - if (tr.Text != null && tr.Text.Trim().Length > 0) - { - entry.Text = tr.Text; - } - else - { - entry.Text = null; - } - } - - tr = info.GetTextEntry(102); // condition - if (tr != null && (entry.Condition == null || entry.Condition.Length < 230)) - { - if (tr.Text != null && tr.Text.Trim().Length > 0) - { - entry.Condition = tr.Text; - } - else - { - entry.Condition = null; - } - } - - tr = info.GetTextEntry(103); // action - if (tr != null && (entry.Action == null || entry.Action.Length < 230)) - { - if (tr.Text != null && tr.Text.Trim().Length > 0) - { - entry.Action = tr.Text; - } - else - { - entry.Action = null; - } - } - - tr = info.GetTextEntry(104); // gump - if (tr != null && (entry.Gump == null || entry.Gump.Length < 230)) - { - if (tr.Text != null && tr.Text.Trim().Length > 0) - { - entry.Gump = tr.Text; - } - else - { - entry.Gump = null; - } - } - - entry.LockConversation = info.IsSwitched(250); // lock conversation - entry.AllowNPCTrigger = info.IsSwitched(251); // allow npc - entry.IgnoreCarried = info.IsSwitched(252); // ignorecarried - } - - - - switch (info.ButtonID) - { - - case 0: // Close - { - - m_Dialog.DeleteTextEntryBook(); - - return; - } - case 100: // toggle running status - { - - m_Dialog.Running = !m_Dialog.Running; - - break; - } - case 155: // add new entry - { - - if (m_SearchList != null) - { - // find the last entry - int lastentry = 0; - foreach(XmlDialog.SpeechEntry e in m_SearchList) - { - if (e.EntryNumber > lastentry) - { - lastentry = e.EntryNumber; - } - } - lastentry += 10; - XmlDialog.SpeechEntry se = new XmlDialog.SpeechEntry(); - se.EntryNumber = lastentry; - se.ID = lastentry; - m_SearchList.Add(se); - Selected = m_SearchList.Count -1; - } - break; - } - - case 156: // Delete selected entries - { - XmlEditDialogGump g = Refresh(state); - int allcount = 0; - if (m_SearchList != null) - { - allcount = m_SearchList.Count; - } - - state.Mobile.SendGump(new XmlConfirmDeleteGump(state.Mobile, g, m_SearchList, m_SelectionList, DisplayFrom, SelectAll, allcount)); - return; - } - - case 159: // save to a .npc file - { - - // Create a new gump - Refresh(state); - // try to save - m_Dialog.DoSaveNPC(state.Mobile, SaveFilename, true); - - return; - } - - case 201: // forward block - { - // clear the selections - if (m_SelectionList != null && !SelectAll) - { - Array.Clear(m_SelectionList,0,m_SelectionList.Length); - } - - if (m_SearchList != null && DisplayFrom + MaxEntries < m_SearchList.Count) - { - DisplayFrom += MaxEntries; - // clear any selection - Selected = -1; - } - break; - } - case 202: // backward block - { - // clear the selections - if (m_SelectionList != null && !SelectAll) - { - Array.Clear(m_SelectionList,0,m_SelectionList.Length); - } - - DisplayFrom -= MaxEntries; - if (DisplayFrom < 0) - { - DisplayFrom = 0; - } - - // clear any selection - Selected = -1; - break; - } - - case 700: // Sort - { - // clear any selection - Selected = -1; - // clear the selections - if (m_SelectionList != null && !SelectAll) - { - Array.Clear(m_SelectionList,0,m_SelectionList.Length); - } - - SortFindList(); - break; - } - - case 9998: // refresh the gump - { - // clear any selection - Selected = -1; - break; - } - default: - { - - if (info.ButtonID >= 1000 && info.ButtonID < 1000+ MaxEntries) - { - // flag the entry selected - Selected = info.ButtonID - 1000; - } - else - if (info.ButtonID == 3998) - { - - SelectAll = !SelectAll; - - // dont allow individual selection with the selectall button selected - if (m_SelectionList != null) - { - for(int i = 0; i < MaxEntries;i++) - { - if (i < m_SelectionList.Length) - { - // only toggle the selection list entries for things that actually have entries - m_SelectionList[i] = SelectAll; - } - else - { - break; - } - } - } - } - else - if (info.ButtonID == 3999) - { - - // dont allow individual selection with the selectall button selected - if (m_SelectionList != null && m_SearchList != null && !SelectAll) - { - for(int i = 0; i < MaxEntries;i++) - { - if (i < m_SelectionList.Length) - { - // only toggle the selection list entries for things that actually have entries - if (m_SearchList.Count - DisplayFrom > i) - { - m_SelectionList[i] = !m_SelectionList[i]; - } - } - else - { - break; - } - } - } - } - else - if (info.ButtonID >= 4000 && info.ButtonID < 4000+ MaxEntries) - { - int i = info.ButtonID - 4000; - // dont allow individual selection with the selectall button selected - if (m_SelectionList != null && i >= 0 && i < m_SelectionList.Length && !SelectAll) - { - // only toggle the selection list entries for things that actually have entries - if (m_SearchList != null && m_SearchList.Count - DisplayFrom > i) - { - m_SelectionList[i] = !m_SelectionList[i]; - } - } - } - else - if (info.ButtonID >= 5000 && info.ButtonID < 5100) - { - - - // text entry book buttons - int textid = info.ButtonID - 5000; - - // entry information - XmlDialog.SpeechEntry entry = null; - - if (m_SearchList != null && Selected >= 0 && Selected + DisplayFrom >= 0 && Selected + DisplayFrom < m_SearchList.Count) - { - entry = (XmlDialog.SpeechEntry)m_SearchList[Selected + DisplayFrom]; - } - - string text = String.Empty; - string title = String.Empty; - switch (textid) - { - case 0: // text - { - if (entry != null) - { - text = entry.Text; - } - - title = "Text"; - break; - } - case 1: // keywords - { - if (entry != null) - { - text = entry.Keywords; - } - - title = "Keywords"; - break; - } - case 2: // condition - { - if (entry != null) - { - text = entry.Condition; - } - - title = "Condition"; - break; - } - case 3: // action - { - if (entry != null) - { - text = entry.Action; - } - - title = "Action"; - break; - } - case 4: // gump - { - if (entry != null) - { - text = entry.Gump; - } - - title = "Gump"; - break; - } - case 5: // trigoncarried - { - text = m_Dialog.TriggerOnCarried; - title = "TrigOnCarried"; - break; - } - case 6: // notrigoncarried - { - text = m_Dialog.NoTriggerOnCarried; - title = "NoTrigOnCarried"; - break; - } - } - - object [] args = new object[6]; - - args[0] = m_Dialog; - args[1] = entry; - args[2] = textid; - args[3] = Selected; - args[4] = DisplayFrom; - args[5] = SaveFilename; - - XmlTextEntryBook book = new XmlTextEntryBook(0, String.Empty, m_Dialog.Name, 20, true); - //XmlTextEntryBook book = new XmlTextEntryBook(0, String.Empty, m_Dialog.Name, 20, true, new XmlTextEntryBookCallback(ProcessXmlEditBookEntry), args); - if (m_Dialog.m_TextEntryBook == null) - { - m_Dialog.m_TextEntryBook = new ArrayList(); - } - m_Dialog.m_TextEntryBook.Add(book); - - book.Title = title; - book.Author = Name; - - // fill the contents of the book with the current text entry data - book.FillTextEntryBook(text); - - // put the book at the location of the player so that it can be opened, but drop it below visible range - book.Visible = false; - book.Movable = false; - book.MoveToWorld(new Point3D(state.Mobile.Location.X,state.Mobile.Location.Y,state.Mobile.Location.Z-100), state.Mobile.Map); - - // Create a new gump - Refresh(state); - - // and open it - book.OnDoubleClick(state.Mobile); - - return; - - } - break; - } - } - // Create a new gump - Refresh(state); - } - - - public class XmlConfirmDeleteGump : Gump - { - private ArrayList SearchList; - private bool [] SelectedList; - private Mobile From; - private int DisplayFrom; - private bool selectAll; - XmlEditDialogGump m_Gump; - - public XmlConfirmDeleteGump(Mobile from, XmlEditDialogGump gump, ArrayList searchlist, bool [] selectedlist, int displayfrom, bool selectall, int allcount) : base (0, 0) - { - SearchList = searchlist; - SelectedList = selectedlist; - DisplayFrom = displayfrom; - selectAll = selectall; - m_Gump = gump; - From = from; - Closable = false; - Draggable = true; - AddPage(0); - AddBackground(10, 200, 200, 130, 5054); - int count = 0; - if (selectall) - { - count = allcount; - } - else - { - for(int i =0;i 0) - { - radiostate = info.Switches[0]; - } - switch (info.ButtonID) - { - - default: - { - if (radiostate == 1 && SearchList != null && SelectedList != null) - { // accept - ArrayList dlist = new ArrayList(); - for(int i = 0;i < SearchList.Count;i++) - { - int index = i-DisplayFrom; - if (index >= 0 && index < SelectedList.Length && SelectedList[index] || selectAll) - { - object o = SearchList[i]; - // delete the entry; - dlist.Add(o); - } - } - - foreach(object o in dlist) - { - SearchList.Remove(o); - } - - // clear the selections - Array.Clear(SelectedList,0,SelectedList.Length); - - if (m_Gump != null) - { - state.Mobile.CloseGump(); - m_Gump.Refresh(state); - } - } - break; - } - } - } - } -} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs index 7ad581eba..34ea93a2e 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs @@ -59,7 +59,7 @@ public class XmlFindGump : Gump from.SendGump(gump); if (status_str != null) { - from.SendMessage(33, "XmlFind: {0}", status_str); + from.SendMessage(33, $"XmlFind: {status_str}"); } } } @@ -280,7 +280,7 @@ public class XmlFindGump : Gump if (direction) { // true means allow only mobs greater than the age - if (DateTime.UtcNow - mob.Created > TimeSpan.FromHours(age)) + if (Core.Now - mob.Created > TimeSpan.FromHours(age)) { return true; } @@ -288,7 +288,7 @@ public class XmlFindGump : Gump else { // false means allow only mobs less than the age - if (DateTime.UtcNow - mob.Created < TimeSpan.FromHours(age)) + if (Core.Now - mob.Created < TimeSpan.FromHours(age)) { return true; } @@ -843,7 +843,7 @@ public class XmlFindGump : Gump catch { dorange = false; - e.Mobile.SendMessage("Invalid range argument {0}", e.Arguments[1]); + e.Mobile.SendMessage($"Invalid range argument {e.Arguments[1]}"); } } @@ -1844,7 +1844,7 @@ public class XmlFindGump : Gump return; } } - from.SendMessage("Invalid command: {0}", args[0]); + from.SendMessage($"Invalid command: {args[0]}"); } } } @@ -1987,8 +1987,7 @@ public class XmlFindGump : Gump case 4: // SubSearch { // do the search - string status_str; - m_SearchList = Search(m_SearchCriteria, out status_str); + m_SearchList = Search(m_SearchCriteria, out _); break; } case 150: // Open the map gump From c60c3b62ad9ae246477cfc6f02c01fb9bc01a07b Mon Sep 17 00:00:00 2001 From: Voxpire Date: Wed, 11 Oct 2023 09:51:49 +0100 Subject: [PATCH 3/8] BaseXmlSpawner housekeeping. --- .../Engines/XMLSpawner/BaseXmlSpawner.cs | 1348 +++++++++-------- 1 file changed, 751 insertions(+), 597 deletions(-) diff --git a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs index e7a33b48e..5b652409e 100644 --- a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs @@ -1,14 +1,15 @@ -using Server.Commands; -using Server.Items; using System; using System.Collections.Generic; using System.Globalization; using System.Reflection; -using Server.Engines.XmlSpawner2; + +using Server.Commands; +using Server.Items; namespace Server.Mobiles; public delegate void XmlGumpCallback(Mobile from, object invoker, string response); + public class BaseXmlSpawner { @@ -30,12 +31,17 @@ public class BaseXmlSpawner private static readonly Type typeofTimeSpan = typeof(TimeSpan); private static readonly Type typeofCustomEnum = typeof(CustomEnumAttribute); + private static bool IsParsable(Type t) + { + return t == typeofTimeSpan || t.GetMethod("Parse", m_ParseTypes) != null; + } + private static readonly Type[] m_ParseTypes = { typeof(string) }; private static readonly object[] m_ParseParams = new object[1]; private static object Parse(object o, Type t, string value) { - MethodInfo method = t.GetMethod("Parse", m_ParseTypes); + var method = t.GetMethod("Parse", m_ParseTypes); m_ParseParams[0] = value; @@ -50,25 +56,43 @@ public class BaseXmlSpawner typeof(long), typeof(ulong), typeof(Serial) }; - public static bool IsNumeric(Type t) => Array.IndexOf(m_NumericTypes, t) >= 0; + public static bool IsNumeric(Type t) + { + return Array.IndexOf(m_NumericTypes, t) >= 0; + } private static readonly Type typeofType = typeof(Type); - private static bool IsType(Type t) => t == typeofType; + private static bool IsType(Type t) + { + return t == typeofType; + } private static readonly Type typeofChar = typeof(char); - private static bool IsChar(Type t) => t == typeofChar; + private static bool IsChar(Type t) + { + return t == typeofChar; + } private static readonly Type typeofString = typeof(string); - private static bool IsString(Type t) => t == typeofString; + private static bool IsString(Type t) + { + return t == typeofString; + } - private static bool IsEnum(Type t) => t.IsEnum; + private static bool IsEnum(Type t) + { + return t.IsEnum; + } - private static bool IsCustomEnum(Type t) => t.IsDefined(typeofCustomEnum, false); + private static bool IsCustomEnum(Type t) + { + return t.IsDefined(typeofCustomEnum, false); + } - private enum typeKeyword + private enum TypeKeyword { SET, GOTO, @@ -77,18 +101,13 @@ public class BaseXmlSpawner DESPAWN } - private enum typemodKeyword - { - // Preparing for removal. - } - - private enum valueKeyword + private enum ValueKeyword { PLAYERSINRANGE, RANDNAME } - private enum valuemodKeyword + private enum ValuemodKeyword { INC, MOB, @@ -101,10 +120,9 @@ public class BaseXmlSpawner // if this is null, then COMMANDS can only be issued when triggered by players of the appropriate accesslevel private static readonly string CommandMobileName = null; - private static readonly Dictionary typeKeywordHash = new(); - private static readonly Dictionary typemodKeywordHash = new(); - private static readonly Dictionary valueKeywordHash = new(); - private static readonly Dictionary valuemodKeywordHash = new(); + private static readonly Dictionary typeKeywordHash = new(); + private static readonly Dictionary valueKeywordHash = new(); + private static readonly Dictionary valuemodKeywordHash = new(); private static readonly char[] slashdelim = { '/' }; private static readonly char[] commadelim = { ',' }; @@ -160,13 +178,11 @@ public class BaseXmlSpawner name = name.Trim().ToUpper(); - typeKeywordHash.Remove(name); + _ = typeKeywordHash.Remove(name); - typemodKeywordHash.Remove(name); + _ = valueKeywordHash.Remove(name); - valueKeywordHash.Remove(name); - - valuemodKeywordHash.Remove(name); + _ = valuemodKeywordHash.Remove(name); } public class KeywordTag @@ -211,10 +227,7 @@ public class BaseXmlSpawner if (spawner != null && !spawner.Deleted) { m_TrigMob = spawner.TriggerMob; - if (spawner.m_KeywordTagList == null) - { - spawner.m_KeywordTagList = new List(); - } + 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) { @@ -230,32 +243,32 @@ public class BaseXmlSpawner switch (type) { case 0: // WAIT timer type - { - // start up the timer - DoTimer(delay, m_Delay, condition, gotogroup); - Flags |= KeywordFlags.HoldSpawn; - Flags |= KeywordFlags.Serialize; + { + // start up the timer + DoTimer(delay, m_Delay, condition, gotogroup); + Flags |= KeywordFlags.HoldSpawn; + Flags |= KeywordFlags.Serialize; - break; - } + break; + } case 1: // GUMP type - { - break; - } + { + break; + } case 2: // GOTO type - { - Flags |= KeywordFlags.HoldSequence; - Flags |= KeywordFlags.Serialize; + { + Flags |= KeywordFlags.HoldSequence; + Flags |= KeywordFlags.Serialize; - break; - } + break; + } default: - { - // dont do anything for other types - Flags |= KeywordFlags.Defrag; - break; - } + { + // dont do anything for other types + Flags |= KeywordFlags.Defrag; + break; + } } } } @@ -279,13 +292,10 @@ public class BaseXmlSpawner { m_End = Core.Now + delay; - if (m_Timer != null) - { - m_Timer.Stop(); - } + m_Timer?.Stop(); m_Timer = new KeywordTimer(m_Spawner, this, delay, repeatdelay, condition, gotogroup); - m_Timer.Start(); + _ = m_Timer.Start(); } public void Serialize(IGenericWriter writer) @@ -312,36 +322,36 @@ public class BaseXmlSpawner public void Deserialize(IGenericReader reader) { - int version = reader.ReadInt(); + var version = reader.ReadInt(); switch (version) { case 1: - { - Flags = (KeywordFlags)reader.ReadInt(); - goto case 0; - } + { + Flags = (KeywordFlags)reader.ReadInt(); + goto case 0; + } case 0: + { + m_Spawner = reader.ReadEntity(); + Type = reader.ReadInt(); + Serial = reader.ReadInt(); + if (Type == 0) { - m_Spawner = reader.ReadEntity(); - 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(); + // get any timer info + var delay = reader.ReadTimeSpan(); + m_Delay = reader.ReadTimeSpan(); + m_Condition = reader.ReadString(); + m_Goto = reader.ReadInt(); - TimeSpan timeoutdelay = reader.ReadTimeSpan(); - m_TimeoutEnd = Core.Now + timeoutdelay; - m_Timeout = reader.ReadTimeSpan(); - m_TrigMob = reader.ReadEntity(); + var timeoutdelay = reader.ReadTimeSpan(); + m_TimeoutEnd = Core.Now + timeoutdelay; + m_Timeout = reader.ReadTimeSpan(); + m_TrigMob = reader.ReadEntity(); - DoTimer(delay, m_Delay, m_Condition, m_Goto); - } - break; + DoTimer(delay, m_Delay, m_Condition, m_Goto); } + break; + } } } @@ -352,7 +362,7 @@ public class BaseXmlSpawner private readonly XmlSpawner m_Spawner; private readonly string m_Condition; private readonly int m_Goto; - private TimeSpan m_Repeatdelay; + private readonly TimeSpan m_Repeatdelay; public KeywordTimer(XmlSpawner spawner, KeywordTag tag, TimeSpan delay, TimeSpan repeatdelay, string condition, int gotogroup) : base(delay) @@ -383,7 +393,7 @@ public class BaseXmlSpawner } // spawn the subgroup - m_Spawner.SpawnSubGroup(m_Goto, 0); + _ = m_Spawner.SpawnSubGroup(m_Goto, 0); } // get rid of the temporary tag @@ -435,7 +445,7 @@ public class BaseXmlSpawner public static void RemoveFromTagList(XmlSpawner spawner, KeywordTag tag) { - for (int i = 0; i < spawner.m_KeywordTagList.Count; i++) + for (var i = 0; i < spawner.m_KeywordTagList.Count; i++) { if (tag == spawner.m_KeywordTagList[i]) { @@ -447,7 +457,7 @@ public class BaseXmlSpawner public static KeywordTag GetFromTagList(XmlSpawner spawner, int serial) { - for (int i = 0; i < spawner.m_KeywordTagList.Count; i++) + for (var i = 0; i < spawner.m_KeywordTagList.Count; i++) { if (serial == spawner.m_KeywordTagList[i].Serial) { @@ -459,7 +469,7 @@ public class BaseXmlSpawner private static string InternalGetValue(object o, PropertyInfo p, int index) { - Type type = p.PropertyType; + var type = p.PropertyType; object value = null; if (type.IsPrimitive) @@ -470,7 +480,7 @@ public class BaseXmlSpawner { try { - object arrayvalue = p.GetValue(o, null); + var arrayvalue = p.GetValue(o, null); value = ((IList)arrayvalue)[index]; } catch { } @@ -506,9 +516,15 @@ public class BaseXmlSpawner return $"{p.Name} = {toString}"; } - public static bool IsItem(Type type) => type != null && (type == typeof(Item) || type.IsSubclassOf(typeof(Item))); + public static bool IsItem(Type type) + { + return type != null && (type == typeof(Item) || type.IsSubclassOf(typeof(Item))); + } - public static bool IsMobile(Type type) => type != null && (type == typeof(Mobile) || type.IsSubclassOf(typeof(Mobile))); + 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) { @@ -534,7 +550,7 @@ public class BaseXmlSpawner { try { - MethodInfo info = p.PropertyType.GetMethod("Parse", new[] { typeof(string) }); + var info = p.PropertyType.GetMethod("Parse", new[] { typeof(string) }); if (info != null) { toSet = info.Invoke(null, new object[] { value }); @@ -574,6 +590,17 @@ public class BaseXmlSpawner 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; @@ -594,8 +621,8 @@ public class BaseXmlSpawner try { // parse out the mobile or item name from the value string - int ispace = value.IndexOf(' '); - string valstr = value.Substring(2); + var ispace = value.IndexOf(' '); + var valstr = value.Substring(2); if (ispace > 0) { valstr = value.Substring(2, ispace - 2); @@ -618,11 +645,11 @@ public class BaseXmlSpawner try { - object arrayvalue = p.GetValue(obj, null); + var arrayvalue = p.GetValue(obj, null); - object po = ((IList)arrayvalue)[0]; + var po = ((IList)arrayvalue)[0]; - Type atype = po.GetType(); + var atype = po.GetType(); toSet = Parse(obj, atype, value); } @@ -651,9 +678,9 @@ public class BaseXmlSpawner public static string InternalSetValue(Mobile from, object o, PropertyInfo p, string value, bool shouldLog, int index) { object toSet = null; - Type ptype = p.PropertyType; + var ptype = p.PropertyType; - string result = ConstructFromString(p, p.PropertyType, o, value, ref toSet); + var result = ConstructFromString(p, p.PropertyType, o, value, ref toSet); if (result != null) { @@ -675,7 +702,7 @@ public class BaseXmlSpawner { try { - object arrayvalue = p.GetValue(o, null); + var arrayvalue = p.GetValue(o, null); ((IList)arrayvalue)[index] = toSet; } catch { } @@ -702,36 +729,36 @@ public class BaseXmlSpawner return "Null object"; } - Type type = o.GetType(); + var type = o.GetType(); - PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + var 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, "."); + var arglist = ParseString(name, 2, "."); - string propname = arglist[0]; + var propname = arglist[0]; // do a bit of parsing to handle array references - string[] arraystring = propname.Split('['); - int index = 0; + var arraystring = propname.Split('['); + var 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(']'); + var arrayvalue = arraystring[1].Split(']'); if (arrayvalue.Length > 0) { - int.TryParse(arraystring[0], out index); + _ = int.TryParse(arraystring[0], out index); } } if (arglist.Length == 2) { - PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); + var plookup = LookupPropertyInfo(spawner, type, propname); object po; if (plookup != null) @@ -743,7 +770,7 @@ public class BaseXmlSpawner } // is a nested property with attributes so first get the property - foreach (PropertyInfo p in props) + foreach (var p in props) { if (p.Name.InsensitiveEquals(propname)) { @@ -758,7 +785,7 @@ public class BaseXmlSpawner { // its just a simple single property - PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); + var plookup = LookupPropertyInfo(spawner, type, propname); if (plookup != null) { @@ -767,14 +794,14 @@ public class BaseXmlSpawner return "Property is read only."; } - string returnvalue = InternalSetValue(null, o, plookup, value, false, index); + var returnvalue = InternalSetValue(null, o, plookup, value, false, index); return returnvalue; } // note, looping through all of the props turns out to be a significant performance bottleneck // good place for optimization - foreach (PropertyInfo p in props) + foreach (var p in props) { if (p.Name.InsensitiveEquals(propname)) { @@ -783,7 +810,7 @@ public class BaseXmlSpawner return "Property is read only."; } - string returnvalue = InternalSetValue(null, o, p, value, false, index); + var returnvalue = InternalSetValue(null, o, p, value, false, index); return returnvalue; @@ -801,20 +828,20 @@ public class BaseXmlSpawner return "Null object"; } - Type type = o.GetType(); + var type = o.GetType(); - PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + var 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, "."); + var 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]); + var plookup = LookupPropertyInfo(spawner, type, arglist[0]); object po; if (plookup != null) @@ -825,7 +852,7 @@ public class BaseXmlSpawner return SetPropertyObject(spawner, po, arglist[1], value); } - foreach (PropertyInfo p in props) + foreach (var p in props) { if (p.Name.InsensitiveEquals(arglist[0])) { @@ -842,7 +869,7 @@ public class BaseXmlSpawner // its just a simple single property // use the lookup table for optimization if possible - PropertyInfo plookup = LookupPropertyInfo(spawner, type, name); + var plookup = LookupPropertyInfo(spawner, type, name); if (plookup != null) { @@ -861,7 +888,7 @@ public class BaseXmlSpawner return "Property is not of type Mobile."; } - foreach (PropertyInfo p in props) + foreach (var p in props) { if (p.Name.InsensitiveEquals(name)) { @@ -894,7 +921,7 @@ public class BaseXmlSpawner return null; } - Type type = o.GetType(); + var type = o.GetType(); object po = null; PropertyInfo[] props; @@ -910,10 +937,10 @@ public class BaseXmlSpawner // parse the strings of the form property.attribute into two parts // first get the property - string[] arglist = ParseString(name, 2, "."); - string propname = arglist[0]; + var arglist = ParseString(name, 2, "."); + var propname = arglist[0]; // parse up to 4 comma separated args for special keyword properties - string[] keywordargs = ParseString(propname, 4, ","); + var keywordargs = ParseString(propname, 4, ","); if (keywordargs[0] == "SERIAL") { @@ -948,15 +975,15 @@ public class BaseXmlSpawner } // do a bit of parsing to handle array references - string[] arraystring = arglist[0].Split('['); - int index = -1; + var arraystring = arglist[0].Split('['); + var 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(']'); + var arrayvalue = arraystring[1].Split(']'); if (arrayvalue.Length > 0) { @@ -970,7 +997,7 @@ public class BaseXmlSpawner if (arglist.Length == 2) { // use the lookup table for optimization if possible - PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); + var plookup = LookupPropertyInfo(spawner, type, propname); if (plookup != null) { @@ -988,7 +1015,7 @@ public class BaseXmlSpawner { try { - object arrayvalue = plookup.GetValue(o, null); + var arrayvalue = plookup.GetValue(o, null); po = ((IList)arrayvalue)[index]; } catch { } @@ -1002,7 +1029,7 @@ public class BaseXmlSpawner } // is a nested property with attributes so first get the property - foreach (PropertyInfo p in props) + foreach (var p in props) { //if (Insensitive.Equals(p.Name, arglist[0])) if (p.Name.InsensitiveEquals(propname)) @@ -1021,7 +1048,7 @@ public class BaseXmlSpawner { try { - object arrayvalue = p.GetValue(o, null); + var arrayvalue = p.GetValue(o, null); po = ((IList)arrayvalue)[index]; } catch { } @@ -1038,7 +1065,7 @@ public class BaseXmlSpawner else { // use the lookup table for optimization if possible - PropertyInfo plookup = LookupPropertyInfo(spawner, type, propname); + var plookup = LookupPropertyInfo(spawner, type, propname); if (plookup != null) { @@ -1053,7 +1080,7 @@ public class BaseXmlSpawner } // its just a simple single property - foreach (PropertyInfo p in props) + foreach (var p in props) { //if (Insensitive.Equals(p.Name, name)) if (p.Name.InsensitiveEquals(propname)) @@ -1088,7 +1115,7 @@ public class BaseXmlSpawner // 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; + var terminated = false; str = str.Trim(); if (str[str.Length - 1] != '/') @@ -1107,7 +1134,7 @@ public class BaseXmlSpawner remainder = arglist[1]; } - bool no_error = true; + var no_error = true; // process the modifier string if there is anything while (arglist.Length > 1) @@ -1120,7 +1147,7 @@ public class BaseXmlSpawner // singlearglist will contain the propname and the remainder // for those keywords that do not have value args - string[] singlearglist = ParseSlashArgs(remainder, 2); + var singlearglist = ParseSlashArgs(remainder, 2); if (arglist.Length > 1) { @@ -1129,14 +1156,14 @@ public class BaseXmlSpawner // 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, "["); + var groupedarglist = ParseString(arglist[1], 2, "["); string groupargstring = null; if (groupedarglist.Length > 1) { // take that argument list that should like like arg2/ag3/arg4>/arg5 // need to find the matching ">" - string[] groupargs = ParseToMatchingParen(groupedarglist[1], '[', ']'); + var 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]; @@ -1145,7 +1172,7 @@ public class BaseXmlSpawner // 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(','); + var value_keywordargs = groupedarglist[0].Trim().Split(','); if (!string.IsNullOrEmpty(groupargstring)) { @@ -1157,8 +1184,7 @@ public class BaseXmlSpawner // 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])) + 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 @@ -1168,13 +1194,13 @@ public class BaseXmlSpawner { //support for literal terminator singlearglist = ParseLiteralTerminator(singlearglist[1]); - string lstr = singlearglist[0]; + var 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)); + var result = SetPropertyValue(spawner, o, arglist[0], lstr.Remove(0, 1)); // see if it was successful if (result != "Property has been set.") @@ -1193,7 +1219,7 @@ public class BaseXmlSpawner } else { - string result = SetPropertyValue(spawner, o, arglist[0], arglist[1]); + var result = SetPropertyValue(spawner, o, arglist[0], arglist[1]); // see if it was successful if (result != "Property has been set.") @@ -1214,19 +1240,18 @@ public class BaseXmlSpawner { if (IsValuemodKeyword(value_keywordargs[0])) { - valuemodKeyword kw = valuemodKeywordHash[value_keywordargs[0]]; + var kw = valuemodKeywordHash[value_keywordargs[0]]; - if (kw == valuemodKeyword.INC) + 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"; + var 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)) + if (int.TryParse(value_keywordargs[1], out var min) && int.TryParse(value_keywordargs[2], out var max)) { incvalue = $"{Utility.RandomMinMax(min, max)}"; } @@ -1237,9 +1262,7 @@ public class BaseXmlSpawner incvalue = value_keywordargs[1]; } // get the current property value - Type ptype; - string tmpvalue = GetPropertyValue(spawner, o, arglist[0], out ptype); - + var tmpvalue = GetPropertyValue(spawner, o, arglist[0], out var ptype); // see if it was successful if (ptype == null) @@ -1249,19 +1272,18 @@ public class BaseXmlSpawner } else { - string currentvalue = "0"; + var currentvalue = "0"; try { - string[] arglist2 = ParseString(tmpvalue, 2, "="); - string[] arglist3 = ParseString(arglist2[1], 2, " "); + var arglist2 = ParseString(tmpvalue, 2, "="); + var arglist3 = ParseString(arglist2[1], 2, " "); currentvalue = arglist3[0].Trim(); } catch { } - string tmpstr = currentvalue; + var 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)) + if (double.TryParse(currentvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out var d0) && double.TryParse(incvalue, NumberStyles.Any, CultureInfo.InvariantCulture, out var d1)) { tmpstr = ((int)(d0 + d1)).ToString(); } @@ -1269,7 +1291,7 @@ public class BaseXmlSpawner { 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); + var result = SetPropertyValue(spawner, o, arglist[0], tmpstr); // see if it was successful if (result != "Property has been set.") { @@ -1290,7 +1312,7 @@ public class BaseXmlSpawner remainder = arglist[2]; } - else if (kw == valuemodKeyword.MOB) + else if (kw == ValuemodKeyword.MOB) { // lookup the mob id based on the name. format is /MOB,name[,type]/ if (value_keywordargs.Length > 1) @@ -1309,7 +1331,7 @@ public class BaseXmlSpawner 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); + var result = SetPropertyObject(spawner, o, arglist[0], mob_id); // see if it was successful if (result != "Property has been set.") @@ -1330,9 +1352,9 @@ public class BaseXmlSpawner remainder = arglist[2]; } - else if (kw == valuemodKeyword.TRIGMOB) + else if (kw == ValuemodKeyword.TRIGMOB) { - string result = SetPropertyObject(spawner, o, arglist[0], trigmob); + var result = SetPropertyObject(spawner, o, arglist[0], trigmob); // see if it was successful if (result != "Property has been set.") { @@ -1346,15 +1368,15 @@ public class BaseXmlSpawner remainder = arglist[2]; } - else if (kw == valuemodKeyword.PLAYERSINRANGE) + else if (kw == ValuemodKeyword.PLAYERSINRANGE) { // syntax is PLAYERSINRANGE,range - int nplayers = 0; - int range = 0; + var nplayers = 0; + var range = 0; // get the number of players in range if (value_keywordargs.Length > 1) { - int.TryParse(value_keywordargs[1], out range); + _ = int.TryParse(value_keywordargs[1], out range); } // count nearby players @@ -1383,7 +1405,7 @@ public class BaseXmlSpawner ie.Free(); } - string result = SetPropertyValue(spawner, o, arglist[0], nplayers.ToString()); + var result = SetPropertyValue(spawner, o, arglist[0], nplayers.ToString()); // see if it was successful if (result != "Property has been set.") @@ -1406,13 +1428,13 @@ public class BaseXmlSpawner { //support for literal terminator singlearglist = ParseLiteralTerminator(singlearglist[1]); - string lstr = singlearglist[0]; + var 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)); + var result = SetPropertyValue(spawner, o, arglist[0], lstr.Remove(0, 1)); // see if it was successful if (result != "Property has been set.") { @@ -1430,7 +1452,7 @@ public class BaseXmlSpawner } else { - string result = SetPropertyValue(spawner, o, arglist[0], arglist[1]); + var result = SetPropertyValue(spawner, o, arglist[0], arglist[1]); // see if it was successful if (result != "Property has been set.") { @@ -1460,7 +1482,7 @@ public class BaseXmlSpawner return false; } - bool testreturn = CheckPropertyString(spawner, mobile, testString, out status_str); + var testreturn = CheckPropertyString(spawner, mobile, testString, out status_str); return testreturn; } @@ -1474,7 +1496,7 @@ public class BaseXmlSpawner return false; } - bool testreturn = CheckPropertyString(spawner, ObjectPropertyItem, testString, out status_str); + var testreturn = CheckPropertyString(spawner, ObjectPropertyItem, testString, out status_str); return testreturn; } @@ -1488,15 +1510,12 @@ public class BaseXmlSpawner // look up the info in the current list - if (spawner.PropertyInfoList == null) - { - spawner.PropertyInfoList = new List(); - } + spawner.PropertyInfoList ??= new List(); PropertyInfo pinfo = null; TypeInfo tinfo = null; - foreach (TypeInfo to in spawner.PropertyInfoList) + foreach (var to in spawner.PropertyInfoList) { // check the type if (to.t == type) @@ -1505,7 +1524,7 @@ public class BaseXmlSpawner tinfo = to; // now search the property list - foreach (PropertyInfo p in to.plist) + foreach (var p in to.plist) { if (p.Name.InsensitiveEquals(propname)) { @@ -1522,9 +1541,9 @@ public class BaseXmlSpawner } // 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); + var props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); - foreach (PropertyInfo p in props) + foreach (var p in props) { if (p.Name.InsensitiveEquals(propname)) { @@ -1558,7 +1577,7 @@ public class BaseXmlSpawner return null; } - string str = valstr.Trim(); + var str = valstr.Trim(); // look for keywords // need to handle the case of nested arglists like arg,arg, @@ -1567,41 +1586,40 @@ public class BaseXmlSpawner // 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, "["); + var groupedarglist = ParseString(str, 2, "["); string groupargstring = null; if (groupedarglist.Length > 1) { // take that argument list that should like like arg2/ag3/arg4>/arg5 // need to find the matching ">" - string[] groupargs = ParseToMatchingParen(groupedarglist[1], '[', ']'); + var 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 = groupedarglist[0].Trim().Split(','); + var arglist = groupedarglist[0].Trim().Split(','); if (!string.IsNullOrEmpty(groupargstring) && arglist.Length > 0) { arglist[arglist.Length - 1] = groupargstring; } - - string pname = arglist[0].Trim(); - char startc = str[0]; + var pname = arglist[0].Trim(); + var startc = str[0]; // first see whether it is a standard numeric value - if (startc == '.' || startc == '-' || startc == '+' || startc >= '0' && startc <= '9') + if (startc is '.' or '-' or '+' or >= '0' and <= '9') { // determine the type - ptype = str.IndexOf(".") >= 0 ? typeof(double) : typeof(int); + ptype = str.Contains('.') ? typeof(double) : typeof(int); return str; } - if (startc == '"' || startc == '(') + if (startc is '"' or '(') { ptype = typeof(string); return str; @@ -1614,7 +1632,7 @@ public class BaseXmlSpawner } // or a bool - if (str.ToLower() == "true" || str.ToLower() == "false") + if (str.ToLower() is "true" or "false") { ptype = typeof(bool); return str; @@ -1623,23 +1641,22 @@ public class BaseXmlSpawner if (IsValueKeyword(pname)) { - valueKeyword kw = valueKeywordHash[pname]; + var kw = valueKeywordHash[pname]; - if (kw == valueKeyword.PLAYERSINRANGE && arglist.Length > 1) + if (kw == ValueKeyword.PLAYERSINRANGE && arglist.Length > 1) { // syntax is PLAYERSINRANGE,range ptype = typeof(int); - int nplayers = 0; - int range; + var nplayers = 0; // get the number of players in range - int.TryParse(arglist[1], out range); + _ = int.TryParse(arglist[1], out var range); // count nearby players if (spawner?.SpawnRegion != null && range < 0) { - foreach (Mobile p in spawner.SpawnRegion.GetPlayers()) + foreach (var p in spawner.SpawnRegion.GetPlayers()) { if (p.AccessLevel <= spawner.TriggerAccessLevel) { @@ -1674,7 +1691,7 @@ public class BaseXmlSpawner return nplayers.ToString(); } - if (kw == valueKeyword.RANDNAME && arglist.Length > 1) + if (kw == ValueKeyword.RANDNAME && arglist.Length > 1) { // syntax is RANDNAME,nametype return NameList.RandomName(arglist[1]); @@ -1691,7 +1708,7 @@ public class BaseXmlSpawner } // otherwise treat it as a property name - string result = GetPropertyValue(spawner, o, pname, out ptype); + var result = GetPropertyValue(spawner, o, pname, out ptype); return ParseGetValue(result, ptype); } @@ -1709,14 +1726,14 @@ public class BaseXmlSpawner } // find the separator - string[] arglist = str.Split("=".ToCharArray(), 2); + var 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); + var arglist2 = arglist[1].Trim().Split(" ".ToCharArray(), 2); return arglist2[0]; } @@ -1744,24 +1761,24 @@ public class BaseXmlSpawner return false; } // parse the property test string for and(&)/or(|) operators - string[] arglist = ParseString(testString, 2, "&|"); + var arglist = ParseString(testString, 2, "&|"); if (arglist.Length < 2) { - bool returnval = CheckSingleProperty(spawner, o, testString, out status_str); + var returnval = CheckSingleProperty(spawner, o, testString, out status_str); // simple conditional test with no and/or operators return returnval; } // test each half independently and combine the results - bool first = CheckSingleProperty(spawner, o, arglist[0], out status_str); + var first = CheckSingleProperty(spawner, o, arglist[0], out _); // 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], out status_str); + var second = CheckPropertyString(spawner, o, arglist[1], out status_str); - int andposition = testString.IndexOf("&"); - int orposition = testString.IndexOf("|"); + var andposition = testString.IndexOf("&"); + var orposition = testString.IndexOf("|"); // combine them based upon the operator if (andposition > 0 && orposition <= 0 || andposition > 0 && andposition < orposition) @@ -1794,7 +1811,7 @@ public class BaseXmlSpawner // also support the 'not' operator ~ at the beginning of a test, like ~prop=prop testString = testString.Trim(); - bool invertreturn = false; + var invertreturn = false; if (testString.Length > 0 && testString[0] == '~') { @@ -1802,16 +1819,16 @@ public class BaseXmlSpawner testString = testString.Substring(1, testString.Length - 1); } - string[] arglist = ParseString(testString, 2, "=> 0) { @@ -1839,10 +1856,7 @@ public class BaseXmlSpawner return false; } - Type ptype1; - Type ptype2; - - string value1 = ParseForKeywords(spawner, o, arglist[0].Trim(), false, out ptype1); + var value1 = ParseForKeywords(spawner, o, arglist[0].Trim(), false, out var ptype1); // see if it was successful if (ptype1 == null) @@ -1853,7 +1867,7 @@ public class BaseXmlSpawner //return false; } - string value2 = ParseForKeywords(spawner, o, arglist[1].Trim(), false, out ptype2); + var value2 = ParseForKeywords(spawner, o, arglist[1].Trim(), false, out var ptype2); // see if it was successful if (ptype2 == null) @@ -1865,8 +1879,8 @@ public class BaseXmlSpawner } // look for hex numeric specifications - int base1 = 10; - int base2 = 10; + var base1 = 10; + var base2 = 10; if (IsNumeric(ptype1) && !string.IsNullOrEmpty(value1) && value1.StartsWith("0x")) { base1 = 16; @@ -1882,8 +1896,7 @@ public class BaseXmlSpawner { if (hasequal) { - TimeSpan ts1, ts2; - if (TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2)) + if (TimeSpan.TryParse(value1, out var ts1) && TimeSpan.TryParse(value2, out var ts2)) { if (ts1 == ts2) { @@ -1897,8 +1910,7 @@ public class BaseXmlSpawner } else if (hasnotequals) { - TimeSpan ts1, ts2; - if (TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2)) + if (TimeSpan.TryParse(value1, out var ts1) && TimeSpan.TryParse(value2, out var ts2)) { if (ts1 != ts2) { @@ -1912,8 +1924,7 @@ public class BaseXmlSpawner } else if (hasgreaterthan) { - TimeSpan ts1, ts2; - if (TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2)) + if (TimeSpan.TryParse(value1, out var ts1) && TimeSpan.TryParse(value2, out var ts2)) { if (ts1 > ts2) { @@ -1927,8 +1938,7 @@ public class BaseXmlSpawner } else { - TimeSpan ts1, ts2; - if (TimeSpan.TryParse(value1, out ts1) && TimeSpan.TryParse(value2, out ts2)) + if (TimeSpan.TryParse(value1, out var ts1) && TimeSpan.TryParse(value2, out var ts2)) { if (ts1 < ts2) { @@ -1942,13 +1952,12 @@ public class BaseXmlSpawner } } else - // and do the type dependent comparisons + // and do the type dependent comparisons if (ptype2 == typeof(DateTime) || ptype1 == typeof(DateTime)) { if (hasequal) { - DateTime dt1, dt2; - if (DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) + if (DateTime.TryParse(value1, out var dt1) && DateTime.TryParse(value2, out var dt2)) { if (dt1 == dt2) { @@ -1962,8 +1971,7 @@ public class BaseXmlSpawner } else if (hasnotequals) { - DateTime dt1, dt2; - if (DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) + if (DateTime.TryParse(value1, out var dt1) && DateTime.TryParse(value2, out var dt2)) { if (dt1 != dt2) { @@ -1977,8 +1985,7 @@ public class BaseXmlSpawner } else if (hasgreaterthan) { - DateTime dt1, dt2; - if (DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) + if (DateTime.TryParse(value1, out var dt1) && DateTime.TryParse(value2, out var dt2)) { if (dt1 > dt2) { @@ -1992,8 +1999,7 @@ public class BaseXmlSpawner } else { - DateTime dt1, dt2; - if (DateTime.TryParse(value1, out dt1) && DateTime.TryParse(value2, out dt2)) + if (DateTime.TryParse(value1, out var dt1) && DateTime.TryParse(value2, out var dt2)) { if (dt1 < dt2) { @@ -2317,8 +2323,12 @@ public class BaseXmlSpawner return invertreturn; } - public static Item SearchMobileForItem(Mobile m, string targetName, string typeStr, bool searchbank) => SearchMobileForItem(m, targetName, typeStr, searchbank, false); +#if XML_QUESTS + 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) { @@ -2326,11 +2336,11 @@ public class BaseXmlSpawner if (m != null && !m.Deleted) { // go through all of the items in the pack - List packlist = m.Items; + var packlist = m.Items; - for (int i = 0; i < packlist.Count; ++i) + for (var i = 0; i < packlist.Count; ++i) { - Item item = packlist[i]; + var item = packlist[i]; // dont search bank boxes if (item is BankBox && !searchbank && !equippedonly) @@ -2343,7 +2353,7 @@ public class BaseXmlSpawner { if (item is Container container && !equippedonly) { - Item itemTarget = SearchPackForItem(container, targetName, typeStr); + var itemTarget = SearchPackForItem(container, targetName, typeStr); if (itemTarget != null) { @@ -2364,13 +2374,13 @@ public class BaseXmlSpawner } } // now check any item that might be held - Item held = m.Holding; + var held = m.Holding; if (held != null && !held.Deleted && !equippedonly) { if (held is Container container) { - Item itemTarget = SearchPackForItem(container, targetName, typeStr); + var itemTarget = SearchPackForItem(container, targetName, typeStr); if (itemTarget != null) { @@ -2402,18 +2412,18 @@ public class BaseXmlSpawner } // go through all of the items in the pack - List packlist = pack.Items; + var packlist = pack.Items; - for (int i = 0; i < packlist.Count; ++i) + for (var i = 0; i < packlist.Count; ++i) { - Item item = packlist[i]; + var item = packlist[i]; if (item != null && !item.Deleted) { if (item is Container container) { - Item itemTarget = SearchPackForItem(container, targetName, typestr); + var itemTarget = SearchPackForItem(container, targetName, typestr); if (itemTarget != null) { @@ -2434,11 +2444,13 @@ public class BaseXmlSpawner } return null; } - private static bool CheckNameMatch(string targetname, string name) => + private static bool CheckNameMatch(string targetname, string name) + { // a "*" targetname will match anything // a null or empty targetname will match a null name // otherwise the strings must match - targetname == "*" || name == targetname || targetname != null && targetname.Length == 0 && name == null; + return targetname == "*" || name == targetname || targetname != null && targetname.Length == 0 && name == null; + } public static bool CheckType(object o, string typename) { @@ -2448,7 +2460,7 @@ public class BaseXmlSpawner } // test the type - Type objecttype = o.GetType(); + var objecttype = o.GetType(); Type targettype = null; @@ -2475,7 +2487,7 @@ public class BaseXmlSpawner } // parse the objective string that might be of the form 'obj &| obj &| obj ...' - string[] arglist = ParseString(objectivestr, 2, "&|"); + var arglist = ParseString(objectivestr, 2, "&|"); if (arglist.Length < 2) { // simple test with no and/or operators @@ -2483,14 +2495,14 @@ public class BaseXmlSpawner } // test each half independently and combine the results - bool first = SingleCheckForCarried(m, arglist[0]); + var 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]); + var second = CheckForCarried(m, arglist[1]); - int andposition = objectivestr.IndexOf("&"); - int orposition = objectivestr.IndexOf("|"); + var andposition = objectivestr.IndexOf("&"); + var orposition = objectivestr.IndexOf("|"); // combine them based upon the operator if (andposition > 0 && orposition <= 0 || andposition > 0 && andposition < orposition) @@ -2515,20 +2527,21 @@ public class BaseXmlSpawner return false; } - bool has_valid_item = false; + var 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, ","); + var objstr = ParseString(objectivestr, 8, ","); - string itemname = objstr[0]; + var itemname = objstr[0]; // check for attachment keyword if (itemname == "ATTACHMENT") { +#if XML_ATTACH // syntax is ATTACHMENT,name,type if (objstr.Length > 1) { - string aname = objstr[1]; + var aname = objstr[1]; Type atype = null; if (objstr.Length > 2) { @@ -2539,15 +2552,22 @@ public class BaseXmlSpawner catch { } } + // try to find the attachment on the mob + if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) + { + return true; + } + return false; } +#endif return false; } - bool equippedonly = false; + var equippedonly = false; string typestr = null; - int objoffset = 1; + var objoffset = 1; // is there a type specification? while (objoffset < objstr.Length) @@ -2555,9 +2575,9 @@ public class BaseXmlSpawner if (objstr[objoffset] != null && objstr[objoffset].Length > 0) { - char startc = objstr[objoffset][0]; + var startc = objstr[objoffset][0]; - if (startc >= '0' && startc <= '9') + if (startc is >= '0' and <= '9') { // this is the start of the numeric objective specifications break; @@ -2577,19 +2597,92 @@ public class BaseXmlSpawner objoffset++; } - - Item testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly); + var testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly); // found the item if (testitem != null) { - // is the equippedonly flag set? If so then see if the item is equipped - if (equippedonly && testitem.Parent == m || !equippedonly) + // 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 token) { - has_valid_item = true; + 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 (var n = objoffset; n < objstr.Length; n++) + { + try + { + switch (int.Parse(objstr[n]) - 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; + } + } + } + catch { } + } + } + 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 bool CheckForNotCarried(Mobile m, string objectivestr) @@ -2600,7 +2693,7 @@ public class BaseXmlSpawner } // parse the objective string that might be of the form 'obj &| obj &| obj ...' - string[] arglist = ParseString(objectivestr, 2, "&|"); + var arglist = ParseString(objectivestr, 2, "&|"); if (arglist.Length < 2) { // simple test with no and/or operators @@ -2608,14 +2701,14 @@ public class BaseXmlSpawner } // test each half independently and combine the results - bool first = SingleCheckForNotCarried(m, arglist[0]); + var 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]); + var second = CheckForNotCarried(m, arglist[1]); - int andposition = objectivestr.IndexOf("&"); - int orposition = objectivestr.IndexOf("|"); + var andposition = objectivestr.IndexOf("&"); + var orposition = objectivestr.IndexOf("|"); // for the & operator // notrigger if @@ -2650,19 +2743,20 @@ public class BaseXmlSpawner return true; } - bool has_no_such_item = true; + var 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]; + var objstr = ParseString(objectivestr, 8, ","); + var itemname = objstr[0]; // check for attachment keyword if (itemname == "ATTACHMENT") { +#if XML_ATTACH // syntax is ATTACHMENT,name,type if (objstr.Length > 1) { - string aname = objstr[1]; + var aname = objstr[1]; Type atype = null; if (objstr.Length > 2) { @@ -2673,26 +2767,32 @@ public class BaseXmlSpawner catch { } } + // try to find the attachment on the mob + if (XmlAttach.FindAttachmentOnMobile(m, atype, aname) != null) + { + return false; + } + return true; } +#endif return true; } - bool equippedonly = false; + var equippedonly = false; string typestr = null; - int objoffset = 1; + var objoffset = 1; // is there a type specification? - while (objoffset < objstr.Length) { if (objstr[objoffset] != null && objstr[objoffset].Length > 0) { - char startc = objstr[objoffset][0]; + var startc = objstr[objoffset][0]; - if (startc >= '0' && startc <= '9') + if (startc is >= '0' and <= '9') { // this is the start of the numeric objective specifications break; @@ -2713,19 +2813,91 @@ public class BaseXmlSpawner } // look for the item - Item testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly); + var testitem = SearchMobileForItem(m, itemname, typestr, false, equippedonly); // found the item if (testitem != null) { - // is the equippedonly flag set? If so then see if the item is equipped - if (equippedonly && testitem.Parent == m || !equippedonly) + // 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 token && token.IsValid) { - has_no_such_item = false; + 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 (var n = objoffset; n < objstr.Length; n++) + { + try + { + switch (int.Parse(objstr[n]) - 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; + } + } + } + catch { } + } + } + 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; } +#endif public static Item FindItemByName(XmlSpawner fromspawner, string name, string typestr) { @@ -2734,9 +2906,9 @@ public class BaseXmlSpawner return null; } - int count = 0; + var count = 0; - Item founditem = FindInRecentItemSearchList(fromspawner, name, typestr); + var founditem = FindInRecentItemSearchList(fromspawner, name, typestr); if (founditem != null) { @@ -2750,9 +2922,9 @@ public class BaseXmlSpawner } // search through all items in the world and find the first one with a matching name - foreach (Item item in World.Items.Values) + foreach (var item in World.Items.Values) { - Type itemtype = item.GetType(); + var itemtype = item.GetType(); if (!item.Deleted && (name.Length == 0 || string.Compare(item.Name, name, true) == 0)) { @@ -2786,9 +2958,9 @@ public class BaseXmlSpawner return null; } - int count = 0; + var count = 0; - Mobile foundmobile = FindInRecentMobileSearchList(fromspawner, name, typestr); + var foundmobile = FindInRecentMobileSearchList(fromspawner, name, typestr); if (foundmobile != null) { @@ -2802,9 +2974,9 @@ public class BaseXmlSpawner } // search through all mobiles in the world and find one with a matching name - foreach (Mobile mobile in World.Mobiles.Values) + foreach (var mobile in World.Mobiles.Values) { - Type mobtype = mobile.GetType(); + var mobtype = mobile.GetType(); if (!mobile.Deleted && (name.Length == 0 || string.Compare(mobile.Name, name, true) == 0) && (typestr == null || targettype != null && (mobtype.Equals(targettype) || mobtype.IsSubclassOf(targettype)))) { @@ -2846,17 +3018,17 @@ public class BaseXmlSpawner } // do a quick search through the recent search list to see if it is there - XmlSpawner foundspawner = FindInRecentSpawnerSearchList(fromspawner, name); + var foundspawner = FindInRecentSpawnerSearchList(fromspawner, name); if (foundspawner != null) { return foundspawner; } - int count = 0; + var count = 0; // search through all xmlspawners in the world and find one with a matching name - foreach (Item item in World.Items.Values) + foreach (var item in World.Items.Values) { if (item is XmlSpawner spawner) { @@ -2890,10 +3062,7 @@ public class BaseXmlSpawner return; } - if (spawner.RecentSpawnerSearchList == null) - { - spawner.RecentSpawnerSearchList = new List(); - } + spawner.RecentSpawnerSearchList ??= new List(); spawner.RecentSpawnerSearchList.Add(target); // check the length and truncate if it gets too long @@ -2913,15 +3082,12 @@ public class BaseXmlSpawner List deletelist = null; XmlSpawner foundspawner = null; - foreach (XmlSpawner s in spawner.RecentSpawnerSearchList) + foreach (var s in spawner.RecentSpawnerSearchList) { if (s.Deleted) { // clean it up - if (deletelist == null) - { - deletelist = new List(); - } + deletelist ??= new List(); deletelist.Add(s); } @@ -2935,9 +3101,9 @@ public class BaseXmlSpawner if (deletelist != null) { - foreach (XmlSpawner i in deletelist) + foreach (var i in deletelist) { - spawner.RecentSpawnerSearchList.Remove(i); + _ = spawner.RecentSpawnerSearchList.Remove(i); } } @@ -2951,10 +3117,7 @@ public class BaseXmlSpawner return; } - if (spawner.RecentItemSearchList == null) - { - spawner.RecentItemSearchList = new List(); - } + spawner.RecentItemSearchList ??= new List(); spawner.RecentItemSearchList.Add(target); @@ -2981,15 +3144,12 @@ public class BaseXmlSpawner targettype = AssemblyHandler.FindTypeByName(typestr); } - foreach (Item item in spawner.RecentItemSearchList) + foreach (var item in spawner.RecentItemSearchList) { if (item.Deleted) { // clean it up - if (deletelist == null) - { - deletelist = new List(); - } + deletelist ??= new List(); deletelist.Add(item); } @@ -3007,9 +3167,9 @@ public class BaseXmlSpawner if (deletelist != null) { - foreach (Item i in deletelist) + foreach (var i in deletelist) { - spawner.RecentItemSearchList.Remove(i); + _ = spawner.RecentItemSearchList.Remove(i); } } @@ -3023,10 +3183,7 @@ public class BaseXmlSpawner return; } - if (spawner.RecentMobileSearchList == null) - { - spawner.RecentMobileSearchList = new List(); - } + spawner.RecentMobileSearchList ??= new List(); spawner.RecentMobileSearchList.Add(target); @@ -3053,15 +3210,12 @@ public class BaseXmlSpawner targettype = AssemblyHandler.FindTypeByName(typestr); } - foreach (Mobile m in spawner.RecentMobileSearchList) + foreach (var m in spawner.RecentMobileSearchList) { if (m.Deleted) { // clean it up - if (deletelist == null) - { - deletelist = new List(); - } + deletelist ??= new List(); deletelist.Add(m); } @@ -3080,9 +3234,9 @@ public class BaseXmlSpawner if (deletelist != null) { - foreach (Mobile i in deletelist) + foreach (var i in deletelist) { - spawner.RecentMobileSearchList.Remove(i); + _ = spawner.RecentMobileSearchList.Remove(i); } } @@ -3091,42 +3245,42 @@ public class BaseXmlSpawner public static string ApplySubstitution(XmlSpawner spawner, object o, string typeName) { - System.Text.StringBuilder sb = new System.Text.StringBuilder(); + var sb = new System.Text.StringBuilder(); // go through the string looking for instances of {keyword} - string remaining = typeName; + var remaining = typeName; while (!string.IsNullOrEmpty(remaining)) { - int startindex = remaining.IndexOf('{'); + var 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); + _ = sb.Append(remaining); break; } // might be a substitution, check for keywords - int endindex = remaining.Substring(startindex + 1).IndexOf("}"); + var endindex = remaining.Substring(startindex + 1).IndexOf("}"); // if the ending delimiter cannot be found then just append and finish if (endindex == -1) { - sb.Append(remaining); + _ = sb.Append(remaining); break; } // get the string up to the delimiter - string firstpart = remaining.Substring(0, startindex); - sb.Append(firstpart); + var firstpart = remaining.Substring(0, startindex); + _ = sb.Append(firstpart); - string keypart = remaining.Substring(startindex + 1, endindex); + var keypart = remaining.Substring(startindex + 1, endindex); // try to evaluate and then substitute the arg - string value = ParseForKeywords(spawner, o, keypart.Trim(), true, out _); + var value = ParseForKeywords(spawner, o, keypart.Trim(), true, out _); // trim off the " from strings if (value != null) @@ -3135,7 +3289,7 @@ public class BaseXmlSpawner } // replace the parsed value for the keyword - sb.Append(value); + _ = sb.Append(value); // continue processing the rest of the string if (endindex + startindex + 2 >= remaining.Length) @@ -3150,11 +3304,11 @@ public class BaseXmlSpawner public static string ParseObjectType(string str) { - string[] arglist = ParseSlashArgs(str, 2); + var 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); + var typeargs = ParseCommaArgs(arglist[0], 2); if (typeargs.Length > 1) { return typeargs[0]; @@ -3167,14 +3321,14 @@ public class BaseXmlSpawner public static string[] ParseObjectArgs(string str) { - string[] arglist = ParseSlashArgs(str, 2); + var arglist = ParseSlashArgs(str, 2); if (arglist.Length > 0) { - string itemtypestring = arglist[0]; + var 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; + var argstart = 0; if (!string.IsNullOrEmpty(itemtypestring)) { argstart = itemtypestring.IndexOf(",") + 1; @@ -3194,10 +3348,10 @@ public class BaseXmlSpawner // 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++) + var nopen = 1; + var nclose = 0; + var splitpoint = str.Length; + for (var i = 0; i < str.Length; i++) { // walk through the string until a matching close delimstr is found if (str[i] == opendelim) @@ -3217,7 +3371,7 @@ public class BaseXmlSpawner } } - string[] args = new string[2]; + var args = new string[2]; // allow missing closing delimiters at the end of the line, basically just treat eol as a closing delim @@ -3238,9 +3392,9 @@ public class BaseXmlSpawner return null; } - char[] delims = delimstr.ToCharArray(); + var delims = delimstr.ToCharArray(); str = str.Trim(); - string[] args = str.Split(delims, nitems); + var args = str.Split(delims, nitems); return args; } @@ -3254,18 +3408,17 @@ public class BaseXmlSpawner str = str.Trim(); - string[] args; // this supports strings that may have special html formatting in them that use the / - if (str.IndexOf("= 0 || str.IndexOf("/>") >= 0) + if (str.Contains("")) { // or use indexof to do it with more context control - List tmparray = new List(); + var tmparray = new List(); // find the next slash char - int index = 0; - int preindex = 0; - int searchindex = 0; - int length = str.Length; + var index = 0; + var preindex = 0; + var searchindex = 0; + var length = str.Length; while (index >= 0 && searchindex < length && tmparray.Count < nitems - 1) { index = str.IndexOf('/', searchindex); @@ -3321,7 +3474,7 @@ public class BaseXmlSpawner str = str.Trim(); - string[] args = str.Split(commadelim, nitems); + var args = str.Split(commadelim, nitems); return args; } @@ -3334,7 +3487,7 @@ public class BaseXmlSpawner str = str.Trim(); - string[] args = str.Split(literalend, 2); + var args = str.Split(literalend, 2); return args; } @@ -3347,7 +3500,7 @@ public class BaseXmlSpawner str = str.Trim(); - string[] args = str.Split(semicolondelim, nitems); + var args = str.Split(semicolondelim, nitems); return args; } @@ -3358,8 +3511,8 @@ public class BaseXmlSpawner return null; } - int lastindex = 0; - List strargs = new List(); + var lastindex = 0; + var strargs = new List(); while (true) { // go through the string and find the first instance of the separator @@ -3371,7 +3524,7 @@ public class BaseXmlSpawner break; } - string arg = str.Substring(lastindex, index); + var arg = str.Substring(lastindex, index); strargs.Add(arg); @@ -3379,8 +3532,8 @@ public class BaseXmlSpawner } // now make the string args - string[] args = new string[strargs.Count]; - for (int i = 0; i < strargs.Count; i++) + var args = new string[strargs.Count]; + for (var i = 0; i < strargs.Count; i++) { args[i] = strargs[i]; } @@ -3427,7 +3580,7 @@ public class BaseXmlSpawner // if this is in any container such as a pack then add to the container. if (spawner.Parent is Container parent) { - Point3D loc = spawner.Location; + var loc = spawner.Location; if (!smartspawn) { @@ -3452,12 +3605,12 @@ public class BaseXmlSpawner { // if the spawn entry is in a subgroup and has a packrange, then get the packcoord - Point3D packcoord = Point3D.Zero; + var packcoord = Point3D.Zero; if (theSpawn.PackRange >= 0 && theSpawn.SubGroup > 0) { packcoord = spawner.GetPackCoord(theSpawn.SubGroup); } - Point3D loc = spawner.GetSpawnPosition(requiresurface, theSpawn.PackRange, packcoord, spawnpositioning); + var loc = spawner.GetSpawnPosition(requiresurface, theSpawn.PackRange, packcoord, spawnpositioning); if (!smartspawn) { @@ -3496,13 +3649,15 @@ public class BaseXmlSpawner // 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 - ApplyObjectStringProperties(spawner, propertyString, item, trigmob, spawner, out status_str); + _ = ApplyObjectStringProperties(spawner, propertyString, item, trigmob, spawner, out status_str); } public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, - Mobile triggermob, Map map, out string status_str) => - SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, + Mobile triggermob, Map map, out string status_str) + { + return SpawnTypeKeyword(invoker, TheSpawn, typeName, substitutedtypeName, triggermob, map, out status_str, 0); + } public static bool SpawnTypeKeyword(object invoker, XmlSpawner.SpawnObject TheSpawn, string typeName, string substitutedtypeName, Mobile triggermob, Map map, out string status_str, byte loops) { @@ -3513,262 +3668,261 @@ public class BaseXmlSpawner return false; } - XmlSpawner spawner = invoker as XmlSpawner; + var spawner = invoker as XmlSpawner; // check for any special keywords that might appear in the type such as SET, GIVE, or TAKE if (IsTypeKeyword(typeName)) { - typeKeyword kw = typeKeywordHash[typeName]; + var kw = typeKeywordHash[typeName]; switch (kw) { - case typeKeyword.SET: + case TypeKeyword.SET: + { + // the syntax is SET/prop/value/prop2/value... + // check for the SET,itemname or serialno[,itemtype]/prop/value form is used + var arglist = ParseSlashArgs(substitutedtypeName, 3); + var keywordargs = ParseString(arglist[0], 3, ","); + + if (keywordargs.Length > 1) { - // 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) { - string typestr = null; - if (keywordargs.Length > 2) - { - typestr = keywordargs[2]; - } + typestr = keywordargs[2]; + } - // is the itemname a serialno? - object setitem = null; - if (keywordargs[1].StartsWith("0x")) + // is the itemname a serialno? + object setitem = null; + if (keywordargs[1].StartsWith("0x")) + { + uint serial; + try { - uint serial; - try - { - serial = Convert.ToUInt32(keywordargs[1], 16); - setitem = World.FindEntity((Serial)serial); - } - catch { } - } - else - { - // just look it up by name - setitem = FindItemByName(spawner, keywordargs[1], typestr); + serial = Convert.ToUInt32(keywordargs[1], 16); + setitem = World.FindEntity((Serial)serial); } + catch { } + } + else + { + // just look it up by name + setitem = FindItemByName(spawner, keywordargs[1], typestr); + } - if (setitem == null) + if (setitem == null) + { + status_str = $"cant find unique item :{keywordargs[1]}"; + return false; + } + + _ = 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.DESPAWN: + { + // the syntax is DESPAWN[,spawnername],subgroup + + // first find the spawner and group + var subgroup = -1; + var arglist = ParseSlashArgs(substitutedtypeName, 3); + var targetspawner = spawner; + if (arglist.Length > 0) + { + var keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length < 2) + { + status_str = "missing subgroup in DESPAWN"; + return false; + } + + var 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 + var subgroup = -1; + var arglist = ParseSlashArgs(substitutedtypeName, 3); + var targetspawner = spawner; + if (arglist.Length > 0) + { + var keywordargs = ParseString(arglist[0], 3, ","); + if (keywordargs.Length < 2) + { + status_str = "missing subgroup in SPAWN"; + return false; + } + + var 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 = $"cant find unique item :{keywordargs[1]}"; + status_str = "recursive looping stop in SPAWN"; return false; } - - ApplyObjectStringProperties(spawner, substitutedtypeName, setitem, triggermob, invoker, out status_str); + _ = targetspawner.SpawnSubGroup(subgroup, false, true, (byte)(loops + 1)); } - else if (spawner != null) + else { - ApplyObjectStringProperties(spawner, substitutedtypeName, spawner.SetItem, triggermob, invoker, out status_str); - } - - - 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) + if (loops >= XmlSpawner.MaxLoops) { - status_str = "missing subgroup in DESPAWN"; + status_str = "recursive looping stop in SPAWN"; return false; } - - 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; - } + _ = targetspawner.SpawnSubGroup(subgroup, (byte)(loops + 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: + else { - // 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; - } - - 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; + status_str = "invalid spawner in SPAWN"; + return false; } - case typeKeyword.GOTO: + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } + case TypeKeyword.GOTO: + { + // the syntax is GOTO/subgroup + var arglist = ParseSlashArgs(substitutedtypeName, 3); + var group = -1; + if (arglist.Length < 2) { - // 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; + status_str = "insufficient args to GOTO"; } - case typeKeyword.COMMAND: + else { - // the syntax is COMMAND/commandstring - string[] arglist = ParseSlashArgs(substitutedtypeName, 3); - if (arglist.Length > 0) + if (!int.TryParse(arglist[1], out group)) { - // mod to use a dummy char to issue commands - if (CommandMobileName != null) + 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 + var arglist = ParseSlashArgs(substitutedtypeName, 3); + if (arglist.Length > 0) + { + // mod to use a dummy char to issue commands + if (CommandMobileName != null) + { + var dummy = FindMobileByName(spawner, CommandMobileName, "Mobile"); + if (dummy != null) { - Mobile dummy = FindMobileByName(spawner, CommandMobileName, "Mobile"); - if (dummy != null) - { - CommandSystem.Handle(dummy, $"{CommandSystem.Prefix}{arglist[1]}"); - } - } - else - if (triggermob != null && !triggermob.Deleted) - { - CommandSystem.Handle(triggermob, $"{CommandSystem.Prefix}{arglist[1]}"); + _ = CommandSystem.Handle(dummy, $"{CommandSystem.Prefix}{arglist[1]}"); } } else + if (triggermob != null && !triggermob.Deleted) { - status_str = "insufficient args to COMMAND"; + _ = CommandSystem.Handle(triggermob, $"{CommandSystem.Prefix}{arglist[1]}"); } - - TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); - - break; } + else + { + status_str = "insufficient args to COMMAND"; + } + + TheSpawn.SpawnedObjects.Add(new KeywordTag(substitutedtypeName, spawner)); + + break; + } default: - { - status_str = "unrecognized keyword"; - // should never get here - break; - } + { + status_str = "unrecognized keyword"; + // should never get here + break; + } } // indicate successful keyword spawn return true; @@ -3781,21 +3935,21 @@ public class BaseXmlSpawner public static List GetItems(Region r) { - List list = new List(); + var list = new List(); if (r == null) { return list; } - Sector[] sectors = r.Sectors; + var sectors = r.Sectors; if (sectors != null) { - for (int i = 0; i < sectors.Length; i++) + for (var i = 0; i < sectors.Length; i++) { - Sector sector = sectors[i]; + var sector = sectors[i]; - foreach (Item item in sector.Items) + foreach (var item in sector.Items) { if (Region.Find(item.Location, item.Map).IsPartOf(r)) { From a823299a7cb54863fb7cddfef7a91c84de2e8a9e Mon Sep 17 00:00:00 2001 From: Voxpire Date: Wed, 11 Oct 2023 10:57:23 +0100 Subject: [PATCH 4/8] XmlSpawner housekeeping. --- .../Engines/XMLSpawner/XmlSpawner.cs | 5242 ++++++++--------- 1 file changed, 2448 insertions(+), 2794 deletions(-) diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs index d0c629154..42f9bdd71 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs @@ -1,10 +1,3 @@ -using Server.Accounting; -using Server.Commands; -using Server.Commands.Generic; -using Server.ContextMenus; -using Server.Items; -using Server.Network; -using Server.Targeting; using System; using System.Collections.Generic; using System.Data; @@ -12,7 +5,15 @@ using System.Diagnostics; using System.IO; using System.Reflection; using System.Xml; + +using Server.Accounting; +using Server.Commands; +using Server.Commands.Generic; +using Server.ContextMenus; using Server.Engines.Spawners; +using Server.Items; +using Server.Network; +using Server.Targeting; namespace Server.Mobiles; @@ -67,7 +68,7 @@ public class XmlSpawner : Item, ISpawner private const string XmlTableName = "Properties"; private const string XmlDataSetName = "XmlSpawner"; public static AccessLevel DiskAccessLevel = AccessLevel.Administrator; // minimum access level required by commands that can access the disk such as XmlLoad, XmlSave, and the Save function of XmlEdit -#if (RESTRICTConstructible) +#if RESTRICTConstructible public static AccessLevel ConstructibleAccessLevel = AccessLevel.GameMaster; // only allow spawning of objects that have Constructible access restrictions at this level or lower. Must define RESTRICTConstructible to enable this. #endif private static int MaxMoveCheck = 10; // limit number of players that can be checked for triggering in a single OnMovement tick @@ -83,7 +84,7 @@ public class XmlSpawner : Item, ISpawner private static TimeSpan defTODStart = TimeSpan.FromMinutes(0); private static TimeSpan defTODEnd = TimeSpan.FromMinutes(0); private static TimeSpan defDuration = TimeSpan.FromMinutes(0); - private static TimeSpan defDespawnTime = TimeSpan.FromHours(0); + private static readonly TimeSpan defDespawnTime = TimeSpan.FromHours(0); private static bool defIsGroup; private static int defTeam; private static int defProximityTriggerSound = defaultTriggerSound; @@ -110,13 +111,9 @@ public class XmlSpawner : Item, ISpawner private static readonly Dictionary>[] GlobalSectorTable = new Dictionary>[6]; private string m_Name = string.Empty; - private string m_UniqueId = string.Empty; - private bool m_PlayerCreated; - private bool m_HomeRangeIsRelative; private int m_Team; private int m_HomeRange; - // added a amount parameter for stacked item spawns - private int m_StackAmount; + // this is actually redundant with the width height spec for spawning area // just an easier way of specifying it private int m_SpawnRange; @@ -138,17 +135,10 @@ public class XmlSpawner : Item, ISpawner private int m_Y; private int m_Width; private int m_Height; - private WayPoint m_WayPoint; - private Static m_ShowContainerStatic; private bool m_proximityActivated; private bool m_refractActivated; private bool m_durActivated; - private TimeSpan m_TODStart; - private TimeSpan m_TODEnd; - // time after proximity activation when the spawn cannot be reactivated - private TimeSpan m_MinRefractory; - private TimeSpan m_MaxRefractory; private string m_ItemTriggerName; private string m_NoItemTriggerName; private Item m_ObjectPropertyItem; @@ -157,42 +147,16 @@ public class XmlSpawner : Item, ISpawner public int m_killcount; // added proximity range sensor private int m_ProximityRange; - // sound played when a proximity triggered spawner is tripped by a player - // set this to zero if you dont want to hear anything - private int m_ProximityTriggerSound; - private string m_ProximityTriggerMessage; - private string m_SpeechTrigger; private bool m_speechTriggerActivated; - private string m_MobPropertyName; - private string m_MobTriggerName; - private string m_PlayerPropertyName; - private double m_TriggerProbability = defTriggerProbability; - private Mobile m_mob_who_triggered; - private Item m_SetPropertyItem; - private bool m_skipped; - private int m_KillReset = defKillReset; // number of spawn ticks that pass without kills before killcount gets reset to zero private int m_spawncheck; - private TODModeType m_TODMode = TODModeType.Realtime; - private string m_GumpState; - private bool m_ExternalTriggering; - private bool m_ExternalTrigger; - private int m_SequentialSpawning = -1; // off by default private DateTime m_SeqEnd; private Region m_Region; // 2004.02.08 :: Omega Red private string m_RegionName = string.Empty; // 2004.02.08 :: Omega Red - private AccessLevel m_TriggerAccessLevel = AccessLevel.Player; public List m_TextEntryBook; - private XmlSpawnerGump m_SpawnerGump; - - private bool m_AllowGhostTriggering; - private bool m_AllowNPCTriggering; - private string m_ConfigFile; private bool m_OnHold; private bool m_HoldSequence; - private bool m_SpawnOnTrigger; - private List m_MovementList; private MovementTimer m_MovementTimer; internal List m_KeywordTagList = new(); @@ -200,12 +164,7 @@ public class XmlSpawner : Item, ISpawner public List RecentSpawnerSearchList = null; public List RecentItemSearchList = null; public List RecentMobileSearchList = null; - private TimeSpan m_DespawnTime; - - private string m_SkillTrigger; private SkillName m_skill_that_triggered; - private bool m_FreeRun; // override for all other triggering modes - private Map currentmap; public bool m_IsInactivated; @@ -221,9 +180,6 @@ public class XmlSpawner : Item, ISpawner private bool inrespawn; private List sectorList; - - private bool m_DisableGlobalAutoReset; - private Point3D mostRecentSpawnPosition = Point3D.Zero; // does not decay @@ -247,7 +203,7 @@ public class XmlSpawner : Item, ISpawner { get { - int count = 0; + var count = 0; if (ProximityRange >= 0) { IPooledEnumerable eable = GetMobilesInRange(ProximityRange); @@ -275,10 +231,8 @@ public class XmlSpawner : Item, ISpawner { get { - int hours; - int minutes; - Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); + Clock.GetTime(Map, Location.X, Location.Y, out var hours, out int minutes); return new DateTime(Core.Now.Year, Core.Now.Month, Core.Now.Day, hours, minutes, 0).TimeOfDay; } } @@ -293,15 +247,9 @@ public class XmlSpawner : Item, ISpawner public MoonPhase MoonPhase => Clock.GetMoonPhase(Map, Location.X, Location.Y); - public XmlSpawnerGump SpawnerGump - { - get => m_SpawnerGump; - set => m_SpawnerGump = value; - } + public XmlSpawnerGump SpawnerGump { get; set; } - public bool DisableGlobalAutoReset { get => m_DisableGlobalAutoReset; - set => m_DisableGlobalAutoReset = value; - } + public bool DisableGlobalAutoReset { get; set; } public bool DoDefrag { @@ -316,9 +264,8 @@ public class XmlSpawner : Item, ISpawner } private readonly bool sectorIsActive = false; - private bool UseSectorActivate; - public bool SingleSector => UseSectorActivate; + public bool SingleSector { get; private set; } public bool InActivationRange(Sector s1, Sector s2) { @@ -335,13 +282,13 @@ public class XmlSpawner : Item, ISpawner { get { - Sector ssec = Map.GetSector(Location); + var ssec = Map.GetSector(Location); // go through the spawn lists - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { - for (int x = 0; x < so.SpawnedObjects.Count; x++) + for (var x = 0; x < so.SpawnedObjects.Count; x++) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (o is BaseCreature creature) { @@ -354,9 +301,9 @@ public class XmlSpawner : Item, ISpawner // if the spawn moves into a sector that is not activatable from a sector on the sector list then dont smartspawn if (creature.Map != null && creature.Map != Map.Internal) { - Sector bsec = creature.Map.GetSector(creature.Location); + var bsec = creature.Map.GetSector(creature.Location); - if (UseSectorActivate) + if (SingleSector) { // is it in activatable range of the sector the spawner is in if (!InActivationRange(bsec, ssec)) @@ -366,11 +313,11 @@ public class XmlSpawner : Item, ISpawner } else { - bool outofsec = true; + var outofsec = true; if (sectorList != null) { - foreach (Sector s in sectorList) + foreach (var s in sectorList) { // is the creatures sector within activation range of any of the sectors in the list if (InActivationRange(bsec, s)) @@ -417,7 +364,7 @@ public class XmlSpawner : Item, ISpawner } // confirm that players with the proper access level are present - foreach (Mobile m in players) + foreach (var m in players) { if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden)) { @@ -427,7 +374,7 @@ public class XmlSpawner : Item, ISpawner return false; } // is this a single sector spawner? - if (UseSectorActivate) + if (SingleSector) { return sectorIsActive; } @@ -435,18 +382,18 @@ public class XmlSpawner : Item, ISpawner // if there is no sector list made for this spawner then create one. if (sectorList == null) { - Point3D loc = Location; + var loc = Location; sectorList = new List(); // is this container held? if (Parent != null) { - if (RootParent is Mobile mobile) + if (RootParent is Mobile) { loc = ((Mobile)RootParent).Location; } else - if (RootParent is Item item) + if (RootParent is Item) { loc = ((Item)RootParent).Location; } @@ -454,18 +401,18 @@ public class XmlSpawner : Item, ISpawner // find the max detection range by examining both spawnrange // note, sectors will activate when within +-2 sectors - int bufferzone = 2 * Map.SectorSize; - int x1 = m_X - bufferzone; - int width = m_Width + 2 * bufferzone; - int y1 = m_Y - bufferzone; - int height = m_Height + 2 * bufferzone; + var bufferzone = 2 * Map.SectorSize; + var x1 = m_X - bufferzone; + var width = m_Width + 2 * bufferzone; + var y1 = m_Y - bufferzone; + var height = m_Height + 2 * bufferzone; // go through all of the sectors within the SpawnRange of the spawner to see if any are active - for (int x = x1; x <= x1 + width; x += Map.SectorSize) + for (var x = x1; x <= x1 + width; x += Map.SectorSize) { - for (int y = y1; y <= y1 + height; y += Map.SectorSize) + for (var y = y1; y <= y1 + height; y += Map.SectorSize) { - Sector s = Map.GetSector(new Point3D(x, y, loc.Z)); + var s = Map.GetSector(new Point3D(x, y, loc.Z)); if (s == null) { @@ -473,8 +420,8 @@ public class XmlSpawner : Item, ISpawner } // dont add any redundant sectors - bool duplicate = false; - foreach (Sector olds in sectorList) + var duplicate = false; + foreach (var olds in sectorList) { if (olds == s) { @@ -492,8 +439,7 @@ public class XmlSpawner : Item, ISpawner } // add this sector and the spawner associated with it to the global sector table - List spawnerlist; - if (GlobalSectorTable[Map.MapID].TryGetValue(s, out spawnerlist)) //.Contains(s)) + if (GlobalSectorTable[Map.MapID].TryGetValue(s, out var spawnerlist)) //.Contains(s)) { //List spawnerlist = GlobalSectorTable[Map.MapID][s]; if (spawnerlist == null) @@ -512,8 +458,10 @@ public class XmlSpawner : Item, ISpawner } else { - spawnerlist = new List(); - spawnerlist.Add(this); + spawnerlist = new List + { + this + }; // add a new entry to the table GlobalSectorTable[Map.MapID][s] = spawnerlist; } @@ -530,11 +478,9 @@ public class XmlSpawner : Item, ISpawner { Console.WriteLine("SmartSpawning disabled at {0} {1} : Range too large.", loc, Map); - using (StreamWriter op = new StreamWriter("badspawn.log", true)) - { - op.WriteLine("{0} SmartSpawning disabled at {1} {2} : Range too large.", Core.Now, loc, Map); - op.WriteLine(); - } + using var op = new StreamWriter("badspawn.log", true); + op.WriteLine("{0} SmartSpawning disabled at {1} {2} : Range too large.", Core.Now, loc, Map); + op.WriteLine(); } catch (Exception e) { @@ -547,18 +493,18 @@ public class XmlSpawner : Item, ISpawner } } - UseSectorActivate = false; + SingleSector = false; } _TraceStart(2); // go through the sectorlist and see if any of the sectors are active - foreach (Sector s in sectorList) + foreach (var s in sectorList) { if (s != null && s.Active && s.Clients != null && s.Clients.Count > 0) { // confirm that players with the proper access level are present - foreach (NetState ns in s.Clients) + foreach (var ns in s.Clients) { var m = ns.Mobile; if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden)) @@ -596,11 +542,7 @@ public class XmlSpawner : Item, ISpawner } } - public bool PlayerCreated - { - get => m_PlayerCreated; - set => m_PlayerCreated = value; - } + public bool PlayerCreated { get; set; } public bool OnHold { @@ -617,7 +559,7 @@ public class XmlSpawner : Item, ISpawner return false; } - foreach (BaseXmlSpawner.KeywordTag sot in m_KeywordTagList) + foreach (var sot in m_KeywordTagList) { // check for any keyword tag with the holdspawn flag if (sot != null && !sot.Deleted && (sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSpawn) != 0) @@ -638,10 +580,10 @@ public class XmlSpawner : Item, ISpawner { if (!string.IsNullOrEmpty(value)) { - string str = value.Trim(); - string typestr = BaseXmlSpawner.ParseObjectType(str); + var str = value.Trim(); + var typestr = BaseXmlSpawner.ParseObjectType(str); - Type type = AssemblyHandler.FindTypeByName(typestr); + var type = AssemblyHandler.FindTypeByName(typestr); if (type != null) { @@ -664,16 +606,12 @@ public class XmlSpawner : Item, ISpawner } } - public string UniqueId => m_UniqueId; + public string UniqueId { get; private set; } = string.Empty; // does not perform a defrag, so less accurate but can be used while looping through world object enums public int SafeCurrentCount => SafeTotalSpawnedObjects; - public bool FreeRun - { - get => m_FreeRun; - set => m_FreeRun = value; - } + public bool FreeRun { get; set; } public bool CanFreeSpawn { @@ -682,9 +620,9 @@ public class XmlSpawner : Item, ISpawner // allow free spawning if proximity sensing is off and if all of the potential free-spawning triggers are disabled if (Running && m_ProximityRange == -1 && string.IsNullOrEmpty(m_ObjectPropertyName) && - (string.IsNullOrEmpty(m_MobPropertyName) || - m_MobTriggerName == null || m_MobTriggerName.Length == 0) && - !m_ExternalTriggering) + (string.IsNullOrEmpty(MobTriggerProp) || + MobTriggerName == null || MobTriggerName.Length == 0) && + !ExternalTriggering) { return true; } @@ -701,17 +639,17 @@ public class XmlSpawner : Item, ISpawner if (value != null && value.Length > 0) { - foreach (SpawnObject so in value) + foreach (var so in value) { if (so == null) { continue; } - bool AlreadyInList = false; + var AlreadyInList = false; // Check if the new array has an existing spawn object - foreach (SpawnObject TheSpawn in m_SpawnObjects) + foreach (var TheSpawn in m_SpawnObjects) { if (TheSpawn.TypeName.ToUpper() == so.TypeName.ToUpper()) { @@ -755,7 +693,7 @@ public class XmlSpawner : Item, ISpawner return false; } - foreach (BaseXmlSpawner.KeywordTag sot in m_KeywordTagList) + foreach (var sot in m_KeywordTagList) { // check for any keyword tag with the holdsequence flag if (sot != null && !sot.Deleted && (sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSequence) != 0) @@ -804,7 +742,7 @@ public class XmlSpawner : Item, ISpawner { get { - int nobj = TotalSpawnedObjects; + var nobj = TotalSpawnedObjects; return nobj >= m_Count || nobj >= TotalSpawnObjectCount; } @@ -820,9 +758,9 @@ public class XmlSpawner : Item, ISpawner return 0; } - int count = 0; + var count = 0; - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { count += so.SpawnedObjects.Count; } @@ -843,9 +781,9 @@ public class XmlSpawner : Item, ISpawner // defrag so that accurately reflects currently active spawns Defrag(true); - int count = 0; + var count = 0; - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { count += so.SpawnedObjects.Count; } @@ -861,7 +799,7 @@ public class XmlSpawner : Item, ISpawner return true; } - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { if (so.SpawnedObjects != null && so.SpawnedObjects.Count > 0) { @@ -879,9 +817,9 @@ public class XmlSpawner : Item, ISpawner { get { - int count = 0; + var count = 0; - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { count += so.MaxCount; } @@ -898,7 +836,7 @@ public class XmlSpawner : Item, ISpawner { if (value) { - m_SpawnerGump = null; + SpawnerGump = null; } } } @@ -941,7 +879,7 @@ public class XmlSpawner : Item, ISpawner return; } - foreach (Region region in Region.Regions) + foreach (var region in Region.Regions) { if (string.Compare(region.Name, m_RegionName, true) == 0) { @@ -956,7 +894,6 @@ public class XmlSpawner : Item, ISpawner } } - [CommandProperty(AccessLevel.GameMaster)] public Point3D X1_Y1 { @@ -991,8 +928,8 @@ public class XmlSpawner : Item, ISpawner int X2; int Y2; - int OriginalX2 = m_X + m_Width; - int OriginalY2 = m_Y + m_Height; + var OriginalX2 = m_X + m_Width; + var OriginalY2 = m_Y + m_Height; // reset the sector list ResetSectorList(); @@ -1036,9 +973,9 @@ public class XmlSpawner : Item, ISpawner m_SpawnRange = -1; } - if (m_HomeRangeIsRelative == false) + if (HomeRangeIsRelative == false) { - int NewHomeRange = m_Width > m_Height ? m_Height : m_Width; + var NewHomeRange = m_Width > m_Height ? m_Height : m_Width; m_HomeRange = NewHomeRange > 0 ? NewHomeRange : 0; } @@ -1108,28 +1045,25 @@ public class XmlSpawner : Item, ISpawner { if (value && ShowBounds == false) { - if (m_ShowBoundsItems == null) - { - m_ShowBoundsItems = new List(); - } + m_ShowBoundsItems ??= new List(); // Boundary lines - int ValidX1 = m_X; - int ValidX2 = m_X + m_Width; - int ValidY1 = m_Y; - int ValidY2 = m_Y + m_Height; + var ValidX1 = m_X; + var ValidX2 = m_X + m_Width; + var ValidY1 = m_Y; + var ValidY2 = m_Y + m_Height; - for (int x = 0; x <= m_Width; x++) + for (var x = 0; x <= m_Width; x++) { - int NewX = m_X + x; - for (int y = 0; y <= m_Height; y++) + var NewX = m_X + x; + for (var y = 0; y <= m_Height; y++) { - int NewY = m_Y + y; + var NewY = m_Y + y; if (NewX == ValidX1 || NewX == ValidX2 || NewX == ValidY1 || NewX == ValidY2 || NewY == ValidX1 || NewY == ValidX2 || NewY == ValidY1 || NewY == ValidY2) { // Add an object to show the spawn area - Static s = new Static(ShowBoundsItemId) + var s = new Static(ShowBoundsItemId) { Visible = false }; @@ -1143,7 +1077,7 @@ public class XmlSpawner : Item, ISpawner if (value == false && m_ShowBoundsItems != null) { // Remove all of the items from the array - foreach (Static s in m_ShowBoundsItems) + foreach (var s in m_ShowBoundsItems) { s.Delete(); } @@ -1168,25 +1102,13 @@ public class XmlSpawner : Item, ISpawner public int CurrentCount => TotalSpawnedObjects; [CommandProperty(AccessLevel.GameMaster)] - public WayPoint WayPoint - { - get => m_WayPoint; - set => m_WayPoint = value; - } + public WayPoint WayPoint { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public bool ExternalTriggering - { - get => m_ExternalTriggering; - set => m_ExternalTriggering = value; - } + public bool ExternalTriggering { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public bool ExtTrigState - { - get => m_ExternalTrigger; - set => m_ExternalTrigger = value; - } + public bool ExtTrigState { get; set; } [CommandProperty(AccessLevel.GameMaster)] public bool Running @@ -1218,11 +1140,7 @@ public class XmlSpawner : Item, ISpawner public Region Region { get; } [CommandProperty(AccessLevel.GameMaster)] - public bool HomeRangeIsRelative - { - get => m_HomeRangeIsRelative; - set => m_HomeRangeIsRelative = value; - } + public bool HomeRangeIsRelative { get; set; } [CommandProperty(AccessLevel.GameMaster)] public int Team @@ -1231,11 +1149,7 @@ public class XmlSpawner : Item, ISpawner set { m_Team = value; InvalidateProperties(); } } [CommandProperty(AccessLevel.GameMaster)] - public int StackAmount - { - get => m_StackAmount; - set => m_StackAmount = value; - } + public int StackAmount { get; set; } [CommandProperty(AccessLevel.GameMaster)] public TimeSpan MinDelay { @@ -1269,33 +1183,17 @@ public class XmlSpawner : Item, ISpawner set => m_killcount = value; } [CommandProperty(AccessLevel.GameMaster)] - public int KillReset - { - get => m_KillReset; - set => m_KillReset = value; - } + public int KillReset { get; set; } = defKillReset; [CommandProperty(AccessLevel.GameMaster)] - public double TriggerProbability - { - get => m_TriggerProbability; - set => m_TriggerProbability = value; - } + public double TriggerProbability { get; set; } = defTriggerProbability; //added refractory period support [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan RefractMin - { - get => m_MinRefractory; - set => m_MinRefractory = value; - } + public TimeSpan RefractMin { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan RefractMax - { - get => m_MaxRefractory; - set => m_MaxRefractory = value; - } + public TimeSpan RefractMax { get; set; } [CommandProperty(AccessLevel.GameMaster)] public TimeSpan RefractoryOver @@ -1317,50 +1215,38 @@ public class XmlSpawner : Item, ISpawner { get { - if (m_SetPropertyItem == null || m_SetPropertyItem.Deleted) + if (SetItem == null || SetItem.Deleted) { return null; } - return m_SetPropertyItem.Name; + return SetItem.Name; } } [CommandProperty(AccessLevel.GameMaster)] - public Item SetItem - { - get => m_SetPropertyItem; - set => m_SetPropertyItem = value; - } + public Item SetItem { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public string MobTriggerProp - { - get => m_MobPropertyName; - set => m_MobPropertyName = value; - } + public string MobTriggerProp { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public string MobTriggerName - { - get => m_MobTriggerName; - set => m_MobTriggerName = value; - } + public string MobTriggerName { get; set; } [CommandProperty(AccessLevel.GameMaster)] public Mobile MobTriggerId { get { - if (m_MobTriggerName == null) + if (MobTriggerName == null) { return null; } // try to parse out the type information if it has also been saved - string[] typeargs = m_MobTriggerName.Split(",".ToCharArray(), 2); + var typeargs = MobTriggerName.Split(",".ToCharArray(), 2); string typestr = null; - string namestr = m_MobTriggerName; + var namestr = MobTriggerName; if (typeargs.Length > 1) { @@ -1372,36 +1258,22 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public string PlayerTriggerProp - { - get => m_PlayerPropertyName; - set => m_PlayerPropertyName = value; - } + public string PlayerTriggerProp { get; set; } // time of day activation [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan TODStart - { - get => m_TODStart; - set => m_TODStart = value; - } + public TimeSpan TODStart { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan TODEnd - { - get => m_TODEnd; - set => m_TODEnd = value; - } + public TimeSpan TODEnd { get; set; } [CommandProperty(AccessLevel.GameMaster)] public TimeSpan TOD { get { - if (m_TODMode == TODModeType.Gametime) + if (TODMode == TODModeType.Gametime) { - int hours; - int minutes; - Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); + Clock.GetTime(Map, Location.X, Location.Y, out var hours, out int minutes); return new DateTime(Core.Now.Year, Core.Now.Month, Core.Now.Day, hours, minutes, 0).TimeOfDay; } @@ -1411,29 +1283,23 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public TODModeType TODMode - { - get => m_TODMode; - set => m_TODMode = value; - } + public TODModeType TODMode { get; set; } = TODModeType.Realtime; [CommandProperty(AccessLevel.GameMaster)] public bool TODInRange { get { - if (m_TODStart == m_TODEnd) + if (TODStart == TODEnd) { return true; } DateTime now; - if (m_TODMode == TODModeType.Gametime) + if (TODMode == TODModeType.Gametime) { - int hours; - int minutes; - Clock.GetTime(Map, Location.X, Location.Y, out hours, out minutes); + Clock.GetTime(Map, Location.X, Location.Y, out var hours, out int minutes); now = new DateTime(Core.Now.Year, Core.Now.Month, Core.Now.Day, hours, minutes, 0); } else @@ -1443,8 +1309,8 @@ public class XmlSpawner : Item, ISpawner } var day_start = new DateTime(now.Year, now.Month, now.Day); // calculate the starting TOD window by adding the TODStart to day_start - var TOD_start = day_start + m_TODStart; - var TOD_end = day_start + m_TODEnd; + var TOD_start = day_start + TODStart; + var TOD_end = day_start + TODEnd; // handle the case when TODstart is before midnight and end is after @@ -1468,11 +1334,7 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public TimeSpan DespawnTime - { - get => m_DespawnTime; - set => m_DespawnTime = value; - } + public TimeSpan DespawnTime { get; set; } [CommandProperty(AccessLevel.GameMaster)] public TimeSpan Duration @@ -1510,7 +1372,6 @@ public class XmlSpawner : Item, ISpawner } } - // proximity range activated? [CommandProperty(AccessLevel.GameMaster)] public bool ProximityActivated @@ -1531,32 +1392,16 @@ public class XmlSpawner : Item, ISpawner // proximity trigger sound parameter [CommandProperty(AccessLevel.GameMaster)] - public int ProximitySound - { - get => m_ProximityTriggerSound; - set => m_ProximityTriggerSound = value; - } + public int ProximitySound { get; set; } // proximity trigger message parameter [CommandProperty(AccessLevel.GameMaster)] - public string ProximityMsg - { - get => m_ProximityTriggerMessage; - set => m_ProximityTriggerMessage = value; - } + public string ProximityMsg { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public string SpeechTrigger - { - get => m_SpeechTrigger; - set => m_SpeechTrigger = value; - } + public string SpeechTrigger { get; set; } - public string SkillTrigger - { - get => m_SkillTrigger; - set => m_SkillTrigger = value; - } + public string SkillTrigger { get; set; } [CommandProperty(AccessLevel.GameMaster)] public TimeSpan NextSpawn @@ -1578,11 +1423,7 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public bool SpawnOnTrigger - { - get => m_SpawnOnTrigger; - set => m_SpawnOnTrigger = value; - } + public bool SpawnOnTrigger { get; set; } [CommandProperty(AccessLevel.GameMaster)] public bool Group @@ -1592,18 +1433,10 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public string GumpState - { - get => m_GumpState; - set => m_GumpState = value; - } + public string GumpState { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public int SequentialSpawn - { - get => m_SequentialSpawning; - set => m_SequentialSpawning = value; - } + public int SequentialSpawn { get; set; } = -1; [CommandProperty(AccessLevel.GameMaster)] public TimeSpan NextSeqReset @@ -1621,12 +1454,7 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public AccessLevel TriggerAccessLevel - { - get => m_TriggerAccessLevel; - set => m_TriggerAccessLevel = value; - } - + public AccessLevel TriggerAccessLevel { get; set; } = AccessLevel.Player; [CommandProperty(AccessLevel.GameMaster)] public bool DoRespawn @@ -1638,7 +1466,7 @@ public class XmlSpawner : Item, ISpawner // if so then dont do it, otherwise you will infinitely recurse and crash with a stack overflow if (value && !inrespawn) { - TryRespawn(); + _ = TryRespawn(); } } } @@ -1647,7 +1475,9 @@ public class XmlSpawner : Item, ISpawner public bool DoReset { get => false; - set { if (value) + set + { + if (value) { Reset(); } @@ -1655,31 +1485,21 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public bool AllowGhostTrig - { - get => m_AllowGhostTriggering; - set => m_AllowGhostTriggering = value; - } + public bool AllowGhostTrig { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public bool AllowNPCTrig - { - get => m_AllowNPCTriggering; - set => m_AllowNPCTriggering = value; - } + public bool AllowNPCTrig { get; set; } [CommandProperty(AccessLevel.GameMaster)] - public string ConfigFile - { - get => m_ConfigFile; - set => m_ConfigFile = value; - } + public string ConfigFile { get; set; } [CommandProperty(AccessLevel.GameMaster)] public bool LoadConfig { get => false; - set { if (value) + set + { + if (value) { LoadXmlConfig(ConfigFile); } @@ -1687,11 +1507,7 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public Mobile TriggerMob - { - get => m_mob_who_triggered; - set => m_mob_who_triggered = value; - } + public Mobile TriggerMob { get; set; } [CommandProperty(AccessLevel.GameMaster)] public bool SmartSpawning @@ -1742,13 +1558,13 @@ public class XmlSpawner : Item, ISpawner return; } - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { - for (int i = 0; i < so.SpawnedObjects.Count; ++i) + for (var i = 0; i < so.SpawnedObjects.Count; ++i) { if (so.SpawnedObjects[i] == spawn) { - so.SpawnedObjects.Remove(spawn); + _ = so.SpawnedObjects.Remove(spawn); if (SequentialSpawn >= 0 && so.RestrictKillsToSubgroup) { if (so.SubGroup == SequentialSpawn) @@ -1775,11 +1591,11 @@ public class XmlSpawner : Item, ISpawner return; } - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { - for (int i = 0; i < so.SpawnedObjects.Count; ++i) + for (var i = 0; i < so.SpawnedObjects.Count; ++i) { - object o = so.SpawnedObjects[i]; + var o = so.SpawnedObjects[i]; if (o is Item item) { item.Spawner = this; @@ -1810,21 +1626,21 @@ public class XmlSpawner : Item, ISpawner public override void OnDoubleClick(Mobile from) { - if (from == null || from.Deleted || from.AccessLevel < AccessLevel.GameMaster || m_SpawnerGump != null && SomeOneHasGumpOpen) + if (from == null || from.Deleted || from.AccessLevel < AccessLevel.GameMaster || SpawnerGump != null && SomeOneHasGumpOpen) { return; } DeleteTextEntryBook(); // clear any text entry books that might still be around - int x = 0; - int y = 0; + var x = 0; + var y = 0; - Account acct = from.Account as Account; // read the text entries for default values + // read the text entries for default values - if (acct != null) + if (from.Account is Account acct) { - XmlSpawnerDefaults.DefaultEntry defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); + var defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); if (defs != null) { x = defs.SpawnerGumpX; @@ -1832,8 +1648,8 @@ public class XmlSpawner : Item, ISpawner } } - XmlSpawnerGump g = new XmlSpawnerGump(this, x, y, 0, 0, 0); - from.SendGump(g); + var g = new XmlSpawnerGump(this, x, y, 0, 0, 0); + _ = from.SendGump(g); } public override void GetProperties(IPropertyList list) @@ -1847,7 +1663,7 @@ public class XmlSpawner : Item, ISpawner list.Add(1060656, m_Count.ToString()); // amount to make: ~1_val~ list.Add(1061169, m_HomeRange.ToString()); // range ~1_val~ - int nlist_items = 6; + var nlist_items = 6; if (m_Group) { @@ -1880,9 +1696,9 @@ public class XmlSpawner : Item, ISpawner if (m_SpawnObjects != null) { - for (int i = 0; i < nlist_items && i < m_SpawnObjects.Count; ++i) + for (var i = 0; i < nlist_items && i < m_SpawnObjects.Count; ++i) { - string typename = m_SpawnObjects[i].TypeName; + var typename = m_SpawnObjects[i].TypeName; if (typename != null && typename.Length > 20) { typename = typename[..20]; @@ -1909,20 +1725,11 @@ public class XmlSpawner : Item, ISpawner // remove any text entry books that might still be attached to the spawner DeleteTextEntryBook(); - if (m_Timer != null) - { - m_Timer.Stop(); - } + m_Timer?.Stop(); - if (m_DurTimer != null) - { - m_DurTimer.Stop(); - } + m_DurTimer?.Stop(); - if (m_RefractoryTimer != null) - { - m_RefractoryTimer.Stop(); - } + m_RefractoryTimer?.Stop(); // if statics were added for marking container held spawners, delete them if (m_ShowContainerStatic != null && !m_ShowContainerStatic.Deleted) @@ -1931,7 +1738,7 @@ public class XmlSpawner : Item, ISpawner } } - static bool IgnoreLocationChange; + private static bool IgnoreLocationChange; public override void OnLocationChange(Point3D oldLocation) { if (IgnoreLocationChange) @@ -1940,12 +1747,11 @@ public class XmlSpawner : Item, ISpawner return; } - // calculate the positional shift if (oldLocation.X > 0 && oldLocation.Y > 0) { - int diffx = X - oldLocation.X; - int diffy = Y - oldLocation.Y; + var diffx = X - oldLocation.X; + var diffy = Y - oldLocation.Y; m_X += diffx; m_Y += diffy; } @@ -1988,7 +1794,6 @@ public class XmlSpawner : Item, ISpawner } } - public static void SpawnerGumpCallback(Mobile from, object invoker, string response) { // assign the response to the gumpstate @@ -2002,7 +1807,7 @@ public class XmlSpawner : Item, ISpawner { if (m_TextEntryBook != null) { - foreach (XmlTextEntryBook s in m_TextEntryBook) + foreach (var s in m_TextEntryBook) { s.Delete(); } @@ -2011,7 +1816,10 @@ public class XmlSpawner : Item, ISpawner } } - private static bool IsConstructible(ConstructorInfo ctor) => ctor.IsDefined(typeof(ConstructibleAttribute), false); + private static bool IsConstructible(ConstructorInfo ctor) + { + return ctor.IsDefined(typeof(ConstructibleAttribute), false); + } public static int ConvertToInt(string value) { @@ -2025,7 +1833,7 @@ public class XmlSpawner : Item, ISpawner public static void ExecuteAction(object attachedto, Mobile trigmob, string action) { - Point3D loc = Point3D.Zero; + var loc = Point3D.Zero; Map map = null; if (attachedto is IEntity entity) { @@ -2038,27 +1846,26 @@ public class XmlSpawner : Item, ISpawner return; } - SpawnObject TheSpawn = new SpawnObject(null, 0) + var TheSpawn = new SpawnObject(null, 0) { TypeName = action }; - string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, attachedto, action); - string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); - + var substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, attachedto, action); + var typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); string status_str; if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) { - BaseXmlSpawner.SpawnTypeKeyword(attachedto, TheSpawn, typeName, substitutedtypeName, trigmob, map, out status_str); + _ = BaseXmlSpawner.SpawnTypeKeyword(attachedto, TheSpawn, typeName, substitutedtypeName, trigmob, map, out _); } else { // its a regular type descriptor so find out what it is - Type type = AssemblyHandler.FindTypeByName(typeName); + var type = AssemblyHandler.FindTypeByName(typeName); try { - string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); - object o = CreateObject(type, arglist[0]); + var arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + var o = CreateObject(type, arglist[0]); if (o == null) { @@ -2075,7 +1882,7 @@ public class XmlSpawner : Item, ISpawner mobile.Location = loc; mobile.Map = map; - BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, mobile, trigmob, attachedto, out status_str); + _ = BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, mobile, trigmob, attachedto, out status_str); } else if (o is Item item) @@ -2098,13 +1905,12 @@ public class XmlSpawner : Item, ISpawner } // find the sector - List spawnerlist; - if (GlobalSectorTable[s.Owner.MapID].TryGetValue(s, out spawnerlist) && spawnerlist != null) + if (GlobalSectorTable[s.Owner.MapID].TryGetValue(s, out var spawnerlist) && spawnerlist != null) { //List spawnerlist = GlobalSectorTable[s.Owner.MapID][s]; if (spawnerlist.Contains(spawner)) { - spawnerlist.Remove(spawner); + _ = spawnerlist.Remove(spawner); } } } @@ -2114,17 +1920,17 @@ public class XmlSpawner : Item, ISpawner // remove the global sector entries if (sectorList != null) { - foreach (Sector s in sectorList) + foreach (var s in sectorList) { RemoveFromSectorTable(s, this); } } sectorList = null; - UseSectorActivate = false; + SingleSector = false; // force an update of the sector list - bool sectorrefresh = HasActiveSectors; + _ = HasActiveSectors; } public void LoadXmlConfig(string filename) @@ -2154,13 +1960,13 @@ public class XmlSpawner : Item, ISpawner } // Create the data set - DataSet ds = new DataSet(XmlDataSetName); + var ds = new DataSet(XmlDataSetName); // Read in the file - bool fileerror = false; + var fileerror = false; try { - ds.ReadXml(fs); + _ = ds.ReadXml(fs); } catch { fileerror = true; } // close the file @@ -2179,9 +1985,9 @@ public class XmlSpawner : Item, ISpawner foreach (DataRow dr in ds.Tables[XmlTableName].Rows) { string strEntry = null; - bool boolEntry = true; + var boolEntry = true; double doubleEntry = 0; - int intEntry = 0; + var intEntry = 0; var valid_entry = true; try { strEntry = (string)dr["Name"]; } @@ -2226,7 +2032,7 @@ public class XmlSpawner : Item, ISpawner valid_entry = true; try { intEntry = int.Parse((string)dr["SequentialSpawning"]); } catch { valid_entry = false; } - if (valid_entry) { m_SequentialSpawning = intEntry; } + if (valid_entry) { SequentialSpawn = intEntry; } valid_entry = true; try { intEntry = int.Parse((string)dr["ProximityRange"]); } @@ -2236,22 +2042,22 @@ public class XmlSpawner : Item, ISpawner valid_entry = true; try { strEntry = (string)dr["ProximityTriggerMessage"]; } catch { valid_entry = false; } - if (valid_entry) { m_ProximityTriggerMessage = strEntry; } + if (valid_entry) { ProximityMsg = strEntry; } valid_entry = true; try { strEntry = (string)dr["SpeechTrigger"]; } catch { valid_entry = false; } - if (valid_entry) { m_SpeechTrigger = strEntry; } + if (valid_entry) { SpeechTrigger = strEntry; } valid_entry = true; try { strEntry = (string)dr["SkillTrigger"]; } catch { valid_entry = false; } - if (valid_entry) { m_SkillTrigger = strEntry; } + if (valid_entry) { SkillTrigger = strEntry; } valid_entry = true; try { intEntry = int.Parse((string)dr["ProximityTriggerSound"]); } catch { valid_entry = false; } - if (valid_entry) { m_ProximityTriggerSound = intEntry; } + if (valid_entry) { ProximitySound = intEntry; } valid_entry = true; try { strEntry = (string)dr["ItemTriggerName"]; } @@ -2264,7 +2070,7 @@ public class XmlSpawner : Item, ISpawner if (valid_entry) { m_NoItemTriggerName = strEntry; } // check for the delayinsec entry - bool delayinsec = false; + var delayinsec = false; try { delayinsec = bool.Parse((string)dr["DelayInSec"]); } catch { } @@ -2292,37 +2098,37 @@ public class XmlSpawner : Item, ISpawner valid_entry = true; try { doubleEntry = double.Parse((string)dr["DespawnTime"]); } catch { valid_entry = false; } - if (valid_entry) { m_DespawnTime = TimeSpan.FromHours(doubleEntry); } + if (valid_entry) { DespawnTime = TimeSpan.FromHours(doubleEntry); } valid_entry = true; try { doubleEntry = double.Parse((string)dr["MinRefractory"]); } catch { valid_entry = false; } - if (valid_entry) { m_MinRefractory = TimeSpan.FromMinutes(doubleEntry); } + if (valid_entry) { RefractMin = TimeSpan.FromMinutes(doubleEntry); } valid_entry = true; try { doubleEntry = double.Parse((string)dr["MaxRefractory"]); } catch { valid_entry = false; } - if (valid_entry) { m_MaxRefractory = TimeSpan.FromMinutes(doubleEntry); } + if (valid_entry) { RefractMax = TimeSpan.FromMinutes(doubleEntry); } valid_entry = true; try { doubleEntry = double.Parse((string)dr["TODStart"]); } catch { valid_entry = false; } - if (valid_entry) { m_TODStart = TimeSpan.FromMinutes(doubleEntry); } + if (valid_entry) { TODStart = TimeSpan.FromMinutes(doubleEntry); } valid_entry = true; try { doubleEntry = double.Parse((string)dr["TODEnd"]); } catch { valid_entry = false; } - if (valid_entry) { m_TODEnd = TimeSpan.FromMinutes(doubleEntry); } + if (valid_entry) { TODEnd = TimeSpan.FromMinutes(doubleEntry); } valid_entry = true; try { intEntry = int.Parse((string)dr["TODMode"]); } catch { valid_entry = false; } - if (valid_entry) { m_TODMode = (TODModeType)intEntry; } + if (valid_entry) { TODMode = (TODModeType)intEntry; } valid_entry = true; try { intEntry = int.Parse((string)dr["Amount"]); } catch { valid_entry = false; } - if (valid_entry) { m_StackAmount = intEntry; } + if (valid_entry) { StackAmount = intEntry; } valid_entry = true; try { intEntry = int.Parse((string)dr["MaxCount"]); } @@ -2342,22 +2148,22 @@ public class XmlSpawner : Item, ISpawner valid_entry = true; try { strEntry = (string)dr["WayPoint"]; } catch { valid_entry = false; } - if (valid_entry) { m_WayPoint = GetWaypoint(strEntry); } + if (valid_entry) { WayPoint = GetWaypoint(strEntry); } valid_entry = true; try { intEntry = int.Parse((string)dr["KillReset"]); } catch { valid_entry = false; } - if (valid_entry) { m_KillReset = intEntry; } + if (valid_entry) { KillReset = intEntry; } valid_entry = true; try { doubleEntry = double.Parse((string)dr["TriggerProbability"]); } catch { valid_entry = false; } - if (valid_entry) { m_TriggerProbability = doubleEntry; } + if (valid_entry) { TriggerProbability = doubleEntry; } valid_entry = true; try { boolEntry = bool.Parse((string)dr["ExternalTriggering"]); } catch { valid_entry = false; } - if (valid_entry) { m_ExternalTriggering = boolEntry; } + if (valid_entry) { ExternalTriggering = boolEntry; } valid_entry = true; try { boolEntry = bool.Parse((string)dr["IsGroup"]); } @@ -2367,22 +2173,22 @@ public class XmlSpawner : Item, ISpawner valid_entry = true; try { boolEntry = bool.Parse((string)dr["IsHomeRangeRelative"]); } catch { valid_entry = false; } - if (valid_entry) { m_HomeRangeIsRelative = boolEntry; } + if (valid_entry) { HomeRangeIsRelative = boolEntry; } valid_entry = true; try { boolEntry = bool.Parse((string)dr["AllowGhostTriggering"]); } catch { valid_entry = false; } - if (valid_entry) { m_AllowGhostTriggering = boolEntry; } + if (valid_entry) { AllowGhostTrig = boolEntry; } valid_entry = true; try { boolEntry = bool.Parse((string)dr["AllowNPCTriggering"]); } catch { valid_entry = false; } - if (valid_entry) { m_AllowNPCTriggering = boolEntry; } + if (valid_entry) { AllowNPCTrig = boolEntry; } valid_entry = true; try { boolEntry = bool.Parse((string)dr["SpawnOnTrigger"]); } catch { valid_entry = false; } - if (valid_entry) { m_SpawnOnTrigger = boolEntry; } + if (valid_entry) { SpawnOnTrigger = boolEntry; } valid_entry = true; try { boolEntry = bool.Parse((string)dr["SmartSpawning"]); } @@ -2402,7 +2208,7 @@ public class XmlSpawner : Item, ISpawner catch { valid_entry = false; } if (valid_entry) { - m_PlayerPropertyName = strEntry; + PlayerTriggerProp = strEntry; } valid_entry = true; @@ -2410,7 +2216,7 @@ public class XmlSpawner : Item, ISpawner catch { valid_entry = false; } if (valid_entry) { - m_MobPropertyName = strEntry; + MobTriggerProp = strEntry; } valid_entry = true; @@ -2418,7 +2224,7 @@ public class XmlSpawner : Item, ISpawner catch { valid_entry = false; } if (valid_entry) { - m_MobTriggerName = strEntry; + MobTriggerName = strEntry; } valid_entry = true; @@ -2434,9 +2240,9 @@ public class XmlSpawner : Item, ISpawner catch { valid_entry = false; } if (valid_entry) { - string[] typeargs = strEntry.Split(",".ToCharArray(), 2); + var typeargs = strEntry.Split(",".ToCharArray(), 2); string typestr = null; - string namestr = strEntry; + var namestr = strEntry; if (typeargs.Length > 1) { @@ -2451,16 +2257,16 @@ public class XmlSpawner : Item, ISpawner catch { valid_entry = false; } if (valid_entry) { - string[] typeargs = strEntry.Split(",".ToCharArray(), 2); + var typeargs = strEntry.Split(",".ToCharArray(), 2); string typestr = null; - string namestr = strEntry; + var namestr = strEntry; if (typeargs.Length > 1) { namestr = typeargs[0]; typestr = typeargs[1]; } - m_SetPropertyItem = BaseXmlSpawner.FindItemByName(this, namestr, typestr); + SetItem = BaseXmlSpawner.FindItemByName(this, namestr, typestr); } valid_entry = true; @@ -2485,8 +2291,8 @@ public class XmlSpawner : Item, ISpawner } // try loading the new spawn specifications first - SpawnObject[] Spawns = new SpawnObject[0]; - bool havenew = true; + var Spawns = new SpawnObject[0]; + var havenew = true; valid_entry = true; try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); } catch { havenew = false; } @@ -2520,10 +2326,10 @@ public class XmlSpawner : Item, ISpawner if (PropertyInfoList != null) { Console.WriteLine("PropertyInfoList: {0}", PropertyInfoList.Count); - foreach (BaseXmlSpawner.TypeInfo to in PropertyInfoList) + foreach (var to in PropertyInfoList) { Console.WriteLine("\t{0}", to.t); - foreach (PropertyInfo p in to.plist) + foreach (var p in to.plist) { Console.WriteLine("\t\t{0}", p); } @@ -2531,27 +2337,26 @@ public class XmlSpawner : Item, ISpawner } ShowTagList(this); - int count = 0; + var count = 0; Console.WriteLine("Registered SkillsTotal = {0}", count); } -#if (TRACE) - - readonly string setname1 = _traceName[1] = "XmlFind"; - readonly string setname2 = _traceName[2] = "HasSector"; - readonly string setname4 = _traceName[4] = "AttachSpeech"; - readonly string setname5 = _traceName[5] = "HasHold"; - readonly string setname8 = _traceName[8] = "OnTick"; - readonly string setname9 = _traceName[9] = "Defrag"; - readonly string setname10 = _traceName[10] = "Respawn"; - readonly string setname11 = _traceName[11] = "SetProp"; - readonly string setname12 = _traceName[12] = "AttachMovement"; - readonly string setname13 = _traceName[13] = "ActiveSector"; - readonly string setname15 = _traceName[15] = "DistroTick"; - readonly string setname16 = _traceName[16] = "GetScaledFaction"; - readonly string setname17 = _traceName[17] = "FactionOnKill"; - readonly string setname18 = _traceName[18] = "CheckAcquire"; +#if TRACE + private readonly string setname1 = _traceName[1] = "XmlFind"; + private readonly string setname2 = _traceName[2] = "HasSector"; + private readonly string setname4 = _traceName[4] = "AttachSpeech"; + private readonly string setname5 = _traceName[5] = "HasHold"; + private readonly string setname8 = _traceName[8] = "OnTick"; + private readonly string setname9 = _traceName[9] = "Defrag"; + private readonly string setname10 = _traceName[10] = "Respawn"; + private readonly string setname11 = _traceName[11] = "SetProp"; + private readonly string setname12 = _traceName[12] = "AttachMovement"; + private readonly string setname13 = _traceName[13] = "ActiveSector"; + private readonly string setname15 = _traceName[15] = "DistroTick"; + private readonly string setname16 = _traceName[16] = "GetScaledFaction"; + private readonly string setname17 = _traceName[17] = "FactionOnKill"; + private readonly string setname18 = _traceName[18] = "CheckAcquire"; private const int MaxTraces = 20; private static readonly DateTime[] _traceStart = new DateTime[MaxTraces]; @@ -2590,7 +2395,7 @@ public class XmlSpawner : Item, ISpawner return false; } - return (m.Player || m_AllowNPCTriggering) && m.AccessLevel <= TriggerAccessLevel && (!m.Body.IsGhost && !m_AllowGhostTriggering || m.Body.IsGhost && m_AllowGhostTriggering); + return (m.Player || AllowNPCTrig) && m.AccessLevel <= TriggerAccessLevel && (!m.Body.IsGhost && !AllowGhostTrig || m.Body.IsGhost && AllowGhostTrig); } private bool AllowTriggering => m_Running && !m_refractActivated && TODInRange && CanSpawn; @@ -2600,16 +2405,16 @@ public class XmlSpawner : Item, ISpawner DoTimer(); // reset the timer // start the refractory timer to set proximity activated to false, thus enabling another activation - if (m_MaxRefractory > TimeSpan.FromMinutes(0)) + if (RefractMax > TimeSpan.FromMinutes(0)) { - int minSeconds = (int)m_MinRefractory.TotalSeconds; - int maxSeconds = (int)m_MaxRefractory.TotalSeconds; + var minSeconds = (int)RefractMin.TotalSeconds; + var maxSeconds = (int)RefractMax.TotalSeconds; DoTimer3(TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds))); } // if the spawnontrigger flag is set, then spawn immediately - if (m_SpawnOnTrigger) + if (SpawnOnTrigger) { NextSpawn = TimeSpan.Zero; ResetNextSpawnTimes(); @@ -2623,9 +2428,9 @@ public class XmlSpawner : Item, ISpawner { if (AllowTriggering && !m_proximityActivated) // only proximity trigger when no spawns have already been triggered { - bool needs_speech_trigger = false; - bool needs_player_trigger = false; - bool has_player_trigger = false; + var needs_speech_trigger = false; + var needs_player_trigger = false; + var has_player_trigger = false; m_skipped = false; @@ -2633,13 +2438,13 @@ public class XmlSpawner : Item, ISpawner // if a low demand one has already failed. // check for external triggering - if (m_ExternalTriggering && !m_ExternalTrigger) + if (ExternalTriggering && !ExtTrigState) { return; } // if speech triggering is set then test for successful activation - if (!string.IsNullOrEmpty(m_SpeechTrigger)) + if (!string.IsNullOrEmpty(SpeechTrigger)) { needs_speech_trigger = true; } @@ -2650,12 +2455,11 @@ public class XmlSpawner : Item, ISpawner } // if player property triggering is set then look for the mob and test properties - if (!string.IsNullOrEmpty(m_PlayerPropertyName)) + if (!string.IsNullOrEmpty(PlayerTriggerProp)) { needs_player_trigger = true; - string status_str; - if (BaseXmlSpawner.TestMobProperty(this, m, m_PlayerPropertyName, out status_str)) + if (BaseXmlSpawner.TestMobProperty(this, m, PlayerTriggerProp, out var status_str)) { has_player_trigger = true; } @@ -2673,7 +2477,7 @@ public class XmlSpawner : Item, ISpawner } // if this was called without being proximity triggered then check to see that the non-movement triggers were enabled. - if (!hasproximity && !m_ExternalTriggering) + if (!hasproximity && !ExternalTriggering) { return; } @@ -2681,18 +2485,18 @@ public class XmlSpawner : Item, ISpawner // all of the necessary trigger conditions have been met so go ahead and trigger // after you make the probability check - if (Utility.RandomDouble() < m_TriggerProbability) + if (Utility.RandomDouble() < TriggerProbability) { // play a sound indicating the spawner has been triggered - if (m_ProximityTriggerSound > 0 && m != null && !m.Deleted) + if (ProximitySound > 0 && m != null && !m.Deleted) { - m.PlaySound(m_ProximityTriggerSound); + m.PlaySound(ProximitySound); } // display the trigger message - if (!string.IsNullOrEmpty(m_ProximityTriggerMessage) && m != null && !m.Deleted) + if (!string.IsNullOrEmpty(ProximityMsg) && m != null && !m.Deleted) { - m.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, m_ProximityTriggerMessage); + m.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, ProximityMsg); } // enable spawning at the next ontick @@ -2700,7 +2504,7 @@ public class XmlSpawner : Item, ISpawner ProximityActivated = true; // keep track of who triggered this - m_mob_who_triggered = m; + TriggerMob = m; } else { @@ -2711,7 +2515,7 @@ public class XmlSpawner : Item, ISpawner } } } - public bool HandlesOnSkillUse => m_Running && m_SkillTrigger != null && m_SkillTrigger.Length > 0; + public bool HandlesOnSkillUse => m_Running && SkillTrigger != null && SkillTrigger.Length > 0; // this is the handler for skill use public void OnSkillUse(Mobile m, Skill skill, bool success) @@ -2740,7 +2544,7 @@ public class XmlSpawner : Item, ISpawner // } } } - public override bool HandlesOnSpeech => m_Running && !string.IsNullOrEmpty(m_SpeechTrigger); + public override bool HandlesOnSpeech => m_Running && !string.IsNullOrEmpty(SpeechTrigger); public override void OnSpeech(SpeechEventArgs e) { @@ -2753,7 +2557,7 @@ public class XmlSpawner : Item, ISpawner return; } - if (m_SpeechTrigger != null && e.Speech.ToLower().IndexOf(m_SpeechTrigger.ToLower()) >= 0) + if (SpeechTrigger != null && e.Speech.ToLower().IndexOf(SpeechTrigger.ToLower()) >= 0) { e.Handled = true; @@ -2770,10 +2574,7 @@ public class XmlSpawner : Item, ISpawner public void AddToMovementList(Mobile m) { // go through the list and check for redundancy - if (m_MovementList == null) - { - m_MovementList = new List(); - } + m_MovementList ??= new List(); // check to see if the movement timer is running if (m_MovementTimer == null || !m_MovementTimer.Running) @@ -2781,11 +2582,11 @@ public class XmlSpawner : Item, ISpawner DoMovementTimer(TimeSpan.FromSeconds(1)); } - bool add = true; + var add = true; - foreach (MovementInfo moveinfo in m_MovementList) + foreach (var moveinfo in m_MovementList) { - Mobile mtrig = moveinfo.trigMob; + var mtrig = moveinfo.trigMob; if (mtrig == m) { add = false; @@ -2813,21 +2614,21 @@ public class XmlSpawner : Item, ISpawner public void DoMovementTimer(TimeSpan delay) { - if (m_MovementTimer != null) - { - m_MovementTimer.Stop(); - } + m_MovementTimer?.Stop(); m_MovementTimer = new MovementTimer(this, delay); - m_MovementTimer.Start(); + _ = m_MovementTimer.Start(); } private class MovementTimer : Timer { private readonly XmlSpawner m_Spawner; - public MovementTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_Spawner = spawner; + public MovementTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) + { + m_Spawner = spawner; + } protected override void OnTick() { @@ -2836,11 +2637,11 @@ public class XmlSpawner : Item, ISpawner { if (m_Spawner.m_Running && !m_Spawner.m_proximityActivated && !m_Spawner.m_refractActivated && m_Spawner.TODInRange && m_Spawner.CanSpawn) { - int count = 0; - int maxspeed = 0; - foreach (MovementInfo moveinfo in m_Spawner.m_MovementList) + var count = 0; + var maxspeed = 0; + foreach (var moveinfo in m_Spawner.m_MovementList) { - Mobile m = moveinfo.trigMob; + var m = moveinfo.trigMob; if (m == null) { continue; @@ -2853,7 +2654,7 @@ public class XmlSpawner : Item, ISpawner break; } - int speed = (int)GetDistance(m.Location, moveinfo.trigLocation); + var speed = (int)GetDistance(m.Location, moveinfo.trigLocation); if (speed > maxspeed) { maxspeed = speed; @@ -2873,8 +2674,8 @@ public class XmlSpawner : Item, ISpawner public static double GetDistance(Point3D p1, Point3D p2) { - int xDelta = p1.X - p2.X; - int yDelta = p1.Y - p2.Y; + var xDelta = p1.X - p2.X; + var yDelta = p1.Y - p2.Y; return Math.Sqrt(xDelta * xDelta + yDelta * yDelta); } @@ -2906,92 +2707,92 @@ public class XmlSpawner : Item, ISpawner switch (argname) { case "XmlSpawnDir": - { - XmlSpawnDir = value; - break; - } + { + XmlSpawnDir = value; + break; + } case "DiskAccessLevel": - { - DiskAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); - break; - } + { + DiskAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); + break; + } case "SmartSpawnAccessLevel": - { - SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); - break; - } + { + SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); + break; + } case "defaultTriggerSound": - { - defaultTriggerSound = ConvertToInt(value); - defProximityTriggerSound = defaultTriggerSound; - break; - } + { + defaultTriggerSound = ConvertToInt(value); + defProximityTriggerSound = defaultTriggerSound; + break; + } case "BaseItemId": - { - BaseItemId = ConvertToInt(value); - break; - } + { + BaseItemId = ConvertToInt(value); + break; + } case "ShowItemId": - { - ShowItemId = ConvertToInt(value); - break; - } + { + ShowItemId = ConvertToInt(value); + break; + } case "MaxMoveCheck": - { - MaxMoveCheck = ConvertToInt(value); - break; - } + { + MaxMoveCheck = ConvertToInt(value); + break; + } case "defMinDelay": - { - defMinDelay = TimeSpan.FromMinutes(ConvertToInt(value)); - break; - } + { + defMinDelay = TimeSpan.FromMinutes(ConvertToInt(value)); + break; + } case "defMaxDelay": - { - defMaxDelay = TimeSpan.FromMinutes(ConvertToInt(value)); - break; - } + { + defMaxDelay = TimeSpan.FromMinutes(ConvertToInt(value)); + break; + } case "defRelativeHome": - { - defRelativeHome = bool.Parse(value); - break; - } + { + defRelativeHome = bool.Parse(value); + break; + } case "defSpawnRange": - { - defSpawnRange = ConvertToInt(value); - break; - } + { + defSpawnRange = ConvertToInt(value); + break; + } case "defHomeRange": - { - defHomeRange = ConvertToInt(value); - break; - } + { + defHomeRange = ConvertToInt(value); + break; + } case "BlockKeyword": + { + // parse the keyword list and remove them from the keyword hashtables + var keywordlist = value.Split(','); + + if (keywordlist.Length > 0) { - // parse the keyword list and remove them from the keyword hashtables - string[] keywordlist = value.Split(','); - - if (keywordlist.Length > 0) + for (var i = 0; i < keywordlist.Length; i++) { - for (int i = 0; i < keywordlist.Length; i++) - { - BaseXmlSpawner.RemoveKeyword(keywordlist[i]); - } + BaseXmlSpawner.RemoveKeyword(keywordlist[i]); } - - break; } + + break; + } case "BlockCommand": case "ChangeCommand": - { - // delay processing of these settings until after all commands have been registered in their Initialize methods - Timer.DelayCall(TimeSpan.Zero, DelayedAssignSettings, argname, value); - break; - } + { + // delay processing of these settings until after all commands have been registered in their Initialize methods + _ = Timer.DelayCall(TimeSpan.Zero, DelayedAssignSettings, argname, value); + break; + } default: - { - return false; - } + { + return false; + } } return true; @@ -3002,137 +2803,137 @@ public class XmlSpawner : Item, ISpawner switch (argname) { case "BlockCommand": - { - // delay processing of this until after all commands have been registered in their Initialize methods - // parse the command list and remove them from the command hashtables - // the syntax is "commandname, commandname, etc." - string[] keywordlist = value.Split(','); + { + // delay processing of this until after all commands have been registered in their Initialize methods + // parse the command list and remove them from the command hashtables + // the syntax is "commandname, commandname, etc." + var keywordlist = value.Split(','); - if (keywordlist.Length > 0) + if (keywordlist.Length > 0) + { + for (var i = 0; i < keywordlist.Length; i++) { - for (int i = 0; i < keywordlist.Length; i++) + var commandname = keywordlist[i].Trim().ToLower(); + try { - string commandname = keywordlist[i].Trim().ToLower(); - try - { - CommandSystem.Entries.Remove(commandname); - } - catch - { - Console.WriteLine("{0}: invalid command {1}", argname, commandname); - } + _ = CommandSystem.Entries.Remove(commandname); + } + catch + { + Console.WriteLine("{0}: invalid command {1}", argname, commandname); } } - break; } + break; + } case "ChangeCommand": + { + // delay processing of this until after all commands have been registered in their Initialize methods + // parse the command list and rehash them into the command hashtables + // the syntax is "oldname:newname[:accesslevel], oldname:newname[:accesslevel], etc." + var keywordlist = value.Split(','); + + if (keywordlist.Length > 0) { - // delay processing of this until after all commands have been registered in their Initialize methods - // parse the command list and rehash them into the command hashtables - // the syntax is "oldname:newname[:accesslevel], oldname:newname[:accesslevel], etc." - string[] keywordlist = value.Split(','); - - if (keywordlist.Length > 0) + for (var i = 0; i < keywordlist.Length; i++) { - for (int i = 0; i < keywordlist.Length; i++) + var namelist = keywordlist[i].Split(':'); + if (namelist.Length > 1) { - string[] namelist = keywordlist[i].Split(':'); - if (namelist.Length > 1) + var oldname = namelist[0].Trim().ToLower(); + var newname = namelist[1].Trim(); + + if (newname.Length == 0) { - string oldname = namelist[0].Trim().ToLower(); - string newname = namelist[1].Trim(); + newname = oldname; + } - if (newname.Length == 0) - { - newname = oldname; - } - - AccessLevel access = AccessLevel.Player; - bool validaccess = false; - if (namelist.Length > 2) - { - // get the new accesslevel - try - { - access = (AccessLevel)Enum.Parse(typeof(AccessLevel), namelist[2].Trim(), true); - validaccess = true; - } - catch - { - Console.WriteLine("{0}: invalid accesslevel {1} for {2}", argname, namelist[2], newname); - } - } - // find the command entry for the old name - CommandEntry e = null; + var access = AccessLevel.Player; + var validaccess = false; + if (namelist.Length > 2) + { + // get the new accesslevel try { - e = CommandSystem.Entries[oldname]; + access = (AccessLevel)Enum.Parse(typeof(AccessLevel), namelist[2].Trim(), true); + validaccess = true; } catch { - Console.WriteLine("{0}: invalid command {1}", argname, oldname); + Console.WriteLine("{0}: invalid accesslevel {1} for {2}", argname, namelist[2], newname); } - if (e != null) + } + // find the command entry for the old name + CommandEntry e = null; + try + { + e = CommandSystem.Entries[oldname]; + } + catch + { + Console.WriteLine("{0}: invalid command {1}", argname, oldname); + } + if (e != null) + { + if (!validaccess) { - if (!validaccess) - { - // use the old accesslevel - access = e.AccessLevel; - } - // remove the old command entry - CommandSystem.Entries.Remove(oldname); - // register the new command using the old handler - CommandSystem.Register(newname, access, e.Handler); + // use the old accesslevel + access = e.AccessLevel; } + // remove the old command entry + _ = CommandSystem.Entries.Remove(oldname); + // register the new command using the old handler + CommandSystem.Register(newname, access, e.Handler); + } - // also look in the targetcommands list and adjust name and accesslevel there - foreach (BaseCommand b in TargetCommands.AllCommands) + // also look in the targetcommands list and adjust name and accesslevel there + foreach (var b in TargetCommands.AllCommands) + { + if (b.Commands != null) { - if (b.Commands != null) + for (var j = 0; j < b.Commands.Length; j++) { - for (int j = 0; j < b.Commands.Length; j++) + var commandname = b.Commands[j]; + if (commandname.ToLower() == oldname) { - string commandname = b.Commands[j]; - if (commandname.ToLower() == oldname) + // modify the basecommand with the new name and access + b.Commands[j] = newname; + if (validaccess) { - // modify the basecommand with the new name and access - b.Commands[j] = newname; - if (validaccess) - { - b.AccessLevel = access; - } - - // re-register it in the implementors hashtable - List impls = BaseCommandImplementor.Implementors; - - for (int k = 0; k < impls.Count; ++k) - { - BaseCommandImplementor impl = impls[k]; - - if ((b.Supports & impl.SupportRequirement) != 0) - { - try - { - impl.Commands.Remove(commandname); - } - catch (Exception ex) - { - Diagnostics.ExceptionLogging.LogException(ex); - } - impl.Register(b); - } - } - - break; + b.AccessLevel = access; } + + // re-register it in the implementors hashtable + var impls = BaseCommandImplementor.Implementors; + + for (var k = 0; k < impls.Count; ++k) + { + var impl = impls[k]; + + if ((b.Supports & impl.SupportRequirement) != 0) + { + try + { + _ = impl.Commands.Remove(commandname); + } + catch (Exception ex) + { + Diagnostics.ExceptionLogging.LogException(ex); + } + impl.Register(b); + } + } + + break; } } } } } } - break; } + break; + } } } @@ -3142,7 +2943,7 @@ public class XmlSpawner : Item, ISpawner public static void LoadSettings(AssignSettingsHandler settingshandler, string section) { // Check if the file exists - string path = Path.Combine(Core.BaseDirectory, "Data/xmlspawner.cfg"); + var path = Path.Combine(Core.BaseDirectory, "Data/xmlspawner.cfg"); if (!File.Exists(path)) { @@ -3150,74 +2951,72 @@ public class XmlSpawner : Item, ISpawner } Console.WriteLine("Loading {0} configuration", section); - using (StreamReader ip = new StreamReader(path)) + using var ip = new StreamReader(path); + string line; + string currentsection = null; + var nsettings = 0; + + while ((line = ip.ReadLine()) != null) { - string line; - string currentsection = null; - int nsettings = 0; + line = line.Trim(); - while ((line = ip.ReadLine()) != null) + // skip comments + if (line.Length == 0 || line.StartsWith("#")) { - line = line.Trim(); + continue; + } - // skip comments - if (line.Length == 0 || line.StartsWith("#")) + if (line.StartsWith("[")) + { + // parse the section name + var args = line.Split("[]".ToCharArray(), 3); + if (args.Length > 2) + { + currentsection = args[1].Trim(); + } + } + + // only process the matching classname section + if (currentsection != section) + { + continue; + } + + var split = line.Split('='); + + if (split.Length >= 2) + { + var argname = split[0].Trim(); + var value = split[1].Trim(); + + if (argname.Length == 0 || value.Length == 0) { continue; } - if (line.StartsWith("[")) + try { - // parse the section name - string[] args = line.Split("[]".ToCharArray(), 3); - if (args.Length > 2) + if (settingshandler(argname, value)) { - currentsection = args[1].Trim(); + nsettings++; + } + else + { + Console.WriteLine("'{0}' setting is invalid in section [{1}]", argname, currentsection); } } - - // only process the matching classname section - if (currentsection != section) + catch (Exception e) { - continue; - } - - string[] split = line.Split('='); - - if (split.Length >= 2) - { - string argname = split[0].Trim(); - string value = split[1].Trim(); - - if (argname.Length == 0 || value.Length == 0) - { - continue; - } - - try - { - if (settingshandler(argname, value)) - { - nsettings++; - } - else - { - Console.WriteLine("'{0}' setting is invalid in section [{1}]", argname, currentsection); - } - } - catch (Exception e) - { - Console.WriteLine("Config error '{0}'='{1}'", argname, value); - Console.WriteLine("Error: {0}", e.Message); - Diagnostics.ExceptionLogging.LogException(e); - } + Console.WriteLine("Config error '{0}'='{1}'", argname, value); + Console.WriteLine("Error: {0}", e.Message); + Diagnostics.ExceptionLogging.LogException(e); } } + } - if (nsettings > 0) - { - Console.WriteLine("{0} settings processed", nsettings); - } + if (nsettings > 0) + { + Console.WriteLine("{0} settings processed", nsettings); } } @@ -3226,14 +3025,14 @@ public class XmlSpawner : Item, ISpawner LoadSettings(AssignSettings, "XmlSpawner"); // initialize the default waypoint name - WayPoint tmpwaypoint = new WayPoint(); + var tmpwaypoint = new WayPoint(); defwaypointname = tmpwaypoint.Name; tmpwaypoint.Delete(); - int count = 0; - int regional = 0; + var count = 0; + var regional = 0; - foreach (Item item in World.Items.Values) + foreach (var item in World.Items.Values) { if (item is XmlSpawner spawner) { @@ -3247,7 +3046,7 @@ public class XmlSpawner : Item, ISpawner // check for smart spawning and restart timers after deser if needed // note, HasActiveSectors will recalculate the sector list and UseSectorActivate property - bool recalc_sectors = spawner.HasActiveSectors; + var recalc_sectors = spawner.HasActiveSectors; spawner.RestoreISpawner(); } @@ -3294,7 +3093,7 @@ public class XmlSpawner : Item, ISpawner TargetCommands.Register(new XmlSetCommand()); TargetCommands.Register(new XmlSaveSingle()); -#if (TRACE) +#if TRACE CommandSystem.Register("XmlMake", AccessLevel.Administrator, XmlMake_OnCommand); CommandSystem.Register("XmlTrace", AccessLevel.Administrator, XmlTrace_OnCommand); CommandSystem.Register("XmlResetTrace", AccessLevel.Administrator, XmlResetTrace_OnCommand); @@ -3312,14 +3111,15 @@ public class XmlSpawner : Item, ISpawner { private readonly CommandEventArgs m_e; public GetValueTarget(CommandEventArgs e) - : base(30, false, TargetFlags.None) => + : base(30, false, TargetFlags.None) + { m_e = e; + } protected override void OnTarget(Mobile from, object targeted) { - string pname = m_e.GetString(0); - Type ptype; - string result = BaseXmlSpawner.GetPropertyValue(null, targeted, pname, out ptype); + var pname = m_e.GetString(0); + var result = BaseXmlSpawner.GetPropertyValue(null, targeted, pname, out var ptype); // see if it was successful if (ptype == null) @@ -3347,7 +3147,7 @@ public class XmlSpawner : Item, ISpawner { if (e.Length >= 2) { - string result = BaseXmlSpawner.SetPropertyValue(null, obj, e.GetString(0), e.GetString(1)); + var result = BaseXmlSpawner.SetPropertyValue(null, obj, e.GetString(0), e.GetString(1)); if (result == "Property has been set.") { @@ -3377,8 +3177,10 @@ public class XmlSpawner : Item, ISpawner private readonly CommandEventArgs m_e; public TagListTarget(CommandEventArgs e) - : base(30, false, TargetFlags.None) => + : base(30, false, TargetFlags.None) + { m_e = e; + } protected override void OnTarget(Mobile from, object targeted) { @@ -3391,23 +3193,24 @@ public class XmlSpawner : Item, ISpawner public void ShowTagList(XmlSpawner spawner) { - int count = 0; + var count = 0; Console.WriteLine("{0} tags", spawner.m_KeywordTagList.Count); - foreach (BaseXmlSpawner.KeywordTag tag in spawner.m_KeywordTagList) + foreach (var tag in spawner.m_KeywordTagList) { count++; Console.WriteLine("tag {0} : {1}", count, BaseXmlSpawner.TagInfo(tag)); } } - // added in targeting for the [xmlhome command private class XmlHomeTarget : Target { private readonly CommandEventArgs m_e; public XmlHomeTarget(CommandEventArgs e) - : base(30, false, TargetFlags.None) => + : base(30, false, TargetFlags.None) + { m_e = e; + } protected override void OnTarget(Mobile from, object targeted) { @@ -3422,7 +3225,6 @@ public class XmlSpawner : Item, ISpawner } } - if (targeted is Mobile mobile) { spawner = mobile.Spawner as XmlSpawner; @@ -3440,11 +3242,11 @@ public class XmlSpawner : Item, ISpawner } // check to make sure it is still on the spawner - foreach (SpawnObject so in spawner.m_SpawnObjects) + foreach (var so in spawner.m_SpawnObjects) { - for (int x = 0; x < so.SpawnedObjects.Count; x++) + for (var x = 0; x < so.SpawnedObjects.Count; x++) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (o == targeted) { @@ -3512,9 +3314,9 @@ public class XmlSpawner : Item, ISpawner return; } - using (StreamWriter op = new StreamWriter(filePath)) + using (var op = new StreamWriter(filePath)) { - XmlTextWriter xml = new XmlTextWriter(op) + var xml = new XmlTextWriter(op) { Formatting = Formatting.Indented, IndentChar = '\t', @@ -3596,10 +3398,10 @@ public class XmlSpawner : Item, ISpawner if (File.Exists(filePath)) { - XmlDocument doc = new XmlDocument(); + var doc = new XmlDocument(); doc.Load(filePath); - XmlElement root = doc["XmlDefaults"]; + var root = doc["XmlDefaults"]; LoadDefaults(root); m.SendMessage($"defaults loaded successfully from {filePath}"); } @@ -3693,7 +3495,7 @@ public class XmlSpawner : Item, ISpawner { Diagnostics.ExceptionLogging.LogException(e); } - int todmode = 0; + var todmode = 0; try { todmode = int.Parse(node["defTODMode"].InnerText); } catch (Exception e) { @@ -3702,15 +3504,15 @@ public class XmlSpawner : Item, ISpawner switch (todmode) { case (int)TODModeType.Realtime: - { - defTODMode = TODModeType.Realtime; - break; - } + { + defTODMode = TODModeType.Realtime; + break; + } case (int)TODModeType.Gametime: - { - defTODMode = TODModeType.Gametime; - break; - } + { + defTODMode = TODModeType.Gametime; + break; + } } } @@ -3718,7 +3520,7 @@ public class XmlSpawner : Item, ISpawner [Description("Returns or changes the default settings of the spawner.")] public static void XmlDefaults_OnCommand(CommandEventArgs e) { - Mobile m = e.Mobile; + var m = e.Mobile; if (m == null || m.Deleted) { return; @@ -3867,19 +3669,19 @@ public class XmlSpawner : Item, ISpawner { try { - int todmode = Convert.ToInt32(e.Arguments[1]); + var todmode = Convert.ToInt32(e.Arguments[1]); switch (todmode) { case (int)TODModeType.Gametime: - { - defTODMode = TODModeType.Gametime; - break; - } + { + defTODMode = TODModeType.Gametime; + break; + } case (int)TODModeType.Realtime: - { - defTODMode = TODModeType.Realtime; - break; - } + { + defTODMode = TODModeType.Realtime; + break; + } } m.SendMessage($"TODMode = {defTODMode}"); } @@ -3938,8 +3740,8 @@ public class XmlSpawner : Item, ISpawner [Description("Makes all XmlSpawner objects movable and also changes the item id to a blue ships mast for easy identification.")] public static void ShowSpawnPoints_OnCommand(CommandEventArgs e) { - List ToShow = new List(); - foreach (Item item in World.Items.Values) + var ToShow = new List(); + foreach (var item in World.Items.Values) { if (item is XmlSpawner) { @@ -3965,11 +3767,11 @@ public class XmlSpawner : Item, ISpawner if ((xml_item.m_ShowContainerStatic == null || xml_item.m_ShowContainerStatic.Deleted) && xml_item.RootParent is Container rootItem) { // calculate a world location for the static. Position it just above the container - int x = rootItem.Location.X; - int y = rootItem.Location.Y; - int z = rootItem.Location.Z + 10; + var x = rootItem.Location.X; + var y = rootItem.Location.Y; + var z = rootItem.Location.Z + 10; - Static s = new Static(ShowItemId) + var s = new Static(ShowItemId) { Visible = false }; @@ -3986,8 +3788,8 @@ public class XmlSpawner : Item, ISpawner [Description("Makes all XmlSpawner objects invisible and unmovable returns the object id to the default.")] public static void HideSpawnPoints_OnCommand(CommandEventArgs e) { - List ToDelete = new List(); - foreach (Item item in World.Items.Values) + var ToDelete = new List(); + foreach (var item in World.Items.Values) { if (item is XmlSpawner xmlItem) { @@ -4022,12 +3824,12 @@ public class XmlSpawner : Item, ISpawner return; } - Mobile from = e.Mobile; + var from = e.Mobile; // Make sure a map name was given at least if (from != null && e.Length >= 1) { - string MapName = e.Arguments[0]; + var MapName = e.Arguments[0]; // Get the map Map NewMap; @@ -4070,9 +3872,9 @@ public class XmlSpawner : Item, ISpawner // Map & X Y ONLY if (NewMap != null) { - int x = e.GetInt32(1); - int y = e.GetInt32(2); - int z = NewMap.GetAverageZ(x, y); + var x = e.GetInt32(1); + var y = e.GetInt32(2); + var z = NewMap.GetAverageZ(x, y); from.Map = NewMap; from.Location = new Point3D(x, y, z); } @@ -4109,17 +3911,17 @@ public class XmlSpawner : Item, ISpawner } // handle the // number of spawners - int count = 0; + var count = 0; // number of actual spawns - int currentcount = 0; - int smartcount = 0; - int inactivecount = 0; + var currentcount = 0; + var smartcount = 0; + var inactivecount = 0; // maximum possible spawns - int totalcount = 0; - int maxcount = 0; + var totalcount = 0; + var maxcount = 0; // maximum possible of spawns that are currently inactivated - int savings = 0; - foreach (Item item in World.Items.Values) + var savings = 0; + foreach (var item in World.Items.Values) { if (item is XmlSpawner spawner) { @@ -4148,9 +3950,9 @@ public class XmlSpawner : Item, ISpawner } } - int percent = 0; + var percent = 0; - int maxpercent = 0; + var maxpercent = 0; if (totalcount > 0) { percent = 100 * savings / totalcount; @@ -4175,7 +3977,7 @@ public class XmlSpawner : Item, ISpawner [Description("Activates SmartSpawning on XmlSpawners that are well-suited for use of this feature.")] public static void OptimalSmartSpawning_OnCommand(CommandEventArgs e) { - int maxdiff = 1; + var maxdiff = 1; if (e.Arguments.Length > 0) { try @@ -4187,9 +3989,9 @@ public class XmlSpawner : Item, ISpawner Diagnostics.ExceptionLogging.LogException(ex); } } - int count = 0; - int maxcount = 0; - foreach (Item item in World.Items.Values) + var count = 0; + var maxcount = 0; + foreach (var item in World.Items.Values) { if (item is XmlSpawner spawner) { @@ -4210,15 +4012,15 @@ public class XmlSpawner : Item, ISpawner } // check the relative spawnrange and homerange. Dont set it on spawners with a larger homerange than spawnrange - int width = spawner.m_Width; - int height = spawner.m_Height; + var width = spawner.m_Width; + var height = spawner.m_Height; if (spawner.HomeRange * 2 > width + maxdiff * 2 || spawner.HomeRange * 2 > height + maxdiff * 2 && spawner.m_Region != null) { continue; } - int nso = 0; + var nso = 0; if (spawner.m_SpawnObjects != null) { @@ -4231,21 +4033,21 @@ public class XmlSpawner : Item, ISpawner continue; } - bool skipit = false; + var skipit = false; // check the spawn types - for (int i = 0; i < nso; ++i) + for (var i = 0; i < nso; ++i) { - SpawnObject so = spawner.m_SpawnObjects[i]; + var so = spawner.m_SpawnObjects[i]; if (so == null) { continue; } - string typestr = so.TypeName; + var typestr = so.TypeName; - Type type = AssemblyHandler.FindTypeByName(typestr); + var type = AssemblyHandler.FindTypeByName(typestr); // if it has basevendors on it or invalid types, then skip it if (typestr == null || type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor))) || @@ -4293,8 +4095,8 @@ public class XmlSpawner : Item, ISpawner return; } - int total_processed_maps = 0; - int total_processed_spawners = 0; + var total_processed_maps = 0; + var total_processed_spawners = 0; // Check if the file exists if (File.Exists(filename)) @@ -4308,10 +4110,7 @@ public class XmlSpawner : Item, ISpawner if (fs == null) { - if (from != null) - { - from.SendMessage($"Unable to open {filename} for unloading"); - } + from?.SendMessage($"Unable to open {filename} for unloading"); return; } @@ -4320,7 +4119,7 @@ public class XmlSpawner : Item, ISpawner } else - // check to see if it is a directory + // check to see if it is a directory if (Directory.Exists(filename)) { // if so then import all of the .xml files in the directory @@ -4332,12 +4131,9 @@ public class XmlSpawner : Item, ISpawner catch { } if (files != null && files.Length > 0) { - if (from != null) - { - from.SendMessage($"UnLoading {files.Length} .xml files from directory {filename}"); - } + from?.SendMessage($"UnLoading {files.Length} .xml files from directory {filename}"); - foreach (string file in files) + foreach (var file in files) { XmlUnLoadFromFile(file, SpawnerPrefix, from, out processedmaps, out processedspawners); total_processed_maps += processedmaps; @@ -4353,27 +4149,21 @@ public class XmlSpawner : Item, ISpawner catch { } if (dirs != null && dirs.Length > 0) { - foreach (string dir in dirs) + foreach (var dir in dirs) { XmlUnLoadFromFile(dir, SpawnerPrefix, from, out processedmaps, out processedspawners); total_processed_maps += processedmaps; total_processed_spawners += processedspawners; } } - if (from != null) - { - from.SendMessage($"UnLoaded a total of {total_processed_maps} .xml files and {total_processed_spawners} spawners from directory {filename}"); - } + from?.SendMessage($"UnLoaded a total of {total_processed_maps} .xml files and {total_processed_spawners} spawners from directory {filename}"); processedmaps = total_processed_maps; processedspawners = total_processed_spawners; } else { - if (from != null) - { - from.SendMessage($"{filename} does not exist"); - } + from?.SendMessage($"{filename} does not exist"); } } @@ -4388,39 +4178,33 @@ public class XmlSpawner : Item, ISpawner return; } - int TotalCount = 0; - int TrammelCount = 0; - int FeluccaCount = 0; - int IlshenarCount = 0; - int MalasCount = 0; - int TokunoCount = 0; - int OtherCount = 0; - int bad_spawner_count = 0; - int spawners_deleted = 0; + var TotalCount = 0; + var TrammelCount = 0; + var FeluccaCount = 0; + var IlshenarCount = 0; + var MalasCount = 0; + var TokunoCount = 0; + var OtherCount = 0; + var bad_spawner_count = 0; + var spawners_deleted = 0; - if (from != null) - { - from.SendMessage( + from?.SendMessage( $"UnLoading {"XmlSpawner"} objects{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} from file {filename}." ); - } // Create the data set - DataSet ds = new DataSet(SpawnDataSetName); + var ds = new DataSet(SpawnDataSetName); // Read in the file //ds.ReadXml(e.Arguments[0].ToString()); - bool fileerror = false; + var fileerror = false; try { - ds.ReadXml(fs); + _ = ds.ReadXml(fs); } catch { - if (from != null) - { - from.SendMessage(33, $"Error reading xml file {filename}"); - } + from?.SendMessage(33, $"Error reading xml file {filename}"); fileerror = true; } @@ -4443,16 +4227,16 @@ public class XmlSpawner : Item, ISpawner // the exception handler for those will flag bad_spawner and the result will be logged // Each row makes up a single spawner - string SpawnName = "Spawner"; + var SpawnName = "Spawner"; try { SpawnName = (string)dr["Name"]; } catch { } // Check if there is any spawner name criteria specified on the unload if (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || SpawnName.StartsWith(SpawnerPrefix)) { - bool bad_spawner = false; + var bad_spawner = false; // Try load the GUID (might not work so create a new GUID) - Guid SpawnId = Guid.NewGuid(); + var SpawnId = Guid.NewGuid(); try { SpawnId = new Guid((string)dr["UniqueId"]); } catch { bad_spawner = true; } // have to have a GUID or no point in continuing @@ -4462,8 +4246,8 @@ public class XmlSpawner : Item, ISpawner continue; } // Get the map (default to the mobiles map) - Map SpawnMap = Map.Internal; - string XmlMapName = SpawnMap.Name; + var SpawnMap = Map.Internal; + var XmlMapName = SpawnMap.Name; // Try to get the "map" field, but in case it doesn't exist, catch and discard the exception try { XmlMapName = (string)dr["Map"]; } @@ -4507,7 +4291,7 @@ public class XmlSpawner : Item, ISpawner // Check if this spawner already exists XmlSpawner OldSpawner = null; - foreach (Item i in World.Items.Values) + foreach (var i in World.Items.Values) { if (i is XmlSpawner checkXmlSpawner) { @@ -4540,19 +4324,13 @@ public class XmlSpawner : Item, ISpawner } catch { } - if (from != null) - { - from.SendMessage( + from?.SendMessage( $"{spawners_deleted}/{TotalCount} spawner(s) were unloaded using file {filename} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}]." ); - } if (bad_spawner_count > 0) { - if (from != null) - { - from.SendMessage(33, $"{bad_spawner_count} bad spawners detected."); - } + from?.SendMessage(33, $"{bad_spawner_count} bad spawners detected."); } processedmaps = 1; @@ -4569,7 +4347,7 @@ public class XmlSpawner : Item, ISpawner if (e.Arguments.Length >= 1) { // Spawner unload criteria (if any) - string SpawnerPrefix = string.Empty; + var SpawnerPrefix = string.Empty; // Check if there is an argument provided (load criteria) if (e.Arguments.Length > 1) @@ -4577,7 +4355,7 @@ public class XmlSpawner : Item, ISpawner SpawnerPrefix = e.Arguments[1]; } - string filename = LocateFile(e.Arguments[0]); + var filename = LocateFile(e.Arguments[0]); XmlUnLoadFromFile(filename, SpawnerPrefix, e.Mobile, out _, out _); } else @@ -4599,7 +4377,7 @@ public class XmlSpawner : Item, ISpawner { if (e.Arguments.Length >= 1) { - string filename = e.Arguments[0]; + var filename = e.Arguments[0]; XmlImportMap(filename, e.Mobile, out _, out _); } @@ -4618,8 +4396,8 @@ public class XmlSpawner : Item, ISpawner { processedmaps = 0; processedspawners = 0; - int total_processed_maps = 0; - int total_processed_spawners = 0; + var total_processed_maps = 0; + var total_processed_spawners = 0; if (filename == null || filename.Length <= 0 || from == null || from.Deleted) { return; @@ -4628,57 +4406,55 @@ public class XmlSpawner : Item, ISpawner // Check if the file exists if (File.Exists(filename)) { - int spawnercount = 0; - int badspawnercount = 0; - int linenumber = 0; + var spawnercount = 0; + var badspawnercount = 0; + var linenumber = 0; // default is no map override, use the map spec from each spawn line - int overridemap = -1; + var overridemap = -1; double overridemintime = -1; double overridemaxtime = -1; - bool newformat = false; + var newformat = false; try { // Create an instance of StreamReader to read from a file. // The using statement also closes the StreamReader. - using (StreamReader sr = new StreamReader(filename)) + using var 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) { - string line; - // Read and display lines from the file until the end of - // the file is reached. - while ((line = sr.ReadLine()) != null) + // the old format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1 + // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount + // * | typename:typename:... |s1 |s2 |s3 |s4 |s5 | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount | maxcount1 | maxcount2 | maxcount3 | maxcount4 | maxcount5 + // where s1-5 are additional spawn type entries with their own maxcounts + // the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1 + + linenumber++; + // is this the new format? + string[] args; + if (line.IndexOf('|') >= 0) { - // the old format of each .map line is * Dragon:Wyvern 5209 965 -40 2 2 10 50 30 1 - // * typename:typename:... x y z map mindelay maxdelay homerange spawnrange maxcount - // * | typename:typename:... |s1 |s2 |s3 |s4 |s5 | x | y | z | map | mindelay maxdelay homerange spawnrange spawnid maxcount | maxcount1 | maxcount2 | maxcount3 | maxcount4 | maxcount5 - // where s1-5 are additional spawn type entries with their own maxcounts - // the new format of each .map line is * |Dragon:Wyvern| spawns:spawns| | | | | 5209 | 965 | -40 | 2 | 2 | 10 | 50 | 30 | 1 - - linenumber++; - // is this the new format? - string[] args; - if (line.IndexOf('|') >= 0) - { - args = line.Trim().Split('|'); - newformat = true; - } - else - { - args = line.Trim().Split(' '); - } - - // determine the format of this line and parse accordingly - if (newformat) - { - ParseNewMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime); - } - else - { - ParseOldMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime); - } - + args = line.Trim().Split('|'); + newformat = true; } - sr.Close(); + else + { + args = line.Trim().Split(' '); + } + + // determine the format of this line and parse accordingly + if (newformat) + { + ParseNewMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime); + } + else + { + ParseOldMapFormat(from, filename, line, args, linenumber, ref spawnercount, ref badspawnercount, ref overridemap, ref overridemintime, ref overridemaxtime); + } + } + sr.Close(); } catch (Exception e) { @@ -4691,7 +4467,7 @@ public class XmlSpawner : Item, ISpawner processedspawners = spawnercount; } else - // check to see if it is a directory + // check to see if it is a directory if (Directory.Exists(filename)) { // if so then import all of the .map files in the directory @@ -4704,7 +4480,7 @@ public class XmlSpawner : Item, ISpawner if (files != null && files.Length > 0) { from.SendMessage($"Importing {files.Length} .map files from directory {filename}"); - foreach (string file in files) + foreach (var file in files) { XmlImportMap(file, from, out processedmaps, out processedspawners); total_processed_maps += processedmaps; @@ -4720,7 +4496,7 @@ public class XmlSpawner : Item, ISpawner catch { } if (dirs != null && dirs.Length > 0) { - foreach (string dir in dirs) + foreach (var dir in dirs) { XmlImportMap(dir, from, out processedmaps, out processedspawners); total_processed_maps += processedmaps; @@ -4790,29 +4566,29 @@ public class XmlSpawner : Item, ISpawner catch { } } else - // look for a spawn spec line + // look for a spawn spec line if (args.Length > 0 && args[0] == "*") { - bool badspawn = false; - int x = 0; - int y = 0; - int z = 0; - int map = 0; + var badspawn = false; + var x = 0; + var y = 0; + var z = 0; + var map = 0; double mindelay = 0; double maxdelay = 0; - int homerange = 0; - int spawnrange = 0; - string[][] typenames = new string[6][]; + var homerange = 0; + var spawnrange = 0; + var typenames = new string[6][]; - int[] maxcount = new int[6]; + var maxcount = new int[6]; // parse the main args try { // get the list of spawns - for (int k = 0; k < 6; k++) + for (var k = 0; k < 6; k++) { typenames[k] = args[k + 1].Split(':'); } @@ -4825,9 +4601,9 @@ public class XmlSpawner : Item, ISpawner maxdelay = double.Parse(args[12]); homerange = int.Parse(args[13]); spawnrange = int.Parse(args[14]); - int spawnid = int.Parse(args[15]); + var spawnid = int.Parse(args[15]); - for (int k = 0; k < 6; k++) + for (var k = 0; k < 6; k++) { maxcount[k] = int.Parse(args[k + 16]); } @@ -4835,17 +4611,17 @@ public class XmlSpawner : Item, ISpawner catch { from.SendMessage($"Parsing error at line {linenumber}"); badspawn = true; } // compute the total number of spawns - int totalspawns = 0; - int totalmaxcount = 0; + var totalspawns = 0; + var totalmaxcount = 0; - for (int k = 0; k < 6; k++) + for (var k = 0; k < 6; k++) { if (typenames[k] == null) { continue; } - for (int i = 0; i < typenames[k].Length; i++) + for (var i = 0; i < typenames[k].Length; i++) { if (typenames[k][i] == null || typenames[k][i].Length == 0) { @@ -4881,40 +4657,40 @@ public class XmlSpawner : Item, ISpawner map = overridemap; } - Map spawnmap = Map.Internal; + var spawnmap = Map.Internal; switch (map) { case 0: - { - spawnmap = Map.Felucca; - // note it also does trammel - break; - } + { + spawnmap = Map.Felucca; + // note it also does trammel + break; + } case 1: - { - spawnmap = Map.Felucca; - break; - } + { + spawnmap = Map.Felucca; + break; + } case 2: - { - spawnmap = Map.Trammel; - break; - } + { + spawnmap = Map.Trammel; + break; + } case 3: - { - spawnmap = Map.Ilshenar; - break; - } + { + spawnmap = Map.Ilshenar; + break; + } case 4: - { - spawnmap = Map.Malas; - break; - } + { + spawnmap = Map.Malas; + break; + } case 5: - { - spawnmap = Map.Tokuno; - break; - } + { + spawnmap = Map.Tokuno; + break; + } } if (!IsValidMapLocation(x, y, spawnmap)) @@ -4928,17 +4704,17 @@ public class XmlSpawner : Item, ISpawner // allow it to make an xmlspawner instead // first add all of the creatures on the list - SpawnObject[] so = new SpawnObject[totalspawns]; - int count = 0; - bool hasvendor = true; - for (int k = 0; k < 6; k++) + var so = new SpawnObject[totalspawns]; + var count = 0; + var hasvendor = true; + for (var k = 0; k < 6; k++) { if (typenames[k] == null) { continue; } - for (int i = 0; i < typenames[k].Length; i++) + for (var i = 0; i < typenames[k].Length; i++) { if (typenames[k][i] == null || typenames[k][i].Length == 0 || count > totalspawns) { @@ -4948,7 +4724,7 @@ public class XmlSpawner : Item, ISpawner so[count++] = new SpawnObject(typenames[k][i], maxcount[k]); // check the type to see if there are vendors on it - Type type = AssemblyHandler.FindTypeByName(typenames[k][i]); + var type = AssemblyHandler.FindTypeByName(typenames[k][i]); // check for vendor-only spawners which get special spawnrange treatment if (type != null && type != typeof(BaseVendor) && !type.IsSubclassOf(typeof(BaseVendor))) @@ -4960,22 +4736,23 @@ public class XmlSpawner : Item, ISpawner } // assign it a unique id - Guid SpawnId = Guid.NewGuid(); + var SpawnId = Guid.NewGuid(); // and give it a name based on the spawner count and file - string spawnername = $"{Path.GetFileNameWithoutExtension(filename)}#{spawnercount}"; + var spawnername = $"{Path.GetFileNameWithoutExtension(filename)}#{spawnercount}"; // Create the new xml spawner - XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount, + var spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, totalmaxcount, TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), null, null, null, null, null, null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, - TimeSpan.FromHours(0), null, false, null); + TimeSpan.FromHours(0), null, false, null) + { + SpawnRange = hasvendor ? 0 : spawnrange, - spawner.SpawnRange = hasvendor ? 0 : spawnrange; - - spawner.m_PlayerCreated = true; + PlayerCreated = true + }; spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); if (spawner.Map == Map.Internal) @@ -5002,7 +4779,7 @@ public class XmlSpawner : Item, ISpawner TimeSpan.FromHours(0), null, false, null) { SpawnRange = spawnrange, - m_PlayerCreated = true + PlayerCreated = true }; spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); @@ -5075,21 +4852,21 @@ public class XmlSpawner : Item, ISpawner catch { } } else - // look for a spawn spec line + // look for a spawn spec line if (args.Length > 0 && args[0] == "*") { - bool badspawn = false; - int x = 0; - int y = 0; - int z = 0; - int map = 0; + var badspawn = false; + var x = 0; + var y = 0; + var z = 0; + var map = 0; double mindelay = 0; double maxdelay = 0; - int homerange = 0; - int spawnrange = 0; - int maxcount = 0; + var homerange = 0; + var spawnrange = 0; + var maxcount = 0; string[] typenames = null; - if (args.Length != 11 && args.Length != 12) + if (args.Length is not 11 and not 12) { badspawn = true; from.SendMessage($"Invalid arg count {args.Length} at line {linenumber}"); @@ -5132,7 +4909,7 @@ public class XmlSpawner : Item, ISpawner maxdelay = double.Parse(args[7]); homerange = int.Parse(args[8]); spawnrange = int.Parse(args[9]); - int spawnid = int.Parse(args[10]); + var spawnid = int.Parse(args[10]); maxcount = int.Parse(args[11]); } @@ -5140,7 +4917,6 @@ public class XmlSpawner : Item, ISpawner } } - // apply mi/maxdelay overrides if (overridemintime != -1) { @@ -5164,40 +4940,40 @@ public class XmlSpawner : Item, ISpawner map = overridemap; } - Map spawnmap = Map.Internal; + var spawnmap = Map.Internal; switch (map) { case 0: - { - spawnmap = Map.Felucca; - // note it also does trammel - break; - } + { + spawnmap = Map.Felucca; + // note it also does trammel + break; + } case 1: - { - spawnmap = Map.Felucca; - break; - } + { + spawnmap = Map.Felucca; + break; + } case 2: - { - spawnmap = Map.Trammel; - break; - } + { + spawnmap = Map.Trammel; + break; + } case 3: - { - spawnmap = Map.Ilshenar; - break; - } + { + spawnmap = Map.Ilshenar; + break; + } case 4: - { - spawnmap = Map.Malas; - break; - } + { + spawnmap = Map.Malas; + break; + } case 5: - { - spawnmap = Map.Tokuno; - break; - } + { + spawnmap = Map.Tokuno; + break; + } } if (!IsValidMapLocation(x, y, spawnmap)) @@ -5211,15 +4987,15 @@ public class XmlSpawner : Item, ISpawner // allow it to make an xmlspawner instead // first add all of the creatures on the list - SpawnObject[] so = new SpawnObject[typenames.Length]; + var so = new SpawnObject[typenames.Length]; - bool hasvendor = true; - for (int i = 0; i < typenames.Length; i++) + var hasvendor = true; + for (var i = 0; i < typenames.Length; i++) { so[i] = new SpawnObject(typenames[i], maxcount); // check the type to see if there are vendors on it - Type type = AssemblyHandler.FindTypeByName(typenames[i]); + var type = AssemblyHandler.FindTypeByName(typenames[i]); // check for vendor-only spawners which get special spawnrange treatment if (type != null && type != typeof(BaseVendor) && !type.IsSubclassOf(typeof(BaseVendor))) @@ -5230,22 +5006,23 @@ public class XmlSpawner : Item, ISpawner } // assign it a unique id - Guid SpawnId = Guid.NewGuid(); + var SpawnId = Guid.NewGuid(); // and give it a name based on the spawner count and file - string spawnername = $"{Path.GetFileNameWithoutExtension(filename)}#{spawnercount}"; + var spawnername = $"{Path.GetFileNameWithoutExtension(filename)}#{spawnercount}"; // Create the new xml spawner - XmlSpawner spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount, + var spawner = new XmlSpawner(SpawnId, x, y, 0, 0, spawnername, maxcount, TimeSpan.FromMinutes(mindelay), TimeSpan.FromMinutes(maxdelay), TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, 0, homerange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), null, null, null, null, null, null, null, null, null, 1, null, false, defTODMode, defKillReset, false, -1, null, false, false, false, null, - TimeSpan.FromHours(0), null, false, null); + TimeSpan.FromHours(0), null, false, null) + { + SpawnRange = hasvendor ? 0 : spawnrange, - spawner.SpawnRange = hasvendor ? 0 : spawnrange; - - spawner.m_PlayerCreated = true; + PlayerCreated = true + }; spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); if (spawner.Map == Map.Internal) @@ -5272,7 +5049,7 @@ public class XmlSpawner : Item, ISpawner TimeSpan.FromHours(0), null, false, null) { SpawnRange = spawnrange, - m_PlayerCreated = true + PlayerCreated = true }; spawner.MoveToWorld(new Point3D(x, y, z), spawnmap); @@ -5300,11 +5077,11 @@ public class XmlSpawner : Item, ISpawner { if (e.Arguments.Length >= 1) { - string filename = e.GetString(0); - string filePath = Path.Combine("Saves/Spawners", filename); + var filename = e.GetString(0); + var filePath = Path.Combine("Saves/Spawners", filename); if (File.Exists(filePath)) { - XmlDocument doc = new XmlDocument(); + var doc = new XmlDocument(); try { doc.Load(filePath); @@ -5315,7 +5092,7 @@ public class XmlSpawner : Item, ISpawner return; } - XmlElement root = doc["spawners"]; + var root = doc["spawners"]; int successes = 0, failures = 0; if (root?.GetElementsByTagName("spawner") != null) { @@ -5354,36 +5131,36 @@ public class XmlSpawner : Item, ISpawner private static void ImportSpawner(XmlElement node, Mobile from) { - int count = int.Parse(GetText(node["count"], "1")); - int homeRange = int.Parse(GetText(node["homerange"], "4")); - int walkingRange = int.Parse(GetText(node["walkingrange"], "-1")); + var count = int.Parse(GetText(node["count"], "1")); + var homeRange = int.Parse(GetText(node["homerange"], "4")); + var walkingRange = int.Parse(GetText(node["walkingrange"], "-1")); // width of the spawning area - int spawnwidth = homeRange * 2; + var spawnwidth = homeRange * 2; if (walkingRange >= 0) { spawnwidth = walkingRange * 2; } - int team = int.Parse(GetText(node["team"], "0")); - bool group = bool.Parse(GetText(node["group"], "False")); - TimeSpan maxDelay = TimeSpan.Parse(GetText(node["maxdelay"], "10:00")); - TimeSpan minDelay = TimeSpan.Parse(GetText(node["mindelay"], "05:00")); - List creaturesName = LoadCreaturesName(node["creaturesname"]); - string name = GetText(node["name"], "Spawner"); - Point3D location = Point3D.Parse(GetText(node["location"], "Error")); - Map map = Map.Parse(GetText(node["map"], "Error")); + var team = int.Parse(GetText(node["team"], "0")); + var group = bool.Parse(GetText(node["group"], "False")); + var maxDelay = TimeSpan.Parse(GetText(node["maxdelay"], "10:00")); + var minDelay = TimeSpan.Parse(GetText(node["mindelay"], "05:00")); + var creaturesName = LoadCreaturesName(node["creaturesname"]); + var name = GetText(node["name"], "Spawner"); + var location = Point3D.Parse(GetText(node["location"], "Error")); + var map = Map.Parse(GetText(node["map"], "Error")); // allow it to make an xmlspawner instead // first add all of the creatures on the list - SpawnObject[] so = new SpawnObject[creaturesName.Count]; + var so = new SpawnObject[creaturesName.Count]; - bool hasvendor = false; + var hasvendor = false; - for (int i = 0; i < creaturesName.Count; i++) + for (var i = 0; i < creaturesName.Count; i++) { so[i] = new SpawnObject(creaturesName[i], count); // check the type to see if there are vendors on it - Type type = AssemblyHandler.FindTypeByName(creaturesName[i]); + var type = AssemblyHandler.FindTypeByName(creaturesName[i]); // if it has basevendors on it or invalid types, then skip it if (type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor)))) @@ -5393,17 +5170,18 @@ public class XmlSpawner : Item, ISpawner } // assign it a unique id - Guid SpawnId = Guid.NewGuid(); + var SpawnId = Guid.NewGuid(); // Create the new xml spawner - XmlSpawner spawner = new XmlSpawner(SpawnId, location.X, location.Y, spawnwidth, spawnwidth, name, count, + var spawner = new XmlSpawner(SpawnId, location.X, location.Y, spawnwidth, spawnwidth, name, count, minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), null, null, null, null, null, - null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); - - spawner.SpawnRange = hasvendor ? 0 : homeRange; - spawner.m_PlayerCreated = true; + null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null) + { + SpawnRange = hasvendor ? 0 : homeRange, + PlayerCreated = true + }; spawner.MoveToWorld(location, map); if (!IsValidMapLocation(location, spawner.Map)) @@ -5415,7 +5193,7 @@ public class XmlSpawner : Item, ISpawner private static List LoadCreaturesName(XmlElement node) { - List names = new List(); + var names = new List(); if (node != null) { @@ -5441,12 +5219,12 @@ public class XmlSpawner : Item, ISpawner string filename = e.GetString(0); string filePath = Path.Combine("Data/Megaspawner", filename); */ - string filePath = e.GetString(0); + var filePath = e.GetString(0); if (File.Exists(filePath)) { - XmlDocument doc = new XmlDocument(); + var doc = new XmlDocument(); doc.Load(filePath); - XmlElement root = doc["MegaSpawners"]; + var root = doc["MegaSpawners"]; if (root != null) { int successes = 0, failures = 0; @@ -5480,32 +5258,30 @@ public class XmlSpawner : Item, ISpawner private static void ImportMegaSpawner(Mobile from, XmlElement node) { - string name = GetText(node["Name"], "MegaSpawner"); - bool running = bool.Parse(GetText(node["Active"], "True")); - Point3D location = Point3D.Parse(GetText(node["Location"], "Error")); - Map map = Map.Parse(GetText(node["Map"], "Error")); + var name = GetText(node["Name"], "MegaSpawner"); + _ = bool.Parse(GetText(node["Active"], "True")); + var location = Point3D.Parse(GetText(node["Location"], "Error")); + var map = Map.Parse(GetText(node["Map"], "Error")); + var team = 0; + var group = false; + var maxcount = 0; // default maxcount of the spawner + var homeRange = 4; // default homerange + var spawnRange = 4; // default homerange + var maxDelay = TimeSpan.FromMinutes(10); + var minDelay = TimeSpan.FromMinutes(5); - int team = 0; - bool group = false; - int maxcount = 0; // default maxcount of the spawner - int homeRange = 4; // default homerange - int spawnRange = 4; // default homerange - TimeSpan maxDelay = TimeSpan.FromMinutes(10); - TimeSpan minDelay = TimeSpan.FromMinutes(5); + var listnode = node["EntryLists"]; - XmlElement listnode = node["EntryLists"]; - - int nentries = 0; + var nentries = 0; SpawnObject[] so = null; - if (listnode != null) { // get the number of entries if (listnode.HasAttributes) { - XmlAttributeCollection attr = listnode.Attributes; + var attr = listnode.Attributes; nentries = int.Parse(attr.GetNamedItem("count").Value); } @@ -5513,8 +5289,8 @@ public class XmlSpawner : Item, ISpawner { so = new SpawnObject[nentries]; - int entrycount = 0; - bool diff = false; + var entrycount = 0; + var diff = false; foreach (XmlElement entrynode in listnode.GetElementsByTagName("EntryList")) { // go through each entry and add a spawn object for it @@ -5539,12 +5315,9 @@ public class XmlSpawner : Item, ISpawner // log it try { - using (StreamWriter op = new StreamWriter("badimport.log", true)) - { - op.WriteLine("MSFimport : individual group entry difference: {0} vs {1}", - GetText(entrynode["GroupSpawn"], "False"), group); - - } + using var op = new StreamWriter("badimport.log", true); + op.WriteLine("MSFimport : individual group entry difference: {0} vs {1}", + GetText(entrynode["GroupSpawn"], "False"), group); } catch { } } @@ -5554,12 +5327,9 @@ public class XmlSpawner : Item, ISpawner // log it try { - using (StreamWriter op = new StreamWriter("badimport.log", true)) - { - op.WriteLine("MSFimport : individual mindelay entry difference: {0} vs {1}", - GetText(entrynode["MinDelay"], "05:00"), minDelay); - - } + using var op = new StreamWriter("badimport.log", true); + op.WriteLine("MSFimport : individual mindelay entry difference: {0} vs {1}", + GetText(entrynode["MinDelay"], "05:00"), minDelay); } catch { } } @@ -5569,12 +5339,9 @@ public class XmlSpawner : Item, ISpawner // log it try { - using (StreamWriter op = new StreamWriter("badimport.log", true)) - { - op.WriteLine("MSFimport : individual maxdelay entry difference: {0} vs {1}", - GetText(entrynode["MaxDelay"], "10:00"), maxDelay); - - } + using var op = new StreamWriter("badimport.log", true); + op.WriteLine("MSFimport : individual maxdelay entry difference: {0} vs {1}", + GetText(entrynode["MaxDelay"], "10:00"), maxDelay); } catch { } } @@ -5584,12 +5351,9 @@ public class XmlSpawner : Item, ISpawner // log it try { - using (StreamWriter op = new StreamWriter("badimport.log", true)) - { - op.WriteLine("MSFimport : individual homerange entry difference: {0} vs {1}", - GetText(entrynode["WalkRange"], "10"), homeRange); - - } + using var op = new StreamWriter("badimport.log", true); + op.WriteLine("MSFimport : individual homerange entry difference: {0} vs {1}", + GetText(entrynode["WalkRange"], "10"), homeRange); } catch { } } @@ -5599,20 +5363,17 @@ public class XmlSpawner : Item, ISpawner // log it try { - using (StreamWriter op = new StreamWriter("badimport.log", true)) - { - op.WriteLine("MSFimport : individual spawnrange entry difference: {0} vs {1}", - GetText(entrynode["SpawnRange"], "4"), spawnRange); - - } + using var op = new StreamWriter("badimport.log", true); + op.WriteLine("MSFimport : individual spawnrange entry difference: {0} vs {1}", + GetText(entrynode["SpawnRange"], "4"), spawnRange); } catch { } } } // these apply to individual entries - int amount = int.Parse(GetText(entrynode["Amount"], "1")); - string entryname = GetText(entrynode["EntryType"], ""); + var amount = int.Parse(GetText(entrynode["Amount"], "1")); + var entryname = GetText(entrynode["EntryType"], ""); // keep track of the maxcount for the spawner by adding the individual amounts maxcount += amount; @@ -5626,11 +5387,9 @@ public class XmlSpawner : Item, ISpawner // log it try { - using (StreamWriter op = new StreamWriter("badimport.log", true)) - { - op.WriteLine($"{Core.Now} MSFImport Error; inconsistent entry count {location} {map}"); - op.WriteLine(); - } + using var op = new StreamWriter("badimport.log", true); + op.WriteLine($"{Core.Now} MSFImport Error; inconsistent entry count {location} {map}"); + op.WriteLine(); } catch { } from.SendMessage($"Inconsistent entry count detected at {location} {map}."); @@ -5645,11 +5404,9 @@ public class XmlSpawner : Item, ISpawner // log it try { - using (StreamWriter op = new StreamWriter("badimport.log", true)) - { - op.WriteLine($"{Core.Now} MSFImport: Individual entry setting differences listed above from spawner at {location} {map}"); - op.WriteLine(); - } + using var op = new StreamWriter("badimport.log", true); + op.WriteLine($"{Core.Now} MSFImport: Individual entry setting differences listed above from spawner at {location} {map}"); + op.WriteLine(); } catch { } } @@ -5657,27 +5414,27 @@ public class XmlSpawner : Item, ISpawner } // assign it a unique id - Guid SpawnId = Guid.NewGuid(); + var SpawnId = Guid.NewGuid(); // Create the new xml spawner - XmlSpawner spawner = new XmlSpawner(SpawnId, location.X, location.Y, 0, 0, name, maxcount, + var spawner = new XmlSpawner(SpawnId, location.X, location.Y, 0, 0, name, maxcount, minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), null, null, null, null, null, null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null) { SpawnRange = spawnRange, - m_PlayerCreated = true + PlayerCreated = true }; // Try to find a valid Z height if required (Z == -999) if (location.Z == -999) { - int NewZ = map.GetAverageZ(location.X, location.Y); + var NewZ = map.GetAverageZ(location.X, location.Y); if (map.CanFit(location.X, location.Y, NewZ, SpawnFitSize) == false) { - for (int x = 1; x <= 39; x++) + for (var x = 1; x <= 39; x++) { if (map.CanFit(location.X, location.Y, NewZ + x, SpawnFitSize)) { @@ -5698,14 +5455,12 @@ public class XmlSpawner : Item, ISpawner } } - - public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) { processedmaps = 0; processedspawners = 0; - int total_processed_maps = 0; - int total_processed_spawners = 0; + var total_processed_maps = 0; + var total_processed_spawners = 0; if (filename == null || filename.Length <= 0) { @@ -5724,10 +5479,7 @@ public class XmlSpawner : Item, ISpawner if (fs == null) { - if (from != null) - { - from.SendMessage($"Unable to open {filename} for loading"); - } + from?.SendMessage($"Unable to open {filename} for loading"); return; } @@ -5747,12 +5499,9 @@ public class XmlSpawner : Item, ISpawner catch { } if (files != null && files.Length > 0) { - if (from != null) - { - from.SendMessage($"Loading {files.Length} .xml files from directory {filename}"); - } + from?.SendMessage($"Loading {files.Length} .xml files from directory {filename}"); - foreach (string file in files) + foreach (var file in files) { XmlLoadFromFile(file, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); total_processed_maps += processedmaps; @@ -5768,27 +5517,21 @@ public class XmlSpawner : Item, ISpawner catch { } if (dirs != null && dirs.Length > 0) { - foreach (string dir in dirs) + foreach (var dir in dirs) { XmlLoadFromFile(dir, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners); total_processed_maps += processedmaps; total_processed_spawners += processedspawners; } } - if (from != null) - { - from.SendMessage($"Loaded a total of {total_processed_maps} .xml files and {filename} spawners from directory {total_processed_spawners}"); - } + from?.SendMessage($"Loaded a total of {total_processed_maps} .xml files and {filename} spawners from directory {total_processed_spawners}"); processedmaps = total_processed_maps; processedspawners = total_processed_spawners; } else { - if (from != null) - { - from.SendMessage($"{filename} does not exist"); - } + from?.SendMessage($"{filename} does not exist"); } } @@ -5818,7 +5561,6 @@ public class XmlSpawner : Item, ISpawner } - public static void XmlLoadFromStream(Stream fs, string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) { XmlLoadFromStream(fs, filename, SpawnerPrefix, from, fromloc, frommap, loadrelative, maxrange, loadnew, out processedmaps, out processedspawners, false); @@ -5835,47 +5577,41 @@ public class XmlSpawner : Item, ISpawner } // assign an id that will be used to distinguish the newly loaded spawners by appending it to their name - Guid newloadid = Guid.NewGuid(); + var newloadid = Guid.NewGuid(); - int TotalCount = 0; - int TrammelCount = 0; - int FeluccaCount = 0; - int IlshenarCount = 0; - int MalasCount = 0; - int TokunoCount = 0; - int OtherCount = 0; - bool questionable_spawner = false; - bool bad_spawner = false; - int badcount = 0; - int questionablecount = 0; + var TotalCount = 0; + var TrammelCount = 0; + var FeluccaCount = 0; + var IlshenarCount = 0; + var MalasCount = 0; + var TokunoCount = 0; + var OtherCount = 0; + var questionable_spawner = false; + var bad_spawner = false; + var badcount = 0; + var questionablecount = 0; - int failedobjectitemcount = 0; - int failedsetitemcount = 0; - int relativex = -1; - int relativey = -1; - int relativez = 0; + var failedobjectitemcount = 0; + var failedsetitemcount = 0; + var relativex = -1; + var relativey = -1; + var relativez = 0; Map relativemap = null; - if (from != null) - { - from.SendMessage($"Loading {"XmlSpawner"} objects{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} from file {filename}."); - } + from?.SendMessage($"Loading {"XmlSpawner"} objects{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} from file {filename}."); // Create the data set - DataSet ds = new DataSet(SpawnDataSetName); + var ds = new DataSet(SpawnDataSetName); // Read in the file - bool fileerror = false; + var fileerror = false; try { - ds.ReadXml(fs); + _ = ds.ReadXml(fs); } catch { - if (from != null) - { - from.SendMessage(33, $"Error reading xml file {filename}"); - } + from?.SendMessage(33, $"Error reading xml file {filename}"); fileerror = true; } @@ -5898,7 +5634,7 @@ public class XmlSpawner : Item, ISpawner // the exception handler for those will flag bad_spawner and the result will be logged // Each row makes up a single spawner - string SpawnName = "Spawner"; + var SpawnName = "Spawner"; try { SpawnName = (string)dr["Name"]; } catch { questionable_spawner = true; } @@ -5912,7 +5648,7 @@ public class XmlSpawner : Item, ISpawner if (string.IsNullOrEmpty(SpawnerPrefix) || SpawnName.StartsWith(SpawnerPrefix)) { // Try load the GUID (might not work so create a new GUID) - Guid SpawnId = Guid.NewGuid(); + var SpawnId = Guid.NewGuid(); if (!loadnew) { try { SpawnId = new Guid((string)dr["UniqueId"]); } @@ -5928,9 +5664,9 @@ public class XmlSpawner : Item, ISpawner catch { Console.WriteLine("unable to set UniqueId"); } } - int SpawnCentreX = fromloc.X; - int SpawnCentreY = fromloc.Y; - int SpawnCentreZ = fromloc.Z; + var SpawnCentreX = fromloc.X; + var SpawnCentreY = fromloc.Y; + var SpawnCentreZ = fromloc.Z; try { SpawnCentreX = int.Parse((string)dr["CentreX"]); } catch { bad_spawner = true; } @@ -5939,10 +5675,10 @@ public class XmlSpawner : Item, ISpawner try { SpawnCentreZ = int.Parse((string)dr["CentreZ"]); } catch { bad_spawner = true; } - int SpawnX = SpawnCentreX; - int SpawnY = SpawnCentreY; - int SpawnWidth = 0; - int SpawnHeight = 0; + var SpawnX = SpawnCentreX; + var SpawnY = SpawnCentreY; + var SpawnWidth = 0; + var SpawnHeight = 0; try { SpawnX = int.Parse((string)dr["X"]); } catch { questionable_spawner = true; } try { SpawnY = int.Parse((string)dr["Y"]); } @@ -5953,10 +5689,10 @@ public class XmlSpawner : Item, ISpawner catch { questionable_spawner = true; } // Try load the InContainer (default to false) - bool InContainer = false; - int ContainerX = 0; - int ContainerY = 0; - int ContainerZ = 0; + var InContainer = false; + var ContainerX = 0; + var ContainerY = 0; + var ContainerZ = 0; try { InContainer = bool.Parse((string)dr["InContainer"]); } catch { } if (InContainer) @@ -5971,9 +5707,9 @@ public class XmlSpawner : Item, ISpawner // Get the map (default to the mobiles map) if the relative distance is too great, then use the defined map - Map SpawnMap = frommap; + var SpawnMap = frommap; - string XmlMapName = frommap.Name; + var XmlMapName = frommap.Name; //if (!loadrelative && !loadnew) { @@ -6030,8 +5766,8 @@ public class XmlSpawner : Item, ISpawner relativemap = SpawnMap; } - int SpawnRelZ = 0; - int OrigZ = SpawnCentreZ; + var SpawnRelZ = 0; + var OrigZ = SpawnCentreZ; if (loadrelative && Math.Abs(relativex - SpawnCentreX) <= maxrange && Math.Abs(relativey - SpawnCentreY) <= maxrange && SpawnMap == relativemap) { @@ -6052,32 +5788,29 @@ public class XmlSpawner : Item, ISpawner SpawnMap = frommap; } - if (SpawnMap == Map.Internal) { bad_spawner = true; } // Try load the IsRelativeHomeRange (default to true) - bool SpawnIsRelativeHomeRange = true; + var SpawnIsRelativeHomeRange = true; try { SpawnIsRelativeHomeRange = bool.Parse((string)dr["IsHomeRangeRelative"]); } catch { } - - int SpawnHomeRange = 5; + var SpawnHomeRange = 5; try { SpawnHomeRange = int.Parse((string)dr["Range"]); } catch { questionable_spawner = true; } - int SpawnMaxCount = 1; + var SpawnMaxCount = 1; try { SpawnMaxCount = int.Parse((string)dr["MaxCount"]); } catch { questionable_spawner = true; } //deal with double format for delay. default is the old minute format - bool delay_in_sec = false; + var delay_in_sec = false; try { delay_in_sec = bool.Parse((string)dr["DelayInSec"]); } catch { } - TimeSpan SpawnMinDelay = TimeSpan.FromMinutes(5); - TimeSpan SpawnMaxDelay = TimeSpan.FromMinutes(10); - + var SpawnMinDelay = TimeSpan.FromMinutes(5); + var SpawnMaxDelay = TimeSpan.FromMinutes(10); if (delay_in_sec) { @@ -6093,41 +5826,41 @@ public class XmlSpawner : Item, ISpawner try { SpawnMaxDelay = TimeSpan.FromMinutes(int.Parse((string)dr["MaxDelay"])); } catch { } } - TimeSpan SpawnMinRefractory = TimeSpan.FromMinutes(0); + var SpawnMinRefractory = TimeSpan.FromMinutes(0); try { SpawnMinRefractory = TimeSpan.FromMinutes(double.Parse((string)dr["MinRefractory"])); } catch { } - TimeSpan SpawnMaxRefractory = TimeSpan.FromMinutes(0); + var SpawnMaxRefractory = TimeSpan.FromMinutes(0); try { SpawnMaxRefractory = TimeSpan.FromMinutes(double.Parse((string)dr["MaxRefractory"])); } catch { } - TimeSpan SpawnTODStart = TimeSpan.FromMinutes(0); + var SpawnTODStart = TimeSpan.FromMinutes(0); try { SpawnTODStart = TimeSpan.FromMinutes(double.Parse((string)dr["TODStart"])); } catch { } - TimeSpan SpawnTODEnd = TimeSpan.FromMinutes(0); + var SpawnTODEnd = TimeSpan.FromMinutes(0); try { SpawnTODEnd = TimeSpan.FromMinutes(double.Parse((string)dr["TODEnd"])); } catch { } - int todmode = (int)TODModeType.Realtime; - TODModeType SpawnTODMode = TODModeType.Realtime; + var todmode = (int)TODModeType.Realtime; + var SpawnTODMode = TODModeType.Realtime; try { todmode = int.Parse((string)dr["TODMode"]); } catch { } switch (todmode) { case (int)TODModeType.Gametime: - { - SpawnTODMode = TODModeType.Gametime; - break; - } + { + SpawnTODMode = TODModeType.Gametime; + break; + } case (int)TODModeType.Realtime: - { - SpawnTODMode = TODModeType.Realtime; - break; - } + { + SpawnTODMode = TODModeType.Realtime; + break; + } } - int SpawnKillReset = defKillReset; + var SpawnKillReset = defKillReset; try { SpawnKillReset = int.Parse((string)dr["KillReset"]); } catch { } @@ -6166,7 +5899,7 @@ public class XmlSpawner : Item, ISpawner try { SpawnTriggerProbability = double.Parse((string)dr["TriggerProbability"]); } catch { } - int SpawnSequentialSpawning = -1; + var SpawnSequentialSpawning = -1; try { SpawnSequentialSpawning = int.Parse((string)dr["SequentialSpawning"]); } catch { } @@ -6178,23 +5911,23 @@ public class XmlSpawner : Item, ISpawner try { SpawnConfigFile = (string)dr["ConfigFile"]; } catch { } - bool SpawnAllowGhost = false; + var SpawnAllowGhost = false; try { SpawnAllowGhost = bool.Parse((string)dr["AllowGhostTriggering"]); } catch { } - bool SpawnAllowNPC = false; + var SpawnAllowNPC = false; try { SpawnAllowNPC = bool.Parse((string)dr["AllowNPCTriggering"]); } catch { } - bool SpawnSpawnOnTrigger = false; + var SpawnSpawnOnTrigger = false; try { SpawnSpawnOnTrigger = bool.Parse((string)dr["SpawnOnTrigger"]); } catch { } - bool SpawnSmartSpawning = false; + var SpawnSmartSpawning = false; try { SpawnSmartSpawning = bool.Parse((string)dr["SmartSpawning"]); } catch { } - bool TickReset = false; + var TickReset = false; try { TickReset = bool.Parse((string)dr["TickReset"]); } catch { } @@ -6211,28 +5944,28 @@ public class XmlSpawner : Item, ISpawner // read the duration parameter from the xml file // but older files wont have it so deal with that condition and set it to the default of "0", i.e. infinite duration // Try to get the "Duration" field, but in case it doesn't exist, catch and discard the exception - TimeSpan SpawnDuration = TimeSpan.FromMinutes(0); + var SpawnDuration = TimeSpan.FromMinutes(0); try { SpawnDuration = TimeSpan.FromMinutes(double.Parse((string)dr["Duration"])); } catch { } - TimeSpan SpawnDespawnTime = TimeSpan.FromHours(0); + var SpawnDespawnTime = TimeSpan.FromHours(0); try { SpawnDespawnTime = TimeSpan.FromHours(double.Parse((string)dr["DespawnTime"])); } catch { } - int SpawnProximityRange = -1; + var SpawnProximityRange = -1; // Try to get the "ProximityRange" field, but in case it doesn't exist, catch and discard the exception try { SpawnProximityRange = int.Parse((string)dr["ProximityRange"]); } catch { } - int SpawnProximityTriggerSound = 0; + var SpawnProximityTriggerSound = 0; // Try to get the "ProximityTriggerSound" field, but in case it doesn't exist, catch and discard the exception try { SpawnProximityTriggerSound = int.Parse((string)dr["ProximityTriggerSound"]); } catch { } - int SpawnAmount = 1; + var SpawnAmount = 1; try { SpawnAmount = int.Parse((string)dr["Amount"]); } catch { } - bool SpawnExternalTriggering = false; + var SpawnExternalTriggering = false; try { SpawnExternalTriggering = bool.Parse((string)dr["ExternalTriggering"]); } catch { } @@ -6240,20 +5973,20 @@ public class XmlSpawner : Item, ISpawner try { waypointstr = (string)dr["Waypoint"]; } catch { } - WayPoint SpawnWaypoint = GetWaypoint(waypointstr); + var SpawnWaypoint = GetWaypoint(waypointstr); - int SpawnTeam = 0; + var SpawnTeam = 0; try { SpawnTeam = int.Parse((string)dr["Team"]); } catch { questionable_spawner = true; } - bool SpawnIsGroup = false; + var SpawnIsGroup = false; try { SpawnIsGroup = bool.Parse((string)dr["IsGroup"]); } catch { questionable_spawner = true; } - bool SpawnIsRunning = false; + var SpawnIsRunning = false; try { SpawnIsRunning = bool.Parse((string)dr["IsRunning"]); } catch { questionable_spawner = true; } // try loading the new spawn specifications first - SpawnObject[] Spawns = new SpawnObject[0]; - bool havenew = true; + var Spawns = new SpawnObject[0]; + var havenew = true; try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); } catch { havenew = false; } if (!havenew) @@ -6267,22 +6000,19 @@ public class XmlSpawner : Item, ISpawner // do a check on the location of the spawner if (!IsValidMapLocation(SpawnCentreX, SpawnCentreY, SpawnMap)) { - if (from != null) - { - from.SendMessage(33, $"Invalid location '{SpawnName}' at [{SpawnCentreX} {SpawnCentreY}] in {XmlMapName}"); - } + from?.SendMessage(33, $"Invalid location '{SpawnName}' at [{SpawnCentreX} {SpawnCentreY}] in {XmlMapName}"); bad_spawner = true; } // Check if this spawner already exists XmlSpawner OldSpawner = null; - bool found_container = false; - bool found_spawner = false; + var found_container = false; + var found_spawner = false; Container spawn_container = null; if (!bad_spawner) { - foreach (Item i in World.Items.Values) + foreach (var i in World.Items.Values) { if (i is XmlSpawner checkXmlSpawner) { @@ -6316,10 +6046,7 @@ public class XmlSpawner : Item, ISpawner if (bad_spawner) { badcount++; - if (from != null) - { - from.SendMessage(33, "Invalid spawner"); - } + from?.SendMessage(33, "Invalid spawner"); // log it long fileposition = -1; @@ -6327,11 +6054,9 @@ public class XmlSpawner : Item, ISpawner catch { } try { - using (StreamWriter op = new StreamWriter("badxml.log", true)) - { - op.WriteLine("# Invalid spawner : {0}: Fileposition {1} {2}", Core.Now, fileposition, filename); - op.WriteLine(); - } + using var op = new StreamWriter("badxml.log", true); + op.WriteLine("# Invalid spawner : {0}: Fileposition {1} {2}", Core.Now, fileposition, filename); + op.WriteLine(); } catch { } } @@ -6339,10 +6064,7 @@ public class XmlSpawner : Item, ISpawner if (questionable_spawner) { questionablecount++; - if (from != null) - { - from.SendMessage(33, $"Questionable spawner '{SpawnName}' at [{SpawnCentreX} {SpawnCentreY}] in {XmlMapName}"); - } + from?.SendMessage(33, $"Questionable spawner '{SpawnName}' at [{SpawnCentreX} {SpawnCentreY}] in {XmlMapName}"); // log it long fileposition = -1; @@ -6350,25 +6072,20 @@ public class XmlSpawner : Item, ISpawner catch { } try { - using (StreamWriter op = new StreamWriter("badxml.log", true)) - { - op.WriteLine("# Questionable spawner : {0}: Format: X Y Z Map SpawnerName Fileposition Xmlfile", Core.Now); - op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", SpawnCentreX, SpawnCentreY, SpawnCentreZ, XmlMapName, SpawnName, fileposition, filename); - op.WriteLine(); - } + using var op = new StreamWriter("badxml.log", true); + op.WriteLine("# Questionable spawner : {0}: Format: X Y Z Map SpawnerName Fileposition Xmlfile", Core.Now); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", SpawnCentreX, SpawnCentreY, SpawnCentreZ, XmlMapName, SpawnName, fileposition, filename); + op.WriteLine(); } catch { } } if (!bad_spawner) { // Delete the old spawner if it exists - if (OldSpawner != null) - { - OldSpawner.Delete(); - } + OldSpawner?.Delete(); // Create the new spawner - XmlSpawner TheSpawn = new XmlSpawner(SpawnId, SpawnX, SpawnY, SpawnWidth, SpawnHeight, SpawnName, SpawnMaxCount, + var TheSpawn = new XmlSpawner(SpawnId, SpawnX, SpawnY, SpawnWidth, SpawnHeight, SpawnName, SpawnMaxCount, SpawnMinDelay, SpawnMaxDelay, SpawnDuration, SpawnProximityRange, SpawnProximityTriggerSound, SpawnAmount, SpawnTeam, SpawnHomeRange, SpawnIsRelativeHomeRange, Spawns, SpawnMinRefractory, SpawnMaxRefractory, SpawnTODStart, SpawnTODEnd, SpawnObjectPropertyItem, SpawnObjectPropertyName, SpawnProximityMessage, SpawnItemTriggerName, SpawnNoItemTriggerName, @@ -6376,11 +6093,11 @@ public class XmlSpawner : Item, ISpawner SpawnSetPropertyItem, SpawnIsGroup, SpawnTODMode, SpawnKillReset, SpawnExternalTriggering, SpawnSequentialSpawning, SpawnRegionName, SpawnAllowGhost, SpawnAllowNPC, SpawnSpawnOnTrigger, SpawnConfigFile, SpawnDespawnTime, SpawnSkillTrigger, SpawnSmartSpawning, SpawnWaypoint) { - m_DisableGlobalAutoReset = TickReset + DisableGlobalAutoReset = TickReset }; // Try to find a valid Z height if required (SpawnCentreZ = short.MinValue) - int NewZ = 0; + var NewZ = 0; // Check if relative loading is set. If so then try loading at the z-offset position first with no surface requirement, then try auto /*if (loadrelative && SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, OrigZ - SpawnRelZ, SpawnFitSize,true, false,false)) */ @@ -6395,7 +6112,7 @@ public class XmlSpawner : Item, ISpawner if (SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, NewZ, SpawnFitSize) == false) { - for (int x = 1; x <= 39; x++) + for (var x = 1; x <= 39; x++) { if (SpawnMap.CanFit(SpawnCentreX, SpawnCentreY, NewZ + x, SpawnFitSize)) { @@ -6432,7 +6149,6 @@ public class XmlSpawner : Item, ISpawner TheSpawn.NextSpawn = TimeSpan.Zero; TheSpawn.ResetNextSpawnTimes(); - // Send a message to the client that the spawner is created if (from != null && verbose) { @@ -6451,18 +6167,15 @@ public class XmlSpawner : Item, ISpawner } } - if (from != null) - { - from.SendMessage("Resolving spawner self references"); - } + from?.SendMessage("Resolving spawner self references"); if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) { foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) { // Try load the GUID - bool badid = false; - Guid SpawnId = Guid.NewGuid(); + var badid = false; + var SpawnId = Guid.NewGuid(); try { SpawnId = new Guid((string)dr["UniqueId"]); } catch { badid = true; } if (badid) @@ -6471,8 +6184,8 @@ public class XmlSpawner : Item, ISpawner } // Get the map - Map SpawnMap = frommap; - string XmlMapName = frommap.Name; + var SpawnMap = frommap; + var XmlMapName = frommap.Name; if (!loadrelative) { @@ -6487,9 +6200,9 @@ public class XmlSpawner : Item, ISpawner catch { } } - bool found_spawner = false; + var found_spawner = false; XmlSpawner OldSpawner = null; - foreach (Item i in World.Items.Values) + foreach (var i in World.Items.Values) { if (i is XmlSpawner checkXmlSpawner) { @@ -6518,9 +6231,9 @@ public class XmlSpawner : Item, ISpawner if (!string.IsNullOrEmpty(setObjectName)) { // try to parse out the type information if it has also been saved - string[] typeargs = setObjectName.Split(",".ToCharArray(), 2); + var typeargs = setObjectName.Split(",".ToCharArray(), 2); string typestr = null; - string namestr = setObjectName; + var namestr = setObjectName; if (typeargs.Length > 1) { @@ -6531,33 +6244,25 @@ public class XmlSpawner : Item, ISpawner // if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid if (loadnew) { - string tmpsetObjectName = $"{namestr}-{newloadid}"; - OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, tmpsetObjectName, typestr); + var tmpsetObjectName = $"{namestr}-{newloadid}"; + OldSpawner.SetItem = BaseXmlSpawner.FindItemByName(null, tmpsetObjectName, typestr); } // if this fails then try the original - if (OldSpawner.m_SetPropertyItem == null) - { - OldSpawner.m_SetPropertyItem = BaseXmlSpawner.FindItemByName(null, namestr, typestr); - } - if (OldSpawner.m_SetPropertyItem == null) + OldSpawner.SetItem ??= BaseXmlSpawner.FindItemByName(null, namestr, typestr); + if (OldSpawner.SetItem == null) { failedsetitemcount++; - if (from != null) - { - from.SendMessage(33, $"Failed to initialize SetItemProperty Object '{setObjectName}' on ' '{OldSpawner.Name}' at [{OldSpawner.Location.X} {OldSpawner.Location.Y}] in {OldSpawner.Map}"); - } + from?.SendMessage(33, $"Failed to initialize SetItemProperty Object '{setObjectName}' on ' '{OldSpawner.Name}' at [{OldSpawner.Location.X} {OldSpawner.Location.Y}] in {OldSpawner.Map}"); // log it try { - using (StreamWriter op = new StreamWriter("badxml.log", true)) - { - op.WriteLine("# Failed SetItemProperty Object initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", - Core.Now); - op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", - setObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); - op.WriteLine(); - } + using var op = new StreamWriter("badxml.log", true); + op.WriteLine("# Failed SetItemProperty Object initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", + Core.Now); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", + setObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); + op.WriteLine(); } catch { } } @@ -6569,9 +6274,9 @@ public class XmlSpawner : Item, ISpawner if (!string.IsNullOrEmpty(triggerObjectName)) { - string[] typeargs = triggerObjectName.Split(",".ToCharArray(), 2); + var typeargs = triggerObjectName.Split(",".ToCharArray(), 2); string typestr = null; - string namestr = triggerObjectName; + var namestr = triggerObjectName; if (typeargs.Length > 1) { @@ -6582,33 +6287,25 @@ public class XmlSpawner : Item, ISpawner // if this is a new load then assume that it will be referring to another newly loaded object so append the newloadid if (loadnew) { - string tmptriggerObjectName = $"{namestr}-{newloadid}"; + var tmptriggerObjectName = $"{namestr}-{newloadid}"; OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, tmptriggerObjectName, typestr); } // if this fails then try the original - if (OldSpawner.m_ObjectPropertyItem == null) - { - OldSpawner.m_ObjectPropertyItem = BaseXmlSpawner.FindItemByName(null, namestr, typestr); - } + OldSpawner.m_ObjectPropertyItem ??= BaseXmlSpawner.FindItemByName(null, namestr, typestr); if (OldSpawner.m_ObjectPropertyItem == null) { failedobjectitemcount++; - if (from != null) - { - from.SendMessage(33, $"Failed to initialize TriggerObject '{triggerObjectName}' on ' '{OldSpawner.Name}' at [{OldSpawner.Location.X} {OldSpawner.Location.Y}] in {OldSpawner.Map}"); - } + from?.SendMessage(33, $"Failed to initialize TriggerObject '{triggerObjectName}' on ' '{OldSpawner.Name}' at [{OldSpawner.Location.X} {OldSpawner.Location.Y}] in {OldSpawner.Map}"); // log it try { - using (StreamWriter op = new StreamWriter("badxml.log", true)) - { - op.WriteLine("# Failed TriggerObject initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", - Core.Now); - op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", - triggerObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); - op.WriteLine(); - } + using var op = new StreamWriter("badxml.log", true); + op.WriteLine("# Failed TriggerObject initialization : {0}: Format: ObjectName X Y Z Map SpawnerName Xmlfile", + Core.Now); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", + triggerObjectName, OldSpawner.Location.X, OldSpawner.Location.Y, OldSpawner.Location.Z, OldSpawner.Map, OldSpawner.Name, filename); + op.WriteLine(); } catch { } } @@ -6625,38 +6322,23 @@ public class XmlSpawner : Item, ISpawner } catch { } - if (from != null) - { - from.SendMessage($"{TotalCount} spawner(s) were created from file {filename} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount} Other={OtherCount}]."); - } + from?.SendMessage($"{TotalCount} spawner(s) were created from file {filename} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount} Other={OtherCount}]."); if (failedobjectitemcount > 0) { - if (from != null) - { - from.SendMessage(33, $"Failed to initialize TriggerObjects in {failedobjectitemcount} spawners. Saved to 'badxml.log'"); - } + from?.SendMessage(33, $"Failed to initialize TriggerObjects in {failedobjectitemcount} spawners. Saved to 'badxml.log'"); } if (failedsetitemcount > 0) { - if (from != null) - { - from.SendMessage(33, $"Failed to initialize SetItemProperty Objects in {failedsetitemcount} spawners. Saved to 'badxml.log'"); - } + from?.SendMessage(33, $"Failed to initialize SetItemProperty Objects in {failedsetitemcount} spawners. Saved to 'badxml.log'"); } if (badcount > 0) { - if (from != null) - { - from.SendMessage(33, $"{badcount} bad spawners detected. Saved to 'badxml.log'"); - } + from?.SendMessage(33, $"{badcount} bad spawners detected. Saved to 'badxml.log'"); } if (questionablecount > 0) { - if (from != null) - { - from.SendMessage(33, $"{questionablecount} questionable spawners detected. Saved to 'badxml.log'"); - } + from?.SendMessage(33, $"{questionablecount} questionable spawners detected. Saved to 'badxml.log'"); } processedmaps = 1; processedspawners = TotalCount; @@ -6665,7 +6347,7 @@ public class XmlSpawner : Item, ISpawner public static string LocateFile(string filename) { - bool found = false; + var found = false; string dirname = null; @@ -6693,10 +6375,10 @@ public class XmlSpawner : Item, ISpawner { if (e.Arguments.Length >= 1) { - string filename = LocateFile(e.Arguments[0]); + var filename = LocateFile(e.Arguments[0]); // Spawner load criteria (if any) - string SpawnerPrefix = string.Empty; + var SpawnerPrefix = string.Empty; // Check if there is an argument provided (load criteria) if (e.Arguments.Length > 1) @@ -6727,10 +6409,10 @@ public class XmlSpawner : Item, ISpawner { if (e.Arguments.Length >= 1) { - string filename = LocateFile(e.Arguments[0]); + var filename = LocateFile(e.Arguments[0]); // Spawner load criteria (if any) - string SpawnerPrefix = string.Empty; + var SpawnerPrefix = string.Empty; // Check if there is an argument provided (load criteria) if (e.Arguments.Length > 1) @@ -6759,18 +6441,18 @@ public class XmlSpawner : Item, ISpawner { if (e.Arguments.Length >= 1) { - string filename = LocateFile(e.Arguments[0]); + var filename = LocateFile(e.Arguments[0]); // Spawner load criteria (if any) - string SpawnerPrefix = string.Empty; - bool badargs = false; - int maxrange = 48; + var SpawnerPrefix = string.Empty; + var badargs = false; + var maxrange = 48; // Check if there is an argument provided (load criteria) try { // Check if there is an argument provided (load criteria) - for (int nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++) + for (var nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++) { // is it a maxrange option? if (e.Arguments[nxtarg].ToLower() == "-maxrange") @@ -6809,17 +6491,17 @@ public class XmlSpawner : Item, ISpawner { if (e.Arguments.Length >= 1) { - string filename = LocateFile(e.Arguments[0]); + var filename = LocateFile(e.Arguments[0]); // Spawner load criteria (if any) - string SpawnerPrefix = string.Empty; - bool badargs = false; - int maxrange = 48; + var SpawnerPrefix = string.Empty; + var badargs = false; + var maxrange = 48; try { // Check if there is an argument provided (load criteria) - for (int nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++) + for (var nxtarg = 1; nxtarg < e.Arguments.Length; nxtarg++) { // is it a maxrange option? if (e.Arguments[nxtarg].ToLower() == "-maxrange") @@ -6896,17 +6578,15 @@ public class XmlSpawner : Item, ISpawner return; } - string filename = e.Arguments[0]; + var filename = e.Arguments[0]; - XmlSpawner xmlspawner = obj as XmlSpawner; - - if (xmlspawner == null) + if (obj is not XmlSpawner xmlspawner) { e.Mobile.SendMessage("You can select only XmlSpawner objects!"); return; } - Mobile m = e.Mobile; + var m = e.Mobile; CommandLogging.WriteLine(m, $"{m.AccessLevel} {CommandLogging.Format(m)} Saving XmlSpawner {CommandLogging.Format(xmlspawner)} on file {CommandLogging.Format(filename)}"); SaveSpawns(m, xmlspawner, filename); @@ -6936,9 +6616,11 @@ public class XmlSpawner : Item, ISpawner m.SendMessage($"Saving object in folder {dirname} - file {filename} - spawner {xmlspawner}."); - List saveslist = new List(1); - saveslist.Add(xmlspawner); - SaveSpawnList(m, saveslist, dirname, false, true); + var saveslist = new List(1) + { + xmlspawner + }; + _ = SaveSpawnList(m, saveslist, dirname, false, true); } private static void SaveSpawns(CommandEventArgs e, bool SaveAllMaps, bool oldformat) @@ -6961,7 +6643,7 @@ public class XmlSpawner : Item, ISpawner } // Spawner save criteria (if any) - string SpawnerPrefix = string.Empty; + var SpawnerPrefix = string.Empty; // Check if there is an argument provided (save criteria) if (e.Arguments.Length > 1) @@ -6969,7 +6651,7 @@ public class XmlSpawner : Item, ISpawner SpawnerPrefix = e.Arguments[1]; } - string filename = e.Arguments[0]; + var filename = e.Arguments[0]; string dirname; if (Directory.Exists(XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) @@ -6996,15 +6678,14 @@ public class XmlSpawner : Item, ISpawner ); } - - List saveslist = new List(); + var saveslist = new List(); // Add each spawn point to the list - foreach (Item i in World.Items.Values) + foreach (var i in World.Items.Values) { if (i is XmlSpawner spawner && !spawner.Deleted && (SaveAllMaps || spawner.Map == e.Mobile.Map) //check for mob carried spawners and ignore them - && !(spawner.RootParent is Mobile) + && spawner.RootParent is not Mobile && (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || spawner.Name != null && spawner.Name.StartsWith(SpawnerPrefix))) { saveslist.Add(spawner); @@ -7012,10 +6693,13 @@ public class XmlSpawner : Item, ISpawner } // save the list - SaveSpawnList(e.Mobile, saveslist, dirname, oldformat, true); + _ = SaveSpawnList(e.Mobile, saveslist, dirname, oldformat, true); } - public static bool SaveSpawnList(List savelist, Stream stream) => SaveSpawnList(null, savelist, null, stream, false, false); + public static bool SaveSpawnList(List savelist, Stream stream) + { + return SaveSpawnList(null, savelist, null, stream, false, false); + } public static bool SaveSpawnList(Mobile from, List savelist, string dirname, bool oldformat, bool verbose) { @@ -7024,8 +6708,7 @@ public class XmlSpawner : Item, ISpawner return false; } - - bool save_ok = true; + var save_ok = true; FileStream fs = null; try @@ -7035,10 +6718,7 @@ public class XmlSpawner : Item, ISpawner } catch { - if (from != null) - { - from.SendMessage($"Error creating file {dirname}"); - } + from?.SendMessage($"Error creating file {dirname}"); save_ok = false; } @@ -7057,7 +6737,6 @@ public class XmlSpawner : Item, ISpawner return save_ok; } - public static bool SaveSpawnList(Mobile from, List savelist, string dirname, Stream stream, bool oldformat, bool verbose) { if (savelist == null || stream == null) @@ -7065,86 +6744,85 @@ public class XmlSpawner : Item, ISpawner return false; } - int TotalCount = 0; - int TrammelCount = 0; - int FeluccaCount = 0; - int IlshenarCount = 0; - int MalasCount = 0; - int TokunoCount = 0; - int OtherCount = 0; - + var TotalCount = 0; + var TrammelCount = 0; + var FeluccaCount = 0; + var IlshenarCount = 0; + var MalasCount = 0; + var TokunoCount = 0; + var OtherCount = 0; // Create the data set - DataSet ds = new DataSet(SpawnDataSetName); + var ds = new DataSet(SpawnDataSetName); // Load the data set up - ds.Tables.Add(SpawnTablePointName); + _ = ds.Tables.Add(SpawnTablePointName); // Create spawn point schema - ds.Tables[SpawnTablePointName].Columns.Add("Name"); - ds.Tables[SpawnTablePointName].Columns.Add("UniqueId"); - ds.Tables[SpawnTablePointName].Columns.Add("Map"); - ds.Tables[SpawnTablePointName].Columns.Add("X"); - ds.Tables[SpawnTablePointName].Columns.Add("Y"); - ds.Tables[SpawnTablePointName].Columns.Add("Width"); - ds.Tables[SpawnTablePointName].Columns.Add("Height"); - ds.Tables[SpawnTablePointName].Columns.Add("CentreX"); - ds.Tables[SpawnTablePointName].Columns.Add("CentreY"); - ds.Tables[SpawnTablePointName].Columns.Add("CentreZ"); - ds.Tables[SpawnTablePointName].Columns.Add("Range"); - ds.Tables[SpawnTablePointName].Columns.Add("MaxCount"); - ds.Tables[SpawnTablePointName].Columns.Add("MinDelay"); - ds.Tables[SpawnTablePointName].Columns.Add("MaxDelay"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Name"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("UniqueId"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Map"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("X"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Y"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Width"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Height"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("CentreX"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("CentreY"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("CentreZ"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Range"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("MaxCount"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("MinDelay"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("MaxDelay"); // deal with the double format for delay. old format stored them as minutes in int format. that meant that short delays were lost // proper solution would simply be to store as doubles, but older progs still assume int format (like spawneditor) // so this is the solution. add a flag and do it both ways. - ds.Tables[SpawnTablePointName].Columns.Add("DelayInSec"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("DelayInSec"); // add the duration and proximity range and sound parameters, and in container flag and coords inside the container - ds.Tables[SpawnTablePointName].Columns.Add("Duration"); - ds.Tables[SpawnTablePointName].Columns.Add("DespawnTime"); - ds.Tables[SpawnTablePointName].Columns.Add("ProximityRange"); - ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerSound"); - ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerMessage"); - ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyName"); - ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyItemName"); - ds.Tables[SpawnTablePointName].Columns.Add("SetPropertyItemName"); - ds.Tables[SpawnTablePointName].Columns.Add("ItemTriggerName"); - ds.Tables[SpawnTablePointName].Columns.Add("NoItemTriggerName"); - ds.Tables[SpawnTablePointName].Columns.Add("MobTriggerName"); - ds.Tables[SpawnTablePointName].Columns.Add("MobPropertyName"); - ds.Tables[SpawnTablePointName].Columns.Add("PlayerPropertyName"); - ds.Tables[SpawnTablePointName].Columns.Add("TriggerProbability"); - ds.Tables[SpawnTablePointName].Columns.Add("SpeechTrigger"); - ds.Tables[SpawnTablePointName].Columns.Add("SkillTrigger"); - ds.Tables[SpawnTablePointName].Columns.Add("InContainer"); - ds.Tables[SpawnTablePointName].Columns.Add("ContainerX"); - ds.Tables[SpawnTablePointName].Columns.Add("ContainerY"); - ds.Tables[SpawnTablePointName].Columns.Add("ContainerZ"); - ds.Tables[SpawnTablePointName].Columns.Add("MinRefractory"); - ds.Tables[SpawnTablePointName].Columns.Add("MaxRefractory"); - ds.Tables[SpawnTablePointName].Columns.Add("TODStart"); - ds.Tables[SpawnTablePointName].Columns.Add("TODEnd"); - ds.Tables[SpawnTablePointName].Columns.Add("TODMode"); - ds.Tables[SpawnTablePointName].Columns.Add("KillReset"); - ds.Tables[SpawnTablePointName].Columns.Add("ExternalTriggering"); - ds.Tables[SpawnTablePointName].Columns.Add("SequentialSpawning"); - ds.Tables[SpawnTablePointName].Columns.Add("RegionName"); - ds.Tables[SpawnTablePointName].Columns.Add("AllowGhostTriggering"); - ds.Tables[SpawnTablePointName].Columns.Add("AllowNPCTriggering"); - ds.Tables[SpawnTablePointName].Columns.Add("SpawnOnTrigger"); - ds.Tables[SpawnTablePointName].Columns.Add("ConfigFile"); - ds.Tables[SpawnTablePointName].Columns.Add("SmartSpawning"); - ds.Tables[SpawnTablePointName].Columns.Add("TickReset"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Duration"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("DespawnTime"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ProximityRange"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerSound"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ProximityTriggerMessage"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ObjectPropertyItemName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("SetPropertyItemName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ItemTriggerName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("NoItemTriggerName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("MobTriggerName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("MobPropertyName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("PlayerPropertyName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("TriggerProbability"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("SpeechTrigger"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("SkillTrigger"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("InContainer"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ContainerX"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ContainerY"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ContainerZ"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("MinRefractory"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("MaxRefractory"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("TODStart"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("TODEnd"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("TODMode"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("KillReset"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ExternalTriggering"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("SequentialSpawning"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("RegionName"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("AllowGhostTriggering"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("AllowNPCTriggering"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("SpawnOnTrigger"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("ConfigFile"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("SmartSpawning"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("TickReset"); - ds.Tables[SpawnTablePointName].Columns.Add("WayPoint"); - ds.Tables[SpawnTablePointName].Columns.Add("Team"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("WayPoint"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Team"); // amount for stacked item spawns - ds.Tables[SpawnTablePointName].Columns.Add("Amount"); - ds.Tables[SpawnTablePointName].Columns.Add("IsGroup"); - ds.Tables[SpawnTablePointName].Columns.Add("IsRunning"); - ds.Tables[SpawnTablePointName].Columns.Add("IsHomeRangeRelative"); - ds.Tables[SpawnTablePointName].Columns.Add(oldformat ? "Objects" : "Objects2"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("Amount"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("IsGroup"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("IsRunning"); + _ = ds.Tables[SpawnTablePointName].Columns.Add("IsHomeRangeRelative"); + _ = ds.Tables[SpawnTablePointName].Columns.Add(oldformat ? "Objects" : "Objects2"); // Always export sorted by UUID to help diffs savelist.Sort((a, b) => @@ -7153,7 +6831,7 @@ public class XmlSpawner : Item, ISpawner }); // Add each spawn point to the new table - foreach (XmlSpawner sp in savelist) + foreach (var sp in savelist) { if (sp == null || sp.Map == null || sp.Deleted) { @@ -7161,19 +6839,19 @@ public class XmlSpawner : Item, ISpawner } if (verbose && from != null) - // Send a message to the client that the spawner is being saved + // Send a message to the client that the spawner is being saved { from.SendMessage(68, $"Saving '{sp.Name}' in {sp.Map.Name} at {sp.Location}"); } // Create a new data row - DataRow dr = ds.Tables[SpawnTablePointName].NewRow(); + var dr = ds.Tables[SpawnTablePointName].NewRow(); // Populate the data dr["Name"] = sp.Name; // Set the unqiue id - dr["UniqueId"] = sp.m_UniqueId; + dr["UniqueId"] = sp.UniqueId; // Get the map name dr["Map"] = sp.Map.Name; @@ -7252,19 +6930,19 @@ public class XmlSpawner : Item, ISpawner } // additional parameters - dr["TODStart"] = sp.m_TODStart.TotalMinutes; - dr["TODEnd"] = sp.m_TODEnd.TotalMinutes; - dr["TODMode"] = (int)sp.m_TODMode; - dr["KillReset"] = sp.m_KillReset; - dr["MinRefractory"] = sp.m_MinRefractory.TotalMinutes; - dr["MaxRefractory"] = sp.m_MaxRefractory.TotalMinutes; + dr["TODStart"] = sp.TODStart.TotalMinutes; + dr["TODEnd"] = sp.TODEnd.TotalMinutes; + dr["TODMode"] = (int)sp.TODMode; + dr["KillReset"] = sp.KillReset; + dr["MinRefractory"] = sp.RefractMin.TotalMinutes; + dr["MaxRefractory"] = sp.RefractMax.TotalMinutes; dr["Duration"] = sp.m_Duration.TotalMinutes; - dr["DespawnTime"] = sp.m_DespawnTime.TotalHours; - dr["ExternalTriggering"] = sp.m_ExternalTriggering; + dr["DespawnTime"] = sp.DespawnTime.TotalHours; + dr["ExternalTriggering"] = sp.ExternalTriggering; dr["ProximityRange"] = sp.m_ProximityRange; - dr["ProximityTriggerSound"] = sp.m_ProximityTriggerSound; - dr["ProximityTriggerMessage"] = sp.m_ProximityTriggerMessage; + dr["ProximityTriggerSound"] = sp.ProximitySound; + dr["ProximityTriggerMessage"] = sp.ProximityMsg; if (sp.m_ObjectPropertyItem != null && !sp.m_ObjectPropertyItem.Deleted) { dr["ObjectPropertyItemName"] = $"{sp.m_ObjectPropertyItem.Name},{sp.m_ObjectPropertyItem.GetType().Name}"; @@ -7275,9 +6953,9 @@ public class XmlSpawner : Item, ISpawner } dr["ObjectPropertyName"] = sp.m_ObjectPropertyName; - if (sp.m_SetPropertyItem != null && !sp.m_SetPropertyItem.Deleted) + if (sp.SetItem != null && !sp.SetItem.Deleted) { - dr["SetPropertyItemName"] = $"{sp.m_SetPropertyItem.Name},{sp.m_SetPropertyItem.GetType().Name}"; + dr["SetPropertyItemName"] = $"{sp.SetItem.Name},{sp.SetItem.GetType().Name}"; } else { @@ -7286,42 +6964,42 @@ public class XmlSpawner : Item, ISpawner dr["ItemTriggerName"] = sp.m_ItemTriggerName; dr["NoItemTriggerName"] = sp.m_NoItemTriggerName; - dr["MobTriggerName"] = sp.m_MobTriggerName; - dr["MobPropertyName"] = sp.m_MobPropertyName; - dr["PlayerPropertyName"] = sp.m_PlayerPropertyName; - dr["TriggerProbability"] = sp.m_TriggerProbability; - dr["SequentialSpawning"] = sp.m_SequentialSpawning; + dr["MobTriggerName"] = sp.MobTriggerName; + dr["MobPropertyName"] = sp.MobTriggerProp; + dr["PlayerPropertyName"] = sp.PlayerTriggerProp; + dr["TriggerProbability"] = sp.TriggerProbability; + dr["SequentialSpawning"] = sp.SequentialSpawn; dr["RegionName"] = sp.m_RegionName; - dr["AllowGhostTriggering"] = sp.m_AllowGhostTriggering; - dr["AllowNPCTriggering"] = sp.m_AllowNPCTriggering; - dr["SpawnOnTrigger"] = sp.m_SpawnOnTrigger; - dr["ConfigFile"] = sp.m_ConfigFile; + dr["AllowGhostTriggering"] = sp.AllowGhostTrig; + dr["AllowNPCTriggering"] = sp.AllowNPCTrig; + dr["SpawnOnTrigger"] = sp.SpawnOnTrigger; + dr["ConfigFile"] = sp.ConfigFile; dr["SmartSpawning"] = sp.m_SmartSpawning; - dr["TickReset"] = sp.m_DisableGlobalAutoReset; + dr["TickReset"] = sp.DisableGlobalAutoReset; - dr["SpeechTrigger"] = sp.m_SpeechTrigger; - dr["SkillTrigger"] = sp.m_SkillTrigger; - dr["Amount"] = sp.m_StackAmount; + dr["SpeechTrigger"] = sp.SpeechTrigger; + dr["SkillTrigger"] = sp.SkillTrigger; + dr["Amount"] = sp.StackAmount; dr["Team"] = sp.m_Team; // assign the waypoint based on the waypoint name if it deviates from the default waypoint name, otherwise do it by serial string waystr = null; - if (sp.m_WayPoint != null) + if (sp.WayPoint != null) { - if (sp.m_WayPoint.Name != defwaypointname && !string.IsNullOrEmpty(sp.m_WayPoint.Name)) + if (sp.WayPoint.Name != defwaypointname && !string.IsNullOrEmpty(sp.WayPoint.Name)) { - waystr = sp.m_WayPoint.Name; + waystr = sp.WayPoint.Name; } else { - waystr = $"SERIAL,{sp.m_WayPoint.Serial}"; + waystr = $"SERIAL,{sp.WayPoint.Serial}"; } } dr["WayPoint"] = waystr; dr["IsGroup"] = sp.m_Group; dr["IsRunning"] = sp.m_Running; - dr["IsHomeRangeRelative"] = sp.m_HomeRangeIsRelative; + dr["IsHomeRangeRelative"] = sp.HomeRangeIsRelative; if (oldformat) { dr["Objects"] = sp.GetSerializedObjectList(); @@ -7339,7 +7017,7 @@ public class XmlSpawner : Item, ISpawner } // Write out the file - bool file_error = false; + var file_error = false; if (TotalCount > 0) { try @@ -7360,10 +7038,7 @@ public class XmlSpawner : Item, ISpawner } catch { } // Indicate how many spawners were written - if (from != null) - { - from.SendMessage($"{TotalCount} spawner(s) were saved to file {dirname} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}]."); - } + from?.SendMessage($"{TotalCount} spawner(s) were saved to file {dirname} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}]."); return true; } @@ -7378,7 +7053,7 @@ public class XmlSpawner : Item, ISpawner if (e.Mobile.AccessLevel >= AccessLevel.Administrator) { // Spawner delete criteria (if any) - string SpawnerPrefix = string.Empty; + var SpawnerPrefix = string.Empty; // Check if there is an argument provided (delete criteria) if (e.Arguments != null && e.Arguments.Length > 0) @@ -7396,9 +7071,9 @@ public class XmlSpawner : Item, ISpawner } // Delete Xml spawner's in the world based on the mobiles current map - int Count = 0; - List ToDelete = new List(); - foreach (Item i in World.Items.Values) + var Count = 0; + var ToDelete = new List(); + foreach (var i in World.Items.Values) { if (i is XmlSpawner && (WipeAll || i.Map == e.Mobile.Map) && i.Deleted == false) { @@ -7415,7 +7090,7 @@ public class XmlSpawner : Item, ISpawner } // Delete the items in the array list - foreach (Item i in ToDelete) + foreach (var i in ToDelete) { i.Delete(); } @@ -7435,7 +7110,6 @@ public class XmlSpawner : Item, ISpawner } } - [Usage("XmlSpawnerRespawn [SpawnerPrefixFilter]")] [Description("Respawns all XmlSpawner objects from the current map.")] public static void Respawn_OnCommand(CommandEventArgs e) @@ -7460,7 +7134,7 @@ public class XmlSpawner : Item, ISpawner if (e.Mobile.AccessLevel >= AccessLevel.Administrator) { // Spawner Respawn criteria (if any) - string SpawnerPrefix = string.Empty; + var SpawnerPrefix = string.Empty; // Check if there is an argument provided (respawn criteria) if (e.Arguments != null && e.Arguments.Length > 0) @@ -7478,9 +7152,9 @@ public class XmlSpawner : Item, ISpawner } // Respawn Xml spawner's in the world based on the mobiles current map - int Count = 0; - List ToRespawn = new List(); - foreach (Item i in World.Items.Values) + var Count = 0; + var ToRespawn = new List(); + foreach (var i in World.Items.Values) { try { @@ -7497,13 +7171,13 @@ public class XmlSpawner : Item, ISpawner catch (Exception ex) { Console.WriteLine("Error attempting to add {0}, {1}", i, ex.Message); } } // Respawn the items in the array list - foreach (Item i in ToRespawn) + foreach (var i in ToRespawn) { // Send a message to the client that the spawner is being respawned e.Mobile.SendMessage(33, $"Respawning '{i.Name}' in {i.Map.Name} at {i.Location}"); - XmlSpawner CheckXmlSpawner = (XmlSpawner)i; - CheckXmlSpawner.TryRespawn(); + var CheckXmlSpawner = (XmlSpawner)i; + _ = CheckXmlSpawner.TryRespawn(); } if (RespawnAll) @@ -7521,33 +7195,37 @@ public class XmlSpawner : Item, ISpawner } } -#if (TRACE) +#if TRACE public static void XmlMake_OnCommand(CommandEventArgs e) { if (e.Arguments.Length > 0) { - int count = 0; + var count = 0; try { count = Convert.ToInt32(e.Arguments[0], 10); } catch (Exception ex) { Diagnostics.ExceptionLogging.LogException(ex); } - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { if (e.Arguments.Length > 2) { - Spawner x = new Spawner(10, 1, 1, 0, 2, e.Arguments[1]); - x.Location = new Point3D(5400 + Utility.Random(700), 1090 + Utility.Random(180), 0); - x.Map = Map.Trammel; + _ = new Spawner(10, 1, 1, 0, 2, e.Arguments[1]) + { + Location = new Point3D(5400 + Utility.Random(700), 1090 + Utility.Random(180), 0), + Map = Map.Trammel + }; } else if (e.Arguments.Length > 1) { - XmlSpawner x = new XmlSpawner(10, 1, 1, 0, 2, e.Arguments[1]); - x.Location = new Point3D(5400 + Utility.Random(700), 1090 + Utility.Random(180), 0); - x.Map = Map.Trammel; + _ = new XmlSpawner(10, 1, 1, 0, 2, e.Arguments[1]) + { + Location = new Point3D(5400 + Utility.Random(700), 1090 + Utility.Random(180), 0), + Map = Map.Trammel + }; //x.MinDelay = TimeSpan.FromSeconds(1); //x.MaxDelay = TimeSpan.FromSeconds(1); //x.ProximityRange = 0; @@ -7562,7 +7240,6 @@ public class XmlSpawner : Item, ISpawner e.Mobile.SendMessage($"Created {count} XmlSpawner objects."); } - } } @@ -7573,9 +7250,9 @@ public class XmlSpawner : Item, ISpawner public static void XmlTrace_OnCommand(CommandEventArgs e) { - Process currentprocess = Process.GetCurrentProcess(); - TimeSpan runningtime = Core.Now - _traceStartTime; - double processtime = currentprocess.UserProcessorTime.TotalMilliseconds - _startProcessTime; + var currentprocess = Process.GetCurrentProcess(); + var runningtime = Core.Now - _traceStartTime; + var processtime = currentprocess.UserProcessorTime.TotalMilliseconds - _startProcessTime; double sysload = 0; if (runningtime.TotalMilliseconds > 0) @@ -7589,7 +7266,7 @@ public class XmlSpawner : Item, ISpawner Console.WriteLine("Adjusted Process Time = {0:####.####} secs", processtime / 1000); Console.WriteLine("Processor Time = {0} ({1:p3} avg sys load)", currentprocess.UserProcessorTime, sysload); - for (int i = 0; i < MaxTraces; i++) + for (var i = 0; i < MaxTraces; i++) { if (_traceCount[i] > 0) { @@ -7610,14 +7287,14 @@ public class XmlSpawner : Item, ISpawner if (e.Arguments.Length >= 0) { - for (int i = 0; i < MaxTraces; i++) + for (var i = 0; i < MaxTraces; i++) { _traceCount[i] = 0; _traceTotal[i] = TimeSpan.Zero; } _traceStartTime = Core.Now; - Process currentprocess = Process.GetCurrentProcess(); + var currentprocess = Process.GetCurrentProcess(); _startProcessTime = currentprocess.UserProcessorTime.TotalMilliseconds; Console.WriteLine("Traces reset"); @@ -7629,8 +7306,8 @@ public class XmlSpawner : Item, ISpawner public XmlSpawner() : base(BaseItemId) { - m_PlayerCreated = true; - m_UniqueId = Guid.NewGuid().ToString(); + PlayerCreated = true; + UniqueId = Guid.NewGuid().ToString(); SpawnRange = defSpawnRange; InitSpawn(0, 0, m_Width, m_Height, string.Empty, 0, defMinDelay, defMaxDelay, defDuration, @@ -7643,10 +7320,10 @@ public class XmlSpawner : Item, ISpawner public XmlSpawner(int amount, int minDelay, int maxDelay, int team, int homeRange, string creatureName) : base(BaseItemId) { - m_PlayerCreated = true; - m_UniqueId = Guid.NewGuid().ToString(); + PlayerCreated = true; + UniqueId = Guid.NewGuid().ToString(); SpawnRange = homeRange; - SpawnObject[] so = new SpawnObject[1]; + var so = new SpawnObject[1]; so[0] = new SpawnObject(creatureName, amount); InitSpawn(0, 0, m_Width, m_Height, string.Empty, amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), defDuration, @@ -7659,10 +7336,10 @@ public class XmlSpawner : Item, ISpawner public XmlSpawner(int amount, int minDelay, int maxDelay, int team, int homeRange, int spawnRange, string creatureName) : base(BaseItemId) { - m_PlayerCreated = true; - m_UniqueId = Guid.NewGuid().ToString(); + PlayerCreated = true; + UniqueId = Guid.NewGuid().ToString(); SpawnRange = spawnRange; - SpawnObject[] so = new SpawnObject[1]; + var so = new SpawnObject[1]; so[0] = new SpawnObject(creatureName, amount); InitSpawn(0, 0, m_Width, m_Height, string.Empty, amount, TimeSpan.FromMinutes(minDelay), TimeSpan.FromMinutes(maxDelay), defDuration, @@ -7675,9 +7352,9 @@ public class XmlSpawner : Item, ISpawner public XmlSpawner(string creatureName) : base(BaseItemId) { - m_PlayerCreated = true; - m_UniqueId = Guid.NewGuid().ToString(); - SpawnObject[] so = new SpawnObject[1]; + PlayerCreated = true; + UniqueId = Guid.NewGuid().ToString(); + var so = new SpawnObject[1]; so[0] = new SpawnObject(creatureName, 1); SpawnRange = defSpawnRange; @@ -7695,7 +7372,7 @@ public class XmlSpawner : Item, ISpawner bool allowghost, bool allownpc, bool spawnontrigger, string configfile, TimeSpan despawnTime, string skillTrigger, bool smartSpawning, WayPoint wayPoint) : base(BaseItemId) { - m_UniqueId = uniqueId.ToString(); + UniqueId = uniqueId.ToString(); InitSpawn(x, y, width, height, name, maxCount, minDelay, maxDelay, duration, proximityRange, proximityTriggerSound, amount, team, homeRange, isRelativeHomeRange, spawnObjects, minRefractory, maxRefractory, todstart, todend, objectPropertyItem, objectPropertyName, proximityMessage, itemTriggerName, noitemTriggerName, speechTrigger, mobTriggerName, mobPropertyName, playerPropertyName, @@ -7703,7 +7380,6 @@ public class XmlSpawner : Item, ISpawner despawnTime, skillTrigger, smartSpawning, wayPoint); } - public void InitSpawn(int x, int y, int width, int height, string name, int maxCount, TimeSpan minDelay, TimeSpan maxDelay, TimeSpan duration, int proximityRange, int proximityTriggerSound, int amount, int team, int homeRange, bool isRelativeHomeRange, SpawnObject[] objectsToSpawn, TimeSpan minRefractory, TimeSpan maxRefractory, TimeSpan todstart, TimeSpan todend, Item objectPropertyItem, string objectPropertyName, string proximityMessage, @@ -7738,46 +7414,46 @@ public class XmlSpawner : Item, ISpawner m_MaxDelay = maxDelay; // duration and proximity range parameter - m_MinRefractory = minRefractory; - m_MaxRefractory = maxRefractory; - m_TODStart = todstart; - m_TODEnd = todend; - m_TODMode = todMode; - m_KillReset = killReset; + RefractMin = minRefractory; + RefractMax = maxRefractory; + TODStart = todstart; + TODEnd = todend; + TODMode = todMode; + KillReset = killReset; m_Duration = duration; - m_DespawnTime = despawnTime; + DespawnTime = despawnTime; m_ProximityRange = proximityRange; - m_ProximityTriggerSound = proximityTriggerSound; + ProximitySound = proximityTriggerSound; m_proximityActivated = false; m_durActivated = false; m_refractActivated = false; m_Count = maxCount; m_Team = team; - m_StackAmount = amount; + StackAmount = amount; m_HomeRange = homeRange; - m_HomeRangeIsRelative = isRelativeHomeRange; + HomeRangeIsRelative = isRelativeHomeRange; m_ObjectPropertyItem = objectPropertyItem; m_ObjectPropertyName = objectPropertyName; - m_ProximityTriggerMessage = proximityMessage; + ProximityMsg = proximityMessage; m_ItemTriggerName = itemTriggerName; m_NoItemTriggerName = noitemTriggerName; - m_SpeechTrigger = speechTrigger; + SpeechTrigger = speechTrigger; SkillTrigger = skillTrigger; // note this will register the skill as well - m_MobTriggerName = mobTriggerName; - m_MobPropertyName = mobPropertyName; - m_PlayerPropertyName = playerPropertyName; - m_TriggerProbability = triggerProbability; - m_SetPropertyItem = setPropertyItem; - m_ExternalTriggering = externalTriggering; - m_ExternalTrigger = false; - m_SequentialSpawning = sequentialSpawning; + MobTriggerName = mobTriggerName; + MobTriggerProp = mobPropertyName; + PlayerTriggerProp = playerPropertyName; + TriggerProbability = triggerProbability; + SetItem = setPropertyItem; + ExternalTriggering = externalTriggering; + ExtTrigState = false; + SequentialSpawn = sequentialSpawning; RegionName = regionName; - m_AllowGhostTriggering = allowghost; - m_AllowNPCTriggering = allownpc; - m_SpawnOnTrigger = spawnontrigger; + AllowGhostTrig = allowghost; + AllowNPCTrig = allownpc; + SpawnOnTrigger = spawnontrigger; m_SmartSpawning = smartSpawning; ConfigFile = configfile; - m_WayPoint = wayPoint; + WayPoint = wayPoint; // set the totalitem property to -1 so that it doesnt show up in the item count of containers //TotalItems = -1; @@ -7805,20 +7481,20 @@ public class XmlSpawner : Item, ISpawner return; } - bool removed = false; - int total_removed = 0; + var removed = false; + var total_removed = 0; - List deleteilist = new List(); - List deletemlist = new List(); - foreach (SpawnObject so in m_SpawnObjects) + var deleteilist = new List(); + var deletemlist = new List(); + foreach (var so in m_SpawnObjects) { - for (int x = 0; x < so.SpawnedObjects.Count; x++) + for (var x = 0; x < so.SpawnedObjects.Count; x++) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (o is Item item) { - bool despawned = false; + var despawned = false; // check to see if the despawn time has elapsed. If so, then delete it if it hasnt been picked up or stolen. if (DespawnTime.TotalHours > 0 && !item.Deleted && item.LastMoved < Core.Now - DespawnTime && item.Parent == Parent && (!ItemFlags.GetTaken(item) || item.Parent != null && item.Parent == Parent)) // can despawn if just moved within the same container @@ -7837,7 +7513,7 @@ public class XmlSpawner : Item, ISpawner if (item.Deleted || despawned || item.Parent != Parent // different container || ItemFlags.GetTaken(item) && (item.Parent == null || item.Parent != Parent)) // taken and in the world, or a different container { - so.SpawnedObjects.Remove(item); + _ = so.SpawnedObjects.Remove(item); x--; removed = true; // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if @@ -7858,7 +7534,7 @@ public class XmlSpawner : Item, ISpawner } else if (o is Mobile mobile) { - bool despawned = false; + var despawned = false; // check to see if the despawn time has elapsed. If so, and the sector is not active then delete it. if (DespawnTime.TotalHours > 0 && !mobile.Deleted && mobile.Created < Core.Now - DespawnTime && mobile.Map != null && mobile.Map != Map.Internal && !mobile.Map.GetSector(mobile.Location).Active) @@ -7871,7 +7547,7 @@ public class XmlSpawner : Item, ISpawner if (mobile.Deleted || despawned) { // Remove the delete mobile from the list - so.SpawnedObjects.Remove(mobile); + _ = so.SpawnedObjects.Remove(mobile); x--; removed = true; // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if @@ -7895,7 +7571,7 @@ public class XmlSpawner : Item, ISpawner // and if it is, remove it from the list of spawns if (creature.Controlled || creature.IsStabled || creature.Owners != null && creature.Owners.Count > 0) { - so.SpawnedObjects.Remove(mobile); + _ = so.SpawnedObjects.Remove(mobile); x--; removed = true; // if sequential spawning is active and the RestrictKillsToSubgroup flag is set, then check to see if @@ -7920,7 +7596,7 @@ public class XmlSpawner : Item, ISpawner { if (tag.Deleted) { - so.SpawnedObjects.Remove(o); + _ = so.SpawnedObjects.Remove(o); x--; removed = true; } @@ -7929,7 +7605,7 @@ public class XmlSpawner : Item, ISpawner { // Don't know what this is, so remove it Console.WriteLine("removing unknown {0} from spawnlist", so); - so.SpawnedObjects.Remove(o); + _ = so.SpawnedObjects.Remove(o); x--; removed = true; } @@ -7959,19 +7635,19 @@ public class XmlSpawner : Item, ISpawner return; } - List ToDelete = new List(); - foreach (SpawnObject so in m_SpawnObjects) + var ToDelete = new List(); + foreach (var so in m_SpawnObjects) { - for (int x = 0; x < so.SpawnedObjects.Count; x++) + for (var x = 0; x < so.SpawnedObjects.Count; x++) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (o is BaseXmlSpawner.KeywordTag sot) { // clear the tags except for gump and delay tags if (sot.Type == 2) { ToDelete.Add(sot); - so.SpawnedObjects.Remove(o); + _ = so.SpawnedObjects.Remove(o); x--; } @@ -7979,9 +7655,9 @@ public class XmlSpawner : Item, ISpawner } } - for (int x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) + for (var x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) { - BaseXmlSpawner.KeywordTag i = ToDelete[x]; + var i = ToDelete[x]; if (i != null && !i.Deleted) { i.Delete(); @@ -7997,20 +7673,20 @@ public class XmlSpawner : Item, ISpawner return; } - bool removed = false; - List ToDelete = new List(); - foreach (SpawnObject so in m_SpawnObjects) + var removed = false; + var ToDelete = new List(); + foreach (var so in m_SpawnObjects) { - for (int x = 0; x < so.SpawnedObjects.Count; x++) + for (var x = 0; x < so.SpawnedObjects.Count; x++) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (o is BaseXmlSpawner.KeywordTag sot) { // clear the tags except for gump and delay tags if (all || (sot.Flags & BaseXmlSpawner.KeywordFlags.Defrag) != 0) { ToDelete.Add(sot); - so.SpawnedObjects.Remove(o); + _ = so.SpawnedObjects.Remove(o); x--; removed = true; } @@ -8019,9 +7695,9 @@ public class XmlSpawner : Item, ISpawner } } - for (int x = ToDelete.Count - 1; x >= 0; --x) //each (BaseXmlSpawner.KeywordTag i in ToDelete) + for (var x = ToDelete.Count - 1; x >= 0; --x) //each (BaseXmlSpawner.KeywordTag i in ToDelete) { - BaseXmlSpawner.KeywordTag i = ToDelete[x]; + var i = ToDelete[x]; if (i != null && !i.Deleted) { i.Delete(); @@ -8048,20 +7724,20 @@ public class XmlSpawner : Item, ISpawner return; } - bool removed = false; - List ToDelete = new List(); - foreach (SpawnObject so in m_SpawnObjects) + var removed = false; + var ToDelete = new List(); + foreach (var so in m_SpawnObjects) { - for (int x = 0; x < so.SpawnedObjects.Count; x++) + for (var x = 0; x < so.SpawnedObjects.Count; x++) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (o is BaseXmlSpawner.KeywordTag sot) { // clear the gump tags if (sot.Type == 1) { ToDelete.Add(sot); - so.SpawnedObjects.Remove(o); + _ = so.SpawnedObjects.Remove(o); x--; removed = true; } @@ -8069,9 +7745,9 @@ public class XmlSpawner : Item, ISpawner } } - for (int x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) + for (var x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) { - BaseXmlSpawner.KeywordTag i = ToDelete[x]; + var i = ToDelete[x]; if (i != null && !i.Deleted) { i.Delete(); @@ -8092,20 +7768,20 @@ public class XmlSpawner : Item, ISpawner return; } - bool removed = false; - List ToDelete = new List(); - foreach (SpawnObject so in m_SpawnObjects) + var removed = false; + var ToDelete = new List(); + foreach (var so in m_SpawnObjects) { - for (int x = 0; x < so.SpawnedObjects.Count; x++) + for (var x = 0; x < so.SpawnedObjects.Count; x++) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (o is BaseXmlSpawner.KeywordTag sot) { // clear the matching tags if (sot == tag) { ToDelete.Add(sot); - so.SpawnedObjects.Remove(o); + _ = so.SpawnedObjects.Remove(o); x--; removed = true; } @@ -8113,9 +7789,9 @@ public class XmlSpawner : Item, ISpawner } } - for (int x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) + for (var x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) { - BaseXmlSpawner.KeywordTag i = ToDelete[x]; + var i = ToDelete[x]; if (i != null && !i.Deleted) { i.Delete(); @@ -8136,10 +7812,10 @@ public class XmlSpawner : Item, ISpawner return 0; } - int nsub = 0; - for (int i = 0; i < m_SpawnObjects.Count; i++) + var nsub = 0; + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject s = m_SpawnObjects[i]; + var s = m_SpawnObjects[i]; if (s.SubGroup == sgroup) { @@ -8150,9 +7826,11 @@ public class XmlSpawner : Item, ISpawner return nsub; } - private int RandomAvailableSpawnIndex() => + private int RandomAvailableSpawnIndex() + { // get spawn indices randomly from all available spawns independent of group - RandomAvailableSpawnIndex(-1); + return RandomAvailableSpawnIndex(-1); + } // get spawn indices randomly from all available spawns of a group private int RandomAvailableSpawnIndex(int sgroup) @@ -8162,14 +7840,14 @@ public class XmlSpawner : Item, ISpawner return -1; } - int maxrange = 0; + var maxrange = 0; List sgrouplist = null; - int totalcount = 0; + var totalcount = 0; // make a pass to determine which subgroups are available for spawning // by finding any subgroups that do not have available spawns - for (int i = 0; i < m_SpawnObjects.Count; i++) + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject s = m_SpawnObjects[i]; + var s = m_SpawnObjects[i]; if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) { continue; @@ -8179,17 +7857,14 @@ public class XmlSpawner : Item, ISpawner if (s.SubGroup > 0 && s.SpawnedObjects.Count >= s.MaxCount) { // this subgroup is not available so add it to the list - if (sgrouplist == null) - { - sgrouplist = new List(); - } + sgrouplist ??= new List(); sgrouplist.Add(s.SubGroup); } } - for (int i = 0; i < m_SpawnObjects.Count; i++) + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject s = m_SpawnObjects[i]; + var s = m_SpawnObjects[i]; if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) { @@ -8215,13 +7890,13 @@ public class XmlSpawner : Item, ISpawner // note, subgroup zero is exempt from this check. if (maxrange > 0) { - int randindex = Utility.Random(maxrange); + var randindex = Utility.Random(maxrange); // and map it into the avail spawns - int currentrange = 0; - for (int i = 0; i < m_SpawnObjects.Count; i++) + var currentrange = 0; + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject s = m_SpawnObjects[i]; + var s = m_SpawnObjects[i]; if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) { continue; @@ -8256,11 +7931,11 @@ public class XmlSpawner : Item, ISpawner return -1; } - int avail = 0; - int maxrange = 0; - for (int i = 0; i < m_SpawnObjects.Count; i++) + var avail = 0; + var maxrange = 0; + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject s = m_SpawnObjects[i]; + var s = m_SpawnObjects[i]; // keep track of the number of spawn objects that are not at max (hence available for spawning) if (sgroup < 0 || sgroup == s.SubGroup) @@ -8272,14 +7947,14 @@ public class XmlSpawner : Item, ISpawner // now generate a random number over the available spawnobjects if (avail > 0 && maxrange > 0) { - int randindex = Utility.Random(maxrange); + var randindex = Utility.Random(maxrange); // and map it into the avail spawns - int currentrange = 0; + var currentrange = 0; - for (int i = 0; i < m_SpawnObjects.Count; i++) + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject s = m_SpawnObjects[i]; + var s = m_SpawnObjects[i]; // keep track of the number of spawn objects that are not at max (hence available for spawning) if (sgroup < 0 || sgroup == s.SubGroup) @@ -8309,19 +7984,19 @@ public class XmlSpawner : Item, ISpawner return 0; } - int finddirection = 1; - int largergroup = -1; + var finddirection = 1; + var largergroup = -1; //find the next subgroup that is greater than the current one - for (int j = 0; j < m_SpawnObjects.Count; j++) + for (var j = 0; j < m_SpawnObjects.Count; j++) { - SpawnObject s = m_SpawnObjects[j]; + var s = m_SpawnObjects[j]; if (s.SubGroup > 0 && (s.Ignore || s.Disabled)) { continue; } - int thisgroup = s.SubGroup; + var thisgroup = s.SubGroup; // start off by finding a subgroup that is larger if (finddirection == 1) @@ -8373,9 +8048,9 @@ public class XmlSpawner : Item, ISpawner } //return the first instance of a spawn object that is an available member of the requested subgroup - for (int j = 0; j < m_SpawnObjects.Count; j++) + for (var j = 0; j < m_SpawnObjects.Count; j++) { - SpawnObject s = m_SpawnObjects[j]; + var s = m_SpawnObjects[j]; if (s.SubGroup == sgroup && s.MaxCount > s.SpawnedObjects.Count) { @@ -8405,7 +8080,7 @@ public class XmlSpawner : Item, ISpawner } //return the first instance of a spawn object that is an available member of the requested subgroup - for (int j = 0; j < m_SpawnObjects.Count; j++) + for (var j = 0; j < m_SpawnObjects.Count; j++) { if (m_SpawnObjects[j].SubGroup == sgroup) { @@ -8427,13 +8102,13 @@ public class XmlSpawner : Item, ISpawner // this will get the index of the first spawn entry in the subgroup // it will have the subgroup timer settings - int spawnindex = GetCurrentSequentialSpawnIndex(sgroup); + var spawnindex = GetCurrentSequentialSpawnIndex(sgroup); if (spawnindex >= 0) { // if it is greater than zero then initiate reset - SpawnObject s = m_SpawnObjects[spawnindex]; - m_SequentialSpawning = s.SequentialResetTo; + var s = m_SpawnObjects[spawnindex]; + SequentialSpawn = s.SequentialResetTo; InitiateSequentialReset(sgroup); @@ -8450,19 +8125,19 @@ public class XmlSpawner : Item, ISpawner { // check the SequentialResetTime on the subgroup // cant do resets on subgroup 0 - if (m_SequentialSpawning == 0) + if (SequentialSpawn == 0) { return false; } // this will get the index of the first spawn entry in the subgroup // it will have the subgroup timer settings - int spawnindex = GetCurrentSequentialSpawnIndex(m_SequentialSpawning); + var spawnindex = GetCurrentSequentialSpawnIndex(SequentialSpawn); if (spawnindex >= 0) { // check the reset time on it - SpawnObject s = m_SpawnObjects[spawnindex]; + var s = m_SpawnObjects[spawnindex]; // if it is greater than zero then resetting is possible if (s.SequentialResetTime > 0) { @@ -8488,23 +8163,22 @@ public class XmlSpawner : Item, ISpawner // this will get the index of the first spawn entry in the subgroup // it will have the subgroup timer settings - int spawnindex = GetCurrentSequentialSpawnIndex(sgroup); + var spawnindex = GetCurrentSequentialSpawnIndex(sgroup); if (spawnindex >= 0) { // if it is greater than zero then initiate reset - SpawnObject s = m_SpawnObjects[spawnindex]; + var s = m_SpawnObjects[spawnindex]; NextSeqReset = TimeSpan.FromMinutes(s.SequentialResetTime); } } - public void ResetSequential() { // go back to the lowest level - if (m_SequentialSpawning >= 0) + if (SequentialSpawn >= 0) { - m_SequentialSpawning = NextSequentialIndex(-1); + SequentialSpawn = NextSequentialIndex(-1); } // reset the nextspawn times @@ -8530,27 +8204,27 @@ public class XmlSpawner : Item, ISpawner } // if kills needed is greater than zero then check the killcount as well - int spawnindex = GetCurrentSequentialSpawnIndex(m_SequentialSpawning); + var spawnindex = GetCurrentSequentialSpawnIndex(SequentialSpawn); - int killsneeded = 0; - int subgroup = -1; - bool clearedobjects = false; + var killsneeded = 0; + var subgroup = -1; + var clearedobjects = false; if (spawnindex >= 0) { - SpawnObject s = m_SpawnObjects[spawnindex]; + var s = m_SpawnObjects[spawnindex]; subgroup = s.SubGroup; killsneeded = s.KillsNeeded; } // advance the sequential spawn index if it is enabled and kills needed have been satisfied - if (m_SequentialSpawning >= 0 && (killsneeded == 0 || KillCount >= killsneeded)) + if (SequentialSpawn >= 0 && (killsneeded == 0 || KillCount >= killsneeded)) { - m_SequentialSpawning = NextSequentialIndex(m_SequentialSpawning); + SequentialSpawn = NextSequentialIndex(SequentialSpawn); // set the sequential reset based on the current sequence state // this will be checked in the spawner OnTick to determine whether to Reset the sequential state - InitiateSequentialReset(m_SequentialSpawning); + InitiateSequentialReset(SequentialSpawn); // clear the spawns if there is a killcount on the level if (killsneeded >= 0) @@ -8567,7 +8241,7 @@ public class XmlSpawner : Item, ISpawner return clearedobjects; } - int killcount_held; + private int killcount_held; public void OnTick() { @@ -8586,7 +8260,7 @@ public class XmlSpawner : Item, ISpawner // Check the count before and then after the spawn passes. // if the spawner is still refractory then dont do a reset of the killcount. //int startcount = this.m_killcount; - int startcount = killcount_held; + var startcount = killcount_held; if (!m_skipped) { killcount_held = m_killcount; @@ -8599,7 +8273,7 @@ public class XmlSpawner : Item, ISpawner // note, tags only last a single ontick except for WAIT type ClearTags(false); - if (!m_DisableGlobalAutoReset && startcount == m_killcount && !m_refractActivated && !m_skipped) + if (!DisableGlobalAutoReset && startcount == m_killcount && !m_refractActivated && !m_skipped) { m_spawncheck--; } @@ -8609,7 +8283,7 @@ public class XmlSpawner : Item, ISpawner if (m_spawncheck <= 0) { m_killcount = 0; - m_spawncheck = m_KillReset; // wait for 1 spawn ticks to pass before resetting. This can be set to anything you like + m_spawncheck = KillReset; // wait for 1 spawn ticks to pass before resetting. This can be set to anything you like } // check for smart spawning @@ -8667,9 +8341,9 @@ public class XmlSpawner : Item, ISpawner if (CheckForSequentialReset()) { // it has expired so reset the sequential spawn level - SeqResetTo(m_SequentialSpawning); + SeqResetTo(SequentialSpawn); - bool triedtospawn = TryRespawn(); + var triedtospawn = TryRespawn(); if (triedtospawn) { @@ -8686,13 +8360,13 @@ public class XmlSpawner : Item, ISpawner { // advance the sequential spawn index if it is enabled - AdvanceSequential(); + _ = AdvanceSequential(); //bool hadhold = HoldSequence; //HoldSequence = false; - bool triedtospawn = TryRespawn(); + var triedtospawn = TryRespawn(); if (triedtospawn) { @@ -8708,7 +8382,7 @@ public class XmlSpawner : Item, ISpawner if (CheckForSequentialReset()) { // it has expired so reset the sequential spawn level - SeqResetTo(m_SequentialSpawning); + SeqResetTo(SequentialSpawn); // dont advance if the spawn isnt triggered after resetting HoldSequence = true; @@ -8716,7 +8390,7 @@ public class XmlSpawner : Item, ISpawner else { // advance the sequence before spawning - AdvanceSequential(); + _ = AdvanceSequential(); } // keep track of the hold flag before trying to spawn in case no spawn attempt is made @@ -8726,7 +8400,7 @@ public class XmlSpawner : Item, ISpawner //HoldSequence = false; // try to spawn. If spawning conditions such as triggering or TOD are not met, then it returns false - bool triedtospawn = Spawn(false, 0); + var triedtospawn = Spawn(false, 0); if (triedtospawn) { @@ -8736,7 +8410,7 @@ public class XmlSpawner : Item, ISpawner if (!FreeRun) { - m_mob_who_triggered = null; + TriggerMob = null; } } @@ -8744,7 +8418,6 @@ public class XmlSpawner : Item, ISpawner // remove any keyword tags that were made except for WAIT type ClearTags(false); - // and clear triggering flags if (!OnHold && !FreeRun) { @@ -8759,7 +8432,6 @@ public class XmlSpawner : Item, ISpawner ResetNextSpawnTimes(); } - //this.m_ExternalTrigger = false; // if it is out of the TOD range then delete the spawns if (!TODInRange) @@ -8781,9 +8453,9 @@ public class XmlSpawner : Item, ISpawner return; } - for (int i = 0; i < m_SpawnObjects.Count; i++) + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject sobj = m_SpawnObjects[i]; + var sobj = m_SpawnObjects[i]; if (sobj != null) { sobj.SpawnedThisTick = false; @@ -8811,7 +8483,7 @@ public class XmlSpawner : Item, ISpawner int SpawnIndex; // see if sequential spawning has been selected - SpawnIndex = m_SequentialSpawning >= 0 ? GetCurrentAvailableSequentialSpawnIndex(m_SequentialSpawning) : RandomAvailableSpawnIndex(); + SpawnIndex = SequentialSpawn >= 0 ? GetCurrentAvailableSequentialSpawnIndex(SequentialSpawn) : RandomAvailableSpawnIndex(); // no spawns are available so no point in continuing if (SpawnIndex < 0) @@ -8820,13 +8492,13 @@ public class XmlSpawner : Item, ISpawner return true; } - SpawnObject sobj = m_SpawnObjects[SpawnIndex]; - int sgroup = sobj.SubGroup; + var sobj = m_SpawnObjects[SpawnIndex]; + var sgroup = sobj.SubGroup; // if this is part of a non-zero group, then spawn all of the group members as well if (sgroup != 0) { - SpawnSubGroup(sgroup, smartspawn, loops); + _ = SpawnSubGroup(sgroup, smartspawn, loops); } else { @@ -8856,9 +8528,9 @@ public class XmlSpawner : Item, ISpawner return false; } - bool didspawn = false; + var didspawn = false; - SpawnObject so = m_SpawnObjects[index]; + var so = m_SpawnObjects[index]; if (so == null) { @@ -8868,12 +8540,12 @@ public class XmlSpawner : Item, ISpawner Defrag(false); // make sure you dont go over the individual entry maxcount - int somax = so.MaxCount; - int socnt = so.SpawnedObjects.Count; - int nspawn = so.SpawnsPerTick; - int scnt = SafeCurrentCount; + var somax = so.MaxCount; + var socnt = so.SpawnedObjects.Count; + var nspawn = so.SpawnsPerTick; + var scnt = SafeCurrentCount; - for (int k = 0; k < nspawn && k + socnt < somax && k + scnt < MaxCount; k++) + for (var k = 0; k < nspawn && k + socnt < somax && k + scnt < MaxCount; k++) { if (packrange >= 0 && so.SubGroup > 0 && packcoord == Point3D.Zero) { @@ -8890,10 +8562,16 @@ public class XmlSpawner : Item, ISpawner } // spawn an individual entry by index up to count times - public bool Spawn(int index, bool smartspawn, int count, byte loops) => Spawn(index, smartspawn, count, false, loops); + public bool Spawn(int index, bool smartspawn, int count, byte loops) + { + return Spawn(index, smartspawn, count, false, loops); + } // spawn an individual entry by index up to count times - public bool Spawn(int index, bool smartspawn, int count, bool ignoreloopprotection, byte loops) => Spawn(index, smartspawn, count, -1, Point3D.Zero, ignoreloopprotection, loops); + public bool Spawn(int index, bool smartspawn, int count, bool ignoreloopprotection, byte loops) + { + return Spawn(index, smartspawn, count, -1, Point3D.Zero, ignoreloopprotection, loops); + } // spawn an individual entry by spawn object public void Spawn(string SpawnObjectTypeName, bool smartspawn, int packrange, Point3D packcoord, byte loops) @@ -8903,7 +8581,7 @@ public class XmlSpawner : Item, ISpawner return; } - for (int i = 0; i < m_SpawnObjects.Count; i++) + for (var i = 0; i < m_SpawnObjects.Count; i++) { if (m_SpawnObjects[i].TypeName.ToUpper() == SpawnObjectTypeName.ToUpper()) { @@ -8924,12 +8602,15 @@ public class XmlSpawner : Item, ISpawner } // spawn an individual entry by index - public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, byte loops) => Spawn(index, smartspawn, packrange, packcoord, false, loops); + public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, byte loops) + { + return Spawn(index, smartspawn, packrange, packcoord, false, loops); + } // spawn an individual entry by index public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, bool ignoreloopprotection, byte loops) { - Map map = Map; + var map = Map; // Make sure everything is ok to spawn an object if (map == null || @@ -8947,7 +8628,7 @@ public class XmlSpawner : Item, ISpawner Defrag(false); // Get the spawn object at the required index - SpawnObject TheSpawn = m_SpawnObjects[index]; + var TheSpawn = m_SpawnObjects[index]; // Check if the object retrieved is a valid SpawnObject if (TheSpawn != null) @@ -8965,8 +8646,8 @@ public class XmlSpawner : Item, ISpawner return false; } - int CurrentCreatureMax = TheSpawn.MaxCount; - int CurrentCreatureCount = TheSpawn.SpawnedObjects.Count; + var CurrentCreatureMax = TheSpawn.MaxCount; + var CurrentCreatureCount = TheSpawn.SpawnedObjects.Count; // Check that the current object to be spawned has not reached its maximum allowed // and make sure that the maximum spawner count has not been exceeded as well @@ -8977,27 +8658,24 @@ public class XmlSpawner : Item, ISpawner } // check for string substitions - string substitutedtypeName = BaseXmlSpawner.ApplySubstitution(this, this, TheSpawn.TypeName); + var substitutedtypeName = BaseXmlSpawner.ApplySubstitution(this, this, TheSpawn.TypeName); // random positioning is the default List spawnpositioning = null; // require valid surfaces by default - bool requiresurface = true; + var requiresurface = true; // parse the # function specification for the entry while (substitutedtypeName.StartsWith("#")) { - string[] args = BaseXmlSpawner.ParseSemicolonArgs(substitutedtypeName, 2); + var args = BaseXmlSpawner.ParseSemicolonArgs(substitutedtypeName, 2); if (args.Length > 0) { - if (spawnpositioning == null) - { - spawnpositioning = new List(); - } + spawnpositioning ??= new List(); // parse any comma args - string[] keyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 10); + var keyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 10); if (keyvalueargs.Length > 0) { @@ -9005,95 +8683,95 @@ public class XmlSpawner : Item, ISpawner switch (keyvalueargs[0]) { case "#NOITEMID": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoItemID, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoItemID, TriggerMob, keyvalueargs)); + break; + } case "#ITEMID": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ItemID, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ItemID, TriggerMob, keyvalueargs)); + break; + } case "#NOTILES": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoTiles, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoTiles, TriggerMob, keyvalueargs)); + break; + } case "#TILES": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Tiles, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Tiles, TriggerMob, keyvalueargs)); + break; + } case "#WET": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Wet, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Wet, TriggerMob, keyvalueargs)); + break; + } case "#XFILL": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RowFill, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RowFill, TriggerMob, keyvalueargs)); + break; + } case "#YFILL": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ColFill, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ColFill, TriggerMob, keyvalueargs)); + break; + } case "#EDGE": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Perimeter, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Perimeter, TriggerMob, keyvalueargs)); + break; + } case "#PLAYER": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Player, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Player, TriggerMob, keyvalueargs)); + break; + } case "#WAYPOINT": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Waypoint, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Waypoint, TriggerMob, keyvalueargs)); + break; + } case "#RELXY": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RelXY, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RelXY, TriggerMob, keyvalueargs)); + break; + } case "#DXY": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.DeltaLocation, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.DeltaLocation, TriggerMob, keyvalueargs)); + break; + } case "#XY": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Location, m_mob_who_triggered, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Location, TriggerMob, keyvalueargs)); + break; + } case "#CONDITION": + { + // test the specified condition string + // syntax is #CONDITION,proptest + // reparse with only one arg after the comma, this allows property tests that use commas as well + var ckeyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 2); + if (ckeyvalueargs.Length > 1) { - // test the specified condition string - // syntax is #CONDITION,proptest - // reparse with only one arg after the comma, this allows property tests that use commas as well - string[] ckeyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 2); - if (ckeyvalueargs.Length > 1) + // dont spawn if it fails the test + if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out status_str)) { - // dont spawn if it fails the test - if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out status_str)) - { - return false; - } + return false; } - else - { - status_str = $"invalid #CONDITION specification: {args[0]}"; - } - break; } + else + { + status_str = $"invalid #CONDITION specification: {args[0]}"; + } + break; + } default: - { - status_str = $"invalid # specification: {args[0]}"; - break; - } + { + status_str = $"invalid # specification: {args[0]}"; + break; + } } } } @@ -9102,7 +8780,6 @@ public class XmlSpawner : Item, ISpawner substitutedtypeName = args.Length > 1 ? args[1].Trim() : string.Empty; } - if (substitutedtypeName.StartsWith("*")) { requiresurface = false; @@ -9111,14 +8788,13 @@ public class XmlSpawner : Item, ISpawner TheSpawn.RequireSurface = requiresurface; - string typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); + var typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) { - string status_str = null; - bool completedtypespawn = BaseXmlSpawner.SpawnTypeKeyword(this, TheSpawn, typeName, substitutedtypeName, - m_mob_who_triggered, Map, out status_str, loops); + var completedtypespawn = BaseXmlSpawner.SpawnTypeKeyword(this, TheSpawn, typeName, substitutedtypeName, + TriggerMob, Map, out var status_str, loops); if (status_str != null) { @@ -9141,15 +8817,15 @@ public class XmlSpawner : Item, ISpawner } // its a regular type descriptor so find out what it is - Type type = AssemblyHandler.FindTypeByName(typeName); + var type = AssemblyHandler.FindTypeByName(typeName); // dont try to spawn invalid types, or Mobile type spawns in containers if (type != null && !(Parent != null && (type == typeof(Mobile) || type.IsSubclassOf(typeof(Mobile))))) { - string[] arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); + var arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); - object o = CreateObject(type, arglist[0]); + var o = CreateObject(type, arglist[0]); if (o == null) { @@ -9185,7 +8861,7 @@ public class XmlSpawner : Item, ISpawner if (mob is BaseCreature mobile) { mobile.RangeHome = m_HomeRange; - mobile.CurrentWayPoint = m_WayPoint; + mobile.CurrentWayPoint = WayPoint; if (m_Team > 0) { @@ -9194,7 +8870,7 @@ public class XmlSpawner : Item, ISpawner // Check if this spawner uses absolute (from spawnER location) // or relative (from spawnED location) as the mobiles home point - mobile.Home = m_HomeRangeIsRelative ? mobile.Location : Location; + mobile.Home = HomeRangeIsRelative ? mobile.Location : Location; } // if the object has an OnSpawned method, then invoke it @@ -9205,9 +8881,8 @@ public class XmlSpawner : Item, ISpawner // 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 - string status_str; - BaseXmlSpawner.ApplyObjectStringProperties(this, substitutedtypeName, mob, m_mob_who_triggered, this, out status_str); + _ = BaseXmlSpawner.ApplyObjectStringProperties(this, substitutedtypeName, mob, TriggerMob, this, out var status_str); if (status_str != null) { @@ -9224,9 +8899,8 @@ public class XmlSpawner : Item, ISpawner if (o is Item item) { - string status_str; - BaseXmlSpawner.AddSpawnItem(this, TheSpawn, item, Location, map, m_mob_who_triggered, requiresurface, spawnpositioning, substitutedtypeName, smartspawn, out status_str); + BaseXmlSpawner.AddSpawnItem(this, TheSpawn, item, Location, map, TriggerMob, requiresurface, spawnpositioning, substitutedtypeName, smartspawn, out var status_str); if (status_str != null) { @@ -9252,9 +8926,15 @@ public class XmlSpawner : Item, ISpawner return false; } - public bool SpawnSubGroup(int sgroup, byte loops) => SpawnSubGroup(sgroup, false, loops); + public bool SpawnSubGroup(int sgroup, byte loops) + { + return SpawnSubGroup(sgroup, false, loops); + } - public bool SpawnSubGroup(int sgroup, bool smartspawn, byte loops) => SpawnSubGroup(sgroup, false, false, loops); + public bool SpawnSubGroup(int sgroup, bool smartspawn, byte loops) + { + return SpawnSubGroup(sgroup, false, false, loops); + } public bool SpawnSubGroup(int sgroup, bool smartspawn, bool ignoreloopprotection, byte loops) { @@ -9265,12 +8945,12 @@ public class XmlSpawner : Item, ISpawner if (sgroup >= 0) { - bool didspawn = false; - Point3D packcoord = Point3D.Zero; + var didspawn = false; + var packcoord = Point3D.Zero; - for (int j = 0; j < m_SpawnObjects.Count; j++) + for (var j = 0; j < m_SpawnObjects.Count; j++) { - SpawnObject so = m_SpawnObjects[j]; + var so = m_SpawnObjects[j]; if (so != null && so.SubGroup == sgroup) { @@ -9281,7 +8961,7 @@ public class XmlSpawner : Item, ISpawner } // get the SpawnsPerTick count and spawn up to that number - bool success = Spawn(j, smartspawn, so.SpawnsPerTick, so.PackRange, packcoord, ignoreloopprotection, loops); + var success = Spawn(j, smartspawn, so.SpawnsPerTick, so.PackRange, packcoord, ignoreloopprotection, loops); if (success) { @@ -9306,9 +8986,9 @@ public class XmlSpawner : Item, ISpawner public Point3D GetPackCoord(int sgroup) { - for (int j = 0; j < m_SpawnObjects.Count; j++) + for (var j = 0; j < m_SpawnObjects.Count; j++) { - SpawnObject so = m_SpawnObjects[j]; + var so = m_SpawnObjects[j]; if (so != null && so.SubGroup == sgroup && so.SpawnedObjects.Count > 0 && so.PackRange >= 0) { @@ -9316,9 +8996,9 @@ public class XmlSpawner : Item, ISpawner // the origin for pack spawning using the first existing pack spawn // in the subgroup - for (int i = 0; i < so.SpawnedObjects.Count; ++i) + for (var i = 0; i < so.SpawnedObjects.Count; ++i) { - object o = so.SpawnedObjects[i]; + var o = so.SpawnedObjects[i]; if (o is Item item) { return item.Location; @@ -9335,23 +9015,24 @@ public class XmlSpawner : Item, ISpawner return Point3D.Zero; } - //used by the reset button in the gump public void ResetAllFlags() { m_proximityActivated = false; - m_ExternalTrigger = false; + ExtTrigState = false; m_durActivated = false; m_refractActivated = false; - m_mob_who_triggered = null; + TriggerMob = null; m_killcount = 0; - m_GumpState = null; + GumpState = null; FreeRun = false; } public bool BringHome { - set { if (value) + set + { + if (value) { BringToHome(); } @@ -9367,11 +9048,11 @@ public class XmlSpawner : Item, ISpawner Defrag(false); - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { - for (int i = 0; i < so.SpawnedObjects.Count; ++i) + for (var i = 0; i < so.SpawnedObjects.Count; ++i) { - object o = so.SpawnedObjects[i]; + var o = so.SpawnedObjects[i]; if (o is Mobile mobile) { @@ -9425,25 +9106,16 @@ public class XmlSpawner : Item, ISpawner if (m_Running) { // turn off all timers - if (m_Timer != null) - { - m_Timer.Stop(); - } + m_Timer?.Stop(); - if (m_DurTimer != null) - { - m_DurTimer.Stop(); - } + m_DurTimer?.Stop(); - if (m_RefractoryTimer != null) - { - m_RefractoryTimer.Stop(); - } + m_RefractoryTimer?.Stop(); m_Running = false; m_proximityActivated = false; - m_ExternalTrigger = false; - m_mob_who_triggered = null; + ExtTrigState = false; + TriggerMob = null; } } @@ -9468,7 +9140,7 @@ public class XmlSpawner : Item, ISpawner public void Respawn() { - TryRespawn(); + _ = TryRespawn(); } public bool TryRespawn() @@ -9489,12 +9161,12 @@ public class XmlSpawner : Item, ISpawner // Respawn all objects up to the spawners current maximum allowed // note that by default, for proximity sensing, the spawner will only trigger once, but for respawns allow them all - bool keepProximityActivated = m_proximityActivated; + var keepProximityActivated = m_proximityActivated; - bool triedtospawn = false; + var triedtospawn = false; // attempt to spawn up to the MaxCount of the spawner - for (int x = 0; x < m_Count; x++) + for (var x = 0; x < m_Count; x++) { triedtospawn = Spawn(false, 0); @@ -9505,7 +9177,7 @@ public class XmlSpawner : Item, ISpawner } if (!FreeRun) { - m_mob_who_triggered = null; + TriggerMob = null; } ClearTags(true); @@ -9534,12 +9206,12 @@ public class XmlSpawner : Item, ISpawner // Respawn all objects up to the spawners current maximum allowed // note that by default, for proximity sensing, the spawner will only trigger once, but for respawns allow them all - bool keepProximityActivated = m_proximityActivated; + var keepProximityActivated = m_proximityActivated; // attempt to spawn up to the MaxCount of the spawner - for (int x = 0; x < m_Count; x++) + for (var x = 0; x < m_Count; x++) { - Spawn(true, 0); + _ = Spawn(true, 0); if (x < m_Count - 1 || OnHold) { @@ -9549,7 +9221,7 @@ public class XmlSpawner : Item, ISpawner if (!FreeRun) { - m_mob_who_triggered = null; + TriggerMob = null; } ClearTags(true); @@ -9557,7 +9229,6 @@ public class XmlSpawner : Item, ISpawner inrespawn = false; } - public void SortSpawns() { if (m_SpawnObjects == null) @@ -9566,9 +9237,9 @@ public class XmlSpawner : Item, ISpawner } // establish the entry order - int count = 0; + var count = 0; - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { so.EntryOrder = count++; } @@ -9597,7 +9268,7 @@ public class XmlSpawner : Item, ISpawner return null; } - for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + for (var i = 0; i < spawner.m_SpawnObjects.Count; i++) { // find the first entry with matching subgroup id if (spawner.m_SpawnObjects[i].SubGroup == sgroup) @@ -9615,7 +9286,7 @@ public class XmlSpawner : Item, ISpawner return null; } - for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + for (var i = 0; i < spawner.m_SpawnObjects.Count; i++) { // find the first entry with matching subgroup id if (spawner.m_SpawnObjects[i].SubGroup == sgroup) @@ -9632,14 +9303,14 @@ public class XmlSpawner : Item, ISpawner public static List GetSpawnedList(XmlSpawner spawner, int sgroup) { - List newlist = new List(); + var newlist = new List(); if (spawner == null || spawner.m_SpawnObjects == null) { return null; } - for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + for (var i = 0; i < spawner.m_SpawnObjects.Count; i++) { // find the first entry with matching subgroup id if (spawner.m_SpawnObjects[i].SubGroup == sgroup) @@ -9648,7 +9319,7 @@ public class XmlSpawner : Item, ISpawner if (spawner.m_SpawnObjects[i].SpawnedObjects.Count > 0) { - for (int j = 0; j < spawner.m_SpawnObjects[i].SpawnedObjects.Count; j++) + for (var j = 0; j < spawner.m_SpawnObjects[i].SpawnedObjects.Count; j++) { newlist.Add(spawner.m_SpawnObjects[i].SpawnedObjects[j]); } @@ -9665,7 +9336,7 @@ public class XmlSpawner : Item, ISpawner return false; } - for (int j = 0; j < m_SpawnObjects.Count; j++) + for (var j = 0; j < m_SpawnObjects.Count; j++) { if (m_SpawnObjects[j].SubGroup > 0) { @@ -9690,9 +9361,9 @@ public class XmlSpawner : Item, ISpawner if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) { - for (int i = 0; i < m_SpawnObjects.Count; i++) + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject so = m_SpawnObjects[i]; + var so = m_SpawnObjects[i]; if (so.MinDelay != -1 || so.MaxDelay != -1) { @@ -9708,9 +9379,9 @@ public class XmlSpawner : Item, ISpawner if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) { - for (int i = 0; i < m_SpawnObjects.Count; i++) + for (var i = 0; i < m_SpawnObjects.Count; i++) { - SpawnObject so = m_SpawnObjects[i]; + var so = m_SpawnObjects[i]; so.NextSpawn = Core.Now; } @@ -9724,8 +9395,8 @@ public class XmlSpawner : Item, ISpawner return; } - int mind = (int)(so.MinDelay * 60); - int maxd = (int)(so.MaxDelay * 60); + var mind = (int)(so.MinDelay * 60); + var maxd = (int)(so.MaxDelay * 60); if (mind < 0 || maxd < 0) { so.NextSpawn = Core.Now; @@ -9733,7 +9404,7 @@ public class XmlSpawner : Item, ISpawner else { - TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(mind, maxd)); + var delay = TimeSpan.FromSeconds(Utility.RandomMinMax(mind, maxd)); so.NextSpawn = Core.Now + delay; } @@ -9790,7 +9461,7 @@ public class XmlSpawner : Item, ISpawner // try parsing the waypoint name to determine the waypoint. object syntax is "SERIAL,sernumber" or "waypointname" if (!string.IsNullOrEmpty(waypointstr)) { - string[] wayargs = BaseXmlSpawner.ParseString(waypointstr, 2, ","); + var wayargs = BaseXmlSpawner.ParseString(waypointstr, 2, ","); if (wayargs != null && wayargs.Length > 0) { // is this a SERIAL specification? @@ -9804,7 +9475,7 @@ public class XmlSpawner : Item, ISpawner try { sernum = (uint)Convert.ToUInt64(wayargs[1][2..], 16); - IEntity e = World.FindEntity((Serial)sernum); + var e = World.FindEntity((Serial)sernum); if (e is WayPoint point) { @@ -9817,7 +9488,7 @@ public class XmlSpawner : Item, ISpawner else { // just look it up by name - Item wayitem = BaseXmlSpawner.FindItemByName(null, wayargs[0], "WayPoint"); + var wayitem = BaseXmlSpawner.FindItemByName(null, wayargs[0], "WayPoint"); if (wayitem is WayPoint point) { waypoint = point; @@ -9836,7 +9507,7 @@ public class XmlSpawner : Item, ISpawner return false; } - StaticTile[] tiles = map.Tiles.GetStaticTiles(X, Y, true); + var tiles = map.Tiles.GetStaticTiles(X, Y, true); if (tiles == null) { @@ -9844,9 +9515,9 @@ public class XmlSpawner : Item, ISpawner } // go through the tiles and see if any are at the Z location - foreach (StaticTile o in tiles) + foreach (var o in tiles) { - StaticTile i = o; + var i = o; if (i.Z + i.Height == Z) { @@ -9865,12 +9536,8 @@ public class XmlSpawner : Item, ISpawner } // try looking this up in the lookup table - if (holdSmartSpawningHash == null) - { - holdSmartSpawningHash = new Dictionary(); - } - PropertyInfo prop; - if (!holdSmartSpawningHash.TryGetValue(o.GetType(), out prop)) + holdSmartSpawningHash ??= new Dictionary(); + if (!holdSmartSpawningHash.TryGetValue(o.GetType(), out var prop)) { prop = o.GetType().GetProperty("HoldSmartSpawning"); // check to make sure the HoldSmartSpawning property for this object has the right type @@ -9899,11 +9566,11 @@ public class XmlSpawner : Item, ISpawner get { // go through the spawn lists - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { - for (int x = 0; x < so.SpawnedObjects.Count; x++) + for (var x = 0; x < so.SpawnedObjects.Count; x++) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (CheckHoldSmartSpawning(o)) { return true; @@ -9918,7 +9585,7 @@ public class XmlSpawner : Item, ISpawner // if a non-null mob argument is passed, then check the canswim and cantwalk props to determine valid placement public bool CanFit(int x, int y, int z, int height, bool checkBlocksFit, bool checkMobiles, bool requireSurface, Mobile mob) { - Map map = Map; + var map = Map; if (DebugThis) { @@ -9934,10 +9601,10 @@ public class XmlSpawner : Item, ISpawner return false; } - bool hasSurface = false; - bool checkmob = false; - bool canswim = false; - bool cantwalk = false; + var hasSurface = false; + var checkmob = false; + var canswim = false; + var cantwalk = false; if (mob != null) { @@ -9949,13 +9616,13 @@ public class XmlSpawner : Item, ISpawner { Console.WriteLine("fitting mob {0} checkmob={1} swim={2} walk={3}", mob, checkmob, canswim, cantwalk); } - LandTile lt = map.Tiles.GetLandTile(x, y); + var lt = map.Tiles.GetLandTile(x, y); bool surface; - bool wet = false; + var wet = false; map.GetAverageZ(x, y, out var lowZ, out var avgZ, out var topZ); - TileFlag landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; + var landFlags = TileData.LandTable[lt.ID & TileData.MaxLandValue].Flags; if (DebugThis) { @@ -9994,11 +9661,11 @@ public class XmlSpawner : Item, ISpawner Console.WriteLine("landtile at {0},{1},{2} wet={3} impassable={4} hassurface={5}", x, y, z, wet, impassable, hasSurface); } - StaticTile[] staticTiles = map.Tiles.GetStaticTiles(x, y, true); + var staticTiles = map.Tiles.GetStaticTiles(x, y, true); - for (int i = 0; i < staticTiles.Length; ++i) + for (var i = 0; i < staticTiles.Length; ++i) { - ItemData id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; + var id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; surface = id.Surface; impassable = id.Impassable; if (checkmob) @@ -10033,17 +9700,17 @@ public class XmlSpawner : Item, ISpawner Console.WriteLine("statics hassurface={0}", hasSurface); } - Sector sector = map.GetSector(x, y); - List items = sector.Items; - List mobs = sector.Mobiles; + var sector = map.GetSector(x, y); + var items = sector.Items; + var mobs = sector.Mobiles; - for (int i = 0; i < items.Count; ++i) + for (var i = 0; i < items.Count; ++i) { - Item item = items[i]; + var item = items[i]; if (item.ItemID < 0x4000 && item.AtWorldPoint(x, y)) { - ItemData id = item.ItemData; + var id = item.ItemData; surface = id.Surface; impassable = id.Impassable; if (checkmob) @@ -10082,9 +9749,9 @@ public class XmlSpawner : Item, ISpawner if (checkMobiles) { - for (int i = 0; i < mobs.Count; ++i) + for (var i = 0; i < mobs.Count; ++i) { - Mobile m = mobs[i]; + var m = mobs[i]; if (m.Location.X == x && m.Location.Y == y && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) { @@ -10114,7 +9781,10 @@ public class XmlSpawner : Item, ISpawner return Region.Find(new Point3D(x, y, z), Map).AllowSpawn() && Map.CanFit(x, y, z, 16); } - public static bool HasRegionPoints(Region r) => r != null && r.Area.Length > 0; + public static bool HasRegionPoints(Region r) + { + return r != null && r.Area.Length > 0; + } public Rectangle2D SpawnerBounds => new(m_X, m_Y, m_Width + 1, m_Height + 1); @@ -10125,23 +9795,20 @@ public class XmlSpawner : Item, ISpawner return; } - if (locations == null) - { - locations = new List(); - } + locations ??= new List(); bool includetile; bool excludetile; - for (int x = startx; x <= startx + width; x++) + for (var x = startx; x <= startx + width; x++) { - for (int y = starty; y <= starty + height; y++) + for (var y = starty; y <= starty + height; y++) { - bool allok = false; - Point3D p = Point3D.Zero; + var allok = false; + var p = Point3D.Zero; // go through all of the tiles at the location and find those that are in the allowed tiles list - LandTile ltile = map.Tiles.GetLandTile(x, y); - TileFlag lflags = TileData.LandTable[ltile.ID & TileData.MaxLandValue].Flags; + var ltile = map.Tiles.GetLandTile(x, y); + var lflags = TileData.LandTable[ltile.ID & TileData.MaxLandValue].Flags; // check the land tile if (includetilelist != null && includetilelist.Count > 0) @@ -10170,13 +9837,13 @@ public class XmlSpawner : Item, ISpawner allok = true; } - StaticTile[] statictiles = map.Tiles.GetStaticTiles(x, y, true); + var statictiles = map.Tiles.GetStaticTiles(x, y, true); // check the static tiles - for (int i = 0; i < statictiles.Length; ++i) + for (var i = 0; i < statictiles.Length; ++i) { - StaticTile stile = statictiles[i]; - TileFlag sflags = TileData.ItemTable[stile.ID & TileData.MaxItemValue].Flags; + var stile = statictiles[i]; + var sflags = TileData.ItemTable[stile.ID & TileData.MaxItemValue].Flags; if (includetilelist != null && includetilelist.Count > 0) { @@ -10231,7 +9898,7 @@ public class XmlSpawner : Item, ISpawner excludetile = true; } - TileFlag iflags = TileData.ItemTable[i.ItemID & TileData.MaxItemValue].Flags; + var iflags = TileData.ItemTable[i.ItemID & TileData.MaxItemValue].Flags; if (includetilelist != null && includetilelist.Count > 0) { includetile = includetilelist.Contains(i.ItemID & TileData.MaxItemValue); @@ -10275,21 +9942,18 @@ public class XmlSpawner : Item, ISpawner return; } - int count = r.Area.Length; + var count = r.Area.Length; - if (locations == null) - { - locations = new List(); - } + locations ??= new List(); // calculate fields of all rectangles (for probability calculating) - for (int n = 0; n < count; n++) + for (var n = 0; n < count; n++) { - Rectangle3D ra = r.Area[n]; - int sx = ra.Start.X; - int sy = ra.Start.Y; - int w = ra.Width; - int h = ra.Height; + var ra = r.Area[n]; + var sx = ra.Start.X; + var sy = ra.Start.Y; + var w = ra.Width; + var h = ra.Height; // find all of the valid tile locations in the area FindTileLocations(ref locations, r.Map, sx, sy, w, h, includetilelist, excludetilelist, tileflag, checkitems, spawnerZ); @@ -10298,33 +9962,33 @@ public class XmlSpawner : Item, ISpawner public Point2D GetRandomRegionPoint(Region r) { - int count = r.Area.Length; + var count = r.Area.Length; - int[] FieldArray = new int[count]; - int total = 0; + var FieldArray = new int[count]; + var total = 0; // calculate fields of all rectangles (for probability calculating) - for (int i = 0; i < count; i++) + for (var i = 0; i < count; i++) { - Rectangle3D ra = r.Area[i]; + var ra = r.Area[i]; total += FieldArray[i] = ra.Width * ra.Height; } - int sum = 0; - int rnd = 0; + var sum = 0; + var rnd = 0; if (total > 0) { rnd = Utility.Random(total); } - int x = 0; - int y = 0; - for (int i = 0; i < count; i++) + var x = 0; + var y = 0; + for (var i = 0; i < count; i++) { sum += FieldArray[i]; if (sum > rnd) { - Rectangle3D r3d = r.Area[i]; + var r3d = r.Area[i]; if (r3d.Width >= 0) { x = r3d.Start.X + Utility.Random(r3d.Width); @@ -10342,17 +10006,24 @@ public class XmlSpawner : Item, ISpawner return new Point2D(x, y); } - public Point3D GetSpawnPosition(ISpawnable spawned, Map map) => GetSpawnPosition(true, spawned as Mobile); + public Point3D GetSpawnPosition(ISpawnable spawned, Map map) + { + return GetSpawnPosition(true, spawned as Mobile); + } // used for getting non-mobile spawn positions - public Point3D GetSpawnPosition(bool requiresurface) => + public Point3D GetSpawnPosition(bool requiresurface) + { // no pack spawning - GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, null); + return GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, null); + } // used for getting mobile spawn positions - public Point3D GetSpawnPosition(bool requiresurface, Mobile mob) => + public Point3D GetSpawnPosition(bool requiresurface, Mobile mob) + { // no pack spawning - GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, mob); + return GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, mob); + } // used for getting non-mobile spawn positions public Point3D GetSpawnPosition( @@ -10360,11 +10031,14 @@ public class XmlSpawner : Item, ISpawner int packrange, Point3D packcoord, List spawnpositioning - ) => GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, null); + ) + { + return GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, null); + } public Point3D GetSpawnPosition(bool requiresurface, int packrange, Point3D packcoord, List spawnpositioning, Mobile mob) { - Map map = Map; + var map = Map; if (map == null) { @@ -10372,25 +10046,25 @@ public class XmlSpawner : Item, ISpawner } // random positioning by default - SpawnPositionType positioning = SpawnPositionType.Random; + var positioning = SpawnPositionType.Random; Mobile trigmob = null; List includetilelist = null; List excludetilelist = null; - bool checkitems = false; + var checkitems = false; // restrictions on tile flags - TileFlag tileflag = TileFlag.None; + var tileflag = TileFlag.None; List locations = null; - int fillinc = 1; - int positionrange = 0; + var fillinc = 1; + var positionrange = 0; string prefix = null; List WayList = null; - int xinc = 0; - int yinc = 0; - int zinc = 0; + var xinc = 0; + var yinc = 0; + var zinc = 0; if (spawnpositioning != null) { - foreach (SpawnPositionInfo s in spawnpositioning) + foreach (var s in spawnpositioning) { if (s == null) { @@ -10398,220 +10072,211 @@ public class XmlSpawner : Item, ISpawner } trigmob = s.trigMob; - string[] positionargs = s.positionArgs; + var positionargs = s.positionArgs; // parse the possible args to the spawn position control keywords switch (s.positionType) { case SpawnPositionType.Wet: - { - // syntax Wet - // find all of the wet tiles - tileflag |= TileFlag.Wet; - requiresurface = false; - break; - } + { + // syntax Wet + // find all of the wet tiles + tileflag |= TileFlag.Wet; + requiresurface = false; + break; + } case SpawnPositionType.ItemID: - { - checkitems = true; - goto case SpawnPositionType.Tiles; - } + { + checkitems = true; + goto case SpawnPositionType.Tiles; + } case SpawnPositionType.NoItemID: - { - checkitems = true; - goto case SpawnPositionType.NoTiles; - } + { + checkitems = true; + goto case SpawnPositionType.NoTiles; + } case SpawnPositionType.Tiles: + { + // syntax Tiles,start[,end] + // get the tiles in the range + requiresurface = false; + var start = -1; + var end = -1; + if (positionargs != null && positionargs.Length > 1) { - // syntax Tiles,start[,end] - // get the tiles in the range - requiresurface = false; - int start = -1; - int end = -1; - if (positionargs != null && positionargs.Length > 1) + try { - try - { - start = int.Parse(positionargs[1]); - } - catch { } + start = int.Parse(positionargs[1]); } - if (positionargs != null && positionargs.Length > 2) - { - try - { - end = int.Parse(positionargs[2]); - } - catch { } - } - if (includetilelist == null) - { - includetilelist = new List(); - } - - // add the tiles to the list - if (start > -1 && end < 0) - { - includetilelist.Add(start); - } - else - if (start > -1 && end > -1) - { - for (int j = start; j <= end; j++) - { - includetilelist.Add(j); - } - } - break; + catch { } } + if (positionargs != null && positionargs.Length > 2) + { + try + { + end = int.Parse(positionargs[2]); + } + catch { } + } + includetilelist ??= new List(); + + // add the tiles to the list + if (start > -1 && end < 0) + { + includetilelist.Add(start); + } + else + if (start > -1 && end > -1) + { + for (var j = start; j <= end; j++) + { + includetilelist.Add(j); + } + } + break; + } case SpawnPositionType.NoTiles: + { + // syntax Tiles,start[,end] + // get the tiles in the range + requiresurface = false; + var start = -1; + var end = -1; + if (positionargs != null && positionargs.Length > 1) { - // syntax Tiles,start[,end] - // get the tiles in the range - requiresurface = false; - int start = -1; - int end = -1; - if (positionargs != null && positionargs.Length > 1) + try { - try - { - start = int.Parse(positionargs[1]); - } - catch { } + start = int.Parse(positionargs[1]); } - if (positionargs != null && positionargs.Length > 2) - { - try - { - end = int.Parse(positionargs[2]); - } - catch { } - } - if (excludetilelist == null) - { - excludetilelist = new List(); - } - - // add the tiles to the list - if (start > -1 && end < 0) - { - excludetilelist.Add(start); - } - else - if (start > -1 && end > -1) - { - for (int j = start; j <= end; j++) - { - excludetilelist.Add(j); - } - } - break; + catch { } } + if (positionargs != null && positionargs.Length > 2) + { + try + { + end = int.Parse(positionargs[2]); + } + catch { } + } + excludetilelist ??= new List(); + + // add the tiles to the list + if (start > -1 && end < 0) + { + excludetilelist.Add(start); + } + else + if (start > -1 && end > -1) + { + for (var j = start; j <= end; j++) + { + excludetilelist.Add(j); + } + } + break; + } case SpawnPositionType.RowFill: case SpawnPositionType.ColFill: case SpawnPositionType.Perimeter: + { + // syntax XFILL[,inc] + // syntax YFILL[,inc] + // syntax EDGE[,inc] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) { - // syntax XFILL[,inc] - // syntax YFILL[,inc] - // syntax EDGE[,inc] - positioning = s.positionType; - if (positionargs != null && positionargs.Length > 1) + try { - try - { - fillinc = int.Parse(positionargs[1]); - } - catch { } + fillinc = int.Parse(positionargs[1]); } - break; + catch { } } + break; + } case SpawnPositionType.RelXY: case SpawnPositionType.DeltaLocation: case SpawnPositionType.Location: + { + // syntax RELXY,xinc,yinc[,zinc] + // syntax XY,x,y[,z] + // syntax DXY,dx,dy[,dz] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 2) { - // syntax RELXY,xinc,yinc[,zinc] - // syntax XY,x,y[,z] - // syntax DXY,dx,dy[,dz] - positioning = s.positionType; - if (positionargs != null && positionargs.Length > 2) + try { - try - { - xinc = int.Parse(positionargs[1]); - yinc = int.Parse(positionargs[2]); - } - catch { } + xinc = int.Parse(positionargs[1]); + yinc = int.Parse(positionargs[2]); } - if (positionargs != null && positionargs.Length > 3) - { - try - { - zinc = int.Parse(positionargs[3]); - } - catch { } - } - break; + catch { } } + if (positionargs != null && positionargs.Length > 3) + { + try + { + zinc = int.Parse(positionargs[3]); + } + catch { } + } + break; + } case SpawnPositionType.Waypoint: + { + // syntax WAYPOINT,prefix[,range] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) { - // syntax WAYPOINT,prefix[,range] - positioning = s.positionType; - if (positionargs != null && positionargs.Length > 1) + prefix = positionargs[1]; + } + + if (positionargs != null && positionargs.Length > 2) + { + try { - prefix = positionargs[1]; + positionrange = int.Parse(positionargs[2]); } + catch { } + } - if (positionargs != null && positionargs.Length > 2) + // find a list of items that match the waypoint prefix + if (prefix != null) + { + // see if there is an existing hashtable for the waypoint lists + spawnPositionWayTable ??= new Dictionary>(); + + // no existing list so create a new one + if (!spawnPositionWayTable.TryGetValue(prefix, out WayList) || WayList == null) { - try - { - positionrange = int.Parse(positionargs[2]); - } - catch { } - } + WayList = new List(); - // find a list of items that match the waypoint prefix - if (prefix != null) - { - // see if there is an existing hashtable for the waypoint lists - if (spawnPositionWayTable == null) + foreach (var i in World.Items.Values) { - spawnPositionWayTable = new Dictionary>(); - } - - // no existing list so create a new one - if (!spawnPositionWayTable.TryGetValue(prefix, out WayList) || WayList == null) - { - WayList = new List(); - - foreach (Item i in World.Items.Values) + if (i is WayPoint && !string.IsNullOrEmpty(i.Name) && i.Map == Map && i.Name == prefix) { - if (i is WayPoint && !string.IsNullOrEmpty(i.Name) && i.Map == Map && i.Name == prefix) - { - // add it to the list of items - WayList.Add(i); - } + // add it to the list of items + WayList.Add(i); } - // add the new list to the local table - spawnPositionWayTable[prefix] = WayList; } + // add the new list to the local table + spawnPositionWayTable[prefix] = WayList; } - break; } + break; + } case SpawnPositionType.Player: + { + // syntax PLAYER[,range] + positioning = s.positionType; + if (positionargs != null && positionargs.Length > 1) { - // syntax PLAYER[,range] - positioning = s.positionType; - if (positionargs != null && positionargs.Length > 1) + try { - try - { - positionrange = int.Parse(positionargs[1]); - } - catch { } + positionrange = int.Parse(positionargs[1]); } - break; + catch { } } + break; + } } } } @@ -10631,13 +10296,13 @@ public class XmlSpawner : Item, ISpawner // Try 10 times to find a Spawnable location. // trace profiling indicates that this is a major bottleneck - for (int i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { - int x = X; - int y = Y; - int z = Z; + var x = X; + var y = Y; + _ = Z; - int defaultZ = Z; + var defaultZ = Z; if (packrange >= 0 && packcoord != Point3D.Zero) { defaultZ = packcoord.Z; @@ -10658,7 +10323,7 @@ public class XmlSpawner : Item, ISpawner // use the precalculated tile locations if (locations != null && locations.Count > 0) { - Point3D p = locations[Utility.Random(locations.Count)]; + var p = locations[Utility.Random(locations.Count)]; x = p.X; y = p.Y; defaultZ = p.Z; @@ -10666,7 +10331,7 @@ public class XmlSpawner : Item, ISpawner } else { - Point2D p = GetRandomRegionPoint(m_Region); + var p = GetRandomRegionPoint(m_Region); x = p.X; y = p.Y; } @@ -10676,208 +10341,208 @@ public class XmlSpawner : Item, ISpawner switch (positioning) { case SpawnPositionType.Random: + { + if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) { - if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) + + if (locations != null && locations.Count > 0) { - - if (locations != null && locations.Count > 0) - { - Point3D p = locations[Utility.Random(locations.Count)]; - x = p.X; - y = p.Y; - defaultZ = p.Z; - } + var p = locations[Utility.Random(locations.Count)]; + x = p.X; + y = p.Y; + defaultZ = p.Z; } - else - { - - if (m_Width > 0) - { - x = m_X + Utility.Random(m_Width + 1); - } - - if (m_Height > 0) - { - y = m_Y + Utility.Random(m_Height + 1); - } - } - break; } + else + { + + if (m_Width > 0) + { + x = m_X + Utility.Random(m_Width + 1); + } + + if (m_Height > 0) + { + y = m_Y + Utility.Random(m_Height + 1); + } + } + break; + } case SpawnPositionType.RelXY: - { - x = mostRecentSpawnPosition.X + xinc; - y = mostRecentSpawnPosition.Y + yinc; - defaultZ = mostRecentSpawnPosition.Z + zinc; - break; - } + { + x = mostRecentSpawnPosition.X + xinc; + y = mostRecentSpawnPosition.Y + yinc; + defaultZ = mostRecentSpawnPosition.Z + zinc; + break; + } case SpawnPositionType.DeltaLocation: - { - x = X + xinc; - y = Y + yinc; - defaultZ = Z + zinc; - break; - } + { + x = X + xinc; + y = Y + yinc; + defaultZ = Z + zinc; + break; + } case SpawnPositionType.Location: - { - x = xinc; - y = yinc; - defaultZ = zinc; - break; - } + { + x = xinc; + y = yinc; + defaultZ = zinc; + break; + } case SpawnPositionType.RowFill: + { + x = mostRecentSpawnPosition.X + fillinc; + y = mostRecentSpawnPosition.Y; + + if (x < m_X) { - x = mostRecentSpawnPosition.X + fillinc; - y = mostRecentSpawnPosition.Y; - - if (x < m_X) - { - x = m_X; - } - - if (y < m_Y) - { - y = m_Y; - } - - if (x > m_X + m_Width) - { - x = m_X + (x - m_X - m_Width - 1); - y++; - } - - if (y > m_Y + m_Height) - { - y = m_Y; - } - - break; + x = m_X; } + if (y < m_Y) + { + y = m_Y; + } + + if (x > m_X + m_Width) + { + x = m_X + (x - m_X - m_Width - 1); + y++; + } + + if (y > m_Y + m_Height) + { + y = m_Y; + } + + break; + } + case SpawnPositionType.ColFill: + { + x = mostRecentSpawnPosition.X; + y = mostRecentSpawnPosition.Y + fillinc; + + if (x < m_X) { - x = mostRecentSpawnPosition.X; - y = mostRecentSpawnPosition.Y + fillinc; - - if (x < m_X) - { - x = m_X; - } - - if (y < m_Y) - { - y = m_Y; - } - - if (y > m_Y + m_Height) - { - y = m_Y + (y - m_Y - m_Height - 1); - x++; - } - - if (x > m_X + m_Width) - { - x = m_X; - } - - break; + x = m_X; } + if (y < m_Y) + { + y = m_Y; + } + + if (y > m_Y + m_Height) + { + y = m_Y + (y - m_Y - m_Height - 1); + x++; + } + + if (x > m_X + m_Width) + { + x = m_X; + } + + break; + } + case SpawnPositionType.Perimeter: + { + x = mostRecentSpawnPosition.X; + y = mostRecentSpawnPosition.Y; + + // if the point is not on the perimeter, reset it to the corner + if (x != m_X && x != m_X + m_Width && y != m_Y && y != m_Y + m_Height) { - x = mostRecentSpawnPosition.X; - y = mostRecentSpawnPosition.Y; - - // if the point is not on the perimeter, reset it to the corner - if (x != m_X && x != m_X + m_Width && y != m_Y && y != m_Y + m_Height) - { - x = m_X; - y = m_Y; - } - - if (y == m_Y && x < m_X + m_Width) - { - x += fillinc; - } - else - if (y == m_Y + m_Height && x > m_X) - { - x -= fillinc; - } - else - if (x == m_X && y > m_Y) - { - y -= fillinc; - } - else - if (x == m_X + m_Width && y < m_Y + m_Height) - { - y += fillinc; - } - - if (x > m_X + m_Width) - { - x = m_X + m_Width; - } - - if (y > m_Y + m_Height) - { - y = m_Y + m_Height; - } - - if (x < m_X) - { - x = m_X; - } - - if (y < m_Y) - { - y = m_Y; - } - - break; + x = m_X; + y = m_Y; } - case SpawnPositionType.Player: + if (y == m_Y && x < m_X + m_Width) { - if (trigmob != null) + x += fillinc; + } + else + if (y == m_Y + m_Height && x > m_X) + { + x -= fillinc; + } + else + if (x == m_X && y > m_Y) + { + y -= fillinc; + } + else + if (x == m_X + m_Width && y < m_Y + m_Height) + { + y += fillinc; + } + + if (x > m_X + m_Width) + { + x = m_X + m_Width; + } + + if (y > m_Y + m_Height) + { + y = m_Y + m_Height; + } + + if (x < m_X) + { + x = m_X; + } + + if (y < m_Y) + { + y = m_Y; + } + + break; + } + + case SpawnPositionType.Player: + { + if (trigmob != null) + { + x = trigmob.Location.X; + y = trigmob.Location.Y; + if (positionrange > 0) { - x = trigmob.Location.X; - y = trigmob.Location.Y; + x += Utility.Random(positionrange * 2 + 1) - positionrange; + y += Utility.Random(positionrange * 2 + 1) - positionrange; + } + } + break; + } + + case SpawnPositionType.Waypoint: + { + // pick an item randomly from the waylist + if (WayList != null && WayList.Count > 0) + { + var index = Utility.Random(WayList.Count); + var waypoint = WayList[index]; + if (waypoint != null) + { + x = waypoint.Location.X; + y = waypoint.Location.Y; + defaultZ = waypoint.Location.Z; if (positionrange > 0) { x += Utility.Random(positionrange * 2 + 1) - positionrange; y += Utility.Random(positionrange * 2 + 1) - positionrange; } } - break; } - case SpawnPositionType.Waypoint: - { - // pick an item randomly from the waylist - if (WayList != null && WayList.Count > 0) - { - int index = Utility.Random(WayList.Count); - Item waypoint = WayList[index]; - if (waypoint != null) - { - x = waypoint.Location.X; - y = waypoint.Location.Y; - defaultZ = waypoint.Location.Z; - if (positionrange > 0) - { - x += Utility.Random(positionrange * 2 + 1) - positionrange; - y += Utility.Random(positionrange * 2 + 1) - positionrange; - } - } - } - - break; - } + break; + } } mostRecentSpawnPosition = new Point3D(x, y, defaultZ); @@ -10899,7 +10564,7 @@ public class XmlSpawner : Item, ISpawner return new Point3D(x, y, defaultZ); } - z = Map.GetAverageZ(x, y); + var z = Map.GetAverageZ(x, y); fit = requiresurface ? CanSpawnMobile(x, y, z, mob) : Map.CanFit(x, y, z, SpawnFitSize, true, false, false); @@ -10936,7 +10601,7 @@ public class XmlSpawner : Item, ISpawner return; } - foreach (object o in list) + foreach (var o in list) { if (o is Item item) { @@ -10953,7 +10618,7 @@ public class XmlSpawner : Item, ISpawner { if (listi != null) { - int i = listi.Count; + var i = listi.Count; while (--i >= 0) { @@ -10973,7 +10638,7 @@ public class XmlSpawner : Item, ISpawner if (listm != null) { - int i = listm.Count; + var i = listm.Count; while (--i >= 0) { @@ -11002,14 +10667,14 @@ public class XmlSpawner : Item, ISpawner Defrag(false); ClearTags(true); - List deletelist = new List(); - foreach (SpawnObject so in m_SpawnObjects) + var deletelist = new List(); + foreach (var so in m_SpawnObjects) { - for (int i = 0; i < so.SpawnedObjects.Count; ++i) + for (var i = 0; i < so.SpawnedObjects.Count; ++i) { - object o = so.SpawnedObjects[i]; + var o = so.SpawnedObjects[i]; - if (o is Item || o is Mobile) + if (o is Item or Mobile) { deletelist.Add(o); } @@ -11022,7 +10687,6 @@ public class XmlSpawner : Item, ISpawner Defrag(false); } - public void RemoveSpawnObjects(SpawnObject so) { if (so == null) @@ -11032,13 +10696,13 @@ public class XmlSpawner : Item, ISpawner Defrag(false); - List deletelist = new List(); + var deletelist = new List(); - for (int i = 0; i < so.SpawnedObjects.Count; ++i) + for (var i = 0; i < so.SpawnedObjects.Count; ++i) { - object o = so.SpawnedObjects[i]; + var o = so.SpawnedObjects[i]; - if (o is Item || o is Mobile) + if (o is Item or Mobile) { deletelist.Add(o); } @@ -11060,19 +10724,19 @@ public class XmlSpawner : Item, ISpawner Defrag(false); ClearTags(true); - List deletelist = new List(); - foreach (SpawnObject so in m_SpawnObjects) + var deletelist = new List(); + foreach (var so in m_SpawnObjects) { if (so.SubGroup != subgroup || !so.ClearOnAdvance) { continue; } - for (int i = 0; i < so.SpawnedObjects.Count; ++i) + for (var i = 0; i < so.SpawnedObjects.Count; ++i) { - object o = so.SpawnedObjects[i]; + var o = so.SpawnedObjects[i]; - if (o is Item || o is Mobile) + if (o is Item or Mobile) { deletelist.Add(o); } @@ -11085,7 +10749,6 @@ public class XmlSpawner : Item, ISpawner Defrag(false); } - // used to optimize smart spawning by removing all objects except those that have hold smartspawning public void SmartRemoveSpawnObjects() { @@ -11097,12 +10760,12 @@ public class XmlSpawner : Item, ISpawner Defrag(false); ClearTags(true); - List deletelist = new List(); - foreach (SpawnObject so in m_SpawnObjects) + var deletelist = new List(); + foreach (var so in m_SpawnObjects) { - for (int i = 0; i < so.SpawnedObjects.Count; ++i) + for (var i = 0; i < so.SpawnedObjects.Count; ++i) { - object o = so.SpawnedObjects[i]; + var o = so.SpawnedObjects[i]; // new optimization for smart spawning to remove all objects except those with hold smartspawning enabled if (CheckHoldSmartSpawning(o)) @@ -11110,7 +10773,7 @@ public class XmlSpawner : Item, ISpawner continue; } - if (o is Item || o is Mobile) + if (o is Item or Mobile) { deletelist.Add(o); } @@ -11133,7 +10796,7 @@ public class XmlSpawner : Item, ISpawner Defrag(false); // Find the spawn object and increment its count by one - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper()) { @@ -11156,7 +10819,7 @@ public class XmlSpawner : Item, ISpawner public void DeleteSpawnObject(Mobile from, string SpawnObjectName) { - bool WasRunning = m_Running; + var WasRunning = m_Running; try { @@ -11170,7 +10833,7 @@ public class XmlSpawner : Item, ISpawner SpawnObject TheSpawn = null; // Find the spawn object and increment its count by one - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper()) { @@ -11183,7 +10846,7 @@ public class XmlSpawner : Item, ISpawner // Was the spawn object found if (TheSpawn != null) { - bool delete_this_entry = false; + var delete_this_entry = false; // Decrement the max count for the current creature TheSpawn.ActualMaxCount--; @@ -11208,20 +10871,20 @@ public class XmlSpawner : Item, ISpawner } - List deletelist = new List(); + var deletelist = new List(); // Remove any spawns over the count while (TheSpawn.SpawnedObjects != null && TheSpawn.SpawnedObjects.Count > 0 && TheSpawn.SpawnedObjects.Count > TheSpawn.MaxCount) { - object o = TheSpawn.SpawnedObjects[0]; + var o = TheSpawn.SpawnedObjects[0]; // Delete the object - if (o is Item || o is Mobile) + if (o is Item or Mobile) { deletelist.Add(o); } - TheSpawn.SpawnedObjects.Remove(o); + _ = TheSpawn.SpawnedObjects.Remove(o); } DeleteFromList(deletelist); @@ -11229,7 +10892,7 @@ public class XmlSpawner : Item, ISpawner // Check if the spawn object should be removed if (delete_this_entry) { - m_SpawnObjects.Remove(TheSpawn); + _ = m_SpawnObjects.Remove(TheSpawn); if (from != null) { var loc = GetWorldLocation(); @@ -11253,16 +10916,19 @@ public class XmlSpawner : Item, ISpawner { if (m_SpawnObjects.Contains(so)) { - m_SpawnObjects.Remove(so); + _ = m_SpawnObjects.Remove(so); } } - public static object CreateObject(Type type, string itemtypestring) => CreateObject(type, itemtypestring, true); + public static object CreateObject(Type type, string itemtypestring) + { + return CreateObject(type, itemtypestring, true); + } public static object CreateObject(Type type, string itemtypestring, bool requireConstructible) { // look for constructor arguments to be passed to it with the syntax type,arg1,arg2,.../ - string[] typewordargs = BaseXmlSpawner.ParseObjectArgs(itemtypestring); + var typewordargs = BaseXmlSpawner.ParseObjectArgs(itemtypestring); return CreateObject(type, typewordargs, requireConstructible); } @@ -11276,22 +10942,22 @@ public class XmlSpawner : Item, ISpawner object o = null; - int typearglen = 0; + var typearglen = 0; if (typewordargs != null) { typearglen = typewordargs.Length; } // ok, there are args in the typename, so we need to invoke the proper constructor - ConstructorInfo[] ctors = type.GetConstructors(); + var ctors = type.GetConstructors(); // go through all the constructors for this type - for (int i = 0; i < ctors.Length; ++i) + for (var i = 0; i < ctors.Length; ++i) { - ConstructorInfo ctor = ctors[i]; + var ctor = ctors[i]; // if requireConstructible is true, then allow either condition -#if (RESTRICTConstructible) +#if RESTRICTConstructible if (!(requireConstructible && Add.IsConstructible(ctor,requester))) continue; #else @@ -11302,7 +10968,7 @@ public class XmlSpawner : Item, ISpawner #endif // check the parameter list of the constructor - ParameterInfo[] paramList = ctor.GetParameters(); + var paramList = ctor.GetParameters(); // and compare with the argument list provided if (typearglen == paramList.Length) @@ -11353,14 +11019,11 @@ public class XmlSpawner : Item, ISpawner private static void DoGlobalSectorTimer(TimeSpan delay) { - if (m_GlobalSectorTimer != null) - { - m_GlobalSectorTimer.Stop(); - } + m_GlobalSectorTimer?.Stop(); m_GlobalSectorTimer = new GlobalSectorTimer(delay); - m_GlobalSectorTimer.Start(); + _ = m_GlobalSectorTimer.Start(); } private class GlobalSectorTimer : Timer @@ -11375,24 +11038,24 @@ public class XmlSpawner : Item, ISpawner // check the sectors // check all active players - foreach (NetState state in TcpServer.Instances) + foreach (var state in TcpServer.Instances) { - Mobile m = state.Mobile; + var m = state.Mobile; if (m != null && (m.AccessLevel <= SmartSpawnAccessLevel || !m.Hidden)) { // activate any spawner in the sector they are in if (m.Map != null && m.Map != Map.Internal) { - Sector s = m.Map.GetSector(m.Location); + var s = m.Map.GetSector(m.Location); if (s != null && GlobalSectorTable[m.Map.MapID] != null) { - List spawnerlist; // = GlobalSectorTable[m.Map.MapID][s]; - if (GlobalSectorTable[m.Map.MapID].TryGetValue(s, out spawnerlist) && spawnerlist != null) + // = GlobalSectorTable[m.Map.MapID][s]; + if (GlobalSectorTable[m.Map.MapID].TryGetValue(s, out var spawnerlist) && spawnerlist != null) { - foreach (XmlSpawner spawner in spawnerlist) + foreach (var spawner in spawnerlist) { if (spawner != null && !spawner.Deleted && spawner.Running && spawner.SmartSpawning && spawner.IsInactivated) @@ -11410,21 +11073,21 @@ public class XmlSpawner : Item, ISpawner public void DoSectorTimer(TimeSpan delay) { - if (m_SectorTimer != null) - { - m_SectorTimer.Stop(); - } + m_SectorTimer?.Stop(); m_SectorTimer = new SectorTimer(this, delay); - m_SectorTimer.Start(); + _ = m_SectorTimer.Start(); } private class SectorTimer : Timer { private readonly XmlSpawner m_Spawner; - public SectorTimer(XmlSpawner spawner, TimeSpan delay) : base(delay, delay) => m_Spawner = spawner; + public SectorTimer(XmlSpawner spawner, TimeSpan delay) : base(delay, delay) + { + m_Spawner = spawner; + } protected override void OnTick() { @@ -11477,7 +11140,7 @@ public class XmlSpawner : Item, ISpawner : base(TimeSpan.FromSeconds(1.0)) { m_List = new List(); - Start(); + _ = Start(); } public void Add(Point3D p, Map map, string name) @@ -11491,20 +11154,18 @@ public class XmlSpawner : Item, ISpawner { Console.WriteLine("Warning: {0} bad spawns detected, logged: 'badspawn.log'", m_List.Count); - using (StreamWriter op = new StreamWriter("badspawn.log", true)) + using var op = new StreamWriter("badspawn.log", true); + op.WriteLine("# Bad spawns : {0}", Core.Now); + op.WriteLine("# Format: X Y Z F Name"); + op.WriteLine(); + + foreach (var e in m_List) { - op.WriteLine("# Bad spawns : {0}", Core.Now); - op.WriteLine("# Format: X Y Z F Name"); - op.WriteLine(); - - foreach (WarnEntry2 e in m_List) - { - op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", e.m_Point.X, e.m_Point.Y, e.m_Point.Z, e.m_Map, e.m_Name); - } - - op.WriteLine(); - op.WriteLine(); + op.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}", e.m_Point.X, e.m_Point.Y, e.m_Point.Z, e.m_Map, e.m_Name); } + + op.WriteLine(); + op.WriteLine(); } catch { } @@ -11518,10 +11179,10 @@ public class XmlSpawner : Item, ISpawner return; } - int minSeconds = (int)m_MinDelay.TotalSeconds; - int maxSeconds = (int)m_MaxDelay.TotalSeconds; + var minSeconds = (int)m_MinDelay.TotalSeconds; + var maxSeconds = (int)m_MaxDelay.TotalSeconds; - TimeSpan delay = TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds)); + var delay = TimeSpan.FromSeconds(Utility.RandomMinMax(minSeconds, maxSeconds)); DoTimer(delay); } @@ -11534,13 +11195,10 @@ public class XmlSpawner : Item, ISpawner m_End = Core.Now + delay; - if (m_Timer != null) - { - m_Timer.Stop(); - } + m_Timer?.Stop(); m_Timer = new SpawnerTimer(this, delay); - m_Timer.Start(); + _ = m_Timer.Start(); } public void DoTimer2(TimeSpan delay) @@ -11548,13 +11206,10 @@ public class XmlSpawner : Item, ISpawner m_DurEnd = Core.Now + delay; if (m_Duration > TimeSpan.FromMinutes(0) || m_durActivated) { - if (m_DurTimer != null) - { - m_DurTimer.Stop(); - } + m_DurTimer?.Stop(); m_DurTimer = new InternalTimer(this, delay); - m_DurTimer.Start(); + _ = m_DurTimer.Start(); m_durActivated = true; } } @@ -11564,13 +11219,10 @@ public class XmlSpawner : Item, ISpawner m_RefractEnd = Core.Now + delay; m_refractActivated = true; - if (m_RefractoryTimer != null) - { - m_RefractoryTimer.Stop(); - } + m_RefractoryTimer?.Stop(); m_RefractoryTimer = new InternalTimer3(this, delay); - m_RefractoryTimer.Start(); + _ = m_RefractoryTimer.Start(); } // added the duration timer that begins on spawning @@ -11578,7 +11230,10 @@ public class XmlSpawner : Item, ISpawner { private readonly XmlSpawner m_spawner; - public InternalTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_spawner = spawner; + public InternalTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) + { + m_spawner = spawner; + } protected override void OnTick() { @@ -11595,7 +11250,10 @@ public class XmlSpawner : Item, ISpawner { private readonly XmlSpawner m_Spawner; - public SpawnerTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_Spawner = spawner; + public SpawnerTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) + { + m_Spawner = spawner; + } protected override void OnTick() { @@ -11611,7 +11269,10 @@ public class XmlSpawner : Item, ISpawner { private readonly XmlSpawner m_spawner; - public InternalTimer3(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_spawner = spawner; + public InternalTimer3(XmlSpawner spawner, TimeSpan delay) : base(delay) + { + m_spawner = spawner; + } protected override void OnTick() { @@ -11629,15 +11290,15 @@ public class XmlSpawner : Item, ISpawner writer.Write(32); // version // version 31 - writer.Write(m_DisableGlobalAutoReset); + writer.Write(DisableGlobalAutoReset); // Version 30 - writer.Write(m_AllowNPCTriggering); + writer.Write(AllowNPCTrig); // Version 29 if (m_SpawnObjects != null) { writer.Write(m_SpawnObjects.Count); - for (int i = 0; i < m_SpawnObjects.Count; ++i) + for (var i = 0; i < m_SpawnObjects.Count; ++i) { // Write the spawns per tick value writer.Write(m_SpawnObjects[i].SpawnsPerTick); @@ -11652,18 +11313,17 @@ public class XmlSpawner : Item, ISpawner // Version 28 if (m_SpawnObjects != null) { - for (int i = 0; i < m_SpawnObjects.Count; ++i) + for (var i = 0; i < m_SpawnObjects.Count; ++i) { // Write the pack range value writer.Write(m_SpawnObjects[i].PackRange); } } - // Version 27 if (m_SpawnObjects != null) { - for (int i = 0; i < m_SpawnObjects.Count; ++i) + for (var i = 0; i < m_SpawnObjects.Count; ++i) { // Write the disable spawn flag writer.Write(m_SpawnObjects[i].Disabled); @@ -11671,14 +11331,14 @@ public class XmlSpawner : Item, ISpawner } // Version 26 - writer.Write(m_SpawnOnTrigger); + writer.Write(SpawnOnTrigger); // Version 24 if (m_SpawnObjects != null) { - for (int i = 0; i < m_SpawnObjects.Count; ++i) + for (var i = 0; i < m_SpawnObjects.Count; ++i) { - SpawnObject so = m_SpawnObjects[i]; + var so = m_SpawnObjects[i]; // Write the restrict kills flag writer.Write(so.RestrictKillsToSubgroup); // Write the clear on advance flag @@ -11708,28 +11368,28 @@ public class XmlSpawner : Item, ISpawner writer.Write(IsInactivated); writer.Write(m_SmartSpawning); // Version 22 - writer.Write(m_SkillTrigger); + writer.Write(SkillTrigger); writer.Write((int)m_skill_that_triggered); - writer.Write(m_FreeRun); - writer.Write(m_mob_who_triggered); + writer.Write(FreeRun); + writer.Write(TriggerMob); // Version 21 - writer.Write(m_DespawnTime); + writer.Write(DespawnTime); // Version 20 if (m_SpawnObjects != null) { - for (int i = 0; i < m_SpawnObjects.Count; ++i) + for (var i = 0; i < m_SpawnObjects.Count; ++i) { // Write the requiresurface flag writer.Write(m_SpawnObjects[i].RequireSurface); } } // Version 19 - writer.Write(m_ConfigFile); + writer.Write(ConfigFile); writer.Write(m_OnHold); writer.Write(m_HoldSequence); // compute the number of tags to save - int tagcount = 0; - for (int i = 0; i < m_KeywordTagList.Count; i++) + var tagcount = 0; + for (var i = 0; i < m_KeywordTagList.Count; i++) { // only save WAIT type keywords or other keywords that have the save flag set if ((m_KeywordTagList[i].Flags & BaseXmlSpawner.KeywordFlags.Serialize) != 0) @@ -11739,7 +11399,7 @@ public class XmlSpawner : Item, ISpawner } writer.Write(tagcount); // and write them out - for (int i = 0; i < m_KeywordTagList.Count; i++) + for (var i = 0; i < m_KeywordTagList.Count; i++) { if ((m_KeywordTagList[i].Flags & BaseXmlSpawner.KeywordFlags.Serialize) != 0) { @@ -11747,20 +11407,20 @@ public class XmlSpawner : Item, ISpawner } } // Version 18 - writer.Write(m_AllowGhostTriggering); + writer.Write(AllowGhostTrig); // Version 17 // removed in version 25 //writer.Write(m_TextEntryBook); // Version 16 - writer.Write(m_SequentialSpawning); + writer.Write(SequentialSpawn); // write out the remaining time until sequential reset writer.Write(NextSeqReset); // Write the spawn object list if (m_SpawnObjects != null) { - for (int i = 0; i < m_SpawnObjects.Count; ++i) + for (var i = 0; i < m_SpawnObjects.Count; ++i) { - SpawnObject so = m_SpawnObjects[i]; + var so = m_SpawnObjects[i]; // Write the subgroup and sequential reset time writer.Write(so.SubGroup); writer.Write(so.SequentialResetTime); @@ -11771,58 +11431,58 @@ public class XmlSpawner : Item, ISpawner writer.Write(m_RegionName); // Version 15 - writer.Write(m_ExternalTriggering); - writer.Write(m_ExternalTrigger); + writer.Write(ExternalTriggering); + writer.Write(ExtTrigState); // Version 14 writer.Write(m_NoItemTriggerName); // Version 13 - writer.Write(m_GumpState); + writer.Write(GumpState); // Version 12 - int todtype = (int)m_TODMode; + var todtype = (int)TODMode; writer.Write(todtype); // Version 11 - writer.Write(m_KillReset); + writer.Write(KillReset); writer.Write(m_skipped); writer.Write(m_spawncheck); // Version 10 - writer.Write(m_SetPropertyItem); + writer.Write(SetItem); // Version 9 - writer.Write(m_TriggerProbability); + writer.Write(TriggerProbability); // Version 8 - writer.Write(m_MobPropertyName); - writer.Write(m_MobTriggerName); - writer.Write(m_PlayerPropertyName); + writer.Write(MobTriggerProp); + writer.Write(MobTriggerName); + writer.Write(PlayerTriggerProp); // Version 7 - writer.Write(m_SpeechTrigger); + writer.Write(SpeechTrigger); // Version 6 writer.Write(m_ItemTriggerName); // Version 5 - writer.Write(m_ProximityTriggerMessage); + writer.Write(ProximityMsg); writer.Write(m_ObjectPropertyItem); writer.Write(m_ObjectPropertyName); writer.Write(m_killcount); // Version 4 writer.Write(m_ProximityRange); - writer.Write(m_ProximityTriggerSound); + writer.Write(ProximitySound); writer.Write(m_proximityActivated); writer.Write(m_durActivated); writer.Write(m_refractActivated); - writer.Write(m_StackAmount); - writer.Write(m_TODStart); - writer.Write(m_TODEnd); - writer.Write(m_MinRefractory); - writer.Write(m_MaxRefractory); + writer.Write(StackAmount); + writer.Write(TODStart); + writer.Write(TODEnd); + writer.Write(RefractMin); + writer.Write(RefractMax); if (m_refractActivated) { writer.Write(m_RefractEnd - Core.Now); @@ -11839,8 +11499,8 @@ public class XmlSpawner : Item, ISpawner writer.Write(m_Duration); // Version 1 - writer.Write(m_UniqueId); - writer.Write(m_HomeRangeIsRelative); + writer.Write(UniqueId); + writer.Write(HomeRangeIsRelative); // Version 0 writer.Write(m_Name); @@ -11848,7 +11508,7 @@ public class XmlSpawner : Item, ISpawner writer.Write(m_Y); writer.Write(m_Width); writer.Write(m_Height); - writer.Write(m_WayPoint); + writer.Write(WayPoint); writer.Write(m_Group); writer.Write(m_MinDelay); writer.Write(m_MaxDelay); @@ -11863,16 +11523,16 @@ public class XmlSpawner : Item, ISpawner } // Write the spawn object list - int nso = 0; + var nso = 0; if (m_SpawnObjects != null) { nso = m_SpawnObjects.Count; } writer.Write(nso); - for (int i = 0; i < nso; ++i) + for (var i = 0; i < nso; ++i) { - SpawnObject so = m_SpawnObjects[i]; + var so = m_SpawnObjects[i]; // Write the type and maximum count writer.Write(so.TypeName); @@ -11880,9 +11540,9 @@ public class XmlSpawner : Item, ISpawner // Write the spawned object information writer.Write(so.SpawnedObjects.Count); - for (int x = 0; x < so.SpawnedObjects.Count; ++x) + for (var x = 0; x < so.SpawnedObjects.Count; ++x) { - object o = so.SpawnedObjects[x]; + var o = so.SpawnedObjects[x]; if (o is Item item) { @@ -11912,10 +11572,10 @@ public class XmlSpawner : Item, ISpawner { base.Deserialize(reader); - int version = reader.ReadInt(); - bool haveproximityrange = false; - bool hasnewobjectinfo = false; - int tmpSpawnListSize = 0; + var version = reader.ReadInt(); + var haveproximityrange = false; + var hasnewobjectinfo = false; + var tmpSpawnListSize = 0; List tmpSubGroup = null; List tmpSequentialResetTime = null; List tmpSequentialResetTo = null; @@ -11934,468 +11594,467 @@ public class XmlSpawner : Item, ISpawner { case 32: case 31: - { - m_DisableGlobalAutoReset = reader.ReadBool(); - goto case 30; - } + { + DisableGlobalAutoReset = reader.ReadBool(); + goto case 30; + } case 30: - { - m_AllowNPCTriggering = reader.ReadBool(); - goto case 29; - } + { + AllowNPCTrig = reader.ReadBool(); + goto case 29; + } case 29: + { + tmpSpawnListSize = reader.ReadInt(); + tmpSpawnsPer = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) { - tmpSpawnListSize = reader.ReadInt(); - tmpSpawnsPer = new List(tmpSpawnListSize); - for (int i = 0; i < tmpSpawnListSize; ++i) - { - int spawnsper = reader.ReadInt(); + var spawnsper = reader.ReadInt(); - tmpSpawnsPer.Add(spawnsper); + tmpSpawnsPer.Add(spawnsper); - } - goto case 28; } + goto case 28; + } case 28: + { + tmpPackRange = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) { - tmpPackRange = new List(tmpSpawnListSize); - for (int i = 0; i < tmpSpawnListSize; ++i) - { - int packrange = reader.ReadInt(); + var packrange = reader.ReadInt(); - tmpPackRange.Add(packrange); + tmpPackRange.Add(packrange); - } - goto case 27; } + goto case 27; + } case 27: + { + tmpDisableSpawn = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) { - tmpDisableSpawn = new List(tmpSpawnListSize); - for (int i = 0; i < tmpSpawnListSize; ++i) - { - bool disablespawn = reader.ReadBool(); + var disablespawn = reader.ReadBool(); - tmpDisableSpawn.Add(disablespawn); + tmpDisableSpawn.Add(disablespawn); - } - goto case 26; } + goto case 26; + } case 26: - { - m_SpawnOnTrigger = reader.ReadBool(); + { + SpawnOnTrigger = reader.ReadBool(); - if (version < 32) - { - // Delete First & Last Modified - reader.ReadDateTime(); - reader.ReadDateTime(); - } - goto case 25; + if (version < 32) + { + // Delete First & Last Modified + _ = reader.ReadDateTime(); + _ = reader.ReadDateTime(); } + goto case 25; + } case 25: - { - goto case 24; - } + { + goto case 24; + } case 24: + { + tmpRestrictKillsToSubgroup = new List(tmpSpawnListSize); + tmpClearOnAdvance = new List(tmpSpawnListSize); + tmpMinDelay = new List(tmpSpawnListSize); + tmpMaxDelay = new List(tmpSpawnListSize); + tmpNextSpawn = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) { - tmpRestrictKillsToSubgroup = new List(tmpSpawnListSize); - tmpClearOnAdvance = new List(tmpSpawnListSize); - tmpMinDelay = new List(tmpSpawnListSize); - tmpMaxDelay = new List(tmpSpawnListSize); - tmpNextSpawn = new List(tmpSpawnListSize); - for (int i = 0; i < tmpSpawnListSize; ++i) - { - bool restrictkills = reader.ReadBool(); - bool clearadvance = reader.ReadBool(); - double mind = reader.ReadDouble(); - double maxd = reader.ReadDouble(); - DateTime nextspawn = reader.ReadDeltaTime(); + var restrictkills = reader.ReadBool(); + var clearadvance = reader.ReadBool(); + var mind = reader.ReadDouble(); + var maxd = reader.ReadDouble(); + var nextspawn = reader.ReadDeltaTime(); - tmpRestrictKillsToSubgroup.Add(restrictkills); - tmpClearOnAdvance.Add(clearadvance); - tmpMinDelay.Add(mind); - tmpMaxDelay.Add(maxd); - tmpNextSpawn.Add(nextspawn); - } - - bool hasitems = reader.ReadBool(); - - if (hasitems) - { - m_ShowBoundsItems = reader.ReadEntityList(); - } - goto case 23; + tmpRestrictKillsToSubgroup.Add(restrictkills); + tmpClearOnAdvance.Add(clearadvance); + tmpMinDelay.Add(mind); + tmpMaxDelay.Add(maxd); + tmpNextSpawn.Add(nextspawn); } + + var hasitems = reader.ReadBool(); + + if (hasitems) + { + m_ShowBoundsItems = reader.ReadEntityList(); + } + goto case 23; + } case 23: - { - IsInactivated = reader.ReadBool(); - SmartSpawning = reader.ReadBool(); + { + IsInactivated = reader.ReadBool(); + SmartSpawning = reader.ReadBool(); - goto case 22; - } + goto case 22; + } case 22: - { - SkillTrigger = reader.ReadString(); // note this will also register the skill - m_skill_that_triggered = (SkillName)reader.ReadInt(); - m_FreeRun = reader.ReadBool(); - m_mob_who_triggered = reader.ReadEntity(); - goto case 21; - } + { + SkillTrigger = reader.ReadString(); // note this will also register the skill + m_skill_that_triggered = (SkillName)reader.ReadInt(); + FreeRun = reader.ReadBool(); + TriggerMob = reader.ReadEntity(); + goto case 21; + } case 21: - { - m_DespawnTime = reader.ReadTimeSpan(); - goto case 20; - } + { + DespawnTime = reader.ReadTimeSpan(); + goto case 20; + } case 20: + { + tmpRequireSurface = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) { - tmpRequireSurface = new List(tmpSpawnListSize); - for (int i = 0; i < tmpSpawnListSize; ++i) - { - bool requiresurface = reader.ReadBool(); - tmpRequireSurface.Add(requiresurface); - } - goto case 19; + var requiresurface = reader.ReadBool(); + tmpRequireSurface.Add(requiresurface); } + goto case 19; + } case 19: + { + ConfigFile = reader.ReadString(); + m_OnHold = reader.ReadBool(); + m_HoldSequence = reader.ReadBool(); + + if (version < 32) { - m_ConfigFile = reader.ReadString(); - m_OnHold = reader.ReadBool(); - m_HoldSequence = reader.ReadBool(); - - if (version < 32) - { - // // Delete First & Last Modified By - // // Delete First & Last Modified By - reader.ReadString(); - reader.ReadString(); - } - - // deserialize the keyword tag list - int tagcount = reader.ReadInt(); - m_KeywordTagList = new List(tagcount); - for (int i = 0; i < tagcount; i++) - { - BaseXmlSpawner.KeywordTag tag = new BaseXmlSpawner.KeywordTag(null, this); - tag.Deserialize(reader); - } - goto case 18; + // // Delete First & Last Modified By + // // Delete First & Last Modified By + _ = reader.ReadString(); + _ = reader.ReadString(); } + + // deserialize the keyword tag list + var tagcount = reader.ReadInt(); + m_KeywordTagList = new List(tagcount); + for (var i = 0; i < tagcount; i++) + { + var tag = new BaseXmlSpawner.KeywordTag(null, this); + tag.Deserialize(reader); + } + goto case 18; + } case 18: - { - m_AllowGhostTriggering = reader.ReadBool(); - goto case 17; - } + { + AllowGhostTrig = reader.ReadBool(); + goto case 17; + } case 17: - { - goto case 16; - } + { + goto case 16; + } case 16: - { - hasnewobjectinfo = true; - m_SequentialSpawning = reader.ReadInt(); - TimeSpan seqdelay = reader.ReadTimeSpan(); - m_SeqEnd = Core.Now + seqdelay; + { + hasnewobjectinfo = true; + SequentialSpawn = reader.ReadInt(); + var seqdelay = reader.ReadTimeSpan(); + m_SeqEnd = Core.Now + seqdelay; - tmpSubGroup = new List(tmpSpawnListSize); - tmpSequentialResetTime = new List(tmpSpawnListSize); - tmpSequentialResetTo = new List(tmpSpawnListSize); - tmpKillsNeeded = new List(tmpSpawnListSize); - for (int i = 0; i < tmpSpawnListSize; ++i) - { - int subgroup = reader.ReadInt(); - double resettime = reader.ReadDouble(); - int resetto = reader.ReadInt(); - int killsneeded = reader.ReadInt(); - tmpSubGroup.Add(subgroup); - tmpSequentialResetTime.Add(resettime); - tmpSequentialResetTo.Add(resetto); - tmpKillsNeeded.Add(killsneeded); - } - m_RegionName = reader.ReadString(); - goto case 15; + tmpSubGroup = new List(tmpSpawnListSize); + tmpSequentialResetTime = new List(tmpSpawnListSize); + tmpSequentialResetTo = new List(tmpSpawnListSize); + tmpKillsNeeded = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) + { + var subgroup = reader.ReadInt(); + var resettime = reader.ReadDouble(); + var resetto = reader.ReadInt(); + var killsneeded = reader.ReadInt(); + tmpSubGroup.Add(subgroup); + tmpSequentialResetTime.Add(resettime); + tmpSequentialResetTo.Add(resetto); + tmpKillsNeeded.Add(killsneeded); } + m_RegionName = reader.ReadString(); + goto case 15; + } case 15: - { - m_ExternalTriggering = reader.ReadBool(); - m_ExternalTrigger = reader.ReadBool(); - goto case 14; - } + { + ExternalTriggering = reader.ReadBool(); + ExtTrigState = reader.ReadBool(); + goto case 14; + } case 14: - { - m_NoItemTriggerName = reader.ReadString(); - goto case 13; - } + { + m_NoItemTriggerName = reader.ReadString(); + goto case 13; + } case 13: - { - m_GumpState = reader.ReadString(); - goto case 12; - } + { + GumpState = reader.ReadString(); + goto case 12; + } case 12: + { + var todtype = reader.ReadInt(); + switch (todtype) { - int todtype = reader.ReadInt(); - switch (todtype) + case (int)TODModeType.Gametime: { - case (int)TODModeType.Gametime: - { - m_TODMode = TODModeType.Gametime; - break; - } - case (int)TODModeType.Realtime: - { - m_TODMode = TODModeType.Realtime; - break; - } + TODMode = TODModeType.Gametime; + break; + } + case (int)TODModeType.Realtime: + { + TODMode = TODModeType.Realtime; + break; } - goto case 11; } + goto case 11; + } case 11: - { - m_KillReset = reader.ReadInt(); - m_skipped = reader.ReadBool(); - m_spawncheck = reader.ReadInt(); - goto case 10; - } + { + KillReset = reader.ReadInt(); + m_skipped = reader.ReadBool(); + m_spawncheck = reader.ReadInt(); + goto case 10; + } case 10: - { - m_SetPropertyItem = reader.ReadEntity(); - goto case 9; - } + { + SetItem = reader.ReadEntity(); + goto case 9; + } case 9: - { - m_TriggerProbability = reader.ReadDouble(); - goto case 8; - } + { + TriggerProbability = reader.ReadDouble(); + goto case 8; + } case 8: - { - m_MobPropertyName = reader.ReadString(); - m_MobTriggerName = reader.ReadString(); - m_PlayerPropertyName = reader.ReadString(); - goto case 7; - } + { + MobTriggerProp = reader.ReadString(); + MobTriggerName = reader.ReadString(); + PlayerTriggerProp = reader.ReadString(); + goto case 7; + } case 7: - { - m_SpeechTrigger = reader.ReadString(); - goto case 6; - } + { + SpeechTrigger = reader.ReadString(); + goto case 6; + } case 6: - { - m_ItemTriggerName = reader.ReadString(); - goto case 5; - } + { + m_ItemTriggerName = reader.ReadString(); + goto case 5; + } case 5: - { - m_ProximityTriggerMessage = reader.ReadString(); - m_ObjectPropertyItem = reader.ReadEntity(); - m_ObjectPropertyName = reader.ReadString(); - m_killcount = reader.ReadInt(); - goto case 4; - } + { + ProximityMsg = reader.ReadString(); + m_ObjectPropertyItem = reader.ReadEntity(); + m_ObjectPropertyName = reader.ReadString(); + m_killcount = reader.ReadInt(); + goto case 4; + } case 4: + { + haveproximityrange = true; + m_ProximityRange = reader.ReadInt(); + ProximitySound = reader.ReadInt(); + m_proximityActivated = reader.ReadBool(); + m_durActivated = reader.ReadBool(); + m_refractActivated = reader.ReadBool(); + StackAmount = reader.ReadInt(); + TODStart = reader.ReadTimeSpan(); + TODEnd = reader.ReadTimeSpan(); + RefractMin = reader.ReadTimeSpan(); + RefractMax = reader.ReadTimeSpan(); + if (m_refractActivated) { - haveproximityrange = true; - m_ProximityRange = reader.ReadInt(); - m_ProximityTriggerSound = reader.ReadInt(); - m_proximityActivated = reader.ReadBool(); - m_durActivated = reader.ReadBool(); - m_refractActivated = reader.ReadBool(); - m_StackAmount = reader.ReadInt(); - m_TODStart = reader.ReadTimeSpan(); - m_TODEnd = reader.ReadTimeSpan(); - m_MinRefractory = reader.ReadTimeSpan(); - m_MaxRefractory = reader.ReadTimeSpan(); - if (m_refractActivated) - { - TimeSpan delay = reader.ReadTimeSpan(); - DoTimer3(delay); - } - if (m_durActivated) - { - TimeSpan delay = reader.ReadTimeSpan(); - DoTimer2(delay); - } - goto case 3; + var delay = reader.ReadTimeSpan(); + DoTimer3(delay); } + if (m_durActivated) + { + var delay = reader.ReadTimeSpan(); + DoTimer2(delay); + } + goto case 3; + } case 3: - { - m_ShowContainerStatic = reader.ReadEntity() ; - goto case 2; - } + { + m_ShowContainerStatic = reader.ReadEntity(); + goto case 2; + } case 2: - { - m_Duration = reader.ReadTimeSpan(); - goto case 1; - } + { + m_Duration = reader.ReadTimeSpan(); + goto case 1; + } case 1: - { - m_UniqueId = reader.ReadString(); - m_HomeRangeIsRelative = reader.ReadBool(); - goto case 0; - } + { + UniqueId = reader.ReadString(); + HomeRangeIsRelative = reader.ReadBool(); + goto case 0; + } case 0: + { + m_Name = reader.ReadString(); + // backward compatibility with old name storage + if (!string.IsNullOrEmpty(m_Name)) { - m_Name = reader.ReadString(); - // backward compatibility with old name storage - if (!string.IsNullOrEmpty(m_Name)) - { - Name = m_Name; - } - - m_X = reader.ReadInt(); - m_Y = reader.ReadInt(); - m_Width = reader.ReadInt(); - m_Height = reader.ReadInt(); - //we HAVE to check if the area is even or if coordinates point to the original spawner, otherwise it's custom area! - if (m_Width == m_Height && m_Width % 2 == 0 && m_X + m_Width / 2 == X && m_Y + m_Height / 2 == Y) - { - m_SpawnRange = m_Width / 2; - } - else - { - m_SpawnRange = -1; - } - - if (!haveproximityrange) - { - m_ProximityRange = -1; - } - m_WayPoint = reader.ReadEntity(); - m_Group = reader.ReadBool(); - m_MinDelay = reader.ReadTimeSpan(); - m_MaxDelay = reader.ReadTimeSpan(); - m_Count = reader.ReadInt(); - m_Team = reader.ReadInt(); - m_HomeRange = reader.ReadInt(); - m_Running = reader.ReadBool(); - - if (m_Running) - { - TimeSpan delay = reader.ReadTimeSpan(); - DoTimer(delay); - } - - // Read in the size of the spawn object list - int SpawnListSize = reader.ReadInt(); - m_SpawnObjects = new List(SpawnListSize); - for (int i = 0; i < SpawnListSize; ++i) - { - string TypeName = reader.ReadString(); - int TypeMaxCount = reader.ReadInt(); - - SpawnObject TheSpawnObject = new SpawnObject(TypeName, TypeMaxCount); - - m_SpawnObjects.Add(TheSpawnObject); - - string typeName = BaseXmlSpawner.ParseObjectType(TypeName); - - if (typeName == null || AssemblyHandler.FindTypeByName(typeName) == null && - !BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && typeName.IndexOf('{') == -1 && !typeName.StartsWith("*") && !typeName.StartsWith("#")) - { - if (m_WarnTimer == null) - { - m_WarnTimer = new WarnTimer2(); - } - - m_WarnTimer.Add(Location, Map, TypeName); - - status_str = $"invalid type: {typeName}"; - } - - // Read in the number of spawns already - int SpawnedCount = reader.ReadInt(); - - TheSpawnObject.SpawnedObjects = new List(SpawnedCount); - - for (int x = 0; x < SpawnedCount; ++x) - { - int serial = reader.ReadInt(); - if (serial < -1) - { - // minusone is reserved for unknown types by default - // minustwo on is used for referencing keyword tags - int tagserial = -1 * (serial + 2); - // get the tag with that serial and add it - BaseXmlSpawner.KeywordTag t = BaseXmlSpawner.GetFromTagList(this, tagserial); - if (t != null) - { - TheSpawnObject.SpawnedObjects.Add(t); - } - } - else - { - IEntity e = World.FindEntity((Serial)(uint)serial); - - if (e != null) - { - TheSpawnObject.SpawnedObjects.Add(e); - } - } - } - } - // now have to reintegrate the later version spawnobject information into the earlier version desered objects - if (hasnewobjectinfo && tmpSpawnListSize == SpawnListSize) - { - for (int i = 0; i < SpawnListSize; ++i) - { - SpawnObject so = m_SpawnObjects[i]; - - so.SubGroup = tmpSubGroup[i]; - so.SequentialResetTime = tmpSequentialResetTime[i]; - so.SequentialResetTo = tmpSequentialResetTo[i]; - so.KillsNeeded = tmpKillsNeeded[i]; - if (version > 19) - { - so.RequireSurface = tmpRequireSurface[i]; - } - - bool restrictkills = false; - bool clearadvance = true; - double mind = -1; - double maxd = -1; - DateTime nextspawn = DateTime.MinValue; - if (version > 23) - { - restrictkills = tmpRestrictKillsToSubgroup[i]; - clearadvance = tmpClearOnAdvance[i]; - mind = tmpMinDelay[i]; - maxd = tmpMaxDelay[i]; - nextspawn = tmpNextSpawn[i]; - } - so.RestrictKillsToSubgroup = restrictkills; - so.ClearOnAdvance = clearadvance; - so.MinDelay = mind; - so.MaxDelay = maxd; - so.NextSpawn = nextspawn; - - bool disablespawn = false; - if (version > 26) - { - disablespawn = tmpDisableSpawn[i]; - } - so.Disabled = disablespawn; - - int packrange = -1; - if (version > 27) - { - packrange = tmpPackRange[i]; - } - so.PackRange = packrange; - - int spawnsper = 1; - if (version > 28) - { - spawnsper = tmpSpawnsPer[i]; - } - so.SpawnsPerTick = spawnsper; - - } - } - - break; + Name = m_Name; } + + m_X = reader.ReadInt(); + m_Y = reader.ReadInt(); + m_Width = reader.ReadInt(); + m_Height = reader.ReadInt(); + //we HAVE to check if the area is even or if coordinates point to the original spawner, otherwise it's custom area! + if (m_Width == m_Height && m_Width % 2 == 0 && m_X + m_Width / 2 == X && m_Y + m_Height / 2 == Y) + { + m_SpawnRange = m_Width / 2; + } + else + { + m_SpawnRange = -1; + } + + if (!haveproximityrange) + { + m_ProximityRange = -1; + } + WayPoint = reader.ReadEntity(); + m_Group = reader.ReadBool(); + m_MinDelay = reader.ReadTimeSpan(); + m_MaxDelay = reader.ReadTimeSpan(); + m_Count = reader.ReadInt(); + m_Team = reader.ReadInt(); + m_HomeRange = reader.ReadInt(); + m_Running = reader.ReadBool(); + + if (m_Running) + { + var delay = reader.ReadTimeSpan(); + DoTimer(delay); + } + + // Read in the size of the spawn object list + var SpawnListSize = reader.ReadInt(); + m_SpawnObjects = new List(SpawnListSize); + for (var i = 0; i < SpawnListSize; ++i) + { + var TypeName = reader.ReadString(); + var TypeMaxCount = reader.ReadInt(); + + var TheSpawnObject = new SpawnObject(TypeName, TypeMaxCount); + + m_SpawnObjects.Add(TheSpawnObject); + + var typeName = BaseXmlSpawner.ParseObjectType(TypeName); + + if (typeName == null || AssemblyHandler.FindTypeByName(typeName) == null && + !BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && typeName.IndexOf('{') == -1 && !typeName.StartsWith("*") && !typeName.StartsWith("#")) + { + m_WarnTimer ??= new WarnTimer2(); + + m_WarnTimer.Add(Location, Map, TypeName); + + status_str = $"invalid type: {typeName}"; + } + + // Read in the number of spawns already + var SpawnedCount = reader.ReadInt(); + + TheSpawnObject.SpawnedObjects = new List(SpawnedCount); + + for (var x = 0; x < SpawnedCount; ++x) + { + var serial = reader.ReadInt(); + if (serial < -1) + { + // minusone is reserved for unknown types by default + // minustwo on is used for referencing keyword tags + var tagserial = -1 * (serial + 2); + // get the tag with that serial and add it + var t = BaseXmlSpawner.GetFromTagList(this, tagserial); + if (t != null) + { + TheSpawnObject.SpawnedObjects.Add(t); + } + } + else + { + var e = World.FindEntity((Serial)(uint)serial); + + if (e != null) + { + TheSpawnObject.SpawnedObjects.Add(e); + } + } + } + } + // now have to reintegrate the later version spawnobject information into the earlier version desered objects + if (hasnewobjectinfo && tmpSpawnListSize == SpawnListSize) + { + for (var i = 0; i < SpawnListSize; ++i) + { + var so = m_SpawnObjects[i]; + + so.SubGroup = tmpSubGroup[i]; + so.SequentialResetTime = tmpSequentialResetTime[i]; + so.SequentialResetTo = tmpSequentialResetTo[i]; + so.KillsNeeded = tmpKillsNeeded[i]; + if (version > 19) + { + so.RequireSurface = tmpRequireSurface[i]; + } + + var restrictkills = false; + var clearadvance = true; + double mind = -1; + double maxd = -1; + var nextspawn = DateTime.MinValue; + if (version > 23) + { + restrictkills = tmpRestrictKillsToSubgroup[i]; + clearadvance = tmpClearOnAdvance[i]; + mind = tmpMinDelay[i]; + maxd = tmpMaxDelay[i]; + nextspawn = tmpNextSpawn[i]; + } + so.RestrictKillsToSubgroup = restrictkills; + so.ClearOnAdvance = clearadvance; + so.MinDelay = mind; + so.MaxDelay = maxd; + so.NextSpawn = nextspawn; + + var disablespawn = false; + if (version > 26) + { + disablespawn = tmpDisableSpawn[i]; + } + so.Disabled = disablespawn; + + var packrange = -1; + if (version > 27) + { + packrange = tmpPackRange[i]; + } + so.PackRange = packrange; + + var spawnsper = 1; + if (version > 28) + { + spawnsper = tmpSpawnsPer[i]; + } + so.SpawnsPerTick = spawnsper; + + } + } + + break; + } } if (m_RegionName != null) { - Timer.DelayCall(delegate { if (!Deleted && m_RegionName != null) + _ = Timer.DelayCall(delegate + { + if (!Deleted && m_RegionName != null) { RegionName = m_RegionName; } @@ -12405,16 +12064,16 @@ public class XmlSpawner : Item, ISpawner internal string GetSerializedObjectList() { - System.Text.StringBuilder sb = new System.Text.StringBuilder(); + var sb = new System.Text.StringBuilder(); - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { if (sb.Length > 0) { - sb.Append(':'); // ':' Separates multiple object types + _ = sb.Append(':'); // ':' Separates multiple object types } - sb.AppendFormat("{0}={1}", so.TypeName, so.ActualMaxCount); // '=' separates object name from maximum amount + _ = sb.AppendFormat("{0}={1}", so.TypeName, so.ActualMaxCount); // '=' separates object name from maximum amount } return sb.ToString(); @@ -12422,16 +12081,16 @@ public class XmlSpawner : Item, ISpawner internal string GetSerializedObjectList2() { - System.Text.StringBuilder sb = new System.Text.StringBuilder(); + var sb = new System.Text.StringBuilder(); - foreach (SpawnObject so in m_SpawnObjects) + foreach (var so in m_SpawnObjects) { if (sb.Length > 0) { - sb.Append(":OBJ="); // Separates multiple object types + _ = sb.Append(":OBJ="); // Separates multiple object types } - sb.AppendFormat("{0}:MX={1}:SB={2}:RT={3}:TO={4}:KL={5}:RK={6}:CA={7}:DN={8}:DX={9}:SP={10}:PR={11}", + _ = sb.AppendFormat("{0}:MX={1}:SB={2}:RT={3}:TO={4}:KL={5}:RK={6}:CA={7}:DN={8}:DX={9}:SP={10}:PR={11}", so.TypeName, so.ActualMaxCount, so.SubGroup, so.SequentialResetTime, so.SequentialResetTo, so.KillsNeeded, so.RestrictKillsToSubgroup ? 1 : 0, so.ClearOnAdvance ? 1 : 0, so.MinDelay, so.MaxDelay, so.SpawnsPerTick, so.PackRange); } @@ -12441,7 +12100,6 @@ public class XmlSpawner : Item, ISpawner public class SpawnObject { - private int m_MaxCount; // temporary variable used to calculate weighted spawn probabilities public bool Available; @@ -12466,15 +12124,11 @@ public class XmlSpawner : Item, ISpawner return 0; } - return m_MaxCount; + return ActualMaxCount; } - set => m_MaxCount = value; - } - public int ActualMaxCount - { - get => m_MaxCount; - set => m_MaxCount = value; + set => ActualMaxCount = value; } + public int ActualMaxCount { get; set; } public int SubGroup { get; set; } public int SpawnsPerTick { get; set; } = 1; public int SequentialResetTo { get; set; } @@ -12493,13 +12147,13 @@ public class XmlSpawner : Item, ISpawner if (from != null && spawner != null) { - bool found = false; + var found = false; // go through the current spawner objects and see if this is a new entry if (spawner.m_SpawnObjects != null) { - for (int i = 0; i < spawner.m_SpawnObjects.Count; i++) + for (var i = 0; i < spawner.m_SpawnObjects.Count; i++) { - SpawnObject s = spawner.m_SpawnObjects[i]; + var s = spawner.m_SpawnObjects[i]; if (s != null && s.TypeName == name) { found = true; @@ -12562,12 +12216,12 @@ public class XmlSpawner : Item, ISpawner // find the parm separator in the string // then look for the termination at the ':' or end of string // and return the stuff between - string[] arg = BaseXmlSpawner.SplitString(str, separator); + var arg = BaseXmlSpawner.SplitString(str, separator); //should be 2 args if (arg.Length > 1) { // look for the end of parm terminator (could also be eol) - string[] parm = arg[1].Split(':'); + var parm = arg[1].Split(':'); if (parm.Length > 0) { return parm[0]; @@ -12579,18 +12233,18 @@ public class XmlSpawner : Item, ISpawner internal static SpawnObject[] LoadSpawnObjectsFromString(string ObjectList) { // Clear the spawn object list - List NewSpawnObjects = new List(); + var NewSpawnObjects = new List(); if (!string.IsNullOrEmpty(ObjectList)) { // Split the string based on the object separator first ':' - string[] SpawnObjectList = ObjectList.Split(':'); + var SpawnObjectList = ObjectList.Split(':'); // Parse each item in the array - foreach (string s in SpawnObjectList) + foreach (var s in SpawnObjectList) { // Split the single spawn object item by the max count '=' - string[] SpawnObjectDetails = s.Split('='); + var SpawnObjectDetails = s.Split('='); // Should be two entries if (SpawnObjectDetails.Length == 2) @@ -12603,7 +12257,7 @@ public class XmlSpawner : Item, ISpawner // Make sure the max count part has a valid length if (SpawnObjectDetails[1].Length > 0) { - int maxCount = 1; + var maxCount = 1; try { @@ -12614,7 +12268,7 @@ public class XmlSpawner : Item, ISpawner } // Create the spawn object and store it in the array list - SpawnObject so = new SpawnObject(SpawnObjectDetails[0], maxCount); + var so = new SpawnObject(SpawnObjectDetails[0], maxCount); NewSpawnObjects.Add(so); } } @@ -12628,20 +12282,20 @@ public class XmlSpawner : Item, ISpawner internal static SpawnObject[] LoadSpawnObjectsFromString2(string ObjectList) { // Clear the spawn object list - List NewSpawnObjects = new List(); + var NewSpawnObjects = new List(); // spawn object definitions will take the form typestring:MX=int:SB=int:RT=double:TO=int:KL=int // or typestring:MX=int:SB=int:RT=double:TO=int:KL=int:OBJ=typestring... if (!string.IsNullOrEmpty(ObjectList)) { - string[] SpawnObjectList = BaseXmlSpawner.SplitString(ObjectList, ":OBJ="); + var SpawnObjectList = BaseXmlSpawner.SplitString(ObjectList, ":OBJ="); // Parse each item in the array - foreach (string s in SpawnObjectList) + foreach (var s in SpawnObjectList) { // at this point each spawn string will take the form typestring:MX=int:SB=int:RT=double:TO=int:KL=int // Split the single spawn object item by the max count to get the typename and the remaining parms - string[] SpawnObjectDetails = BaseXmlSpawner.SplitString(s, ":MX="); + var SpawnObjectDetails = BaseXmlSpawner.SplitString(s, ":MX="); // Should be two entries if (SpawnObjectDetails.Length == 2) @@ -12656,15 +12310,15 @@ public class XmlSpawner : Item, ISpawner { // now parse out the parms // MaxCount - string parmstr = GetParm(s, ":MX="); - int maxCount = 1; + var parmstr = GetParm(s, ":MX="); + var maxCount = 1; try { maxCount = int.Parse(parmstr); } catch { } // SubGroup parmstr = GetParm(s, ":SB="); - int subGroup = 0; + var subGroup = 0; try { subGroup = int.Parse(parmstr); } catch { } @@ -12676,19 +12330,19 @@ public class XmlSpawner : Item, ISpawner // SequentialSpawnResetTo parmstr = GetParm(s, ":TO="); - int resetTo = 0; + var resetTo = 0; try { resetTo = int.Parse(parmstr); } catch { } // KillsNeeded parmstr = GetParm(s, ":KL="); - int killsNeeded = 0; + var killsNeeded = 0; try { killsNeeded = int.Parse(parmstr); } catch { } // RestrictKills parmstr = GetParm(s, ":RK="); - bool restrictKills = false; + var restrictKills = false; if (parmstr != null) { try { restrictKills = int.Parse(parmstr) == 1; } @@ -12697,7 +12351,7 @@ public class XmlSpawner : Item, ISpawner // ClearOnAdvance parmstr = GetParm(s, ":CA="); - bool clearAdvance = true; + var clearAdvance = true; // if kills needed is zero, then set CA to false by default. This maintains consistency with the // previous default behavior for old spawn specs that havent specified CA if (killsNeeded == 0) @@ -12725,18 +12379,18 @@ public class XmlSpawner : Item, ISpawner // SpawnsPerTick parmstr = GetParm(s, ":SP="); - int spawnsPer = 1; + var spawnsPer = 1; try { spawnsPer = int.Parse(parmstr); } catch { } // PackRange parmstr = GetParm(s, ":PR="); - int packRange = -1; + var packRange = -1; try { packRange = int.Parse(parmstr); } catch { } // Create the spawn object and store it in the array list - SpawnObject so = new SpawnObject(SpawnObjectDetails[0], maxCount, subGroup, resetTime, resetTo, killsNeeded, + var so = new SpawnObject(SpawnObjectDetails[0], maxCount, subGroup, resetTime, resetTo, killsNeeded, restrictKills, clearAdvance, minD, maxD, spawnsPer, packRange); NewSpawnObjects.Add(so); From 2c334d1a1f3e1ed6703188154a5adeddc9e12e83 Mon Sep 17 00:00:00 2001 From: Voxpire Date: Wed, 11 Oct 2023 11:59:58 +0100 Subject: [PATCH 5/8] XmlSpawner housekeeping. --- .../Engines/XMLSpawner/XmlSpawner.cs | 434 +++++++++--------- 1 file changed, 214 insertions(+), 220 deletions(-) diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs index 42f9bdd71..5405013cc 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs @@ -53,28 +53,40 @@ public class XmlSpawner : Item, ISpawner } public const string Version = "5.0"; // RUADUCK's EDIT + public const byte MaxLoops = 10; //maximum number of recursive calls from spawner to itself. this is to prevent stack overflow from xmlspawner scripting + private const int ShowBoundsItemId = 14089; // 14089 Fire Column // 3555 Campfire // 8708 Skull Pole + private const string SpawnDataSetName = "Spawns"; private const string SpawnTablePointName = "Points"; + private const int SpawnFitSize = 16; // Normal wall/door height for a mobile is 20 to walk through + private static int BaseItemId = 0x1F1C; // Purple Magic Crystal private static int ShowItemId = 0x3E57; // ships mast + private static int defaultTriggerSound = 0x1F4; // click and sparkle sound by default (0x1F4) , click sound (0x3A4) - public static string XmlSpawnDir = "XmlSpawner"; // default directory for saving/loading .xml files with [xmlload [xmlsave + + public static string XmlSpawnDir { get; set; } = "XmlSpawner"; // default directory for saving/loading .xml files with [xmlload [xmlsave + private const int MaxSmartSectorListSize = 1024; // maximum sector list size for use in smart spawning. This gives a 512x512 tile range. private static string defwaypointname; // default waypoint name will get assigned in Initialize + private const string XmlTableName = "Properties"; private const string XmlDataSetName = "XmlSpawner"; - public static AccessLevel DiskAccessLevel = AccessLevel.Administrator; // minimum access level required by commands that can access the disk such as XmlLoad, XmlSave, and the Save function of XmlEdit + + public static AccessLevel DiskAccessLevel { get; set; } = AccessLevel.Administrator; // minimum access level required by commands that can access the disk such as XmlLoad, XmlSave, and the Save function of XmlEdit + #if RESTRICTConstructible - public static AccessLevel ConstructibleAccessLevel = AccessLevel.GameMaster; // only allow spawning of objects that have Constructible access restrictions at this level or lower. Must define RESTRICTConstructible to enable this. + public static AccessLevel ConstructibleAccessLevel { get; set; } = AccessLevel.GameMaster; // only allow spawning of objects that have Constructible access restrictions at this level or lower. Must define RESTRICTConstructible to enable this. #endif + private static int MaxMoveCheck = 10; // limit number of players that can be checked for triggering in a single OnMovement tick // specifies the level at which smartspawning will be triggered. Players with AccessLevel above this will not trigger smartspawning unless unhidden. - public static AccessLevel SmartSpawnAccessLevel = AccessLevel.Player; + public static AccessLevel SmartSpawnAccessLevel { get; set; } = AccessLevel.Player; // define the default values used in making spawners private static TimeSpan defMinDelay = TimeSpan.FromMinutes(5); @@ -85,6 +97,7 @@ public class XmlSpawner : Item, ISpawner private static TimeSpan defTODEnd = TimeSpan.FromMinutes(0); private static TimeSpan defDuration = TimeSpan.FromMinutes(0); private static readonly TimeSpan defDespawnTime = TimeSpan.FromHours(0); + private static bool defIsGroup; private static int defTeam; private static int defProximityTriggerSound = defaultTriggerSound; @@ -105,7 +118,7 @@ public class XmlSpawner : Item, ISpawner // hash table for optimizing HoldSmartSpawning method invocation private static Dictionary holdSmartSpawningHash; - public static int seccount; + public static int seccount { get; set; } // sector hashtable for each map private static readonly Dictionary>[] GlobalSectorTable = new Dictionary>[6]; @@ -122,7 +135,7 @@ public class XmlSpawner : Item, ISpawner private TimeSpan m_MaxDelay; // added a duration parameter for time-limited spawns private TimeSpan m_Duration; - public List m_SpawnObjects = new(); // List of objects to spawn + private List m_SpawnObjects = new(); // List of objects to spawn private DateTime m_End; private DateTime m_RefractEnd; private DateTime m_DurEnd; @@ -143,8 +156,10 @@ public class XmlSpawner : Item, ISpawner private string m_NoItemTriggerName; private Item m_ObjectPropertyItem; private string m_ObjectPropertyName; - public string status_str; - public int m_killcount; + + public string status_str { get; set; } + + private int m_killcount; // added proximity range sensor private int m_ProximityRange; private bool m_speechTriggerActivated; @@ -159,21 +174,24 @@ public class XmlSpawner : Item, ISpawner private bool m_HoldSequence; private List m_MovementList; private MovementTimer m_MovementTimer; - internal List m_KeywordTagList = new(); - public List RecentSpawnerSearchList = null; - public List RecentItemSearchList = null; - public List RecentMobileSearchList = null; + private List m_KeywordTagList = new(); + + public List RecentSpawnerSearchList { get; set; } + public List RecentItemSearchList { get; set; } + public List RecentMobileSearchList { get; set; } + private SkillName m_skill_that_triggered; + private Map currentmap; - public bool m_IsInactivated; + private bool m_IsInactivated; private bool m_SmartSpawning; private SectorTimer m_SectorTimer; private List m_ShowBoundsItems = new(); - public List PropertyInfoList = null; // used to optimize property info lookup used by set and get property methods. + public List PropertyInfoList { get; set; } // used to optimize property info lookup used by set and get property methods. private Dictionary> spawnPositionWayTable; // used to optimize #waypoint lookup @@ -193,7 +211,7 @@ public class XmlSpawner : Item, ISpawner // private double m_SkillTriggerMax; // private int m_SkillTriggerSuccess; - public bool DebugThis { get; set; } = false; + public bool DebugThis { get; set; } public int MovingPlayerCount { get; set; } @@ -237,13 +255,13 @@ public class XmlSpawner : Item, ISpawner } } - public TimeSpan RealTOD => Core.Now.TimeOfDay; + public static TimeSpan RealTOD => Core.Now.TimeOfDay; - public int RealDay => Core.Now.Day; + public static int RealDay => Core.Now.Day; - public int RealMonth => Core.Now.Month; + public static int RealMonth => Core.Now.Month; - public DayOfWeek RealDayOfWeek => Core.Now.DayOfWeek; + public static DayOfWeek RealDayOfWeek => Core.Now.DayOfWeek; public MoonPhase MoonPhase => Clock.GetMoonPhase(Map, Location.X, Location.Y); @@ -267,7 +285,7 @@ public class XmlSpawner : Item, ISpawner public bool SingleSector { get; private set; } - public bool InActivationRange(Sector s1, Sector s2) + public static bool InActivationRange(Sector s1, Sector s2) { // check to see if the sectors are within +- 2 of one another if (s1 == null || s2 == null) @@ -388,14 +406,9 @@ public class XmlSpawner : Item, ISpawner // is this container held? if (Parent != null) { - if (RootParent is Mobile) + if (RootParent is IPoint3D e) { - loc = ((Mobile)RootParent).Location; - } - else - if (RootParent is Item) - { - loc = ((Item)RootParent).Location; + loc = new Point3D(e); } } @@ -496,7 +509,7 @@ public class XmlSpawner : Item, ISpawner SingleSector = false; } - _TraceStart(2); + TraceStart(2); // go through the sectorlist and see if any of the sectors are active foreach (var s in sectorList) @@ -512,16 +525,16 @@ public class XmlSpawner : Item, ISpawner return true; } } - _TraceEnd(2); + TraceEnd(2); } seccount++; } - _TraceEnd(2); + TraceEnd(2); return false; } } - public int SecCount => seccount; + public static int SecCount => seccount; public bool IsInactivated { @@ -792,27 +805,6 @@ public class XmlSpawner : Item, ISpawner } } - public bool isEmpty() - { - if (m_SpawnObjects == null) - { - return true; - } - - foreach (var so in m_SpawnObjects) - { - if (so.SpawnedObjects != null && so.SpawnedObjects.Count > 0) - { - if (so.SpawnedObjects[0] is Mobile) - { - return false; - } - } - - } - return true; - } - public int TotalSpawnObjectCount { get @@ -1534,7 +1526,29 @@ public class XmlSpawner : Item, ISpawner } [CommandProperty(AccessLevel.GameMaster)] - public bool IsEmpty => isEmpty(); + public bool IsEmpty + { + get + { + if (m_SpawnObjects == null) + { + return true; + } + + foreach (var so in m_SpawnObjects) + { + if (so.SpawnedObjects != null && so.SpawnedObjects.Count > 0) + { + if (so.SpawnedObjects[0] is Mobile) + { + return false; + } + } + + } + return true; + } + } public Guid Guid { get; } public bool UnlinkOnTaming => true; @@ -1738,7 +1752,8 @@ public class XmlSpawner : Item, ISpawner } } - private static bool IgnoreLocationChange; + private bool IgnoreLocationChange; + public override void OnLocationChange(Point3D oldLocation) { if (IgnoreLocationChange) @@ -1774,7 +1789,7 @@ public class XmlSpawner : Item, ISpawner } } - public bool SomeOneHasGumpOpen + public static bool SomeOneHasGumpOpen { get { @@ -2291,7 +2306,7 @@ public class XmlSpawner : Item, ISpawner } // try loading the new spawn specifications first - var Spawns = new SpawnObject[0]; + var Spawns = Array.Empty(); var havenew = true; valid_entry = true; try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); } @@ -2343,49 +2358,55 @@ public class XmlSpawner : Item, ISpawner #if TRACE - private readonly string setname1 = _traceName[1] = "XmlFind"; - private readonly string setname2 = _traceName[2] = "HasSector"; - private readonly string setname4 = _traceName[4] = "AttachSpeech"; - private readonly string setname5 = _traceName[5] = "HasHold"; - private readonly string setname8 = _traceName[8] = "OnTick"; - private readonly string setname9 = _traceName[9] = "Defrag"; - private readonly string setname10 = _traceName[10] = "Respawn"; - private readonly string setname11 = _traceName[11] = "SetProp"; - private readonly string setname12 = _traceName[12] = "AttachMovement"; - private readonly string setname13 = _traceName[13] = "ActiveSector"; - private readonly string setname15 = _traceName[15] = "DistroTick"; - private readonly string setname16 = _traceName[16] = "GetScaledFaction"; - private readonly string setname17 = _traceName[17] = "FactionOnKill"; - private readonly string setname18 = _traceName[18] = "CheckAcquire"; + public static readonly string[] _traceName = + { + string.Empty, + "XmlFind", + "HasSector", + string.Empty, + "AttachSpeech", + "HasHold", + string.Empty, + string.Empty, + "OnTick", + "Defrag", + "Respawn", + "SetProp", + "AttachMovement", + "ActiveSector", + string.Empty, + "DistroTick", + "GetScaledFaction", + "FactionOnKill", + "CheckAcquire", + string.Empty, + }; + + private static readonly DateTime[] _traceStart = new DateTime[_traceName.Length]; + private static readonly TimeSpan[] _traceTotal = new TimeSpan[_traceName.Length]; + private static readonly int[] _traceCount = new int[_traceName.Length]; - private const int MaxTraces = 20; - private static readonly DateTime[] _traceStart = new DateTime[MaxTraces]; - public static TimeSpan[] _traceTotal = new TimeSpan[MaxTraces]; - public static string[] _traceName = new string[MaxTraces]; - public static int[] _traceCount = new int[MaxTraces]; private static DateTime _traceStartTime = Core.Now; private static double _startProcessTime; - public static void _TraceStart(int index) + public static void TraceStart(int index) { - if (index < MaxTraces) + if (index < _traceStart.Length) { _traceStart[index] = Core.Now; - //_traceStart[index] = Process.GetCurrentProcess().UserProcessorTime; } } - public static void _TraceEnd(int index) + public static void TraceEnd(int index) { - if (index < MaxTraces) + if (index < _traceStart.Length) { - _traceTotal[index] = _traceTotal[index].Add(Core.Now - _traceStart[index]); - //XmlSpawner._traceTotal[index] = XmlSpawner._traceTotal[index].Add(Process.GetCurrentProcess().UserProcessorTime - _traceStart[index]); + _traceTotal[index] += Core.Now - _traceStart[index]; _traceCount[index]++; } } #else - public static void _TraceStart(int index) { } - public static void _TraceEnd(int index) { } + public static void TraceStart(int index) { } + public static void TraceEnd(int index) { } #endif private bool ValidPlayerTrig(Mobile m) @@ -2515,15 +2536,14 @@ public class XmlSpawner : Item, ISpawner } } } + public bool HandlesOnSkillUse => m_Running && SkillTrigger != null && SkillTrigger.Length > 0; // this is the handler for skill use public void OnSkillUse(Mobile m, Skill skill, bool success) { - if (m_Running && m_ProximityRange >= 0 && ValidPlayerTrig(m) && CanSpawn && !m_refractActivated && TODInRange) { - if (!Utility.InRange(m.Location, Location, m_ProximityRange)) { return; @@ -2544,6 +2564,7 @@ public class XmlSpawner : Item, ISpawner // } } } + public override bool HandlesOnSpeech => m_Running && !string.IsNullOrEmpty(SpeechTrigger); public override void OnSpeech(SpeechEventArgs e) @@ -2586,8 +2607,7 @@ public class XmlSpawner : Item, ISpawner foreach (var moveinfo in m_MovementList) { - var mtrig = moveinfo.trigMob; - if (mtrig == m) + if (moveinfo.trigMob == m) { add = false; break; @@ -2597,7 +2617,6 @@ public class XmlSpawner : Item, ISpawner // wasnt on the list so add it if (add) { - // is the list at max throttling length? if (m_MovementList.Count > MaxMoveCheck) { @@ -2639,9 +2658,11 @@ public class XmlSpawner : Item, ISpawner { var count = 0; var maxspeed = 0; + foreach (var moveinfo in m_Spawner.m_MovementList) { var m = moveinfo.trigMob; + if (m == null) { continue; @@ -2649,12 +2670,14 @@ public class XmlSpawner : Item, ISpawner // additional throttling in here by limiting number of mobs that can be checked in a single ontick count++; + if (count > MaxMoveCheck) { break; } var speed = (int)GetDistance(m.Location, moveinfo.trigLocation); + if (speed > maxspeed) { maxspeed = speed; @@ -2667,6 +2690,7 @@ public class XmlSpawner : Item, ISpawner m_Spawner.FastestPlayerSpeed = maxspeed; } + m_Spawner.m_MovementList.Clear(); } } @@ -2699,6 +2723,7 @@ public class XmlSpawner : Item, ISpawner m_speechTriggerActivated = false; } } + base.OnMovement(m, oldLocation); } @@ -3169,17 +3194,14 @@ public class XmlSpawner : Item, ISpawner [Description("Lists the keyword taglist for a spawner")] public static void ShowTagList_OnCommand(CommandEventArgs e) { - e.Mobile.Target = new TagListTarget(e); + e.Mobile.Target = new TagListTarget(); } private class TagListTarget : Target { - private readonly CommandEventArgs m_e; - - public TagListTarget(CommandEventArgs e) + public TagListTarget() : base(30, false, TargetFlags.None) { - m_e = e; } protected override void OnTarget(Mobile from, object targeted) @@ -3225,14 +3247,9 @@ public class XmlSpawner : Item, ISpawner } } - if (targeted is Mobile mobile) + if (targeted is ISpawnable s) { - spawner = mobile.Spawner as XmlSpawner; - } - else - if (targeted is Item item) - { - spawner = item.Spawner as XmlSpawner; + spawner = s.Spawner as XmlSpawner; } if (spawner == null) @@ -3740,27 +3757,27 @@ public class XmlSpawner : Item, ISpawner [Description("Makes all XmlSpawner objects movable and also changes the item id to a blue ships mast for easy identification.")] public static void ShowSpawnPoints_OnCommand(CommandEventArgs e) { - var ToShow = new List(); + var ToShow = new List(); foreach (var item in World.Items.Values) { - if (item is XmlSpawner) + if (item is XmlSpawner xmlItem) { //turned off visibility. Admins will still see masts but players will not. - item.Visible = false; // set the spawn item visibility - item.Movable = false; // Make the spawn item movable - item.Hue = 88; // Bright blue colour so its easy to spot - item.ItemID = ShowItemId; // Ship Mast (Very tall, easy to see if beneath other objects) + xmlItem.Visible = false; // set the spawn item visibility + xmlItem.Movable = false; // Make the spawn item movable + xmlItem.Hue = 88; // Bright blue colour so its easy to spot + xmlItem.ItemID = ShowItemId; // Ship Mast (Very tall, easy to see if beneath other objects) // find container-held spawners to be marked with an external static - if (item.Parent != null && item.RootParent is Container) + if (xmlItem.Parent != null && xmlItem.RootParent is Container) { - ToShow.Add(item); + ToShow.Add(xmlItem); } } } // place the statics - foreach (XmlSpawner xml_item in ToShow) + foreach (var xml_item in ToShow) { // does the spawner already have a static attached to it? could happen if two showall commands are issued in a row. // if so then dont add another @@ -3788,7 +3805,7 @@ public class XmlSpawner : Item, ISpawner [Description("Makes all XmlSpawner objects invisible and unmovable returns the object id to the default.")] public static void HideSpawnPoints_OnCommand(CommandEventArgs e) { - var ToDelete = new List(); + var ToDelete = new List(); foreach (var item in World.Items.Values) { if (item is XmlSpawner xmlItem) @@ -3806,7 +3823,7 @@ public class XmlSpawner : Item, ISpawner } } } - foreach (XmlSpawner xml_item in ToDelete) + foreach (var xml_item in ToDelete) { if (xml_item.m_ShowContainerStatic != null && !xml_item.m_ShowContainerStatic.Deleted) { @@ -3959,18 +3976,28 @@ public class XmlSpawner : Item, ISpawner maxpercent = 100 * maxcount / totalcount; } - e.Mobile.SendMessage($"Smartspawning access level is {SmartSpawnAccessLevel}"); - e.Mobile.SendMessage($"--------------------------------"); - e.Mobile.SendMessage($"{count} XmlSpawners"); - e.Mobile.SendMessage($"{smartcount} are configured for SmartSpawning\n"); - e.Mobile.SendMessage($"{inactivecount} are currently inactivated"); - e.Mobile.SendMessage($"{totalSectorsMonitored} sectors being monitored\n"); - e.Mobile.SendMessage($"Maximum possible spawn count is {totalcount}"); - e.Mobile.SendMessage($"Maximum possible spawn reduction is {maxcount}\n"); - e.Mobile.SendMessage($"Current spawn count is {currentcount}"); - e.Mobile.SendMessage($"Current spawn reduction is {savings}"); - e.Mobile.SendMessage($"Maximum possible savings is {maxpercent}%"); - e.Mobile.SendMessage($"Current savings is {percent}%"); + var notice = new Gumps.NoticeGump + ( + 1060637, + 30720, + $"Smartspawning access level is {SmartSpawnAccessLevel}\n" + + $"--------------------------------\n" + + $"{count:N0} XmlSpawners\n" + + $"{smartcount:N0} are configured for SmartSpawning\n" + + $"{inactivecount:N0} are currently inactivated\n" + + $"{totalSectorsMonitored:N0} sectors being monitored\n" + + $"Maximum possible spawn count is {totalcount:N0}\n" + + $"Maximum possible spawn reduction is {maxcount:N0}\n" + + $"Current spawn count is {currentcount:N0}\n" + + $"Current spawn reduction is {savings:N0}\n" + + $"Maximum possible savings is {maxpercent}%\n" + + $"Current savings is {percent}%\n", + 0xFFC000, + 420, + 280 + ); + + e.Mobile.SendGump(notice); } [Usage("OptimalSmartSpawning [max spawn/homerange diff]")] @@ -4051,7 +4078,7 @@ public class XmlSpawner : Item, ISpawner // if it has basevendors on it or invalid types, then skip it if (typestr == null || type != null && (type == typeof(BaseVendor) || type.IsSubclassOf(typeof(BaseVendor))) || - type == null && !BaseXmlSpawner.IsTypeOrItemKeyword(typestr) && typestr.IndexOf('{') == -1 && !typestr.StartsWith("*") && !typestr.StartsWith("#")) + type == null && !BaseXmlSpawner.IsTypeOrItemKeyword(typestr) && !typestr.Contains('{') && !typestr.StartsWith("*") && !typestr.StartsWith("#")) { skipit = true; break; @@ -4067,8 +4094,8 @@ public class XmlSpawner : Item, ISpawner } } - e.Mobile.SendMessage($"Configured {count} XmlSpawners for SmartSpawning using maxdiff of {maxdiff}"); - e.Mobile.SendMessage($"Estimated item/mob reduction is {maxcount}"); + e.Mobile.SendMessage($"Configured {count:N0} XmlSpawners for SmartSpawning using maxdiff of {maxdiff:N0}"); + e.Mobile.SendMessage($"Estimated item/mob reduction is {maxcount:N0}"); } [Usage("XmlSpawnerWipe [SpawnerPrefixFilter]")] @@ -4433,7 +4460,7 @@ public class XmlSpawner : Item, ISpawner linenumber++; // is this the new format? string[] args; - if (line.IndexOf('|') >= 0) + if (line.Contains('|')) { args = line.Trim().Split('|'); newformat = true; @@ -5100,13 +5127,13 @@ public class XmlSpawner : Item, ISpawner { try { - ImportSpawner(spawner, e.Mobile); + ImportSpawner(spawner); successes++; } catch (Exception ex) { e.Mobile.SendMessage(33, $"{ex.Message} {spawner.InnerText}"); failures++; } } } - e.Mobile.SendMessage($"{successes} spawners loaded successfully from {filePath}, {failures} failures."); + e.Mobile.SendMessage($"{successes:N0} spawners loaded successfully from {filePath}, {failures:N0} failures."); } else { @@ -5129,7 +5156,7 @@ public class XmlSpawner : Item, ISpawner return node.InnerText; } - private static void ImportSpawner(XmlElement node, Mobile from) + private static void ImportSpawner(XmlElement node) { var count = int.Parse(GetText(node["count"], "1")); var homeRange = int.Parse(GetText(node["homerange"], "4")); @@ -5238,7 +5265,7 @@ public class XmlSpawner : Item, ISpawner } catch (Exception ex) { e.Mobile.SendMessage(33, $"{ex.Message} {spawner.InnerText}"); failures++; } } - e.Mobile.SendMessage($"{successes} megaspawners loaded successfully from {filePath}, {failures} failures."); + e.Mobile.SendMessage($"{successes:N0} megaspawners loaded successfully from {filePath}, {failures:N0} failures."); } else { @@ -5985,7 +6012,7 @@ public class XmlSpawner : Item, ISpawner try { SpawnIsRunning = bool.Parse((string)dr["IsRunning"]); } catch { questionable_spawner = true; } // try loading the new spawn specifications first - var Spawns = new SpawnObject[0]; + var Spawns = Array.Empty(); var havenew = true; try { Spawns = SpawnObject.LoadSpawnObjectsFromString2((string)dr["Objects2"]); } catch { havenew = false; } @@ -6137,7 +6164,7 @@ public class XmlSpawner : Item, ISpawner else { // disable the X_Y adjustments in OnLocationChange - IgnoreLocationChange = true; + TheSpawn.IgnoreLocationChange = true; TheSpawn.MoveToWorld(new Point3D(SpawnCentreX, SpawnCentreY, NewZ), SpawnMap); } @@ -7038,7 +7065,7 @@ public class XmlSpawner : Item, ISpawner } catch { } // Indicate how many spawners were written - from?.SendMessage($"{TotalCount} spawner(s) were saved to file {dirname} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}]."); + from?.SendMessage($"{TotalCount} spawner(s) were saved to file {dirname} [Trammel={TrammelCount:N0}, Felucca={FeluccaCount:N0}, Ilshenar={IlshenarCount:N0}, Malas={MalasCount:N0}, Tokuno={TokunoCount:N0}, Other={OtherCount:N0}]."); return true; } @@ -7097,11 +7124,11 @@ public class XmlSpawner : Item, ISpawner if (WipeAll) { - e.Mobile.SendMessage($"Removed {Count} XmlSpawner objects from the world."); + e.Mobile.SendMessage($"Removed {Count:N0} XmlSpawner objects from the world."); } else { - e.Mobile.SendMessage($"Removed {Count} XmlSpawner objects from {e.Mobile.Map}."); + e.Mobile.SendMessage($"Removed {Count:N0} XmlSpawner objects from {e.Mobile.Map}."); } } else @@ -7182,11 +7209,11 @@ public class XmlSpawner : Item, ISpawner if (RespawnAll) { - e.Mobile.SendMessage($"Respawned {Count} XmlSpawner objects from the world."); + e.Mobile.SendMessage($"Respawned {Count:N0} XmlSpawner objects from the world."); } else { - e.Mobile.SendMessage($"Respawned {Count} XmlSpawner objects from {e.Mobile.Map}."); + e.Mobile.SendMessage($"Respawned {Count:N0} XmlSpawner objects from {e.Mobile.Map}."); } } else @@ -7266,7 +7293,7 @@ public class XmlSpawner : Item, ISpawner Console.WriteLine("Adjusted Process Time = {0:####.####} secs", processtime / 1000); Console.WriteLine("Processor Time = {0} ({1:p3} avg sys load)", currentprocess.UserProcessorTime, sysload); - for (var i = 0; i < MaxTraces; i++) + for (var i = 0; i < _traceCount.Length; i++) { if (_traceCount[i] > 0) { @@ -7284,10 +7311,9 @@ public class XmlSpawner : Item, ISpawner public static void XmlResetTrace_OnCommand(CommandEventArgs e) { - if (e.Arguments.Length >= 0) { - for (var i = 0; i < MaxTraces; i++) + for (var i = 0; i < _traceCount.Length; i++) { _traceCount[i] = 0; _traceTotal[i] = TimeSpan.Zero; @@ -7311,7 +7337,7 @@ public class XmlSpawner : Item, ISpawner SpawnRange = defSpawnRange; InitSpawn(0, 0, m_Width, m_Height, string.Empty, 0, defMinDelay, defMaxDelay, defDuration, - defProximityRange, defProximityTriggerSound, defAmount, defTeam, defHomeRange, defRelativeHome, new SpawnObject[0], defMinRefractory, defMaxRefractory, + defProximityRange, defProximityTriggerSound, defAmount, defTeam, defHomeRange, defRelativeHome, Array.Empty(), defMinRefractory, defMaxRefractory, defTODStart, defTODEnd, null, null, null, null, null, null, null, null, null, defTriggerProbability, null, defIsGroup, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null); } @@ -8245,7 +8271,7 @@ public class XmlSpawner : Item, ISpawner public void OnTick() { - _TraceStart(8); + TraceStart(8); // start up the timer again for the next Ontick DoTimer(); @@ -8301,7 +8327,7 @@ public class XmlSpawner : Item, ISpawner // dont process spawn ticks while inactivated if smart spawning is enabled if (SmartSpawning && IsInactivated) { - _TraceEnd(8); + TraceEnd(8); return; } @@ -8440,8 +8466,8 @@ public class XmlSpawner : Item, ISpawner ResetAllFlags(); } - _TraceEnd(8); + TraceEnd(8); } public bool ClearSpawnedThisTick @@ -8756,8 +8782,9 @@ public class XmlSpawner : Item, ISpawner if (ckeyvalueargs.Length > 1) { // dont spawn if it fails the test - if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out status_str)) + if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out var status)) { + status_str = status; return false; } } @@ -9091,13 +9118,10 @@ public class XmlSpawner : Item, ISpawner public void Start() { - if (m_Running == false) + if (!m_Running && m_SpawnObjects?.Count > 0) { - if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) - { - m_Running = true; - DoTimer(); - } + m_Running = true; + DoTimer(); } } @@ -9467,7 +9491,6 @@ public class XmlSpawner : Item, ISpawner // is this a SERIAL specification? if (wayargs[0] == "SERIAL") { - // look it up by serial if (wayargs.Length > 1) { @@ -9591,6 +9614,7 @@ public class XmlSpawner : Item, ISpawner { Console.WriteLine("CanFit mob {0}, map={1}", mob, map); } + if (map == null || map == Map.Internal) { return false; @@ -9612,10 +9636,12 @@ public class XmlSpawner : Item, ISpawner canswim = mob.CanSwim; cantwalk = mob.CantWalk; } + if (DebugThis) { Console.WriteLine("fitting mob {0} checkmob={1} swim={2} walk={3}", mob, checkmob, canswim, cantwalk); } + var lt = map.Tiles.GetLandTile(x, y); bool surface; @@ -9960,7 +9986,7 @@ public class XmlSpawner : Item, ISpawner } } - public Point2D GetRandomRegionPoint(Region r) + public static Point2D GetRandomRegionPoint(Region r) { var count = r.Area.Length; @@ -10594,67 +10620,35 @@ public class XmlSpawner : Item, ISpawner return m_SpawnObjects[index].MaxCount; } - private void DeleteFromList(List list) + private static void DeleteFromList(List list) where T : IEntity { if (list == null) { return; } - foreach (var o in list) + var i = list.Count; + + while (--i >= 0) { - if (o is Item item) + if (i < list.Count) { - item.Delete(); - } - else if (o is Mobile mobile) - { - mobile.Delete(); + try + { + list[i]?.Delete(); + } + catch + { } } } + + list.Clear(); } - private void DeleteFromList(List listi, List listm) + private static void DeleteFromList(List listi, List listm) { - if (listi != null) - { - var i = listi.Count; - - while (--i >= 0) - { - if (i < listi.Count && listi[i] != null) - { - try - { - listi[i].Delete(); - } - catch - { } - } - } - - listi.Clear(); - } - - if (listm != null) - { - var i = listm.Count; - - while (--i >= 0) - { - if (i < listm.Count && listm[i] != null) - { - try - { - listm[i].Delete(); - } - catch - { } - } - } - - listm.Clear(); - } + DeleteFromList(listi); + DeleteFromList(listm); } public void RemoveSpawnObjects() @@ -10667,16 +10661,16 @@ public class XmlSpawner : Item, ISpawner Defrag(false); ClearTags(true); - var deletelist = new List(); + var deletelist = new List(); foreach (var so in m_SpawnObjects) { for (var i = 0; i < so.SpawnedObjects.Count; ++i) { var o = so.SpawnedObjects[i]; - if (o is Item or Mobile) + if (o is IEntity e) { - deletelist.Add(o); + deletelist.Add(e); } } } @@ -10696,15 +10690,15 @@ public class XmlSpawner : Item, ISpawner Defrag(false); - var deletelist = new List(); + var deletelist = new List(); for (var i = 0; i < so.SpawnedObjects.Count; ++i) { var o = so.SpawnedObjects[i]; - if (o is Item or Mobile) + if (o is IEntity e) { - deletelist.Add(o); + deletelist.Add(e); } } @@ -10724,7 +10718,7 @@ public class XmlSpawner : Item, ISpawner Defrag(false); ClearTags(true); - var deletelist = new List(); + var deletelist = new List(); foreach (var so in m_SpawnObjects) { if (so.SubGroup != subgroup || !so.ClearOnAdvance) @@ -10736,9 +10730,9 @@ public class XmlSpawner : Item, ISpawner { var o = so.SpawnedObjects[i]; - if (o is Item or Mobile) + if (o is IEntity e) { - deletelist.Add(o); + deletelist.Add(e); } } } @@ -10760,7 +10754,7 @@ public class XmlSpawner : Item, ISpawner Defrag(false); ClearTags(true); - var deletelist = new List(); + var deletelist = new List(); foreach (var so in m_SpawnObjects) { for (var i = 0; i < so.SpawnedObjects.Count; ++i) @@ -10773,9 +10767,9 @@ public class XmlSpawner : Item, ISpawner continue; } - if (o is Item or Mobile) + if (o is IEntity e) { - deletelist.Add(o); + deletelist.Add(e); } } } @@ -10798,7 +10792,7 @@ public class XmlSpawner : Item, ISpawner // Find the spawn object and increment its count by one foreach (var so in m_SpawnObjects) { - if (so.TypeName.ToUpper() == SpawnObjectName.ToUpper()) + if (InsensitiveStringHelpers.Equals(so.TypeName, SpawnObjectName)) { // Add one to the total count m_Count++; @@ -10871,7 +10865,7 @@ public class XmlSpawner : Item, ISpawner } - var deletelist = new List(); + var deletelist = new List(); // Remove any spawns over the count while (TheSpawn.SpawnedObjects != null && TheSpawn.SpawnedObjects.Count > 0 && TheSpawn.SpawnedObjects.Count > TheSpawn.MaxCount) @@ -10879,9 +10873,9 @@ public class XmlSpawner : Item, ISpawner var o = TheSpawn.SpawnedObjects[0]; // Delete the object - if (o is Item or Mobile) + if (o is IEntity e) { - deletelist.Add(o); + deletelist.Add(e); } _ = TheSpawn.SpawnedObjects.Remove(o); @@ -11948,7 +11942,7 @@ public class XmlSpawner : Item, ISpawner var typeName = BaseXmlSpawner.ParseObjectType(TypeName); if (typeName == null || AssemblyHandler.FindTypeByName(typeName) == null && - !BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && typeName.IndexOf('{') == -1 && !typeName.StartsWith("*") && !typeName.StartsWith("#")) + !BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && !typeName.Contains('{') && !typeName.StartsWith("*") && !typeName.StartsWith("#")) { m_WarnTimer ??= new WarnTimer2(); From a4040ae7bf9d5f4ff1e8a78240e5ac038213b318 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:11:02 -0800 Subject: [PATCH 6/8] Paring down more --- .../Engines/XMLSpawner/BaseXmlSpawner.cs | 14 +- .../Engines/XMLSpawner/XmlSpawner.cs | 2858 +++++++---------- .../Engines/XMLSpawner/XmlSpawnerGumps.cs | 10 +- .../Engines/XMLSpawner/XmlUtils/WriteMulti.cs | 461 --- .../Engines/XMLSpawner/XmlUtils/XmlFind.cs | 2366 -------------- 5 files changed, 1212 insertions(+), 4497 deletions(-) delete mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs delete mode 100644 Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs diff --git a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs index 5b652409e..2ca8fa0ae 100644 --- a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs @@ -1382,8 +1382,7 @@ public class BaseXmlSpawner // count nearby players if (refobject is Item item) { - IPooledEnumerable ie = item.GetMobilesInRange(range); - foreach (Mobile p in ie) + foreach (Mobile p in item.GetMobilesInRange(range)) { if (p.Player && p.AccessLevel == AccessLevel.Player) { @@ -1394,8 +1393,7 @@ public class BaseXmlSpawner } else if (refobject is Mobile mobile) { - IPooledEnumerable ie = mobile.GetMobilesInRange(range); - foreach (Mobile p in ie) + foreach (Mobile p in mobile.GetMobilesInRange(range)) { if (p.Player && p.AccessLevel == AccessLevel.Player) { @@ -1666,27 +1664,23 @@ public class BaseXmlSpawner } else if (o is Item item) { - IPooledEnumerable ie = item.GetMobilesInRange(range); - foreach (Mobile p in ie) + foreach (Mobile p in item.GetMobilesInRange(range)) { if (p.Player && p.AccessLevel == AccessLevel.Player) { nplayers++; } } - ie.Free(); } else if (o is Mobile mobile) { - IPooledEnumerable ie = mobile.GetMobilesInRange(range); - foreach (Mobile p in ie) + foreach (Mobile p in mobile.GetMobilesInRange(range)) { if (p.Player && p.AccessLevel == AccessLevel.Player) { nplayers++; } } - ie.Free(); } return nplayers.ToString(); diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs index 5405013cc..735ad243c 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs @@ -224,16 +224,13 @@ public class XmlSpawner : Item, ISpawner var count = 0; if (ProximityRange >= 0) { - IPooledEnumerable eable = GetMobilesInRange(ProximityRange); - foreach (Mobile m in eable) + foreach (Mobile m in GetMobilesInRange(ProximityRange)) { - if (m != null && m.Player) + if (m?.Player == true) { count++; } } - - eable.Free(); } return count; } @@ -281,7 +278,7 @@ public class XmlSpawner : Item, ISpawner } } - private readonly bool sectorIsActive = false; + private const bool SectorIsActive = false; public bool SingleSector { get; private set; } @@ -308,48 +305,50 @@ public class XmlSpawner : Item, ISpawner { var o = so.SpawnedObjects[x]; - if (o is BaseCreature creature) + if (o is not BaseCreature creature) { - // if the mob is damaged or outside of smartspawning detection range then return true - if (creature.Hits < creature.HitsMax || creature.Mana < creature.ManaMax || creature.Stam < creature.StamMax || creature.Map != Map) - { - return true; - } + continue; + } - // if the spawn moves into a sector that is not activatable from a sector on the sector list then dont smartspawn - if (creature.Map != null && creature.Map != Map.Internal) - { - var bsec = creature.Map.GetSector(creature.Location); + // if the mob is damaged or outside of smartspawning detection range then return true + if (creature.Hits < creature.HitsMax || creature.Mana < creature.ManaMax || creature.Stam < creature.StamMax || creature.Map != Map) + { + return true; + } - if (SingleSector) + // if the spawn moves into a sector that is not activatable from a sector on the sector list then dont smartspawn + if (creature.Map != null && creature.Map != Map.Internal) + { + var bsec = creature.Map.GetSector(creature.Location); + + if (SingleSector) + { + // is it in activatable range of the sector the spawner is in + if (!InActivationRange(bsec, ssec)) { - // is it in activatable range of the sector the spawner is in - if (!InActivationRange(bsec, ssec)) - { - return true; - } + return true; } - else - { - var outofsec = true; + } + else + { + var outofsec = true; - if (sectorList != null) + if (sectorList != null) + { + foreach (var s in sectorList) { - foreach (var s in sectorList) + // is the creatures sector within activation range of any of the sectors in the list + if (InActivationRange(bsec, s)) { - // is the creatures sector within activation range of any of the sectors in the list - if (InActivationRange(bsec, s)) - { - outofsec = false; - break; - } + outofsec = false; + break; } } + } - if (outofsec) - { - return true; - } + if (outofsec) + { + return true; } } } @@ -394,7 +393,7 @@ public class XmlSpawner : Item, ISpawner // is this a single sector spawner? if (SingleSector) { - return sectorIsActive; + return SectorIsActive; } // if there is no sector list made for this spawner then create one. @@ -575,7 +574,7 @@ public class XmlSpawner : Item, ISpawner foreach (var sot in m_KeywordTagList) { // check for any keyword tag with the holdspawn flag - if (sot != null && !sot.Deleted && (sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSpawn) != 0) + if (sot?.Deleted == false && (sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSpawn) != 0) { return true; } @@ -649,7 +648,7 @@ public class XmlSpawner : Item, ISpawner get => m_SpawnObjects.ToArray(); set { - if (value != null && value.Length > 0) + if (value?.Length > 0) { foreach (var so in value) @@ -709,7 +708,7 @@ public class XmlSpawner : Item, ISpawner foreach (var sot in m_KeywordTagList) { // check for any keyword tag with the holdsequence flag - if (sot != null && !sot.Deleted && (sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSequence) != 0) + if (sot?.Deleted == false && (sot.Flags & BaseXmlSpawner.KeywordFlags.HoldSequence) != 0) { return true; } @@ -873,7 +872,7 @@ public class XmlSpawner : Item, ISpawner foreach (var region in Region.Regions) { - if (string.Compare(region.Name, m_RegionName, true) == 0) + if (region.Name.InsensitiveEquals(m_RegionName)) { m_Region = region; m_RegionName = region.Name; @@ -1032,7 +1031,7 @@ public class XmlSpawner : Item, ISpawner [CommandProperty(AccessLevel.GameMaster)] public bool ShowBounds { - get => m_ShowBoundsItems != null && m_ShowBoundsItems.Count > 0; + get => m_ShowBoundsItems?.Count > 0; set { if (value && ShowBounds == false) @@ -1207,7 +1206,7 @@ public class XmlSpawner : Item, ISpawner { get { - if (SetItem == null || SetItem.Deleted) + if (SetItem?.Deleted != false) { return null; } @@ -1514,7 +1513,7 @@ public class XmlSpawner : Item, ISpawner // if any spawner is smartspawning, then the smartspawning system is enabled SmartSpawningSystemEnabled = true; // check to see if the global sector timer is running - if (m_GlobalSectorTimer == null || !m_GlobalSectorTimer.Running) + if (m_GlobalSectorTimer?.Running != true) { // start the global smartspawning timer DoGlobalSectorTimer(TimeSpan.FromSeconds(1)); @@ -1537,7 +1536,7 @@ public class XmlSpawner : Item, ISpawner foreach (var so in m_SpawnObjects) { - if (so.SpawnedObjects != null && so.SpawnedObjects.Count > 0) + if (so.SpawnedObjects?.Count > 0) { if (so.SpawnedObjects[0] is Mobile) { @@ -1640,7 +1639,7 @@ public class XmlSpawner : Item, ISpawner public override void OnDoubleClick(Mobile from) { - if (from == null || from.Deleted || from.AccessLevel < AccessLevel.GameMaster || SpawnerGump != null && SomeOneHasGumpOpen) + if (from?.Deleted != false || from.AccessLevel < AccessLevel.GameMaster || SpawnerGump != null && SomeOneHasGumpOpen) { return; } @@ -1713,7 +1712,7 @@ public class XmlSpawner : Item, ISpawner for (var i = 0; i < nlist_items && i < m_SpawnObjects.Count; ++i) { var typename = m_SpawnObjects[i].TypeName; - if (typename != null && typename.Length > 20) + if (typename?.Length > 20) { typename = typename[..20]; } @@ -1746,7 +1745,7 @@ public class XmlSpawner : Item, ISpawner m_RefractoryTimer?.Stop(); // if statics were added for marking container held spawners, delete them - if (m_ShowContainerStatic != null && !m_ShowContainerStatic.Deleted) + if (m_ShowContainerStatic?.Deleted == false) { m_ShowContainerStatic.Delete(); } @@ -1831,20 +1830,10 @@ public class XmlSpawner : Item, ISpawner } } - private static bool IsConstructible(ConstructorInfo ctor) - { - return ctor.IsDefined(typeof(ConstructibleAttribute), false); - } + private static bool IsConstructible(ConstructorInfo ctor) => ctor.IsDefined(typeof(ConstructibleAttribute), false); - public static int ConvertToInt(string value) - { - if (value.StartsWith("0x")) - { - return Convert.ToInt32(value.Substring(2), 16); - } - - return Convert.ToInt32(value); - } + public static int ConvertToInt(string value) => + value.StartsWith("0x") ? Convert.ToInt32(value.Substring(2), 16) : Convert.ToInt32(value); public static void ExecuteAction(object attachedto, Mobile trigmob, string action) { @@ -1868,7 +1857,6 @@ public class XmlSpawner : Item, ISpawner var substitutedtypeName = BaseXmlSpawner.ApplySubstitution(null, attachedto, action); var typeName = BaseXmlSpawner.ParseObjectType(substitutedtypeName); - string status_str; if (BaseXmlSpawner.IsTypeOrItemKeyword(typeName)) { _ = BaseXmlSpawner.SpawnTypeKeyword(attachedto, TheSpawn, typeName, substitutedtypeName, trigmob, map, out _); @@ -1882,11 +1870,6 @@ public class XmlSpawner : Item, ISpawner var arglist = BaseXmlSpawner.ParseString(substitutedtypeName, 3, "/"); var o = CreateObject(type, arglist[0]); - if (o == null) - { - status_str = $"invalid type specification: {arglist[0]}"; - } - else if (o is Mobile mobile) { if (mobile is BaseCreature creature) @@ -1897,12 +1880,11 @@ public class XmlSpawner : Item, ISpawner mobile.Location = loc; mobile.Map = map; - _ = BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, mobile, trigmob, attachedto, out status_str); + _ = BaseXmlSpawner.ApplyObjectStringProperties(null, substitutedtypeName, mobile, trigmob, attachedto, out _); } - else - if (o is Item item) + else if (o is Item item) { - BaseXmlSpawner.AddSpawnItem(null, attachedto, TheSpawn, item, loc, map, trigmob, false, substitutedtypeName, out status_str); + BaseXmlSpawner.AddSpawnItem(null, attachedto, TheSpawn, item, loc, map, trigmob, false, substitutedtypeName, out _); } } catch (Exception e) @@ -1995,7 +1977,7 @@ public class XmlSpawner : Item, ISpawner // Check that at least a single table was loaded if (ds.Tables.Count > 0) { - if (ds.Tables[XmlTableName] != null && ds.Tables[XmlTableName].Rows.Count > 0) + if (ds.Tables[XmlTableName]?.Rows.Count > 0) { foreach (DataRow dr in ds.Tables[XmlTableName].Rows) { @@ -2411,7 +2393,7 @@ public class XmlSpawner : Item, ISpawner private bool ValidPlayerTrig(Mobile m) { - if (m == null || m.Deleted) + if (m?.Deleted != false) { return false; } @@ -2509,13 +2491,13 @@ public class XmlSpawner : Item, ISpawner if (Utility.RandomDouble() < TriggerProbability) { // play a sound indicating the spawner has been triggered - if (ProximitySound > 0 && m != null && !m.Deleted) + if (ProximitySound > 0 && m?.Deleted == false) { m.PlaySound(ProximitySound); } // display the trigger message - if (!string.IsNullOrEmpty(ProximityMsg) && m != null && !m.Deleted) + if (!string.IsNullOrEmpty(ProximityMsg) && m?.Deleted == false) { m.PublicOverheadMessage(MessageType.Regular, 0x3B2, false, ProximityMsg); } @@ -2537,7 +2519,7 @@ public class XmlSpawner : Item, ISpawner } } - public bool HandlesOnSkillUse => m_Running && SkillTrigger != null && SkillTrigger.Length > 0; + public bool HandlesOnSkillUse => m_Running && SkillTrigger?.Length > 0; // this is the handler for skill use public void OnSkillUse(Mobile m, Skill skill, bool success) @@ -2598,7 +2580,7 @@ public class XmlSpawner : Item, ISpawner m_MovementList ??= new List(); // check to see if the movement timer is running - if (m_MovementTimer == null || !m_MovementTimer.Running) + if (m_MovementTimer?.Running != true) { DoMovementTimer(TimeSpan.FromSeconds(1)); } @@ -2644,15 +2626,12 @@ public class XmlSpawner : Item, ISpawner { private readonly XmlSpawner m_Spawner; - public MovementTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) - { - m_Spawner = spawner; - } + public MovementTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_Spawner = spawner; protected override void OnTick() { // check everyone on the movement list then clear the list - if (m_Spawner != null && !m_Spawner.Deleted) + if (m_Spawner?.Deleted == false) { if (m_Spawner.m_Running && !m_Spawner.m_proximityActivated && !m_Spawner.m_refractActivated && m_Spawner.TODInRange && m_Spawner.CanSpawn) { @@ -2732,92 +2711,92 @@ public class XmlSpawner : Item, ISpawner switch (argname) { case "XmlSpawnDir": - { - XmlSpawnDir = value; - break; - } - case "DiskAccessLevel": - { - DiskAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); - break; - } - case "SmartSpawnAccessLevel": - { - SmartSpawnAccessLevel = (AccessLevel)Enum.Parse(typeof(AccessLevel), value, true); - break; - } - case "defaultTriggerSound": - { - defaultTriggerSound = ConvertToInt(value); - defProximityTriggerSound = defaultTriggerSound; - break; - } - case "BaseItemId": - { - BaseItemId = ConvertToInt(value); - break; - } - case "ShowItemId": - { - ShowItemId = ConvertToInt(value); - break; - } - case "MaxMoveCheck": - { - MaxMoveCheck = ConvertToInt(value); - break; - } - case "defMinDelay": - { - defMinDelay = TimeSpan.FromMinutes(ConvertToInt(value)); - break; - } - case "defMaxDelay": - { - defMaxDelay = TimeSpan.FromMinutes(ConvertToInt(value)); - break; - } - case "defRelativeHome": - { - defRelativeHome = bool.Parse(value); - break; - } - case "defSpawnRange": - { - defSpawnRange = ConvertToInt(value); - break; - } - case "defHomeRange": - { - defHomeRange = ConvertToInt(value); - break; - } - case "BlockKeyword": - { - // parse the keyword list and remove them from the keyword hashtables - var keywordlist = value.Split(','); - - if (keywordlist.Length > 0) { - for (var i = 0; i < keywordlist.Length; i++) - { - BaseXmlSpawner.RemoveKeyword(keywordlist[i]); - } + XmlSpawnDir = value; + break; } + case "DiskAccessLevel": + { + DiskAccessLevel = Enum.Parse(value, true); + break; + } + case "SmartSpawnAccessLevel": + { + SmartSpawnAccessLevel = Enum.Parse(value, true); + break; + } + case "defaultTriggerSound": + { + defaultTriggerSound = ConvertToInt(value); + defProximityTriggerSound = defaultTriggerSound; + break; + } + case "BaseItemId": + { + BaseItemId = ConvertToInt(value); + break; + } + case "ShowItemId": + { + ShowItemId = ConvertToInt(value); + break; + } + case "MaxMoveCheck": + { + MaxMoveCheck = ConvertToInt(value); + break; + } + case "defMinDelay": + { + defMinDelay = TimeSpan.FromMinutes(ConvertToInt(value)); + break; + } + case "defMaxDelay": + { + defMaxDelay = TimeSpan.FromMinutes(ConvertToInt(value)); + break; + } + case "defRelativeHome": + { + defRelativeHome = bool.Parse(value); + break; + } + case "defSpawnRange": + { + defSpawnRange = ConvertToInt(value); + break; + } + case "defHomeRange": + { + defHomeRange = ConvertToInt(value); + break; + } + case "BlockKeyword": + { + // parse the keyword list and remove them from the keyword hashtables + var keywordlist = value.Split(','); - break; - } + if (keywordlist.Length > 0) + { + for (var i = 0; i < keywordlist.Length; i++) + { + BaseXmlSpawner.RemoveKeyword(keywordlist[i]); + } + } + + break; + } case "BlockCommand": case "ChangeCommand": - { - // delay processing of these settings until after all commands have been registered in their Initialize methods - _ = Timer.DelayCall(TimeSpan.Zero, DelayedAssignSettings, argname, value); - break; - } + { + // delay processing of these settings until after all commands have been registered in their Initialize methods + _ = Timer.DelayCall(TimeSpan.Zero, DelayedAssignSettings, argname, value); + break; + } default: - { - return false; - } + { + return false; + } } return true; @@ -2828,137 +2807,137 @@ public class XmlSpawner : Item, ISpawner switch (argname) { case "BlockCommand": - { - // delay processing of this until after all commands have been registered in their Initialize methods - // parse the command list and remove them from the command hashtables - // the syntax is "commandname, commandname, etc." - var keywordlist = value.Split(','); - - if (keywordlist.Length > 0) { - for (var i = 0; i < keywordlist.Length; i++) + // delay processing of this until after all commands have been registered in their Initialize methods + // parse the command list and remove them from the command hashtables + // the syntax is "commandname, commandname, etc." + var keywordlist = value.Split(','); + + if (keywordlist.Length > 0) { - var commandname = keywordlist[i].Trim().ToLower(); - try + for (var i = 0; i < keywordlist.Length; i++) { - _ = CommandSystem.Entries.Remove(commandname); - } - catch - { - Console.WriteLine("{0}: invalid command {1}", argname, commandname); - } - } - } - break; - } - case "ChangeCommand": - { - // delay processing of this until after all commands have been registered in their Initialize methods - // parse the command list and rehash them into the command hashtables - // the syntax is "oldname:newname[:accesslevel], oldname:newname[:accesslevel], etc." - var keywordlist = value.Split(','); - - if (keywordlist.Length > 0) - { - for (var i = 0; i < keywordlist.Length; i++) - { - var namelist = keywordlist[i].Split(':'); - if (namelist.Length > 1) - { - var oldname = namelist[0].Trim().ToLower(); - var newname = namelist[1].Trim(); - - if (newname.Length == 0) - { - newname = oldname; - } - - var access = AccessLevel.Player; - var validaccess = false; - if (namelist.Length > 2) - { - // get the new accesslevel - try - { - access = (AccessLevel)Enum.Parse(typeof(AccessLevel), namelist[2].Trim(), true); - validaccess = true; - } - catch - { - Console.WriteLine("{0}: invalid accesslevel {1} for {2}", argname, namelist[2], newname); - } - } - // find the command entry for the old name - CommandEntry e = null; + var commandname = keywordlist[i].Trim().ToLower(); try { - e = CommandSystem.Entries[oldname]; + _ = CommandSystem.Entries.Remove(commandname); } catch { - Console.WriteLine("{0}: invalid command {1}", argname, oldname); + Console.WriteLine("{0}: invalid command {1}", argname, commandname); } - if (e != null) + } + } + break; + } + case "ChangeCommand": + { + // delay processing of this until after all commands have been registered in their Initialize methods + // parse the command list and rehash them into the command hashtables + // the syntax is "oldname:newname[:accesslevel], oldname:newname[:accesslevel], etc." + var keywordlist = value.Split(','); + + if (keywordlist.Length > 0) + { + for (var i = 0; i < keywordlist.Length; i++) + { + var namelist = keywordlist[i].Split(':'); + if (namelist.Length > 1) { - if (!validaccess) + var oldname = namelist[0].Trim().ToLower(); + var newname = namelist[1].Trim(); + + if (newname.Length == 0) { - // use the old accesslevel - access = e.AccessLevel; + newname = oldname; } - // remove the old command entry - _ = CommandSystem.Entries.Remove(oldname); - // register the new command using the old handler - CommandSystem.Register(newname, access, e.Handler); - } - // also look in the targetcommands list and adjust name and accesslevel there - foreach (var b in TargetCommands.AllCommands) - { - if (b.Commands != null) + var access = AccessLevel.Player; + var validaccess = false; + if (namelist.Length > 2) { - for (var j = 0; j < b.Commands.Length; j++) + // get the new accesslevel + try { - var commandname = b.Commands[j]; - if (commandname.ToLower() == oldname) + access = (AccessLevel)Enum.Parse(typeof(AccessLevel), namelist[2].Trim(), true); + validaccess = true; + } + catch + { + Console.WriteLine("{0}: invalid accesslevel {1} for {2}", argname, namelist[2], newname); + } + } + // find the command entry for the old name + CommandEntry e = null; + try + { + e = CommandSystem.Entries[oldname]; + } + catch + { + Console.WriteLine("{0}: invalid command {1}", argname, oldname); + } + if (e != null) + { + if (!validaccess) + { + // use the old accesslevel + access = e.AccessLevel; + } + // remove the old command entry + _ = CommandSystem.Entries.Remove(oldname); + // register the new command using the old handler + CommandSystem.Register(newname, access, e.Handler); + } + + // also look in the targetcommands list and adjust name and accesslevel there + foreach (var b in TargetCommands.AllCommands) + { + if (b.Commands != null) + { + for (var j = 0; j < b.Commands.Length; j++) { - // modify the basecommand with the new name and access - b.Commands[j] = newname; - if (validaccess) + var commandname = b.Commands[j]; + if (commandname.ToLower() == oldname) { - b.AccessLevel = access; - } - - // re-register it in the implementors hashtable - var impls = BaseCommandImplementor.Implementors; - - for (var k = 0; k < impls.Count; ++k) - { - var impl = impls[k]; - - if ((b.Supports & impl.SupportRequirement) != 0) + // modify the basecommand with the new name and access + b.Commands[j] = newname; + if (validaccess) { - try - { - _ = impl.Commands.Remove(commandname); - } - catch (Exception ex) - { - Diagnostics.ExceptionLogging.LogException(ex); - } - impl.Register(b); + b.AccessLevel = access; } - } - break; + // re-register it in the implementors hashtable + var impls = BaseCommandImplementor.Implementors; + + for (var k = 0; k < impls.Count; ++k) + { + var impl = impls[k]; + + if ((b.Supports & impl.SupportRequirement) != 0) + { + try + { + _ = impl.Commands.Remove(commandname); + } + catch (Exception ex) + { + Diagnostics.ExceptionLogging.LogException(ex); + } + impl.Register(b); + } + } + + break; + } } } } } } } + break; } - break; - } } } @@ -3136,10 +3115,8 @@ public class XmlSpawner : Item, ISpawner { private readonly CommandEventArgs m_e; public GetValueTarget(CommandEventArgs e) - : base(30, false, TargetFlags.None) - { + : base(30, false, TargetFlags.None) => m_e = e; - } protected override void OnTarget(Mobile from, object targeted) { @@ -3208,12 +3185,12 @@ public class XmlSpawner : Item, ISpawner { if (targeted is XmlSpawner spawner) { - spawner.ShowTagList(spawner); + ShowTagList(spawner); } } } - public void ShowTagList(XmlSpawner spawner) + public static void ShowTagList(XmlSpawner spawner) { var count = 0; Console.WriteLine("{0} tags", spawner.m_KeywordTagList.Count); @@ -3229,10 +3206,8 @@ public class XmlSpawner : Item, ISpawner { private readonly CommandEventArgs m_e; public XmlHomeTarget(CommandEventArgs e) - : base(30, false, TargetFlags.None) - { + : base(30, false, TargetFlags.None) => m_e = e; - } protected override void OnTarget(Mobile from, object targeted) { @@ -3405,7 +3380,7 @@ public class XmlSpawner : Item, ISpawner public static void XmlLoadDefaults(string filePath, Mobile m) { - if (m == null || m.Deleted) + if (m?.Deleted != false) { return; } @@ -3518,19 +3493,13 @@ public class XmlSpawner : Item, ISpawner { Diagnostics.ExceptionLogging.LogException(e); } - switch (todmode) + + defTODMode = todmode switch { - case (int)TODModeType.Realtime: - { - defTODMode = TODModeType.Realtime; - break; - } - case (int)TODModeType.Gametime: - { - defTODMode = TODModeType.Gametime; - break; - } - } + (int)TODModeType.Realtime => TODModeType.Realtime, + (int)TODModeType.Gametime => TODModeType.Gametime, + _ => defTODMode + }; } [Usage("XmlDefaults [defaultpropertyname value]")] @@ -3538,7 +3507,7 @@ public class XmlSpawner : Item, ISpawner public static void XmlDefaults_OnCommand(CommandEventArgs e) { var m = e.Mobile; - if (m == null || m.Deleted) + if (m?.Deleted != false) { return; } @@ -3687,19 +3656,12 @@ public class XmlSpawner : Item, ISpawner try { var todmode = Convert.ToInt32(e.Arguments[1]); - switch (todmode) + defTODMode = todmode switch { - case (int)TODModeType.Gametime: - { - defTODMode = TODModeType.Gametime; - break; - } - case (int)TODModeType.Realtime: - { - defTODMode = TODModeType.Realtime; - break; - } - } + (int)TODModeType.Gametime => TODModeType.Gametime, + (int)TODModeType.Realtime => TODModeType.Realtime, + _ => defTODMode + }; m.SendMessage($"TODMode = {defTODMode}"); } catch { m.SendMessage($"invalid value : {e.Arguments[1]}"); } @@ -3817,7 +3779,7 @@ public class XmlSpawner : Item, ISpawner // get rid of the external static marker for container-held spawners // check anything that might have been tagged with a container static - if (xmlItem.m_ShowContainerStatic != null && !xmlItem.m_ShowContainerStatic.Deleted) + if (xmlItem.m_ShowContainerStatic?.Deleted == false) { ToDelete.Add(xmlItem); } @@ -3825,7 +3787,7 @@ public class XmlSpawner : Item, ISpawner } foreach (var xml_item in ToDelete) { - if (xml_item.m_ShowContainerStatic != null && !xml_item.m_ShowContainerStatic.Deleted) + if (xml_item.m_ShowContainerStatic?.Deleted == false) { xml_item.m_ShowContainerStatic.Delete(); } @@ -3851,23 +3813,23 @@ public class XmlSpawner : Item, ISpawner // Get the map Map NewMap; // Convert the xml map value to a real map object - if (string.Compare(MapName, Map.Trammel.Name, true) == 0) + if (MapName.InsensitiveEquals(Map.Trammel.Name)) { NewMap = Map.Trammel; } - else if (string.Compare(MapName, Map.Felucca.Name, true) == 0) + else if (MapName.InsensitiveEquals(Map.Felucca.Name)) { NewMap = Map.Felucca; } - else if (string.Compare(MapName, Map.Ilshenar.Name, true) == 0) + else if (MapName.InsensitiveEquals(Map.Ilshenar.Name)) { NewMap = Map.Ilshenar; } - else if (string.Compare(MapName, Map.Malas.Name, true) == 0) + else if (MapName.InsensitiveEquals(Map.Malas.Name)) { NewMap = Map.Malas; } - else if (string.Compare(MapName, Map.Tokuno.Name, true) == 0) + else if (MapName.InsensitiveEquals(Map.Tokuno.Name)) { NewMap = Map.Tokuno; } @@ -3913,7 +3875,7 @@ public class XmlSpawner : Item, ISpawner [Description("Returns the spawn reduction due to SmartSpawning.")] public static void SmartStat_OnCommand(CommandEventArgs e) { - if (e == null || e.Mobile == null) + if (e?.Mobile == null) { return; } @@ -4145,9 +4107,7 @@ public class XmlSpawner : Item, ISpawner XmlUnLoadFromStream(fs, filename, SpawnerPrefix, from, out processedmaps, out processedspawners); } - else - // check to see if it is a directory - if (Directory.Exists(filename)) + else if (Directory.Exists(filename)) // check to see if it is a directory { // if so then import all of the .xml files in the directory string[] files = null; @@ -4156,7 +4116,7 @@ public class XmlSpawner : Item, ISpawner files = Directory.GetFiles(filename, "*.xml"); } catch { } - if (files != null && files.Length > 0) + if (files?.Length > 0) { from?.SendMessage($"UnLoading {files.Length} .xml files from directory {filename}"); @@ -4174,7 +4134,7 @@ public class XmlSpawner : Item, ISpawner dirs = Directory.GetDirectories(filename); } catch { } - if (dirs != null && dirs.Length > 0) + if (dirs?.Length > 0) { foreach (var dir in dirs) { @@ -4216,8 +4176,8 @@ public class XmlSpawner : Item, ISpawner var spawners_deleted = 0; from?.SendMessage( - $"UnLoading {"XmlSpawner"} objects{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} from file {filename}." - ); + $"UnLoading {"XmlSpawner"} objects{(!string.IsNullOrEmpty(SpawnerPrefix) ? $" beginning with {SpawnerPrefix}" : string.Empty)} from file {filename}." + ); // Create the data set var ds = new DataSet(SpawnDataSetName); @@ -4246,7 +4206,7 @@ public class XmlSpawner : Item, ISpawner if (ds.Tables.Count > 0) { // Add each spawn point to the current map - if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + if (ds.Tables[SpawnTablePointName]?.Rows.Count > 0) { foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) { @@ -4281,27 +4241,27 @@ public class XmlSpawner : Item, ISpawner catch { } // Convert the xml map value to a real map object - if (string.Compare(XmlMapName, Map.Trammel.Name, true) == 0 || XmlMapName == "Trammel") + if (XmlMapName.InsensitiveEquals(Map.Trammel.Name) || XmlMapName == "Trammel") { SpawnMap = Map.Trammel; TrammelCount++; } - else if (string.Compare(XmlMapName, Map.Felucca.Name, true) == 0 || XmlMapName == "Felucca") + else if (XmlMapName.InsensitiveEquals(Map.Felucca.Name) || XmlMapName == "Felucca") { SpawnMap = Map.Felucca; FeluccaCount++; } - else if (string.Compare(XmlMapName, Map.Ilshenar.Name, true) == 0 || XmlMapName == "Ilshenar") + else if (XmlMapName.InsensitiveEquals(Map.Ilshenar.Name) || XmlMapName == "Ilshenar") { SpawnMap = Map.Ilshenar; IlshenarCount++; } - else if (string.Compare(XmlMapName, Map.Malas.Name, true) == 0 || XmlMapName == "Malas") + else if (XmlMapName.InsensitiveEquals(Map.Malas.Name) || XmlMapName == "Malas") { SpawnMap = Map.Malas; MalasCount++; } - else if (string.Compare(XmlMapName, Map.Tokuno.Name, true) == 0 || XmlMapName == "Tokuno") + else if (XmlMapName.InsensitiveEquals(Map.Tokuno.Name) || XmlMapName == "Tokuno") { SpawnMap = Map.Tokuno; TokunoCount++; @@ -4317,7 +4277,6 @@ public class XmlSpawner : Item, ISpawner } // Check if this spawner already exists - XmlSpawner OldSpawner = null; foreach (var i in World.Items.Values) { if (i is XmlSpawner checkXmlSpawner) @@ -4327,11 +4286,10 @@ public class XmlSpawner : Item, ISpawner if (checkXmlSpawner.UniqueId == SpawnId.ToString() /*&& (CheckXmlSpawner.Map == SpawnMap)*/) { - OldSpawner = checkXmlSpawner; - if (OldSpawner != null) + if (checkXmlSpawner != null) { spawners_deleted++; - OldSpawner.Delete(); + checkXmlSpawner.Delete(); } break; @@ -4352,8 +4310,8 @@ public class XmlSpawner : Item, ISpawner catch { } from?.SendMessage( - $"{spawners_deleted}/{TotalCount} spawner(s) were unloaded using file {filename} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}]." - ); + $"{spawners_deleted}/{TotalCount} spawner(s) were unloaded using file {filename} [Trammel={TrammelCount}, Felucca={FeluccaCount}, Ilshenar={IlshenarCount}, Malas={MalasCount}, Tokuno={TokunoCount}, Other={OtherCount}]." + ); if (bad_spawner_count > 0) { @@ -4425,7 +4383,7 @@ public class XmlSpawner : Item, ISpawner processedspawners = 0; var total_processed_maps = 0; var total_processed_spawners = 0; - if (filename == null || filename.Length <= 0 || from == null || from.Deleted) + if (filename == null || filename.Length <= 0 || from?.Deleted != false) { return; } @@ -4493,9 +4451,7 @@ public class XmlSpawner : Item, ISpawner processedmaps = 1; processedspawners = spawnercount; } - else - // check to see if it is a directory - if (Directory.Exists(filename)) + else if (Directory.Exists(filename)) // check to see if it is a directory { // if so then import all of the .map files in the directory string[] files = null; @@ -4504,7 +4460,7 @@ public class XmlSpawner : Item, ISpawner files = Directory.GetFiles(filename, "*.map"); } catch { } - if (files != null && files.Length > 0) + if (files?.Length > 0) { from.SendMessage($"Importing {files.Length} .map files from directory {filename}"); foreach (var file in files) @@ -4521,7 +4477,7 @@ public class XmlSpawner : Item, ISpawner dirs = Directory.GetDirectories(filename); } catch { } - if (dirs != null && dirs.Length > 0) + if (dirs?.Length > 0) { foreach (var dir in dirs) { @@ -4684,41 +4640,16 @@ public class XmlSpawner : Item, ISpawner map = overridemap; } - var spawnmap = Map.Internal; - switch (map) + var spawnmap = map switch { - case 0: - { - spawnmap = Map.Felucca; - // note it also does trammel - break; - } - case 1: - { - spawnmap = Map.Felucca; - break; - } - case 2: - { - spawnmap = Map.Trammel; - break; - } - case 3: - { - spawnmap = Map.Ilshenar; - break; - } - case 4: - { - spawnmap = Map.Malas; - break; - } - case 5: - { - spawnmap = Map.Tokuno; - break; - } - } + 0 => Map.Felucca, + 1 => Map.Felucca, + 2 => Map.Trammel, + 3 => Map.Ilshenar, + 4 => Map.Malas, + 5 => Map.Tokuno, + _ => Map.Internal + }; if (!IsValidMapLocation(x, y, spawnmap)) { @@ -4967,41 +4898,16 @@ public class XmlSpawner : Item, ISpawner map = overridemap; } - var spawnmap = Map.Internal; - switch (map) + var spawnmap = map switch { - case 0: - { - spawnmap = Map.Felucca; - // note it also does trammel - break; - } - case 1: - { - spawnmap = Map.Felucca; - break; - } - case 2: - { - spawnmap = Map.Trammel; - break; - } - case 3: - { - spawnmap = Map.Ilshenar; - break; - } - case 4: - { - spawnmap = Map.Malas; - break; - } - case 5: - { - spawnmap = Map.Tokuno; - break; - } - } + 0 => Map.Felucca, + 1 => Map.Felucca, + 2 => Map.Trammel, + 3 => Map.Ilshenar, + 4 => Map.Malas, + 5 => Map.Tokuno, + _ => Map.Internal + }; if (!IsValidMapLocation(x, y, spawnmap)) { @@ -5232,256 +5138,10 @@ public class XmlSpawner : Item, ISpawner } } } + return names; } - [Usage("XmlImportMSF filename")] - [Description("Loads msf files created by Morxeton's megaspawner as xmlspawners.")] - public static void XmlImportMSF_OnCommand(CommandEventArgs e) - { - if (e.Arguments.Length >= 1) - { - /* - // I'm not sure what the default location for .msf files is - string filename = e.GetString(0); - string filePath = Path.Combine("Data/Megaspawner", filename); - */ - var filePath = e.GetString(0); - if (File.Exists(filePath)) - { - var doc = new XmlDocument(); - doc.Load(filePath); - var root = doc["MegaSpawners"]; - if (root != null) - { - int successes = 0, failures = 0; - foreach (XmlElement spawner in root.GetElementsByTagName("MegaSpawner")) - { - - try - { - ImportMegaSpawner(e.Mobile, spawner); - successes++; - } - catch (Exception ex) { e.Mobile.SendMessage(33, $"{ex.Message} {spawner.InnerText}"); failures++; } - } - e.Mobile.SendMessage($"{successes:N0} megaspawners loaded successfully from {filePath}, {failures:N0} failures."); - } - else - { - e.Mobile.SendMessage("Invalid .msf file. No MegaSpawners node found"); - } - } - else - { - e.Mobile.SendMessage($"File {filePath} does not exist."); - } - } - else - { - e.Mobile.SendMessage("Usage: [XmlImportMSF "); - } - } - - private static void ImportMegaSpawner(Mobile from, XmlElement node) - { - var name = GetText(node["Name"], "MegaSpawner"); - _ = bool.Parse(GetText(node["Active"], "True")); - var location = Point3D.Parse(GetText(node["Location"], "Error")); - var map = Map.Parse(GetText(node["Map"], "Error")); - - var team = 0; - var group = false; - var maxcount = 0; // default maxcount of the spawner - var homeRange = 4; // default homerange - var spawnRange = 4; // default homerange - var maxDelay = TimeSpan.FromMinutes(10); - var minDelay = TimeSpan.FromMinutes(5); - - var listnode = node["EntryLists"]; - - var nentries = 0; - SpawnObject[] so = null; - - if (listnode != null) - { - // get the number of entries - if (listnode.HasAttributes) - { - var attr = listnode.Attributes; - - nentries = int.Parse(attr.GetNamedItem("count").Value); - } - if (nentries > 0) - { - so = new SpawnObject[nentries]; - - var entrycount = 0; - var diff = false; - foreach (XmlElement entrynode in listnode.GetElementsByTagName("EntryList")) - { - // go through each entry and add a spawn object for it - if (entrynode != null) - { - if (entrycount == 0) - { - // get the spawner defaults from the first entry - // dont handle the individually specified entry attributes - group = bool.Parse(GetText(entrynode["GroupSpawn"], "False")); - maxDelay = TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MaxDelay"], "10:00"))); - minDelay = TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MinDelay"], "05:00"))); - homeRange = int.Parse(GetText(entrynode["WalkRange"], "10")); - spawnRange = int.Parse(GetText(entrynode["SpawnRange"], "4")); - } - else - { - // just check for consistency with other entries and report discrepancies - if (group != bool.Parse(GetText(entrynode["GroupSpawn"], "False"))) - { - diff = true; - // log it - try - { - using var op = new StreamWriter("badimport.log", true); - op.WriteLine("MSFimport : individual group entry difference: {0} vs {1}", - GetText(entrynode["GroupSpawn"], "False"), group); - } - catch { } - } - if (minDelay != TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MinDelay"], "05:00")))) - { - diff = true; - // log it - try - { - using var op = new StreamWriter("badimport.log", true); - op.WriteLine("MSFimport : individual mindelay entry difference: {0} vs {1}", - GetText(entrynode["MinDelay"], "05:00"), minDelay); - } - catch { } - } - if (maxDelay != TimeSpan.FromSeconds(int.Parse(GetText(entrynode["MaxDelay"], "10:00")))) - { - diff = true; - // log it - try - { - using var op = new StreamWriter("badimport.log", true); - op.WriteLine("MSFimport : individual maxdelay entry difference: {0} vs {1}", - GetText(entrynode["MaxDelay"], "10:00"), maxDelay); - } - catch { } - } - if (homeRange != int.Parse(GetText(entrynode["WalkRange"], "10"))) - { - diff = true; - // log it - try - { - using var op = new StreamWriter("badimport.log", true); - op.WriteLine("MSFimport : individual homerange entry difference: {0} vs {1}", - GetText(entrynode["WalkRange"], "10"), homeRange); - } - catch { } - } - if (spawnRange != int.Parse(GetText(entrynode["SpawnRange"], "4"))) - { - diff = true; - // log it - try - { - using var op = new StreamWriter("badimport.log", true); - op.WriteLine("MSFimport : individual spawnrange entry difference: {0} vs {1}", - GetText(entrynode["SpawnRange"], "4"), spawnRange); - } - catch { } - } - } - - // these apply to individual entries - var amount = int.Parse(GetText(entrynode["Amount"], "1")); - var entryname = GetText(entrynode["EntryType"], ""); - - // keep track of the maxcount for the spawner by adding the individual amounts - maxcount += amount; - - // add the creature entry - so[entrycount] = new SpawnObject(entryname, amount); - - entrycount++; - if (entrycount > nentries) - { - // log it - try - { - using var op = new StreamWriter("badimport.log", true); - op.WriteLine($"{Core.Now} MSFImport Error; inconsistent entry count {location} {map}"); - op.WriteLine(); - } - catch { } - from.SendMessage($"Inconsistent entry count detected at {location} {map}."); - break; - } - - } - } - if (diff) - { - from.SendMessage($"Individual entry setting detected at {location} {map}."); - // log it - try - { - using var op = new StreamWriter("badimport.log", true); - op.WriteLine($"{Core.Now} MSFImport: Individual entry setting differences listed above from spawner at {location} {map}"); - op.WriteLine(); - } - catch { } - } - } - } - - // assign it a unique id - var SpawnId = Guid.NewGuid(); - // Create the new xml spawner - var spawner = new XmlSpawner(SpawnId, location.X, location.Y, 0, 0, name, maxcount, - minDelay, maxDelay, TimeSpan.FromMinutes(0), -1, defaultTriggerSound, 1, - team, homeRange, false, so, TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), TimeSpan.FromMinutes(0), - TimeSpan.FromMinutes(0), null, null, null, null, null, - null, null, null, null, 1, null, group, defTODMode, defKillReset, false, -1, null, false, false, false, null, defDespawnTime, null, false, null) - { - SpawnRange = spawnRange, - PlayerCreated = true - }; - - // Try to find a valid Z height if required (Z == -999) - - if (location.Z == -999) - { - var NewZ = map.GetAverageZ(location.X, location.Y); - - if (map.CanFit(location.X, location.Y, NewZ, SpawnFitSize) == false) - { - for (var x = 1; x <= 39; x++) - { - if (map.CanFit(location.X, location.Y, NewZ + x, SpawnFitSize)) - { - NewZ += x; - break; - } - } - } - location.Z = NewZ; - } - - spawner.MoveToWorld(location, map); - - if (!IsValidMapLocation(location, spawner.Map)) - { - spawner.Delete(); - throw new Exception("Invalid spawner location."); - } - } - public static void XmlLoadFromFile(string filename, string SpawnerPrefix, Mobile from, Point3D fromloc, Map frommap, bool loadrelative, int maxrange, bool loadnew, out int processedmaps, out int processedspawners) { processedmaps = 0; @@ -5524,7 +5184,7 @@ public class XmlSpawner : Item, ISpawner files = Directory.GetFiles(filename, "*.xml"); } catch { } - if (files != null && files.Length > 0) + if (files?.Length > 0) { from?.SendMessage($"Loading {files.Length} .xml files from directory {filename}"); @@ -5542,7 +5202,7 @@ public class XmlSpawner : Item, ISpawner dirs = Directory.GetDirectories(filename); } catch { } - if (dirs != null && dirs.Length > 0) + if (dirs?.Length > 0) { foreach (var dir in dirs) { @@ -5653,7 +5313,7 @@ public class XmlSpawner : Item, ISpawner if (ds.Tables.Count > 0) { // Add each spawn point to the current map - if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + if (ds.Tables[SpawnTablePointName]?.Rows.Count > 0) { foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) { @@ -5745,27 +5405,27 @@ public class XmlSpawner : Item, ISpawner catch { questionable_spawner = true; } // Convert the xml map value to a real map object - if (string.Compare(XmlMapName, Map.Trammel.Name, true) == 0 || XmlMapName == "Trammel") + if (XmlMapName.InsensitiveEquals(Map.Trammel.Name) || XmlMapName == "Trammel") { SpawnMap = Map.Trammel; TrammelCount++; } - else if (string.Compare(XmlMapName, Map.Felucca.Name, true) == 0 || XmlMapName == "Felucca") + else if (XmlMapName.InsensitiveEquals(Map.Felucca.Name) || XmlMapName == "Felucca") { SpawnMap = Map.Felucca; FeluccaCount++; } - else if (string.Compare(XmlMapName, Map.Ilshenar.Name, true) == 0 || XmlMapName == "Ilshenar") + else if (XmlMapName.InsensitiveEquals(Map.Ilshenar.Name) || XmlMapName == "Ilshenar") { SpawnMap = Map.Ilshenar; IlshenarCount++; } - else if (string.Compare(XmlMapName, Map.Malas.Name, true) == 0 || XmlMapName == "Malas") + else if (XmlMapName.InsensitiveEquals(Map.Malas.Name) || XmlMapName == "Malas") { SpawnMap = Map.Malas; MalasCount++; } - else if (string.Compare(XmlMapName, Map.Tokuno.Name, true) == 0 || XmlMapName == "Tokuno") + else if (XmlMapName.InsensitiveEquals(Map.Tokuno.Name) || XmlMapName == "Tokuno") { SpawnMap = Map.Tokuno; TokunoCount++; @@ -5873,19 +5533,13 @@ public class XmlSpawner : Item, ISpawner var SpawnTODMode = TODModeType.Realtime; try { todmode = int.Parse((string)dr["TODMode"]); } catch { } - switch (todmode) + + SpawnTODMode = todmode switch { - case (int)TODModeType.Gametime: - { - SpawnTODMode = TODModeType.Gametime; - break; - } - case (int)TODModeType.Realtime: - { - SpawnTODMode = TODModeType.Realtime; - break; - } - } + (int)TODModeType.Gametime => TODModeType.Gametime, + (int)TODModeType.Realtime => TODModeType.Realtime, + _ => SpawnTODMode + }; var SpawnKillReset = defKillReset; try { SpawnKillReset = int.Parse((string)dr["KillReset"]); } @@ -6156,7 +5810,7 @@ public class XmlSpawner : Item, ISpawner } // if this is a container held spawner, drop it in the container - if (found_container && spawn_container != null && !spawn_container.Deleted) + if (found_container && spawn_container?.Deleted == false) { TheSpawn.Location = new Point3D(ContainerX, ContainerY, ContainerZ); spawn_container.AddItem(TheSpawn); @@ -6196,7 +5850,7 @@ public class XmlSpawner : Item, ISpawner from?.SendMessage("Resolving spawner self references"); - if (ds.Tables[SpawnTablePointName] != null && ds.Tables[SpawnTablePointName].Rows.Count > 0) + if (ds.Tables[SpawnTablePointName]?.Rows.Count > 0) { foreach (DataRow dr in ds.Tables[SpawnTablePointName].Rows) { @@ -6249,7 +5903,7 @@ public class XmlSpawner : Item, ISpawner } } - if (found_spawner && OldSpawner != null && !OldSpawner.Deleted) + if (found_spawner && OldSpawner?.Deleted == false) { // resolve item name references since they may have referred to spawners that were just created string setObjectName = null; @@ -6594,7 +6248,7 @@ public class XmlSpawner : Item, ISpawner public override void Execute(CommandEventArgs e, object obj) { - if (e == null || e.Mobile == null || e.Arguments == null) + if (e?.Mobile == null || e.Arguments == null) { return; } @@ -6630,7 +6284,7 @@ public class XmlSpawner : Item, ISpawner string dirname; - if (Directory.Exists(XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + if (Directory.Exists(XmlSpawnDir) && filename?.StartsWith("/") == false && !filename.StartsWith("\\")) { // put it in the defaults directory if it exists dirname = $"{XmlSpawnDir}/{filename}"; @@ -6652,7 +6306,7 @@ public class XmlSpawner : Item, ISpawner private static void SaveSpawns(CommandEventArgs e, bool SaveAllMaps, bool oldformat) { - if (e == null || e.Mobile == null || e.Arguments == null || e.Arguments.Length < 1) + if (e?.Mobile == null || e.Arguments == null || e.Arguments.Length < 1) { return; } @@ -6663,7 +6317,7 @@ public class XmlSpawner : Item, ISpawner return; } - if (e.Arguments != null && e.Arguments.Length < 1) + if (e.Arguments?.Length < 1) { e.Mobile.SendMessage($"Usage: {e.Command} [SpawnerPrefixFilter]"); return; @@ -6681,7 +6335,7 @@ public class XmlSpawner : Item, ISpawner var filename = e.Arguments[0]; string dirname; - if (Directory.Exists(XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) + if (Directory.Exists(XmlSpawnDir) && filename?.StartsWith("/") == false && !filename.StartsWith("\\")) { // put it in the defaults directory if it exists dirname = $"{XmlSpawnDir}/{filename}"; @@ -6713,7 +6367,7 @@ public class XmlSpawner : Item, ISpawner if (i is XmlSpawner spawner && !spawner.Deleted && (SaveAllMaps || spawner.Map == e.Mobile.Map) //check for mob carried spawners and ignore them && spawner.RootParent is not Mobile - && (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || spawner.Name != null && spawner.Name.StartsWith(SpawnerPrefix))) + && (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || spawner.Name?.StartsWith(SpawnerPrefix) == true)) { saveslist.Add(spawner); } @@ -6723,10 +6377,7 @@ public class XmlSpawner : Item, ISpawner _ = SaveSpawnList(e.Mobile, saveslist, dirname, oldformat, true); } - public static bool SaveSpawnList(List savelist, Stream stream) - { - return SaveSpawnList(null, savelist, null, stream, false, false); - } + public static bool SaveSpawnList(List savelist, Stream stream) => SaveSpawnList(null, savelist, null, stream, false, false); public static bool SaveSpawnList(Mobile from, List savelist, string dirname, bool oldformat, bool verbose) { @@ -6860,13 +6511,13 @@ public class XmlSpawner : Item, ISpawner // Add each spawn point to the new table foreach (var sp in savelist) { - if (sp == null || sp.Map == null || sp.Deleted) + if (sp?.Map == null || sp.Deleted) { continue; } - if (verbose && from != null) // Send a message to the client that the spawner is being saved + if (verbose && from != null) { from.SendMessage(68, $"Saving '{sp.Name}' in {sp.Map.Name} at {sp.Location}"); } @@ -6884,23 +6535,23 @@ public class XmlSpawner : Item, ISpawner dr["Map"] = sp.Map.Name; // Convert the xml map value to a real map object - if (string.Compare(sp.Map.Name, Map.Trammel.Name, true) == 0) + if (sp.Map.Name.InsensitiveEquals(Map.Trammel.Name)) { TrammelCount++; } - else if (string.Compare(sp.Map.Name, Map.Felucca.Name, true) == 0) + else if (sp.Map.Name.InsensitiveEquals(Map.Felucca.Name)) { FeluccaCount++; } - else if (string.Compare(sp.Map.Name, Map.Ilshenar.Name, true) == 0) + else if (sp.Map.Name.InsensitiveEquals(Map.Ilshenar.Name)) { IlshenarCount++; } - else if (string.Compare(sp.Map.Name, Map.Malas.Name, true) == 0) + else if (sp.Map.Name.InsensitiveEquals(Map.Malas.Name)) { MalasCount++; } - else if (string.Compare(sp.Map.Name, Map.Tokuno.Name, true) == 0) + else if (sp.Map.Name.InsensitiveEquals(Map.Tokuno.Name)) { TokunoCount++; } @@ -6970,7 +6621,7 @@ public class XmlSpawner : Item, ISpawner dr["ProximityRange"] = sp.m_ProximityRange; dr["ProximityTriggerSound"] = sp.ProximitySound; dr["ProximityTriggerMessage"] = sp.ProximityMsg; - if (sp.m_ObjectPropertyItem != null && !sp.m_ObjectPropertyItem.Deleted) + if (sp.m_ObjectPropertyItem?.Deleted == false) { dr["ObjectPropertyItemName"] = $"{sp.m_ObjectPropertyItem.Name},{sp.m_ObjectPropertyItem.GetType().Name}"; } @@ -6980,7 +6631,7 @@ public class XmlSpawner : Item, ISpawner } dr["ObjectPropertyName"] = sp.m_ObjectPropertyName; - if (sp.SetItem != null && !sp.SetItem.Deleted) + if (sp.SetItem?.Deleted == false) { dr["SetPropertyItemName"] = $"{sp.SetItem.Name},{sp.SetItem.GetType().Name}"; } @@ -7072,7 +6723,7 @@ public class XmlSpawner : Item, ISpawner private static void WipeSpawners(CommandEventArgs e, bool WipeAll) { - if (e == null || e.Mobile == null) + if (e?.Mobile == null) { return; } @@ -7083,7 +6734,7 @@ public class XmlSpawner : Item, ISpawner var SpawnerPrefix = string.Empty; // Check if there is an argument provided (delete criteria) - if (e.Arguments != null && e.Arguments.Length > 0) + if (e.Arguments?.Length > 0) { SpawnerPrefix = e.Arguments[0]; } @@ -7153,7 +6804,7 @@ public class XmlSpawner : Item, ISpawner private static void RespawnSpawners(CommandEventArgs e, bool RespawnAll) { - if (e == null || e.Mobile == null) + if (e?.Mobile == null) { return; } @@ -7164,7 +6815,7 @@ public class XmlSpawner : Item, ISpawner var SpawnerPrefix = string.Empty; // Check if there is an argument provided (respawn criteria) - if (e.Arguments != null && e.Arguments.Length > 0) + if (e.Arguments?.Length > 0) { SpawnerPrefix = e.Arguments[0]; } @@ -7188,7 +6839,7 @@ public class XmlSpawner : Item, ISpawner if (i is XmlSpawner && (RespawnAll || i.Map == e.Mobile.Map) && i.Deleted == false) { // Check if there is a respawn condition - if (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || i.Name != null && i.Name.StartsWith(SpawnerPrefix)) + if (SpawnerPrefix == null || SpawnerPrefix.Length == 0 || i.Name?.StartsWith(SpawnerPrefix) == true) { ToRespawn.Add(i); Count++; @@ -7595,7 +7246,7 @@ public class XmlSpawner : Item, ISpawner { // Check if the creature has been tamed or previously tamed and released // and if it is, remove it from the list of spawns - if (creature.Controlled || creature.IsStabled || creature.Owners != null && creature.Owners.Count > 0) + if (creature.Controlled || creature.IsStabled || creature.Owners?.Count > 0) { _ = so.SpawnedObjects.Remove(mobile); x--; @@ -7684,7 +7335,7 @@ public class XmlSpawner : Item, ISpawner for (var x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) { var i = ToDelete[x]; - if (i != null && !i.Deleted) + if (i?.Deleted == false) { i.Delete(); } @@ -7724,7 +7375,7 @@ public class XmlSpawner : Item, ISpawner for (var x = ToDelete.Count - 1; x >= 0; --x) //each (BaseXmlSpawner.KeywordTag i in ToDelete) { var i = ToDelete[x]; - if (i != null && !i.Deleted) + if (i?.Deleted == false) { i.Delete(); } @@ -7774,7 +7425,7 @@ public class XmlSpawner : Item, ISpawner for (var x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) { var i = ToDelete[x]; - if (i != null && !i.Deleted) + if (i?.Deleted == false) { i.Delete(); } @@ -7818,7 +7469,7 @@ public class XmlSpawner : Item, ISpawner for (var x = ToDelete.Count - 1; x >= 0; --x) //BaseXmlSpawner.KeywordTag i in ToDelete) { var i = ToDelete[x]; - if (i != null && !i.Deleted) + if (i?.Deleted == false) { i.Delete(); } @@ -7852,11 +7503,9 @@ public class XmlSpawner : Item, ISpawner return nsub; } - private int RandomAvailableSpawnIndex() - { + private int RandomAvailableSpawnIndex() => // get spawn indices randomly from all available spawns independent of group - return RandomAvailableSpawnIndex(-1); - } + RandomAvailableSpawnIndex(-1); // get spawn indices randomly from all available spawns of a group private int RandomAvailableSpawnIndex(int sgroup) @@ -8346,16 +7995,13 @@ public class XmlSpawner : Item, ISpawner if (m_ProximityRange >= 0 && CanSpawn) { // check all nearby players - IPooledEnumerable eable = GetMobilesInRange(m_ProximityRange); - foreach (Mobile p in eable) + foreach (Mobile p in GetMobilesInRange(m_ProximityRange)) { if (ValidPlayerTrig(p)) { CheckTriggers(p, null, true); } } - - eable.Free(); } if (m_Group) @@ -8494,7 +8140,7 @@ public class XmlSpawner : Item, ISpawner // return false if it cannot spawn, e.g. there is nothing to spawn or it is a triggerable spawner and has not been triggered public bool Spawn(bool smartspawn, byte loops) { - if (m_SpawnObjects != null && m_SpawnObjects.Count > 0 && (m_proximityActivated || CanFreeSpawn) && TODInRange) + if (m_SpawnObjects?.Count > 0 && (m_proximityActivated || CanFreeSpawn) && TODInRange) { m_HoldSequence = false; @@ -8588,16 +8234,10 @@ public class XmlSpawner : Item, ISpawner } // spawn an individual entry by index up to count times - public bool Spawn(int index, bool smartspawn, int count, byte loops) - { - return Spawn(index, smartspawn, count, false, loops); - } + public bool Spawn(int index, bool smartspawn, int count, byte loops) => Spawn(index, smartspawn, count, false, loops); // spawn an individual entry by index up to count times - public bool Spawn(int index, bool smartspawn, int count, bool ignoreloopprotection, byte loops) - { - return Spawn(index, smartspawn, count, -1, Point3D.Zero, ignoreloopprotection, loops); - } + public bool Spawn(int index, bool smartspawn, int count, bool ignoreloopprotection, byte loops) => Spawn(index, smartspawn, count, -1, Point3D.Zero, ignoreloopprotection, loops); // spawn an individual entry by spawn object public void Spawn(string SpawnObjectTypeName, bool smartspawn, int packrange, Point3D packcoord, byte loops) @@ -8628,10 +8268,7 @@ public class XmlSpawner : Item, ISpawner } // spawn an individual entry by index - public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, byte loops) - { - return Spawn(index, smartspawn, packrange, packcoord, false, loops); - } + public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, byte loops) => Spawn(index, smartspawn, packrange, packcoord, false, loops); // spawn an individual entry by index public bool Spawn(int index, bool smartspawn, int packrange, Point3D packcoord, bool ignoreloopprotection, byte loops) @@ -8693,7 +8330,7 @@ public class XmlSpawner : Item, ISpawner var requiresurface = true; // parse the # function specification for the entry - while (substitutedtypeName.StartsWith("#")) + while (substitutedtypeName.StartsWith('#')) { var args = BaseXmlSpawner.ParseSemicolonArgs(substitutedtypeName, 2); @@ -8709,96 +8346,96 @@ public class XmlSpawner : Item, ISpawner switch (keyvalueargs[0]) { case "#NOITEMID": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoItemID, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoItemID, TriggerMob, keyvalueargs)); + break; + } case "#ITEMID": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ItemID, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ItemID, TriggerMob, keyvalueargs)); + break; + } case "#NOTILES": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoTiles, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.NoTiles, TriggerMob, keyvalueargs)); + break; + } case "#TILES": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Tiles, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Tiles, TriggerMob, keyvalueargs)); + break; + } case "#WET": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Wet, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Wet, TriggerMob, keyvalueargs)); + break; + } case "#XFILL": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RowFill, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RowFill, TriggerMob, keyvalueargs)); + break; + } case "#YFILL": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ColFill, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.ColFill, TriggerMob, keyvalueargs)); + break; + } case "#EDGE": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Perimeter, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Perimeter, TriggerMob, keyvalueargs)); + break; + } case "#PLAYER": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Player, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Player, TriggerMob, keyvalueargs)); + break; + } case "#WAYPOINT": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Waypoint, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Waypoint, TriggerMob, keyvalueargs)); + break; + } case "#RELXY": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RelXY, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.RelXY, TriggerMob, keyvalueargs)); + break; + } case "#DXY": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.DeltaLocation, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.DeltaLocation, TriggerMob, keyvalueargs)); + break; + } case "#XY": - { - spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Location, TriggerMob, keyvalueargs)); - break; - } + { + spawnpositioning.Add(new SpawnPositionInfo(SpawnPositionType.Location, TriggerMob, keyvalueargs)); + break; + } case "#CONDITION": - { - // test the specified condition string - // syntax is #CONDITION,proptest - // reparse with only one arg after the comma, this allows property tests that use commas as well - var ckeyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 2); - if (ckeyvalueargs.Length > 1) { - // dont spawn if it fails the test - if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out var status)) + // test the specified condition string + // syntax is #CONDITION,proptest + // reparse with only one arg after the comma, this allows property tests that use commas as well + var ckeyvalueargs = BaseXmlSpawner.ParseCommaArgs(args[0], 2); + if (ckeyvalueargs.Length > 1) { - status_str = status; - return false; + // dont spawn if it fails the test + if (!BaseXmlSpawner.CheckPropertyString(this, this, ckeyvalueargs[1], out var status)) + { + status_str = status; + return false; + } } + else + { + status_str = $"invalid #CONDITION specification: {args[0]}"; + } + break; } - else - { - status_str = $"invalid #CONDITION specification: {args[0]}"; - } - break; - } default: - { - status_str = $"invalid # specification: {args[0]}"; - break; - } + { + status_str = $"invalid # specification: {args[0]}"; + break; + } } } } @@ -8953,15 +8590,9 @@ public class XmlSpawner : Item, ISpawner return false; } - public bool SpawnSubGroup(int sgroup, byte loops) - { - return SpawnSubGroup(sgroup, false, loops); - } + public bool SpawnSubGroup(int sgroup, byte loops) => SpawnSubGroup(sgroup, false, loops); - public bool SpawnSubGroup(int sgroup, bool smartspawn, byte loops) - { - return SpawnSubGroup(sgroup, false, false, loops); - } + public bool SpawnSubGroup(int sgroup, bool smartspawn, byte loops) => SpawnSubGroup(sgroup, false, false, loops); public bool SpawnSubGroup(int sgroup, bool smartspawn, bool ignoreloopprotection, byte loops) { @@ -8979,7 +8610,7 @@ public class XmlSpawner : Item, ISpawner { var so = m_SpawnObjects[j]; - if (so != null && so.SubGroup == sgroup) + if (so?.SubGroup == sgroup) { // find the first subgroup spawn to determine the packspawning reference coordinates if (so.PackRange >= 0 && packcoord == Point3D.Zero) @@ -9017,7 +8648,7 @@ public class XmlSpawner : Item, ISpawner { var so = m_SpawnObjects[j]; - if (so != null && so.SubGroup == sgroup && so.SpawnedObjects.Count > 0 && so.PackRange >= 0) + if (so?.SubGroup == sgroup && so.SpawnedObjects.Count > 0 && so.PackRange >= 0) { // if pack spawning is enabled for this subgroup, then get the // the origin for pack spawning using the first existing pack spawn @@ -9287,7 +8918,7 @@ public class XmlSpawner : Item, ISpawner public static SpawnObject GetSpawnObject(XmlSpawner spawner, int sgroup) { - if (spawner == null || spawner.m_SpawnObjects == null) + if (spawner?.m_SpawnObjects == null) { return null; } @@ -9305,7 +8936,7 @@ public class XmlSpawner : Item, ISpawner public static object GetSpawned(XmlSpawner spawner, int sgroup) { - if (spawner == null || spawner.m_SpawnObjects == null) + if (spawner?.m_SpawnObjects == null) { return null; } @@ -9329,7 +8960,7 @@ public class XmlSpawner : Item, ISpawner { var newlist = new List(); - if (spawner == null || spawner.m_SpawnObjects == null) + if (spawner?.m_SpawnObjects == null) { return null; } @@ -9383,7 +9014,7 @@ public class XmlSpawner : Item, ISpawner public bool HasIndividualSpawnTimes() { - if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + if (m_SpawnObjects?.Count > 0) { for (var i = 0; i < m_SpawnObjects.Count; i++) { @@ -9401,7 +9032,7 @@ public class XmlSpawner : Item, ISpawner private void ResetNextSpawnTimes() { - if (m_SpawnObjects != null && m_SpawnObjects.Count > 0) + if (m_SpawnObjects?.Count > 0) { for (var i = 0; i < m_SpawnObjects.Count; i++) { @@ -9412,7 +9043,7 @@ public class XmlSpawner : Item, ISpawner } } - public void RefreshNextSpawnTime(SpawnObject so) + public static void RefreshNextSpawnTime(SpawnObject so) { if (so == null) { @@ -9486,7 +9117,7 @@ public class XmlSpawner : Item, ISpawner if (!string.IsNullOrEmpty(waypointstr)) { var wayargs = BaseXmlSpawner.ParseString(waypointstr, 2, ","); - if (wayargs != null && wayargs.Length > 0) + if (wayargs?.Length > 0) { // is this a SERIAL specification? if (wayargs[0] == "SERIAL") @@ -9530,19 +9161,10 @@ public class XmlSpawner : Item, ISpawner return false; } - var tiles = map.Tiles.GetStaticTiles(X, Y, true); - - if (tiles == null) - { - return false; - } - // go through the tiles and see if any are at the Z location - foreach (var o in tiles) + foreach (var staticTile in map.Tiles.GetStaticAndMultiTiles(X, Y)) { - var i = o; - - if (i.Z + i.Height == Z) + if (staticTile.Z + staticTile.Height == Z) { return true; } @@ -9551,7 +9173,7 @@ public class XmlSpawner : Item, ISpawner return false; } - private bool CheckHoldSmartSpawning(object o) + private static bool CheckHoldSmartSpawning(object o) { if (o == null) { @@ -9687,11 +9309,9 @@ public class XmlSpawner : Item, ISpawner Console.WriteLine("landtile at {0},{1},{2} wet={3} impassable={4} hassurface={5}", x, y, z, wet, impassable, hasSurface); } - var staticTiles = map.Tiles.GetStaticTiles(x, y, true); - - for (var i = 0; i < staticTiles.Length; ++i) + foreach (var staticTile in map.Tiles.GetStaticAndMultiTiles(x, y)) { - var id = TileData.ItemTable[staticTiles[i].ID & TileData.MaxItemValue]; + var id = TileData.ItemTable[staticTile.ID & TileData.MaxItemValue]; surface = id.Surface; impassable = id.Impassable; if (checkmob) @@ -9711,12 +9331,12 @@ public class XmlSpawner : Item, ISpawner } } - if ((surface || impassable) && staticTiles[i].Z + id.CalcHeight > z && z + height > staticTiles[i].Z) + if ((surface || impassable) && staticTile.Z + id.CalcHeight > z && z + height > staticTile.Z) { return false; } - if (surface && !impassable && z == staticTiles[i].Z + id.CalcHeight) + if (surface && !impassable && z == staticTile.Z + id.CalcHeight) { hasSurface = true; } @@ -9726,45 +9346,41 @@ public class XmlSpawner : Item, ISpawner Console.WriteLine("statics hassurface={0}", hasSurface); } - var sector = map.GetSector(x, y); - var items = sector.Items; - var mobs = sector.Mobiles; - - for (var i = 0; i < items.Count; ++i) + foreach (var item in map.GetItemsAt(x, y)) { - var item = items[i]; - - if (item.ItemID < 0x4000 && item.AtWorldPoint(x, y)) + if (item.ItemID >= 0x4000) { - var id = item.ItemData; - surface = id.Surface; - impassable = id.Impassable; - if (checkmob) - { - wet = (id.Flags & TileFlag.Wet) != 0; - // dont allow wateronly creatures on land - if (cantwalk && !wet) - { - impassable = true; - } + continue; + } - // allow water creatures on water - if (canswim && wet) - { - surface = true; - impassable = false; - } + var id = item.ItemData; + surface = id.Surface; + impassable = id.Impassable; + if (checkmob) + { + wet = (id.Flags & TileFlag.Wet) != 0; + // dont allow wateronly creatures on land + if (cantwalk && !wet) + { + impassable = true; } - if ((surface || impassable || checkBlocksFit && item.BlocksFit) && item.Z + id.CalcHeight > z && z + height > item.Z) + // allow water creatures on water + if (canswim && wet) { - return false; + surface = true; + impassable = false; } + } - if (surface && !impassable && !item.Movable && z == item.Z + id.CalcHeight) - { - hasSurface = true; - } + if ((surface || impassable || checkBlocksFit && item.BlocksFit) && item.Z + id.CalcHeight > z && z + height > item.Z) + { + return false; + } + + if (surface && !impassable && !item.Movable && z == item.Z + id.CalcHeight) + { + hasSurface = true; } } @@ -9775,16 +9391,11 @@ public class XmlSpawner : Item, ISpawner if (checkMobiles) { - for (var i = 0; i < mobs.Count; ++i) + foreach (var m in map.GetMobilesAt(x, y)) { - var m = mobs[i]; - - if (m.Location.X == x && m.Location.Y == y && (m.AccessLevel == AccessLevel.Player || !m.Hidden)) + if ((m.AccessLevel == AccessLevel.Player || !m.Hidden) && m.Z + 16 > z && z + height > m.Z) { - if (m.Z + 16 > z && z + height > m.Z) - { - return false; - } + return false; } } } @@ -9807,14 +9418,23 @@ public class XmlSpawner : Item, ISpawner return Region.Find(new Point3D(x, y, z), Map).AllowSpawn() && Map.CanFit(x, y, z, 16); } - public static bool HasRegionPoints(Region r) - { - return r != null && r.Area.Length > 0; - } + public static bool HasRegionPoints(Region r) => r?.Area.Length > 0; public Rectangle2D SpawnerBounds => new(m_X, m_Y, m_Width + 1, m_Height + 1); - private void FindTileLocations(ref List locations, Map map, int startx, int starty, int width, int height, List includetilelist, List excludetilelist, TileFlag tileflag, bool checkitems, int spawnerZ) + private static void FindTileLocations( + ref List locations, + Map map, + int startx, + int starty, + int width, + int height, + List includetilelist, + List excludetilelist, + TileFlag tileflag, + bool checkitems, + int spawnerZ + ) { if (width < 0 || height < 0 || map == null) { @@ -9823,9 +9443,6 @@ public class XmlSpawner : Item, ISpawner locations ??= new List(); - bool includetile; - bool excludetile; - for (var x = startx; x <= startx + width; x++) { for (var y = starty; y <= starty + height; y++) @@ -9837,7 +9454,8 @@ public class XmlSpawner : Item, ISpawner var lflags = TileData.LandTable[ltile.ID & TileData.MaxLandValue].Flags; // check the land tile - if (includetilelist != null && includetilelist.Count > 0) + bool includetile; + if (includetilelist?.Count > 0) { includetile = includetilelist.Contains(ltile.ID & TileData.MaxLandValue); } @@ -9847,7 +9465,8 @@ public class XmlSpawner : Item, ISpawner } // non-excluded tiles must also be passable - if (excludetilelist != null && excludetilelist.Count > 0) + bool excludetile; + if (excludetilelist?.Count > 0) { // also require the tile to be passable excludetile = (lflags & TileFlag.Impassable) != 0 || excludetilelist.Contains(ltile.ID & TileData.MaxLandValue); @@ -9863,15 +9482,12 @@ public class XmlSpawner : Item, ISpawner allok = true; } - var statictiles = map.Tiles.GetStaticTiles(x, y, true); - // check the static tiles - for (var i = 0; i < statictiles.Length; ++i) + foreach (var stile in map.Tiles.GetStaticAndMultiTiles(x, y)) { - var stile = statictiles[i]; var sflags = TileData.ItemTable[stile.ID & TileData.MaxItemValue].Flags; - if (includetilelist != null && includetilelist.Count > 0) + if (includetilelist?.Count > 0) { includetile = includetilelist.Contains(stile.ID & TileData.MaxItemValue); } @@ -9881,7 +9497,7 @@ public class XmlSpawner : Item, ISpawner } // non-excluded tiles must also be passable - if (excludetilelist != null && excludetilelist.Count > 0) + if (excludetilelist?.Count > 0) { excludetile = (sflags & TileFlag.Impassable) != 0 || excludetilelist.Contains(stile.ID & TileData.MaxItemValue); } @@ -9914,10 +9530,8 @@ public class XmlSpawner : Item, ISpawner if (checkitems) { - IPooledEnumerable itemslist = map.GetItemsInRange(new Point3D(x, y, 0), 0); - // check the itemsid - foreach (Item i in itemslist) + foreach (Item i in map.GetItemsAt(x, y)) { if (i.ItemData.Impassable) { @@ -9925,7 +9539,7 @@ public class XmlSpawner : Item, ISpawner } var iflags = TileData.ItemTable[i.ItemID & TileData.MaxItemValue].Flags; - if (includetilelist != null && includetilelist.Count > 0) + if (includetilelist?.Count > 0) { includetile = includetilelist.Contains(i.ItemID & TileData.MaxItemValue); } @@ -9934,7 +9548,7 @@ public class XmlSpawner : Item, ISpawner includetile = true; } - if (excludetilelist != null && excludetilelist.Count > 0) + if (excludetilelist?.Count > 0) { excludetile = excludetilelist.Contains(i.ItemID & TileData.MaxItemValue); } @@ -9949,8 +9563,6 @@ public class XmlSpawner : Item, ISpawner allok = true; } } - - itemslist.Free(); } if (allok && !excludetile) @@ -9963,7 +9575,7 @@ public class XmlSpawner : Item, ISpawner private void FindRegionTileLocations(ref List locations, Region r, List includetilelist, List excludetilelist, TileFlag tileflag, bool checkitems, int spawnerZ) { - if (r == null || r.Area == null) + if (r?.Area == null) { return; } @@ -10032,24 +9644,17 @@ public class XmlSpawner : Item, ISpawner return new Point2D(x, y); } - public Point3D GetSpawnPosition(ISpawnable spawned, Map map) - { - return GetSpawnPosition(true, spawned as Mobile); - } + public Point3D GetSpawnPosition(ISpawnable spawned, Map map) => GetSpawnPosition(true, spawned as Mobile); // used for getting non-mobile spawn positions - public Point3D GetSpawnPosition(bool requiresurface) - { + public Point3D GetSpawnPosition(bool requiresurface) => // no pack spawning - return GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, null); - } + GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, null); // used for getting mobile spawn positions - public Point3D GetSpawnPosition(bool requiresurface, Mobile mob) - { + public Point3D GetSpawnPosition(bool requiresurface, Mobile mob) => // no pack spawning - return GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, mob); - } + GetSpawnPosition(requiresurface, -1, Point3D.Zero, null, mob); // used for getting non-mobile spawn positions public Point3D GetSpawnPosition( @@ -10057,10 +9662,8 @@ public class XmlSpawner : Item, ISpawner int packrange, Point3D packcoord, List spawnpositioning - ) - { - return GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, null); - } + ) => + GetSpawnPosition(requiresurface, packrange, packcoord, spawnpositioning, null); public Point3D GetSpawnPosition(bool requiresurface, int packrange, Point3D packcoord, List spawnpositioning, Mobile mob) { @@ -10104,205 +9707,206 @@ public class XmlSpawner : Item, ISpawner switch (s.positionType) { case SpawnPositionType.Wet: - { - // syntax Wet - // find all of the wet tiles - tileflag |= TileFlag.Wet; - requiresurface = false; - break; - } + { + // syntax Wet + // find all of the wet tiles + tileflag |= TileFlag.Wet; + requiresurface = false; + break; + } case SpawnPositionType.ItemID: - { - checkitems = true; - goto case SpawnPositionType.Tiles; - } + { + checkitems = true; + goto case SpawnPositionType.Tiles; + } case SpawnPositionType.NoItemID: - { - checkitems = true; - goto case SpawnPositionType.NoTiles; - } + + { + checkitems = true; + goto case SpawnPositionType.NoTiles; + } case SpawnPositionType.Tiles: - { - // syntax Tiles,start[,end] - // get the tiles in the range - requiresurface = false; - var start = -1; - var end = -1; - if (positionargs != null && positionargs.Length > 1) { - try + // syntax Tiles,start[,end] + // get the tiles in the range + requiresurface = false; + var start = -1; + var end = -1; + if (positionargs?.Length > 1) { - start = int.Parse(positionargs[1]); + try + { + start = int.Parse(positionargs[1]); + } + catch { } } - catch { } - } - if (positionargs != null && positionargs.Length > 2) - { - try + if (positionargs?.Length > 2) { - end = int.Parse(positionargs[2]); + try + { + end = int.Parse(positionargs[2]); + } + catch { } } - catch { } - } - includetilelist ??= new List(); + includetilelist ??= new List(); - // add the tiles to the list - if (start > -1 && end < 0) - { - includetilelist.Add(start); - } - else - if (start > -1 && end > -1) - { - for (var j = start; j <= end; j++) + // add the tiles to the list + if (start > -1 && end < 0) { - includetilelist.Add(j); + includetilelist.Add(start); } + else + if (start > -1 && end > -1) + { + for (var j = start; j <= end; j++) + { + includetilelist.Add(j); + } + } + break; } - break; - } case SpawnPositionType.NoTiles: - { - // syntax Tiles,start[,end] - // get the tiles in the range - requiresurface = false; - var start = -1; - var end = -1; - if (positionargs != null && positionargs.Length > 1) { - try + // syntax Tiles,start[,end] + // get the tiles in the range + requiresurface = false; + var start = -1; + var end = -1; + if (positionargs?.Length > 1) { - start = int.Parse(positionargs[1]); + try + { + start = int.Parse(positionargs[1]); + } + catch { } } - catch { } - } - if (positionargs != null && positionargs.Length > 2) - { - try + if (positionargs?.Length > 2) { - end = int.Parse(positionargs[2]); + try + { + end = int.Parse(positionargs[2]); + } + catch { } } - catch { } - } - excludetilelist ??= new List(); + excludetilelist ??= new List(); - // add the tiles to the list - if (start > -1 && end < 0) - { - excludetilelist.Add(start); - } - else - if (start > -1 && end > -1) - { - for (var j = start; j <= end; j++) + // add the tiles to the list + if (start > -1 && end < 0) { - excludetilelist.Add(j); + excludetilelist.Add(start); } + else + if (start > -1 && end > -1) + { + for (var j = start; j <= end; j++) + { + excludetilelist.Add(j); + } + } + break; } - break; - } case SpawnPositionType.RowFill: case SpawnPositionType.ColFill: case SpawnPositionType.Perimeter: - { - // syntax XFILL[,inc] - // syntax YFILL[,inc] - // syntax EDGE[,inc] - positioning = s.positionType; - if (positionargs != null && positionargs.Length > 1) { - try + // syntax XFILL[,inc] + // syntax YFILL[,inc] + // syntax EDGE[,inc] + positioning = s.positionType; + if (positionargs?.Length > 1) { - fillinc = int.Parse(positionargs[1]); + try + { + fillinc = int.Parse(positionargs[1]); + } + catch { } } - catch { } + break; } - break; - } case SpawnPositionType.RelXY: case SpawnPositionType.DeltaLocation: case SpawnPositionType.Location: - { - // syntax RELXY,xinc,yinc[,zinc] - // syntax XY,x,y[,z] - // syntax DXY,dx,dy[,dz] - positioning = s.positionType; - if (positionargs != null && positionargs.Length > 2) { - try + // syntax RELXY,xinc,yinc[,zinc] + // syntax XY,x,y[,z] + // syntax DXY,dx,dy[,dz] + positioning = s.positionType; + if (positionargs?.Length > 2) { - xinc = int.Parse(positionargs[1]); - yinc = int.Parse(positionargs[2]); - } - catch { } - } - if (positionargs != null && positionargs.Length > 3) - { - try - { - zinc = int.Parse(positionargs[3]); - } - catch { } - } - break; - } - case SpawnPositionType.Waypoint: - { - // syntax WAYPOINT,prefix[,range] - positioning = s.positionType; - if (positionargs != null && positionargs.Length > 1) - { - prefix = positionargs[1]; - } - - if (positionargs != null && positionargs.Length > 2) - { - try - { - positionrange = int.Parse(positionargs[2]); - } - catch { } - } - - // find a list of items that match the waypoint prefix - if (prefix != null) - { - // see if there is an existing hashtable for the waypoint lists - spawnPositionWayTable ??= new Dictionary>(); - - // no existing list so create a new one - if (!spawnPositionWayTable.TryGetValue(prefix, out WayList) || WayList == null) - { - WayList = new List(); - - foreach (var i in World.Items.Values) + try { - if (i is WayPoint && !string.IsNullOrEmpty(i.Name) && i.Map == Map && i.Name == prefix) - { - // add it to the list of items - WayList.Add(i); - } + xinc = int.Parse(positionargs[1]); + yinc = int.Parse(positionargs[2]); } - // add the new list to the local table - spawnPositionWayTable[prefix] = WayList; + catch { } } - } - break; - } - case SpawnPositionType.Player: - { - // syntax PLAYER[,range] - positioning = s.positionType; - if (positionargs != null && positionargs.Length > 1) - { - try + if (positionargs?.Length > 3) { - positionrange = int.Parse(positionargs[1]); + try + { + zinc = int.Parse(positionargs[3]); + } + catch { } } - catch { } + break; + } + case SpawnPositionType.Waypoint: + { + // syntax WAYPOINT,prefix[,range] + positioning = s.positionType; + if (positionargs?.Length > 1) + { + prefix = positionargs[1]; + } + + if (positionargs?.Length > 2) + { + try + { + positionrange = int.Parse(positionargs[2]); + } + catch { } + } + + // find a list of items that match the waypoint prefix + if (prefix != null) + { + // see if there is an existing hashtable for the waypoint lists + spawnPositionWayTable ??= new Dictionary>(); + + // no existing list so create a new one + if (!spawnPositionWayTable.TryGetValue(prefix, out WayList) || WayList == null) + { + WayList = new List(); + + foreach (var i in World.Items.Values) + { + if (i is WayPoint && !string.IsNullOrEmpty(i.Name) && i.Map == Map && i.Name == prefix) + { + // add it to the list of items + WayList.Add(i); + } + } + // add the new list to the local table + spawnPositionWayTable[prefix] = WayList; + } + } + break; + } + case SpawnPositionType.Player: + { + // syntax PLAYER[,range] + positioning = s.positionType; + if (positionargs?.Length > 1) + { + try + { + positionrange = int.Parse(positionargs[1]); + } + catch { } + } + break; } - break; - } } } } @@ -10347,7 +9951,7 @@ public class XmlSpawner : Item, ISpawner if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) { // use the precalculated tile locations - if (locations != null && locations.Count > 0) + if (locations?.Count > 0) { var p = locations[Utility.Random(locations.Count)]; x = p.X; @@ -10367,208 +9971,205 @@ public class XmlSpawner : Item, ISpawner switch (positioning) { case SpawnPositionType.Random: - { - if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) { - - if (locations != null && locations.Count > 0) + if (includetilelist != null || excludetilelist != null || tileflag != TileFlag.None) { - var p = locations[Utility.Random(locations.Count)]; - x = p.X; - y = p.Y; - defaultZ = p.Z; + + if (locations?.Count > 0) + { + var p = locations[Utility.Random(locations.Count)]; + x = p.X; + y = p.Y; + defaultZ = p.Z; + } } + else + { + + if (m_Width > 0) + { + x = m_X + Utility.Random(m_Width + 1); + } + + if (m_Height > 0) + { + y = m_Y + Utility.Random(m_Height + 1); + } + } + break; } - else - { - - if (m_Width > 0) - { - x = m_X + Utility.Random(m_Width + 1); - } - - if (m_Height > 0) - { - y = m_Y + Utility.Random(m_Height + 1); - } - } - break; - } case SpawnPositionType.RelXY: - { - x = mostRecentSpawnPosition.X + xinc; - y = mostRecentSpawnPosition.Y + yinc; - defaultZ = mostRecentSpawnPosition.Z + zinc; - break; - } + { + x = mostRecentSpawnPosition.X + xinc; + y = mostRecentSpawnPosition.Y + yinc; + defaultZ = mostRecentSpawnPosition.Z + zinc; + break; + } case SpawnPositionType.DeltaLocation: - { - x = X + xinc; - y = Y + yinc; - defaultZ = Z + zinc; - break; - } + { + x = X + xinc; + y = Y + yinc; + defaultZ = Z + zinc; + break; + } case SpawnPositionType.Location: - { - x = xinc; - y = yinc; - defaultZ = zinc; - break; - } + { + x = xinc; + y = yinc; + defaultZ = zinc; + break; + } case SpawnPositionType.RowFill: - { - x = mostRecentSpawnPosition.X + fillinc; - y = mostRecentSpawnPosition.Y; - - if (x < m_X) { - x = m_X; - } + x = mostRecentSpawnPosition.X + fillinc; + y = mostRecentSpawnPosition.Y; - if (y < m_Y) - { - y = m_Y; - } + if (x < m_X) + { + x = m_X; + } - if (x > m_X + m_Width) - { - x = m_X + (x - m_X - m_Width - 1); - y++; - } + if (y < m_Y) + { + y = m_Y; + } - if (y > m_Y + m_Height) - { - y = m_Y; - } + if (x > m_X + m_Width) + { + x = m_X + (x - m_X - m_Width - 1); + y++; + } - break; - } + if (y > m_Y + m_Height) + { + y = m_Y; + } + + break; + } case SpawnPositionType.ColFill: - { - x = mostRecentSpawnPosition.X; - y = mostRecentSpawnPosition.Y + fillinc; - - if (x < m_X) { - x = m_X; - } + x = mostRecentSpawnPosition.X; + y = mostRecentSpawnPosition.Y + fillinc; - if (y < m_Y) - { - y = m_Y; - } + if (x < m_X) + { + x = m_X; + } - if (y > m_Y + m_Height) - { - y = m_Y + (y - m_Y - m_Height - 1); - x++; - } + if (y < m_Y) + { + y = m_Y; + } - if (x > m_X + m_Width) - { - x = m_X; - } + if (y > m_Y + m_Height) + { + y = m_Y + (y - m_Y - m_Height - 1); + x++; + } - break; - } + if (x > m_X + m_Width) + { + x = m_X; + } + + break; + } case SpawnPositionType.Perimeter: - { - x = mostRecentSpawnPosition.X; - y = mostRecentSpawnPosition.Y; + { + x = mostRecentSpawnPosition.X; + y = mostRecentSpawnPosition.Y; - // if the point is not on the perimeter, reset it to the corner - if (x != m_X && x != m_X + m_Width && y != m_Y && y != m_Y + m_Height) - { - x = m_X; - y = m_Y; - } + // if the point is not on the perimeter, reset it to the corner + if (x != m_X && x != m_X + m_Width && y != m_Y && y != m_Y + m_Height) + { + x = m_X; + y = m_Y; + } - if (y == m_Y && x < m_X + m_Width) - { - x += fillinc; - } - else - if (y == m_Y + m_Height && x > m_X) - { - x -= fillinc; - } - else - if (x == m_X && y > m_Y) - { - y -= fillinc; - } - else - if (x == m_X + m_Width && y < m_Y + m_Height) - { - y += fillinc; - } + if (y == m_Y && x < m_X + m_Width) + { + x += fillinc; + } + else if (y == m_Y + m_Height && x > m_X) + { + x -= fillinc; + } + else if (x == m_X && y > m_Y) + { + y -= fillinc; + } + else if (x == m_X + m_Width && y < m_Y + m_Height) + { + y += fillinc; + } - if (x > m_X + m_Width) - { - x = m_X + m_Width; - } + if (x > m_X + m_Width) + { + x = m_X + m_Width; + } - if (y > m_Y + m_Height) - { - y = m_Y + m_Height; - } + if (y > m_Y + m_Height) + { + y = m_Y + m_Height; + } - if (x < m_X) - { - x = m_X; - } + if (x < m_X) + { + x = m_X; + } - if (y < m_Y) - { - y = m_Y; - } + if (y < m_Y) + { + y = m_Y; + } - break; - } + break; + } case SpawnPositionType.Player: - { - if (trigmob != null) { - x = trigmob.Location.X; - y = trigmob.Location.Y; - if (positionrange > 0) + if (trigmob != null) { - x += Utility.Random(positionrange * 2 + 1) - positionrange; - y += Utility.Random(positionrange * 2 + 1) - positionrange; - } - } - break; - } - - case SpawnPositionType.Waypoint: - { - // pick an item randomly from the waylist - if (WayList != null && WayList.Count > 0) - { - var index = Utility.Random(WayList.Count); - var waypoint = WayList[index]; - if (waypoint != null) - { - x = waypoint.Location.X; - y = waypoint.Location.Y; - defaultZ = waypoint.Location.Z; + x = trigmob.Location.X; + y = trigmob.Location.Y; if (positionrange > 0) { x += Utility.Random(positionrange * 2 + 1) - positionrange; y += Utility.Random(positionrange * 2 + 1) - positionrange; } } + break; } - break; - } + case SpawnPositionType.Waypoint: + { + // pick an item randomly from the waylist + if (WayList?.Count > 0) + { + var index = Utility.Random(WayList.Count); + var waypoint = WayList[index]; + if (waypoint != null) + { + x = waypoint.Location.X; + y = waypoint.Location.Y; + defaultZ = waypoint.Location.Z; + if (positionrange > 0) + { + x += Utility.Random(positionrange * 2 + 1) - positionrange; + y += Utility.Random(positionrange * 2 + 1) - positionrange; + } + } + } + + break; + } } mostRecentSpawnPosition = new Point3D(x, y, defaultZ); @@ -10611,13 +10212,7 @@ public class XmlSpawner : Item, ISpawner public int GetCreatureMax(int index) { Defrag(false); - - if (m_SpawnObjects == null) - { - return 0; - } - - return m_SpawnObjects[index].MaxCount; + return m_SpawnObjects?[index]?.MaxCount ?? 0; } private static void DeleteFromList(List list) where T : IEntity @@ -10868,7 +10463,7 @@ public class XmlSpawner : Item, ISpawner var deletelist = new List(); // Remove any spawns over the count - while (TheSpawn.SpawnedObjects != null && TheSpawn.SpawnedObjects.Count > 0 && TheSpawn.SpawnedObjects.Count > TheSpawn.MaxCount) + while (TheSpawn.SpawnedObjects?.Count > 0 && TheSpawn.SpawnedObjects.Count > TheSpawn.MaxCount) { var o = TheSpawn.SpawnedObjects[0]; @@ -10914,10 +10509,7 @@ public class XmlSpawner : Item, ISpawner } } - public static object CreateObject(Type type, string itemtypestring) - { - return CreateObject(type, itemtypestring, true); - } + public static object CreateObject(Type type, string itemtypestring) => CreateObject(type, itemtypestring, true); public static object CreateObject(Type type, string itemtypestring, bool requireConstructible) { @@ -11052,7 +10644,7 @@ public class XmlSpawner : Item, ISpawner foreach (var spawner in spawnerlist) { - if (spawner != null && !spawner.Deleted && spawner.Running && spawner.SmartSpawning && spawner.IsInactivated) + if (spawner?.Deleted == false && spawner.Running && spawner.SmartSpawning && spawner.IsInactivated) { spawner.SmartRespawn(); } @@ -11078,15 +10670,12 @@ public class XmlSpawner : Item, ISpawner { private readonly XmlSpawner m_Spawner; - public SectorTimer(XmlSpawner spawner, TimeSpan delay) : base(delay, delay) - { - m_Spawner = spawner; - } + public SectorTimer(XmlSpawner spawner, TimeSpan delay) : base(delay, delay) => m_Spawner = spawner; protected override void OnTick() { // check the sectors - if (m_Spawner != null && !m_Spawner.Deleted && m_Spawner.Running && m_Spawner.IsInactivated) + if (m_Spawner?.Deleted == false && m_Spawner.Running && m_Spawner.IsInactivated) { if (m_Spawner.SmartSpawning) { @@ -11224,14 +10813,11 @@ public class XmlSpawner : Item, ISpawner { private readonly XmlSpawner m_spawner; - public InternalTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) - { - m_spawner = spawner; - } + public InternalTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_spawner = spawner; protected override void OnTick() { - if (m_spawner != null && !m_spawner.Deleted) + if (m_spawner?.Deleted == false) { m_spawner.RemoveSpawnObjects(); m_spawner.m_durActivated = false; @@ -11244,14 +10830,11 @@ public class XmlSpawner : Item, ISpawner { private readonly XmlSpawner m_Spawner; - public SpawnerTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) - { - m_Spawner = spawner; - } + public SpawnerTimer(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_Spawner = spawner; protected override void OnTick() { - if (m_Spawner != null && !m_Spawner.Deleted) + if (m_Spawner?.Deleted == false) { m_Spawner.OnTick(); } @@ -11263,14 +10846,11 @@ public class XmlSpawner : Item, ISpawner { private readonly XmlSpawner m_spawner; - public InternalTimer3(XmlSpawner spawner, TimeSpan delay) : base(delay) - { - m_spawner = spawner; - } + public InternalTimer3(XmlSpawner spawner, TimeSpan delay) : base(delay) => m_spawner = spawner; protected override void OnTick() { - if (m_spawner != null && !m_spawner.Deleted) + if (m_spawner?.Deleted == false) { // reenable triggering m_spawner.m_refractActivated = false; @@ -11347,7 +10927,7 @@ public class XmlSpawner : Item, ISpawner } } - if (m_ShowBoundsItems != null && m_ShowBoundsItems.Count > 0) + if (m_ShowBoundsItems?.Count > 0) { writer.Write(true); writer.Write(m_ShowBoundsItems); @@ -11588,461 +11168,442 @@ public class XmlSpawner : Item, ISpawner { case 32: case 31: - { - DisableGlobalAutoReset = reader.ReadBool(); - goto case 30; - } + { + DisableGlobalAutoReset = reader.ReadBool(); + goto case 30; + } case 30: - { - AllowNPCTrig = reader.ReadBool(); - goto case 29; - } + { + AllowNPCTrig = reader.ReadBool(); + goto case 29; + } case 29: - { - tmpSpawnListSize = reader.ReadInt(); - tmpSpawnsPer = new List(tmpSpawnListSize); - for (var i = 0; i < tmpSpawnListSize; ++i) { - var spawnsper = reader.ReadInt(); + tmpSpawnListSize = reader.ReadInt(); + tmpSpawnsPer = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) + { + var spawnsper = reader.ReadInt(); - tmpSpawnsPer.Add(spawnsper); + tmpSpawnsPer.Add(spawnsper); + } + goto case 28; } - goto case 28; - } case 28: - { - tmpPackRange = new List(tmpSpawnListSize); - for (var i = 0; i < tmpSpawnListSize; ++i) { - var packrange = reader.ReadInt(); + tmpPackRange = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) + { + var packrange = reader.ReadInt(); - tmpPackRange.Add(packrange); + tmpPackRange.Add(packrange); + } + goto case 27; } - goto case 27; - } case 27: - { - tmpDisableSpawn = new List(tmpSpawnListSize); - for (var i = 0; i < tmpSpawnListSize; ++i) { - var disablespawn = reader.ReadBool(); + tmpDisableSpawn = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) + { + var disablespawn = reader.ReadBool(); - tmpDisableSpawn.Add(disablespawn); + tmpDisableSpawn.Add(disablespawn); + } + goto case 26; } - goto case 26; - } case 26: - { - SpawnOnTrigger = reader.ReadBool(); - - if (version < 32) { - // Delete First & Last Modified - _ = reader.ReadDateTime(); - _ = reader.ReadDateTime(); + SpawnOnTrigger = reader.ReadBool(); + + if (version < 32) + { + // Delete First & Last Modified + _ = reader.ReadDateTime(); + _ = reader.ReadDateTime(); + } + goto case 25; } - goto case 25; - } case 25: - { - goto case 24; - } case 24: - { - tmpRestrictKillsToSubgroup = new List(tmpSpawnListSize); - tmpClearOnAdvance = new List(tmpSpawnListSize); - tmpMinDelay = new List(tmpSpawnListSize); - tmpMaxDelay = new List(tmpSpawnListSize); - tmpNextSpawn = new List(tmpSpawnListSize); - for (var i = 0; i < tmpSpawnListSize; ++i) { - var restrictkills = reader.ReadBool(); - var clearadvance = reader.ReadBool(); - var mind = reader.ReadDouble(); - var maxd = reader.ReadDouble(); - var nextspawn = reader.ReadDeltaTime(); + tmpRestrictKillsToSubgroup = new List(tmpSpawnListSize); + tmpClearOnAdvance = new List(tmpSpawnListSize); + tmpMinDelay = new List(tmpSpawnListSize); + tmpMaxDelay = new List(tmpSpawnListSize); + tmpNextSpawn = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) + { + var restrictkills = reader.ReadBool(); + var clearadvance = reader.ReadBool(); + var mind = reader.ReadDouble(); + var maxd = reader.ReadDouble(); + var nextspawn = reader.ReadDeltaTime(); - tmpRestrictKillsToSubgroup.Add(restrictkills); - tmpClearOnAdvance.Add(clearadvance); - tmpMinDelay.Add(mind); - tmpMaxDelay.Add(maxd); - tmpNextSpawn.Add(nextspawn); + tmpRestrictKillsToSubgroup.Add(restrictkills); + tmpClearOnAdvance.Add(clearadvance); + tmpMinDelay.Add(mind); + tmpMaxDelay.Add(maxd); + tmpNextSpawn.Add(nextspawn); + } + + var hasitems = reader.ReadBool(); + + if (hasitems) + { + m_ShowBoundsItems = reader.ReadEntityList(); + } + goto case 23; } - - var hasitems = reader.ReadBool(); - - if (hasitems) - { - m_ShowBoundsItems = reader.ReadEntityList(); - } - goto case 23; - } case 23: - { - IsInactivated = reader.ReadBool(); - SmartSpawning = reader.ReadBool(); + { + IsInactivated = reader.ReadBool(); + SmartSpawning = reader.ReadBool(); - goto case 22; - } + goto case 22; + } case 22: - { - SkillTrigger = reader.ReadString(); // note this will also register the skill - m_skill_that_triggered = (SkillName)reader.ReadInt(); - FreeRun = reader.ReadBool(); - TriggerMob = reader.ReadEntity(); - goto case 21; - } + { + SkillTrigger = reader.ReadString(); // note this will also register the skill + m_skill_that_triggered = (SkillName)reader.ReadInt(); + FreeRun = reader.ReadBool(); + TriggerMob = reader.ReadEntity(); + goto case 21; + } case 21: - { - DespawnTime = reader.ReadTimeSpan(); - goto case 20; - } + { + DespawnTime = reader.ReadTimeSpan(); + goto case 20; + } case 20: - { - tmpRequireSurface = new List(tmpSpawnListSize); - for (var i = 0; i < tmpSpawnListSize; ++i) { - var requiresurface = reader.ReadBool(); - tmpRequireSurface.Add(requiresurface); + tmpRequireSurface = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) + { + var requiresurface = reader.ReadBool(); + tmpRequireSurface.Add(requiresurface); + } + goto case 19; } - goto case 19; - } case 19: - { - ConfigFile = reader.ReadString(); - m_OnHold = reader.ReadBool(); - m_HoldSequence = reader.ReadBool(); - - if (version < 32) { - // // Delete First & Last Modified By - // // Delete First & Last Modified By - _ = reader.ReadString(); - _ = reader.ReadString(); - } + ConfigFile = reader.ReadString(); + m_OnHold = reader.ReadBool(); + m_HoldSequence = reader.ReadBool(); - // deserialize the keyword tag list - var tagcount = reader.ReadInt(); - m_KeywordTagList = new List(tagcount); - for (var i = 0; i < tagcount; i++) - { - var tag = new BaseXmlSpawner.KeywordTag(null, this); - tag.Deserialize(reader); + if (version < 32) + { + // // Delete First & Last Modified By + // // Delete First & Last Modified By + _ = reader.ReadString(); + _ = reader.ReadString(); + } + + // deserialize the keyword tag list + var tagcount = reader.ReadInt(); + m_KeywordTagList = new List(tagcount); + for (var i = 0; i < tagcount; i++) + { + var tag = new BaseXmlSpawner.KeywordTag(null, this); + tag.Deserialize(reader); + } + goto case 18; } - goto case 18; - } case 18: - { - AllowGhostTrig = reader.ReadBool(); - goto case 17; - } + { + AllowGhostTrig = reader.ReadBool(); + goto case 17; + } case 17: - { - goto case 16; - } case 16: - { - hasnewobjectinfo = true; - SequentialSpawn = reader.ReadInt(); - var seqdelay = reader.ReadTimeSpan(); - m_SeqEnd = Core.Now + seqdelay; - - tmpSubGroup = new List(tmpSpawnListSize); - tmpSequentialResetTime = new List(tmpSpawnListSize); - tmpSequentialResetTo = new List(tmpSpawnListSize); - tmpKillsNeeded = new List(tmpSpawnListSize); - for (var i = 0; i < tmpSpawnListSize; ++i) { - var subgroup = reader.ReadInt(); - var resettime = reader.ReadDouble(); - var resetto = reader.ReadInt(); - var killsneeded = reader.ReadInt(); - tmpSubGroup.Add(subgroup); - tmpSequentialResetTime.Add(resettime); - tmpSequentialResetTo.Add(resetto); - tmpKillsNeeded.Add(killsneeded); + hasnewobjectinfo = true; + SequentialSpawn = reader.ReadInt(); + var seqdelay = reader.ReadTimeSpan(); + m_SeqEnd = Core.Now + seqdelay; + + tmpSubGroup = new List(tmpSpawnListSize); + tmpSequentialResetTime = new List(tmpSpawnListSize); + tmpSequentialResetTo = new List(tmpSpawnListSize); + tmpKillsNeeded = new List(tmpSpawnListSize); + for (var i = 0; i < tmpSpawnListSize; ++i) + { + var subgroup = reader.ReadInt(); + var resettime = reader.ReadDouble(); + var resetto = reader.ReadInt(); + var killsneeded = reader.ReadInt(); + tmpSubGroup.Add(subgroup); + tmpSequentialResetTime.Add(resettime); + tmpSequentialResetTo.Add(resetto); + tmpKillsNeeded.Add(killsneeded); + } + m_RegionName = reader.ReadString(); + goto case 15; } - m_RegionName = reader.ReadString(); - goto case 15; - } case 15: - { - ExternalTriggering = reader.ReadBool(); - ExtTrigState = reader.ReadBool(); - goto case 14; - } + { + ExternalTriggering = reader.ReadBool(); + ExtTrigState = reader.ReadBool(); + goto case 14; + } case 14: - { - m_NoItemTriggerName = reader.ReadString(); - goto case 13; - } + { + m_NoItemTriggerName = reader.ReadString(); + goto case 13; + } case 13: - { - GumpState = reader.ReadString(); - goto case 12; - } + { + GumpState = reader.ReadString(); + goto case 12; + } case 12: - { - var todtype = reader.ReadInt(); - switch (todtype) { - case (int)TODModeType.Gametime: - { - TODMode = TODModeType.Gametime; - break; - } - case (int)TODModeType.Realtime: - { - TODMode = TODModeType.Realtime; - break; - } + TODMode = (TODModeType)reader.ReadInt(); + goto case 11; } - goto case 11; - } case 11: - { - KillReset = reader.ReadInt(); - m_skipped = reader.ReadBool(); - m_spawncheck = reader.ReadInt(); - goto case 10; - } + { + KillReset = reader.ReadInt(); + m_skipped = reader.ReadBool(); + m_spawncheck = reader.ReadInt(); + goto case 10; + } case 10: - { - SetItem = reader.ReadEntity(); - goto case 9; - } + { + SetItem = reader.ReadEntity(); + goto case 9; + } case 9: - { - TriggerProbability = reader.ReadDouble(); - goto case 8; - } + { + TriggerProbability = reader.ReadDouble(); + goto case 8; + } case 8: - { - MobTriggerProp = reader.ReadString(); - MobTriggerName = reader.ReadString(); - PlayerTriggerProp = reader.ReadString(); - goto case 7; - } + { + MobTriggerProp = reader.ReadString(); + MobTriggerName = reader.ReadString(); + PlayerTriggerProp = reader.ReadString(); + goto case 7; + } case 7: - { - SpeechTrigger = reader.ReadString(); - goto case 6; - } + { + SpeechTrigger = reader.ReadString(); + goto case 6; + } case 6: - { - m_ItemTriggerName = reader.ReadString(); - goto case 5; - } + { + m_ItemTriggerName = reader.ReadString(); + goto case 5; + } case 5: - { - ProximityMsg = reader.ReadString(); - m_ObjectPropertyItem = reader.ReadEntity(); - m_ObjectPropertyName = reader.ReadString(); - m_killcount = reader.ReadInt(); - goto case 4; - } + { + ProximityMsg = reader.ReadString(); + m_ObjectPropertyItem = reader.ReadEntity(); + m_ObjectPropertyName = reader.ReadString(); + m_killcount = reader.ReadInt(); + goto case 4; + } case 4: - { - haveproximityrange = true; - m_ProximityRange = reader.ReadInt(); - ProximitySound = reader.ReadInt(); - m_proximityActivated = reader.ReadBool(); - m_durActivated = reader.ReadBool(); - m_refractActivated = reader.ReadBool(); - StackAmount = reader.ReadInt(); - TODStart = reader.ReadTimeSpan(); - TODEnd = reader.ReadTimeSpan(); - RefractMin = reader.ReadTimeSpan(); - RefractMax = reader.ReadTimeSpan(); - if (m_refractActivated) { - var delay = reader.ReadTimeSpan(); - DoTimer3(delay); + haveproximityrange = true; + m_ProximityRange = reader.ReadInt(); + ProximitySound = reader.ReadInt(); + m_proximityActivated = reader.ReadBool(); + m_durActivated = reader.ReadBool(); + m_refractActivated = reader.ReadBool(); + StackAmount = reader.ReadInt(); + TODStart = reader.ReadTimeSpan(); + TODEnd = reader.ReadTimeSpan(); + RefractMin = reader.ReadTimeSpan(); + RefractMax = reader.ReadTimeSpan(); + if (m_refractActivated) + { + var delay = reader.ReadTimeSpan(); + DoTimer3(delay); + } + if (m_durActivated) + { + var delay = reader.ReadTimeSpan(); + DoTimer2(delay); + } + goto case 3; } - if (m_durActivated) - { - var delay = reader.ReadTimeSpan(); - DoTimer2(delay); - } - goto case 3; - } case 3: - { - m_ShowContainerStatic = reader.ReadEntity(); - goto case 2; - } + { + m_ShowContainerStatic = reader.ReadEntity(); + goto case 2; + } case 2: - { - m_Duration = reader.ReadTimeSpan(); - goto case 1; - } + { + m_Duration = reader.ReadTimeSpan(); + goto case 1; + } case 1: - { - UniqueId = reader.ReadString(); - HomeRangeIsRelative = reader.ReadBool(); - goto case 0; - } + { + UniqueId = reader.ReadString(); + HomeRangeIsRelative = reader.ReadBool(); + goto case 0; + } case 0: - { - m_Name = reader.ReadString(); - // backward compatibility with old name storage - if (!string.IsNullOrEmpty(m_Name)) { - Name = m_Name; - } - - m_X = reader.ReadInt(); - m_Y = reader.ReadInt(); - m_Width = reader.ReadInt(); - m_Height = reader.ReadInt(); - //we HAVE to check if the area is even or if coordinates point to the original spawner, otherwise it's custom area! - if (m_Width == m_Height && m_Width % 2 == 0 && m_X + m_Width / 2 == X && m_Y + m_Height / 2 == Y) - { - m_SpawnRange = m_Width / 2; - } - else - { - m_SpawnRange = -1; - } - - if (!haveproximityrange) - { - m_ProximityRange = -1; - } - WayPoint = reader.ReadEntity(); - m_Group = reader.ReadBool(); - m_MinDelay = reader.ReadTimeSpan(); - m_MaxDelay = reader.ReadTimeSpan(); - m_Count = reader.ReadInt(); - m_Team = reader.ReadInt(); - m_HomeRange = reader.ReadInt(); - m_Running = reader.ReadBool(); - - if (m_Running) - { - var delay = reader.ReadTimeSpan(); - DoTimer(delay); - } - - // Read in the size of the spawn object list - var SpawnListSize = reader.ReadInt(); - m_SpawnObjects = new List(SpawnListSize); - for (var i = 0; i < SpawnListSize; ++i) - { - var TypeName = reader.ReadString(); - var TypeMaxCount = reader.ReadInt(); - - var TheSpawnObject = new SpawnObject(TypeName, TypeMaxCount); - - m_SpawnObjects.Add(TheSpawnObject); - - var typeName = BaseXmlSpawner.ParseObjectType(TypeName); - - if (typeName == null || AssemblyHandler.FindTypeByName(typeName) == null && - !BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && !typeName.Contains('{') && !typeName.StartsWith("*") && !typeName.StartsWith("#")) + m_Name = reader.ReadString(); + // backward compatibility with old name storage + if (!string.IsNullOrEmpty(m_Name)) { - m_WarnTimer ??= new WarnTimer2(); - - m_WarnTimer.Add(Location, Map, TypeName); - - status_str = $"invalid type: {typeName}"; + Name = m_Name; } - // Read in the number of spawns already - var SpawnedCount = reader.ReadInt(); - - TheSpawnObject.SpawnedObjects = new List(SpawnedCount); - - for (var x = 0; x < SpawnedCount; ++x) + m_X = reader.ReadInt(); + m_Y = reader.ReadInt(); + m_Width = reader.ReadInt(); + m_Height = reader.ReadInt(); + //we HAVE to check if the area is even or if coordinates point to the original spawner, otherwise it's custom area! + if (m_Width == m_Height && m_Width % 2 == 0 && m_X + m_Width / 2 == X && m_Y + m_Height / 2 == Y) { - var serial = reader.ReadInt(); - if (serial < -1) - { - // minusone is reserved for unknown types by default - // minustwo on is used for referencing keyword tags - var tagserial = -1 * (serial + 2); - // get the tag with that serial and add it - var t = BaseXmlSpawner.GetFromTagList(this, tagserial); - if (t != null) - { - TheSpawnObject.SpawnedObjects.Add(t); - } - } - else - { - var e = World.FindEntity((Serial)(uint)serial); - - if (e != null) - { - TheSpawnObject.SpawnedObjects.Add(e); - } - } + m_SpawnRange = m_Width / 2; } - } - // now have to reintegrate the later version spawnobject information into the earlier version desered objects - if (hasnewobjectinfo && tmpSpawnListSize == SpawnListSize) - { + else + { + m_SpawnRange = -1; + } + + if (!haveproximityrange) + { + m_ProximityRange = -1; + } + WayPoint = reader.ReadEntity(); + m_Group = reader.ReadBool(); + m_MinDelay = reader.ReadTimeSpan(); + m_MaxDelay = reader.ReadTimeSpan(); + m_Count = reader.ReadInt(); + m_Team = reader.ReadInt(); + m_HomeRange = reader.ReadInt(); + m_Running = reader.ReadBool(); + + if (m_Running) + { + var delay = reader.ReadTimeSpan(); + DoTimer(delay); + } + + // Read in the size of the spawn object list + var SpawnListSize = reader.ReadInt(); + m_SpawnObjects = new List(SpawnListSize); for (var i = 0; i < SpawnListSize; ++i) { - var so = m_SpawnObjects[i]; + var TypeName = reader.ReadString(); + var TypeMaxCount = reader.ReadInt(); - so.SubGroup = tmpSubGroup[i]; - so.SequentialResetTime = tmpSequentialResetTime[i]; - so.SequentialResetTo = tmpSequentialResetTo[i]; - so.KillsNeeded = tmpKillsNeeded[i]; - if (version > 19) + var TheSpawnObject = new SpawnObject(TypeName, TypeMaxCount); + + m_SpawnObjects.Add(TheSpawnObject); + + var typeName = BaseXmlSpawner.ParseObjectType(TypeName); + + if (typeName == null || AssemblyHandler.FindTypeByName(typeName) == null && + !BaseXmlSpawner.IsTypeOrItemKeyword(typeName) && !typeName.Contains('{') && !typeName.StartsWith("*") && !typeName.StartsWith("#")) { - so.RequireSurface = tmpRequireSurface[i]; + m_WarnTimer ??= new WarnTimer2(); + + m_WarnTimer.Add(Location, Map, TypeName); + + status_str = $"invalid type: {typeName}"; } - var restrictkills = false; - var clearadvance = true; - double mind = -1; - double maxd = -1; - var nextspawn = DateTime.MinValue; - if (version > 23) - { - restrictkills = tmpRestrictKillsToSubgroup[i]; - clearadvance = tmpClearOnAdvance[i]; - mind = tmpMinDelay[i]; - maxd = tmpMaxDelay[i]; - nextspawn = tmpNextSpawn[i]; - } - so.RestrictKillsToSubgroup = restrictkills; - so.ClearOnAdvance = clearadvance; - so.MinDelay = mind; - so.MaxDelay = maxd; - so.NextSpawn = nextspawn; + // Read in the number of spawns already + var SpawnedCount = reader.ReadInt(); - var disablespawn = false; - if (version > 26) - { - disablespawn = tmpDisableSpawn[i]; - } - so.Disabled = disablespawn; + TheSpawnObject.SpawnedObjects = new List(SpawnedCount); - var packrange = -1; - if (version > 27) + for (var x = 0; x < SpawnedCount; ++x) { - packrange = tmpPackRange[i]; - } - so.PackRange = packrange; + var serial = reader.ReadInt(); + if (serial < -1) + { + // minusone is reserved for unknown types by default + // minustwo on is used for referencing keyword tags + var tagserial = -1 * (serial + 2); + // get the tag with that serial and add it + var t = BaseXmlSpawner.GetFromTagList(this, tagserial); + if (t != null) + { + TheSpawnObject.SpawnedObjects.Add(t); + } + } + else + { + var e = World.FindEntity((Serial)(uint)serial); - var spawnsper = 1; - if (version > 28) - { - spawnsper = tmpSpawnsPer[i]; + if (e != null) + { + TheSpawnObject.SpawnedObjects.Add(e); + } + } } - so.SpawnsPerTick = spawnsper; - } - } + // now have to reintegrate the later version spawnobject information into the earlier version desered objects + if (hasnewobjectinfo && tmpSpawnListSize == SpawnListSize) + { + for (var i = 0; i < SpawnListSize; ++i) + { + var so = m_SpawnObjects[i]; - break; - } + so.SubGroup = tmpSubGroup[i]; + so.SequentialResetTime = tmpSequentialResetTime[i]; + so.SequentialResetTo = tmpSequentialResetTo[i]; + so.KillsNeeded = tmpKillsNeeded[i]; + if (version > 19) + { + so.RequireSurface = tmpRequireSurface[i]; + } + + var restrictkills = false; + var clearadvance = true; + double mind = -1; + double maxd = -1; + var nextspawn = DateTime.MinValue; + if (version > 23) + { + restrictkills = tmpRestrictKillsToSubgroup[i]; + clearadvance = tmpClearOnAdvance[i]; + mind = tmpMinDelay[i]; + maxd = tmpMaxDelay[i]; + nextspawn = tmpNextSpawn[i]; + } + so.RestrictKillsToSubgroup = restrictkills; + so.ClearOnAdvance = clearadvance; + so.MinDelay = mind; + so.MaxDelay = maxd; + so.NextSpawn = nextspawn; + + var disablespawn = false; + if (version > 26) + { + disablespawn = tmpDisableSpawn[i]; + } + so.Disabled = disablespawn; + + var packrange = -1; + if (version > 27) + { + packrange = tmpPackRange[i]; + } + so.PackRange = packrange; + + var spawnsper = 1; + if (version > 28) + { + spawnsper = tmpSpawnsPer[i]; + } + so.SpawnsPerTick = spawnsper; + + } + } + + break; + } } if (m_RegionName != null) { @@ -12084,9 +11645,9 @@ public class XmlSpawner : Item, ISpawner _ = sb.Append(":OBJ="); // Separates multiple object types } - _ = sb.AppendFormat("{0}:MX={1}:SB={2}:RT={3}:TO={4}:KL={5}:RK={6}:CA={7}:DN={8}:DX={9}:SP={10}:PR={11}", - so.TypeName, so.ActualMaxCount, so.SubGroup, so.SequentialResetTime, so.SequentialResetTo, so.KillsNeeded, - so.RestrictKillsToSubgroup ? 1 : 0, so.ClearOnAdvance ? 1 : 0, so.MinDelay, so.MaxDelay, so.SpawnsPerTick, so.PackRange); + _ = sb.Append( + $"{so.TypeName}:MX={so.ActualMaxCount}:SB={so.SubGroup}:RT={so.SequentialResetTime}:TO={so.SequentialResetTo}:KL={so.KillsNeeded}:RK={(so.RestrictKillsToSubgroup ? 1 : 0)}:CA={(so.ClearOnAdvance ? 1 : 0)}:DN={so.MinDelay}:DX={so.MaxDelay}:SP={so.SpawnsPerTick}:PR={so.PackRange}" + ); } return sb.ToString(); @@ -12111,15 +11672,7 @@ public class XmlSpawner : Item, ISpawner public int MaxCount { - get - { - if (Disabled) - { - return 0; - } - - return ActualMaxCount; - } + get => Disabled ? 0 : ActualMaxCount; set => ActualMaxCount = value; } public int ActualMaxCount { get; set; } @@ -12345,14 +11898,9 @@ public class XmlSpawner : Item, ISpawner // ClearOnAdvance parmstr = GetParm(s, ":CA="); - var clearAdvance = true; // if kills needed is zero, then set CA to false by default. This maintains consistency with the - // previous default behavior for old spawn specs that havent specified CA - if (killsNeeded == 0) - { - clearAdvance = false; - } - + // previous default behavior for old spawn specs that haven't specified CA + bool clearAdvance = killsNeeded != 0; if (parmstr != null) { try { clearAdvance = int.Parse(parmstr) == 1; } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs index a708f2c22..7669f1bb2 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs @@ -893,14 +893,14 @@ public class XmlSpawnerGump : Gump if (grpval != m_Spawner.SpawnObjects[i].MinDelay) { m_Spawner.SpawnObjects[i].MinDelay = grpval; - m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + XmlSpawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); } } else { m_Spawner.SpawnObjects[i].MinDelay = -1; m_Spawner.SpawnObjects[i].MaxDelay = -1; - m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + XmlSpawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); } } @@ -922,14 +922,14 @@ public class XmlSpawnerGump : Gump if (grpval != m_Spawner.SpawnObjects[i].MaxDelay) { m_Spawner.SpawnObjects[i].MaxDelay = grpval; - m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + XmlSpawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); } } else { m_Spawner.SpawnObjects[i].MinDelay = -1; m_Spawner.SpawnObjects[i].MaxDelay = -1; - m_Spawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); + XmlSpawner.RefreshNextSpawnTime(m_Spawner.SpawnObjects[i]); } } @@ -1031,7 +1031,7 @@ public class XmlSpawnerGump : Gump { m_Spawner.TryRespawn(); //m_Spawner.AdvanceSequential(); - m_Spawner.m_killcount = 0; + m_Spawner.KillCount = 0; break; } case 4: // Goto diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs deleted file mode 100644 index ce083ed65..000000000 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/WriteMulti.cs +++ /dev/null @@ -1,461 +0,0 @@ -using System.IO; -using System.Collections; -using Server.Items; -using Server.Mobiles; - -namespace Server.Engines.XmlSpawner2; - -public class WriteMulti -{ - private class TileEntry - { - public int ID; - public int X; - public int Y; - public int Z; - - public TileEntry(int id, int x, int y, int z) - { - ID = id; - X = x; - Y = y; - Z = z; - } - } - - public static void Initialize() - { - - CommandSystem.Register("WriteMulti", XmlSpawner.DiskAccessLevel, WriteMulti_OnCommand); - } - - [Usage("WriteMulti [zmin zmax][-noitems][-nostatics][-nomultis][-noaddons][-invisible]")] - [Description("Creates a multi text file from the objects within the targeted area. The min/max z range can also be specified.")] - public static void WriteMulti_OnCommand(CommandEventArgs e) - { - if (e == null || e.Mobile == null) - { - return; - } - - if (e.Mobile.AccessLevel < XmlSpawner.DiskAccessLevel) - { - e.Mobile.SendMessage("You do not have rights to perform this command."); - return; - } - - if (e.Arguments != null && e.Arguments.Length < 1) - { - e.Mobile.SendMessage($"Usage: {e.Command} [zmin zmax][-noitems][-nostatics][-nomultis][-noaddons][-invisible]"); - return; - } - - string filename = e.Arguments[0]; - - int zmin = int.MinValue; - int zmax = int.MinValue; - bool includeitems = true; - bool includestatics = true; - bool includemultis = true; - bool includeaddons = true; - bool includeinvisible = false; - - if (e.Arguments.Length > 1) - { - int index = 1; - while (index < e.Arguments.Length) - { - if (e.Arguments[index] == "-noitems") - { - includeitems = false; - index++; - } - else if (e.Arguments[index] == "-nostatics") - { - includestatics = false; - index++; - } - else if (e.Arguments[index] == "-nomultis") - { - includemultis = false; - index++; - } - else if (e.Arguments[index] == "-noaddons") - { - includeaddons = false; - index++; - } - else if (e.Arguments[index] == "-invisible") - { - includeinvisible = true; - index++; - } - else - { - try - { - zmin = int.Parse(e.Arguments[index++]); - zmax = int.Parse(e.Arguments[index++]); - } - catch - { - e.Mobile.SendMessage($"{e.Command} : Invalid zmin zmax arguments"); - return; - } - } - } - } - - string dirname; - if (Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) - { - // put it in the defaults directory if it exists - dirname = $"{XmlSpawner.XmlSpawnDir}/{filename}"; - } - else - { - // otherwise just put it in the main installation dir - dirname = filename; - } - - // check to see if the file already exists and can be written to by the owner - if (File.Exists(dirname)) - { - - // check the file - try - { - StreamReader op = new StreamReader(dirname, false); - string line = op.ReadLine(); - - op.Close(); - - // check the first line - if (line != null && line.Length > 0) - { - - string[] args = line.Split(" ".ToCharArray(), 3); - if (args.Length < 3) - { - e.Mobile.SendMessage($"Cannot overwrite file {dirname} : not owner"); - return; - } - - if (args[2] != e.Mobile.Name) - { - e.Mobile.SendMessage($"Cannot overwrite file {dirname} : not owner"); - return; - } - } - else - { - e.Mobile.SendMessage($"Cannot overwrite file {dirname} : not owner"); - return; - } - - } - catch - { - e.Mobile.SendMessage($"Cannot overwrite file {dirname}"); - return; - } - - } - - DefineMultiArea(e.Mobile, dirname, zmin, zmax, includeitems, includestatics, includemultis, includeinvisible, includeaddons); - } - - public static void DefineMultiArea(Mobile m, string dirname, int zmin, int zmax, bool includeitems, bool includestatics, - bool includemultis, bool includeinvisible, bool includeaddons) - { - BoundingBoxPicker.Begin( - m, - (map, start, end) => DefineMultiArea_Callback( - m, - map, - start, - end, - dirname, - zmin, - zmax, - includeitems, - includestatics, - includemultis, - includeinvisible, - includeaddons - ) - ); - } - - private static void DefineMultiArea_Callback( - Mobile from, - Map map, - Point3D start, - Point3D end, - string dirname, - int zmin, - int zmax, - bool includeitems, - bool includestatics, - bool includemultis, - bool includeinvisible, - bool includeaddons - ) - { - if (from != null && map != null) - { - ArrayList itemlist = new ArrayList(); - ArrayList staticlist = new ArrayList(); - ArrayList tilelist = new ArrayList(); - - int sx = start.X > end.X ? end.X : start.X; - int sy = start.Y > end.Y ? end.Y : start.Y; - int ex = start.X < end.X ? end.X : start.X; - int ey = start.Y < end.Y ? end.Y : start.Y; - - // find all of the world-placed items within the specified area - if (includeitems) - { - // make the first pass for items only - IPooledEnumerable eable = map.GetItemsInBounds(new Rectangle2D(sx, sy, ex - sx + 1, ey - sy + 1)); - - foreach (Item item in eable) - { - // is it within the bounding area - if (item.Parent == null && (zmin == int.MinValue || item.Location.Z >= zmin && item.Location.Z <= zmax)) - { - // add the item - if ((includeinvisible || item.Visible) && item.ItemID <= 16383) - { - itemlist.Add(item); - } - } - } - - eable.Free(); - - int searchrange = 100; - - // make the second expanded pass to pick up addon components and multi components - eable = map.GetItemsInBounds(new Rectangle2D(sx - searchrange, sy - searchrange, ex - sy + searchrange * 2 + 1, - ey - sy + searchrange * 2 + 1)); - - foreach (Item item in eable) - { - // is it within the bounding area - if (item.Parent == null) - { - - if (item is BaseAddon addon && includeaddons) - { - // go through all of the addon components - foreach (AddonComponent c in addon.Components) - { - int x = c.X; - int y = c.Y; - int z = c.Z; - - if ((includeinvisible || addon.Visible) && (addon.ItemID <= 16383 || includemultis) && - x >= sx && x <= ex && y >= sy && y <= ey && (zmin == int.MinValue || z >= zmin && z <= zmax)) - { - itemlist.Add(c); - } - } - } - - if (item is BaseMulti multi && includemultis) - { - // go through all of the multi components - MultiComponentList mcl = multi.Components; - if (mcl != null && mcl.List != null) - { - for (int i = 0; i < mcl.List.Length; i++) - { - MultiTileEntry t = mcl.List[i]; - - int x = t.OffsetX + multi.X; - int y = t.OffsetY + multi.Y; - int z = t.OffsetZ + multi.Z; - int itemID = t.ItemId & 0x3FFF; - - if (x >= sx && x <= ex && y >= sy && y <= ey && (zmin == int.MinValue || z >= zmin && z <= zmax)) - { - tilelist.Add(new TileEntry(itemID, x, y, z)); - } - } - - } - } - } - } - - eable.Free(); - } - - // find all of the static tiles within the specified area - if (includestatics) - { - // count the statics - for (int x = sx; x < ex; x++) - { - for (int y = sy; y < ey; y++) - { - StaticTile[] statics = map.Tiles.GetStaticTiles(x, y, false); - - for (int j = 0; j < statics.Length; j++) - { - if (zmin == int.MinValue || statics[j].Z >= zmin && statics[j].Z <= zmax) - { - staticlist.Add(new TileEntry(statics[j].ID & 0x3FFF, x, y, statics[j].Z)); - } - } - } - } - } - - int nstatics = staticlist.Count; - int nitems = itemlist.Count; - int ntiles = tilelist.Count; - - int ntotal = nitems + nstatics + ntiles; - - int ninvisible = 0; - int nmultis = ntiles; - int naddons = 0; - - foreach (Item item in itemlist) - { - int x = item.X - from.X; - int y = item.Y - from.Y; - int z = item.Z - from.Z; - - if (item.ItemID > 16383) - { - nmultis++; - } - if (!item.Visible) - { - ninvisible++; - } - if (item is BaseAddon || item is AddonComponent) - { - naddons++; - } - } - - try - { - // open the file, overwrite any previous contents - StreamWriter op = new StreamWriter(dirname, false); - - if (op != null) - { - // write the header - op.WriteLine("1 version {0}", from.Name); - op.WriteLine("{0} num components", ntotal); - - // write out the items - foreach (Item item in itemlist) - { - - int x = item.X - from.X; - int y = item.Y - from.Y; - int z = item.Z - from.Z; - - if (item.Hue > 0) - { - // format is x y z visible hue - op.WriteLine("{0} {1} {2} {3} {4} {5}", item.ItemID, x, y, z, item.Visible ? 1 : 0, item.Hue); - } - else - { - // format is x y z visible - op.WriteLine("{0} {1} {2} {3} {4}", item.ItemID, x, y, z, item.Visible ? 1 : 0); - } - } - - if (includestatics) - { - foreach (TileEntry s in staticlist) - { - int x = s.X - from.X; - int y = s.Y - from.Y; - int z = s.Z - from.Z; - int ID = s.ID; - op.WriteLine("{0} {1} {2} {3} {4}", ID, x, y, z, 1); - } - } - - if (includemultis) - { - foreach (TileEntry s in tilelist) - { - int x = s.X - from.X; - int y = s.Y - from.Y; - int z = s.Z - from.Z; - int ID = s.ID; - op.WriteLine("{0} {1} {2} {3} {4}", ID, x, y, z, 1); - } - } - } - - op.Close(); - } - catch - { - from.SendMessage($"Error writing multi file {dirname}"); - return; - } - - from.SendMessage(66, "WriteMulti results:"); - - if (includeitems) - { - from.SendMessage(66, $"Included {nitems} items"); - - if (includemultis) - { - from.SendMessage($"{nmultis} multis"); - } - else - { - from.SendMessage(33, "Ignored multis"); - } - - if (includeinvisible) - { - from.SendMessage($"{ninvisible} invisible"); - } - else - { - from.SendMessage(33, "Ignored invisible"); - } - - if (includeaddons) - { - from.SendMessage($"{naddons} addons"); - } - else - { - from.SendMessage(33, "Ignored addons"); - } - - } - else - { - from.SendMessage(33, "Ignored items"); - } - - if (includestatics) - { - from.SendMessage(66, $"Included {nstatics} statics"); - } - else - { - from.SendMessage(33, "Ignored statics"); - } - - from.SendMessage(66, $"Saved {ntotal} components to {dirname}"); - } - } -} diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs deleted file mode 100644 index 34ea93a2e..000000000 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlFind.cs +++ /dev/null @@ -1,2366 +0,0 @@ -using Server.Accounting; -using Server.Commands; -using Server.Commands.Generic; -using Server.Gumps; -using Server.Items; -using Server.Multis; -using Server.Network; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using Server.Engines.Spawners; - -namespace Server.Mobiles; - -public class XmlFindGump : Gump -{ - public class XmlFindThread - { - readonly SearchCriteria m_SearchCriteria; - readonly Mobile m_From; - readonly string m_commandstring; - - public XmlFindThread(Mobile from, SearchCriteria criteria, string commandstring) - { - m_SearchCriteria = criteria; - m_From = from; - m_commandstring = commandstring; - } - - public void XmlFindThreadMain() - { - if (m_From == null) - { - return; - } - - string status_str; - - ArrayList results = Search(m_SearchCriteria, out status_str); - - XmlFindGump gump = new XmlFindGump(m_From, m_From.Location, m_From.Map, true, true, false, - - m_SearchCriteria, - - results, -1, 0, null, m_commandstring, - false, false, false, false, false, false, 0, 0); - - // display the updated gump synched with the main server thread - Core.LoopContext.Post(() => GumpDisplayCallback(m_From, gump, status_str)); - - } - - public void GumpDisplayCallback(Mobile from, XmlFindGump gump, string status_str) - { - if (from != null && !from.Deleted) - { - from.SendGump(gump); - if (status_str != null) - { - from.SendMessage(33, $"XmlFind: {status_str}"); - } - } - } - } - - private const int MaxEntries = 18; - private const int MaxEntriesPerPage = 18; - - public class SearchEntry - { - public bool Selected; - public object Object; - - public SearchEntry(object o) => Object = o; - } - - public class SearchCriteria - { - public bool Dosearchtype; - public bool Dosearchname; - public bool Dosearchrange; - public bool Dosearchregion; - public bool Dosearchspawnentry; - public bool Dosearchspawntype; - public bool Dosearchcondition; - public bool Dosearchfel; - public bool Dosearchtram; - public bool Dosearchmal; - public bool Dosearchilsh; - public bool Dosearchtok; - public bool Dosearchter; - public bool Dosearchint; - public bool Dosearchnull; - public bool Dosearcherr; - public bool Dosearchage; - public bool Dohidevalidint; - public bool Searchagedirection; - public double Searchage; - public int Searchrange; - public string Searchregion; - public string Searchcondition; - public string Searchtype; - public string Searchname; - public string Searchspawnentry; - - public Map Currentmap; - public Point3D Currentloc; - - public SearchCriteria(bool dotype, bool doname, bool dorange, bool doregion, bool doentry, bool doentrytype, bool docondition, bool dofel, bool dotram, - bool domal, bool doilsh, bool dotok, bool doter, bool doint, bool donull, bool doerr, bool doage, bool dohidevalid, - bool agedirection, double age, int range, string region, string condition, string type, string name, string entry - ) - { - Dosearchtype = dotype; - Dosearchname = doname; - Dosearchrange = dorange; - Dosearchregion = doregion; - Dosearchspawnentry = doentry; - Dosearchspawntype = doentrytype; - Dosearchcondition = docondition; - Dosearchfel = dofel; - Dosearchtram = dotram; - Dosearchmal = domal; - Dosearchilsh = doilsh; - Dosearchtok = dotok; - Dosearchter = doter; - Dosearchint = doint; - Dosearchnull = donull; - Dosearcherr = doerr; - Dosearchage = doage; - Dohidevalidint = dohidevalid; - Searchagedirection = agedirection; - Searchage = age; - Searchrange = range; - Searchregion = region; - Searchcondition = condition; - Searchtype = type; - Searchname = name; - Searchspawnentry = entry; - } - - public SearchCriteria() - { - } - } - - private readonly SearchCriteria m_SearchCriteria; - private bool Sorttype; - private bool Sortrange; - private bool Sortname; - private bool Sortmap; - private bool Sortselect; - private readonly Mobile m_From; - private readonly Point3D StartingLoc; - private readonly Map StartingMap; - private bool m_ShowExtension; - private bool Descendingsort; - private int Selected; - private int DisplayFrom; - private string SaveFilename; - private string CommandString; - - private bool SelectAll; - - private ArrayList m_SearchList; - - public static void Initialize() - { - CommandSystem.Register("XmlFind", AccessLevel.GameMaster, XmlFind_OnCommand); - } - - private static bool TestRange(object o, int range, Map currentmap, Point3D currentloc) - { - if (range < 0) - { - return true; - } - - if (o is Item item) - { - if (item.Map != currentmap) - { - return false; - } - - // is the item in a container? - // if so, then check the range of the parent rather than the item - Point3D loc = item.Location; - if (item.Parent != null && item.RootParent != null) - { - if (item.RootParent is Mobile mobile) - { - loc = mobile.Location; - } - else - if (item.RootParent is Container container) - { - loc = container.Location; - } - - } - return Utility.InRange(currentloc, loc, range); - - } - if (o is Mobile mob) - { - if (mob.Map != currentmap) - { - return false; - } - - return Utility.InRange(currentloc, mob.Location, range); - - } - return false; - } - - private static bool TestRegion(object o, string regionname) - { - if (regionname == null) - { - return false; - } - - if (o is Item item) - { - // is the item in a container? - // if so, then check the region of the parent rather than the item - Point3D loc = item.Location; - if (item.Parent != null && item.RootParent != null) - { - if (item.RootParent is Mobile mobile) - { - loc = mobile.Location; - } - else - if (item.RootParent is Container container) - { - loc = container.Location; - } - } - - Region r = Region.Regions.FirstOrDefault(reg => reg.Map == item.Map && !string.IsNullOrEmpty(reg.Name) && string.Equals(reg.Name, regionname, StringComparison.CurrentCultureIgnoreCase)); - - if (r == null) - { - return false; - } - - return r.Contains(loc); - } - - if (o is Mobile mob) - { - Region r = Region.Regions.FirstOrDefault(reg => reg.Map == mob.Map && !string.IsNullOrEmpty(reg.Name) && string.Equals(reg.Name, regionname, StringComparison.CurrentCultureIgnoreCase)); - - if (r == null) - { - return false; - } - - return r.Contains(mob.Location); - - } - - return false; - } - - private static bool TestAge(object o, double age, bool direction) - { - if (age <= 0) - { - return true; - } - - if (o is Mobile mob) - { - if (direction) - { - // true means allow only mobs greater than the age - if (Core.Now - mob.Created > TimeSpan.FromHours(age)) - { - return true; - } - } - else - { - // false means allow only mobs less than the age - if (Core.Now - mob.Created < TimeSpan.FromHours(age)) - { - return true; - } - } - } - - return false; - } - - private static void IgnoreManagedInternal(object i, ref ArrayList ignoreList) - { - // ignore valid internalized commodity deed items - if (i is CommodityDeed deed && deed.Commodity != null && deed.Commodity.Map == Map.Internal) - { - ignoreList.Add(deed.Commodity); - } - - // ignore valid internalized keyring keys - if (i is KeyRing keyring && keyring.Keys != null) - { - foreach (Key k in keyring.Keys) - { - ignoreList.Add(k); - } - } - - // ignore valid internalized relocatable house items - if (i is BaseHouse house) - { - foreach (RelocatedEntity relEntity in house.RelocatedEntities) - { - if (relEntity.Entity is Item) - { - ignoreList.Add(relEntity.Entity); - } - } - - foreach (VendorInventory inventory in house.VendorInventories) - { - foreach (Item subItem in inventory.Items) - { - ignoreList.Add(subItem); - } - } - } - } - - // test for valid items/mobs on the internal map - private static bool TestValidInternal(object o) - { - if (o is Mobile m) - { - if (m.Map != Map.Internal || m.Account != null || - (m as IMount)?.Rider != null || - m is BaseCreature creature && creature.IsStabled || - m is PlayerVendor && BaseHouse.AllHouses.Any(x => x.InternalizedVendors.Contains(m))) - { - return true; - } - } - else if (o is Item i) - { - // note, in order to test for a vendors display container that contains valid internal map items - if (i.Map != Map.Internal || i.Parent != null || i is Fists or MountItem or EffectItem || i.HeldBy != null || - i is MovingCrate || i.GetType().DeclaringType == typeof(GenericBuyInfo)) - { - return true; - } - - // boat stuffs - if (i is Static && i.Name != null && (i.Name.ToLower() == "weapon pad" || i.Name.ToLower() == "deck")) - { - return true; - } - - // Ship/Vehicle parts - if (i is BaseDockedBoat or BaseBoat or Plank or TillerMan or Hold) - { - return true; - } - - // TODO: Ignores addons, persistence, and other items that are internalized while not in use - } - - return false; - } - - public static ArrayList Search(SearchCriteria criteria, out string status_str) - { - status_str = null; - ArrayList newarray = new ArrayList(); - ArrayList ignoreList = new ArrayList(); - - if (criteria == null) - { - status_str = "Empty search criteria"; - return newarray; - } - - Type targetType = null; - - Map tokunomap = null; - try - { - tokunomap = Map.Parse("Tokuno"); - } - catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } - - // if the type is specified then get the search type - if (criteria.Dosearchtype && criteria.Searchtype != null) - { - targetType = AssemblyHandler.FindTypeByName(criteria.Searchtype); - if (targetType == null) - { - status_str = $"Invalid type: {criteria.Searchtype}"; - return newarray; - } - } - - // do the search through items - - // make a copy so that we dont get enumeration errors if World.Items.Values changes while searching - ArrayList itemarray = null; - - ICollection itemvalues = World.Items.Values; - - lock (itemvalues.SyncRoot) - { - try - { - itemarray = new ArrayList(itemvalues); - } - catch (SystemException e) { status_str = $"Unable to search World.Items: {e.Message}"; } - } - - if (itemarray != null) - { - foreach (Item i in itemarray) - { - bool hastype = false; - bool hasname = false; - bool hasentry = false; - bool hascondition = false; - bool hasrange = false; - bool hasregion = false; - bool hasmap = false; - bool hasspawnerr = false; - bool hasvalidhidden = false; - - if (i == null || i.Deleted) - { - continue; - } - - // this will deal with items that are not on the internal map but hold valid internal items - if (criteria.Dohidevalidint && i.Map != Map.Internal && i.Map != null) - { - IgnoreManagedInternal(i, ref ignoreList); - } - - // check for map - if (i.Map == Map.Felucca && criteria.Dosearchfel || i.Map == Map.Trammel && criteria.Dosearchtram || - i.Map == Map.Malas && criteria.Dosearchmal || i.Map == Map.Ilshenar && criteria.Dosearchilsh || - i.Map == Map.TerMur && criteria.Dosearchter || i.Map == Map.Internal && criteria.Dosearchint || - i.Map == null && criteria.Dosearchnull) - { - hasmap = true; - } - - if (tokunomap != null && i.Map == tokunomap && criteria.Dosearchtok) - { - hasmap = true; - } - - if (!hasmap) - { - continue; - } - - // check for type - if (criteria.Dosearchtype && (i.GetType().IsSubclassOf(targetType) || i.GetType() == targetType)) - { - hastype = true; - } - if (criteria.Dosearchtype && !hastype) - { - continue; - } - - // check for name - if (criteria.Dosearchname && i.Name != null && criteria.Searchname != null && i.Name.ToLower().IndexOf(criteria.Searchname.ToLower()) >= 0) - { - hasname = true; - } - - if (criteria.Dosearchname && !hasname) - { - continue; - } - - // check for valid internal map items - if (criteria.Dohidevalidint && TestValidInternal(i)) - { - hasvalidhidden = true; - - // this will deal with items that are on the internal map and hold valid internal items - IgnoreManagedInternal(i, ref ignoreList); - } - if (criteria.Dohidevalidint && hasvalidhidden) - { - continue; - } - - // check for range - if (criteria.Dosearchrange && TestRange(i, criteria.Searchrange, criteria.Currentmap, criteria.Currentloc)) - { - hasrange = true; - } - if (criteria.Dosearchrange && !hasrange) - { - continue; - } - - // check for region - if (criteria.Dosearchregion && TestRegion(i, criteria.Searchregion)) - { - hasregion = true; - } - if (criteria.Dosearchregion && !hasregion) - { - continue; - } - - // check for condition - if (criteria.Dosearchcondition && criteria.Searchcondition != null) - { - // check the property test - hascondition = BaseXmlSpawner.CheckPropertyString(null, i, criteria.Searchcondition, out status_str); - } - if (criteria.Dosearchcondition && !hascondition) - { - continue; - } - - // check for entry - if (criteria.Dosearchspawnentry) - { - Type targetentrytype = null; - - if (criteria.Dosearchspawntype) - { - targetentrytype = AssemblyHandler.FindTypeByName(criteria.Searchspawnentry.ToLower()); - } - - if (criteria.Searchspawnentry == null || targetentrytype == null && criteria.Dosearchspawntype) - { - hasentry = false; - } - else - { - // see what kind of spawner it is - if (i is XmlSpawner spawner) - { - // search the entries of the spawner - foreach (XmlSpawner.SpawnObject so in spawner.m_SpawnObjects) - { - if (criteria.Dosearchspawntype) - { - // search by entry type - Type type = null; - - if (so.TypeName != null) - { - string[] args = so.TypeName.Split('/'); - string typestr = null; - if (args != null && args.Length > 0) - { - typestr = args[0]; - } - - type = AssemblyHandler.FindTypeByName(typestr); - } - - if (type != null && (type == targetentrytype || type.IsSubclassOf(targetentrytype))) - { - hasentry = true; - break; - } - } - else - { - // search by entry string - if (so.TypeName != null && so.TypeName.ToLower().IndexOf(criteria.Searchspawnentry.ToLower()) >= 0) - { - hasentry = true; - break; - } - } - } - } - else if (i is Spawner spawner1) - { - // search the entries of the spawner - foreach (var entry in spawner1.Entries) - { - string so = entry.SpawnedName; - - if (criteria.Dosearchspawntype) - { - // search by entry type - Type type = null; - - if (so != null) - { - type = AssemblyHandler.FindTypeByName(so); - } - - if (type != null && (type == targetentrytype || type.IsSubclassOf(targetentrytype))) - { - hasentry = true; - break; - } - } - else - { - if (so != null && so.ToLower().IndexOf(criteria.Searchspawnentry.ToLower()) >= 0) - { - hasentry = true; - break; - } - } - } - } - else - { - hasentry = false; - } - } - } - - if (criteria.Dosearchspawnentry && !hasentry) - { - continue; - } - - if (criteria.Dosearcherr && i is XmlSpawner hasSpawn && hasSpawn.status_str != null) - { - hasspawnerr = true; - } - - if (criteria.Dosearcherr && !hasspawnerr) - { - continue; - } - - // satisfied all conditions so add it - newarray.Add(new SearchEntry(i)); - } - } - - // do the search through mobiles - if (!criteria.Dosearcherr) - { - // make a copy so that we dont get enumeration errors if World.Mobiles.Values changes while searching - ArrayList mobilearray = null; - ICollection mobilevalues = World.Mobiles.Values; - lock (mobilevalues.SyncRoot) - { - try - { - mobilearray = new ArrayList(mobilevalues); - } - catch (SystemException e) { status_str = $"Unable to search World.Mobiles: {e.Message}"; } - } - - if (mobilearray != null) - { - foreach (Mobile i in mobilearray) - { - bool hastype = false; - bool hasname = false; - bool hascondition = false; - bool hasrange = false; - bool hasregion = false; - bool hasmap = false; - bool hasage = false; - bool hasvalidhidden = false; - - if (i == null || i.Deleted) - { - continue; - } - - // check for map - if (i.Map == Map.Felucca && criteria.Dosearchfel || i.Map == Map.Trammel && criteria.Dosearchtram || - i.Map == Map.Malas && criteria.Dosearchmal || i.Map == Map.Ilshenar && criteria.Dosearchilsh || - i.Map == Map.TerMur && criteria.Dosearchter || i.Map == Map.Internal && criteria.Dosearchint || - i.Map == null && criteria.Dosearchnull) - { - hasmap = true; - } - - if (tokunomap != null && i.Map == tokunomap && criteria.Dosearchtok) - { - hasmap = true; - } - - if (!hasmap) - { - continue; - } - - // check for range - if (criteria.Dosearchrange && TestRange(i, criteria.Searchrange, criteria.Currentmap, criteria.Currentloc)) - { - hasrange = true; - } - if (criteria.Dosearchrange && !hasrange) - { - continue; - } - - // check for region - if (criteria.Dosearchregion && TestRegion(i, criteria.Searchregion)) - { - hasregion = true; - } - if (criteria.Dosearchregion && !hasregion) - { - continue; - } - - // check for valid internal map mobiles - if (criteria.Dohidevalidint && TestValidInternal(i)) - { - hasvalidhidden = true; - } - if (criteria.Dohidevalidint && hasvalidhidden) - { - continue; - } - - // check for age - if (criteria.Dosearchage && TestAge(i, criteria.Searchage, criteria.Searchagedirection)) - { - hasage = true; - } - if (criteria.Dosearchage && !hasage) - { - continue; - } - - // check for type - if (criteria.Dosearchtype && (i.GetType().IsSubclassOf(targetType) || i.GetType() == targetType)) - { - hastype = true; - } - if (criteria.Dosearchtype && !hastype) - { - continue; - } - - // check for name - if (criteria.Dosearchname && i.Name != null && criteria.Searchname != null && i.Name.ToLower().IndexOf(criteria.Searchname.ToLower()) >= 0) - { - hasname = true; - } - if (criteria.Dosearchname && !hasname) - { - continue; - } - - // check for condition - if (criteria.Dosearchcondition && criteria.Searchcondition != null) - { - // check the property test - hascondition = BaseXmlSpawner.CheckPropertyString(null, i, criteria.Searchcondition, out status_str); - } - if (criteria.Dosearchcondition && !hascondition) - { - continue; - } - - // passed all conditions so add it to the list - - newarray.Add(new SearchEntry(i)); - } - } - } - - ArrayList removelist = new ArrayList(); - for (int i = 0; i < ignoreList.Count; ++i) - { - foreach (SearchEntry se in newarray) - { - if (se.Object == ignoreList[i]) - { - removelist.Add(se); - break; - } - } - } - - foreach (SearchEntry se in removelist) - { - newarray.Remove(se); - } - - return newarray; - } - - [Usage("XmlFind [objecttype] [range]")] - [Description("Finds objects in the world")] - public static void XmlFind_OnCommand(CommandEventArgs e) - { - if (e?.Mobile == null) - { - return; - } - - Account acct = e.Mobile.Account as Account; - int x = 0; - int y = 0; - XmlSpawnerDefaults.DefaultEntry defs = null; - if (acct != null) - { - defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), e.Mobile.Name); - } - - if (defs != null) - { - x = defs.FindGumpX; - y = defs.FindGumpY; - } - - string typename = "Xmlspawner"; - int range = -1; - bool dorange = false; - - if (e.Arguments.Length > 0) - { - typename = e.Arguments[0]; - } - - if (e.Arguments.Length > 1) - { - dorange = true; - try - { - range = int.Parse(e.Arguments[1]); - } - catch - { - dorange = false; - e.Mobile.SendMessage($"Invalid range argument {e.Arguments[1]}"); - } - } - - e.Mobile.SendGump(new XmlFindGump(e.Mobile, e.Mobile.Location, e.Mobile.Map, typename, range, dorange, x, y)); - } - - public XmlFindGump(Mobile from, Point3D startloc, Map startmap, int x, int y) - : this(from, startloc, startmap, null, x, y) - { - } - - public XmlFindGump(Mobile from, Point3D startloc, Map startmap, string type, int x, int y) - : this(from, startloc, startmap, type, -1, false, x, y) - { - } - - public XmlFindGump(Mobile from, Point3D startloc, Map startmap, string type, int range, bool dorange, int x, int y) - : this(from, startloc, startmap, true, false, false, - - new SearchCriteria( - true, // dotype - false, // doname - dorange, // dorange - false, // doregion - false, // doentry - false, // doentrytype - false, // docondition - true, // dofel - true, // dotram - true, // domal - true, // doilsh - true, // dotok - true, // doter - false, // doint - false, // donull - false, // doerr - false, // doage - false, // dohidevalid - true, // agedirection - 0, // age - range, // range - null, // region - null, // condition - type, // type - null, // name - null // entry - ), - - null, -1, 0, null, null, - false, false, false, false, false, false, x, y) - { - } - - public XmlFindGump( - Mobile from, - Point3D startloc, - Map startmap, - bool firststart, - bool extension, - bool descend, - SearchCriteria criteria, - ArrayList searchlist, - int selected, - int displayfrom, - string savefilename, - string commandstring, - bool sorttype, - bool sortname, - bool sortrange, - bool sortmap, - bool sortselect, - bool selectall, - int X, - int Y - ) - : base(X, Y) - { - - StartingMap = startmap; - StartingLoc = startloc; - if (from != null && !from.Deleted) - { - m_From = from; - if (firststart) - { - StartingMap = from.Map; - StartingLoc = from.Location; - } - } - - SaveFilename = savefilename; - CommandString = commandstring; - SelectAll = selectall; - Sorttype = sorttype; - Sortname = sortname; - Sortrange = sortrange; - Sortmap = sortmap; - Sortselect = sortselect; - DisplayFrom = displayfrom; - Selected = selected; - m_ShowExtension = extension; - Descendingsort = descend; - - m_SearchCriteria = criteria ?? new SearchCriteria(); - - m_SearchList = searchlist; - - // prepare the page - const int height = 500; - - AddPage(0); - if (m_ShowExtension) - { - AddBackground(0, 0, 755, height, 5054); - AddAlphaRegion(0, 0, 755, height); - } - else - { - AddBackground(0, 0, 170, height, 5054); - AddAlphaRegion(0, 0, 170, height); - } - - // ---------------- - // SORT section - // ---------------- - int y = 5; - // add the Sort button - AddButton(5, y, 0xFAB, 0xFAD, 700); - AddLabel(38, y, 0x384, "Sort"); - - // add the sort direction button - if (Descendingsort) - { - AddButton(75, y + 3, 0x15E2, 0x15E6, 701); - AddLabel(95, y, 0x384, "descend"); - } - else - { - AddButton(75, y + 3, 0x15E0, 0x15E4, 701); - AddLabel(95, y, 0x384, "ascend"); - } - y += 22; - // add the Sort on type toggle - AddRadio(5, y, 0xD2, 0xD3, Sorttype, 0); - AddLabel(28, y, 0x384, "type"); - - // add the Sort on name toggle - AddRadio(75, y, 0xD2, 0xD3, Sortname, 1); - AddLabel(98, y, 0x384, "name"); - - y += 20; - // add the Sort on range toggle - AddRadio(5, y, 0xD2, 0xD3, Sortrange, 2); - AddLabel(28, y, 0x384, "range"); - - // add the Sort on map toggle - AddRadio(75, y, 0xD2, 0xD3, Sortmap, 4); - AddLabel(98, y, 0x384, "map"); - - y += 20; - // add the Sort on selected toggle - AddRadio(5, y, 0xD2, 0xD3, Sortselect, 5); - AddLabel(28, y, 0x384, "select"); - - // ---------------- - // SEARCH section - // ---------------- - y = 85; - // add the Search button - AddButton(5, y, 0xFA8, 0xFAA, 3); - AddLabel(38, y, 0x384, "Search"); - - y += 20; - // add the map buttons - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchint, 312); - AddLabel(28, y, 0x384, "Int"); - AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchnull, 314); - AddLabel(98, y, 0x384, "Null"); - - y += 20; - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchfel, 308); - AddLabel(28, y, 0x384, "Fel"); - AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtram, 309); - AddLabel(98, y, 0x384, "Tram"); - - y += 20; - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchmal, 310); - AddLabel(28, y, 0x384, "Mal"); - AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchilsh, 311); - AddLabel(98, y, 0x384, "Ilsh"); - - y += 20; - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtok, 318); - AddLabel(28, y, 0x384, "Tok"); - AddCheck(75, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchter, 320); - AddLabel(98, y, 0x384, "Ter"); - - y += 20; - // add the hide valid internal map button - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dohidevalidint, 316); - AddLabel(28, y, 0x384, "Hide valid internal"); - - // ---------------- - // FILTER section - // ---------------- - y = height - 295; - - // add the search region entry - AddLabel(28, y, 0x384, "region"); - AddImageTiled(70, y, 68, 19, 0xBBC); - AddTextEntry(70, y, 250, 19, 0, 106, m_SearchCriteria.Searchregion); - // add the toggle to enable search region - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchregion, 319); - - y += 20; - // add the search age entry - AddLabel(28, y, 0x384, "age"); - //AddImageTiled(80, 220, 50, 23, 0x52); - AddImageTiled(70, y, 45, 19, 0xBBC); - AddTextEntry(70, y, 45, 19, 0, 105, m_SearchCriteria.Searchage.ToString()); - AddLabel(117, y, 0x384, "Hrs"); - // add the toggle to enable search age - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchage, 303); - // add the toggle to set the search age test direction - AddCheck(50, y + 2, 0x1467, 0x1468, m_SearchCriteria.Searchagedirection, 302); - - y += 20; - // add the search range entry - AddLabel(28, y, 0x384, "range"); - AddImageTiled(70, y, 45, 19, 0xBBC); - AddTextEntry(70, y, 45, 19, 0, 100, m_SearchCriteria.Searchrange.ToString()); - // add the toggle to enable search range - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchrange, 304); - - y += 20; - // add the search type entry - AddLabel(28, y, 0x384, "type"); - // add the toggle to enable search by type - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchtype, 305); - //AddImageTiled(5, 285, 135, 23, 0x52); - AddImageTiled(6, y + 20, 132, 19, 0xBBC); - AddTextEntry(6, y + 20, 250, 19, 0, 101, m_SearchCriteria.Searchtype); - - y += 41; - // add the search condition entry - AddLabel(28, y, 0x384, "property test"); - // add the toggle to enable search by condition - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchcondition, 315); - //AddImageTiled(5, 285, 135, 23, 0x52); - AddImageTiled(6, y + 20, 132, 19, 0xBBC); - AddTextEntry(6, y + 20, 500, 19, 0, 104, m_SearchCriteria.Searchcondition); - - y += 41; - // add the search name entry - AddLabel(28, y, 0x384, "name"); - // add the toggle to enable search by name - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchname, 306); - //AddImageTiled(5, 350, 135, 23, 0x52); - AddImageTiled(6, y + 20, 132, 19, 0xBBC); - AddTextEntry(6, y + 20, 250, 19, 0, 102, m_SearchCriteria.Searchname); - - y += 41; - // add the search spawner entries - AddLabel(28, y, 0x384, "entry"); - // add the toggle to enable search spawner entries - AddCheck(5, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchspawnentry, 307); - - // add the search spawner entries by type - AddLabel(88, y, 0x384, "type"); - // add the toggle to enable search spawner entry types - AddCheck(65, y, 0xD2, 0xD3, m_SearchCriteria.Dosearchspawntype, 326); - - //AddImageTiled(5, 415, 135, 23, 0x52); - AddImageTiled(6, y + 20, 132, 19, 0xBBC); - AddTextEntry(6, y + 20, 250, 19, 0, 103, m_SearchCriteria.Searchspawnentry); - - // add the search spawner errors - AddLabel(140, y, 0x384, "err"); - // add the toggle to enable search spawner entries - AddCheck(117, y, 0xD2, 0xD3, m_SearchCriteria.Dosearcherr, 313); - - // add the Show Map button - //AddButton(5, 450, 0xFAB, 0xFAD, 150, GumpButtonType.Reply, 0); - //AddLabel(38, 450, 0x384, "Map"); - - // ---------------- - // CONTROL section - // ---------------- - - y = height - 25; - // add the Return button - AddButton(72, y, 0xFAE, 0xFAF, 155); - AddLabel(105, y, 0x384, "Return"); - - y = height - 25; - // add the Bring button - AddButton(5, y, 0xFAE, 0xFAF, 154); - AddLabel(38, y, 0x384, "Bring"); - - - // add gump extension button - if (m_ShowExtension) - { - AddButton(720, y + 5, 0x15E3, 0x15E7, 200); - } - else - { - AddButton(150, y + 5, 0x15E1, 0x15E5, 200); - } - - if (m_ShowExtension) - { - AddLabel(143, 5, 0x384, "Gump"); - AddLabel(178, 5, 0x384, "Prop"); - AddLabel(210, 5, 0x384, "Goto"); - AddLabel(250, 5, 0x384, "Name"); - AddLabel(365, 5, 0x384, "Type"); - AddLabel(460, 5, 0x384, "Location"); - AddLabel(578, 5, 0x384, "Map"); - AddLabel(650, 5, 0x384, "Owner"); - - // add the Delete button - AddButton(150, y, 0xFB1, 0xFB3, 156); - AddLabel(183, height - 25, 0x384, "Delete"); - - // add the Reset button - AddButton(230, y, 0xFA2, 0xFA3, 157); - AddLabel(263, y, 0x384, "Reset"); - - // add the Respawn button - AddButton(310, y, 0xFA8, 0xFAA, 158); - AddLabel(343, y, 0x384, "Respawn"); - - // add the xmlsave entry - AddButton(150, y - 25, 0xFA8, 0xFAA, 159); - AddLabel(183, y - 25, 0x384, "Save to file:"); - - AddImageTiled(270, y - 25, 180, 19, 0xBBC); - AddTextEntry(270, y - 25, 180, 19, 0, 300, SaveFilename); - - // add the commandstring entry - AddButton(470, y - 25, 0xFA8, 0xFAA, 160); - AddLabel(503, y - 25, 0x384, "Command:"); - - AddImageTiled(560, y - 25, 180, 19, 0xBBC); - AddTextEntry(560, y - 25, 180, 19, 0, 301, CommandString); - - - // add the page buttons - for (int i = 0; i < MaxEntries / MaxEntriesPerPage; i++) - { - //AddButton(38+i*30, 365, 2206, 2206, 0, GumpButtonType.Page, 1+i); - AddButton(418 + i * 25, height - 25, 0x8B1 + i, 0x8B1 + i, 0, GumpButtonType.Page, 1 + i); - } - - // add the advance pageblock buttons - AddButton(415 + 25 * (MaxEntries / MaxEntriesPerPage), height - 25, 0x15E1, 0x15E5, 201); // block forward - AddButton(395, height - 25, 0x15E3, 0x15E7, 202); // block backward - - // add the displayfrom entry - AddLabel(460, y, 0x384, "Display"); - AddImageTiled(500, y, 60, 21, 0xBBC); - AddTextEntry(501, y, 60, 21, 0, 400, DisplayFrom.ToString()); - AddButton(560, y, 0xFAB, 0xFAD, 9998); - - // display the item list - if (m_SearchList != null) - { - AddLabel(180, y - 50, 68, $"Found {m_SearchList.Count} items/mobiles"); - AddLabel(400, y - 50, 68, - $"Displaying {DisplayFrom}-{(DisplayFrom + MaxEntries < m_SearchList.Count ? DisplayFrom + MaxEntries : m_SearchList.Count)}" - ); - - // count the number of selected objects - int count = 0; - foreach (SearchEntry e in m_SearchList) - { - if (e.Selected) - { - count++; - } - } - AddLabel(600, y - 50, 33, $"Selected {count}"); - } - - // display the select-all-displayed toggle - AddButton(730, 5, 0xD2, 0xD3, 3999); - - AddLabel(610, y, 0x384, "Select All"); - // display the select-all toggle - AddButton(670, y, SelectAll ? 0xD3 : 0xD2, SelectAll ? 0xD2 : 0xD3, 3998); - - for (int i = 0; i < MaxEntries; i++) - { - int index = i + DisplayFrom; - if (m_SearchList == null || index >= m_SearchList.Count) - { - break; - } - - SearchEntry e = (SearchEntry)m_SearchList[index]; - - int page = i / MaxEntriesPerPage; - - if (i % MaxEntriesPerPage == 0) - { - AddPage(page + 1); - // add highlighted page button - //AddImageTiled(235+page*25, 448, 25, 25, 0xBBC); - //AddImage(238+page*25, 450, 0x8B1+page); - } - - // background for search results area - AddImageTiled(235, 22 * (i % MaxEntriesPerPage) + 30, 386, 23, 0x52); - AddImageTiled(236, 22 * (i % MaxEntriesPerPage) + 31, 384, 21, 0xBBC); - - // add the Goto button for each entry - AddButton(205, 22 * (i % MaxEntriesPerPage) + 30, 0xFAE, 0xFAF, 1000 + i); - - object o = e.Object; - - // add the Gump button for spawner entries - if (o is XmlSpawner || o is Spawner) - { - AddButton(145, 22 * (i % MaxEntriesPerPage) + 30, 0xFBD, 0xFBE, 2000 + i); - } - - // add the Props button for each entry - AddButton(175, 22 * (i % MaxEntriesPerPage) + 30, 0xFAB, 0xFAD, 3000 + i); - - string namestr = string.Empty; - string typestr = string.Empty; - string locstr = string.Empty; - string mapstr = string.Empty; - string ownstr = string.Empty; - int texthue = 0; - - if (o is Item) - { - Item item = (Item)e.Object; - // change the color if it is in a container - namestr = item.Name; - string str = item.GetType().ToString(); - if (str != null) - { - string[] arglist = str.Split('.'); - typestr = arglist[arglist.Length - 1]; - } - // check for in container - // if so then display parent loc - // change the color for container held items - if (item.Parent != null) - { - if (item.RootParent is Mobile m) - { - texthue = m.Player ? 44 : 24; - locstr = m.Location.ToString(); - ownstr = m.Name; - } - else if (item.RootParent is Container c) - { - texthue = 5; - locstr = c.Location.ToString(); - ownstr = c.Name ?? c.ItemData.Name; - } - } - else - { - locstr = item.Location.ToString(); - } - - if (item.Deleted) - { - mapstr = "Deleted"; - } - else - if (item.Map != null) - { - mapstr = item.Map.ToString(); - } - } - else if (o is Mobile) - { - Mobile mob = (Mobile)e.Object; - // change the color if it is in a container - namestr = mob.Name; - string str = mob.GetType().ToString(); - if (str != null) - { - string[] arglist = str.Split('.'); - typestr = arglist[arglist.Length - 1]; - } - locstr = mob.Location.ToString(); - if (mob.Deleted) - { - mapstr = "Deleted"; - } - else - if (mob.Map != null) - { - mapstr = mob.Map.ToString(); - } - } - - if (e.Selected) - { - texthue = 33; - } - - if (i == Selected) - { - texthue = 68; - } - - // display the name - AddLabelCropped(248, 22 * (i % MaxEntriesPerPage) + 31, 110, 21, texthue, namestr ?? string.Empty); - - // display the type - AddImageTiled(360, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, 0xBBC); - AddLabelCropped(360, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, texthue, typestr); - // display the loc - AddImageTiled(450, 22 * (i % MaxEntriesPerPage) + 31, 137, 21, 0xBBC); - AddLabel(450, 22 * (i % MaxEntriesPerPage) + 31, texthue, locstr); - // display the map - AddImageTiled(571, 22 * (i % MaxEntriesPerPage) + 31, 70, 21, 0xBBC); - AddLabel(571, 22 * (i % MaxEntriesPerPage) + 31, texthue, mapstr); - // display the owner - AddImageTiled(640, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, 0xBBC); - AddLabelCropped(640, 22 * (i % MaxEntriesPerPage) + 31, 90, 21, texthue, ownstr); - - // display the selection button - - AddButton(730, 22 * (i % MaxEntriesPerPage) + 32, e.Selected ? 0xD3 : 0xD2, e.Selected ? 0xD2 : 0xD3, 4000 + i); - } - } - } - - private void DoGoTo(int index) - { - if (m_From == null || m_From.Deleted) - { - return; - } - - if (m_SearchList != null && index < m_SearchList.Count) - { - object o = ((SearchEntry)m_SearchList[index]).Object; - if (o is Item item) - { - Point3D itemloc; - if (item.Parent != null) - { - if (item.RootParent is Mobile mobile) - { - itemloc = mobile.Location; - } - else if (item.RootParent is Container container) - { - itemloc = container.Location; - } - else - { - return; - } - } - else - { - itemloc = item.Location; - } - if (item.Deleted || item.Map == null || item.Map == Map.Internal) - { - return; - } - - m_From.Location = itemloc; - m_From.Map = item.Map; - } - - else if (o is Mobile mob) - { - if (mob.Deleted || mob.Map == null || mob.Map == Map.Internal) - { - return; - } - - m_From.Location = mob.Location; - m_From.Map = mob.Map; - } - } - } - - private void DoShowGump(int index) - { - if (m_From == null || m_From.Deleted) - { - return; - } - - if (m_SearchList != null && index < m_SearchList.Count) - { - object o = ((SearchEntry)m_SearchList[index]).Object; - if (o is XmlSpawner x1) - { - // dont open anything with a null map null item or deleted - if (x1.Deleted || x1.Map == null || x1.Map == Map.Internal) - { - return; - } - - x1.OnDoubleClick(m_From); - } - else if (o is Spawner x2) - { - if (x2.Deleted || x2.Map == null || x2.Map == Map.Internal) - { - return; - } - - x2.OnDoubleClick(m_From); - } - } - } - - private void DoShowProps(int index) - { - if (m_From == null || m_From.Deleted) - { - return; - } - - if (m_SearchList != null && index < m_SearchList.Count) - { - object o = ((SearchEntry)m_SearchList[index]).Object; - if (o is Item x1) - { - if (x1.Deleted) - { - return; - } - - m_From.SendGump(new PropertiesGump(m_From, x1)); - } - else if (o is Mobile x2) - { - if (x2.Deleted) - { - return; - } - - m_From.SendGump(new PropertiesGump(m_From, x2)); - } - } - } - - private void SortFindList() - { - if (m_SearchList != null && m_SearchList.Count > 0) - { - if (Sorttype) - { - m_SearchList.Sort(new ListTypeSorter(Descendingsort)); - } - else if (Sortname) - { - m_SearchList.Sort(new ListNameSorter(Descendingsort)); - } - else if (Sortmap) - { - m_SearchList.Sort(new ListMapSorter(Descendingsort)); - } - else if (Sortrange) - { - m_SearchList.Sort(new ListRangeSorter(m_From, Descendingsort)); - } - else if (Sortselect) - { - m_SearchList.Sort(new ListSelectSorter(Descendingsort)); - } - } - } - - private class ListTypeSorter : IComparer - { - private readonly bool Dsort; - - public ListTypeSorter(bool descend) => Dsort = descend; - - public int Compare(object e1, object e2) - { - string xstr = (e1 as SearchEntry)?.Object?.GetType().Name; - string ystr = (e2 as SearchEntry)?.Object?.GetType().Name; - - if (Dsort) - { - return string.Compare(ystr, xstr, true); - } - - return string.Compare(xstr, ystr, true); - } - } - - private class ListNameSorter : IComparer - { - private readonly bool Dsort; - - public ListNameSorter(bool descend) => Dsort = descend; - - public int Compare(object e1, object e2) - { - string xstr = (e1 as SearchEntry)?.Object switch - { - Item item => item.Name, - Mobile mobile => mobile.Name, - _ => null - }; - - string ystr = (e2 as SearchEntry)?.Object switch - { - Item item => item.Name, - Mobile mobile => mobile.Name, - _ => null - }; - - if (Dsort) - { - return string.Compare(ystr, xstr, true); - } - - return string.Compare(xstr, ystr, true); - } - } - - private class ListMapSorter : IComparer - { - private readonly bool Dsort; - - public ListMapSorter(bool descend) => Dsort = descend; - - public int Compare(object e1, object e2) - { - string xstr = ((e1 as SearchEntry)?.Object as IEntity)?.Map.Name; - string ystr = ((e2 as SearchEntry)?.Object as IEntity)?.Map.Name; - - if (Dsort) - { - return string.Compare(ystr, xstr, true); - } - - return string.Compare(xstr, ystr, true); - } - } - - private class ListRangeSorter : IComparer - { - private readonly Mobile From; - private readonly bool Dsort; - - public ListRangeSorter(Mobile from, bool descend) - { - From = from; - Dsort = descend; - } - - public int Compare(object e1, object e2) - { - if (From == null || From.Deleted) - { - return 0; - } - - IEntity entity1 = (e1 as SearchEntry)?.Object as IEntity; - IEntity entity2 = (e2 as SearchEntry)?.Object as IEntity; - - if (entity1 == null && entity2 == null) - { - return 0; - } - - if (entity1 == null) - { - return Dsort ? 1 : -1; - } - if (entity2 == null) - { - return Dsort ? -1 : 1; - } - - if (entity1.Map != From.Map && entity2.Map != From.Map) - { - return 0; - } - - if (entity1.Map == From.Map && entity2.Map != From.Map) - { - return Dsort ? 1 : -1; - } - - if (entity1.Map != From.Map && entity2.Map == From.Map) - { - return Dsort ? -1 : 1; - } - - if (Dsort) - { - return From.GetDistanceToSqrt(entity2.Location).CompareTo(From.GetDistanceToSqrt(entity1.Location)); - } - - return From.GetDistanceToSqrt(entity1.Location).CompareTo(From.GetDistanceToSqrt(entity2.Location)); - } - } - - private class ListSelectSorter : IComparer - { - private readonly bool Dsort; - - public ListSelectSorter(bool descend) => Dsort = descend; - - public int Compare(object e1, object e2) - { - int x = 0; - int y = 0; - - if (e1 is SearchEntry entry) - { - x = entry.Selected ? 1 : 0; - } - - if (e2 is SearchEntry searchEntry) - { - y = searchEntry.Selected ? 1 : 0; - } - - if (Dsort) - { - return x - y; - } - - return y - x; - } - } - - private void Refresh(NetState state) - { - state.Mobile.SendGump(new XmlFindGump(m_From, StartingLoc, StartingMap, false, m_ShowExtension, Descendingsort, m_SearchCriteria, m_SearchList, Selected, DisplayFrom, SaveFilename, - CommandString, Sorttype, Sortname, Sortrange, - Sortmap, Sortselect, SelectAll, X, Y)); - } - - private void ResetList() - { - if (m_SearchList == null) - { - return; - } - - for (int i = 0; i < m_SearchList.Count; i++) - { - SearchEntry e = (SearchEntry)m_SearchList[i]; - - if (e.Selected) - { - object o = e.Object; - - if (o is XmlSpawner spawner) - { - spawner.DoReset = true; - } - } - } - } - - private void RespawnList() - { - if (m_SearchList == null) - { - return; - } - - for (int i = 0; i < m_SearchList.Count; i++) - { - SearchEntry e = (SearchEntry)m_SearchList[i]; - - if (e.Selected) - { - object o = e.Object; - - if (o is XmlSpawner spawner) - { - spawner.DoRespawn = true; - } - } - } - } - - private void SaveList(Mobile from, string filename) - { - if (m_SearchList == null) - { - return; - } - - string dirname; - if (System.IO.Directory.Exists(XmlSpawner.XmlSpawnDir) && filename != null && !filename.StartsWith("/") && !filename.StartsWith("\\")) - { - // put it in the defaults directory if it exists - dirname = $"{XmlSpawner.XmlSpawnDir}/{filename}"; - } - else - { - // otherwise just put it in the main installation dir - dirname = filename; - } - - List savelist = new List(); - - for (int i = 0; i < m_SearchList.Count; i++) - { - SearchEntry e = (SearchEntry)m_SearchList[i]; - - if (e.Selected) - { - object o = e.Object; - - if (o is XmlSpawner spawner) - { - // add it to the saves list - savelist.Add(spawner); - } - } - } - - // write out the spawners to a file - XmlSpawner.SaveSpawnList(from, savelist, dirname, false, true); - } - - private void ExecuteCommand(Mobile from, string command) - { - if (m_SearchList == null) - { - return; - } - - var executelist = new List(); - - for (int i = 0; i < m_SearchList.Count; i++) - { - SearchEntry e = (SearchEntry)m_SearchList[i]; - - if (e.Selected) - { - object o = e.Object; - - // add it to the execute list - executelist.Add(o); - - } - } - - // lookup the command - // and execute it - if (!string.IsNullOrEmpty(command)) - { - string[] args = command.Split(' '); - - if (args.Length > 1) - { - string[] cargs = new string[args.Length - 1]; - for (int i = 0; i < args.Length - 1; i++) - { - cargs[i] = args[i + 1]; - } - - CommandEventArgs e = new CommandEventArgs(from, args[0], command, cargs); - - foreach (BaseCommand c in TargetCommands.AllCommands) - { - // find the matching command - if (string.Equals(c.Commands[0], args[0], StringComparison.CurrentCultureIgnoreCase)) - { - bool flushToLog = false; - - // execute the command on the objects in the list - - if (executelist.Count > 20) - { - CommandLogging.Enabled = false; - } - - c.ExecuteList(e, executelist); - - if (executelist.Count > 20) - { - flushToLog = true; - CommandLogging.Enabled = true; - } - - c.Flush(from, flushToLog); - return; - } - } - from.SendMessage($"Invalid command: {args[0]}"); - } - } - } - - public override void OnResponse(NetState state, RelayInfo info) - { - if (info == null || state?.Mobile == null || m_SearchCriteria == null) - { - return; - } - - int radiostate = -1; - if (info.Switches.Length > 0) - { - radiostate = info.Switches[0]; - } - - // read the text entries for the search criteria - TextRelay tr = info.GetTextEntry(105); // range info - m_SearchCriteria.Searchage = 0; - if (tr?.Text != null && tr.Text.Length > 0) - { - try { m_SearchCriteria.Searchage = double.Parse(tr.Text); } - catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } - } - - // read the text entries for the search criteria - tr = info.GetTextEntry(100); // range info - m_SearchCriteria.Searchrange = -1; - if (tr?.Text != null && tr.Text.Length > 0) - { - try { m_SearchCriteria.Searchrange = int.Parse(tr.Text); } - catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } - } - - tr = info.GetTextEntry(101); // type info - if (tr != null) - { - m_SearchCriteria.Searchtype = tr.Text; - } - - tr = info.GetTextEntry(102); // name info - if (tr != null) - { - m_SearchCriteria.Searchname = tr.Text; - } - - tr = info.GetTextEntry(103); // entry info - if (tr != null) - { - m_SearchCriteria.Searchspawnentry = tr.Text; - } - - tr = info.GetTextEntry(104); // condition info - if (tr != null) - { - m_SearchCriteria.Searchcondition = tr.Text; - } - - tr = info.GetTextEntry(106); // region info - if (tr != null) - { - m_SearchCriteria.Searchregion = tr.Text; - } - - - tr = info.GetTextEntry(400); // displayfrom info - if (tr != null) - { - DisplayFrom = Utility.ToInt32(tr.Text); - } - - tr = info.GetTextEntry(300); // savefilename info - if (tr != null) - { - SaveFilename = tr.Text; - } - - tr = info.GetTextEntry(301); // commandstring info - if (tr != null) - { - CommandString = tr.Text; - } - - - // check all of the check boxes - m_SearchCriteria.Searchagedirection = info.IsSwitched(302); - m_SearchCriteria.Dosearchage = info.IsSwitched(303); - m_SearchCriteria.Dosearchrange = info.IsSwitched(304); - m_SearchCriteria.Dosearchtype = info.IsSwitched(305); - m_SearchCriteria.Dosearchname = info.IsSwitched(306); - m_SearchCriteria.Dosearchspawnentry = info.IsSwitched(307); - m_SearchCriteria.Dosearchspawntype = info.IsSwitched(326); - m_SearchCriteria.Dosearcherr = info.IsSwitched(313); - m_SearchCriteria.Dosearchcondition = info.IsSwitched(315); - - m_SearchCriteria.Dosearchint = info.IsSwitched(312); - m_SearchCriteria.Dosearchfel = info.IsSwitched(308); - m_SearchCriteria.Dosearchtram = info.IsSwitched(309); - m_SearchCriteria.Dosearchmal = info.IsSwitched(310); - m_SearchCriteria.Dosearchilsh = info.IsSwitched(311); - m_SearchCriteria.Dosearchtok = info.IsSwitched(318); - m_SearchCriteria.Dosearchter = info.IsSwitched(320); - m_SearchCriteria.Dosearchnull = info.IsSwitched(314); - - m_SearchCriteria.Dohidevalidint = info.IsSwitched(316); - m_SearchCriteria.Dosearchregion = info.IsSwitched(319); - - switch (info.ButtonID) - { - - case 0: // Close - { - return; - } - case 3: // Search - { - // clear any selection - Selected = -1; - - // reset displayfrom - DisplayFrom = 0; - - // do the search - m_SearchCriteria.Currentloc = state.Mobile.Location; - m_SearchCriteria.Currentmap = state.Mobile.Map; - - //m_SearchList = Search(m_SearchCriteria, out status_str); - XmlFindThread tobj = new XmlFindThread(state.Mobile, m_SearchCriteria, CommandString); - Thread find = new Thread(tobj.XmlFindThreadMain) - { - Name = "XmlFind Thread" - }; - find.Start(); - - // turn on gump extension - m_ShowExtension = true; - return; - } - case 4: // SubSearch - { - // do the search - m_SearchList = Search(m_SearchCriteria, out _); - break; - } - case 150: // Open the map gump - { - break; - } - case 154: // Bring all selected objects to the current location - { - Refresh(state); - - state.Mobile.SendGump(new XmlConfirmBringGump(m_SearchList)); - return; - } - case 155: // Return the player to the starting loc - { - m_From.Location = StartingLoc; - m_From.Map = StartingMap; - break; - } - case 156: // Delete selected items - { - Refresh(state); - - state.Mobile.SendGump(new XmlConfirmDeleteGump(m_SearchList)); - return; - } - case 157: // Reset selected items - { - ResetList(); - break; - } - case 158: // Respawn selected items - { - RespawnList(); - break; - } - case 159: // xmlsave selected spawners - { - SaveList(state.Mobile, SaveFilename); - break; - } - case 160: // execute the command on the selected items - { - ExecuteCommand(state.Mobile, CommandString); - break; - } - case 200: // gump extension - { - m_ShowExtension = !m_ShowExtension; - break; - } - case 201: // forward block - { - if (m_SearchList != null && DisplayFrom + MaxEntries < m_SearchList.Count) - { - DisplayFrom += MaxEntries; - // clear any selection - Selected = -1; - } - break; - } - case 202: // backward block - { - - DisplayFrom -= MaxEntries; - if (DisplayFrom < 0) - { - DisplayFrom = 0; - } - - // clear any selection - Selected = -1; - break; - } - - case 700: // Sort - { - // clear any selection - Selected = -1; - - Sorttype = false; - Sortname = false; - Sortrange = false; - Sortmap = false; - Sortselect = false; - // read the toggle switches that determine the sort - if (radiostate == 0) // sort by type - { - Sorttype = true; - } - else - if (radiostate == 1) // sort by name - { - Sortname = true; - } - else - if (radiostate == 2) // sort by range - { - Sortrange = true; - } - else - if (radiostate == 4) // sort by entry - { - Sortmap = true; - } - else - if (radiostate == 5) // sort by selected - { - Sortselect = true; - } - - SortFindList(); - break; - } - case 701: // descending sort - { - Descendingsort = !Descendingsort; - break; - } - case 9998: // refresh the gump - { - // clear any selection - Selected = -1; - break; - } - default: - { - - if (info.ButtonID >= 1000 && info.ButtonID < 1000 + MaxEntries) - { - // flag the entry selected - Selected = info.ButtonID - 1000; - // then go to it - DoGoTo(info.ButtonID - 1000 + DisplayFrom); - } - if (info.ButtonID >= 2000 && info.ButtonID < 2000 + MaxEntries) - { - // flag the entry selected - Selected = info.ButtonID - 2000; - // then open the gump - Refresh(state); - DoShowGump(info.ButtonID - 2000 + DisplayFrom); - return; - } - if (info.ButtonID >= 3000 && info.ButtonID < 3000 + MaxEntries) - { - Selected = info.ButtonID - 3000; - // Show the props window - Refresh(state); - DoShowProps(info.ButtonID - 3000 + DisplayFrom); - return; - } - if (info.ButtonID == 3998) - { - SelectAll = !SelectAll; - - if (m_SearchList != null) - { - foreach (SearchEntry e in m_SearchList) - { - e.Selected = SelectAll; - } - } - } - if (info.ButtonID == 3999) - { - // toggle selection of everything currently displayed - if (m_SearchList != null) - { - for (int i = 0; i < MaxEntries; i++) - { - if (i + DisplayFrom < m_SearchList.Count) - { - SearchEntry e = (SearchEntry)m_SearchList[i + DisplayFrom]; - - e.Selected = !e.Selected; - } - else - { - break; - } - } - } - } - if (info.ButtonID >= 4000 && info.ButtonID < 4000 + MaxEntries) - { - int i = info.ButtonID - 4000; - - if (m_SearchList != null && i >= 0 && m_SearchList.Count > i + DisplayFrom) - { - SearchEntry e = (SearchEntry)m_SearchList[i + DisplayFrom]; - - e.Selected = !e.Selected; - } - } - - break; - } - } - - Refresh(state); - } - - public class XmlConfirmBringGump : Gump - { - private readonly ArrayList SearchList; - - public XmlConfirmBringGump(ArrayList searchlist) - : base(0, 0) - { - SearchList = searchlist; - - Closable = false; - Draggable = true; - AddPage(0); - AddBackground(10, 200, 200, 130, 5054); - int count = 0; - - if (SearchList != null) - { - for (int i = 0; i < SearchList.Count; i++) - { - if (((SearchEntry)SearchList[i]).Selected) - { - count++; - } - } - } - - AddLabel(20, 225, 33, $"Bring {count} objects to you?"); - AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio - AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio - AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff); // Yes - AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff); // No - AddButton(80, 289, 2130, 2129, 3); // Okay button - - } - public override void OnResponse(NetState state, RelayInfo info) - { - if (info == null || state?.Mobile == null) - { - return; - } - - int radiostate = -1; - - Point3D myloc = state.Mobile.Location; - Map mymap = state.Mobile.Map; - - if (info.Switches.Length > 0) - { - radiostate = info.Switches[0]; - } - switch (info.ButtonID) - { - default: - { - if (radiostate == 1 && SearchList != null) - { // accept - for (int i = 0; i < SearchList.Count; i++) - { - SearchEntry e = (SearchEntry)SearchList[i]; - - if (e.Selected) - { - object o = e.Object; - - if (o is Item item) - { - - item.MoveToWorld(myloc, mymap); - - } - else if (o is Mobile mobile) - { - - mobile.MoveToWorld(myloc, mymap); - - } - } - } - } - break; - } - } - } - } - - public class XmlConfirmDeleteGump : Gump - { - private readonly ArrayList SearchList; - - public XmlConfirmDeleteGump(ArrayList searchlist) - : base(0, 0) - { - SearchList = searchlist; - - Closable = false; - Draggable = true; - AddPage(0); - AddBackground(10, 200, 200, 130, 5054); - int count = 0; - - if (SearchList != null) - { - for (int i = 0; i < SearchList.Count; i++) - { - if (((SearchEntry)SearchList[i]).Selected) - { - count++; - } - } - } - - AddLabel(20, 225, 33, $"Delete {count} objects?"); - AddRadio(35, 255, 9721, 9724, false, 1); // accept/yes radio - AddRadio(135, 255, 9721, 9724, true, 2); // decline/no radio - AddHtmlLocalized(72, 255, 200, 30, 1049016, 0x7fff); // Yes - AddHtmlLocalized(172, 255, 200, 30, 1049017, 0x7fff); // No - AddButton(80, 289, 2130, 2129, 3); // Okay button - - } - public override void OnResponse(NetState state, RelayInfo info) - { - if (info == null || state?.Mobile == null) - { - return; - } - - int radiostate = -1; - if (info.Switches.Length > 0) - { - radiostate = info.Switches[0]; - } - switch (info.ButtonID) - { - - default: - { - if (radiostate == 1 && SearchList != null) - { // accept - for (int i = 0; i < SearchList.Count; i++) - { - SearchEntry e = (SearchEntry)SearchList[i]; - - if (e.Selected) - { - object o = e.Object; - - if (o is Item item) - { - // some objects may not delete gracefully (null map items are particularly error prone) so trap them - try - { - item.Delete(); - } - catch (Exception ex) { Diagnostics.ExceptionLogging.LogException(ex); } - } - else if (o is Mobile mobile && !mobile.Player) - { - try - { - mobile.Delete(); - } - catch (Exception ex) { Diagnostics.ExceptionLogging.LogException(ex); } - } - } - } - } - - break; - } - } - } - } -} From 8f20ea34c465a7ccb03cdc2205649faee194c305 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:12:41 -0800 Subject: [PATCH 7/8] Revert change --- Projects/Server/Main.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 43fa92fae..d17c45108 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -164,7 +164,7 @@ public static class Core { // See notes above for _now and why this is a volatile variable. var now = _now; - return now == DateTime.MinValue ? Core.Now : now; + return now == DateTime.MinValue ? DateTime.UtcNow : now; } } @@ -557,7 +557,7 @@ public static class Core while (!Closing) { _tickCount = TickCount; - _now = Core.Now; + _now = DateTime.UtcNow; Mobile.ProcessDeltaQueue(); Item.ProcessDeltaQueue(); From 3882fbe5992f0af68c91382a57dba7e5520f8f6f Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 12 Feb 2024 19:14:16 -0800 Subject: [PATCH 8/8] use var --- .../Engines/XMLSpawner/BaseXmlSpawner.cs | 10 +- .../UOContent/Engines/XMLSpawner/ItemFlags.cs | 12 +- .../Engines/XMLSpawner/SpawnerExporter.cs | 48 +++--- .../XMLSpawner/XmlPropsGumps/XmlPropsGump.cs | 92 +++++------ .../XmlPropsGumps/XmlSetCustomEnumGump.cs | 4 +- .../XMLSpawner/XmlPropsGumps/XmlSetGump.cs | 14 +- .../XmlPropsGumps/XmlSetListOptionGump.cs | 30 ++-- .../XmlPropsGumps/XmlSetObjectGump.cs | 8 +- .../XmlPropsGumps/XmlSetPoint2DGump.cs | 12 +- .../XmlPropsGumps/XmlSetPoint3DGump.cs | 14 +- .../XmlPropsGumps/XmlSetTimeSpanGump.cs | 12 +- .../Engines/XMLSpawner/XmlSpawner.cs | 8 +- .../Engines/XMLSpawner/XmlSpawnerGumps.cs | 154 +++++++++--------- .../XMLSpawner/XmlSpawnerSkillCheck.cs | 30 ++-- .../Engines/XMLSpawner/XmlTextEntryBook.cs | 16 +- .../Engines/XMLSpawner/XmlUtils/XmlAdd.cs | 132 +++++++-------- .../XmlUtils/XmlCategorizedAddGump.cs | 34 ++-- .../XmlUtils/XmlPartialCategorizedAddGump.cs | 42 ++--- 18 files changed, 335 insertions(+), 337 deletions(-) diff --git a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs index 2ca8fa0ae..fca83853d 100644 --- a/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/BaseXmlSpawner.cs @@ -1382,25 +1382,23 @@ public class BaseXmlSpawner // count nearby players if (refobject is Item item) { - foreach (Mobile p in item.GetMobilesInRange(range)) + foreach (var p in item.GetMobilesInRange(range)) { if (p.Player && p.AccessLevel == AccessLevel.Player) { nplayers++; } } - ie.Free(); } else if (refobject is Mobile mobile) { - foreach (Mobile p in mobile.GetMobilesInRange(range)) + foreach (var p in mobile.GetMobilesInRange(range)) { if (p.Player && p.AccessLevel == AccessLevel.Player) { nplayers++; } } - ie.Free(); } var result = SetPropertyValue(spawner, o, arglist[0], nplayers.ToString()); @@ -1664,7 +1662,7 @@ public class BaseXmlSpawner } else if (o is Item item) { - foreach (Mobile p in item.GetMobilesInRange(range)) + foreach (var p in item.GetMobilesInRange(range)) { if (p.Player && p.AccessLevel == AccessLevel.Player) { @@ -1674,7 +1672,7 @@ public class BaseXmlSpawner } else if (o is Mobile mobile) { - foreach (Mobile p in mobile.GetMobilesInRange(range)) + foreach (var p in mobile.GetMobilesInRange(range)) { if (p.Player && p.AccessLevel == AccessLevel.Player) { diff --git a/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs b/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs index 0ed76c387..802ed50cf 100644 --- a/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs +++ b/Projects/UOContent/Engines/XMLSpawner/ItemFlags.cs @@ -24,8 +24,8 @@ public partial class ItemFlags [Description("Gets the state of the specified SavedFlag on any item")] public static void GetFlag_OnCommand(CommandEventArgs e) { - int flag=0; - bool error = false; + var flag=0; + var error = false; if (e.Arguments.Length > 0) { if (e.Arguments[0].StartsWith("0x")) @@ -62,7 +62,7 @@ public partial class ItemFlags { if (targeted is Item item) { - bool state = item.GetSavedFlag(m_flag); + var state = item.GetSavedFlag(m_flag); from.SendMessage($"Flag (0x{m_flag:X}) = {state}"); } else @@ -77,8 +77,8 @@ public partial class ItemFlags [Description("Sets/gets the stealable flag on any item")] public static void SetStealable_OnCommand(CommandEventArgs e) { - bool state = false; - bool error = false; + var state = false; + var error = false; if (e.Arguments.Length > 0) { try @@ -121,7 +121,7 @@ public partial class ItemFlags SetStealable(item, m_state); } - bool state = GetStealable(item); + var state = GetStealable(item); from.SendMessage($"Stealable = {state}"); diff --git a/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs b/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs index d8df61e43..a99f9cb44 100644 --- a/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs +++ b/Projects/UOContent/Engines/XMLSpawner/SpawnerExporter.cs @@ -43,15 +43,15 @@ public class SpawnerExporter public override void ExecuteList(CommandEventArgs e, List list) { - string filename = e.GetString(0); + var filename = e.GetString(0); - ArrayList spawners = new ArrayList(); + var spawners = new ArrayList(); - for (int i = 0; i < list.Count; ++i) + for (var i = 0; i < list.Count; ++i) { if (list[i] is Spawner) { - Spawner spawner = (Spawner)list[i]; + var spawner = (Spawner)list[i]; if (!spawner.Deleted && spawner.Map != Map.Internal && spawner.Parent == null) { spawners.Add(spawner); @@ -87,11 +87,11 @@ public class SpawnerExporter Directory.CreateDirectory("Saves/Spawners"); } - string filePath = Path.Combine("Saves/Spawners", filename); + var filePath = Path.Combine("Saves/Spawners", filename); - using (StreamWriter op = new StreamWriter(filePath)) + using (var op = new StreamWriter(filePath)) { - XmlTextWriter xml = new XmlTextWriter(op) + var xml = new XmlTextWriter(op) { Formatting = Formatting.Indented, IndentChar = '\t', @@ -180,15 +180,15 @@ public class SpawnerExporter { if (e.Arguments.Length >= 1) { - string filename = e.GetString(0); - string filePath = Path.Combine("Saves/Spawners", filename); + var filename = e.GetString(0); + var filePath = Path.Combine("Saves/Spawners", filename); if (File.Exists(filePath)) { - XmlDocument doc = new XmlDocument(); + var doc = new XmlDocument(); doc.Load(filePath); - XmlElement root = doc["spawners"]; + var root = doc["spawners"]; int successes = 0, failures = 0; @@ -231,23 +231,23 @@ public class SpawnerExporter private static void ImportSpawner(XmlNode node) { - int count = int.Parse(GetText(node["count"], "1")); - int homeRange = int.Parse(GetText(node["homerange"], "4")); + var count = int.Parse(GetText(node["count"], "1")); + var homeRange = int.Parse(GetText(node["homerange"], "4")); - int walkingRange = int.Parse(GetText(node["walkingrange"], "-1")); + var walkingRange = int.Parse(GetText(node["walkingrange"], "-1")); - int team = int.Parse(GetText(node["team"], "0")); + var team = int.Parse(GetText(node["team"], "0")); - bool group = bool.Parse(GetText(node["group"], "False")); - TimeSpan maxDelay = TimeSpan.Parse(GetText(node["maxdelay"], "10:00")); - TimeSpan minDelay = TimeSpan.Parse(GetText(node["mindelay"], "05:00")); - IEnumerable creaturesName = LoadCreaturesName(node["creaturesname"]); + var group = bool.Parse(GetText(node["group"], "False")); + var maxDelay = TimeSpan.Parse(GetText(node["maxdelay"], "10:00")); + var minDelay = TimeSpan.Parse(GetText(node["mindelay"], "05:00")); + var creaturesName = LoadCreaturesName(node["creaturesname"]); - string name = GetText(node["name"], "Spawner"); - Point3D location = Point3D.Parse(GetText(node["location"], "Error")); - Map map = Map.Parse(GetText(node["map"], "Error")); + var name = GetText(node["name"], "Spawner"); + var location = Point3D.Parse(GetText(node["location"], "Error")); + var map = Map.Parse(GetText(node["map"], "Error")); - Spawner spawner = new Spawner(count, minDelay, maxDelay, team, homeRange, creaturesName.ToArray()); + var spawner = new Spawner(count, minDelay, maxDelay, team, homeRange, creaturesName.ToArray()); if (walkingRange >= 0) { spawner.WalkingRange = walkingRange; @@ -265,7 +265,7 @@ public class SpawnerExporter private static IEnumerable LoadCreaturesName(XmlElement node) { - List names = new List(); + var names = new List(); if (node != null) { diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs index 053386ae3..aa7c4c066 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlPropsGump.cs @@ -95,7 +95,7 @@ public class XmlPropertiesGump : Gump { m_Page = page; - int count = m_List.Count - page * EntryCount; + var count = m_List.Count - page * EntryCount; if (count < 0) { @@ -106,33 +106,33 @@ public class XmlPropertiesGump : Gump count = EntryCount; } - int lastIndex = page * EntryCount + count - 1; + var lastIndex = page * EntryCount + count - 1; if (lastIndex >= 0 && lastIndex < m_List.Count && m_List[lastIndex] == null) { --count; } - int totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (ColumnEntryCount + 1); + var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (ColumnEntryCount + 1); AddPage(0); AddBackground(0, 0, TotalWidth * 3 + BorderSize * 2, BorderSize + totalHeight + BorderSize, BackGumpID); AddImageTiled(BorderSize, BorderSize + EntryHeight, (TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0)) * 3, totalHeight - EntryHeight, OffsetGumpID); - int x = BorderSize + OffsetSize; - int y = BorderSize; + var x = BorderSize + OffsetSize; + var y = BorderSize; if (m_Object is Item item) { AddLabelCropped(x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, TextHue, item.Name); } - int propcount = 0; + var propcount = 0; for (int i = 0, index = page * EntryCount; i <= count && index < m_List.Count; ++i, ++index) { // do the multi column display - int column = propcount / ColumnEntryCount; + var column = propcount / ColumnEntryCount; if (propcount % ColumnEntryCount == 0) { y = BorderSize; @@ -141,7 +141,7 @@ public class XmlPropertiesGump : Gump x = BorderSize + OffsetSize + column * (ValueWidth + NameWidth + OffsetSize * 2 + SetOffsetX + SetWidth); y += EntryHeight + OffsetSize; - object o = m_List[index]; + var o = m_List[index]; if (o == null) { @@ -154,9 +154,9 @@ public class XmlPropertiesGump : Gump // look for the default value of the equivalent property in the XmlSpawnerDefaults.DefaultEntry class - int huemodifier = TextHue; - Mobiles.XmlSpawnerDefaults.DefaultEntry de = new Mobiles.XmlSpawnerDefaults.DefaultEntry(); - Type ftype = de.GetType(); + var huemodifier = TextHue; + var de = new Mobiles.XmlSpawnerDefaults.DefaultEntry(); + var ftype = de.GetType(); var finfo = ftype.GetField(prop.Name); @@ -182,7 +182,7 @@ public class XmlPropertiesGump : Gump AddImageTiled(x, y, SetWidth, EntryHeight, SetGumpID); } - CPA cpa = GetCPA(prop); + var cpa = GetCPA(prop); if (prop.CanWrite && cpa != null && m_Mobile.AccessLevel >= cpa.WriteLevel) { @@ -200,7 +200,7 @@ public class XmlPropertiesGump : Gump public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = state.Mobile; + var from = state.Mobile; if (!BaseCommand.IsAccessible(from, m_Object)) { @@ -214,7 +214,7 @@ public class XmlPropertiesGump : Gump { if (m_Stack != null && m_Stack.Count > 0) { - StackEntry entry = m_Stack.Pop(); + var entry = m_Stack.Pop(); from.SendGump(new XmlPropertiesGump(from, entry.m_Object, m_Stack, null)); } @@ -240,25 +240,25 @@ public class XmlPropertiesGump : Gump } default: { - int index = m_Page * EntryCount + (info.ButtonID - 3); + var index = m_Page * EntryCount + (info.ButtonID - 3); if (index >= 0 && index < m_List.Count) { - PropertyInfo prop = m_List[index] as PropertyInfo; + var prop = m_List[index] as PropertyInfo; if (prop == null) { return; } - CPA attr = GetCPA(prop); + var attr = GetCPA(prop); if (!prop.CanWrite || attr == null || from.AccessLevel < attr.WriteLevel) { return; } - Type type = prop.PropertyType; + var type = prop.PropertyType; if (IsType(type, typeofMobile) || IsType(type, typeofItem)) { @@ -311,7 +311,7 @@ public class XmlPropertiesGump : Gump } else if (HasAttribute(type, typeofPropertyObject, true)) { - object obj = prop.GetValue(m_Object, null); + var obj = prop.GetValue(m_Object, null); from.SendGump(obj != null ? new XmlPropertiesGump(from, obj, m_Stack, @@ -327,9 +327,9 @@ public class XmlPropertiesGump : Gump private static object[] GetObjects(Array a) { - object[] list = new object[a.Length]; + var list = new object[a.Length]; - for (int i = 0; i < list.Length; ++i) + for (var i = 0; i < list.Length; ++i) { list[i] = a.GetValue(i); } @@ -341,14 +341,14 @@ public class XmlPropertiesGump : Gump private static string[] GetCustomEnumNames(Type type) { - object[] attrs = type.GetCustomAttributes(typeofCustomEnum, false); + var attrs = type.GetCustomAttributes(typeofCustomEnum, false); if (attrs.Length == 0) { return new string[0]; } - CustomEnumAttribute ce = attrs[0] as CustomEnumAttribute; + var ce = attrs[0] as CustomEnumAttribute; if (ce == null) { @@ -360,7 +360,7 @@ public class XmlPropertiesGump : Gump private static bool HasAttribute(Type type, Type check, bool inherit) { - object[] objs = type.GetCustomAttributes(check, inherit); + var objs = type.GetCustomAttributes(check, inherit); return objs.Length > 0; } @@ -369,7 +369,7 @@ public class XmlPropertiesGump : Gump private static bool IsType(Type type, Type[] check) { - for (int i = 0; i < check.Length; ++i) + for (var i = 0; i < check.Length; ++i) { if (IsType(type, check[i])) { @@ -497,17 +497,17 @@ public class XmlPropertiesGump : Gump private ArrayList BuildList() { - Type type = m_Object.GetType(); + var type = m_Object.GetType(); - PropertyInfo[] props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); + var props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public); - ArrayList groups = GetGroups(type, props); - ArrayList list = new ArrayList(); + var groups = GetGroups(type, props); + var list = new ArrayList(); - for (int i = 0; i < groups.Count; ++i) + for (var i = 0; i < groups.Count; ++i) { - DictionaryEntry de = (DictionaryEntry)groups[i]; - ArrayList groupList = (ArrayList)de.Value; + var de = (DictionaryEntry)groups[i]; + var groupList = (ArrayList)de.Value; if (!HasAttribute((Type)de.Key, typeofNoSort, false)) { @@ -531,7 +531,7 @@ public class XmlPropertiesGump : Gump private static CPA GetCPA(PropertyInfo prop) { - object[] attrs = prop.GetCustomAttributes(typeofCPA, false); + var attrs = prop.GetCustomAttributes(typeofCPA, false); if (attrs.Length > 0) { @@ -543,23 +543,23 @@ public class XmlPropertiesGump : Gump private ArrayList GetGroups(Type objectType, PropertyInfo[] props) { - Hashtable groups = new Hashtable(); + var groups = new Hashtable(); - for (int i = 0; i < props.Length; ++i) + for (var i = 0; i < props.Length; ++i) { - PropertyInfo prop = props[i]; + var prop = props[i]; if (prop.CanRead) { - CPA attr = GetCPA(prop); + var attr = GetCPA(prop); if (attr != null && m_Mobile.AccessLevel >= attr.ReadLevel) { - Type type = prop.DeclaringType; + var type = prop.DeclaringType; while (true) { - Type baseType = type.BaseType; + var baseType = type.BaseType; if (baseType == null || baseType == typeofObject) { @@ -576,7 +576,7 @@ public class XmlPropertiesGump : Gump } } - ArrayList list = (ArrayList)groups[type]; + var list = (ArrayList)groups[type]; if (list == null) { @@ -588,7 +588,7 @@ public class XmlPropertiesGump : Gump } } - ArrayList sorted = new ArrayList(groups); + var sorted = new ArrayList(groups); sorted.Sort(new GroupComparer(objectType)); @@ -650,8 +650,8 @@ public class XmlPropertiesGump : Gump return 1; } - PropertyInfo a = x as PropertyInfo; - PropertyInfo b = y as PropertyInfo; + var a = x as PropertyInfo; + var b = y as PropertyInfo; if (a == null || b == null) { @@ -672,7 +672,7 @@ public class XmlPropertiesGump : Gump private int GetDistance(Type type) { - Type current = m_Start; + var current = m_Start; int dist; @@ -706,8 +706,8 @@ public class XmlPropertiesGump : Gump throw new ArgumentException(); } - Type a = (Type)de1.Key; - Type b = (Type)de2.Key; + var a = (Type)de1.Key; + var b = (Type)de2.Key; return GetDistance(a).CompareTo(GetDistance(b)); } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetCustomEnumGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetCustomEnumGump.cs index a45d8f1da..bf545351a 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetCustomEnumGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetCustomEnumGump.cs @@ -17,13 +17,13 @@ public class XmlSetCustomEnumGump : XmlSetListOptionGump public override void OnResponse(NetState sender, RelayInfo relayInfo) { - int index = relayInfo.ButtonID - 1; + var index = relayInfo.ButtonID - 1; if (index >= 0 && index < m_Names.Length) { try { - MethodInfo info = m_Property.PropertyType.GetMethod("Parse", new[] { typeof(string) }); + var info = m_Property.PropertyType.GetMethod("Parse", new[] { typeof(string) }); CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, m_Names[index]); diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetGump.cs index e3decf23f..73ad7c6a7 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetGump.cs @@ -56,16 +56,16 @@ public class XmlSetGump : Gump m_Page = page; m_List = list; - bool canNull = !prop.PropertyType.IsValueType; - bool canDye = prop.IsDefined(typeof(HueAttribute), false); + var canNull = !prop.PropertyType.IsValueType; + var canDye = prop.IsDefined(typeof(HueAttribute), false); - int xextend = 0; + var xextend = 0; if (prop.PropertyType == typeof(string)) { xextend = 300; } - object val = prop.GetValue(m_Object, null); + var val = prop.GetValue(m_Object, null); var initialText = val == null ? "" : val.ToString(); @@ -74,8 +74,8 @@ public class XmlSetGump : Gump AddBackground(0, 0, BackWidth + xextend, BackHeight + (canNull ? EntryHeight + OffsetSize : 0) + (canDye ? EntryHeight + OffsetSize : 0), BackGumpID); AddImageTiled(BorderSize, BorderSize, TotalWidth + xextend - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight + (canNull ? EntryHeight + OffsetSize : 0) + (canDye ? EntryHeight + OffsetSize : 0), OffsetGumpID); - int x = BorderSize + OffsetSize; - int y = BorderSize + OffsetSize; + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize; AddImageTiled(x, y, EntryWidth + xextend, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y, EntryWidth + xextend - TextOffsetX, EntryHeight, TextHue, prop.Name); @@ -179,7 +179,7 @@ public class XmlSetGump : Gump { case 1: { - TextRelay text = info.GetTextEntry(0); + var text = info.GetTextEntry(0); if (text != null) { diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetListOptionGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetListOptionGump.cs index ab7e061a1..7c40d47be 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetListOptionGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetListOptionGump.cs @@ -77,33 +77,33 @@ public class XmlSetListOptionGump : Gump m_Values = values; - int pages = (names.Length + EntryCount - 1) / EntryCount; - int index = 0; + var pages = (names.Length + EntryCount - 1) / EntryCount; + var index = 0; - for (int page = 1; page <= pages; ++page) + for (var page = 1; page <= pages; ++page) { AddPage(page); - int start = (page - 1) * EntryCount; - int count = names.Length - start; + var start = (page - 1) * EntryCount; + var count = names.Length - start; if (count > EntryCount) { count = EntryCount; } - int totalHeight = OffsetSize + (count + 2) * (EntryHeight + OffsetSize); - int backHeight = BorderSize + totalHeight + BorderSize; + var totalHeight = OffsetSize + (count + 2) * (EntryHeight + OffsetSize); + var backHeight = BorderSize + totalHeight + BorderSize; AddBackground(0, 0, BackWidth, backHeight, BackGumpID); AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID); - int x = BorderSize + OffsetSize; - int y = BorderSize + OffsetSize; + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize; - int emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4 - (OldStyle ? SetWidth + OffsetSize : 0); + var emptyWidth = TotalWidth - PrevWidth - NextWidth - OffsetSize * 4 - (OldStyle ? SetWidth + OffsetSize : 0); AddImageTiled(x, y, PrevWidth, EntryHeight, HeaderGumpID); @@ -145,7 +145,7 @@ public class XmlSetListOptionGump : Gump AddRect(0, prop.Name, 0); - for (int i = 0; i < count; ++i) + for (var i = 0; i < count; ++i) { AddRect(i + 1, names[index], ++index); } @@ -154,8 +154,8 @@ public class XmlSetListOptionGump : Gump private void AddRect(int index, string str, int button) { - int x = BorderSize + OffsetSize; - int y = BorderSize + OffsetSize + (index + 1) * (EntryHeight + OffsetSize); + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize + (index + 1) * (EntryHeight + OffsetSize); AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, str); @@ -175,13 +175,13 @@ public class XmlSetListOptionGump : Gump public override void OnResponse(NetState sender, RelayInfo info) { - int index = info.ButtonID - 1; + var index = info.ButtonID - 1; if (index >= 0 && index < m_Values.Length) { try { - object toSet = m_Values[index]; + var toSet = m_Values[index]; CommandLogging.LogChangeProperty(m_Mobile, m_Object, m_Property.Name, toSet == null ? "(-null-)" : toSet.ToString()); m_Property.SetValue(m_Object, toSet, null); } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs index b69949db6..d973cdf60 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetObjectGump.cs @@ -60,15 +60,15 @@ public class XmlSetObjectGump : Gump m_Page = page; m_List = list; - string initialText = XmlPropertiesGump.ValueToString(o, prop); + var initialText = XmlPropertiesGump.ValueToString(o, prop); AddPage(0); AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID); - int x = BorderSize + OffsetSize; - int y = BorderSize + OffsetSize; + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize; AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); @@ -252,7 +252,7 @@ public class XmlSetObjectGump : Gump { shouldSet = false; - object obj = m_Property.GetValue(m_Object, null); + var obj = m_Property.GetValue(m_Object, null); if (obj == null) { diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint2DGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint2DGump.cs index eb5f634cb..ed9f30b83 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint2DGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint2DGump.cs @@ -57,15 +57,15 @@ public class XmlSetPoint2DGump : Gump m_Page = page; m_List = list; - Point2D p = (Point2D)prop.GetValue(o, null); + var p = (Point2D)prop.GetValue(o, null); AddPage(0); AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID); - int x = BorderSize + OffsetSize; - int y = BorderSize + OffsetSize; + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize; AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); @@ -146,7 +146,7 @@ public class XmlSetPoint2DGump : Gump protected override void OnTarget(Mobile from, object targeted) { - IPoint3D p = targeted as IPoint3D; + var p = targeted as IPoint3D; if (p != null) { @@ -195,8 +195,8 @@ public class XmlSetPoint2DGump : Gump } case 3: // Use values { - TextRelay x = info.GetTextEntry(0); - TextRelay y = info.GetTextEntry(1); + var x = info.GetTextEntry(0); + var y = info.GetTextEntry(1); toSet = new Point2D(x == null ? 0 : Utility.ToInt32(x.Text), y == null ? 0 : Utility.ToInt32(y.Text)); shouldSet = true; diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint3DGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint3DGump.cs index b0fa3c0a3..e6d4a99a9 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint3DGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetPoint3DGump.cs @@ -57,15 +57,15 @@ public class XmlSetPoint3DGump : Gump m_Page = page; m_List = list; - Point3D p = (Point3D)prop.GetValue(o, null); + var p = (Point3D)prop.GetValue(o, null); AddPage(0); AddBackground(0, 0, BackWidth, BackHeight, BackGumpID); AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), TotalHeight, OffsetGumpID); - int x = BorderSize + OffsetSize; - int y = BorderSize + OffsetSize; + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize; AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, prop.Name); @@ -151,7 +151,7 @@ public class XmlSetPoint3DGump : Gump protected override void OnTarget(Mobile from, object targeted) { - IPoint3D p = targeted as IPoint3D; + var p = targeted as IPoint3D; if (p != null) { @@ -200,9 +200,9 @@ public class XmlSetPoint3DGump : Gump } case 3: // Use values { - TextRelay x = info.GetTextEntry(0); - TextRelay y = info.GetTextEntry(1); - TextRelay z = info.GetTextEntry(2); + var x = info.GetTextEntry(0); + var y = info.GetTextEntry(1); + var z = info.GetTextEntry(2); toSet = new Point3D(x == null ? 0 : Utility.ToInt32(x.Text), y == null ? 0 : Utility.ToInt32(y.Text), z == null ? 0 : Utility.ToInt32(z.Text)); shouldSet = true; diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetTimeSpanGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetTimeSpanGump.cs index 2e1c45a6e..79550de54 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetTimeSpanGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlPropsGumps/XmlSetTimeSpanGump.cs @@ -56,7 +56,7 @@ public class XmlSetTimeSpanGump : Gump m_Page = page; m_List = list; - TimeSpan ts = (TimeSpan)prop.GetValue(o, null); + var ts = (TimeSpan)prop.GetValue(o, null); AddPage(0); @@ -74,8 +74,8 @@ public class XmlSetTimeSpanGump : Gump private void AddRect(int index, string str, int button, int text) { - int x = BorderSize + OffsetSize; - int y = BorderSize + OffsetSize + index * (EntryHeight + OffsetSize); + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize + index * (EntryHeight + OffsetSize); AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, str); @@ -103,9 +103,9 @@ public class XmlSetTimeSpanGump : Gump TimeSpan toSet; bool shouldSet, shouldSend; - TextRelay h = info.GetTextEntry(0); - TextRelay m = info.GetTextEntry(1); - TextRelay s = info.GetTextEntry(2); + var h = info.GetTextEntry(0); + var m = info.GetTextEntry(1); + var s = info.GetTextEntry(2); switch (info.ButtonID) { diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs index 735ad243c..b7bcd12c2 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawner.cs @@ -224,7 +224,7 @@ public class XmlSpawner : Item, ISpawner var count = 0; if (ProximityRange >= 0) { - foreach (Mobile m in GetMobilesInRange(ProximityRange)) + foreach (var m in GetMobilesInRange(ProximityRange)) { if (m?.Player == true) { @@ -7995,7 +7995,7 @@ public class XmlSpawner : Item, ISpawner if (m_ProximityRange >= 0 && CanSpawn) { // check all nearby players - foreach (Mobile p in GetMobilesInRange(m_ProximityRange)) + foreach (var p in GetMobilesInRange(m_ProximityRange)) { if (ValidPlayerTrig(p)) { @@ -9531,7 +9531,7 @@ public class XmlSpawner : Item, ISpawner if (checkitems) { // check the itemsid - foreach (Item i in map.GetItemsAt(x, y)) + foreach (var i in map.GetItemsAt(x, y)) { if (i.ItemData.Impassable) { @@ -11900,7 +11900,7 @@ public class XmlSpawner : Item, ISpawner parmstr = GetParm(s, ":CA="); // if kills needed is zero, then set CA to false by default. This maintains consistency with the // previous default behavior for old spawn specs that haven't specified CA - bool clearAdvance = killsNeeded != 0; + var clearAdvance = killsNeeded != 0; if (parmstr != null) { try { clearAdvance = int.Parse(parmstr) == 1; } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs index 7669f1bb2..9d6605b87 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerGumps.cs @@ -35,7 +35,7 @@ public class TextEntryGump : Gump AddImageTiled(23, 5, 214, 270, 0x52); AddImageTiled(24, 6, 213, 261, 0xBBC); - string label = $"{spawner.Name} entry {index}"; + var label = $"{spawner.Name} entry {index}"; AddLabel(28, 10, 0x384, label); // OK button @@ -75,8 +75,8 @@ public class TextEntryGump : Gump return; } - bool update_entry = false; - bool edit_entry = false; + var update_entry = false; + var edit_entry = false; switch (info.ButtonID) { @@ -103,26 +103,26 @@ public class TextEntryGump : Gump if (edit_entry) { // get the old text - TextRelay entry = info.GetTextEntry(1); - string oldtext = entry.Text; + var entry = info.GetTextEntry(1); + var oldtext = entry.Text; // get the new text entry = info.GetTextEntry(2); - string newtext = entry.Text; + var newtext = entry.Text; // make the substitution entry = info.GetTextEntry(0); - string origtext = entry.Text; + var origtext = entry.Text; if (origtext != null && oldtext != null && newtext != null) { try { - int firstindex = origtext.IndexOf(oldtext); + var firstindex = origtext.IndexOf(oldtext); if (firstindex >= 0) { - int secondindex = firstindex + oldtext.Length; + var secondindex = firstindex + oldtext.Length; - int lastindex = origtext.Length - 1; + var lastindex = origtext.Length - 1; string editedtext; if (firstindex > 0) @@ -154,7 +154,7 @@ public class TextEntryGump : Gump } if (update_entry) { - TextRelay entry = info.GetTextEntry(0); + var entry = info.GetTextEntry(0); if (m_index < m_Spawner.SpawnObjects.Length) { m_Spawner.SpawnObjects[m_index].TypeName = entry.Text; @@ -341,7 +341,7 @@ public class XmlSpawnerGump : Gump // add the status string AddTextEntry(38, 384, 235, 33, 33, 900, m_Spawner.status_str); // add the page buttons - for (int i = 0; i < MaxSpawnEntries / MaxEntriesPerPage; i++) + for (var i = 0; i < MaxSpawnEntries / MaxEntriesPerPage; i++) { //AddButton(38+i*30, 365, 2206, 2206, 0, GumpButtonType.Page, 1+i); AddButton(38 + i * 25, 365, 0x8B1 + i, 0x8B1 + i, 4000 + i); @@ -373,16 +373,16 @@ public class XmlSpawnerGump : Gump } - for (int i = 0; i < MaxSpawnEntries; i++) + for (var i = 0; i < MaxSpawnEntries; i++) { if (page != i / MaxEntriesPerPage) { continue; } - string str = string.Empty; - int texthue = 0; - int background = 0xBBC; + var str = string.Empty; + var texthue = 0; + var background = 0xBBC; if (i % MaxEntriesPerPage == 0) { @@ -408,7 +408,7 @@ public class XmlSpawnerGump : Gump } } - bool hasreplacement = false; + var hasreplacement = false; // check for replacement entries if (Rentry != null && Rentry.Index == i) @@ -444,10 +444,10 @@ public class XmlSpawnerGump : Gump str = m_Spawner.SpawnObjects[i].TypeName; } - int count = m_Spawner.SpawnObjects[i].SpawnedObjects.Count; - int max = m_Spawner.SpawnObjects[i].ActualMaxCount; - int subgrp = m_Spawner.SpawnObjects[i].SubGroup; - int spawnsper = m_Spawner.SpawnObjects[i].SpawnsPerTick; + var count = m_Spawner.SpawnObjects[i].SpawnedObjects.Count; + var max = m_Spawner.SpawnObjects[i].ActualMaxCount; + var subgrp = m_Spawner.SpawnObjects[i].SubGroup; + var spawnsper = m_Spawner.SpawnObjects[i].SpawnsPerTick; texthue = subgrp * 11; if (texthue < 0) @@ -482,7 +482,7 @@ public class XmlSpawnerGump : Gump string strmind = null; string strmaxd = null; string strpackrange = null; - string strspawnsper = spawnsper.ToString(); + var strspawnsper = spawnsper.ToString(); if (m_Spawner.SpawnObjects[i].SequentialResetTime > 0 && m_Spawner.SpawnObjects[i].SubGroup > 0) { @@ -529,7 +529,7 @@ public class XmlSpawnerGump : Gump strnext = m_Spawner.NextSpawn.ToString(); } - int yoff = 22 * (i % MaxEntriesPerPage) + 30; + var yoff = 22 * (i % MaxEntriesPerPage) + 30; // spawns per tick AddImageTiled(303 + xoffset, yoff, 30, 23, 0x52); @@ -585,15 +585,15 @@ public class XmlSpawnerGump : Gump public XmlSpawner.SpawnObject[] CreateArray(RelayInfo info, Mobile from) { - ArrayList SpawnObjects = new ArrayList(); + var SpawnObjects = new ArrayList(); - for (int i = 0; i < MaxSpawnEntries; i++) + for (var i = 0; i < MaxSpawnEntries; i++) { - TextRelay te = info.GetTextEntry(i); + var te = info.GetTextEntry(i); if (te != null) { - string str = te.Text; + var str = te.Text; if (str.Length > 0) { @@ -601,16 +601,16 @@ public class XmlSpawnerGump : Gump #if (BOOKTEXTENTRY) if (i < m_Spawner.SpawnObjects.Length) { - string currenttext = m_Spawner.SpawnObjects[i].TypeName; + var currenttext = m_Spawner.SpawnObjects[i].TypeName; if (currenttext != null && currenttext.Length >= 230) { str = currenttext; } } #endif - string typestr = BaseXmlSpawner.ParseObjectType(str); + var typestr = BaseXmlSpawner.ParseObjectType(str); - Type type = AssemblyHandler.FindTypeByName(typestr); + var type = AssemblyHandler.FindTypeByName(typestr); if (type != null) { @@ -639,13 +639,13 @@ public class XmlSpawnerGump : Gump public void UpdateTypeNames(Mobile from, RelayInfo info) { - for (int i = 0; i < MaxSpawnEntries; i++) + for (var i = 0; i < MaxSpawnEntries; i++) { - TextRelay te = info.GetTextEntry(i); + var te = info.GetTextEntry(i); if (te != null) { - string str = te.Text; + var str = te.Text; if (str.Length > 0) { @@ -657,7 +657,7 @@ public class XmlSpawnerGump : Gump // that could be longer than the buffer if booktextentry is used #if (BOOKTEXTENTRY) - string currentstr = m_Spawner.SpawnObjects[i].TypeName; + var currentstr = m_Spawner.SpawnObjects[i].TypeName; if (currentstr != null && currentstr.Length < 230) #endif { @@ -685,13 +685,13 @@ public class XmlSpawnerGump : Gump return; } - NetState ns = from.NetState; + var ns = from.NetState; if (ns?.Gumps != null) { - ArrayList refresh = new ArrayList(); + var refresh = new ArrayList(); - foreach (Gump g in ns.Gumps) + foreach (var g in ns.Gumps) { // clear the gump status on the spawner associated with the gump if (g is XmlSpawnerGump xg && xg.m_Spawner != null) @@ -712,7 +712,7 @@ public class XmlSpawnerGump : Gump // flag the current gump on the spawner as closed g.m_Spawner.GumpReset = true; - XmlSpawnerGump xg = new XmlSpawnerGump(g.m_Spawner, g.X, g.Y, g.m_ShowGump, g.xoffset, g.page, g.Rentry); + var xg = new XmlSpawnerGump(g.m_Spawner, g.X, g.Y, g.m_ShowGump, g.xoffset, g.page, g.Rentry); from.SendGump(xg); } @@ -763,7 +763,7 @@ public class XmlSpawnerGump : Gump } // Get the current name - TextRelay tr = info.GetTextEntry(999); + var tr = info.GetTextEntry(999); if (tr != null) { m_Spawner.Name = tr.Text; @@ -781,7 +781,7 @@ public class XmlSpawnerGump : Gump return; } - for (int i = 0; i < m_Spawner.SpawnObjects.Length; i++) + for (var i = 0; i < m_Spawner.SpawnObjects.Length; i++) { if (page != i / MaxEntriesPerPage) { @@ -789,10 +789,10 @@ public class XmlSpawnerGump : Gump } // check the max count entry - TextRelay temcnt = info.GetTextEntry(500 + i); + var temcnt = info.GetTextEntry(500 + i); if (temcnt != null) { - int maxval = 0; + var maxval = 0; try { maxval = Convert.ToInt32(temcnt.Text, 10); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } if (maxval < 0) @@ -806,10 +806,10 @@ public class XmlSpawnerGump : Gump if (m_ShowGump > 0) { // check the subgroup entry - TextRelay tegrp = info.GetTextEntry(600 + i); + var tegrp = info.GetTextEntry(600 + i); if (tegrp != null) { - int grpval = 0; + var grpval = 0; try { grpval = Convert.ToInt32(tegrp.Text, 10); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } if (grpval < 0) @@ -824,7 +824,7 @@ public class XmlSpawnerGump : Gump if (m_ShowGump > 1) { // note, while these values can be entered in any spawn entry, they will only be assigned to the subgroup leader - int subgroupindex = m_Spawner.GetCurrentSequentialSpawnIndex(m_Spawner.SpawnObjects[i].SubGroup); + var subgroupindex = m_Spawner.GetCurrentSequentialSpawnIndex(m_Spawner.SpawnObjects[i].SubGroup); TextRelay tegrp; if (subgroupindex >= 0 && subgroupindex < m_Spawner.SpawnObjects.Length) @@ -849,7 +849,7 @@ public class XmlSpawnerGump : Gump tegrp = info.GetTextEntry(1100 + i); if (tegrp?.Text != null && tegrp.Text.Length > 0) { - int grpval = 0; + var grpval = 0; try { grpval = Convert.ToInt32(tegrp.Text, 10); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } if (grpval < 0) @@ -863,7 +863,7 @@ public class XmlSpawnerGump : Gump tegrp = info.GetTextEntry(1200 + i); if (tegrp?.Text != null && tegrp.Text.Length > 0) { - int grpval = 0; + var grpval = 0; try { grpval = Convert.ToInt32(tegrp.Text, 10); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } if (grpval < 0) @@ -939,7 +939,7 @@ public class XmlSpawnerGump : Gump { if (!string.IsNullOrEmpty(tegrp.Text)) { - int grpval = 1; + var grpval = 1; try { grpval = int.Parse(tegrp.Text); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } if (grpval < 0) @@ -965,7 +965,7 @@ public class XmlSpawnerGump : Gump { if (!string.IsNullOrEmpty(tegrp.Text)) { - int grpval = 1; + var grpval = 1; try { grpval = int.Parse(tegrp.Text); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } if (grpval < 0) @@ -988,10 +988,10 @@ public class XmlSpawnerGump : Gump } // Update the maxcount - TextRelay temax = info.GetTextEntry(300); + var temax = info.GetTextEntry(300); if (temax != null) { - int maxval = 0; + var maxval = 0; try { maxval = Convert.ToInt32(temax.Text, 10); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } if (maxval < 0) @@ -1097,7 +1097,7 @@ public class XmlSpawnerGump : Gump // check the restrict kills flag if (info.ButtonID >= 300 && info.ButtonID < 300 + MaxSpawnEntries) { - int index = info.ButtonID - 300; + var index = info.ButtonID - 300; if (index < m_Spawner.SpawnObjects.Length) { m_Spawner.SpawnObjects[index].RestrictKillsToSubgroup = !m_Spawner.SpawnObjects[index].RestrictKillsToSubgroup; @@ -1105,7 +1105,7 @@ public class XmlSpawnerGump : Gump } else if (info.ButtonID >= 400 && info.ButtonID < 400 + MaxSpawnEntries) { - int index = info.ButtonID - 400; + var index = info.ButtonID - 400; if (index < m_Spawner.SpawnObjects.Length) { m_Spawner.SpawnObjects[index].ClearOnAdvance = !m_Spawner.SpawnObjects[index].ClearOnAdvance; @@ -1114,11 +1114,11 @@ public class XmlSpawnerGump : Gump else if (info.ButtonID >= 800 && info.ButtonID < 800 + MaxSpawnEntries) { // open the text entry gump - int index = info.ButtonID - 800; + var index = info.ButtonID - 800; // open a text entry gump #if (BOOKTEXTENTRY) // display a new gump - XmlSpawnerGump newgump = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page); + var newgump = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page); state.Mobile.SendGump(newgump); // is there an existing book associated with the gump? @@ -1127,7 +1127,7 @@ public class XmlSpawnerGump : Gump m_Spawner.m_TextEntryBook = new List(); } - object[] args = new object[6]; + var args = new object[6]; args[0] = m_Spawner; args[1] = index; @@ -1136,7 +1136,7 @@ public class XmlSpawnerGump : Gump args[4] = m_ShowGump; args[5] = page; - XmlTextEntryBook book = new XmlTextEntryBook(0, string.Empty, m_Spawner.Name, 20, true); + var book = new XmlTextEntryBook(0, string.Empty, m_Spawner.Name, 20, true); m_Spawner.m_TextEntryBook.Add(book); @@ -1144,7 +1144,7 @@ public class XmlSpawnerGump : Gump book.Author = m_Spawner.Name; // fill the contents of the book with the current text entry data - string text = string.Empty; + var text = string.Empty; if (m_Spawner.SpawnObjects != null && index < m_Spawner.SpawnObjects.Length) { text = m_Spawner.SpawnObjects[index].TypeName; @@ -1168,21 +1168,21 @@ public class XmlSpawnerGump : Gump { nclicks++; // find the location of the spawn at the specified index - int index = info.ButtonID - 1300; + var index = info.ButtonID - 1300; if (index < m_Spawner.SpawnObjects.Length) { - int scount = m_Spawner.SpawnObjects[index].SpawnedObjects.Count; + var scount = m_Spawner.SpawnObjects[index].SpawnedObjects.Count; if (scount > 0) { - object so = m_Spawner.SpawnObjects[index].SpawnedObjects[nclicks % scount]; + var so = m_Spawner.SpawnObjects[index].SpawnedObjects[nclicks % scount]; if (ValidGotoObject(state.Mobile, so)) { - IPoint3D o = so as IPoint3D; + var o = so as IPoint3D; if (o != null) { - Map m = m_Spawner.Map; + var m = m_Spawner.Map; if (o is Item item) { @@ -1209,7 +1209,7 @@ public class XmlSpawnerGump : Gump } else if (info.ButtonID >= 6000 && info.ButtonID < 6000 + MaxSpawnEntries) { - int index = info.ButtonID - 6000; + var index = info.ButtonID - 6000; if (index < m_Spawner.SpawnObjects.Length) { @@ -1224,18 +1224,18 @@ public class XmlSpawnerGump : Gump } else if (info.ButtonID >= 5000 && info.ButtonID < 5000 + MaxSpawnEntries) { - int i = info.ButtonID - 5000; + var i = info.ButtonID - 5000; string categorystring = null; string entrystring = null; - TextRelay te = info.GetTextEntry(i); + var te = info.GetTextEntry(i); if (te?.Text != null) { // get the string - string[] cargs = te.Text.Split(','); + var cargs = te.Text.Split(','); // parse out any comma separated args categorystring = cargs[0]; @@ -1246,7 +1246,7 @@ public class XmlSpawnerGump : Gump if (string.IsNullOrEmpty(categorystring)) { - XmlSpawnerGump newg = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page); + var newg = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page); state.Mobile.SendGump(newg); // if no string has been entered then just use the full categorized add gump @@ -1259,17 +1259,17 @@ public class XmlSpawnerGump : Gump state.Mobile.CloseGump(); //Type [] types = (Type[])XmlPartialCategorizedAddGump.Match(categorystring).ToArray(typeof(Type)); - ArrayList types = XmlPartialCategorizedAddGump.Match(categorystring); + var types = XmlPartialCategorizedAddGump.Match(categorystring); - ReplacementEntry re = new ReplacementEntry + var re = new ReplacementEntry { Typename = entrystring, Index = i, Color = 0x1436 }; - XmlSpawnerGump newg = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page, re); + var newg = new XmlSpawnerGump(m_Spawner, X, Y, m_ShowGump, xoffset, page, re); state.Mobile.SendGump(new XmlPartialCategorizedAddGump(state.Mobile, categorystring, 0, types, true, i, newg)); @@ -1281,20 +1281,20 @@ public class XmlSpawnerGump : Gump else { // up and down arrows - int buttonID = info.ButtonID - 6; - int index = buttonID / 2; - int type = buttonID % 2; + var buttonID = info.ButtonID - 6; + var index = buttonID / 2; + var type = buttonID % 2; - TextRelay entry = info.GetTextEntry(index); + var entry = info.GetTextEntry(index); if (entry != null && entry.Text.Length > 0) { - string entrystr = entry.Text; + var entrystr = entry.Text; #if (BOOKTEXTENTRY) if (index < m_Spawner.SpawnObjects.Length) { - string str = m_Spawner.SpawnObjects[index].TypeName; + var str = m_Spawner.SpawnObjects[index].TypeName; if (str != null && str.Length >= 230) { diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs index fa1b2b6ed..0cf7bf50b 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlSpawnerSkillCheck.cs @@ -10,7 +10,7 @@ public class XmlSpawnerSkillCheck // alternate skillcheck hooks to replace those in SkillCheck.cs public static bool Mobile_SkillCheckLocation(Mobile from, SkillName skillName, double minSkill, double maxSkill) { - Skill skill = from.Skills[skillName]; + var skill = from.Skills[skillName]; if (skill == null) { @@ -18,7 +18,7 @@ public class XmlSpawnerSkillCheck } // call the default skillcheck handler - bool success = SkillCheck.Mobile_SkillCheckLocation( from, skillName, minSkill, maxSkill); + var success = SkillCheck.Mobile_SkillCheckLocation( from, skillName, minSkill, maxSkill); // call the xmlspawner skillcheck handler CheckSkillUse(from, skill, success); @@ -28,7 +28,7 @@ public class XmlSpawnerSkillCheck public static bool Mobile_SkillCheckDirectLocation(Mobile from, SkillName skillName, double chance) { - Skill skill = from.Skills[skillName]; + var skill = from.Skills[skillName]; if (skill == null) { @@ -36,7 +36,7 @@ public class XmlSpawnerSkillCheck } // call the default skillcheck handler - bool success = SkillCheck.Mobile_SkillCheckDirectLocation( from, skillName, chance); + var success = SkillCheck.Mobile_SkillCheckDirectLocation( from, skillName, chance); // call the xmlspawner skillcheck handler CheckSkillUse(from, skill, success); @@ -46,7 +46,7 @@ public class XmlSpawnerSkillCheck public static bool Mobile_SkillCheckTarget(Mobile from, SkillName skillName, object target, double minSkill, double maxSkill) { - Skill skill = from.Skills[skillName]; + var skill = from.Skills[skillName]; if (skill == null) { @@ -54,7 +54,7 @@ public class XmlSpawnerSkillCheck } // call the default skillcheck handler - bool success = SkillCheck.Mobile_SkillCheckTarget( from, skillName, target, minSkill, maxSkill); + var success = SkillCheck.Mobile_SkillCheckTarget( from, skillName, target, minSkill, maxSkill); // call the xmlspawner skillcheck handler CheckSkillUse(from, skill, success); @@ -64,7 +64,7 @@ public class XmlSpawnerSkillCheck public static bool Mobile_SkillCheckDirectTarget(Mobile from, SkillName skillName, object target, double chance) { - Skill skill = from.Skills[skillName]; + var skill = from.Skills[skillName]; if (skill == null) { @@ -72,7 +72,7 @@ public class XmlSpawnerSkillCheck } // call the default skillcheck handler - bool success = SkillCheck.Mobile_SkillCheckDirectTarget( from, skillName, target, chance); + var success = SkillCheck.Mobile_SkillCheckDirectTarget( from, skillName, target, chance); // call the xmlspawner skillcheck handler CheckSkillUse(from, skill, success); @@ -153,9 +153,9 @@ public class XmlSpawnerSkillCheck } // go through the list and if the spawner is not on it yet, then add it - bool found = false; + var found = false; - ArrayList skilllist = RegisteredSkill.TriggerList(s, map); + var skilllist = RegisteredSkill.TriggerList(s, map); if (skilllist == null) { @@ -175,7 +175,7 @@ public class XmlSpawnerSkillCheck // if it hasnt already been added to the list, then add it if (!found) { - RegisteredSkill newrs = new RegisteredSkill(); + var newrs = new RegisteredSkill(); newrs.target = o; newrs.sid = s; @@ -194,9 +194,9 @@ public class XmlSpawnerSkillCheck // go through the list and if the spawner is on it regardless of the skill registered, then remove it if (all) { - for(int i = 0;i 20) { length = 20; @@ -52,11 +52,11 @@ public class XmlTextEntryBook : BaseBook pagenum++; } // empty the remaining contents - for (int j = pagenum; j < PagesCount; j++) + for (var j = pagenum; j < PagesCount; j++) { if (Pages[j].Lines.Length > 0) { - for (int i = 0; i < Pages[j].Lines.Length; i++) + for (var i = 0; i < Pages[j].Lines.Length; i++) { Pages[j].Lines[i] = string.Empty; } diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs index c74c2fa30..145895cb8 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlAdd.cs @@ -83,9 +83,9 @@ public class XmlSpawnerDefaults // find the default entry corresponding to the account and username if (DefaultEntryList != null) { - for (int i = 0; i < DefaultEntryList.Count; i++) + for (var i = 0; i < DefaultEntryList.Count; i++) { - DefaultEntry entry = (DefaultEntry)DefaultEntryList[i]; + var entry = (DefaultEntry)DefaultEntryList[i]; if (entry != null && string.Compare(entry.PlayerName, name, true) == 0 && string.Compare(entry.AccountName, account, true) == 0) { return entry; @@ -93,7 +93,7 @@ public class XmlSpawnerDefaults } } // if not found then add one - DefaultEntry newentry = new DefaultEntry + var newentry = new DefaultEntry { PlayerName = name, AccountName = account @@ -187,9 +187,9 @@ public class XmlAddGump : Gump return "0"; } - System.Text.StringBuilder sb = new System.Text.StringBuilder(); + var sb = new System.Text.StringBuilder(); sb.AppendFormat("{0}", defs.NameList.Length); - for (int i = 0; i < defs.NameList.Length; i++) + for (var i = 0; i < defs.NameList.Length; i++) { sb.AppendFormat(":{0}", defs.NameList[i]); } @@ -203,9 +203,9 @@ public class XmlAddGump : Gump return "0"; } - System.Text.StringBuilder sb = new System.Text.StringBuilder(); + var sb = new System.Text.StringBuilder(); sb.AppendFormat("{0}", defs.SelectionList.Length); - for (int i = 0; i < defs.SelectionList.Length; i++) + for (var i = 0; i < defs.SelectionList.Length; i++) { sb.AppendFormat(":{0}", defs.SelectionList[i] ? 1 : 0); } @@ -214,9 +214,9 @@ public class XmlAddGump : Gump private static string[] StringToNameList(string namelist) { - string[] newlist = new string[MaxEntries]; - string[] tmplist = namelist.Split(':'); - for (int i = 1; i < tmplist.Length; i++) + var newlist = new string[MaxEntries]; + var tmplist = namelist.Split(':'); + for (var i = 1; i < tmplist.Length; i++) { if (i - 1 >= newlist.Length) { @@ -230,9 +230,9 @@ public class XmlAddGump : Gump private static bool[] StringToSelectionList(string selectionlist) { - bool[] newlist = new bool[MaxEntries]; - string[] tmplist = selectionlist.Split(':'); - for (int i = 1; i < tmplist.Length; i++) + var newlist = new bool[MaxEntries]; + var tmplist = selectionlist.Split(':'); + for (var i = 1; i < tmplist.Length; i++) { if (i - 1 >= newlist.Length) { @@ -259,7 +259,7 @@ public class XmlAddGump : Gump } // Create the data set - DataSet ds = new DataSet(DefsDataSetName); + var ds = new DataSet(DefsDataSetName); // Load the data set up ds.Tables.Add(DefsTablePointName); @@ -312,7 +312,7 @@ public class XmlAddGump : Gump ds.Tables[DefsTablePointName].Columns.Add("AutoNumberValue"); // Create a new data row - DataRow dr = ds.Tables[DefsTablePointName].NewRow(); + var dr = ds.Tables[DefsTablePointName].NewRow(); // Populate the data //dr["AccountName"] = (string)defs.AccountName; @@ -364,7 +364,7 @@ public class XmlAddGump : Gump ds.Tables[DefsTablePointName].Rows.Add(dr); // Write out the file - bool file_error = false; + var file_error = false; var dirname = Directory.Exists(DefsDir) ? $"{DefsDir}/{filename}.defs" : $"{filename}.defs"; @@ -431,11 +431,11 @@ public class XmlAddGump : Gump } // Create the data set - DataSet ds = new DataSet(DefsDataSetName); + var ds = new DataSet(DefsDataSetName); // Read in the file //ds.ReadXml(e.Arguments[0].ToString()); - bool fileerror = false; + var fileerror = false; try { ds.ReadXml(fs); @@ -460,17 +460,17 @@ public class XmlAddGump : Gump if (ds.Tables[DefsTablePointName] != null && ds.Tables[DefsTablePointName].Rows.Count > 0) { //foreach(DataRow dr in ds.Tables[DefsTablePointName].Rows){ - DataRow dr = ds.Tables[DefsTablePointName].Rows[0]; + var dr = ds.Tables[DefsTablePointName].Rows[0]; try { defs.SpawnerName = (string)dr["SpawnerName"]; } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } - double mindelay = defs.MinDelay.TotalMinutes; + var mindelay = defs.MinDelay.TotalMinutes; try { mindelay = double.Parse((string)dr["MinDelay"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } defs.MinDelay = TimeSpan.FromMinutes(mindelay); - double maxdelay = defs.MaxDelay.TotalMinutes; + var maxdelay = defs.MaxDelay.TotalMinutes; try { maxdelay = double.Parse((string)dr["MaxDelay"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } defs.MaxDelay = TimeSpan.FromMinutes(maxdelay); @@ -486,22 +486,22 @@ public class XmlAddGump : Gump try { defs.Team = int.Parse((string)dr["Team"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } - double minrefract = defs.RefractMin.TotalMinutes; + var minrefract = defs.RefractMin.TotalMinutes; try { minrefract = double.Parse((string)dr["MinRefractory"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } defs.RefractMin = TimeSpan.FromMinutes(minrefract); - double maxrefract = defs.RefractMax.TotalMinutes; + var maxrefract = defs.RefractMax.TotalMinutes; try { maxrefract = double.Parse((string)dr["MaxRefractory"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } defs.RefractMax = TimeSpan.FromMinutes(maxrefract); - double todstart = defs.TODStart.TotalMinutes; + var todstart = defs.TODStart.TotalMinutes; try { todstart = double.Parse((string)dr["TODStart"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } defs.TODStart = TimeSpan.FromMinutes(todstart); - double todend = defs.TODEnd.TotalMinutes; + var todend = defs.TODEnd.TotalMinutes; try { todend = double.Parse((string)dr["TODEnd"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } defs.TODEnd = TimeSpan.FromMinutes(todend); @@ -522,12 +522,12 @@ public class XmlAddGump : Gump } } - double duration = defs.Duration.TotalMinutes; + var duration = defs.Duration.TotalMinutes; try { duration = double.Parse((string)dr["Duration"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } defs.Duration = TimeSpan.FromMinutes(duration); - double despawnTime = defs.DespawnTime.TotalHours; + var despawnTime = defs.DespawnTime.TotalHours; try { despawnTime = double.Parse((string)dr["DespawnTime"]); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); } defs.DespawnTime = TimeSpan.FromHours(despawnTime); @@ -613,9 +613,9 @@ public class XmlAddGump : Gump [Description("Opens a gump that can add Xmlspawners with specified default settings")] public static void XmlAdd_OnCommand(CommandEventArgs e) { - Account acct = e.Mobile.Account as Account; - int x = 440; - int y = 0; + var acct = e.Mobile.Account as Account; + var x = 440; + var y = 0; XmlSpawnerDefaults.DefaultEntry defs = null; if (acct != null) { @@ -631,7 +631,7 @@ public class XmlAddGump : Gump try { // Check if there is an argument provided (load criteria) - for (int nxtarg = 0; nxtarg < e.Arguments.Length; nxtarg++) + for (var nxtarg = 0; nxtarg < e.Arguments.Length; nxtarg++) { // is it a defaults option? if (e.Arguments[nxtarg].ToLower() == "-defaults") @@ -663,7 +663,7 @@ public class XmlAddGump : Gump m_From = from; // read the text entries for default values - Account acct = from.Account as Account; + var acct = from.Account as Account; if (acct != null) { defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); @@ -943,10 +943,10 @@ public class XmlAddGump : Gump // display the clear all toggle AddButton(475, 5, 0xD2, 0xD3, 3999); // display the selection entries - for (int i = 0; i < MaxEntries; i++) + for (var i = 0; i < MaxEntries; i++) { - int xpos = i / MaxEntriesPerColumn * 155; - int ypos = i % MaxEntriesPerColumn * 22 + 30; + var xpos = i / MaxEntriesPerColumn * 155; + var ypos = i % MaxEntriesPerColumn * 22 + 30; // background for search results area AddImageTiled(xpos + 205, ypos, 116, 23, 0x52); @@ -954,13 +954,13 @@ public class XmlAddGump : Gump // has this been selected for category info specification? AddImageTiled(xpos + 206, ypos + 1, 114, 21, i == defs.CategorySelectionIndex ? 0x1436 : 0xBBC); - bool sel = false; + var sel = false; if (defs.SelectionList != null && i < defs.SelectionList.Length) { sel = defs.SelectionList[i]; } - int texthue = 0; + var texthue = 0; if (sel) { texthue = 68; @@ -1059,7 +1059,7 @@ public class XmlAddGump : Gump // read the text entries for default values XmlSpawnerDefaults.DefaultEntry defs = null; - Account acct = from.Account as Account; + var acct = from.Account as Account; if (acct != null) { defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), from.Name); @@ -1070,8 +1070,8 @@ public class XmlAddGump : Gump return; } - int x = defs.AddGumpX; - int y = defs.AddGumpY; + var x = defs.AddGumpX; + var y = defs.AddGumpY; if (defs.ShowExtension) { // shift the starting point @@ -1101,7 +1101,7 @@ public class XmlAddGump : Gump // read the text entries for default values defs = null; - Account acct = state.Mobile.Account as Account; + var acct = state.Mobile.Account as Account; if (acct != null) { defs = XmlSpawnerDefaults.GetDefaults(acct.ToString(), state.Mobile.Name); @@ -1123,10 +1123,10 @@ public class XmlAddGump : Gump } // assign it a unique id - Guid SpawnId = Guid.NewGuid(); + var SpawnId = Guid.NewGuid(); // count the number of entries to be added for maxcount - int maxcount = 0; - for (int i = 0; i < MaxEntries; i++) + var maxcount = 0; + for (var i = 0; i < MaxEntries; i++) { if (defs.SelectionList != null && i < defs.SelectionList.Length && defs.SelectionList[i] && defs.NameList != null && i < defs.NameList.Length && defs.NameList[i] != null && defs.NameList[i].Length > 0) @@ -1136,13 +1136,13 @@ public class XmlAddGump : Gump } // if autonumbering is enabled, name the spawner with the name+number - string sname = defs.SpawnerName; + var sname = defs.SpawnerName; if (defs.AutoNumber) { sname = $"{defs.SpawnerName}#{defs.AutoNumberValue}"; } - XmlSpawner spawner = new XmlSpawner(SpawnId, from.Location.X, from.Location.Y, 0, 0, sname, maxcount, + var spawner = new XmlSpawner(SpawnId, from.Location.X, from.Location.Y, 0, 0, sname, maxcount, defs.MinDelay, defs.MaxDelay, defs.Duration, defs.ProximityRange, defs.ProximitySound, 1, defs.Team, defs.HomeRange, defs.HomeRangeIsRelative, new XmlSpawner.SpawnObject[0], defs.RefractMin, defs.RefractMax, defs.TODStart, defs.TODEnd, null, defs.TriggerObjectProp, defs.ProximityMsg, defs.TriggerOnCarried, defs.NoTriggerOnCarried, @@ -1160,7 +1160,7 @@ public class XmlAddGump : Gump else { // place the spawner at the targeted location - IPoint3D p = targeted as IPoint3D; + var p = targeted as IPoint3D; if (p == null) { spawner.Delete(); @@ -1176,7 +1176,7 @@ public class XmlAddGump : Gump spawner.SpawnRange = defs.SpawnRange; // add entries from the name list - for (int i = 0; i < MaxEntries; i++) + for (var i = 0; i < MaxEntries; i++) { if (defs.SelectionList != null && i < defs.SelectionList.Length && defs.SelectionList[i] && defs.NameList != null && i < defs.NameList.Length && defs.NameList[i] != null && defs.NameList[i].Length > 0) @@ -1209,13 +1209,13 @@ public class XmlAddGump : Gump } // read the text entries for default values - XmlSpawnerDefaults.DefaultEntry defaults = XmlSpawnerDefaults.GetDefaults(state.Account.ToString(), state.Mobile.Name); + var defaults = XmlSpawnerDefaults.GetDefaults(state.Account.ToString(), state.Mobile.Name); if (defaults.IgnoreUpdate) { return; } - TextRelay tr = info.GetTextEntry(100); // mindelay + var tr = info.GetTextEntry(100); // mindelay if (tr?.Text != null && tr.Text.Length > 0) { try { defaults.MinDelay = TimeSpan.FromMinutes(double.Parse(tr.Text)); } @@ -1259,7 +1259,7 @@ public class XmlAddGump : Gump tr = info.GetTextEntry(106); // Speech trigger if (tr != null) { - string txt = tr.Text; + var txt = tr.Text; if (txt != null && txt.Length == 0) { txt = null; @@ -1333,7 +1333,7 @@ public class XmlAddGump : Gump tr = info.GetTextEntry(117); // trigger on carried if (tr != null) { - string txt = tr.Text; + var txt = tr.Text; if (txt != null && txt.Length == 0) { txt = null; @@ -1345,7 +1345,7 @@ public class XmlAddGump : Gump tr = info.GetTextEntry(118); // no trigger on carried if (tr != null) { - string txt = tr.Text; + var txt = tr.Text; if (txt != null && txt.Length == 0) { txt = null; @@ -1357,7 +1357,7 @@ public class XmlAddGump : Gump tr = info.GetTextEntry(119); // proximity message if (tr != null) { - string txt = tr.Text; + var txt = tr.Text; if (txt != null && txt.Length == 0) { txt = null; @@ -1369,7 +1369,7 @@ public class XmlAddGump : Gump tr = info.GetTextEntry(120); // player trig prop if (tr != null) { - string txt = tr.Text; + var txt = tr.Text; if (txt != null && txt.Length == 0) { txt = null; @@ -1388,7 +1388,7 @@ public class XmlAddGump : Gump tr = info.GetTextEntry(122); // trig object prop if (tr != null) { - string txt = tr.Text; + var txt = tr.Text; if (txt != null && txt.Length == 0) { txt = null; @@ -1407,7 +1407,7 @@ public class XmlAddGump : Gump tr = info.GetTextEntry(124); // Skill trigger if (tr != null) { - string txt = tr.Text; + var txt = tr.Text; if (txt != null && txt.Length == 0) { txt = null; @@ -1426,7 +1426,7 @@ public class XmlAddGump : Gump // fill the NameList from the text entries if (defaults.ShowExtension) { - for (int i = 0; i < MaxEntries; i++) + for (var i = 0; i < MaxEntries; i++) { tr = info.GetTextEntry(1000 + i); if (defaults.NameList != null && i < defaults.NameList.Length && tr != null) @@ -1579,7 +1579,7 @@ public class XmlAddGump : Gump { if (info.ButtonID >= 4000 && info.ButtonID < 4000 + MaxEntries) { - int i = info.ButtonID - 4000; + var i = info.ButtonID - 4000; if (defaults.SelectionList != null && i >= 0 && i < defaults.SelectionList.Length) { defaults.SelectionList[i] = !defaults.SelectionList[i]; @@ -1587,10 +1587,10 @@ public class XmlAddGump : Gump } if (info.ButtonID >= 5000 && info.ButtonID < 5000 + MaxEntries) { - int i = info.ButtonID - 5000; + var i = info.ButtonID - 5000; defaults.CategorySelectionIndex = i; - XmlAddGump newg = new XmlAddGump(state.Mobile, defaults.StartingLoc, defaults.StartingMap, false, defaults.ShowExtension, 0, 0); + var newg = new XmlAddGump(state.Mobile, defaults.StartingLoc, defaults.StartingMap, false, defaults.ShowExtension, 0, 0); state.Mobile.SendGump(newg); @@ -1606,7 +1606,7 @@ public class XmlAddGump : Gump state.Mobile.CloseGump(); //Type [] types = (Type[])XmlPartialCategorizedAddGump.Match(defs.NameList[i]).ToArray(typeof(Type)); - ArrayList types = XmlPartialCategorizedAddGump.Match(defaults.NameList[i]); + var types = XmlPartialCategorizedAddGump.Match(defaults.NameList[i]); state.Mobile.SendGump(new XmlPartialCategorizedAddGump(state.Mobile, defaults.NameList[i], 0, types, true, i, newg)); } @@ -1625,7 +1625,7 @@ public class XmlAddGump : Gump public XmlAddOptionsGump(Mobile from) : base(0, 0) { // read the text entries for default values - Account acct = from.Account as Account; + var acct = from.Account as Account; XmlSpawnerDefaults.DefaultEntry defs = null; if (acct != null) @@ -1680,13 +1680,13 @@ public class XmlAddGump : Gump } // read the text entries for default values - XmlSpawnerDefaults.DefaultEntry defs = XmlSpawnerDefaults.GetDefaults(state.Account.ToString(), state.Mobile.Name); + var defs = XmlSpawnerDefaults.GetDefaults(state.Account.ToString(), state.Mobile.Name); if (defs == null) { return; } - TextRelay tr = info.GetTextEntry(100); // AddGumpX + var tr = info.GetTextEntry(100); // AddGumpX if (tr?.Text != null && tr.Text.Length > 0) { try { defs.AddGumpX = int.Parse(tr.Text); } @@ -1752,7 +1752,7 @@ public class XmlAddGump : Gump return; } - int radiostate = -1; + var radiostate = -1; if (info.Switches.Length > 0) { radiostate = info.Switches[0]; diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlCategorizedAddGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlCategorizedAddGump.cs index f8077e55a..9f2d863a2 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlCategorizedAddGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlCategorizedAddGump.cs @@ -42,11 +42,11 @@ public class XmlAddCAGObject : XmlAddCAGNode } else if (gump is XmlSpawnerGump spawnerGump) { - XmlSpawner m_Spawner = spawnerGump.m_Spawner; + var m_Spawner = spawnerGump.m_Spawner; if (m_Spawner != null) { - XmlSpawnerGump xg = m_Spawner.SpawnerGump; + var xg = m_Spawner.SpawnerGump; if (xg != null) { @@ -130,7 +130,7 @@ public class XmlAddCAGCategory : XmlAddCAGNode } else { - ArrayList nodes = new ArrayList(); + var nodes = new ArrayList(); try { @@ -170,7 +170,7 @@ public class XmlAddCAGCategory : XmlAddCAGNode { if (File.Exists(path)) { - XmlTextReader xml = new XmlTextReader(path) + var xml = new XmlTextReader(path) { WhitespaceHandling = WhitespaceHandling.None }; @@ -179,7 +179,7 @@ public class XmlAddCAGCategory : XmlAddCAGNode { if (xml.Name == "category" && xml.NodeType == XmlNodeType.Element) { - XmlAddCAGCategory cat = new XmlAddCAGCategory(null, xml); + var cat = new XmlAddCAGCategory(null, xml); xml.Close(); @@ -285,9 +285,9 @@ public class XmlCategorizedAddGump : Gump { m_Page = page; - XmlAddCAGNode[] nodes = m_Category.Nodes; + var nodes = m_Category.Nodes; - int count = nodes.Length - page * EntryCount; + var count = nodes.Length - page * EntryCount; if (count < 0) { @@ -298,15 +298,15 @@ public class XmlCategorizedAddGump : Gump count = EntryCount; } - int totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); + var totalHeight = OffsetSize + (EntryHeight + OffsetSize) * (count + 1); AddPage(0); AddBackground(0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID); AddImageTiled(BorderSize, BorderSize, TotalWidth - (OldStyle ? SetWidth + OffsetSize : 0), totalHeight, OffsetGumpID); - int x = BorderSize + OffsetSize; - int y = BorderSize + OffsetSize; + var x = BorderSize + OffsetSize; + var y = BorderSize + OffsetSize; if (OldStyle) { @@ -329,7 +329,7 @@ public class XmlCategorizedAddGump : Gump x += PrevWidth + OffsetSize; - int emptyWidth = TotalWidth - PrevWidth * 2 - NextWidth - OffsetSize * 5 - (OldStyle ? SetWidth + OffsetSize : 0); + var emptyWidth = TotalWidth - PrevWidth * 2 - NextWidth - OffsetSize * 5 - (OldStyle ? SetWidth + OffsetSize : 0); if (!OldStyle) { @@ -382,7 +382,7 @@ public class XmlCategorizedAddGump : Gump x = BorderSize + OffsetSize; y += EntryHeight + OffsetSize; - XmlAddCAGNode node = nodes[index]; + var node = nodes[index]; AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID); AddLabelCropped(x + TextOffsetX, y + (EntryHeight - 20) / 2, EntryWidth - TextOffsetX, EntryHeight, TextHue, node.Caption); @@ -398,9 +398,9 @@ public class XmlCategorizedAddGump : Gump if (node is XmlAddCAGObject obj) { - int itemID = obj.ItemID; + var itemID = obj.ItemID; - Rectangle2D bounds = ItemBounds.Table[itemID]; + var bounds = ItemBounds.Table[itemID]; if (itemID != 1 && bounds.Height < EntryHeight * 2) { @@ -419,7 +419,7 @@ public class XmlCategorizedAddGump : Gump public override void OnResponse(NetState state, RelayInfo info) { - Mobile from = m_Owner; + var from = m_Owner; switch (info.ButtonID) { @@ -431,7 +431,7 @@ public class XmlCategorizedAddGump : Gump { if (m_Category.Parent != null) { - int index = Array.IndexOf(m_Category.Parent.Nodes, m_Category) / EntryCount; + var index = Array.IndexOf(m_Category.Parent.Nodes, m_Category) / EntryCount; if (index < 0) { @@ -463,7 +463,7 @@ public class XmlCategorizedAddGump : Gump } default: { - int index = m_Page * EntryCount + (info.ButtonID - 4); + var index = m_Page * EntryCount + (info.ButtonID - 4); if (index >= 0 && index < m_Category.Nodes.Length) { diff --git a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlPartialCategorizedAddGump.cs b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlPartialCategorizedAddGump.cs index 00de759ff..641714baf 100644 --- a/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlPartialCategorizedAddGump.cs +++ b/Projects/UOContent/Engines/XMLSpawner/XmlUtils/XmlPartialCategorizedAddGump.cs @@ -55,17 +55,17 @@ public class XmlPartialCategorizedAddGump : Gump if (searchResults.Count > 0) { - for (int i = page * 10; i < (page + 1) * 10 && i < searchResults.Count; ++i) + for (var i = page * 10; i < (page + 1) * 10 && i < searchResults.Count; ++i) { - int index = i % 10; + var index = i % 10; - SearchEntry se = (SearchEntry)searchResults[i]; + var se = (SearchEntry)searchResults[i]; - string labelstr = se.EntryType.Name; + var labelstr = se.EntryType.Name; if (se.Parameters.Length > 0) { - for (int j = 0; j < se.Parameters.Length; j++) + for (var j = 0; j < se.Parameters.Length; j++) { labelstr += $", {se.Parameters[j].Name}"; } @@ -122,19 +122,19 @@ public class XmlPartialCategorizedAddGump : Gump match = match.ToLower(); - for (int i = 0; i < types.Count; ++i) + for (var i = 0; i < types.Count; ++i) { - Type t = types[i]; + var t = types[i]; if ((typeofMobile.IsAssignableFrom(t) || typeofItem.IsAssignableFrom(t)) && t.Name.ToLower().IndexOf(match) >= 0 && !results.Contains(t)) { - ConstructorInfo[] ctors = t.GetConstructors(); + var ctors = t.GetConstructors(); - for (int j = 0; j < ctors.Length; ++j) + for (var j = 0; j < ctors.Length; ++j) { if (/*ctors[j].GetParameters().Length == 0 && */ ctors[j].IsDefined(typeof(ConstructibleAttribute), false)) { - SearchEntry s = new SearchEntry + var s = new SearchEntry { EntryType = t, Parameters = ctors[j].GetParameters() @@ -150,12 +150,12 @@ public class XmlPartialCategorizedAddGump : Gump public static ArrayList Match(string match) { - ArrayList results = new ArrayList(); + var results = new ArrayList(); Type[] types; - Assembly[] asms = AssemblyHandler.Assemblies; + var asms = AssemblyHandler.Assemblies; - for (int i = 0; i < asms.Length; ++i) + for (var i = 0; i < asms.Length; ++i) { types = AssemblyHandler.GetTypeCache(asms[i]).Types; Match(match, types, results); @@ -173,8 +173,8 @@ public class XmlPartialCategorizedAddGump : Gump { public int Compare(object x, object y) { - SearchEntry a = x as SearchEntry; - SearchEntry b = y as SearchEntry; + var a = x as SearchEntry; + var b = y as SearchEntry; return a.EntryType.Name.CompareTo(b.EntryType.Name); } @@ -183,14 +183,14 @@ public class XmlPartialCategorizedAddGump : Gump public override void OnResponse(Network.NetState sender, RelayInfo info) { - Mobile from = sender.Mobile; + var from = sender.Mobile; switch (info.ButtonID) { case 1: // Search { - TextRelay te = info.GetTextEntry(0); - string match = te == null ? "" : te.Text.Trim(); + var te = info.GetTextEntry(0); + var match = te == null ? "" : te.Text.Trim(); if (match.Length < 3) { @@ -224,11 +224,11 @@ public class XmlPartialCategorizedAddGump : Gump } default: { - int index = info.ButtonID - 4; + var index = info.ButtonID - 4; if (index >= 0 && index < m_SearchResults.Count) { - Type type = ((SearchEntry)m_SearchResults[index]).EntryType; + var type = ((SearchEntry)m_SearchResults[index]).EntryType; if (m_Gump is XmlAddGump mXmlAddGump && type != null) { @@ -240,7 +240,7 @@ public class XmlPartialCategorizedAddGump : Gump } else if (m_Spawner != null && type != null) { - XmlSpawnerGump xg = m_Spawner.SpawnerGump; + var xg = m_Spawner.SpawnerGump; if (xg != null) {