Editor/WeaponImporter/Core/Analysis/AnimationRole.cs
#nullable enable annotations
namespace WeaponImporter.Core.Analysis;
/// <summary>What an animation is for. The importer maps each role to one clip.</summary>
public enum AnimationRole
{
Unknown,
Idle,
Fire,
FireEmpty,
Reload,
TacticalReload,
EmptyReload,
Draw,
Holster,
Inspect,
Sprint,
Walk,
Ads,
AdsFire,
Melee,
Bolt,
Jam,
Unjam,
/// <summary>Lowering the sights (played when aiming stops).</summary>
AdsOut,
/// <summary>Looping aimed pose (while aiming, after ADS raised the sights).</summary>
AdsIdle,
/// <summary>Shell-by-shell reload, first part (to the loading port).</summary>
ReloadStart,
/// <summary>Shell-by-shell reload: one shell (repeated per shell).</summary>
ReloadInsert,
/// <summary>Shell-by-shell reload, last part (pump, back to idle).</summary>
ReloadEnd,
}
public static class AnimationRoles
{
/// <summary>Roles shown in the editor, in the order they appear.</summary>
public static readonly AnimationRole[] All =
{
AnimationRole.Idle, AnimationRole.Fire, AnimationRole.FireEmpty, AnimationRole.Reload,
AnimationRole.TacticalReload, AnimationRole.EmptyReload, AnimationRole.ReloadStart, AnimationRole.ReloadInsert, AnimationRole.ReloadEnd, AnimationRole.Draw, AnimationRole.Holster,
AnimationRole.Inspect, AnimationRole.Sprint, AnimationRole.Walk, AnimationRole.Ads, AnimationRole.AdsIdle, AnimationRole.AdsOut, AnimationRole.AdsFire,
AnimationRole.Melee, AnimationRole.Bolt, AnimationRole.Jam, AnimationRole.Unjam,
};
/// <summary>Roles every firearm should have; missing ones are reported by validation.</summary>
public static readonly AnimationRole[] Required = { AnimationRole.Fire, AnimationRole.Reload };
public static string Label(AnimationRole role) => role switch
{
AnimationRole.FireEmpty => "Fire Empty",
AnimationRole.TacticalReload => "Tactical Reload",
AnimationRole.EmptyReload => "Empty Reload",
AnimationRole.Ads => "ADS",
AnimationRole.AdsOut => "ADS Out",
AnimationRole.AdsIdle => "ADS Idle",
AnimationRole.ReloadStart => "Reload Start",
AnimationRole.ReloadInsert => "Insert Shell",
AnimationRole.ReloadEnd => "Reload End",
AnimationRole.AdsFire => "ADS Fire",
AnimationRole.Bolt => "Bolt / Charge",
_ => role.ToString(),
};
/// <summary>
/// Roles that cycle. ADS is not one: it raises the sights and the aimed pose is held at its
/// last frame while the player aims (Weapon Hold's Aiming).
/// </summary>
/// <summary>A part of a shell-by-shell reload (start, one shell, end).</summary>
public static bool IsShellReload(AnimationRole role)
=> role is AnimationRole.ReloadStart or AnimationRole.ReloadInsert or AnimationRole.ReloadEnd;
public static bool Loops(AnimationRole role)
=> role is AnimationRole.Idle or AnimationRole.Sprint or AnimationRole.Walk or AnimationRole.AdsIdle;
/// <summary>Role the given one falls back to when it has no clip (empty reload plays reload).</summary>
public static AnimationRole? Fallback(AnimationRole role) => role switch
{
AnimationRole.TacticalReload or AnimationRole.EmptyReload => AnimationRole.Reload,
AnimationRole.FireEmpty or AnimationRole.AdsFire => AnimationRole.Fire,
AnimationRole.Ads or AnimationRole.Walk or AnimationRole.Inspect => AnimationRole.Idle,
AnimationRole.Sprint => AnimationRole.Walk,
AnimationRole.Unjam => AnimationRole.Bolt,
_ => null,
};
/// <summary>
/// The citizen/human animgraph parameter that triggers the role in game, when there is one.
/// </summary>
public static string? GraphTrigger(AnimationRole role) => role switch
{
AnimationRole.Fire or AnimationRole.AdsFire or AnimationRole.FireEmpty => "b_attack",
AnimationRole.Reload or AnimationRole.TacticalReload or AnimationRole.EmptyReload or AnimationRole.ReloadStart or AnimationRole.ReloadInsert or AnimationRole.ReloadEnd => "b_reload",
AnimationRole.Draw => "b_deploy",
_ => null,
};
}