Skip to content

Creature animations

This page tracks how creatures advance animation phase and select atlas frames.

See also: Creature pool struct, Atlas notes.

Animation phase (creature_anim_phase / offset 0x94)

  • creature_anim_phase (float) is advanced in creature_update_all (FUN_00426220) using the per-type rate stored in the type table (DAT_00482728).

  • The phase wraps at 31 for the long strip or 15 for the short ping‑pong strip.

  • Evidence: analysis/frida/creature_anim_trace_summary.json (captured via scripts/frida/creature_anim_trace.js).

Strip selection and frame mapping

The renderer (creature_render_type, FUN_00418b60) selects an atlas frame based on:

  • the type table base_frame
  • the per-creature flags (creature_flags)
  • the integer part of anim_phase
  • the creature heading (rotation)

Known behaviors (medium confidence):

  • Flag 0x4 selects the short 8-frame ping‑pong strip.
  • Flag 0x40 forces the long strip even when 0x4 is set.
  • For the short strip: frame = base + 0x10 + ping_pong(int(phase) & 0xf), where ping‑pong folds 0..15 into 0..7..0.

  • For the long strip (alive, hitbox_size >= 16.0): frame = __ftol(anim_phase + 0.5).

  • If the type mirror flag is set and frame > 0x0f, the index is mirrored: frame = 0x1f - frame.
  • If per‑creature flags include 0x10, the frame offset shifts by +0x20 (alt strip for some spawns).
  • For the long strip during death staging (0 <= hitbox_size < 16.0): frame = __ftol((base_frame + 0x0f) - hitbox_size)
  • This effectively ramps through the 16 death frames as hitbox_size decays from ~16 to 0.
  • For long-strip corpses (hitbox_size < 0.0): frame = base_frame + 0x0f (static corpse frame).
  • Rotation: grim_set_rotation(creature_heading - pi/2); creatures visually face along their movement heading.

Shadow/outline pass (fx_detail_0)

When crimson.cfg fx_detail_0 is enabled (config_fx_detail_flag0) and the Monster Vision perk is not active, creature_render_type runs an extra pre-pass that darkens behind each creature sprite:

  • alpha is derived from creature tint alpha (tint_a * 0.4 in the decompile)
  • the sprite is slightly upscaled (~size * 1.07) and offset down-right before the main draw
  • for long-strip corpses (hitbox_size < 0.0), the shadow alpha decays much faster: tint_a * 0.4 + hitbox_size * 0.5 (clamped to >= 0).
  • Evidence: analysis/frida/creature_render_trace_summary.json (captured via scripts/frida/creature_render_trace.js).

The creature_flags bitfield is consulted in creature_update_all and related helpers:

  • 0x4 — short ping‑pong animation strip.
  • 0x10 — ranged attack variant; also selects the +0x20 strip offset in rendering.
  • 0x40 — force long animation strip even if 0x4 is set.

Creature type table (creature_type_texture / DAT_00482728)

Stride: 0x44 bytes (0x11 floats). Indexed by type_id.

data_map now labels the entry bases:

  • creature_type_table[0] (zombie) at 0x00482728
  • creature_type_lizard at 0x0048276c
  • creature_type_alien at 0x004827b0
  • creature_type_spider_sp1 at 0x004827f4
  • creature_type_spider_sp2 at 0x00482838
  • creature_type_trooper at 0x0048287c

Field map (partial):

Offset Field Evidence
0x00 sprite texture handle bound in creature_render_type via grim_bind_texture.
0x04 sfx bank A [0] creature_apply_damage chooses rand() & 3 and plays a per-type sound.
0x08 sfx bank A [1] same selection as above.
0x0c sfx bank A [2] same selection as above; also used by chain-kill paths.
0x10 sfx bank A [3] same selection as above (0..3 range proves this slot is live).
0x14 sfx bank B [0] contact-damage removal path picks rand() & 1 and plays a per-type sound.
0x18 sfx bank B [1] same selection as above (second slot in the 0..1 range).
0x20 unknown (const 1.0) set to 1.0 for every type in the init routine; no reads found in decompiled output.
0x34 anim rate multiplies animation step in creature_update_all.
0x38 atlas base frame start frame for the long strip (used with +0x10 / +0x20 offsets in creature_render_type).
0x3c corpse frame used by corpse sprite paths.
0x40 anim mirror flag when set, the long strip mirrors frames > 0x0f in creature_render_type.

Known initial entries (from the reset/init routine that loads creature textures):

type_id texture anim rate base frame corpse frame flags
0 s_zombie_0047375c 1.2 0x20 0 0
1 s_lizard_00473754 1.6 0x10 3 1
2 s_alien_00473734 1.35 0x20 4 0
3 s_spider_sp1_00473748 1.5 0x10 1 1
4 s_spider_sp2_0047373c 1.5 0x10 2 1
5 s_trooper_0047372c not set in init not set in init 7 not set in init

Notes:

  • No references to offsets 0x1c..0x30 were found in the decompiled output. Only offset 0x20 is initialized (to 1.0), so the remaining fields appear unused or reserved in this build.