Oh hey, there is a thread!
Today was fun:
- Play nostalgia game.
- Get interested in mechanics.
- Look up mechanics formulae in wiki.
- Make a test prediction.
- Test prediction fails.
- Double check formulae. More predictions. More failures.
- Google-fu never fails!
- Google-fu has failed.
- Check game source code.
- Is unofficial android port. Is written in eldritch tongue.
- Has enigmatic folder name scheme. Main has sauce? No, just android UI, shell, and shit.
- Check manual? Manual in Ukrainian.
- Where game sauce?!
- Fuck it, check PC sauce.
- Is C++. Delve greedily and deeply.
- Double check headers (because default values are hidden here for some reason).
- Follow step-by-step with prediction data.
- Prediction success.
- Double check. Prediction success
- Conclude that the wiki is WRONG.
* da_nang slams his head onto his desk.
Today's issue has been the mechanics of the Enchant skill in OpenMW, specifically the formulae for self enchanting. I can only conclude that the UESPwiki is wrong, the OpenMW PC engine source code comments on this as well. To add to my confusion, the (unofficial) Android port I'm using appears to be a wrapper, since I can't for the life of me find its engine source on the GitHub. The wiki appears to be wrong in two ways.
The first error is that the values for the
min,
max, and
area when calculating the Enchant Points in OpenMW have a minimum value of 1. The source code uses
std::max(1,min) etc. for these. There is also strong evidence that the value for
duration is also 1. The source code just fetches
mDuration and while I don't know the default value, I know this: you can't go below 1 in the UI, and durationless spell effects seem to be using 1 as well (e.g. by calculating Enchant Points for a Mark spell effect with
duration set to 0 or 1 and comparing with in-game values). This accounts for some of the peculiarities I've noticed.
The second error is when calculating the Enchant Chance. Based on the wiki, you would multiply the sum
(Enchant + Intelligence/5 + Luck/10 - 3*EnchantPoints) with the factor
(0.75 + %Fatigue). (This then gets halved for constant effect enchantments). What's
%Fatigue? The wiki suggests its the ratio of the Current Fatigue to the Maximum Modified Fatigue. Well, this formula gets massively wrong in the predictions.
First, the tiny yet-not-so-insignificant details. OpenMW keeps track of the precise Enchant Points. The Enchant Points you see in the UI? That's just the floored version, which the wiki is kind enough to have written down but not point out. However, the Enchant Chance in OpenMW uses the precise version. So the sum would be
(Enchant - 3*PreciseEnchantPoints + 0.2*Intelligence + 0.1*Luck), rewritten to closer match the source code (presumably to avoid overflow or cancellation issues). Divisions are also replaced as in source.
But the big villain is the fatigue factor, or fatigue term as it's called in the source. Using %Fatigue to represent the same ratio, the factor you multiply is not
(0.75 + %Fatigue) but
(1.25 - 0.5*(1 - %Fatigue)) which equals
(0.75 + 0.5 * %Fatigue). That's a huge error! At max
%Fatigue, you're multiplying by 1.25, not 1.75! A whooping 40% relative error just from that. Finally, the whole value then gets truncated to an integer by
static_cast<int>. Since that is what's returned by the function, this is what the game then compares to a dice roll to see if the enchantment is successful.
(There's some additional code related to enchantment of throwing weapons, arrows, and bolts, but I didn't test that out.)
Compounding of multiple spell effects seems to follow the general principle found on the Wiki. However, remember that OpenMW keeps track of the precise points, while the display uses floored points. In fact, the display is compounding with floored values*. While this doesn't affect capacity, since that appears to be a pure UI check using floored values,
the Enchant Chance for a multiple spell effect enchantment still uses the precise points when compounding.EDIT: *Slight correction. The display accumulates an
internal cost with precise points, but the
display cost is compounded with the floor of the
internal cost at the end of each iteration. For instance, say the precise points of the individual effects are 5.5 and 6.7. When adding the first effect, the
internal cost becomes 5.5 and the
display cost is 5. When adding the second effect, the
internal cost becomes 5.5 + 6.7 = 12.2, and the
display cost becomes 5 + 12 = 17, not 5+(5+6) = 16. In other words, the
display cost = Σ
n=1Nfloor(S
n) where S
n = Σ
i=1np
i and p
i are the precise points of the effects (ordered top to bottom on the effects list).
So that has been sleep-deprived fun. I hope it may be useful.
Then again, most people probably just chug bootstrapped Fortify Intelligence potions rather than delve into this madness.