feat(anim): Phase L.1c classify combat animation commands
This commit is contained in:
parent
268af82e28
commit
831392a7b2
3 changed files with 420 additions and 0 deletions
278
src/AcDream.Core/Combat/CombatAnimationPlanner.cs
Normal file
278
src/AcDream.Core/Combat/CombatAnimationPlanner.cs
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
using AcDream.Core.Physics;
|
||||
|
||||
namespace AcDream.Core.Combat;
|
||||
|
||||
/// <summary>
|
||||
/// Retail-faithful combat animation planner for server-sent motion commands.
|
||||
///
|
||||
/// Retail evidence:
|
||||
/// - <c>ClientCombatSystem::ExecuteAttack</c> (0x0056BB70) only sends the
|
||||
/// targeted melee/missile GameAction and sets response state; it does not
|
||||
/// locally choose or play a swing animation.
|
||||
/// - <c>ClientCombatSystem::HandleCommenceAttackEvent</c> (0x0056AD20)
|
||||
/// updates the power bar/busy state; it carries no MotionCommand.
|
||||
/// - ACE <c>Player_Melee.DoSwingMotion</c> chooses a swing via
|
||||
/// <c>CombatManeuverTable.GetMotion</c> and broadcasts that MotionCommand
|
||||
/// in <c>UpdateMotion</c>.
|
||||
///
|
||||
/// So acdream treats combat GameEvents as state/UI signals and treats
|
||||
/// UpdateMotion command IDs as the animation authority.
|
||||
/// </summary>
|
||||
public static class CombatAnimationPlanner
|
||||
{
|
||||
public static CombatAnimationPlan PlanForEvent(CombatAnimationEvent combatEvent)
|
||||
{
|
||||
_ = combatEvent;
|
||||
return CombatAnimationPlan.None;
|
||||
}
|
||||
|
||||
public static CombatAnimationPlan PlanFromWireCommand(ushort wireCommand, float speedMod = 1f)
|
||||
{
|
||||
uint fullCommand = MotionCommandResolver.ReconstructFullCommand(wireCommand);
|
||||
return PlanFromFullCommand(fullCommand, speedMod);
|
||||
}
|
||||
|
||||
public static CombatAnimationPlan PlanFromFullCommand(uint fullCommand, float speedMod = 1f)
|
||||
{
|
||||
var kind = ClassifyMotionCommand(fullCommand);
|
||||
if (kind == CombatAnimationKind.None)
|
||||
return CombatAnimationPlan.None;
|
||||
|
||||
return new CombatAnimationPlan(
|
||||
kind,
|
||||
AnimationCommandRouter.Classify(fullCommand),
|
||||
fullCommand,
|
||||
speedMod);
|
||||
}
|
||||
|
||||
public static CombatAnimationKind ClassifyMotionCommand(uint fullCommand)
|
||||
{
|
||||
return fullCommand switch
|
||||
{
|
||||
CombatAnimationMotionCommands.HandCombat
|
||||
or CombatAnimationMotionCommands.SwordCombat
|
||||
or CombatAnimationMotionCommands.SwordShieldCombat
|
||||
or CombatAnimationMotionCommands.TwoHandedSwordCombat
|
||||
or CombatAnimationMotionCommands.BowCombat
|
||||
or CombatAnimationMotionCommands.CrossbowCombat
|
||||
or CombatAnimationMotionCommands.SlingCombat
|
||||
or CombatAnimationMotionCommands.AtlatlCombat
|
||||
or CombatAnimationMotionCommands.ThrownShieldCombat
|
||||
or CombatAnimationMotionCommands.Magic => CombatAnimationKind.CombatStance,
|
||||
|
||||
CombatAnimationMotionCommands.ThrustMed
|
||||
or CombatAnimationMotionCommands.ThrustLow
|
||||
or CombatAnimationMotionCommands.ThrustHigh
|
||||
or CombatAnimationMotionCommands.SlashHigh
|
||||
or CombatAnimationMotionCommands.SlashMed
|
||||
or CombatAnimationMotionCommands.SlashLow
|
||||
or CombatAnimationMotionCommands.BackhandHigh
|
||||
or CombatAnimationMotionCommands.BackhandMed
|
||||
or CombatAnimationMotionCommands.BackhandLow
|
||||
or CombatAnimationMotionCommands.DoubleSlashLow
|
||||
or CombatAnimationMotionCommands.DoubleSlashMed
|
||||
or CombatAnimationMotionCommands.DoubleSlashHigh
|
||||
or CombatAnimationMotionCommands.TripleSlashLow
|
||||
or CombatAnimationMotionCommands.TripleSlashMed
|
||||
or CombatAnimationMotionCommands.TripleSlashHigh
|
||||
or CombatAnimationMotionCommands.DoubleThrustLow
|
||||
or CombatAnimationMotionCommands.DoubleThrustMed
|
||||
or CombatAnimationMotionCommands.DoubleThrustHigh
|
||||
or CombatAnimationMotionCommands.TripleThrustLow
|
||||
or CombatAnimationMotionCommands.TripleThrustMed
|
||||
or CombatAnimationMotionCommands.TripleThrustHigh
|
||||
or CombatAnimationMotionCommands.OffhandSlashHigh
|
||||
or CombatAnimationMotionCommands.OffhandSlashMed
|
||||
or CombatAnimationMotionCommands.OffhandSlashLow
|
||||
or CombatAnimationMotionCommands.OffhandThrustHigh
|
||||
or CombatAnimationMotionCommands.OffhandThrustMed
|
||||
or CombatAnimationMotionCommands.OffhandThrustLow
|
||||
or CombatAnimationMotionCommands.OffhandDoubleSlashLow
|
||||
or CombatAnimationMotionCommands.OffhandDoubleSlashMed
|
||||
or CombatAnimationMotionCommands.OffhandDoubleSlashHigh
|
||||
or CombatAnimationMotionCommands.OffhandTripleSlashLow
|
||||
or CombatAnimationMotionCommands.OffhandTripleSlashMed
|
||||
or CombatAnimationMotionCommands.OffhandTripleSlashHigh
|
||||
or CombatAnimationMotionCommands.OffhandDoubleThrustLow
|
||||
or CombatAnimationMotionCommands.OffhandDoubleThrustMed
|
||||
or CombatAnimationMotionCommands.OffhandDoubleThrustHigh
|
||||
or CombatAnimationMotionCommands.OffhandTripleThrustLow
|
||||
or CombatAnimationMotionCommands.OffhandTripleThrustMed
|
||||
or CombatAnimationMotionCommands.OffhandTripleThrustHigh
|
||||
or CombatAnimationMotionCommands.OffhandKick => CombatAnimationKind.MeleeSwing,
|
||||
|
||||
CombatAnimationMotionCommands.Shoot
|
||||
or CombatAnimationMotionCommands.MissileAttack1
|
||||
or CombatAnimationMotionCommands.MissileAttack2
|
||||
or CombatAnimationMotionCommands.MissileAttack3
|
||||
or CombatAnimationMotionCommands.Reload => CombatAnimationKind.MissileAttack,
|
||||
|
||||
CombatAnimationMotionCommands.AttackHigh1
|
||||
or CombatAnimationMotionCommands.AttackMed1
|
||||
or CombatAnimationMotionCommands.AttackLow1
|
||||
or CombatAnimationMotionCommands.AttackHigh2
|
||||
or CombatAnimationMotionCommands.AttackMed2
|
||||
or CombatAnimationMotionCommands.AttackLow2
|
||||
or CombatAnimationMotionCommands.AttackHigh3
|
||||
or CombatAnimationMotionCommands.AttackMed3
|
||||
or CombatAnimationMotionCommands.AttackLow3
|
||||
or CombatAnimationMotionCommands.AttackHigh4
|
||||
or CombatAnimationMotionCommands.AttackMed4
|
||||
or CombatAnimationMotionCommands.AttackLow4
|
||||
or CombatAnimationMotionCommands.AttackHigh5
|
||||
or CombatAnimationMotionCommands.AttackMed5
|
||||
or CombatAnimationMotionCommands.AttackLow5
|
||||
or CombatAnimationMotionCommands.AttackHigh6
|
||||
or CombatAnimationMotionCommands.AttackMed6
|
||||
or CombatAnimationMotionCommands.AttackLow6 => CombatAnimationKind.CreatureAttack,
|
||||
|
||||
CombatAnimationMotionCommands.CastSpell
|
||||
or CombatAnimationMotionCommands.UseMagicStaff
|
||||
or CombatAnimationMotionCommands.UseMagicWand => CombatAnimationKind.SpellCast,
|
||||
|
||||
CombatAnimationMotionCommands.FallDown
|
||||
or CombatAnimationMotionCommands.Twitch1
|
||||
or CombatAnimationMotionCommands.Twitch2
|
||||
or CombatAnimationMotionCommands.Twitch3
|
||||
or CombatAnimationMotionCommands.Twitch4
|
||||
or CombatAnimationMotionCommands.StaggerBackward
|
||||
or CombatAnimationMotionCommands.StaggerForward
|
||||
or CombatAnimationMotionCommands.Sanctuary => CombatAnimationKind.HitReaction,
|
||||
|
||||
MotionCommand.Dead => CombatAnimationKind.Death,
|
||||
|
||||
_ => CombatAnimationKind.None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public readonly record struct CombatAnimationPlan(
|
||||
CombatAnimationKind Kind,
|
||||
AnimationCommandRouteKind RouteKind,
|
||||
uint MotionCommand,
|
||||
float SpeedMod)
|
||||
{
|
||||
public static CombatAnimationPlan None { get; } = new(
|
||||
CombatAnimationKind.None,
|
||||
AnimationCommandRouteKind.None,
|
||||
0u,
|
||||
0f);
|
||||
|
||||
public bool HasMotion => Kind != CombatAnimationKind.None && MotionCommand != 0;
|
||||
}
|
||||
|
||||
public enum CombatAnimationEvent
|
||||
{
|
||||
CombatCommenceAttack,
|
||||
AttackDone,
|
||||
AttackerNotification,
|
||||
DefenderNotification,
|
||||
EvasionAttackerNotification,
|
||||
EvasionDefenderNotification,
|
||||
VictimNotification,
|
||||
KillerNotification,
|
||||
}
|
||||
|
||||
public enum CombatAnimationKind
|
||||
{
|
||||
None = 0,
|
||||
CombatStance,
|
||||
MeleeSwing,
|
||||
MissileAttack,
|
||||
CreatureAttack,
|
||||
SpellCast,
|
||||
HitReaction,
|
||||
Death,
|
||||
}
|
||||
|
||||
internal static class CombatAnimationMotionCommands
|
||||
{
|
||||
public const uint HandCombat = 0x8000003Cu;
|
||||
public const uint SwordCombat = 0x8000003Eu;
|
||||
public const uint BowCombat = 0x8000003Fu;
|
||||
public const uint SwordShieldCombat = 0x80000040u;
|
||||
public const uint CrossbowCombat = 0x80000041u;
|
||||
public const uint TwoHandedSwordCombat = 0x80000046u;
|
||||
public const uint SlingCombat = 0x80000047u;
|
||||
public const uint Magic = 0x80000049u;
|
||||
public const uint AtlatlCombat = 0x8000013Bu;
|
||||
public const uint ThrownShieldCombat = 0x8000013Cu;
|
||||
|
||||
public const uint FallDown = 0x10000050u;
|
||||
public const uint Twitch1 = 0x10000051u;
|
||||
public const uint Twitch2 = 0x10000052u;
|
||||
public const uint Twitch3 = 0x10000053u;
|
||||
public const uint Twitch4 = 0x10000054u;
|
||||
public const uint StaggerBackward = 0x10000055u;
|
||||
public const uint StaggerForward = 0x10000056u;
|
||||
public const uint Sanctuary = 0x10000057u;
|
||||
public const uint ThrustMed = 0x10000058u;
|
||||
public const uint ThrustLow = 0x10000059u;
|
||||
public const uint ThrustHigh = 0x1000005Au;
|
||||
public const uint SlashHigh = 0x1000005Bu;
|
||||
public const uint SlashMed = 0x1000005Cu;
|
||||
public const uint SlashLow = 0x1000005Du;
|
||||
public const uint BackhandHigh = 0x1000005Eu;
|
||||
public const uint BackhandMed = 0x1000005Fu;
|
||||
public const uint BackhandLow = 0x10000060u;
|
||||
public const uint Shoot = 0x10000061u;
|
||||
public const uint AttackHigh1 = 0x10000062u;
|
||||
public const uint AttackMed1 = 0x10000063u;
|
||||
public const uint AttackLow1 = 0x10000064u;
|
||||
public const uint AttackHigh2 = 0x10000065u;
|
||||
public const uint AttackMed2 = 0x10000066u;
|
||||
public const uint AttackLow2 = 0x10000067u;
|
||||
public const uint AttackHigh3 = 0x10000068u;
|
||||
public const uint AttackMed3 = 0x10000069u;
|
||||
public const uint AttackLow3 = 0x1000006Au;
|
||||
|
||||
public const uint MissileAttack1 = 0x100000D0u;
|
||||
public const uint MissileAttack2 = 0x100000D1u;
|
||||
public const uint MissileAttack3 = 0x100000D2u;
|
||||
public const uint CastSpell = 0x400000D3u;
|
||||
public const uint Reload = 0x100000D4u;
|
||||
public const uint UseMagicStaff = 0x400000E0u;
|
||||
public const uint UseMagicWand = 0x400000E1u;
|
||||
|
||||
public const uint DoubleSlashLow = 0x1000011Fu;
|
||||
public const uint DoubleSlashMed = 0x10000120u;
|
||||
public const uint DoubleSlashHigh = 0x10000121u;
|
||||
public const uint TripleSlashLow = 0x10000122u;
|
||||
public const uint TripleSlashMed = 0x10000123u;
|
||||
public const uint TripleSlashHigh = 0x10000124u;
|
||||
public const uint DoubleThrustLow = 0x10000125u;
|
||||
public const uint DoubleThrustMed = 0x10000126u;
|
||||
public const uint DoubleThrustHigh = 0x10000127u;
|
||||
public const uint TripleThrustLow = 0x10000128u;
|
||||
public const uint TripleThrustMed = 0x10000129u;
|
||||
public const uint TripleThrustHigh = 0x1000012Au;
|
||||
|
||||
public const uint OffhandSlashHigh = 0x10000173u;
|
||||
public const uint OffhandSlashMed = 0x10000174u;
|
||||
public const uint OffhandSlashLow = 0x10000175u;
|
||||
public const uint OffhandThrustHigh = 0x10000176u;
|
||||
public const uint OffhandThrustMed = 0x10000177u;
|
||||
public const uint OffhandThrustLow = 0x10000178u;
|
||||
public const uint OffhandDoubleSlashLow = 0x10000179u;
|
||||
public const uint OffhandDoubleSlashMed = 0x1000017Au;
|
||||
public const uint OffhandDoubleSlashHigh = 0x1000017Bu;
|
||||
public const uint OffhandTripleSlashLow = 0x1000017Cu;
|
||||
public const uint OffhandTripleSlashMed = 0x1000017Du;
|
||||
public const uint OffhandTripleSlashHigh = 0x1000017Eu;
|
||||
public const uint OffhandDoubleThrustLow = 0x1000017Fu;
|
||||
public const uint OffhandDoubleThrustMed = 0x10000180u;
|
||||
public const uint OffhandDoubleThrustHigh = 0x10000181u;
|
||||
public const uint OffhandTripleThrustLow = 0x10000182u;
|
||||
public const uint OffhandTripleThrustMed = 0x10000183u;
|
||||
public const uint OffhandTripleThrustHigh = 0x10000184u;
|
||||
public const uint OffhandKick = 0x10000185u;
|
||||
public const uint AttackHigh4 = 0x10000186u;
|
||||
public const uint AttackMed4 = 0x10000187u;
|
||||
public const uint AttackLow4 = 0x10000188u;
|
||||
public const uint AttackHigh5 = 0x10000189u;
|
||||
public const uint AttackMed5 = 0x1000018Au;
|
||||
public const uint AttackLow5 = 0x1000018Bu;
|
||||
public const uint AttackHigh6 = 0x1000018Cu;
|
||||
public const uint AttackMed6 = 0x1000018Du;
|
||||
public const uint AttackLow6 = 0x1000018Eu;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue