acdream/docs/research/2026-05-04-l3-port/13-cycle-picker.md
Erik de129bc164 feat(motion): L.3 M1 — fresh InterpolationManager port + retail spec
Rewrites src/AcDream.Core/Physics/InterpolationManager.cs from the spec
in docs/research/2026-05-04-l3-port/04-interp-manager.md. Public API
preserved (Vector3-returning AdjustOffset, Enqueue, Clear, IsActive,
Count) so PositionManager + GameWindow callers continue to compile;
internals are full retail spec.

Bug fixes vs prior port (audit 04-interp-manager.md § 7):

  #1  progress_quantum accumulates dt (sum of frame deltas), not step
      magnitude. Retail line 353140; the prior port's `+= step` made
      the secondary stall ratio meaningless.

  #3  Far-branch Enqueue (dist > AutonomyBlipDistance = 100m) sets
      _failCount = StallFailCountThreshold + 1 = 4, so the next
      AdjustOffset call's post-stall check fires an immediate blip-to-
      tail snap. Retail line 352944. Prior port silently drifted
      toward far targets at catch-up speed instead of teleporting.

  #4  Secondary stall test ports the retail formula verbatim:
      cumulative / progress_quantum / dt < CREATURE_FAILED_INTERPOLATION_PERCENTAGE.
      Audit notes the units are 1/sec (likely Turbine bug or x87 FPU
      misread by Binary Ninja) — mirrored byte-for-byte regardless.

  #5  Tail-prune is a tail-walking loop, not a single-tail compare.
      Multiple consecutive stale tail entries within DesiredDistance
      (0.05 m) of the new target collapse together. Retail line 352977.

  #6  Cap-eviction at the HEAD when count reaches 20 (already correct
      in the prior port; verified).

New API: Enqueue gains an optional `currentBodyPosition` parameter so
the far-branch detection can reference the body when the queue is
empty. Backward-compatible (default null = pre-far-branch behavior).

UseTime collapsed into AdjustOffset's tail (post-stall blip check)
since acdream has no per-tick UseTime call separate from
adjust_offset; identical semantic outcome.

State fields renamed to retail names with sentinel values:
  _frameCounter, _progressQuantum, _originalDistance (init = 999999f
  sentinel per retail line 0x00555D30 ctor), _failCount.

Tests:
- 17/17 InterpolationManagerTests green.
- New test Enqueue_FarBranch_PrearmsImmediateBlipOnNextAdjustOffset
  pins the bug #3 fix: enqueueing 150 m away triggers a same-tick
  blip (delta length ≈ 150 m), and the queue clears.

Spec tree: 17 research docs (00–14) under docs/research/2026-05-04-l3-port/.
00-master-plan + 00-port-plan describe the 8-phase rollout. 01-per-tick,
03-up-routing, 04-interp-manager, 05-position-manager-and-partarray,
06-acdream-audit, 14-local-player-audit are the L.3 spec used by this
commit and the M2 follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 14:56:42 +02:00

26 KiB
Raw Blame History

13 — Retail's cycle decision tree

Question: When InterpretedMotionState has simultaneous forward_command=RunForward + sidestep_command=SidestepRight + turn_command=TurnLeft, what cycle plays in retail?

Answer (TL;DR): All three. Retail does not pick "the winning substate" out of a 3-axis state. Instead, apply_interpreted_movement issues three separate DoInterpretedMotion calls — forward-cmd, then sidestep-cmd, then turn-cmd — each landing in CMotionTable::GetObjectSequence, which dispatches by command class bits (0x40000000 substate / 0x10000000 action / 0x20000000 modifier) to either replace the substate or attach a modifier. Forward goes into the substate slot; sidestep+turn go into the modifier list. The CSequence is rebuilt with all three layers via add_motion.

This means acdream's "priority winner" picker is wrong — and so is the RunForward → WalkForward → Ready fallback chain. Retail has no fallback chain; it just calls GetObjectSequence per axis and ignores NULL results.


