diff --git a/Projects/UOContent/Items/Weapons/Axes/BaseAxe.cs b/Projects/UOContent/Items/Weapons/Axes/BaseAxe.cs index 77cce81939..64b19aa89b 100644 --- a/Projects/UOContent/Items/Weapons/Axes/BaseAxe.cs +++ b/Projects/UOContent/Items/Weapons/Axes/BaseAxe.cs @@ -105,10 +105,6 @@ public override void GetContextMenuEntries(Mobile from, List l } } - private void Deserialize(IGenericReader reader, int version) - { - } - public override void OnHit(Mobile attacker, Mobile defender, double damageBonus = 1) { base.OnHit(attacker, defender, damageBonus); diff --git a/Projects/UOContent/Migrations/Server.Items.HousePlacementTool.v0.json b/Projects/UOContent/Migrations/Server.Items.HousePlacementTool.v0.json new file mode 100644 index 0000000000..4efca73707 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.HousePlacementTool.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.HousePlacementTool" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.HouseTeleporter.v2.json b/Projects/UOContent/Migrations/Server.Items.HouseTeleporter.v2.json new file mode 100644 index 0000000000..2ee54d866d --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.HouseTeleporter.v2.json @@ -0,0 +1,16 @@ +{ + "version": 2, + "type": "Server.Items.HouseTeleporter", + "properties": [ + { + "name": "Level", + "type": "Server.Multis.SecureLevel", + "rule": "EnumMigrationRule" + }, + { + "name": "Target", + "type": "Server.Item", + "rule": "SerializableInterfaceMigrationRule" + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.ToggleItem.v0.json b/Projects/UOContent/Migrations/Server.Items.ToggleItem.v0.json new file mode 100644 index 0000000000..c5cc3cb567 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.ToggleItem.v0.json @@ -0,0 +1,30 @@ +{ + "version": 0, + "type": "Server.Items.ToggleItem", + "properties": [ + { + "name": "InactiveItemId", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "ActiveItemId", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "PlayersCanToggle", + "type": "bool", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Misc.ShardPollOption.v1.json b/Projects/UOContent/Migrations/Server.Misc.ShardPollOption.v1.json new file mode 100644 index 0000000000..800db20333 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Misc.ShardPollOption.v1.json @@ -0,0 +1,23 @@ +{ + "version": 1, + "type": "Server.Misc.ShardPollOption", + "properties": [ + { + "name": "Title", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Voters", + "type": "System.Net.IPAddress[]", + "rule": "ArrayMigrationRule", + "ruleArguments": [ + "System.Net.IPAddress", + "PrimitiveTypeMigrationRule" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Misc.ShardPoller.v1.json b/Projects/UOContent/Migrations/Server.Misc.ShardPoller.v1.json new file mode 100644 index 0000000000..46345e368d --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Misc.ShardPoller.v1.json @@ -0,0 +1,45 @@ +{ + "version": 1, + "type": "Server.Misc.ShardPoller", + "properties": [ + { + "name": "Title", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Duration", + "type": "System.TimeSpan", + "rule": "PrimitiveTypeMigrationRule" + }, + { + "name": "StartTime", + "type": "System.DateTime", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Active", + "type": "bool", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Options", + "type": "Server.Misc.ShardPollOption[]", + "rule": "ArrayMigrationRule", + "ruleArguments": [ + "Server.Misc.ShardPollOption", + "RawSerializableMigrationRule", + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.PlayerVendor.v3.json b/Projects/UOContent/Migrations/Server.Mobiles.PlayerVendor.v3.json new file mode 100644 index 0000000000..aee2b1da6d --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.PlayerVendor.v3.json @@ -0,0 +1,62 @@ +{ + "version": 3, + "type": "Server.Mobiles.PlayerVendor", + "properties": [ + { + "name": "ShopName", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "NextPayTime", + "type": "System.DateTime", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "DeltaTime" + ] + }, + { + "name": "House", + "type": "Server.Multis.BaseHouse", + "rule": "SerializableInterfaceMigrationRule" + }, + { + "name": "Owner", + "type": "Server.Mobile", + "rule": "SerializableInterfaceMigrationRule" + }, + { + "name": "BankAccount", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "HoldGold", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "SellItems", + "type": "System.Collections.Generic.Dictionary\u003CServer.Item, Server.Mobiles.VendorItem\u003E", + "rule": "DictionaryMigrationRule", + "ruleArguments": [ + "Server.Item", + "SerializableInterfaceMigrationRule", + "0", + "Server.Mobiles.VendorItem", + "RawSerializableMigrationRule", + "1", + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.PlayerVendorPlaceholder.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.PlayerVendorPlaceholder.v0.json new file mode 100644 index 0000000000..bf6971759f --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.PlayerVendorPlaceholder.v0.json @@ -0,0 +1,11 @@ +{ + "version": 0, + "type": "Server.Mobiles.PlayerVendorPlaceholder", + "properties": [ + { + "name": "Vendor", + "type": "Server.Mobiles.PlayerVendor", + "rule": "SerializableInterfaceMigrationRule" + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.VendorBackpack.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.VendorBackpack.v0.json new file mode 100644 index 0000000000..f0c9f6baf2 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.VendorBackpack.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Mobiles.VendorBackpack" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Mobiles.VendorItem.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.VendorItem.v0.json new file mode 100644 index 0000000000..b1fa351fc2 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Mobiles.VendorItem.v0.json @@ -0,0 +1,35 @@ +{ + "version": 0, + "type": "Server.Mobiles.VendorItem", + "properties": [ + { + "name": "Item", + "type": "Server.Item", + "rule": "SerializableInterfaceMigrationRule" + }, + { + "name": "Price", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Description", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Created", + "type": "System.DateTime", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Multis.HouseSign.v0.json b/Projects/UOContent/Migrations/Server.Multis.HouseSign.v0.json new file mode 100644 index 0000000000..4a1fca7564 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Multis.HouseSign.v0.json @@ -0,0 +1,16 @@ +{ + "version": 0, + "type": "Server.Multis.HouseSign", + "properties": [ + { + "name": "Owner", + "type": "Server.Multis.BaseHouse", + "rule": "SerializableInterfaceMigrationRule" + }, + { + "name": "OriginalOwner", + "type": "Server.Mobile", + "rule": "SerializableInterfaceMigrationRule" + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Misc/ShardPoller.cs b/Projects/UOContent/Misc/ShardPoller.cs index 3c12dc1726..85696ca0ab 100644 --- a/Projects/UOContent/Misc/ShardPoller.cs +++ b/Projects/UOContent/Misc/ShardPoller.cs @@ -2,670 +2,612 @@ using System.Collections.Generic; using System.Net; using System.Text.RegularExpressions; +using ModernUO.Serialization; using Server.Gumps; using Server.Network; using Server.Prompts; -namespace Server.Misc +namespace Server.Misc; + +[SerializationGenerator(1, false)] +public partial class ShardPoller : Item { - public class ShardPoller : Item - { - private static readonly List m_ActivePollers = new(); + private static readonly List _activePollers = new(); - private bool m_Active; - private string m_Title; + [SerializableField(1)] + [SerializedCommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + private TimeSpan _duration; - [Constructible(AccessLevel.Administrator)] - public ShardPoller() : base(0x1047) - { - Duration = TimeSpan.FromHours(24.0); - Options = Array.Empty(); - Addresses = Array.Empty(); + [SerializableField(2)] + [SerializedCommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + private DateTime _startTime; - Movable = false; - } + [SerializableField(4)] + private ShardPollOption[] _options; - public ShardPoller(Serial serial) : base(serial) - { - } - - public ShardPollOption[] Options { get; set; } + [Constructible(AccessLevel.Administrator)] + public ShardPoller() : base(0x1047) + { + _duration = TimeSpan.FromHours(24.0); + _options = []; - public IPAddress[] Addresses { get; set; } + Movable = false; + } - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public string Title + [SerializableProperty(0)] + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public string Title + { + get => _title; + set { - get => m_Title; - set => m_Title = ShardPollPrompt.UrlToHref(value); + _title = ShardPollPrompt.UrlToHref(value); + this.MarkDirty(); } + } - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public TimeSpan Duration { get; set; } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public DateTime StartTime { get; set; } - - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public TimeSpan TimeRemaining => - StartTime == DateTime.MinValue || !m_Active - ? TimeSpan.Zero - : Utility.Max(StartTime + Duration - Core.Now, TimeSpan.Zero); + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public TimeSpan TimeRemaining => + StartTime == DateTime.MinValue || !_active + ? TimeSpan.Zero + : Utility.Max(StartTime + Duration - Core.Now, TimeSpan.Zero); - [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] - public bool Active + [SerializableProperty(3)] + [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)] + public bool Active + { + get => _active; + set { - get => m_Active; - set + if (_active == value) { - if (m_Active == value) - { - return; - } + return; + } - m_Active = value; + _active = value; - if (m_Active) - { - StartTime = Core.Now; - m_ActivePollers.Add(this); - } - else - { - m_ActivePollers.Remove(this); - } + if (_active) + { + StartTime = Core.Now; + _activePollers.Add(this); + } + else + { + _activePollers.Remove(this); } + + this.MarkDirty(); } + } - public override string DefaultName => "shard poller"; + public override string DefaultName => "shard poller"; - public bool HasAlreadyVoted(NetState ns) + public bool HasAlreadyVoted(NetState ns) + { + for (var i = 0; i < Options.Length; ++i) { - for (var i = 0; i < Options.Length; ++i) + if (Options[i].HasAlreadyVoted(ns)) { - if (Options[i].HasAlreadyVoted(ns)) - { - return true; - } + return true; } - - return false; } - public void AddVote(NetState ns, ShardPollOption option) + return false; + } + + public void AddVote(NetState ns, ShardPollOption option) + { + option.AddVote(ns); + } + + public void RemoveOption(ShardPollOption option) + { + var index = Array.IndexOf(Options, option); + + if (index < 0) { - option.AddVote(ns); + return; } - public void RemoveOption(ShardPollOption option) - { - var index = Array.IndexOf(Options, option); + var old = Options; + Options = new ShardPollOption[old.Length - 1]; + Array.Copy(old, Options, index); + Array.Copy(old, index + 1, Options, index, Options.Length - index); - if (index < 0) - { - return; - } + } - var old = Options; - Options = new ShardPollOption[old.Length - 1]; + public void AddOption(ShardPollOption option) + { + var old = Options; + Options = new ShardPollOption[old.Length + 1]; + Array.Copy(old, Options, old.Length); - for (var i = 0; i < index; ++i) - { - Options[i] = old[i]; - } + Options[^1] = option; + } - for (var i = index; i < Options.Length; ++i) - { - Options[i] = old[i + 1]; - } - } + public static void Initialize() + { + EventSink.Login += EventSink_Login; + } - public void AddOption(ShardPollOption option) + private static void EventSink_Login(Mobile m) + { + if (_activePollers.Count == 0) { - var old = Options; - Options = new ShardPollOption[old.Length + 1]; + return; + } - for (var i = 0; i < old.Length; ++i) - { - Options[i] = old[i]; - } + Timer.StartTimer(TimeSpan.FromSeconds(1.0), () => EventSink_Login_Callback(m)); + } - Options[old.Length] = option; - } + private static void EventSink_Login_Callback(Mobile from) + { + var ns = from.NetState; - public static void Initialize() + if (ns == null) { - EventSink.Login += EventSink_Login; + return; } - private static void EventSink_Login(Mobile m) - { - if (m_ActivePollers.Count == 0) - { - return; - } - - Timer.StartTimer(TimeSpan.FromSeconds(1.0), () => EventSink_Login_Callback(m)); - } + ShardPollGump spg = null; - private static void EventSink_Login_Callback(Mobile from) + for (var i = 0; i < _activePollers.Count; ++i) { - var ns = from.NetState; + var poller = _activePollers[i]; - if (ns == null) + if (poller.Deleted || !poller.Active) { - return; + continue; } - ShardPollGump spg = null; - - for (var i = 0; i < m_ActivePollers.Count; ++i) + if (poller.TimeRemaining > TimeSpan.Zero) { - var poller = m_ActivePollers[i]; - - if (poller.Deleted || !poller.Active) + if (poller.HasAlreadyVoted(ns)) { continue; } - if (poller.TimeRemaining > TimeSpan.Zero) + if (spg == null) { - if (poller.HasAlreadyVoted(ns)) - { - continue; - } - - if (spg == null) - { - spg = new ShardPollGump(from, poller, false, null); - from.SendGump(spg); - } - else - { - spg.QueuePoll(poller); - } + spg = new ShardPollGump(from, poller, false, null); + from.SendGump(spg); } else { - poller.Active = false; + spg.QueuePoll(poller); } } - } - - public override void OnDoubleClick(Mobile from) - { - if (from.AccessLevel >= AccessLevel.Administrator) + else { - from.SendGump(new ShardPollGump(from, this, true, null)); + poller.Active = false; } } + } - public override void Serialize(IGenericWriter writer) + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.Administrator) { - base.Serialize(writer); - - writer.Write(0); // version + from.SendGump(new ShardPollGump(from, this, true, null)); + } + } - writer.Write(m_Title); - writer.Write(Duration); - writer.Write(StartTime); - writer.Write(m_Active); + private void Deserialize(IGenericReader reader, int version) + { + _title = reader.ReadString(); + _duration = reader.ReadTimeSpan(); + _startTime = reader.ReadDateTime(); + _active = reader.ReadBool(); - writer.Write(Options.Length); + _options = new ShardPollOption[reader.ReadInt()]; - for (var i = 0; i < Options.Length; ++i) - { - Options[i].Serialize(writer); - } + for (var i = 0; i < _options.Length; ++i) + { + var option = _options[i] = new ShardPollOption(); + option.Deserialize(reader); } + } - public override void Deserialize(IGenericReader reader) + [AfterDeserialization] + private void AfterDeserialization() + { + if (_active) { - base.Deserialize(reader); + _activePollers.Add(this); + } + } - var version = reader.ReadInt(); + public override void OnDelete() + { + base.OnDelete(); - switch (version) - { - case 0: - { - m_Title = reader.ReadString(); - Duration = reader.ReadTimeSpan(); - StartTime = reader.ReadDateTime(); - m_Active = reader.ReadBool(); + Active = false; + } +} - Options = new ShardPollOption[reader.ReadInt()]; +[SerializationGenerator(1, false)] +public partial class ShardPollOption +{ + private int _lineBreaks = -1; - for (var i = 0; i < Options.Length; ++i) - { - Options[i] = new ShardPollOption(reader); - } + [SerializableField(1)] + private IPAddress[] _voters; - if (m_Active) - { - m_ActivePollers.Add(this); - } + public ShardPollOption() => _voters = []; - break; - } - } - } + public ShardPollOption(string title) + { + _title = title; + _voters = []; + } - public override void OnDelete() - { - base.OnDelete(); + private void Deserialize(IGenericReader reader, int version) + { + _title = reader.ReadString(); + + _voters = new IPAddress[reader.ReadInt()]; - Active = false; + for (var i = 0; i < _voters.Length; ++i) + { + _voters[i] = Utility.Intern(reader.ReadIPAddress()); } } - public class ShardPollOption + [SerializableProperty(0)] + public string Title { - private string m_Title; - - public ShardPollOption(string title) + get => _title; + set { - m_Title = title; - LineBreaks = GetBreaks(m_Title); - Voters = Array.Empty(); + _title = value; + _lineBreaks = -1; } + } - public ShardPollOption(IGenericReader reader) + public int Votes => Voters.Length; + + public bool HasAlreadyVoted(NetState ns) + { + if (ns == null) { - var version = reader.ReadInt(); + return false; + } - switch (version) - { - case 0: - { - m_Title = reader.ReadString(); - LineBreaks = GetBreaks(m_Title); + var ipAddress = ns.Address; - Voters = new IPAddress[reader.ReadInt()]; + for (var i = 0; i < Voters.Length; ++i) + { + if (Voters[i].MatchClassC(ipAddress)) + { + return true; + } + } - for (var i = 0; i < Voters.Length; ++i) - { - Voters[i] = Utility.Intern(reader.ReadIPAddress()); - } + return false; + } - break; - } - } + public void AddVote(NetState ns) + { + if (ns == null) + { + return; } - public string Title + var old = Voters; + Voters = new IPAddress[old.Length + 1]; + + for (var i = 0; i < old.Length; ++i) { - get => m_Title; - set - { - m_Title = value; - LineBreaks = GetBreaks(m_Title); - } + Voters[i] = old[i]; } - public int LineBreaks { get; private set; } + Voters[old.Length] = ns.Address; + } - public int Votes => Voters.Length; - public IPAddress[] Voters { get; set; } + public int ComputeHeight() + { + var height = GetBreaks() * 18; - public bool HasAlreadyVoted(NetState ns) + if (height > 30) { - if (ns == null) - { - return false; - } + return height; + } - var ipAddress = ns.Address; + return 30; + } - for (var i = 0; i < Voters.Length; ++i) - { - if (Voters[i].MatchClassC(ipAddress)) - { - return true; - } - } + public int GetBreaks() + { + var title = _title; + if (title == null) + { + return 1; + } - return false; + if (_lineBreaks > -1) + { + return _lineBreaks; } - public void AddVote(NetState ns) + var count = 0; + var index = -1; + + do { - if (ns == null) - { - return; - } + ++count; + index = title.IndexOfOrdinal("
", index + 1); + } while (index >= 0); - var old = Voters; - Voters = new IPAddress[old.Length + 1]; + return _lineBreaks = count; + } +} - for (var i = 0; i < old.Length; ++i) - { - Voters[i] = old[i]; - } +public class ShardPollGump : Gump +{ + private const int LabelColor32 = 0xFFFFFF; + private readonly Mobile _from; + private readonly ShardPoller _poller; + private Queue _polls; - Voters[old.Length] = ns.Address; - } + public ShardPollGump(Mobile from, ShardPoller poller, bool editing, Queue polls) : base(50, 50) + { + _from = from; + _poller = poller; + Editing = editing; + _polls = polls; - public int ComputeHeight() - { - var height = LineBreaks * 18; + Closable = false; - if (height > 30) - { - return height; - } + AddPage(0); - return 30; - } + var totalVotes = 0; + var totalOptionHeight = 0; - public int GetBreaks(string title) + for (var i = 0; i < poller.Options.Length; ++i) { - if (title == null) - { - return 1; - } + totalVotes += poller.Options[i].Votes; + totalOptionHeight += poller.Options[i].ComputeHeight() + 5; + } - var count = 0; - var index = -1; + var isViewingResults = editing && poller.Active; + var isCompleted = totalVotes > 0 && !poller.Active; - do - { - ++count; - index = title.IndexOfOrdinal("
", index + 1); - } while (index >= 0); - - return count; + if (editing && !isViewingResults) + { + totalOptionHeight += 35; } - public void Serialize(IGenericWriter writer) - { - writer.Write(0); // version + var height = 115 + totalOptionHeight; - writer.Write(m_Title); + AddBackground(1, 1, 398, height - 2, 3600); + AddAlphaRegion(16, 15, 369, height - 31); - writer.Write(Voters.Length); + AddItem(308, 30, 0x1E5E); - for (var i = 0; i < Voters.Length; ++i) - { - writer.Write(Voters[i]); - } + string title; + + if (editing) + { + title = isCompleted ? "Poll Completed" : "Poll Editor"; + } + else + { + title = "Shard Poll"; } - } - public class ShardPollGump : Gump - { - private const int LabelColor32 = 0xFFFFFF; - private readonly Mobile m_From; - private readonly ShardPoller m_Poller; - private Queue m_Polls; + AddHtml(22, 22, 294, 20, title.Center(LabelColor32)); - public ShardPollGump(Mobile from, ShardPoller poller, bool editing, Queue polls) : base(50, 50) + if (editing) { - m_From = from; - m_Poller = poller; - Editing = editing; - m_Polls = polls; - - Closable = false; + AddHtml(22, 22, 294, 20, $"{totalVotes} total".Color(LabelColor32)); + AddButton(287, 23, 0x2622, 0x2623, 2); + } - AddPage(0); + AddHtml(22, 50, 294, 40, poller.Title.Color(0x99CC66)); - var totalVotes = 0; - var totalOptionHeight = 0; + AddImageTiled(32, 88, 264, 1, 9107); + AddImageTiled(42, 90, 264, 1, 9157); - for (var i = 0; i < poller.Options.Length; ++i) - { - totalVotes += poller.Options[i].Votes; - totalOptionHeight += poller.Options[i].ComputeHeight() + 5; - } + var y = 100; - var isViewingResults = editing && poller.Active; - var isCompleted = totalVotes > 0 && !poller.Active; + for (var i = 0; i < poller.Options.Length; ++i) + { + var option = poller.Options[i]; + var text = option.Title; - if (editing && !isViewingResults) + if (editing && totalVotes > 0) { - totalOptionHeight += 35; - } - - var height = 115 + totalOptionHeight; + var perc = option.Votes / (double)totalVotes; - AddBackground(1, 1, 398, height - 2, 3600); - AddAlphaRegion(16, 15, 369, height - 31); + text = $"[{option.Votes}: {(int)(perc * 100)}%] {text}"; + } - AddItem(308, 30, 0x1E5E); + var optHeight = option.ComputeHeight(); - string title; + y += optHeight / 2; - if (editing) + if (isViewingResults) { - title = isCompleted ? "Poll Completed" : "Poll Editor"; + AddImage(24, y - 15, 0x25FE); } else { - title = "Shard Poll"; + AddRadio(24, y - 15, 0x25F9, 0x25FC, false, 1 + i); } - AddHtml(22, 22, 294, 20, title.Center(LabelColor32)); - - if (editing) - { - AddHtml(22, 22, 294, 20, $"{totalVotes} total".Color(LabelColor32)); - AddButton(287, 23, 0x2622, 0x2623, 2); - } - - AddHtml(22, 50, 294, 40, poller.Title.Color(0x99CC66)); - - AddImageTiled(32, 88, 264, 1, 9107); - AddImageTiled(42, 90, 264, 1, 9157); + var lineBreaks = option.GetBreaks(); - var y = 100; + AddHtml(60, y - 9 * lineBreaks, 250, 18 * lineBreaks, text.Color(LabelColor32)); - for (var i = 0; i < poller.Options.Length; ++i) - { - var option = poller.Options[i]; - var text = option.Title; - - if (editing && totalVotes > 0) - { - var perc = option.Votes / (double)totalVotes; - - text = $"[{option.Votes}: {(int)(perc * 100)}%] {text}"; - } + y += optHeight / 2; + y += 5; + } - var optHeight = option.ComputeHeight(); + if (editing && !isViewingResults) + { + AddRadio(24, y + 15 - 15, 0x25F9, 0x25FC, false, 1 + poller.Options.Length); + AddHtml(60, y + 15 - 9, 250, 18, "Create new option.".Color(0x99CC66)); + } - y += optHeight / 2; + AddButton(314, height - 73, 247, 248, 1); + AddButton(314, height - 47, 242, 241, 0); + } - if (isViewingResults) - { - AddImage(24, y - 15, 0x25FE); - } - else - { - AddRadio(24, y - 15, 0x25F9, 0x25FC, false, 1 + i); - } + public bool Editing { get; } - AddHtml(60, y - 9 * option.LineBreaks, 250, 18 * option.LineBreaks, text.Color(LabelColor32)); + public void QueuePoll(ShardPoller poller) + { + _polls ??= new Queue(4); + _polls.Enqueue(poller); + } - y += optHeight / 2; - y += 5; - } + public override void OnResponse(NetState sender, in RelayInfo info) + { + if (_polls?.Count > 0) + { + var shardPoller = _polls.Dequeue(); - if (editing && !isViewingResults) + if (shardPoller != null) { - AddRadio(24, y + 15 - 15, 0x25F9, 0x25FC, false, 1 + poller.Options.Length); - AddHtml(60, y + 15 - 9, 250, 18, "Create new option.".Color(0x99CC66)); + Timer.StartTimer( + TimeSpan.FromSeconds(1.0), + () => _from.SendGump(new ShardPollGump(_from, shardPoller, false, _polls)) + ); } - - AddButton(314, height - 73, 247, 248, 1); - AddButton(314, height - 47, 242, 241, 0); } - public bool Editing { get; } - - public void QueuePoll(ShardPoller poller) + if (info.ButtonID == 1) { - m_Polls ??= new Queue(4); - - m_Polls.Enqueue(poller); - } + var switches = info.Switches; - public override void OnResponse(NetState sender, in RelayInfo info) - { - if (m_Polls?.Count > 0) + if (switches.Length == 0) { - var shardPoller = m_Polls.Dequeue(); - - if (shardPoller != null) - { - Timer.StartTimer( - TimeSpan.FromSeconds(1.0), - () => m_From.SendGump(new ShardPollGump(m_From, shardPoller, false, m_Polls)) - ); - } + return; } - if (info.ButtonID == 1) - { - var switches = info.Switches; - - if (switches.Length == 0) - { - return; - } + var switched = switches[0] - 1; + ShardPollOption opt = null; - var switched = switches[0] - 1; - ShardPollOption opt = null; - - if (switched >= 0 && switched < m_Poller.Options.Length) - { - opt = m_Poller.Options[switched]; - } + if (switched >= 0 && switched < _poller.Options.Length) + { + opt = _poller.Options[switched]; + } - if (opt == null && !Editing) - { - return; - } + if (opt == null && !Editing) + { + return; + } - if (Editing) + if (Editing) + { + if (!_poller.Active) { - if (!m_Poller.Active) + if (opt == null) { - if (opt == null) - { - m_From.SendMessage($"Enter a title for the option. Escape to cancel."); - } - else - { - m_From.SendMessage($"Enter a title for the option. Escape to cancel. Use \"DEL\" to delete."); - } - - m_From.Prompt = new ShardPollPrompt(m_Poller, opt); + _from.SendMessage("Enter a title for the option. Escape to cancel."); } else { - m_From.SendMessage("You may not edit an active poll. Deactivate it first."); - m_From.SendGump(new ShardPollGump(m_From, m_Poller, Editing, m_Polls)); + _from.SendMessage("Enter a title for the option. Escape to cancel. Use \"DEL\" to delete."); } + + _from.Prompt = new ShardPollPrompt(_poller, opt); } else { - if (!m_Poller.Active) - { - m_From.SendMessage("The poll has been deactivated."); - } - else if (m_Poller.HasAlreadyVoted(sender)) - { - m_From.SendMessage("You have already voted on this poll."); - } - else - { - m_Poller.AddVote(sender, opt); - } + _from.SendMessage("You may not edit an active poll. Deactivate it first."); + _from.SendGump(new ShardPollGump(_from, _poller, Editing, _polls)); } } - else if (info.ButtonID == 2 && Editing) + else { - m_From.SendGump(new ShardPollGump(m_From, m_Poller, Editing, m_Polls)); - m_From.SendGump(new PropertiesGump(m_From, m_Poller)); + if (!_poller.Active) + { + _from.SendMessage("The poll has been deactivated."); + } + else if (_poller.HasAlreadyVoted(sender)) + { + _from.SendMessage("You have already voted on this poll."); + } + else + { + _poller.AddVote(sender, opt); + } } } + else if (info.ButtonID == 2 && Editing) + { + _from.SendGump(new ShardPollGump(_from, _poller, Editing, _polls)); + _from.SendGump(new PropertiesGump(_from, _poller)); + } } +} + +public partial class ShardPollPrompt : Prompt +{ + private readonly ShardPollOption _option; + private readonly ShardPoller _poller; - public class ShardPollPrompt : Prompt + public ShardPollPrompt(ShardPoller poller, ShardPollOption opt) { - private static readonly Regex m_UrlRegex = - new(@"\[url(?:=(.*?))?\](.*?)\[/url\]", RegexOptions.IgnoreCase | RegexOptions.Compiled); + _poller = poller; + _option = opt; + } - private readonly ShardPollOption m_Option; - private readonly ShardPoller m_Poller; + public override void OnCancel(Mobile from) + { + from.SendGump(new ShardPollGump(from, _poller, true, null)); + } - public ShardPollPrompt(ShardPoller poller, ShardPollOption opt) + private static string UrlRegex_Match(Match m) + { + if (m.Groups[1].Success) { - m_Poller = poller; - m_Option = opt; + if (m.Groups[2].Success) + { + return $"{m.Groups[2].Value}"; + } } - - public override void OnCancel(Mobile from) + else if (m.Groups[2].Success) { - from.SendGump(new ShardPollGump(from, m_Poller, true, null)); + return $"{m.Groups[2].Value}"; } - private static string UrlRegex_Match(Match m) - { - if (m.Groups[1].Success) - { - if (m.Groups[2].Success) - { - return $"{m.Groups[2].Value}"; - } - } - else if (m.Groups[2].Success) - { - return $"{m.Groups[2].Value}"; - } + return m.Value; + } - return m.Value; - } + public static string UrlToHref(string text) => text == null ? null : UrlHrefRegex().Replace(text, UrlRegex_Match); - public static string UrlToHref(string text) + public override void OnResponse(Mobile from, string text) + { + if (_poller.Active) { - if (text == null) - { - return null; - } - - return m_UrlRegex.Replace(text, UrlRegex_Match); + from.SendMessage("You may not edit an active poll. Deactivate it first."); } - - public override void OnResponse(Mobile from, string text) + else if (text == "DEL") { - if (m_Poller.Active) + if (_option != null) { - from.SendMessage("You may not edit an active poll. Deactivate it first."); + _poller.RemoveOption(_option); } - else if (text == "DEL") + } + else + { + text = UrlToHref(text); + + if (_option == null) { - if (m_Option != null) - { - m_Poller.RemoveOption(m_Option); - } + _poller.AddOption(new ShardPollOption(text)); } else { - text = UrlToHref(text); - - if (m_Option == null) - { - m_Poller.AddOption(new ShardPollOption(text)); - } - else - { - m_Option.Title = text; - } + _option.Title = text; } - - from.SendGump(new ShardPollGump(from, m_Poller, true, null)); } + + from.SendGump(new ShardPollGump(from, _poller, true, null)); } + + [GeneratedRegex(@"\[url(?:=(.*?))?\](.*?)\[/url\]", RegexOptions.IgnoreCase | RegexOptions.Compiled)] + private static partial Regex UrlHrefRegex(); } diff --git a/Projects/UOContent/Misc/ToggleItem.cs b/Projects/UOContent/Misc/ToggleItem.cs index cf6d475e3b..a2ecac79f7 100644 --- a/Projects/UOContent/Misc/ToggleItem.cs +++ b/Projects/UOContent/Misc/ToggleItem.cs @@ -1,109 +1,87 @@ +using ModernUO.Serialization; using Server.Commands.Generic; -namespace Server.Items +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class ToggleItem : Item { - public class ToggleItem : Item - { - [Constructible] - public ToggleItem(int inactiveItemID, int activeItemID, bool playersCanToggle = false) - : base(inactiveItemID) - { - Movable = false; + [SerializableField(0)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _inactiveItemId; - InactiveItemID = inactiveItemID; - ActiveItemID = activeItemID; - PlayersCanToggle = playersCanToggle; - } + [SerializableField(1)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _activeItemId; - public ToggleItem(Serial serial) - : base(serial) - { - } + [SerializableField(2)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private bool _playersCanToggle; - [CommandProperty(AccessLevel.GameMaster)] - public int InactiveItemID { get; set; } + [Constructible] + public ToggleItem(int inactiveItemID, int activeItemID, bool playersCanToggle = false) : base(inactiveItemID) + { + Movable = false; - [CommandProperty(AccessLevel.GameMaster)] - public int ActiveItemID { get; set; } + _inactiveItemId = inactiveItemID; + _activeItemId = activeItemID; + _playersCanToggle = playersCanToggle; + } - [CommandProperty(AccessLevel.GameMaster)] - public bool PlayersCanToggle { get; set; } + public static void Configure() + { + TargetCommands.Register(new ToggleCommand()); + } - public static void Configure() + public override void OnDoubleClick(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster) { - TargetCommands.Register(new ToggleCommand()); + Toggle(); } - - public override void OnDoubleClick(Mobile from) + else if (!PlayersCanToggle) { - if (from.AccessLevel >= AccessLevel.GameMaster) - { - Toggle(); - } - else if (PlayersCanToggle) - { - if (from.InRange(GetWorldLocation(), 1)) - { - Toggle(); - } - else - { - from.SendLocalizedMessage(500446); // That is too far away. - } - } + return; } - public void Toggle() + if (from.InRange(GetWorldLocation(), 1)) { - ItemID = ItemID == ActiveItemID ? InactiveItemID : ActiveItemID; - Visible = ItemID != 0x1; + Toggle(); } - - public override void Serialize(IGenericWriter writer) + else { - base.Serialize(writer); - - writer.Write(0); // version - - writer.Write(InactiveItemID); - writer.Write(ActiveItemID); - writer.Write(PlayersCanToggle); + from.SendLocalizedMessage(500446); // That is too far away. } + } - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); + public void Toggle() + { + ItemID = ItemID == _activeItemId ? _inactiveItemId : _activeItemId; + Visible = ItemID != 0x1; + } - InactiveItemID = reader.ReadInt(); - ActiveItemID = reader.ReadInt(); - PlayersCanToggle = reader.ReadBool(); + public class ToggleCommand : BaseCommand + { + public ToggleCommand() + { + AccessLevel = AccessLevel.GameMaster; + Supports = CommandSupport.AllItems; + Commands = ["Toggle"]; + ObjectTypes = ObjectTypes.Items; + Usage = "Toggle"; + Description = "Toggles a targeted ToggleItem."; } - public class ToggleCommand : BaseCommand + public override void Execute(CommandEventArgs e, object obj) { - public ToggleCommand() + if (obj is ToggleItem item) { - AccessLevel = AccessLevel.GameMaster; - Supports = CommandSupport.AllItems; - Commands = new[] { "Toggle" }; - ObjectTypes = ObjectTypes.Items; - Usage = "Toggle"; - Description = "Toggles a targeted ToggleItem."; + item.Toggle(); + AddResponse("The item has been toggled."); } - - public override void Execute(CommandEventArgs e, object obj) + else { - if (obj is ToggleItem item) - { - item.Toggle(); - AddResponse("The item has been toggled."); - } - else - { - LogFailure("That is not a ToggleItem."); - } + LogFailure("That is not a ToggleItem."); } } } diff --git a/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs b/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs index 7c3ce75067..0b7f1ed1f9 100644 --- a/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs +++ b/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Globalization; -using System.Linq; +using ModernUO.Serialization; using Server.ContextMenus; using Server.Engines.BulkOrders; -using Server.Ethics; using Server.Gumps; using Server.Items; using Server.Misc; @@ -12,1700 +10,1274 @@ using Server.Prompts; using Server.Targeting; -namespace Server.Mobiles +namespace Server.Mobiles; + +[AttributeUsage(AttributeTargets.Class)] +public class PlayerVendorTargetAttribute : Attribute; + +/** + * Note: When upgrading player vendors to the new system (Expansion enter AOS+), bump the serialization version up by 1. + * Next, uncomment the MigrateFrom function and change the `V3Content` type to match the serialization version + * before it was bumped. Then run publish.cmd to generate the migration file. + */ +[SerializationGenerator(3, false)] +public partial class PlayerVendor : Mobile { - [AttributeUsage(AttributeTargets.Class)] - public class PlayerVendorTargetAttribute : Attribute - { - } + private Timer _payTimer; + + [InvalidateProperties] + [SerializableField(0)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private string _shopName; + + [DeltaDateTime] + [SerializableField(1, setter: "private")] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private DateTime _nextPayTime; + + [SerializableField(3)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private Mobile _owner; + + [SerializableField(4)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _bankAccount; - public class VendorItem + [SerializableField(5)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _holdGold; + + [SerializableField(6)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private Dictionary _sellItems; + + public PlayerVendor(Mobile owner, BaseHouse house) { - private string m_Description; + Owner = owner; + House = house; - public VendorItem(Item item, int price, string description, DateTime created) + if (BaseHouse.NewVendorSystem) + { + BankAccount = 0; + HoldGold = 4; + } + else { - Item = item; - Price = price; - m_Description = description ?? ""; - Created = created; - Valid = true; + BankAccount = 1000; + HoldGold = 0; } - public Item Item { get; } + ShopName = "Shop Not Yet Named"; - public int Price { get; } + _sellItems = new Dictionary(); - public string FormattedPrice => - Core.ML ? Price.ToString("N0", CultureInfo.GetCultureInfo("en-US")) : Price.ToString(); + CantWalk = true; - public string Description + if (!Core.AOS) { - get => m_Description; - set - { - m_Description = value ?? ""; - - if (Valid) - { - Item.InvalidateProperties(); - } - } + NameHue = 0x35; } - public DateTime Created { get; } + InitStats(100, 100, 25); + InitBody(); + InitOutfit(); - public bool IsForSale => Price >= 0; - public bool IsForFree => Price == 0; + var delay = PayTimer.GetInterval(); - public bool Valid { get; private set; } + _payTimer = new PayTimer(this, delay); + _payTimer.Start(); - public void Invalidate() - { - Valid = false; - } + NextPayTime = Core.Now + delay; } - public class VendorBackpack : Backpack + public PlayerVendorPlaceholder Placeholder { get; set; } + + [SerializableProperty(2)] + public BaseHouse House { - public VendorBackpack() + get => _house; + set { - Layer = Layer.Backpack; - Weight = 1.0; - } + _house?.PlayerVendors.Remove(this); + value?.PlayerVendors.Add(this); - public VendorBackpack(Serial serial) : base(serial) - { + _house = value; + this.MarkDirty(); } + } - public override int DefaultMaxWeight => 0; - - public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) + public int ChargePerDay + { + get { - if (!base.CheckHold(m, item, message, checkItems, plusItems, plusWeight)) + if (BaseHouse.NewVendorSystem) { - return false; + return ChargePerRealWorldDay / 12; } - if (Ethic.IsImbued(item, true)) + long total = 0; + foreach (var value in _sellItems.Values) { - if (message) - { - m.SendMessage("Imbued items may not be sold here."); - } - - return false; + total += value.Price; } - if (!BaseHouse.NewVendorSystem && Parent is PlayerVendor vendor) - { - var house = vendor.House; + return (int)(20 + Math.Max(total - 500, 0) / 500); + } + } - if (house?.IsAosRules == true && !house.CheckAosStorage(1 + item.TotalItems + plusItems)) + public int ChargePerRealWorldDay + { + get + { + if (BaseHouse.NewVendorSystem) + { + long total = 0; + foreach (var value in _sellItems.Values) { - if (message) - { - m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. - } - - return false; + total += value.Price; } + + return (int)(60 + total / 500 * 3); } - return true; + return ChargePerDay * 12; } + } - public override bool IsAccessibleTo(Mobile m) => true; + /* + // Uncomment this to migrate to the new vendor system. + // Make sure to update V3Content to match the serialization version before the bump. + private void MigrateFrom(V3Content content) + { + MigrateToNewVendorSystem(); + } + */ - public override bool CheckItemUse(Mobile from, Item item) + private void MigrateToNewVendorSystem() + { + if (BaseHouse.NewVendorSystem) { - if (!base.CheckItemUse(from, item)) - { - return false; - } + Timer.StartTimer(FixDresswear); - if (item is Container or BulkOrderBook) - { - return true; - } + NextPayTime = Core.Now + PayTimer.GetInterval(); + HoldGold += BankAccount; + BankAccount = 0; + } + } - from.SendLocalizedMessage(500447); // That is not accessible. - return false; + private void Deserialize(IGenericReader reader, int version) + { + reader.ReadBool(); // New vendor system? + _shopName = reader.ReadString(); + _nextPayTime = reader.ReadDeltaTime(); + _house = reader.ReadEntity(); + _owner = reader.ReadEntity(); + _bankAccount = reader.ReadInt(); + _holdGold = reader.ReadInt(); + var count = reader.ReadInt(); + + _sellItems = new Dictionary(count); + for (var i = 0; i < count; i++) + { + var item = reader.ReadEntity(); + var vi = new VendorItem(); + vi.Deserialize(reader); + _sellItems[item] = vi; } + } - public override bool CheckTarget(Mobile from, Target targ, object targeted) => - base.CheckTarget(from, targ, targeted) && - (from.AccessLevel >= AccessLevel.GameMaster || - targ.GetType().IsDefined(typeof(PlayerVendorTargetAttribute), false)); + [AfterDeserialization] + private void AfterDeserialization() + { + var delay = _nextPayTime - Core.Now; + + _payTimer = new PayTimer(this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero); + _payTimer.Start(); - public override void GetChildContextMenuEntries(Mobile from, List list, Item item) + Blessed = false; + + if (Core.AOS && NameHue == 0x35) { - base.GetChildContextMenuEntries(from, list, item); + NameHue = -1; + } + } - if (RootParent is not PlayerVendor pv || pv.IsOwner(from)) - { - return; - } + public void InitBody() + { + Hue = Race.Human.RandomSkinHue(); + SpeechHue = 0x3B2; - var vi = pv.GetVendorItem(item); + if (!Core.AOS) + { + NameHue = 0x35; + } - if (vi != null) - { - list.Add(new BuyEntry(item)); - } + if (Female = Utility.RandomBool()) + { + Body = 0x191; + Name = NameList.RandomName("female"); + } + else + { + Body = 0x190; + Name = NameList.RandomName("male"); } + } + + public virtual void InitOutfit() + { + Item item = new FancyShirt(Utility.RandomNeutralHue()); + item.Layer = Layer.InnerTorso; + AddItem(item); + AddItem(new LongPants(Utility.RandomNeutralHue())); + AddItem(new BodySash(Utility.RandomNeutralHue())); + AddItem(new Boots(Utility.RandomNeutralHue())); + AddItem(new Cloak(Utility.RandomNeutralHue())); + + Utility.AssignRandomHair(this); + + Container pack = new VendorBackpack(); + pack.Movable = false; + AddItem(pack); + } - public override void GetChildNameProperties(IPropertyList list, Item item) + public virtual bool IsOwner(Mobile m) + { + if (m.AccessLevel >= AccessLevel.GameMaster) { - base.GetChildNameProperties(list, item); + return true; + } - var pv = RootParent as PlayerVendor; + if (BaseHouse.NewVendorSystem && House != null) + { + return House.IsOwner(m); + } - var vi = pv?.GetVendorItem(item); + return m == Owner; + } - if (vi == null) - { - return; - } + protected List GetItems() + { + var list = new List(); - if (!vi.IsForSale) - { - list.Add(1043307); // Price: Not for sale. - } - else if (vi.IsForFree) - { - list.Add(1043306); // Price: FREE! - } - else + foreach (var item in Items) + { + if (item.Movable && item != Backpack && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair) { - list.Add(1043304, vi.FormattedPrice); // Price: ~1_COST~ + list.Add(item); } } - public override void GetChildProperties(IPropertyList list, Item item) + if (Backpack != null) { - base.GetChildProperties(list, item); + list.AddRange(Backpack.Items); + } - var pv = RootParent as PlayerVendor; + return list; + } - var vi = pv?.GetVendorItem(item); + public virtual void Destroy(bool toBackpack) + { + Return(); - if (vi?.Description?.Length > 0) - { - list.Add(1043305, vi.Description); //
Seller's Description:
"~1_DESC~" - } + if (!BaseHouse.NewVendorSystem) + { + FixDresswear(); } - public override void OnSingleClickContained(Mobile from, Item item) + /* Possible cases regarding item return: + * + * 1. No item must be returned + * -> do nothing. + * 2. ( toBackpack is false OR the vendor is in the internal map ) AND the vendor is associated with a AOS house + * -> put the items into the moving crate or a vendor inventory, + * depending on whether the vendor owner is also the house owner. + * 3. ( toBackpack is true OR the vendor isn't associated with any AOS house ) AND the vendor isn't in the internal map + * -> put the items into a backpack. + * 4. The vendor isn't associated with any house AND it's in the internal map + * -> do nothing (we can't do anything). + */ + + var list = GetItems(); + + if (list.Count > 0 || HoldGold > 0) // No case 1 { - if (RootParent is PlayerVendor vendor) + if ((!toBackpack || Map == Map.Internal) && House?.IsAosRules == true) // Case 2 { - var vi = vendor.GetVendorItem(item); - - if (vi != null) + if (House.IsOwner(Owner)) // Move to moving crate { - if (!vi.IsForSale) - { - item.LabelTo(from, 1043307); // Price: Not for sale. - } - else if (vi.IsForFree) + House.MovingCrate ??= new MovingCrate(House); + + if (HoldGold > 0) { - item.LabelTo(from, 1043306); // Price: FREE! + Banker.Deposit(House.MovingCrate, HoldGold); } - else + + foreach (var item in list) { - item.LabelTo(from, 1043304, vi.FormattedPrice); // Price: ~1_COST~ + House.MovingCrate.DropItem(item); } + } + else // Move to vendor inventory + { + var inventory = new VendorInventory(House, Owner, Name, ShopName); + inventory.Gold = HoldGold; - if (!string.IsNullOrEmpty(vi.Description)) + foreach (var item in list) { - item.LabelTo(from, $"Description: {vi.Description}"); + inventory.AddItem(item); } + + House.VendorInventories.Add(inventory); } } + else if ((toBackpack || House?.IsAosRules != true) && Map != Map.Internal) // Case 3 - Move to backpack + { + var backpack = new Backpack(); - base.OnSingleClickContained(from, item); - } + if (HoldGold > 0) + { + Banker.Deposit(backpack, HoldGold); + } - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); + foreach (var item in list) + { + backpack.DropItem(item); + } - writer.Write(0); // version + backpack.MoveToWorld(Location, Map); + } } - public override void Deserialize(IGenericReader reader) + Delete(); + } + + private void FixDresswear() + { + for (var i = 0; i < Items.Count; ++i) { - base.Deserialize(reader); + var item = Items[i]; + + item.Layer = item switch + { + BaseHat => Layer.Helm, + BaseMiddleTorso => Layer.MiddleTorso, + BaseOuterLegs => Layer.OuterLegs, + BaseOuterTorso => Layer.OuterTorso, + BasePants => Layer.Pants, + BaseShirt => Layer.Shirt, + BaseWaist => Layer.Waist, + BaseShoes => Layer.Shoes, + _ => item.Layer + }; - var version = reader.ReadInt(); + if (item is Sandals) + { + item.Hue = 0; + } } + } - private class BuyEntry : ContextMenuEntry - { - private readonly Item m_Item; + public override void OnAfterDelete() + { + base.OnAfterDelete(); - public BuyEntry(Item item) : base(6103) => m_Item = item; + _payTimer.Stop(); - public override bool NonLocalUse => true; + House = null; - public override void OnClick() - { - if (m_Item.Deleted) - { - return; - } + Placeholder?.Delete(); + } - PlayerVendor.TryToBuy(m_Item, Owner.From); - } + public override bool IsSnoop(Mobile from) => false; + + public override void GetProperties(IPropertyList list) + { + base.GetProperties(list); + + if (BaseHouse.NewVendorSystem) + { + list.Add(1062449, ShopName); // Shop Name: ~1_NAME~ } } - public class PlayerVendor : Mobile + public VendorItem GetVendorItem(Item item) + { + _sellItems.TryGetValue(item, out var v); + return v; + } + + private VendorItem SetVendorItem(Item item, int price, string description) => + SetVendorItem(item, price, description, Core.Now); + + private VendorItem SetVendorItem(Item item, int price, string description, DateTime created) { - private BaseHouse m_House; + RemoveVendorItem(item); + + var vi = new VendorItem(item, price, description, created); + _sellItems[item] = vi; - private Timer m_PayTimer; - private Dictionary m_SellItems; + item.InvalidateProperties(); + + return vi; + } - private string m_ShopName; + private void RemoveVendorItem(Item item) + { + var vi = GetVendorItem(item); - public PlayerVendor(Mobile owner, BaseHouse house) + if (vi != null) { - Owner = owner; - House = house; + vi.Invalidate(); + _sellItems.Remove(item); - if (BaseHouse.NewVendorSystem) - { - BankAccount = 0; - HoldGold = 4; - } - else + foreach (var subItem in item.Items) { - BankAccount = 1000; - HoldGold = 0; + RemoveVendorItem(subItem); } - ShopName = "Shop Not Yet Named"; + item.InvalidateProperties(); + } + } + + private bool CanBeVendorItem(Item item) + { + var parent = item.Parent as Item; - m_SellItems = new Dictionary(); + if (parent == Backpack) + { + return true; + } - CantWalk = true; + if (parent is Container) + { + var parentVI = GetVendorItem(parent); - if (!Core.AOS) + if (parentVI != null) { - NameHue = 0x35; + return !parentVI.IsForSale; } + } - InitStats(100, 100, 25); - InitBody(); - InitOutfit(); - - var delay = PayTimer.GetInterval(); + return false; + } - m_PayTimer = new PayTimer(this, delay); - m_PayTimer.Start(); + public override void OnSubItemAdded(Item item) + { + base.OnSubItemAdded(item); - NextPayTime = Core.Now + delay; + if (GetVendorItem(item) == null && CanBeVendorItem(item)) + { + SetVendorItem(item, 999, ""); } + } - public PlayerVendor(Serial serial) : base(serial) + public override void OnSubItemRemoved(Item item) + { + base.OnSubItemRemoved(item); + + if (item.GetBounce() == null) { + RemoveVendorItem(item); } + } - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Owner { get; set; } + public override void OnSubItemBounceCleared(Item item) + { + base.OnSubItemBounceCleared(item); - [CommandProperty(AccessLevel.GameMaster)] - public int BankAccount { get; set; } + if (!CanBeVendorItem(item)) + { + RemoveVendorItem(item); + } + } - [CommandProperty(AccessLevel.GameMaster)] - public int HoldGold { get; set; } + public override void OnItemRemoved(Item item) + { + base.OnItemRemoved(item); - [CommandProperty(AccessLevel.GameMaster)] - public string ShopName + if (item == Backpack) { - get => m_ShopName; - set + foreach (var subItem in item.Items) { - m_ShopName = value ?? ""; - - InvalidateProperties(); + RemoveVendorItem(subItem); } } + } - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextPayTime { get; private set; } - - public PlayerVendorPlaceholder Placeholder { get; set; } - - public BaseHouse House + public override bool OnDragDrop(Mobile from, Item item) + { + if (!IsOwner(from)) { - get => m_House; - set - { - m_House?.PlayerVendors.Remove(this); - - value?.PlayerVendors.Add(this); - - m_House = value; - } + SayTo(from, 503209); // I can only take item from the shop owner. + return false; } - public int ChargePerDay + if (item is Gold) { - get + if (BaseHouse.NewVendorSystem) { - if (BaseHouse.NewVendorSystem) + if (HoldGold < 1000000) { - return ChargePerRealWorldDay / 12; + SayTo(from, 503210); // I'll take that to fund my services. + + HoldGold += item.Amount; + item.Delete(); + + return true; } - var total = m_SellItems.Values.Aggregate( - 0, - (current, vi) => - current + vi.Price - ) - 500; + from.SendLocalizedMessage( + 1062493 + ); // Your vendor has sufficient funds for operation and cannot accept this gold. - return (int)(20 + Math.Max(total, 0) / 500); + return false; } - } - public int ChargePerRealWorldDay - { - get + if (BankAccount < 1000000) { - if (BaseHouse.NewVendorSystem) - { - var total = m_SellItems.Values.Aggregate(0, (current, vi) => current + vi.Price); + SayTo(from, 503210); // I'll take that to fund my services. - return (int)(60 + total / 500 * 3); - } + BankAccount += item.Amount; + item.Delete(); - return ChargePerDay * 12; + return true; } + + from.SendLocalizedMessage( + 1062493 + ); // Your vendor has sufficient funds for operation and cannot accept this gold. + + return false; } - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); + var newItem = GetVendorItem(item) == null; - writer.Write(2); // version + if (Backpack?.TryDropItem(from, item, false) == true) + { + if (newItem) + { + OnItemGiven(from, item); + } - writer.Write(BaseHouse.NewVendorSystem); - writer.Write(m_ShopName); - writer.WriteDeltaTime(NextPayTime); - writer.Write(House); + return true; + } - writer.Write(Owner); - writer.Write(BankAccount); - writer.Write(HoldGold); + SayTo(from, 503211); // I can't carry any more. + return false; + } - writer.Write(m_SellItems.Count); - foreach (var vi in m_SellItems.Values) + public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) + { + if (IsOwner(from)) + { + if (GetVendorItem(item) == null) { - writer.Write(vi.Item); - writer.Write(vi.Price); - writer.Write(vi.Description); - - writer.Write(vi.Created); + Timer.StartTimer(() => OnItemGiven(from, item)); } + + return true; } - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); + SayTo(from, 503209); // I can only take item from the shop owner. + return false; + } - var version = reader.ReadInt(); + private void OnItemGiven(Mobile from, Item item) + { + var vi = GetVendorItem(item); - var newVendorSystem = false; + if (vi == null) + { + return; + } - switch (version) - { - case 2: - case 1: - { - newVendorSystem = reader.ReadBool(); - m_ShopName = reader.ReadString(); - NextPayTime = reader.ReadDeltaTime(); - House = (BaseHouse)reader.ReadEntity(); + var name = item.Name.DefaultIfNullOrEmpty($"#{item.LabelNumber}"); - goto case 0; - } - case 0: - { - Owner = reader.ReadEntity(); - BankAccount = reader.ReadInt(); - HoldGold = reader.ReadInt(); + from.SendLocalizedMessage(1043303, name); // Type in a price and description for ~1_ITEM~ (ESC=not for sale) + from.Prompt = new VendorPricePrompt(this, vi); + } - var count = reader.ReadInt(); + public override bool AllowEquipFrom(Mobile from) => + BaseHouse.NewVendorSystem && IsOwner(from) || base.AllowEquipFrom(from); - m_SellItems = new Dictionary(count); + public override bool CheckNonlocalLift(Mobile from, Item item) + { + if (item.IsChildOf(Backpack)) + { + if (IsOwner(from)) + { + return true; + } - for (var i = 0; i < count; i++) - { - var item = reader.ReadEntity(); + SayTo(from, 503223); // If you'd like to purchase an item, just ask. + return false; + } - var price = reader.ReadInt(); - if (price > 100000000) - { - price = 100000000; - } + if (BaseHouse.NewVendorSystem && IsOwner(from)) + { + return true; + } - var description = reader.ReadString(); + return base.CheckNonlocalLift(from, item); + } - var created = version < 1 ? Core.Now : reader.ReadDateTime(); + public bool CanInteractWith(Mobile from, bool ownerOnly) + { + if (!from.CanSee(this) || !Utility.InUpdateRange(from.Location, Location) || !from.CheckAlive()) + { + return false; + } - if (item != null) - { - SetVendorItem(item, version < 1 && price <= 0 ? -1 : price, description, created); - } - } + if (ownerOnly) + { + return IsOwner(from); + } - break; - } - } + if (House?.IsBanned(from) == true && !IsOwner(from)) + { + from.SendLocalizedMessage( + 1062674 + ); // You can't shop from this home as you have been banned from this establishment. + return false; + } - var newVendorSystemActivated = BaseHouse.NewVendorSystem && !newVendorSystem; + return true; + } - if (version < 1 || newVendorSystemActivated) - { - if (version < 1) - { - m_ShopName = "Shop Not Yet Named"; - Timer.StartTimer(() => UpgradeFromVersion0(newVendorSystemActivated)); - } - else - { - Timer.StartTimer(FixDresswear); - } - - NextPayTime = Core.Now + PayTimer.GetInterval(); - - if (newVendorSystemActivated) - { - HoldGold += BankAccount; - BankAccount = 0; - } - } - - if (version < 2 && RawStr == 75 && RawDex == 75 && RawInt == 75) - { - InitStats(100, 100, 25); - } - - var delay = NextPayTime - Core.Now; - - m_PayTimer = new PayTimer(this, delay > TimeSpan.Zero ? delay : TimeSpan.Zero); - m_PayTimer.Start(); - - Blessed = false; - - if (Core.AOS && NameHue == 0x35) - { - NameHue = -1; - } - } - - private void UpgradeFromVersion0(bool newVendorSystem) + public override void OnDoubleClick(Mobile from) + { + if (IsOwner(from)) { - var toRemove = new List(); - - foreach (var vi in m_SellItems.Values) - { - if (!CanBeVendorItem(vi.Item)) - { - toRemove.Add(vi.Item); - } - else - { - vi.Description = vi.Description.FixHtml(); - } - } - - foreach (var item in toRemove) - { - RemoveVendorItem(item); - } - - House = BaseHouse.FindHouseAt(this); - - if (newVendorSystem) - { - ActivateNewVendorSystem(); - } + SendOwnerGump(from); } - - private void ActivateNewVendorSystem() + else if (CanInteractWith(from, false)) { - FixDresswear(); - - if (House?.IsOwner(Owner) == false) - { - Destroy(false); - } + OpenBackpack(from); } + } - public void InitBody() + public override void DisplayPaperdollTo(Mobile m) + { + if (BaseHouse.NewVendorSystem) { - Hue = Race.Human.RandomSkinHue(); - SpeechHue = 0x3B2; - - if (!Core.AOS) - { - NameHue = 0x35; - } - - if (Female = Utility.RandomBool()) - { - Body = 0x191; - Name = NameList.RandomName("female"); - } - else - { - Body = 0x190; - Name = NameList.RandomName("male"); - } + base.DisplayPaperdollTo(m); } - - public virtual void InitOutfit() + else if (CanInteractWith(m, false)) { - Item item = new FancyShirt(Utility.RandomNeutralHue()); - item.Layer = Layer.InnerTorso; - AddItem(item); - AddItem(new LongPants(Utility.RandomNeutralHue())); - AddItem(new BodySash(Utility.RandomNeutralHue())); - AddItem(new Boots(Utility.RandomNeutralHue())); - AddItem(new Cloak(Utility.RandomNeutralHue())); - - Utility.AssignRandomHair(this); - - Container pack = new VendorBackpack(); - pack.Movable = false; - AddItem(pack); + OpenBackpack(m); } + } - public virtual bool IsOwner(Mobile m) + public void SendOwnerGump(Mobile to) + { + if (BaseHouse.NewVendorSystem) { - if (m.AccessLevel >= AccessLevel.GameMaster) - { - return true; - } + to.CloseGump(); + to.CloseGump(); - if (BaseHouse.NewVendorSystem && House != null) - { - return House.IsOwner(m); - } - - return m == Owner; + to.SendGump(new NewPlayerVendorOwnerGump(this)); } - - protected List GetItems() + else { - var list = new List(); - - foreach (var item in Items) - { - if (item.Movable && item != Backpack && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair) - { - list.Add(item); - } - } + to.CloseGump(); + to.CloseGump(); - if (Backpack != null) - { - list.AddRange(Backpack.Items); - } - - return list; + to.SendGump(new PlayerVendorOwnerGump(this)); } + } - public virtual void Destroy(bool toBackpack) + public void OpenBackpack(Mobile from) + { + if (Backpack != null) { - Return(); - - if (!BaseHouse.NewVendorSystem) - { - FixDresswear(); - } - - /* Possible cases regarding item return: - * - * 1. No item must be returned - * -> do nothing. - * 2. ( toBackpack is false OR the vendor is in the internal map ) AND the vendor is associated with a AOS house - * -> put the items into the moving crate or a vendor inventory, - * depending on whether the vendor owner is also the house owner. - * 3. ( toBackpack is true OR the vendor isn't associated with any AOS house ) AND the vendor isn't in the internal map - * -> put the items into a backpack. - * 4. The vendor isn't associated with any house AND it's in the internal map - * -> do nothing (we can't do anything). - */ - - var list = GetItems(); - - if (list.Count > 0 || HoldGold > 0) // No case 1 - { - if ((!toBackpack || Map == Map.Internal) && House?.IsAosRules == true) // Case 2 - { - if (House.IsOwner(Owner)) // Move to moving crate - { - House.MovingCrate ??= new MovingCrate(House); + SayTo(from, IsOwner(from) ? 1010642 : 503208); // Take a look at my/your goods. - if (HoldGold > 0) - { - Banker.Deposit(House.MovingCrate, HoldGold); - } - - foreach (var item in list) - { - House.MovingCrate.DropItem(item); - } - } - else // Move to vendor inventory - { - var inventory = new VendorInventory(House, Owner, Name, ShopName); - inventory.Gold = HoldGold; - - foreach (var item in list) - { - inventory.AddItem(item); - } - - House.VendorInventories.Add(inventory); - } - } - else if ((toBackpack || House?.IsAosRules != true) && Map != Map.Internal) // Case 3 - Move to backpack - { - Container backpack = new Backpack(); - - if (HoldGold > 0) - { - Banker.Deposit(backpack, HoldGold); - } - - foreach (var item in list) - { - backpack.DropItem(item); - } - - backpack.MoveToWorld(Location, Map); - } - } - - Delete(); + Backpack.DisplayTo(from); } + } - private void FixDresswear() + public static void TryToBuy(Item item, Mobile from) + { + if (item.RootParent is not PlayerVendor vendor || !vendor.CanInteractWith(from, false)) { - for (var i = 0; i < Items.Count; ++i) - { - var item = Items[i]; - - item.Layer = item switch - { - BaseHat => Layer.Helm, - BaseMiddleTorso => Layer.MiddleTorso, - BaseOuterLegs => Layer.OuterLegs, - BaseOuterTorso => Layer.OuterTorso, - BasePants => Layer.Pants, - BaseShirt => Layer.Shirt, - BaseWaist => Layer.Waist, - BaseShoes => Layer.Shoes, - _ => item.Layer - }; - - if (item is Sandals) - { - item.Hue = 0; - } - } + return; } - public override void OnAfterDelete() + if (vendor.IsOwner(from)) { - base.OnAfterDelete(); - - m_PayTimer.Stop(); - - House = null; - - Placeholder?.Delete(); + vendor.SayTo(from, 503212); // You own this shop, just take what you want. + return; } - public override bool IsSnoop(Mobile from) => false; + var vi = vendor.GetVendorItem(item); - public override void GetProperties(IPropertyList list) + if (vi == null) { - base.GetProperties(list); - - if (BaseHouse.NewVendorSystem) - { - list.Add(1062449, ShopName); // Shop Name: ~1_NAME~ - } + vendor.SayTo(from, 503216); // You can't buy that. } - - public VendorItem GetVendorItem(Item item) + else if (!vi.IsForSale) { - m_SellItems.TryGetValue(item, out var v); - return v; + vendor.SayTo(from, 503202); // This item is not for sale. } - - private VendorItem SetVendorItem(Item item, int price, string description) => - SetVendorItem(item, price, description, Core.Now); - - private VendorItem SetVendorItem(Item item, int price, string description, DateTime created) + else if (vi.Created + TimeSpan.FromMinutes(1.0) > Core.Now) { - RemoveVendorItem(item); - - var vi = new VendorItem(item, price, description, created); - m_SellItems[item] = vi; - - item.InvalidateProperties(); - - return vi; + from.SendMessage("You cannot buy this item right now. Please wait one minute and try again."); } - - private void RemoveVendorItem(Item item) + else { - var vi = GetVendorItem(item); - - if (vi != null) - { - vi.Invalidate(); - m_SellItems.Remove(item); - - foreach (var subItem in item.Items) - { - RemoveVendorItem(subItem); - } - - item.InvalidateProperties(); - } + from.CloseGump(); + from.SendGump(new PlayerVendorBuyGump(vendor, vi)); } + } - private bool CanBeVendorItem(Item item) + public void CollectGold(Mobile to) + { + if (HoldGold > 0) { - var parent = item.Parent as Item; - - if (parent == Backpack) - { - return true; - } - - if (parent is Container) - { - var parentVI = GetVendorItem(parent); + SayTo(to, $"How much of the {HoldGold} that I'm holding would you like?"); + to.SendMessage("Enter the amount of gold you wish to withdraw (ESC = CANCEL):"); - if (parentVI != null) - { - return !parentVI.IsForSale; - } - } - - return false; + to.Prompt = new CollectGoldPrompt(this); } - - public override void OnSubItemAdded(Item item) + else { - base.OnSubItemAdded(item); - - if (GetVendorItem(item) == null && CanBeVendorItem(item)) - { - SetVendorItem(item, 999, ""); - } + SayTo(to, 503215); // I am holding no gold for you. } + } - public override void OnSubItemRemoved(Item item) + public int GiveGold(Mobile to, int amount) + { + if (amount <= 0) { - base.OnSubItemRemoved(item); - - if (item.GetBounce() == null) - { - RemoveVendorItem(item); - } + return 0; } - public override void OnSubItemBounceCleared(Item item) + if (amount > HoldGold) { - base.OnSubItemBounceCleared(item); - - if (!CanBeVendorItem(item)) - { - RemoveVendorItem(item); - } + SayTo(to, $"I'm sorry, but I'm only holding {HoldGold} gold for you."); + return 0; } - public override void OnItemRemoved(Item item) - { - base.OnItemRemoved(item); + var amountGiven = Banker.DepositUpTo(to, amount); + HoldGold -= amountGiven; - if (item == Backpack) - { - foreach (var subItem in item.Items) - { - RemoveVendorItem(subItem); - } - } - } - - public override bool OnDragDrop(Mobile from, Item item) + if (amountGiven > 0) { - if (!IsOwner(from)) - { - SayTo(from, 503209); // I can only take item from the shop owner. - return false; - } - - if (item is Gold) - { - if (BaseHouse.NewVendorSystem) - { - if (HoldGold < 1000000) - { - SayTo(from, 503210); // I'll take that to fund my services. - - HoldGold += item.Amount; - item.Delete(); - - return true; - } - - from.SendLocalizedMessage( - 1062493 - ); // Your vendor has sufficient funds for operation and cannot accept this gold. - - return false; - } - - if (BankAccount < 1000000) - { - SayTo(from, 503210); // I'll take that to fund my services. - - BankAccount += item.Amount; - item.Delete(); - - return true; - } - - from.SendLocalizedMessage( - 1062493 - ); // Your vendor has sufficient funds for operation and cannot accept this gold. - - return false; - } - - var newItem = GetVendorItem(item) == null; - - if (Backpack?.TryDropItem(from, item, false) == true) - { - if (newItem) - { - OnItemGiven(from, item); - } - - return true; - } - - SayTo(from, 503211); // I can't carry any more. - return false; + to.SendLocalizedMessage( + 1060397, + amountGiven.ToString() + ); // ~1_AMOUNT~ gold has been deposited into your bank box. } - public override bool CheckNonlocalDrop(Mobile from, Item item, Item target) + if (amountGiven == 0) { - if (IsOwner(from)) - { - if (GetVendorItem(item) == null) - { - Timer.StartTimer(() => OnItemGiven(from, item)); - } - - return true; - } - - SayTo(from, 503209); // I can only take item from the shop owner. - return false; + SayTo( + to, + 1070755 + ); // Your bank box cannot hold the gold you are requesting. I will keep the gold until you can take it. } - - private void OnItemGiven(Mobile from, Item item) + else if (amount > amountGiven) { - var vi = GetVendorItem(item); - - if (vi == null) - { - return; - } - - var name = item.Name.DefaultIfNullOrEmpty($"#{item.LabelNumber}"); - - from.SendLocalizedMessage(1043303, name); // Type in a price and description for ~1_ITEM~ (ESC=not for sale) - from.Prompt = new VendorPricePrompt(this, vi); + SayTo( + to, + 1070756 + ); // I can only give you part of the gold now, as your bank box is too full to hold the full amount. } - - public override bool AllowEquipFrom(Mobile from) => - BaseHouse.NewVendorSystem && IsOwner(from) || base.AllowEquipFrom(from); - - public override bool CheckNonlocalLift(Mobile from, Item item) + else if (HoldGold > 0) { - if (item.IsChildOf(Backpack)) - { - if (IsOwner(from)) - { - return true; - } - - SayTo(from, 503223); // If you'd like to purchase an item, just ask. - return false; - } - - if (BaseHouse.NewVendorSystem && IsOwner(from)) - { - return true; - } - - return base.CheckNonlocalLift(from, item); - } - - public bool CanInteractWith(Mobile from, bool ownerOnly) - { - if (!from.CanSee(this) || !Utility.InUpdateRange(from.Location, Location) || !from.CheckAlive()) - { - return false; - } - - if (ownerOnly) - { - return IsOwner(from); - } - - if (House?.IsBanned(from) == true && !IsOwner(from)) - { - from.SendLocalizedMessage( - 1062674 - ); // You can't shop from this home as you have been banned from this establishment. - return false; - } - - return true; - } - - public override void OnDoubleClick(Mobile from) - { - if (IsOwner(from)) - { - SendOwnerGump(from); - } - else if (CanInteractWith(from, false)) - { - OpenBackpack(from); - } + SayTo(to, 1042639); // Your gold has been transferred. } - - public override void DisplayPaperdollTo(Mobile m) + else { - if (BaseHouse.NewVendorSystem) - { - base.DisplayPaperdollTo(m); - } - else if (CanInteractWith(m, false)) - { - OpenBackpack(m); - } + SayTo(to, 503234); // All the gold I have been carrying for you has been deposited into your bank account. } - public void SendOwnerGump(Mobile to) - { - if (BaseHouse.NewVendorSystem) - { - to.CloseGump(); - to.CloseGump(); - - to.SendGump(new NewPlayerVendorOwnerGump(this)); - } - else - { - to.CloseGump(); - to.CloseGump(); + return amountGiven; + } - to.SendGump(new PlayerVendorOwnerGump(this)); - } - } + public void Dismiss(Mobile from) + { + var pack = Backpack; - public void OpenBackpack(Mobile from) + if (pack?.Items.Count > 0) { - if (Backpack != null) - { - SayTo(from, IsOwner(from) ? 1010642 : 503208); // Take a look at my/your goods. - - Backpack.DisplayTo(from); - } + SayTo(from, 1038325); // You cannot dismiss me while I am holding your goods. + return; } - public static void TryToBuy(Item item, Mobile from) + if (HoldGold > 0) { - if (item.RootParent is not PlayerVendor vendor || !vendor.CanInteractWith(from, false)) - { - return; - } - - if (vendor.IsOwner(from)) - { - vendor.SayTo(from, 503212); // You own this shop, just take what you want. - return; - } - - var vi = vendor.GetVendorItem(item); - - if (vi == null) - { - vendor.SayTo(from, 503216); // You can't buy that. - } - else if (!vi.IsForSale) - { - vendor.SayTo(from, 503202); // This item is not for sale. - } - else if (vi.Created + TimeSpan.FromMinutes(1.0) > Core.Now) - { - from.SendMessage("You cannot buy this item right now. Please wait one minute and try again."); - } - else - { - from.CloseGump(); - from.SendGump(new PlayerVendorBuyGump(vendor, vi)); - } - } + GiveGold(from, HoldGold); - public void CollectGold(Mobile to) - { if (HoldGold > 0) { - SayTo(to, $"How much of the {HoldGold} that I'm holding would you like?"); - to.SendMessage("Enter the amount of gold you wish to withdraw (ESC = CANCEL):"); - - to.Prompt = new CollectGoldPrompt(this); - } - else - { - SayTo(to, 503215); // I am holding no gold for you. + return; } } - public int GiveGold(Mobile to, int amount) - { - if (amount <= 0) - { - return 0; - } + Destroy(true); + } - if (amount > HoldGold) - { - SayTo(to, $"I'm sorry, but I'm only holding {HoldGold} gold for you."); - return 0; - } + public void Rename(Mobile from) + { + from.SendLocalizedMessage(1062494); // Enter a new name for your vendor (20 characters max): - var amountGiven = Banker.DepositUpTo(to, amount); - HoldGold -= amountGiven; + from.Prompt = new VendorNamePrompt(this); + } - if (amountGiven > 0) - { - to.SendLocalizedMessage( - 1060397, - amountGiven.ToString() - ); // ~1_AMOUNT~ gold has been deposited into your bank box. - } + public void RenameShop(Mobile from) + { + from.SendLocalizedMessage(1062433); // Enter a new name for your shop (20 chars max): - if (amountGiven == 0) - { - SayTo( - to, - 1070755 - ); // Your bank box cannot hold the gold you are requesting. I will keep the gold until you can take it. - } - else if (amount > amountGiven) - { - SayTo( - to, - 1070756 - ); // I can only give you part of the gold now, as your bank box is too full to hold the full amount. - } - else if (HoldGold > 0) - { - SayTo(to, 1042639); // Your gold has been transferred. - } - else - { - SayTo(to, 503234); // All the gold I have been carrying for you has been deposited into your bank account. - } + from.Prompt = new ShopNamePrompt(this); + } - return amountGiven; + public bool CheckTeleport(Mobile to) + { + if (Deleted || !IsOwner(to) || House == null || Map == Map.Internal) + { + return false; } - public void Dismiss(Mobile from) + if (House.IsInside(to) || to.Map != House.Map || !House.InRange(to.Location, 5)) { - var pack = Backpack; - - if (pack?.Items.Count > 0) - { - SayTo(from, 1038325); // You cannot dismiss me while I am holding your goods. - return; - } - - if (HoldGold > 0) - { - GiveGold(from, HoldGold); - - if (HoldGold > 0) - { - return; - } - } - - Destroy(true); + return false; } - public void Rename(Mobile from) + if (Placeholder == null) { - from.SendLocalizedMessage(1062494); // Enter a new name for your vendor (20 characters max): + Placeholder = new PlayerVendorPlaceholder(this); + Placeholder.MoveToWorld(Location, Map); - from.Prompt = new VendorNamePrompt(this); - } + MoveToWorld(to.Location, to.Map); - public void RenameShop(Mobile from) + to.SendLocalizedMessage( + 1062431 + ); // This vendor has been moved out of the house to your current location temporarily. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. + } + else { - from.SendLocalizedMessage(1062433); // Enter a new name for your shop (20 chars max): + Placeholder.RestartTimer(); - from.Prompt = new ShopNamePrompt(this); + to.SendLocalizedMessage( + 1062430 + ); // This vendor is currently temporarily in a location outside its house. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. } - public bool CheckTeleport(Mobile to) - { - if (Deleted || !IsOwner(to) || House == null || Map == Map.Internal) - { - return false; - } + return true; + } - if (House.IsInside(to) || to.Map != House.Map || !House.InRange(to.Location, 5)) - { - return false; - } + public void Return() + { + Placeholder?.Delete(); + } - if (Placeholder == null) - { - Placeholder = new PlayerVendorPlaceholder(this); - Placeholder.MoveToWorld(Location, Map); + public override void GetContextMenuEntries(Mobile from, List list) + { + if (from.Alive && Placeholder != null && IsOwner(from)) + { + list.Add(new ReturnVendorEntry(this)); + } - MoveToWorld(to.Location, to.Map); + base.GetContextMenuEntries(from, list); + } - to.SendLocalizedMessage( - 1062431 - ); // This vendor has been moved out of the house to your current location temporarily. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. - } - else - { - Placeholder.RestartTimer(); + public override bool HandlesOnSpeech(Mobile from) => from.Alive && from.GetDistanceToSqrt(this) <= 3; - to.SendLocalizedMessage( - 1062430 - ); // This vendor is currently temporarily in a location outside its house. The vendor will return home automatically after two minutes have passed once you are done managing its inventory or customizing it. - } + public bool WasNamed(string speech) => Name != null && speech.InsensitiveStartsWith(Name); - return true; - } + public override void OnSpeech(SpeechEventArgs e) + { + var from = e.Mobile; - public void Return() + if (e.Handled || !from.Alive || from.GetDistanceToSqrt(this) > 3) { - Placeholder?.Delete(); + return; } - public override void GetContextMenuEntries(Mobile from, List list) + if (e.HasKeyword(0x3C) || e.HasKeyword(0x171) && WasNamed(e.Speech)) // vendor buy, *buy* { - if (from.Alive && Placeholder != null && IsOwner(from)) + if (IsOwner(from)) { - list.Add(new ReturnVendorEntry(this)); + SayTo(from, 503212); // You own this shop, just take what you want. } + else if (House?.IsBanned(from) != true) + { + from.SendLocalizedMessage(503213); // Select the item you wish to buy. + from.Target = new PVBuyTarget(); - base.GetContextMenuEntries(from, list); + e.Handled = true; + } } - - public override bool HandlesOnSpeech(Mobile from) => from.Alive && from.GetDistanceToSqrt(this) <= 3; - - public bool WasNamed(string speech) => Name != null && speech.InsensitiveStartsWith(Name); - - public override void OnSpeech(SpeechEventArgs e) + else if (e.HasKeyword(0x3D) || e.HasKeyword(0x172) && WasNamed(e.Speech)) // vendor browse, *browse { - var from = e.Mobile; - - if (e.Handled || !from.Alive || from.GetDistanceToSqrt(this) > 3) - { - return; - } - - if (e.HasKeyword(0x3C) || e.HasKeyword(0x171) && WasNamed(e.Speech)) // vendor buy, *buy* + if (House?.IsBanned(from) == true && !IsOwner(from)) { - if (IsOwner(from)) - { - SayTo(from, 503212); // You own this shop, just take what you want. - } - else if (House?.IsBanned(from) != true) - { - from.SendLocalizedMessage(503213); // Select the item you wish to buy. - from.Target = new PVBuyTarget(); - - e.Handled = true; - } + SayTo(from, 1062674); // You can't shop from this home as you have been banned from this establishment. } - else if (e.HasKeyword(0x3D) || e.HasKeyword(0x172) && WasNamed(e.Speech)) // vendor browse, *browse + else { - if (House?.IsBanned(from) == true && !IsOwner(from)) + if (WasNamed(e.Speech)) { - SayTo(from, 1062674); // You can't shop from this home as you have been banned from this establishment. + OpenBackpack(from); } else { - if (WasNamed(e.Speech)) - { - OpenBackpack(from); - } - else + foreach (var m in e.Mobile.GetMobilesInRange(2)) { - foreach (var m in e.Mobile.GetMobilesInRange(2)) + if (m.CanSee(e.Mobile) && m.InLOS(e.Mobile)) { - if (m.CanSee(e.Mobile) && m.InLOS(e.Mobile)) - { - m.OpenBackpack(from); - } + m.OpenBackpack(from); } } - - e.Handled = true; } + + e.Handled = true; } - else if (e.HasKeyword(0x3E) || e.HasKeyword(0x173) && WasNamed(e.Speech)) // vendor collect, *collect + } + else if (e.HasKeyword(0x3E) || e.HasKeyword(0x173) && WasNamed(e.Speech)) // vendor collect, *collect + { + if (IsOwner(from)) { - if (IsOwner(from)) - { - CollectGold(from); + CollectGold(from); - e.Handled = true; - } + e.Handled = true; } - else if (e.HasKeyword(0x3F) || e.HasKeyword(0x174) && WasNamed(e.Speech)) // vendor status, *status + } + else if (e.HasKeyword(0x3F) || e.HasKeyword(0x174) && WasNamed(e.Speech)) // vendor status, *status + { + if (IsOwner(from)) { - if (IsOwner(from)) - { - SendOwnerGump(from); + SendOwnerGump(from); - e.Handled = true; - } - else - { - SayTo(from, 503226); // What do you care? You don't run this shop. - } + e.Handled = true; } - else if (e.HasKeyword(0x40) || e.HasKeyword(0x175) && WasNamed(e.Speech)) // vendor dismiss, *dismiss + else { - if (IsOwner(from)) - { - Dismiss(from); + SayTo(from, 503226); // What do you care? You don't run this shop. + } + } + else if (e.HasKeyword(0x40) || e.HasKeyword(0x175) && WasNamed(e.Speech)) // vendor dismiss, *dismiss + { + if (IsOwner(from)) + { + Dismiss(from); - e.Handled = true; - } + e.Handled = true; } - else if (e.HasKeyword(0x41) || e.HasKeyword(0x176) && WasNamed(e.Speech)) // vendor cycle, *cycle + } + else if (e.HasKeyword(0x41) || e.HasKeyword(0x176) && WasNamed(e.Speech)) // vendor cycle, *cycle + { + if (IsOwner(from)) { - if (IsOwner(from)) - { - Direction = GetDirectionTo(from); + Direction = GetDirectionTo(from); - e.Handled = true; - } + e.Handled = true; } } + } - public override bool CanBeDamaged() => false; + public override bool CanBeDamaged() => false; - private class ReturnVendorEntry : ContextMenuEntry - { - private readonly PlayerVendor m_Vendor; + private class ReturnVendorEntry : ContextMenuEntry + { + private readonly PlayerVendor m_Vendor; - public ReturnVendorEntry(PlayerVendor vendor) : base(6214) => m_Vendor = vendor; + public ReturnVendorEntry(PlayerVendor vendor) : base(6214) => m_Vendor = vendor; - public override void OnClick() - { - var from = Owner.From; + public override void OnClick() + { + var from = Owner.From; - if (!m_Vendor.Deleted && m_Vendor.IsOwner(from) && from.CheckAlive()) - { - m_Vendor.Return(); - } + if (!m_Vendor.Deleted && m_Vendor.IsOwner(from) && from.CheckAlive()) + { + m_Vendor.Return(); } } + } - private class PayTimer : Timer + private class PayTimer : Timer + { + private readonly PlayerVendor m_Vendor; + + public PayTimer(PlayerVendor vendor, TimeSpan delay) : base(delay, GetInterval()) { - private readonly PlayerVendor m_Vendor; + m_Vendor = vendor; + } - public PayTimer(PlayerVendor vendor, TimeSpan delay) : base(delay, GetInterval()) + public static TimeSpan GetInterval() + { + if (BaseHouse.NewVendorSystem) { - m_Vendor = vendor; + return TimeSpan.FromDays(1.0); } - public static TimeSpan GetInterval() - { - if (BaseHouse.NewVendorSystem) - { - return TimeSpan.FromDays(1.0); - } + return TimeSpan.FromMinutes(Clock.MinutesPerUODay); + } - return TimeSpan.FromMinutes(Clock.MinutesPerUODay); - } + protected override void OnTick() + { + m_Vendor.NextPayTime = Core.Now + Interval; - protected override void OnTick() + int pay; + int totalGold; + if (BaseHouse.NewVendorSystem) { - m_Vendor.NextPayTime = Core.Now + Interval; - - int pay; - int totalGold; - if (BaseHouse.NewVendorSystem) - { - pay = m_Vendor.ChargePerRealWorldDay; - totalGold = m_Vendor.HoldGold; - } - else - { - pay = m_Vendor.ChargePerDay; - totalGold = m_Vendor.BankAccount + m_Vendor.HoldGold; - } + pay = m_Vendor.ChargePerRealWorldDay; + totalGold = m_Vendor.HoldGold; + } + else + { + pay = m_Vendor.ChargePerDay; + totalGold = m_Vendor.BankAccount + m_Vendor.HoldGold; + } - if (pay > totalGold) - { - m_Vendor.Destroy(!BaseHouse.NewVendorSystem); - } - else + if (pay > totalGold) + { + m_Vendor.Destroy(!BaseHouse.NewVendorSystem); + } + else + { + if (!BaseHouse.NewVendorSystem) { - if (!BaseHouse.NewVendorSystem) + if (m_Vendor.BankAccount >= pay) { - if (m_Vendor.BankAccount >= pay) - { - m_Vendor.BankAccount -= pay; - pay = 0; - } - else - { - pay -= m_Vendor.BankAccount; - m_Vendor.BankAccount = 0; - } + m_Vendor.BankAccount -= pay; + pay = 0; + } + else + { + pay -= m_Vendor.BankAccount; + m_Vendor.BankAccount = 0; } - - m_Vendor.HoldGold -= pay; } + + m_Vendor.HoldGold -= pay; } } + } - [PlayerVendorTarget] - private class PVBuyTarget : Target - { - public PVBuyTarget() : base(3, false, TargetFlags.None) => AllowNonlocal = true; + [PlayerVendorTarget] + private class PVBuyTarget : Target + { + public PVBuyTarget() : base(3, false, TargetFlags.None) => AllowNonlocal = true; - protected override void OnTarget(Mobile from, object targeted) + protected override void OnTarget(Mobile from, object targeted) + { + if (targeted is Item item) { - if (targeted is Item item) - { - TryToBuy(item, from); - } + TryToBuy(item, from); } } + } + + private class VendorPricePrompt : Prompt + { + private readonly PlayerVendor m_Vendor; + private readonly VendorItem m_VI; - private class VendorPricePrompt : Prompt + public VendorPricePrompt(PlayerVendor vendor, VendorItem vi) { - private readonly PlayerVendor m_Vendor; - private readonly VendorItem m_VI; + m_Vendor = vendor; + m_VI = vi; + } - public VendorPricePrompt(PlayerVendor vendor, VendorItem vi) + public override void OnResponse(Mobile from, string text) + { + if (!m_VI.Valid || !m_Vendor.CanInteractWith(from, true)) { - m_Vendor = vendor; - m_VI = vi; + return; } - public override void OnResponse(Mobile from, string text) - { - if (!m_VI.Valid || !m_Vendor.CanInteractWith(from, true)) - { - return; - } + string firstWord; - string firstWord; + var sep = text.IndexOfAny(new[] { ' ', ',' }); + firstWord = sep >= 0 ? text[..sep] : text; - var sep = text.IndexOfAny(new[] { ' ', ',' }); - firstWord = sep >= 0 ? text[..sep] : text; + string description; - string description; + if (int.TryParse(firstWord, out var price)) + { + description = sep >= 0 ? text[(sep + 1)..].Trim() : ""; + } + else + { + price = -1; + description = text.Trim(); + } - if (int.TryParse(firstWord, out var price)) - { - description = sep >= 0 ? text[(sep + 1)..].Trim() : ""; - } - else - { - price = -1; - description = text.Trim(); - } + SetInfo(from, price, description.FixHtml()); + } - SetInfo(from, price, description.FixHtml()); + public override void OnCancel(Mobile from) + { + if (!m_VI.Valid || !m_Vendor.CanInteractWith(from, true)) + { + return; } - public override void OnCancel(Mobile from) - { - if (!m_VI.Valid || !m_Vendor.CanInteractWith(from, true)) - { - return; - } + SetInfo(from, -1, ""); + } - SetInfo(from, -1, ""); - } + private void SetInfo(Mobile from, int price, string description) + { + var item = m_VI.Item; - private void SetInfo(Mobile from, int price, string description) - { - var item = m_VI.Item; + var setPrice = false; - var setPrice = false; + if (price < 0) // Not for sale + { + price = -1; - if (price < 0) // Not for sale + if (item is Container) { - price = -1; - - if (item is Container) + if (item is LockableContainer container && container.Locked) { - if (item is LockableContainer container && container.Locked) - { - m_Vendor.SayTo(from, 1043298); // Locked items may not be made not-for-sale. - } - else if (item.Items.Count > 0) - { - m_Vendor.SayTo(from, 1043299); // To be not for sale, all items in a container must be for sale. - } - else - { - setPrice = true; - } + m_Vendor.SayTo(from, 1043298); // Locked items may not be made not-for-sale. } - else if (item is BaseBook or BulkOrderBook) + else if (item.Items.Count > 0) { - setPrice = true; + m_Vendor.SayTo(from, 1043299); // To be not for sale, all items in a container must be for sale. } else { - m_Vendor.SayTo( - from, - 1043301 - ); // Only the following may be made not-for-sale: books, containers, keyrings, and items in for-sale containers. + setPrice = true; } } - else + else if (item is BaseBook or BulkOrderBook) { - if (price > 100000000) - { - price = 100000000; - from.SendMessage("You cannot price items above 100,000,000 gold. The price has been adjusted."); - } - setPrice = true; } - - if (setPrice) - { - m_Vendor.SetVendorItem(item, price, description); - } else { - m_VI.Description = description; + m_Vendor.SayTo( + from, + 1043301 + ); // Only the following may be made not-for-sale: books, containers, keyrings, and items in for-sale containers. } } - } - - private class CollectGoldPrompt : Prompt - { - private readonly PlayerVendor m_Vendor; - - public CollectGoldPrompt(PlayerVendor vendor) => m_Vendor = vendor; - - public override void OnResponse(Mobile from, string text) + else { - if (!m_Vendor.CanInteractWith(from, true)) - { - return; - } - - text = text.Trim(); - - if (!int.TryParse(text, out var amount)) + if (price > 100000000) { - amount = 0; + price = 100000000; + from.SendMessage("You cannot price items above 100,000,000 gold. The price has been adjusted."); } - GiveGold(from, amount); + setPrice = true; } - public override void OnCancel(Mobile from) + if (setPrice) { - if (!m_Vendor.CanInteractWith(from, true)) - { - return; - } - - GiveGold(from, 0); + m_Vendor.SetVendorItem(item, price, description); } - - private void GiveGold(Mobile to, int amount) + else { - if (amount <= 0) - { - m_Vendor.SayTo(to, "Very well. I will hold on to the money for now then."); - } - else - { - m_Vendor.GiveGold(to, amount); - } + m_VI.Description = description; } } + } - private class VendorNamePrompt : Prompt - { - private readonly PlayerVendor m_Vendor; + private class CollectGoldPrompt : Prompt + { + private readonly PlayerVendor m_Vendor; - public VendorNamePrompt(PlayerVendor vendor) => m_Vendor = vendor; + public CollectGoldPrompt(PlayerVendor vendor) => m_Vendor = vendor; - public override void OnResponse(Mobile from, string text) + public override void OnResponse(Mobile from, string text) + { + if (!m_Vendor.CanInteractWith(from, true)) { - if (!m_Vendor.CanInteractWith(from, true)) - { - return; - } - - var name = text.Trim(); - - if (!NameVerification.Validate(name, 1, 20, true, true, true, 0, NameVerification.Empty)) - { - m_Vendor.SayTo(from, "That name is unacceptable."); - return; - } - - m_Vendor.Name = name.FixHtml(); + return; + } - from.SendLocalizedMessage(1062496); // Your vendor has been renamed. + text = text.Trim(); - from.SendGump(new NewPlayerVendorOwnerGump(m_Vendor)); + if (!int.TryParse(text, out var amount)) + { + amount = 0; } + + GiveGold(from, amount); } - private class ShopNamePrompt : Prompt + public override void OnCancel(Mobile from) { - private readonly PlayerVendor m_Vendor; - - public ShopNamePrompt(PlayerVendor vendor) => m_Vendor = vendor; - - public override void OnResponse(Mobile from, string text) + if (!m_Vendor.CanInteractWith(from, true)) { - if (!m_Vendor.CanInteractWith(from, true)) - { - return; - } - - var name = text.Trim(); - - if (!NameVerification.Validate(name, 1, 20, true, true, true, 0, NameVerification.Empty)) - { - m_Vendor.SayTo(from, "That name is unacceptable."); - return; - } + return; + } - m_Vendor.ShopName = name.FixHtml(); + GiveGold(from, 0); + } - from.SendGump(new NewPlayerVendorOwnerGump(m_Vendor)); + private void GiveGold(Mobile to, int amount) + { + if (amount <= 0) + { + m_Vendor.SayTo(to, "Very well. I will hold on to the money for now then."); + } + else + { + m_Vendor.GiveGold(to, amount); } } } - public class PlayerVendorPlaceholder : Item + private class VendorNamePrompt : Prompt { - private readonly ExpireTimer m_Timer; - - public PlayerVendorPlaceholder(PlayerVendor vendor) : base(0x1F28) - { - Hue = 0x672; - Movable = false; - - Vendor = vendor; - - m_Timer = new ExpireTimer(this); - m_Timer.Start(); - } + private readonly PlayerVendor m_Vendor; - public PlayerVendorPlaceholder(Serial serial) : base(serial) - { - } + public VendorNamePrompt(PlayerVendor vendor) => m_Vendor = vendor; - [CommandProperty(AccessLevel.GameMaster)] - public PlayerVendor Vendor { get; private set; } - - public override void GetProperties(IPropertyList list) + public override void OnResponse(Mobile from, string text) { - base.GetProperties(list); - - if (Vendor != null) + if (!m_Vendor.CanInteractWith(from, true)) { - list.Add(1062498, Vendor.Name); // reserved for vendor ~1_NAME~ + return; } - } - public void RestartTimer() - { - m_Timer.Stop(); - m_Timer.Start(); - } + var name = text.Trim(); - public override void OnDelete() - { - if (Vendor?.Deleted == false) + if (!NameVerification.Validate(name, 1, 20, true, true, true, 0, NameVerification.Empty)) { - Vendor.MoveToWorld(Location, Map); - Vendor.Placeholder = null; + m_Vendor.SayTo(from, "That name is unacceptable."); + return; } - } - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); + m_Vendor.Name = name.FixHtml(); - writer.WriteEncodedInt(0); + from.SendLocalizedMessage(1062496); // Your vendor has been renamed. - writer.Write(Vendor); + from.SendGump(new NewPlayerVendorOwnerGump(m_Vendor)); } + } - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - - Vendor = (PlayerVendor)reader.ReadEntity(); + private class ShopNamePrompt : Prompt + { + private readonly PlayerVendor m_Vendor; - Timer.StartTimer(Delete); - } + public ShopNamePrompt(PlayerVendor vendor) => m_Vendor = vendor; - private class ExpireTimer : Timer + public override void OnResponse(Mobile from, string text) { - private readonly PlayerVendorPlaceholder m_Placeholder; - - public ExpireTimer(PlayerVendorPlaceholder placeholder) : base(TimeSpan.FromMinutes(2.0)) + if (!m_Vendor.CanInteractWith(from, true)) { - m_Placeholder = placeholder; + return; } - protected override void OnTick() + var name = text.Trim(); + + if (!NameVerification.Validate(name, 1, 20, true, true, true, 0, NameVerification.Empty)) { - m_Placeholder.Delete(); + m_Vendor.SayTo(from, "That name is unacceptable."); + return; } + + m_Vendor.ShopName = name.FixHtml(); + + from.SendGump(new NewPlayerVendorOwnerGump(m_Vendor)); } } } diff --git a/Projects/UOContent/Mobiles/Vendors/PlayerVendorPlaceholder.cs b/Projects/UOContent/Mobiles/Vendors/PlayerVendorPlaceholder.cs new file mode 100644 index 0000000000..f4eb079857 --- /dev/null +++ b/Projects/UOContent/Mobiles/Vendors/PlayerVendorPlaceholder.cs @@ -0,0 +1,52 @@ +using System; +using ModernUO.Serialization; + +namespace Server.Mobiles; + +[SerializationGenerator(0)] +public partial class PlayerVendorPlaceholder : Item +{ + private readonly Timer _timer; + + [SerializableField(0, setter: "private")] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private PlayerVendor _vendor; + + public PlayerVendorPlaceholder(PlayerVendor vendor) : base(0x1F28) + { + Hue = 0x672; + Movable = false; + + _vendor = vendor; + + _timer = Timer.DelayCall(TimeSpan.FromMinutes(2.0), Delete); + } + + public override void GetProperties(IPropertyList list) + { + base.GetProperties(list); + + if (Vendor != null) + { + list.Add(1062498, Vendor.Name); // reserved for vendor ~1_NAME~ + } + } + + public void RestartTimer() + { + _timer.Stop(); + _timer.Start(); + } + + public override void OnDelete() + { + if (Vendor?.Deleted == false) + { + Vendor.MoveToWorld(Location, Map); + Vendor.Placeholder = null; + } + } + + [AfterDeserialization(false)] + private void AfterDeserialization() => Delete(); +} diff --git a/Projects/UOContent/Mobiles/Vendors/VendorBackpack.cs b/Projects/UOContent/Mobiles/Vendors/VendorBackpack.cs new file mode 100644 index 0000000000..4d628bccfa --- /dev/null +++ b/Projects/UOContent/Mobiles/Vendors/VendorBackpack.cs @@ -0,0 +1,188 @@ +using System.Collections.Generic; +using ModernUO.Serialization; +using Server.ContextMenus; +using Server.Engines.BulkOrders; +using Server.Ethics; +using Server.Items; +using Server.Multis; +using Server.Targeting; + +namespace Server.Mobiles; + +[SerializationGenerator(0, false)] +public partial class VendorBackpack : Backpack +{ + public VendorBackpack() + { + Layer = Layer.Backpack; + Weight = 1.0; + } + + public override int DefaultMaxWeight => 0; + + public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight) + { + if (!base.CheckHold(m, item, message, checkItems, plusItems, plusWeight)) + { + return false; + } + + if (Ethic.IsImbued(item, true)) + { + if (message) + { + m.SendMessage("Imbued items may not be sold here."); + } + + return false; + } + + if (!BaseHouse.NewVendorSystem && Parent is PlayerVendor vendor) + { + var house = vendor.House; + + if (house?.IsAosRules == true && !house.CheckAosStorage(1 + item.TotalItems + plusItems)) + { + if (message) + { + m.SendLocalizedMessage(1061839); // This action would exceed the secure storage limit of the house. + } + + return false; + } + } + + return true; + } + + public override bool IsAccessibleTo(Mobile m) => true; + + public override bool CheckItemUse(Mobile from, Item item) + { + if (!base.CheckItemUse(from, item)) + { + return false; + } + + if (item is Container or BulkOrderBook) + { + return true; + } + + from.SendLocalizedMessage(500447); // That is not accessible. + return false; + } + + public override bool CheckTarget(Mobile from, Target targ, object targeted) => + base.CheckTarget(from, targ, targeted) && + (from.AccessLevel >= AccessLevel.GameMaster || + targ.GetType().IsDefined(typeof(PlayerVendorTargetAttribute), false)); + + public override void GetChildContextMenuEntries(Mobile from, List list, Item item) + { + base.GetChildContextMenuEntries(from, list, item); + + if (RootParent is not PlayerVendor pv || pv.IsOwner(from)) + { + return; + } + + var vi = pv.GetVendorItem(item); + + if (vi != null) + { + list.Add(new BuyEntry(item)); + } + } + + public override void GetChildNameProperties(IPropertyList list, Item item) + { + base.GetChildNameProperties(list, item); + + var pv = RootParent as PlayerVendor; + + var vi = pv?.GetVendorItem(item); + + if (vi == null) + { + return; + } + + if (!vi.IsForSale) + { + list.Add(1043307); // Price: Not for sale. + } + else if (vi.IsForFree) + { + list.Add(1043306); // Price: FREE! + } + else + { + list.Add(1043304, vi.FormattedPrice); // Price: ~1_COST~ + } + } + + public override void GetChildProperties(IPropertyList list, Item item) + { + base.GetChildProperties(list, item); + + var pv = RootParent as PlayerVendor; + + var vi = pv?.GetVendorItem(item); + + if (vi?.Description?.Length > 0) + { + list.Add(1043305, vi.Description); //
Seller's Description:
"~1_DESC~" + } + } + + public override void OnSingleClickContained(Mobile from, Item item) + { + if (RootParent is PlayerVendor vendor) + { + var vi = vendor.GetVendorItem(item); + + if (vi != null) + { + if (!vi.IsForSale) + { + item.LabelTo(from, 1043307); // Price: Not for sale. + } + else if (vi.IsForFree) + { + item.LabelTo(from, 1043306); // Price: FREE! + } + else + { + item.LabelTo(from, 1043304, vi.FormattedPrice); // Price: ~1_COST~ + } + + if (!string.IsNullOrEmpty(vi.Description)) + { + item.LabelTo(from, $"Description: {vi.Description}"); + } + } + } + + base.OnSingleClickContained(from, item); + } + + private class BuyEntry : ContextMenuEntry + { + private readonly Item m_Item; + + public BuyEntry(Item item) : base(6103) => m_Item = item; + + public override bool NonLocalUse => true; + + public override void OnClick() + { + if (m_Item.Deleted) + { + return; + } + + PlayerVendor.TryToBuy(m_Item, Owner.From); + } + } +} diff --git a/Projects/UOContent/Mobiles/Vendors/VendorItem.cs b/Projects/UOContent/Mobiles/Vendors/VendorItem.cs new file mode 100644 index 0000000000..6ff8482138 --- /dev/null +++ b/Projects/UOContent/Mobiles/Vendors/VendorItem.cs @@ -0,0 +1,64 @@ +using System; +using System.Globalization; +using ModernUO.Serialization; + +namespace Server.Mobiles; + +[SerializationGenerator(0, false)] +public partial class VendorItem +{ + [SerializableField(0)] + private Item _item; + + [SerializableField(1)] + private int _price; + + [SerializableField(3)] + private DateTime _created; + + public VendorItem() + { + } + + public VendorItem(Item item, int price, string description, DateTime created) + { + _item = item; + _price = price; + _description = description ?? ""; + _created = created; + Valid = true; + } + + public string FormattedPrice => + Core.ML ? Price.ToString("N0", CultureInfo.GetCultureInfo("en-US")) : Price.ToString(); + + [SerializableProperty(2)] + public string Description + { + get => _description; + set + { + _description = value ?? ""; + + if (Valid) + { + Item.InvalidateProperties(); + } + } + } + + public bool IsForSale => Price >= 0; + public bool IsForFree => Price == 0; + public bool Valid { get; private set; } + + public void Invalidate() => Valid = false; + + [AfterDeserialization] + private void AfterDeserialization() + { + if (_price > 100000000) + { + _price = 100000000; + } + } +} diff --git a/Projects/UOContent/Multis/Houses/HousePlacementTool.cs b/Projects/UOContent/Multis/Houses/HousePlacementTool.cs index ed0a068622..d03a615976 100644 --- a/Projects/UOContent/Multis/Houses/HousePlacementTool.cs +++ b/Projects/UOContent/Multis/Houses/HousePlacementTool.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using ModernUO.Serialization; using Server.Gumps; using Server.Mobiles; using Server.Multis; @@ -7,2305 +8,2281 @@ using Server.Regions; using Server.Targeting; -namespace Server.Items +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class HousePlacementTool : Item { - public class HousePlacementTool : Item + [Constructible] + public HousePlacementTool() : base(0x14F6) { - [Constructible] - public HousePlacementTool() : base(0x14F6) - { - Weight = 3.0; - LootType = LootType.Blessed; - } - - public HousePlacementTool(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1060651; // a house placement tool + Weight = 3.0; + LootType = LootType.Blessed; + } - public override void OnDoubleClick(Mobile from) - { - if (IsChildOf(from.Backpack)) - { - from.SendGump(new HousePlacementCategoryGump(from)); - } - else - { - from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. - } - } + public override int LabelNumber => 1060651; // a house placement tool - public override void Serialize(IGenericWriter writer) + public override void OnDoubleClick(Mobile from) + { + if (IsChildOf(from.Backpack)) { - base.Serialize(writer); - - writer.Write(0); // version + from.SendGump(new HousePlacementCategoryGump(from)); } - - public override void Deserialize(IGenericReader reader) + else { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - if (Weight == 0.0) - { - Weight = 3.0; - } + from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. } } +} + +public class HousePlacementCategoryGump : Gump +{ + private const int LabelColor = 0x7FFF; + private const int LabelColorDisabled = 0x4210; + private readonly Mobile _from; - public class HousePlacementCategoryGump : Gump + public HousePlacementCategoryGump(Mobile from) : base(50, 50) { - private const int LabelColor = 0x7FFF; - private const int LabelColorDisabled = 0x4210; - private readonly Mobile m_From; + _from = from; - public HousePlacementCategoryGump(Mobile from) : base(50, 50) - { - m_From = from; + from.CloseGump(); + from.CloseGump(); - from.CloseGump(); - from.CloseGump(); + AddPage(0); - AddPage(0); + AddBackground(0, 0, 270, 145, 5054); - AddBackground(0, 0, 270, 145, 5054); + AddImageTiled(10, 10, 250, 125, 2624); + AddAlphaRegion(10, 10, 250, 125); - AddImageTiled(10, 10, 250, 125, 2624); - AddAlphaRegion(10, 10, 250, 125); + AddHtmlLocalized(10, 10, 250, 20, 1060239, LabelColor); //
HOUSE PLACEMENT TOOL
- AddHtmlLocalized(10, 10, 250, 20, 1060239, LabelColor); //
HOUSE PLACEMENT TOOL
+ AddButton(10, 110, 4017, 4019, 0); + AddHtmlLocalized(45, 110, 150, 20, 3000363, LabelColor); // Close - AddButton(10, 110, 4017, 4019, 0); - AddHtmlLocalized(45, 110, 150, 20, 3000363, LabelColor); // Close + AddButton(10, 40, 4005, 4007, 1); + AddHtmlLocalized(45, 40, 200, 20, 1060390, LabelColor); // Classic Houses - AddButton(10, 40, 4005, 4007, 1); - AddHtmlLocalized(45, 40, 200, 20, 1060390, LabelColor); // Classic Houses + AddButton(10, 60, 4005, 4007, 2); + AddHtmlLocalized(45, 60, 200, 20, 1060391, LabelColor); // 2-Story Customizable Houses - AddButton(10, 60, 4005, 4007, 2); - AddHtmlLocalized(45, 60, 200, 20, 1060391, LabelColor); // 2-Story Customizable Houses + AddButton(10, 80, 4005, 4007, 3); + AddHtmlLocalized(45, 80, 200, 20, 1060392, LabelColor); // 3-Story Customizable Houses + } - AddButton(10, 80, 4005, 4007, 3); - AddHtmlLocalized(45, 80, 200, 20, 1060392, LabelColor); // 3-Story Customizable Houses + public override void OnResponse(NetState sender, in RelayInfo info) + { + if (!_from.CheckAlive() || _from.Backpack?.FindItemByType() == null) + { + return; } - public override void OnResponse(NetState sender, in RelayInfo info) + switch (info.ButtonID) { - if (!m_From.CheckAlive() || m_From.Backpack?.FindItemByType() == null) - { - return; - } - - switch (info.ButtonID) - { - case 1: // Classic Houses - { - var entry = Core.EJ ? HousePlacementEntry.HousesEJ : HousePlacementEntry.ClassicHouses; - m_From.SendGump(new HousePlacementListGump(m_From, entry)); + case 1: // Classic Houses + { + var entry = Core.EJ ? HousePlacementEntry.HousesEJ : HousePlacementEntry.ClassicHouses; + _from.SendGump(new HousePlacementListGump(_from, entry)); - break; - } - case 2: // 2-Story Customizable Houses - { - m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.TwoStoryFoundations)); - break; - } - case 3: // 3-Story Customizable Houses - { - m_From.SendGump(new HousePlacementListGump(m_From, HousePlacementEntry.ThreeStoryFoundations)); - break; - } - } + break; + } + case 2: // 2-Story Customizable Houses + { + _from.SendGump(new HousePlacementListGump(_from, HousePlacementEntry.TwoStoryFoundations)); + break; + } + case 3: // 3-Story Customizable Houses + { + _from.SendGump(new HousePlacementListGump(_from, HousePlacementEntry.ThreeStoryFoundations)); + break; + } } } +} - public class HousePlacementListGump : Gump +public class HousePlacementListGump : Gump +{ + private const int LabelColor = 0x7FFF; + private const int LabelHue = 0x480; + private readonly HousePlacementEntry[] _entries; + private readonly Mobile _from; + + public HousePlacementListGump(Mobile from, HousePlacementEntry[] entries) : base(50, 50) { - private const int LabelColor = 0x7FFF; - private const int LabelHue = 0x480; - private readonly HousePlacementEntry[] m_Entries; - private readonly Mobile m_From; + _from = from; + _entries = entries; - public HousePlacementListGump(Mobile from, HousePlacementEntry[] entries) : base(50, 50) - { - m_From = from; - m_Entries = entries; + from.CloseGump(); + from.CloseGump(); - from.CloseGump(); - from.CloseGump(); + AddPage(0); - AddPage(0); + AddBackground(0, 0, 520, 420, 5054); - AddBackground(0, 0, 520, 420, 5054); + AddImageTiled(10, 10, 500, 20, 2624); + AddAlphaRegion(10, 10, 500, 20); - AddImageTiled(10, 10, 500, 20, 2624); - AddAlphaRegion(10, 10, 500, 20); + AddHtmlLocalized(10, 10, 500, 20, 1060239, LabelColor); //
HOUSE PLACEMENT TOOL
- AddHtmlLocalized(10, 10, 500, 20, 1060239, LabelColor); //
HOUSE PLACEMENT TOOL
+ AddImageTiled(10, 40, 500, 20, 2624); + AddAlphaRegion(10, 40, 500, 20); - AddImageTiled(10, 40, 500, 20, 2624); - AddAlphaRegion(10, 40, 500, 20); + AddHtmlLocalized(50, 40, 225, 20, 1060235, LabelColor); // House Description + AddHtmlLocalized(275, 40, 75, 20, 1060236, LabelColor); // Storage + AddHtmlLocalized(350, 40, 75, 20, 1060237, LabelColor); // Lockdowns + AddHtmlLocalized(425, 40, 75, 20, 1060034, LabelColor); // Cost - AddHtmlLocalized(50, 40, 225, 20, 1060235, LabelColor); // House Description - AddHtmlLocalized(275, 40, 75, 20, 1060236, LabelColor); // Storage - AddHtmlLocalized(350, 40, 75, 20, 1060237, LabelColor); // Lockdowns - AddHtmlLocalized(425, 40, 75, 20, 1060034, LabelColor); // Cost + AddImageTiled(10, 70, 500, 280, 2624); + AddAlphaRegion(10, 70, 500, 280); - AddImageTiled(10, 70, 500, 280, 2624); - AddAlphaRegion(10, 70, 500, 280); + AddImageTiled(10, 360, 500, 20, 2624); + AddAlphaRegion(10, 360, 500, 20); - AddImageTiled(10, 360, 500, 20, 2624); - AddAlphaRegion(10, 360, 500, 20); + AddHtmlLocalized(10, 360, 250, 20, 1060645, LabelColor); // Bank Balance: + AddLabel(250, 360, LabelHue, Banker.GetBalance(from).ToString()); - AddHtmlLocalized(10, 360, 250, 20, 1060645, LabelColor); // Bank Balance: - AddLabel(250, 360, LabelHue, Banker.GetBalance(from).ToString()); + AddImageTiled(10, 390, 500, 20, 2624); + AddAlphaRegion(10, 390, 500, 20); - AddImageTiled(10, 390, 500, 20, 2624); - AddAlphaRegion(10, 390, 500, 20); + AddButton(10, 390, 4017, 4019, 0); + AddHtmlLocalized(50, 390, 100, 20, 3000363, LabelColor); // Close - AddButton(10, 390, 4017, 4019, 0); - AddHtmlLocalized(50, 390, 100, 20, 3000363, LabelColor); // Close + for (var i = 0; i < entries.Length; ++i) + { + var page = 1 + i / 14; + var index = i % 14; - for (var i = 0; i < entries.Length; ++i) + if (index == 0) { - var page = 1 + i / 14; - var index = i % 14; - - if (index == 0) + if (page > 1) { - if (page > 1) - { - AddButton(450, 390, 4005, 4007, 0, GumpButtonType.Page, page); - AddHtmlLocalized(400, 390, 100, 20, 3000406, LabelColor); // Next - } + AddButton(450, 390, 4005, 4007, 0, GumpButtonType.Page, page); + AddHtmlLocalized(400, 390, 100, 20, 3000406, LabelColor); // Next + } - AddPage(page); + AddPage(page); - if (page > 1) - { - AddButton(200, 390, 4014, 4016, 0, GumpButtonType.Page, page - 1); - AddHtmlLocalized(250, 390, 100, 20, 3000405, LabelColor); // Previous - } + if (page > 1) + { + AddButton(200, 390, 4014, 4016, 0, GumpButtonType.Page, page - 1); + AddHtmlLocalized(250, 390, 100, 20, 3000405, LabelColor); // Previous } + } - var entry = entries[i]; + var entry = entries[i]; - var y = 70 + index * 20; + var y = 70 + index * 20; - AddButton(10, y, 4005, 4007, 1 + i); - AddHtmlLocalized(50, y, 225, 20, entry.Description, LabelColor); - AddLabel(275, y, LabelHue, entry.Storage.ToString()); - AddLabel(350, y, LabelHue, entry.Lockdowns.ToString()); - AddLabel(425, y, LabelHue, entry.Cost.ToString()); - } + AddButton(10, y, 4005, 4007, 1 + i); + AddHtmlLocalized(50, y, 225, 20, entry.Description, LabelColor); + AddLabel(275, y, LabelHue, entry.Storage.ToString()); + AddLabel(350, y, LabelHue, entry.Lockdowns.ToString()); + AddLabel(425, y, LabelHue, entry.Cost.ToString()); } + } - public override void OnResponse(NetState sender, in RelayInfo info) + public override void OnResponse(NetState sender, in RelayInfo info) + { + if (!_from.CheckAlive() || _from.Backpack?.FindItemByType() == null) { - if (!m_From.CheckAlive() || m_From.Backpack?.FindItemByType() == null) - { - return; - } + return; + } - var index = info.ButtonID - 1; + var index = info.ButtonID - 1; - if (index >= 0 && index < m_Entries.Length) + if (index >= 0 && index < _entries.Length) + { + if (_from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(_from)) { - if (m_From.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(m_From)) - { - m_From.SendLocalizedMessage(501271); // You already own a house, you may not place another! - } - else - { - m_From.Target = new NewHousePlacementTarget(m_Entries, m_Entries[index]); - } + _from.SendLocalizedMessage(501271); // You already own a house, you may not place another! } else { - m_From.SendGump(new HousePlacementCategoryGump(m_From)); + _from.Target = new NewHousePlacementTarget(_entries, _entries[index]); } } + else + { + _from.SendGump(new HousePlacementCategoryGump(_from)); + } } +} + +public class NewHousePlacementTarget : MultiTarget +{ + private readonly HousePlacementEntry[] _entries; + private readonly HousePlacementEntry _entry; + + private bool _placed; - public class NewHousePlacementTarget : MultiTarget + public NewHousePlacementTarget(HousePlacementEntry[] entries, HousePlacementEntry entry) : base( + entry.MultiID, + entry.Offset + ) { - private readonly HousePlacementEntry[] m_Entries; - private readonly HousePlacementEntry m_Entry; + Range = 14; - private bool m_Placed; + _entries = entries; + _entry = entry; + } - public NewHousePlacementTarget(HousePlacementEntry[] entries, HousePlacementEntry entry) : base( - entry.MultiID, - entry.Offset - ) + protected override void OnTarget(Mobile from, object o) + { + if (o is not IPoint3D ip) { - Range = 14; - - m_Entries = entries; - m_Entry = entry; + return; } - protected override void OnTarget(Mobile from, object o) + if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) { - if (o is not IPoint3D ip) - { - return; - } - - if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) - { - return; - } + return; + } - Point3D p = ip switch - { - Item item => item.GetWorldTop(), - Mobile m => m.Location, - _ => new Point3D(ip) - }; + Point3D p = ip switch + { + Item item => item.GetWorldTop(), + Mobile m => m.Location, + _ => new Point3D(ip) + }; - var reg = Region.Find(p, from.Map); + var reg = Region.Find(p, from.Map); - if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p)) - { - m_Placed = m_Entry.OnPlacement(from, p); - } - else if (reg.IsPartOf()) - { - // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. - from.SendLocalizedMessage(501270); - } - else if (reg.IsPartOf() || reg.IsPartOf()) - { - // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. - from.SendLocalizedMessage(1043287); - } - else if (reg.IsPartOf()) - { - from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. - } - else - { - from.SendLocalizedMessage(501265); // Housing can not be created in this area. - } + if (from.AccessLevel >= AccessLevel.GameMaster || reg.AllowHousing(from, p)) + { + _placed = _entry.OnPlacement(from, p); } - - protected override void OnTargetFinish(Mobile from) + else if (reg.IsPartOf()) { - if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) - { - return; - } - - if (!m_Placed) - { - from.SendGump(new HousePlacementListGump(from, m_Entries)); - } + // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + from.SendLocalizedMessage(501270); + } + else if (reg.IsPartOf() || reg.IsPartOf()) + { + // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + from.SendLocalizedMessage(1043287); + } + else if (reg.IsPartOf()) + { + from.SendLocalizedMessage(1150493); // You must have a deed for this plot of land in order to build here. + } + else + { + from.SendLocalizedMessage(501265); // Housing can not be created in this area. } } - public class HousePlacementEntry + protected override void OnTargetFinish(Mobile from) { - private static readonly Dictionary m_Table; - private readonly int m_Lockdowns; - private readonly int m_NewLockdowns; - private readonly int m_NewStorage; - private readonly int m_Storage; - - static HousePlacementEntry() + if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) { - m_Table = new Dictionary(); - - FillTable(Core.EJ ? HousesEJ : ClassicHouses); - FillTable(TwoStoryFoundations); - FillTable(ThreeStoryFoundations); + return; } - public HousePlacementEntry( - Type type, int description, int storage, int lockdowns, int newStorage, int newLockdowns, - int vendors, int cost, int xOffset, int yOffset, int zOffset, int multiID - ) + if (!_placed) { - Type = type; - Description = description; - m_Storage = storage; - m_Lockdowns = lockdowns; - m_NewStorage = newStorage; - m_NewLockdowns = newLockdowns; - Vendors = vendors; - Cost = cost; - - Offset = new Point3D(xOffset, yOffset, zOffset); - - MultiID = multiID; + from.SendGump(new HousePlacementListGump(from, _entries)); } + } +} + +public class HousePlacementEntry +{ + private static readonly Dictionary _table; + private readonly int _lockdowns; + private readonly int _newLockdowns; + private readonly int _newStorage; + private readonly int _storage; - public Type Type { get; } + static HousePlacementEntry() + { + _table = new Dictionary(); - public int Description { get; } + FillTable(Core.EJ ? HousesEJ : ClassicHouses); + FillTable(TwoStoryFoundations); + FillTable(ThreeStoryFoundations); + } - public int Storage => BaseHouse.NewVendorSystem ? m_NewStorage : m_Storage; - public int Lockdowns => BaseHouse.NewVendorSystem ? m_NewLockdowns : m_Lockdowns; - public int Vendors { get; } + public HousePlacementEntry( + Type type, int description, int storage, int lockdowns, int newStorage, int newLockdowns, + int vendors, int cost, int xOffset, int yOffset, int zOffset, int multiID + ) + { + Type = type; + Description = description; + _storage = storage; + _lockdowns = lockdowns; + _newStorage = newStorage; + _newLockdowns = newLockdowns; + Vendors = vendors; + Cost = cost; + + Offset = new Point3D(xOffset, yOffset, zOffset); + + MultiID = multiID; + } - public int Cost { get; } + public Type Type { get; } - public int MultiID { get; } + public int Description { get; } - public Point3D Offset { get; } + public int Storage => BaseHouse.NewVendorSystem ? _newStorage : _storage; + public int Lockdowns => BaseHouse.NewVendorSystem ? _newLockdowns : _lockdowns; + public int Vendors { get; } - public static HousePlacementEntry[] ClassicHouses { get; } = - { - new(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0064), - new(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0066), - new(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0068), - new(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35250, 0, 4, 0, 0x006A), - new(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006C), - new(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006E), - new(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50500, -1, 4, 0, 0x00A0), - new(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52500, 0, 4, 0, 0x00A2), - new(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73500, 3, 4, 0, 0x0098), - new(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113750, 3, 6, 0, 0x009E), - new(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76500, -1, 4, 0, 0x009C), - new(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81750, 1, 6, 0, 0x009A), - new(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131500, -1, 7, 0, 0x0074), - new(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0076), - new(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162000, -3, 7, 0, 0x0078), - new(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129250, -4, 7, 0, 0x008C), - new(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160500, -4, 7, 0, 0x0096), - new(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366500, 0, 7, 0, 0x007A), - new(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 572750, 0, 11, 0, 0x007C), - new(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865250, 0, 16, 0, 0x007E) - }; + public int Cost { get; } - public static HousePlacementEntry[] HousesEJ { get; } = - { - new(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0064), - new(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0066), - new(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x0068), - new(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35000, 0, 4, 0, 0x006A), - new(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006C), - new(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006E), - new(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50250, -1, 4, 0, 0x00A0), - new(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52250, 0, 4, 0, 0x00A2), - new(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73250, 3, 4, 0, 0x0098), - new(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113500, 3, 6, 0, 0x009E), - new(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76250, -1, 4, 0, 0x009C), - new(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81250, 1, 6, 0, 0x009A), - new(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131250, -1, 7, 0, 0x0074), - new(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162500, -3, 7, 0, 0x0076), - new(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0078), - new(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129000, -4, 7, 0, 0x008C), - new(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160250, -4, 7, 0, 0x0096), - new(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366250, 0, 7, 0, 0x007A), - new(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 562500, 0, 11, 0, 0x007C), - new(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865000, 0, 16, 0, 0x007E), - - new(typeof(TrinsicKeep), 1158748, 2625, 1312, 3019, 1509, 52, 29643750, 0, 11, 0, 0x147E), - new( - typeof(GothicRoseCastle), - 1158749, - 4076, - 2038, - 4688, - 2344, - 78, - 44808750, - 0, - 16, - 0, - 0x147F - ), - new(typeof(ElsaCastle), 1158750, 4076, 2038, 4688, 2344, 78, 45450000, 0, 16, 0, 0x1480), - new(typeof(Spires), 1158761, 4076, 2038, 4688, 2344, 78, 47025000, 0, 16, 0, 0x1481), - new( - typeof(CastleOfOceania), - 1158760, - 4076, - 2038, - 4688, - 2344, - 78, - 48971250, - 0, - 16, - 0, - 0x1482 - ), - new(typeof(FeudalCastle), 1158762, 4076, 2038, 4688, 2344, 78, 27337500, 0, 16, 0, 0x1483), - new(typeof(RobinsNest), 1158850, 2625, 1312, 3019, 1509, 52, 25301250, 0, 11, 0, 0x1484), - new( - typeof(TraditionalKeep), - 1158851, - 2625, - 1312, - 3019, - 1509, - 52, - 26685000, - 0, - 11, - 0, - 0x1485 - ), - new(typeof(VillaCrowley), 1158852, 2625, 1312, 3019, 1509, 52, 21813750, 0, 11, 0, 0x1486), - new(typeof(DarkthornKeep), 1158853, 2625, 1312, 3019, 1509, 52, 27990000, 0, 11, 0, 0x1487), - new(typeof(SandalwoodKeep), 1158854, 2625, 1312, 3019, 1509, 52, 23456250, 0, 11, 0, 0x1488), - new(typeof(CasaMoga), 1158855, 2625, 1312, 3019, 1509, 52, 26313750, 0, 11, 0, 0x1489), - - new(typeof(RobinsRoost), 1158960, 4076, 2038, 4688, 2344, 78, 43863750, 0, 16, 0, 0x148A), - new(typeof(Camelot), 1158961, 4076, 2038, 4688, 2344, 78, 47092500, 0, 16, 0, 0x148B), - new( - typeof(LacrimaeInCaelo), - 1158962, - 4076, - 2038, - 4688, - 2344, - 78, - 45315000, - 0, - 16, - 0, - 0x148C - ), - new( - typeof(OkinawaSweetDreamCastle), - 1158963, - 4076, - 2038, - 4688, - 2344, - 78, - 40128750, - 0, - 16, - 0, - 0x148D - ), - new( - typeof(TheSandstoneCastle), - 1158964, - 4076, - 2038, - 4688, - 2344, - 78, - 48690000, - 0, - 16, - 0, - 0x148E - ), - new( - typeof(GrimswindSisters), - 1158965, - 4076, - 2038, - 4688, - 2344, - 78, - 42142500, - 0, - 16, - 0, - 0x148F - ) - }; + public int MultiID { get; } - public static HousePlacementEntry[] TwoStoryFoundations { get; } = - { - new( - typeof(HouseFoundation), - 1060241, - 425, - 212, - 489, - 244, - 10, - 30500, - 0, - 4, - 0, - 0x13EC - ), // 7x7 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060242, - 580, - 290, - 667, - 333, - 14, - 34500, - 0, - 5, - 0, - 0x13ED - ), // 7x8 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060243, - 650, - 325, - 748, - 374, - 16, - 38500, - 0, - 5, - 0, - 0x13EE - ), // 7x9 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060244, - 700, - 350, - 805, - 402, - 16, - 42500, - 0, - 6, - 0, - 0x13EF - ), // 7x10 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060245, - 750, - 375, - 863, - 431, - 16, - 46500, - 0, - 6, - 0, - 0x13F0 - ), // 7x11 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060246, - 800, - 400, - 920, - 460, - 18, - 50500, - 0, - 7, - 0, - 0x13F1 - ), // 7x12 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060253, - 580, - 290, - 667, - 333, - 14, - 34500, - 0, - 4, - 0, - 0x13F8 - ), // 8x7 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060254, - 650, - 325, - 748, - 374, - 16, - 39000, - 0, - 5, - 0, - 0x13F9 - ), // 8x8 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060255, - 700, - 350, - 805, - 402, - 16, - 43500, - 0, - 5, - 0, - 0x13FA - ), // 8x9 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060256, - 750, - 375, - 863, - 431, - 16, - 48000, - 0, - 6, - 0, - 0x13FB - ), // 8x10 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060257, - 800, - 400, - 920, - 460, - 18, - 52500, - 0, - 6, - 0, - 0x13FC - ), // 8x11 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060258, - 850, - 425, - 1265, - 632, - 24, - 57000, - 0, - 7, - 0, - 0x13FD - ), // 8x12 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060259, - 1100, - 550, - 1265, - 632, - 24, - 61500, - 0, - 7, - 0, - 0x13FE - ), // 8x13 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060265, - 650, - 325, - 748, - 374, - 16, - 38500, - 0, - 4, - 0, - 0x1404 - ), // 9x7 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060266, - 700, - 350, - 805, - 402, - 16, - 43500, - 0, - 5, - 0, - 0x1405 - ), // 9x8 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060267, - 750, - 375, - 863, - 431, - 16, - 48500, - 0, - 5, - 0, - 0x1406 - ), // 9x9 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060268, - 800, - 400, - 920, - 460, - 18, - 53500, - 0, - 6, - 0, - 0x1407 - ), // 9x10 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060269, - 850, - 425, - 1265, - 632, - 24, - 58500, - 0, - 6, - 0, - 0x1408 - ), // 9x11 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060270, - 1100, - 550, - 1265, - 632, - 24, - 63500, - 0, - 7, - 0, - 0x1409 - ), // 9x12 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060271, - 1100, - 550, - 1265, - 632, - 24, - 68500, - 0, - 7, - 0, - 0x140A - ), // 9x13 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060277, - 700, - 350, - 805, - 402, - 16, - 42500, - 0, - 4, - 0, - 0x1410 - ), // 10x7 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060278, - 750, - 375, - 863, - 431, - 16, - 48000, - 0, - 5, - 0, - 0x1411 - ), // 10x8 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060279, - 800, - 400, - 920, - 460, - 18, - 53500, - 0, - 5, - 0, - 0x1412 - ), // 10x9 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060280, - 850, - 425, - 1265, - 632, - 24, - 59000, - 0, - 6, - 0, - 0x1413 - ), // 10x10 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060281, - 1100, - 550, - 1265, - 632, - 24, - 64500, - 0, - 6, - 0, - 0x1414 - ), // 10x11 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060282, - 1100, - 550, - 1265, - 632, - 24, - 70000, - 0, - 7, - 0, - 0x1415 - ), // 10x12 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060283, - 1150, - 575, - 1323, - 661, - 24, - 75500, - 0, - 7, - 0, - 0x1416 - ), // 10x13 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060289, - 750, - 375, - 863, - 431, - 16, - 46500, - 0, - 4, - 0, - 0x141C - ), // 11x7 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060290, - 800, - 400, - 920, - 460, - 18, - 52500, - 0, - 5, - 0, - 0x141D - ), // 11x8 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060291, - 850, - 425, - 1265, - 632, - 24, - 58500, - 0, - 5, - 0, - 0x141E - ), // 11x9 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060292, - 1100, - 550, - 1265, - 632, - 24, - 64500, - 0, - 6, - 0, - 0x141F - ), // 11x10 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060293, - 1100, - 550, - 1265, - 632, - 24, - 70500, - 0, - 6, - 0, - 0x1420 - ), // 11x11 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060294, - 1150, - 575, - 1323, - 661, - 24, - 76500, - 0, - 7, - 0, - 0x1421 - ), // 11x12 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060295, - 1200, - 600, - 1380, - 690, - 26, - 82500, - 0, - 7, - 0, - 0x1422 - ), // 11x13 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060301, - 800, - 400, - 920, - 460, - 18, - 50500, - 0, - 4, - 0, - 0x1428 - ), // 12x7 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060302, - 850, - 425, - 1265, - 632, - 24, - 57000, - 0, - 5, - 0, - 0x1429 - ), // 12x8 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060303, - 1100, - 550, - 1265, - 632, - 24, - 63500, - 0, - 5, - 0, - 0x142A - ), // 12x9 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060304, - 1100, - 550, - 1265, - 632, - 24, - 70000, - 0, - 6, - 0, - 0x142B - ), // 12x10 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060305, - 1150, - 575, - 1323, - 661, - 24, - 76500, - 0, - 6, - 0, - 0x142C - ), // 12x11 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060306, - 1200, - 600, - 1380, - 690, - 26, - 83000, - 0, - 7, - 0, - 0x142D - ), // 12x12 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060307, - 1250, - 625, - 1438, - 719, - 26, - 89500, - 0, - 7, - 0, - 0x142E - ), // 12x13 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060314, - 1100, - 550, - 1265, - 632, - 24, - 61500, - 0, - 5, - 0, - 0x1435 - ), // 13x8 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060315, - 1100, - 550, - 1265, - 632, - 24, - 68500, - 0, - 5, - 0, - 0x1436 - ), // 13x9 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060316, - 1150, - 575, - 1323, - 661, - 24, - 75500, - 0, - 6, - 0, - 0x1437 - ), // 13x10 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060317, - 1200, - 600, - 1380, - 690, - 26, - 82500, - 0, - 6, - 0, - 0x1438 - ), // 13x11 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060318, - 1250, - 625, - 1438, - 719, - 26, - 89500, - 0, - 7, - 0, - 0x1439 - ), // 13x12 2-Story Customizable House - new( - typeof(HouseFoundation), - 1060319, - 1300, - 650, - 1495, - 747, - 28, - 96500, - 0, - 7, - 0, - 0x143A - ) // 13x13 2-Story Customizable House - }; + public Point3D Offset { get; } - public static HousePlacementEntry[] ThreeStoryFoundations { get; } = - { - new( - typeof(HouseFoundation), - 1060272, - 1150, - 575, - 1323, - 661, - 24, - 73500, - 0, - 8, - 0, - 0x140B - ), // 9x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060284, - 1200, - 600, - 1380, - 690, - 26, - 81000, - 0, - 8, - 0, - 0x1417 - ), // 10x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060285, - 1250, - 625, - 1438, - 719, - 26, - 86500, - 0, - 8, - 0, - 0x1418 - ), // 10x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060296, - 1250, - 625, - 1438, - 719, - 26, - 88500, - 0, - 8, - 0, - 0x1423 - ), // 11x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060297, - 1300, - 650, - 1495, - 747, - 28, - 94500, - 0, - 8, - 0, - 0x1424 - ), // 11x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060298, - 1350, - 675, - 1553, - 776, - 28, - 100500, - 0, - 9, - 0, - 0x1425 - ), // 11x16 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060308, - 1300, - 650, - 1495, - 747, - 28, - 96000, - 0, - 8, - 0, - 0x142F - ), // 12x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060309, - 1350, - 675, - 1553, - 776, - 28, - 102500, - 0, - 8, - 0, - 0x1430 - ), // 12x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060310, - 1370, - 685, - 1576, - 788, - 28, - 109000, - 0, - 9, - 0, - 0x1431 - ), // 12x16 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060311, - 1370, - 685, - 1576, - 788, - 28, - 115500, - 0, - 9, - 0, - 0x1432 - ), // 12x17 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060320, - 1350, - 675, - 1553, - 776, - 28, - 103500, - 0, - 8, - 0, - 0x143B - ), // 13x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060321, - 1370, - 685, - 1576, - 788, - 28, - 110500, - 0, - 8, - 0, - 0x143C - ), // 13x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060322, - 1370, - 685, - 1576, - 788, - 28, - 117500, - 0, - 9, - 0, - 0x143D - ), // 13x16 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060323, - 2119, - 1059, - 2437, - 1218, - 42, - 124500, - 0, - 9, - 0, - 0x143E - ), // 13x17 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060324, - 2119, - 1059, - 2437, - 1218, - 42, - 131500, - 0, - 10, - 0, - 0x143F - ), // 13x18 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060327, - 1150, - 575, - 1323, - 661, - 24, - 73500, - 0, - 5, - 0, - 0x1442 - ), // 14x9 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060328, - 1200, - 600, - 1380, - 690, - 26, - 81000, - 0, - 6, - 0, - 0x1443 - ), // 14x10 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060329, - 1250, - 625, - 1438, - 719, - 26, - 88500, - 0, - 6, - 0, - 0x1444 - ), // 14x11 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060330, - 1300, - 650, - 1495, - 747, - 28, - 96000, - 0, - 7, - 0, - 0x1445 - ), // 14x12 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060331, - 1350, - 675, - 1553, - 776, - 28, - 103500, - 0, - 7, - 0, - 0x1446 - ), // 14x13 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060332, - 1370, - 685, - 1576, - 788, - 28, - 111000, - 0, - 8, - 0, - 0x1447 - ), // 14x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060333, - 1370, - 685, - 1576, - 788, - 28, - 118500, - 0, - 8, - 0, - 0x1448 - ), // 14x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060334, - 2119, - 1059, - 2437, - 1218, - 42, - 126000, - 0, - 9, - 0, - 0x1449 - ), // 14x16 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060335, - 2119, - 1059, - 2437, - 1218, - 42, - 133500, - 0, - 9, - 0, - 0x144A - ), // 14x17 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060336, - 2119, - 1059, - 2437, - 1218, - 42, - 141000, - 0, - 10, - 0, - 0x144B - ), // 14x18 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060340, - 1250, - 625, - 1438, - 719, - 26, - 86500, - 0, - 6, - 0, - 0x144F - ), // 15x10 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060341, - 1300, - 650, - 1495, - 747, - 28, - 94500, - 0, - 6, - 0, - 0x1450 - ), // 15x11 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060342, - 1350, - 675, - 1553, - 776, - 28, - 102500, - 0, - 7, - 0, - 0x1451 - ), // 15x12 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060343, - 1370, - 685, - 1576, - 788, - 28, - 110500, - 0, - 7, - 0, - 0x1452 - ), // 15x13 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060344, - 1370, - 685, - 1576, - 788, - 28, - 118500, - 0, - 8, - 0, - 0x1453 - ), // 15x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060345, - 2119, - 1059, - 2437, - 1218, - 42, - 126500, - 0, - 8, - 0, - 0x1454 - ), // 15x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060346, - 2119, - 1059, - 2437, - 1218, - 42, - 134500, - 0, - 9, - 0, - 0x1455 - ), // 15x16 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060347, - 2119, - 1059, - 2437, - 1218, - 42, - 142500, - 0, - 9, - 0, - 0x1456 - ), // 15x17 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060348, - 2119, - 1059, - 2437, - 1218, - 42, - 150500, - 0, - 10, - 0, - 0x1457 - ), // 15x18 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060353, - 1350, - 675, - 1553, - 776, - 28, - 100500, - 0, - 6, - 0, - 0x145C - ), // 16x11 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060354, - 1370, - 685, - 1576, - 788, - 28, - 109000, - 0, - 7, - 0, - 0x145D - ), // 16x12 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060355, - 1370, - 685, - 1576, - 788, - 28, - 117500, - 0, - 7, - 0, - 0x145E - ), // 16x13 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060356, - 2119, - 1059, - 2437, - 1218, - 42, - 126000, - 0, - 8, - 0, - 0x145F - ), // 16x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060357, - 2119, - 1059, - 2437, - 1218, - 42, - 134500, - 0, - 8, - 0, - 0x1460 - ), // 16x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060358, - 2119, - 1059, - 2437, - 1218, - 42, - 143000, - 0, - 9, - 0, - 0x1461 - ), // 16x16 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060359, - 2119, - 1059, - 2437, - 1218, - 42, - 151500, - 0, - 9, - 0, - 0x1462 - ), // 16x17 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060360, - 2119, - 1059, - 2437, - 1218, - 42, - 160000, - 0, - 10, - 0, - 0x1463 - ), // 16x18 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060366, - 1370, - 685, - 1576, - 788, - 28, - 115500, - 0, - 7, - 0, - 0x1469 - ), // 17x12 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060367, - 2119, - 1059, - 2437, - 1218, - 42, - 124500, - 0, - 7, - 0, - 0x146A - ), // 17x13 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060368, - 2119, - 1059, - 2437, - 1218, - 42, - 133500, - 0, - 8, - 0, - 0x146B - ), // 17x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060369, - 2119, - 1059, - 2437, - 1218, - 42, - 142500, - 0, - 8, - 0, - 0x146C - ), // 17x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060370, - 2119, - 1059, - 2437, - 1218, - 42, - 151500, - 0, - 9, - 0, - 0x146D - ), // 17x16 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060371, - 2119, - 1059, - 2437, - 1218, - 42, - 160500, - 0, - 9, - 0, - 0x146E - ), // 17x17 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060372, - 2119, - 1059, - 2437, - 1218, - 42, - 169500, - 0, - 10, - 0, - 0x146F - ), // 17x18 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060379, - 2119, - 1059, - 2437, - 1218, - 42, - 131500, - 0, - 7, - 0, - 0x1476 - ), // 18x13 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060380, - 2119, - 1059, - 2437, - 1218, - 42, - 141000, - 0, - 8, - 0, - 0x1477 - ), // 18x14 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060381, - 2119, - 1059, - 2437, - 1218, - 42, - 150500, - 0, - 8, - 0, - 0x1478 - ), // 18x15 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060382, - 2119, - 1059, - 2437, - 1218, - 42, - 160000, - 0, - 9, - 0, - 0x1479 - ), // 18x16 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060383, - 2119, - 1059, - 2437, - 1218, - 42, - 169500, - 0, - 9, - 0, - 0x147A - ), // 18x17 3-Story Customizable House - new( - typeof(HouseFoundation), - 1060384, - 2119, - 1059, - 2437, - 1218, - 42, - 179000, - 0, - 10, - 0, - 0x147B - ) // 18x18 3-Story Customizable House - }; + public static HousePlacementEntry[] ClassicHouses { get; } = + { + new(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0064), + new(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 37000, 0, 4, 0, 0x0066), + new(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0068), + new(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35250, 0, 4, 0, 0x006A), + new(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006C), + new(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x006E), + new(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50500, -1, 4, 0, 0x00A0), + new(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52500, 0, 4, 0, 0x00A2), + new(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73500, 3, 4, 0, 0x0098), + new(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113750, 3, 6, 0, 0x009E), + new(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76500, -1, 4, 0, 0x009C), + new(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81750, 1, 6, 0, 0x009A), + new(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131500, -1, 7, 0, 0x0074), + new(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0076), + new(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162000, -3, 7, 0, 0x0078), + new(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129250, -4, 7, 0, 0x008C), + new(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160500, -4, 7, 0, 0x0096), + new(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366500, 0, 7, 0, 0x007A), + new(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 572750, 0, 11, 0, 0x007C), + new(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865250, 0, 16, 0, 0x007E) + }; + + public static HousePlacementEntry[] HousesEJ { get; } = + { + new(typeof(SmallOldHouse), 1011303, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0064), + new(typeof(SmallOldHouse), 1011304, 425, 212, 489, 244, 10, 36750, 0, 4, 0, 0x0066), + new(typeof(SmallOldHouse), 1011305, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x0068), + new(typeof(SmallOldHouse), 1011306, 425, 212, 489, 244, 10, 35000, 0, 4, 0, 0x006A), + new(typeof(SmallOldHouse), 1011307, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006C), + new(typeof(SmallOldHouse), 1011308, 425, 212, 489, 244, 10, 36500, 0, 4, 0, 0x006E), + new(typeof(SmallShop), 1011321, 425, 212, 489, 244, 10, 50250, -1, 4, 0, 0x00A0), + new(typeof(SmallShop), 1011322, 425, 212, 489, 244, 10, 52250, 0, 4, 0, 0x00A2), + new(typeof(SmallTower), 1011317, 580, 290, 667, 333, 14, 73250, 3, 4, 0, 0x0098), + new(typeof(TwoStoryVilla), 1011319, 1100, 550, 1265, 632, 24, 113500, 3, 6, 0, 0x009E), + new(typeof(SandStonePatio), 1011320, 850, 425, 1265, 632, 24, 76250, -1, 4, 0, 0x009C), + new(typeof(LogCabin), 1011318, 1100, 550, 1265, 632, 24, 81250, 1, 6, 0, 0x009A), + new(typeof(GuildHouse), 1011309, 1370, 685, 1576, 788, 28, 131250, -1, 7, 0, 0x0074), + new(typeof(TwoStoryHouse), 1011310, 1370, 685, 1576, 788, 28, 162500, -3, 7, 0, 0x0076), + new(typeof(TwoStoryHouse), 1011311, 1370, 685, 1576, 788, 28, 162750, -3, 7, 0, 0x0078), + new(typeof(LargePatioHouse), 1011315, 1370, 685, 1576, 788, 28, 129000, -4, 7, 0, 0x008C), + new(typeof(LargeMarbleHouse), 1011316, 1370, 685, 1576, 788, 28, 160250, -4, 7, 0, 0x0096), + new(typeof(Tower), 1011312, 2119, 1059, 2437, 1218, 42, 366250, 0, 7, 0, 0x007A), + new(typeof(Keep), 1011313, 2625, 1312, 3019, 1509, 52, 562500, 0, 11, 0, 0x007C), + new(typeof(Castle), 1011314, 4076, 2038, 4688, 2344, 78, 865000, 0, 16, 0, 0x007E), + + new(typeof(TrinsicKeep), 1158748, 2625, 1312, 3019, 1509, 52, 29643750, 0, 11, 0, 0x147E), + new( + typeof(GothicRoseCastle), + 1158749, + 4076, + 2038, + 4688, + 2344, + 78, + 44808750, + 0, + 16, + 0, + 0x147F + ), + new(typeof(ElsaCastle), 1158750, 4076, 2038, 4688, 2344, 78, 45450000, 0, 16, 0, 0x1480), + new(typeof(Spires), 1158761, 4076, 2038, 4688, 2344, 78, 47025000, 0, 16, 0, 0x1481), + new( + typeof(CastleOfOceania), + 1158760, + 4076, + 2038, + 4688, + 2344, + 78, + 48971250, + 0, + 16, + 0, + 0x1482 + ), + new(typeof(FeudalCastle), 1158762, 4076, 2038, 4688, 2344, 78, 27337500, 0, 16, 0, 0x1483), + new(typeof(RobinsNest), 1158850, 2625, 1312, 3019, 1509, 52, 25301250, 0, 11, 0, 0x1484), + new( + typeof(TraditionalKeep), + 1158851, + 2625, + 1312, + 3019, + 1509, + 52, + 26685000, + 0, + 11, + 0, + 0x1485 + ), + new(typeof(VillaCrowley), 1158852, 2625, 1312, 3019, 1509, 52, 21813750, 0, 11, 0, 0x1486), + new(typeof(DarkthornKeep), 1158853, 2625, 1312, 3019, 1509, 52, 27990000, 0, 11, 0, 0x1487), + new(typeof(SandalwoodKeep), 1158854, 2625, 1312, 3019, 1509, 52, 23456250, 0, 11, 0, 0x1488), + new(typeof(CasaMoga), 1158855, 2625, 1312, 3019, 1509, 52, 26313750, 0, 11, 0, 0x1489), + + new(typeof(RobinsRoost), 1158960, 4076, 2038, 4688, 2344, 78, 43863750, 0, 16, 0, 0x148A), + new(typeof(Camelot), 1158961, 4076, 2038, 4688, 2344, 78, 47092500, 0, 16, 0, 0x148B), + new( + typeof(LacrimaeInCaelo), + 1158962, + 4076, + 2038, + 4688, + 2344, + 78, + 45315000, + 0, + 16, + 0, + 0x148C + ), + new( + typeof(OkinawaSweetDreamCastle), + 1158963, + 4076, + 2038, + 4688, + 2344, + 78, + 40128750, + 0, + 16, + 0, + 0x148D + ), + new( + typeof(TheSandstoneCastle), + 1158964, + 4076, + 2038, + 4688, + 2344, + 78, + 48690000, + 0, + 16, + 0, + 0x148E + ), + new( + typeof(GrimswindSisters), + 1158965, + 4076, + 2038, + 4688, + 2344, + 78, + 42142500, + 0, + 16, + 0, + 0x148F + ) + }; - public BaseHouse ConstructHouse(Mobile from) + public static HousePlacementEntry[] TwoStoryFoundations { get; } = + { + new( + typeof(HouseFoundation), + 1060241, + 425, + 212, + 489, + 244, + 10, + 30500, + 0, + 4, + 0, + 0x13EC + ), // 7x7 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060242, + 580, + 290, + 667, + 333, + 14, + 34500, + 0, + 5, + 0, + 0x13ED + ), // 7x8 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060243, + 650, + 325, + 748, + 374, + 16, + 38500, + 0, + 5, + 0, + 0x13EE + ), // 7x9 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060244, + 700, + 350, + 805, + 402, + 16, + 42500, + 0, + 6, + 0, + 0x13EF + ), // 7x10 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060245, + 750, + 375, + 863, + 431, + 16, + 46500, + 0, + 6, + 0, + 0x13F0 + ), // 7x11 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060246, + 800, + 400, + 920, + 460, + 18, + 50500, + 0, + 7, + 0, + 0x13F1 + ), // 7x12 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060253, + 580, + 290, + 667, + 333, + 14, + 34500, + 0, + 4, + 0, + 0x13F8 + ), // 8x7 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060254, + 650, + 325, + 748, + 374, + 16, + 39000, + 0, + 5, + 0, + 0x13F9 + ), // 8x8 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060255, + 700, + 350, + 805, + 402, + 16, + 43500, + 0, + 5, + 0, + 0x13FA + ), // 8x9 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060256, + 750, + 375, + 863, + 431, + 16, + 48000, + 0, + 6, + 0, + 0x13FB + ), // 8x10 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060257, + 800, + 400, + 920, + 460, + 18, + 52500, + 0, + 6, + 0, + 0x13FC + ), // 8x11 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060258, + 850, + 425, + 1265, + 632, + 24, + 57000, + 0, + 7, + 0, + 0x13FD + ), // 8x12 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060259, + 1100, + 550, + 1265, + 632, + 24, + 61500, + 0, + 7, + 0, + 0x13FE + ), // 8x13 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060265, + 650, + 325, + 748, + 374, + 16, + 38500, + 0, + 4, + 0, + 0x1404 + ), // 9x7 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060266, + 700, + 350, + 805, + 402, + 16, + 43500, + 0, + 5, + 0, + 0x1405 + ), // 9x8 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060267, + 750, + 375, + 863, + 431, + 16, + 48500, + 0, + 5, + 0, + 0x1406 + ), // 9x9 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060268, + 800, + 400, + 920, + 460, + 18, + 53500, + 0, + 6, + 0, + 0x1407 + ), // 9x10 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060269, + 850, + 425, + 1265, + 632, + 24, + 58500, + 0, + 6, + 0, + 0x1408 + ), // 9x11 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060270, + 1100, + 550, + 1265, + 632, + 24, + 63500, + 0, + 7, + 0, + 0x1409 + ), // 9x12 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060271, + 1100, + 550, + 1265, + 632, + 24, + 68500, + 0, + 7, + 0, + 0x140A + ), // 9x13 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060277, + 700, + 350, + 805, + 402, + 16, + 42500, + 0, + 4, + 0, + 0x1410 + ), // 10x7 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060278, + 750, + 375, + 863, + 431, + 16, + 48000, + 0, + 5, + 0, + 0x1411 + ), // 10x8 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060279, + 800, + 400, + 920, + 460, + 18, + 53500, + 0, + 5, + 0, + 0x1412 + ), // 10x9 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060280, + 850, + 425, + 1265, + 632, + 24, + 59000, + 0, + 6, + 0, + 0x1413 + ), // 10x10 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060281, + 1100, + 550, + 1265, + 632, + 24, + 64500, + 0, + 6, + 0, + 0x1414 + ), // 10x11 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060282, + 1100, + 550, + 1265, + 632, + 24, + 70000, + 0, + 7, + 0, + 0x1415 + ), // 10x12 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060283, + 1150, + 575, + 1323, + 661, + 24, + 75500, + 0, + 7, + 0, + 0x1416 + ), // 10x13 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060289, + 750, + 375, + 863, + 431, + 16, + 46500, + 0, + 4, + 0, + 0x141C + ), // 11x7 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060290, + 800, + 400, + 920, + 460, + 18, + 52500, + 0, + 5, + 0, + 0x141D + ), // 11x8 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060291, + 850, + 425, + 1265, + 632, + 24, + 58500, + 0, + 5, + 0, + 0x141E + ), // 11x9 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060292, + 1100, + 550, + 1265, + 632, + 24, + 64500, + 0, + 6, + 0, + 0x141F + ), // 11x10 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060293, + 1100, + 550, + 1265, + 632, + 24, + 70500, + 0, + 6, + 0, + 0x1420 + ), // 11x11 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060294, + 1150, + 575, + 1323, + 661, + 24, + 76500, + 0, + 7, + 0, + 0x1421 + ), // 11x12 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060295, + 1200, + 600, + 1380, + 690, + 26, + 82500, + 0, + 7, + 0, + 0x1422 + ), // 11x13 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060301, + 800, + 400, + 920, + 460, + 18, + 50500, + 0, + 4, + 0, + 0x1428 + ), // 12x7 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060302, + 850, + 425, + 1265, + 632, + 24, + 57000, + 0, + 5, + 0, + 0x1429 + ), // 12x8 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060303, + 1100, + 550, + 1265, + 632, + 24, + 63500, + 0, + 5, + 0, + 0x142A + ), // 12x9 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060304, + 1100, + 550, + 1265, + 632, + 24, + 70000, + 0, + 6, + 0, + 0x142B + ), // 12x10 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060305, + 1150, + 575, + 1323, + 661, + 24, + 76500, + 0, + 6, + 0, + 0x142C + ), // 12x11 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060306, + 1200, + 600, + 1380, + 690, + 26, + 83000, + 0, + 7, + 0, + 0x142D + ), // 12x12 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060307, + 1250, + 625, + 1438, + 719, + 26, + 89500, + 0, + 7, + 0, + 0x142E + ), // 12x13 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060314, + 1100, + 550, + 1265, + 632, + 24, + 61500, + 0, + 5, + 0, + 0x1435 + ), // 13x8 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060315, + 1100, + 550, + 1265, + 632, + 24, + 68500, + 0, + 5, + 0, + 0x1436 + ), // 13x9 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060316, + 1150, + 575, + 1323, + 661, + 24, + 75500, + 0, + 6, + 0, + 0x1437 + ), // 13x10 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060317, + 1200, + 600, + 1380, + 690, + 26, + 82500, + 0, + 6, + 0, + 0x1438 + ), // 13x11 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060318, + 1250, + 625, + 1438, + 719, + 26, + 89500, + 0, + 7, + 0, + 0x1439 + ), // 13x12 2-Story Customizable House + new( + typeof(HouseFoundation), + 1060319, + 1300, + 650, + 1495, + 747, + 28, + 96500, + 0, + 7, + 0, + 0x143A + ) // 13x13 2-Story Customizable House + }; + + public static HousePlacementEntry[] ThreeStoryFoundations { get; } = + { + new( + typeof(HouseFoundation), + 1060272, + 1150, + 575, + 1323, + 661, + 24, + 73500, + 0, + 8, + 0, + 0x140B + ), // 9x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060284, + 1200, + 600, + 1380, + 690, + 26, + 81000, + 0, + 8, + 0, + 0x1417 + ), // 10x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060285, + 1250, + 625, + 1438, + 719, + 26, + 86500, + 0, + 8, + 0, + 0x1418 + ), // 10x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060296, + 1250, + 625, + 1438, + 719, + 26, + 88500, + 0, + 8, + 0, + 0x1423 + ), // 11x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060297, + 1300, + 650, + 1495, + 747, + 28, + 94500, + 0, + 8, + 0, + 0x1424 + ), // 11x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060298, + 1350, + 675, + 1553, + 776, + 28, + 100500, + 0, + 9, + 0, + 0x1425 + ), // 11x16 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060308, + 1300, + 650, + 1495, + 747, + 28, + 96000, + 0, + 8, + 0, + 0x142F + ), // 12x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060309, + 1350, + 675, + 1553, + 776, + 28, + 102500, + 0, + 8, + 0, + 0x1430 + ), // 12x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060310, + 1370, + 685, + 1576, + 788, + 28, + 109000, + 0, + 9, + 0, + 0x1431 + ), // 12x16 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060311, + 1370, + 685, + 1576, + 788, + 28, + 115500, + 0, + 9, + 0, + 0x1432 + ), // 12x17 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060320, + 1350, + 675, + 1553, + 776, + 28, + 103500, + 0, + 8, + 0, + 0x143B + ), // 13x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060321, + 1370, + 685, + 1576, + 788, + 28, + 110500, + 0, + 8, + 0, + 0x143C + ), // 13x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060322, + 1370, + 685, + 1576, + 788, + 28, + 117500, + 0, + 9, + 0, + 0x143D + ), // 13x16 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060323, + 2119, + 1059, + 2437, + 1218, + 42, + 124500, + 0, + 9, + 0, + 0x143E + ), // 13x17 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060324, + 2119, + 1059, + 2437, + 1218, + 42, + 131500, + 0, + 10, + 0, + 0x143F + ), // 13x18 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060327, + 1150, + 575, + 1323, + 661, + 24, + 73500, + 0, + 5, + 0, + 0x1442 + ), // 14x9 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060328, + 1200, + 600, + 1380, + 690, + 26, + 81000, + 0, + 6, + 0, + 0x1443 + ), // 14x10 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060329, + 1250, + 625, + 1438, + 719, + 26, + 88500, + 0, + 6, + 0, + 0x1444 + ), // 14x11 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060330, + 1300, + 650, + 1495, + 747, + 28, + 96000, + 0, + 7, + 0, + 0x1445 + ), // 14x12 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060331, + 1350, + 675, + 1553, + 776, + 28, + 103500, + 0, + 7, + 0, + 0x1446 + ), // 14x13 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060332, + 1370, + 685, + 1576, + 788, + 28, + 111000, + 0, + 8, + 0, + 0x1447 + ), // 14x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060333, + 1370, + 685, + 1576, + 788, + 28, + 118500, + 0, + 8, + 0, + 0x1448 + ), // 14x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060334, + 2119, + 1059, + 2437, + 1218, + 42, + 126000, + 0, + 9, + 0, + 0x1449 + ), // 14x16 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060335, + 2119, + 1059, + 2437, + 1218, + 42, + 133500, + 0, + 9, + 0, + 0x144A + ), // 14x17 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060336, + 2119, + 1059, + 2437, + 1218, + 42, + 141000, + 0, + 10, + 0, + 0x144B + ), // 14x18 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060340, + 1250, + 625, + 1438, + 719, + 26, + 86500, + 0, + 6, + 0, + 0x144F + ), // 15x10 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060341, + 1300, + 650, + 1495, + 747, + 28, + 94500, + 0, + 6, + 0, + 0x1450 + ), // 15x11 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060342, + 1350, + 675, + 1553, + 776, + 28, + 102500, + 0, + 7, + 0, + 0x1451 + ), // 15x12 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060343, + 1370, + 685, + 1576, + 788, + 28, + 110500, + 0, + 7, + 0, + 0x1452 + ), // 15x13 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060344, + 1370, + 685, + 1576, + 788, + 28, + 118500, + 0, + 8, + 0, + 0x1453 + ), // 15x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060345, + 2119, + 1059, + 2437, + 1218, + 42, + 126500, + 0, + 8, + 0, + 0x1454 + ), // 15x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060346, + 2119, + 1059, + 2437, + 1218, + 42, + 134500, + 0, + 9, + 0, + 0x1455 + ), // 15x16 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060347, + 2119, + 1059, + 2437, + 1218, + 42, + 142500, + 0, + 9, + 0, + 0x1456 + ), // 15x17 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060348, + 2119, + 1059, + 2437, + 1218, + 42, + 150500, + 0, + 10, + 0, + 0x1457 + ), // 15x18 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060353, + 1350, + 675, + 1553, + 776, + 28, + 100500, + 0, + 6, + 0, + 0x145C + ), // 16x11 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060354, + 1370, + 685, + 1576, + 788, + 28, + 109000, + 0, + 7, + 0, + 0x145D + ), // 16x12 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060355, + 1370, + 685, + 1576, + 788, + 28, + 117500, + 0, + 7, + 0, + 0x145E + ), // 16x13 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060356, + 2119, + 1059, + 2437, + 1218, + 42, + 126000, + 0, + 8, + 0, + 0x145F + ), // 16x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060357, + 2119, + 1059, + 2437, + 1218, + 42, + 134500, + 0, + 8, + 0, + 0x1460 + ), // 16x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060358, + 2119, + 1059, + 2437, + 1218, + 42, + 143000, + 0, + 9, + 0, + 0x1461 + ), // 16x16 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060359, + 2119, + 1059, + 2437, + 1218, + 42, + 151500, + 0, + 9, + 0, + 0x1462 + ), // 16x17 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060360, + 2119, + 1059, + 2437, + 1218, + 42, + 160000, + 0, + 10, + 0, + 0x1463 + ), // 16x18 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060366, + 1370, + 685, + 1576, + 788, + 28, + 115500, + 0, + 7, + 0, + 0x1469 + ), // 17x12 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060367, + 2119, + 1059, + 2437, + 1218, + 42, + 124500, + 0, + 7, + 0, + 0x146A + ), // 17x13 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060368, + 2119, + 1059, + 2437, + 1218, + 42, + 133500, + 0, + 8, + 0, + 0x146B + ), // 17x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060369, + 2119, + 1059, + 2437, + 1218, + 42, + 142500, + 0, + 8, + 0, + 0x146C + ), // 17x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060370, + 2119, + 1059, + 2437, + 1218, + 42, + 151500, + 0, + 9, + 0, + 0x146D + ), // 17x16 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060371, + 2119, + 1059, + 2437, + 1218, + 42, + 160500, + 0, + 9, + 0, + 0x146E + ), // 17x17 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060372, + 2119, + 1059, + 2437, + 1218, + 42, + 169500, + 0, + 10, + 0, + 0x146F + ), // 17x18 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060379, + 2119, + 1059, + 2437, + 1218, + 42, + 131500, + 0, + 7, + 0, + 0x1476 + ), // 18x13 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060380, + 2119, + 1059, + 2437, + 1218, + 42, + 141000, + 0, + 8, + 0, + 0x1477 + ), // 18x14 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060381, + 2119, + 1059, + 2437, + 1218, + 42, + 150500, + 0, + 8, + 0, + 0x1478 + ), // 18x15 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060382, + 2119, + 1059, + 2437, + 1218, + 42, + 160000, + 0, + 9, + 0, + 0x1479 + ), // 18x16 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060383, + 2119, + 1059, + 2437, + 1218, + 42, + 169500, + 0, + 9, + 0, + 0x147A + ), // 18x17 3-Story Customizable House + new( + typeof(HouseFoundation), + 1060384, + 2119, + 1059, + 2437, + 1218, + 42, + 179000, + 0, + 10, + 0, + 0x147B + ) // 18x18 3-Story Customizable House + }; + + public BaseHouse ConstructHouse(Mobile from) + { + try { - try - { - object[] args; + object[] args; - if (Type == typeof(HouseFoundation)) - { - args = new object[] { from, MultiID, m_Storage, m_Lockdowns }; - } - else if (Type == typeof(SmallOldHouse) || Type == typeof(SmallShop) || Type == typeof(TwoStoryHouse)) - { - args = new object[] { from, MultiID }; - } - else - { - args = new object[] { from }; - } - - return Type.CreateInstance(args); + if (Type == typeof(HouseFoundation)) + { + args = new object[] { from, MultiID, _storage, _lockdowns }; + } + else if (Type == typeof(SmallOldHouse) || Type == typeof(SmallShop) || Type == typeof(TwoStoryHouse)) + { + args = new object[] { from, MultiID }; } - catch + else { - // ignored + args = new object[] { from }; } - return null; + return Type.CreateInstance(args); + } + catch + { + // ignored } - public void PlacementWarning_Callback(Mobile from, bool okay, PreviewHouse prevHouse) + return null; + } + + public void PlacementWarning_Callback(Mobile from, bool okay, PreviewHouse prevHouse) + { + if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) { - if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) - { - return; - } + return; + } - if (!okay) - { - prevHouse.Delete(); - return; - } + if (!okay) + { + prevHouse.Delete(); + return; + } - if (prevHouse.Deleted) - { - from.SendGump(new HousePlacementTimeoutNoticeGump()); - return; - } + if (prevHouse.Deleted) + { + from.SendGump(new HousePlacementTimeoutNoticeGump()); + return; + } - var center = prevHouse.Location; + var center = prevHouse.Location; - prevHouse.Delete(); + prevHouse.Delete(); - // Point3D center = new Point3D( p.X - m_Offset.X, p.Y - m_Offset.Y, p.Z - m_Offset.Z ); - var res = HousePlacement.Check(from, MultiID, center, out var toMove); + var res = HousePlacement.Check(from, MultiID, center, out var toMove); - switch (res) - { - case HousePlacementResult.Valid: + switch (res) + { + case HousePlacementResult.Valid: + { + if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + { + from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } + else { - if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) + var house = ConstructHouse(from); + + if (house == null) { - from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + return; } - else - { - var house = ConstructHouse(from); - if (house == null) - { - return; - } + house.Price = Cost; - house.Price = Cost; - - if (from.AccessLevel >= AccessLevel.GameMaster) + if (from.AccessLevel >= AccessLevel.GameMaster) + { + from.SendMessage( + $"{Cost} gold would have been withdrawn from your bank if you were not a GM." + ); + } + else + { + if (Banker.Withdraw(from, Cost)) { - from.SendMessage( - $"{Cost} gold would have been withdrawn from your bank if you were not a GM." - ); + // ~1_AMOUNT~ gold has been withdrawn from your bank box. + from.SendLocalizedMessage(1060398, Cost.ToString()); } else { - if (Banker.Withdraw(from, Cost)) - { - // ~1_AMOUNT~ gold has been withdrawn from your bank box. - from.SendLocalizedMessage(1060398, Cost.ToString()); - } - else - { - house.RemoveKeys(from); - house.Delete(); - // You do not have the funds available in your bank box to purchase this house. Try placing a smaller house, or adding gold or checks to your bank box. - from.SendLocalizedMessage(1060646); - return; - } + house.RemoveKeys(from); + house.Delete(); + // You do not have the funds available in your bank box to purchase this house. Try placing a smaller house, or adding gold or checks to your bank box. + from.SendLocalizedMessage(1060646); + return; } + } + + house.MoveToWorld(center, from.Map); - house.MoveToWorld(center, from.Map); + for (var i = 0; i < toMove.Count; ++i) + { + object o = toMove[i]; - for (var i = 0; i < toMove.Count; ++i) + if (o is Mobile mobile) + { + mobile.Location = house.BanLocation; + } + else if (o is Item item) { - object o = toMove[i]; - - if (o is Mobile mobile) - { - mobile.Location = house.BanLocation; - } - else if (o is Item item) - { - item.Location = house.BanLocation; - } + item.Location = house.BanLocation; } } - - break; - } - case HousePlacementResult.BadItem: - case HousePlacementResult.BadLand: - case HousePlacementResult.BadStatic: - case HousePlacementResult.BadRegionHidden: - case HousePlacementResult.NoSurface: - { - // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. - from.SendLocalizedMessage(1043287); - break; - } - case HousePlacementResult.BadRegion: - { - from.SendLocalizedMessage(501265); // Housing cannot be created in this area. - break; } - case HousePlacementResult.BadRegionTemp: - { - // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. - from.SendLocalizedMessage(501270); - break; - } - case HousePlacementResult.BadRegionRaffle: - { - // You must have a deed for this plot of land in order to build here. - from.SendLocalizedMessage(1150493); - break; - } - case HousePlacementResult.InvalidCastleKeep: - { - from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here. - break; - } - } + + break; + } + case HousePlacementResult.BadItem: + case HousePlacementResult.BadLand: + case HousePlacementResult.BadStatic: + case HousePlacementResult.BadRegionHidden: + case HousePlacementResult.NoSurface: + { + // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + from.SendLocalizedMessage(1043287); + break; + } + case HousePlacementResult.BadRegion: + { + from.SendLocalizedMessage(501265); // Housing cannot be created in this area. + break; + } + case HousePlacementResult.BadRegionTemp: + { + // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + from.SendLocalizedMessage(501270); + break; + } + case HousePlacementResult.BadRegionRaffle: + { + // You must have a deed for this plot of land in order to build here. + from.SendLocalizedMessage(1150493); + break; + } + case HousePlacementResult.InvalidCastleKeep: + { + from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here. + break; + } } + } - public bool OnPlacement(Mobile from, Point3D p) + public bool OnPlacement(Mobile from, Point3D p) + { + if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) { - if (!from.CheckAlive() || from.Backpack?.FindItemByType() == null) - { - return false; - } + return false; + } - var center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); - var res = HousePlacement.Check(from, MultiID, center, out var toMove); + var center = new Point3D(p.X - Offset.X, p.Y - Offset.Y, p.Z - Offset.Z); + var res = HousePlacement.Check(from, MultiID, center, out var toMove); - switch (res) - { - case HousePlacementResult.Valid: + switch (res) + { + case HousePlacementResult.Valid: + { + if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) { - if (from.AccessLevel < AccessLevel.GameMaster && BaseHouse.HasAccountHouse(from)) - { - from.SendLocalizedMessage(501271); // You already own a house, you may not place another! - } - else - { - from.SendLocalizedMessage(1011576); // This is a valid location. + from.SendLocalizedMessage(501271); // You already own a house, you may not place another! + } + else + { + from.SendLocalizedMessage(1011576); // This is a valid location. - var prev = new PreviewHouse(MultiID); + var prev = new PreviewHouse(MultiID); - var mcl = prev.Components; + var mcl = prev.Components; - var banLoc = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Max.Y + 1, center.Z); + var banLoc = new Point3D(center.X + mcl.Min.X, center.Y + mcl.Max.Y + 1, center.Z); - for (var i = 0; i < mcl.List.Length; ++i) - { - var entry = mcl.List[i]; + for (var i = 0; i < mcl.List.Length; ++i) + { + var entry = mcl.List[i]; - int itemID = entry.ItemId; + int itemID = entry.ItemId; - if (itemID >= 0xBA3 && itemID <= 0xC0E) - { - banLoc = new Point3D(center.X + entry.OffsetX, center.Y + entry.OffsetY, center.Z); - break; - } + if (itemID >= 0xBA3 && itemID <= 0xC0E) + { + banLoc = new Point3D(center.X + entry.OffsetX, center.Y + entry.OffsetY, center.Z); + break; } + } - for (var i = 0; i < toMove.Count; ++i) + for (var i = 0; i < toMove.Count; ++i) + { + object o = toMove[i]; + + if (o is Mobile mobile) { - object o = toMove[i]; - - if (o is Mobile mobile) - { - mobile.Location = banLoc; - } - else if (o is Item item) - { - item.Location = banLoc; - } + mobile.Location = banLoc; } + else if (o is Item item) + { + item.Location = banLoc; + } + } - prev.MoveToWorld(center, from.Map); - - from.SendGump( - new CondemnWarningGump(okay => PlacementWarning_Callback(from, okay, prev)) - ); + prev.MoveToWorld(center, from.Map); - return true; - } + from.SendGump( + new CondemnWarningGump(okay => PlacementWarning_Callback(from, okay, prev)) + ); - break; - } - case HousePlacementResult.BadItem: - case HousePlacementResult.BadLand: - case HousePlacementResult.BadStatic: - case HousePlacementResult.BadRegionHidden: - case HousePlacementResult.NoSurface: - { - // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. - from.SendLocalizedMessage(1043287); - break; - } - case HousePlacementResult.BadRegion: - { - from.SendLocalizedMessage(501265); // Housing cannot be created in this area. - break; - } - case HousePlacementResult.BadRegionTemp: - { - // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. - from.SendLocalizedMessage(501270); - break; - } - case HousePlacementResult.BadRegionRaffle: - { - // You must have a deed for this plot of land in order to build here. - from.SendLocalizedMessage(1150493); - break; + return true; } - case HousePlacementResult.InvalidCastleKeep: - { - from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here. - break; - } - } - return false; + break; + } + case HousePlacementResult.BadItem: + case HousePlacementResult.BadLand: + case HousePlacementResult.BadStatic: + case HousePlacementResult.BadRegionHidden: + case HousePlacementResult.NoSurface: + { + // The house could not be created here. Either something is blocking the house, or the house would not be on valid terrain. + from.SendLocalizedMessage(1043287); + break; + } + case HousePlacementResult.BadRegion: + { + from.SendLocalizedMessage(501265); // Housing cannot be created in this area. + break; + } + case HousePlacementResult.BadRegionTemp: + { + // Lord British has decreed a 'no build' period, thus you cannot build this house at this time. + from.SendLocalizedMessage(501270); + break; + } + case HousePlacementResult.BadRegionRaffle: + { + // You must have a deed for this plot of land in order to build here. + from.SendLocalizedMessage(1150493); + break; + } + case HousePlacementResult.InvalidCastleKeep: + { + from.SendLocalizedMessage(1061122); // Castles and keeps cannot be created here. + break; + } } - public static HousePlacementEntry Find(BaseHouse house) - { - m_Table.TryGetValue(house.GetType(), out var obj); + return false; + } - if (obj is HousePlacementEntry entry) - { - return entry; - } + public static HousePlacementEntry Find(BaseHouse house) + { + _table.TryGetValue(house.GetType(), out var obj); - if (obj is List list) + if (obj is HousePlacementEntry entry) + { + return entry; + } + + if (obj is List list) + { + foreach (var hpe in list) { - foreach (var hpe in list) + if (hpe.MultiID == house.ItemID) { - if (hpe.MultiID == house.ItemID) - { - return hpe; - } + return hpe; } - - return null; - } - - if (obj is Dictionary table) - { - return table[house.ItemID]; } return null; } - private static void FillTable(HousePlacementEntry[] entries) + if (obj is Dictionary table) { - for (var i = 0; i < entries.Length; ++i) - { - var e = entries[i]; + return table[house.ItemID]; + } - if (!m_Table.TryGetValue(e.Type, out var obj)) - { - m_Table[e.Type] = e; - } - else if (obj is HousePlacementEntry entry) - { - var list = new List { entry, e }; + return null; + } - m_Table[e.Type] = list; - } - else if (obj is List list) - { - if (list.Count == 8) - { - var table = new Dictionary(); + private static void FillTable(HousePlacementEntry[] entries) + { + for (var i = 0; i < entries.Length; ++i) + { + var e = entries[i]; - foreach (var t in list) - { - table[t.MultiID] = t; - } + if (!_table.TryGetValue(e.Type, out var obj)) + { + _table[e.Type] = e; + } + else if (obj is HousePlacementEntry entry) + { + var list = new List { entry, e }; - table[e.MultiID] = e; + _table[e.Type] = list; + } + else if (obj is List list) + { + if (list.Count == 8) + { + var table = new Dictionary(); - m_Table[e.Type] = table; - } - else + foreach (var t in list) { - list.Add(e); + table[t.MultiID] = t; } + + table[e.MultiID] = e; + + _table[e.Type] = table; } - else if (obj is Dictionary table) + else { - table[e.MultiID] = e; + list.Add(e); } } - } - - private class CondemnWarningGump : StaticWarningGump - { - /* - * You are about to place a new house. - * Placing this house will condemn any and all of your other houses that you may have. - * All of your houses on all shards will be affected.

In addition, you will not be able to place - * another house or have one transferred to you for one (1) real-life week.

- * Once you accept these terms, these effects cannot be reversed. - * Re-deeding or transferring your new house will not uncondemn your other house(s) nor will the one - * week timer be removed.

If you are absolutely certain you wish to proceed, click the button next to OKAY below. - * If you do not wish to trade for this house, click CANCEL. - */ - - public override int StaticLocalizedContent => 1049583; - public override int Width => 420; - public override int Height => 280; - - public CondemnWarningGump(Action callback) : base(callback) + else if (obj is Dictionary table) { + table[e.MultiID] = e; } } + } - private class HousePlacementTimeoutNoticeGump : StaticWarningGump + private class CondemnWarningGump : StaticWarningGump + { + /* + * You are about to place a new house. + * Placing this house will condemn any and all of your other houses that you may have. + * All of your houses on all shards will be affected.

In addition, you will not be able to place + * another house or have one transferred to you for one (1) real-life week.

+ * Once you accept these terms, these effects cannot be reversed. + * Re-deeding or transferring your new house will not uncondemn your other house(s) nor will the one + * week timer be removed.

If you are absolutely certain you wish to proceed, click the button next to OKAY below. + * If you do not wish to trade for this house, click CANCEL. + */ + + public override int StaticLocalizedContent => 1049583; + public override int Width => 420; + public override int Height => 280; + + public CondemnWarningGump(Action callback) : base(callback) { - // Too much time has passed and the test house you created has been deleted. Please try again! - public override int StaticLocalizedContent => 1060647; - public override int Width => 320; - public override int Height => 180; } } + + private class HousePlacementTimeoutNoticeGump : StaticWarningGump + { + // Too much time has passed and the test house you created has been deleted. Please try again! + public override int StaticLocalizedContent => 1060647; + public override int Width => 320; + public override int Height => 180; + } } diff --git a/Projects/UOContent/Multis/Houses/HouseSign.cs b/Projects/UOContent/Multis/Houses/HouseSign.cs index 8737b048b4..2cacd3c5e1 100644 --- a/Projects/UOContent/Multis/Houses/HouseSign.cs +++ b/Projects/UOContent/Multis/Houses/HouseSign.cs @@ -1,311 +1,274 @@ using System; using System.Collections.Generic; +using ModernUO.Serialization; using Server.ContextMenus; using Server.Gumps; -namespace Server.Multis +namespace Server.Multis; + +[SerializationGenerator(0, false)] +public partial class HouseSign : Item { - public class HouseSign : Item - { - public HouseSign(BaseHouse owner) : base(0xBD2) - { - Owner = owner; - OriginalOwner = Owner.Owner; - Movable = false; - } + [SerializableField(0, setter: "private")] + private BaseHouse _owner; - public HouseSign(Serial serial) : base(serial) - { - } + [SerializableField(1, setter: "private")] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private Mobile _originalOwner; - public BaseHouse Owner { get; private set; } + public HouseSign(BaseHouse owner) : base(0xBD2) + { + Owner = owner; + OriginalOwner = Owner.Owner; + Movable = false; + } - [CommandProperty(AccessLevel.GameMaster)] - public bool RestrictDecay + [CommandProperty(AccessLevel.GameMaster)] + public bool RestrictDecay + { + get => Owner?.RestrictDecay == true; + set { - get => Owner?.RestrictDecay == true; - set + if (Owner != null) { - if (Owner != null) - { - Owner.RestrictDecay = value; - } + Owner.RestrictDecay = value; } } + } - [CommandProperty(AccessLevel.GameMaster)] - public Mobile OriginalOwner { get; private set; } - - public override bool ForceShowProperties => ObjectPropertyList.Enabled; + public int LabelNumber => 1061638; // A House Sign - public bool GettingProperties { get; private set; } + public override bool ForceShowProperties => ObjectPropertyList.Enabled; - public string GetName() => Name ?? "An Unnamed House"; + public bool GettingProperties { get; private set; } - public override void OnAfterDelete() - { - base.OnAfterDelete(); + public string GetName() => Name ?? "An Unnamed House"; - if (Owner?.Deleted == false) - { - Owner.Delete(); - } - } + public override void OnAfterDelete() + { + base.OnAfterDelete(); - public override void AddNameProperty(IPropertyList list) + if (Owner?.Deleted == false) { - list.Add(1061638); // A House Sign + Owner.Delete(); } + } - public override void GetProperties(IPropertyList list) - { - base.GetProperties(list); - - list.Add(1061639, GetName().FixHtml()); // Name: ~1_NAME~ - list.Add(1061640, Owner?.Owner == null ? "nobody" : Owner.Owner.Name); // Owner: ~1_OWNER~ - - if (Owner != null) - { - list.Add(Owner.Public ? 1061641 : 1061642); // This House is Open to the Public : This is a Private Home + public override void GetProperties(IPropertyList list) + { + base.GetProperties(list); - GettingProperties = true; - var level = Owner.DecayLevel; - GettingProperties = false; + list.Add(1061639, GetName().FixHtml()); // Name: ~1_NAME~ + list.Add(1061640, Owner?.Owner?.Name ?? "nobody"); // Owner: ~1_OWNER~ - if (level == DecayLevel.DemolitionPending) - { - list.Add(1062497); // Demolition Pending - } - else if (level != DecayLevel.Ageless) - { - if (level == DecayLevel.Collapsed) - { - level = DecayLevel.IDOC; - } + if (Owner != null) + { + list.Add(Owner.Public ? 1061641 : 1061642); // This House is Open to the Public : This is a Private Home - list.AddLocalized(1062028, 1043009 + (int)level); // Condition: This structure is ... - } - } - } + GettingProperties = true; + var level = Owner.DecayLevel; + GettingProperties = false; - public override void OnSingleClick(Mobile from) - { - if (BaseHouse.DecayEnabled && Owner != null && Owner.DecayPeriod != TimeSpan.Zero) + if (level == DecayLevel.DemolitionPending) { - var message = Owner.DecayLevel switch - { - DecayLevel.Ageless => "ageless", - DecayLevel.Fairly => "fairly worn", - DecayLevel.Greatly => "greatly worn", - DecayLevel.LikeNew => "like new", - DecayLevel.Slightly => "slightly worn", - DecayLevel.Somewhat => "somewhat worn", - _ => "in danger of collapsing" - }; - - LabelTo(from, $"This house is {message}."); + list.Add(1062497); // Demolition Pending } - - base.OnSingleClick(from); - } - - public void ShowSign(Mobile m) - { - if (Owner != null) + else if (level != DecayLevel.Ageless) { - if (Owner.IsFriend(m) && m.AccessLevel < AccessLevel.GameMaster) + if (level == DecayLevel.Collapsed) { - if (Core.ML && Owner.IsOwner(m) || !Core.ML) - { - Owner.RefreshDecay(); - } - - if (!Core.AOS) - { - m.SendLocalizedMessage(501293); // Welcome back to the house, friend! - } + level = DecayLevel.IDOC; } - if (Owner.IsAosRules) - { - m.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Information, m, Owner)); - } - else - { - m.SendGump(new HouseGump(m, Owner)); - } + list.AddLocalized(1062028, 1043009 + (int)level); // Condition: This structure is ... } } + } - public void ClaimGump_Callback(Mobile from, bool okay) + public override void OnSingleClick(Mobile from) + { + if (BaseHouse.DecayEnabled && Owner != null && Owner.DecayPeriod != TimeSpan.Zero) { - if (okay && Owner != null && Owner.Owner == null && Owner.DecayLevel != DecayLevel.DemolitionPending) + var message = Owner.DecayLevel switch { - var canClaim = Owner.CoOwners?.Count > 0 && Owner.IsCoOwner(from) || Owner.IsFriend(from); + DecayLevel.Ageless => "ageless", + DecayLevel.Fairly => "fairly worn", + DecayLevel.Greatly => "greatly worn", + DecayLevel.LikeNew => "like new", + DecayLevel.Slightly => "slightly worn", + DecayLevel.Somewhat => "somewhat worn", + _ => "in danger of collapsing" + }; + + LabelTo(from, $"This house is {message}."); + } - if (canClaim && !BaseHouse.HasAccountHouse(from)) - { - Owner.Owner = from; - Owner.LastTraded = Core.Now; - } - } + base.OnSingleClick(from); + } - ShowSign(from); + public void ShowSign(Mobile m) + { + if (Owner == null) + { + return; } - public override void OnDoubleClick(Mobile m) + if (Owner.IsFriend(m) && m.AccessLevel < AccessLevel.GameMaster) { - if (Owner == null) + if (Core.ML && Owner.IsOwner(m) || !Core.ML) { - return; + Owner.RefreshDecay(); } - if (m.AccessLevel < AccessLevel.GameMaster && Owner.Owner == null && - Owner.DecayLevel != DecayLevel.DemolitionPending) + if (!Core.AOS) { - var canClaim = Owner.IsCoOwner(m) || Owner.IsFriend(m); - - if (canClaim && !BaseHouse.HasAccountHouse(m)) - { - m.SendGump( - new ClaimHouseWarningGump(okay => ClaimGump_Callback(m, okay)) - ); - } + m.SendLocalizedMessage(501293); // Welcome back to the house, friend! } - - ShowSign(m); } - private class ClaimHouseWarningGump : StaticWarningGump + if (Owner.IsAosRules) { - public override int Header => 501036; // Claim house - public override int HeaderColor => 0x7F00; - - /* - * You do not currently own any house on any shard with this account, and this house currently does not have an owner. - * If you wish, you may choose to claim this house and become its rightful owner. - * If you do this, it will become your Primary house and automatically refresh. - * If you claim this house, you will be unable to place another house or have another house transferred to you for the next 7 days. - * Do you wish to claim this house? - */ - public override int StaticLocalizedContent => 1049719; - - public override int Width => 420; - public override int Height => 280; - - public ClaimHouseWarningGump(Action callback) : base(callback) - { - } + m.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Information, m, Owner)); + } + else + { + m.SendGump(new HouseGump(m, Owner)); } + } - public override void GetContextMenuEntries(Mobile from, List list) + public void ClaimGump_Callback(Mobile from, bool okay) + { + if (okay && Owner != null && Owner.Owner == null && Owner.DecayLevel != DecayLevel.DemolitionPending) { - base.GetContextMenuEntries(from, list); + var canClaim = Owner.CoOwners?.Count > 0 && Owner.IsCoOwner(from) || Owner.IsFriend(from); - if (!BaseHouse.NewVendorSystem || !from.Alive || Owner?.IsAosRules != true) + if (canClaim && !BaseHouse.HasAccountHouse(from)) { - return; + Owner.Owner = from; + Owner.LastTraded = Core.Now; } + } - if (Owner.AreThereAvailableVendorsFor(from)) - { - list.Add(new VendorsEntry(this)); - } + ShowSign(from); + } + + public override void OnDoubleClick(Mobile m) + { + if (Owner == null) + { + return; + } + + if (m.AccessLevel < AccessLevel.GameMaster && Owner.Owner == null && + Owner.DecayLevel != DecayLevel.DemolitionPending) + { + var canClaim = Owner.IsCoOwner(m) || Owner.IsFriend(m); - if (Owner.VendorInventories.Count > 0) + if (canClaim && !BaseHouse.HasAccountHouse(m)) { - list.Add(new ReclaimVendorInventoryEntry(this)); + m.SendGump( + new ClaimHouseWarningGump(okay => ClaimGump_Callback(m, okay)) + ); } } - public override void Serialize(IGenericWriter writer) + ShowSign(m); + } + + private class ClaimHouseWarningGump : StaticWarningGump + { + public override int Header => 501036; // Claim house + public override int HeaderColor => 0x7F00; + + /* + * You do not currently own any house on any shard with this account, and this house currently does not have an owner. + * If you wish, you may choose to claim this house and become its rightful owner. + * If you do this, it will become your Primary house and automatically refresh. + * If you claim this house, you will be unable to place another house or have another house transferred to you for the next 7 days. + * Do you wish to claim this house? + */ + public override int StaticLocalizedContent => 1049719; + + public override int Width => 420; + public override int Height => 280; + + public ClaimHouseWarningGump(Action callback) : base(callback) { - base.Serialize(writer); + } + } - writer.Write(0); // version + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); - writer.Write(Owner); - writer.Write(OriginalOwner); + if (!BaseHouse.NewVendorSystem || !from.Alive || Owner?.IsAosRules != true) + { + return; } - public override void Deserialize(IGenericReader reader) + if (Owner.AreThereAvailableVendorsFor(from)) { - base.Deserialize(reader); - - var version = reader.ReadInt(); + list.Add(new VendorsEntry(this)); + } - switch (version) - { - case 0: - { - Owner = reader.ReadEntity(); - OriginalOwner = reader.ReadEntity(); + if (Owner.VendorInventories.Count > 0) + { + list.Add(new ReclaimVendorInventoryEntry(this)); + } + } - break; - } - } + private class VendorsEntry : ContextMenuEntry + { + private readonly HouseSign m_Sign; - if (Name == "a house sign") - { - Name = null; - } - } + public VendorsEntry(HouseSign sign) : base(6211) => m_Sign = sign; - private class VendorsEntry : ContextMenuEntry + public override void OnClick() { - private readonly HouseSign m_Sign; + var from = Owner.From; - public VendorsEntry(HouseSign sign) : base(6211) => m_Sign = sign; - - public override void OnClick() + if (!from.CheckAlive() || m_Sign.Deleted || m_Sign.Owner?.AreThereAvailableVendorsFor(from) != true) { - var from = Owner.From; - - if (!from.CheckAlive() || m_Sign.Deleted || m_Sign.Owner?.AreThereAvailableVendorsFor(from) != true) - { - return; - } + return; + } - if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5)) - { - from.SendLocalizedMessage( - 1062429 - ); // You must be within five paces of the house sign to use this option. - } - else - { - from.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Vendors, from, m_Sign.Owner)); - } + if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5)) + { + // You must be within five paces of the house sign to use this option. + from.SendLocalizedMessage(1062429); + } + else + { + from.SendGump(new HouseGumpAOS(HouseGumpPageAOS.Vendors, from, m_Sign.Owner)); } } + } - private class ReclaimVendorInventoryEntry : ContextMenuEntry - { - private readonly HouseSign m_Sign; + private class ReclaimVendorInventoryEntry : ContextMenuEntry + { + private readonly HouseSign m_Sign; - public ReclaimVendorInventoryEntry(HouseSign sign) : base(6213) => m_Sign = sign; + public ReclaimVendorInventoryEntry(HouseSign sign) : base(6213) => m_Sign = sign; - public override void OnClick() - { - var from = Owner.From; + public override void OnClick() + { + var from = Owner.From; - if (m_Sign.Deleted || m_Sign.Owner == null || m_Sign.Owner.VendorInventories.Count == 0 || - !from.CheckAlive()) - { - return; - } + if (m_Sign.Deleted || m_Sign.Owner == null || m_Sign.Owner.VendorInventories.Count == 0 || + !from.CheckAlive()) + { + return; + } - if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5)) - { - from.SendLocalizedMessage( - 1062429 - ); // You must be within five paces of the house sign to use this option. - } - else - { - from.CloseGump(); - from.SendGump(new VendorInventoryGump(m_Sign.Owner, from)); - } + if (from.Map != m_Sign.Map || !from.InRange(m_Sign, 5)) + { + // You must be within five paces of the house sign to use this option. + from.SendLocalizedMessage(1062429); + } + else + { + from.CloseGump(); + from.SendGump(new VendorInventoryGump(m_Sign.Owner, from)); } } } diff --git a/Projects/UOContent/Multis/Houses/HouseTeleporter.cs b/Projects/UOContent/Multis/Houses/HouseTeleporter.cs index 5e78261200..087cf3cdfd 100644 --- a/Projects/UOContent/Multis/Houses/HouseTeleporter.cs +++ b/Projects/UOContent/Multis/Houses/HouseTeleporter.cs @@ -1,198 +1,163 @@ using System; using System.Collections.Generic; +using ModernUO.Serialization; using Server.ContextMenus; using Server.Gumps; using Server.Mobiles; using Server.Multis; -namespace Server.Items -{ - public class HouseTeleporter : Item, ISecurable - { - public HouseTeleporter(int itemID, Item target = null) : base(itemID) - { - Movable = false; +namespace Server.Items; - Level = SecureLevel.Anyone; +[SerializationGenerator(2, false)] +public partial class HouseTeleporter : Item, ISecurable +{ + [SerializableField(0)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private SecureLevel _level; - Target = target; - } + [SerializableField(1)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private Item _target; - public HouseTeleporter(Serial serial) : base(serial) - { - } + public HouseTeleporter(int itemID, Item target = null) : base(itemID) + { + Movable = false; + _level = SecureLevel.Anyone; + _target = target; + } - [CommandProperty(AccessLevel.GameMaster)] - public Item Target { get; set; } + public bool CheckAccess(Mobile m) + { + var house = BaseHouse.FindHouseAt(this); - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } + return (house == null || house.Public && !house.IsBanned(m) || house.HasAccess(m)) && + house?.HasSecureAccess(m, Level) == true; + } - public bool CheckAccess(Mobile m) + public override bool OnMoveOver(Mobile m) + { + if (Target?.Deleted != false) { - var house = BaseHouse.FindHouseAt(this); - - return (house == null || house.Public && !house.IsBanned(m) || house.HasAccess(m)) && - house?.HasSecureAccess(m, Level) == true; + return true; } - public override bool OnMoveOver(Mobile m) + if (!CheckAccess(m)) { - if (Target?.Deleted == false) - { - if (CheckAccess(m)) - { - if (!m.Hidden || m.AccessLevel == AccessLevel.Player) - { - new EffectTimer(Location, Map, 2023, 0x1F0, TimeSpan.FromSeconds(0.4)).Start(); - } - - new DelayTimer(this, m).Start(); - } - else - { - m.SendLocalizedMessage(1061637); // You are not allowed to access this. - } - } - - return true; + m.SendLocalizedMessage(1061637); // You are not allowed to access this. + return false; } - public override void GetContextMenuEntries(Mobile from, List list) + if (!m.Hidden || m.AccessLevel == AccessLevel.Player) { - base.GetContextMenuEntries(from, list); - SetSecureLevelEntry.AddTo(from, this, list); + new EffectTimer(Location, Map, 2023, 0x1F0, TimeSpan.FromSeconds(0.4)).Start(); } - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); + new DelayTimer(this, m).Start(); + return true; + } - writer.Write(1); // version + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + SetSecureLevelEntry.AddTo(from, this, list); + } - writer.Write((int)Level); + private void Deserialize(IGenericReader reader, int version) + { + Level = (SecureLevel)reader.ReadInt(); + Target = reader.ReadEntity(); + } - writer.Write(Target); - } + private class EffectTimer : Timer + { + private readonly int _effectId; + private readonly Point3D _location; + private readonly Map _map; + private readonly int _soundId; - public override void Deserialize(IGenericReader reader) + public EffectTimer(Point3D p, Map map, int effectID, int soundID, TimeSpan delay) : base(delay) { - base.Deserialize(reader); - - var version = reader.ReadInt(); + _location = p; + _map = map; + _effectId = effectID; + _soundId = soundID; + } - switch (version) + protected override void OnTick() + { + Effects.SendLocationParticles( + EffectItem.Create(_location, _map, EffectItem.DefaultDuration), + 0x3728, + 10, + 10, + _effectId, + 0 + ); + + if (_soundId != -1) { - case 1: - { - Level = (SecureLevel)reader.ReadInt(); - goto case 0; - } - case 0: - { - Target = reader.ReadEntity(); - - if (version < 1) - { - Level = SecureLevel.Anyone; - } - - break; - } + Effects.PlaySound(_location, _map, _soundId); } } + } + + private class DelayTimer : Timer + { + private readonly Mobile _mobile; + private readonly HouseTeleporter _teleporter; + + public DelayTimer(HouseTeleporter tp, Mobile m) : base(TimeSpan.FromSeconds(1.0)) + { + _teleporter = tp; + _mobile = m; + } - private class EffectTimer : Timer + protected override void OnTick() { - private readonly int m_EffectID; - private readonly Point3D m_Location; - private readonly Map m_Map; - private readonly int m_SoundID; + var target = _teleporter.Target; - public EffectTimer(Point3D p, Map map, int effectID, int soundID, TimeSpan delay) : base(delay) + if (target?.Deleted != false) { - m_Location = p; - m_Map = map; - m_EffectID = effectID; - m_SoundID = soundID; + return; } - protected override void OnTick() + if (_mobile.Location != _teleporter.Location || _mobile.Map != _teleporter.Map) { - Effects.SendLocationParticles( - EffectItem.Create(m_Location, m_Map, EffectItem.DefaultDuration), - 0x3728, - 10, - 10, - m_EffectID, - 0 - ); - - if (m_SoundID != -1) - { - Effects.PlaySound(m_Location, m_Map, m_SoundID); - } + return; } - } - private class DelayTimer : Timer - { - private readonly Mobile m_Mobile; - private readonly HouseTeleporter m_Teleporter; + var p = target.GetWorldTop(); + var map = target.Map; - public DelayTimer(HouseTeleporter tp, Mobile m) : base(TimeSpan.FromSeconds(1.0)) - { - m_Teleporter = tp; - m_Mobile = m; - } + BaseCreature.TeleportPets(_mobile, p, map); - protected override void OnTick() + _mobile.MoveToWorld(p, map); + + if (_mobile.Hidden && _mobile.AccessLevel != AccessLevel.Player) { - var target = m_Teleporter.Target; - - if (target?.Deleted != false) - { - return; - } - - if (m_Mobile.Location != m_Teleporter.Location || m_Mobile.Map != m_Teleporter.Map) - { - return; - } - - var p = target.GetWorldTop(); - var map = target.Map; - - BaseCreature.TeleportPets(m_Mobile, p, map); - - m_Mobile.MoveToWorld(p, map); - - if (m_Mobile.Hidden && m_Mobile.AccessLevel != AccessLevel.Player) - { - return; - } - - Effects.PlaySound(target.Location, target.Map, 0x1FE); - - Effects.SendLocationParticles( - EffectItem.Create(m_Teleporter.Location, m_Teleporter.Map, EffectItem.DefaultDuration), - 0x3728, - 10, - 10, - 2023, - 0 - ); - Effects.SendLocationParticles( - EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), - 0x3728, - 10, - 10, - 5023, - 0 - ); - - new EffectTimer(target.Location, target.Map, 2023, -1, TimeSpan.FromSeconds(0.4)).Start(); + return; } + + Effects.PlaySound(target.Location, target.Map, 0x1FE); + + Effects.SendLocationParticles( + EffectItem.Create(_teleporter.Location, _teleporter.Map, EffectItem.DefaultDuration), + 0x3728, + 10, + 10, + 2023, + 0 + ); + Effects.SendLocationParticles( + EffectItem.Create(target.Location, target.Map, EffectItem.DefaultDuration), + 0x3728, + 10, + 10, + 5023, + 0 + ); + + new EffectTimer(target.Location, target.Map, 2023, -1, TimeSpan.FromSeconds(0.4)).Start(); } } }