diff --git a/Projects/UOContent/Engines/Khaldun/PuzzleChest.cs b/Projects/UOContent/Engines/Khaldun/PuzzleChest.cs index 216706930..2bc0bee22 100644 --- a/Projects/UOContent/Engines/Khaldun/PuzzleChest.cs +++ b/Projects/UOContent/Engines/Khaldun/PuzzleChest.cs @@ -267,7 +267,7 @@ namespace Server.Items protected override void SetLockLevel() { - LockLevel = 0; // Can't be unlocked + LockLevel = ILockpickable.CannotPick; // Can't be unlocked } public override bool CheckLocked(Mobile from) diff --git a/Projects/UOContent/Items/Containers/LockableContainer.cs b/Projects/UOContent/Items/Containers/LockableContainer.cs index c541abaa2..2d465001f 100644 --- a/Projects/UOContent/Items/Containers/LockableContainer.cs +++ b/Projects/UOContent/Items/Containers/LockableContainer.cs @@ -2,355 +2,234 @@ using System; using Server.Engines.Craft; using Server.Network; -namespace Server.Items +namespace Server.Items; + +[Serializable(0, false)] +public abstract partial class LockableContainer : TrappableContainer, ILockable, ILockpickable, ICraftable, IShipwreckedItem { - public abstract class LockableContainer : TrappableContainer, ILockable, ILockpickable, ICraftable, IShipwreckedItem + public LockableContainer(int itemID) : base(itemID) => MaxLockLevel = 100; + + public override bool TrapOnOpen => !_trapOnLockpick; + + public override bool DisplaysContent => !_rawLocked; + + public int OnCraft( + int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue + ) { - private bool m_Locked; - - public LockableContainer(int itemID) : base(itemID) => MaxLockLevel = 100; - - public LockableContainer(Serial serial) : base(serial) + if (from.CheckSkill(SkillName.Tinkering, -5.0, 15.0)) { + from.SendLocalizedMessage(500636); // Your tinker skill was sufficient to make the item lockable. + + var key = new Key(KeyType.Copper, Key.RandomValue()); + + _keyValue = key.KeyValue; + DropItem(key); + + var tinkering = from.Skills.Tinkering.Value; + var level = (int)(tinkering * 0.8); + + _requiredSkill = Math.Min(level - 4, 95); + _maxLockLevel = Math.Min(level + 35, 95); + + // Lock level of 0 means it is not pickable, so change it to -1 + _lockLevel = level == 14 ? -1 : Math.Min(level - 14, 95); + } + else + { + from.SendLocalizedMessage(500637); // Your tinker skill was insufficient to make the item lockable. } - public override bool TrapOnOpen => !TrapOnLockpick; + return 1; + } - [CommandProperty(AccessLevel.GameMaster)] - public bool TrapOnLockpick { get; set; } + [CommandProperty(AccessLevel.GameMaster)] + public Mobile Picker { get; set; } - public override bool DisplaysContent => !m_Locked; + [SerializableField(0)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private bool _isShipwreckedItem; - public int OnCraft( - int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue - ) + [SerializableField(1)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private bool _trapOnLockpick; + + [SerializableField(2)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private int _requiredSkill; + + [SerializableField(3)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private int _maxLockLevel; + + [SerializableField(4)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private uint _keyValue; + + [SerializableField(5)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private int _lockLevel; + + [SerializableField(6, getter: "private", setter: "private")] + private bool _rawLocked; + + [CommandProperty(AccessLevel.GameMaster)] + public virtual bool Locked + { + get => _rawLocked; + set { - if (from.CheckSkill(SkillName.Tinkering, -5.0, 15.0)) + _rawLocked = value; + + if (_rawLocked) { - from.SendLocalizedMessage(500636); // Your tinker skill was sufficient to make the item lockable. - - var key = new Key(KeyType.Copper, Key.RandomValue()); - - KeyValue = key.KeyValue; - DropItem(key); - - var tinkering = from.Skills.Tinkering.Value; - var level = (int)(tinkering * 0.8); - - RequiredSkill = level - 4; - LockLevel = level - 14; - MaxLockLevel = level + 35; - - if (LockLevel == 0) - { - LockLevel = -1; - } - else if (LockLevel > 95) - { - LockLevel = 95; - } - - if (RequiredSkill > 95) - { - RequiredSkill = 95; - } - - if (MaxLockLevel > 95) - { - MaxLockLevel = 95; - } - } - else - { - from.SendLocalizedMessage(500637); // Your tinker skill was insufficient to make the item lockable. + Picker = null; } - return 1; + InvalidateProperties(); + this.MarkDirty(); + } + } + + public virtual void LockPick(Mobile from) + { + Locked = false; + Picker = from; + + if (_trapOnLockpick && ExecuteTrap(from)) + { + _trapOnLockpick = false; + } + } + + public override bool CheckContentDisplay(Mobile from) => !_rawLocked && base.CheckContentDisplay(from); + + public override bool TryDropItem(Mobile from, Item dropped, bool sendFullMessage) + { + if (from.AccessLevel < AccessLevel.GameMaster && _rawLocked) + { + from.SendLocalizedMessage(501747); // It appears to be locked. + return false; } - [CommandProperty(AccessLevel.GameMaster)] - public virtual bool Locked + return base.TryDropItem(from, dropped, sendFullMessage); + } + + public override bool OnDragDropInto(Mobile from, Item item, Point3D p) + { + if (from.AccessLevel < AccessLevel.GameMaster && _rawLocked) { - get => m_Locked; - set - { - m_Locked = value; - - if (m_Locked) - { - Picker = null; - } - - InvalidateProperties(); - } + from.SendLocalizedMessage(501747); // It appears to be locked. + return false; } - [CommandProperty(AccessLevel.GameMaster)] - public uint KeyValue { get; set; } + return base.OnDragDropInto(from, item, p); + } - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Picker { get; set; } + public override bool CheckLift(Mobile from, Item item, ref LRReason reject) => + base.CheckLift(from, item, ref reject) && + (item == this || from.AccessLevel >= AccessLevel.GameMaster || !_rawLocked); - [CommandProperty(AccessLevel.GameMaster)] - public int MaxLockLevel { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int LockLevel { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int RequiredSkill { get; set; } - - public virtual void LockPick(Mobile from) + public override bool CheckItemUse(Mobile from, Item item) + { + if (!base.CheckItemUse(from, item)) { - Locked = false; - Picker = from; - - if (TrapOnLockpick && ExecuteTrap(from)) - { - TrapOnLockpick = false; - } + return false; } - [CommandProperty(AccessLevel.GameMaster)] - public bool IsShipwreckedItem { get; set; } - - public override void Serialize(IGenericWriter writer) + if (item != this && from.AccessLevel < AccessLevel.GameMaster && _rawLocked) { - base.Serialize(writer); - - writer.Write(6); // version - - writer.Write(IsShipwreckedItem); - - writer.Write(TrapOnLockpick); - - writer.Write(RequiredSkill); - - writer.Write(MaxLockLevel); - - writer.Write(KeyValue); - writer.Write(LockLevel); - writer.Write(m_Locked); + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return false; } - public override void Deserialize(IGenericReader reader) + return true; + } + + public virtual bool CheckLocked(Mobile from) + { + if (!_rawLocked) { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - switch (version) - { - case 6: - { - IsShipwreckedItem = reader.ReadBool(); - - goto case 5; - } - case 5: - { - TrapOnLockpick = reader.ReadBool(); - - goto case 4; - } - case 4: - { - RequiredSkill = reader.ReadInt(); - - goto case 3; - } - case 3: - { - MaxLockLevel = reader.ReadInt(); - - goto case 2; - } - case 2: - { - KeyValue = reader.ReadUInt(); - - goto case 1; - } - case 1: - { - LockLevel = reader.ReadInt(); - - goto case 0; - } - case 0: - { - if (version < 3) - { - MaxLockLevel = 100; - } - - if (version < 4) - { - if (MaxLockLevel - LockLevel == 40) - { - RequiredSkill = LockLevel + 6; - LockLevel = RequiredSkill - 10; - MaxLockLevel = RequiredSkill + 39; - } - else - { - RequiredSkill = LockLevel; - } - } - - m_Locked = reader.ReadBool(); - - break; - } - } + return false; } - public override bool CheckContentDisplay(Mobile from) => !m_Locked && base.CheckContentDisplay(from); + var inaccessible = from.AccessLevel < AccessLevel.GameMaster; - public override bool TryDropItem(Mobile from, Item dropped, bool sendFullMessage) + int number = inaccessible + ? 501747 // It appears to be locked. + : 502502; // That is locked, but you open it with your godly powers. + + from.NetState.SendMessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number); + + return inaccessible; + } + + public override void OnTelekinesis(Mobile from) + { + if (CheckLocked(from)) { - if (from.AccessLevel < AccessLevel.GameMaster && m_Locked) - { - from.SendLocalizedMessage(501747); // It appears to be locked. - return false; - } - - return base.TryDropItem(from, dropped, sendFullMessage); + Effects.SendLocationParticles( + EffectItem.Create(Location, Map, EffectItem.DefaultDuration), + 0x376A, + 9, + 32, + 5022 + ); + Effects.PlaySound(Location, Map, 0x1F5); + return; } - public override bool OnDragDropInto(Mobile from, Item item, Point3D p) - { - if (from.AccessLevel < AccessLevel.GameMaster && m_Locked) - { - from.SendLocalizedMessage(501747); // It appears to be locked. - return false; - } + base.OnTelekinesis(from); + } - return base.OnDragDropInto(from, item, p); + public override void OnDoubleClickSecureTrade(Mobile from) + { + if (CheckLocked(from)) + { + return; } - public override bool CheckLift(Mobile from, Item item, ref LRReason reject) + base.OnDoubleClickSecureTrade(from); + } + + public override void Open(Mobile from) + { + if (CheckLocked(from)) { - if (!base.CheckLift(from, item, ref reject)) - { - return false; - } - - if (item != this && from.AccessLevel < AccessLevel.GameMaster && m_Locked) - { - return false; - } - - return true; + return; } - public override bool CheckItemUse(Mobile from, Item item) + base.Open(from); + } + + public override void OnSnoop(Mobile from) + { + if (CheckLocked(from)) { - if (!base.CheckItemUse(from, item)) - { - return false; - } - - if (item != this && from.AccessLevel < AccessLevel.GameMaster && m_Locked) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - return false; - } - - return true; + return; } - public virtual bool CheckLocked(Mobile from) + base.OnSnoop(from); + } + + public override void AddNameProperties(ObjectPropertyList list) + { + base.AddNameProperties(list); + + if (_isShipwreckedItem) { - var inaccessible = false; - - if (m_Locked) - { - int number; - - if (from.AccessLevel >= AccessLevel.GameMaster) - { - number = 502502; // That is locked, but you open it with your godly powers. - } - else - { - number = 501747; // It appears to be locked. - inaccessible = true; - } - - from.NetState.SendMessageLocalized(Serial, ItemID, MessageType.Regular, 0x3B2, 3, number); - } - - return inaccessible; + list.Add(1041645); // recovered from a shipwreck } + } - public override void OnTelekinesis(Mobile from) + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + if (_isShipwreckedItem) { - if (CheckLocked(from)) - { - Effects.SendLocationParticles( - EffectItem.Create(Location, Map, EffectItem.DefaultDuration), - 0x376A, - 9, - 32, - 5022 - ); - Effects.PlaySound(Location, Map, 0x1F5); - return; - } - - base.OnTelekinesis(from); - } - - public override void OnDoubleClickSecureTrade(Mobile from) - { - if (CheckLocked(from)) - { - return; - } - - base.OnDoubleClickSecureTrade(from); - } - - public override void Open(Mobile from) - { - if (CheckLocked(from)) - { - return; - } - - base.Open(from); - } - - public override void OnSnoop(Mobile from) - { - if (CheckLocked(from)) - { - return; - } - - base.OnSnoop(from); - } - - public override void AddNameProperties(ObjectPropertyList list) - { - base.AddNameProperties(list); - - if (IsShipwreckedItem) - { - list.Add(1041645); // recovered from a shipwreck - } - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - if (IsShipwreckedItem) - { - LabelTo(from, 1041645); // recovered from a shipwreck - } + LabelTo(from, 1041645); // recovered from a shipwreck } } } diff --git a/Projects/UOContent/Items/Containers/MarkContainer.cs b/Projects/UOContent/Items/Containers/MarkContainer.cs index 1bf5baa27..5099c7e3e 100644 --- a/Projects/UOContent/Items/Containers/MarkContainer.cs +++ b/Projects/UOContent/Items/Containers/MarkContainer.cs @@ -48,7 +48,7 @@ public partial class MarkContainer : LockableContainer if (locked) { - LockLevel = -255; + LockLevel = ILockpickable.MagicLock; } } @@ -225,7 +225,7 @@ public partial class MarkContainer : LockableContainer protected override void OnTick() { Container.Locked = true; - Container.LockLevel = -255; + Container.LockLevel = ILockpickable.MagicLock; } } } diff --git a/Projects/UOContent/Items/Containers/TreasureMapChest.cs b/Projects/UOContent/Items/Containers/TreasureMapChest.cs index 8d07ca786..bbe01747f 100644 --- a/Projects/UOContent/Items/Containers/TreasureMapChest.cs +++ b/Projects/UOContent/Items/Containers/TreasureMapChest.cs @@ -159,7 +159,7 @@ public partial class TreasureMapChest : LockableContainer if (level == 0) { - cont.LockLevel = 0; + cont.LockLevel = ILockpickable.CannotPick; cont.DropItem(new Gold(Utility.RandomMinMax(50, 100))); diff --git a/Projects/UOContent/Items/Misc/Key.cs b/Projects/UOContent/Items/Misc/Key.cs index 758f8c1ad..263a9ac03 100644 --- a/Projects/UOContent/Items/Misc/Key.cs +++ b/Projects/UOContent/Items/Misc/Key.cs @@ -2,295 +2,294 @@ using Server.Network; using Server.Prompts; using Server.Targeting; -namespace Server.Items +namespace Server.Items; + +public enum KeyType { - public enum KeyType + Copper = 0x100E, + Gold = 0x100F, + Iron = 0x1010, + Rusty = 0x1013 +} + +public interface ILockable +{ + bool Locked { get; set; } + uint KeyValue { get; set; } +} + +public class Key : Item +{ + private string m_Description; + private uint m_KeyVal; + + [Constructible] + public Key(uint val = 0) : this(KeyType.Iron, val) { - Copper = 0x100E, - Gold = 0x100F, - Iron = 0x1010, - Rusty = 0x1013 } - public interface ILockable + public Key(KeyType type, uint val = 0, Item link = null) : base((int)type) { - bool Locked { get; set; } - uint KeyValue { get; set; } + Weight = 1.0; + + MaxRange = 3; + m_KeyVal = val; + Link = link; } - public class Key : Item + public Key(Serial serial) : base(serial) { - private string m_Description; - private uint m_KeyVal; + } - [Constructible] - public Key(uint val = 0) : this(KeyType.Iron, val) + [CommandProperty(AccessLevel.GameMaster)] + public string Description + { + get => m_Description; + set { + m_Description = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public int MaxRange { get; set; } + + [CommandProperty(AccessLevel.GameMaster)] + public uint KeyValue + { + get => m_KeyVal; + + set + { + m_KeyVal = value; + InvalidateProperties(); + } + } + + [CommandProperty(AccessLevel.GameMaster)] + public Item Link { get; set; } + + public static uint RandomValue() => (uint)(0xFFFFFFFE * Utility.RandomDouble()) + 1; + + public static void RemoveKeys(Mobile m, uint keyValue) + { + if (keyValue == 0) + { + return; } - public Key(KeyType type, uint val = 0, Item link = null) : base((int)type) - { - Weight = 1.0; + RemoveKeys(m.Backpack, keyValue); + RemoveKeys(m.BankBox, keyValue); + } - MaxRange = 3; - m_KeyVal = val; - Link = link; + public static void RemoveKeys(Container cont, uint keyValue) + { + if (cont == null || keyValue == 0) + { + return; } - public Key(Serial serial) : base(serial) - { - } + var items = cont.FindItemsByType(new[] { typeof(Key), typeof(KeyRing) }); - [CommandProperty(AccessLevel.GameMaster)] - public string Description + foreach (var item in items) { - get => m_Description; - set + if (item is Key key) { - m_Description = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int MaxRange { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public uint KeyValue - { - get => m_KeyVal; - - set - { - m_KeyVal = value; - InvalidateProperties(); - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public Item Link { get; set; } - - public static uint RandomValue() => (uint)(0xFFFFFFFE * Utility.RandomDouble()) + 1; - - public static void RemoveKeys(Mobile m, uint keyValue) - { - if (keyValue == 0) - { - return; - } - - RemoveKeys(m.Backpack, keyValue); - RemoveKeys(m.BankBox, keyValue); - } - - public static void RemoveKeys(Container cont, uint keyValue) - { - if (cont == null || keyValue == 0) - { - return; - } - - var items = cont.FindItemsByType(new[] { typeof(Key), typeof(KeyRing) }); - - foreach (var item in items) - { - if (item is Key key) + if (key.KeyValue == keyValue) { - if (key.KeyValue == keyValue) + key.Delete(); + } + } + else + { + var keyRing = (KeyRing)item; + + keyRing.RemoveKeys(keyValue); + } + } + } + + public static bool ContainsKey(Container cont, uint keyValue) + { + if (cont == null) + { + return false; + } + + var items = cont.FindItemsByType(new[] { typeof(Key), typeof(KeyRing) }); + + foreach (var item in items) + { + if (item is Key key) + { + if (key.KeyValue == keyValue) + { + return true; + } + } + else + { + var keyRing = (KeyRing)item; + + if (keyRing.ContainsKey(keyValue)) + { + return true; + } + } + } + + return false; + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(2); // version + + writer.Write(MaxRange); + + writer.Write(Link); + + writer.Write(m_Description); + writer.Write(m_KeyVal); + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + var version = reader.ReadInt(); + + switch (version) + { + case 2: + { + MaxRange = reader.ReadInt(); + + goto case 1; + } + case 1: + { + Link = reader.ReadEntity(); + + goto case 0; + } + case 0: + { + if (version < 2 || MaxRange == 0) { - key.Delete(); + MaxRange = 3; } - } - else - { - var keyRing = (KeyRing)item; - keyRing.RemoveKeys(keyValue); + m_Description = reader.ReadString(); + + m_KeyVal = reader.ReadUInt(); + + break; } - } + } + } + + public override void OnDoubleClick(Mobile from) + { + if (!IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(501661); // That key is unreachable. + return; } - public static bool ContainsKey(Container cont, uint keyValue) + Target t; + int number; + + if (m_KeyVal != 0) { - if (cont == null) + number = 501662; // What shall I use this key on? + t = new UnlockTarget(this); + } + else + { + number = 501663; // This key is a key blank. Which key would you like to make a copy of? + t = new CopyTarget(this); + } + + from.SendLocalizedMessage(number); + from.Target = t; + } + + public override void GetProperties(ObjectPropertyList list) + { + base.GetProperties(list); + + string desc; + + if (m_KeyVal == 0) + { + desc = "(blank)"; + } + else if ((desc = m_Description) == null || (desc = desc.Trim()).Length <= 0) + { + desc = null; + } + + if (desc != null) + { + list.Add(desc); + } + } + + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); + + string desc; + + if (m_KeyVal == 0) + { + desc = "(blank)"; + } + else + { + desc = m_Description?.Trim() ?? ""; + } + + if (desc.Length > 0) + { + from.NetState.SendMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, false, "ENU", "", desc); + } + } + + public bool UseOn(Mobile from, ILockable o) + { + if (o.KeyValue == KeyValue) + { + if (o is BaseDoor door && !door.UseLocks()) { return false; } - var items = cont.FindItemsByType(new[] { typeof(Key), typeof(KeyRing) }); + o.Locked = !o.Locked; - foreach (var item in items) + if (o is Item item) { - if (item is Key key) + if (o.Locked) { - if (key.KeyValue == keyValue) - { - return true; - } + item.SendLocalizedMessageTo(from, 1048000); // You lock it. } else { - var keyRing = (KeyRing)item; - - if (keyRing.ContainsKey(keyValue)) - { - return true; - } - } - } - - return false; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(2); // version - - writer.Write(MaxRange); - - writer.Write(Link); - - writer.Write(m_Description); - writer.Write(m_KeyVal); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - switch (version) - { - case 2: - { - MaxRange = reader.ReadInt(); - - goto case 1; - } - case 1: - { - Link = reader.ReadEntity(); - - goto case 0; - } - case 0: - { - if (version < 2 || MaxRange == 0) - { - MaxRange = 3; - } - - m_Description = reader.ReadString(); - - m_KeyVal = reader.ReadUInt(); - - break; - } - } - } - - public override void OnDoubleClick(Mobile from) - { - if (!IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(501661); // That key is unreachable. - return; - } - - Target t; - int number; - - if (m_KeyVal != 0) - { - number = 501662; // What shall I use this key on? - t = new UnlockTarget(this); - } - else - { - number = 501663; // This key is a key blank. Which key would you like to make a copy of? - t = new CopyTarget(this); - } - - from.SendLocalizedMessage(number); - from.Target = t; - } - - public override void GetProperties(ObjectPropertyList list) - { - base.GetProperties(list); - - string desc; - - if (m_KeyVal == 0) - { - desc = "(blank)"; - } - else if ((desc = m_Description) == null || (desc = desc.Trim()).Length <= 0) - { - desc = null; - } - - if (desc != null) - { - list.Add(desc); - } - } - - public override void OnSingleClick(Mobile from) - { - base.OnSingleClick(from); - - string desc; - - if (m_KeyVal == 0) - { - desc = "(blank)"; - } - else - { - desc = m_Description?.Trim() ?? ""; - } - - if (desc.Length > 0) - { - from.NetState.SendMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, false, "ENU", "", desc); - } - } - - public bool UseOn(Mobile from, ILockable o) - { - if (o.KeyValue == KeyValue) - { - if (o is BaseDoor door && !door.UseLocks()) - { - return false; + item.SendLocalizedMessageTo(from, 1048001); // You unlock it. } - o.Locked = !o.Locked; - - if (o is LockableContainer cont1) + if (item is LockableContainer cont) { - if (cont1.LockLevel == -255) + if (cont.LockLevel == ILockpickable.MagicLock) { - cont1.LockLevel = cont1.RequiredSkill - 10; - } - } - - if (o is Item item) - { - if (o.Locked) - { - item.SendLocalizedMessageTo(from, 1048000); // You lock it. - } - else - { - item.SendLocalizedMessageTo(from, 1048001); // You unlock it. + cont.LockLevel = cont.RequiredSkill - 10; } - if (item is LockableContainer cont && cont.TrapType != TrapType.None && cont.TrapOnLockpick) + if (cont.TrapType != TrapType.None && cont.TrapOnLockpick) { if (o.Locked) { @@ -298,138 +297,136 @@ namespace Server.Items } else { - cont.SendLocalizedMessageTo( - from, - 501672 - ); // You disable the trap temporarily. Lock it again to re-enable it. + // You disable the trap temporarily. Lock it again to re-enable it. + cont.SendLocalizedMessageTo(from, 501672); } } } - - return true; } - return false; + return true; } - private class RenamePrompt : Prompt + return false; + } + + private class RenamePrompt : Prompt + { + private readonly Key m_Key; + + public RenamePrompt(Key key) => m_Key = key; + + public override void OnResponse(Mobile from, string text) { - private readonly Key m_Key; - - public RenamePrompt(Key key) => m_Key = key; - - public override void OnResponse(Mobile from, string text) + if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack)) { - if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(501661); // That key is unreachable. - return; - } - - m_Key.Description = Utility.FixHtml(text); + from.SendLocalizedMessage(501661); // That key is unreachable. + return; } + + m_Key.Description = Utility.FixHtml(text); + } + } + + private class UnlockTarget : Target + { + private readonly Key m_Key; + + public UnlockTarget(Key key) : base(key.MaxRange, false, TargetFlags.None) + { + m_Key = key; + CheckLOS = false; } - private class UnlockTarget : Target + protected override void OnTarget(Mobile from, object targeted) { - private readonly Key m_Key; - - public UnlockTarget(Key key) : base(key.MaxRange, false, TargetFlags.None) + if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack)) { - m_Key = key; - CheckLOS = false; + from.SendLocalizedMessage(501661); // That key is unreachable. + return; } - protected override void OnTarget(Mobile from, object targeted) + int number; + + if (targeted == m_Key) { - if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(501661); // That key is unreachable. - return; - } + number = 501665; // Enter a description for this key. - int number; - - if (targeted == m_Key) + from.Prompt = new RenamePrompt(m_Key); + } + else if (targeted is ILockable lockable) + { + if (m_Key.UseOn(from, lockable)) { - number = 501665; // Enter a description for this key. - - from.Prompt = new RenamePrompt(m_Key); - } - else if (targeted is ILockable lockable) - { - if (m_Key.UseOn(from, lockable)) - { - number = -1; - } - else - { - number = 501668; // This key doesn't seem to unlock that. - } + number = -1; } else { - number = 501666; // You can't unlock that! - } - - if (number != -1) - { - from.SendLocalizedMessage(number); + number = 501668; // This key doesn't seem to unlock that. } } - } - - private class CopyTarget : Target - { - private readonly Key m_Key; - - public CopyTarget(Key key) : base(3, false, TargetFlags.None) => m_Key = key; - - protected override void OnTarget(Mobile from, object targeted) + else { - if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack)) - { - from.SendLocalizedMessage(501661); // That key is unreachable. - return; - } - - int number; - - if (targeted is Key k) - { - if (k.m_KeyVal == 0) - { - number = 501675; // This key is also blank. - } - else if (from.CheckTargetSkill(SkillName.Tinkering, k, 0, 75.0)) - { - number = 501676; // You make a copy of the key. - - m_Key.Description = k.Description; - m_Key.KeyValue = k.KeyValue; - m_Key.Link = k.Link; - m_Key.MaxRange = k.MaxRange; - } - else if (Utility.RandomDouble() <= 0.1) // 10% chance to destroy the key - { - from.SendLocalizedMessage(501677); // You fail to make a copy of the key. - - number = 501678; // The key was destroyed in the attempt. - - m_Key.Delete(); - } - else - { - number = 501677; // You fail to make a copy of the key. - } - } - else - { - number = 501688; // Not a key. - } + number = 501666; // You can't unlock that! + } + if (number != -1) + { from.SendLocalizedMessage(number); } } } + + private class CopyTarget : Target + { + private readonly Key m_Key; + + public CopyTarget(Key key) : base(3, false, TargetFlags.None) => m_Key = key; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Key.Deleted || !m_Key.IsChildOf(from.Backpack)) + { + from.SendLocalizedMessage(501661); // That key is unreachable. + return; + } + + int number; + + if (targeted is Key k) + { + if (k.m_KeyVal == 0) + { + number = 501675; // This key is also blank. + } + else if (from.CheckTargetSkill(SkillName.Tinkering, k, 0, 75.0)) + { + number = 501676; // You make a copy of the key. + + m_Key.Description = k.Description; + m_Key.KeyValue = k.KeyValue; + m_Key.Link = k.Link; + m_Key.MaxRange = k.MaxRange; + } + else if (Utility.RandomDouble() <= 0.1) // 10% chance to destroy the key + { + from.SendLocalizedMessage(501677); // You fail to make a copy of the key. + + number = 501678; // The key was destroyed in the attempt. + + m_Key.Delete(); + } + else + { + number = 501677; // You fail to make a copy of the key. + } + } + else + { + number = 501688; // Not a key. + } + + from.SendLocalizedMessage(number); + } + } } diff --git a/Projects/UOContent/Items/Skill Items/Thief/LockPick.cs b/Projects/UOContent/Items/Skill Items/Thief/LockPick.cs index e94194e44..0e3ae8b03 100644 --- a/Projects/UOContent/Items/Skill Items/Thief/LockPick.cs +++ b/Projects/UOContent/Items/Skill Items/Thief/LockPick.cs @@ -1,163 +1,165 @@ using System; using Server.Targeting; -namespace Server.Items -{ - public interface ILockpickable : IPoint2D - { - int LockLevel { get; set; } - bool Locked { get; set; } - Mobile Picker { get; set; } - int MaxLockLevel { get; set; } - int RequiredSkill { get; set; } +namespace Server.Items; - void LockPick(Mobile from); +public interface ILockpickable : IPoint2D +{ + const int CannotPick = 0; + const int MagicLock = -255; + + int LockLevel { get; set; } + bool Locked { get; set; } + Mobile Picker { get; set; } + int MaxLockLevel { get; set; } + int RequiredSkill { get; set; } + + void LockPick(Mobile from); +} + +[Flippable(0x14fc, 0x14fb)] +public class Lockpick : Item +{ + [Constructible] + public Lockpick(int amount = 1) : base(0x14FC) + { + Stackable = true; + Amount = amount; } - [Flippable(0x14fc, 0x14fb)] - public class Lockpick : Item + public Lockpick(Serial serial) : base(serial) { - [Constructible] - public Lockpick(int amount = 1) : base(0x14FC) + } + + public override void Serialize(IGenericWriter writer) + { + base.Serialize(writer); + + writer.Write(1); // version + } + + public override void Deserialize(IGenericReader reader) + { + base.Deserialize(reader); + + var version = reader.ReadInt(); + + if (version == 0 && Weight == 0.1) { - Stackable = true; - Amount = amount; + Weight = -1; } + } - public Lockpick(Serial serial) : base(serial) + public override void OnDoubleClick(Mobile from) + { + from.SendLocalizedMessage(502068); // What do you want to pick? + from.Target = new InternalTarget(this); + } + + private class InternalTarget : Target + { + private readonly Lockpick m_Item; + + public InternalTarget(Lockpick item) : base(1, false, TargetFlags.None) => m_Item = item; + + protected override void OnTarget(Mobile from, object targeted) { - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - if (version == 0 && Weight == 0.1) + if (m_Item.Deleted) { - Weight = -1; + return; + } + + if (targeted is ILockpickable lockpickable) + { + var item = lockpickable as Item; + from.Direction = from.GetDirectionTo(item); + + if (lockpickable.Locked) + { + from.PlaySound(0x241); + + new InternalTimer(from, lockpickable, m_Item).Start(); + } + else + { + // The door is not locked + from.SendLocalizedMessage(502069); // This does not appear to be locked + } + } + else + { + from.SendLocalizedMessage(501666); // You can't unlock that! } } - public override void OnDoubleClick(Mobile from) + private class InternalTimer : Timer { - from.SendLocalizedMessage(502068); // What do you want to pick? - from.Target = new InternalTarget(this); - } + private readonly Mobile m_From; + private readonly ILockpickable m_Item; + private readonly Lockpick m_Lockpick; - private class InternalTarget : Target - { - private readonly Lockpick m_Item; - - public InternalTarget(Lockpick item) : base(1, false, TargetFlags.None) => m_Item = item; - - protected override void OnTarget(Mobile from, object targeted) + public InternalTimer(Mobile from, ILockpickable item, Lockpick lockpick) : base(TimeSpan.FromSeconds(3.0)) { - if (m_Item.Deleted) + m_From = from; + m_Item = item; + m_Lockpick = lockpick; + } + + protected void BrokeLockPickTest() + { + // When failed, a 25% chance to break the lockpick + if (Utility.Random(4) == 0) + { + var item = (Item)m_Item; + + // You broke the lockpick. + item.SendLocalizedMessageTo(m_From, 502074); + + m_From.PlaySound(0x3A4); + m_Lockpick.Consume(); + } + } + + protected override void OnTick() + { + var item = (Item)m_Item; + + if (!m_From.InRange(item.GetWorldLocation(), 1)) { return; } - if (targeted is ILockpickable lockpickable) + if (m_Item.LockLevel is ILockpickable.CannotPick or ILockpickable.MagicLock) { - var item = lockpickable as Item; - from.Direction = from.GetDirectionTo(item); + // LockLevel of 0 means that the door can't be picklocked + // LockLevel of -255 means it's magic locked + item.SendLocalizedMessageTo(m_From, 502073); // This lock cannot be picked by normal means + return; + } - if (lockpickable.Locked) - { - from.PlaySound(0x241); + if (m_From.Skills.Lockpicking.Value < m_Item.RequiredSkill) + { + /* + // Do some training to gain skills + m_From.CheckSkill( SkillName.Lockpicking, 0, m_Item.LockLevel );*/ - new InternalTimer(from, lockpickable, m_Item).Start(); - } - else - { - // The door is not locked - from.SendLocalizedMessage(502069); // This does not appear to be locked - } + // The LockLevel is higher thant the LockPicking of the player + item.SendLocalizedMessageTo(m_From, 502072); // You don't see how that lock can be manipulated. + return; + } + + if (m_From.CheckTargetSkill(SkillName.Lockpicking, m_Item, m_Item.LockLevel, m_Item.MaxLockLevel)) + { + // Success! Pick the lock! + item.SendLocalizedMessageTo(m_From, 502076); // The lock quickly yields to your skill. + m_From.PlaySound(0x4A); + m_Item.LockPick(m_From); } else { - from.SendLocalizedMessage(501666); // You can't unlock that! - } - } - - private class InternalTimer : Timer - { - private readonly Mobile m_From; - private readonly ILockpickable m_Item; - private readonly Lockpick m_Lockpick; - - public InternalTimer(Mobile from, ILockpickable item, Lockpick lockpick) : base(TimeSpan.FromSeconds(3.0)) - { - m_From = from; - m_Item = item; - m_Lockpick = lockpick; - } - - protected void BrokeLockPickTest() - { - // When failed, a 25% chance to break the lockpick - if (Utility.Random(4) == 0) - { - var item = (Item)m_Item; - - // You broke the lockpick. - item.SendLocalizedMessageTo(m_From, 502074); - - m_From.PlaySound(0x3A4); - m_Lockpick.Consume(); - } - } - - protected override void OnTick() - { - var item = (Item)m_Item; - - if (!m_From.InRange(item.GetWorldLocation(), 1)) - { - return; - } - - if (m_Item.LockLevel is 0 or -255) - { - // LockLevel of 0 means that the door can't be picklocked - // LockLevel of -255 means it's magic locked - item.SendLocalizedMessageTo(m_From, 502073); // This lock cannot be picked by normal means - return; - } - - if (m_From.Skills.Lockpicking.Value < m_Item.RequiredSkill) - { - /* - // Do some training to gain skills - m_From.CheckSkill( SkillName.Lockpicking, 0, m_Item.LockLevel );*/ - - // The LockLevel is higher thant the LockPicking of the player - item.SendLocalizedMessageTo(m_From, 502072); // You don't see how that lock can be manipulated. - return; - } - - if (m_From.CheckTargetSkill(SkillName.Lockpicking, m_Item, m_Item.LockLevel, m_Item.MaxLockLevel)) - { - // Success! Pick the lock! - item.SendLocalizedMessageTo(m_From, 502076); // The lock quickly yields to your skill. - m_From.PlaySound(0x4A); - m_Item.LockPick(m_From); - } - else - { - // The player failed to pick the lock - BrokeLockPickTest(); - item.SendLocalizedMessageTo(m_From, 502075); // You are unable to pick the lock. - } + // The player failed to pick the lock + BrokeLockPickTest(); + item.SendLocalizedMessageTo(m_From, 502075); // You are unable to pick the lock. } } } diff --git a/Projects/UOContent/Migrations/Server.Items.LockableContainer.v0.json b/Projects/UOContent/Migrations/Server.Items.LockableContainer.v0.json new file mode 100644 index 000000000..e9d8da768 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.LockableContainer.v0.json @@ -0,0 +1,62 @@ +{ + "version": 0, + "type": "Server.Items.LockableContainer", + "properties": [ + { + "name": "IsShipwreckedItem", + "type": "bool", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "TrapOnLockpick", + "type": "bool", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "RequiredSkill", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "MaxLockLevel", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "KeyValue", + "type": "uint", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "LockLevel", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "RawLocked", + "type": "bool", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Spells/Third/MagicLock.cs b/Projects/UOContent/Spells/Third/MagicLock.cs index c9cfef434..2f8e23c59 100644 --- a/Projects/UOContent/Spells/Third/MagicLock.cs +++ b/Projects/UOContent/Spells/Third/MagicLock.cs @@ -30,13 +30,10 @@ namespace Server.Spells.Third } else if (BaseHouse.CheckLockedDownOrSecured(cont)) { - Caster.LocalOverheadMessage( - MessageType.Regular, - 0x22, - 501761 - ); // You cannot cast this on a locked down item. + // You cannot cast this on a locked down item. + Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 501761); } - else if (cont.Locked || cont.LockLevel == 0 || cont is ParagonChest) + else if (cont.Locked || cont.LockLevel == ILockpickable.CannotPick || cont is ParagonChest) { Caster.SendLocalizedMessage(501762); // Target must be an unlocked chest. } @@ -59,7 +56,7 @@ namespace Server.Spells.Third // The chest is now locked! Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 501763); - cont.LockLevel = -255; // signal magic lock + cont.LockLevel = ILockpickable.MagicLock; // signal magic lock cont.Locked = true; } diff --git a/Projects/UOContent/Spells/Third/Unlock.cs b/Projects/UOContent/Spells/Third/Unlock.cs index a29040d06..445b23e23 100644 --- a/Projects/UOContent/Spells/Third/Unlock.cs +++ b/Projects/UOContent/Spells/Third/Unlock.cs @@ -40,52 +40,44 @@ namespace Server.Spells.Third if (p is Mobile) { - Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503101); // That did not need to be unlocked. + // That did not need to be unlocked. + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503101); } else if (p is not LockableContainer cont) { Caster.SendLocalizedMessage(501666); // You can't unlock that! } + else if (BaseHouse.CheckSecured(cont)) + { + Caster.SendLocalizedMessage(503098); // You cannot cast this on a secure item. + } + else if (!cont.Locked) + { + // That did not need to be unlocked. + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503101); + } + else if (cont.LockLevel == ILockpickable.CannotPick) + { + Caster.SendLocalizedMessage(501666); // You can't unlock that! + } else { - if (BaseHouse.CheckSecured(cont)) + var level = (int)(Caster.Skills.Magery.Value * 0.8) - 4; + + if (level >= cont.RequiredSkill && + !(cont is TreasureMapChest chest && chest.Level > 2)) { - Caster.SendLocalizedMessage(503098); // You cannot cast this on a secure item. - } - else if (!cont.Locked) - { - Caster.LocalOverheadMessage( - MessageType.Regular, - 0x3B2, - 503101 - ); // That did not need to be unlocked. - } - else if (cont.LockLevel == 0) - { - Caster.SendLocalizedMessage(501666); // You can't unlock that! + cont.Locked = false; + + if (cont.LockLevel == ILockpickable.MagicLock) + { + cont.LockLevel = cont.RequiredSkill - 10; + } } else { - var level = (int)(Caster.Skills.Magery.Value * 0.8) - 4; - - if (level >= cont.RequiredSkill && - !(cont is TreasureMapChest chest && chest.Level > 2)) - { - cont.Locked = false; - - if (cont.LockLevel == -255) - { - cont.LockLevel = cont.RequiredSkill - 10; - } - } - else - { - Caster.LocalOverheadMessage( - MessageType.Regular, - 0x3B2, - 503099 - ); // My spell does not seem to have an effect on that lock. - } + // My spell does not seem to have an effect on that lock. + Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503099); } } }