#define ServUO using System; using System.Text; using Server; using Server.Commands; using Server.Commands.Generic; using Server.Network; using System.Collections; using System.Collections.Generic; using Server.Mobiles; using Server.Targeting; using CPA = Server.CommandPropertyAttribute; using System.Reflection; using Server.Gumps; using Server.Items; using System.IO; using System.Diagnostics; using Server.Accounting; using System.Net.Mail; using Server.Misc; using Server.ContextMenus; namespace Server.Engines.XmlSpawner2 { [AttributeUsage(AttributeTargets.Constructor)] public class Attachable : Attribute { public Attachable() { } } public class ASerial { private int m_SerialValue; public int Value { get { return m_SerialValue; } } public ASerial(int serial) { m_SerialValue = serial; } private static int m_GlobalSerialValue; public static bool serialInitialized = false; public static ASerial NewSerial() { // it is possible for new attachments to be constructed before existing attachments are deserialized and the current m_globalserialvalue // restored. This creates a possible serial conflict, so dont allow assignment of valid serials until proper deser of m_globalserialvalue // Resolve unassigned serials in initialization if (!serialInitialized) return new ASerial(0); if (m_GlobalSerialValue == int.MaxValue || m_GlobalSerialValue < 0) m_GlobalSerialValue = 0; // try the next serial number in the series int newserialno = m_GlobalSerialValue + 1; // check to make sure that it is not in use while (XmlAttach.AllAttachments.ContainsKey(newserialno)) { newserialno++; if (newserialno == int.MaxValue || newserialno < 0) newserialno = 1; } m_GlobalSerialValue = newserialno; return new ASerial(m_GlobalSerialValue); } internal static void GlobalSerialize(GenericWriter writer) { writer.Write(m_GlobalSerialValue); } internal static void GlobalDeserialize(GenericReader reader) { m_GlobalSerialValue = reader.ReadInt(); } } public class XmlAttach { private static Type m_AttachableType = typeof(Attachable); public static bool IsAttachable(ConstructorInfo ctor) { return ctor.IsDefined(m_AttachableType, false); } public static void HashSerial(ASerial key, XmlAttachment o) { if (key.Value != 0) { AllAttachments[key.Value]=o;//.Add(key.Value, o); } else { UnassignedAttachments.Add(o); } } // each entry in the hashtable is an array of XmlAttachments that is keyed by an object. public static Dictionary> ItemAttachments = new Dictionary>(); public static Dictionary> MobileAttachments = new Dictionary>(); public static Dictionary AllAttachments = new Dictionary(); private static List UnassignedAttachments = new List(); public static bool HasAttachments(object o) { if (o == null) return false; List alist; if (o is Item && ItemAttachments.TryGetValue((Item)o, out alist))//.Contains(o)) { // see if the attachment list is empty if (alist == null || alist.Count == 0) return false; // check to see if there are any valid attachments in the list foreach (XmlAttachment a in alist) { if (!a.Deleted) return true; } return false; } if (o is Mobile && MobileAttachments.TryGetValue((Mobile)o, out alist))//.Contains(o)) { // see if the attachment list is empty if (alist == null || alist.Count == 0) return false; // check to see if there are any valid attachments in the list foreach (XmlAttachment a in alist) { if (!a.Deleted) return true; } return false; } return false; } public static XmlAttachment[] Values { get { XmlAttachment[] valuearray = new XmlAttachment[XmlAttach.AllAttachments.Count]; XmlAttach.AllAttachments.Values.CopyTo(valuearray, 0); return valuearray; } } public static void Configure() { EventSink.WorldLoad += new WorldLoadEventHandler(Load); EventSink.WorldSave += new WorldSaveEventHandler(Save); } public static void Initialize() { ASerial.serialInitialized = true; // resolve unassigned serials foreach (XmlAttachment a in UnassignedAttachments) { // get the next unique serial id ASerial serial = ASerial.NewSerial(); a.Serial = serial; // register the attachment in the serial keyed hashtable XmlAttach.HashSerial(serial, a); } // Register our speech handler EventSink.Speech += new SpeechEventHandler(EventSink_Speech); // Register our movement handler EventSink.Movement += new MovementEventHandler(EventSink_Movement); //CommandSystem.Register( "ItemAtt", AccessLevel.GameMaster, new CommandEventHandler( ListItemAttachments_OnCommand ) ); //CommandSystem.Register( "MobAtt", AccessLevel.GameMaster, new CommandEventHandler( ListMobileAttachments_OnCommand ) ); CommandSystem.Register("GetAtt", AccessLevel.GameMaster, new CommandEventHandler(GetAttachments_OnCommand)); //CommandSystem.Register( "DelAtt", AccessLevel.GameMaster, new CommandEventHandler( DeleteAttachments_OnCommand ) ); //CommandSystem.Register( "TrigAtt", AccessLevel.GameMaster, new CommandEventHandler( ActivateAttachments_OnCommand ) ); //CommandSystem.Register( "AddAtt", AccessLevel.GameMaster, new CommandEventHandler( AddAttachment_OnCommand ) ); TargetCommands.Register(new AddAttCommand()); TargetCommands.Register(new DelAttCommand()); CommandSystem.Register("AvailAtt", AccessLevel.GameMaster, new CommandEventHandler(ListAvailableAttachments_OnCommand)); } public class AddAttCommand : BaseCommand { public AddAttCommand() { AccessLevel = AccessLevel.GameMaster; Supports = CommandSupport.All; Commands = new string[] { "AddAtt" }; ObjectTypes = ObjectTypes.Both; Usage = "AddAtt type [args]"; Description = "Adds an attachment to the targeted object."; ListOptimized = true; } public override bool ValidateArgs(BaseCommandImplementor impl, CommandEventArgs e) { if (e.Arguments.Length >= 1) return true; e.Mobile.SendMessage("Usage: " + Usage); return false; } public override void ExecuteList(CommandEventArgs e, ArrayList list) { if (e != null && list != null && e.Length >= 1) { // create a new attachment and add it to the item int nargs = e.Arguments.Length - 1; string[] args = new string[nargs]; for (int j = 0; j < nargs; j++) { args[j] = (string)e.Arguments[j + 1]; } Type attachtype = SpawnerType.GetType(e.Arguments[0]); if (attachtype != null && attachtype.IsSubclassOf(typeof(XmlAttachment))) { // go through all of the objects in the list int count = 0; for (int i = 0; i < list.Count; ++i) { XmlAttachment o = (XmlAttachment)XmlSpawner.CreateObject(attachtype, args, false, true); if (o == null) { AddResponse(String.Format("Unable to construct {0} with specified args", attachtype.Name)); break; } if (XmlAttach.AttachTo(null, list[i], o, true)) { if (list.Count < 10) { AddResponse(String.Format("Added {0} to {1}", attachtype.Name, list[i])); } count++; } else LogFailure(String.Format("Attachment {0} not added to {1}", attachtype.Name, list[i])); } if (count > 0) { AddResponse(String.Format("Attachment {0} has been added [{1}]", attachtype.Name, count)); } else { AddResponse(String.Format("Attachment {0} not added", attachtype.Name)); } } else { AddResponse(String.Format("Invalid attachment type {0}", e.Arguments[0])); } } } } public class DelAttCommand : BaseCommand { public DelAttCommand() { AccessLevel = AccessLevel.GameMaster; Supports = CommandSupport.All; Commands = new string[] { "DelAtt" }; ObjectTypes = ObjectTypes.Both; Usage = "DelAtt type"; Description = "Deletes an attachment on the targeted object."; ListOptimized = true; } public override bool ValidateArgs(BaseCommandImplementor impl, CommandEventArgs e) { if (e.Arguments.Length >= 1) return true; e.Mobile.SendMessage("Usage: " + Usage); return false; } public override void ExecuteList(CommandEventArgs e, ArrayList list) { if (e != null && list != null && e.Length >= 1) { Type attachtype = SpawnerType.GetType(e.Arguments[0]); if (attachtype != null && attachtype.IsSubclassOf(typeof(XmlAttachment))) { // go through all of the objects in the list int count = 0; for (int i = 0; i < list.Count; ++i) { List alist = XmlAttach.FindAttachments(list[i], attachtype); if (alist != null) { // delete the attachments foreach (XmlAttachment a in alist) { a.Delete(); if (list.Count < 10) { AddResponse(String.Format("Deleted {0} from {1}", attachtype.Name, list[i])); } count++; } } } if (count > 0) { AddResponse(String.Format("Attachment {0} has been deleted [{1}]", attachtype.Name, count)); } else { AddResponse(String.Format("Attachment {0} not deleted", attachtype.Name)); } } else { AddResponse(String.Format("Invalid attachment type {0}", e.Arguments[0])); } } } } public static void CleanUp() { // clean up any unowned attachments foreach (XmlAttachment a in XmlAttach.Values) { if (a.OwnedBy == null || (a.OwnedBy is Mobile && ((Mobile)a.OwnedBy).Deleted) || (a.OwnedBy is Item && ((Item)a.OwnedBy).Deleted)) { a.Delete(); } } } public static void Save(WorldSaveEventArgs e) { if (XmlAttach.MobileAttachments == null && XmlAttach.ItemAttachments == null) return; CleanUp(); if (!Directory.Exists("Saves/Attachments")) Directory.CreateDirectory("Saves/Attachments"); string filePath = Path.Combine("Saves/Attachments", "Attachments.bin"); // the attachment serializations string imaPath = Path.Combine("Saves/Attachments", "Attachments.ima"); // the item/mob attachment tables string fpiPath = Path.Combine("Saves/Attachments", "Attachments.fpi"); // the file position indices BinaryFileWriter writer = null; BinaryFileWriter imawriter = null; BinaryFileWriter fpiwriter = null; try { writer = new BinaryFileWriter(filePath, true); imawriter = new BinaryFileWriter(imaPath, true); fpiwriter = new BinaryFileWriter(fpiPath, true); } catch (Exception err) { ErrorReporter.GenerateErrorReport(err.ToString()); return; } if (writer != null && imawriter != null && fpiwriter != null) { // save the current global attachment serial state ASerial.GlobalSerialize(writer); // remove all deleted attachments XmlAttach.FullDefrag(); // save the attachments themselves if (XmlAttach.AllAttachments != null) { writer.Write(XmlAttach.AllAttachments.Count); XmlAttachment[] valuearray = new XmlAttachment[XmlAttach.AllAttachments.Count]; XmlAttach.AllAttachments.Values.CopyTo(valuearray, 0); int[] keyarray = new int[XmlAttach.AllAttachments.Count]; XmlAttach.AllAttachments.Keys.CopyTo(keyarray, 0); for (int i = 0; i < keyarray.Length; i++) { // write the key writer.Write((int)keyarray[i]); XmlAttachment a = valuearray[i]; // write the value type writer.Write(a.GetType().ToString()); // serialize the attachment itself a.Serialize(writer); // save the fileposition index fpiwriter.Write(writer.Position); } } else { writer.Write((int)0); } writer.Close(); // save the hash table info for items and mobiles // mobile attachments if (XmlAttach.MobileAttachments != null) { imawriter.Write(XmlAttach.MobileAttachments.Count); List[] valuearray = new List[XmlAttach.MobileAttachments.Count]; XmlAttach.MobileAttachments.Values.CopyTo(valuearray, 0); Mobile[] keyarray = new Mobile[XmlAttach.MobileAttachments.Count]; XmlAttach.MobileAttachments.Keys.CopyTo(keyarray, 0); for (int i = 0; i < keyarray.Length; i++) { // write the key imawriter.Write(keyarray[i]); // write out the attachments List alist = valuearray[i]; imawriter.Write(alist.Count); foreach (XmlAttachment a in alist) { // write the attachment serial imawriter.Write(a.Serial.Value); // write the value type imawriter.Write(a.GetType().ToString()); // save the fileposition index fpiwriter.Write(imawriter.Position); } } } else { // no mobile attachments imawriter.Write((int)0); } // item attachments if (XmlAttach.ItemAttachments != null) { imawriter.Write(XmlAttach.ItemAttachments.Count); List[] valuearray = new List[XmlAttach.ItemAttachments.Count]; XmlAttach.ItemAttachments.Values.CopyTo(valuearray, 0); Item[] keyarray = new Item[XmlAttach.ItemAttachments.Count]; XmlAttach.ItemAttachments.Keys.CopyTo(keyarray, 0); for (int i = 0; i < keyarray.Length; i++) { // write the key imawriter.Write(keyarray[i]); // write out the attachments List alist = valuearray[i]; imawriter.Write(alist.Count); foreach (XmlAttachment a in alist) { // write the attachment serial imawriter.Write(a.Serial.Value); // write the value type imawriter.Write(a.GetType().ToString()); // save the fileposition index fpiwriter.Write(imawriter.Position); } } } else { // no item attachments imawriter.Write((int)0); } imawriter.Close(); fpiwriter.Close(); } } public static void Load() { string filePath = Path.Combine("Saves/Attachments", "Attachments.bin"); // the attachment serializations string imaPath = Path.Combine("Saves/Attachments", "Attachments.ima"); // the item/mob attachment tables string fpiPath = Path.Combine("Saves/Attachments", "Attachments.fpi"); // the file position indices if (!File.Exists(filePath)) { return; } FileStream fs = null; BinaryFileReader reader = null; FileStream imafs = null; BinaryFileReader imareader = null; FileStream fpifs = null; BinaryFileReader fpireader = null; try { fs = new FileStream(filePath, (FileMode)3, (FileAccess)1, (FileShare)1); reader = new BinaryFileReader(new BinaryReader(fs)); imafs = new FileStream(imaPath, (FileMode)3, (FileAccess)1, (FileShare)1); imareader = new BinaryFileReader(new BinaryReader(imafs)); fpifs = new FileStream(fpiPath, (FileMode)3, (FileAccess)1, (FileShare)1); fpireader = new BinaryFileReader(new BinaryReader(fpifs)); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } if (reader != null && imareader != null && fpireader != null) { // restore the current global attachment serial state try { ASerial.GlobalDeserialize(reader); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } ASerial.serialInitialized = true; // read in the serial attachment hash table information int count = 0; try { count = reader.ReadInt(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } for (int i = 0; i < count; i++) { // read the serial ASerial serialno = null; try { serialno = new ASerial(reader.ReadInt()); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } // read the attachment type string valuetype = null; try { valuetype = reader.ReadString(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } // read the position of the beginning of the next attachment deser within the .bin file long position = 0; try { position = fpireader.ReadLong(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } bool skip = false; XmlAttachment o = null; try { o = (XmlAttachment)Activator.CreateInstance(Type.GetType(valuetype), new object[] { serialno }); } catch { skip = true; } if (skip) { if (!AlreadyReported(valuetype)) { Console.WriteLine("\nError deserializing attachments {0}.\nMissing a serial constructor?\n", valuetype); ReportDeserError(valuetype, "Missing a serial constructor?"); } // position the .ima file at the next deser point try { reader.Seek(position, SeekOrigin.Begin); } catch { ErrorReporter.GenerateErrorReport("Error deserializing. Attachments save file corrupted. Attachment load aborted."); return; } continue; } try { o.Deserialize(reader); } catch { skip = true; } // confirm the read position if (reader.Position != position || skip) { if (!AlreadyReported(valuetype)) { Console.WriteLine("\nError deserializing attachments {0}\n", valuetype); ReportDeserError(valuetype, "save file corruption or incorrect Serialize/Deserialize methods?"); } // position the .ima file at the next deser point try { reader.Seek(position, SeekOrigin.Begin); } catch { ErrorReporter.GenerateErrorReport("Error deserializing. Attachments save file corrupted. Attachment load aborted."); return; } continue; } // add it to the hash table try { AllAttachments.Add(serialno.Value, o); } catch { ErrorReporter.GenerateErrorReport(String.Format("\nError deserializing {0} serialno {1}. Attachments save file corrupted. Attachment load aborted.\n", valuetype, serialno.Value)); return; } } // read in the mobile attachment hash table information try { count = imareader.ReadInt(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } for (int i = 0; i < count; i++) { Mobile key = null; try { key = imareader.ReadMobile(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } int nattach = 0; try { nattach = imareader.ReadInt(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } for (int j = 0; j < nattach; j++) { // and serial ASerial serialno = null; try { serialno = new ASerial(imareader.ReadInt()); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } // read the attachment type string valuetype = null; try { valuetype = imareader.ReadString(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } // read the position of the beginning of the next attachment deser within the .bin file long position = 0; try { position = fpireader.ReadLong(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } XmlAttachment o = FindAttachmentBySerial(serialno.Value); if (o == null || imareader.Position != position) { if (!AlreadyReported(valuetype)) { Console.WriteLine("\nError deserializing attachments of type {0}.\n", valuetype); ReportDeserError(valuetype, "save file corruption or incorrect Serialize/Deserialize methods?"); } // position the .ima file at the next deser point try { imareader.Seek(position, SeekOrigin.Begin); } catch { ErrorReporter.GenerateErrorReport("Error deserializing. Attachments save file corrupted. Attachment load aborted."); return; } continue; } // attachment successfully deserialized so attach it AttachTo(key, o, false); } } // read in the item attachment hash table information try { count = imareader.ReadInt(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } for (int i = 0; i < count; i++) { Item key = null; try { key = imareader.ReadItem(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } int nattach = 0; try { nattach = imareader.ReadInt(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } for (int j = 0; j < nattach; j++) { // and serial ASerial serialno = null; try { serialno = new ASerial(imareader.ReadInt()); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } // read the attachment type string valuetype = null; try { valuetype = imareader.ReadString(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } // read the position of the beginning of the next attachment deser within the .bin file long position = 0; try { position = fpireader.ReadLong(); } catch (Exception e) { ErrorReporter.GenerateErrorReport(e.ToString()); return; } XmlAttachment o = FindAttachmentBySerial(serialno.Value); if (o == null || imareader.Position != position) { if (!AlreadyReported(valuetype)) { Console.WriteLine("\nError deserializing attachments of type {0}.\n", valuetype); ReportDeserError(valuetype, "save file corruption or incorrect Serialize/Deserialize methods?"); } // position the .ima file at the next deser point try { imareader.Seek(position, SeekOrigin.Begin); } catch { ErrorReporter.GenerateErrorReport("Error deserializing. Attachments save file corrupted. Attachment load aborted."); return; } continue; } // attachment successfully deserialized so attach it AttachTo(key, o, false); } } if (fs != null) fs.Close(); if (imafs != null) imafs.Close(); if (fpifs != null) fpifs.Close(); if (desererror != null) { ErrorReporter.GenerateErrorReport("Error deserializing particular attachments."); } } } private class DeserErrorDetails { public string Type; public string Details; public DeserErrorDetails(string type, string details) { Type = type; Details = details; } } private static List desererror = null; private static void ReportDeserError(string typestr, string detailstr) { if (desererror == null) desererror = new List(); desererror.Add(new DeserErrorDetails(typestr, detailstr)); } private static bool AlreadyReported(string typestr) { if (desererror == null) return false; foreach (DeserErrorDetails s in desererror) { if (s.Type == typestr) return true; } return false; } public static void CheckOnBeforeKill(Mobile m_killed, Mobile m_killer) { // do not register creature vs creature kills, nor any kills involving staff // if (m_killer == null || m_killed == null || !(m_killer.Player || m_killed.Player) /*|| (m_killer.AccessLevel > AccessLevel.Player) || (m_killed.AccessLevel > AccessLevel.Player) */) // return; if (m_killer != null) { // check the killer List alist = XmlAttach.FindAttachments(m_killer); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.HandlesOnKill) { a.OnBeforeKill(m_killed, m_killer); } } } // check any equipped items List equiplist = m_killer.Items; if (equiplist != null) { foreach (Item i in equiplist) { if (i == null || i.Deleted) continue; alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.CanActivateEquipped && a.HandlesOnKill) { a.OnBeforeKill(m_killed, m_killer); } } } } } } if (m_killed != null) { // check the killed List alist = XmlAttach.FindAttachments(m_killed); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.HandlesOnKilled) { a.OnBeforeKilled(m_killed, m_killer); } } } } } public static void CheckOnKill(Mobile m_killed, Mobile m_killer) { // do not register creature vs creature kills, nor any kills involving staff // if (m_killer == null || m_killed == null || !(m_killer.Player || m_killed.Player) /*|| (m_killer.AccessLevel > AccessLevel.Player) || (m_killed.AccessLevel > AccessLevel.Player) */) // return; if (m_killer != null) { // check the killer List alist = XmlAttach.FindAttachments(m_killer); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.HandlesOnKill) { a.OnKill(m_killed, m_killer); } } } // check any equipped items List equiplist = m_killer.Items; if (equiplist != null) { foreach (Item i in equiplist) { if (i == null || i.Deleted) continue; alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.CanActivateEquipped && a.HandlesOnKill) { a.OnKill(m_killed, m_killer); } } } } } } if (m_killed != null) { // check the killed List alist = XmlAttach.FindAttachments(m_killed); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.HandlesOnKilled) { a.OnKilled(m_killed, m_killer); } } } } } public static void EventSink_Movement(MovementEventArgs args) { Mobile from = args.Mobile; if (!from.Player /* || from.AccessLevel > AccessLevel.Player */) return; // check for any items in the same sector if (from.Map != null) { IPooledEnumerable itemlist = from.Map.GetItemsInRange(from.Location, Map.SectorSize); if (itemlist != null) { foreach (Item i in itemlist) { if (i == null || i.Deleted) continue; List alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.HandlesOnMovement) { a.OnMovement(args); } } } } itemlist.Free(); } // check for mobiles IPooledEnumerable moblist = from.Map.GetMobilesInRange(from.Location, Map.SectorSize); if (moblist != null) { foreach (Mobile i in moblist) { // dont respond to self motion if (i == null || i.Deleted || i == from) continue; List alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.HandlesOnMovement) { a.OnMovement(args); } } } } moblist.Free(); } } } public static void EventSink_Speech(SpeechEventArgs args) { Mobile from = args.Mobile; if (from == null || from.Map == null /*|| from.AccessLevel > AccessLevel.Player */) return; // check the mob for any attachments that might handle speech List alist = XmlAttach.FindAttachments(from); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.HandlesOnSpeech) { a.OnSpeech(args); } } } // check for any nearby items IPooledEnumerable itemlist = from.Map.GetItemsInRange(from.Location, Map.SectorSize); if (itemlist != null) { foreach (Item i in itemlist) { if (i == null || i.Deleted) continue; alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.CanActivateInWorld && a.HandlesOnSpeech) { a.OnSpeech(args); } } } } itemlist.Free(); } // check for any nearby mobs IPooledEnumerable moblist = from.Map.GetMobilesInRange(from.Location, Map.SectorSize); if (moblist != null) { foreach (Mobile i in moblist) { if (i == null || i.Deleted) continue; alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.HandlesOnSpeech) { a.OnSpeech(args); } } } } moblist.Free(); } // also check for any items in the mobs toplevel backpack if (from.Backpack != null) { List packlist = from.Backpack.Items; if (packlist != null) { foreach (Item i in packlist) { if (i == null || i.Deleted) continue; alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.CanActivateInBackpack && a.HandlesOnSpeech) { a.OnSpeech(args); } } } } } } // check any equipped items List equiplist = from.Items; if (equiplist != null) { foreach (Item i in equiplist) { if (i == null || i.Deleted) continue; alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && a.CanActivateEquipped && a.HandlesOnSpeech) { a.OnSpeech(args); } } } } } } public static XmlAttachment FindAttachmentOnMobile(Mobile from, Type type, string name) { if (from == null) return null; // check the mob for any attachments List alist = XmlAttach.FindAttachments(from); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && (type == null || (a.GetType() == type || a.GetType().IsSubclassOf(type))) && (name == null || name == a.Name)) { return a; } } } // also check for any items in the mobs toplevel backpack if (from.Backpack != null) { List itemlist = from.Backpack.Items; if (itemlist != null) { foreach (Item i in itemlist) { if (i == null || i.Deleted) continue; alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && (type == null || (a.GetType() == type || a.GetType().IsSubclassOf(type))) && (name == null || name == a.Name)) { return a; } } } } } } // check any equipped items List equiplist = from.Items; if (equiplist != null) { foreach (Item i in equiplist) { if (i == null || i.Deleted) continue; alist = XmlAttach.FindAttachments(i); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted && (type == null || (a.GetType() == type || a.GetType().IsSubclassOf(type))) && (name == null || name == a.Name)) { return a; } } } } } return null; } private class AttachTarget : Target { private CommandEventArgs m_e; private string m_set = null; public AttachTarget(CommandEventArgs e, string set) : base(30, false, TargetFlags.None) { m_e = e; m_set = set; } protected override void OnTarget(Mobile from, object targeted) { if (from == null || targeted == null) return; Type type = null; string name = null; if (m_e.Arguments.Length > 0) { type = SpawnerType.GetType(m_e.Arguments[0]); } if (m_e.Arguments.Length > 1) { name = m_e.Arguments[1]; } XmlAttach.Defrag(targeted); List plist = XmlAttach.FindAttachments(targeted, type); if (plist == null && m_set != "add") { from.SendMessage("No attachments"); return; } switch (m_set) { case "add": if (m_e.Arguments.Length < 1) { from.SendMessage("Must specify an attachment type."); return; } // create a new attachment and add it to the item int nargs = m_e.Arguments.Length - 1; string[] args = new string[nargs]; for (int j = 0; j < nargs; j++) { args[j] = (string)m_e.Arguments[j + 1]; } XmlAttachment o = null; Type attachtype = SpawnerType.GetType(m_e.Arguments[0]); if (attachtype != null && attachtype.IsSubclassOf(typeof(XmlAttachment))) { o = (XmlAttachment)XmlSpawner.CreateObject(attachtype, args, false, true); } if (o != null) { //o.Name = aname; if (XmlAttach.AttachTo(from, targeted, o, true)) from.SendMessage("Added attachment {2} : {0} to {1}", m_e.Arguments[0], targeted, o.Serial.Value); else from.SendMessage("Attachment not added: {0}", m_e.Arguments[0]); } else { from.SendMessage("Unable to construct attachment {0}", m_e.Arguments[0]); } break; case "get": /* foreach(XmlAttachment p in plist) { if(p == null || p.Deleted || (name != null && name != p.Name) || (type != null && type != p.GetType())) continue; from.SendMessage("Found attachment {3} : {0} : {1} : {2}",p.GetType().Name,p.Name,p.OnIdentify(from), p.Serial.Value); } */ from.SendGump(new XmlGetAttGump(from, targeted, 0, 0)); break; case "delete": /* foreach(XmlAttachment p in plist) { if(p == null || p.Deleted || (name != null && name != p.Name) || (type != null && type != p.GetType())) continue; from.SendMessage("Deleting attachment {3} : {0} : {1} : {2}",p.GetType().Name,p.Name,p.OnIdentify(from), p.Serial.Value); p.Delete(); } */ from.SendGump(new XmlGetAttGump(from, targeted, 0, 0)); break; case "activate": foreach (XmlAttachment p in plist) { if (p == null || p.Deleted || (name != null && name != p.Name) || (type != null && type != p.GetType())) continue; from.SendMessage("Activating attachment {3} : {0} : {1} : {2}", p.GetType().Name, p.Name, p.OnIdentify(from), p.Serial.Value); p.OnTrigger(null, from); } break; } } } [Usage("GetAtt [type/serialno [name]]")] [Description("Returns descriptions of the attachments on the targeted object.")] public static void GetAttachments_OnCommand(CommandEventArgs e) { int ser = -1; if (e.Arguments.Length > 0) { // is this a numeric arg? char c = e.Arguments[0][0]; if (c >= '0' && c <= '9') { try { ser = int.Parse(e.Arguments[0]); } catch { } XmlAttachment a = FindAttachmentBySerial(ser); if (a != null) { // open up the props gump on the attachment e.Mobile.SendGump(new PropertiesGump(e.Mobile, a)); } else { e.Mobile.SendMessage("Attachment {0} does not exist", ser); } } } if (ser == -1) e.Mobile.Target = new AttachTarget(e, "get"); } [Usage("AddAtt type [args]")] [Description("Adds an attachment to the targeted object.")] public static void AddAttachment_OnCommand(CommandEventArgs e) { e.Mobile.Target = new AttachTarget(e, "add"); } [Usage("DelAtt [type/serialno [name]]")] [Description("Deletes attachments on the targeted object.")] public static void DeleteAttachments_OnCommand(CommandEventArgs e) { int ser = -1; if (e.Arguments.Length > 0) { // is this a numeric arg? char c = e.Arguments[0][0]; if (c >= '0' && c <= '9') { try { ser = int.Parse(e.Arguments[0]); } catch { } XmlAttachment a = FindAttachmentBySerial(ser); if (a != null) { e.Mobile.SendMessage("Deleting attachment {0} : {1}", ser, a); a.Delete(); } else { e.Mobile.SendMessage("Attachment {0} does not exist", ser); } } } if (ser == -1) e.Mobile.Target = new AttachTarget(e, "delete"); } [Usage("TrigAtt [type [name]]")] [Description("Triggers attachments on the targeted object.")] public static void ActivateAttachments_OnCommand(CommandEventArgs e) { e.Mobile.Target = new AttachTarget(e, "activate"); } [Usage("ItemAtt")] [Description("Lists all item attachments.")] public static void ListItemAttachments_OnCommand(CommandEventArgs e) { if (ItemAttachments == null) return; XmlAttach.FullDefrag(ItemAttachments); Item[] itemarray = new Item[ItemAttachments.Count]; ItemAttachments.Keys.CopyTo(itemarray, 0); e.Mobile.SendMessage("{0} items with attachments", ItemAttachments.Count); for (int i = 0; i < itemarray.Length; i++) { e.Mobile.SendMessage("Attachments for {0} :", itemarray[i]); List list = FindAttachments(itemarray[i]); if (list != null) { foreach (XmlAttachment a in list) { if (a != null && !a.Deleted) e.Mobile.SendMessage("\t{0} : {1} : {2}", a.GetType().Name, a.Name, a.OnIdentify(e.Mobile)); } } } } [Usage("MobAtt")] [Description("Lists all mobile attachments.")] public static void ListMobileAttachments_OnCommand(CommandEventArgs e) { if (MobileAttachments == null) return; XmlAttach.FullDefrag(MobileAttachments); Mobile[] mobilearray = new Mobile[MobileAttachments.Count]; MobileAttachments.Keys.CopyTo(mobilearray, 0); e.Mobile.SendMessage("{0} mobiles with attachments", MobileAttachments.Count); for (int i = 0; i < mobilearray.Length; i++) { e.Mobile.SendMessage("Attachments for {0} :", mobilearray[i]); List list = FindAttachments(mobilearray[i]); if (list != null) { foreach (XmlAttachment a in list) { if (a != null && !a.Deleted) e.Mobile.SendMessage("\t{0} : {1} : {2}", a.GetType().Name, a.Name, a.OnIdentify(e.Mobile)); } } } } private static void Match(Type matchtype, Type[] types, List results) { if (matchtype == null) return; for (int i = 0; i < types.Length; ++i) { Type t = types[i]; if (t.IsSubclassOf(matchtype)) { results.Add(t); } } } private static List Match(Type matchtype) { List results = new List(); Type[] types; Assembly[] asms = ScriptCompiler.Assemblies; for (int i = 0; i < asms.Length; ++i) { types = ScriptCompiler.GetTypeCache(asms[i]).Types; Match(matchtype, types, results); } types = ScriptCompiler.GetTypeCache(Core.Assembly).Types; Match(matchtype, types, results); results.Sort(new TypeNameComparer()); return results; } private class TypeNameComparer : IComparer { public int Compare(Type a, Type b) { return a.Name.CompareTo(b.Name); } } [Usage("AvailAtt")] [Description("Lists all available attachments.")] public static void ListAvailableAttachments_OnCommand(CommandEventArgs e) { List attachtypes = Match(typeof(XmlAttachment)); string parmliststr = null; foreach (Type attachtype in attachtypes) { // get all constructors derived from the XmlAttachment class ConstructorInfo[] ctors = attachtype.GetConstructors(); for (int i = 0; i < ctors.Length; ++i) { ConstructorInfo ctor = ctors[i]; if (!IsAttachable(ctor)) { continue; } ParameterInfo[] paramList = ctor.GetParameters(); if (paramList != null) { string parms = attachtype.Name; for (int j = 0; j < paramList.Length; j++) { parms += ", " + paramList[j].Name; } parmliststr += parms + "\n"; } } } e.Mobile.SendGump(new ListAttachmentsGump(parmliststr, 20, 20)); } private class ListAttachmentsGump : Gump { public ListAttachmentsGump(string attachmentlist, int X, int Y) : base(X, Y) { AddPage(0); AddBackground(20, 0, 330, 480, 5054); AddPage(1); AddImageTiled(20, 0, 330, 480, 0x52); AddLabel(27, 2, 0x384, "Available Attachments"); AddHtml(25, 22, 320, 458, attachmentlist, false, true); } } private class DisplayAttachmentGump : Gump { public DisplayAttachmentGump(Mobile from, string text, int X, int Y) : base(X, Y) { // prepare the page AddPage(0); AddBackground(0, 0, 400, 150, 5054); AddAlphaRegion(0, 0, 400, 150); AddLabel(20, 2, 55, "Attachment Description(s)"); AddHtml(20, 20, 360, 110, text, true, true); } } public static void RevealAttachments(Mobile from, object o) { if (from == null || o == null) return; List plist = XmlAttach.FindAttachments(o); if (plist == null) return; string msg = null; foreach (XmlAttachment p in plist) { if (p != null && !p.Deleted) { string pmsg = p.OnIdentify(from); if (pmsg != null) msg += String.Format("\n{0}\n", pmsg); } } if (msg != null) { from.CloseGump(typeof(DisplayAttachmentGump)); from.SendMessage("Hidden attributes revealed!"); from.SendGump(new DisplayAttachmentGump(from, msg, 0, 0)); } } public static bool AttachTo(object o, XmlAttachment attachment) { return AttachTo(null, o, attachment, true); } public static bool AttachTo(object from, object o, XmlAttachment attachment) { return AttachTo(from, o, attachment, true); } public static bool AttachTo(object o, XmlAttachment attachment, bool first) { return AttachTo(null, o, attachment, first); } private static bool AttachTo(object from, object o, XmlAttachment attachment, bool first) { if (attachment == null || o == null) return false; Item it=null; Mobile mob=null; List attachmententry; if (o is Item) { it=(Item)o; XmlAttach.Defrag(ItemAttachments, it); attachmententry = FindAttachments(it, true); } else if (o is Mobile) { mob=(Mobile)o; XmlAttach.Defrag(MobileAttachments, mob); attachmententry = FindAttachments(mob, true); } else return false; // see if there is already an attachment list for the object if (attachmententry != null) { // if an existing entry list was found then just add the attachment to that list after making sure there is not a duplicate foreach (XmlAttachment i in attachmententry) { // and attachment is considered a duplicate if both the type and name match if (i != null && !i.Deleted && i.GetType() == attachment.GetType() && i.Name == attachment.Name) { // duplicate found so replace it i.Delete(); } } attachmententry.Add(attachment); } else { // otherwise make a new entry list attachmententry = new List(); // containing the attachment attachmententry.Add(attachment); // and add it to the correct dictionary table if(mob!=null) MobileAttachments[mob]=attachmententry; else if(it!=null) ItemAttachments[it]=attachmententry; } attachment.AttachedTo = o; attachment.OwnedBy = o; if (from is Mobile) { attachment.SetAttachedBy(((Mobile)from).Name); } else if (from is Item) { attachment.SetAttachedBy(((Item)from).Name); } // if this is being attached for the first time, then call the OnAttach method // if it is being reattached due to deserialization then dont if (first) { attachment.OnAttach(); } else { attachment.OnReattach(); } return !attachment.Deleted; } public static List FindAttachments(object o) { return FindAttachments(o, null, null); } public static List FindAttachments(Item o) { return FindAttachments(ItemAttachments, o, null, null, false); } public static List FindAttachments(Mobile o) { return FindAttachments(MobileAttachments, o, null, null, false); } public static List FindAttachments(object o, Type type) { return FindAttachments(o, type, null); } public static List FindAttachments(Item o, Type type) { return FindAttachments(ItemAttachments, o, type, null); } public static List FindAttachments(Mobile o, Type type) { return FindAttachments(MobileAttachments, o, type, null); } public static List FindAttachments(object o, Type type, string name) { if (o is Item) { return FindAttachments(ItemAttachments, (Item)o, type, name, false); } else if (o is Mobile) { return FindAttachments(MobileAttachments, (Mobile)o, type, name, false); } return null; } public static List FindAttachments(Item o, Type type, string name) { return FindAttachments(ItemAttachments, (Item)o, type, name, false); } public static List FindAttachments(Mobile o, Type type, string name) { return FindAttachments(MobileAttachments, (Mobile)o, type, name, false); } public static List FindAttachments(Item o, bool original) { return FindAttachments(ItemAttachments, o, null, null, original); } public static List FindAttachments(Mobile o, bool original) { return FindAttachments(MobileAttachments, o, null, null, original); } public static List FindAttachments(Dictionary> attachments, Item o, Type type, string name) { return FindAttachments(attachments, o, type, name, false); } public static List FindAttachments(Dictionary> attachments, Mobile o, Type type, string name) { return FindAttachments(attachments, o, type, name, false); } public static List FindAttachments(Dictionary> attachments, Item o, Type type, string name, bool original) { if (o == null || attachments == null || o.Deleted) return null; List list; if(!attachments.TryGetValue(o, out list) || list==null) return null; if (type == null && name == null) { if(original) return list; else return list.GetRange(0, list.Count); } else { // just get those of a particular type and/or name List newlist = new List(); foreach (XmlAttachment i in list) { // see if it is deleted if (i == null || i.Deleted) continue; Type itype = i.GetType(); if ((type == null || (itype != null && (itype == type || itype.IsSubclassOf(type)))) && (name == null || (name == i.Name))) { newlist.Add(i); } } return newlist; } } public static List FindAttachments(Dictionary> attachments, Mobile o, Type type, string name, bool original) { if (o == null || attachments == null || o.Deleted) return null; List list; if(!attachments.TryGetValue(o, out list) || list==null) return null; if (type == null && name == null) { if(original) return list; else return list.GetRange(0, list.Count); } else { // just get those of a particular type and/or name List newlist = new List(); foreach (XmlAttachment i in list) { // see if it is deleted if (i == null || i.Deleted) continue; Type itype = i.GetType(); if ((type == null || (itype != null && (itype == type || itype.IsSubclassOf(type)))) && (name == null || (name == i.Name))) { newlist.Add(i); } } return newlist; } } public static XmlAttachment FindAttachment(object o) { return FindAttachment(o, null, null); } public static XmlAttachment FindAttachment(Item o) { return FindAttachment(o, null, null); } public static XmlAttachment FindAttachment(Mobile o) { return FindAttachment(o, null, null); } public static XmlAttachment FindAttachment(object o, Type type) { return FindAttachment(o, type, null); } public static XmlAttachment FindAttachment(Item o, Type type) { return FindAttachment(o, type, null); } public static XmlAttachment FindAttachment(Mobile o, Type type) { return FindAttachment(o, type, null); } public static XmlAttachment FindAttachment(object o, Type type, string name) { if (o is Item) { return FindAttachment(ItemAttachments, (Item)o, type, name); } else if (o is Mobile) { return FindAttachment(MobileAttachments, (Mobile)o, type, name); } return null; } public static XmlAttachment FindAttachment(Item o, Type type, string name) { return FindAttachment(ItemAttachments, o, type, name); } public static XmlAttachment FindAttachment(Mobile o, Type type, string name) { return FindAttachment(MobileAttachments, o, type, name); } public static XmlAttachment FindAttachment(Dictionary> attachments, Item o, Type type) { return FindAttachment(attachments, o, type, null); } public static XmlAttachment FindAttachment(Dictionary> attachments, Mobile o, Type type) { return FindAttachment(attachments, o, type, null); } public static XmlAttachment FindAttachment(Dictionary> attachments, Item o, Type type, string name) { List list; if(o == null || attachments == null || o.Deleted || !attachments.TryGetValue(o, out list) || list==null) return null; if (type == null && name == null) { // return the first valid attachment foreach (XmlAttachment i in list) { if (i != null && !i.Deleted) return i; } } else { // just get those of a particular type and/or name foreach (XmlAttachment i in list) { // see if it is deleted if (i == null || i.Deleted) continue; Type itype = i.GetType(); if ((type == null || (itype != null && (itype == type || itype.IsSubclassOf(type)))) && (name == null || (name == i.Name))) { return i; } } } return null; } public static XmlAttachment FindAttachment(Dictionary> attachments, Mobile o, Type type, string name) { List list; if(o == null || attachments == null || o.Deleted || !attachments.TryGetValue(o, out list) || list==null) return null; if (type == null && name == null) { // return the first valid attachment foreach (XmlAttachment i in list) { if (i != null && !i.Deleted) return i; } } else { // just get those of a particular type and/or name foreach (XmlAttachment i in list) { // see if it is deleted if (i == null || i.Deleted) continue; Type itype = i.GetType(); if ((type == null || (itype != null && (itype == type || itype.IsSubclassOf(type)))) && (name == null || (name == i.Name))) { return i; } } } return null; } public static XmlAttachment FindAttachmentBySerial(int serialno) { if (serialno <= 0) return null; XmlAttachment a; AllAttachments.TryGetValue(serialno, out a); return a; } private static void FullDefrag() { // defrag the mobile/item tables FullDefrag(ItemAttachments); FullDefrag(MobileAttachments); // defrag the serial table FullSerialDefrag(AllAttachments); } private static void FullDefrag(Dictionary> attachments) { Item[] keyarray = new Item[attachments.Count]; attachments.Keys.CopyTo(keyarray, 0); for(int i=keyarray.Length - 1; i>=0; --i) Defrag(attachments, keyarray[i]); } private static void FullDefrag(Dictionary> attachments) { Mobile[] keyarray = new Mobile[attachments.Count]; attachments.Keys.CopyTo(keyarray, 0); for(int i=keyarray.Length - 1; i>=0; --i) Defrag(attachments, keyarray[i]); } private static void FullSerialDefrag(Dictionary attachments) { // go through the item attachments int[] keyarray = new int[attachments.Count]; attachments.Keys.CopyTo(keyarray, 0); for (int i = 0; i < keyarray.Length; i++) { XmlAttachment a = attachments[keyarray[i]]; if (a == null || a.Deleted) { attachments.Remove(keyarray[i]); } } } private static void SerialDefrag(XmlAttachment a) { if (a != null && a.Deleted) AllAttachments.Remove(a.Serial.Value); } /// /// To be used if you are not sure of the object type passed to defrag, if you are sure you should specify the dictionary type and always pass the exact type /// /// the generic object passed, allowed are Mobile or Item public static void Defrag(object o) { //Hashtable attachments = null; if (o is Item) { Defrag(ItemAttachments, (Item)o); //attachments = ItemAttachments; } else if (o is Mobile) { Defrag(MobileAttachments, (Mobile)o); //attachments = MobileAttachments; } //Defrag(attachments, o); } private static void Defrag(Dictionary> attachments, Item o) { if (o == null || attachments == null) return; bool removeall = false; List list = null; if(ItemAttachments.TryGetValue(o, out list)) removeall = o.Deleted; if (list != null) { if (removeall) { attachments.Remove(o); } else { for(int i = list.Count - 1; i>=0; --i) { XmlAttachment x = list[i]; if (x == null || x.Deleted) list.Remove(x); } if(list.Count == 0) attachments.Remove(o); } } else attachments.Remove(o); } private static void Defrag(Dictionary> attachments, Mobile o) { if (o == null || attachments == null) return; bool removeall = false; List list = null; if(MobileAttachments.TryGetValue(o, out list)) removeall = o.Deleted; if (list != null) { if (removeall) { attachments.Remove(o); } else { for(int i = list.Count - 1; i>=0; --i) { XmlAttachment x = list[i]; if (x == null || x.Deleted) list.Remove(x); } if(list.Count == 0) attachments.Remove(o); } } else attachments.Remove(o); } public static bool CheckCanEquip(Item item, Mobile from) { // call the CanEquip method on any attachments on the item // look for attachments on the item List attachments = FindAttachments(item); if (attachments != null) { foreach (XmlAttachment a in attachments) { if (a != null && !a.Deleted) if (!a.CanEquip(from)) return false; } } return true; } public static void CheckOnEquip(Item item, Mobile from) { // look for attachments on the item List attachments = FindAttachments(item); if (attachments != null) { foreach (XmlAttachment a in attachments) { if (a != null && !a.Deleted) a.OnEquip(from); } } } public static void CheckOnRemoved(Item item, object parent) { // look for attachments on the item List attachments = FindAttachments(item); if (attachments != null) { foreach (XmlAttachment a in attachments) { if (a != null && !a.Deleted) a.OnRemoved(parent); } } } public static void OnWeaponHit(BaseWeapon weapon, Mobile attacker, Mobile defender, int damage) { // look for attachments on the weapon List attachments = FindAttachments(weapon); if (attachments != null) { foreach (XmlAttachment a in attachments) { if (a != null && !a.Deleted) a.OnWeaponHit(attacker, defender, weapon, damage); } } // also support OnWeaponHit for the mobile owner attachments = FindAttachments(attacker); if (attachments != null) { foreach (XmlAttachment a in attachments) { if (a != null && !a.Deleted) a.OnWeaponHit(attacker, defender, weapon, damage); } } } public static int OnArmorHit(Mobile attacker, Mobile defender, Item armor, BaseWeapon weapon, int damage) { int damageTaken = 0; // figure out who the attacker and defender are based upon who is carrying the armor/weapon // look for attachments on the armor if (armor != null) { List attachments = FindAttachments(armor); if (attachments != null) { foreach (XmlAttachment a in attachments) { if (a != null && !a.Deleted) damageTaken += a.OnArmorHit(attacker, defender, armor, weapon, damage); } } } return damageTaken; } public static void AddAttachmentProperties(object parent, ObjectPropertyList list) { if (parent == null) return; string propstr = null; List plist = XmlAttach.FindAttachments(parent); if (plist != null && plist.Count > 0) { bool more=plist.Count>1; for (int i = 0; i < plist.Count; i++) { XmlAttachment a = plist[i]; if (a != null && !a.Deleted) { // give the attachment an opportunity to modify the properties list of the parent a.AddProperties(list); // get any displayed properties on the attachment string str = a.DisplayedProperties(null); if (str != null) { if(more && i>0) propstr +="\n"; propstr += str; //the method below don't work well in some cases //if (i < plist.Count - 1) propstr += "\n"; } } } } if (propstr != null && list != null) list.Add(1062613, propstr); } public static void UseReq(NetState state, PacketReader pvSrc) { Mobile from = state.Mobile; #if(ServUO || NEWTIMERS) if (from.AccessLevel >= AccessLevel.GameMaster || Core.TickCount >= from.NextActionTime) #else if (from.AccessLevel >= AccessLevel.GameMaster || DateTime.UtcNow >= from.NextActionTime) #endif { int value = pvSrc.ReadInt32(); if ((value & ~0x7FFFFFFF) != 0) { from.OnPaperdollRequest(); } else { Serial s = value; bool blockdefaultonuse = false; if (s.IsMobile) { Mobile m = World.FindMobile(s); if (m != null && !m.Deleted) { // get attachments on the mobile doing the using List fromlist = FindAttachments(from); if (fromlist != null) { foreach (XmlAttachment a in fromlist) { if (a != null && !a.Deleted) { if (a.BlockDefaultOnUse(from, m)) blockdefaultonuse = true; a.OnUser(m); } } } // get attachments on the mob List alist = FindAttachments(m); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted) { if (a.BlockDefaultOnUse(from, m)) blockdefaultonuse = true; a.OnUse(from); } } } if (!blockdefaultonuse) from.Use(m); } } else if (s.IsItem) { Item item = World.FindItem(s); if (item != null && !item.Deleted) { // get attachments on the mobile doing the using List fromlist = FindAttachments(from); if (fromlist != null) { foreach (XmlAttachment a in fromlist) { if (a != null && !a.Deleted) { if (a.BlockDefaultOnUse(from, item)) blockdefaultonuse = true; a.OnUser(item); } } } // get attachments on the mob List alist = FindAttachments(item); if (alist != null) { foreach (XmlAttachment a in alist) { if (a != null && !a.Deleted) { if (a.BlockDefaultOnUse(from, item)) blockdefaultonuse = true; a.OnUse(from); } } } // need to check the item again in case it was modified in the OnUse or OnUser method if (!blockdefaultonuse) from.Use(item); } } } } else { from.SendActionMessage(); } } public static bool OnDragLift(Mobile from, Item item) { // look for attachments on the item if (item != null) { List attachments = FindAttachments(item); if (attachments != null) { foreach (XmlAttachment a in attachments) { if (a != null && !a.Deleted && !a.OnDragLift(from, item)) return false; } } } // allow lifts by default return true; } public class ErrorReporter { private static void SendEmail(string filePath) { Console.Write("XmlSpawner2 Attachment error: Sending email..."); MailMessage message = null; try { message = new MailMessage("RunUO@localhost", Email.CrashAddresses); } catch { } if (message == null) { Console.Write("Unable to send email. Possible invalid email address."); return; } message.Subject = "Automated XmlSpawner2 Attachment Error Report"; message.Body = "Automated XmlSpawner2 Attachment Report. See attachment for details."; message.Attachments.Add(new Attachment(filePath)); if (Email.Send(message)) Console.WriteLine("done"); else Console.WriteLine("failed"); } private static string GetRoot() { try { return Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]); } catch { return ""; } } private static string Combine(string path1, string path2) { if (path1 == "") return path2; return Path.Combine(path1, path2); } private static void CreateDirectory(string path) { if (!Directory.Exists(path)) Directory.CreateDirectory(path); } private static void CreateDirectory(string path1, string path2) { CreateDirectory(Combine(path1, path2)); } private static void CopyFile(string rootOrigin, string rootBackup, string path) { string originPath = Combine(rootOrigin, path); string backupPath = Combine(rootBackup, path); try { if (File.Exists(originPath)) File.Copy(originPath, backupPath); } catch { } } public static void GenerateErrorReport(string error) { Console.Write("\nXmlSpawner2 Attachment Error:\n{0}\nGenerating report...", error); try { string timeStamp = GetTimeStamp(); string fileName = String.Format("Attachment Error {0}.log", timeStamp); string root = GetRoot(); string filePath = Combine(root, fileName); using (StreamWriter op = new StreamWriter(filePath)) { Version ver = Core.Assembly.GetName().Version; op.WriteLine("XmlSpawner2 Attachment Error Report"); op.WriteLine("==================="); op.WriteLine(); op.WriteLine("RunUO Version {0}.{1}.{3}, Build {2}", ver.Major, ver.Minor, ver.Revision, ver.Build); op.WriteLine("Operating System: {0}", Environment.OSVersion); op.WriteLine(".NET Framework: {0}", Environment.Version); op.WriteLine("XmlSpawner2: {0}", XmlSpawner.Version); op.WriteLine("Time: {0}", DateTime.UtcNow); op.WriteLine(); op.WriteLine("Error:"); op.WriteLine(error); op.WriteLine(); op.WriteLine("Specific Attachment Errors:"); foreach (DeserErrorDetails s in XmlAttach.desererror) { op.WriteLine("{0} - {1}", s.Type, s.Details); } } Console.WriteLine("done"); if (Email.CrashAddresses != null) SendEmail(filePath); } catch { Console.WriteLine("failed"); } } private static string GetTimeStamp() { DateTime now = DateTime.UtcNow; return String.Format("{0}-{1}-{2}-{3}-{4}-{5}", now.Day, now.Month, now.Year, now.Hour, now.Minute, now.Second ); } } } }