A. Top of the call tree — CMotionInterp::apply_interpreted_movement

Line 305713305788 (acclient_2013_pseudo_c.txt), address 00528600.

void CMotionInterp::apply_interpreted_movement(this, arg2, arg3) {
    if (!physics_obj) return;
    MovementParameters var_2c;                              // 305719
    MovementParameters::MovementParameters(&var_2c);

    // Sync run-rate from forward_speed if running
    if (interpreted_state.forward_command == 0x44000007 /*RunForward*/)
        my_run_rate = (float)interpreted_state.forward_speed;  // 305722

    // 1) Always re-issue current_style (e.g. CombatMode_NonCombat)
    DoInterpretedMotion(this, interpreted_state.current_style, &var_2c);  // 305724

    // 2) Forward axis
    if (!contact_allows_move(this, interpreted_state.forward_command)) {
        var_18_2 = 0x3f800000;                              // 1.0f speed
        DoInterpretedMotion(this, 0x40000015 /*Stand*/, &var_2c);  // 305729
    } else if (standing_longjump) {
        DoInterpretedMotion(this, 0x41000003 /*Ready*/, &var_2c);  // 305738
        StopInterpretedMotion(this, 0x6500000f /*Sidestep*/, &var_2c);
    } else {
        DoInterpretedMotion(this, interpreted_state.forward_command, &var_2c);  // 305744

        // 3) Sidestep axis
        if (interpreted_state.sidestep_command == 0)
            StopInterpretedMotion(this, 0x6500000f /*Sidestep*/, &var_2c);  // 305748
        else
            DoInterpretedMotion(this, interpreted_state.sidestep_command, &var_2c);  // 305752
    }

    // 4) Turn axis
    if (interpreted_state.turn_command != 0)
        DoInterpretedMotion(this, interpreted_state.turn_command, &var_2c);  // 305762
    else
        // No turn — explicitly stop any prior TurnLeft modifier
        StopInterpretedMotion(this, 0x6500000d /*TurnLeft*/, &var_2c);  // implied 305770
}

Critical observation: this is four DoInterpretedMotion calls per UM (current_style, forward, sidestep, turn). Each one is a distinct MotionTableManager::PerformMovementCMotionTable::DoObjectMotionCMotionTable::GetObjectSequence round-trip. The composite cycle is the sum of four state-machine transitions, not the result of a priority pick.

apply_interpreted_movement is invoked by apply_current_movement (305838305857). apply_current_movement is called by every UM arrival on the player or remote object after RawMotionState::ApplyMotion (or InterpretedMotionState::ApplyMotion) populates the state struct.


B. The state-routing dispatcher — RawMotionState::ApplyMotion

Line 293630293703, address 0051eb60. This is the retail analog of acdream's AnimationCommandRouter.Classify.

void RawMotionState::ApplyMotion(this, arg2, arg3) {
    // arg2 = motion command (e.g. 0x44000007 RunForward)
    // arg3 = MovementParameters (speed, hold_key_to_apply, etc.)

    if ((arg2 - 0x6500000d) > 3) {                  // not Turn/Sidestep range
        if ((arg2 & 0x40000000) == 0) {             // not substate
            if (arg2 >= 0) {
                if ((arg2 & 0x10000000) != 0)       // ACTION class
                    AddAction(this, arg2, ...);     // 293640 → action queue
            } else if (current_style != arg2) {     // STYLE change
                forward_command = 0x41000003;       // Ready
                current_style = arg2;               // 293645
            }
        } else if (arg2 != 0x44000007 /*RunForward*/) {
            // 0x40000000-class but NOT RunForward (i.e. WalkForward,
            // BackForward etc) goes into FORWARD slot
            forward_command = arg2;                 // 293650
            forward_holdkey = arg3->hold_key_to_apply;
            forward_speed = arg3->speed;
        }
        return;
    }

    switch (arg2) {                                  // 293666
    case 0x6500000d /*TurnLeft*/:
    case 0x6500000e /*TurnRight*/:
        turn_command = arg2;                         // 293671
        turn_holdkey = arg3->hold_key_to_apply;
        turn_speed = arg3->speed;
        return;
    case 0x6500000f /*SidestepRight*/:
    case 0x65000010 /*SidestepLeft*/:
        sidestep_command = arg2;                     // 293688
        sidestep_holdkey = arg3->hold_key_to_apply;
        sidestep_speed = arg3->speed;
        return;
    }
}

