The DS3 Codex
Chapter VI

Movement & collision

In DS3 the stick doesn't set a velocity. It picks which animation plays and how fast, and the animation's root motion moves you. Physics only adds gravity and slides the result against the world.

A roll is sixteen frames of invulnerability and 4.45 metres of someone else's motion capture. The ground decides only whether you land.Codex · a000_027114

In short
  • The player's rules are a Havok Script (Lua 5.1) state machine, c0000.hks: 15,439 decompiled lines. It fires behaviour events that a Havok Behavior graph maps to clips.
  • Root motion moves the character: walk 1.5 m/s, run ~4, sprint 6.04. TAE flags switch off gravity, collision, turning and pushing per frame, and open cancel windows.
  • The body is a Havok character proxy: a kinematic 1.9 × 0.4 m capsule with a 60° slope limit, a 0.3 m step-up and a downward snap.
  • The running jump has no take-off speed. A TAE event ramps the gravity multiplier from 0 back to 1; the height you see is in the pose.

1The pipeline

Inputstick, buttons
HKS player script · c0000.hksstate machine and rules: SetVariable("MoveSpeedLevel", …), ExecEvent("W_RollingMedium"), act(…), reads the engine through env(…)
Havok Behavior graph · c0000.behbndevents → states → clips; blends walk / run / dash; crossfades
root motion per frame · TAE events
ChrCtrl / PlayerCtrl× speed multipliers, rotated by the facing quaternion → desired displacement
Physics module + Havok character proxy+ gravity × multiplier; collide and slide; step up; probe down and snap
env(200) falling · env(201) landed · env(224) fall height · env(296) slide
Back to the scriptposition, grounded, ground material, air time

2The state machine is a script

action/script/c0000.hks is compiled Havok Script. DSLuaDecompiler turns it into 15,439 lines, 977 functions of Lua. Every frame, the graph calls <State>_onUpdate() for each active state. The script reads engine state with env(id, …), writes graph variables, fires transitions with ExecEvent("W_…"), and calls engine actions with act(id, …). AttackCommonFunction shows the priority of everything: passive actions, evasion, guard, items, magic, weapon arts, the next attack, weapon change, then movement and quick turns.

Close

We don't run the script. Our engine re-implements the states we need by hand, from the decompiled source, with the same thresholds and event names.

From an event to a clip

ExecEvent("W_RollingMedium") names a behaviour event, not a clip. The graph (c0000.behbnd: 7,026 clip generators, 2,589 FromSoft CustomManualSelectorGenerators, 1,091 states, 1,267 event names) maps it. Our graph reader lists it all:

EventClip(s)
W_Idlea000_000000
W_RollingLight / Medium / HeavyA blend on RollingAngleReal of left, right, front and back clips a000_0271w2-7 (w = weight class). The forward roll 027110 everyone uses isn't in the graph.
W_BackStepLight / Nomal / Heavy027000 / 027010 / 027020
W_Jump / W_JumpLong027410 / 027400
W_FallStart → W_FallLoop004050 → 004000
W_AttackRightLight1/2/330000 / 30010 / 30020 with the right weapon's motion category as prefix: a023_030000

Each event's transition names its crossfade: 0.1 s for rolls, damage and guard reactions; 1/6 s for jumps; FromSoft's own "DefaultTransition" uses the clip's TAE Blend event (attacks 0.2-0.33 s).

3Locomotion

ClipsLengthRoot speed
walk a000_0200x0, 4 directions1.33 s1.50 m/s
run 0201x00.73-0.80 s3.7-4.0 m/s
dash 0202x0 (front only)0.57-0.67 s6.04 m/s
quick turns 026001-260310.67-0.73 syaw ±90° / ±180° in place
ladder 0280xx0.4-2.0 s±0.5 m vertical per step

Locked on, the graph picks one directional clip by MoveDirection; there's no 2-D blend. The script sets the "4-direction move thresholds" (60, 45, 60, 60). A locked-on dash releases the angle lock. Rolls turn to the target at once and pick a direction by RollingAngle. Lock-on range is 15 m (LockCamParam), 9 or 5 m in the dark.

Stops and turns: letting go at ≤ 0.35 goes straight to idle; ≤ 1 plays a run stop by direction; above that, W_DashStop (0.65 m of slide), from which a stick pushed past 90° plays a 180° dash turn whose root motion turns you while sliding.

Faithful

Clips, root motion, smoothing constants, thresholds and directional picks are all DS3's. How the engine maps stick deflection to the level isn't traced.

4Rolls, backsteps and jumps

A medium roll, frame by frame
A medium roll, 0.15 s apart, in our engine: root motion carries the knight 4.45 m forward.

The medium rolls (1.83 s) share their TAE windows: flag 8 Invincible 0-0.533 s (16 frames of i-frames), flag 7 no turning 0.1-0.7 s, and flag 11 "stick may cancel" from 0.733 s. Distances: light 5.07 m, medium 4.45, heavy 3.31. Costs: roll 16 stamina, backstep 11, jump 16 (26 / 18 / 26 when overweight).

A running jump, frame by frame
A running jump: dash, then evade.

The jump has no take-off speed

