From b44c69bcee04e0a27a425f15a39cae343df81c01 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Wed, 7 Sep 2022 01:13:20 -0700 Subject: [PATCH] fix: Source generates map item serialization (#1166) --- Projects/Server/Geometry/Rectangle2D.cs | 259 +-- Projects/UOContent/Items/Maps/BlankMap.cs | 40 +- Projects/UOContent/Items/Maps/CityMap.cs | 66 +- .../UOContent/Items/Maps/IndecipherableMap.cs | 52 +- Projects/UOContent/Items/Maps/LocalMap.cs | 48 +- Projects/UOContent/Items/Maps/MapItem.cs | 472 +++-- .../UOContent/Items/Maps/MapItemPackets.cs | 36 +- Projects/UOContent/Items/Maps/PresetMap.cs | 242 ++- Projects/UOContent/Items/Maps/SeaChart.cs | 66 +- Projects/UOContent/Items/Maps/TreasureMap.cs | 1655 ++++++++--------- Projects/UOContent/Items/Maps/WorldMap.cs | 62 +- .../Migrations/Server.Items.BlankMap.v0.json | 4 + .../Migrations/Server.Items.CityMap.v0.json | 4 + .../Server.Items.IndecipherableMap.v0.json | 4 + .../Migrations/Server.Items.LocalMap.v0.json | 4 + .../Migrations/Server.Items.MapItem.v1.json | 65 + .../Migrations/Server.Items.PresetMap.v0.json | 14 + .../Migrations/Server.Items.SeaChart.v0.json | 4 + .../Server.Items.TreasureChestDirt.v0.json | 4 + .../Server.Items.TreasureMap.v0.json | 48 + .../Migrations/Server.Items.WorldMap.v0.json | 4 + 21 files changed, 1517 insertions(+), 1636 deletions(-) create mode 100644 Projects/UOContent/Migrations/Server.Items.BlankMap.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.CityMap.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.IndecipherableMap.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.LocalMap.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.MapItem.v1.json create mode 100644 Projects/UOContent/Migrations/Server.Items.PresetMap.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.SeaChart.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.TreasureChestDirt.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.TreasureMap.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.WorldMap.v0.json diff --git a/Projects/Server/Geometry/Rectangle2D.cs b/Projects/Server/Geometry/Rectangle2D.cs index 3eaefc70a..ad3550dd6 100644 --- a/Projects/Server/Geometry/Rectangle2D.cs +++ b/Projects/Server/Geometry/Rectangle2D.cs @@ -15,133 +15,140 @@ using System; -namespace Server +namespace Server; + +[NoSort] +[Parsable] +[PropertyObject] +public struct Rectangle2D { - [NoSort] - [Parsable] - [PropertyObject] - public struct Rectangle2D + public bool Equals(Rectangle2D other) => m_Start == other.m_Start && m_End == other.m_End; + + public static bool operator ==(Rectangle2D l, Rectangle2D r) => l.m_Start == r.m_Start && l.m_End == r.m_End; + + public static bool operator !=(Rectangle2D l, Rectangle2D r) => l.m_Start != r.m_Start || l.m_End != r.m_End; + + public override int GetHashCode() => HashCode.Combine(m_Start, m_End); + + private Point2D m_Start; + private Point2D m_End; + + public Rectangle2D(Point2D start, Point2D end) { - private Point2D m_Start; - private Point2D m_End; - - public Rectangle2D(Point2D start, Point2D end) - { - m_Start = start; - m_End = end; - } - - public Rectangle2D(int x, int y, int width, int height) - { - m_Start = new Point2D(x, y); - m_End = new Point2D(x + width, y + height); - } - - public void Set(int x, int y, int width, int height) - { - m_Start = new Point2D(x, y); - m_End = new Point2D(x + width, y + height); - } - - public static Rectangle2D Parse(string value) - { - var start = value.IndexOfOrdinal('('); - var end = value.IndexOf(',', start + 1); - - Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x); - - start = end; - end = value.IndexOf(',', start + 1); - - Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y); - - start = end; - end = value.IndexOf(',', start + 1); - - Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var w); - - start = end; - end = value.IndexOf(')', start + 1); - - Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var h); - - return new Rectangle2D(x, y, w, h); - } - - [CommandProperty(AccessLevel.Counselor)] - public Point2D Start - { - get => m_Start; - set => m_Start = value; - } - - [CommandProperty(AccessLevel.Counselor)] - public Point2D End - { - get => m_End; - set => m_End = value; - } - - [CommandProperty(AccessLevel.Counselor)] - public int X - { - get => m_Start.m_X; - set => m_Start.m_X = value; - } - - [CommandProperty(AccessLevel.Counselor)] - public int Y - { - get => m_Start.m_Y; - set => m_Start.m_Y = value; - } - - [CommandProperty(AccessLevel.Counselor)] - public int Width - { - get => m_End.m_X - m_Start.m_X; - set => m_End.m_X = m_Start.m_X + value; - } - - [CommandProperty(AccessLevel.Counselor)] - public int Height - { - get => m_End.m_Y - m_Start.m_Y; - set => m_End.m_Y = m_Start.m_Y + value; - } - - public void MakeHold(Rectangle2D r) - { - if (r.m_Start.m_X < m_Start.m_X) - { - m_Start.m_X = r.m_Start.m_X; - } - - if (r.m_Start.m_Y < m_Start.m_Y) - { - m_Start.m_Y = r.m_Start.m_Y; - } - - if (r.m_End.m_X > m_End.m_X) - { - m_End.m_X = r.m_End.m_X; - } - - if (r.m_End.m_Y > m_End.m_Y) - { - m_End.m_Y = r.m_End.m_Y; - } - } - - public readonly bool Contains(Point3D p) => - m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y; - - public readonly bool Contains(Point2D p) => - m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y; - - public readonly bool Contains(int x, int y) => - m_Start.m_X <= x && m_Start.m_Y <= y && m_End.m_X > x && m_End.m_Y > y; - - public override string ToString() => $"({X}, {Y})+({Width}, {Height})"; + m_Start = start; + m_End = end; } + + public Rectangle2D(int x, int y, int width, int height) + { + m_Start = new Point2D(x, y); + m_End = new Point2D(x + width, y + height); + } + + public void Set(int x, int y, int width, int height) + { + m_Start = new Point2D(x, y); + m_End = new Point2D(x + width, y + height); + } + + public static Rectangle2D Parse(string value) + { + var start = value.IndexOfOrdinal('('); + var end = value.IndexOf(',', start + 1); + + Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x); + + start = end; + end = value.IndexOf(',', start + 1); + + Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y); + + start = end; + end = value.IndexOf(',', start + 1); + + Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var w); + + start = end; + end = value.IndexOf(')', start + 1); + + Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var h); + + return new Rectangle2D(x, y, w, h); + } + + [CommandProperty(AccessLevel.Counselor)] + public Point2D Start + { + get => m_Start; + set => m_Start = value; + } + + [CommandProperty(AccessLevel.Counselor)] + public Point2D End + { + get => m_End; + set => m_End = value; + } + + [CommandProperty(AccessLevel.Counselor)] + public int X + { + get => m_Start.m_X; + set => m_Start.m_X = value; + } + + [CommandProperty(AccessLevel.Counselor)] + public int Y + { + get => m_Start.m_Y; + set => m_Start.m_Y = value; + } + + [CommandProperty(AccessLevel.Counselor)] + public int Width + { + get => m_End.m_X - m_Start.m_X; + set => m_End.m_X = m_Start.m_X + value; + } + + [CommandProperty(AccessLevel.Counselor)] + public int Height + { + get => m_End.m_Y - m_Start.m_Y; + set => m_End.m_Y = m_Start.m_Y + value; + } + + public void MakeHold(Rectangle2D r) + { + if (r.m_Start.m_X < m_Start.m_X) + { + m_Start.m_X = r.m_Start.m_X; + } + + if (r.m_Start.m_Y < m_Start.m_Y) + { + m_Start.m_Y = r.m_Start.m_Y; + } + + if (r.m_End.m_X > m_End.m_X) + { + m_End.m_X = r.m_End.m_X; + } + + if (r.m_End.m_Y > m_End.m_Y) + { + m_End.m_Y = r.m_End.m_Y; + } + } + + public readonly bool Contains(Point3D p) => + m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y; + + public readonly bool Contains(Point2D p) => + m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y; + + public readonly bool Contains(int x, int y) => + m_Start.m_X <= x && m_Start.m_Y <= y && m_End.m_X > x && m_End.m_Y > y; + + public override string ToString() => $"({X}, {Y})+({Width}, {Height})"; } diff --git a/Projects/UOContent/Items/Maps/BlankMap.cs b/Projects/UOContent/Items/Maps/BlankMap.cs index 5c7667e1a..c1c5c893f 100644 --- a/Projects/UOContent/Items/Maps/BlankMap.cs +++ b/Projects/UOContent/Items/Maps/BlankMap.cs @@ -1,33 +1,17 @@ -namespace Server.Items +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class BlankMap : MapItem { - public class BlankMap : MapItem + [Constructible] + public BlankMap() { - [Constructible] - public BlankMap() - { - } + } - public BlankMap(Serial serial) : base(serial) - { - } - - public override void OnDoubleClick(Mobile from) - { - SendLocalizedMessageTo(from, 500208); // It appears to be blank. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } + public override void OnDoubleClick(Mobile from) + { + SendLocalizedMessageTo(from, 500208); // It appears to be blank. } } diff --git a/Projects/UOContent/Items/Maps/CityMap.cs b/Projects/UOContent/Items/Maps/CityMap.cs index f5c34b81b..095e923e7 100644 --- a/Projects/UOContent/Items/Maps/CityMap.cs +++ b/Projects/UOContent/Items/Maps/CityMap.cs @@ -1,55 +1,25 @@ -namespace Server.Items +using System; +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class CityMap : MapItem { - public class CityMap : MapItem + [Constructible] + public CityMap() { - [Constructible] - public CityMap() - { - SetDisplay(0, 0, 5119, 4095, 400, 400); - } + SetDisplay(0, 0, 5119, 4095, 400, 400); + } - public CityMap(Serial serial) : base(serial) - { - } + public override int LabelNumber => 1015231; // city map - public override int LabelNumber => 1015231; // city map + public override void CraftInit(Mobile from) + { + var skillValue = from.Skills.Cartography.Value; + var dist = Math.Max(64 + (int)(skillValue * 4), 200); + var size = Math.Clamp(32 + (int)(skillValue * 2), 200, 400); - public override void CraftInit(Mobile from) - { - var skillValue = from.Skills.Cartography.Value; - var dist = 64 + (int)(skillValue * 4); - - if (dist < 200) - { - dist = 200; - } - - var size = 32 + (int)(skillValue * 2); - - if (size < 200) - { - size = 200; - } - else if (size > 400) - { - size = 400; - } - - SetDisplay(from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, size, size); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } + SetDisplay(from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, size, size); } } diff --git a/Projects/UOContent/Items/Maps/IndecipherableMap.cs b/Projects/UOContent/Items/Maps/IndecipherableMap.cs index 2eae61a5a..c0c8a7fdb 100644 --- a/Projects/UOContent/Items/Maps/IndecipherableMap.cs +++ b/Projects/UOContent/Items/Maps/IndecipherableMap.cs @@ -1,43 +1,17 @@ -namespace Server.Items +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0)] +public partial class IndecipherableMap : MapItem { - public class IndecipherableMap : MapItem + [Constructible] + public IndecipherableMap() => Hue = Utility.RandomDouble() < 0.2 ? 0x965 : 0x961; + + public override int LabelNumber => 1070799; // indecipherable map + + public override void OnDoubleClick(Mobile from) { - [Constructible] - public IndecipherableMap() - { - if (Utility.RandomDouble() < 0.2) - { - Hue = 0x965; - } - else - { - Hue = 0x961; - } - } - - public IndecipherableMap(Serial serial) : base(serial) - { - } - - public override int LabelNumber => 1070799; // indecipherable map - - public override void OnDoubleClick(Mobile from) - { - from.SendLocalizedMessage(1070801); // You cannot decipher this ruined map. - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - } + from.SendLocalizedMessage(1070801); // You cannot decipher this ruined map. } } diff --git a/Projects/UOContent/Items/Maps/LocalMap.cs b/Projects/UOContent/Items/Maps/LocalMap.cs index 574bf64e7..47ac3170a 100644 --- a/Projects/UOContent/Items/Maps/LocalMap.cs +++ b/Projects/UOContent/Items/Maps/LocalMap.cs @@ -1,39 +1,23 @@ -namespace Server.Items +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class LocalMap : MapItem { - public class LocalMap : MapItem + [Constructible] + public LocalMap() { - [Constructible] - public LocalMap() - { - SetDisplay(0, 0, 5119, 4095, 400, 400); - } + SetDisplay(0, 0, 5119, 4095, 400, 400); + } - public LocalMap(Serial serial) : base(serial) - { - } + public override int LabelNumber => 1015230; // local map - public override int LabelNumber => 1015230; // local map + public override void CraftInit(Mobile from) + { + var skillValue = from.Skills.Cartography.Value; + var dist = 64 + (int)(skillValue * 2); - public override void CraftInit(Mobile from) - { - var skillValue = from.Skills.Cartography.Value; - var dist = 64 + (int)(skillValue * 2); - - SetDisplay(from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, 200, 200); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } + SetDisplay(from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, 200, 200); } } diff --git a/Projects/UOContent/Items/Maps/MapItem.cs b/Projects/UOContent/Items/Maps/MapItem.cs index 1037cb3a4..6fe549253 100644 --- a/Projects/UOContent/Items/Maps/MapItem.cs +++ b/Projects/UOContent/Items/Maps/MapItem.cs @@ -1,324 +1,300 @@ using System; using System.Collections.Generic; +using ModernUO.Serialization; using Server.Engines.Craft; using Server.Network; -namespace Server.Items +namespace Server.Items; + +[Flippable(0x14EB, 0x14EC)] +[SerializationGenerator(1, false)] +public partial class MapItem : Item, ICraftable { - [Flippable(0x14EB, 0x14EC)] - public class MapItem : Item, ICraftable + private const int MaxUserPins = 50; + + [SerializableField(0)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private Rectangle2D _bounds; + + [SerializableField(1)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private int _width; + + [SerializableField(2)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private int _height; + + [SerializableField(3)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private bool _protected; + + [SerializableField(4, setter: "private")] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private List _pins; + + [SerializableField(5)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private Map _facet; + + [SerializableField(6)] + private bool _editable; + + [Constructible] + public MapItem(Map facet = null) : base(0x14EC) { - private const int MaxUserPins = 50; - private bool m_Editable; + Weight = 1.0; + _width = 200; + _height = 200; + _facet = facet; + _pins = new List(); + } - [Constructible] - public MapItem(Map facet = null) : base(0x14EC) + public int OnCraft( + int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue + ) + { + CraftInit(from); + return 1; + } + + public virtual void CraftInit(Mobile from) + { + } + + public void SetDisplay(int x1, int y1, int x2, int y2, int w, int h) + { + Width = w; + Height = h; + + if (x1 < 0) { - Weight = 1.0; - - Width = 200; - Height = 200; - Facet = facet; + x1 = 0; } - public MapItem(Serial serial) : base(serial) + if (y1 < 0) { + y1 = 0; } - [CommandProperty(AccessLevel.GameMaster)] - public bool Protected { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Rectangle2D Bounds { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Width { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public int Height { get; set; } - - [CommandProperty(AccessLevel.GameMaster)] - public Map Facet { get; set; } - - public List Pins { get; } = new(); - - public int OnCraft( - int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue - ) + if (x2 > 5119) { - CraftInit(from); - return 1; + x2 = 5119; } - public virtual void CraftInit(Mobile from) + if (y2 > 4095) { + y2 = 4095; } - public void SetDisplay(int x1, int y1, int x2, int y2, int w, int h) + Bounds = new Rectangle2D(x1, y1, x2 - x1, y2 - y1); + } + + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), 2)) { - Width = w; - Height = h; + DisplayTo(from); + } + else + { + from.SendLocalizedMessage(500446); // That is too far away. + } + } - if (x1 < 0) - { - x1 = 0; - } + public virtual void DisplayTo(Mobile from) + { + var ns = from.NetState; - if (y1 < 0) - { - y1 = 0; - } - - if (x2 >= 5120) - { - x2 = 5119; - } - - if (y2 >= 4096) - { - y2 = 4095; - } - - Bounds = new Rectangle2D(x1, y1, x2 - x1, y2 - y1); + if (!ns.NewCharacterList && _facet != null && _facet != Map.Felucca && _facet != Map.Trammel) + { + from.SendMessage("You must have client 7.0.13.0 or higher to display this map."); + return; } - public override void OnDoubleClick(Mobile from) + ns.SendMapDetails(this); + ns.SendMapDisplay(this); + + for (var i = 0; i < Pins.Count; ++i) { - if (from.InRange(GetWorldLocation(), 2)) - { - DisplayTo(from); - } - else - { - from.SendLocalizedMessage(500446); // That is too far away. - } + ns.SendMapAddPin(this, Pins[i]); } - public virtual void DisplayTo(Mobile from) + ns.SendMapSetEditable(this, ValidateEdit(from)); + } + + public virtual void OnAddPin(Mobile from, int x, int y) + { + if (!ValidateEdit(from)) { - var ns = from.NetState; - - if (!ns.NewCharacterList && Facet != null && Facet != Map.Felucca && Facet != Map.Trammel) - { - from.SendMessage("You must have client 7.0.13.0 or higher to display this map."); - return; - } - - ns.SendMapDetails(this); - ns.SendMapDisplay(this); - - for (var i = 0; i < Pins.Count; ++i) - { - ns.SendMapAddPin(this, Pins[i]); - } - - ns.SendMapSetEditable(this, ValidateEdit(from)); + return; } - public virtual void OnAddPin(Mobile from, int x, int y) + if (Pins.Count >= MaxUserPins) { - if (!ValidateEdit(from)) - { - return; - } - - if (Pins.Count >= MaxUserPins) - { - return; - } - - Validate(ref x, ref y); - AddPin(x, y); + return; } - public virtual void OnRemovePin(Mobile from, int number) - { - if (!ValidateEdit(from)) - { - return; - } + Validate(ref x, ref y); + AddPin(x, y); + } - RemovePin(number); + public virtual void OnRemovePin(Mobile from, int number) + { + if (!ValidateEdit(from)) + { + return; } - public virtual void OnChangePin(Mobile from, int number, int x, int y) - { - if (!ValidateEdit(from)) - { - return; - } + RemovePin(number); + } - Validate(ref x, ref y); - ChangePin(number, x, y); + public virtual void OnChangePin(Mobile from, int number, int x, int y) + { + if (!ValidateEdit(from)) + { + return; } - public virtual void OnInsertPin(Mobile from, int number, int x, int y) + Validate(ref x, ref y); + ChangePin(number, x, y); + } + + public virtual void OnInsertPin(Mobile from, int number, int x, int y) + { + if (!ValidateEdit(from)) { - if (!ValidateEdit(from)) - { - return; - } - - if (Pins.Count >= MaxUserPins) - { - return; - } - - Validate(ref x, ref y); - InsertPin(number, x, y); + return; } - public virtual void OnClearPins(Mobile from) + if (Pins.Count >= MaxUserPins) { - if (!ValidateEdit(from)) - { - return; - } - - ClearPins(); + return; } - public virtual void OnToggleEditable(Mobile from) - { - if (Validate(from)) - { - m_Editable = !m_Editable; - } + Validate(ref x, ref y); + InsertPin(number, x, y); + } - from.NetState.SendMapSetEditable(this, m_Editable && Validate(from)); + public virtual void OnClearPins(Mobile from) + { + if (!ValidateEdit(from)) + { + return; } - public virtual void Validate(ref int x, ref int y) + ClearPins(); + } + + public virtual void OnToggleEditable(Mobile from) + { + if (Validate(from)) { - x = Math.Clamp(x, 0, Width - 1); - y = Math.Clamp(y, 0, Height - 1); + _editable = !_editable; } - public virtual bool ValidateEdit(Mobile from) => m_Editable && Validate(from); + from.NetState.SendMapSetEditable(this, _editable && Validate(from)); + } - public virtual bool Validate(Mobile from) + public virtual void Validate(ref int x, ref int y) + { + x = Math.Clamp(x, 0, Width - 1); + y = Math.Clamp(y, 0, Height - 1); + } + + public virtual bool ValidateEdit(Mobile from) => _editable && Validate(from); + + public virtual bool Validate(Mobile from) + { + if (!from.CanSee(this) || from.Map != Map || !from.Alive || InSecureTrade) { - if (!from.CanSee(this) || from.Map != Map || !from.Alive || InSecureTrade) - { - return false; - } - - if (from.AccessLevel >= AccessLevel.GameMaster) - { - return true; - } - - if (!Movable || Protected || !from.InRange(GetWorldLocation(), 2)) - { - return false; - } - - return !(RootParent is Mobile && RootParent != from); + return false; } - public void ConvertToWorld(int x, int y, out int worldX, out int worldY) + if (from.AccessLevel >= AccessLevel.GameMaster) { - worldX = Bounds.Width * x / Width + Bounds.X; - worldY = Bounds.Height * y / Height + Bounds.Y; + return true; } - public void ConvertToMap(int x, int y, out int mapX, out int mapY) + if (!Movable || Protected || !from.InRange(GetWorldLocation(), 2)) { - mapX = (x - Bounds.X) * Width / Bounds.Width; - mapY = (y - Bounds.Y) * Width / Bounds.Height; + return false; } - public virtual void AddWorldPin(int x, int y) - { - ConvertToMap(x, y, out var mapX, out var mapY); - AddPin(mapX, mapY); - } + return !(RootParent is Mobile && RootParent != from); + } - public virtual void AddPin(int x, int y) + public void ConvertToWorld(int x, int y, out int worldX, out int worldY) + { + worldX = Bounds.Width * x / Width + Bounds.X; + worldY = Bounds.Height * y / Height + Bounds.Y; + } + + public void ConvertToMap(int x, int y, out int mapX, out int mapY) + { + mapX = (x - Bounds.X) * Width / Bounds.Width; + mapY = (y - Bounds.Y) * Width / Bounds.Height; + } + + public virtual void AddWorldPin(int x, int y) + { + ConvertToMap(x, y, out var mapX, out var mapY); + AddPin(mapX, mapY); + } + + public virtual void AddPin(int x, int y) + { + Pins.Add(new Point2D(x, y)); + } + + public virtual void RemovePin(int index) + { + if (index > 0 && index < Pins.Count) + { + Pins.RemoveAt(index); + } + } + + public virtual void InsertPin(int index, int x, int y) + { + if (index < 0 || index >= Pins.Count) { Pins.Add(new Point2D(x, y)); } - - public virtual void RemovePin(int index) + else { - if (index > 0 && index < Pins.Count) - { - Pins.RemoveAt(index); - } + Pins.Insert(index, new Point2D(x, y)); } + } - public virtual void InsertPin(int index, int x, int y) + public virtual void ChangePin(int index, int x, int y) + { + if (index >= 0 && index < Pins.Count) { - if (index < 0 || index >= Pins.Count) - { - Pins.Add(new Point2D(x, y)); - } - else - { - Pins.Insert(index, new Point2D(x, y)); - } + Pins[index] = new Point2D(x, y); } + } - public virtual void ChangePin(int index, int x, int y) + public virtual void ClearPins() + { + Pins.Clear(); + } + + private void Deserialize(IGenericReader reader, int version) + { + // Version 0 doesn't serialize Facet/Editable, and count is not encoded + + Bounds = reader.ReadRect2D(); + + Width = reader.ReadInt(); + Height = reader.ReadInt(); + + Protected = reader.ReadBool(); + + var count = reader.ReadInt(); + for (var i = 0; i < count; i++) { - if (index >= 0 && index < Pins.Count) - { - Pins[index] = new Point2D(x, y); - } - } - - public virtual void ClearPins() - { - Pins.Clear(); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - - writer.Write(Bounds); - - writer.Write(Width); - writer.Write(Height); - - writer.Write(Protected); - - writer.Write(Pins.Count); - for (var i = 0; i < Pins.Count; ++i) - { - writer.Write(Pins[i]); - } - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - switch (version) - { - case 0: - { - Bounds = reader.ReadRect2D(); - - Width = reader.ReadInt(); - Height = reader.ReadInt(); - - Protected = reader.ReadBool(); - - var count = reader.ReadInt(); - for (var i = 0; i < count; i++) - { - Pins.Add(reader.ReadPoint2D()); - } - - break; - } - } + Pins.Add(reader.ReadPoint2D()); } } } diff --git a/Projects/UOContent/Items/Maps/MapItemPackets.cs b/Projects/UOContent/Items/Maps/MapItemPackets.cs index 935331792..1783aa284 100644 --- a/Projects/UOContent/Items/Maps/MapItemPackets.cs +++ b/Projects/UOContent/Items/Maps/MapItemPackets.cs @@ -43,23 +43,35 @@ namespace Server.Network switch (command) { case 1: - map.OnAddPin(from, x, y); - break; + { + map.OnAddPin(from, x, y); + break; + } case 2: - map.OnInsertPin(from, number, x, y); - break; + { + map.OnInsertPin(from, number, x, y); + break; + } case 3: - map.OnChangePin(from, number, x, y); - break; + { + map.OnChangePin(from, number, x, y); + break; + } case 4: - map.OnRemovePin(from, number); - break; + { + map.OnRemovePin(from, number); + break; + } case 5: - map.OnClearPins(from); - break; + { + map.OnClearPins(from); + break; + } case 6: - map.OnToggleEditable(from); - break; + { + map.OnToggleEditable(from); + break; + } } } diff --git a/Projects/UOContent/Items/Maps/PresetMap.cs b/Projects/UOContent/Items/Maps/PresetMap.cs index 48bdc2490..5e147bcc7 100644 --- a/Projects/UOContent/Items/Maps/PresetMap.cs +++ b/Projects/UOContent/Items/Maps/PresetMap.cs @@ -1,147 +1,121 @@ -namespace Server.Items +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class PresetMap : MapItem { - public class PresetMap : MapItem + private int _labelNumber; + + [Constructible] + public PresetMap(PresetMapType type) { - private int m_LabelNumber; + var v = (int)type; - [Constructible] - public PresetMap(PresetMapType type) + if (v >= 0 && v < PresetMapEntry.Table.Length) { - var v = (int)type; - - if (v >= 0 && v < PresetMapEntry.Table.Length) - { - InitEntry(PresetMapEntry.Table[v]); - } - } - - public PresetMap(PresetMapEntry entry) - { - InitEntry(entry); - } - - public PresetMap(Serial serial) : base(serial) - { - } - - public override int LabelNumber => m_LabelNumber == 0 ? base.LabelNumber : m_LabelNumber; - - public void InitEntry(PresetMapEntry entry) - { - m_LabelNumber = entry.Name; - - Width = entry.Width; - Height = entry.Height; - - Bounds = entry.Bounds; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - - writer.Write(m_LabelNumber); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - switch (version) - { - case 0: - { - m_LabelNumber = reader.ReadInt(); - break; - } - } + InitEntry(PresetMapEntry.Table[v]); } } - public class PresetMapEntry + public PresetMap(PresetMapEntry entry) { - public PresetMapEntry(int name, int width, int height, int xLeft, int yTop, int xRight, int yBottom) - { - Name = name; - Width = width; - Height = height; - Bounds = new Rectangle2D(xLeft, yTop, xRight - xLeft, yBottom - yTop); - } - - public int Name { get; } - - public int Width { get; } - - public int Height { get; } - - public Rectangle2D Bounds { get; } - - public static PresetMapEntry[] Table { get; } = - { - new(1041189, 200, 200, 1092, 1396, 1736, 1924), // map of Britain - new(1041203, 200, 200, 0256, 1792, 1736, 2560), // map of Britain to Skara Brae - new(1041192, 200, 200, 1024, 1280, 2304, 3072), // map of Britain to Trinsic - new(1041183, 200, 200, 2500, 1900, 3000, 2400), // map of Buccaneer's Den - new(1041198, 200, 200, 2560, 1792, 3840, 2560), // map of Buccaneer's Den to Magincia - new(1041194, 200, 200, 2560, 1792, 3840, 3072), // map of Buccaneer's Den to Ocllo - new(1041181, 200, 200, 1088, 3572, 1528, 4056), // map of Jhelom - new(1041186, 200, 200, 3530, 2022, 3818, 2298), // map of Magincia - new(1041199, 200, 200, 3328, 1792, 3840, 2304), // map of Magincia to Ocllo - new(1041182, 200, 200, 2360, 0356, 2706, 0702), // map of Minoc - new(1041190, 200, 200, 0000, 0256, 2304, 3072), // map of Minoc to Yew - new(1041191, 200, 200, 2467, 0572, 2878, 0746), // map of Minoc to Vesper - new(1041188, 200, 200, 4156, 0808, 4732, 1528), // map of Moonglow - new(1041201, 200, 200, 3328, 0768, 4864, 1536), // map of Moonglow to Nujelm - new(1041185, 200, 200, 3446, 1030, 3832, 1424), // map of Nujelm - new(1041197, 200, 200, 3328, 1024, 3840, 2304), // map of Nujelm to Magincia - new(1041187, 200, 200, 3582, 2456, 3770, 2742), // map of Ocllo - new(1041184, 200, 200, 2714, 3329, 3100, 3639), // map of Serpent's Hold - new(1041200, 200, 200, 2560, 2560, 3840, 3840), // map of Serpent's Hold to Ocllo - new(1041180, 200, 200, 0524, 2064, 0960, 2452), // map of Skara Brae - new(1041204, 200, 200, 0000, 0000, 5199, 4095), // map of The World - new(1041177, 200, 200, 1792, 2630, 2118, 2952), // map of Trinsic - new(1041193, 200, 200, 1792, 1792, 3072, 3072), // map of Trinsic to Buccaneer's Den - new(1041195, 200, 200, 0256, 1792, 2304, 4095), // map of Trinsic to Jhelom - new(1041178, 200, 200, 2636, 0592, 3064, 1012), // map of Vesper - new(1041196, 200, 200, 2636, 0592, 3840, 1536), // map of Vesper to Nujelm - new(1041179, 200, 200, 0236, 0741, 0766, 1269), // map of Yew - new(1041202, 200, 200, 0000, 0512, 1792, 2048) // map of Yew to Britain - }; + InitEntry(entry); } - public enum PresetMapType + [SerializableProperty(0, useField: nameof(_labelNumber))] + public override int LabelNumber => _labelNumber == 0 ? base.LabelNumber : _labelNumber; + + public void InitEntry(PresetMapEntry entry) { - Britain, - BritainToSkaraBrae, - BritainToTrinsic, - BucsDen, - BucsDenToMagincia, - BucsDenToOcllo, - Jhelom, - Magincia, - MaginciaToOcllo, - Minoc, - MinocToYew, - MinocToVesper, - Moonglow, - MoonglowToNujelm, - Nujelm, - NujelmToMagincia, - Ocllo, - SerpentsHold, - SerpentsHoldToOcllo, - SkaraBrae, - TheWorld, - Trinsic, - TrinsicToBucsDen, - TrinsicToJhelom, - Vesper, - VesperToNujelm, - Yew, - YewToBritain + _labelNumber = entry.Name; + + Width = entry.Width; + Height = entry.Height; + + Bounds = entry.Bounds; } } + +public class PresetMapEntry +{ + public PresetMapEntry(int name, int width, int height, int xLeft, int yTop, int xRight, int yBottom) + { + Name = name; + Width = width; + Height = height; + Bounds = new Rectangle2D(xLeft, yTop, xRight - xLeft, yBottom - yTop); + } + + public int Name { get; } + + public int Width { get; } + + public int Height { get; } + + public Rectangle2D Bounds { get; } + + public static PresetMapEntry[] Table { get; } = + { + new(1041189, 200, 200, 1092, 1396, 1736, 1924), // map of Britain + new(1041203, 200, 200, 0256, 1792, 1736, 2560), // map of Britain to Skara Brae + new(1041192, 200, 200, 1024, 1280, 2304, 3072), // map of Britain to Trinsic + new(1041183, 200, 200, 2500, 1900, 3000, 2400), // map of Buccaneer's Den + new(1041198, 200, 200, 2560, 1792, 3840, 2560), // map of Buccaneer's Den to Magincia + new(1041194, 200, 200, 2560, 1792, 3840, 3072), // map of Buccaneer's Den to Ocllo + new(1041181, 200, 200, 1088, 3572, 1528, 4056), // map of Jhelom + new(1041186, 200, 200, 3530, 2022, 3818, 2298), // map of Magincia + new(1041199, 200, 200, 3328, 1792, 3840, 2304), // map of Magincia to Ocllo + new(1041182, 200, 200, 2360, 0356, 2706, 0702), // map of Minoc + new(1041190, 200, 200, 0000, 0256, 2304, 3072), // map of Minoc to Yew + new(1041191, 200, 200, 2467, 0572, 2878, 0746), // map of Minoc to Vesper + new(1041188, 200, 200, 4156, 0808, 4732, 1528), // map of Moonglow + new(1041201, 200, 200, 3328, 0768, 4864, 1536), // map of Moonglow to Nujelm + new(1041185, 200, 200, 3446, 1030, 3832, 1424), // map of Nujelm + new(1041197, 200, 200, 3328, 1024, 3840, 2304), // map of Nujelm to Magincia + new(1041187, 200, 200, 3582, 2456, 3770, 2742), // map of Ocllo + new(1041184, 200, 200, 2714, 3329, 3100, 3639), // map of Serpent's Hold + new(1041200, 200, 200, 2560, 2560, 3840, 3840), // map of Serpent's Hold to Ocllo + new(1041180, 200, 200, 0524, 2064, 0960, 2452), // map of Skara Brae + new(1041204, 200, 200, 0000, 0000, 5199, 4095), // map of The World + new(1041177, 200, 200, 1792, 2630, 2118, 2952), // map of Trinsic + new(1041193, 200, 200, 1792, 1792, 3072, 3072), // map of Trinsic to Buccaneer's Den + new(1041195, 200, 200, 0256, 1792, 2304, 4095), // map of Trinsic to Jhelom + new(1041178, 200, 200, 2636, 0592, 3064, 1012), // map of Vesper + new(1041196, 200, 200, 2636, 0592, 3840, 1536), // map of Vesper to Nujelm + new(1041179, 200, 200, 0236, 0741, 0766, 1269), // map of Yew + new(1041202, 200, 200, 0000, 0512, 1792, 2048) // map of Yew to Britain + }; +} + +public enum PresetMapType +{ + Britain, + BritainToSkaraBrae, + BritainToTrinsic, + BucsDen, + BucsDenToMagincia, + BucsDenToOcllo, + Jhelom, + Magincia, + MaginciaToOcllo, + Minoc, + MinocToYew, + MinocToVesper, + Moonglow, + MoonglowToNujelm, + Nujelm, + NujelmToMagincia, + Ocllo, + SerpentsHold, + SerpentsHoldToOcllo, + SkaraBrae, + TheWorld, + Trinsic, + TrinsicToBucsDen, + TrinsicToJhelom, + Vesper, + VesperToNujelm, + Yew, + YewToBritain +} diff --git a/Projects/UOContent/Items/Maps/SeaChart.cs b/Projects/UOContent/Items/Maps/SeaChart.cs index 3be85b596..5deef564f 100644 --- a/Projects/UOContent/Items/Maps/SeaChart.cs +++ b/Projects/UOContent/Items/Maps/SeaChart.cs @@ -1,55 +1,25 @@ -namespace Server.Items +using System; +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class SeaChart : MapItem { - public class SeaChart : MapItem + [Constructible] + public SeaChart() { - [Constructible] - public SeaChart() - { - SetDisplay(0, 0, 5119, 4095, 400, 400); - } + SetDisplay(0, 0, 5119, 4095, 400, 400); + } - public SeaChart(Serial serial) : base(serial) - { - } + public override int LabelNumber => 1015232; // sea chart - public override int LabelNumber => 1015232; // sea chart + public override void CraftInit(Mobile from) + { + var skillValue = from.Skills.Cartography.Value; + var dist = Math.Max(64 + (int)(skillValue * 10), 200); + var size = Math.Clamp(24 + (int)(skillValue * 3.3), 200, 400); - public override void CraftInit(Mobile from) - { - var skillValue = from.Skills.Cartography.Value; - var dist = 64 + (int)(skillValue * 10); - - if (dist < 200) - { - dist = 200; - } - - var size = 24 + (int)(skillValue * 3.3); - - if (size < 200) - { - size = 200; - } - else if (size > 400) - { - size = 400; - } - - SetDisplay(from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, size, size); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } + SetDisplay(from.X - dist, from.Y - dist, from.X + dist, from.Y + dist, size, size); } } diff --git a/Projects/UOContent/Items/Maps/TreasureMap.cs b/Projects/UOContent/Items/Maps/TreasureMap.cs index b7f91c41c..046d1a7d6 100644 --- a/Projects/UOContent/Items/Maps/TreasureMap.cs +++ b/Projects/UOContent/Items/Maps/TreasureMap.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using ModernUO.Serialization; using Server.ContextMenus; using Server.Engines.Harvest; using Server.Mobiles; @@ -8,351 +9,559 @@ using Server.Network; using Server.Targeting; using Server.Utilities; -namespace Server.Items +namespace Server.Items; + +[SerializationGenerator(0, false)] +public partial class TreasureMap : MapItem { - public class TreasureMap : MapItem + public const double LootChance = 0.01; // 1% chance to appear as loot + + private static Point2D[] _locations; + private static Point2D[] _havenLocations; + + private static Type[][] m_SpawnTypes = { - public const double LootChance = 0.01; // 1% chance to appear as loot + new[] { typeof(HeadlessOne), typeof(Skeleton) }, + new[] { typeof(Mongbat), typeof(Ratman), typeof(HeadlessOne), typeof(Skeleton), typeof(Zombie) }, + new[] { typeof(OrcishMage), typeof(Gargoyle), typeof(Gazer), typeof(HellHound), typeof(EarthElemental) }, + new[] { typeof(Lich), typeof(OgreLord), typeof(DreadSpider), typeof(AirElemental), typeof(FireElemental) }, + new[] { typeof(DreadSpider), typeof(LichLord), typeof(Daemon), typeof(ElderGazer), typeof(OgreLord) }, + new[] { typeof(LichLord), typeof(Daemon), typeof(ElderGazer), typeof(PoisonElemental), typeof(BloodElemental) }, + new[] { typeof(AncientWyrm), typeof(Balron), typeof(BloodElemental), typeof(PoisonElemental), typeof(Titan) } + }; - private static Point2D[] m_Locations; - private static Point2D[] m_HavenLocations; + [InvalidateProperties] + [SerializableField(0)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private Mobile _completedBy; - private static readonly Type[][] m_SpawnTypes = + [InvalidateProperties] + [SerializableField(1)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private int _level; + + [InvalidateProperties] + [SerializableField(2)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private bool _completed; + + [InvalidateProperties] + [SerializableField(3)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private Mobile _decoder; + + [InvalidateProperties] + [SerializableField(4)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private Map _chestMap; + + [SerializableField(5)] + [SerializableFieldAttr("[CommandProperty(AccessLevel.GameMaster)]")] + private Point2D _chestLocation; + + [Constructible] + public TreasureMap(int level, Map map) + { + _level = level; + _chestMap = map; + + _chestLocation = level == 0 ? GetRandomHavenLocation() : GetRandomLocation(); + + Width = 300; + Height = 300; + + const int width = 600; + const int height = 600; + + var x1 = ChestLocation.X - Utility.RandomMinMax(width / 4, width / 4 * 3); + var y1 = ChestLocation.Y - Utility.RandomMinMax(height / 4, height / 4 * 3); + + if (x1 < 0) { - new[] { typeof(HeadlessOne), typeof(Skeleton) }, - new[] { typeof(Mongbat), typeof(Ratman), typeof(HeadlessOne), typeof(Skeleton), typeof(Zombie) }, - new[] { typeof(OrcishMage), typeof(Gargoyle), typeof(Gazer), typeof(HellHound), typeof(EarthElemental) }, - new[] { typeof(Lich), typeof(OgreLord), typeof(DreadSpider), typeof(AirElemental), typeof(FireElemental) }, - new[] { typeof(DreadSpider), typeof(LichLord), typeof(Daemon), typeof(ElderGazer), typeof(OgreLord) }, - new[] { typeof(LichLord), typeof(Daemon), typeof(ElderGazer), typeof(PoisonElemental), typeof(BloodElemental) }, - new[] { typeof(AncientWyrm), typeof(Balron), typeof(BloodElemental), typeof(PoisonElemental), typeof(Titan) } - }; - - private bool m_Completed; - private Mobile m_CompletedBy; - private Mobile m_Decoder; - private int m_Level; - private Map m_Map; - - [Constructible] - public TreasureMap(int level, Map map) - { - m_Level = level; - m_Map = map; - - if (level == 0) - { - ChestLocation = GetRandomHavenLocation(); - } - else - { - ChestLocation = GetRandomLocation(); - } - - Width = 300; - Height = 300; - - var width = 600; - var height = 600; - - var x1 = ChestLocation.X - Utility.RandomMinMax(width / 4, width / 4 * 3); - var y1 = ChestLocation.Y - Utility.RandomMinMax(height / 4, height / 4 * 3); - - if (x1 < 0) - { - x1 = 0; - } - - if (y1 < 0) - { - y1 = 0; - } - - var x2 = x1 + width; - var y2 = y1 + height; - - if (x2 >= 5120) - { - x2 = 5119; - } - - if (y2 >= 4096) - { - y2 = 4095; - } - - x1 = x2 - width; - y1 = y2 - height; - - Bounds = new Rectangle2D(x1, y1, width, height); - Protected = true; - - AddWorldPin(ChestLocation.X, ChestLocation.Y); + x1 = 0; } - public TreasureMap(Serial serial) : base(serial) + if (y1 < 0) { + y1 = 0; } - [CommandProperty(AccessLevel.GameMaster)] - public int Level + var x2 = x1 + width; + var y2 = y1 + height; + + if (x2 > 5119) { - get => m_Level; - set - { - m_Level = value; - InvalidateProperties(); - } + x2 = 5119; } - [CommandProperty(AccessLevel.GameMaster)] - public bool Completed + if (y2 > 4095) { - get => m_Completed; - set - { - m_Completed = value; - InvalidateProperties(); - } + y2 = 4095; } - [CommandProperty(AccessLevel.GameMaster)] - public Mobile CompletedBy - { - get => m_CompletedBy; - set - { - m_CompletedBy = value; - InvalidateProperties(); - } - } + x1 = x2 - width; + y1 = y2 - height; - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Decoder - { - get => m_Decoder; - set - { - m_Decoder = value; - InvalidateProperties(); - } - } + Bounds = new Rectangle2D(x1, y1, width, height); + Protected = true; - [CommandProperty(AccessLevel.GameMaster)] - public Map ChestMap - { - get => m_Map; - set - { - m_Map = value; - InvalidateProperties(); - } - } + AddWorldPin(ChestLocation.X, ChestLocation.Y); + } - [CommandProperty(AccessLevel.GameMaster)] - public Point2D ChestLocation { get; set; } - - public override int LabelNumber + public override int LabelNumber + { + get { - get + if (_decoder != null) { - if (m_Decoder != null) + if (_level == 6) { - if (m_Level == 6) - { - return 1063453; - } - - return 1041516 + m_Level; + return 1063453; } - if (m_Level == 6) - { - return 1063452; - } - - return 1041510 + m_Level; - } - } - - public static Point2D GetRandomLocation() - { - if (m_Locations == null) - { - LoadLocations(); + return 1041516 + _level; } - return m_Locations?.RandomElement() ?? Point2D.Zero; - } - - public static Point2D GetRandomHavenLocation() - { - if (m_HavenLocations == null) + if (_level == 6) { - LoadLocations(); + return 1063452; } - return m_HavenLocations?.RandomElement() ?? Point2D.Zero; + return 1041510 + _level; + } + } + + public static Point2D GetRandomLocation() + { + if (_locations == null) + { + LoadLocations(); } - private static void LoadLocations() + return _locations?.RandomElement() ?? Point2D.Zero; + } + + public static Point2D GetRandomHavenLocation() + { + if (_havenLocations == null) { - var filePath = Path.Combine(Core.BaseDirectory, "Data/treasure.cfg"); - - var list = new List(); - var havenList = new List(); - - if (File.Exists(filePath)) - { - using var ip = new StreamReader(filePath); - string line; - - while ((line = ip.ReadLine()) != null) - { - try - { - var split = line.Split(' '); - - int x = Convert.ToInt32(split[0]), y = Convert.ToInt32(split[1]); - - var loc = new Point2D(x, y); - list.Add(loc); - - if (IsInHavenIsland(loc)) - { - havenList.Add(loc); - } - } - catch - { - // ignored - } - } - } - - m_Locations = list.ToArray(); - m_HavenLocations = havenList.ToArray(); + LoadLocations(); } - public static bool IsInHavenIsland(IPoint2D loc) => loc.X >= 3314 && loc.X <= 3814 && loc.Y >= 2345 && loc.Y <= 3095; + return _havenLocations?.RandomElement() ?? Point2D.Zero; + } - public static BaseCreature Spawn(int level, Point3D p, bool guardian) + private static void LoadLocations() + { + var filePath = Path.Combine(Core.BaseDirectory, "Data/treasure.cfg"); + + var list = new List(); + var havenList = new List(); + + if (File.Exists(filePath)) { - if (level >= 0 && level < m_SpawnTypes.Length) - { - BaseCreature bc; + using var ip = new StreamReader(filePath); + string line; + while ((line = ip.ReadLine()) != null) + { try { - bc = m_SpawnTypes[level].RandomElement().CreateInstance(); + var split = line.Split(' '); + + int x = Convert.ToInt32(split[0]), y = Convert.ToInt32(split[1]); + + var loc = new Point2D(x, y); + list.Add(loc); + + if (IsInHavenIsland(loc)) + { + havenList.Add(loc); + } } catch { - return null; + // ignored } - - bc.Home = p; - bc.RangeHome = 5; - - if (guardian && level == 0) - { - bc.Name = "a chest guardian"; - bc.Hue = 0x835; - } - - return bc; } - - return null; } - public static BaseCreature Spawn(int level, Point3D p, Map map, Mobile target, bool guardian) + _locations = list.ToArray(); + _havenLocations = havenList.ToArray(); + } + + public static bool IsInHavenIsland(IPoint2D loc) => loc.X >= 3314 && loc.X <= 3814 && loc.Y >= 2345 && loc.Y <= 3095; + + public static BaseCreature Spawn(int level, Point3D p, bool guardian) + { + if (level >= 0 && level < m_SpawnTypes.Length) { - if (map == null) + BaseCreature bc; + + try + { + bc = m_SpawnTypes[level].RandomElement().CreateInstance(); + } + catch { return null; } - var c = Spawn(level, p, guardian); + bc.Home = p; + bc.RangeHome = 5; - if (c != null) + if (guardian && level == 0) { - var spawned = false; - - for (var i = 0; !spawned && i < 10; ++i) - { - var x = p.X - 3 + Utility.Random(7); - var y = p.Y - 3 + Utility.Random(7); - - if (map.CanSpawnMobile(x, y, p.Z)) - { - c.MoveToWorld(new Point3D(x, y, p.Z), map); - spawned = true; - } - else - { - var z = map.GetAverageZ(x, y); - - if (map.CanSpawnMobile(x, y, z)) - { - c.MoveToWorld(new Point3D(x, y, z), map); - spawned = true; - } - } - } - - if (!spawned) - { - c.Delete(); - return null; - } - - if (target != null) - { - c.Combatant = target; - } - - return c; + bc.Name = "a chest guardian"; + bc.Hue = 0x835; } + return bc; + } + + return null; + } + + public static BaseCreature Spawn(int level, Point3D p, Map map, Mobile target, bool guardian) + { + if (map == null) + { return null; } - public static bool HasDiggingTool(Mobile m) - { - if (m.Backpack == null) - { - return false; - } + var c = Spawn(level, p, guardian); - foreach (var tool in m.Backpack.FindItemsByType()) + if (c != null) + { + var spawned = false; + + for (var i = 0; !spawned && i < 10; ++i) { - if (tool.HarvestSystem == Mining.System) + var x = p.X - 3 + Utility.Random(7); + var y = p.Y - 3 + Utility.Random(7); + + if (map.CanSpawnMobile(x, y, p.Z)) { - return true; + c.MoveToWorld(new Point3D(x, y, p.Z), map); + spawned = true; + } + else + { + var z = map.GetAverageZ(x, y); + + if (map.CanSpawnMobile(x, y, z)) + { + c.MoveToWorld(new Point3D(x, y, z), map); + spawned = true; + } } } + if (!spawned) + { + c.Delete(); + return null; + } + + if (target != null) + { + c.Combatant = target; + } + + return c; + } + + return null; + } + + public static bool HasDiggingTool(Mobile m) + { + if (m.Backpack == null) + { return false; } - public void OnBeginDig(Mobile from) + foreach (var tool in m.Backpack.FindItemsByType()) { - if (m_Completed) + if (tool.HarvestSystem == Mining.System) + { + return true; + } + } + + return false; + } + + public void OnBeginDig(Mobile from) + { + if (_completed) + { + from.SendLocalizedMessage(503028); // The treasure for this map has already been found. + } + else if (_level == 0 && !CheckYoung(from)) + { + from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map. + } + /* + else if (from != m_Decoder) + { + from.SendLocalizedMessage( 503016 ); // Only the person who decoded this map may actually dig up the treasure. + } + */ + else if (_decoder != from && !HasRequiredSkill(from)) + { + // You did not decode this map and have no clue where to look for the treasure. + from.SendLocalizedMessage(503031); + } + else if (!from.CanBeginAction()) + { + from.SendLocalizedMessage(503020); // You are already digging treasure. + } + else if (from.Map != _chestMap) + { + from.SendLocalizedMessage(1010479); // You seem to be in the right place, but may be on the wrong facet! + } + else + { + from.SendLocalizedMessage(503033); // Where do you wish to dig? + from.Target = new DigTarget(this); + } + } + + public override void OnDoubleClick(Mobile from) + { + if (!from.InRange(GetWorldLocation(), 2)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. + return; + } + + if (!_completed && _decoder == null) + { + Decode(from); + } + else + { + DisplayTo(from); + } + } + + private bool CheckYoung(Mobile from) + { + if (from.AccessLevel >= AccessLevel.GameMaster) + { + return true; + } + + if (from is PlayerMobile mobile && mobile.Young) + { + return true; + } + + if (from == Decoder) + { + Level = 1; + from.SendLocalizedMessage(1046446); // This is now a level one treasure map. + return true; + } + + return false; + } + + private double GetMinSkillLevel() + { + return _level switch + { + 1 => -3.0, + 2 => 41.0, + 3 => 51.0, + 4 => 61.0, + 5 => 70.0, + 6 => 70.0, + _ => 0.0 + }; + } + + private bool HasRequiredSkill(Mobile from) => from.Skills.Cartography.Value >= GetMinSkillLevel(); + + public void Decode(Mobile from) + { + if (_completed || _decoder != null) + { + return; + } + + if (_level == 0) + { + if (!CheckYoung(from)) + { + from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map. + return; + } + } + else + { + var minSkill = GetMinSkillLevel(); + + if (from.Skills.Cartography.Value < minSkill) + { + from.SendLocalizedMessage(503013); // The map is too difficult to attempt to decode. + } + + var maxSkill = minSkill + 60.0; + + if (!from.CheckSkill(SkillName.Cartography, minSkill, maxSkill)) + { + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503018); // You fail to make anything of the map. + return; + } + } + + from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503019); // You successfully decode a treasure map! + Decoder = from; + + if (Core.AOS) + { + LootType = LootType.Blessed; + } + + DisplayTo(from); + } + + public override void DisplayTo(Mobile from) + { + if (_completed) + { + SendLocalizedMessageTo(from, 503014); // This treasure hunt has already been completed. + } + else if (_level == 0 && !CheckYoung(from)) + { + from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map. + return; + } + else if (_decoder != from && !HasRequiredSkill(from)) + { + // You did not decode this map and have no clue where to look for the treasure. + from.SendLocalizedMessage(503031); + return; + } + else + { + // The treasure is marked by the red pin. Grab a shovel and go dig it up! + SendLocalizedMessageTo(from, 503017); + } + + from.PlaySound(0x249); + base.DisplayTo(from); + } + + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + + if (!_completed) + { + if (_decoder == null) + { + list.Add(new DecodeMapEntry(this)); + } + else + { + var digTool = HasDiggingTool(from); + + list.Add(new OpenMapEntry(this)); + list.Add(new DigEntry(this, digTool)); + } + } + } + + public override void GetProperties(IPropertyList list) + { + base.GetProperties(list); + + list.Add(_chestMap == Map.Felucca ? 1041502 : 1041503); // for somewhere in Felucca : for somewhere in Trammel + + if (_completed) + { + list.Add(1041507, _completedBy?.RawName ?? "someone"); // completed by ~1_val~ + } + } + + public override void OnSingleClick(Mobile from) + { + if (_completed) + { + from.NetState.SendMessageLocalizedAffix( + Serial, + ItemID, + MessageType.Label, + 0x3B2, + 3, + 1048030, + "", + AffixType.Append, + $" completed by {_completedBy?.RawName ?? "someone"}" + ); + } + else if (_decoder != null) + { + if (_level == 6) + { + LabelTo(from, 1063453); + } + else + { + LabelTo(from, 1041516 + _level); + } + } + else + { + if (_level == 6) + { + LabelTo(from, 1041522, $"#{1063452}\t \t#{(_chestMap == Map.Felucca ? 1041502 : 1041503)}"); + } + else + { + LabelTo(from, 1041522, $"#{1041510 + _level}\t \t#{(_chestMap == Map.Felucca ? 1041502 : 1041503)}"); + } + } + } + + [AfterDeserialization] + private void AfterDeserialization() + { + if (Core.AOS && _decoder != null && LootType == LootType.Regular) + { + LootType = LootType.Blessed; + } + } + + private class DigTarget : Target + { + private readonly TreasureMap m_Map; + + public DigTarget(TreasureMap map) : base(6, true, TargetFlags.None) => m_Map = map; + + protected override void OnTarget(Mobile from, object targeted) + { + if (m_Map.Deleted) + { + return; + } + + var map = m_Map._chestMap; + + if (m_Map._completed) { from.SendLocalizedMessage(503028); // The treasure for this map has already been found. } - else if (m_Level == 0 && !CheckYoung(from)) - { - from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map. - } /* - else if (from != m_Decoder) + else if (from != m_Map.m_Decoder) { from.SendLocalizedMessage( 503016 ); // Only the person who decoded this map may actually dig up the treasure. } */ - else if (m_Decoder != from && !HasRequiredSkill(from)) + else if (m_Map._decoder != from && !m_Map.HasRequiredSkill(from)) { // You did not decode this map and have no clue where to look for the treasure. from.SendLocalizedMessage(503031); @@ -361,675 +570,365 @@ namespace Server.Items { from.SendLocalizedMessage(503020); // You are already digging treasure. } - else if (from.Map != m_Map) + else if (!HasDiggingTool(from)) + { + from.SendMessage("You must have a digging tool to dig for treasure."); + } + else if (from.Map != map) { from.SendLocalizedMessage(1010479); // You seem to be in the right place, but may be on the wrong facet! } else { - from.SendLocalizedMessage(503033); // Where do you wish to dig? - from.Target = new DigTarget(this); - } - } + var p = targeted as IPoint3D; - public override void OnDoubleClick(Mobile from) - { - if (!from.InRange(GetWorldLocation(), 2)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 1019045); // I can't reach that. - return; - } + var targ3D = (p as Item)?.GetWorldLocation() ?? new Point3D(p); - if (!m_Completed && m_Decoder == null) - { - Decode(from); - } - else - { - DisplayTo(from); - } - } + var skillValue = from.Skills.Mining.Value; - private bool CheckYoung(Mobile from) - { - if (from.AccessLevel >= AccessLevel.GameMaster) - { - return true; - } - - if (from is PlayerMobile mobile && mobile.Young) - { - return true; - } - - if (from == Decoder) - { - Level = 1; - from.SendLocalizedMessage(1046446); // This is now a level one treasure map. - return true; - } - - return false; - } - - private double GetMinSkillLevel() - { - return m_Level switch - { - 1 => -3.0, - 2 => 41.0, - 3 => 51.0, - 4 => 61.0, - 5 => 70.0, - 6 => 70.0, - _ => 0.0 - }; - } - - private bool HasRequiredSkill(Mobile from) => from.Skills.Cartography.Value >= GetMinSkillLevel(); - - public void Decode(Mobile from) - { - if (m_Completed || m_Decoder != null) - { - return; - } - - if (m_Level == 0) - { - if (!CheckYoung(from)) + var maxRange = skillValue switch { - from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map. - return; - } - } - else - { - var minSkill = GetMinSkillLevel(); + >= 100.0 => 4, + >= 81.0 => 3, + >= 51.0 => 2, + _ => 1 + }; - if (from.Skills.Cartography.Value < minSkill) + var loc = m_Map.ChestLocation; + int x = loc.X, y = loc.Y; + + var chest3D0 = new Point3D(loc, 0); + + if (Utility.InRange(targ3D, chest3D0, maxRange)) { - from.SendLocalizedMessage(503013); // The map is too difficult to attempt to decode. - } - - var maxSkill = minSkill + 60.0; - - if (!from.CheckSkill(SkillName.Cartography, minSkill, maxSkill)) - { - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503018); // You fail to make anything of the map. - return; - } - } - - from.LocalOverheadMessage(MessageType.Regular, 0x3B2, 503019); // You successfully decode a treasure map! - Decoder = from; - - if (Core.AOS) - { - LootType = LootType.Blessed; - } - - DisplayTo(from); - } - - public override void DisplayTo(Mobile from) - { - if (m_Completed) - { - SendLocalizedMessageTo(from, 503014); // This treasure hunt has already been completed. - } - else if (m_Level == 0 && !CheckYoung(from)) - { - from.SendLocalizedMessage(1046447); // Only a young player may use this treasure map. - return; - } - else if (m_Decoder != from && !HasRequiredSkill(from)) - { - // You did not decode this map and have no clue where to look for the treasure. - from.SendLocalizedMessage(503031); - return; - } - else - { - // The treasure is marked by the red pin. Grab a shovel and go dig it up! - SendLocalizedMessageTo(from, 503017); - } - - from.PlaySound(0x249); - base.DisplayTo(from); - } - - public override void GetContextMenuEntries(Mobile from, List list) - { - base.GetContextMenuEntries(from, list); - - if (!m_Completed) - { - if (m_Decoder == null) - { - list.Add(new DecodeMapEntry(this)); - } - else - { - var digTool = HasDiggingTool(from); - - list.Add(new OpenMapEntry(this)); - list.Add(new DigEntry(this, digTool)); - } - } - } - - public override void GetProperties(IPropertyList list) - { - base.GetProperties(list); - - list.Add(m_Map == Map.Felucca ? 1041502 : 1041503); // for somewhere in Felucca : for somewhere in Trammel - - if (m_Completed) - { - list.Add(1041507, m_CompletedBy?.RawName ?? "someone"); // completed by ~1_val~ - } - } - - public override void OnSingleClick(Mobile from) - { - if (m_Completed) - { - from.NetState.SendMessageLocalizedAffix( - Serial, - ItemID, - MessageType.Label, - 0x3B2, - 3, - 1048030, - "", - AffixType.Append, - $" completed by {m_CompletedBy?.RawName ?? "someone"}" - ); - } - else if (m_Decoder != null) - { - if (m_Level == 6) - { - LabelTo(from, 1063453); - } - else - { - LabelTo(from, 1041516 + m_Level); - } - } - else - { - if (m_Level == 6) - { - LabelTo(from, 1041522, $"#{1063452}\t \t#{(m_Map == Map.Felucca ? 1041502 : 1041503)}"); - } - else - { - LabelTo(from, 1041522, $"#{1041510 + m_Level}\t \t#{(m_Map == Map.Felucca ? 1041502 : 1041503)}"); - } - } - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(1); - - writer.Write(m_CompletedBy); - - writer.Write(m_Level); - writer.Write(m_Completed); - writer.Write(m_Decoder); - writer.Write(m_Map); - writer.Write(ChestLocation); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - - switch (version) - { - case 1: + if (from.Location.X == x && from.Location.Y == y) { - m_CompletedBy = reader.ReadEntity(); - - goto case 0; + // The chest can't be dug up because you are standing on top of it. + from.SendLocalizedMessage(503030); } - case 0: + else if (map != null) { - m_Level = reader.ReadInt(); - m_Completed = reader.ReadBool(); - m_Decoder = reader.ReadEntity(); - m_Map = reader.ReadMap(); - ChestLocation = reader.ReadPoint2D(); + var z = map.GetAverageZ(x, y); - if (version == 0 && m_Completed) + if (!map.CanFit(x, y, z, 16, true)) { - m_CompletedBy = m_Decoder; + // You have found the treasure chest but something is keeping it from being dug up. + from.SendLocalizedMessage(503021); } - - break; - } - } - - if (Core.AOS && m_Decoder != null && LootType == LootType.Regular) - { - LootType = LootType.Blessed; - } - } - - private class DigTarget : Target - { - private readonly TreasureMap m_Map; - - public DigTarget(TreasureMap map) : base(6, true, TargetFlags.None) => m_Map = map; - - protected override void OnTarget(Mobile from, object targeted) - { - if (m_Map.Deleted) - { - return; - } - - var map = m_Map.m_Map; - - if (m_Map.m_Completed) - { - from.SendLocalizedMessage(503028); // The treasure for this map has already been found. - } - /* - else if (from != m_Map.m_Decoder) - { - from.SendLocalizedMessage( 503016 ); // Only the person who decoded this map may actually dig up the treasure. - } - */ - else if (m_Map.m_Decoder != from && !m_Map.HasRequiredSkill(from)) - { - // You did not decode this map and have no clue where to look for the treasure. - from.SendLocalizedMessage(503031); - } - else if (!from.CanBeginAction()) - { - from.SendLocalizedMessage(503020); // You are already digging treasure. - } - else if (!HasDiggingTool(from)) - { - from.SendMessage("You must have a digging tool to dig for treasure."); - } - else if (from.Map != map) - { - from.SendLocalizedMessage(1010479); // You seem to be in the right place, but may be on the wrong facet! - } - else - { - var p = targeted as IPoint3D; - - var targ3D = (p as Item)?.GetWorldLocation() ?? new Point3D(p); - - var skillValue = from.Skills.Mining.Value; - - var maxRange = skillValue switch - { - >= 100.0 => 4, - >= 81.0 => 3, - >= 51.0 => 2, - _ => 1 - }; - - var loc = m_Map.ChestLocation; - int x = loc.X, y = loc.Y; - - var chest3D0 = new Point3D(loc, 0); - - if (Utility.InRange(targ3D, chest3D0, maxRange)) - { - if (from.Location.X == x && from.Location.Y == y) + else if (from.BeginAction()) { - // The chest can't be dug up because you are standing on top of it. - from.SendLocalizedMessage(503030); - } - else if (map != null) - { - var z = map.GetAverageZ(x, y); - - if (!map.CanFit(x, y, z, 16, true)) - { - // You have found the treasure chest but something is keeping it from being dug up. - from.SendLocalizedMessage(503021); - } - else if (from.BeginAction()) - { - new DigTimer(from, m_Map, new Point3D(x, y, z), map).Start(); - } - else - { - from.SendLocalizedMessage(503020); // You are already digging treasure. - } - } - } - else if (m_Map.Level > 0) - { - if (Utility.InRange(targ3D, chest3D0, 8)) // We're close, but not quite - { - from.SendLocalizedMessage(503032); // You dig and dig but no treasure seems to be here. + new DigTimer(from, m_Map, new Point3D(x, y, z), map).Start(); } else { - from.SendLocalizedMessage(503035); // You dig and dig but fail to find any treasure. + from.SendLocalizedMessage(503020); // You are already digging treasure. } } + } + else if (m_Map.Level > 0) + { + if (Utility.InRange(targ3D, chest3D0, 8)) // We're close, but not quite + { + from.SendLocalizedMessage(503032); // You dig and dig but no treasure seems to be here. + } else { - if (Utility.InRange(targ3D, chest3D0, 8)) // We're close, but not quite - { - from.SendAsciiMessage(0x44, "The treasure chest is very close!"); - } - else - { - var dir = Utility.GetDirection(targ3D, chest3D0); + from.SendLocalizedMessage(503035); // You dig and dig but fail to find any treasure. + } + } + else + { + if (Utility.InRange(targ3D, chest3D0, 8)) // We're close, but not quite + { + from.SendAsciiMessage(0x44, "The treasure chest is very close!"); + } + else + { + var dir = Utility.GetDirection(targ3D, chest3D0); - var sDir = dir switch - { - Direction.North => "north", - Direction.Right => "northeast", - Direction.East => "east", - Direction.Down => "southeast", - Direction.South => "south", - Direction.Left => "southwest", - Direction.West => "west", - _ => "northwest" - }; + var sDir = dir switch + { + Direction.North => "north", + Direction.Right => "northeast", + Direction.East => "east", + Direction.Down => "southeast", + Direction.South => "south", + Direction.Left => "southwest", + Direction.West => "west", + _ => "northwest" + }; - from.SendAsciiMessage(0x44, "Try looking for the treasure chest more to the {0}.", sDir); - } + from.SendAsciiMessage(0x44, "Try looking for the treasure chest more to the {0}.", sDir); } } } } + } - private class DigTimer : Timer + private class DigTimer : Timer + { + private Mobile m_From; + private long m_LastMoveTime; + private Map m_Map; + private long m_NextActionTime; + + private long m_NextSkillTime; + private long m_NextSpellTime; + private TreasureMap m_TreasureMap; + private TreasureMapChest m_Chest; + + private int m_Count; + + private TreasureChestDirt m_Dirt1; + private TreasureChestDirt m_Dirt2; + + private Point3D m_Location; + + public DigTimer(Mobile from, TreasureMap treasureMap, Point3D location, Map map) : base( + TimeSpan.Zero, + TimeSpan.FromSeconds(1.0) + ) { - private readonly Mobile m_From; - private readonly long m_LastMoveTime; - private readonly Map m_Map; - private readonly long m_NextActionTime; + m_From = from; + m_TreasureMap = treasureMap; - private readonly long m_NextSkillTime; - private readonly long m_NextSpellTime; - private readonly TreasureMap m_TreasureMap; - private TreasureMapChest m_Chest; + m_Location = location; + m_Map = map; - private int m_Count; + m_NextSkillTime = from.NextSkillTime; + m_NextSpellTime = from.NextSpellTime; + m_NextActionTime = from.NextActionTime; + m_LastMoveTime = from.LastMoveTime; + } - private TreasureChestDirt m_Dirt1; - private TreasureChestDirt m_Dirt2; + private void Terminate() + { + Stop(); + m_From.EndAction(); - private Point3D m_Location; + m_Chest?.Delete(); + m_Dirt1?.Delete(); + m_Dirt2?.Delete(); + } - public DigTimer(Mobile from, TreasureMap treasureMap, Point3D location, Map map) : base( - TimeSpan.Zero, - TimeSpan.FromSeconds(1.0) - ) + protected override void OnTick() + { + if (m_NextSkillTime != m_From.NextSkillTime || m_NextSpellTime != m_From.NextSpellTime || + m_NextActionTime != m_From.NextActionTime) { - m_From = from; - m_TreasureMap = treasureMap; - - m_Location = location; - m_Map = map; - - m_NextSkillTime = from.NextSkillTime; - m_NextSpellTime = from.NextSpellTime; - m_NextActionTime = from.NextActionTime; - m_LastMoveTime = from.LastMoveTime; + Terminate(); + return; } - private void Terminate() + if (m_LastMoveTime != m_From.LastMoveTime) + { + // You cannot move around while digging up treasure. You will need to start digging anew. + m_From.SendLocalizedMessage(503023); + Terminate(); + return; + } + + var z = m_Chest?.Z + m_Chest?.ItemData.Height ?? int.MinValue; + var height = 16; + + if (z > m_Location.Z) + { + height -= z - m_Location.Z; + } + else + { + z = m_Location.Z; + } + + if (!m_Map.CanFit(m_Location.X, m_Location.Y, z, height, true, true, false)) + { + // You stop digging because something is directly on top of the treasure chest. + m_From.SendLocalizedMessage(503024); + Terminate(); + return; + } + + m_Count++; + + m_From.RevealingAction(); + m_From.Direction = m_From.GetDirectionTo(m_Location); + + if (m_Count > 1 && m_Dirt1 == null) + { + m_Dirt1 = new TreasureChestDirt(); + m_Dirt1.MoveToWorld(m_Location, m_Map); + + m_Dirt2 = new TreasureChestDirt(); + m_Dirt2.MoveToWorld(new Point3D(m_Location.X, m_Location.Y - 1, m_Location.Z), m_Map); + } + + if (m_Count == 5) + { + m_Dirt1.Turn1(); + } + else if (m_Count == 10) + { + m_Dirt1.Turn2(); + m_Dirt2.Turn2(); + } + else if (m_Count > 10) + { + if (m_Chest == null) + { + m_Chest = new TreasureMapChest(m_From, m_TreasureMap.Level, true); + m_Chest.MoveToWorld(new Point3D(m_Location.X, m_Location.Y, m_Location.Z - 15), m_Map); + } + else + { + m_Chest.Z++; + } + + Effects.PlaySound(m_Chest.Location, m_Map, 0x33B); + } + + if (m_Chest?.Location.Z >= m_Location.Z) { Stop(); m_From.EndAction(); - m_Chest?.Delete(); - m_Dirt1?.Delete(); - m_Dirt2?.Delete(); + m_Chest.Temporary = false; + m_TreasureMap.Completed = true; + m_TreasureMap.CompletedBy = m_From; + + var spawns = m_TreasureMap.Level switch + { + 0 => 3, + 1 => 0, + _ => 4 + }; + + for (var i = 0; i < spawns; ++i) + { + var bc = Spawn(m_TreasureMap.Level, m_Chest.Location, m_Chest.Map, null, true); + + if (bc != null) + { + m_Chest.Guardians.Add(bc); + } + } + } + else + { + if (m_From.Body.IsHuman && !m_From.Mounted) + { + m_From.Animate(11, 5, 1, true, false, 0); + } + + new SoundTimer(m_From, 0x125 + m_Count % 2).Start(); + } + } + + private class SoundTimer : Timer + { + private readonly Mobile m_From; + private readonly int m_SoundID; + + public SoundTimer(Mobile from, int soundID) : base(TimeSpan.FromSeconds(0.9)) + { + m_From = from; + m_SoundID = soundID; } protected override void OnTick() { - if (m_NextSkillTime != m_From.NextSkillTime || m_NextSpellTime != m_From.NextSpellTime || - m_NextActionTime != m_From.NextActionTime) - { - Terminate(); - return; - } - - if (m_LastMoveTime != m_From.LastMoveTime) - { - // You cannot move around while digging up treasure. You will need to start digging anew. - m_From.SendLocalizedMessage(503023); - Terminate(); - return; - } - - var z = m_Chest?.Z + m_Chest?.ItemData.Height ?? int.MinValue; - var height = 16; - - if (z > m_Location.Z) - { - height -= z - m_Location.Z; - } - else - { - z = m_Location.Z; - } - - if (!m_Map.CanFit(m_Location.X, m_Location.Y, z, height, true, true, false)) - { - // You stop digging because something is directly on top of the treasure chest. - m_From.SendLocalizedMessage(503024); - Terminate(); - return; - } - - m_Count++; - - m_From.RevealingAction(); - m_From.Direction = m_From.GetDirectionTo(m_Location); - - if (m_Count > 1 && m_Dirt1 == null) - { - m_Dirt1 = new TreasureChestDirt(); - m_Dirt1.MoveToWorld(m_Location, m_Map); - - m_Dirt2 = new TreasureChestDirt(); - m_Dirt2.MoveToWorld(new Point3D(m_Location.X, m_Location.Y - 1, m_Location.Z), m_Map); - } - - if (m_Count == 5) - { - m_Dirt1.Turn1(); - } - else if (m_Count == 10) - { - m_Dirt1.Turn2(); - m_Dirt2.Turn2(); - } - else if (m_Count > 10) - { - if (m_Chest == null) - { - m_Chest = new TreasureMapChest(m_From, m_TreasureMap.Level, true); - m_Chest.MoveToWorld(new Point3D(m_Location.X, m_Location.Y, m_Location.Z - 15), m_Map); - } - else - { - m_Chest.Z++; - } - - Effects.PlaySound(m_Chest.Location, m_Map, 0x33B); - } - - if (m_Chest?.Location.Z >= m_Location.Z) - { - Stop(); - m_From.EndAction(); - - m_Chest.Temporary = false; - m_TreasureMap.Completed = true; - m_TreasureMap.CompletedBy = m_From; - - var spawns = m_TreasureMap.Level switch - { - 0 => 3, - 1 => 0, - _ => 4 - }; - - for (var i = 0; i < spawns; ++i) - { - var bc = Spawn(m_TreasureMap.Level, m_Chest.Location, m_Chest.Map, null, true); - - if (bc != null) - { - m_Chest.Guardians.Add(bc); - } - } - } - else - { - if (m_From.Body.IsHuman && !m_From.Mounted) - { - m_From.Animate(11, 5, 1, true, false, 0); - } - - new SoundTimer(m_From, 0x125 + m_Count % 2).Start(); - } - } - - private class SoundTimer : Timer - { - private readonly Mobile m_From; - private readonly int m_SoundID; - - public SoundTimer(Mobile from, int soundID) : base(TimeSpan.FromSeconds(0.9)) - { - m_From = from; - m_SoundID = soundID; - } - - protected override void OnTick() - { - m_From.PlaySound(m_SoundID); - } - } - } - - private class DecodeMapEntry : ContextMenuEntry - { - private readonly TreasureMap m_Map; - - public DecodeMapEntry(TreasureMap map) : base(6147, 2) => m_Map = map; - - public override void OnClick() - { - if (!m_Map.Deleted) - { - m_Map.Decode(Owner.From); - } - } - } - - private class OpenMapEntry : ContextMenuEntry - { - private readonly TreasureMap m_Map; - - public OpenMapEntry(TreasureMap map) : base(6150, 2) => m_Map = map; - - public override void OnClick() - { - if (!m_Map.Deleted) - { - m_Map.DisplayTo(Owner.From); - } - } - } - - private class DigEntry : ContextMenuEntry - { - private readonly TreasureMap m_Map; - - public DigEntry(TreasureMap map, bool enabled) : base(6148, 2) - { - m_Map = map; - - if (!enabled) - { - Flags |= CMEFlags.Disabled; - } - } - - public override void OnClick() - { - if (m_Map.Deleted) - { - return; - } - - var from = Owner.From; - - if (HasDiggingTool(from)) - { - m_Map.OnBeginDig(from); - } - else - { - from.SendMessage("You must have a digging tool to dig for treasure."); - } + m_From.PlaySound(m_SoundID); } } } - public class TreasureChestDirt : Item + private class DecodeMapEntry : ContextMenuEntry { - public TreasureChestDirt() : base(0x912) - { - Movable = false; + private readonly TreasureMap m_Map; - Timer.StartTimer(TimeSpan.FromMinutes(2.0), Delete); + public DecodeMapEntry(TreasureMap map) : base(6147, 2) => m_Map = map; + + public override void OnClick() + { + if (!m_Map.Deleted) + { + m_Map.Decode(Owner.From); + } + } + } + + private class OpenMapEntry : ContextMenuEntry + { + private readonly TreasureMap m_Map; + + public OpenMapEntry(TreasureMap map) : base(6150, 2) => m_Map = map; + + public override void OnClick() + { + if (!m_Map.Deleted) + { + m_Map.DisplayTo(Owner.From); + } + } + } + + private class DigEntry : ContextMenuEntry + { + private readonly TreasureMap m_Map; + + public DigEntry(TreasureMap map, bool enabled) : base(6148, 2) + { + m_Map = map; + + if (!enabled) + { + Flags |= CMEFlags.Disabled; + } } - public TreasureChestDirt(Serial serial) : base(serial) + public override void OnClick() { - } + if (m_Map.Deleted) + { + return; + } - public void Turn1() - { - ItemID = 0x913; - } + var from = Owner.From; - public void Turn2() - { - ItemID = 0x914; - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.WriteEncodedInt(0); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadEncodedInt(); - - Delete(); + if (HasDiggingTool(from)) + { + m_Map.OnBeginDig(from); + } + else + { + from.SendMessage("You must have a digging tool to dig for treasure."); + } } } } + +[SerializationGenerator(0)] +public partial class TreasureChestDirt : Item +{ + public TreasureChestDirt() : base(0x912) + { + Movable = false; + + Timer.StartTimer(TimeSpan.FromMinutes(2.0), Delete); + } + + public void Turn1() + { + ItemID = 0x913; + } + + public void Turn2() + { + ItemID = 0x914; + } + + [AfterDeserialization(false)] + private void AfterDeserialization() + { + Delete(); + } +} diff --git a/Projects/UOContent/Items/Maps/WorldMap.cs b/Projects/UOContent/Items/Maps/WorldMap.cs index 455ca7822..a22f50803 100644 --- a/Projects/UOContent/Items/Maps/WorldMap.cs +++ b/Projects/UOContent/Items/Maps/WorldMap.cs @@ -1,51 +1,27 @@ -namespace Server.Items +using System; +using ModernUO.Serialization; + +namespace Server.Items; + +[SerializationGenerator(0)] +public partial class WorldMap : MapItem { - public class WorldMap : MapItem + [Constructible] + public WorldMap() { - [Constructible] - public WorldMap() - { - SetDisplay(0, 0, 5119, 4095, 400, 400); - } + SetDisplay(0, 0, 5119, 4095, 400, 400); + } - public WorldMap(Serial serial) : base(serial) - { - } + public override int LabelNumber => 1015233; // world map - public override int LabelNumber => 1015233; // world map + public override void CraftInit(Mobile from) + { + // Unlike the others, world map is not based on crafted location - public override void CraftInit(Mobile from) - { - // Unlike the others, world map is not based on crafted location + var skillValue = from.Skills.Cartography.Value; + var x20 = (int)(skillValue * 20); + var size = Math.Clamp(25 + (int)(skillValue * 6.6), 200, 400); - var skillValue = from.Skills.Cartography.Value; - var x20 = (int)(skillValue * 20); - var size = 25 + (int)(skillValue * 6.6); - - if (size < 200) - { - size = 200; - } - else if (size > 400) - { - size = 400; - } - - SetDisplay(1344 - x20, 1600 - x20, 1472 + x20, 1728 + x20, size, size); - } - - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); - } + SetDisplay(1344 - x20, 1600 - x20, 1472 + x20, 1728 + x20, size, size); } } diff --git a/Projects/UOContent/Migrations/Server.Items.BlankMap.v0.json b/Projects/UOContent/Migrations/Server.Items.BlankMap.v0.json new file mode 100644 index 000000000..45bfda687 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.BlankMap.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.BlankMap" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.CityMap.v0.json b/Projects/UOContent/Migrations/Server.Items.CityMap.v0.json new file mode 100644 index 000000000..bf3d82ee7 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.CityMap.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.CityMap" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.IndecipherableMap.v0.json b/Projects/UOContent/Migrations/Server.Items.IndecipherableMap.v0.json new file mode 100644 index 000000000..46fda4ba7 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.IndecipherableMap.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.IndecipherableMap" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.LocalMap.v0.json b/Projects/UOContent/Migrations/Server.Items.LocalMap.v0.json new file mode 100644 index 000000000..24c6c8aa0 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.LocalMap.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.LocalMap" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.MapItem.v1.json b/Projects/UOContent/Migrations/Server.Items.MapItem.v1.json new file mode 100644 index 000000000..da0beae9b --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.MapItem.v1.json @@ -0,0 +1,65 @@ +{ + "version": 1, + "type": "Server.Items.MapItem", + "properties": [ + { + "name": "Bounds", + "type": "Server.Rectangle2D", + "rule": "PrimitiveUOTypeMigrationRule", + "ruleArguments": [ + "Rect2D" + ] + }, + { + "name": "Width", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Height", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Protected", + "type": "bool", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Pins", + "type": "System.Collections.Generic.List\u003CServer.Point2D\u003E", + "rule": "ListMigrationRule", + "ruleArguments": [ + "", + "Server.Point2D", + "PrimitiveUOTypeMigrationRule", + "Point2D" + ] + }, + { + "name": "Facet", + "type": "Server.Map", + "rule": "PrimitiveUOTypeMigrationRule", + "ruleArguments": [ + "Map" + ] + }, + { + "name": "Editable", + "type": "bool", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.PresetMap.v0.json b/Projects/UOContent/Migrations/Server.Items.PresetMap.v0.json new file mode 100644 index 000000000..067157543 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.PresetMap.v0.json @@ -0,0 +1,14 @@ +{ + "version": 0, + "type": "Server.Items.PresetMap", + "properties": [ + { + "name": "LabelNumber", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.SeaChart.v0.json b/Projects/UOContent/Migrations/Server.Items.SeaChart.v0.json new file mode 100644 index 000000000..12abb45b3 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.SeaChart.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.SeaChart" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.TreasureChestDirt.v0.json b/Projects/UOContent/Migrations/Server.Items.TreasureChestDirt.v0.json new file mode 100644 index 000000000..ff0053ffe --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.TreasureChestDirt.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.TreasureChestDirt" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.TreasureMap.v0.json b/Projects/UOContent/Migrations/Server.Items.TreasureMap.v0.json new file mode 100644 index 000000000..cd69f5536 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.TreasureMap.v0.json @@ -0,0 +1,48 @@ +{ + "version": 0, + "type": "Server.Items.TreasureMap", + "properties": [ + { + "name": "CompletedBy", + "type": "Server.Mobile", + "rule": "SerializableInterfaceMigrationRule" + }, + { + "name": "Level", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Completed", + "type": "bool", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Decoder", + "type": "Server.Mobile", + "rule": "SerializableInterfaceMigrationRule" + }, + { + "name": "ChestMap", + "type": "Server.Map", + "rule": "PrimitiveUOTypeMigrationRule", + "ruleArguments": [ + "Map" + ] + }, + { + "name": "ChestLocation", + "type": "Server.Point2D", + "rule": "PrimitiveUOTypeMigrationRule", + "ruleArguments": [ + "Point2D" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.WorldMap.v0.json b/Projects/UOContent/Migrations/Server.Items.WorldMap.v0.json new file mode 100644 index 000000000..f26361b2e --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.WorldMap.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.WorldMap" +} \ No newline at end of file