Routing classes (matches 0x40000000/0x10000000/0x20000000 mask checks, also visible in CMotionTable::GetObjectSequence):

Class bit Range Slot Effect
0x40000000 substate (e.g. 0x44000007 RunForward, 0x40000015 Stand) forward_command (or replaces substate) replaces previous substate; modifiers may be cleared
0x10000000 action (e.g. emote) action_head queue overlay; substate cycle keeps running
0x20000000 modifier modifier_head list overlay; substate cycle keeps running
0x6500000d-10 turn/sidestep (special-cased) turn_command / sidestep_command dedicated slots (effectively modifiers)
< 0 (0x80...) style change current_style full reset, forward_command → Ready
0x44000007 RunForward is special-cased OUT of the forward slot here — see below not stored in forward_command directly by RawMotionState; it's the result of adjust_motion running on WalkForward + HoldKey.Run

(The InterpretedMotionState equivalent at line 293531 is functionally the same with one extra branch — current_style initialization.)


C. adjust_motion — the WalkForward + RunRunForward transform

Line 305343305400, address 00528010. This is what DoMotion calls before DoInterpretedMotion to translate a raw key event into a substate.

void CMotionInterp::adjust_motion(this, arg2 /*&cmd*/, arg3 /*&speed*/, arg4 /*hold_key*/) {
    if (weenie_obj == 0 || weenie_obj->IsCreature()) {
        switch (*arg2) {
        case 0x65000010 /*SidestepLeft*/:
            *arg2 = 0x6500000f;                  // collapse Left → Right
            *arg3 *= -1;                          // with negative speed
            // fallthrough
        case 0x6500000f /*SidestepRight*/:
            // Sidestep speed-mod: (3.12/1.25) * 0.5 = 1.248
            *arg3 = (3.12f / 1.25f) * 0.5f * (*arg3);
            break;
        case 0x6500000e /*TurnRight*/:
            *arg2 = 0x6500000d;                  // collapse Right → Left
            *arg3 *= -1;                          // with negative speed
            break;
        case 0x45000006 /*WalkBackward*/:
            *arg2 = 0x45000005;                  // collapse to BackForward
            *arg3 = -0.65f * (*arg3);
            break;
        case 0x44000007 /*RunForward*/:
            // already a run cmd — fall through to apply_run_to_command
            break;
        }

        // Then: if hold_key == HoldKey_Run, escalate to RunForward
        HoldKey current = arg4 == HoldKey_Invalid ? raw_state.current_holdkey : arg4;
        if (current == HoldKey_Run)
            apply_run_to_command(this, arg2, arg3);
    }
}

apply_run_to_command (line 305062, addr 00527be0):

void CMotionInterp::apply_run_to_command(this, arg2, arg3) {
    float run_rate = weenie_obj ? weenie_obj->InqRunRate() : my_run_rate;

    if (*arg2 == 0x45000005 /*WalkForward*/) {
        if (*arg3 != 0)
            *arg2 = 0x44000007;          // → RunForward
        *arg3 *= run_rate;               // speed *= runRate (e.g. 2.94)
    } else if (*arg2 == 0x6500000d /*TurnLeft*/) {
        *arg3 *= 1.5f;                    // turn 1.5x while running
    } else if (*arg2 == 0x6500000f /*SidestepRight*/) {
        *arg3 *= run_rate;
        // clamp to ±3 m/s
        if (fabs(*arg3) > 3.0f)
            *arg3 = (sign(*arg3)) * 3.0f;
    }
}

So the way RunForward gets into forward_command in retail is:

  1. Wire UM has cmd=WalkForward (0x45000005) + hold_key=HoldKey_Run
  2. DoMotion(0x45000005, params) is called.
  3. adjust_motion swaps cmd → 0x44000007 RunForward, speed *= runRate.
  4. RawMotionState::ApplyMotion(0x44000007, ...) runs. The special-case arg2 != 0x44000007 branch at line 293648 means RunForward is NOT stored in forward_command here. (This appears intentional — RunForward is the post-adjust_motion form; the persistent RawMotionState keeps the original WalkForward.)
  5. InterpretedMotionState stores the post-adjust value because apply_raw_movement (305817) copies raw_state.* then runs adjust_motion over each of the three axes (305829-305831) before apply_interpreted_movement consumes it.

ACE matches this: it auto-upgrades WalkForward + HoldKey.RunRunForward on the outbound wire to remote observers, which is why our inbound parser sees fwd=0x07 for "remote is running."


D. The cycle-decision core — CMotionTable::GetObjectSequence

Line 298636298950, address 00522860. This is where a single motion command lands and the CSequence is rebuilt. It is invoked once per DoInterpretedMotion call.

Signature:

int CMotionTable::GetObjectSequence(
    this,
    uint32_t   motion,           // arg2 — the command
    MotionState* state,          // arg3 — table-internal state
    CSequence* sequence,         // arg4 — the part-array sequence to mutate
    float      speed_mod,        // arg5
    uint32_t*  num_anims_out,    // arg6
    int32_t    force_flag);      // arg7 — re-modify recursion guard

Three dispatch branches based on the high-bit class of motion:

D.1 — motion < 0 (style change, e.g. 0x80000003D)

Lines 298661298735. Substate's effect: reset to default substate of the new style, optionally clear modifiers, replace cycles.

D.2 — motion & 0x40000000 (substate)

Lines 298737298848. The forward-axis path.

if ((motion & 0x40000000) != 0) {                   // 298737
    uint32_t key = (motion & 0xffffff);
    MotionData* incoming = LongHash::lookup(&this->cycles, (state->style << 0x10) | key);
    if (incoming == 0)
        incoming = LongHash::lookup(&this->cycles, (this->default_style << 0x10) | key);  // fallback to default style
    if (incoming != 0 && is_allowed(this, motion, incoming, state)) {
        // Same-cycle re-speed shortcut: we're already on this cycle
        // and just changing speed (e.g. forward_speed delta)
        if (motion == state->substate &&
            same_sign(speed_mod, state->substate_mod) &&
            sequence->has_anims()) {
            change_cycle_speed(sequence, incoming, state->substate_mod, speed_mod);
            subtract_motion(sequence, incoming, state->substate_mod);
            combine_motion(sequence, incoming, speed_mod);
            state->substate_mod = speed_mod;
            return 1;
        }

        // Full transition: clear-anims + (link from current substate) + (incoming)
        if (incoming->bitfield & 1)
            state->clear_modifiers();           // some cycles clear modifiers on entry

        MotionData* link = get_link(this, state->style, state->substate, state->substate_mod, motion, speed_mod);
        // (with two-stage fallback through default_substate if direct link missing)

        sequence->clear_physics();
        sequence->remove_cyclic_anims();
        // If no direct link, route through default substate
        add_motion(sequence, link, ...);                       // transition anim
        add_motion(sequence, incoming, speed_mod);             // new cycle

        // Re-add prior substate as a modifier if it had the 0x20000000 flag
        if (state->substate != motion && (state->substate & 0x20000000))
            state->add_modifier_no_check(state->substate, state->substate_mod);

        state->substate_mod = speed_mod;
        state->substate = motion;
        re_modify(this, sequence, state);  // re-attach all modifiers
        return 1;
    }
}

Key takeaway: if the cycle-bound lookup LongHash::lookup(&cycles, (style<<16)|key) returns NULL and the default-style fallback also returns NULL, retail returns 0 (failure) and the call has no effect. There is no RunForward → WalkForward → Ready fallback chain — that is purely an acdream artifact.

