Skill lvl400/getting gold when buy items

Discuss coding questions, pull requests, and implementation details.
Post Reply
WolframPolizei
Posts: 1
Joined: Sun Apr 05, 2020 11:34 am

Skill lvl400/getting gold when buy items

Post by WolframPolizei »

SAVE9.7z
(199.98 KiB) Downloaded 27 times
Alpha 0.10.21

I did enchant my items with enhanse mercantile. My Skill went over 100 and at some point the shopkeepers offered me " - gold" when i wanted to buy an item. They actually gave me the gold so if it is -20 gold i get the item and 20 gold.
The turningpoint lies between skill lvl of 241 and 256. I could boost my mercantile skill up to 406
(with a base skill of 31), for that i used up every slot for equipement.

I use mods but none of them mess with the skill system. In classic, it was possible to raise skills above 100 to an absurd amount too but i can't remember if the effect with "- gold" was there too.
(my mod list: https://prnt.sc/rtf11k)

best regards
Aleks

ps: here is a photo of a baby bat https://prnt.sc/rtf36q

User avatar
pango
Posts: 2607
Joined: Wed Jul 18, 2018 6:14 pm
Location: France
Contact:

Re: Skill lvl400/getting gold when buy items

Post by pango »

Welcome to the forums WolframPolizei
WolframPolizei wrote: Sun Apr 05, 2020 12:24 pm I use mods but none of them mess with the skill system. In classic, it was possible to raise skills above 100 to an absurd amount too but i can't remember if the effect with "- gold" was there too.
I remember reading about DagSkills breaking mercantile in classic in a similar way. I don't know if that was ever fixed, maybe Ferital knows better.
And I'm pretty sure the formulas were reverse engineered from assembly, from the look of it:
https://github.com/Interkarma/daggerfal ... r.cs#L1904
(some range tests could have been missed, though)

If you look past the integer operations, it is actually quite simple: everything relies on the use of a function f so that f(100) = 2 * f(0), that's used over and over as a factor in selling and buying prices. Its parameter is an ability or a skill, and when that ability or skill is supposed to drive prices down, then f(100 - x) is used instead.
If we refactorize the code according to that analysis, this gives:

Code: Select all

private static int MercantileF(int level)
{
    return (level << 8) / 200 + 128;
}
...
if (selling)
{
    delta_mercantile = MercantileF(100 - merchant_mercantile_level) * MercantileF(player.Skills.GetLiveSkillValue(DFCareer.Skills.Mercantile)) >> 8;
    delta_personality = MercantileF(100 - merchant_personality_level) * MercantileF(player.Stats.LivePersonality) >> 8;
    amount = ((((179 * delta_mercantile) >> 8) + ((51 * delta_personality) >> 8)) * cost) >> 8;
}
else // buying
{
    delta_mercantile = MercantileF(merchant_mercantile_level) * MercantileF(100 - player.Skills.GetLiveSkillValue(DFCareer.Skills.Mercantile)) >> 8;
    delta_personality = MercantileF(merchant_personality_level) * MercantileF(100 - player.Stats.LivePersonality) >> 8 << 6;
    amount = ((((192 * delta_mercantile) >> 8) + (delta_personality >> 8)) * cost) >> 8;
}
As we can see, f is (again if you don't look too closely at integer operations) a simple linear function, basically f(x) = 128 * (1 + x/100).
The trouble comes from the use of 100 - x as parameter, because when x becomes greater than 200, f(100-x) becomes zero, then negative, and hell breaks loose.

One way to deal with that would be to cap that function, so that it stops decreasing with some negative value of its parameter. It would give no incentive for reaching insane skill levels, so I'm sure some players will disagree with that approach ;)

I think an implementation that would better extend past 0..100 values would be an exponential; If prices double (or are halved) as you go from skill 0 to 100, it should be doubled again (or halved again) as skill go from 100 to 200, etc.

Code: Select all

private static int MercantileF(int level)
{
    return (int) (128 * Mathf.Exp(Mathf.Log(2f) / 100f * level));
}
This does not match perfectly with the classic linear function over 0..100 (worse can being around x = 53, where it's about 8% lower), so we could use classic formula for 0..100 range and new formula to extend it outside this range:

Code: Select all

private static int MercantileF(int level)
{
    if (level >= 0 && level <= 100)
        // classic formula
        return (level << 8) / 200 + 128;
    else
        // exponential extension of above
        return (int) (128 * Mathf.Exp(Mathf.Log(2f) / 100f * level));
}
At least that's something to try, and see how it feels in game...
When a measure becomes a target, it ceases to be a good measure.
-- Charles Goodhart

Post Reply