From 10b26741c71115b7c22493ff17aa9aa517bcb0e5 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Fri, 24 Feb 2023 19:04:21 -0800 Subject: [PATCH] fix: Codegens spellbooks (#1349) --- .../Skill Items/Magical/BookOfBushido.cs | 43 +- .../Skill Items/Magical/BookOfChivalry.cs | 43 +- .../Skill Items/Magical/BookOfNinjitsu.cs | 43 +- .../Skill Items/Magical/MysticSpellbook.cs | 40 +- .../Magical/NecromancerSpellbook.cs | 43 +- .../Items/Skill Items/Magical/Runebook.cs | 670 ++++---- .../Items/Skill Items/Magical/Spellbook.cs | 1373 ++++++++--------- .../Skill Items/Magical/SpellweavingBook.cs | 44 +- .../Server.Items.BookOfBushido.v0.json | 4 + .../Server.Items.BookOfChivalry.v0.json | 4 + .../Server.Items.BookOfNinjitsu.v0.json | 4 + .../Server.Items.MysticSpellbook.v0.json | 4 + .../Server.Items.NecromancerSpellbook.v0.json | 4 + .../Migrations/Server.Items.Runebook.v4.json | 66 + .../Server.Items.RunebookEntry.v2.json | 35 + .../Migrations/Server.Items.Spellbook.v6.json | 69 + .../Server.Items.SpellweavingBook.v0.json | 4 + 17 files changed, 1185 insertions(+), 1308 deletions(-) create mode 100644 Projects/UOContent/Migrations/Server.Items.BookOfBushido.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.BookOfChivalry.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.BookOfNinjitsu.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.MysticSpellbook.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.NecromancerSpellbook.v0.json create mode 100644 Projects/UOContent/Migrations/Server.Items.Runebook.v4.json create mode 100644 Projects/UOContent/Migrations/Server.Items.RunebookEntry.v2.json create mode 100644 Projects/UOContent/Migrations/Server.Items.Spellbook.v6.json create mode 100644 Projects/UOContent/Migrations/Server.Items.SpellweavingBook.v0.json diff --git a/Projects/UOContent/Items/Skill Items/Magical/BookOfBushido.cs b/Projects/UOContent/Items/Skill Items/Magical/BookOfBushido.cs index 83348f2ea2..c8c37d529e 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/BookOfBushido.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/BookOfBushido.cs @@ -1,36 +1,15 @@ -namespace Server.Items -{ - public class BookOfBushido : Spellbook - { - [Constructible] - public BookOfBushido(ulong content = 0x3F) : base(content, 0x238C) => - Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - - public BookOfBushido(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Samurai; - public override int BookOffset => 400; - public override int BookCount => 6; +using ModernUO.Serialization; - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); +namespace Server.Items; - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); +[SerializationGenerator(0, false)] +public partial class BookOfBushido : Spellbook +{ + [Constructible] + public BookOfBushido(ulong content = 0x3F) : base(content, 0x238C) => + Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - if (version == 0 && Core.ML) - { - Layer = Layer.OneHanded; - } - } - } + public override SpellbookType SpellbookType => SpellbookType.Samurai; + public override int BookOffset => 400; + public override int BookCount => 6; } diff --git a/Projects/UOContent/Items/Skill Items/Magical/BookOfChivalry.cs b/Projects/UOContent/Items/Skill Items/Magical/BookOfChivalry.cs index 984ded43ec..8aec590ea2 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/BookOfChivalry.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/BookOfChivalry.cs @@ -1,36 +1,15 @@ -namespace Server.Items -{ - public class BookOfChivalry : Spellbook - { - [Constructible] - public BookOfChivalry(ulong content = 0x3FF) : base(content, 0x2252) => - Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - - public BookOfChivalry(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Paladin; - public override int BookOffset => 200; - public override int BookCount => 10; +using ModernUO.Serialization; - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); +namespace Server.Items; - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); +[SerializationGenerator(0, false)] +public partial class BookOfChivalry : Spellbook +{ + [Constructible] + public BookOfChivalry(ulong content = 0x3FF) : base(content, 0x2252) => + Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - if (version == 0 && Core.ML) - { - Layer = Layer.OneHanded; - } - } - } + public override SpellbookType SpellbookType => SpellbookType.Paladin; + public override int BookOffset => 200; + public override int BookCount => 10; } diff --git a/Projects/UOContent/Items/Skill Items/Magical/BookOfNinjitsu.cs b/Projects/UOContent/Items/Skill Items/Magical/BookOfNinjitsu.cs index aaae744f7b..51d1e6bc93 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/BookOfNinjitsu.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/BookOfNinjitsu.cs @@ -1,36 +1,15 @@ -namespace Server.Items -{ - public class BookOfNinjitsu : Spellbook - { - [Constructible] - public BookOfNinjitsu(ulong content = 0xFF) : base(content, 0x23A0) => - Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - - public BookOfNinjitsu(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Ninja; - public override int BookOffset => 500; - public override int BookCount => 8; +using ModernUO.Serialization; - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); +namespace Server.Items; - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); +[SerializationGenerator(0, false)] +public partial class BookOfNinjitsu : Spellbook +{ + [Constructible] + public BookOfNinjitsu(ulong content = 0xFF) : base(content, 0x23A0) => + Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - if (version == 0 && Core.ML) - { - Layer = Layer.OneHanded; - } - } - } + public override SpellbookType SpellbookType => SpellbookType.Ninja; + public override int BookOffset => 500; + public override int BookCount => 8; } diff --git a/Projects/UOContent/Items/Skill Items/Magical/MysticSpellbook.cs b/Projects/UOContent/Items/Skill Items/Magical/MysticSpellbook.cs index 4f979fc5c0..b09d208598 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/MysticSpellbook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/MysticSpellbook.cs @@ -1,35 +1,15 @@ -namespace Server.Items -{ - public class MysticSpellbook : Spellbook - { - [Constructible] - public MysticSpellbook(ulong content = 0) - : base(content, 0x2D9D) => - Layer = Layer.OneHanded; - - public MysticSpellbook(Serial serial) - : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Mystic; +using ModernUO.Serialization; - public override int BookOffset => 677; - public override int BookCount => 16; +namespace Server.Items; - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); - - writer.Write(0); // version - } +[SerializationGenerator(0, false)] +public partial class MysticSpellbook : Spellbook +{ + [Constructible] + public MysticSpellbook(ulong content = 0) : base(content, 0x2D9D) => Layer = Layer.OneHanded; - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); + public override SpellbookType SpellbookType => SpellbookType.Mystic; - /*int version = */ - reader.ReadInt(); - } - } + public override int BookOffset => 677; + public override int BookCount => 16; } diff --git a/Projects/UOContent/Items/Skill Items/Magical/NecromancerSpellbook.cs b/Projects/UOContent/Items/Skill Items/Magical/NecromancerSpellbook.cs index d7ce5604ec..5fb930c248 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/NecromancerSpellbook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/NecromancerSpellbook.cs @@ -1,36 +1,15 @@ -namespace Server.Items -{ - public class NecromancerSpellbook : Spellbook - { - [Constructible] - public NecromancerSpellbook(ulong content = 0) : base(content, 0x2253) => - Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - - public NecromancerSpellbook(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Necromancer; - public override int BookOffset => 100; - public override int BookCount => Core.SE ? 17 : 16; +using ModernUO.Serialization; - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); +namespace Server.Items; - writer.Write(1); // version - } - - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - - var version = reader.ReadInt(); +[SerializationGenerator(0, false)] +public partial class NecromancerSpellbook : Spellbook +{ + [Constructible] + public NecromancerSpellbook(ulong content = 0) : base(content, 0x2253) => + Layer = Core.ML ? Layer.OneHanded : Layer.Invalid; - if (version == 0 && Core.ML) - { - Layer = Layer.OneHanded; - } - } - } + public override SpellbookType SpellbookType => SpellbookType.Necromancer; + public override int BookOffset => 100; + public override int BookCount => Core.SE ? 17 : 16; } diff --git a/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs b/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs index 3d1ac368ca..c1e98265a6 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs @@ -1,519 +1,431 @@ using System; using System.Collections.Generic; +using ModernUO.Serialization; using Server.ContextMenus; using Server.Engines.Craft; using Server.Gumps; using Server.Mobiles; using Server.Multis; -namespace Server.Items +namespace Server.Items; + +[SerializationGenerator(4, false)] +public partial class Runebook : Item, ISecurable, ICraftable { - public class Runebook : Item, ISecurable, ICraftable - { - public static readonly TimeSpan UseDelay = TimeSpan.FromSeconds(7.0); - private Mobile m_Crafter; - private int m_DefaultIndex; + public static readonly TimeSpan UseDelay = TimeSpan.FromSeconds(7.0); - private string m_Description; + [InvalidateProperties] + [SerializableField(0)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private BookQuality _quality; - private BookQuality m_Quality; + [InvalidateProperties] + [SerializableField(1)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private string _crafter; - [Constructible] - public Runebook() : this(Core.SE ? 12 : 6) - { - } + [SerializableField(2)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private SecureLevel _level; - [Constructible] - public Runebook(int maxCharges) : base(Core.AOS ? 0x22C5 : 0xEFA) - { - Weight = Core.SE ? 1.0 : 3.0; - LootType = LootType.Blessed; - Hue = 0x461; + [SerializableField(3, setter: "private")] + private List _entries; - Layer = Core.AOS ? Layer.Invalid : Layer.OneHanded; + [InvalidateProperties] + [SerializableField(4)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private string _description; - Entries = new List(); + [SerializableField(5)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _curCharges; - MaxCharges = maxCharges; + [SerializableField(6)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _maxCharges; - m_DefaultIndex = -1; + [SerializableField(7, getter: "private", setter: "private")] + private int _defaultIndex; - Level = SecureLevel.CoOwners; - } + [Constructible] + public Runebook() : this(Core.SE ? 12 : 6) + { + } - public Runebook(Serial serial) : base(serial) - { - } + [Constructible] + public Runebook(int maxCharges) : base(Core.AOS ? 0x22C5 : 0xEFA) + { + Weight = Core.SE ? 1.0 : 3.0; + LootType = LootType.Blessed; + Hue = 0x461; - [CommandProperty(AccessLevel.GameMaster)] - public BookQuality Quality - { - get => m_Quality; - set - { - m_Quality = value; - InvalidateProperties(); - } - } + Layer = Core.AOS ? Layer.Invalid : Layer.OneHanded; - [CommandProperty(AccessLevel.GameMaster)] - public DateTime NextUse { get; set; } + _entries = new List(); + _maxCharges = maxCharges; + _defaultIndex = -1; + _level = SecureLevel.CoOwners; + } - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; - InvalidateProperties(); - } - } + [CommandProperty(AccessLevel.GameMaster)] + public DateTime NextUse { get; set; } + + public List Openers { get; set; } = new(); + + public override int LabelNumber => 1041267; // runebook - [CommandProperty(AccessLevel.GameMaster)] - public string Description + public RunebookEntry Default + { + get { - get => m_Description; - set + if (_defaultIndex >= 0 && _defaultIndex < Entries.Count) { - m_Description = value; - InvalidateProperties(); + return Entries[_defaultIndex]; } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int CurCharges { get; set; } - [CommandProperty(AccessLevel.GameMaster)] - public int MaxCharges { get; set; } + return null; + } + set => DefaultIndex = value == null ? -1 : Entries.IndexOf(value); + } - public List Openers { get; set; } = new(); + public override bool DisplayLootType => Core.AOS; - public override int LabelNumber => 1041267; // runebook + public int OnCraft( + int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, + CraftItem craftItem, int resHue + ) + { + var charges = Math.Min(5 + quality + (int)(from.Skills.Inscribe.Value / 30), 10); - public List Entries { get; private set; } + MaxCharges = Core.SE ? charges * 2 : charges; - public RunebookEntry Default + if (makersMark) { - get - { - if (m_DefaultIndex >= 0 && m_DefaultIndex < Entries.Count) - { - return Entries[m_DefaultIndex]; - } - - return null; - } - set - { - if (value == null) - { - m_DefaultIndex = -1; - } - else - { - m_DefaultIndex = Entries.IndexOf(value); - } - } + Crafter = from.RawName; } - public override bool DisplayLootType => Core.AOS; - - public int OnCraft( - int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, - CraftItem craftItem, int resHue - ) - { - var charges = 5 + quality + (int)(from.Skills.Inscribe.Value / 30); + Quality = (BookQuality)(quality - 1); - if (charges > 10) - { - charges = 10; - } + return quality; + } - MaxCharges = Core.SE ? charges * 2 : charges; + public override bool AllowEquippedCast(Mobile from) => true; - if (makersMark) - { - Crafter = from; - } + public override void GetContextMenuEntries(Mobile from, List list) + { + base.GetContextMenuEntries(from, list); + SetSecureLevelEntry.AddTo(from, this, list); + } - m_Quality = (BookQuality)(quality - 1); + private void Deserialize(IGenericReader reader, int version) + { + base.Deserialize(reader); - return quality; - } + _quality = (BookQuality)reader.ReadByte(); + _crafter = reader.ReadEntity()?.RawName; + _level = (SecureLevel)reader.ReadInt(); - [CommandProperty(AccessLevel.GameMaster)] - public SecureLevel Level { get; set; } + var count = reader.ReadInt(); - public override bool AllowEquippedCast(Mobile from) => true; + Entries = new List(count); - public override void GetContextMenuEntries(Mobile from, List list) + for (var i = 0; i < count; ++i) { - base.GetContextMenuEntries(from, list); - SetSecureLevelEntry.AddTo(from, this, list); + Entries.Add(new RunebookEntry(reader)); } - public override void Serialize(IGenericWriter writer) + _description = reader.ReadString(); + _curCharges = reader.ReadInt(); + _maxCharges = reader.ReadInt(); + _defaultIndex = reader.ReadInt(); + } + + public void DropRune(Mobile from, RunebookEntry e, int index) + { + if (_defaultIndex > index) { - base.Serialize(writer); + DefaultIndex -= 1; + } + else if (_defaultIndex == index) + { + DefaultIndex = -1; + } - writer.Write(3); + this.RemoveAt(_entries, index); - writer.Write((byte)m_Quality); + var rune = new RecallRune + { + Target = e.Location, + TargetMap = e.Map, + Description = e.Description, + House = e.House, + Marked = true + }; - writer.Write(m_Crafter); + from.AddToBackpack(rune); - writer.Write((int)Level); + from.SendLocalizedMessage(502421); // You have removed the rune. + } + + public bool IsOpen(Mobile toCheck) + { + var ns = toCheck.NetState; - writer.Write(Entries.Count); + if (ns == null) + { + return false; + } - for (var i = 0; i < Entries.Count; ++i) + foreach (var gump in ns.Gumps) + { + if ((gump as RunebookGump)?.Book == this) { - Entries[i].Serialize(writer); + return true; } - - writer.Write(m_Description); - writer.Write(CurCharges); - writer.Write(MaxCharges); - writer.Write(m_DefaultIndex); } - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); + return false; + } + + public override void GetProperties(IPropertyList list) + { + base.GetProperties(list); - LootType = LootType.Blessed; + if (_quality == BookQuality.Exceptional) + { + list.Add(1063341); // exceptional + } - if (Core.SE && Weight == 3.0) - { - Weight = 1.0; - } + if (_crafter != null) + { + list.Add(1050043, _crafter); // crafted by ~1_NAME~ + } - var version = reader.ReadInt(); + if (!string.IsNullOrEmpty(_description)) + { + list.Add(_description); + } + } - switch (version) - { - case 3: - { - m_Quality = (BookQuality)reader.ReadByte(); - goto case 2; - } - case 2: - { - m_Crafter = reader.ReadEntity(); - goto case 1; - } - case 1: - { - Level = (SecureLevel)reader.ReadInt(); - goto case 0; - } - case 0: - { - var count = reader.ReadInt(); - - Entries = new List(count); - - for (var i = 0; i < count; ++i) - { - Entries.Add(new RunebookEntry(reader)); - } - - m_Description = reader.ReadString(); - CurCharges = reader.ReadInt(); - MaxCharges = reader.ReadInt(); - m_DefaultIndex = reader.ReadInt(); - - break; - } - } + public override bool OnDragLift(Mobile from) + { + if (from.HasGump()) + { + from.SendLocalizedMessage(500169); // You cannot pick that up. + return false; } - public void DropRune(Mobile from, RunebookEntry e, int index) + foreach (var m in Openers) { - if (m_DefaultIndex > index) - { - m_DefaultIndex -= 1; - } - else if (m_DefaultIndex == index) + if (IsOpen(m)) { - m_DefaultIndex = -1; + m.CloseGump(); } + } - Entries.RemoveAt(index); + Openers.Clear(); - var rune = new RecallRune(); + return true; + } - rune.Target = e.Location; - rune.TargetMap = e.Map; - rune.Description = e.Description; - rune.House = e.House; - rune.Marked = true; + public override void OnSingleClick(Mobile from) + { + if (_description?.Length > 0) + { + LabelTo(from, _description); + } - from.AddToBackpack(rune); + base.OnSingleClick(from); - from.SendLocalizedMessage(502421); // You have removed the rune. + if (_crafter != null) + { + LabelTo(from, 1050043, _crafter); } + } - public bool IsOpen(Mobile toCheck) + public override void OnDoubleClick(Mobile from) + { + if (from.InRange(GetWorldLocation(), Core.ML ? 3 : 1) && CheckAccess(from)) { - var ns = toCheck.NetState; - - if (ns == null) + if (RootParent is BaseCreature) { - return false; + from.SendLocalizedMessage(502402); // That is inaccessible. + return; } - foreach (var gump in ns.Gumps) + if (Core.Now < NextUse) { - if (gump is RunebookGump bookGump && bookGump.Book == this) - { - return true; - } + from.SendLocalizedMessage(502406); // This book needs time to recharge. + return; } - return false; + from.CloseGump(); + from.SendGump(new RunebookGump(from, this)); + + Openers.Add(from); } + } - public override void GetProperties(IPropertyList list) + public virtual void OnTravel() + { + if (!Core.SA) { - base.GetProperties(list); - - if (m_Quality == BookQuality.Exceptional) - { - list.Add(1063341); // exceptional - } - - if (m_Crafter != null) - { - list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ - } - - if (!string.IsNullOrEmpty(m_Description)) - { - list.Add(m_Description); - } + NextUse = Core.Now + UseDelay; } + } - public override bool OnDragLift(Mobile from) + public override void OnAfterDuped(Item newItem) + { + if (newItem is not Runebook book) { - if (from.HasGump()) - { - from.SendLocalizedMessage(500169); // You cannot pick that up. - return false; - } + return; + } - foreach (var m in Openers) - { - if (IsOpen(m)) - { - m.CloseGump(); - } - } + book.Entries = new List(); + + for (var i = 0; i < Entries.Count; i++) + { + var entry = Entries[i]; - Openers.Clear(); + book.Entries.Add(new RunebookEntry(entry.Location, entry.Map, entry.Description, entry.House)); + } + } + public bool CheckAccess(Mobile m) + { + if (!IsLockedDown || m.AccessLevel >= AccessLevel.GameMaster) + { return true; } - public override void OnSingleClick(Mobile from) + var house = BaseHouse.FindHouseAt(this); + + return (house?.IsAosRules != true || house.Public && !house.IsBanned(m) || house.HasAccess(m)) && + house?.HasSecureAccess(m, Level) == true; + } + + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is RecallRune rune) { - if (m_Description?.Length > 0) + if (IsLockedDown && from.AccessLevel < AccessLevel.GameMaster) { - LabelTo(from, m_Description); + from.SendLocalizedMessage(502413, null, 0x35); // That cannot be done while the book is locked down. + return false; } - base.OnSingleClick(from); + if (IsOpen(from)) + { + from.SendLocalizedMessage(1005571); // You cannot place objects in the book while viewing the contents. + return false; + } - if (m_Crafter != null) + if (Entries.Count >= 16) { - LabelTo(from, 1050043, m_Crafter.Name); + from.SendLocalizedMessage(502401); // This runebook is full. + return false; } - } - public override void OnDoubleClick(Mobile from) - { - if (from.InRange(GetWorldLocation(), Core.ML ? 3 : 1) && CheckAccess(from)) + if (rune.Marked && rune.TargetMap != null) { - if (RootParent is BaseCreature) - { - from.SendLocalizedMessage(502402); // That is inaccessible. - return; - } + Entries.Add(new RunebookEntry(rune.Target, rune.TargetMap, rune.Description, rune.House)); - if (Core.Now < NextUse) - { - from.SendLocalizedMessage(502406); // This book needs time to recharge. - return; - } + rune.Delete(); - from.CloseGump(); - from.SendGump(new RunebookGump(from, this)); + from.SendSound(0x42, GetWorldLocation()); + from.SendMessage((rune.Description?.Trim()).DefaultIfNullOrEmpty("(indescript)")); - Openers.Add(from); + return true; } - } - public virtual void OnTravel() - { - if (!Core.SA) - { - NextUse = Core.Now + UseDelay; - } + from.SendLocalizedMessage(502409); // This rune does not have a marked location. + return false; } - public override void OnAfterDuped(Item newItem) + if (dropped is RecallScroll) { - if (newItem is not Runebook book) + if (CurCharges >= MaxCharges) { - return; + from.SendLocalizedMessage(502410); // This book already has the maximum amount of charges. + return false; } - book.Entries = new List(); + from.SendSound(0x249, GetWorldLocation()); - for (var i = 0; i < Entries.Count; i++) - { - var entry = Entries[i]; + var amount = dropped.Amount; - book.Entries.Add(new RunebookEntry(entry.Location, entry.Map, entry.Description, entry.House)); + if (amount > MaxCharges - CurCharges) + { + dropped.Consume(MaxCharges - CurCharges); + CurCharges = MaxCharges; } - } - - public bool CheckAccess(Mobile m) - { - if (!IsLockedDown || m.AccessLevel >= AccessLevel.GameMaster) + else { + CurCharges += amount; + dropped.Delete(); + return true; } + } - var house = BaseHouse.FindHouseAt(this); + return false; + } +} - return (house?.IsAosRules != true || house.Public && !house.IsBanned(m) || house.HasAccess(m)) && - house?.HasSecureAccess(m, Level) == true; - } +[ManualDirtyChecking] +public class RunebookEntry +{ + public RunebookEntry(Point3D loc, Map map, string description, BaseHouse house = null) + { + Location = loc; + Map = map; + Description = description; + House = house; + } - public override bool OnDragDrop(Mobile from, Item dropped) + public RunebookEntry(IGenericReader reader) + { + var version = reader.ReadByte(); + switch (version) { - if (dropped is RecallRune rune) - { - if (IsLockedDown && from.AccessLevel < AccessLevel.GameMaster) - { - from.SendLocalizedMessage(502413, null, 0x35); // That cannot be done while the book is locked down. - } - else if (IsOpen(from)) + case 1: { - from.SendLocalizedMessage(1005571); // You cannot place objects in the book while viewing the contents. + House = reader.ReadEntity(); + goto case 0; } - else if (Entries.Count < 16) + case 0: { - if (rune.Marked && rune.TargetMap != null) - { - Entries.Add(new RunebookEntry(rune.Target, rune.TargetMap, rune.Description, rune.House)); - - rune.Delete(); - - from.SendSound(0x42, GetWorldLocation()); + Location = reader.ReadPoint3D(); + Map = reader.ReadMap(); + Description = reader.ReadString(); - from.SendMessage((rune.Description?.Trim()).DefaultIfNullOrEmpty("(indescript)")); - - return true; - } - - from.SendLocalizedMessage(502409); // This rune does not have a marked location. - } - else - { - from.SendLocalizedMessage(502401); // This runebook is full. - } - } - else if (dropped is RecallScroll) - { - if (CurCharges < MaxCharges) - { - from.SendSound(0x249, GetWorldLocation()); - - var amount = dropped.Amount; - - if (amount > MaxCharges - CurCharges) - { - dropped.Consume(MaxCharges - CurCharges); - CurCharges = MaxCharges; - } - else - { - CurCharges += amount; - dropped.Delete(); - - return true; - } - } - else - { - from.SendLocalizedMessage(502410); // This book already has the maximum amount of charges. + break; } - } - - return false; } } - public class RunebookEntry + public void Serialize(IGenericWriter writer) { - public RunebookEntry(Point3D loc, Map map, string desc, BaseHouse house = null) + if (House?.Deleted == false) { - Location = loc; - Map = map; - Description = desc; - House = house; + writer.Write((byte)1); // version + writer.Write(House); } - - public RunebookEntry(IGenericReader reader) + else { - int version = reader.ReadByte(); - - switch (version) - { - case 1: - { - House = reader.ReadEntity(); - goto case 0; - } - case 0: - { - Location = reader.ReadPoint3D(); - Map = reader.ReadMap(); - Description = reader.ReadString(); - - break; - } - } + writer.Write((byte)0); // version } - public Point3D Location { get; } - - public Map Map { get; } - - public string Description { get; } + writer.Write(Location); + writer.Write(Map); + writer.Write(Description); + } - public BaseHouse House { get; } + public BaseHouse House { get; } - public void Serialize(IGenericWriter writer) - { - if (House?.Deleted == false) - { - writer.Write((byte)1); // version + public Point3D Location { get; } - writer.Write(House); - } - else - { - writer.Write((byte)0); // version - } + public Map Map { get; } - writer.Write(Location); - writer.Write(Map); - writer.Write(Description); - } - } + public string Description { get; } } diff --git a/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs b/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs index 4e61ee8702..7e712018d8 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using ModernUO.Serialization; using Server.Commands; using Server.Engines.Craft; using Server.Ethics; @@ -8,331 +9,313 @@ using Server.Spells; using Server.Targeting; -namespace Server.Items -{ - public enum SpellbookType - { - Invalid = -1, - Regular, - Necromancer, - Paladin, - Ninja, - Samurai, - Arcanist, - Mystic - } - - public enum BookQuality - { - Regular, - Exceptional - } - - public class Spellbook : Item, ICraftable, ISlayer, IAosItem - { - private static readonly Dictionary> m_Table = new(); - - private static readonly int[] m_LegendPropertyCounts = - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 21/52 : 40% - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 15/52 : 29% - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 2 properties : 10/52 : 19% - 3, 3, 3, 3, 3, 3 // 3 properties : 6/52 : 12% - }; +namespace Server.Items; - private static readonly int[] m_ElderPropertyCounts = - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 15/34 : 44% - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 10/34 : 29% - 2, 2, 2, 2, 2, 2, // 2 properties : 6/34 : 18% - 3, 3, 3 // 3 properties : 3/34 : 9% - }; +public enum SpellbookType +{ + Invalid = -1, + Regular, + Necromancer, + Paladin, + Ninja, + Samurai, + Arcanist, + Mystic +} - private static readonly int[] m_GrandPropertyCounts = - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 10/20 : 50% - 1, 1, 1, 1, 1, 1, // 1 property : 6/20 : 30% - 2, 2, 2, // 2 properties : 3/20 : 15% - 3 // 3 properties : 1/20 : 5% - }; +public enum BookQuality +{ + Regular, + Exceptional +} - private static readonly int[] m_MasterPropertyCounts = - { - 0, 0, 0, 0, 0, 0, // 0 properties : 6/10 : 60% - 1, 1, 1, // 1 property : 3/10 : 30% - 2 // 2 properties : 1/10 : 10% - }; +[SerializationGenerator(6, false)] +public partial class Spellbook : Item, ICraftable, ISlayer, IAosItem +{ + private static readonly Dictionary> _table = new(); - private static readonly int[] m_AdeptPropertyCounts = - { - 0, 0, 0, // 0 properties : 3/4 : 75% - 1 // 1 property : 1/4 : 25% - }; + private static readonly int[] _legendPropertyCounts = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 21/52 : 40% + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 15/52 : 29% + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 2 properties : 10/52 : 19% + 3, 3, 3, 3, 3, 3 // 3 properties : 6/52 : 12% + }; - private ulong m_Content; + private static readonly int[] _elderPropertyCounts = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 15/34 : 44% + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 property : 10/34 : 29% + 2, 2, 2, 2, 2, 2, // 2 properties : 6/34 : 18% + 3, 3, 3 // 3 properties : 3/34 : 9% + }; - private Mobile m_Crafter; - private string m_EngravedText; - private BookQuality m_Quality; + private static readonly int[] _grandPropertyCounts = + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 properties : 10/20 : 50% + 1, 1, 1, 1, 1, 1, // 1 property : 6/20 : 30% + 2, 2, 2, // 2 properties : 3/20 : 15% + 3 // 3 properties : 1/20 : 5% + }; - private SlayerName m_Slayer; - private SlayerName m_Slayer2; + private static readonly int[] _masterPropertyCounts = + { + 0, 0, 0, 0, 0, 0, // 0 properties : 6/10 : 60% + 1, 1, 1, // 1 property : 3/10 : 30% + 2 // 2 properties : 1/10 : 10% + }; - [Constructible] - public Spellbook(ulong content = 0, int itemID = 0xEFA) : base(itemID) - { - Attributes = new AosAttributes(this); - SkillBonuses = new AosSkillBonuses(this); + private static readonly int[] _adeptPropertyCounts = + { + 0, 0, 0, // 0 properties : 3/4 : 75% + 1 // 1 property : 1/4 : 25% + }; + + [InvalidateProperties] + [SerializableField(0)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private BookQuality _quality; + + [InvalidateProperties] + [SerializableField(1)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private string _engravedText; + + [InvalidateProperties] + [SerializableField(2)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private string _crafter; + + [InvalidateProperties] + [SerializableField(3)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private SlayerName _slayer; + + [InvalidateProperties] + [SerializableField(4)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private SlayerName _slayer2; + + [SerializableField(5, setter: "private")] + [SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)] + private AosAttributes _attributes; + + [SerializableField(6, setter: "private")] + [SerializedCommandProperty(AccessLevel.GameMaster, canModify: true)] + private AosSkillBonuses _skillBonuses; + + [SerializableField(8)] + [SerializedCommandProperty(AccessLevel.GameMaster)] + private int _spellCount; + + [Constructible] + public Spellbook(ulong content = 0, int itemID = 0xEFA) : base(itemID) + { + _attributes = new AosAttributes(this); + _skillBonuses = new AosSkillBonuses(this); - Weight = 3.0; - Layer = Layer.OneHanded; - LootType = LootType.Blessed; + Weight = 3.0; + Layer = Layer.OneHanded; + LootType = LootType.Blessed; - Content = content; - } + _content = content; + } - public Spellbook(Serial serial) : base(serial) - { - } + public override bool DisplayWeight => false; - [CommandProperty(AccessLevel.GameMaster)] - public string EngravedText - { - get => m_EngravedText; - set - { - m_EngravedText = value; - InvalidateProperties(); - } - } + public virtual SpellbookType SpellbookType => SpellbookType.Regular; + public virtual int BookOffset => 0; + public virtual int BookCount => 64; - [CommandProperty(AccessLevel.GameMaster)] - public BookQuality Quality + [CommandProperty(AccessLevel.GameMaster)] + [SerializableProperty(7)] + public ulong Content + { + get => _content; + set { - get => m_Quality; - set + if (_content != value) { - m_Quality = value; - InvalidateProperties(); - } - } - - public override bool DisplayWeight => false; - - [CommandProperty(AccessLevel.GameMaster, canModify: true)] - public AosAttributes Attributes { get; private set; } + _content = value; - [CommandProperty(AccessLevel.GameMaster, canModify: true)] - public AosSkillBonuses SkillBonuses { get; private set; } + // This assignment will mark it as dirty + SpellCount = 0; - public virtual SpellbookType SpellbookType => SpellbookType.Regular; - public virtual int BookOffset => 0; - public virtual int BookCount => 64; - - [CommandProperty(AccessLevel.GameMaster)] - public ulong Content - { - get => m_Content; - set - { - if (m_Content != value) + while (value > 0) { - m_Content = value; - - SpellCount = 0; - - while (value > 0) - { - SpellCount += (int)(value & 0x1); - value >>= 1; - } - - InvalidateProperties(); + _spellCount += (int)(value & 0x1); + value >>= 1; } - } - } - - [CommandProperty(AccessLevel.GameMaster)] - public int SpellCount { get; private set; } - [CommandProperty(AccessLevel.GameMaster)] - public Mobile Crafter - { - get => m_Crafter; - set - { - m_Crafter = value; InvalidateProperties(); } } + } - public override bool DisplayLootType => Core.AOS; + public override bool DisplayLootType => Core.AOS; - public virtual int OnCraft( - int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, - BaseTool tool, CraftItem craftItem, int resHue - ) + public virtual int OnCraft( + int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, + BaseTool tool, CraftItem craftItem, int resHue + ) + { + var magery = from.Skills.Magery.BaseFixedPoint; + + if (magery >= 800) { - var magery = from.Skills.Magery.BaseFixedPoint; + int[] propertyCounts; + int minIntensity; + int maxIntensity; - if (magery >= 800) + if (magery >= 1000) { - int[] propertyCounts; - int minIntensity; - int maxIntensity; - - if (magery >= 1000) + if (magery >= 1200) { - if (magery >= 1200) - { - propertyCounts = m_LegendPropertyCounts; - } - else if (magery >= 1100) - { - propertyCounts = m_ElderPropertyCounts; - } - else - { - propertyCounts = m_GrandPropertyCounts; - } - - minIntensity = 55; - maxIntensity = 75; + propertyCounts = _legendPropertyCounts; } - else if (magery >= 900) + else if (magery >= 1100) { - propertyCounts = m_MasterPropertyCounts; - minIntensity = 25; - maxIntensity = 45; + propertyCounts = _elderPropertyCounts; } else { - propertyCounts = m_AdeptPropertyCounts; - minIntensity = 0; - maxIntensity = 15; + propertyCounts = _grandPropertyCounts; } - var propertyCount = propertyCounts.RandomElement(); - - BaseRunicTool.ApplyAttributesTo(this, true, 0, propertyCount, minIntensity, maxIntensity); + minIntensity = 55; + maxIntensity = 75; } - - if (makersMark) + else if (magery >= 900) + { + propertyCounts = _masterPropertyCounts; + minIntensity = 25; + maxIntensity = 45; + } + else { - Crafter = from; + propertyCounts = _adeptPropertyCounts; + minIntensity = 0; + maxIntensity = 15; } - m_Quality = (BookQuality)(quality - 1); + var propertyCount = propertyCounts.RandomElement(); - return quality; + BaseRunicTool.ApplyAttributesTo(this, true, 0, propertyCount, minIntensity, maxIntensity); } - // Currently though there are no dual slayer spellbooks, OSI has a habit of putting dual slayer stuff in later - [CommandProperty(AccessLevel.GameMaster)] - public SlayerName Slayer + if (makersMark) { - get => m_Slayer; - set - { - m_Slayer = value; - InvalidateProperties(); - } + Crafter = from.RawName; } - [CommandProperty(AccessLevel.GameMaster)] - public SlayerName Slayer2 - { - get => m_Slayer2; - set - { - m_Slayer2 = value; - InvalidateProperties(); - } - } + Quality = (BookQuality)(quality - 1); + return quality; + } + + public static void Initialize() + { + EventSink.OpenSpellbookRequest += EventSink_OpenSpellbookRequest; + EventSink.CastSpellRequest += EventSink_CastSpellRequest; + EventSink.TargetedSpell += EventSink_TargetedSpell; + + CommandSystem.Register("AllSpells", AccessLevel.GameMaster, AllSpells_OnCommand); + } - public static void Initialize() + [Usage("AllSpells"), Description("Completely fills a targeted spellbook with scrolls.")] + private static void AllSpells_OnCommand(CommandEventArgs e) + { + e.Mobile.BeginTarget(-1, false, TargetFlags.None, AllSpells_OnTarget); + e.Mobile.SendMessage("Target the spellbook to fill."); + } + + private static void AllSpells_OnTarget(Mobile from, object obj) + { + if (obj is Spellbook book) { - EventSink.OpenSpellbookRequest += EventSink_OpenSpellbookRequest; - EventSink.CastSpellRequest += EventSink_CastSpellRequest; - EventSink.TargetedSpell += EventSink_TargetedSpell; + book.Content = book.BookCount == 64 ? ulong.MaxValue : (1ul << book.BookCount) - 1; - CommandSystem.Register("AllSpells", AccessLevel.GameMaster, AllSpells_OnCommand); + from.SendMessage("The spellbook has been filled."); + + CommandLogging.WriteLine( + from, + $"{from.AccessLevel} {CommandLogging.Format(from)} filling spellbook {CommandLogging.Format(book)}" + ); + } + else + { + from.BeginTarget(-1, false, TargetFlags.None, AllSpells_OnTarget); + from.SendMessage("That is not a spellbook. Try again."); } + } - [Usage("AllSpells"), Description("Completely fills a targeted spellbook with scrolls.")] - private static void AllSpells_OnCommand(CommandEventArgs e) + private static void EventSink_OpenSpellbookRequest(Mobile from, int typeID) + { + if (!DesignContext.Check(from)) { - e.Mobile.BeginTarget(-1, false, TargetFlags.None, AllSpells_OnTarget); - e.Mobile.SendMessage("Target the spellbook to fill."); + return; // They are customizing } - private static void AllSpells_OnTarget(Mobile from, object obj) + var type = typeID switch { - if (obj is Spellbook book) - { - if (book.BookCount == 64) - { - book.Content = ulong.MaxValue; - } - else - { - book.Content = (1ul << book.BookCount) - 1; - } + 1 => SpellbookType.Regular, + 2 => SpellbookType.Necromancer, + 3 => SpellbookType.Paladin, + 4 => SpellbookType.Ninja, + 5 => SpellbookType.Samurai, + 6 => SpellbookType.Arcanist, + 7 => SpellbookType.Mystic, + _ => SpellbookType.Regular + }; - from.SendMessage("The spellbook has been filled."); + var book = Find(from, -1, type); - CommandLogging.WriteLine( - from, - $"{from.AccessLevel} {CommandLogging.Format(from)} filling spellbook {CommandLogging.Format(book)}" - ); - } - else - { - from.BeginTarget(-1, false, TargetFlags.None, AllSpells_OnTarget); - from.SendMessage("That is not a spellbook. Try again."); - } - } + book?.DisplayTo(from); + } - private static void EventSink_OpenSpellbookRequest(Mobile from, int typeID) + private static void EventSink_TargetedSpell(Mobile from, IEntity target, int spellId) + { + if (!DesignContext.Check(from)) { - if (!DesignContext.Check(from)) - { - return; // They are customizing - } + return; // They are customizing + } - var type = typeID switch - { - 1 => SpellbookType.Regular, - 2 => SpellbookType.Necromancer, - 3 => SpellbookType.Paladin, - 4 => SpellbookType.Ninja, - 5 => SpellbookType.Samurai, - 6 => SpellbookType.Arcanist, - 7 => SpellbookType.Mystic, - _ => SpellbookType.Regular - }; + var book = Find(from, spellId); + + if (book?.HasSpell(spellId) != true) + { + from.SendLocalizedMessage(500015); // You do not have that spell! + return; + } - var book = Find(from, -1, type); + var move = SpellRegistry.GetSpecialMove(spellId); - book?.DisplayTo(from); + if (move != null) + { + SpecialMove.SetCurrentMove(from, move); } + else + { + SpellRegistry.NewSpell(spellId, from, null)?.Cast(); + } + } - private static void EventSink_TargetedSpell(Mobile from, IEntity target, int spellId) + private static void EventSink_CastSpellRequest(Mobile from, int spellID, Item item) + { + if (!DesignContext.Check(from)) { - if (!DesignContext.Check(from)) - { - return; // They are customizing - } + return; // They are customizing + } - var book = Find(from, spellId); + var book = item as Spellbook; - if (book?.HasSpell(spellId) != true) - { - from.SendLocalizedMessage(500015); // You do not have that spell! - return; - } + if (book?.HasSpell(spellID) != true) + { + book = Find(from, spellID); + } - var move = SpellRegistry.GetSpecialMove(spellId); + if (book?.HasSpell(spellID) == true) + { + var move = SpellRegistry.GetSpecialMove(spellID); if (move != null) { @@ -340,650 +323,558 @@ private static void EventSink_TargetedSpell(Mobile from, IEntity target, int spe } else { - SpellRegistry.NewSpell(spellId, from, null)?.Cast(); - } - } - - private static void EventSink_CastSpellRequest(Mobile from, int spellID, Item item) - { - if (!DesignContext.Check(from)) - { - return; // They are customizing - } - - var book = item as Spellbook; - - if (book?.HasSpell(spellID) != true) - { - book = Find(from, spellID); - } - - if (book?.HasSpell(spellID) == true) - { - var move = SpellRegistry.GetSpecialMove(spellID); + var spell = SpellRegistry.NewSpell(spellID, from, null); - if (move != null) + if (spell != null) { - SpecialMove.SetCurrentMove(from, move); + spell.Cast(); } else { - var spell = SpellRegistry.NewSpell(spellID, from, null); - - if (spell != null) - { - spell.Cast(); - } - else - { - from.SendLocalizedMessage(502345); // This spell has been temporarily disabled. - } + from.SendLocalizedMessage(502345); // This spell has been temporarily disabled. } } - else - { - from.SendLocalizedMessage(500015); // You do not have that spell! - } } - - public static SpellbookType GetTypeForSpell(int spellID) + else { - if (spellID >= 0 && spellID < 64) - { - return SpellbookType.Regular; - } - - if (spellID >= 100 && spellID < 117) - { - return SpellbookType.Necromancer; - } - - if (spellID >= 200 && spellID < 210) - { - return SpellbookType.Paladin; - } - - if (spellID >= 400 && spellID < 406) - { - return SpellbookType.Samurai; - } - - if (spellID >= 500 && spellID < 508) - { - return SpellbookType.Ninja; - } - - if (spellID >= 600 && spellID < 617) - { - return SpellbookType.Arcanist; - } - - if (spellID >= 677 && spellID < 693) - { - return SpellbookType.Mystic; - } + from.SendLocalizedMessage(500015); // You do not have that spell! + } + } - return SpellbookType.Invalid; + public static SpellbookType GetTypeForSpell(int spellID) + { + if (spellID >= 0 && spellID < 64) + { + return SpellbookType.Regular; } - public static Spellbook FindRegular(Mobile from) => Find(from, -1, SpellbookType.Regular); + if (spellID >= 100 && spellID < 117) + { + return SpellbookType.Necromancer; + } - public static Spellbook FindNecromancer(Mobile from) => Find(from, -1, SpellbookType.Necromancer); + if (spellID >= 200 && spellID < 210) + { + return SpellbookType.Paladin; + } - public static Spellbook FindPaladin(Mobile from) => Find(from, -1, SpellbookType.Paladin); + if (spellID >= 400 && spellID < 406) + { + return SpellbookType.Samurai; + } - public static Spellbook FindSamurai(Mobile from) => Find(from, -1, SpellbookType.Samurai); + if (spellID >= 500 && spellID < 508) + { + return SpellbookType.Ninja; + } - public static Spellbook FindNinja(Mobile from) => Find(from, -1, SpellbookType.Ninja); + if (spellID >= 600 && spellID < 617) + { + return SpellbookType.Arcanist; + } - public static Spellbook FindArcanist(Mobile from) => Find(from, -1, SpellbookType.Arcanist); + if (spellID >= 677 && spellID < 693) + { + return SpellbookType.Mystic; + } - public static Spellbook FindMystic(Mobile from) => Find(from, -1, SpellbookType.Mystic); + return SpellbookType.Invalid; + } - public static Spellbook Find(Mobile from, int spellID) => Find(from, spellID, GetTypeForSpell(spellID)); + public static Spellbook FindRegular(Mobile from) => Find(from, -1, SpellbookType.Regular); - public static Spellbook Find(Mobile from, int spellID, SpellbookType type) - { - if (from == null) - { - return null; - } + public static Spellbook FindNecromancer(Mobile from) => Find(from, -1, SpellbookType.Necromancer); - if (from.Deleted) - { - m_Table.Remove(from); - return null; - } + public static Spellbook FindPaladin(Mobile from) => Find(from, -1, SpellbookType.Paladin); - var searchAgain = false; + public static Spellbook FindSamurai(Mobile from) => Find(from, -1, SpellbookType.Samurai); - if (!m_Table.TryGetValue(from, out var list)) - { - m_Table[from] = list = FindAllSpellbooks(from); - } - else - { - searchAgain = true; - } + public static Spellbook FindNinja(Mobile from) => Find(from, -1, SpellbookType.Ninja); - var book = FindSpellbookInList(list, from, spellID, type); + public static Spellbook FindArcanist(Mobile from) => Find(from, -1, SpellbookType.Arcanist); - if (book == null && searchAgain) - { - m_Table[from] = list = FindAllSpellbooks(from); + public static Spellbook FindMystic(Mobile from) => Find(from, -1, SpellbookType.Mystic); - book = FindSpellbookInList(list, from, spellID, type); - } + public static Spellbook Find(Mobile from, int spellID) => Find(from, spellID, GetTypeForSpell(spellID)); - return book; + public static Spellbook Find(Mobile from, int spellID, SpellbookType type) + { + if (from == null) + { + return null; } - public static Spellbook FindSpellbookInList(List list, Mobile from, int spellID, SpellbookType type) + if (from.Deleted) { - var pack = from.Backpack; + _table.Remove(from); + return null; + } - for (var i = list.Count - 1; i >= 0; --i) - { - if (i >= list.Count) - { - continue; - } + var searchAgain = false; - var book = list[i]; + if (!_table.TryGetValue(from, out var list)) + { + _table[from] = list = FindAllSpellbooks(from); + } + else + { + searchAgain = true; + } - if (!book.Deleted && (book.Parent == from || pack != null && book.Parent == pack) && - ValidateSpellbook(book, spellID, type)) - { - return book; - } + var book = FindSpellbookInList(list, from, spellID, type); - list.RemoveAt(i); - } + if (book == null && searchAgain) + { + _table[from] = list = FindAllSpellbooks(from); - return null; + book = FindSpellbookInList(list, from, spellID, type); } - public static List FindAllSpellbooks(Mobile from) - { - var list = new List(); + return book; + } - var spellbook = FindEquippedSpellbook(from); + public static Spellbook FindSpellbookInList(List list, Mobile from, int spellID, SpellbookType type) + { + var pack = from.Backpack; - if (spellbook != null) + for (var i = list.Count - 1; i >= 0; --i) + { + if (i >= list.Count) { - list.Add(spellbook); + continue; } - var pack = from.Backpack; + var book = list[i]; - for (var i = 0; i < pack?.Items.Count; ++i) + if (!book.Deleted && (book.Parent == from || pack != null && book.Parent == pack) && + ValidateSpellbook(book, spellID, type)) { - if (pack.Items[i] is Spellbook sp) - { - list.Add(sp); - } + return book; } - return list; + list.RemoveAt(i); } - public static Spellbook FindEquippedSpellbook(Mobile from) => from.FindItemOnLayer(Layer.OneHanded); + return null; + } - public static bool ValidateSpellbook(Spellbook book, int spellID, SpellbookType type) => - book.SpellbookType == type && (spellID == -1 || book.HasSpell(spellID)); + public static List FindAllSpellbooks(Mobile from) + { + var list = new List(); - public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) => - Ethic.CheckTrade(from, to, newOwner, this) && base.AllowSecureTrade(from, to, newOwner, accepted); + var spellbook = FindEquippedSpellbook(from); - public override bool CanEquip(Mobile from) + if (spellbook != null) { - if (!Ethic.CheckEquip(from, this)) - { - return false; - } - - if (!from.CanBeginAction()) - { - return false; - } - - return base.CanEquip(from); + list.Add(spellbook); } - public override bool AllowEquippedCast(Mobile from) => true; + var pack = from.Backpack; - public override bool OnDragDrop(Mobile from, Item dropped) + for (var i = 0; i < pack?.Items.Count; ++i) { - if (dropped is not SpellScroll { Amount: 1 } scroll) + if (pack.Items[i] is Spellbook sp) { - return false; - } - - var type = GetTypeForSpell(scroll.SpellID); - - if (type != SpellbookType) - { - return false; + list.Add(sp); } + } - if (HasSpell(scroll.SpellID)) - { - from.SendLocalizedMessage(500179); // That spell is already present in that spellbook. - return false; - } + return list; + } - var val = scroll.SpellID - BookOffset; + public static Spellbook FindEquippedSpellbook(Mobile from) => from.FindItemOnLayer(Layer.OneHanded); - if (val >= 0 && val < BookCount) - { - m_Content |= (ulong)1 << val; - ++SpellCount; + public static bool ValidateSpellbook(Spellbook book, int spellID, SpellbookType type) => + book.SpellbookType == type && (spellID == -1 || book.HasSpell(spellID)); - InvalidateProperties(); + public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted) => + Ethic.CheckTrade(from, to, newOwner, this) && base.AllowSecureTrade(from, to, newOwner, accepted); - scroll.Delete(); + public override bool CanEquip(Mobile from) => + Ethic.CheckEquip(from, this) && from.CanBeginAction() && base.CanEquip(from); - from.SendSound(0x249, GetWorldLocation()); - return true; - } + public override bool AllowEquippedCast(Mobile from) => true; + public override bool OnDragDrop(Mobile from, Item dropped) + { + if (dropped is not SpellScroll { Amount: 1 } scroll) + { return false; } - public override void OnAfterDuped(Item newItem) - { - if (newItem is not Spellbook book) - { - return; - } + var type = GetTypeForSpell(scroll.SpellID); - book.Attributes = new AosAttributes(newItem, Attributes); - book.SkillBonuses = new AosSkillBonuses(newItem, SkillBonuses); + if (type != SpellbookType) + { + return false; } - public override void OnAdded(IEntity parent) + if (HasSpell(scroll.SpellID)) { - if (Core.AOS && parent is Mobile from) - { - SkillBonuses.AddTo(from); - - var strBonus = Attributes.BonusStr; - var dexBonus = Attributes.BonusDex; - var intBonus = Attributes.BonusInt; - - if (strBonus != 0 || dexBonus != 0 || intBonus != 0) - { - var serial = Serial; - - if (strBonus != 0) - { - from.AddStatMod(new StatMod(StatType.Str, $"{serial}Str", strBonus, TimeSpan.Zero)); - } - - if (dexBonus != 0) - { - from.AddStatMod(new StatMod(StatType.Dex, $"{serial}Dex", dexBonus, TimeSpan.Zero)); - } - - if (intBonus != 0) - { - from.AddStatMod(new StatMod(StatType.Int, $"{serial}Int", intBonus, TimeSpan.Zero)); - } - } - - from.CheckStatTimers(); - } + from.SendLocalizedMessage(500179); // That spell is already present in that spellbook. + return false; } - public override void OnRemoved(IEntity parent) + var val = scroll.SpellID - BookOffset; + + if (val >= 0 && val < BookCount) { - if (Core.AOS && parent is Mobile from) - { - SkillBonuses.Remove(); + _content |= (ulong)1 << val; + ++SpellCount; - var serial = Serial; + InvalidateProperties(); - from.RemoveStatMod($"{serial}Str"); - from.RemoveStatMod($"{serial}Dex"); - from.RemoveStatMod($"{serial}Int"); + scroll.Delete(); - from.CheckStatTimers(); - } + from.SendSound(0x249, GetWorldLocation()); + return true; } - public bool HasSpell(int spellID) - { - spellID -= BookOffset; + return false; + } - return spellID >= 0 && spellID < BookCount && (m_Content & ((ulong)1 << spellID)) != 0; + public override void OnAfterDuped(Item newItem) + { + if (newItem is not Spellbook book) + { + return; } - public void DisplayTo(Mobile to) + book.Attributes = new AosAttributes(newItem, _attributes); + book.SkillBonuses = new AosSkillBonuses(newItem, _skillBonuses); + book.Content = _content; + book.SpellCount = _spellCount; + book.Slayer = _slayer; + book.Slayer2 = _slayer2; + book.Quality = _quality; + book.EngravedText = _engravedText; + book.Crafter = _crafter; + } + + public override void OnAdded(IEntity parent) + { + if (Core.AOS && parent is Mobile from) { - // The client must know about the spellbook or it will crash! - var ns = to.NetState; + SkillBonuses.AddTo(from); - if (ns.CannotSendPackets()) - { - return; - } + var strBonus = Attributes.BonusStr; + var dexBonus = Attributes.BonusDex; + var intBonus = Attributes.BonusInt; - if (Parent == null) - { - SendWorldPacketTo(to.NetState); - } - else if (Parent is Item) + if (strBonus != 0 || dexBonus != 0 || intBonus != 0) { - to.NetState.SendContainerContentUpdate(this); - } - else if (Parent is Mobile) - { - to.NetState.SendEquipUpdate(this); + var serial = Serial; + + if (strBonus != 0) + { + from.AddStatMod(new StatMod(StatType.Str, $"{serial}Str", strBonus, TimeSpan.Zero)); + } + + if (dexBonus != 0) + { + from.AddStatMod(new StatMod(StatType.Dex, $"{serial}Dex", dexBonus, TimeSpan.Zero)); + } + + if (intBonus != 0) + { + from.AddStatMod(new StatMod(StatType.Int, $"{serial}Int", intBonus, TimeSpan.Zero)); + } } - to.NetState.SendDisplaySpellbook(Serial); - to.NetState.SendSpellbookContent(Serial, ItemID, BookOffset + 1, m_Content); + from.CheckStatTimers(); } + } - public override void GetProperties(IPropertyList list) + public override void OnRemoved(IEntity parent) + { + if (Core.AOS && parent is Mobile from) { - base.GetProperties(list); + SkillBonuses.Remove(); - if (m_Quality == BookQuality.Exceptional) - { - list.Add(1063341); // exceptional - } + var serial = Serial; - if (m_EngravedText != null) - { - list.Add(1072305, m_EngravedText); // Engraved: ~1_INSCRIPTION~ - } - - if (m_Crafter != null) - { - list.Add(1050043, m_Crafter.Name); // crafted by ~1_NAME~ - } + from.RemoveStatMod($"{serial}Str"); + from.RemoveStatMod($"{serial}Dex"); + from.RemoveStatMod($"{serial}Int"); - SkillBonuses.GetProperties(list); + from.CheckStatTimers(); + } + } - if (m_Slayer != SlayerName.None) - { - var entry = SlayerGroup.GetEntryByName(m_Slayer); - if (entry != null) - { - list.Add(entry.Title); - } - } + public bool HasSpell(int spellID) + { + spellID -= BookOffset; - if (m_Slayer2 != SlayerName.None) - { - var entry = SlayerGroup.GetEntryByName(m_Slayer2); - if (entry != null) - { - list.Add(entry.Title); - } - } + return spellID >= 0 && spellID < BookCount && (_content & ((ulong)1 << spellID)) != 0; + } - int prop; + public void DisplayTo(Mobile to) + { + // The client must know about the spellbook or it will crash! + var ns = to.NetState; - if ((prop = Attributes.WeaponDamage) != 0) - { - list.Add(1060401, prop); // damage increase ~1_val~% - } + if (ns.CannotSendPackets()) + { + return; + } - if ((prop = Attributes.DefendChance) != 0) - { - list.Add(1060408, prop); // defense chance increase ~1_val~% - } + if (Parent == null) + { + SendWorldPacketTo(to.NetState); + } + else if (Parent is Item) + { + to.NetState.SendContainerContentUpdate(this); + } + else if (Parent is Mobile) + { + to.NetState.SendEquipUpdate(this); + } - if ((prop = Attributes.BonusDex) != 0) - { - list.Add(1060409, prop); // dexterity bonus ~1_val~ - } + to.NetState.SendDisplaySpellbook(Serial); + to.NetState.SendSpellbookContent(Serial, ItemID, BookOffset + 1, _content); + } - if ((prop = Attributes.EnhancePotions) != 0) - { - list.Add(1060411, prop); // enhance potions ~1_val~% - } + public override void GetProperties(IPropertyList list) + { + base.GetProperties(list); - if ((prop = Attributes.CastRecovery) != 0) - { - list.Add(1060412, prop); // faster cast recovery ~1_val~ - } + if (_quality == BookQuality.Exceptional) + { + list.Add(1063341); // exceptional + } - if ((prop = Attributes.CastSpeed) != 0) - { - list.Add(1060413, prop); // faster casting ~1_val~ - } + if (_engravedText != null) + { + list.Add(1072305, _engravedText); // Engraved: ~1_INSCRIPTION~ + } - if ((prop = Attributes.AttackChance) != 0) - { - list.Add(1060415, prop); // hit chance increase ~1_val~% - } + if (_crafter != null) + { + list.Add(1050043, _crafter); // crafted by ~1_NAME~ + } - if ((prop = Attributes.BonusHits) != 0) - { - list.Add(1060431, prop); // hit point increase ~1_val~ - } + _skillBonuses.GetProperties(list); - if ((prop = Attributes.BonusInt) != 0) + if (_slayer != SlayerName.None) + { + var entry = SlayerGroup.GetEntryByName(_slayer); + if (entry != null) { - list.Add(1060432, prop); // intelligence bonus ~1_val~ + list.Add(entry.Title); } + } - if ((prop = Attributes.LowerManaCost) != 0) + if (_slayer2 != SlayerName.None) + { + var entry = SlayerGroup.GetEntryByName(_slayer2); + if (entry != null) { - list.Add(1060433, prop); // lower mana cost ~1_val~% + list.Add(entry.Title); } + } - if ((prop = Attributes.LowerRegCost) != 0) - { - list.Add(1060434, prop); // lower reagent cost ~1_val~% - } + int prop; - if ((prop = Attributes.Luck) != 0) - { - list.Add(1060436, prop); // luck ~1_val~ - } + if ((prop = _attributes.WeaponDamage) != 0) + { + list.Add(1060401, prop); // damage increase ~1_val~% + } - if ((prop = Attributes.BonusMana) != 0) - { - list.Add(1060439, prop); // mana increase ~1_val~ - } + if ((prop = _attributes.DefendChance) != 0) + { + list.Add(1060408, prop); // defense chance increase ~1_val~% + } - if ((prop = Attributes.RegenMana) != 0) - { - list.Add(1060440, prop); // mana regeneration ~1_val~ - } + if ((prop = _attributes.BonusDex) != 0) + { + list.Add(1060409, prop); // dexterity bonus ~1_val~ + } - if (Attributes.NightSight != 0) - { - list.Add(1060441); // night sight - } + if ((prop = _attributes.EnhancePotions) != 0) + { + list.Add(1060411, prop); // enhance potions ~1_val~% + } - if ((prop = Attributes.ReflectPhysical) != 0) - { - list.Add(1060442, prop); // reflect physical damage ~1_val~% - } + if ((prop = _attributes.CastRecovery) != 0) + { + list.Add(1060412, prop); // faster cast recovery ~1_val~ + } - if ((prop = Attributes.RegenStam) != 0) - { - list.Add(1060443, prop); // stamina regeneration ~1_val~ - } + if ((prop = _attributes.CastSpeed) != 0) + { + list.Add(1060413, prop); // faster casting ~1_val~ + } - if ((prop = Attributes.RegenHits) != 0) - { - list.Add(1060444, prop); // hit point regeneration ~1_val~ - } + if ((prop = _attributes.AttackChance) != 0) + { + list.Add(1060415, prop); // hit chance increase ~1_val~% + } - if (Attributes.SpellChanneling != 0) - { - list.Add(1060482); // spell channeling - } + if ((prop = _attributes.BonusHits) != 0) + { + list.Add(1060431, prop); // hit point increase ~1_val~ + } - if ((prop = Attributes.SpellDamage) != 0) - { - list.Add(1060483, prop); // spell damage increase ~1_val~% - } + if ((prop = _attributes.BonusInt) != 0) + { + list.Add(1060432, prop); // intelligence bonus ~1_val~ + } - if ((prop = Attributes.BonusStam) != 0) - { - list.Add(1060484, prop); // stamina increase ~1_val~ - } + if ((prop = _attributes.LowerManaCost) != 0) + { + list.Add(1060433, prop); // lower mana cost ~1_val~% + } - if ((prop = Attributes.BonusStr) != 0) - { - list.Add(1060485, prop); // strength bonus ~1_val~ - } + if ((prop = _attributes.LowerRegCost) != 0) + { + list.Add(1060434, prop); // lower reagent cost ~1_val~% + } - if ((prop = Attributes.WeaponSpeed) != 0) - { - list.Add(1060486, prop); // swing speed increase ~1_val~% - } + if ((prop = _attributes.Luck) != 0) + { + list.Add(1060436, prop); // luck ~1_val~ + } - if (Core.ML && (prop = Attributes.IncreasedKarmaLoss) != 0) - { - list.Add(1075210, prop); // Increased Karma Loss ~1val~% - } + if ((prop = _attributes.BonusMana) != 0) + { + list.Add(1060439, prop); // mana increase ~1_val~ + } - list.Add(1042886, SpellCount); // ~1_NUMBERS_OF_SPELLS~ Spells + if ((prop = _attributes.RegenMana) != 0) + { + list.Add(1060440, prop); // mana regeneration ~1_val~ } - public override void OnSingleClick(Mobile from) + if (_attributes.NightSight != 0) { - base.OnSingleClick(from); + list.Add(1060441); // night sight + } - if (m_Crafter != null) - { - LabelTo(from, 1050043, m_Crafter.Name); // crafted by ~1_NAME~ - } + if ((prop = _attributes.ReflectPhysical) != 0) + { + list.Add(1060442, prop); // reflect physical damage ~1_val~% + } - LabelTo(from, 1042886, SpellCount.ToString()); + if ((prop = _attributes.RegenStam) != 0) + { + list.Add(1060443, prop); // stamina regeneration ~1_val~ } - public override void OnDoubleClick(Mobile from) + if ((prop = _attributes.RegenHits) != 0) { - var pack = from.Backpack; + list.Add(1060444, prop); // hit point regeneration ~1_val~ + } - if (Parent == from || pack != null && Parent == pack) - { - DisplayTo(from); - } - else - { - from.SendLocalizedMessage( - 500207 - ); // The spellbook must be in your backpack (and not in a container within) to open. - } + if (_attributes.SpellChanneling != 0) + { + list.Add(1060482); // spell channeling } - public override void Serialize(IGenericWriter writer) + if ((prop = _attributes.SpellDamage) != 0) { - base.Serialize(writer); + list.Add(1060483, prop); // spell damage increase ~1_val~% + } - writer.Write(5); // version + if ((prop = _attributes.BonusStam) != 0) + { + list.Add(1060484, prop); // stamina increase ~1_val~ + } - writer.Write((byte)m_Quality); + if ((prop = _attributes.BonusStr) != 0) + { + list.Add(1060485, prop); // strength bonus ~1_val~ + } - writer.Write(m_EngravedText); + if ((prop = _attributes.WeaponSpeed) != 0) + { + list.Add(1060486, prop); // swing speed increase ~1_val~% + } - writer.Write(m_Crafter); + if (Core.ML && (prop = _attributes.IncreasedKarmaLoss) != 0) + { + list.Add(1075210, prop); // Increased Karma Loss ~1val~% + } - writer.Write((int)m_Slayer); - writer.Write((int)m_Slayer2); + list.Add(1042886, _spellCount); // ~1_NUMBERS_OF_SPELLS~ Spells + } - Attributes.Serialize(writer); - SkillBonuses.Serialize(writer); + public override void OnSingleClick(Mobile from) + { + base.OnSingleClick(from); - writer.Write(m_Content); - writer.Write(SpellCount); + if (_crafter != null) + { + LabelTo(from, 1050043, _crafter); // crafted by ~1_NAME~ } - public override void Deserialize(IGenericReader reader) + LabelTo(from, 1042886, _spellCount.ToString()); + } + + public override void OnDoubleClick(Mobile from) + { + var pack = from.Backpack; + + if (Parent == from || pack != null && Parent == pack) { - base.Deserialize(reader); + DisplayTo(from); + } + else + { + from.SendLocalizedMessage( + 500207 + ); // The spellbook must be in your backpack (and not in a container within) to open. + } + } - var version = reader.ReadInt(); + private void Deserialize(IGenericReader reader, int version) + { + _quality = (BookQuality)reader.ReadByte(); + _engravedText = reader.ReadString(); + _crafter = reader.ReadEntity()?.RawName; + _slayer = (SlayerName)reader.ReadInt(); + _slayer2 = (SlayerName)reader.ReadInt(); - switch (version) - { - case 5: - { - m_Quality = (BookQuality)reader.ReadByte(); - - goto case 4; - } - case 4: - { - m_EngravedText = reader.ReadString(); - - goto case 3; - } - case 3: - { - m_Crafter = reader.ReadEntity(); - goto case 2; - } - case 2: - { - m_Slayer = (SlayerName)reader.ReadInt(); - m_Slayer2 = (SlayerName)reader.ReadInt(); - goto case 1; - } - case 1: - { - Attributes = new AosAttributes(this); - Attributes.Deserialize(reader); - SkillBonuses = new AosSkillBonuses(this); - SkillBonuses.Deserialize(reader); - - goto case 0; - } - case 0: - { - m_Content = reader.ReadULong(); - SpellCount = reader.ReadInt(); - - break; - } - } + _attributes = new AosAttributes(this); + _attributes.Deserialize(reader); + _skillBonuses = new AosSkillBonuses(this); + _skillBonuses.Deserialize(reader); - Attributes ??= new AosAttributes(this); - SkillBonuses ??= new AosSkillBonuses(this); + _content = reader.ReadULong(); + _spellCount = reader.ReadInt(); - if (Core.AOS && Parent is Mobile mobile) - { - SkillBonuses.AddTo(mobile); - } + if (Core.AOS && Parent is Mobile mobile) + { + _skillBonuses.AddTo(mobile); + } - var strBonus = Attributes.BonusStr; - var dexBonus = Attributes.BonusDex; - var intBonus = Attributes.BonusInt; + var strBonus = _attributes.BonusStr; + var dexBonus = _attributes.BonusDex; + var intBonus = _attributes.BonusInt; - if (Parent is Mobile m) + if (Parent is Mobile m) + { + if (strBonus != 0 || dexBonus != 0 || intBonus != 0) { - if (strBonus != 0 || dexBonus != 0 || intBonus != 0) + var serial = Serial; + + if (strBonus != 0) { - var serial = Serial; - - if (strBonus != 0) - { - m.AddStatMod(new StatMod(StatType.Str, $"{serial}Str", strBonus, TimeSpan.Zero)); - } - - if (dexBonus != 0) - { - m.AddStatMod(new StatMod(StatType.Dex, $"{serial}Dex", dexBonus, TimeSpan.Zero)); - } - - if (intBonus != 0) - { - m.AddStatMod(new StatMod(StatType.Int, $"{serial}Int", intBonus, TimeSpan.Zero)); - } + m.AddStatMod(new StatMod(StatType.Str, $"{serial}Str", strBonus, TimeSpan.Zero)); } - m.CheckStatTimers(); + if (dexBonus != 0) + { + m.AddStatMod(new StatMod(StatType.Dex, $"{serial}Dex", dexBonus, TimeSpan.Zero)); + } + + if (intBonus != 0) + { + m.AddStatMod(new StatMod(StatType.Int, $"{serial}Int", intBonus, TimeSpan.Zero)); + } } + + m.CheckStatTimers(); } } } diff --git a/Projects/UOContent/Items/Skill Items/Magical/SpellweavingBook.cs b/Projects/UOContent/Items/Skill Items/Magical/SpellweavingBook.cs index bc81fb368b..9cdf3ab867 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/SpellweavingBook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/SpellweavingBook.cs @@ -1,35 +1,19 @@ -namespace Server.Items -{ - public class SpellweavingBook : Spellbook - { - [Constructible] - public SpellweavingBook(ulong content = 0) : base(content, 0x2D50) - { - Hue = 0x8A2; - - Layer = Layer.OneHanded; - } - - public SpellweavingBook(Serial serial) : base(serial) - { - } - - public override SpellbookType SpellbookType => SpellbookType.Arcanist; - public override int BookOffset => 600; - public override int BookCount => 16; +using ModernUO.Serialization; - public override void Serialize(IGenericWriter writer) - { - base.Serialize(writer); +namespace Server.Items; - writer.WriteEncodedInt(0); // version - } +[SerializationGenerator(0)] +public partial class SpellweavingBook : Spellbook +{ + [Constructible] + public SpellweavingBook(ulong content = 0) : base(content, 0x2D50) + { + Hue = 0x8A2; + Layer = Layer.OneHanded; + } - public override void Deserialize(IGenericReader reader) - { - base.Deserialize(reader); - var version = reader.ReadEncodedInt(); - } - } + public override SpellbookType SpellbookType => SpellbookType.Arcanist; + public override int BookOffset => 600; + public override int BookCount => 16; } diff --git a/Projects/UOContent/Migrations/Server.Items.BookOfBushido.v0.json b/Projects/UOContent/Migrations/Server.Items.BookOfBushido.v0.json new file mode 100644 index 0000000000..b9c1c8e7e3 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.BookOfBushido.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.BookOfBushido" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.BookOfChivalry.v0.json b/Projects/UOContent/Migrations/Server.Items.BookOfChivalry.v0.json new file mode 100644 index 0000000000..e6ba78f741 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.BookOfChivalry.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.BookOfChivalry" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.BookOfNinjitsu.v0.json b/Projects/UOContent/Migrations/Server.Items.BookOfNinjitsu.v0.json new file mode 100644 index 0000000000..679060dec5 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.BookOfNinjitsu.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.BookOfNinjitsu" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.MysticSpellbook.v0.json b/Projects/UOContent/Migrations/Server.Items.MysticSpellbook.v0.json new file mode 100644 index 0000000000..e9a218e481 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.MysticSpellbook.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.MysticSpellbook" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.NecromancerSpellbook.v0.json b/Projects/UOContent/Migrations/Server.Items.NecromancerSpellbook.v0.json new file mode 100644 index 0000000000..445d261ba4 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.NecromancerSpellbook.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.NecromancerSpellbook" +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.Runebook.v4.json b/Projects/UOContent/Migrations/Server.Items.Runebook.v4.json new file mode 100644 index 0000000000..1104edda07 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.Runebook.v4.json @@ -0,0 +1,66 @@ +{ + "version": 4, + "type": "Server.Items.Runebook", + "properties": [ + { + "name": "Quality", + "type": "Server.Items.BookQuality", + "rule": "EnumMigrationRule" + }, + { + "name": "Crafter", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Level", + "type": "Server.Multis.SecureLevel", + "rule": "EnumMigrationRule" + }, + { + "name": "Entries", + "type": "System.Collections.Generic.List\u003CServer.Items.RunebookEntry\u003E", + "rule": "ListMigrationRule", + "ruleArguments": [ + "Server.Items.RunebookEntry", + "SerializationMethodSignatureMigrationRule", + "" + ] + }, + { + "name": "Description", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "CurCharges", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "MaxCharges", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "DefaultIndex", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.RunebookEntry.v2.json b/Projects/UOContent/Migrations/Server.Items.RunebookEntry.v2.json new file mode 100644 index 0000000000..59e0909361 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.RunebookEntry.v2.json @@ -0,0 +1,35 @@ +{ + "version": 2, + "type": "Server.Items.RunebookEntry", + "properties": [ + { + "name": "House", + "type": "Server.Multis.BaseHouse", + "rule": "SerializableInterfaceMigrationRule" + }, + { + "name": "Location", + "type": "Server.Point3D", + "rule": "PrimitiveUOTypeMigrationRule", + "ruleArguments": [ + "Point3D" + ] + }, + { + "name": "Map", + "type": "Server.Map", + "rule": "PrimitiveUOTypeMigrationRule", + "ruleArguments": [ + "Map" + ] + }, + { + "name": "Description", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.Spellbook.v6.json b/Projects/UOContent/Migrations/Server.Items.Spellbook.v6.json new file mode 100644 index 0000000000..7803f68919 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.Spellbook.v6.json @@ -0,0 +1,69 @@ +{ + "version": 6, + "type": "Server.Items.Spellbook", + "properties": [ + { + "name": "Quality", + "type": "Server.Items.BookQuality", + "rule": "EnumMigrationRule" + }, + { + "name": "EngravedText", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Crafter", + "type": "string", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "Slayer", + "type": "Server.Items.SlayerName", + "rule": "EnumMigrationRule" + }, + { + "name": "Slayer2", + "type": "Server.Items.SlayerName", + "rule": "EnumMigrationRule" + }, + { + "name": "Attributes", + "type": "Server.AosAttributes", + "rule": "RawSerializableMigrationRule", + "ruleArguments": [ + "DeserializationRequiresParent" + ] + }, + { + "name": "SkillBonuses", + "type": "Server.AosSkillBonuses", + "rule": "RawSerializableMigrationRule", + "ruleArguments": [ + "DeserializationRequiresParent" + ] + }, + { + "name": "Content", + "type": "ulong", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + }, + { + "name": "SpellCount", + "type": "int", + "rule": "PrimitiveTypeMigrationRule", + "ruleArguments": [ + "" + ] + } + ] +} \ No newline at end of file diff --git a/Projects/UOContent/Migrations/Server.Items.SpellweavingBook.v0.json b/Projects/UOContent/Migrations/Server.Items.SpellweavingBook.v0.json new file mode 100644 index 0000000000..af5bbf8e96 --- /dev/null +++ b/Projects/UOContent/Migrations/Server.Items.SpellweavingBook.v0.json @@ -0,0 +1,4 @@ +{ + "version": 0, + "type": "Server.Items.SpellweavingBook" +} \ No newline at end of file