fix: Codegens lockable containers and cleans up lockpickable (#976)

This commit is contained in:
Kamron Batman 2022-03-26 21:48:18 -07:00 committed by GitHub
parent fc0594f87c
commit 8f922c94ae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 762 additions and 833 deletions

View file

@ -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)

View file

@ -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
}
}
}

View file

@ -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;
}
}
}

View file

@ -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)));

View file

@ -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<Item>();
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<Item>();
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);
}
}
}

View file

@ -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.
}
}
}

View file

@ -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": [
""
]
}
]
}

View file

@ -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;
}

View file

@ -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);
}
}
}