feat(anim): Phase L.1c select combat maneuvers

This commit is contained in:
Erik 2026-04-28 11:44:17 +02:00
parent 831392a7b2
commit 646246ba84
6 changed files with 385 additions and 33 deletions

View file

@ -60,6 +60,51 @@ ClassifyMotionCommand(fullCommand):
return None
```
## Maneuver Selection Pseudocode
```text
SelectMotion(table, stance, attackHeight, attackType, powerLevel,
isThrustSlashWeapon):
candidates = []
for maneuver in table.CombatManeuvers:
if maneuver.Style == stance
and maneuver.AttackHeight == attackHeight
and maneuver.AttackType == attackType:
candidates.append(maneuver.Motion)
if candidates is empty:
return None
subdivision = isThrustSlashWeapon ? 0.66 : 0.33
if candidates.Count > 1 and powerLevel < subdivision:
motion = candidates[1]
else:
motion = candidates[0]
return motion
```
This matches ACE `CombatManeuverTable.GetMotion` plus
`Player_Melee.GetSwingAnimation`. The `prevMotion` parameter is present in
ACE's table API but the current ACE implementation does not use it; the
power threshold chooses between multiple entries.
## Named Retail Motion IDs
`DatReaderWriter.Enums.MotionCommand` is shifted by three entries starting
at `AllegianceHometownRecall`. Named retail command tables are:
- `command_ids` table lines 1017626-1017658:
`0x016E..0x0197 -> 0x1000016E..0x10000197`.
- command-name table lines 1068272-1068313:
`OffhandSlashHigh = 0x10000170`, `AttackLow6 = 0x1000018B`,
`PunchFastLow = 0x1000018E`, etc.
`MotionCommandResolver` therefore overrides that range after building the
DRW reflection table, otherwise offhand and late unarmed attack actions
resolve as UI/mappable commands and never reach `PlayAction`.
## Implementation Note
The next table-driven layer can use `DatReaderWriter.DBObjs.CombatTable`