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
68
docs/research/2026-04-28-combat-animation-planner.md
Normal file
68
docs/research/2026-04-28-combat-animation-planner.md
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# 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
|
||||
|
||||
```text
|
||||
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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue