acdream/docs/research/2026-04-28-combat-animation-planner.md

2.4 KiB

Combat Animation Planner Pseudocode

Sources

  • Retail ClientCombatSystem::ExecuteAttack (0x0056BB70): sends targeted melee or missile attack intent and records pending response state. It does not choose a local swing animation.
  • Retail ClientCombatSystem::HandleCommenceAttackEvent (0x0056AD20): starts/updates power-bar and busy UI state. The event carries no MotionCommand.
  • Retail command-name table around 0x00803F34: combat commands include Twitch1..4, StaggerBackward, StaggerForward, ThrustMed, SlashHigh, Shoot, AttackHigh1, and later offhand/multistrike commands.
  • ACE Player_Melee.DoSwingMotion and GetSwingAnimation: server chooses a swing from CombatManeuverTable.GetMotion(...) and broadcasts the selected MotionCommand with UpdateMotion.
  • ACE CombatManeuverTable.GetMotion: indexes (stance, attack height, attack type) to one or more motion commands; power level chooses between multiple entries.

Retail Rule

Combat GameEvents are state/UI notifications. Motion state is the animation authority.

Pseudocode

PlanForEvent(event):
    return None

PlanFromWireCommand(wireCommand, speed):
    fullCommand = MotionCommandResolver.ReconstructFullCommand(wireCommand)
    return PlanFromFullCommand(fullCommand, speed)

PlanFromFullCommand(fullCommand, speed):
    kind = ClassifyMotionCommand(fullCommand)
    if kind is None:
        return None

    routeKind = AnimationCommandRouter.Classify(fullCommand)
    return Plan(kind, routeKind, fullCommand, speed)

ClassifyMotionCommand(fullCommand):
    if command is a combat stance:
        return CombatStance
    if command is a thrust/slash/backhand/offhand/multistrike motion:
        return MeleeSwing
    if command is Shoot, MissileAttack*, or Reload:
        return MissileAttack
    if command is AttackHigh/Med/Low 1..6:
        return CreatureAttack
    if command is CastSpell, UseMagicStaff, or UseMagicWand:
        return SpellCast
    if command is Twitch*, Stagger*, FallDown, or Sanctuary:
        return HitReaction
    if command is Dead:
        return Death
    return None

Implementation Note

The next table-driven layer can use DatReaderWriter.DBObjs.CombatTable and DatReaderWriter.Types.CombatManeuver directly. acdream already references Chorizite.DatReaderWriter; the missing live-state piece is a named CombatTable data-id on player/creature state.