ViperAvatar.cs
using Sandbox;
using System;

namespace PaintballBaddies;

/// <summary>Retargeted locomotion driven by actual movement and collider posture.</summary>
public sealed class ViperAvatar : Component
{
    [Property] public string PreviewSequence { get; set; } = "";
    private static bool UsesMeiLanding(string path) => path is "models/characters/mei_planted_review/mei_protected.vmdl" or "models/characters/mei_protected_morph/mei_protected.vmdl";
    private PlayerController controller;
    private float playbackRate = 1;
    private float smoothedSpeed;
    private float candidateLandingGrace;
    private bool candidateWasVaulting;
    private float landingRecovery = -1;
    protected override void OnStart()
    {
        controller = Components.Get<PlayerController>();
        if(Components.Get<MovementFootsteps>() is null) Components.Create<MovementFootsteps>();
        if ( controller?.Renderer is not { } renderer ) return;
        controller.UseAnimatorControls = false;
        renderer.UseAnimGraph = false;
        renderer.Sequence.Name = "idle";
        renderer.Sequence.Looping = true;
        renderer.Sequence.Blending = true;
    }

    protected override void OnUpdate()
    {
        if ( controller?.Renderer is not { } renderer ) return;
        if (Components.Get<CitizenPlayerPresentation>()?.IsReady == true)
        {
            candidateWasVaulting=false;candidateLandingGrace=0;landingRecovery=-1;
            smoothedSpeed=0;
            return;
        }
        var vault = Components.Get<VaultController>();
        if ( vault?.IsVaulting == true )
        {
            if ( UsesMeiLanding(renderer.Model?.Name) ) { candidateLandingGrace = .12f; candidateWasVaulting = true; landingRecovery = -1; }
            if ( renderer.Sequence.Name != "vault" ) renderer.Sequence.Name = "vault";
            renderer.Sequence.Looping = false; renderer.PlaybackRate = 0;
            if ( UsesMeiLanding(renderer.Model?.Name) ) renderer.Sequence.TimeNormalized = vault.Progress;
            else renderer.Sequence.Time = vault.Progress * .8f;
            var groundOffset = CoveredVaultGroundProfiles.TrySample( renderer.Model?.Name, vault.Progress, out var coveredOffset )
                ? coveredOffset : VaultGroundProfiles.Sample( Components.Get<RosterSelection>()?.Selected ?? 0, vault.Progress );
            renderer.LocalPosition = vault.VisualBasePosition + Vector3.Down * groundOffset;
            renderer.WorldRotation = vault.Facing;
            return;
        }
        if ( candidateWasVaulting )
        {
            candidateWasVaulting = false;
            if ( vault?.Outcome == "Landed" ) landingRecovery = 0;
        }
        if ( landingRecovery >= 0 )
        {
            var marker = Components.Get<PaintballMarker>();
            var interrupt = controller.WishVelocity.WithZ(0).Length > 1 || controller.IsDucking
                || marker?.ReloadRemaining > 0 || marker?.Aiming == true
                || (marker?.AcceptInput == true && Input.Down("attack1"))
                || Components.Get<CoverController>()?.Attached == true;
            if ( !interrupt && landingRecovery < .3f && UsesMeiLanding(renderer.Model?.Name) )
            {
                if ( renderer.Sequence.Name != "landing_recovery" ) renderer.Sequence.Name = "landing_recovery";
                renderer.Sequence.Blending = false; renderer.Sequence.Looping = false; renderer.PlaybackRate = 0;
                var p = landingRecovery / .3f;
                renderer.Sequence.Time = landingRecovery;
                renderer.LocalPosition = vault.VisualBasePosition + Vector3.Down * MeiLandingRecoveryGround.Sample(p);
                landingRecovery += Time.Delta; smoothedSpeed = 0;
                return;
            }
            landingRecovery = -1;
            renderer.LocalPosition = vault.VisualBasePosition;
            renderer.Sequence.Blending = true;
        }
        var velocity = controller.Velocity.WithZ( 0 );
        var speed = velocity.Length;
        if ( candidateLandingGrace > 0 )
        {
            candidateLandingGrace -= Time.Delta;
            if ( controller.WishVelocity.WithZ(0).Length < 1 ) { speed = 0; smoothedSpeed = 0; }
        }
        smoothedSpeed += (speed - smoothedSpeed) * (1 - MathF.Exp( -16 * Time.Delta ));
        // Slight hysteresis prevents a sequence restart around a speed boundary.
        var moving = smoothedSpeed > (renderer.Sequence.Name == "idle" || renderer.Sequence.Name == "crouch" ? 9 : 5);
        var running = smoothedSpeed > (renderer.Sequence.Name == "run" ? 120 : 135);
        var clip = controller.IsDucking ? (moving ? "crouch_walk" : "crouch")
            : running ? "run" : moving ? "walk" : "idle";
        var cover = Components.Get<CoverController>();
        var weapon = Components.Get<PaintballMarker>();
        var roster = Components.Get<RosterSelection>();
        var combatClips = roster is not null;
        var motionScale = roster?.MotionScale ?? 1;
        var facing = cover?.Attached == true && !cover.Peeking
            ? Rotation.LookAt( -cover.Normal ) : Rotation.FromYaw( controller.EyeAngles.yaw );
        var localVelocity = facing.Inverse * velocity;
        if ( combatClips )
        {
            var facingTarget = cover?.Attached == true || weapon?.Aiming == true;
            if ( moving && facingTarget )
            {
                var wasLateral = renderer.Sequence.Name is "walk_left" or "walk_right" or "crouch_left" or "crouch_right";
                // A small angular dead band prevents alternating clips at diagonal input.
                var lateral = MathF.Abs(localVelocity.y) > MathF.Abs(localVelocity.x) * (wasLateral ? .9f : 1.1f);
                if ( controller.IsDucking && lateral )
                    clip = localVelocity.y > 0 ? "crouch_left" : "crouch_right";
                else if ( !controller.IsDucking && renderer.Model?.Name == RosterSelection.GetModelPath( roster.Selected )
                    && lateral )
                    clip = localVelocity.y > 0 ? "walk_left" : "walk_right";
                else if ( !controller.IsDucking && localVelocity.x < -MathF.Abs( localVelocity.y ) ) clip = "walk_backward";
            }
            // Covered characters keep their locomotion underneath the reload layer,
            // including idle, so entering reload does not replace the whole pose.
            if ( !moving && !controller.IsDucking && weapon?.ReloadRemaining > 0
                && CoveredRosterAssets.ReloadTrack(renderer.Model?.Name) is null ) clip = "reload_standing";
        }
        if ( !string.IsNullOrEmpty( PreviewSequence ) ) clip = PreviewSequence;
        // Assigning Name restarts the native sequence, even when unchanged.
        // Change it only at a state transition so the gait can advance.
        if ( renderer.Sequence.Name != clip )
        {
            CoveredStrideTransition.SetSequence(renderer, clip);
            if ( clip == "reload_standing" ) renderer.Sequence.Time = MathF.Max( 0, (weapon.ActiveReloadDuration - weapon.ReloadRemaining) * 2 );
        }
        var targetRate = clip == "walk" ? (smoothedSpeed / (85f * motionScale)).Clamp( 0.65f, 1.5f )
            : clip == "run" ? (smoothedSpeed / (177f * motionScale)).Clamp( 0.75f, 1.55f )
            : clip == "crouch_walk" ? (smoothedSpeed / (55f * motionScale)).Clamp( 0.65f, 1.4f ) : 1;
        if ( clip == "crouch_left" ) targetRate = (smoothedSpeed / (60.5f * motionScale)).Clamp( .5f, 1.6f );
        if ( clip == "crouch_right" ) targetRate = (smoothedSpeed / (52f * motionScale)).Clamp( .5f, 1.6f );
        if ( (clip == "crouch_right" || clip == "crouch_left" || clip == "crouch_walk")
            && (renderer.Model?.Name == "models/characters/freya_shuffle_pilot/freya_protected.vmdl"
                || UsesMeiLanding(renderer.Model?.Name)
                || renderer.Model?.Name == "models/characters/imani_shuffle_pilot/imani_protected.vmdl"
                || renderer.Model?.Name == "models/characters/imani_protected_morph/imani_protected.vmdl"
                || renderer.Model?.Name == "models/characters/freya_protected_morph/freya_protected.vmdl") )
            targetRate = (smoothedSpeed / 25.59055f).Clamp( .1f, 3f );
        if ( clip == "walk_backward" ) targetRate = (smoothedSpeed / (52.75f * motionScale)).Clamp( .5f, 1.8f );
        if ( clip == "walk_left" || clip == "walk_right" ) targetRate = (smoothedSpeed / (41.36f * motionScale)).Clamp( .5f, 3f );
        if ( clip == "reload_standing" )
        {
            var authoredReload = CoveredRosterAssets.ReloadTrack( renderer.Model?.Name ) is not null;
            targetRate = authoredReload ? 0 : 2;
            if ( authoredReload ) renderer.Sequence.TimeNormalized = weapon.ReloadProgress;
            playbackRate = targetRate;
            renderer.Sequence.Looping = false;
        }
        else renderer.Sequence.Looping = true;
        playbackRate += (targetRate - playbackRate) * (1 - MathF.Exp( -10 * Time.Delta ));
        renderer.PlaybackRate = playbackRate;
        var yaw = speed > 10 && weapon?.Aiming != true && !(weapon?.AcceptInput == true && Input.Down( "attack1" ))
            ? Rotation.LookAt( velocity ).Yaw() : controller.EyeAngles.yaw;
        if ( cover?.Attached == true && !cover.Peeking ) yaw = Rotation.LookAt( -cover.Normal ).Yaw();
        renderer.WorldRotation = Rotation.Slerp( renderer.WorldRotation, Rotation.FromYaw( yaw ), 1 - MathF.Exp( -9 * Time.Delta ) );
    }
}