From baed849f10a5284913652835be5662e9ea1840c8 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Fri, 16 Jun 2023 05:55:55 -0700 Subject: [PATCH] feat: Moves skills to json file (#1411) --- Distribution/Data/skills.json | 814 ++++++++++++++++++ .../Packets/Outgoing/PlayerPacketTests.cs | 40 - Projects/Server/Skills.cs | 74 +- .../UOContent.Tests/Fixtures/ServerFixture.cs | 9 + .../Tests/Skills/SkillPacketsTests.cs | 51 ++ .../UOContent.Tests/UOContent.Tests.csproj | 4 + .../Configuration/ExpansionConfiguration.cs | 2 - Projects/UOContent/Skills/SkillsInfo.cs | 17 + .../UOContent/Skills/Tracking/Tracking.cs | 4 + 9 files changed, 906 insertions(+), 109 deletions(-) create mode 100644 Distribution/Data/skills.json create mode 100644 Projects/UOContent.Tests/Tests/Skills/SkillPacketsTests.cs create mode 100644 Projects/UOContent/Skills/SkillsInfo.cs diff --git a/Distribution/Data/skills.json b/Distribution/Data/skills.json new file mode 100644 index 000000000..3349f359a --- /dev/null +++ b/Distribution/Data/skills.json @@ -0,0 +1,814 @@ +[ + { + "SkillID": 0, + "Name": "Alchemy", + "Title": "Alchemist", + "StrScale": 0, + "DexScale": 0.05, + "IntScale": 0.05, + "StatTotal": 10, + "StrGain": 0, + "DexGain": 0.5, + "IntGain": 0.5, + "GainFactor": 1, + "ProfessionSkillName": "Alchemy" + }, + { + "SkillID": 1, + "Name": "Anatomy", + "Title": "Biologist", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0.15, + "DexGain": 0.15, + "IntGain": 0.7, + "GainFactor": 1, + "ProfessionSkillName": "Anatomy" + }, + { + "SkillID": 2, + "Name": "Animal Lore", + "Title": "Naturalist", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 1, + "GainFactor": 1, + "ProfessionSkillName": "AnimalLore" + }, + { + "SkillID": 3, + "Name": "Item Identification", + "Title": "Merchant", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 1, + "GainFactor": 1, + "ProfessionSkillName": "ItemID" + }, + { + "SkillID": 4, + "Name": "Arms Lore", + "Title": "Weapon Master", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0.75, + "DexGain": 0.15, + "IntGain": 0.1, + "GainFactor": 1, + "ProfessionSkillName": "ArmsLore" + }, + { + "SkillID": 5, + "Name": "Parrying", + "Title": "Duelist", + "StrScale": 0.075, + "DexScale": 0.025, + "IntScale": 0, + "StatTotal": 10, + "StrGain": 0.75, + "DexGain": 0.25, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Parrying" + }, + { + "SkillID": 6, + "Name": "Begging", + "Title": "Beggar", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Begging" + }, + { + "SkillID": 7, + "Name": "Blacksmithy", + "Title": "Blacksmith", + "StrScale": 0.1, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 10, + "StrGain": 1, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Blacksmith" + }, + { + "SkillID": 8, + "Name": "Bowcraft/Fletching", + "Title": "Bowyer", + "StrScale": 0.06, + "DexScale": 0.16, + "IntScale": 0, + "StatTotal": 22, + "StrGain": 0.6, + "DexGain": 1.6, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Bowcraft" + }, + { + "SkillID": 9, + "Name": "Peacemaking", + "Title": "Pacifier", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Peacemaking" + }, + { + "SkillID": 10, + "Name": "Camping", + "Title": "Explorer", + "StrScale": 0.2, + "DexScale": 0.15, + "IntScale": 0.15, + "StatTotal": 50, + "StrGain": 2, + "DexGain": 1.5, + "IntGain": 1.5, + "GainFactor": 1, + "ProfessionSkillName": "Camping" + }, + { + "SkillID": 11, + "Name": "Carpentry", + "Title": "Carpenter", + "StrScale": 0.2, + "DexScale": 0.05, + "IntScale": 0, + "StatTotal": 25, + "StrGain": 2, + "DexGain": 0.5, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Carpentry" + }, + { + "SkillID": 12, + "Name": "Cartography", + "Title": "Cartographer", + "StrScale": 0, + "DexScale": 0.075, + "IntScale": 0.075, + "StatTotal": 15, + "StrGain": 0, + "DexGain": 0.75, + "IntGain": 0.75, + "GainFactor": 1, + "ProfessionSkillName": "Cartography" + }, + { + "SkillID": 13, + "Name": "Cooking", + "Title": "Chef", + "StrScale": 0, + "DexScale": 0.2, + "IntScale": 0.3, + "StatTotal": 50, + "StrGain": 0, + "DexGain": 2, + "IntGain": 3, + "GainFactor": 1, + "ProfessionSkillName": "Cooking" + }, + { + "SkillID": 14, + "Name": "Detecting Hidden", + "Title": "Scout", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0.4, + "IntGain": 0.6, + "GainFactor": 1, + "ProfessionSkillName": "DetectingHidden" + }, + { + "SkillID": 15, + "Name": "Discordance", + "Title": "Demoralizer", + "StrScale": 0, + "DexScale": 0.025, + "IntScale": 0.025, + "StatTotal": 5, + "StrGain": 0, + "DexGain": 0.25, + "IntGain": 0.25, + "GainFactor": 1, + "ProfessionSkillName": "Enticement" + }, + { + "SkillID": 16, + "Name": "Evaluating Intelligence", + "Title": "Scholar", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 1, + "GainFactor": 1, + "ProfessionSkillName": "EvaluateIntelligence" + }, + { + "SkillID": 17, + "Name": "Healing", + "Title": "Healer", + "StrScale": 0.06, + "DexScale": 0.06, + "IntScale": 0.08, + "StatTotal": 20, + "StrGain": 0.6, + "DexGain": 0.6, + "IntGain": 0.8, + "GainFactor": 1, + "ProfessionSkillName": "Healing" + }, + { + "SkillID": 18, + "Name": "Fishing", + "Title": "Fisherman", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0.5, + "DexGain": 0.5, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Fishing" + }, + { + "SkillID": 19, + "Name": "Forensic Evaluation", + "Title": "Detective", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0.2, + "IntGain": 0.8, + "GainFactor": 1, + "ProfessionSkillName": "ForensicEvaluation" + }, + { + "SkillID": 20, + "Name": "Herding", + "Title": "Shepherd", + "StrScale": 0.1625, + "DexScale": 0.0625, + "IntScale": 0.025, + "StatTotal": 25, + "StrGain": 1.625, + "DexGain": 0.625, + "IntGain": 0.25, + "GainFactor": 1, + "ProfessionSkillName": "Herding" + }, + { + "SkillID": 21, + "Name": "Hiding", + "Title": "Shade", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0.8, + "IntGain": 0.2, + "GainFactor": 1, + "ProfessionSkillName": "Hiding" + }, + { + "SkillID": 22, + "Name": "Provocation", + "Title": "Rouser", + "StrScale": 0, + "DexScale": 0.045, + "IntScale": 0.005, + "StatTotal": 5, + "StrGain": 0, + "DexGain": 0.45, + "IntGain": 0.05, + "GainFactor": 1, + "ProfessionSkillName": "Provocation" + }, + { + "SkillID": 23, + "Name": "Inscription", + "Title": "Scribe", + "StrScale": 0, + "DexScale": 0.02, + "IntScale": 0.08, + "StatTotal": 10, + "StrGain": 0, + "DexGain": 0.2, + "IntGain": 0.8, + "GainFactor": 1, + "ProfessionSkillName": "Inscription" + }, + { + "SkillID": 24, + "Name": "Lockpicking", + "Title": "Infiltrator", + "StrScale": 0, + "DexScale": 0.25, + "IntScale": 0, + "StatTotal": 25, + "StrGain": 0, + "DexGain": 2, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Lockpicking" + }, + { + "SkillID": 25, + "Name": "Magery", + "Title": "Mage", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0.15, + "StatTotal": 15, + "StrGain": 0, + "DexGain": 0, + "IntGain": 1.5, + "GainFactor": 1, + "ProfessionSkillName": "Magery" + }, + { + "SkillID": 26, + "Name": "Resisting Spells", + "Title": "Warder", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0.25, + "DexGain": 0.25, + "IntGain": 0.5, + "GainFactor": 1, + "ProfessionSkillName": "ResistingSpells" + }, + { + "SkillID": 27, + "Name": "Tactics", + "Title": "Tactician", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Tactics" + }, + { + "SkillID": 28, + "Name": "Snooping", + "Title": "Spy", + "StrScale": 0, + "DexScale": 0.25, + "IntScale": 0, + "StatTotal": 25, + "StrGain": 0, + "DexGain": 2.5, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Snooping" + }, + { + "SkillID": 29, + "Name": "Musicianship", + "Title": "Bard", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0.8, + "IntGain": 0.2, + "GainFactor": 1, + "ProfessionSkillName": "Musicianship" + }, + { + "SkillID": 30, + "Name": "Poisoning", + "Title": "Assassin", + "StrScale": 0, + "DexScale": 0.04, + "IntScale": 0.16, + "StatTotal": 20, + "StrGain": 0, + "DexGain": 0.4, + "IntGain": 1.6, + "GainFactor": 1, + "ProfessionSkillName": "Poisoning" + }, + { + "SkillID": 31, + "Name": "Archery", + "Title": "Archer", + "StrScale": 0.025, + "DexScale": 0.075, + "IntScale": 0, + "StatTotal": 10, + "StrGain": 0.25, + "DexGain": 0.75, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Archery" + }, + { + "SkillID": 32, + "Name": "Spirit Speak", + "Title": "Medium", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 1, + "GainFactor": 1, + "ProfessionSkillName": "SpiritSpeak" + }, + { + "SkillID": 33, + "Name": "Stealing", + "Title": "Pickpocket", + "StrScale": 0, + "DexScale": 0.1, + "IntScale": 0, + "StatTotal": 10, + "StrGain": 0, + "DexGain": 1, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Stealing" + }, + { + "SkillID": 34, + "Name": "Tailoring", + "Title": "Tailor", + "StrScale": 0.0375, + "DexScale": 0.1625, + "IntScale": 0.05, + "StatTotal": 25, + "StrGain": 0.38, + "DexGain": 1.63, + "IntGain": 0.5, + "GainFactor": 1, + "ProfessionSkillName": "Tailoring" + }, + { + "SkillID": 35, + "Name": "Animal Taming", + "Title": "Tamer", + "StrScale": 0.14, + "DexScale": 0.02, + "IntScale": 0.04, + "StatTotal": 20, + "StrGain": 1.4, + "DexGain": 0.2, + "IntGain": 0.4, + "GainFactor": 1, + "ProfessionSkillName": "AnimalTaming" + }, + { + "SkillID": 36, + "Name": "Taste Identification", + "Title": "Praegustator", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0.2, + "DexGain": 0, + "IntGain": 0.8, + "GainFactor": 1, + "ProfessionSkillName": "TasteIdentification" + }, + { + "SkillID": 37, + "Name": "Tinkering", + "Title": "Tinker", + "StrScale": 0.05, + "DexScale": 0.02, + "IntScale": 0.03, + "StatTotal": 10, + "StrGain": 0.5, + "DexGain": 0.2, + "IntGain": 0.3, + "GainFactor": 1, + "ProfessionSkillName": "Tinkering" + }, + { + "SkillID": 38, + "Name": "Tracking", + "Title": "Ranger", + "StrScale": 0, + "DexScale": 0.125, + "IntScale": 0.125, + "StatTotal": 25, + "StrGain": 0, + "DexGain": 1.25, + "IntGain": 1.25, + "GainFactor": 1, + "ProfessionSkillName": "Tracking" + }, + { + "SkillID": 39, + "Name": "Veterinary", + "Title": "Veterinarian", + "StrScale": 0.08, + "DexScale": 0.04, + "IntScale": 0.08, + "StatTotal": 20, + "StrGain": 0.8, + "DexGain": 0.4, + "IntGain": 0.8, + "GainFactor": 1, + "ProfessionSkillName": "Veterinary" + }, + { + "SkillID": 40, + "Name": "Swordsmanship", + "Title": "Swordsman", + "StrScale": 0.075, + "DexScale": 0.025, + "IntScale": 0, + "StatTotal": 10, + "StrGain": 0.75, + "DexGain": 0.25, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Swordsmanship" + }, + { + "SkillID": 41, + "Name": "Mace Fighting", + "Title": "Armsman", + "StrScale": 0.09, + "DexScale": 0.01, + "IntScale": 0, + "StatTotal": 10, + "StrGain": 0.9, + "DexGain": 0.1, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "MaceFighting" + }, + { + "SkillID": 42, + "Name": "Fencing", + "Title": "Fencer", + "StrScale": 0.045, + "DexScale": 0.055, + "IntScale": 0, + "StatTotal": 10, + "StrGain": 0.45, + "DexGain": 0.55, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Fencing" + }, + { + "SkillID": 43, + "Name": "Wrestling", + "Title": "Wrestler", + "StrScale": 0.09, + "DexScale": 0.01, + "IntScale": 0, + "StatTotal": 10, + "StrGain": 0.9, + "DexGain": 0.1, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Wrestling" + }, + { + "SkillID": 44, + "Name": "Lumberjacking", + "Title": "Lumberjack", + "StrScale": 0.2, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 20, + "StrGain": 2, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Lumberjacking" + }, + { + "SkillID": 45, + "Name": "Mining", + "Title": "Miner", + "StrScale": 0.2, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 20, + "StrGain": 2, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Mining" + }, + { + "SkillID": 46, + "Name": "Meditation", + "Title": "Stoic", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Meditation" + }, + { + "SkillID": 47, + "Name": "Stealth", + "Title": "Rogue", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Stealth" + }, + { + "SkillID": 48, + "Name": "Remove Trap", + "Title": "Trap Specialist", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Disarm" + }, + { + "SkillID": 49, + "Name": "Necromancy", + "Title": "Necromancer", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Necromancy" + }, + { + "SkillID": 50, + "Name": "Focus", + "Title": "Driven", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Focus" + }, + { + "SkillID": 51, + "Name": "Chivalry", + "Title": "Paladin", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Chivalry" + }, + { + "SkillID": 52, + "Name": "Bushido", + "Title": "Samurai", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Bushido" + }, + { + "SkillID": 53, + "Name": "Ninjitsu", + "Title": "Ninja", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Ninjitsu" + }, + { + "SkillID": 54, + "Name": "Spellweaving", + "Title": "Arcanist", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Spellweaving" + }, + { + "SkillID": 55, + "Name": "Mysticism", + "Title": "Mystic", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Mysticism" + }, + { + "SkillID": 56, + "Name": "Imbuing", + "Title": "Artificer", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Imbuing" + }, + { + "SkillID": 57, + "Name": "Throwing", + "Title": "Bladeweaver", + "StrScale": 0, + "DexScale": 0, + "IntScale": 0, + "StatTotal": 0, + "StrGain": 0, + "DexGain": 0, + "IntGain": 0, + "GainFactor": 1, + "ProfessionSkillName": "Throwing" + } +] \ No newline at end of file diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs index 83e1553b8..399fb8706 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs @@ -126,24 +126,6 @@ namespace Server.Tests.Network AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Fact] - public void TestSkillsUpdate() - { - var m = new Mobile((Serial)0x1); - m.DefaultMobileInit(); - - var skills = m.Skills; - m.Skills[Utility.RandomSkill()].BaseFixedPoint = 1000; - - var expected = new SkillUpdate(skills).Compile(); - - var ns = PacketTestUtilities.CreateTestNetState(); - ns.SendSkillsUpdate(skills); - - var result = ns.SendPipe.Reader.TryRead(); - AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); - } - [Theory] [InlineData(0)] [InlineData(10)] @@ -159,28 +141,6 @@ namespace Server.Tests.Network AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } - [Theory] - [InlineData(SkillName.Alchemy, 0, 1)] - [InlineData(SkillName.Archery, 10, 1000)] - [InlineData(SkillName.Begging, 100000, 1000)] - public void TestSkillChange(SkillName skillName, int baseFixedPoint, int capFixedPoint) - { - var m = new Mobile((Serial)0x1); - m.DefaultMobileInit(); - - var skill = m.Skills[skillName]; - skill.BaseFixedPoint = baseFixedPoint; - skill.CapFixedPoint = capFixedPoint; - - var expected = new SkillChange(skill).Compile(); - - var ns = PacketTestUtilities.CreateTestNetState(); - ns.SendSkillChange(skill); - - var result = ns.SendPipe.Reader.TryRead(); - AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); - } - [Theory] [InlineData(null)] [InlineData("")] diff --git a/Projects/Server/Skills.cs b/Projects/Server/Skills.cs index 671e8ca35..6bbb8ebb1 100644 --- a/Projects/Server/Skills.cs +++ b/Projects/Server/Skills.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; using Server.Network; namespace Server; @@ -217,8 +218,6 @@ public class Skill set => CapFixedPoint = (int)(value * 10.0); } - public static bool UseStatMods { get; set; } - public int Fixed => (int)(Value * 10); [CommandProperty(AccessLevel.Counselor)] @@ -255,9 +254,9 @@ public class Skill inv /= 100.0; - var statsOffset = (UseStatMods ? Owner.Owner.Str : Owner.Owner.RawStr) * Info.StrScale + - (UseStatMods ? Owner.Owner.Dex : Owner.Owner.RawDex) * Info.DexScale + - (UseStatMods ? Owner.Owner.Int : Owner.Owner.RawInt) * Info.IntScale; + var statsOffset = Owner.Owner.RawStr * Info.StrScale + + Owner.Owner.RawDex * Info.DexScale + + Owner.Owner.RawInt * Info.IntScale; var statTotal = Info.StatTotal * inv; statsOffset *= inv; @@ -384,6 +383,7 @@ public class Skill public class SkillInfo { + [JsonConstructor] public SkillInfo( int skillID, string name, double strScale, double dexScale, double intScale, string title, SkillUseCallback callback, double strGain, double dexGain, double intGain, double gainFactor, @@ -431,67 +431,7 @@ public class SkillInfo public string ProfessionSkillName { get; set; } - public static SkillInfo[] Table { get; set; } = - { - new(0, "Alchemy", 0.0, 5.0, 5.0, "Alchemist", null, 0.0, 0.5, 0.5, 1.0), - new(1, "Anatomy", 0.0, 0.0, 0.0, "Biologist", null, 0.15, 0.15, 0.7, 1.0), - new(2, "Animal Lore", 0.0, 0.0, 0.0, "Naturalist", null, 0.0, 0.0, 1.0, 1.0), - new(3, "Item Identification", 0.0, 0.0, 0.0, "Merchant", null, 0.0, 0.0, 1.0, 1.0, "ItemID"), - new(4, "Arms Lore", 0.0, 0.0, 0.0, "Weapon Master", null, 0.75, 0.15, 0.1, 1.0), - new(5, "Parrying", 7.5, 2.5, 0.0, "Duelist", null, 0.75, 0.25, 0.0, 1.0), - new(6, "Begging", 0.0, 0.0, 0.0, "Beggar", null, 0.0, 0.0, 0.0, 1.0), - new(7, "Blacksmithy", 10.0, 0.0, 0.0, "Blacksmith", null, 1.0, 0.0, 0.0, 1.0, "Blacksmith"), - new(8, "Bowcraft/Fletching", 6.0, 16.0, 0.0, "Bowyer", null, 0.6, 1.6, 0.0, 1.0, "Bowcraft"), - new(9, "Peacemaking", 0.0, 0.0, 0.0, "Pacifier", null, 0.0, 0.0, 0.0, 1.0), - new(10, "Camping", 20.0, 15.0, 15.0, "Explorer", null, 2.0, 1.5, 1.5, 1.0), - new(11, "Carpentry", 20.0, 5.0, 0.0, "Carpenter", null, 2.0, 0.5, 0.0, 1.0), - new(12, "Cartography", 0.0, 7.5, 7.5, "Cartographer", null, 0.0, 0.75, 0.75, 1.0), - new(13, "Cooking", 0.0, 20.0, 30.0, "Chef", null, 0.0, 2.0, 3.0, 1.0), - new(14, "Detecting Hidden", 0.0, 0.0, 0.0, "Scout", null, 0.0, 0.4, 0.6, 1.0), - new(15, "Discordance", 0.0, 2.5, 2.5, "Demoralizer", null, 0.0, 0.25, 0.25, 1.0, "Enticement"), - new(16, "Evaluating Intelligence", 0.0, 0.0, 0.0, "Scholar", null, 0.0, 0.0, 1.0, 1.0, "EvaluateIntelligence"), - new(17, "Healing", 6.0, 6.0, 8.0, "Healer", null, 0.6, 0.6, 0.8, 1.0), - new(18, "Fishing", 0.0, 0.0, 0.0, "Fisherman", null, 0.5, 0.5, 0.0, 1.0), - new(19, "Forensic Evaluation", 0.0, 0.0, 0.0, "Detective", null, 0.0, 0.2, 0.8, 1.0), - new(20, "Herding", 16.25, 6.25, 2.5, "Shepherd", null, 1.625, 0.625, 0.25, 1.0), - new(21, "Hiding", 0.0, 0.0, 0.0, "Shade", null, 0.0, 0.8, 0.2, 1.0), - new(22, "Provocation", 0.0, 4.5, 0.5, "Rouser", null, 0.0, 0.45, 0.05, 1.0), - new(23, "Inscription", 0.0, 2.0, 8.0, "Scribe", null, 0.0, 0.2, 0.8, 1.0), - new(24, "Lockpicking", 0.0, 25.0, 0.0, "Infiltrator", null, 0.0, 2.0, 0.0, 1.0), - new(25, "Magery", 0.0, 0.0, 15.0, "Mage", null, 0.0, 0.0, 1.5, 1.0), - new(26, "Resisting Spells", 0.0, 0.0, 0.0, "Warder", null, 0.25, 0.25, 0.5, 1.0), - new(27, "Tactics", 0.0, 0.0, 0.0, "Tactician", null, 0.0, 0.0, 0.0, 1.0), - new(28, "Snooping", 0.0, 25.0, 0.0, "Spy", null, 0.0, 2.5, 0.0, 1.0), - new(29, "Musicianship", 0.0, 0.0, 0.0, "Bard", null, 0.0, 0.8, 0.2, 1.0), - new(30, "Poisoning", 0.0, 4.0, 16.0, "Assassin", null, 0.0, 0.4, 1.6, 1.0), - new(31, "Archery", 2.5, 7.5, 0.0, "Archer", null, 0.25, 0.75, 0.0, 1.0), - new(32, "Spirit Speak", 0.0, 0.0, 0.0, "Medium", null, 0.0, 0.0, 1.0, 1.0), - new(33, "Stealing", 0.0, 10.0, 0.0, "Pickpocket", null, 0.0, 1.0, 0.0, 1.0), - new(34, "Tailoring", 3.75, 16.25, 5.0, "Tailor", null, 0.38, 1.63, 0.5, 1.0), - new(35, "Animal Taming", 14.0, 2.0, 4.0, "Tamer", null, 1.4, 0.2, 0.4, 1.0), - new(36, "Taste Identification", 0.0, 0.0, 0.0, "Praegustator", null, 0.2, 0.0, 0.8, 1.0), - new(37, "Tinkering", 5.0, 2.0, 3.0, "Tinker", null, 0.5, 0.2, 0.3, 1.0), - new(38, "Tracking", 0.0, 12.5, 12.5, "Ranger", null, 0.0, 1.25, 1.25, 1.0), - new(39, "Veterinary", 8.0, 4.0, 8.0, "Veterinarian", null, 0.8, 0.4, 0.8, 1.0), - new(40, "Swordsmanship", 7.5, 2.5, 0.0, "Swordsman", null, 0.75, 0.25, 0.0, 1.0), - new(41, "Mace Fighting", 9.0, 1.0, 0.0, "Armsman", null, 0.9, 0.1, 0.0, 1.0), - new(42, "Fencing", 4.5, 5.5, 0.0, "Fencer", null, 0.45, 0.55, 0.0, 1.0), - new(43, "Wrestling", 9.0, 1.0, 0.0, "Wrestler", null, 0.9, 0.1, 0.0, 1.0), - new(44, "Lumberjacking", 20.0, 0.0, 0.0, "Lumberjack", null, 2.0, 0.0, 0.0, 1.0), - new(45, "Mining", 20.0, 0.0, 0.0, "Miner", null, 2.0, 0.0, 0.0, 1.0), - new(46, "Meditation", 0.0, 0.0, 0.0, "Stoic", null, 0.0, 0.0, 0.0, 1.0), - new(47, "Stealth", 0.0, 0.0, 0.0, "Rogue", null, 0.0, 0.0, 0.0, 1.0), - new(48, "Remove Trap", 0.0, 0.0, 0.0, "Trap Specialist", null, 0.0, 0.0, 0.0, 1.0, "Disarm"), - new(49, "Necromancy", 0.0, 0.0, 0.0, "Necromancer", null, 0.0, 0.0, 0.0, 1.0), - new(50, "Focus", 0.0, 0.0, 0.0, "Driven", null, 0.0, 0.0, 0.0, 1.0), - new(51, "Chivalry", 0.0, 0.0, 0.0, "Paladin", null, 0.0, 0.0, 0.0, 1.0), - new(52, "Bushido", 0.0, 0.0, 0.0, "Samurai", null, 0.0, 0.0, 0.0, 1.0), - new(53, "Ninjitsu", 0.0, 0.0, 0.0, "Ninja", null, 0.0, 0.0, 0.0, 1.0), - new(54, "Spellweaving", 0.0, 0.0, 0.0, "Arcanist", null, 0.0, 0.0, 0.0, 1.0), - new(55, "Mysticism", 0.0, 0.0, 0.0, "Mystic", null, 0.0, 0.0, 0.0, 1.0), - new(56, "Imbuing", 0.0, 0.0, 0.0, "Artificer", null, 0.0, 0.0, 0.0, 1.0), - new(57, "Throwing", 0.0, 0.0, 0.0, "Bladeweaver", null, 0.0, 0.0, 0.0, 1.0) - }; + public static SkillInfo[] Table { get; set; } = Array.Empty(); } [PropertyObject] @@ -532,8 +472,8 @@ public class Skills Cap = 7000; } + /*m_Total =*/ if (version < 3) - /*m_Total =*/ { reader.ReadInt(); } diff --git a/Projects/UOContent.Tests/Fixtures/ServerFixture.cs b/Projects/UOContent.Tests/Fixtures/ServerFixture.cs index a5cbdca8e..3a9d0c3d3 100644 --- a/Projects/UOContent.Tests/Fixtures/ServerFixture.cs +++ b/Projects/UOContent.Tests/Fixtures/ServerFixture.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Reflection; using Server.Misc; @@ -16,6 +17,14 @@ namespace Server.Tests // Load Configurations ServerConfiguration.Load(true); + // Load UOContent.dll into the type resolver + ServerConfiguration.AssemblyDirectories.Add(Core.BaseDirectory); + var assembles = new [] { "UOContent.dll" }; + AssemblyHandler.LoadAssemblies(assembles); + + // Load Skills + SkillsInfo.Configure(); + // Configure / Initialize TestMapDefinitions.ConfigureTestMapDefinitions(); diff --git a/Projects/UOContent.Tests/Tests/Skills/SkillPacketsTests.cs b/Projects/UOContent.Tests/Tests/Skills/SkillPacketsTests.cs new file mode 100644 index 000000000..a35b336bd --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Skills/SkillPacketsTests.cs @@ -0,0 +1,51 @@ +using System; +using Server; +using Server.Network; +using Server.Tests; +using Server.Tests.Network; +using Xunit; + +namespace UOContent.Tests; + +public class SkillPacketsTests : IClassFixture +{ + [Theory] + [InlineData(SkillName.Alchemy, 0, 1)] + [InlineData(SkillName.Archery, 10, 1000)] + [InlineData(SkillName.Begging, 100000, 1000)] + public void TestSkillChange(SkillName skillName, int baseFixedPoint, int capFixedPoint) + { + var m = new Mobile((Serial)0x1); + m.DefaultMobileInit(); + + var skill = m.Skills[skillName]; + skill.BaseFixedPoint = baseFixedPoint; + skill.CapFixedPoint = capFixedPoint; + + var expected = new SkillChange(skill).Compile(); + + var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendSkillChange(skill); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } + + [Fact] + public void TestSkillsUpdate() + { + var m = new Mobile((Serial)0x1); + m.DefaultMobileInit(); + + var skills = m.Skills; + m.Skills[Utility.RandomSkill()].BaseFixedPoint = 1000; + + var expected = new SkillUpdate(skills).Compile(); + + var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendSkillsUpdate(skills); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } +} diff --git a/Projects/UOContent.Tests/UOContent.Tests.csproj b/Projects/UOContent.Tests/UOContent.Tests.csproj index 8934554d3..b21a8c0df 100644 --- a/Projects/UOContent.Tests/UOContent.Tests.csproj +++ b/Projects/UOContent.Tests/UOContent.Tests.csproj @@ -10,5 +10,9 @@ + + + + diff --git a/Projects/UOContent/Configuration/ExpansionConfiguration.cs b/Projects/UOContent/Configuration/ExpansionConfiguration.cs index ada2e3282..2399a58b5 100644 --- a/Projects/UOContent/Configuration/ExpansionConfiguration.cs +++ b/Projects/UOContent/Configuration/ExpansionConfiguration.cs @@ -17,8 +17,6 @@ namespace Server if (Core.AOS) { - AOS.DisableStatInfluences(); - if (ObjectPropertyList.Enabled) { // single click for everything is overridden to check object property list diff --git a/Projects/UOContent/Skills/SkillsInfo.cs b/Projects/UOContent/Skills/SkillsInfo.cs new file mode 100644 index 000000000..68cd7897d --- /dev/null +++ b/Projects/UOContent/Skills/SkillsInfo.cs @@ -0,0 +1,17 @@ +using System.IO; +using Server.Json; + +namespace Server; + +public static class SkillsInfo +{ + public static void Configure() + { + SkillInfo.Table = JsonConfig.Deserialize(Path.Combine(Core.BaseDirectory, "Data/skills.json")); + + if (Core.AOS) + { + AOS.DisableStatInfluences(); + } + } +} diff --git a/Projects/UOContent/Skills/Tracking/Tracking.cs b/Projects/UOContent/Skills/Tracking/Tracking.cs index 805d2aed3..56163f180 100644 --- a/Projects/UOContent/Skills/Tracking/Tracking.cs +++ b/Projects/UOContent/Skills/Tracking/Tracking.cs @@ -15,6 +15,10 @@ namespace Server.SkillHandlers public static unsafe void Configure() { IncomingExtendedCommandPackets.RegisterExtended(0x07, true, &QuestArrow); + } + + public static void Initialize() + { SkillInfo.Table[(int)SkillName.Tracking].Callback = OnUse; }