Custom Creature: reference tables
Lookup tables for creature work: animation clip flags, action types, the .tpac container format,
and known-good skeleton fingerprints.
Part of the Custom Creatures guide.
Version
Read out of Bannerlord v1.4.8. Flag values are from the engine enum.
Animation flags
How the word is built
AnimFlags is a 64-bit word with two different things packed into it:
- The low byte (
0xFF) is a priority integer, not a set of bits. - Everything above it is independent behaviour flags.
Reading the low byte as bits is a real mistake with real consequences, because ORing a stray value into it changes which clip wins an arbitration.
You cannot toggle these from a Harmony patch
Only two flags are ever bit-tested in managed C#: anf_synch_with_ladder_movement and
anf_displace_position. Every other flag is consumed entirely inside the native engine DLL.
You can OR additional flags in through SetActionChannel's additionalFlags parameter, but you
cannot inspect or clear a clip's authored flags from managed code. Set them in the Modding Kit.
Priority levels (the low byte)
Higher wins. A request whose priority is greater than or equal to the current action takes the body.
| Level | Value | Level | Value | |
|---|---|---|---|---|
continue (locomotion, idle) |
0x1 |
rear |
0x4A |
|
jump / ride / crouch |
0x2 |
upperbody_while_kick |
0x4B |
|
attack |
0xA |
striked (hit reaction) |
0x50 |
|
cancel |
0xC |
fall_from_horse / jump_loop |
0x51 |
|
defend |
0xE |
jump_end |
0x52 |
|
parry / throw / blocked / parried |
0xF |
die |
0x5F |
|
kick |
0x21 |
mask (the extraction mask) |
0xFF |
|
reload |
0x3C |
|||
mount |
0x40 |
|||
equip |
0x46 |
For a creature: locomotion at continue, attacks at attack, hurt reactions at striked, death at
die.
Movement and root motion
The category that decides whether your creature slides.
| Flag | Bit | What it does |
|---|---|---|
anf_synch_with_movement |
0x2000000 |
Time-warps a locomotion clip to the agent's real ground speed. The main anti-skate flag. Required on walk, run and turn. |
anf_displace_position |
0x400000000000 |
Root motion on: the clip's baked root travel moves the agent. One-shot lunges only, never on a cyclic walk or run. |
anf_use_last_step_point_as_data |
0x800 |
Marks the stride-reference clip the gait builder samples for stride length. |
anf_affected_by_movement |
0x40000000000 |
Clip is blended by movement state. Broader than synch. |
anf_lock_movement |
0x1000000 |
Pins the agent in place for the clip's duration. |
anf_enforce_root_rotation |
0x8000000000 |
Facing follows the clip's baked root rotation. Turn clips. |
anf_align_with_ground |
0x100000000000 |
Tilts the body to the terrain normal. |
anf_ignore_slope |
0x200000000000 |
The inverse: keep the authored orientation. |
anf_ignore_scale_on_root_position |
0x1000000000000 |
Apply root displacement without the body-scale multiply. Useful on a scaled creature whose lunge overshoots. |
anf_synch_with_horse |
0x200000 |
Rider clip synced to the mount's gait. Rider clips only. |
Body enforcement and lifecycle
| Flag | Bit | What it does |
|---|---|---|
anf_cyclic |
0x4000000000 |
Loops. Required on idle and all locomotion, or they play once and stop. |
anf_enforce_all |
0x2000000000 |
Overrides the whole skeleton, no blend smear. Death, hard transitions. |
anf_enforce_lowerbody |
0x1000000000 |
Overrides the leg bones only. |
anf_allow_head_movement |
0x10000000000 |
Carves the head out so look-at keeps steering it. |
anf_keep |
0x4000 |
Freeze on the last frame. Do not combine with anf_cyclic. |
anf_restart |
0x8000 |
Re-trigger from frame 0 even if already playing. |
anf_disable_alternative_randomization |
0x80000000 |
Opt this clip out of the random variant pool. |
anf_disable_auto_increment_progress |
0x100000000 |
The engine stops advancing progress. Never on a normal clip; it would freeze. |
anf_animation_layer_flags_mask |
0xFFFF000000000 |
A 16-bit layer-routing field at bits 36 to 51. Do not hand-set. |
anf_animation_layer_flags_bits |
0x24 |
The shift value (36) locating that field. This is metadata, not a flag. Never OR it into a clip: it overlaps the priority byte. |
IK, collision, physics
| Flag | Bit | What it does |
|---|---|---|
anf_disable_foot_ik |
0x20000000000 |
Turns off foot grounding. Do not set on a grounded walk or run. Do set on jump, rear and death. |
anf_disable_hand_ik |
0x40000 |
Hands play as authored. Sensible on creature clips, which have no grip target. |
anf_update_bounding_volume |
0x80000000000 |
Recompute cull and hit bounds from the live pose. Wide-pose clips (rear, lunge, death) so limbs sweeping past the rest bounds are not culled or mis-hit-tested. |
anf_disable_agent_agent_collisions |
0x100 |
Pass through other agents. Useful so a large creature's death does not bulldoze troops. |
anf_ignore_static_body_collisions |
0x400 |
Ignore world geometry, stay solid against agents. |
anf_ignore_all_collisions |
0x200 |
Ignore both. Dangerous; can sink through the floor. |
The vanilla rig grounds only two feet
Foot IK solves for r_foot and l_foot. A creature with more than two legs can only ever have
two of them grounded by the engine. Plan the gait around that rather than expecting eight-legged
terrain adaptation.
Sound and networking
| Flag | Bit | What it does |
|---|---|---|
anf_make_walk_sound |
0x20000 |
Footstep foley in gait cadence. Walk and run clips. |
anf_make_bodyfall_sound |
0x1000 |
The heavy body-impact thud. Death and collapse. |
anf_attach_sound_to_agent |
0x400000000 |
Spawned sound follows the moving agent. |
anf_spawn_particle |
0x800000000 |
Enables baked particle keys. Blender-authored clips have none. |
anf_do_not_keep_track_of_sound |
0x20000000 |
Fire and forget. |
anf_client_prediction |
0x2000 |
Multiplayer prediction on any client. Irrelevant in single player. |
Item-handling flags (anf_stick_item_to_left_hand, anf_use_left_hand_during_attack, the rope-weapon
pair, and the rest) are humanoid-only. Leave them unset on a creature.
Per-clip recipe
Confirmed against shipped clips:
| Clip type | Flags |
|---|---|
| Walk / movement | anf_synch_with_movement + anf_cyclic |
| Attack | anf_lock_movement + anf_enforce_all |
Convention, and worth confirming in the Kit against a shipped creature rather than taking on faith:
| Clip type | Flags |
|---|---|
| Run / canter / gallop | the walk set + anf_enforce_lowerbody + anf_make_walk_sound |
| Turn left / right | anf_enforce_root_rotation + anf_synch_with_movement + anf_cyclic |
| Idle / stand | anf_cyclic + anf_align_with_ground |
| Stand-for-movement-data | anf_use_last_step_point_as_data |
| Death | anf_enforce_all + die priority, no anf_cyclic |
| Rear | anf_enforce_all + rear priority |
Flags are not the same thing as clip usages
None of the above is quad_movement, which is a clip usage and lives in a separate section
of the Kit's clip panel. See
the animation page.
Action types
The engine dispatches on an action's type, so these are not cosmetic. For a creature mount
<c>, in action_types.xml:
| Action | Type |
|---|---|
twelve falls: act_<c>_fall_{right,left,roll,backwards,slow_right,slow_left} and each _continue |
actt_fall |
act_<c>_rear, act_<c>_rear_damaged |
actt_rear |
act_<c>_dash |
actt_dash |
act_<c>_kick |
actt_kick |
act_<c>_quick_stop, act_<c>_quick_stop_when_fast |
actt_mount_quick_stop |
act_<c>_hit_object, act_<c>_hit_object_while_falling |
actt_hit_object |
act_<c>_strike_front, act_<c>_strike_back (heavy) |
actt_mount_strike |
act_<c>_strike_front_while_moving, _back_while_moving (light) |
untyped |
act_<c>_idle_1 |
actt_idle |
act_<c>_jump, the one named by jump_start_action |
actt_dash, never actt_jump |
The engine's own classification constants, which is what makes the reskin trap work the way it does:
| Constant | Value |
|---|---|
ActionCodeType.Kick |
28 |
ActionCodeType.Rear |
47 |
StrikeBegin |
48 |
ActionCodeType.MountStrike |
52 |
StrikeEnd |
52 |
Anything in StrikeBegin .. StrikeEnd is read by Agent.IsInBeingStruckAction as being struck.
The .tpac container format
Useful if you are writing tooling. Reverse-engineered from TpacTool (MIT).
Header, 36 bytes
0..3 magic 'TPAC' (0x43415054)
4..7 version (2 in all 6,107 files measured)
8..23 package guid
24..27 item count
28..35 TOC SIZE <- the engine derives data_start = 36 + toc_size
Offset 28 is the field that eats tooling
A parser that skips those 8 bytes leads to a writer that zeroes them, and a zeroed TOC size makes the engine read the table of contents as vertex data. See the assert.
Measured on 250 shipped tpacs across four modules: header[28:36] equals the sum of the item
TOC lengths in 250 of 250, and the first segment's data offset is always exactly
36 + tail.
Item
type_guid(16) | item_guid(16) | item_version(u32, if container version > 1)
| name(sized string) | metadata_size(i64) | metadata | checksum(i64)
| segment_count(i32) | segment_count x segment_header
| udep_count(i32) | udep_count x 48 bytes
Segment header: offset u64, actual_size u64, storage_size u64, owner_guid 16, type_guid 16,
unknown u64, unknown u32, storage_format u8 where storage format 0 is raw and 1 is LZ4HC.
Segment type GUIDs
| GUID | Type |
|---|---|
c635a3d5-eabb-45dd-883e-aa57e4196113 |
Skeleton |
11d07d37-e720-406b-ab67-c846f96a8771 |
SkeletonDefinitionData |
9b6ac06d-a546-40af-a555-40d301ab4b2f |
SkeletonUserData |
5fce4668-0596-c44b-8db2-1edaa9408411 |
Geometry |
Skeleton payloads
SkeletonDefinitionData: name | bone_count(i32) | bone_count x { name, parent_index(i32, -1 for
root), rest_frame(16 floats) }
SkeletonUserData: bounding box, then usage (horse / human / other), then a body list and
a constraint list. Each Body carries bone_name, body_type (abdomen, none, and so on),
mass, ragdoll and collision positions and radii. Each Constraint carries a type (d6, hinge,
ik), the child and parent bone, a rotation quaternion, a position, and for a d6 six lock states
(locked / limited / free) plus their limits in radians.
A skinned mesh stores bone INDICES, not bone names
Bone names live in the Skeleton item. A mesh that binds to a skeleton in a different tpac has no reason to carry a single bone name, and correctly does not.
So scanning a mesh tpac for bone names is not a skinning test: it is a test for "does this file contain a Skeleton item", and every creature sharing an existing skeleton fails it. Test the FBX instead, before it reaches the Kit:
Known-good skeleton fingerprints
For sanity-checking a compile. A healthy creature skeleton has a real usage, typed collision
bodies, and roughly one ragdoll constraint per bone. Zero constraints with every body typed none
means the physics data was dropped, which an FBX re-import does silently.
| Skeleton | Bones | Usage | Ragdoll constraints |
|---|---|---|---|
human_skeleton |
28 | human |
|
horse_skeleton |
32 | horse |
|
skeleton_warg |
49 | horse |
48 |
elephant_skeleton |
60 | horse |
59 |
chariot_skeleton |
60 | ||
spider_skeleton |
62 | other |
Healthy creatures in this sample carry between 48 and 61 constraints.
human_skeleton is not in skeletons.tpac with the others: it lives in
Modules/Native/EmAssetPackages/human/human.tpac.
Sources and credits
Flag values and engine constants are read from the shipped assemblies and asset packages of Bannerlord v1.4.8. The container format derives from TpacTool by szszss, MIT licensed.
Measurements came out of building creatures for TAOM (Tales From the Age of Men), working with assets by Artem (ADOD_Beasts) and Byak0 (Alliance, Alliance.Wargs).