D.3 — motion & 0x10000000 (action, e.g. emote)

Lines 298850298907. Overlay path:

if ((motion & 0x10000000) != 0) {
    uint32_t key = (state->style << 0x10) | (state->substate & 0xffffff);
    MotionData* current_substate_md = LongHash::lookup(&this->cycles, key);
    if (current_substate_md != 0) {
        MotionData* link = get_link(this, state->style, state->substate, state->substate_mod, motion, speed_mod);
        if (link != 0) {
            state->add_action(motion, speed_mod);   // append to action queue
            sequence->clear_physics();
            sequence->remove_cyclic_anims();        // remove looping anims
            add_motion(sequence, link, speed_mod);  // transition anim (one-shot)
            add_motion(sequence, current_substate_md, state->substate_mod);  // re-add substate cycle!
            re_modify(this, sequence, state);
            return 1;
        }
    }
}

Crucial: actions DO NOT replace the substate cycle. They prepend a one-shot link animation, then re-add the current substate cycle so it keeps looping after the action. Acdream's "Action route" is correct in spirit but should preserve the running cycle exactly like this.

D.4 — motion & 0x20000000 (modifier — turn, sidestep, all overlay cycles)

Lines 298909298945. Modifier list overlay:

if ((motion & 0x20000000) != 0) {
    // current substate must be a non-OneShot cycle
    MotionData* current_substate_md = LongHash::lookup(&this->cycles, (state->style << 0x10) | (state->substate & 0xffffff));
    if (current_substate_md != 0 && (current_substate_md->bitfield & 1) == 0) {
        // Look up the modifier cycle
        MotionData* mod_md = LongHash::lookup(&this->modifiers, (state->style << 0x10) | (motion & 0xffffff));
        if (mod_md == 0)
            mod_md = LongHash::lookup(&this->modifiers, (motion & 0xffffff));  // default-style fallback

        if (mod_md != 0) {
            int rc = state->add_modifier(motion, speed_mod);  // adds to modifier_head list
            if (rc == 0) {
                // already has a modifier with this motion — stop it and re-add
                StopSequenceMotion(this, motion, 1.0f, state, sequence, &num_out);
                rc = state->add_modifier(motion, speed_mod);
            }
            if (rc != 0) {
                combine_motion(sequence, mod_md, speed_mod);  // BLEND velocity/omega into sequence
                return 1;
            }
        }
    }
}

combine_motion (line 298472, addr 00522580) — adds the modifier's velocity AND omega into the existing sequence via CSequence::combine_physics. So turn modifiers contribute their omega on top of the substate's velocity. This is how retail composes "running while turning while strafing": three layers of physics contributions in the same CSequence, animated by whichever layers brought animations in.


E. is_allowed — the gating predicate

Line 298526298548, address 005226c0. Determines whether an incoming substate is legal in the current state.

int CMotionTable::is_allowed(this, motion, motion_data, state) {
    if (motion_data == 0) return 0;
    if ((motion_data->bitfield & 2) != 0) {       // requires "default substate"
        if (motion != state->substate) {
            // Look up the default substate for this style; legal only if state is in it
            uint32_t default_substate;
            LongNIValHash::lookup(&style_defaults, state->style, &default_substate);
            return (default_substate == state->substate) ? 1 : 0;
        }
    }
    return 1;
}

