acdream/docs/research/skill_formula_calculate_pseudocode.md
Erik 557eb7ef6b refactor(net): own live session composition
Extract reset, selection, entered-world, and route construction behind LiveSessionHost while preserving the sole LiveSessionController authority. Retain partial route and subscription cleanup for retry, and replace the embedded ACE-only shortcut with the exact named-retail unsigned skill formula.

Co-authored-by: Codex <codex@openai.com>
2026-07-22 10:36:06 +02:00

2.8 KiB

Retail skill-formula calculation

Oracle

  • Named retail: SkillFormula::Calculate @ 0x00591960 in named-retail/acclient_2013_pseudo_c.txt.
  • Retail layout: SkillFormula in named-retail/acclient.h:40199 stores six unsigned 32-bit fields in wire order: W, X, Y, Z, Attr1, Attr2.

The signed-looking branches in the recovered x87 code are not signed formula semantics. They are the compiler's unsigned-32-bit-to-floating-point fix-up: when the high bit is set, it adds 2^32 after the initial signed conversion.

Pseudocode

bool SkillFormula.Calculate(uint attribute1, uint attribute2, out uint result)
{
    uint divisor = Z;
    if (divisor == 0)
        return false;

    // Every operation on this line is uint32 and wraps modulo 2^32.
    uint numerator = X * attribute1 + Y * attribute2 + W;

    // Formula values are non-negative. Retail rounds to nearest integer,
    // with exact halves rounding upward.
    result = uint(floor(double(numerator) / double(divisor) + 0.5));
    return true;
}

Consequences pinned by the port:

  • Z == 0 is the only failure gate. X == 0 remains a valid formula.
  • W participates in the numerator before division; it is not added after division.
  • multiplication and addition wrap as unsigned 32-bit arithmetic before the floating-point division.
  • the division rounds half-up; it does not truncate.

Reference cross-check

ACE's SkillFormula confirms the unsigned DAT order W, X, Y, Z, Attr1, Attr2. ACE's AttributeFormula.GetFormula is only an interpretation aid: it rejects X == 0, assumes unit multipliers, omits W, and rounds a summed-attribute quotient. That is sufficient for ordinary stock ACE data but is not the general retail algorithm.

Chorizite DatReaderWriter's generated SkillFormula independently confirms the same six-field order and maps its public names to W, X, Y, and Z. It exposes the four arithmetic words as signed int, so the retail port must reinterpret their bits as uint. Its summary places the additive value after division; the named retail function proves that the actual client adds W to the numerator instead.

Port decision

RetailSkillFormula is the sole App-layer calculation seam. It reinterprets the DAT words as unsigned, performs the exact unchecked 32-bit numerator, and uses the retail half-up division. LiveSkillCreditResolver performs only the skill-table lookup and treats a missing attribute as zero, matching the prior live-property projection behavior.