feat: Adds configurable skill and stat gain (#1489)
### Summary - Adds the following configurations: ```json "stats.statMax": "125", "stats.gainChanceMultiplier": 1.0, "stats.primaryStatGainChance": 0.75, "stats.gainDelay": "00:10:00", "stats.petGainDelay": "00:05:00", "stats.usePub45StatGain": "False" ``` - Adds Pub 45 stat gain rate for UOML+. - Reduces the gain delay for legacy stat gain from 15 minutes to 10 minutes. - Legacy gain no longer requires a gain in skill to gain in a stat.
This commit is contained in:
parent
29c7d839a7
commit
f9517854d0
4 changed files with 311 additions and 118 deletions
|
|
@ -11,7 +11,9 @@
|
|||
"DexGain": 0.5,
|
||||
"IntGain": 0.5,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Alchemy"
|
||||
"ProfessionSkillName": "Alchemy",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 1,
|
||||
|
|
@ -25,7 +27,9 @@
|
|||
"DexGain": 0.15,
|
||||
"IntGain": 0.7,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Anatomy"
|
||||
"ProfessionSkillName": "Anatomy",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 2,
|
||||
|
|
@ -39,7 +43,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 1,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "AnimalLore"
|
||||
"ProfessionSkillName": "AnimalLore",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 3,
|
||||
|
|
@ -53,7 +59,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 1,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "ItemID"
|
||||
"ProfessionSkillName": "ItemID",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 4,
|
||||
|
|
@ -67,7 +75,9 @@
|
|||
"DexGain": 0.15,
|
||||
"IntGain": 0.1,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "ArmsLore"
|
||||
"ProfessionSkillName": "ArmsLore",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 5,
|
||||
|
|
@ -81,7 +91,9 @@
|
|||
"DexGain": 0.25,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Parrying"
|
||||
"ProfessionSkillName": "Parrying",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 6,
|
||||
|
|
@ -95,7 +107,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Begging"
|
||||
"ProfessionSkillName": "Begging",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 7,
|
||||
|
|
@ -109,7 +123,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Blacksmith"
|
||||
"ProfessionSkillName": "Blacksmith",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 8,
|
||||
|
|
@ -123,7 +139,9 @@
|
|||
"DexGain": 1.6,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Bowcraft"
|
||||
"ProfessionSkillName": "Bowcraft",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 9,
|
||||
|
|
@ -137,7 +155,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Peacemaking"
|
||||
"ProfessionSkillName": "Peacemaking",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 10,
|
||||
|
|
@ -151,7 +171,9 @@
|
|||
"DexGain": 1.5,
|
||||
"IntGain": 1.5,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Camping"
|
||||
"ProfessionSkillName": "Camping",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 11,
|
||||
|
|
@ -165,7 +187,9 @@
|
|||
"DexGain": 0.5,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Carpentry"
|
||||
"ProfessionSkillName": "Carpentry",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 12,
|
||||
|
|
@ -179,7 +203,9 @@
|
|||
"DexGain": 0.75,
|
||||
"IntGain": 0.75,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Cartography"
|
||||
"ProfessionSkillName": "Cartography",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 13,
|
||||
|
|
@ -193,7 +219,9 @@
|
|||
"DexGain": 2,
|
||||
"IntGain": 3,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Cooking"
|
||||
"ProfessionSkillName": "Cooking",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 14,
|
||||
|
|
@ -207,7 +235,9 @@
|
|||
"DexGain": 0.4,
|
||||
"IntGain": 0.6,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "DetectingHidden"
|
||||
"ProfessionSkillName": "DetectingHidden",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 15,
|
||||
|
|
@ -221,7 +251,9 @@
|
|||
"DexGain": 0.25,
|
||||
"IntGain": 0.25,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Enticement"
|
||||
"ProfessionSkillName": "Enticement",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 16,
|
||||
|
|
@ -235,7 +267,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 1,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "EvaluateIntelligence"
|
||||
"ProfessionSkillName": "EvaluateIntelligence",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 17,
|
||||
|
|
@ -249,7 +283,9 @@
|
|||
"DexGain": 0.6,
|
||||
"IntGain": 0.8,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Healing"
|
||||
"ProfessionSkillName": "Healing",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 18,
|
||||
|
|
@ -263,7 +299,9 @@
|
|||
"DexGain": 0.5,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Fishing"
|
||||
"ProfessionSkillName": "Fishing",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 19,
|
||||
|
|
@ -277,7 +315,9 @@
|
|||
"DexGain": 0.2,
|
||||
"IntGain": 0.8,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "ForensicEvaluation"
|
||||
"ProfessionSkillName": "ForensicEvaluation",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 20,
|
||||
|
|
@ -291,7 +331,9 @@
|
|||
"DexGain": 0.625,
|
||||
"IntGain": 0.25,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Herding"
|
||||
"ProfessionSkillName": "Herding",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 21,
|
||||
|
|
@ -305,7 +347,9 @@
|
|||
"DexGain": 0.8,
|
||||
"IntGain": 0.2,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Hiding"
|
||||
"ProfessionSkillName": "Hiding",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 22,
|
||||
|
|
@ -319,7 +363,9 @@
|
|||
"DexGain": 0.45,
|
||||
"IntGain": 0.05,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Provocation"
|
||||
"ProfessionSkillName": "Provocation",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 23,
|
||||
|
|
@ -333,7 +379,9 @@
|
|||
"DexGain": 0.2,
|
||||
"IntGain": 0.8,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Inscription"
|
||||
"ProfessionSkillName": "Inscription",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 24,
|
||||
|
|
@ -347,7 +395,9 @@
|
|||
"DexGain": 2,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Lockpicking"
|
||||
"ProfessionSkillName": "Lockpicking",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 25,
|
||||
|
|
@ -361,7 +411,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 1.5,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Magery"
|
||||
"ProfessionSkillName": "Magery",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 26,
|
||||
|
|
@ -375,7 +427,9 @@
|
|||
"DexGain": 0.25,
|
||||
"IntGain": 0.5,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "ResistingSpells"
|
||||
"ProfessionSkillName": "ResistingSpells",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 27,
|
||||
|
|
@ -389,7 +443,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Tactics"
|
||||
"ProfessionSkillName": "Tactics",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 28,
|
||||
|
|
@ -403,7 +459,9 @@
|
|||
"DexGain": 2.5,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Snooping"
|
||||
"ProfessionSkillName": "Snooping",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 29,
|
||||
|
|
@ -417,7 +475,9 @@
|
|||
"DexGain": 0.8,
|
||||
"IntGain": 0.2,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Musicianship"
|
||||
"ProfessionSkillName": "Musicianship",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 30,
|
||||
|
|
@ -431,7 +491,9 @@
|
|||
"DexGain": 0.4,
|
||||
"IntGain": 1.6,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Poisoning"
|
||||
"ProfessionSkillName": "Poisoning",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 31,
|
||||
|
|
@ -445,7 +507,9 @@
|
|||
"DexGain": 0.75,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Archery"
|
||||
"ProfessionSkillName": "Archery",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 32,
|
||||
|
|
@ -459,7 +523,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 1,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "SpiritSpeak"
|
||||
"ProfessionSkillName": "SpiritSpeak",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 33,
|
||||
|
|
@ -473,7 +539,9 @@
|
|||
"DexGain": 1,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Stealing"
|
||||
"ProfessionSkillName": "Stealing",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 34,
|
||||
|
|
@ -487,7 +555,9 @@
|
|||
"DexGain": 1.63,
|
||||
"IntGain": 0.5,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Tailoring"
|
||||
"ProfessionSkillName": "Tailoring",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 35,
|
||||
|
|
@ -501,7 +571,9 @@
|
|||
"DexGain": 0.2,
|
||||
"IntGain": 0.4,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "AnimalTaming"
|
||||
"ProfessionSkillName": "AnimalTaming",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 36,
|
||||
|
|
@ -515,7 +587,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0.8,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "TasteIdentification"
|
||||
"ProfessionSkillName": "TasteIdentification",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 37,
|
||||
|
|
@ -529,7 +603,9 @@
|
|||
"DexGain": 0.2,
|
||||
"IntGain": 0.3,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Tinkering"
|
||||
"ProfessionSkillName": "Tinkering",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 38,
|
||||
|
|
@ -543,7 +619,9 @@
|
|||
"DexGain": 1.25,
|
||||
"IntGain": 1.25,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Tracking"
|
||||
"ProfessionSkillName": "Tracking",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 39,
|
||||
|
|
@ -557,7 +635,9 @@
|
|||
"DexGain": 0.4,
|
||||
"IntGain": 0.8,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Veterinary"
|
||||
"ProfessionSkillName": "Veterinary",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 40,
|
||||
|
|
@ -571,7 +651,9 @@
|
|||
"DexGain": 0.25,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Swordsmanship"
|
||||
"ProfessionSkillName": "Swordsmanship",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 41,
|
||||
|
|
@ -585,7 +667,9 @@
|
|||
"DexGain": 0.1,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "MaceFighting"
|
||||
"ProfessionSkillName": "MaceFighting",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 42,
|
||||
|
|
@ -599,7 +683,9 @@
|
|||
"DexGain": 0.55,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Fencing"
|
||||
"ProfessionSkillName": "Fencing",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 43,
|
||||
|
|
@ -613,7 +699,9 @@
|
|||
"DexGain": 0.1,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Wrestling"
|
||||
"ProfessionSkillName": "Wrestling",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 44,
|
||||
|
|
@ -627,7 +715,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Lumberjacking"
|
||||
"ProfessionSkillName": "Lumberjacking",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 45,
|
||||
|
|
@ -641,7 +731,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Mining"
|
||||
"ProfessionSkillName": "Mining",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Dex"
|
||||
},
|
||||
{
|
||||
"SkillID": 46,
|
||||
|
|
@ -655,7 +747,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Meditation"
|
||||
"ProfessionSkillName": "Meditation",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 47,
|
||||
|
|
@ -669,7 +763,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Stealth"
|
||||
"ProfessionSkillName": "Stealth",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 48,
|
||||
|
|
@ -683,7 +779,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Disarm"
|
||||
"ProfessionSkillName": "Disarm",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 49,
|
||||
|
|
@ -697,7 +795,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Necromancy"
|
||||
"ProfessionSkillName": "Necromancy",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 50,
|
||||
|
|
@ -711,7 +811,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Focus"
|
||||
"ProfessionSkillName": "Focus",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 51,
|
||||
|
|
@ -725,7 +827,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Chivalry"
|
||||
"ProfessionSkillName": "Chivalry",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 52,
|
||||
|
|
@ -739,7 +843,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Bushido"
|
||||
"ProfessionSkillName": "Bushido",
|
||||
"PrimaryStat": "Str",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 53,
|
||||
|
|
@ -753,7 +859,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Ninjitsu"
|
||||
"ProfessionSkillName": "Ninjitsu",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Int"
|
||||
},
|
||||
{
|
||||
"SkillID": 54,
|
||||
|
|
@ -767,7 +875,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Spellweaving"
|
||||
"ProfessionSkillName": "Spellweaving",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 55,
|
||||
|
|
@ -781,7 +891,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Mysticism"
|
||||
"ProfessionSkillName": "Mysticism",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 56,
|
||||
|
|
@ -795,7 +907,9 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Imbuing"
|
||||
"ProfessionSkillName": "Imbuing",
|
||||
"PrimaryStat": "Int",
|
||||
"SecondaryStat": "Str"
|
||||
},
|
||||
{
|
||||
"SkillID": 57,
|
||||
|
|
@ -809,6 +923,8 @@
|
|||
"DexGain": 0,
|
||||
"IntGain": 0,
|
||||
"GainFactor": 1,
|
||||
"ProfessionSkillName": "Throwing"
|
||||
"ProfessionSkillName": "Throwing",
|
||||
"PrimaryStat": "Dex",
|
||||
"SecondaryStat": "Str"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -64,6 +64,12 @@ public static class ServerConfiguration
|
|||
return bool.TryParse(strValue, out var value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
public static TimeSpan GetSetting(string key, TimeSpan defaultValue)
|
||||
{
|
||||
_settings.Settings.TryGetValue(key, out var strValue);
|
||||
return TimeSpan.TryParse(strValue, out var value) ? value : defaultValue;
|
||||
}
|
||||
|
||||
public static T GetSetting<T>(string key, T defaultValue) where T : struct, Enum
|
||||
{
|
||||
_settings.Settings.TryGetValue(key, out var strValue);
|
||||
|
|
|
|||
|
|
@ -76,6 +76,13 @@ public enum SkillName
|
|||
Throwing = 57
|
||||
}
|
||||
|
||||
public enum Stat
|
||||
{
|
||||
Str,
|
||||
Dex,
|
||||
Int
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class Skill
|
||||
{
|
||||
|
|
@ -135,7 +142,7 @@ public class Skill
|
|||
}
|
||||
}
|
||||
|
||||
if (Lock is < SkillLock.Up or > SkillLock.Locked)
|
||||
if (Lock > SkillLock.Locked)
|
||||
{
|
||||
Lock = SkillLock.Up;
|
||||
}
|
||||
|
|
@ -245,25 +252,29 @@ public class Skill
|
|||
get
|
||||
{
|
||||
var baseValue = Base;
|
||||
var inv = 100.0 - baseValue;
|
||||
|
||||
if (inv < 0.0)
|
||||
{
|
||||
inv = 0.0;
|
||||
}
|
||||
|
||||
inv /= 100.0;
|
||||
|
||||
var statsOffset = Owner.Owner.RawStr * Info.StrScale +
|
||||
Owner.Owner.RawDex * Info.DexScale +
|
||||
Owner.Owner.RawInt * Info.IntScale;
|
||||
var statTotal = Info.StatTotal * inv;
|
||||
|
||||
statsOffset *= inv;
|
||||
var inv = 100.0 - baseValue;
|
||||
|
||||
if (statsOffset > statTotal)
|
||||
if (inv <= 0.0)
|
||||
{
|
||||
statsOffset = statTotal;
|
||||
statsOffset = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
statsOffset *= inv;
|
||||
|
||||
if (Info.StatTotal > 0)
|
||||
{
|
||||
var statTotal = Info.StatTotal * inv;
|
||||
|
||||
if (statsOffset > statTotal)
|
||||
{
|
||||
statsOffset = statTotal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var value = baseValue + statsOffset;
|
||||
|
|
@ -323,7 +334,7 @@ public class Skill
|
|||
|
||||
public void SetLockNoRelay(SkillLock skillLock)
|
||||
{
|
||||
if (skillLock is < SkillLock.Up or > SkillLock.Locked)
|
||||
if (skillLock > SkillLock.Locked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -387,7 +398,7 @@ public class SkillInfo
|
|||
public SkillInfo(
|
||||
int skillID, string name, double strScale, double dexScale, double intScale, string title,
|
||||
SkillUseCallback callback, double strGain, double dexGain, double intGain, double gainFactor,
|
||||
string professionSkillName = null
|
||||
string professionSkillName, Stat primaryStat, Stat secondaryStat
|
||||
)
|
||||
{
|
||||
Name = name;
|
||||
|
|
@ -403,6 +414,8 @@ public class SkillInfo
|
|||
GainFactor = gainFactor;
|
||||
ProfessionSkillName = professionSkillName ?? Name.RemoveOrdinal(" ");
|
||||
StatTotal = strScale + dexScale + intScale;
|
||||
PrimaryStat = primaryStat;
|
||||
SecondaryStat = secondaryStat;
|
||||
}
|
||||
|
||||
public SkillUseCallback Callback { get; set; }
|
||||
|
|
@ -431,6 +444,10 @@ public class SkillInfo
|
|||
|
||||
public string ProfessionSkillName { get; set; }
|
||||
|
||||
public Stat PrimaryStat { get; set; }
|
||||
|
||||
public Stat SecondaryStat { get; set; }
|
||||
|
||||
public static SkillInfo[] Table { get; set; } = Array.Empty<SkillInfo>();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,35 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Misc;
|
||||
|
||||
// TODO: Make this entirely configurable
|
||||
public static class SkillCheck
|
||||
{
|
||||
public enum Stat
|
||||
private static int _statMax;
|
||||
private static double _statGainChanceMultiplier;
|
||||
private static bool _usePub45StatGain;
|
||||
private static double _primaryStatGainChance;
|
||||
private static TimeSpan _statGainDelay;
|
||||
private static TimeSpan _petStatGainDelay;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool RollStatIncreaseChance(double statGain) =>
|
||||
statGain / 33.3 * _statGainChanceMultiplier > Utility.RandomDouble();
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
Str,
|
||||
Dex,
|
||||
Int
|
||||
_statMax = ServerConfiguration.GetOrUpdateSetting("stats.statMax", Core.LBR ? 125 : 100);
|
||||
_statGainChanceMultiplier = ServerConfiguration.GetOrUpdateSetting("stats.gainChanceMultiplier", 1.0);
|
||||
_primaryStatGainChance = ServerConfiguration.GetSetting("stats.primaryStatGainChance", 0.75);
|
||||
_statGainDelay = ServerConfiguration.GetSetting("stats.gainDelay", TimeSpan.FromMinutes(Core.ML ? 0.05 : 10));
|
||||
_petStatGainDelay = ServerConfiguration.GetSetting("stats.petGainDelay", TimeSpan.FromMinutes(5.0));
|
||||
|
||||
// Publish 45 - Preparation for UOKR
|
||||
_usePub45StatGain = ServerConfiguration.GetSetting("stats.usePub45StatGain", Core.ML);
|
||||
}
|
||||
|
||||
// Publish 16 changed max stats from 100 to 125
|
||||
private static int StatMax = Core.LBR ? 125 : 100;
|
||||
|
||||
private static readonly TimeSpan m_StatGainDelay = TimeSpan.FromMinutes(Core.ML ? 0.05 : 15);
|
||||
private static readonly TimeSpan m_PetStatGainDelay = TimeSpan.FromMinutes(5.0);
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Mobile.SkillCheckLocationHandler = Mobile_SkillCheckLocation;
|
||||
|
|
@ -123,6 +133,12 @@ public static class SkillCheck
|
|||
Gain(from, skill);
|
||||
}
|
||||
}
|
||||
|
||||
// Gain one stat per 10 minutes, regardless of whether you gain in the skill
|
||||
if (!_usePub45StatGain && success)
|
||||
{
|
||||
LegacyGain(from, skill.Info);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
|
|
@ -220,43 +236,80 @@ public static class SkillCheck
|
|||
|
||||
if (toLower != skill && toLower.Lock == SkillLock.Down && toLower.BaseFixedPoint >= toGain)
|
||||
{
|
||||
toLower.BaseFixedPoint -= toGain;
|
||||
toLower.BaseFixedPoint = Math.Max(toLower.BaseFixedPoint - toGain, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (from is PlayerMobile pm && skill.SkillName == pm.AcceleratedSkill &&
|
||||
pm.AcceleratedStart > Core.Now)
|
||||
if (from is PlayerMobile pm && skill.SkillName == pm.AcceleratedSkill && pm.AcceleratedStart > Core.Now)
|
||||
{
|
||||
toGain *= Utility.RandomMinMax(2, 5);
|
||||
}
|
||||
|
||||
if (!from.Player || skills.Total + toGain <= skills.Cap)
|
||||
if (!from.Player || skills.Total < skills.Cap)
|
||||
{
|
||||
skill.BaseFixedPoint += toGain;
|
||||
skill.BaseFixedPoint = Math.Min(toGain, skill.CapFixedPoint - skill.BaseFixedPoint);
|
||||
}
|
||||
}
|
||||
|
||||
if (skill.Lock == SkillLock.Up)
|
||||
if (_usePub45StatGain && skill.Lock == SkillLock.Up)
|
||||
{
|
||||
var info = skill.Info;
|
||||
|
||||
if (from.StrLock == StatLockType.Up && info.StrGain / 33.3 > Utility.RandomDouble())
|
||||
var primaryStat = info.PrimaryStat;
|
||||
var secondaryStat = info.SecondaryStat;
|
||||
|
||||
var primaryStatLock = primaryStat.ToLock(from);
|
||||
var secondaryStatLock = secondaryStat.ToLock(from);
|
||||
|
||||
if (primaryStatLock != StatLockType.Up && secondaryStatLock != StatLockType.Up)
|
||||
{
|
||||
GainStat(from, Stat.Str);
|
||||
return;
|
||||
}
|
||||
else if (from.DexLock == StatLockType.Up && info.DexGain / 33.3 > Utility.RandomDouble())
|
||||
|
||||
// Flat 1 in 20 chance to gain anything
|
||||
if (0.05 * _statGainChanceMultiplier > Utility.RandomDouble())
|
||||
{
|
||||
GainStat(from, Stat.Dex);
|
||||
}
|
||||
else if (from.IntLock == StatLockType.Up && info.IntGain / 33.3 > Utility.RandomDouble())
|
||||
{
|
||||
GainStat(from, Stat.Int);
|
||||
// 75% for primary, 25% for secondary - Unless primary is not set to gain.
|
||||
var statToGain = primaryStatLock is StatLockType.Up && _primaryStatGainChance > Utility.RandomDouble()
|
||||
? primaryStat
|
||||
: secondaryStat;
|
||||
|
||||
GainStat(from, statToGain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void LegacyGain(Mobile from, SkillInfo info)
|
||||
{
|
||||
if (info.StrGain > 0 && from.StrLock == StatLockType.Up && RollStatIncreaseChance(info.StrGain))
|
||||
{
|
||||
GainStat(from, Stat.Str);
|
||||
}
|
||||
|
||||
if (info.DexGain > 0 && from.DexLock == StatLockType.Up && RollStatIncreaseChance(info.DexGain))
|
||||
{
|
||||
GainStat(from, Stat.Dex);
|
||||
}
|
||||
|
||||
if (info.IntGain > 0 && from.IntLock == StatLockType.Up && RollStatIncreaseChance(info.IntGain))
|
||||
{
|
||||
GainStat(from, Stat.Int);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static StatLockType ToLock(this Stat stat, Mobile from) =>
|
||||
stat switch
|
||||
{
|
||||
Stat.Str => from.StrLock,
|
||||
Stat.Dex => from.DexLock,
|
||||
Stat.Int => from.IntLock,
|
||||
_ => StatLockType.Up
|
||||
};
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool CanLower(Mobile from, Stat stat)
|
||||
{
|
||||
return stat switch
|
||||
|
|
@ -268,6 +321,7 @@ public static class SkillCheck
|
|||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool CanRaise(Mobile from, Stat stat)
|
||||
{
|
||||
if (!(from is BaseCreature creature && creature.Controlled))
|
||||
|
|
@ -280,9 +334,9 @@ public static class SkillCheck
|
|||
|
||||
return stat switch
|
||||
{
|
||||
Stat.Str => from.StrLock == StatLockType.Up && from.RawStr < StatMax,
|
||||
Stat.Dex => from.DexLock == StatLockType.Up && from.RawDex < StatMax,
|
||||
Stat.Int => from.IntLock == StatLockType.Up && from.RawInt < StatMax,
|
||||
Stat.Str => from.StrLock == StatLockType.Up && from.RawStr < _statMax,
|
||||
Stat.Dex => from.DexLock == StatLockType.Up && from.RawDex < _statMax,
|
||||
Stat.Int => from.IntLock == StatLockType.Up && from.RawInt < _statMax,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
|
@ -299,17 +353,17 @@ public static class SkillCheck
|
|||
{
|
||||
if (CanLower(from, Stat.Dex) && (from.RawDex < from.RawInt || !CanLower(from, Stat.Int)))
|
||||
{
|
||||
--from.RawDex;
|
||||
from.RawDex -= 1;
|
||||
}
|
||||
else if (CanLower(from, Stat.Int))
|
||||
{
|
||||
--from.RawInt;
|
||||
from.RawInt -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (CanRaise(from, Stat.Str))
|
||||
{
|
||||
++from.RawStr;
|
||||
from.RawStr = Math.Min(from.RawStr + 1, _statMax);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -320,17 +374,17 @@ public static class SkillCheck
|
|||
{
|
||||
if (CanLower(from, Stat.Str) && (from.RawStr < from.RawInt || !CanLower(from, Stat.Int)))
|
||||
{
|
||||
--from.RawStr;
|
||||
from.RawStr -= 1;
|
||||
}
|
||||
else if (CanLower(from, Stat.Int))
|
||||
{
|
||||
--from.RawInt;
|
||||
from.RawInt -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (CanRaise(from, Stat.Dex))
|
||||
{
|
||||
++from.RawDex;
|
||||
from.RawDex = Math.Min(from.RawDex + 1, _statMax);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -341,17 +395,17 @@ public static class SkillCheck
|
|||
{
|
||||
if (CanLower(from, Stat.Str) && (from.RawStr < from.RawDex || !CanLower(from, Stat.Dex)))
|
||||
{
|
||||
--from.RawStr;
|
||||
from.RawStr -= 1;
|
||||
}
|
||||
else if (CanLower(from, Stat.Dex))
|
||||
{
|
||||
--from.RawDex;
|
||||
from.RawDex -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (CanRaise(from, Stat.Int))
|
||||
{
|
||||
++from.RawInt;
|
||||
from.RawInt = Math.Min(from.RawInt + 1, _statMax);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -367,12 +421,12 @@ public static class SkillCheck
|
|||
{
|
||||
if (from is BaseCreature creature && creature.Controlled)
|
||||
{
|
||||
if (creature.LastStrGain + m_PetStatGainDelay >= Core.Now)
|
||||
if (creature.LastStrGain + _petStatGainDelay >= Core.Now)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (from.LastStrGain + m_StatGainDelay >= Core.Now)
|
||||
else if (from.LastStrGain + _statGainDelay >= Core.Now)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -384,12 +438,12 @@ public static class SkillCheck
|
|||
{
|
||||
if (from is BaseCreature creature && creature.Controlled)
|
||||
{
|
||||
if (creature.LastDexGain + m_PetStatGainDelay >= Core.Now)
|
||||
if (creature.LastDexGain + _petStatGainDelay >= Core.Now)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (from.LastDexGain + m_StatGainDelay >= Core.Now)
|
||||
else if (from.LastDexGain + _statGainDelay >= Core.Now)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -401,12 +455,12 @@ public static class SkillCheck
|
|||
{
|
||||
if (from is BaseCreature creature && creature.Controlled)
|
||||
{
|
||||
if (creature.LastIntGain + m_PetStatGainDelay >= Core.Now)
|
||||
if (creature.LastIntGain + _petStatGainDelay >= Core.Now)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (from.LastIntGain + m_StatGainDelay >= Core.Now)
|
||||
else if (from.LastIntGain + _statGainDelay >= Core.Now)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue