fix: Codegens lockable containers and cleans up lockpickable (#976)
This commit is contained in:
parent
fc0594f87c
commit
8f922c94ae
9 changed files with 762 additions and 833 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue