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.
This commit is contained in:
Kamron Batman 2024-03-01 21:36:37 -08:00 committed by GitHub
parent de0d205fd3
commit 7a71e8b340
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 120 additions and 62 deletions

View file

@ -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 => $"<basefont color=#FFFFFF>Power Scroll ({Value} Skill):</basefont>";
public override string DefaultTitle => $"<basefont color=#FFFFFF>Power Scroll ({Math.Floor(Value * 10) / 10:0.#} Skill):</basefont>";
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;

View file

@ -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.

View file

@ -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 =>
$"<basefont color=#FFFFFF>Scroll of Transcendence ({Value} Skill):</basefont>";
$"<basefont color=#FFFFFF>Scroll of Transcendence ({Math.Floor(Value * 10) / 10:0.#} Skill):</basefont>";
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;

View file

@ -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)

View file

@ -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)");
}
}

View file

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