Creature struct (creature_pool / DAT_0049bf38)¶
This document tracks the main creature pool used by crimsonland.exe.
Pool facts:
- Entry size:
0x98bytes. - Pool size:
0x180entries. - Base address:
creature_pool(DAT_0049bf38).
Key helpers:
creature_alloc_slot(FUN_00428140) finds a free slot and seeds defaults.creature_spawn(FUN_00428240) spawns a creature and writes position/type/heading.creature_update_all(FUN_00426220) is the primary update loop (movement, targeting, AI, attacks).creatures_none_active(FUN_00428210) scans the pool and returns nonzero when empty.
Field map (medium confidence):
| Offset | Field | Symbol | Evidence |
|---|---|---|---|
0x00 |
active (byte) | creature_pool |
checked for zero in most loops; set to 1 on spawn, cleared on death. |
0x04 |
phase seed | creature_phase_seed |
randomized on spawn; used to offset orbit/aim timing. |
0x08 |
state flag | creature_state_flag |
set to 1 in spawners and during AI transitions; exact meaning TBD. |
0x09 |
collision flag | creature_collision_flag |
set when two creatures are within 45 units; drives periodic contact damage ticks. |
0x0c |
collision timer | creature_collision_timer |
decremented when collision flag is set; when it wraps, applies damage. |
0x10 |
hitbox size | creature_hitbox_size |
set to 16.0 on spawn; used as a sentinel in contact-damage logic. |
0x14 |
pos_x | creature_pos_x |
written by FUN_00428240; used in distance tests/targeting. |
0x18 |
pos_y | creature_pos_y |
written by FUN_00428240; used in distance tests/targeting. |
0x1c |
vel_x | creature_vel_x |
computed from heading/speed and passed to FUN_0041e400. |
0x20 |
vel_y | creature_vel_y |
computed from heading/speed and passed to FUN_0041e400. |
0x24 |
health | creature_health |
used as alive check (> 0) and perk kill logic. |
0x28 |
max_health | creature_max_health |
set from health on spawn; clones use max_health * 0.25. |
0x2c |
heading (radians) | creature_heading |
set on spawn; eased toward desired heading each frame. |
0x30 |
desired heading | creature_target_heading |
computed from target position each frame. |
0x34 |
size/radius | creature_size |
used in collision tests (FUN_00420600) and speed scaling. |
0x38 |
hit flash timer | creature_hit_flash_timer |
decremented each frame; set by FUN_004207c0 on damage. |
0x3c |
tint_r | creature_tint_r |
set from spawn color parameter; modified by difficulty scaling. |
0x40 |
tint_g | creature_tint_g |
set from spawn color parameter; modified by difficulty scaling. |
0x44 |
tint_b | creature_tint_b |
set from spawn color parameter; modified by difficulty scaling. |
0x48 |
tint_a | creature_tint_a |
set from spawn color parameter (defaults to 1.0). |
0x4c |
force-target flag | creature_force_target |
set when target is too near/far; snaps target position to player. |
0x50 |
target_x | creature_target_x |
derived from player/formation/linked enemy. |
0x54 |
target_y | creature_target_y |
derived from player/formation/linked enemy. |
0x58 |
contact damage | creature_contact_damage |
Passed to FUN_00425e50 on player contact; seeded as size * 0.0952381 in FUN_00407611. |
0x5c |
move speed | creature_move_speed |
Per-type speed scalar used to compute velocity; seeded to 0.9.. range in FUN_00407611. |
0x60 |
attack cooldown | creature_attack_cooldown |
Decremented each frame; gates projectile spawns. |
0x64 |
reward value | creature_reward_value |
Seeded from health/contact/speed (health * 0.4 + contact * 0.8 + speed * 5 + rand(10..19)), then scaled by 0.8 in the spawner. |
0x6c |
type id | creature_type_id |
written from spawn param; indexes behavior tables. |
0x70 |
target player index | creature_target_player |
toggled based on distance; indexes player arrays. |
0x78 |
link index / state timer | creature_link_index |
used as linked creature index in AI modes; also used as a timer when the 0x80 flag is set. |
0x7c |
target offset x | creature_target_offset_x |
used when AI mode links to another creature. |
0x80 |
target offset y | creature_target_offset_y |
used when AI mode links to another creature. |
0x84 |
orbit angle | creature_orbit_angle |
combined with heading for orbiting AI modes. |
0x88 |
orbit radius/timer | creature_orbit_radius |
used by orbiting and tethered AI modes. |
0x8c |
flags | creature_flags |
bit tests (0x4/0x8/0x10/0x40/0x80/0x100/0x400) gate behaviors. |
0x90 |
AI mode | creature_ai_mode |
selects movement pattern (cases 0/⅓/⅘/6/⅞). |
0x94 |
anim phase | creature_anim_phase |
accumulates to drive sprite timing; wraps at 31 or 15 depending on flags. |
Global counters:
creature_spawned_countincrements on eachcreature_alloc_slotcall (total spawns).creature_kill_countincrements on creature death paths (used by the HUD progress ratio).creature_active_countis recomputed eachcreature_update_allpass.creature_update_tickis a global tick counter used to throttle some target updates.plaguebearer_infection_countincrements on Plaguebearer contagion kills and caps spread.
Spawn slots (used by creature_update_all when creature_link_index selects a slot):
creature_spawn_slot_owner— pointer to the owning creature (used for collision and cleared on owner death).creature_spawn_slot_count— current spawn count.creature_spawn_slot_limit— max spawns before the slot stops.creature_spawn_slot_interval— seconds between spawns.creature_spawn_slot_timer— countdown timer to the next spawn.creature_spawn_slot_template— spawn template id passed tocreature_spawn_template.
Survival reward tracking (globals):
survival_recent_death_pos_x/survival_recent_death_pos_y— up to 3 recent creature death positions (recorded increature_handle_death).survival_recent_death_count— increments with deaths (caps at 6) and gates the survival weapon reward check insurvival_update.survival_reward_handout_enabled— one-time survival handout gate (cleared after the handout or after 3 death samples).survival_reward_fire_seen— set when the player fires; blocks the survival reward checks insurvival_update.survival_reward_damage_seen— set on player damage; blocks the survival reward checks insurvival_update.
AI mode behaviors (DAT_0049bfc8 / offset 0x90)¶
The AI mode selects how the target position (target_x/target_y) is computed
inside creature_update_all. These notes are medium-confidence.
| Mode | Behavior (inferred) | Evidence |
|---|---|---|
0 |
Orbit toward player; if far (>800) target = player, else target = player + cos/sin(phase) * dist * 0.85. |
Uses player index + per-creature phase (DAT_0049bf3c) and distance to pick a target offset. |
1 |
Tight orbit toward player; same as mode 0 but scale 0.55. |
Same logic with scale 0.55. |
2 |
Force direct chase; target is forced to player when mode == 2. | mode == 2 triggers target override to player. |
3 |
Linked follower; target = linked creature position + per-creature offset (DAT_0049bfb4/b8). |
Uses DAT_0049bfb0 as link index; clears mode if target dead. |
4 |
Linked guard; if link alive, target around player like mode 0; if link dead, mode clears and a damage helper is called. | Clears mode and calls FUN_004207c0 when link is dead. |
5 |
Tethered follower; target = link + offset; movement scale shrinks when very close (dist * 0.015625). |
Computes local_70 from distance to target and clamps in 0..1 range. |
6 |
Orbit around linked creature; target = link + cos/sin(angle + heading) * radius. |
Uses DAT_0049bfc0 (radius) and DAT_0049bfbc (angle). |
7 |
Hold/linger; target = current position while a timer runs. | Uses DAT_0049bfc0 as countdown; clears mode when expired. |
8 |
Wide orbit toward player; same as mode 0 but scale 0.9. |
Same logic with scale 0.9. |
Notes:
- Linked modes use
DAT_0049bfb0as the linked creature index andDAT_0049bfb4/b8as the per-creature offset. - Mode
7interacts with the0x80flag and theDAT_0049bfb0link index; if either guard fails, the mode resets to0.
Related notes:
- See Detangling notes for helper naming and other pool context.
- The pool is updated in
creature_update_all; use that routine for new field discoveries. - On death,
creature_update_allqueues a rotated sprite viafx_queue_add_rotatedusing the creature tint and size. Theeffect_idis usually the creaturetype_id, but short-strip creatures (flags & 0x4without0x40) forceeffect_id = 7(likely a generic corpse sprite). - Animation phase (
0x94) is incremented by a per-type rate stored at&DAT_0048275c + type_id * 0x44and wraps at 31 for the primary strip or 15 for the short ping‑pong strip. The renderer then selects a frame index for the 8×8 atlas (seeFUN_00418b60). creature_update_allscales the animation step by movement speed, size, and a local scale factor (tether/orbit cases), usingrate * speed * dt * (30/size)multiplied by 25 (long strip) or 22 (short strip) before wrapping.- Flags
0x4and0x40influence sprite selection inFUN_00418b60:0x4selects the short 8‑frame ping‑pong strip and0x40forces the long strip even when0x4is set. FUN_00418b60computes the short strip frame asframe = base + 0x10 + ping_pong(int(phase) & 0xf), whereping_pongmirrors indices> 7to0xf - idx. The long strip usesframe = base + int(phase)(mirrored to0x1f - framewhentype_flags & 1andframe > 0x0f), with negative phases falling back tobase + 0x0f.
Creature flags (partial)¶
The creature_flags bitfield is consulted in creature_update_all and related helpers:
- 0x1 — periodic self‑damage tick (
creature_apply_damagewith magnitudedt * 60). - 0x2 — stronger periodic self‑damage tick (
creature_apply_damagewith magnitudedt * 180). - 0x4 — short ping‑pong animation strip (see render notes above).
- 0x10 — ranged attack: when
attack_cooldown <= 0and target distance > 64, spawns projectile type9and playssfx_shock_fire(DAT_004c3f9c). - 0x40 — force long animation strip even if
0x4is set. - 0x80 — uses
creature_link_indexas a timer that toggles AI mode7with randomized positive/negative durations. - 0x100 — ranged attack variant: spawns projectile using the
creature_orbit_radiusfield as the projectile type id and playssfx_plasmaminigun_fire(DAT_004c3fa0).
Creature type table (creature_type_texture / DAT_00482728)¶
Stride: 0x44 bytes (0x11 floats). Indexed by type_id.
Field map (partial):
| Offset | Field | Evidence |
|---|---|---|
| 0x00 | sprite texture handle | creature_type_texture; bound in creature_render_type via grim_bind_texture. |
| 0x04 | sfx bank A [0] | creature_type_sfx_a0; FUN_004207c0 chooses uVar3 = rand() & 3 and calls FUN_0043d260 on &creature_type_sfx_a0 + (uVar3 + type_id * 0x11) * 4. |
| 0x08 | sfx bank A [1] | creature_type_sfx_a1; same selection as above. |
| 0x0c | sfx bank A [2] | creature_type_sfx_a2; same selection as above; also used by chain-kill paths. |
| 0x10 | sfx bank A [3] | creature_type_sfx_a3; same selection as above (the 0..3 range proves this slot is live). |
| 0x14 | sfx bank B [0] | creature_type_sfx_b0; contact-damage removal path picks uVar7 = rand() & 1 and calls FUN_0043d260 on &creature_type_sfx_b0 + (uVar7 + type_id * 0x11) * 4. |
| 0x18 | sfx bank B [1] | creature_type_sfx_b1; 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 the decompiled output. |
| 0x34 | anim rate | creature_type_anim_rate; multiplies animation step in creature_update_all (drives anim phase). |
| 0x38 | atlas base frame | creature_type_base_frame; start frame for the long strip (used with +0x10 or +0x20 offsets in creature_render_type). |
| 0x3c | corpse frame | creature_type_corpse_frame; used by fx_queue_render to select the bodyset frame for corpse sprites. |
| 0x40 | anim mirror flag | creature_type_anim_flags; when bit 1 is 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..0x30were found in the decompiled output. Only offset0x20is initialized (to1.0), so the remaining fields appear unused or reserved in this build.
Spawn template ids (creature_spawn_template)¶
creature_spawn_template uses template_id (aka param_1) as a spawn template id. It assigns the
creature type id (&creature_type_id, formerly DAT_0049bfa4) and optional flags
(&creature_flags, formerly DAT_0049bfc4). The table below lists the direct
assignments found inside the helper.
Generated by uv run python scripts/gen_spawn_templates.py.
| Spawn id (template_id) | Type id | Creature | Flags (creature_flags) | Anim note |
|---|---|---|---|---|
0x0 |
0 |
zombie |
0x44 |
long strip (0x40 overrides 0x4) |
0x1 |
4 |
spider_sp2 |
0x8 |
|
0x3 |
3 |
spider_sp1 |
`` | |
0x4 |
1 |
lizard |
`` | |
0x5 |
4 |
spider_sp2 |
`` | |
0x6 |
2 |
alien |
`` | |
0x7 |
2 |
alien |
0x4 |
short strip (ping-pong) |
0x8 |
1 |
lizard |
0x10 |
|
0x9 |
2 |
alien |
0x4 |
short strip (ping-pong) |
0xa |
2 |
alien |
0x4 |
short strip (ping-pong) |
0xb |
2 |
alien |
0x4 |
short strip (ping-pong) |
0xc |
2 |
alien |
0x4 |
short strip (ping-pong) |
0xd |
2 |
alien |
0x4 |
short strip (ping-pong) |
0xe |
2 |
alien |
0x4 |
short strip (ping-pong) |
0xf |
2 |
alien |
0x4 |
short strip (ping-pong) |
0x10 |
2 |
alien |
0x4 |
short strip (ping-pong) |
0x11 |
1 |
lizard |
`` | |
0x12 |
2 |
alien |
`` | |
0x13 |
2 |
alien |
0x4 |
short strip (ping-pong) |
0x14 |
2 |
alien |
`` | |
0x15 |
2 |
alien |
`` | |
0x16 |
1 |
lizard |
`` | |
0x17 |
3 |
spider_sp1 |
`` | |
0x18 |
2 |
alien |
`` | |
0x19 |
2 |
alien |
`` | |
0x1a |
2 |
alien |
`` | |
0x1b |
3 |
spider_sp1 |
`` | |
0x1c |
3 |
spider_sp1 |
0x10 |
|
0x1d |
2 |
alien |
`` | |
0x1e |
2 |
alien |
`` | |
0x1f |
2 |
alien |
`` | |
0x20 |
2 |
alien |
`` | |
0x21 |
2 |
alien |
`` | |
0x22 |
2 |
alien |
`` | |
0x23 |
2 |
alien |
`` | |
0x24 |
2 |
alien |
`` | |
0x25 |
2 |
alien |
`` | |
0x26 |
2 |
alien |
`` | |
0x27 |
2 |
alien |
0x400 |
|
0x28 |
3 |
spider_sp1 |
0x10 |
|
0x29 |
2 |
alien |
`` | |
0x2a |
2 |
alien |
`` | |
0x2b |
2 |
alien |
`` | |
0x2c |
2 |
alien |
`` | |
0x2d |
2 |
alien |
`` | |
0x2e |
1 |
lizard |
`` | |
0x2f |
1 |
lizard |
`` | |
0x30 |
1 |
lizard |
`` | |
0x31 |
1 |
lizard |
`` | |
0x32 |
2 |
alien |
0x10 |
|
0x33 |
3 |
spider_sp1 |
`` | |
0x34 |
3 |
spider_sp1 |
`` | |
0x35 |
4 |
spider_sp2 |
`` | |
0x36 |
2 |
alien |
`` | |
0x37 |
4 |
spider_sp2 |
0x100 |
|
0x38 |
3 |
spider_sp1 |
0x80 |
|
0x39 |
3 |
spider_sp1 |
0x80 |
|
0x3a |
3 |
spider_sp1 |
0x10 |
|
0x3b |
3 |
spider_sp1 |
`` | |
0x3c |
3 |
spider_sp1 |
0x100 |
|
0x3d |
3 |
spider_sp1 |
`` | |
0x3e |
3 |
spider_sp1 |
`` | |
0x40 |
3 |
spider_sp1 |
`` | |
0x41 |
0 |
zombie |
`` | |
0x42 |
0 |
zombie |
`` | |
0x43 |
0 |
zombie |
`` |
Notes:
- The table is mirrored into
src/crimson/spawn_templates.pyfor Python usage. - Flags
0x4and0x40are the only bits with confirmed animation effects. - Flag
0x8triggers the split‑on‑death behavior (seeFUN_0041e910). - Flag
0x400callsFUN_0041f5b0on death (spawns a bonus entry using two 16‑bit values from&DAT_0049bfb0).
Spawn id sources (call sites)¶
template_id is supplied by a mix of scripted spawners and data tables:
FUN_00402ed0,FUN_00402fe0,FUN_004030f0,FUN_00403250: mode setup helpers called fromFUN_00403390(hard‑coded spawn ids like0x34,0x35,0x38,0x41,0x24,0x25).survival_update(FUN_00407cd0): milestone spawns using0x12,0x2b,0x2c,0x35,0x38,0x3a,0x3c, and1.- Tutorial timeline (
FUN_00408990): scripted spawns using0x24,0x26,0x27,0x28,0x40. - Quest/timeline spawner (
quest_spawn_timeline_update,FUN_00434250): pulls spawn ids from the table atDAT_004857a8(pfVar4[3]) with counts inpfVar4[5]. - AI subspawns (
creature_update_all): periodic spawns using&DAT_00484fe4 + iVar6 * 0x18, which is seeded for some template ids insideFUN_00430af0.
Quest spawn table (DAT_004857a8)¶
Quests populate a fixed table at DAT_004857a8 (entry size 0x18, count in
DAT_00482b08). quest_spawn_timeline_update (FUN_00434250) walks the table and
spawns entries whose trigger time has elapsed.
Entry layout (dwords):
| Offset | Field | Notes |
|---|---|---|
| 0x00 | x | base spawn X; if offscreen, the group spreads along Y instead of X. |
| 0x04 | y | base spawn Y. |
| 0x08 | heading | passed as heading to creature_spawn_template. |
| 0x0c | spawn id | cast to int and passed as template_id to creature_spawn_template. |
| 0x10 | trigger time | compared against DAT_00486fd0 (quest clock). |
| 0x14 | count | number of spawns in the group; decremented to 0 after firing. |
Notes:
quest_start_selected(FUN_0043a790) chooses a quest builder from the table atDAT_00484730. The function pointer lives at&DAT_0048474c; when null, it falls back toquest_build_fallback(FUN_004343e0) (two entries with spawn id0x40, counts 10/0x14, trigger times 500/5000).quest_build_zombie_time(0x00437d70),quest_build_lizard_raze(0x00438840), andquest_build_surrounded_by_reptiles(0x00438940) are examples of quest builders that write multipleDAT_004857a8entries with varying spawn ids and timings.