fix: Fixes special scrolls (#1373)

This commit is contained in:
Kamron Batman 2023-03-12 13:47:12 -07:00 committed by GitHub
parent 7635db4834
commit e797ec7f53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 804 additions and 918 deletions

View file

@ -127,10 +127,8 @@ namespace Server.Items
if (!IsEmpty)
{
list.Add(
1070721, // Skill stored: ~1_skillname~ ~2_skillamount~
$"{AosSkillBonuses.GetLabel(Skill):#}\t{SkillValue:F1}"
);
// Skill stored: ~1_skillname~ ~2_skillamount~
list.Add(1070721, $"{AosSkillBonuses.GetLabel(Skill):#}\t{SkillValue:F1}");
}
if (LastUserName != null)

View file

@ -1,326 +1,318 @@
using System.Collections.Generic;
using System;
using ModernUO.Serialization;
namespace Server.Items
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class PowerScroll : SpecialScroll
{
public class PowerScroll : SpecialScroll
private static readonly SkillName[] _preAosSkills =
{
private static readonly SkillName[] m_Skills =
SkillName.Blacksmith,
SkillName.Tailoring,
SkillName.Swords,
SkillName.Fencing,
SkillName.Macing,
SkillName.Archery,
SkillName.Wrestling,
SkillName.Parry,
SkillName.Tactics,
SkillName.Anatomy,
SkillName.Healing,
SkillName.Magery,
SkillName.Meditation,
SkillName.EvalInt,
SkillName.MagicResist,
SkillName.AnimalTaming,
SkillName.AnimalLore,
SkillName.Veterinary,
SkillName.Musicianship,
SkillName.Provocation,
SkillName.Discordance,
SkillName.Peacemaking
};
private static readonly SkillName[] _aosSkills =
{
SkillName.Chivalry,
SkillName.Focus,
SkillName.Necromancy,
SkillName.Stealing,
SkillName.Stealth,
SkillName.SpiritSpeak
};
private static readonly SkillName[] _seSkills =
{
SkillName.Ninjitsu,
SkillName.Bushido
};
private static readonly SkillName[] _mlSkills =
{
SkillName.Spellweaving
};
/*
private static SkillName[] _saSkills = new SkillName[]
{
SkillName.Throwing,
SkillName.Mysticism,
SkillName.Imbuing
};
private static SkillName[] _hsSkills = new SkillName[]
{
SkillName.Fishing
};
*/
private static SkillName[] _skills;
[Constructible]
public PowerScroll(SkillName skill = SkillName.Alchemy, double value = 0.0) : base(skill, value)
{
Hue = 0x481;
if (Value == 105.0 || skill is SkillName.Blacksmith or SkillName.Tailoring)
{
SkillName.Blacksmith,
SkillName.Tailoring,
SkillName.Swords,
SkillName.Fencing,
SkillName.Macing,
SkillName.Archery,
SkillName.Wrestling,
SkillName.Parry,
SkillName.Tactics,
SkillName.Anatomy,
SkillName.Healing,
SkillName.Magery,
SkillName.Meditation,
SkillName.EvalInt,
SkillName.MagicResist,
SkillName.AnimalTaming,
SkillName.AnimalLore,
SkillName.Veterinary,
SkillName.Musicianship,
SkillName.Provocation,
SkillName.Discordance,
SkillName.Peacemaking
};
private static readonly SkillName[] m_AOSSkills =
{
SkillName.Chivalry,
SkillName.Focus,
SkillName.Necromancy,
SkillName.Stealing,
SkillName.Stealth,
SkillName.SpiritSpeak
};
private static readonly SkillName[] m_SESkills =
{
SkillName.Ninjitsu,
SkillName.Bushido
};
private static readonly SkillName[] m_MLSkills =
{
SkillName.Spellweaving
};
/*
private static SkillName[] m_SASkills = new SkillName[]
{
SkillName.Throwing,
SkillName.Mysticism,
SkillName.Imbuing
};
private static SkillName[] m_HSSkills = new SkillName[]
{
SkillName.Fishing
};
*/
private static readonly List<SkillName> _Skills = new();
[Constructible]
public PowerScroll(SkillName skill = SkillName.Alchemy, double value = 0.0) : base(skill, value)
{
Hue = 0x481;
if (Value == 105.0 || skill is SkillName.Blacksmith or SkillName.Tailoring)
{
LootType = LootType.Regular;
}
}
public PowerScroll(Serial serial) : base(serial)
{
}
/* 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.
* You can view your maximum skill values in your skills window.
* You can view your maximum statistic value in your statistics window.
*/
public override int Message =>
1049469;
public override int Title
{
get
{
var level = (Value - 105.0) / 5.0;
/* Wonderous Scroll (105 Skill): OR
* Exalted Scroll (110 Skill): OR
* Mythical Scroll (115 Skill): OR
* Legendary Scroll (120 Skill):
*/
if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0)
{
return 1049635 + (int)level;
}
return 0;
}
}
public override string DefaultTitle => $"<basefont color=#FFFFFF>Power Scroll ({Value} Skill):</basefont>";
public static List<SkillName> Skills
{
get
{
if (_Skills.Count == 0)
{
_Skills.AddRange(m_Skills);
if (Core.AOS)
{
_Skills.AddRange(m_AOSSkills);
if (Core.SE)
{
_Skills.AddRange(m_SESkills);
if (Core.ML)
{
_Skills.AddRange(m_MLSkills);
}
}
}
}
return _Skills;
}
}
public static PowerScroll CreateRandom(int min, int max)
{
min /= 5;
max /= 5;
return new PowerScroll(Skills.RandomElement(), 100 + Utility.RandomMinMax(min, max) * 5);
}
public static PowerScroll CreateRandomNoCraft(int min, int max)
{
min /= 5;
max /= 5;
SkillName skillName;
do
{
skillName = Skills.RandomElement();
} while (skillName is SkillName.Blacksmith or SkillName.Tailoring);
return new PowerScroll(skillName, 100 + Utility.RandomMinMax(min, max) * 5);
}
public override void AddNameProperty(IPropertyList list)
{
var level = (Value - 105.0) / 5.0;
if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0)
/* a wonderous 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.Add(1049639 + (int)level, GetNameLocalized());
}
else
{
list.Add($"a power scroll of {GetName()} ({Value} Skill)");
}
}
public override void OnSingleClick(Mobile from)
{
var level = (Value - 105.0) / 5.0;
if (level >= 0.0 && level <= 3.0 && Value % 5.0 == 0.0)
{
LabelTo(from, 1049639 + (int)level, GetNameLocalized());
}
else
{
LabelTo(from, $"a power scroll of {GetName()} ({Value} Skill)");
}
}
public override bool CanUse(Mobile from)
{
if (!base.CanUse(from))
{
return false;
}
var skill = from.Skills[Skill];
if (skill == null)
{
return false;
}
if (skill.Cap >= Value)
{
from.SendLocalizedMessage(
1049511,
GetNameLocalized()
); // Your ~1_type~ is too high for this power scroll.
return false;
}
return true;
}
public override void Use(Mobile from)
{
if (!CanUse(from))
{
return;
}
from.SendLocalizedMessage(
1049513,
GetNameLocalized()
); // You feel a surge of magic as the scroll enhances your ~1_type~!
from.Skills[Skill].Cap = Value;
Effects.SendLocationParticles(
EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration),
0,
0,
0,
0,
0,
5060,
0
);
Effects.PlaySound(from.Location, from.Map, 0x243);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
Delete();
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion
if (Value == 105.0 || Skill is SkillName.Blacksmith or SkillName.Tailoring)
{
LootType = LootType.Regular;
}
else
{
LootType = LootType.Cursed;
Insured = false;
}
LootType = LootType.Regular;
}
}
/* 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.
* You can view your maximum skill values in your skills window.
* You can view your maximum statistic value in your statistics window.
*/
public override int Message => 1049469;
public override int Title
{
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)
{
return 1049635 + (int)level;
}
return 0;
}
}
public override string DefaultTitle => $"<basefont color=#FFFFFF>Power Scroll ({Value} Skill):</basefont>";
public static SkillName[] Skills
{
get
{
if (_skills == null)
{
var totalSkills = _preAosSkills.Length;
if (Core.AOS)
{
totalSkills += _aosSkills.Length;
}
if (Core.SE)
{
totalSkills += _seSkills.Length;
}
if (Core.ML)
{
totalSkills += _mlSkills.Length;
}
_skills = new SkillName[totalSkills];
Array.Copy(_preAosSkills, 0, _skills, 0, _preAosSkills.Length);
int pos = 0;
if (Core.AOS)
{
pos = _preAosSkills.Length;
Array.Copy(_aosSkills, 0, _skills, pos, _aosSkills.Length);
}
if (Core.SE)
{
pos += _aosSkills.Length;
Array.Copy(_seSkills, 0, _skills, pos, _seSkills.Length);
}
if (Core.ML)
{
pos += _seSkills.Length;
Array.Copy(_mlSkills, 0, _skills, pos, _mlSkills.Length);
}
}
return _skills;
}
}
public static PowerScroll CreateRandom(int min, int max)
{
min /= 5;
max /= 5;
return new PowerScroll(Skills.RandomElement(), 100 + Utility.RandomMinMax(min, max) * 5);
}
public static PowerScroll CreateRandomNoCraft(int min, int max)
{
min /= 5;
max /= 5;
SkillName skillName;
do
{
skillName = Skills.RandomElement();
} while (skillName is SkillName.Blacksmith or SkillName.Tailoring);
return new PowerScroll(skillName, 100 + Utility.RandomMinMax(min, max) * 5);
}
public override void AddNameProperty(IPropertyList list)
{
var level = (Value - 105.0) / 5.0;
if (level is >= 0.0 and <= 3.0 && Value % 5.0 == 0.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.Add(1049639 + (int)level, AosSkillBonuses.GetLabel(Skill));
}
else
{
list.Add($"a power scroll of {GetName()} ({Value} Skill)");
}
}
public override void OnSingleClick(Mobile from)
{
var level = (Value - 105.0) / 5.0;
if (level is >= 0.0 and <= 3.0 && Value % 5.0 == 0.0)
{
LabelTo(from, 1049639 + (int)level, GetNameLocalized());
}
else
{
LabelTo(from, $"a power scroll of {GetName()} ({Value} Skill)");
}
}
public override bool CanUse(Mobile from)
{
if (!base.CanUse(from))
{
return false;
}
var skill = from.Skills[Skill];
if (skill == null)
{
return false;
}
if (skill.Cap >= Value)
{
// Your ~1_type~ is too high for this power scroll.
from.SendLocalizedMessage(1049511, GetNameLocalized());
return false;
}
return true;
}
public override void Use(Mobile from)
{
if (!CanUse(from))
{
return;
}
// You feel a surge of magic as the scroll enhances your ~1_type~!
from.SendLocalizedMessage(1049513, GetNameLocalized());
from.Skills[Skill].Cap = Value;
Effects.SendLocationParticles(
EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration),
0,
0,
0,
0,
0,
5060,
0
);
Effects.PlaySound(from.Location, from.Map, 0x243);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
Delete();
}
}

