From 7a71e8b3406498aa3c33b40d9cf4d5ffe92e2219 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Fri, 1 Mar 2024 21:36:37 -0800 Subject: [PATCH] fix: Fixes special scroll logic and display (#1691) ### Summary - Fixes edge case calculations with values that aren't exact. - Fixes skill text casing. - Fixes cliloc error for stat cap scroll gump. - Adds `AosSkillBonuses.GetLowercaseLabel()` for lower case localized skill names. - Fixes initial value for constructing a stat scroll so it isn't negative. - Fixes message for Scroll of Alacrity gump. - Fixes missing property invalidation for Skill/Value. --- .../Special/Special Scrolls/PowerScroll.cs | 85 ++++++++++++------- .../Special Scrolls/ScrollofAlacrity.cs | 15 ++-- .../Special Scrolls/ScrollofTranscendence.cs | 23 ++--- .../Special/Special Scrolls/SpecialScroll.cs | 14 ++- .../{StatScroll.cs => StatCapScroll.cs} | 24 ++++-- Projects/UOContent/Misc/AOS.cs | 21 +++++ 6 files changed, 120 insertions(+), 62 deletions(-) rename Projects/UOContent/Items/Special/Special Scrolls/{StatScroll.cs => StatCapScroll.cs} (87%) diff --git a/Projects/UOContent/Items/Special/Special Scrolls/PowerScroll.cs b/Projects/UOContent/Items/Special/Special Scrolls/PowerScroll.cs index 184673eed..0e29302a3 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/PowerScroll.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/PowerScroll.cs @@ -74,7 +74,7 @@ public partial class PowerScroll : SpecialScroll { Hue = 0x481; - if (Value == 105.0 || skill is SkillName.Blacksmith or SkillName.Tailoring) + if (Value - 105.0 < 0.1 || skill is SkillName.Blacksmith or SkillName.Tailoring) { LootType = LootType.Regular; } @@ -91,23 +91,26 @@ public partial class PowerScroll : SpecialScroll { get { - var level = (Value - 105.0) / 5.0; - - /* Wondrous Scroll (105 Skill): OR - * Exalted Scroll (110 Skill): OR - * Mythical Scroll (115 Skill): OR - * Legendary Scroll (120 Skill): - */ - if (level is >= 0.0 and <= 3.0 && Value % 5.0 == 0.0) + var skillValue = Value; + if (skillValue is >= 105 and <= 120) { - return 1049635 + (int)level; + var truncValue = Math.Floor(skillValue); + if (skillValue - truncValue < 0.1) + { + /* Wondrous Scroll (105 Skill): OR + * Exalted Scroll (110 Skill): OR + * Mythical Scroll (115 Skill): OR + * Legendary Scroll (120 Skill): + */ + return 1049635 + ((int)truncValue - 105) / 5; + } } return 0; } } - public override string DefaultTitle => $"Power Scroll ({Value} Skill):"; + public override string DefaultTitle => $"Power Scroll ({Math.Floor(Value * 10) / 10:0.#} Skill):"; public static SkillName[] Skills { @@ -183,35 +186,53 @@ public partial class PowerScroll : SpecialScroll public override void AddNameProperty(IPropertyList list) { - var level = (Value - 105.0) / 5.0; + var skillValue = Value; + // Truncate to 1 decimal by multiplying by 10 and flooring. + var truncValue = Math.Floor(skillValue * 10) / 10.0; - if (level is >= 0.0 and <= 3.0 && Value % 5.0 == 0.0) + // If the scroll is a 105-120 skill scroll and the value is a whole multiple of 5. + if (skillValue is >= 105 and <= 120 && skillValue - truncValue < 0.1) { - /* a wondrous scroll of ~1_type~ (105 Skill) OR - * an exalted scroll of ~1_type~ (110 Skill) OR - * a mythical scroll of ~1_type~ (115 Skill) OR - * a legendary scroll of ~1_type~ (120 Skill) - */ - list.AddLocalized(1049639 + (int)level, AosSkillBonuses.GetLabel(Skill)); - } - else - { - list.Add($"a power scroll of {GetName()} ({Value} Skill)"); + var level = Math.DivRem((int)truncValue - 105, 5, out var rem); + if (rem == 0) + { + /* a wondrous scroll of ~1_type~ (105 Skill) OR + * an exalted scroll of ~1_type~ (110 Skill) OR + * a mythical scroll of ~1_type~ (115 Skill) OR + * a legendary scroll of ~1_type~ (120 Skill) + */ + list.AddLocalized(1049639 + level, AosSkillBonuses.GetLowercaseLabel(Skill)); + return; + } } + + list.Add($"a power scroll of {GetSkillName()} ({truncValue:0.#} Skill)"); } public override void OnSingleClick(Mobile from) { - var level = (Value - 105.0) / 5.0; + var skillValue = Value; + // Truncate to 1 decimal by multiplying by 10 and flooring. + // This will need to be divided by 10 to get the actual value. + var truncValue = Math.Floor(skillValue * 10) / 10.0; - if (level is >= 0.0 and <= 3.0 && Value % 5.0 == 0.0) + // If the scroll is a 105-120 skill scroll and the value is a whole multiple of 5. + if (skillValue is >= 105 and <= 120 && skillValue - truncValue < 0.1) { - LabelTo(from, 1049639 + (int)level, GetNameLocalized()); - } - else - { - LabelTo(from, $"a power scroll of {GetName()} ({Value} Skill)"); + var level = Math.DivRem((int)truncValue - 105, 5, out var rem); + if (rem == 0) + { + /* a wondrous scroll of ~1_type~ (105 Skill) OR + * an exalted scroll of ~1_type~ (110 Skill) OR + * a mythical scroll of ~1_type~ (115 Skill) OR + * a legendary scroll of ~1_type~ (120 Skill) + */ + LabelTo(from, 1049639 + level, $"#{AosSkillBonuses.GetLowercaseLabel(Skill)}"); + return; + } } + + LabelTo(from, $"a power scroll of {GetSkillName()} ({truncValue:0.#} Skill)"); } public override bool CanUse(Mobile from) @@ -231,7 +252,7 @@ public partial class PowerScroll : SpecialScroll if (skill.Cap >= Value) { // Your ~1_type~ is too high for this power scroll. - from.SendLocalizedMessage(1049511, GetNameLocalized()); + from.SendLocalizedMessage(1049511, $"#{AosSkillBonuses.GetLowercaseLabel(Skill)}"); return false; } @@ -246,7 +267,7 @@ public partial class PowerScroll : SpecialScroll } // You feel a surge of magic as the scroll enhances your ~1_type~! - from.SendLocalizedMessage(1049513, GetNameLocalized()); + from.SendLocalizedMessage(1049513, $"#{AosSkillBonuses.GetLowercaseLabel(Skill)}"); from.Skills[Skill].Cap = Value; diff --git a/Projects/UOContent/Items/Special/Special Scrolls/ScrollofAlacrity.cs b/Projects/UOContent/Items/Special/Special Scrolls/ScrollofAlacrity.cs index a7dbbe3fd..99a7d64c8 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/ScrollofAlacrity.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/ScrollofAlacrity.cs @@ -18,9 +18,9 @@ public partial class ScrollofAlacrity : SpecialScroll public override int LabelNumber => 1078604; // Scroll of Alacrity - /* Using a Scroll of Transcendence for a given skill will permanently increase your current - * level in that skill by the amount of points displayed on the scroll. - * As you may not gain skills beyond your maximum skill cap, any excess points will be lost. + /* + * Using a Scroll of Alacrity for a given skill will increase the amount of skillgain you receive for that skill. + * Once the Scroll of Alacrity duration has expired, skillgain will return to normal for that skill. */ public override int Message => 1078602; @@ -30,7 +30,7 @@ public partial class ScrollofAlacrity : SpecialScroll { base.GetProperties(list); - list.Add(1071345, GetName()); // Skill: ~1_val~ + list.AddLocalized(1071345, SkillLabel); // Skill: ~1_val~ list.Add(1071346, 15); // Duration: ~1_val~ minutes } @@ -75,10 +75,11 @@ public partial class ScrollofAlacrity : SpecialScroll return; } - var tskill = from.Skills[Skill].Base; - var tcap = from.Skills[Skill].Cap; + var skill = from.Skills[Skill]; + var skillBase = skill.Base; + var skillCap = skill.Cap; - if (tskill >= tcap || from.Skills[Skill].Lock != SkillLock.Up) + if (skillBase >= skillCap || skill.Lock != SkillLock.Up) { /* You cannot increase this skill at this time. The skill may be locked or set to lower in your skill menu. * If you are at your total skill cap, you must use a Powerscroll to increase your current skill cap. diff --git a/Projects/UOContent/Items/Special/Special Scrolls/ScrollofTranscendence.cs b/Projects/UOContent/Items/Special/Special Scrolls/ScrollofTranscendence.cs index 212ea8de3..17ceba0e6 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/ScrollofTranscendence.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/ScrollofTranscendence.cs @@ -1,3 +1,4 @@ +using System; using ModernUO.Serialization; using Server.Engines.MLQuests; using Server.Engines.MLQuests.Objectives; @@ -24,7 +25,7 @@ public partial class ScrollofTranscendence : SpecialScroll public override int Message => 1094933; public override string DefaultTitle => - $"Scroll of Transcendence ({Value} Skill):"; + $"Scroll of Transcendence ({Math.Floor(Value * 10) / 10:0.#} Skill):"; public static ScrollofTranscendence CreateRandom(int min, int max) => new(Utility.RandomSkill(), Utility.RandomMinMax(min, max) * 0.1); @@ -32,7 +33,7 @@ public partial class ScrollofTranscendence : SpecialScroll public override void GetProperties(IPropertyList list) { base.GetProperties(list); - list.Add(1076759, $"{GetName()}\t{Value:0.#} Skill Points"); + list.Add(1151930, $"{SkillLabel:#}\t{Math.Floor(Value * 10) / 10:0.#}\t{1151931:#}"); } public override bool CanUse(Mobile from) @@ -76,18 +77,19 @@ public partial class ScrollofTranscendence : SpecialScroll return; } - var tskill = from.Skills[Skill].Base; // value of skill without item bonuses etc - var tcap = from.Skills[Skill].Cap; // maximum value permitted + var skill = from.Skills[Skill]; + var skillBase = skill.Base; + var skillCap = skill.Cap; var canGain = false; var newValue = Value; - if (tskill + newValue > tcap) + if (skillBase + newValue > skillCap) { - newValue = tcap - tskill; + newValue = skillCap - skillBase; } - if (tskill < tcap && from.Skills[Skill].Lock == SkillLock.Up) + if (skillBase < skillCap && skill.Lock == SkillLock.Up) { if (from.SkillsTotal + newValue * 10 > from.SkillsCap) { @@ -95,10 +97,11 @@ public partial class ScrollofTranscendence : SpecialScroll for (var i = 0; i < ns; i++) { + var sk = from.Skills[i]; // skill must point down and its value must be enough - if (from.Skills[i].Lock == SkillLock.Down && from.Skills[i].Base >= newValue) + if (sk.Lock == SkillLock.Down && sk.Base >= newValue) { - from.Skills[i].Base -= newValue; + sk.Base -= newValue; canGain = true; break; } @@ -120,7 +123,7 @@ public partial class ScrollofTranscendence : SpecialScroll } // You feel a surge of magic as the scroll enhances your ~1_type~! - from.SendLocalizedMessage(1049513, GetNameLocalized()); + from.SendLocalizedMessage(1049513, $"#{AosSkillBonuses.GetLowercaseLabel(Skill)}"); from.Skills[Skill].Base += newValue; diff --git a/Projects/UOContent/Items/Special/Special Scrolls/SpecialScroll.cs b/Projects/UOContent/Items/Special/Special Scrolls/SpecialScroll.cs index 2129410e9..95b24985d 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/SpecialScroll.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/SpecialScroll.cs @@ -7,10 +7,12 @@ namespace Server.Items; [SerializationGenerator(0, false)] public abstract partial class SpecialScroll : Item { + [InvalidateProperties] [SerializableField(0)] [SerializedCommandProperty(AccessLevel.GameMaster)] private SkillName _skill; + [InvalidateProperties] [SerializableField(1)] [SerializedCommandProperty(AccessLevel.GameMaster)] private double _value; @@ -28,9 +30,9 @@ public abstract partial class SpecialScroll : Item public virtual int Title => 0; public abstract string DefaultTitle { get; } - public virtual string GetNameLocalized() => $"#{AosSkillBonuses.GetLabel(Skill)}"; + public virtual int SkillLabel => AosSkillBonuses.GetLabel(Skill); - public virtual string GetName() + public virtual string GetSkillName() { var index = (int)Skill; var table = SkillInfo.Table; @@ -110,8 +112,12 @@ public abstract partial class SpecialScroll : Item AddHtml(40, 20, 260, 20, _scroll.DefaultTitle); } - var skillLabel = _scroll is StatCapScroll ? 1038019 : AosSkillBonuses.GetLabel(_scroll.Skill); - AddHtmlLocalized(310, 20, 120, 20, skillLabel, 0xFFFFFF); // Power + var skillLabel = _scroll.SkillLabel; + + if (skillLabel > 0) + { + AddHtmlLocalized(310, 20, 120, 20, skillLabel, 0xFFFFFF); + } } public override void OnResponse(NetState state, RelayInfo info) diff --git a/Projects/UOContent/Items/Special/Special Scrolls/StatScroll.cs b/Projects/UOContent/Items/Special/Special Scrolls/StatCapScroll.cs similarity index 87% rename from Projects/UOContent/Items/Special/Special Scrolls/StatScroll.cs rename to Projects/UOContent/Items/Special/Special Scrolls/StatCapScroll.cs index b326b7148..a47fb8ccb 100644 --- a/Projects/UOContent/Items/Special/Special Scrolls/StatScroll.cs +++ b/Projects/UOContent/Items/Special/Special Scrolls/StatCapScroll.cs @@ -1,13 +1,17 @@ +using System; using ModernUO.Serialization; using Server.Mobiles; namespace Server.Items; [SerializationGenerator(0, false)] +[TypeAlias("Server.Items.StatScroll")] public partial class StatCapScroll : SpecialScroll { [Constructible] - public StatCapScroll(int value = 105) : base(SkillName.Alchemy, value) => Hue = 0x481; + public StatCapScroll(int value = 230) : base(SkillName.Alchemy, value) => Hue = 0x481; + + public override int SkillLabel => 0; /* Using a scroll increases the maximum amount of a specific skill or your maximum statistics. * When used, the effect is not immediately seen without a gain of points with that skill or statistics. @@ -20,7 +24,7 @@ public partial class StatCapScroll : SpecialScroll { get { - var level = ((int)Value - 230) / 5; + var level = Math.DivRem((int)Value - 230, 5, out var rem); /* Wondrous Scroll (+5 Maximum Stats): OR * Exalted Scroll (+10 Maximum Stats): OR @@ -28,7 +32,7 @@ public partial class StatCapScroll : SpecialScroll * Legendary Scroll (+20 Maximum Stats): OR * Ultimate Scroll (+25 Maximum Stats): */ - if (level is >= 0 and <= 4 && Value % 5 == 0) + if (level is >= 0 and <= 4 && rem == 0) { return 1049458 + level; } @@ -42,9 +46,10 @@ public partial class StatCapScroll : SpecialScroll public override void AddNameProperty(IPropertyList list) { - var level = ((int)Value - 230) / 5; + var truncValue = (int)Value; + var level = Math.DivRem(truncValue - 230, 5, out var rem); - if (level is >= 0 and <= 4 && (int)Value % 5 == 0) + if (level is >= 0 and <= 4 && rem == 0) { /* a wondrous scroll of ~1_type~ (+5 Maximum Stats) OR * an exalted scroll of ~1_type~ (+10 Maximum Stats) OR @@ -56,22 +61,23 @@ public partial class StatCapScroll : SpecialScroll } else { - var diff = Value - 225; + var diff = truncValue - 225; list.Add($"a scroll of power ({(diff >= 0 ? "+" : "")}{diff} Maximum Stats)"); } } public override void OnSingleClick(Mobile from) { - var level = ((int)Value - 230) / 5; + var truncValue = (int)Value; + var level = (truncValue - 230) / 5; - if (level is >= 0 and <= 4 && (int)Value % 5 == 0) + if (level is >= 0 and <= 4) { LabelTo(from, 1049463 + level, "#1049476"); } else { - var diff = Value - 225; + var diff = truncValue - 225; LabelTo(from, $"a scroll of power ({(diff >= 0 ? "+" : "")}{diff} Maximum Stats)"); } } diff --git a/Projects/UOContent/Misc/AOS.cs b/Projects/UOContent/Misc/AOS.cs index eadddc2b1..e85688839 100644 --- a/Projects/UOContent/Misc/AOS.cs +++ b/Projects/UOContent/Misc/AOS.cs @@ -1085,6 +1085,27 @@ namespace Server }; } + public static int GetLowercaseLabel(SkillName skill) + { + return skill switch + { + SkillName.Provocation => 1049473, // provocation + SkillName.MagicResist => 1049471, // resisting spells + SkillName.AnimalTaming => 1049472, // animal taming + SkillName.Macing => 1049470, // mace fighting + SkillName.Necromancy => 1060842, // necromancy + SkillName.Focus => 1061616, // focus + SkillName.Chivalry => 1061615, // chivalry + SkillName.Bushido => 1062935, // bushido + SkillName.Ninjitsu => 1062936, // ninjitsu + SkillName.Spellweaving => 1074397, // spellweaving + SkillName.Mysticism => 1112544, // mysticism + SkillName.Imbuing => 1112545, // imbuing + SkillName.Throwing => 1112553, // throwing + _ => 1042347 + (int)skill + }; + } + public void AddTo(Mobile m) { Remove();