The running jumps have 3.0 / 2.06 m/s of horizontal root motion and zero vertical. Their TAE has flag 27 Ignore Gravity for 0-0.1 s, and event 300 ActivateJumpTableEarly ramps jump table 27 from 0 to 1 over 0.1-0.3 s. The physics module copies that value into its gravity multiplier (+0x1D4, 0x1409dc600) exe. So the capsule carries on level for a moment, then gravity comes back. The height you see is in the pose. (A popular cheat table's "jump height" patch makes the start value negative: a hack, not a mechanic.)

R1 in the air comes out on landing as the rolling R1, and R2 as the second heavy: the RH-attack window opens as the jump lands. The plunging attack starts once a fall is 2 m deep and R1 is pressed. Its clips carry flag 50, so the plunger falls through the enemy's capsule instead of standing on its head.

5TAE flags: the physics switchboard

FlagNamePlayer eventsExample
27Ignore Gravity477ladders, ledge drops, the first 0.1 s of a jump
19Disable Map/Object Collision364ladder mount, bonfire warp, pushing Gundyr's door
51Disable Falling Animation528landings
74Ladder Collision Start49every ladder clip
50Disable NPCParam HitRadius Push174grabs, plunging
7Disable Turning5,559most attacks
11Cancel – LS Move3,626the stick may end the clip
89 / 90 / 91No movement / no dash or run / no dash339 / 303 / 117heavy actions, drinking

Plus event types 224 SetTurnSpeed, 236 RootMotionReduction (0.8 → 0.7 → 0.5 through a jump) and 300 the jump tables. These carry most of DS3's "feel".

6The body: Havok's character proxy

Characters aren't rigid bodies. Each is a Havok hknpCharacterProxy, a kinematic capsule moved by a shape-cast-and-slide solver, wrapped as NS_SPRJ::CsHkCharacterProxy. The parameters were read off the stack frame of the creation function 0x140dda1c0, with Havok's own descriptions, which are embedded in the exe exe:

FieldDS3Our Jolt CharacterVirtual
maxSlopeπ/3 = 60° (first set to π/2, then overwritten)mMaxSlopeAngle 60° (Jolt's default is 50°)
capsule1.9 m × 0.4 m, feet at the origin (NpcParam)The same, as a shape offset
keepDistance / keepContactTolerance0.05 / 0.1mCharacterPadding / mPredictiveContactDistance
characterStrengthFLT_MAXmMaxStrength large (Jolt's default is 100 N)
penetrationRecoverySpeed1.01.0
maxCastIterations10 (2 with a setup flag)Jolt's iterations
step-up lift0.3 m (0.8 in another mode)mWalkStairsStepUp 0.3
ground probe and snapa downward cast to step + 0.8 m belowmStickToFloorStepDown
gravity(0, −9.8, 0) × the multiplier, zeroed by flagsApplied by hand (Jolt doesn't, for virtual characters)

A character can have two proxies: one against characters and a second, with a different capsule, against the map. The second exists only when NpcParam's subHit size differs. After integrating, the closest upward-facing contact becomes the ground: its normal, and its hit material from body + shape key. The module keeps the last grounded position (+0x170, the fall-height reference) and air time.

Who pushes whom isn't traced. Ours lets a character be stopped only by characters at least as heavy, so the player can't shove hollows about but hollows push the player guess. Corpses block nobody.

Close

DS3's numbers on a different solver from the same family (shape-cast and slide, contact manifold). Unsolved: when DS3 runs "mode A" vs "mode B", the slide speed on slippery material, and FrpgCollisionFilter's layer matrix.

7Falling and fall damage

FallResult (c0000.hks)
≤ 0.3 mno landing animation
0.3-1.3 mW_LandLow
1.3-4 m / 4-8 m / > 8 mW_Land default / middle / heavy
> 20 mdeath on landing, unless SpEffects 4050-4080
≥ 60 m in the airthe fall-death animation mid-air

Fall damage is engine code, on landing, before the script looks exe. For players (0x140634bc0): 0 under 5 m, all of max HP from 20 m, else max HP × CalcCorrectGraph 210 (height → %: 5/8/12/16/20 m → 8/15/50/90/100 %) × 211 (equip load) × 212 (VIT) × 213 (DEX) × SpEffects. The Knight takes ×1.32: 53 HP at 5.4 m, 219 at 10.4 m, all of it from about 14.6 m. Enemies: (h/15)^1.8 × (100 − fallDamageDamp) %.

Faithful

The thresholds, landings, landing deaths and the damage curves, from the script and the exe.

8Bonfires, items, ladders, camera, keys

Interaction

Action buttons are ActionButtonParam cylinders on dummy polys: radius, height, offset, and the facing allowed (AllowAngle 180 = any). Bonfires, Gundyr's sword and the door all work this way (Levels).

Ladders

Objects with attach points. The script asks GetLadderEventCommand; gravity is off and ladder collision on (flags 27 + 74), 0.5 m per rung clip. not done: m40 has few.

Camera

LockCamParam: 4 m target distance, 43° vertical field of view, pivot height 1.42 m guess; a ray pulls it in against the collision. DS3's rotation speeds aren't found.

Keys on PC

The Key Config screen's actions come from the menu text. The defaults (WASD, Space, Q, left/right click, Shift + click for strong attacks, R item, E interact) come from published guides; where DS3 stores them is an open lead.