From OpenMW Wiki
Revision as of 20:49, 11 November 2019 by Jangler (talk | contribs) (→‎Midair: Use better terminology in midair movement equation)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search


Actions affected Movement
Description Describes an actor's movement speed for each mode of movement. Uses common term normalizedEncumbrance.
Implementation status changed since last implementation
Analysis status Still has further interactions with physics

Actor target speeds

Passed to the animation system, as well as used for AI target leading.

if actor is a npc:
    walkSpeed = fMinWalkSpeed + 0.01 * speedAttribute * (fMaxWalkSpeed - fMinWalkSpeed)
    walkSpeed *= 1 - fEncumberedMoveEffect * normalizedEncumbrance
    walkSpeed = max(0, walkSpeed)
    if sneaking: walkSpeed *= fSneakSpeedMultiplier
elif actor is a creature:
    walkSpeed = fMinWalkSpeedCreature + 0.01 * speedAttribute * (fMaxWalkSpeedCreature - fMinWalkSpeedCreature)

runSpeed = walkSpeed * (0.01 * athleticsSkill * fAthleticsRunBonus + fBaseRunMultiplier)

if encumbrance > maxEncumbrance:
    moveSpeed = 0
elif flying or levitating:
    flySpeed = 0.01 * (speedAttribute + levitationBonus)
    flySpeed = fMinFlySpeed + flySpeed * (fMaxFlySpeed - fMinFlySpeed)
    flySpeed *= 1 - fEncumberedMoveEffect * normalizedEncumbrance
    flySpeed = max(0, flySpeed)
    moveSpeed = flySpeed
elif swimming:
    if running mode is on:
        swimSpeed = runSpeed
        swimSpeed = walkSpeed
    swimSpeed *= 1 + 0.01 * swiftSwimBonus
    swimSpeed *= 0.01 * athleticsSkill * fSwimRunAthleticsMult + fSwimRunBase
    moveSpeed = swimSpeed
elif walking or sneaking:
    moveSpeed = walkSpeed
elif running:
    moveSpeed = runSpeed
    moveSpeed = 0

if strafing (not including diagonally): moveSpeed *= 0.75
if actor is a werewolf and running and has no weapon ready: moveSpeed *= fWereWolfRunMult

moveSpeed is stored for later use.

Animation system

Determines movement of the model root bone which feeds back to the physics system.

anim = the relevant movement mode animation:     # diagonal strafe uses the forward/back animations
    Walk, Fly -> Walk<direction>[+weapon]

if actor is a creature:
    moveSpeed is re-calculated as if the creature was not running (as walking)
    referenceAnim = choose the walking equivalent of the current movement mode:
        Walk, Fly, Run -> Walk<direction>
        SwimWalk, SwimRun -> SwimWalk<direction>

if actor is an NPC:
    referenceAnim = anim

dist, dt = distance and time between the root bone positions at the "Loop Start" (or "Start" if it doesnt exist)
           and "Loop Stop" (or "Stop" if it doesnt exist) animation notes for 'referenceAnim'

# note: if there are multiple matching animation notes, the last occurring one is used
# note: if the "Loop Stop" key occurs after the "Stop" key, the "Stop" key is used

animBaseSpeed = int(dist / dt)
animationScale = moveSpeed / animBaseSpeed
animationScale = min(animationScale, 10)

The animation system plays 'anim' with a rate multiplier animationScale. The root bone movement is passed to the physics system.

Physics movement

Provides three-dimensional movement like jumps, falls, navigating stairs, levitation.

The actor reference is updated with the root bone movement from the current frame.

fStromWindSpeed and fStromWalkMult both affect movement, slowing movement into the wind and faster with the wind.
fStromWindSpeed is used with the current wind speed in all weathers. fStromWalkMult is used with storms.
These are not applied when NPCs are underwater, but do seem to apply to slaughterfish.


Creatures have generalized combat, magic and stealth stats which substitute for the specific skills (in the same way as specializations). Creatures do not suffer slow down from encumbrance (fEncumberedMoveEffect). They will only completely stop dead, once they exceed their encumbrance limit.

Note the 10x cap on the animation scaling. This causes an upper limit on the movement rate of actors, which will be at a speed attribute of approximately 1030.


Actions affected Jumping, landing, and midair control
Description Uses common terms fatigueTerm, normalizedEncumbrance.
Implementation status implemented
Analysis status Initial velocity verified; requires testing in combination with physics system

On jumping

encumbranceTerm = fJumpEncumbranceBase + fJumpEncumbranceMultiplier * (1 - normalizedEncumbrance)

if acrobaticsSkill <= 50:
    a = acrobaticsSkill, b = 0
    a = 50, b = acrobaticsSkill - 50

x = fJumpAcrobaticsBase + pow(a / 15.0, fJumpAcroMultiplier)
x += 3 * b * fJumpAcroMultiplier
x += jumpSpellBonus * 64
x *= encumbranceTerm
if actor is running: x *= fJumpRunMultiplier
x *= fatigueTerm
x -= gravityAcceleration [constant; -627.2 exactly]
x /= 3

if actor is standing still:
    set kinematic velocity to {0, 0, x}

if actor is moving:
    groundVelocity = normalize({actorVelocity.x, actorVelocity.y})
    set kinematic velocity to 0.707 * x * {groundVelocity.x, groundVelocity.y, 1.0}

decrease fatigue by fFatigueJumpBase + normalizedEncumbrance * fFatigueJumpMult


Airborne velocity can be offset from the initial jump vector based on ground speed and Acrobatics skill.

jumpMoveTerm = fJumpMoveBase + 0.01 * acrobaticsSkill * fJumpMoveMult
total velocity = kinematic velocity + ground movement velocity * jumpMoveTerm

On landing

fallingDist = distance from peak height

if fallingDist <= fFallDamageDistanceMin: soft landing; skip the rest of the function

x = fallingDist - fFallDamageDistanceMin
x -= 1.5 * acrobaticsSkill + jumpSpellBonus
x = max(0, x)

a = fFallAcroBase + fFallAcroMult * (100 - acrobaticsSkill)
x = fFallDistanceBase + fFallDistanceMult * x
x *= a

if x > 0: damage health by x * (1 - 0.25 * fatigueTerm)

if acrobaticsSkill * fatigueTerm < x: actor falls over

if actor is not incapacitated: acrobatics skill exercised (skill gain from fall damage)


Note that initial actor velocity is taken into account. Animation-driven kinematics mean the jump direction can be offset from the player facing if there is root bone movement. Agility does not appear to be involved in this calculation.