#region References using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Threading.Tasks; using CustomsFramework; using Server.ContextMenus; using Server.Items; using Server.Network; using Server.Targeting; #endregion namespace Server { /// /// Enumeration of item layer values. /// public enum Layer : byte { /// /// Invalid layer. /// Invalid = 0x00, /// /// First valid layer. Equivalent to Layer.OneHanded. /// FirstValid = 0x01, /// /// One handed weapon. /// OneHanded = 0x01, /// /// Two handed weapon or shield. /// TwoHanded = 0x02, /// /// Shoes. /// Shoes = 0x03, /// /// Pants. /// Pants = 0x04, /// /// Shirts. /// Shirt = 0x05, /// /// Helmets, hats, and masks. /// Helm = 0x06, /// /// Gloves. /// Gloves = 0x07, /// /// Rings. /// Ring = 0x08, /// /// Talismans. /// Talisman = 0x09, /// /// Gorgets and necklaces. /// Neck = 0x0A, /// /// Hair. /// Hair = 0x0B, /// /// Half aprons. /// Waist = 0x0C, /// /// Torso, inner layer. /// InnerTorso = 0x0D, /// /// Bracelets. /// Bracelet = 0x0E, /// /// Face. /// Face = 0x0F, /// /// Beards and mustaches. /// FacialHair = 0x10, /// /// Torso, outer layer. /// MiddleTorso = 0x11, /// /// Earings. /// Earrings = 0x12, /// /// Arms and sleeves. /// Arms = 0x13, /// /// Cloaks. /// Cloak = 0x14, /// /// Backpacks. /// Backpack = 0x15, /// /// Torso, outer layer. /// OuterTorso = 0x16, /// /// Leggings, outer layer. /// OuterLegs = 0x17, /// /// Leggings, inner layer. /// InnerLegs = 0x18, /// /// Last valid non-internal layer. Equivalent to Layer.InnerLegs. /// LastUserValid = 0x18, /// /// Mount item layer. /// Mount = 0x19, /// /// Vendor 'buy pack' layer. /// ShopBuy = 0x1A, /// /// Vendor 'resale pack' layer. /// ShopResale = 0x1B, /// /// Vendor 'sell pack' layer. /// ShopSell = 0x1C, /// /// Bank box layer. /// Bank = 0x1D, /// /// Unused, using this layer makes you invisible to other players. Strange. /// /// Reserved_1 = 0x1E, /// /// Secure Trade Layer /// SecureTrade = 0x1F, } /// /// Internal flags used to signal how the item should be updated and resent to nearby clients. /// [Flags] public enum ItemDelta { /// /// Nothing. /// None = 0x00000000, /// /// Resend the item. /// Update = 0x00000001, /// /// Resend the item only if it is equiped. /// EquipOnly = 0x00000002, /// /// Resend the item's properties. /// Properties = 0x00000004 } /// /// Enumeration containing possible ways to handle item ownership on death. /// public enum DeathMoveResult { /// /// The item should be placed onto the corpse. /// MoveToCorpse, /// /// The item should remain equiped. /// RemainEquiped, /// /// The item should be placed into the owners backpack. /// MoveToBackpack } /// /// Enumeration containing all possible light types. These are only applicable to light source items, like lanterns, candles, braziers, etc. /// public enum LightType { /// /// Window shape, arched, ray shining east. /// ArchedWindowEast = 0, /// /// Medium circular shape. /// Circle225 = 1, /// /// Small circular shape. /// Circle150 = 2, /// /// Door shape, shining south. /// DoorSouth = 3, /// /// Door shape, shining east. /// DoorEast = 4, /// /// Large semicircular shape (180 degrees), north wall. /// NorthBig = 5, /// /// Large pie shape (90 degrees), north-east corner. /// NorthEastBig = 6, /// /// Large semicircular shape (180 degrees), east wall. /// EastBig = 7, /// /// Large semicircular shape (180 degrees), west wall. /// WestBig = 8, /// /// Large pie shape (90 degrees), south-west corner. /// SouthWestBig = 9, /// /// Large semicircular shape (180 degrees), south wall. /// SouthBig = 10, /// /// Medium semicircular shape (180 degrees), north wall. /// NorthSmall = 11, /// /// Medium pie shape (90 degrees), north-east corner. /// NorthEastSmall = 12, /// /// Medium semicircular shape (180 degrees), east wall. /// EastSmall = 13, /// /// Medium semicircular shape (180 degrees), west wall. /// WestSmall = 14, /// /// Medium semicircular shape (180 degrees), south wall. /// SouthSmall = 15, /// /// Shaped like a wall decoration, north wall. /// DecorationNorth = 16, /// /// Shaped like a wall decoration, north-east corner. /// DecorationNorthEast = 17, /// /// Small semicircular shape (180 degrees), east wall. /// EastTiny = 18, /// /// Shaped like a wall decoration, west wall. /// DecorationWest = 19, /// /// Shaped like a wall decoration, south-west corner. /// DecorationSouthWest = 20, /// /// Small semicircular shape (180 degrees), south wall. /// SouthTiny = 21, /// /// Window shape, rectangular, no ray, shining south. /// RectWindowSouthNoRay = 22, /// /// Window shape, rectangular, no ray, shining east. /// RectWindowEastNoRay = 23, /// /// Window shape, rectangular, ray shining south. /// RectWindowSouth = 24, /// /// Window shape, rectangular, ray shining east. /// RectWindowEast = 25, /// /// Window shape, arched, no ray, shining south. /// ArchedWindowSouthNoRay = 26, /// /// Window shape, arched, no ray, shining east. /// ArchedWindowEastNoRay = 27, /// /// Window shape, arched, ray shining south. /// ArchedWindowSouth = 28, /// /// Large circular shape. /// Circle300 = 29, /// /// Large pie shape (90 degrees), north-west corner. /// NorthWestBig = 30, /// /// Negative light. Medium pie shape (90 degrees), south-east corner. /// DarkSouthEast = 31, /// /// Negative light. Medium semicircular shape (180 degrees), south wall. /// DarkSouth = 32, /// /// Negative light. Medium pie shape (90 degrees), north-west corner. /// DarkNorthWest = 33, /// /// Negative light. Medium pie shape (90 degrees), south-east corner. Equivalent to LightType.SouthEast. /// DarkSouthEast2 = 34, /// /// Negative light. Medium circular shape (180 degrees), east wall. /// DarkEast = 35, /// /// Negative light. Large circular shape. /// DarkCircle300 = 36, /// /// Opened door shape, shining south. /// DoorOpenSouth = 37, /// /// Opened door shape, shining east. /// DoorOpenEast = 38, /// /// Window shape, square, ray shining east. /// SquareWindowEast = 39, /// /// Window shape, square, no ray, shining east. /// SquareWindowEastNoRay = 40, /// /// Window shape, square, ray shining south. /// SquareWindowSouth = 41, /// /// Window shape, square, no ray, shining south. /// SquareWindowSouthNoRay = 42, /// /// Empty. /// Empty = 43, /// /// Window shape, skinny, no ray, shining south. /// SkinnyWindowSouthNoRay = 44, /// /// Window shape, skinny, ray shining east. /// SkinnyWindowEast = 45, /// /// Window shape, skinny, no ray, shining east. /// SkinnyWindowEastNoRay = 46, /// /// Shaped like a hole, shining south. /// HoleSouth = 47, /// /// Shaped like a hole, shining south. /// HoleEast = 48, /// /// Large circular shape with a moongate graphic embeded. /// Moongate = 49, /// /// Unknown usage. Many rows of slightly angled lines. /// Strips = 50, /// /// Shaped like a small hole, shining south. /// SmallHoleSouth = 51, /// /// Shaped like a small hole, shining east. /// SmallHoleEast = 52, /// /// Large semicircular shape (180 degrees), north wall. Identical graphic as LightType.NorthBig, but slightly different positioning. /// NorthBig2 = 53, /// /// Large semicircular shape (180 degrees), west wall. Identical graphic as LightType.WestBig, but slightly different positioning. /// WestBig2 = 54, /// /// Large pie shape (90 degrees), north-west corner. Equivalent to LightType.NorthWestBig. /// NorthWestBig2 = 55 } /// /// Enumeration of an item's loot and steal state. /// public enum LootType : byte { /// /// Stealable. Lootable. /// Regular = 0, /// /// Unstealable. Unlootable, unless owned by a murderer. /// Newbied = 1, /// /// Unstealable. Unlootable, always. /// Blessed = 2, /// /// Stealable. Lootable, always. /// Cursed = 3 } public class BounceInfo { public Map m_Map; public Point3D m_Location, m_WorldLoc; public object m_Parent; public object m_ParentStack; public byte m_GridLocation; public Mobile m_Mobile; public BounceInfo(Mobile from, Item item) { m_Map = item.Map; m_Location = item.Location; m_WorldLoc = item.GetWorldLocation(); m_Parent = item.Parent; m_ParentStack = null; m_GridLocation = item.GridLocation; m_Mobile = from; } private BounceInfo(Map map, Point3D loc, Point3D worldLoc, IEntity parent) { m_Map = map; m_Location = loc; m_WorldLoc = worldLoc; m_Parent = parent; m_ParentStack = null; } public static BounceInfo Deserialize(GenericReader reader) { if (reader.ReadBool()) { Map map = reader.ReadMap(); Point3D loc = reader.ReadPoint3D(); Point3D worldLoc = reader.ReadPoint3D(); IEntity parent; Serial serial = reader.ReadInt(); if (serial.IsItem) { parent = World.FindItem(serial); } else if (serial.IsMobile) { parent = World.FindMobile(serial); } else { parent = null; } return new BounceInfo(map, loc, worldLoc, parent); } else { return null; } } public static void Serialize(BounceInfo info, GenericWriter writer) { if (info == null) { writer.Write(false); } else { writer.Write(true); writer.Write(info.m_Map); writer.Write(info.m_Location); writer.Write(info.m_WorldLoc); if (info.m_Parent is Mobile) { writer.Write((Mobile)info.m_Parent); } else if (info.m_Parent is Item) { writer.Write((Item)info.m_Parent); } else { writer.Write((Serial)0); } } } } public enum TotalType { Gold, Items, Weight, } [Flags] public enum ExpandFlag { None = 0x000, Name = 0x001, Items = 0x002, Bounce = 0x004, Holder = 0x008, Blessed = 0x010, TempFlag = 0x020, SaveFlag = 0x040, Weight = 0x080, Spawner = 0x100 } public class Item : IEntity, IHued, IComparable, ISerializable, ISpawnable { #region Customs Framework private List m_Modules = new List(); [CommandProperty(AccessLevel.Developer)] public List Modules { get { return m_Modules; } set { m_Modules = value; } } public BaseModule GetModule(string name) { return Modules.FirstOrDefault(mod => mod.Name == name); } public BaseModule GetModule(Type type) { return Modules.FirstOrDefault(mod => mod.GetType() == type); } public List GetModules(string name) { return Modules.Where(mod => mod.Name == name).ToList(); } public List SearchModules(string search) { var keywords = search.ToLower().Split(' '); var modules = new List(); foreach (BaseModule mod in Modules) { bool match = true; string name = mod.Name.ToLower(); foreach (string keyword in keywords) { if (name.IndexOf(keyword, StringComparison.Ordinal) == -1) { match = false; } } if (match) { modules.Add(mod); } } return modules; } #endregion public static readonly List EmptyItems = new List(); public int CompareTo(IEntity other) { if (other == null) { return -1; } return m_Serial.CompareTo(other.Serial); } public int CompareTo(Item other) { return CompareTo((IEntity)other); } public int CompareTo(object other) { if (other == null || other is IEntity) { return CompareTo((IEntity)other); } throw new ArgumentException(); } #region Standard fields private Serial m_Serial; private Point3D m_Location; private int m_ItemID; private int m_Hue; private int m_Amount; private Layer m_Layer; private object m_Parent; // Mobile, Item, or null=World private Map m_Map; private LootType m_LootType; private DateTime m_LastMovedTime; private Direction m_Direction; private LightType m_Light; #endregion private ItemDelta m_DeltaFlags; private ImplFlag m_Flags; #region Packet caches private Packet m_WorldPacket; private Packet m_WorldPacketSA; private Packet m_WorldPacketHS; private Packet m_RemovePacket; private Packet m_OPLPacket; private ObjectPropertyList m_PropertyList; #endregion public int TempFlags { get { CompactInfo info = LookupCompactInfo(); if (info != null) { return info.m_TempFlags; } return 0; } set { CompactInfo info = AcquireCompactInfo(); info.m_TempFlags = value; if (info.m_TempFlags == 0) { VerifyCompactInfo(); } } } public int SavedFlags { get { CompactInfo info = LookupCompactInfo(); if (info != null) { return info.m_SavedFlags; } return 0; } set { CompactInfo info = AcquireCompactInfo(); info.m_SavedFlags = value; if (info.m_SavedFlags == 0) { VerifyCompactInfo(); } } } /// /// The who is currently holding this item. /// public Mobile HeldBy { get { CompactInfo info = LookupCompactInfo(); if (info != null) { return info.m_HeldBy; } return null; } set { CompactInfo info = AcquireCompactInfo(); info.m_HeldBy = value; if (info.m_HeldBy == null) { VerifyCompactInfo(); } } } private byte m_GridLocation = 0; [CommandProperty(AccessLevel.GameMaster)] public byte GridLocation { get { return m_GridLocation; } set { if (Parent is Container) { if (value < 0 || value > 0x7C || !((Container)Parent).IsFreePosition(value)) { m_GridLocation = ((Container)Parent).GetNewPosition(0); } else { m_GridLocation = value; } } else { m_GridLocation = value; } } } [Flags] private enum ImplFlag : byte { None = 0x00, Visible = 0x01, Movable = 0x02, Deleted = 0x04, Stackable = 0x08, InQueue = 0x10, Insured = 0x20, PayedInsurance = 0x40, QuestItem = 0x80 } private class CompactInfo { public string m_Name; public List m_Items; public BounceInfo m_Bounce; public Mobile m_HeldBy; public Mobile m_BlessedFor; public ISpawner m_Spawner; public int m_TempFlags; public int m_SavedFlags; public double m_Weight = -1; } private CompactInfo m_CompactInfo; public ExpandFlag GetExpandFlags() { CompactInfo info = LookupCompactInfo(); ExpandFlag flags = 0; if (info != null) { if (info.m_BlessedFor != null) { flags |= ExpandFlag.Blessed; } if (info.m_Bounce != null) { flags |= ExpandFlag.Bounce; } if (info.m_HeldBy != null) { flags |= ExpandFlag.Holder; } if (info.m_Items != null) { flags |= ExpandFlag.Items; } if (info.m_Name != null) { flags |= ExpandFlag.Name; } if (info.m_Spawner != null) { flags |= ExpandFlag.Spawner; } if (info.m_SavedFlags != 0) { flags |= ExpandFlag.SaveFlag; } if (info.m_TempFlags != 0) { flags |= ExpandFlag.TempFlag; } if (info.m_Weight != -1) { flags |= ExpandFlag.Weight; } } return flags; } private CompactInfo LookupCompactInfo() { return m_CompactInfo; } private CompactInfo AcquireCompactInfo() { if (m_CompactInfo == null) { m_CompactInfo = new CompactInfo(); } return m_CompactInfo; } private void ReleaseCompactInfo() { m_CompactInfo = null; } private void VerifyCompactInfo() { CompactInfo info = m_CompactInfo; if (info == null) { return; } bool isValid = (info.m_Name != null) || (info.m_Items != null) || (info.m_Bounce != null) || (info.m_HeldBy != null) || (info.m_BlessedFor != null) || (info.m_Spawner != null) || (info.m_TempFlags != 0) || (info.m_SavedFlags != 0) || (info.m_Weight != -1); if (!isValid) { ReleaseCompactInfo(); } } public List LookupItems() { if (this is Container) { return ((Container)this).m_Items; } CompactInfo info = LookupCompactInfo(); if (info != null) { return info.m_Items; } return null; } public List AcquireItems() { if (this is Container) { Container cont = (Container)this; if (cont.m_Items == null) { cont.m_Items = new List(); } return cont.m_Items; } CompactInfo info = AcquireCompactInfo(); if (info.m_Items == null) { info.m_Items = new List(); } return info.m_Items; } #region Mondain's Legacy public static Bitmap GetBitmap(int itemID) { try { return Ultima.Art.GetStatic(itemID); } catch { if (Core.Debug) { Utility.PushColor(ConsoleColor.Red); Console.WriteLine("Ultima Art: Unable to read client files."); Utility.PopColor(); } } return null; } public static void Measure(Bitmap bmp, out int xMin, out int yMin, out int xMax, out int yMax) { Ultima.Art.Measure(bmp, out xMin, out yMin, out xMax, out yMax); } public static Rectangle MeasureBound(Bitmap bmp) { int xMin, yMin, xMax, yMax; Measure(bmp, out xMin, out yMin, out xMax, out yMax); return new Rectangle(xMin, yMin, xMax - xMin, yMax - yMin); } public static Size MeasureSize(Bitmap bmp) { int xMin, yMin, xMax, yMax; Measure(bmp, out xMin, out yMin, out xMax, out yMax); return new Size(xMax - xMin, yMax - yMin); } #endregion private void SetFlag(ImplFlag flag, bool value) { if (value) { m_Flags |= flag; } else { m_Flags &= ~flag; } } private bool GetFlag(ImplFlag flag) { return ((m_Flags & flag) != 0); } public BounceInfo GetBounce() { CompactInfo info = LookupCompactInfo(); if (info != null) { return info.m_Bounce; } return null; } public void RecordBounce(Mobile from, Item parentstack = null) { CompactInfo info = AcquireCompactInfo(); info.m_Bounce = new BounceInfo(from, this); info.m_Bounce.m_ParentStack = parentstack; } public void ClearBounce() { CompactInfo info = LookupCompactInfo(); if (info != null) { BounceInfo bounce = info.m_Bounce; if (bounce != null) { info.m_Bounce = null; if (bounce.m_Parent is Item) { Item parent = (Item)bounce.m_Parent; if (!parent.Deleted) { parent.OnItemBounceCleared(this); } } else if (bounce.m_Parent is Mobile) { Mobile parent = (Mobile)bounce.m_Parent; if (!parent.Deleted) { parent.OnItemBounceCleared(this); } } VerifyCompactInfo(); } } } /// /// Overridable. Virtual event invoked when a client, , invokes a 'help request' for the Item. Seemingly no longer functional in newer clients. /// public virtual void OnHelpRequest(Mobile from) { } /// /// Overridable. Method checked to see if the item can be traded. /// /// True if the trade is allowed, false if not. public virtual bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) { return true; } /// /// Overridable. Virtual event invoked when a trade has completed, either successfully or not. /// public virtual void OnSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) { } /// /// Overridable. Method checked to see if the elemental resistances of this Item conflict with another Item on the /// /// . /// /// /// /// /// True /// /// There is a confliction. The elemental resistance bonuses of this Item should not be applied to the /// /// /// /// /// False /// There is no confliction. The bonuses should be applied. /// /// /// public virtual bool CheckPropertyConfliction(Mobile m) { return false; } /// /// Overridable. Sends the object property list to . /// public virtual void SendPropertiesTo(Mobile from) { from.Send(PropertyList); } /// /// Overridable. Adds the name of this item to the given . This method should be /// overriden if the item requires a complex naming format. /// public virtual void AddNameProperty(ObjectPropertyList list) { string name = Name ?? String.Empty; if (String.IsNullOrWhiteSpace(name)) { if (m_Amount <= 1) { list.Add(LabelNumber); } else { list.Add(1050039, "{0}\t#{1}", m_Amount, LabelNumber); // ~1_NUMBER~ ~2_ITEMNAME~ } } else { if (m_Amount <= 1) { list.Add(name); } else { list.Add(1050039, "{0}\t{1}", m_Amount, Name); // ~1_NUMBER~ ~2_ITEMNAME~ } } } /// /// Overridable. Adds the loot type of this item to the given . By default, this will be either 'blessed', 'cursed', or 'insured'. /// public virtual void AddLootTypeProperty(ObjectPropertyList list) { if (DisplayLootType) { if (m_LootType == LootType.Blessed) { list.Add(1038021); // blessed } else if (m_LootType == LootType.Cursed) { list.Add(1049643); // cursed } else if (Insured) { list.Add(1061682); // insured } } } /// /// Overridable. Adds any elemental resistances of this item to the given . /// public virtual void AddResistanceProperties(ObjectPropertyList list) { int v = PhysicalResistance; if (v != 0) { list.Add(1060448, v.ToString()); // physical resist ~1_val~% } v = FireResistance; if (v != 0) { list.Add(1060447, v.ToString()); // fire resist ~1_val~% } v = ColdResistance; if (v != 0) { list.Add(1060445, v.ToString()); // cold resist ~1_val~% } v = PoisonResistance; if (v != 0) { list.Add(1060449, v.ToString()); // poison resist ~1_val~% } v = EnergyResistance; if (v != 0) { list.Add(1060446, v.ToString()); // energy resist ~1_val~% } } /// /// Overridable. Determines whether the item will show . /// public virtual bool DisplayWeight { get { if (!Core.ML) { return false; } if (!Movable && !(IsLockedDown || IsSecure) && ItemData.Weight == 255) { return false; } return true; } } /// /// Overridable. Adds header properties. By default, this invokes , /// /// (if applicable), and (if /// /// ). /// public virtual void AddNameProperties(ObjectPropertyList list) { AddNameProperty(list); if (IsSecure) { AddSecureProperty(list); } else if (IsLockedDown) { AddLockedDownProperty(list); } AddCraftedProperties(list); AddLootTypeProperty(list); AddUsesRemainingProperties(list); AddWeightProperty(list); AppendChildNameProperties(list); if (QuestItem) { AddQuestItemProperty(list); } } /// /// Overrideable, used to add crafted by, excpetional, etc properties to items /// /// public virtual void AddCraftedProperties(ObjectPropertyList list) { } /// /// Overrideable, used for IUsesRemaining UsesRemaining property /// /// public virtual void AddUsesRemainingProperties(ObjectPropertyList list) { } /// /// Overridable. Displays cliloc 1072788-1072789. /// public virtual void AddWeightProperty(ObjectPropertyList list) { if (DisplayWeight && Weight > 0) { int weight = PileWeight + TotalWeight; if (weight == 1) { list.Add(1072788, weight.ToString()); //Weight: ~1_WEIGHT~ stone } else { list.Add(1072789, weight.ToString()); //Weight: ~1_WEIGHT~ stones } } } /// /// Overridable. Adds the "Quest Item" property to the given . /// public virtual void AddQuestItemProperty(ObjectPropertyList list) { list.Add(1072351); // Quest Item } /// /// Overridable. Adds the "Locked Down & Secure" property to the given . /// public virtual void AddSecureProperty(ObjectPropertyList list) { list.Add(501644); // locked down & secure } /// /// Overridable. Adds the "Locked Down" property to the given . /// public virtual void AddLockedDownProperty(ObjectPropertyList list) { list.Add(501643); // locked down } /// /// Overridable. Adds the "Blessed for ~1_NAME~" property to the given . /// public virtual void AddBlessedForProperty(ObjectPropertyList list, Mobile m) { list.Add(1062203, "{0}", m.Name); // Blessed for ~1_NAME~ } public virtual void AddItemSocketProperties(ObjectPropertyList list) { if (Sockets != null) { foreach (var socket in Sockets) { socket.GetProperties(list); } } } public virtual void AddItemPowerProperties(ObjectPropertyList list) { } /// /// Overridable. Fills an with everything applicable. By default, this invokes /// /// , then Item.GetChildProperties or /// /// Mobile.GetChildProperties /// /// . This method should be overriden to add any custom properties. /// public virtual void GetProperties(ObjectPropertyList list) { AddNameProperties(list); AddItemSocketProperties(list); if (Spawner != null) { Spawner.GetSpawnProperties(this, list); } AddItemPowerProperties(list); } /// /// Overridable. Event invoked when a child () is building it's . Recursively calls /// /// Item.GetChildProperties /// /// or Mobile.GetChildProperties. /// public virtual void GetChildProperties(ObjectPropertyList list, Item item) { if (m_Parent is Item) { ((Item)m_Parent).GetChildProperties(list, item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).GetChildProperties(list, item); } } /// /// Overridable. Event invoked when a child () is building it's Name /// /// . Recursively calls Item.GetChildNameProperties or /// /// Mobile.GetChildNameProperties /// /// . /// public virtual void GetChildNameProperties(ObjectPropertyList list, Item item) { if (m_Parent is Item) { ((Item)m_Parent).GetChildNameProperties(list, item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).GetChildNameProperties(list, item); } } public virtual bool IsChildVisibleTo(Mobile m, Item child) { return true; } public void Bounce(Mobile from) { if (m_Parent is Item) { ((Item)m_Parent).RemoveItem(this); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).RemoveItem(this); } m_Parent = null; BounceInfo bounce = GetBounce(); if (bounce != null) { var stack = bounce.m_ParentStack; if (stack is Item) { var s = (Item)stack; if (!s.Deleted) { if (s.IsAccessibleTo(from)) { s.StackWith(from, this); } } } var parent = bounce.m_Parent; if (parent is Item && !((Item)parent).Deleted) { Item p = (Item)parent; var root = p.RootParent; if (p.IsAccessibleTo(from) && (!(root is Mobile) || ((Mobile)root).CheckNonlocalDrop(from, this, p))) { Location = bounce.m_Location; p.AddItem(this); } else { MoveToWorld(from.Location, from.Map); } } else if (parent is Mobile && !((Mobile)parent).Deleted) { if (!((Mobile)parent).EquipItem(this)) { MoveToWorld(bounce.m_WorldLoc, bounce.m_Map); } } else { MoveToWorld(bounce.m_WorldLoc, bounce.m_Map); } ClearBounce(); } else { MoveToWorld(from.Location, from.Map); } } /// /// Overridable. Method checked to see if this item may be equiped while casting a spell. By default, this returns false. It is overriden on spellbook and spell channeling weapons or shields. /// /// True if it may, false if not. /// /// /// public override bool AllowEquipedCast( Mobile from ) /// { /// if ( from.Int >= 100 ) /// return true; /// /// return base.AllowEquipedCast( from ); /// } /// When placed in an Item script, the item may be cast when equiped if the has 100 or more intelligence. Otherwise, it will drop to their backpack. /// public virtual bool AllowEquipedCast(Mobile from) { return false; } public virtual bool CheckConflictingLayer(Mobile m, Item item, Layer layer) { return (m_Layer == layer); } public virtual bool CanEquip(Mobile m) { return m_Layer != Layer.Invalid && m.FindItemOnLayer(m_Layer) == null && CheckEquip(m, true); } public virtual bool CheckEquip(Mobile m, bool message) { if (m == null || m.Deleted) { return false; } if (this == m.Mount || this == m.Backpack || this == m.FindBankNoCreate()) { return true; } var e = new CheckEquipItemEventArgs(m, this, message); EventSink.InvokeCheckEquipItem(e); if (e.Item != this || e.Item.Deleted || e.Block) { return false; } if (m.AccessLevel < AccessLevel.GameMaster && BlessedFor != null && BlessedFor != m) { if (message) { m.SendMessage("You do not own that item."); } return false; } return true; } public virtual void GetChildContextMenuEntries(Mobile from, List list, Item item) { if (m_Parent is Item) { ((Item)m_Parent).GetChildContextMenuEntries(from, list, item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).GetChildContextMenuEntries(from, list, item); } } public virtual void GetContextMenuEntries(Mobile from, List list) { if (m_Parent is Item) { ((Item)m_Parent).GetChildContextMenuEntries(from, list, this); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).GetChildContextMenuEntries(from, list, this); } if (from.Region != null) { from.Region.GetContextMenuEntries(from, list, this); } if (Spawner != null) { Spawner.GetSpawnContextEntries(this, from, list); } } public virtual bool DisplayContextMenu(Mobile from) { return ContextMenu.Display(from, this); } public virtual bool VerifyMove(Mobile from) { return Movable; } public virtual void OnParentKill(Mobile target, Container corpse) { } public virtual DeathMoveResult OnParentDeath(Mobile parent) { if (!Movable) { return DeathMoveResult.RemainEquiped; } else if (parent.KeepsItemsOnDeath) { return DeathMoveResult.MoveToBackpack; } else if (CheckBlessed(parent)) { return DeathMoveResult.MoveToBackpack; } else if (CheckNewbied() && parent.Kills < 5) { return DeathMoveResult.MoveToBackpack; } else if (parent.Player && Nontransferable) { return DeathMoveResult.MoveToBackpack; } else { return DeathMoveResult.MoveToCorpse; } } public virtual DeathMoveResult OnInventoryDeath(Mobile parent) { if (!Movable) { return DeathMoveResult.MoveToBackpack; } else if (parent.KeepsItemsOnDeath) { return DeathMoveResult.MoveToBackpack; } else if (CheckBlessed(parent)) { return DeathMoveResult.MoveToBackpack; } else if (CheckNewbied() && parent.Kills < 5) { return DeathMoveResult.MoveToBackpack; } else if (parent.Player && Nontransferable) { return DeathMoveResult.MoveToBackpack; } else { return DeathMoveResult.MoveToCorpse; } } /// /// Moves the Item to . The Item does not change maps. /// public virtual void MoveToWorld(Point3D location) { MoveToWorld(location, m_Map); } public void LabelTo(Mobile to, int number) { to.Send(new MessageLocalized(m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", "")); } public void LabelTo(Mobile to, int number, string args) { to.Send(new MessageLocalized(m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", args)); } public void LabelTo(Mobile to, string text) { to.Send(new UnicodeMessage(m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, "ENU", "", text)); } public void LabelTo(Mobile to, string format, params object[] args) { LabelTo(to, String.Format(format, args)); } public void LabelToAffix(Mobile to, int number, AffixType type, string affix) { to.Send(new MessageLocalizedAffix(m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, "")); } public void LabelToAffix(Mobile to, int number, AffixType type, string affix, string args) { to.Send(new MessageLocalizedAffix(m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, args)); } public virtual void LabelLootTypeTo(Mobile to) { if (m_LootType == LootType.Blessed) { LabelTo(to, 1041362); // (blessed) } else if (m_LootType == LootType.Cursed) { LabelTo(to, "(cursed)"); } } public bool AtWorldPoint(int x, int y) { return (m_Parent == null && m_Location.m_X == x && m_Location.m_Y == y); } public bool AtPoint(int x, int y) { return (m_Location.m_X == x && m_Location.m_Y == y); } /// /// Moves the Item to a given and . /// public void MoveToWorld(Point3D location, Map map) { if (Deleted) { return; } Point3D oldLocation = GetWorldLocation(); Point3D oldRealLocation = m_Location; SetLastMoved(); if (Parent is Mobile) { ((Mobile)Parent).RemoveItem(this); } else if (Parent is Item) { ((Item)Parent).RemoveItem(this); } if (m_Map != map) { Map old = m_Map; if (m_Map != null) { m_Map.OnLeave(this); if (oldLocation.m_X != 0) { var eable = m_Map.GetClientsInRange(oldLocation, Core.GlobalRadarRange - 4); foreach (NetState state in eable) { Mobile m = state.Mobile; if (Utility.InRange(oldLocation, m.Location, GetUpdateRange(m))) { state.Send(RemovePacket); } } eable.Free(); } } m_Location = location; OnLocationChange(oldRealLocation); ReleaseWorldPackets(); var items = LookupItems(); if (items != null) { for (int i = 0; i < items.Count; ++i) { items[i].Map = map; } } m_Map = map; if (m_Map != null) { m_Map.OnEnter(this); } OnMapChange(); if (m_Map != null) { var eable = m_Map.GetClientsInRange(m_Location, Core.GlobalRadarRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(this) && Utility.InRange(m_Location, m.Location, GetUpdateRange(m))) { SendInfoTo(state); } } eable.Free(); } RemDelta(ItemDelta.Update); if (old == null || old == Map.Internal) { InvalidateProperties(); } } else if (m_Map != null) { IPooledEnumerable eable; if (oldLocation.m_X != 0) { eable = m_Map.GetClientsInRange(oldLocation, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (!m.InUpdateRange(location)) { state.Send(RemovePacket); } } eable.Free(); } Point3D oldInternalLocation = m_Location; m_Location = location; OnLocationChange(oldRealLocation); ReleaseWorldPackets(); eable = m_Map.GetClientsInRange(m_Location, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(this) && m.InUpdateRange(m_Location)) { SendInfoTo(state); } } eable.Free(); m_Map.OnMove(oldInternalLocation, this); RemDelta(ItemDelta.Update); } else { Map = map; Location = location; } } [CommandProperty(AccessLevel.GameMaster)] public bool HonestyItem { get; set; } /// /// Has the item been deleted? /// public bool Deleted { get { return GetFlag(ImplFlag.Deleted); } } [CommandProperty(AccessLevel.GameMaster)] public LootType LootType { get { return m_LootType; } set { if (m_LootType != value) { m_LootType = value; if (DisplayLootType) { InvalidateProperties(); } } } } /// /// If true the item should be considered an artifact /// [CommandProperty(AccessLevel.GameMaster)] public virtual bool IsArtifact { get { return this is IArtifact && ((IArtifact)this).ArtifactRarity > 0; } } private static TimeSpan m_DDT = TimeSpan.FromMinutes(Config.Get("General.DefaultItemDecayTime", 60)); public static TimeSpan DefaultDecayTime { get { return m_DDT; } set { m_DDT = value; } } [CommandProperty(AccessLevel.GameMaster)] public virtual int DecayMultiplier { get { return 1; } } [CommandProperty(AccessLevel.GameMaster)] public virtual bool DefaultDecaySetting { get { return true; } } [CommandProperty(AccessLevel.Decorator)] public virtual TimeSpan DecayTime { get { return TimeSpan.FromMinutes(m_DDT.TotalMinutes * DecayMultiplier); } } [CommandProperty(AccessLevel.Decorator)] public virtual bool Decays { get { // TODO: Make item decay an option on the spawner return DefaultDecaySetting && Movable && Visible && !HonestyItem/* && Spawner == null*/; } } [CommandProperty(AccessLevel.GameMaster)] public TimeSpan TimeToDecay { get { return TimeSpan.FromMinutes((DecayTime - (DateTime.UtcNow - LastMoved)).TotalMinutes); } } public virtual bool OnDecay() { return (Decays && Parent == null && Map != Map.Internal && Region.Find(Location, Map).OnDecay(this)); } public void SetLastMoved() { m_LastMovedTime = DateTime.UtcNow; } public DateTime LastMoved { get { return m_LastMovedTime; } set { m_LastMovedTime = value; } } public virtual bool StackIgnoreItemID { get { return false; } } public virtual bool StackIgnoreHue { get { return false; } } public virtual bool StackIgnoreName { get { return false; } } public bool StackWith(Mobile from, Item dropped) { return StackWith(from, dropped, true); } public virtual bool StackWith(Mobile from, Item dropped, bool playSound) { if (WillStack(from, dropped)) { if (m_LootType != dropped.m_LootType) { m_LootType = LootType.Regular; } Amount += dropped.Amount; dropped.Delete(); if (playSound && from != null) { int soundID = GetDropSound(); if (soundID == -1) { soundID = 0x42; } from.SendSound(soundID, GetWorldLocation()); } return true; } return false; } public virtual bool WillStack(Mobile from, Item item) { if (item == this || item.GetType() != GetType()) { return false; } if (!item.Stackable || !Stackable) { return false; } if (item.Nontransferable || Nontransferable) { return false; } if ((!item.StackIgnoreItemID || !StackIgnoreItemID) && item.ItemID != ItemID) { return false; } if ((!item.StackIgnoreHue || !StackIgnoreHue) && item.Hue != Hue) { return false; } if ((!item.StackIgnoreName || !StackIgnoreName) && item.Name != Name) { return false; } if (item.Amount + Amount > 60000) { return false; } if ((Sockets == null && item.Sockets != null) || (Sockets != null && item.Sockets == null)) { return false; } else if (Sockets != null && item.Sockets != null) { if (Sockets.Any(s => !item.HasSocket(s.GetType()))) { return false; } if (item.Sockets.Any(s => !HasSocket(s.GetType()))) { return false; } } return true; } public virtual bool OnDragDrop(Mobile from, Item dropped) { if (Parent is Container) { return ((Container)Parent).OnStackAttempt(from, this, dropped); } return StackWith(from, dropped); } public Rectangle2D GetGraphicBounds() { int itemID = m_ItemID; bool doubled = m_Amount > 1; if (itemID >= 0xEEA && itemID <= 0xEF2) // Are we coins? { int coinBase = (itemID - 0xEEA) / 3; coinBase *= 3; coinBase += 0xEEA; doubled = false; if (m_Amount <= 1) { // A single coin itemID = coinBase; } else if (m_Amount <= 5) { // A stack of coins itemID = coinBase + 1; } else // m_Amount > 5 { // A pile of coins itemID = coinBase + 2; } } Rectangle2D bounds = ItemBounds.Table[itemID & 0x3FFF]; if (doubled) { bounds.Set(bounds.X, bounds.Y, bounds.Width + 5, bounds.Height + 5); } return bounds; } [CommandProperty(AccessLevel.Decorator)] public bool Stackable { get { return GetFlag(ImplFlag.Stackable); } set { SetFlag(ImplFlag.Stackable, value); } } private readonly object _rpl = new object(); public Packet RemovePacket { get { if (m_RemovePacket == null) { lock (_rpl) { if (m_RemovePacket == null) { m_RemovePacket = new RemoveItem(this); m_RemovePacket.SetStatic(); } } } return m_RemovePacket; } } private readonly object _opll = new object(); public Packet OPLPacket { get { if (m_OPLPacket == null) { lock (_opll) { if (m_OPLPacket == null) { m_OPLPacket = new OPLInfo(PropertyList); m_OPLPacket.SetStatic(); } } } return m_OPLPacket; } } public ObjectPropertyList PropertyList { get { if (m_PropertyList == null) { m_PropertyList = new ObjectPropertyList(this); GetProperties(m_PropertyList); AppendChildProperties(m_PropertyList); m_PropertyList.Terminate(); m_PropertyList.SetStatic(); } return m_PropertyList; } } public virtual void AppendChildProperties(ObjectPropertyList list) { if (m_Parent is Item) { ((Item)m_Parent).GetChildProperties(list, this); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).GetChildProperties(list, this); } } public virtual void AppendChildNameProperties(ObjectPropertyList list) { if (m_Parent is Item) { ((Item)m_Parent).GetChildNameProperties(list, this); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).GetChildNameProperties(list, this); } } public void ClearProperties() { Packet.Release(ref m_PropertyList); Packet.Release(ref m_OPLPacket); } public void InvalidateProperties() { if (!ObjectPropertyList.Enabled) { return; } if (m_Map != null && m_Map != Map.Internal && !World.Loading) { ObjectPropertyList oldList = m_PropertyList; m_PropertyList = null; ObjectPropertyList newList = PropertyList; if (oldList == null || oldList.Hash != newList.Hash) { Packet.Release(ref m_OPLPacket); Delta(ItemDelta.Properties); } } else { ClearProperties(); } } private readonly object _wpl = new object(); private readonly object _wplsa = new object(); private readonly object _wplhs = new object(); public Packet WorldPacket { get { // This needs to be invalidated when any of the following changes: // - ItemID // - Amount // - Location // - Hue // - Packet Flags // - Direction if (m_WorldPacket == null) { lock (_wpl) { if (m_WorldPacket == null) { m_WorldPacket = new WorldItem(this); m_WorldPacket.SetStatic(); } } } return m_WorldPacket; } } public Packet WorldPacketSA { get { // This needs to be invalidated when any of the following changes: // - ItemID // - Amount // - Location // - Hue // - Packet Flags // - Direction if (m_WorldPacketSA == null) { lock (_wplsa) { if (m_WorldPacketSA == null) { m_WorldPacketSA = new WorldItemSA(this); m_WorldPacketSA.SetStatic(); } } } return m_WorldPacketSA; } } public virtual Packet WorldPacketHS { get { // This needs to be invalidated when any of the following changes: // - ItemID // - Amount // - Location // - Hue // - Packet Flags // - Direction if (m_WorldPacketHS == null) { lock (_wplhs) { if (m_WorldPacketHS == null) { m_WorldPacketHS = new WorldItemHS(this); m_WorldPacketHS.SetStatic(); } } } return m_WorldPacketHS; } } public virtual void ReleaseWorldPackets() { Packet.Release(ref m_WorldPacket); Packet.Release(ref m_WorldPacketSA); Packet.Release(ref m_WorldPacketHS); } [CommandProperty(AccessLevel.Decorator)] public bool Visible { get { return GetFlag(ImplFlag.Visible); } set { if (GetFlag(ImplFlag.Visible) != value) { SetFlag(ImplFlag.Visible, value); ReleaseWorldPackets(); if (m_Map != null && m_Map != Map.Internal) { Point3D worldLoc = GetWorldLocation(); var eable = m_Map.GetClientsInRange(worldLoc, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (!m.CanSee(this) && m.InRange(worldLoc, GetUpdateRange(m))) { state.Send(RemovePacket); } } eable.Free(); } Delta(ItemDelta.Update); } } } [CommandProperty(AccessLevel.Decorator)] public bool Movable { get { return GetFlag(ImplFlag.Movable); } set { if (GetFlag(ImplFlag.Movable) != value) { SetFlag(ImplFlag.Movable, value); ReleaseWorldPackets(); Delta(ItemDelta.Update); } } } public virtual bool ForceShowProperties { get { return IsLockedDown || IsSecure; } } public virtual int GetPacketFlags() { int flags = 0; if (!Visible) { flags |= 0x80; } if (Movable || ForceShowProperties) { flags |= 0x20; } return flags; } public virtual bool OnMoveOff(Mobile m) { return true; } public virtual bool OnMoveOver(Mobile m) { return true; } public virtual bool HandlesOnMovement { get { return false; } } public virtual void OnMovement(Mobile m, Point3D oldLocation) { } public void Internalize() { MoveToWorld(Point3D.Zero, Map.Internal); } public virtual void OnMapChange() { } public virtual void OnRemoved(object parent) { } public virtual void OnAdded(object parent) { } [CommandProperty(AccessLevel.Counselor, AccessLevel.Decorator)] public Map Map { get { return m_Map; } set { if (m_Map != value) { Map old = m_Map; if (m_Map != null && m_Parent == null) { m_Map.OnLeave(this); SendRemovePacket(); } var items = LookupItems(); if (items != null) { for (int i = 0; i < items.Count; ++i) { items[i].Map = value; } } m_Map = value; if (m_Map != null && m_Parent == null) { m_Map.OnEnter(this); } Delta(ItemDelta.Update); OnMapChange(); if (old == null || old == Map.Internal) { InvalidateProperties(); } } } } [Flags] private enum SaveFlag { None = 0x00000000, Direction = 0x00000001, Bounce = 0x00000002, LootType = 0x00000004, LocationFull = 0x00000008, ItemID = 0x00000010, Hue = 0x00000020, Amount = 0x00000040, Layer = 0x00000080, Name = 0x00000100, Parent = 0x00000200, Items = 0x00000400, WeightNot1or0 = 0x00000800, Map = 0x00001000, Visible = 0x00002000, Movable = 0x00004000, Stackable = 0x00008000, WeightIs0 = 0x00010000, LocationSByteZ = 0x00020000, LocationShortXY = 0x00040000, LocationByteXY = 0x00080000, ImplFlags = 0x00100000, InsuredFor = 0x00200000, BlessedFor = 0x00400000, HeldBy = 0x00800000, IntWeight = 0x01000000, SavedFlags = 0x02000000, NullWeight = 0x04000000, Light = 0x08000000 } private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf) { if (setIf) { flags |= toSet; } } private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet) { return ((flags & toGet) != 0); } int ISerializable.TypeReference { get { return m_TypeRef; } } int ISerializable.SerialIdentity { get { return m_Serial; } } public virtual void Serialize(GenericWriter writer) { writer.Write(14); // version // 14 writer.Write(Sockets != null ? Sockets.Count : 0); if(Sockets != null) { foreach(var socket in Sockets) { ItemSocket.Save(socket, writer); } } // 13: Merge sync // 12: Light no longer backed by Direction // 11 writer.Write(m_GridLocation); // 10: Honesty moved to ItemSockets // 9 SaveFlag flags = SaveFlag.None; int x = m_Location.m_X, y = m_Location.m_Y, z = m_Location.m_Z; if (x != 0 || y != 0 || z != 0) { if (x >= short.MinValue && x <= short.MaxValue && y >= short.MinValue && y <= short.MaxValue && z >= sbyte.MinValue && z <= sbyte.MaxValue) { if (x != 0 || y != 0) { if (x >= byte.MinValue && x <= byte.MaxValue && y >= byte.MinValue && y <= byte.MaxValue) { flags |= SaveFlag.LocationByteXY; } else { flags |= SaveFlag.LocationShortXY; } } if (z != 0) { flags |= SaveFlag.LocationSByteZ; } } else { flags |= SaveFlag.LocationFull; } } var info = LookupCompactInfo(); var items = LookupItems(); if (m_Direction != Direction.North) { flags |= SaveFlag.Direction; } if (m_Light != 0) { flags |= SaveFlag.Light; } if (info != null && info.m_Bounce != null) { flags |= SaveFlag.Bounce; } if (m_LootType != LootType.Regular) { flags |= SaveFlag.LootType; } if (m_ItemID != 0) { flags |= SaveFlag.ItemID; } if (m_Hue != 0) { flags |= SaveFlag.Hue; } if (m_Amount != 1) { flags |= SaveFlag.Amount; } if (m_Layer != Layer.Invalid) { flags |= SaveFlag.Layer; } if (info != null && info.m_Name != null) { flags |= SaveFlag.Name; } if (m_Parent != null) { flags |= SaveFlag.Parent; } if (items != null && items.Count > 0) { flags |= SaveFlag.Items; } if (m_Map != Map.Internal) { flags |= SaveFlag.Map; } if (info != null && info.m_BlessedFor != null && !info.m_BlessedFor.Deleted) { flags |= SaveFlag.BlessedFor; } if (info != null && info.m_HeldBy != null && !info.m_HeldBy.Deleted) { flags |= SaveFlag.HeldBy; } if (info != null && info.m_SavedFlags != 0) { flags |= SaveFlag.SavedFlags; } if (info == null || info.m_Weight == -1) { flags |= SaveFlag.NullWeight; } else if (info.m_Weight == 0.0) { flags |= SaveFlag.WeightIs0; } else if (info.m_Weight != 1.0) { if (info.m_Weight == (int)info.m_Weight) { flags |= SaveFlag.IntWeight; } else { flags |= SaveFlag.WeightNot1or0; } } var implFlags = (m_Flags & (ImplFlag.Visible | ImplFlag.Movable | ImplFlag.Stackable | ImplFlag.Insured | ImplFlag.PayedInsurance | ImplFlag.QuestItem)); if (implFlags != (ImplFlag.Visible | ImplFlag.Movable)) { flags |= SaveFlag.ImplFlags; } writer.Write((int)flags); /* begin last moved time optimization */ long ticks = m_LastMovedTime.Ticks; long now = DateTime.UtcNow.Ticks; TimeSpan d; try { d = new TimeSpan(ticks - now); } catch { if (ticks < now) { d = TimeSpan.MaxValue; } else { d = TimeSpan.MaxValue; } } double minutes = -d.TotalMinutes; if (minutes < int.MinValue) { minutes = int.MinValue; } else if (minutes > int.MaxValue) { minutes = int.MaxValue; } writer.WriteEncodedInt((int)minutes); /* end */ if (GetSaveFlag(flags, SaveFlag.Direction)) { writer.Write((byte)m_Direction); } if (GetSaveFlag(flags, SaveFlag.Light)) { writer.Write((byte)m_Light); } if (GetSaveFlag(flags, SaveFlag.Bounce)) { // ReSharper disable once PossibleNullReferenceException BounceInfo.Serialize(info.m_Bounce, writer); } if (GetSaveFlag(flags, SaveFlag.LootType)) { writer.Write((byte)m_LootType); } if (GetSaveFlag(flags, SaveFlag.LocationFull)) { writer.WriteEncodedInt(x); writer.WriteEncodedInt(y); writer.WriteEncodedInt(z); } else { if (GetSaveFlag(flags, SaveFlag.LocationByteXY)) { writer.Write((byte)x); writer.Write((byte)y); } else if (GetSaveFlag(flags, SaveFlag.LocationShortXY)) { writer.Write((short)x); writer.Write((short)y); } if (GetSaveFlag(flags, SaveFlag.LocationSByteZ)) { writer.Write((sbyte)z); } } if (GetSaveFlag(flags, SaveFlag.ItemID)) { writer.WriteEncodedInt(m_ItemID); } if (GetSaveFlag(flags, SaveFlag.Hue)) { writer.WriteEncodedInt(m_Hue); } if (GetSaveFlag(flags, SaveFlag.Amount)) { writer.WriteEncodedInt(m_Amount); } if (GetSaveFlag(flags, SaveFlag.Layer)) { writer.Write((byte)m_Layer); } if (GetSaveFlag(flags, SaveFlag.Name)) { writer.Write(info.m_Name); } if (GetSaveFlag(flags, SaveFlag.Parent)) { if (m_Parent is Mobile && !((Mobile)m_Parent).Deleted) { writer.Write(((Mobile)m_Parent).Serial); } else if (m_Parent is Item && !((Item)m_Parent).Deleted) { writer.Write(((Item)m_Parent).Serial); } else { writer.Write(Serial.MinusOne); } } if (GetSaveFlag(flags, SaveFlag.Items)) { writer.Write(items, false); } if (GetSaveFlag(flags, SaveFlag.IntWeight)) { writer.WriteEncodedInt((int)info.m_Weight); } else if (GetSaveFlag(flags, SaveFlag.WeightNot1or0)) { writer.Write(info.m_Weight); } if (GetSaveFlag(flags, SaveFlag.Map)) { writer.Write(m_Map); } if (GetSaveFlag(flags, SaveFlag.ImplFlags)) { writer.WriteEncodedInt((int)implFlags); } if (GetSaveFlag(flags, SaveFlag.InsuredFor)) { writer.Write((Mobile)null); } if (GetSaveFlag(flags, SaveFlag.BlessedFor)) { writer.Write(info.m_BlessedFor); } if (GetSaveFlag(flags, SaveFlag.HeldBy)) { writer.Write(info.m_HeldBy); } if (GetSaveFlag(flags, SaveFlag.SavedFlags)) { writer.WriteEncodedInt(info.m_SavedFlags); } } public IPooledEnumerable GetObjectsInRange(int range) { Map map = m_Map; if (map == null) { return Map.NullEnumerable.Instance; } if (m_Parent == null) { return map.GetObjectsInRange(m_Location, range); } return map.GetObjectsInRange(GetWorldLocation(), range); } public IPooledEnumerable GetItemsInRange(int range) { Map map = m_Map; if (map == null) { return Map.NullEnumerable.Instance; } if (m_Parent == null) { return map.GetItemsInRange(m_Location, range); } return map.GetItemsInRange(GetWorldLocation(), range); } public IPooledEnumerable GetMobilesInRange(int range) { Map map = m_Map; if (map == null) { return Map.NullEnumerable.Instance; } if (m_Parent == null) { return map.GetMobilesInRange(m_Location, range); } return map.GetMobilesInRange(GetWorldLocation(), range); } public IPooledEnumerable GetClientsInRange(int range) { Map map = m_Map; if (map == null) { return Map.NullEnumerable.Instance; } if (m_Parent == null) { return map.GetClientsInRange(m_Location, range); } return map.GetClientsInRange(GetWorldLocation(), range); } private static int m_LockedDownFlag; private static int m_SecureFlag; public static int LockedDownFlag { get { return m_LockedDownFlag; } set { m_LockedDownFlag = value; } } public static int SecureFlag { get { return m_SecureFlag; } set { m_SecureFlag = value; } } public bool IsLockedDown { get { return GetTempFlag(m_LockedDownFlag); } set { SetTempFlag(m_LockedDownFlag, value); InvalidateProperties(); OnLockDownChange(); } } public virtual void OnLockDownChange() { } public bool IsSecure { get { return GetTempFlag(m_SecureFlag); } set { SetTempFlag(m_SecureFlag, value); InvalidateProperties(); OnSecureChange(); } } public virtual void OnSecureChange() { } public bool GetTempFlag(int flag) { CompactInfo info = LookupCompactInfo(); if (info == null) { return false; } return ((info.m_TempFlags & flag) != 0); } public void SetTempFlag(int flag, bool value) { CompactInfo info = AcquireCompactInfo(); if (value) { info.m_TempFlags |= flag; } else { info.m_TempFlags &= ~flag; } if (info.m_TempFlags == 0) { VerifyCompactInfo(); } } public bool GetSavedFlag(int flag) { CompactInfo info = LookupCompactInfo(); if (info == null) { return false; } return ((info.m_SavedFlags & flag) != 0); } public void SetSavedFlag(int flag, bool value) { CompactInfo info = AcquireCompactInfo(); if (value) { info.m_SavedFlags |= flag; } else { info.m_SavedFlags &= ~flag; } if (info.m_SavedFlags == 0) { VerifyCompactInfo(); } } public virtual void Deserialize(GenericReader reader) { int version = reader.ReadInt(); SetLastMoved(); switch (version) { case 14: var socketCount = reader.ReadInt(); for(int i = 0; i < socketCount; i++) { ItemSocket.Load(this, reader); } goto case 13; case 13: case 12: case 11: m_GridLocation = reader.ReadByte(); goto case 10; case 10: { // Honesty removed to ItemSockets if (version < 14) { reader.ReadDateTime(); reader.ReadBool(); reader.ReadMobile(); reader.ReadString(); HonestyItem = reader.ReadBool(); } goto case 9; } case 9: case 8: case 7: case 6: { SaveFlag flags = (SaveFlag)reader.ReadInt(); if (version < 7) { LastMoved = reader.ReadDeltaTime(); } else { int minutes = reader.ReadEncodedInt(); try { LastMoved = DateTime.UtcNow - TimeSpan.FromMinutes(minutes); } catch { LastMoved = DateTime.UtcNow; } } if (GetSaveFlag(flags, SaveFlag.Direction)) { m_Direction = (Direction)reader.ReadByte(); } if (GetSaveFlag(flags, SaveFlag.Light)) { m_Light = (LightType)reader.ReadByte(); } else if(version < 12) { m_Light = (LightType)m_Direction; } if (GetSaveFlag(flags, SaveFlag.Bounce)) { AcquireCompactInfo().m_Bounce = BounceInfo.Deserialize(reader); } if (GetSaveFlag(flags, SaveFlag.LootType)) { m_LootType = (LootType)reader.ReadByte(); } int x = 0, y = 0, z = 0; if (GetSaveFlag(flags, SaveFlag.LocationFull)) { x = reader.ReadEncodedInt(); y = reader.ReadEncodedInt(); z = reader.ReadEncodedInt(); } else { if (GetSaveFlag(flags, SaveFlag.LocationByteXY)) { x = reader.ReadByte(); y = reader.ReadByte(); } else if (GetSaveFlag(flags, SaveFlag.LocationShortXY)) { x = reader.ReadShort(); y = reader.ReadShort(); } if (GetSaveFlag(flags, SaveFlag.LocationSByteZ)) { z = reader.ReadSByte(); } } m_Location = new Point3D(x, y, z); if (GetSaveFlag(flags, SaveFlag.ItemID)) { m_ItemID = reader.ReadEncodedInt(); } if (GetSaveFlag(flags, SaveFlag.Hue)) { m_Hue = reader.ReadEncodedInt(); } if (GetSaveFlag(flags, SaveFlag.Amount)) { m_Amount = reader.ReadEncodedInt(); } else { m_Amount = 1; } if (GetSaveFlag(flags, SaveFlag.Layer)) { m_Layer = (Layer)reader.ReadByte(); } if (GetSaveFlag(flags, SaveFlag.Name)) { string name = reader.ReadString(); if (name != DefaultName) { AcquireCompactInfo().m_Name = name; } } if (GetSaveFlag(flags, SaveFlag.Parent)) { Serial parent = reader.ReadInt(); if (parent.IsMobile) { m_Parent = World.FindMobile(parent); } else if (parent.IsItem) { m_Parent = World.FindItem(parent); } else { m_Parent = null; } if (m_Parent == null && (parent.IsMobile || parent.IsItem)) { Delete(); } } if (GetSaveFlag(flags, SaveFlag.Items)) { var items = reader.ReadStrongItemList(); if (this is Container) { (this as Container).m_Items = items; } else { AcquireCompactInfo().m_Items = items; } } if (version < 8 || !GetSaveFlag(flags, SaveFlag.NullWeight)) { double weight; if (GetSaveFlag(flags, SaveFlag.IntWeight)) { weight = reader.ReadEncodedInt(); } else if (GetSaveFlag(flags, SaveFlag.WeightNot1or0)) { weight = reader.ReadDouble(); } else if (GetSaveFlag(flags, SaveFlag.WeightIs0)) { weight = 0.0; } else { weight = 1.0; } if (weight != DefaultWeight) { AcquireCompactInfo().m_Weight = weight; } } if (GetSaveFlag(flags, SaveFlag.Map)) { m_Map = reader.ReadMap(); } else { m_Map = Map.Internal; } if (GetSaveFlag(flags, SaveFlag.Visible)) { SetFlag(ImplFlag.Visible, reader.ReadBool()); } else { SetFlag(ImplFlag.Visible, true); } if (GetSaveFlag(flags, SaveFlag.Movable)) { SetFlag(ImplFlag.Movable, reader.ReadBool()); } else { SetFlag(ImplFlag.Movable, true); } if (GetSaveFlag(flags, SaveFlag.Stackable)) { SetFlag(ImplFlag.Stackable, reader.ReadBool()); } if (GetSaveFlag(flags, SaveFlag.ImplFlags)) { m_Flags = (ImplFlag)reader.ReadEncodedInt(); } if (GetSaveFlag(flags, SaveFlag.InsuredFor)) { /*m_InsuredFor = */ reader.ReadMobile(); } if (GetSaveFlag(flags, SaveFlag.BlessedFor)) { AcquireCompactInfo().m_BlessedFor = reader.ReadMobile(); } if (GetSaveFlag(flags, SaveFlag.HeldBy)) { AcquireCompactInfo().m_HeldBy = reader.ReadMobile(); } if (GetSaveFlag(flags, SaveFlag.SavedFlags)) { AcquireCompactInfo().m_SavedFlags = reader.ReadEncodedInt(); } if (m_Map != null && m_Parent == null) { m_Map.OnEnter(this); } break; } case 5: { SaveFlag flags = (SaveFlag)reader.ReadInt(); LastMoved = reader.ReadDeltaTime(); if (GetSaveFlag(flags, SaveFlag.Direction)) { m_Direction = (Direction)reader.ReadByte(); } if (GetSaveFlag(flags, SaveFlag.Bounce)) { AcquireCompactInfo().m_Bounce = BounceInfo.Deserialize(reader); } if (GetSaveFlag(flags, SaveFlag.LootType)) { m_LootType = (LootType)reader.ReadByte(); } if (GetSaveFlag(flags, SaveFlag.LocationFull)) { m_Location = reader.ReadPoint3D(); } if (GetSaveFlag(flags, SaveFlag.ItemID)) { m_ItemID = reader.ReadInt(); } if (GetSaveFlag(flags, SaveFlag.Hue)) { m_Hue = reader.ReadInt(); } if (GetSaveFlag(flags, SaveFlag.Amount)) { m_Amount = reader.ReadInt(); } else { m_Amount = 1; } if (GetSaveFlag(flags, SaveFlag.Layer)) { m_Layer = (Layer)reader.ReadByte(); } if (GetSaveFlag(flags, SaveFlag.Name)) { string name = reader.ReadString(); if (name != DefaultName) { AcquireCompactInfo().m_Name = name; } } if (GetSaveFlag(flags, SaveFlag.Parent)) { Serial parent = reader.ReadInt(); if (parent.IsMobile) { m_Parent = World.FindMobile(parent); } else if (parent.IsItem) { m_Parent = World.FindItem(parent); } else { m_Parent = null; } if (m_Parent == null && (parent.IsMobile || parent.IsItem)) { Delete(); } } if (GetSaveFlag(flags, SaveFlag.Items)) { var items = reader.ReadStrongItemList(); if (this is Container) { (this as Container).m_Items = items; } else { AcquireCompactInfo().m_Items = items; } } double weight; if (GetSaveFlag(flags, SaveFlag.IntWeight)) { weight = reader.ReadEncodedInt(); } else if (GetSaveFlag(flags, SaveFlag.WeightNot1or0)) { weight = reader.ReadDouble(); } else if (GetSaveFlag(flags, SaveFlag.WeightIs0)) { weight = 0.0; } else { weight = 1.0; } if (weight != DefaultWeight) { AcquireCompactInfo().m_Weight = weight; } if (GetSaveFlag(flags, SaveFlag.Map)) { m_Map = reader.ReadMap(); } else { m_Map = Map.Internal; } if (GetSaveFlag(flags, SaveFlag.Visible)) { SetFlag(ImplFlag.Visible, reader.ReadBool()); } else { SetFlag(ImplFlag.Visible, true); } if (GetSaveFlag(flags, SaveFlag.Movable)) { SetFlag(ImplFlag.Movable, reader.ReadBool()); } else { SetFlag(ImplFlag.Movable, true); } if (GetSaveFlag(flags, SaveFlag.Stackable)) { SetFlag(ImplFlag.Stackable, reader.ReadBool()); } if (m_Map != null && m_Parent == null) { m_Map.OnEnter(this); } break; } case 4: // Just removed variables case 3: { m_Direction = (Direction)reader.ReadInt(); goto case 2; } case 2: { AcquireCompactInfo().m_Bounce = BounceInfo.Deserialize(reader); LastMoved = reader.ReadDeltaTime(); goto case 1; } case 1: { m_LootType = (LootType)reader.ReadByte(); //m_Newbied = reader.ReadBool(); goto case 0; } case 0: { m_Location = reader.ReadPoint3D(); m_ItemID = reader.ReadInt(); m_Hue = reader.ReadInt(); m_Amount = reader.ReadInt(); m_Layer = (Layer)reader.ReadByte(); string name = reader.ReadString(); if (name != DefaultName) { AcquireCompactInfo().m_Name = name; } Serial parent = reader.ReadInt(); if (parent.IsMobile) { m_Parent = World.FindMobile(parent); } else if (parent.IsItem) { m_Parent = World.FindItem(parent); } else { m_Parent = null; } if (m_Parent == null && (parent.IsMobile || parent.IsItem)) { Delete(); } int count = reader.ReadInt(); if (count > 0) { var items = new List(count); for (int i = 0; i < count; ++i) { Item item = reader.ReadItem(); if (item != null) { items.Add(item); } } if (this is Container) { (this as Container).m_Items = items; } else { AcquireCompactInfo().m_Items = items; } } double weight = reader.ReadDouble(); if (weight != DefaultWeight) { AcquireCompactInfo().m_Weight = weight; } if (version <= 3) { reader.ReadInt(); reader.ReadInt(); reader.ReadInt(); } m_Map = reader.ReadMap(); SetFlag(ImplFlag.Visible, reader.ReadBool()); SetFlag(ImplFlag.Movable, reader.ReadBool()); if (version <= 3) { /*m_Deleted =*/ reader.ReadBool(); } Stackable = reader.ReadBool(); if (m_Map != null && m_Parent == null) { m_Map.OnEnter(this); } break; } } if (HeldBy != null) { Timer.DelayCall(TimeSpan.Zero, FixHolding_Sandbox); } VerifyCompactInfo(); UpdateLight(); } private void FixHolding_Sandbox() { Mobile heldBy = HeldBy; if (heldBy != null) { if (GetBounce() != null) { Bounce(heldBy); } else { heldBy.Holding = null; heldBy.AddToBackpack(this); ClearBounce(); } } } public virtual int GetMaxUpdateRange() { return Core.GlobalMaxUpdateRange; } public virtual int GetUpdateRange(Mobile m) { return m.NetState == null ? Core.GlobalUpdateRange : m.NetState.UpdateRange; } public void SendInfoTo(NetState state) { SendInfoTo(state, state.Mobile != null && state.Mobile.ViewOPL); } public virtual void SendInfoTo(NetState state, bool sendOplPacket) { state.Send(GetWorldPacketFor(state)); if (sendOplPacket) { state.Send(OPLPacket); } } protected virtual Packet GetWorldPacketFor(NetState state) { if (state.HighSeas) { return WorldPacketHS; } else if (state.StygianAbyss) { return WorldPacketSA; } else { return WorldPacket; } } public virtual bool IsVirtualItem { get { return false; } } public virtual int GetTotal(TotalType type) { return 0; } public virtual void UpdateTotal(Item sender, TotalType type, int delta) { if (!IsVirtualItem) { if (m_Parent is Item) { (m_Parent as Item).UpdateTotal(sender, type, delta); } else if (m_Parent is Mobile) { (m_Parent as Mobile).UpdateTotal(sender, type, delta); } else if (HeldBy != null) { (HeldBy).UpdateTotal(sender, type, delta); } } } public virtual void UpdateTotals() { } public virtual int LabelNumber { get { if (m_ItemID < 0x4000) { return 1020000 + m_ItemID; } else { return 1078872 + m_ItemID; } } } [CommandProperty(AccessLevel.GameMaster)] public int TotalGold { get { return GetTotal(TotalType.Gold); } } [CommandProperty(AccessLevel.GameMaster)] public int TotalItems { get { return GetTotal(TotalType.Items); } } [CommandProperty(AccessLevel.GameMaster)] public int TotalWeight { get { return GetTotal(TotalType.Weight); } } public virtual double DefaultWeight { get { if (m_ItemID < 0 || m_ItemID > TileData.MaxItemValue || this is BaseMulti) { return 0; } int weight = TileData.ItemTable[m_ItemID].Weight; if (weight == 255 || weight == 0) { weight = 1; } return weight; } } [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] public double Weight { get { CompactInfo info = LookupCompactInfo(); if (info != null && info.m_Weight != -1) { return info.m_Weight; } return DefaultWeight; } set { if (Weight != value) { CompactInfo info = AcquireCompactInfo(); int oldPileWeight = PileWeight; info.m_Weight = value; if (info.m_Weight == -1) { VerifyCompactInfo(); } int newPileWeight = PileWeight; UpdateTotal(this, TotalType.Weight, newPileWeight - oldPileWeight); InvalidateProperties(); } } } [CommandProperty(AccessLevel.Counselor, AccessLevel.GameMaster)] public int PileWeight { get { return (int)Math.Ceiling(Weight * Amount); } } public virtual int HuedItemID { get { return m_ItemID; } } [Hue, CommandProperty(AccessLevel.GameMaster)] public virtual int Hue { get { return m_Hue; } set { if (m_Hue != value) { m_Hue = value; ReleaseWorldPackets(); Delta(ItemDelta.Update); } } } public virtual bool HiddenQuestItemHue { get; set; } public int QuestItemHue { get { return (HiddenQuestItemHue ? Hue : 0x04EA); } } public virtual bool Nontransferable { get { return QuestItem; } } public virtual void HandleInvalidTransfer(Mobile from) { // OSI sends 1074769, bug! if (QuestItem) { from.SendLocalizedMessage(1049343); // You can only drop quest items into the top-most level of your backpack while you still need them for your quest. } } [CommandProperty(AccessLevel.GameMaster)] public virtual Layer Layer { get { return m_Layer; } set { if (m_Layer != value) { m_Layer = value; Delta(ItemDelta.EquipOnly); } } } public List Items { get { var items = LookupItems(); if (items == null) { items = EmptyItems; } return items; } } [CommandProperty(AccessLevel.GameMaster)] public object RootParent { get { var p = m_Parent; while (p is Item) { Item item = (Item)p; if (item.m_Parent == null) { break; } else { p = item.m_Parent; } } return p; } } public bool ParentsContain() where T : Item { var p = m_Parent; while (p is Item) { if (p is T) { return true; } Item item = (Item)p; if (item.m_Parent == null) { break; } else { p = item.m_Parent; } } return false; } public virtual void AddItem(Item item) { if (item == null || item.Deleted || item.m_Parent == this) { return; } else if (item == this) { Console.WriteLine( "Warning: Adding item to itself: [0x{0:X} {1}].AddItem( [0x{2:X} {3}] )", Serial.Value, GetType().Name, item.Serial.Value, item.GetType().Name); Console.WriteLine(new StackTrace()); return; } else if (IsChildOf(item)) { Console.WriteLine( "Warning: Adding parent item to child: [0x{0:X} {1}].AddItem( [0x{2:X} {3}] )", Serial.Value, GetType().Name, item.Serial.Value, item.GetType().Name); Console.WriteLine(new StackTrace()); return; } else if (item.m_Parent is Mobile) { ((Mobile)item.m_Parent).RemoveItem(item); } else if (item.m_Parent is Item) { ((Item)item.m_Parent).RemoveItem(item); } else { item.SendRemovePacket(); } item.Parent = this; item.Map = m_Map; var items = AcquireItems(); items.Add(item); if (!item.IsVirtualItem) { UpdateTotal(item, TotalType.Gold, item.TotalGold); UpdateTotal(item, TotalType.Items, item.TotalItems + 1); UpdateTotal(item, TotalType.Weight, item.TotalWeight + item.PileWeight); } item.Delta(ItemDelta.Update); item.OnAdded(this); OnItemAdded(item); } private static readonly List m_DeltaQueue = new List(); public void Delta(ItemDelta flags) { if (m_Map == null || m_Map == Map.Internal) { return; } m_DeltaFlags |= flags; if (!GetFlag(ImplFlag.InQueue)) { SetFlag(ImplFlag.InQueue, true); m_DeltaQueue.Add(this); } Core.Set(); } public void RemDelta(ItemDelta flags) { m_DeltaFlags &= ~flags; if (GetFlag(ImplFlag.InQueue) && m_DeltaFlags == ItemDelta.None) { SetFlag(ImplFlag.InQueue, false); m_DeltaQueue.Remove(this); } } private bool m_NoMoveHS; public bool NoMoveHS { get { return m_NoMoveHS; } set { m_NoMoveHS = value; } } public void ProcessDelta() { ItemDelta flags = m_DeltaFlags; SetFlag(ImplFlag.InQueue, false); m_DeltaFlags = ItemDelta.None; Map map = m_Map; if (map != null && !Deleted) { bool sendOPLUpdate = ObjectPropertyList.Enabled && (flags & ItemDelta.Properties) != 0; Container contParent = m_Parent as Container; if (contParent != null && !contParent.IsPublicContainer) { if ((flags & ItemDelta.Update) != 0) { Point3D worldLoc = GetWorldLocation(); Mobile rootParent = contParent.RootParent as Mobile; Mobile tradeRecip = null; if (rootParent != null) { NetState ns = rootParent.NetState; if (ns != null) { if (rootParent.CanSee(this) && rootParent.InRange(worldLoc, GetUpdateRange(rootParent))) { if (ns.ContainerGridLines) { ns.Send(new ContainerContentUpdate6017(this)); } else { ns.Send(new ContainerContentUpdate(this)); } if (rootParent.ViewOPL) { ns.Send(OPLPacket); } } } } SecureTradeContainer stc = GetSecureTradeCont(); if (stc != null) { SecureTrade st = stc.Trade; if (st != null) { Mobile test = st.From.Mobile; if (test != null && test != rootParent) { tradeRecip = test; } test = st.To.Mobile; if (test != null && test != rootParent) { tradeRecip = test; } if (tradeRecip != null) { NetState ns = tradeRecip.NetState; if (ns != null) { if (tradeRecip.CanSee(this) && tradeRecip.InRange(worldLoc, GetUpdateRange(tradeRecip))) { if (ns.ContainerGridLines) { ns.Send(new ContainerContentUpdate6017(this)); } else { ns.Send(new ContainerContentUpdate(this)); } if (tradeRecip.ViewOPL) { ns.Send(OPLPacket); } } } } } } var openers = contParent.Openers; if (openers != null) { lock (openers) { for (int i = 0; i < openers.Count; ++i) { Mobile mob = openers[i]; int range = GetUpdateRange(mob); if (mob.Map != map || !mob.InRange(worldLoc, range)) { openers.RemoveAt(i--); } else { if (mob == rootParent || mob == tradeRecip) { continue; } NetState ns = mob.NetState; if (ns != null && ns.Seeded) { if (mob.CanSee(this)) { if (ns.ContainerGridLines) { ns.Send(new ContainerContentUpdate6017(this)); } else { ns.Send(new ContainerContentUpdate(this)); } if (mob.ViewOPL) { ns.Send(OPLPacket); } } } } } if (openers.Count == 0) { contParent.Openers = null; } } } return; } } if ((flags & ItemDelta.Update) != 0) { Packet p = null; Point3D worldLoc = GetWorldLocation(); var eable = map.GetClientsInRange(worldLoc, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(this) && m.InUpdateRange(worldLoc)) { if (m_Parent == null) { SendInfoTo(state); } else { if (p == null) { if (m_Parent is Item) { if (state.ContainerGridLines) { state.Send(new ContainerContentUpdate6017(this)); } else { state.Send(new ContainerContentUpdate(this)); } } else if (m_Parent is Mobile) { p = new EquipUpdate(this); p.Acquire(); state.Send(p); } } else { state.Send(p); } if (m.ViewOPL) { state.Send(OPLPacket); } } } } if (p != null) { Packet.Release(p); } eable.Free(); sendOPLUpdate = false; } else if ((flags & ItemDelta.EquipOnly) != 0) { if (m_Parent is Mobile) { Packet p = null; Point3D worldLoc = GetWorldLocation(); var eable = map.GetClientsInRange(worldLoc, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(this) && m.InUpdateRange(worldLoc)) { //if ( sendOPLUpdate ) // state.Send( RemovePacket ); if (p == null) { p = Packet.Acquire(new EquipUpdate(this)); } state.Send(p); if (m.ViewOPL) { state.Send(OPLPacket); } } } Packet.Release(p); eable.Free(); sendOPLUpdate = false; } } if (sendOPLUpdate) { Point3D worldLoc = GetWorldLocation(); var eable = map.GetClientsInRange(worldLoc, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(this) && m.InUpdateRange(worldLoc)) { state.Send(OPLPacket); } } eable.Free(); } } } private static bool _Processing; public static void ProcessDeltaQueue() { if (_Processing) { return; } _Processing = true; var i = m_DeltaQueue.Count; while (--i >= 0) { if (i < m_DeltaQueue.Count) { m_DeltaQueue[i].ProcessDelta(); m_DeltaQueue.RemoveAt(i); } } _Processing = false; } public virtual void OnDelete() { if (Spawner != null) { Spawner.Remove(this); Spawner = null; } var region = Region.Find(GetWorldLocation(), Map); if (region != null) { region.OnDelete(this); } } public virtual void OnParentDeleted(object parent) { Delete(); } public virtual void FreeCache() { ReleaseWorldPackets(); Packet.Release(ref m_RemovePacket); Packet.Release(ref m_OPLPacket); Packet.Release(ref m_PropertyList); } public virtual void Delete() { if (Deleted) { return; } else if (!World.OnDelete(this)) { return; } OnDelete(); var items = LookupItems(); if (items != null) { for (int i = items.Count - 1; i >= 0; --i) { if (i < items.Count) { items[i].OnParentDeleted(this); } } } SendRemovePacket(); SetFlag(ImplFlag.Deleted, true); if (Parent is Mobile) { ((Mobile)Parent).RemoveItem(this); } else if (Parent is Item) { ((Item)Parent).RemoveItem(this); } ClearBounce(); if (m_Map != null) { if (m_Parent == null) { m_Map.OnLeave(this); } m_Map = null; } World.RemoveItem(this); OnAfterDelete(); FreeCache(); } public void PublicOverheadMessage(MessageType type, int hue, bool ascii, string text) { if (m_Map != null) { Packet p = null; Point3D worldLoc = GetWorldLocation(); var eable = m_Map.GetClientsInRange(worldLoc, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(this) && m.InUpdateRange(worldLoc)) { if (p == null) { if (ascii) { p = new AsciiMessage(m_Serial, m_ItemID, type, hue, 3, Name, text); } else { p = new UnicodeMessage(m_Serial, m_ItemID, type, hue, 3, "ENU", Name, text); } p.Acquire(); } state.Send(p); } } Packet.Release(p); eable.Free(); } } public void PublicOverheadMessage(MessageType type, int hue, int number) { PublicOverheadMessage(type, hue, number, ""); } public void PublicOverheadMessage(MessageType type, int hue, int number, string args) { if (m_Map != null) { Packet p = null; Point3D worldLoc = GetWorldLocation(); var eable = m_Map.GetClientsInRange(worldLoc, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(this) && m.InUpdateRange(worldLoc)) { if (p == null) { p = Packet.Acquire(new MessageLocalized(m_Serial, m_ItemID, type, hue, 3, number, Name, args)); } state.Send(p); } } Packet.Release(p); eable.Free(); } } public void PrivateOverheadMessage(MessageType type, int hue, int number, NetState state, string args = "") { if (Map != null && state != null) { Packet p = null; Point3D worldLoc = GetWorldLocation(); Mobile m = state.Mobile; if (m != null && m.CanSee(this) && m.InRange(worldLoc, GetUpdateRange(m))) { if (p == null) p = Packet.Acquire(new MessageLocalized(m_Serial, m_ItemID, type, hue, 3, number, Name, args)); state.Send(p); } Packet.Release(p); } } public void PrivateOverheadMessage(MessageType type, int hue, bool ascii, string text, NetState state) { if (Map != null && state != null) { Point3D worldLoc = GetWorldLocation(); Mobile m = state.Mobile; Packet asciip = null; Packet p = null; if (m != null && m.CanSee(this) && m.InRange(worldLoc, GetUpdateRange(m))) { if (ascii) { if (asciip == null) asciip = Packet.Acquire(new AsciiMessage(m_Serial, m_ItemID, type, hue, 3, Name, text)); state.Send(asciip); } else { if (p == null) p = Packet.Acquire(new UnicodeMessage(m_Serial, m_ItemID, type, hue, 3, m.Language, Name, text)); state.Send(p); } } Packet.Release(asciip); Packet.Release(p); } } public Region GetRegion() { return Region.Find(GetWorldLocation(), Map); } public double GetDistanceToSqrt(IPoint3D p) { Point3D loc = GetWorldLocation(); int xDelta = loc.X - p.X; int yDelta = loc.Y - p.Y; return Math.Sqrt((xDelta * xDelta) + (yDelta * yDelta)); } public bool InRange(IPoint3D p, int range) { Point3D loc = GetWorldLocation(); return (p.X >= (loc.X - range)) && (p.X <= (loc.X + range)) && (p.Y >= (loc.Y - range)) && (p.Y <= (loc.Y + range)); } public bool InLOS(Point3D target) { if (Deleted || Map == null || Parent != null) return false; return Map.LineOfSight(this, target); } public virtual void OnAfterDelete() { foreach (BaseModule module in World.GetModules(this)) { module.Delete(); } if(Sockets != null) { Sockets.IterateReverse(socket => { socket.Remove(); }); } Timer.DelayCall(EventSink.InvokeItemDeleted, new ItemDeletedEventArgs(this)); } public virtual void RemoveItem(Item item) { var items = LookupItems(); if (items != null && items.Remove(item)) { item.SendRemovePacket(); if (!item.IsVirtualItem) { UpdateTotal(item, TotalType.Gold, -item.TotalGold); UpdateTotal(item, TotalType.Items, -(item.TotalItems + 1)); UpdateTotal(item, TotalType.Weight, -(item.TotalWeight + item.PileWeight)); } item.Parent = null; item.OnRemoved(this); OnItemRemoved(item); } } public virtual void OnAfterDuped(Item newItem) { if (Sockets != null) { for (int i = 0; i < Sockets.Count; i++) { Sockets[i].OnOwnerDuped(newItem); } } } public virtual bool OnDragLift(Mobile from) { return true; } public virtual bool OnEquip(Mobile from) { return true; } public ISpawner Spawner { get { CompactInfo info = LookupCompactInfo(); if (info != null) { return info.m_Spawner; } return null; } set { CompactInfo info = AcquireCompactInfo(); info.m_Spawner = value; if (info.m_Spawner == null) { VerifyCompactInfo(); } } } public virtual void OnBeforeSpawn(Point3D location, Map m) { } public virtual void OnAfterSpawn() { } public virtual int PhysicalResistance { get { return 0; } } public virtual int FireResistance { get { return 0; } } public virtual int ColdResistance { get { return 0; } } public virtual int PoisonResistance { get { return 0; } } public virtual int EnergyResistance { get { return 0; } } [CommandProperty(AccessLevel.Counselor)] public Serial Serial { get { return m_Serial; } } [CommandProperty(AccessLevel.GameMaster)] public IEntity ParentEntity { get { return Parent as IEntity; } } [CommandProperty(AccessLevel.GameMaster)] public IEntity RootParentEntity { get { return RootParent as IEntity; } } #region Location Location Location! public virtual void OnLocationChange(Point3D oldLocation) { var items = Items; if (items == null) { return; } var i = items.Count; while (--i >= 0) { if (i >= items.Count) { continue; } var o = items[i]; if (o != null) { o.OnParentLocationChange(oldLocation); } } } public virtual void OnParentLocationChange(Point3D oldLocation) { } [CommandProperty(AccessLevel.Counselor, AccessLevel.Decorator)] public virtual Point3D Location { get { return m_Location; } set { Point3D oldLocation = m_Location; if (oldLocation != value) { if (m_Map != null) { if (m_Parent == null) { IPooledEnumerable eable; if (m_Location.m_X != 0) { eable = m_Map.GetClientsInRange(oldLocation, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (!m.InUpdateRange(value)) { state.Send(RemovePacket); } } eable.Free(); } Point3D oldLoc = m_Location; m_Location = value; ReleaseWorldPackets(); SetLastMoved(); eable = m_Map.GetClientsInRange(m_Location, Core.GlobalMaxUpdateRange); foreach (NetState state in eable) { Mobile m = state.Mobile; if (m.CanSee(this) && m.InUpdateRange(m_Location) && (!state.HighSeas || !m_NoMoveHS || (m_DeltaFlags & ItemDelta.Update) != 0 || !m.InRange(oldLoc, GetUpdateRange(m)))) { SendInfoTo(state); } } eable.Free(); RemDelta(ItemDelta.Update); } else if (m_Parent is Item) { m_Location = value; ReleaseWorldPackets(); Delta(ItemDelta.Update); } else { m_Location = value; ReleaseWorldPackets(); } if (m_Parent == null) { m_Map.OnMove(oldLocation, this); } } else { m_Location = value; ReleaseWorldPackets(); } OnLocationChange(oldLocation); } } } [CommandProperty(AccessLevel.Counselor, AccessLevel.Decorator)] public int X { get { return m_Location.m_X; } set { Location = new Point3D(value, m_Location.m_Y, m_Location.m_Z); } } [CommandProperty(AccessLevel.Counselor, AccessLevel.Decorator)] public int Y { get { return m_Location.m_Y; } set { Location = new Point3D(m_Location.m_X, value, m_Location.m_Z); } } [CommandProperty(AccessLevel.Counselor, AccessLevel.Decorator)] public int Z { get { return m_Location.m_Z; } set { Location = new Point3D(m_Location.m_X, m_Location.m_Y, value); } } #endregion [CommandProperty(AccessLevel.Decorator)] public virtual int ItemID { get { return m_ItemID; } set { if (m_ItemID != value) { int oldPileWeight = PileWeight; m_ItemID = value; ReleaseWorldPackets(); int newPileWeight = PileWeight; UpdateTotal(this, TotalType.Weight, newPileWeight - oldPileWeight); UpdateLight(); InvalidateProperties(); Delta(ItemDelta.Update); } } } public virtual string DefaultName { get { return null; } } [CommandProperty(AccessLevel.Decorator)] public string Name { get { CompactInfo info = LookupCompactInfo(); if (info != null && info.m_Name != null) { return info.m_Name; } return DefaultName; } set { if (value == null || value != DefaultName) { CompactInfo info = AcquireCompactInfo(); info.m_Name = value; if (info.m_Name == null) { VerifyCompactInfo(); } InvalidateProperties(); } } } [CommandProperty(AccessLevel.GameMaster)] public virtual object Parent { get { return m_Parent; } set { if (m_Parent == value) { return; } var oldParent = m_Parent; m_Parent = value; OnParentChanged(oldParent); } } protected virtual void OnParentChanged(object oldParent) { if (m_Map != null) { if (oldParent != null && m_Parent == null) { m_Map.OnEnter(this); } else if (oldParent == null && m_Parent != null) { m_Map.OnLeave(this); } } if (!World.Loading) { if (oldParent is Item) { oldParent = ((Item)oldParent).RootParent; } var root = RootParent as Mobile; if (root != null && oldParent != root) { root.Obtained(this); } } } [CommandProperty(AccessLevel.Decorator)] public LightType Light { get { return m_Light; } set { if (m_Light != value) { m_Light = value; ReleaseWorldPackets(); Delta(ItemDelta.Update); } } } [CommandProperty(AccessLevel.Decorator)] public Direction Direction { get { return m_Direction; } set { if (m_Direction != value) { m_Direction = value; ReleaseWorldPackets(); Delta(ItemDelta.Update); } } } [CommandProperty(AccessLevel.GameMaster)] public int Amount { get { return m_Amount; } set { int oldValue = m_Amount; if (oldValue != value) { int oldPileWeight = PileWeight; m_Amount = value; ReleaseWorldPackets(); int newPileWeight = PileWeight; UpdateTotal(this, TotalType.Weight, newPileWeight - oldPileWeight); OnAmountChange(oldValue); Delta(ItemDelta.Update); if (oldValue > 1 || value > 1) { InvalidateProperties(); } if (!Stackable && m_Amount > 1) { Console.WriteLine( "Warning: 0x{0:X}: Amount changed for non-stackable item '{2}'. ({1})", m_Serial.Value, m_Amount, GetType().Name); } } } } protected virtual void OnAmountChange(int oldValue) { } public virtual bool HandlesOnSpeech { get { return false; } } public virtual void OnSpeech(SpeechEventArgs e) { } public virtual bool OnDroppedToMobile(Mobile from, Mobile target) { if (Nontransferable && from.Player && !from.IsStaff()) { HandleInvalidTransfer(from); return false; } return true; } public virtual bool DropToMobile(Mobile from, Mobile target, Point3D p) { if (Deleted || from.Deleted || target.Deleted || from.Map != target.Map || from.Map == null || target.Map == null) { return false; } else if (from.AccessLevel < AccessLevel.GameMaster && !from.InRange(target.Location, 2)) { return false; } else if (!from.CanSee(target) || !from.InLOS(target)) { return false; } else if (!from.OnDroppedItemToMobile(this, target)) { return false; } else if (!OnDroppedToMobile(from, target)) { return false; } else if (!target.OnDragDrop(from, this)) { return false; } else { return true; } } public virtual bool OnDroppedInto(Mobile from, Container target, Point3D p) { if (!from.OnDroppedItemInto(this, target, p)) { return false; } else if (Nontransferable && from.Player && target != from.Backpack) { HandleInvalidTransfer(from); return false; } return target.OnDragDropInto(from, this, p); } public virtual bool OnDroppedOnto(Mobile from, Item target) { if (Deleted || from.Deleted || target.Deleted || from.Map != target.Map || from.Map == null || target.Map == null) { return false; } else if (from.AccessLevel < AccessLevel.GameMaster && !from.InRange(target.GetWorldLocation(), 2)) { return false; } else if (!from.CanSee(target) || !from.InLOS(target)) { return false; } else if (!target.IsAccessibleTo(from)) { return false; } else if (!from.OnDroppedItemOnto(this, target)) { return false; } else if (Nontransferable && from.Player && target != from.Backpack && !from.IsStaff()) { HandleInvalidTransfer(from); return false; } else { return target.OnDragDrop(from, this); } } public virtual bool DropToItem(Mobile from, Item target, Point3D p) { if (Deleted || from.Deleted || target.Deleted || from.Map != target.Map || from.Map == null || target.Map == null) { return false; } var root = target.RootParent; if (from.AccessLevel < AccessLevel.GameMaster && !from.InRange(target.GetWorldLocation(), 2)) { return false; } else if (!from.CanSee(target) || !from.InLOS(target)) { return false; } else if (!target.IsAccessibleTo(from)) { return false; } else if (root is Mobile && !((Mobile)root).CheckNonlocalDrop(from, this, target)) { return false; } else if (!from.OnDroppedItemToItem(this, target, p)) { return false; } else if (target is Container && p.m_X != -1 && p.m_Y != -1) { return OnDroppedInto(from, (Container)target, p); } else { return OnDroppedOnto(from, target); } } public virtual bool OnDroppedToWorld(Mobile from, Point3D p) { if (Nontransferable && from.Player && !from.IsStaff()) { HandleInvalidTransfer(from); return false; } return true; } public virtual int GetLiftSound(Mobile from) { return 0x57; } private static int m_OpenSlots; public virtual bool DropToWorld(Mobile from, Point3D p) { if (Deleted || from.Deleted || from.Map == null) { return false; } else if (!from.InRange(p, 2)) { return false; } if (QuestItem) { from.SendLocalizedMessage(1074769); // An item must be in your backpack (and not in a container within) to be toggled as a quest item. return false; } Map map = from.Map; if (map == null) { return false; } Point3D dest = FindDropPoint(p, map, from.Z + 17); if (dest == Point3D.Zero) return false; if (!from.InLOS(new Point3D(dest.X, dest.Y, dest.Z + 1))) { return false; } else if (!from.OnDroppedItemToWorld(this, dest)) { return false; } else if (!OnDroppedToWorld(from, dest)) { return false; } int soundID = GetDropSound(); MoveToWorld(dest, from.Map); from.SendSound(soundID == -1 ? 0x42 : soundID, GetWorldLocation()); return true; } public bool DropToWorld(Point3D p, Map map) { Point3D dest = FindDropPoint(p, map, int.MaxValue); if (dest == Point3D.Zero) return false; MoveToWorld(dest, map); return true; } private Point3D FindDropPoint(Point3D p, Map map, int maxZ) { if (map == null) return Point3D.Zero; int myTop = -255; int x = p.m_X, y = p.m_Y; int z = int.MinValue; LandTile landTile = map.Tiles.GetLandTile(x, y); TileFlag landFlags = TileData.LandTable[landTile.ID & TileData.MaxLandValue].Flags; int landZ = 0, landAvg = 0, landTop = 0; map.GetAverageZ(x, y, ref landZ, ref landAvg, ref landTop); if (!landTile.Ignored && (landFlags & TileFlag.Impassable) == 0) { if (landAvg <= maxZ) { z = landAvg; } } var tiles = map.Tiles.GetStaticTiles(x, y, true); for (int i = 0; i < tiles.Length; ++i) { StaticTile tile = tiles[i]; ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; if (!id.Surface) { continue; } int top = tile.Z + id.CalcHeight; if (top > p.Z) myTop = top; if (top > maxZ || top < z) { continue; } z = top; } var items = new List(); var eable = map.GetItemsInRange(p, 0); foreach (Item item in eable) { if (item is BaseMulti || item.ItemID > TileData.MaxItemValue) { continue; } items.Add(item); ItemData id = item.ItemData; if (!id.Surface) { continue; } int top = item.Z + id.CalcHeight; if (top > p.Z) myTop = top; if (top > maxZ || top < z) { continue; } z = top; } eable.Free(); if (z == int.MinValue) { return Point3D.Zero; } if (z > maxZ) { return Point3D.Zero; } m_OpenSlots = (1 << 20) - 1; int surfaceZ = z; for (int i = 0; i < tiles.Length; ++i) { StaticTile tile = tiles[i]; ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; int checkZ = tile.Z; int checkTop = checkZ + id.CalcHeight; if (checkTop == checkZ && !id.Surface) { ++checkTop; } int zStart = checkZ - z; int zEnd = checkTop - z; if (zStart >= 20 || zEnd < 0) { continue; } if (zStart < 0) { zStart = 0; } if (zEnd > 19) { zEnd = 19; } int bitCount = zEnd - zStart; m_OpenSlots &= ~(((1 << bitCount) - 1) << zStart); } for (int i = 0; i < items.Count; ++i) { Item item = items[i]; ItemData id = item.ItemData; int checkZ = item.Z; int checkTop = checkZ + id.CalcHeight; if (checkTop == checkZ && !id.Surface) { ++checkTop; } int zStart = checkZ - z; int zEnd = checkTop - z; if (zStart >= 20 || zEnd < 0) { continue; } if (zStart < 0) { zStart = 0; } if (zEnd > 19) { zEnd = 19; } int bitCount = zEnd - zStart; m_OpenSlots &= ~(((1 << bitCount) - 1) << zStart); } int height = ItemData.Height; if (height == 0) { ++height; } if (height > 30) { height = 30; } /* if (myTop != -255) { int match = (1 << height) - 1; bool okay = false; for (int i = 0; i < 20; ++i) { if ((i + height) > 20) { match >>= 1; } okay = ((m_OpenSlots >> i) & match) == match; if (okay) { z += i; break; } } if (!okay) { return Point3D.Zero; } } */ height = ItemData.Height; if (height == 0) { ++height; } if (landAvg > z && (z + height) > landZ) { return Point3D.Zero; } else if ((landFlags & TileFlag.Impassable) != 0 && landAvg > surfaceZ && (z + height) > landZ) { return Point3D.Zero; } for (int i = 0; i < tiles.Length; ++i) { StaticTile tile = tiles[i]; ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; int checkZ = tile.Z; int checkTop = checkZ + id.CalcHeight; if (checkTop > z && (z + height) > checkZ) { return Point3D.Zero; } else if ((id.Surface || id.Impassable) && checkTop > surfaceZ && (z + height) > checkZ) { return Point3D.Zero; } } for (int i = 0; i < items.Count; ++i) { Item item = items[i]; ItemData id = item.ItemData; if (item.Z > p.Z + 17 || item.Z < p.Z) continue; z += id.CalcHeight; if (((item.Z + id.CalcHeight) >= maxZ) || (myTop != -255 && (item.Z + id.CalcHeight) > myTop)) /*&& (z + height) > item.Z)*/ { return Point3D.Zero; } } return new Point3D(x, y, z); } public void SendRemovePacket() { if (!Deleted && m_Map != null) { Point3D worldLoc = GetWorldLocation(); var eable = m_Map.GetClientsInRange(worldLoc, Core.GlobalRadarRange - 4); foreach (NetState state in eable) { Mobile m = state.Mobile; if (Utility.InRange(worldLoc, m.Location, GetUpdateRange(m))) { state.Send(RemovePacket); } } eable.Free(); } } public virtual int GetDropSound() { return -1; } public Point3D GetWorldLocation() { var root = RootParent; if (root == null) { return m_Location; } else { return ((IEntity)root).Location; } //return root == null ? m_Location : new Point3D( (IPoint3D) root ); } public virtual bool BlocksFit { get { return false; } } public Point3D GetSurfaceTop() { var root = RootParentEntity; if (root == null) { return new Point3D(m_Location.m_X, m_Location.m_Y, m_Location.m_Z + (ItemData.Surface ? ItemData.CalcHeight : 0)); } else { return root.Location; } } public Point3D GetWorldTop() { var root = RootParentEntity; if (root == null) { return new Point3D(m_Location.m_X, m_Location.m_Y, m_Location.m_Z + ItemData.CalcHeight); } else { return root.Location; } } public void SendLocalizedMessageTo(Mobile to, int number) { if (Deleted || !to.CanSee(this)) { return; } to.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", "")); } public void SendLocalizedMessageTo(Mobile to, int number, string args) { if (Deleted || !to.CanSee(this)) { return; } to.Send(new MessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", args)); } public void SendLocalizedMessage(int number, string args) { if (Deleted || Map == null) { return; } IPooledEnumerable eable = Map.GetClientsInRange(Location, Core.GlobalMaxUpdateRange); Packet p = Packet.Acquire(new MessageLocalized(m_Serial, m_ItemID, MessageType.Regular, 0x3B2, 3, number, Name, args)); foreach (NetState ns in eable) { ns.Send(p); } Packet.Release(p); eable.Free(); } public void SendLocalizedMessage(MessageType type, int number, AffixType affixType, string affix, string args) { IPooledEnumerable eable = Map.GetClientsInRange(Location, Core.GlobalMaxUpdateRange); Packet p = Packet.Acquire(new MessageLocalizedAffix(m_Serial, m_ItemID, type, 0x3B2, 3, number, "", affixType, affix, args)); foreach (NetState ns in eable) { ns.Send(p); } Packet.Release(p); eable.Free(); } public void SendLocalizedMessageTo(Mobile to, int number, AffixType affixType, string affix, string args) { if (Deleted || !to.CanSee(this)) { return; } to.Send(new MessageLocalizedAffix(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number, "", affixType, affix, args)); } #region OnDoubleClick[...] public virtual void OnDoubleClick(Mobile from) { } public virtual void OnDoubleClickOutOfRange(Mobile from) { } public virtual void OnDoubleClickCantSee(Mobile from) { } public virtual void OnDoubleClickDead(Mobile from) { from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019048); // I am dead and cannot do that. } public virtual void OnDoubleClickNotAccessible(Mobile from) { from.SendLocalizedMessage(500447); // That is not accessible. } public virtual void OnDoubleClickSecureTrade(Mobile from) { from.SendLocalizedMessage(500447); // That is not accessible. } #endregion public virtual void OnSnoop(Mobile from) { } public bool InSecureTrade { get { return (GetSecureTradeCont() != null); } } public SecureTradeContainer GetSecureTradeCont() { object p = this; while (p is Item) { if (p is SecureTradeContainer) { return (SecureTradeContainer)p; } p = ((Item)p).m_Parent; } return null; } public virtual void OnItemAdded(Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnSubItemAdded(item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).OnSubItemAdded(item); } } public virtual void OnItemRemoved(Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnSubItemRemoved(item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).OnSubItemRemoved(item); } } public virtual void OnSubItemAdded(Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnSubItemAdded(item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).OnSubItemAdded(item); } } public virtual void OnSubItemRemoved(Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnSubItemRemoved(item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).OnSubItemRemoved(item); } } public virtual void OnItemBounceCleared(Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnSubItemBounceCleared(item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).OnSubItemBounceCleared(item); } } public virtual void OnSubItemBounceCleared(Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnSubItemBounceCleared(item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).OnSubItemBounceCleared(item); } } public virtual bool CheckTarget(Mobile from, Target targ, object targeted) { if (m_Parent is Item) { return ((Item)m_Parent).CheckTarget(from, targ, targeted); } else if (m_Parent is Mobile) { return ((Mobile)m_Parent).CheckTarget(from, targ, targeted); } return true; } public virtual void OnStatsQuery(Mobile m) { if (m == null || m.Deleted || m.Map != Map || m.NetState == null) { return; } if (Utility.InUpdateRange(m, this) && m.CanSee(this)) { SendStatusTo(m.NetState); } } public virtual void SendStatusTo(NetState state) { var p = GetStatusPacketFor(state); if (p != null) { state.Send(p); } } public virtual Packet GetStatusPacketFor(NetState state) { if (this is IDamageable && state != null && state.Mobile != null && state.HighSeas) { return new MobileStatusCompact(CanBeRenamedBy(state.Mobile), (IDamageable)this); } return null; } public virtual bool CanBeRenamedBy(Mobile m) { return m != null && m.AccessLevel >= AccessLevel.GameMaster; } public virtual bool IsAccessibleTo(Mobile check) { if (m_Parent is Item) { return ((Item)m_Parent).IsAccessibleTo(check); } Region reg = Region.Find(GetWorldLocation(), m_Map); return reg.CheckAccessibility(this, check); } public bool IsChildOf(object o) { return IsChildOf(o, false); } public bool IsChildOf(object o, bool allowNull) { var p = m_Parent; if ((p == null || o == null) && !allowNull) { return false; } if (p == o) { return true; } while (p is Item) { Item item = (Item)p; if (item.m_Parent == null) { break; } else { p = item.m_Parent; if (p == o) { return true; } } } return false; } public ItemData ItemData { get { return TileData.ItemTable[m_ItemID & TileData.MaxItemValue]; } } public virtual void OnItemUsed(Mobile from, Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnItemUsed(from, item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).OnItemUsed(from, item); } } public bool CheckItemUse(Mobile from) { return CheckItemUse(from, this); } public virtual bool CheckItemUse(Mobile from, Item item) { if (m_Parent is Item) { return ((Item)m_Parent).CheckItemUse(from, item); } else if (m_Parent is Mobile) { return ((Mobile)m_Parent).CheckItemUse(from, item); } else { return true; } } public virtual void OnItemLifted(Mobile from, Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnItemLifted(from, item); } else if (m_Parent is Mobile) { ((Mobile)m_Parent).OnItemLifted(from, item); } } public bool CheckLift(Mobile from) { LRReason reject = LRReason.Inspecific; return CheckLift(from, this, ref reject); } public virtual bool CheckLift(Mobile from, Item item, ref LRReason reject) { if (m_Parent is Item) { return ((Item)m_Parent).CheckLift(from, item, ref reject); } else if (m_Parent is Mobile) { return ((Mobile)m_Parent).CheckLift(from, item, ref reject); } else { return true; } } public virtual bool CanTarget { get { return true; } } public virtual bool DisplayLootType { get { return true; } } public virtual void OnSingleClickContained(Mobile from, Item item) { if (m_Parent is Item) { ((Item)m_Parent).OnSingleClickContained(from, item); } } public virtual void OnAosSingleClick(Mobile from) { ObjectPropertyList opl = PropertyList; if (opl.Header > 0) { from.Send(new MessageLocalized(m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, opl.Header, Name, opl.HeaderArgs)); } } public virtual void OnSingleClick(Mobile from) { if (Deleted || !from.CanSee(this)) { return; } if (DisplayLootType) { LabelLootTypeTo(from); } NetState ns = from.NetState; if (ns != null) { if (Name == null) { if (m_Amount <= 1) { ns.Send(new MessageLocalized(m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, LabelNumber, "", "")); } else { ns.Send( new MessageLocalizedAffix( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, LabelNumber, "", AffixType.Append, String.Format(" : {0}", m_Amount), "")); } } else { ns.Send( new UnicodeMessage( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, "ENU", "", Name + (m_Amount > 1 ? " : " + m_Amount : ""))); } } } private static bool m_ScissorCopyLootType; public static bool ScissorCopyLootType { get { return m_ScissorCopyLootType; } set { m_ScissorCopyLootType = value; } } public virtual void ScissorHelper(Mobile from, Item newItem, int amountPerOldItem) { ScissorHelper(from, newItem, amountPerOldItem, true); } public virtual void ScissorHelper(Mobile from, Item newItem, int amountPerOldItem, bool carryHue) { int amount = Amount; if (amount > (60000 / amountPerOldItem)) // let's not go over 60000 { amount = (60000 / amountPerOldItem); } Amount -= amount; int ourHue = Hue; Map thisMap = Map; var thisParent = m_Parent; Point3D worldLoc = GetWorldLocation(); LootType type = LootType; if (Amount == 0) { Delete(); } newItem.Amount = amount * amountPerOldItem; if (carryHue) { newItem.Hue = ourHue; } if (m_ScissorCopyLootType) { newItem.LootType = type; } if (!(thisParent is Container) || !((Container)thisParent).TryDropItem(from, newItem, false)) { newItem.MoveToWorld(worldLoc, thisMap); } } public virtual void Consume() { Consume(1); } public virtual void Consume(int amount) { Amount -= amount; if (Amount <= 0) { Delete(); } } public virtual void ReplaceWith(Item newItem) { if (m_Parent is Container) { ((Container)m_Parent).AddItem(newItem); newItem.Location = m_Location; } else { newItem.MoveToWorld(GetWorldLocation(), m_Map); } Delete(); } [CommandProperty(AccessLevel.GameMaster)] public bool QuestItem { get { return GetFlag(ImplFlag.QuestItem); } set { SetFlag(ImplFlag.QuestItem, value); InvalidateProperties(); ReleaseWorldPackets(); Delta(ItemDelta.Update); } } public bool Insured { get { return GetFlag(ImplFlag.Insured); } set { SetFlag(ImplFlag.Insured, value); InvalidateProperties(); } } public bool PayedInsurance { get { return GetFlag(ImplFlag.PayedInsurance); } set { SetFlag(ImplFlag.PayedInsurance, value); } } public Mobile BlessedFor { get { CompactInfo info = LookupCompactInfo(); if (info != null) { return info.m_BlessedFor; } return null; } set { CompactInfo info = AcquireCompactInfo(); info.m_BlessedFor = value; if (info.m_BlessedFor == null) { VerifyCompactInfo(); } InvalidateProperties(); } } public virtual bool CheckBlessed(object o) { return CheckBlessed(o as Mobile); } public virtual bool CheckBlessed(Mobile m) { if (m_LootType == LootType.Blessed || (Mobile.InsuranceEnabled && Insured)) { return true; } return (m != null && m == BlessedFor); } public virtual bool CheckNewbied() { return (m_LootType == LootType.Newbied); } public virtual bool IsStandardLoot() { if (Mobile.InsuranceEnabled && Insured) { return false; } if (BlessedFor != null) { return false; } return (m_LootType == LootType.Regular); } public override string ToString() { return String.Format("0x{0:X} \"{1}\"", m_Serial.Value, GetType().Name); } internal int m_TypeRef; public Item() { m_Serial = Serial.NewItem; m_Map = Map.Internal; m_Light = LightType.Empty; m_Amount = 1; Visible = true; Movable = true; SetLastMoved(); World.AddItem(this); Type ourType = GetType(); m_TypeRef = World.m_ItemTypes.IndexOf(ourType); if (m_TypeRef == -1) { World.m_ItemTypes.Add(ourType); m_TypeRef = World.m_ItemTypes.Count - 1; } Timer.DelayCall(EventSink.InvokeItemCreated, new ItemCreatedEventArgs(this)); } [Constructable] public Item(int itemID) : this() { m_ItemID = itemID; UpdateLight(); } public Item(Serial serial) { m_Serial = serial; Type ourType = GetType(); m_TypeRef = World.m_ItemTypes.IndexOf(ourType); if (m_TypeRef == -1) { World.m_ItemTypes.Add(ourType); m_TypeRef = World.m_ItemTypes.Count - 1; } } public virtual void UpdateLight() { var data = ItemData; if (!data.Flags.HasFlag(TileFlag.LightSource)) { return; } if (m_Light == LightType.Empty) { var light = data.Quality; if (light >= 0 && light <= 255) { m_Light = (LightType)light; } } } public virtual void OnSectorActivate() { } public virtual void OnSectorDeactivate() { } #region Item Sockets public List Sockets { get; private set; } public void AttachSocket(ItemSocket socket) { if(Sockets == null) { Sockets = new List(); } Sockets.Add(socket); socket.Owner = this; InvalidateProperties(); } public bool RemoveSocket() { var socket = GetSocket(typeof(T)); if (socket != null) { RemoveItemSocket(socket); return true; } return false; } public void RemoveItemSocket(ItemSocket socket) { if (Sockets == null) { return; } Sockets.Remove(socket); socket.OnRemoved(); if (Sockets.Count == 0) { Sockets = null; } InvalidateProperties(); } public T GetSocket() where T : ItemSocket { if (Sockets == null) { return null; } return Sockets.FirstOrDefault(s => s.GetType() == typeof(T)) as T; } public T GetSocket(Func predicate) where T : ItemSocket { if (Sockets == null) { return null; } return Sockets.FirstOrDefault(s => s.GetType() == typeof(T) && (predicate == null || predicate(s as T))) as T; } public ItemSocket GetSocket(Type type) { if (Sockets == null) { return null; } return Sockets.FirstOrDefault(s => s.GetType() == type); } public bool HasSocket() { if (Sockets == null) { return false; } return Sockets.Any(s => s.GetType() == typeof(T)); } public bool HasSocket(Type t) { if (Sockets == null) { return false; } return Sockets.Any(s => s.GetType() == t); } #endregion } public class ItemSocket { [CommandProperty(AccessLevel.GameMaster)] public Item Owner { get; set; } [CommandProperty(AccessLevel.GameMaster)] public DateTime Expires { get; set; } public virtual TimeSpan TickDuration { get { return TimeSpan.FromMinutes(1); } } public Timer Timer { get; set; } public ItemSocket() : this(TimeSpan.Zero) { } public ItemSocket(TimeSpan duration) { if(duration != TimeSpan.Zero) { Expires = DateTime.UtcNow + duration; BeginTimer(); } } protected void BeginTimer() { EndTimer(); Timer = Timer.DelayCall(TickDuration, TickDuration, OnTick); Timer.Start(); } protected void EndTimer() { if(Timer != null) { Timer.Stop(); Timer = null; } } protected virtual void OnTick() { if(Expires < DateTime.UtcNow || Owner.Deleted) { Remove(); } } public virtual void Remove() { EndTimer(); Owner.RemoveItemSocket(this); } public virtual void OnRemoved() { } public virtual void GetProperties(ObjectPropertyList list) { } public virtual void OnOwnerDuped(Item newItem) { ItemSocket newSocket = null; try { newSocket = Activator.CreateInstance(GetType()) as ItemSocket; } catch { Console.WriteLine( "Warning: 0x{0:X}: Item socket must have a zero paramater constructor to be separated from a stack. '{1}'.", Owner.Serial.Value, GetType().Name); } if (newSocket != null) { newSocket.Expires = Expires; if (newSocket.Expires != DateTime.MinValue) { newSocket.BeginTimer(); } newSocket.OnAfterDuped(this); newItem.AttachSocket(newSocket); } } public virtual void OnAfterDuped(ItemSocket oldSocket) { } public virtual void Serialize(GenericWriter writer) { writer.Write(0); writer.Write(Expires); } public virtual void Deserialize(Item owner, GenericReader reader) { reader.ReadInt(); // version Expires = reader.ReadDateTime(); if(Expires != DateTime.MinValue) { if(Expires < DateTime.UtcNow) { return; } else { BeginTimer(); } } owner.AttachSocket(this); } public static void Save(ItemSocket socket, GenericWriter writer) { writer.Write(socket.GetType().Name); socket.Serialize(writer); } public static void Load(Item item, GenericReader reader) { var typeName = ScriptCompiler.FindTypeByName(reader.ReadString()); var socket = Activator.CreateInstance(typeName) as ItemSocket; socket.Deserialize(item, reader); } } }