So a substate transition that requires the "ready" state (bitfield bit

  1. will fail if the player is currently in a non-default substate. This is the retail-correct way to block (for example) a Sit cycle mid-Run — not a custom acdream "skip if airborne" hack.

F. re_modify — the "re-attach modifiers after substate change"

Line 298300298328, address 005222e0. After a substate transition that may have cleared modifiers, this walks the modifier list and re-applies each via GetObjectSequence:

void CMotionTable::re_modify(this, sequence, state) {
    if (state->modifier_head == 0) return;
    MotionState backup;                                    // 298308
    MotionState::MotionState(&backup, state);
    while (i != 0) {
        MotionList* mod = state->modifier_head;
        uint32_t motion = mod->motion;
        float speed = mod->speed_mod;
        state->remove_modifier(mod, NULL);
        backup.remove_modifier(i, NULL);
        GetObjectSequence(this, motion, state, sequence, speed, &num_out, 0);  // recurse
    }
    backup.~MotionState();
}

This is why turn + sidestep persist across forward-cycle transitions (WalkForward → RunForward) — they are stored in modifier_head and get re-blended every time the substate changes.


G. Final critical answers

G.1 — When forward=RunForward + sidestep=SidestepRight + turn=TurnLeft arrive in one UM, what cycle plays?

All three layered. Specifically, after apply_interpreted_movement processes the UM:

  1. DoInterpretedMotion(current_style) — re-asserts style; usually no-op if unchanged.
  2. DoInterpretedMotion(0x44000007 RunForward, speed=runRate*1.0)GetObjectSequence takes the substate path (D.2). Replaces prior substate. state->substate = RunForward.
  3. DoInterpretedMotion(0x6500000f SidestepRight, speed=1.248)GetObjectSequence takes the modifier path (D.4). Adds to modifier_head, calls combine_motion to blend sidestep velocity into the running CSequence. Substate cycle is unchanged (still RunForward).
  4. DoInterpretedMotion(0x6500000d TurnLeft, speed=1.5) — same as 3 but for turn. Blends turn omega into the sequence.

Visual result: the RunForward animation cycle plays. Sidestep and turn contribute velocity/omega only (their cycles are typically motion- data with velocity != 0 and omega != 0 but num_anims == 0 — they're physics-only modifiers that don't override the running anim). Some MotionTables may have animation content on sidestep/turn modifiers for emphasis, in which case the bones get an additive blend.

G.2 — Substate winner pick, sequential SetCycle, or Frame-level composition?

Sequential GetObjectSequence calls per axis (current_style → forward → sidestep → turn), each mutating the same CSequence via:

  • substate: clear_physics + remove_cyclic_anims + add_motion(link) + add_motion(new) (replace)
  • modifier: combine_motion (additive blend) + state->add_modifier (track for re_modify)
  • action: clear_physics + remove_cyclic_anims + add_motion(link) + add_motion(current_substate) (overlay-with-restore)

The final result is a single CSequence carrying:

  • One looping substate cycle (animation + velocity/omega contribution)
  • Zero or more queued action cycles (one-shot anims; auto-pop via MotionState::remove_action_head on completion)
  • Zero or more modifier cycles (additive velocity/omega; usually no animation content)

There is no priority pick. There is no Frame-level layering — all three are blended into the single CSequence's velocity/omega fields by add_motion/combine_motion and the result is integrated once per physics tick.

G.3 — Does the RunForward → WalkForward → Ready fallback chain exist?

No. GetObjectSequence has only one fallback: when the cycle for the current style isn't found, fall back to default_style's version (line 298842 in style-change branch, line 298872-298886 in action branch via style_defaults lookup). If neither exists, return 0 and the call has no effect.

The acdream fallback (RunForward → WalkForward → Ready) is a port artifact that papers over the fact that we're not using MotionTableManager — we're synthesizing cycle-anim association directly from a hardcoded enum. In a faithful port this fallback goes away.

G.4 — For Action overlay packets, does retail leave the substate cycle running?

Yes, exactly. D.3 above:

add_motion(sequence, link, speed_mod);                      // one-shot transition
add_motion(sequence, current_substate_md, state->substate_mod);  // re-add running cycle

The MotionState::action_head queue tracks the active actions; the sequence has both the action's transition anim AND the substate cycle re-applied. When the action's one-shot anim completes, CSequence::CheckForCompletedMotions (in CPhysicsObj) pops the action and re-runs apply_interpreted_movement to restore pure substate state.


H. Acdream port implications

  1. Delete the priority cycle-picker in OnLiveMotionUpdated. Replace with a faithful port of apply_interpreted_movement: 4 sequential MotionTableManager.PerformMovement calls (current_style, forward, sidestep, turn) per UM.

  2. Delete the RunForward → WalkForward → Ready fallback chain entirely. If a MotionTable doesn't have a cycle, retail just silently fails to transition — there is no fallback. Our fallback is masking missing animation data.

  3. Port MotionTableManager so we have an actual MotionState (style + substate + substate_mod + modifier_head + action_head) per remote object, and a CMotionTable lookup chain (cycles/modifiers/links/style_defaults). The current approach of "pick one cycle per UM and play it" cannot represent modifier overlay correctly.

  4. Run-detection: WalkForward+HoldKey.Run → RunForward must happen in adjust_motion BEFORE the routing. Acdream's AnimationCommandRouter.Classify runs after this transform — correct in concept, but only if our outbound and inbound both apply the transform consistently. (ACE does this on the outbound, so inbound 0x07 RunForward is post-adjusted.)

  5. Modifier physics: combine_motion blends velocity AND omega into a single CSequence. Acdream's ObservedOmega workaround (audit doc 06 line 83) is a symptom of not blending omega into the per-tick velocity properly. Once MotionTableManager is ported, omega comes from combine_motion of TurnLeft's modifier cycle and the update_object MinQuantum hack disappears.

  6. Sidestep direction collapse: retail collapses SidestepLeft → SidestepRight (negative speed) and TurnRight → TurnLeft (negative speed) in adjust_motion. The modifier list keys on the collapsed form. Acdream must do the same to match the modifier-table lookups.


I. Citation index

Function Address File line
CMotionInterp::DoMotion 00528d20 306159
CMotionInterp::DoInterpretedMotion 00528360 305575
CMotionInterp::adjust_motion 00528010 305343
CMotionInterp::apply_run_to_command 00527be0 305062
CMotionInterp::apply_interpreted_movement 00528600 305713
CMotionInterp::apply_raw_movement 005287e0 305817
CMotionInterp::apply_current_movement 00528870 305838
CPhysicsObj::DoInterpretedMotion 0050ea70 276348
CPartArray::DoInterpretedMotion 00518750 286772
MotionTableManager::PerformMovement 0051c0b0 290906
MotionTableManager::initialize_state 0051c030 290875
CMotionTable::GetObjectSequence 00522860 298636
CMotionTable::DoObjectMotion 00523e90 300045
CMotionTable::StopObjectMotion 00523ec0 300053
CMotionTable::StopSequenceMotion 00522fc0 298954
CMotionTable::SetDefaultState 005230a0 299004
CMotionTable::is_allowed 005226c0 298526
CMotionTable::get_link 00522710 298552
CMotionTable::re_modify 005222e0 298300
RawMotionState::ApplyMotion 0051eb60 293630
InterpretedMotionState::ApplyMotion 0051ea40 293531
MotionState::add_modifier 00526340 303081
MotionState::add_modifier_no_check 00525ff0 302772
MotionState::add_action 005260a0 302828
MotionState::clear_modifiers 00526070 302810
MotionState::remove_modifier 00526040 302794
add_motion (free fn) 005224b0 298437
combine_motion (free fn) 00522580 298472
subtract_motion (free fn) 00522600 298492
Constant Value Meaning
0x40000000 flag substate class bit (forward axis)
0x10000000 flag action class bit
0x20000000 flag modifier class bit
0x44000007 id RunForward substate
0x45000005 id WalkForward substate
0x45000006 id WalkBackward substate (collapses to BackForward)
0x40000011 id (referenced in jump path)
0x40000015 id Stand substate
0x41000003 id Ready substate
0x6500000d id TurnLeft modifier
0x6500000e id TurnRight modifier (collapses to TurnLeft)
0x6500000f id SidestepRight modifier
0x65000010 id SidestepLeft modifier (collapses to SidestepRight)
0x6500000f (jump-charge) id charge_jump cycle
0x8000003d id "no style" sentinel (CombatMode_NonCombat default)