View file

@ -1,133 +1,111 @@
using System;
using ModernUO.Serialization;
using Server.Engines.MLQuests;
using Server.Engines.MLQuests.Objectives;
using Server.Mobiles;
namespace Server.Items
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class ScrollofAlacrity : SpecialScroll
{
public class ScrollofAlacrity : SpecialScroll
[Constructible]
public ScrollofAlacrity(SkillName skill = SkillName.Alchemy) : base(skill, 0.0)
{
[Constructible]
public ScrollofAlacrity(SkillName skill = SkillName.Alchemy) : base(skill, 0.0)
ItemID = 0x14EF;
Hue = 0x4AB;
}
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.
*/
public override int Message => 1078602;
public override string DefaultTitle => "<basefont color=#FFFFFF>Scroll of Alacrity:</basefont>";
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1071345, GetName()); // Skill: ~1_val~
list.Add(1071346, 15); // Duration: ~1_val~ minutes
}
public override bool CanUse(Mobile from)
{
if (!(base.CanUse(from) && from is PlayerMobile pm))
{
ItemID = 0x14EF;
Hue = 0x4AB;
return false;
}
public ScrollofAlacrity(Serial serial) : base(serial)
var context = MLQuestSystem.GetContext(pm);
if (context != null)
{
}
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.
*/
public override int Message =>
1078602;
public override string DefaultTitle => "<basefont color=#FFFFFF>Scroll of Alacrity:</basefont>";
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1071345, $"{GetName()} 15 Minutes"); // Skill: ~1_val~
}
public override bool CanUse(Mobile from)
{
if (!(base.CanUse(from) && from is PlayerMobile pm))
foreach (var instance in context.QuestInstances)
{
return false;
}
var context = MLQuestSystem.GetContext(pm);
if (context != null)
{
foreach (var instance in context.QuestInstances)
foreach (var objective in instance.Objectives)
{
foreach (var objective in instance.Objectives)
if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance &&
objectiveInstance.Handles(Skill))
{
if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance &&
objectiveInstance.Handles(Skill))
{
from.SendMessage("You are already under the effect of an enhanced skillgain quest.");
return false;
}
from.SendMessage("You are already under the effect of an enhanced skillgain quest.");
return false;
}
}
}
if (pm.AcceleratedStart > Core.Now)
{
from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
return false;
}
return true;
}
public override void Use(Mobile from)
if (pm.AcceleratedStart > Core.Now)
{
if (!(CanUse(from) && from is PlayerMobile pm))
{
return;
}
var tskill = from.Skills[Skill].Base;
var tcap = from.Skills[Skill].Cap;
if (tskill >= tcap || from.Skills[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.
*/
from.SendLocalizedMessage(1094935);
return;
}
from.SendLocalizedMessage(
1077956
); // You are infused with intense energy. You are under the effects of an accelerated skillgain scroll.
Effects.PlaySound(from.Location, from.Map, 0x1E9);
Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
pm.AcceleratedStart = Core.Now + TimeSpan.FromMinutes(15);
Timer.StartTimer(TimeSpan.FromMinutes(15), () => Expire_Callback(from));
pm.AcceleratedSkill = Skill;
Delete();
from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
return false;
}
// TODO: Handle this upon deserialization. Create Dictionary and serialize Mobile/Timers?
private static void Expire_Callback(Mobile m)
return true;
}
public override void Use(Mobile from)
{
if (!(CanUse(from) && from is PlayerMobile pm))
{
m.PlaySound(0x1F8);
m.SendLocalizedMessage(
1077957
); // The intense energy dissipates. You are no longer under the effects of an accelerated skillgain scroll.
return;
}
public override void Serialize(IGenericWriter writer)
var tskill = from.Skills[Skill].Base;
var tcap = from.Skills[Skill].Cap;
if (tskill >= tcap || from.Skills[Skill].Lock != SkillLock.Up)
{
base.Serialize(writer);
writer.Write(0); // version
/* 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.
*/
from.SendLocalizedMessage(1094935);
return;
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
// You are infused with intense energy. You are under the effects of an accelerated skillgain scroll.
from.SendLocalizedMessage(1077956);
var version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion
Effects.PlaySound(from.Location, from.Map, 0x1E9);
Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
LootType = LootType.Cursed;
Insured = false;
}
pm.AcceleratedStart = Core.Now + TimeSpan.FromMinutes(15);
Timer.StartTimer(TimeSpan.FromMinutes(15), () => Expire_Callback(from));
pm.AcceleratedSkill = Skill;
Delete();
}
// TODO: Handle this upon deserialization. Create Dictionary and serialize Mobile/Timers?
private static void Expire_Callback(Mobile m)
{
m.PlaySound(0x1F8);
// The intense energy dissipates. You are no longer under the effects of an accelerated skillgain scroll.
m.SendLocalizedMessage(1077957);
}
}

