/*************************************************************************** * Item.cs * ------------------- * begin : May 1, 2002 * copyright : (C) The RunUO Software Team * email : info@runuo.com * * $Id: Item.cs 274 2007-12-17 20:41:34Z mark $ * ***************************************************************************/ /*************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * ***************************************************************************/ using System; using System.IO; using System.Collections; using System.Collections.Generic; using Server.Network; using Server.Items; using Server.ContextMenus; 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, /// /// Unused. /// Unused_xF = 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, /// /// Last valid layer. Equivalent to Layer.Bank. /// LastValid = 0x1D } /// /// 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, /// /// Medium circular shape. /// Circle225, /// /// Small circular shape. /// Circle150, /// /// Door shape, shining south. /// DoorSouth, /// /// Door shape, shining east. /// DoorEast, /// /// Large semicircular shape (180 degrees), north wall. /// NorthBig, /// /// Large pie shape (90 degrees), north-east corner. /// NorthEastBig, /// /// Large semicircular shape (180 degrees), east wall. /// EastBig, /// /// Large semicircular shape (180 degrees), west wall. /// WestBig, /// /// Large pie shape (90 degrees), south-west corner. /// SouthWestBig, /// /// Large semicircular shape (180 degrees), south wall. /// SouthBig, /// /// Medium semicircular shape (180 degrees), north wall. /// NorthSmall, /// /// Medium pie shape (90 degrees), north-east corner. /// NorthEastSmall, /// /// Medium semicircular shape (180 degrees), east wall. /// EastSmall, /// /// Medium semicircular shape (180 degrees), west wall. /// WestSmall, /// /// Medium semicircular shape (180 degrees), south wall. /// SouthSmall, /// /// Shaped like a wall decoration, north wall. /// DecorationNorth, /// /// Shaped like a wall decoration, north-east corner. /// DecorationNorthEast, /// /// Small semicircular shape (180 degrees), east wall. /// EastTiny, /// /// Shaped like a wall decoration, west wall. /// DecorationWest, /// /// Shaped like a wall decoration, south-west corner. /// DecorationSouthWest, /// /// Small semicircular shape (180 degrees), south wall. /// SouthTiny, /// /// Window shape, rectangular, no ray, shining south. /// RectWindowSouthNoRay, /// /// Window shape, rectangular, no ray, shining east. /// RectWindowEastNoRay, /// /// Window shape, rectangular, ray shining south. /// RectWindowSouth, /// /// Window shape, rectangular, ray shining east. /// RectWindowEast, /// /// Window shape, arched, no ray, shining south. /// ArchedWindowSouthNoRay, /// /// Window shape, arched, no ray, shining east. /// ArchedWindowEastNoRay, /// /// Window shape, arched, ray shining south. /// ArchedWindowSouth, /// /// Large circular shape. /// Circle300, /// /// Large pie shape (90 degrees), north-west corner. /// NorthWestBig, /// /// Negative light. Medium pie shape (90 degrees), south-east corner. /// DarkSouthEast, /// /// Negative light. Medium semicircular shape (180 degrees), south wall. /// DarkSouth, /// /// Negative light. Medium pie shape (90 degrees), north-west corner. /// DarkNorthWest, /// /// Negative light. Medium pie shape (90 degrees), south-east corner. Equivalent to LightType.SouthEast. /// DarkSouthEast2, /// /// Negative light. Medium circular shape (180 degrees), east wall. /// DarkEast, /// /// Negative light. Large circular shape. /// DarkCircle300, /// /// Opened door shape, shining south. /// DoorOpenSouth, /// /// Opened door shape, shining east. /// DoorOpenEast, /// /// Window shape, square, ray shining east. /// SquareWindowEast, /// /// Window shape, square, no ray, shining east. /// SquareWindowEastNoRay, /// /// Window shape, square, ray shining south. /// SquareWindowSouth, /// /// Window shape, square, no ray, shining south. /// SquareWindowSouthNoRay, /// /// Empty. /// Empty, /// /// Window shape, skinny, no ray, shining south. /// SkinnyWindowSouthNoRay, /// /// Window shape, skinny, ray shining east. /// SkinnyWindowEast, /// /// Window shape, skinny, no ray, shining east. /// SkinnyWindowEastNoRay, /// /// Shaped like a hole, shining south. /// HoleSouth, /// /// Shaped like a hole, shining south. /// HoleEast, /// /// Large circular shape with a moongate graphic embeded. /// Moongate, /// /// Unknown usage. Many rows of slightly angled lines. /// Strips, /// /// Shaped like a small hole, shining south. /// SmallHoleSouth, /// /// Shaped like a small hole, shining east. /// SmallHoleEast, /// /// Large semicircular shape (180 degrees), north wall. Identical graphic as LightType.NorthBig, but slightly different positioning. /// NorthBig2, /// /// Large semicircular shape (180 degrees), west wall. Identical graphic as LightType.WestBig, but slightly different positioning. /// WestBig2, /// /// Large pie shape (90 degrees), north-west corner. Equivalent to LightType.NorthWestBig. /// NorthWestBig2 } /// /// 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 BounceInfo( Item item ) { m_Map = item.Map; m_Location = item.Location; m_WorldLoc = item.GetWorldLocation(); m_Parent = item.Parent; } private BounceInfo( Map map, Point3D loc, Point3D worldLoc, object parent ) { m_Map = map; m_Location = loc; m_WorldLoc = worldLoc; m_Parent = parent; } public static BounceInfo Deserialize( GenericReader reader ) { if ( reader.ReadBool() ) { Map map = reader.ReadMap(); Point3D loc = reader.ReadPoint3D(); Point3D worldLoc = reader.ReadPoint3D(); object 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, } public enum ExpandFlag { None = 0x00, Name = 0x01, Items = 0x02, Bounce = 0x04, Holder = 0x08, Blessed = 0x10, TempFlag = 0x20, SaveFlag = 0x40, Weight = 0x80 } public class Item : IEntity, IHued, IComparable, ISerializable { 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 this.CompareTo( (IEntity) other ); } public int CompareTo( object other ) { if ( other == null || other is IEntity ) return this.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; #endregion private ItemDelta m_DeltaFlags; private ImplFlag m_Flags; #region Packet caches private Packet m_WorldPacket; 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(); } } [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 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_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_TempFlags != 0 ) || ( info.m_SavedFlags != 0 ) || ( info.m_Weight != -1 ); if ( !isValid ) ReleaseCompactInfo(); } public List LookupItems() { if ( this is Container ) return ( this as Container ).m_Items; CompactInfo info = LookupCompactInfo(); if ( info != null ) return info.m_Items; return null; } public List AcquireItems() { if ( this is Container ) { Container cont = this as Container; if ( cont.m_Items == null ) { cont.m_Items = new List(); } return cont.m_Items; } CompactInfo info = AcquireCompactInfo(); info.m_Items = new List(); return info.m_Items; } #region Mondain's Legacy private Item m_DupeSource; public Item DupeSource { get { return m_DupeSource; } set { m_DupeSource = value; } } public static System.Drawing.Bitmap GetBitmap( int itemID ) { try { return Ultima.Art.GetStatic( itemID ); } catch ( Exception e ) { Console.WriteLine( e.ToString() ); } return null; } public static void Measure( System.Drawing.Bitmap bmp, out int xMin, out int yMin, out int xMax, out int yMax ) { try { Ultima.Art.Measure( bmp, out xMin, out yMin, out xMax, out yMax ); } catch ( Exception e ) { Console.WriteLine( e.ToString() ); xMin = yMin = xMax = yMax = 0; } } #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() { CompactInfo info = AcquireCompactInfo(); info.m_Bounce = new BounceInfo( this ); } 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 = this.Name; if ( name == null ) { 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 ( 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. Displays cliloc 1072788-1072789. /// public virtual void AddWeightProperty( ObjectPropertyList list ) { int weight = this.PileWeight + this.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 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 ); Mobile blessedFor = this.BlessedFor; if ( blessedFor != null && !blessedFor.Deleted ) AddBlessedForProperty( list, blessedFor ); if ( DisplayLootType ) AddLootTypeProperty( list ); if ( DisplayWeight ) AddWeightProperty( list ); if( QuestItem ) AddQuestItemProperty( list ); AppendChildNameProperties( list ); } /// /// 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~ } /// /// 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 ); } /// /// 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 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 = this.GetBounce(); if ( bounce != null ) { object parent = bounce.m_Parent; if ( parent is Item && !((Item)parent).Deleted ) { Item p = (Item)parent; object 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 ); } 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 ); } public virtual bool VerifyMove( Mobile from ) { return Movable; } 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 ) { Packet remPacket = null; IPooledEnumerable eable = m_Map.GetClientsInRange( oldLocation, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.InRange( oldLocation, GetUpdateRange( m ) ) ) { if ( remPacket == null ) remPacket = this.RemovePacket; state.Send( remPacket ); } } eable.Free(); } } m_Location = location; this.OnLocationChange( oldRealLocation ); Packet.Release( ref m_WorldPacket ); List 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 ) { IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( 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 ) { Packet removeThis = null; eable = m_Map.GetClientsInRange( oldLocation, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( !m.InRange( location, GetUpdateRange( m ) ) ) { if ( removeThis == null ) removeThis = this.RemovePacket; state.Send( removeThis ); } } eable.Free(); } Point3D oldInternalLocation = m_Location; m_Location = location; this.OnLocationChange( oldRealLocation ); Packet.Release( ref m_WorldPacket ); eable = m_Map.GetClientsInRange( m_Location, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( m_Location, GetUpdateRange( m ) ) ) SendInfoTo( state ); } eable.Free(); m_Map.OnMove( oldInternalLocation, this ); RemDelta( ItemDelta.Update ); } else { Map = map; Location = location; } } /// /// 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(); } } } private static TimeSpan m_DDT = TimeSpan.FromHours( 1.0 ); public static TimeSpan DefaultDecayTime{ get{ return m_DDT; } set{ m_DDT = value; } } [CommandProperty( AccessLevel.GameMaster )] public virtual TimeSpan DecayTime { get { return m_DDT; } } [CommandProperty( AccessLevel.GameMaster )] public virtual bool Decays { get { return (Movable && Visible); } } public virtual bool OnDecay() { return ( Decays && Parent == null && Map != Map.Internal && Region.Find( Location, Map ).OnDecay( this ) ); } public void SetLastMoved() { m_LastMovedTime = DateTime.Now; } public DateTime LastMoved { get { return m_LastMovedTime; } set { m_LastMovedTime = value; } } public bool StackWith( Mobile from, Item dropped ) { return StackWith( from, dropped, true ); } public virtual bool StackWith( Mobile from, Item dropped, bool playSound ) { if ( dropped.Stackable && Stackable && dropped.GetType() == GetType() && dropped.ItemID == ItemID && dropped.Hue == Hue && dropped.Name == Name && (dropped.Amount + Amount) <= 60000 ) { 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 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.GameMaster )] public bool Stackable { get{ return GetFlag( ImplFlag.Stackable ); } set{ SetFlag( ImplFlag.Stackable, value ); } } public Packet RemovePacket { get { if ( m_RemovePacket == null ) { m_RemovePacket = new RemoveItem( this ); m_RemovePacket.SetStatic(); } return m_RemovePacket; } } public Packet OPLPacket { get { 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(); } } 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 ) { m_WorldPacket = new WorldItem( this ); m_WorldPacket.SetStatic(); } return m_WorldPacket; } } [CommandProperty( AccessLevel.GameMaster )] public bool Visible { get{ return GetFlag( ImplFlag.Visible ); } set { if ( GetFlag( ImplFlag.Visible ) != value ) { SetFlag( ImplFlag.Visible, value ); Packet.Release( ref m_WorldPacket ); if ( m_Map != null ) { Packet removeThis = null; Point3D worldLoc = GetWorldLocation(); IPooledEnumerable eable = m_Map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( !m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) { if ( removeThis == null ) removeThis = this.RemovePacket; state.Send( removeThis ); } } eable.Free(); } Delta( ItemDelta.Update ); } } } [CommandProperty( AccessLevel.GameMaster )] public bool Movable { get{ return GetFlag( ImplFlag.Movable ); } set { if ( GetFlag( ImplFlag.Movable ) != value ) { SetFlag( ImplFlag.Movable, value ); Packet.Release( ref m_WorldPacket ); Delta( ItemDelta.Update ); } } } public virtual bool ForceShowProperties{ get{ return false; } } 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.GameMaster )] 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(); } List 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 ); this.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, DupeSource = 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( 9 ); // version 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; } } CompactInfo info = LookupCompactInfo(); List items = LookupItems(); if ( m_DupeSource != null ) flags |= SaveFlag.DupeSource; if ( m_Direction != Direction.North ) flags |= SaveFlag.Direction; 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 ( m_InsuredFor != null && !m_InsuredFor.Deleted ) //flags |= SaveFlag.InsuredFor; 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; #region Mondain's Legacy version 10 if ( m_DupeSource != null ) flags |= SaveFlag.DupeSource; #endregion 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; } } ImplFlag 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.Now.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 */ #region Mondain's Legacy version 10 if ( GetSaveFlag( flags, SaveFlag.DupeSource ) ) writer.Write( (Item) m_DupeSource ); #endregion if ( GetSaveFlag( flags, SaveFlag.Direction ) ) writer.Write( (byte) m_Direction ); if ( GetSaveFlag( flags, SaveFlag.Bounce ) ) 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( (int) m_ItemID ); if ( GetSaveFlag( flags, SaveFlag.Hue ) ) writer.WriteEncodedInt( (int) m_Hue ); if ( GetSaveFlag( flags, SaveFlag.Amount ) ) writer.WriteEncodedInt( (int) m_Amount ); if ( GetSaveFlag( flags, SaveFlag.Layer ) ) writer.Write( (byte) m_Layer ); if ( GetSaveFlag( flags, SaveFlag.Name ) ) writer.Write( (string) 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( (int) 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( (double) info.m_Weight ); if ( GetSaveFlag( flags, SaveFlag.Map ) ) writer.Write( (Map) 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 Server.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 Server.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 Server.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 Server.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(); } } public bool IsSecure { get{ return GetTempFlag( m_SecureFlag ); } set{ SetTempFlag( m_SecureFlag, value ); InvalidateProperties(); } } 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 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.Now - TimeSpan.FromMinutes( minutes ); } catch{ LastMoved = DateTime.Now; } } #region Mondain's Legacy if ( GetSaveFlag( flags, SaveFlag.DupeSource ) ) m_DupeSource = reader.ReadItem(); #endregion 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(); 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 != this.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 ) ) { List 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 != this.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 ) ) { List 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 != this.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 ) { List 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 ( this.HeldBy != null ) Timer.DelayCall( TimeSpan.Zero, new TimerCallback( FixHolding_Sandbox ) ); //if ( version < 9 ) VerifyCompactInfo(); } private void FixHolding_Sandbox() { Mobile heldBy = this.HeldBy; if ( heldBy != null ) { if ( this.GetBounce() != null ) { Bounce( heldBy ); } else { heldBy.Holding = null; heldBy.AddToBackpack( this ); ClearBounce(); } } } public virtual int GetMaxUpdateRange() { return 18; } public virtual int GetUpdateRange( Mobile m ) { return 18; } public void SendInfoTo( NetState state ) { SendInfoTo( state, ObjectPropertyList.Enabled ); } public virtual void SendInfoTo( NetState state, bool sendOplPacket ) { state.Send( GetWorldPacketFor( state ) ); if ( sendOplPacket ) { state.Send( OPLPacket ); } } protected virtual Packet GetWorldPacketFor( NetState state ) { return this.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 ( this.HeldBy != null ) ( this.HeldBy as Mobile ).UpdateTotal( sender, type, delta ); } } public virtual void UpdateTotals() { } public virtual int LabelNumber { get { return 1020000 + (m_ItemID & 0x3FFF); } } [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 >= 0x4000 ) 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 this.DefaultWeight; } set { if ( this.Weight != value ) { CompactInfo info = AcquireCompactInfo(); int oldPileWeight = this.PileWeight; info.m_Weight = value; if ( info.m_Weight == -1 ) VerifyCompactInfo(); int newPileWeight = this.PileWeight; UpdateTotal( this, TotalType.Weight, newPileWeight - oldPileWeight ); InvalidateProperties(); } } } [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] public int PileWeight { get { return (int)Math.Ceiling( this.Weight * this.Amount ); } } public virtual int HuedItemID { get { return ( m_ItemID & 0x3FFF ); } } [Hue, CommandProperty( AccessLevel.GameMaster )] public virtual int Hue { get { return (QuestItem ? QuestItemHue : m_Hue); } set { if ( m_Hue != value ) { m_Hue = value; Packet.Release( ref m_WorldPacket ); Delta( ItemDelta.Update ); } } } public virtual int QuestItemHue { get { return 0x04EA; } //HMMMM... For EA? } public virtual bool Nontransferable { get { return QuestItem; } } public virtual void HandleInvalidTransfer( Mobile from ) { 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. } [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 { List items = LookupItems(); if( items == null ) items = EmptyItems; return items; } } public object RootParent { get { object 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 { object 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}] )", this.Serial.Value, this.GetType().Name, item.Serial.Value, item.GetType().Name ); Console.WriteLine( new System.Diagnostics.StackTrace() ); return; } else if ( IsChildOf( item ) ) { Console.WriteLine( "Warning: Adding parent item to child: [0x{0:X} {1}].AddItem( [0x{2:X} {3}] )", this.Serial.Value, this.GetType().Name, item.Serial.Value, item.GetType().Name ); Console.WriteLine( new System.Diagnostics.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; List 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 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 ); } } 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.IsPost6017 ) ns.Send( new ContainerContentUpdate6017( this ) ); else ns.Send( new ContainerContentUpdate( this ) ); if ( ObjectPropertyList.Enabled ) ns.Send( OPLPacket ); } } } SecureTradeContainer stc = this.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.IsPost6017 ) ns.Send( new ContainerContentUpdate6017( this ) ); else ns.Send( new ContainerContentUpdate( this ) ); if ( ObjectPropertyList.Enabled ) ns.Send( OPLPacket ); } } } } } List openers = contParent.Openers; if ( openers != null ) { 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 ) { if ( mob.CanSee( this ) ) { if ( ns.IsPost6017 ) ns.Send( new ContainerContentUpdate6017( this ) ); else ns.Send( new ContainerContentUpdate( this ) ); if ( ObjectPropertyList.Enabled ) ns.Send( OPLPacket ); } } } } if ( openers.Count == 0 ) contParent.Openers = null; } return; } } if ( (flags & ItemDelta.Update) != 0 ) { Packet p = null; Point3D worldLoc = GetWorldLocation(); IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) { if ( m_Parent == null ) { SendInfoTo( state, ObjectPropertyList.Enabled ); } else { if ( p == null ) { if ( m_Parent is Item ) { if ( state.IsPost6017 ) 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 ( ObjectPropertyList.Enabled ) { 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(); IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) { //if ( sendOPLUpdate ) // state.Send( RemovePacket ); if ( p == null ) p = Packet.Acquire( new EquipUpdate( this ) ); state.Send( p ); if ( ObjectPropertyList.Enabled ) state.Send( OPLPacket ); } } Packet.Release( p ); eable.Free(); sendOPLUpdate = false; } } if ( sendOPLUpdate ) { Point3D worldLoc = GetWorldLocation(); IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) state.Send( OPLPacket ); } eable.Free(); } } } public static void ProcessDeltaQueue() { int count = m_DeltaQueue.Count; for ( int i = 0; i < m_DeltaQueue.Count; ++i ) { m_DeltaQueue[i].ProcessDelta(); if ( i >= count ) break; } if ( m_DeltaQueue.Count > 0 ) m_DeltaQueue.Clear(); } public virtual void OnDelete() { if ( m_Spawner != null ) { m_Spawner.Remove( this ); m_Spawner = null; } } public virtual void OnParentDeleted( object parent ) { this.Delete(); } public virtual void FreeCache() { Packet.Release( ref m_RemovePacket ); Packet.Release( ref m_WorldPacket ); Packet.Release( ref m_OPLPacket ); Packet.Release( ref m_PropertyList ); } public virtual void Delete() { if ( Deleted ) return; else if ( !World.OnDelete( this ) ) return; OnDelete(); List 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(); IPooledEnumerable eable = m_Map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) { if ( p == null ) { if ( ascii ) p = new AsciiMessage( m_Serial, m_ItemID, type, hue, 3, this.Name, text ); else p = new UnicodeMessage( m_Serial, m_ItemID, type, hue, 3, "ENU", this.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(); IPooledEnumerable eable = m_Map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) { if ( p == null ) p = Packet.Acquire( new MessageLocalized( m_Serial, m_ItemID, type, hue, 3, number, this.Name, args ) ); state.Send( p ); } } Packet.Release( p ); eable.Free(); } } public virtual void OnAfterDelete() { } public virtual void RemoveItem( Item item ) { List items = LookupItems(); if ( items != null && items.Contains( item ) ) { item.SendRemovePacket(); items.Remove( 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.Parent = null; item.OnRemoved( this ); OnItemRemoved( item ); } } public virtual void OnAfterDuped( Item newItem ) { } public virtual bool OnDragLift( Mobile from ) { return true; } public virtual bool OnEquip( Mobile from ) { return true; } private ISpawner m_Spawner; public ISpawner Spawner{ get{ return m_Spawner; } set{ m_Spawner = value; } } 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 { IEntity p = Parent as IEntity; return p; } } [CommandProperty( AccessLevel.GameMaster )] public IEntity RootParentEntity { get { IEntity p = RootParent as IEntity; return p; } } #region Location Location Location! public virtual void OnLocationChange( Point3D oldLocation ) { } [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] 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 ) { Packet removeThis = null; eable = m_Map.GetClientsInRange( oldLocation, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( !m.InRange( value, GetUpdateRange( m ) ) ) { if ( removeThis == null ) removeThis = this.RemovePacket; state.Send( removeThis ); } } eable.Free(); } m_Location = value; Packet.Release( ref m_WorldPacket ); SetLastMoved(); eable = m_Map.GetClientsInRange( m_Location, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( m_Location, GetUpdateRange( m ) ) ) SendInfoTo( state ); } eable.Free(); RemDelta( ItemDelta.Update ); } else if ( m_Parent is Item ) { m_Location = value; Packet.Release( ref m_WorldPacket ); Delta( ItemDelta.Update ); } else { m_Location = value; Packet.Release( ref m_WorldPacket ); } if ( m_Parent == null ) m_Map.OnMove( oldLocation, this ); } else { m_Location = value; Packet.Release( ref m_WorldPacket ); } this.OnLocationChange( oldLocation ); } } } [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] 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.GameMaster )] 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.GameMaster )] 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.GameMaster )] public virtual int ItemID { get { return m_ItemID; } set { if ( m_ItemID != value ) { int oldPileWeight = this.PileWeight; m_ItemID = value; Packet.Release( ref m_WorldPacket ); int newPileWeight = this.PileWeight; UpdateTotal( this, TotalType.Weight, newPileWeight - oldPileWeight ); InvalidateProperties(); Delta( ItemDelta.Update ); } } } public virtual string DefaultName { get { return null; } } [CommandProperty( AccessLevel.GameMaster )] public string Name { get { CompactInfo info = LookupCompactInfo(); if ( info != null && info.m_Name != null ) return info.m_Name; return this.DefaultName; } set { if ( value == null || value != DefaultName ) { CompactInfo info = AcquireCompactInfo(); info.m_Name = value; if ( info.m_Name == null ) VerifyCompactInfo(); InvalidateProperties(); } } } public virtual object Parent { get { return m_Parent; } set { if ( m_Parent == value ) return; object oldParent = m_Parent; m_Parent = value; if ( m_Map != null ) { if ( oldParent != null && m_Parent == null ) m_Map.OnEnter( this ); else if ( m_Parent != null ) m_Map.OnLeave( this ); } } } [CommandProperty( AccessLevel.GameMaster )] public LightType Light { get { return (LightType)m_Direction; } set { if ( (LightType)m_Direction != value ) { m_Direction = (Direction)value; Packet.Release( ref m_WorldPacket ); Delta( ItemDelta.Update ); } } } [CommandProperty( AccessLevel.GameMaster )] public Direction Direction { get { return m_Direction; } set { if ( m_Direction != value ) { m_Direction = value; Packet.Release( ref m_WorldPacket ); Delta( ItemDelta.Update ); } } } [CommandProperty( AccessLevel.GameMaster )] public int Amount { get { return m_Amount; } set { int oldValue = m_Amount; if ( oldValue != value ) { int oldPileWeight = this.PileWeight; m_Amount = value; Packet.Release( ref m_WorldPacket ); int newPileWeight = this.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.AccessLevel <= AccessLevel.GameMaster ) { 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 && from.AccessLevel <= AccessLevel.GameMaster ) { 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 && from.AccessLevel <= AccessLevel.GameMaster ) { 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; object 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.AccessLevel <= AccessLevel.GameMaster ) { 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; Map map = from.Map; if ( map == null ) return false; int x = p.m_X, y = p.m_Y; int z = int.MinValue; int maxZ = from.Z + 16; Tile landTile = map.Tiles.GetLandTile( x, y ); TileFlag landFlags = TileData.LandTable[landTile.ID & 0x3FFF].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; } Tile[] tiles = map.Tiles.GetStaticTiles( x, y, true ); for ( int i = 0; i < tiles.Length; ++i ) { Tile tile = tiles[i]; ItemData id = TileData.ItemTable[tile.ID & 0x3FFF]; if ( !id.Surface ) continue; int top = tile.Z + id.CalcHeight; if ( top > maxZ || top < z ) continue; z = top; } List items = new List(); IPooledEnumerable eable = map.GetItemsInRange( p, 0 ); foreach ( Item item in eable ) { if ( item.ItemID >= 0x4000 ) continue; items.Add( item ); ItemData id = item.ItemData; if ( !id.Surface ) continue; int top = item.Z + id.CalcHeight; if ( top > maxZ || top < z ) continue; z = top; } eable.Free(); if ( z == int.MinValue ) return false; if ( z > maxZ ) return false; m_OpenSlots = (1<<20)-1; int surfaceZ = z; for ( int i = 0; i < tiles.Length; ++i ) { Tile tile = tiles[i]; ItemData id = TileData.ItemTable[tile.ID & 0x3FFF]; 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<= 20 || zEnd < 0 ) continue; if ( zStart < 0 ) zStart = 0; if ( zEnd > 19 ) zEnd = 19; int bitCount = zEnd-zStart; m_OpenSlots &= ~(((1< 30 ) height = 30; int match = (1< 20 ) match >>= 1; okay = ((m_OpenSlots>>i)&match) == match; if ( okay ) { z += i; break; } } if ( !okay ) return false; height = ItemData.Height; if ( height == 0 ) ++height; if ( landAvg > z && (z + height) > landZ ) return false; else if ( (landFlags & TileFlag.Impassable) != 0 && landAvg > surfaceZ && (z + height) > landZ ) return false; for ( int i = 0; i < tiles.Length; ++i ) { Tile tile = tiles[i]; ItemData id = TileData.ItemTable[tile.ID & 0x3FFF]; int checkZ = tile.Z; int checkTop = checkZ + id.CalcHeight; if ( checkTop > z && (z + height) > checkZ ) return false; else if ( (id.Surface || id.Impassable) && checkTop > surfaceZ && (z + height) > checkZ ) return false; } 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 ( (item.Z + id.CalcHeight) > z && (z + height) > item.Z ) return false; } p = new Point3D( x, y, z ); if ( !from.InLOS( new Point3D( x, y, z + 1 ) ) ) return false; else if ( !from.OnDroppedItemToWorld( this, p ) ) return false; else if ( !OnDroppedToWorld( from, p ) ) return false; int soundID = GetDropSound(); MoveToWorld( p, from.Map ); from.SendSound( soundID == -1 ? 0x42 : soundID, GetWorldLocation() ); return true; } public void SendRemovePacket() { if ( !Deleted && m_Map != null ) { Packet p = null; Point3D worldLoc = GetWorldLocation(); IPooledEnumerable eable = m_Map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); foreach ( NetState state in eable ) { Mobile m = state.Mobile; if ( m.InRange( worldLoc, GetUpdateRange( m ) ) ) { if ( p == null ) p = this.RemovePacket; state.Send( p ); } } eable.Free(); } } public virtual int GetDropSound() { return -1; } public Point3D GetWorldLocation() { object 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() { object root = RootParent; 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 ((IEntity)root).Location; } public Point3D GetWorldTop() { object root = RootParent; if ( root == null ) return new Point3D( m_Location.m_X, m_Location.m_Y, m_Location.m_Z + ItemData.CalcHeight ); else return ((IEntity)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 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, Server.Targeting.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 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 ); /*SecureTradeContainer cont = GetSecureTradeCont(); if ( cont != null && !cont.IsChildOf( check ) ) return false; return true;*/ } public bool IsChildOf( object o ) { return IsChildOf( o, false ); } public bool IsChildOf( object o, bool allowNull ) { object 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 & 0x3FFF]; } } 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 = this.PropertyList; if ( opl.Header > 0 ) from.Send( new MessageLocalized( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, opl.Header, this.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 ( this.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", "", this.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 = this.Map; object thisParent = this.m_Parent; Point3D worldLoc = this.GetWorldLocation(); LootType type = this.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 ) { this.Amount -= amount; if ( this.Amount <= 0 ) this.Delete(); } [CommandProperty( AccessLevel.GameMaster )] public bool QuestItem { get { return GetFlag( ImplFlag.QuestItem ); } set { SetFlag( ImplFlag.QuestItem, value ); InvalidateProperties(); Packet.Release( ref m_WorldPacket ); 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 obj ) { return CheckBlessed( obj as Mobile ); } public virtual bool CheckBlessed( Mobile m ) { if ( m_LootType == LootType.Blessed || (Mobile.InsuranceEnabled && Insured) ) return true; return ( m != null && m == this.BlessedFor ); } public virtual bool CheckNewbied() { return ( m_LootType == LootType.Newbied ); } public virtual bool IsStandardLoot() { if ( Mobile.InsuranceEnabled && Insured ) return false; if ( this.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_Items = new ArrayList( 1 ); Visible = true; Movable = true; Amount = 1; m_Map = Map.Internal; SetLastMoved(); World.AddItem( this ); Type ourType = this.GetType(); m_TypeRef = World.m_ItemTypes.IndexOf( ourType ); if ( m_TypeRef == -1 ) { World.m_ItemTypes.Add( ourType ); m_TypeRef = World.m_ItemTypes.Count - 1; } } [Constructable] public Item( int itemID ) : this() { m_ItemID = itemID; } public Item( Serial serial ) { m_Serial = serial; Type ourType = this.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 OnSectorActivate() { } public virtual void OnSectorDeactivate() { } } }