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();