View file

@ -1,163 +1,133 @@
using ModernUO.Serialization;
using Server.Engines.MLQuests;
using Server.Engines.MLQuests.Objectives;
using Server.Mobiles;
namespace Server.Items
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class ScrollofTranscendence : SpecialScroll
{
public class ScrollofTranscendence : SpecialScroll
[Constructible]
public ScrollofTranscendence(SkillName skill = SkillName.Alchemy, double value = 0.0) : base(skill, value)
{
[Constructible]
public ScrollofTranscendence(SkillName skill = SkillName.Alchemy, double value = 0.0) : base(skill, value)
ItemID = 0x14EF;
Hue = 0x490;
}
public override int LabelNumber => 1094934; // Scroll of Transcendence
/* 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.
*/
public override int Message => 1094933;
public override string DefaultTitle =>
$"<basefont color=#FFFFFF>Scroll of Transcendence ({Value} Skill):</basefont>";
public static ScrollofTranscendence CreateRandom(int min, int max) =>
new(Utility.RandomSkill(), Utility.RandomMinMax(min, max) * 0.1);
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1076759, $"{GetName()}\t{Value:0.#} Skill Points");
}
public override bool CanUse(Mobile from)
{
if (!(base.CanUse(from) && from is PlayerMobile pm))
{
ItemID = 0x14EF;
Hue = 0x490;
return false;
}
public ScrollofTranscendence(Serial serial) : base(serial)
var context = MLQuestSystem.GetContext(pm);
if (context != null)
{
}
public override int LabelNumber => 1094934; // Scroll of Transcendence
/* 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.
*/
public override int Message =>
1094933;
public override string DefaultTitle =>
$"<basefont color=#FFFFFF>Scroll of Transcendence ({Value} Skill):</basefont>";
public static ScrollofTranscendence CreateRandom(int min, int max) =>
new(Utility.RandomSkill(), Utility.RandomMinMax(min, max) * 0.1);
public override void GetProperties(IPropertyList list)
{
base.GetProperties(list);
list.Add(1076759, $"{GetName()}\t{Value:0.#} Skill Points");
}
public override bool CanUse(Mobile from)
{
if (!(base.CanUse(from) && from is PlayerMobile pm))
foreach (var instance in context.QuestInstances)
{
return false;
}
var context = MLQuestSystem.GetContext(pm);
if (context != null)
{
foreach (var instance in context.QuestInstances)
foreach (var objective in instance.Objectives)
{
foreach (var objective in instance.Objectives)
if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance &&
objectiveInstance.Handles(Skill))
{
if (!objective.Expired && objective is GainSkillObjectiveInstance objectiveInstance &&
objectiveInstance.Handles(Skill))
{
from.SendMessage("You are already under the effect of an enhanced skillgain quest.");
return false;
}
from.SendMessage("You are already under the effect of an enhanced skillgain quest.");
return false;
}
}
}
if (pm.AcceleratedStart > Core.Now)
{
from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
return false;
}
return true;
}
public override void Use(Mobile from)
if (pm.AcceleratedStart > Core.Now)
{
if (!CanUse(from))
from.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
return false;
}
return true;
}
public override void Use(Mobile from)
{
if (!CanUse(from))
{
return;
}
var tskill = from.Skills[Skill].Base; // value of skill without item bonuses etc
var tcap = from.Skills[Skill].Cap; // maximum value permitted
var canGain = false;
var newValue = Value;
if (tskill + newValue > tcap)
{
newValue = tcap - tskill;
}
if (tskill < tcap && from.Skills[Skill].Lock == SkillLock.Up)
{
if (from.SkillsTotal + newValue * 10 > from.SkillsCap)
{
return;
}
var ns = from.Skills.Length; // number of items in from.Skills[]
var tskill = from.Skills[Skill].Base; // value of skill without item bonuses etc
var tcap = from.Skills[Skill].Cap; // maximum value permitted
var canGain = false;
var newValue = Value;
if (tskill + newValue > tcap)
{
newValue = tcap - tskill;
}
if (tskill < tcap && from.Skills[Skill].Lock == SkillLock.Up)
{
if (from.SkillsTotal + newValue * 10 > from.SkillsCap)
for (var i = 0; i < ns; i++)
{
var ns = from.Skills.Length; // number of items in from.Skills[]
for (var i = 0; i < ns; i++)
// skill must point down and its value must be enough
// skill must point down and its value must be enough
if (from.Skills[i].Lock == SkillLock.Down && from.Skills[i].Base >= newValue)
{
if (from.Skills[i].Lock == SkillLock.Down && from.Skills[i].Base >= newValue)
{
from.Skills[i].Base -= newValue;
canGain = true;
break;
}
from.Skills[i].Base -= newValue;
canGain = true;
break;
}
}
else
{
canGain = true;
}
}
if (!canGain)
else
{
/* 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.
*/
from.SendLocalizedMessage(
1094935
);
return;
}
from.SendLocalizedMessage(
1049513,
GetNameLocalized()
); // You feel a surge of magic as the scroll enhances your ~1_type~!
from.Skills[Skill].Base += newValue;
Effects.PlaySound(from.Location, from.Map, 0x1F7);
Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
Effects.SendTargetParticles(from, 0x376A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
Delete();
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion
LootType = LootType.Cursed;
Insured = false;
if (Hue == 0x7E)
{
Hue = 0x490;
canGain = true;
}
}
if (!canGain)
{
/* 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.
*/
from.SendLocalizedMessage(1094935);
return;
}
// You feel a surge of magic as the scroll enhances your ~1_type~!
from.SendLocalizedMessage(1049513, GetNameLocalized());
from.Skills[Skill].Base += newValue;
Effects.PlaySound(from.Location, from.Map, 0x1F7);
Effects.SendTargetParticles(from, 0x373A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
Effects.SendTargetParticles(from, 0x376A, 35, 45, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
Delete();
}
}

View file

@ -1,190 +1,124 @@
using ModernUO.Serialization;
using Server.Gumps;
using Server.Network;
namespace Server.Items
namespace Server.Items;
[SerializationGenerator(0, false)]
public abstract partial class SpecialScroll : Item
{
public abstract class SpecialScroll : Item
[SerializableField(0)]
[SerializedCommandProperty(AccessLevel.GameMaster)]
private SkillName _skill;
[SerializableField(1)]
[SerializedCommandProperty(AccessLevel.GameMaster)]
private double _value;
public SpecialScroll(SkillName skill, double value) : base(0x14F0)
{
public SpecialScroll(SkillName skill, double value) : base(0x14F0)
{
LootType = LootType.Cursed;
Weight = 1.0;
LootType = LootType.Cursed;
Weight = 1.0;
Skill = skill;
Value = value;
_skill = skill;
_value = value;
}
public abstract int Message { get; }
public virtual int Title => 0;
public abstract string DefaultTitle { get; }
public virtual string GetNameLocalized() => $"#{AosSkillBonuses.GetLabel(Skill)}";
public virtual string GetName()
{
var index = (int)Skill;
var table = SkillInfo.Table;
if (index >= 0 && index < table.Length)
{
return table[index].Name.ToLower();
}
public SpecialScroll(Serial serial) : base(serial)
return "???";
}
public virtual bool CanUse(Mobile from)
{
if (Deleted)
{
return false;
}
/* DO NOT USE! Only used in serialization of special scrolls that originally derived from Item */
protected bool InheritsItem { get; private set; }
public abstract int Message { get; }
public virtual int Title => 0;
public abstract string DefaultTitle { get; }
[CommandProperty(AccessLevel.GameMaster)]
public SkillName Skill { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public double Value { get; set; }
public virtual string GetNameLocalized() => $"#{AosSkillBonuses.GetLabel(Skill)}";
public virtual string GetName()
if (!IsChildOf(from.Backpack))
{
var index = (int)Skill;
var table = SkillInfo.Table;
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
return false;
}
if (index >= 0 && index < table.Length)
return true;
}
public virtual void Use(Mobile from)
{
}
public override void OnDoubleClick(Mobile from)
{
if (!CanUse(from))
{
return;
}
from.CloseGump<InternalGump>();
from.SendGump(new InternalGump(from, this));
}
public class InternalGump : Gump
{
private readonly Mobile _mobile;
private readonly SpecialScroll _scroll;
public InternalGump(Mobile mobile, SpecialScroll scroll) : base(25, 50)
{
_mobile = mobile;
_scroll = scroll;
AddPage(0);
AddBackground(25, 10, 420, 200, 5054);
AddImageTiled(33, 20, 401, 181, 2624);
AddAlphaRegion(33, 20, 401, 181);
AddHtmlLocalized(40, 48, 387, 100, _scroll.Message, true, true);
AddHtmlLocalized(125, 148, 200, 20, 1049478, 0xFFFFFF); // Do you wish to use this scroll?
AddButton(100, 172, 4005, 4007, 1);
AddHtmlLocalized(135, 172, 120, 20, 1046362, 0xFFFFFF); // Yes
AddButton(275, 172, 4005, 4007, 0);
AddHtmlLocalized(310, 172, 120, 20, 1046363, 0xFFFFFF); // No
if (_scroll.Title != 0)
{
return table[index].Name.ToLower();
AddHtmlLocalized(40, 20, 260, 20, _scroll.Title, 0xFFFFFF);
}
else
{
AddHtml(40, 20, 260, 20, _scroll.DefaultTitle);
}
return "???";
var skillLabel = _scroll is StatCapScroll ? 1038019 : AosSkillBonuses.GetLabel(_scroll.Skill);
AddHtmlLocalized(310, 20, 120, 20, skillLabel, 0xFFFFFF); // Power
}
public virtual bool CanUse(Mobile from)
public override void OnResponse(NetState state, RelayInfo info)
{
if (Deleted)
if (info.ButtonID == 1)
{
return false;
}
if (!IsChildOf(from.Backpack))
{
from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it.
return false;
}
return true;
}
public virtual void Use(Mobile from)
{
}
public override void OnDoubleClick(Mobile from)
{
if (!CanUse(from))
{
return;
}
from.CloseGump<InternalGump>();
from.SendGump(new InternalGump(from, this));
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
writer.Write((int)Skill);
writer.Write(Value);
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = reader.ReadInt();
switch (version)
{
case 1:
{
Skill = (SkillName)reader.ReadInt();
Value = reader.ReadDouble();
break;
}
case 0:
{
InheritsItem = true;
if (this is not StatCapScroll)
{
Skill = (SkillName)reader.ReadInt();
}
else
{
Skill = SkillName.Alchemy;
}
if (this is ScrollofAlacrity)
{
Value = 0.0;
}
else if (this is StatCapScroll)
{
Value = reader.ReadInt();
}
else
{
Value = reader.ReadDouble();
}
break;
}
}
}
public class InternalGump : Gump
{
private readonly Mobile m_Mobile;
private readonly SpecialScroll m_Scroll;
public InternalGump(Mobile mobile, SpecialScroll scroll) : base(25, 50)
{
m_Mobile = mobile;
m_Scroll = scroll;
AddPage(0);
AddBackground(25, 10, 420, 200, 5054);
AddImageTiled(33, 20, 401, 181, 2624);
AddAlphaRegion(33, 20, 401, 181);
AddHtmlLocalized(40, 48, 387, 100, m_Scroll.Message, true, true);
AddHtmlLocalized(125, 148, 200, 20, 1049478, 0xFFFFFF); // Do you wish to use this scroll?
AddButton(100, 172, 4005, 4007, 1);
AddHtmlLocalized(135, 172, 120, 20, 1046362, 0xFFFFFF); // Yes
AddButton(275, 172, 4005, 4007, 0);
AddHtmlLocalized(310, 172, 120, 20, 1046363, 0xFFFFFF); // No
if (m_Scroll.Title != 0)
{
AddHtmlLocalized(40, 20, 260, 20, m_Scroll.Title, 0xFFFFFF);
}
else
{
AddHtml(40, 20, 260, 20, m_Scroll.DefaultTitle);
}
if (m_Scroll is StatCapScroll)
{
AddHtmlLocalized(310, 20, 120, 20, 1038019, 0xFFFFFF); // Power
}
else
{
AddHtmlLocalized(310, 20, 120, 20, AosSkillBonuses.GetLabel(m_Scroll.Skill), 0xFFFFFF);
}
}
public override void OnResponse(NetState state, RelayInfo info)
{
if (info.ButtonID == 1)
{
m_Scroll.Use(m_Mobile);
}
_scroll.Use(_mobile);
}
}
}

View file

@ -1,206 +1,185 @@
using ModernUO.Serialization;
using Server.Mobiles;
namespace Server.Items
namespace Server.Items;
[SerializationGenerator(0, false)]
public partial class StatCapScroll : SpecialScroll
{
public class StatCapScroll : SpecialScroll
[Constructible]
public StatCapScroll(int value = 105) : base(SkillName.Alchemy, value) => Hue = 0x481;
/* 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.
* You can view your maximum skill values in your skills window.
* You can view your maximum statistic value in your statistics window.
*/
public override int Message => 1049469;
public override int Title
{
[Constructible]
public StatCapScroll(int value = 105) : base(SkillName.Alchemy, value) => Hue = 0x481;
public StatCapScroll(Serial serial) : base(serial)
{
}
/* 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.
* You can view your maximum skill values in your skills window.
* You can view your maximum statistic value in your statistics window.
*/
public override int Message =>
1049469;
public override int Title
{
get
{
var level = ((int)Value - 230) / 5;
/* Wonderous Scroll (+5 Maximum Stats): OR
* Exalted Scroll (+10 Maximum Stats): OR
* Mythical Scroll (+15 Maximum Stats): OR
* Legendary Scroll (+20 Maximum Stats): OR
* Ultimate Scroll (+25 Maximum Stats):
*/
if (level >= 0 && level <= 4 && Value % 5 == 0)
{
return 1049458 + level;
}
return 0;
}
}
public override string DefaultTitle =>
$"<basefont color=#FFFFFF>Power Scroll ({((int)Value - 225 >= 0 ? "+" : "")}{(int)Value - 225} Maximum Stats):</basefont>";
public override void AddNameProperty(IPropertyList list)
get
{
var level = ((int)Value - 230) / 5;
if (level >= 0 && level <= 4 && (int)Value % 5 == 0)
/* a wonderous scroll of ~1_type~ (+5 Maximum Stats) OR
* an exalted scroll of ~1_type~ (+10 Maximum Stats) OR
* a mythical scroll of ~1_type~ (+15 Maximum Stats) OR
* a legendary scroll of ~1_type~ (+20 Maximum Stats) OR
* an ultimate scroll of ~1_type~ (+25 Maximum Stats)
*/
/* Wondrous Scroll (+5 Maximum Stats): OR
* Exalted Scroll (+10 Maximum Stats): OR
* Mythical Scroll (+15 Maximum Stats): OR
* Legendary Scroll (+20 Maximum Stats): OR
* Ultimate Scroll (+25 Maximum Stats):
*/
if (level is >= 0 and <= 4 && Value % 5 == 0)
{
list.Add(1049463 + level, "#1049476");
}
else
{
var diff = Value - 225;
list.Add($"a scroll of power ({(diff >= 0 ? "+" : "")}{diff} Maximum Stats)");
}
}
public override void OnSingleClick(Mobile from)
{
var level = ((int)Value - 230) / 5;
if (level >= 0 && level <= 4 && (int)Value % 5 == 0)
{
LabelTo(from, 1049463 + level, "#1049476");
}
else
{
var diff = Value - 225;
LabelTo(from, $"a scroll of power ({(diff >= 0 ? "+" : "")}{diff} Maximum Stats)");
}
}
public override bool CanUse(Mobile from)
{
if (!base.CanUse(from))
{
return false;
return 1049458 + level;
}
var newValue = (int)Value;
if (from is PlayerMobile mobile && mobile.HasStatReward)
{
newValue += 5;
}
if (from.StatCap >= newValue)
{
from.SendLocalizedMessage(1049510); // Your stats are too high for this power scroll.
return false;
}
return true;
}
public override void Use(Mobile from)
{
if (!CanUse(from))
{
return;
}
from.SendLocalizedMessage(1049512); // You feel a surge of magic as the scroll enhances your powers!
if (from is PlayerMobile mobile && mobile.HasStatReward)
{
mobile.StatCap = (int)Value + 5;
}
else
{
from.StatCap = (int)Value;
}
Effects.SendLocationParticles(
EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration),
0,
0,
0,
0,
0,
5060,
0
);
Effects.PlaySound(from.Location, from.Map, 0x243);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
Delete();
}
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(IGenericReader reader)
{
base.Deserialize(reader);
var version = InheritsItem ? 0 : reader.ReadInt(); // Required for SpecialScroll insertion
LootType = LootType.Cursed;
Insured = false;
return 0;
}
}
public override string DefaultTitle =>
$"<basefont color=#FFFFFF>Power Scroll ({((int)Value - 225 >= 0 ? "+" : "")}{(int)Value - 225} Maximum Stats):</basefont>";
public override void AddNameProperty(IPropertyList list)
{
var level = ((int)Value - 230) / 5;
if (level is >= 0 and <= 4 && (int)Value % 5 == 0)
{
/* a wondrous scroll of ~1_type~ (+5 Maximum Stats) OR
* an exalted scroll of ~1_type~ (+10 Maximum Stats) OR
* a mythical scroll of ~1_type~ (+15 Maximum Stats) OR
* a legendary scroll of ~1_type~ (+20 Maximum Stats) OR
* an ultimate scroll of ~1_type~ (+25 Maximum Stats)
*/
list.Add(1049463 + level, 1049476);
}
else
{
var diff = Value - 225;
list.Add($"a scroll of power ({(diff >= 0 ? "+" : "")}{diff} Maximum Stats)");
}
}
public override void OnSingleClick(Mobile from)
{
var level = ((int)Value - 230) / 5;
if (level is >= 0 and <= 4 && (int)Value % 5 == 0)
{
LabelTo(from, 1049463 + level, "#1049476");
}
else
{
var diff = Value - 225;
LabelTo(from, $"a scroll of power ({(diff >= 0 ? "+" : "")}{diff} Maximum Stats)");
}
}
public override bool CanUse(Mobile from)
{
if (!base.CanUse(from))
{
return false;
}
var newValue = (int)Value;
if (from is PlayerMobile { HasStatReward: true })
{
newValue += 5;
}
if (from.StatCap >= newValue)
{
from.SendLocalizedMessage(1049510); // Your stats are too high for this power scroll.
return false;
}
return true;
}
public override void Use(Mobile from)
{
if (!CanUse(from))
{
return;
}
from.SendLocalizedMessage(1049512); // You feel a surge of magic as the scroll enhances your powers!
if (from is PlayerMobile { HasStatReward: true } mobile)
{
mobile.StatCap = (int)Value + 5;
}
else
{
from.StatCap = (int)Value;
}
Effects.SendLocationParticles(
EffectItem.Create(from.Location, from.Map, EffectItem.DefaultDuration),
0,
0,
0,
0,
0,
5060,
0
);
Effects.PlaySound(from.Location, from.Map, 0x243);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 6, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 4, from.Y - 6, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendMovingParticles(
new Entity(Serial.Zero, new Point3D(from.X - 6, from.Y - 4, from.Z + 15), from.Map),
from,
0x36D4,
7,
0,
false,
true,
0x497,
0,
9502,
1,
0,
(EffectLayer)255,
0x100
);
Effects.SendTargetParticles(from, 0x375A, 35, 90, 0x00, 0x00, 9502, (EffectLayer)255, 0x100);
Delete();
}
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.PowerScroll"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.ScrollofAlacrity"
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.ScrollofTranscendence"
}

View file

@ -0,0 +1,19 @@
{
"version": 0,
"type": "Server.Items.SpecialScroll",
"properties": [
{
"name": "Skill",
"type": "Server.SkillName",
"rule": "EnumMigrationRule"
},
{
"name": "Value",
"type": "double",
"rule": "PrimitiveTypeMigrationRule",
"ruleArguments": [
""
]
}
]
}

View file

@ -0,0 +1,4 @@
{
"version": 0,
"type": "Server.Items.StatCapScroll"
}

View file

@ -223,7 +223,7 @@ namespace Server.Misc
// The new AOS bankboxes don't have powerscrolls, they are automatically 'applied':
for (var i = 0; i < PowerScroll.Skills.Count; ++i)
for (var i = 0; i < PowerScroll.Skills.Length; ++i)
{
m.Skills[PowerScroll.Skills[i]].Cap = 120.0;
}
@ -658,7 +658,7 @@ namespace Server.Misc
{
var bag = new Bag();
for (var i = 0; i < PowerScroll.Skills.Count; ++i)
for (var i = 0; i < PowerScroll.Skills.Length; ++i)
{
bag.DropItem(new PowerScroll(PowerScroll.Skills[i], 120.0));
}