fix #266: retail run-rate 800 branch is exact-equality sentinel, not a cap
Raw byte decode of MovementSystem::GetRunRate (0x006b0950, PDB-paired
binary): fild skill; fcom [800f]; fnstsw; test ah, 0x44; jp general —
the C2/C3 parity idiom whose 18/4 fall-through executes ONLY at
skill == 800 exactly. ACE read this as >= 800 ('max run speed?') and
Campaign P P1 inherited that misread when BN dropped the arithmetic,
flat-lining every maxed character at 4.5 (retail-true ~3.70, +21%) and
erasing the vitae differential (both 10200 and 15225 sat above 800).
The [stat-chain] live capture proved the enchant chain correct end to
end (vitae 0.67 -> eff run 10200 -> controller), isolating the formula.
General path byte-verified: (loadMod*(skill/(skill+200)*11)+4)/scaling/4.
InqMaxRunRate's skill=9999 probe gets ~3.6961, not 4.5.
Golden tests pin the 799/800/801 straddle and the maxed-skill vitae
differential; pseudocode doc §6 carries the decode plus a do-not-
reimport-ACE warning. Complete Release suite: 10,025 passed / 5 skips.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
bd3ade625f
commit
61e959169b
5 changed files with 85 additions and 28 deletions
|
|
@ -25,13 +25,28 @@ namespace AcDream.Core.Physics;
|
|||
public static class MovementSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// <c>MovementSystem::GetRunRate</c> 0x006b0950. Retail-verified 800-skill
|
||||
/// cap (<c>InqMaxRunRate</c> passes skill=9999 to reach this cap); general
|
||||
/// case ACE-cross-referenced (BN dropped the arithmetic, see class doc).
|
||||
/// <c>MovementSystem::GetRunRate</c> 0x006b0950. The 800 branch is an
|
||||
/// EXACT-EQUALITY sentinel, not a cap: raw byte decode of the PDB-paired
|
||||
/// binary (#266, 2026-07-30) shows <c>fild skill; fcom [800f]; fnstsw;
|
||||
/// test ah, 0x44; jp general</c> — the C2/C3 parity idiom that falls
|
||||
/// through to <c>18/4</c> ONLY when skill == 800 (<, >, and
|
||||
/// unordered all take the general path). <c>InqMaxRunRate</c> (0x00591b20)
|
||||
/// passes skill=9999 and therefore gets the general formula's ~3.6961,
|
||||
/// NOT 4.5. The general-path arithmetic is byte-verified
|
||||
/// instruction-by-instruction: <c>(loadMod * (skill/(skill+200) * 11) +
|
||||
/// 4) / scaling / 4</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// ACE's <c>MovementSystem.GetRunRate</c> reads this branch as
|
||||
/// <c>>= 800</c> ("max run speed?") — that is ACE's misread of the
|
||||
/// same x87 mush, NOT a tiebreaker. Porting <c>>=</c> made every
|
||||
/// maxed character run a flat 4.5 (vs retail's ~3.70) and erased the
|
||||
/// vitae speed differential entirely (#266). Do not "fix" this back
|
||||
/// from ACE.
|
||||
/// </remarks>
|
||||
public static float GetRunRate(float burden, int runSkill, float scaling = 1f)
|
||||
{
|
||||
if (runSkill >= 800)
|
||||
if (runSkill == 800)
|
||||
return 18f / 4f;
|
||||
|
||||
float loadMod = EncumbranceSystem.LoadMod(burden);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue