Detangling notes¶
Status: In progress
This page tracks high-value functions to name and the evidence gathered so far. Use the hotspot script to refresh the lists when the decompile is regenerated.
Hotspot script¶
Name/data map workflow¶
We keep authoritative function renames/signatures in analysis/ghidra/maps/name_map.json
and data labels in analysis/ghidra/maps/data_map.json, applying both during headless
analysis:
You can also set CRIMSON_NAME_MAP / CRIMSON_DATA_MAP to point at custom maps.
High-call functions (current)¶
crimsonland.exe¶
crimsonland.exe_functions.json
3 2 0046a39e FUN_0046a39e undefined FUN_0046a39e(char * param_1, int param_2, int param_3)
3 1 00461981 FUN_00461981 undefined FUN_00461981(undefined4 param_1, undefined4 param_2, int param_3, undefined * param_4)
3 1 0046ad79 FUN_0046ad79 undefined FUN_0046ad79(undefined4 * param_1)
3 1 0046d5c7 FUN_0046d5c7 undefined FUN_0046d5c7(void)
3 0 00420040 FUN_00420040 int FUN_00420040(float * param_1, int param_2, float param_3)
3 0 0045eac0 FUN_0045eac0 undefined8 * FUN_0045eac0(undefined8 * param_1, undefined8 * param_2, undefined8 * param_3)
3 0 0045eb4b FUN_0045eb4b undefined8 * FUN_0045eb4b(undefined8 * param_1, undefined8 * param_2, undefined8 * param_3)
3 0 004601c0 FUN_004601c0 ulonglong FUN_004601c0(void)
3 0 004608c0 FUN_004608c0 undefined FUN_004608c0(void)
3 0 004654a5 FUN_004654a5 undefined FUN_004654a5(int param_1)
3 0 00466c7b FUN_00466c7b uint FUN_00466c7b(int param_1)
3 0 004679d6 FUN_004679d6 int FUN_004679d6(undefined * param_1, undefined4 * param_2, uint * param_3)
grim.dll¶
grim.dll_functions.json
30 0 100170d6 FUN_100170d6 undefined FUN_100170d6(undefined4 param_1)
20 0 1004b5b0 FUN_1004b5b0 undefined FUN_1004b5b0(void)
10 0 10001160 FUN_10001160 undefined FUN_10001160(void)
8 2 1001029e FUN_1001029e undefined FUN_1001029e(int param_1)
6 1 1001692e FUN_1001692e undefined FUN_1001692e(undefined4 * param_1)
6 0 1000cbff FUN_1000cbff undefined4 FUN_1000cbff(float param_1, float param_2)
6 0 100161b6 FUN_100161b6 undefined4 FUN_100161b6(byte * param_1)
6 0 10020708 FUN_10020708 undefined FUN_10020708(undefined4 param_1)
6 0 1002faab FUN_1002faab undefined4 FUN_1002faab(undefined4 * param_1, uint param_2, int param_3, int param_4)
5 2 100161bb FUN_100161bb int FUN_100161bb(void * this, undefined4 * param_1, int * param_2, undefined4 param_3, uint * param_4, undefined4 param_5, uint param_6)
5 1 1001ac4a FUN_1001ac4a undefined4 * FUN_1001ac4a(void * this, undefined4 * param_1)
4 3 100101f5 FUN_100101f5 undefined FUN_100101f5(undefined4 param_1)
Identified candidates¶
Logging / console queue (high confidence)¶
FUN_0046e8f4->strdup_malloc- Evidence:
strlen+malloc+ copy (FUN_00465c30) pattern. FUN_004017a0->console_push_line- Evidence: pushes strdup’d strings into a list, caps at 0x1000 entries.
FUN_00401870->console_printf- Evidence: formats strings (uses
FUN_00461089) then pushes into the console queue; callsites includeUnknown command/CMOD logs. FUN_00402350->console_register_cvar- Evidence: searches existing entry by name, allocates a 0x24 entry when missing, strdup’s name/value, parses float via
crt_atof_l, and is used byregister_core_cvarswithcv_*strings. FUN_00401940->console_exec_line- Evidence: parses a line into command/cvar targets, executes command callbacks, updates cvar values, and logs
status/errors; called with
exec_autoexec.txtandexec_music_game_tunes.txt.
Status/config paths (high confidence)¶
FUN_00402bd0->game_build_path- Evidence: formats
"%s\\%s"withgame_base_pathand a filename argument; used withconsole.log,game.cfg(save/status blob), andcrimson.cfg(config blob). FUN_0041ec60->config_sync_from_grim- Evidence: pulls Grim config values (
+0x24accessor), seeds default config blob when the Grim config dialog was invoked, loadscrimson.cfgoverrides, and writes the 0x480‑byte blob back out. FUN_0041f130->config_ensure_file- Evidence: ensures
crimson.cfgexists by writing the current config blob when missing.
Console command/cvar helpers (high confidence)¶
FUN_00402580->console_tokenize_line- Evidence: copies the input into
DAT_0047eaa0, splits withcrt_strtok, stores the command inDAT_0047ea60and arguments inDAT_0047ea64.., and updatesDAT_0047f4cc(token count). FUN_00402480->console_cvar_find- Evidence: walks the cvar list at
*thisand string-compares entry names against the target. FUN_004024e0->console_cvar_unregister- Evidence: calls
console_cvar_find, unlinks the node from the list, and returns success. FUN_00402750->console_command_find- Evidence: same search as
console_cvar_find, but over the command list atthis+4. FUN_00402530->console_command_unregister- Evidence: calls
console_command_findand unlinks the node from the command list. FUN_00402630->console_cvar_autocomplete- Evidence: returns an exact match or
_strncmpprefix match; used to fill the input buffer during tab completion. FUN_004027b0->console_command_autocomplete- Evidence: same as
console_cvar_autocomplete, but over the command list.
UI element timeline + transitions (high confidence)¶
FUN_0041a530->ui_elements_update_and_render- Evidence: advances a global timeline (
ui_elements_timeline(DAT_00487248)) based onDAT_00480844, clamps toui_elements_max_timeline, triggers screen transitions viaFUN_004461c0, and iteratesDAT_0048f208..DAT_0048f168callingFUN_00446900+ui_element_render. FUN_00446170->ui_elements_reset_state- Evidence: clears the element active flag (
*(char *)element) and zeroes the per-element hover timer at+0x2f8across the UI element table. FUN_00446190->ui_elements_max_timeline- Evidence: returns the max
element+0x10value among active elements (used to clamp the UI transition timeline).
Game state transitions (high confidence)¶
FUN_004461c0->game_state_set- Evidence: clears UI element state (
ui_elements_reset_state), updatesgame_state_prev/game_state_id, resets transition globals, and seeds UI elements; invoked on startup (game_core_init), when perk selection is requested (FUN_0040af70), and when UI transitions complete (ui_elements_update_and_render).
Gameplay session reset (high confidence)¶
FUN_00412dc0->gameplay_reset_state- Evidence: clears HUD/bonus slots, resets spawn/timer globals, seeds creature type textures/SFX, refreshes weapon/perk availability, and zeroes run/high-score counters; invoked when demo mode starts and on state transitions that require a fresh session.
Demo mode bootstrap (high confidence)¶
FUN_00403390->demo_mode_start- Evidence: forces the demo game state, sets
demo_mode_active, callsgameplay_reset_state, selects one of several demo setups, and advances the demo cycle index.
UI text input (high confidence)¶
FUN_0043ecf0->ui_text_input_update- Evidence: handles focus/hover, polls text input via
console_input_poll, plays typing SFX, and renders the input box plus caret. FUN_004413a0->ui_text_input_render- Evidence: renders the text input field with caret blink and state‑dependent colors; used by high‑score entry paths and other text input flows.
Audio resource packs + loaders (high confidence)¶
FUN_0043b980->resource_pack_set- Evidence: opens the pack file to validate it, caches the path, and flips the pack-enabled flag.
FUN_0043b940->resource_pack_read_cstring- Evidence: reads NUL-terminated entry names from the pack file into
DAT_004c3a68. FUN_0043b9e0->resource_open_read- Evidence: when a resource pack is active, opens the pack and searches entries; otherwise opens the file directly, returns the file size, and leaves the file handle in a global used by sample/track loaders.
FUN_0043bad0->resource_close- Evidence: closes the global resource file handle (
DAT_004c3c68) after a read. FUN_0043bca0->resource_read_alloc- Evidence: opens a resource, allocates a buffer of the reported size, reads it fully, and returns the pointer.
FUN_0043c020->sfx_entry_load_wav- Evidence: reads a WAV resource into memory then parses headers/data into an sfx entry.
FUN_0043c110->wav_parse_into_entry- Evidence: parses RIFF/WAV headers from a memory buffer and copies PCM into the entry.
FUN_0043bcf0->sfx_entry_load_ogg- Evidence: initializes an Ogg/Vorbis decoder from a resource buffer and fills an sfx entry.
FUN_0043c3a0->music_entry_load_ogg- Evidence: initializes an Ogg/Vorbis decoder for music streaming and allocates the stream buffer.
FUN_0043b850->buffer_reader_init- Evidence: sets the buffer pointer/size used by the WAV parser.
FUN_0043b870->buffer_reader_seek- Evidence: sets the current read cursor for the WAV parser.
FUN_0043b880->buffer_reader_read_u16- Evidence: reads a little-endian 16-bit value and advances the cursor.
FUN_0043b8a0->buffer_reader_read_u32- Evidence: reads a little-endian 32-bit value and advances the cursor.
FUN_0043b8c0->buffer_reader_skip- Evidence: advances the read cursor by N bytes.
FUN_0043b8e0->buffer_reader_find_tag- Evidence: scans the buffer for a tag (e.g., RIFF/data) and advances the cursor to it.
FUN_0043baf0->dsound_init- Evidence: creates the DirectSound device and primary buffer (used by
sfx_system_init). FUN_0043bc20->dsound_shutdown- Evidence: releases the DirectSound device.
FUN_0043bc40->dsound_restore_buffer- Evidence: handles
DSERR_BUFFERLOSTby restoring the buffer. FUN_0043c230->sfx_entry_upload_buffer- Evidence: locks a DirectSound buffer, copies PCM data, and unlocks it.
FUN_0043c2b0->sfx_entry_create_buffers- Evidence: creates and duplicates DirectSound buffers for an sfx entry.
FUN_0043c520->music_stream_update- Evidence: advances stream cursors and triggers refills when the play cursor wraps.
FUN_0043c590->music_stream_fill- Evidence: decodes Ogg data and writes the next streaming chunk.
Audio playback + streaming (high confidence)¶
FUN_0043d3f0->audio_update- Evidence: ticks sfx cooldowns, updates music stream buffers, and applies mute fades.
FUN_0043be60->sfx_entry_start_playback- Evidence: selects a free voice/buffer (or streaming buffer) and starts playback.
FUN_0043be20->sfx_entry_seek- Evidence: resets the DirectSound cursor and seeks the Ogg decoder to a sample offset.
FUN_0043bf40->sfx_entry_resume- Evidence: restarts streaming playback (used on resume/unmute).
FUN_0043bf60->sfx_entry_stop- Evidence: stops playback for all voices in the entry (used on suspend/mute).
FUN_0043bfa0->sfx_entry_set_volume- Evidence: applies volume changes across active voices.
Input primary action (high confidence)¶
FUN_00446030->input_primary_just_pressed- Evidence: edge-detects a primary action by latching
DAT_00478e50, checks mouse button(*DAT_0048083c + 0x58)(0), and scans per-player fire bindings atplayer_fire_key(stride0xd8). Used across UI click/confirm paths and player fire/selection logic. FUN_004460f0->input_primary_is_down- Evidence: returns true while the primary action is held (mouse button 0,
player_fire_key, orplayer_alt_fire_key), used by UI scroll/drag handling. FUN_00446000->input_any_key_pressed- Evidence: scans keycodes
2..0x17evia the input callback at(*DAT_0048083c + 0x80).
Data labels (high confidence)¶
DAT_00480348->config_blob- Evidence: 0x480‑byte
crimson.cfgblob; see config layout below. DAT_00480510->config_keybind_table- Evidence: 2×16 dword keybind table inside config blob; copied into runtime binds.
DAT_00482948->bonus_pool- Evidence: bonus/pickup pool base with 16 entries (stride
0x1c). DAT_004908d4->player_health- Evidence: per-player health (table base) with stride
0xd8; see player struct. DAT_004912b8->fx_queue- Evidence: FX queue base with 0x80 entries (stride
0x28). DAT_004926b8->projectile_pool- Evidence: base of 0x60-entry projectile pool with stride 0x40.
DAT_00493eb8->particle_pool- Evidence: particle pool base with 0x80 entries (stride
0x38). DAT_00495ad8->secondary_projectile_pool- Evidence: secondary projectile pool base with 0x40 entries (stride
0x2c). DAT_00496820->sprite_effect_pool- Evidence: sprite effect pool base with stride
0x2c. DAT_0049bf38->creature_pool- Evidence: base of 0x180‑entry creature pool with stride 0x98.
DAT_004aaf3c->fx_queue_rotated- Evidence: rotated FX queue base with 0x40 entries.
DAT_004d7a2c->weapon_table- Evidence: base of weapon table with stride 0x7c (see weapon table doc).
Creature spawn + damage (high confidence)¶
FUN_00430af0->creature_spawn_template- Evidence: calls
creature_alloc_slot, writes theDAT_0049bf38pool fields, mapstemplate_idto type/flags, and spawns linked satellites; heading-100uses a randomized heading. FUN_004207c0->creature_apply_damage- Evidence: applies perk multipliers, reduces HP and knockback, calls
creature_handle_death, spawns effects, and returns1when the creature dies.
Gameplay render pass (high confidence)¶
FUN_00405960->gameplay_render_world- Evidence: updates
ui_transition_alpha(DAT_00487278) (fade), renders the FX queue, creatures, player overlays (dead/alive ordering), projectiles, and bonuses.
Key binding block (DAT_00490bdc..DAT_00490f5c) (medium confidence)¶
These live inside the per-player input struct (stride 0x360 bytes / 0xd8 dwords) and are
queried through grim_is_key_active (+0x80) or grim_is_key_down (+0x44).
Defaults are set in config_load_presets.
| Address | Default (DIK) | Guess | Evidence |
|---|---|---|---|
DAT_00490bdc |
0x11 (W) |
move forward (player_move_key_forward) |
queried via is_key_active in player movement |
DAT_00490be0 |
0x1f (S) |
move backward (player_move_key_backward) |
queried via is_key_active in player movement |
DAT_00490be4 |
0x1e (A) |
turn left (player_turn_key_left) |
rotates heading in movement scheme ½ |
DAT_00490be8 |
0x20 (D) |
turn right (player_turn_key_right) |
rotates heading in movement scheme ½ |
DAT_00490bec |
0x0f (Tab) |
primary fire (player_fire_key) |
used by input_primary_* with stride 0xd8 |
DAT_00490bf8 |
0x10 (Q) |
aim rotate left (player_aim_key_left) |
rotates player_aim_heading in aim scheme 1 |
DAT_00490bfc |
0x12 (E) |
aim rotate right (player_aim_key_right) |
rotates player_aim_heading in aim scheme 1 |
DAT_00490bf0 |
0x11 (W) |
unused/reserved | copied from config, but no is_key_* callsites found |
DAT_00490bf4 |
0x1f (S) |
unused/reserved | copied from config, but no is_key_* callsites found |
DAT_00490f3c |
0xc8 (Up) |
alt move forward (player_alt_move_key_forward) |
used via is_key_down when _DAT_0048035c == 1 |
DAT_00490f40 |
0xd0 (Down) |
alt move backward (player_alt_move_key_backward) |
used via is_key_down when _DAT_0048035c == 1 |
DAT_00490f44 |
0xcb (Left) |
alt turn left (player_alt_turn_key_left) |
used via is_key_down when _DAT_0048035c == 1 |
DAT_00490f48 |
0xcd (Right) |
alt turn right (player_alt_turn_key_right) |
used via is_key_down when _DAT_0048035c == 1 |
DAT_00490f4c |
0x9d (RControl) |
alt primary fire (player_alt_fire_key) |
checked in input_primary_is_down |
DAT_00490f50 |
0x11 (W) |
unused/reserved | defaults set; no callsites yet |
DAT_00490f54 |
0x1f (S) |
unused/reserved | defaults set; no callsites yet |
DAT_00490f58 |
0xd3 (Delete) |
unused/reserved | defaults set; no callsites yet |
DAT_00490f5c |
0xc9 (PageUp) |
unused/reserved | defaults set; no callsites yet |
Key info overlay (ui_render_keybind_help) shows the first five entries per player from the config
blob at DAT_00480510 (stride 5: Forward/Back/TurnLeft/TurnRight/Fire), which matches the active runtime
binds copied from DAT_00480540 into DAT_00490bdc..DAT_00490bec.
Analog axis bindings (per-player, stride 0x360 bytes / 0xd8 dwords)¶
These bindings are read via grim_get_config_float (+0x84) and map to the
analog control schemes selected in the per-player mode flags:
| Address | Symbol | Scheme | Notes |
|---|---|---|---|
DAT_00490c08 |
player_axis_move_x |
movement scheme DAT_00480364 == 3 |
Used with player_axis_move_y to drive movement vectors. |
DAT_00490c0c |
player_axis_move_y |
movement scheme DAT_00480364 == 3 |
Paired with player_axis_move_x. |
DAT_00490c00 |
player_axis_aim_x |
aim scheme DAT_0048038c == 4 |
Used to derive aim vectors for stick/axis aiming. |
DAT_00490c04 |
player_axis_aim_y |
aim scheme DAT_0048038c == 4 |
Paired with player_axis_aim_x. |
Config edit path status:
- No in-game rebind writes to DAT_00480540 found in the decompile.
- config_load_presets reads the 0x480‑byte config blob from disk into DAT_00480348
and then copies the keybind table (DAT_00480540) into the per-player runtime slots.
- FUN_0041ec60 seeds defaults in a local 0x480 blob, optionally reads a 0x480‑byte
config from DAT_00472998, copies the string field at offset 0x74 and the flag
at offset 0x46c into globals (DAT_004803bc, DAT_004807b4), then writes the
global blob (DAT_00480348, size 0x480) using mode DAT_00473668 ("wb").
- FUN_0041f130 is a fallback path that writes the same DAT_00480348 blob using
mode DAT_00473668 ("wb") when the DAT_00472998 config file is missing.
- File evidence: game_bins/crimsonland/1.9.93-gog/crimson.cfg is exactly 0x480 bytes; game_bins/crimsonland/1.9.93-gog/game.cfg is not
(likely a save/progress file). DAT_00472998 is "rb"; the filename is supplied
by FUN_00402bd0 ("%s\\%s").
Config blob layout (partial, 0x480 bytes, base DAT_00480348):
| Offset | Address | Size | Default | Notes |
|---|---|---|---|---|
0x00 |
DAT_00480348 |
u8 |
0 |
Sound disable flag (nonzero skips SFX and music init; applied via config id 0x53). |
0x01 |
DAT_00480349 |
u8 |
0 |
Music disable flag (music init requires DAT_00480348 == 0 and DAT_00480349 == 0). |
0x02 |
DAT_0048034a |
u8 |
0 |
High‑score date validation mode: 1 = year+month, 2 = computed date checksum + year, 3 = day+month+year. |
0x03 |
DAT_0048034b |
u8 |
0 |
High‑score duplicate handling: 1 = replace existing entry with same name (via highscore_find_name_entry). |
0x04 |
DAT_0048034c |
u8[2] |
1,1 |
Per‑player HUD indicator toggle (gates the second indicator draw pass). |
0x08 |
DAT_00480350 |
u32 |
8 |
Unknown; value comes from a stack temp in FUN_0041ec60 (used to query Grim config), no global xrefs. |
0x0e |
DAT_00480356 |
u8 |
0/1 |
FX detail toggle (set by DAT_004807b8). |
0x10 |
DAT_00480358 |
u8 |
0/1 |
FX detail toggle (set by DAT_004807b8). |
0x11 |
DAT_00480359 |
u8 |
0/1 |
FX detail toggle (set by DAT_004807b8). |
0x14 |
DAT_0048035c |
u32 |
1/2 |
Player count (loop bound in most per‑player logic). |
0x18 |
DAT_00480360 |
u32 |
1..8 |
Game mode/state selector (values 1/2/3/4/8 observed). |
0x1c |
DAT_00480364 |
u8[?] |
0 |
Per‑player mode flag (value 4 triggers alternate HUD draw). |
0x44 |
DAT_0048038c |
u32 |
0 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x48 |
DAT_00480390 |
u32 |
0 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x6c |
DAT_004803b4 |
u32 |
0 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x70 |
DAT_004803b8 |
float |
1.0 (clamped 0.5..4.0) |
Texture/terrain scale factor (used when creating ground texture). |
0x74 |
DAT_004803bc |
char[12] |
empty string | Copied from config in FUN_0041ec60; only explicit consumer so far. |
0x80 |
DAT_004803c8 |
u32 |
0 |
Selected name slot (0..7) for the saved‑name list. |
0x84 |
DAT_004803cc |
u32 |
1 |
Saved‑name count / insert index. |
0x88 |
DAT_004803d0 |
u32[8] |
0..7 |
Saved‑name order table (seeded in FUN_0041ec60); no xrefs in the decompile, likely unused. |
0xa8 |
DAT_004803f0 |
char[0xd8] |
"default" x8 |
8 saved names, 0x1b bytes each (DAT_0048040b is entry 2). |
0x180 |
DAT_004804c8 |
char[36] |
DAT_00471314 |
Player name (copied to runtime DAT_00487040 on load). |
0x1a0 |
DAT_004804e8 |
u32 |
DAT_004871e8 |
Player name length (mirrored to runtime on load; config value is overwritten). |
0x1a4 |
DAT_004804ec |
u32 |
100 |
Seeded in FUN_0041ec60; no xrefs yet. |
0x1a8 |
DAT_004804f0 |
u32 |
0 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x1ac |
DAT_004804f4 |
u32 |
0 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x1b0 |
DAT_004804f8 |
u32 |
9000 |
Compared to Grim vtable +0xa4 (FUN_100075b0) in FUN_0041e8f0; returns DAT_1005d850[index] (index 0 here), no callsites, likely dead. |
0x1b4 |
DAT_004804fc |
u32 |
27000 |
Compared to Grim vtable +0xa4 (FUN_100075b0) in FUN_0041e8d0; returns DAT_1005d850[index] (index 0 here), no callsites, likely dead. |
0x1b8 |
DAT_00480500 |
u32 |
32 |
Likely display color depth (bits‑per‑pixel); set alongside width/height via config id 0x2b (inference from defaults and file). |
0x1bc |
DAT_00480504 |
u32 |
800 |
Screen width. |
0x1c0 |
DAT_00480508 |
u32 |
600 |
Screen height. |
0x1c4 |
DAT_0048050c |
u8 |
0 |
Windowed flag (0 = fullscreen). |
0x1c8 |
DAT_00480510 |
u32[0x20] |
see below | Keybind blocks (2 × 16 dwords; indices 0..12 copied). |
0x1f8 |
DAT_00480540 |
u32* |
alias | Points at &DAT_00480510[12] (used for the copy loop). |
0x440 |
DAT_00480788 |
u32 |
0 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x444 |
DAT_0048078c |
u32 |
0 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x448 |
DAT_00480790 |
u8 |
0 |
Hardcore flag (0 normal, 1 hardcore). |
0x449 |
DAT_00480791 |
u8 |
1 |
Full‑version/unlimited flag (gates quest logic and UI strings). |
0x44c |
DAT_00480794 |
u32 |
0 |
Perk prompt counter (0..0x32, increments on each prompt). |
0x450 |
DAT_00480798 |
u32 |
1 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x460 |
DAT_004807a8 |
u32 |
1 |
Unknown (defaulted in FUN_0041ec60, no xrefs). |
0x464 |
DAT_004807ac |
float |
? |
SFX volume multiplier. |
0x468 |
DAT_004807b0 |
float |
? |
Music volume multiplier. |
0x46c |
DAT_004807b4 |
u8 |
0 |
FX toggle (gore/particle path; copied from config; FUN_0041f130 forces 1 when cfg missing). |
0x46d |
DAT_004807b5 |
u8 |
0 |
Score load gating flag (used with DAT_0048034a). |
0x46e |
DAT_004807b6 |
u8 |
? |
Config bool applied via Grim id 0x54 (unknown). |
0x470 |
DAT_004807b8 |
u32 |
? |
Detail preset (drives DAT_00480356/58/59). |
Runtime note (2026-01-19 quest-build capture, 1.1 runs):
- Bytes at DAT_00480790..93 were [1, 1, 0, 0] for hardcore and [0, 1, 0, 0]
for normal (both 1P/2P). This confirms:
- DAT_00480790 toggles with hardcore (0 normal, 1 hardcore).
- DAT_00480791 is the full‑version flag (stayed 1 in all runs).
- DAT_00480794 increments on perk prompt opens (observed 0x1a..0x1d).
- Forcing DAT_00480791 = 0 at runtime showed no visible change (likely read on load).
| 0x478 | DAT_004807c0 | u32 | ? | Keybind: pick perk (Level‑up prompt). |
| 0x47c | DAT_004807c4 | u32 | ? | Keybind: reload. |
Keybind block layout (DAT_00480510, 2 × 16 dwords, indices 0..12 copied into runtime;
DAT_00480540 is &DAT_00480510[12]):
| Index | P1 default | P2 default | Notes |
|---|---|---|---|
0 |
0x11 (W) |
0xc8 (Up) |
Move up (overlay uses indices 0..4). |
1 |
0x1f (S) |
0xd0 (Down) |
Move down. |
2 |
0x1e (A) |
0xcb (Left) |
Move left. |
3 |
0x20 (D) |
0xcd (Right) |
Move right. |
4 |
0x100 |
0x9d (RControl) |
Primary fire (P1 default uses a non‑DIK sentinel). |
5 |
0x17e |
0x17e |
Unused/reserved. |
6 |
0x17e |
0x17e |
Unused/reserved. |
7 |
0x10 (Q) |
0xd3 (Delete) |
Rotate/aux? (mapped to runtime slots). |
8 |
0x12 (E) |
0xd1 (PageDown) |
Rotate/aux? (mapped to runtime slots). |
9 |
0x13f |
0x13f |
Unknown (mapped). |
10 |
0x140 |
0x140 |
Unknown (mapped). |
11 |
0x141 |
0x141 |
Unknown (mapped). |
12 |
0x153 |
0x153 |
Unknown (mapped). |
13 |
0x17e |
0x17e |
Unused/reserved. |
14 |
0x17e |
0x17e |
Unused/reserved. |
15 |
0x17e |
0x17e |
Unused/reserved. |
Grim input query (partial, vtable +0x80 → FUN_10006fe0 in grim.dll):
- code < 0x100: DirectInput keyboard state (raw DIK).
- 0x100..0x104: mouse buttons 0..4 (via Grim +0x58).
- 0x11f..0x12b: joystick buttons 0..12 (via Grim +0xa8).
- 0x13f..0x155: analog axes (reads DAT_1005d830/834/838/83c/840/844, thresholded).
- 0x16d..0x17b: joystick POV/axis queries via DAT_1005d3b4 (if device present).
Grim key‑click helper (vtable +0x48 → FUN_10007390):
- Uses FUN_1000a370 (keyboard state byte) plus per‑key timers; returns 1 on a new press edge.
Grim misc getter (vtable +0xa4 → FUN_100075b0):
- Returns *(DAT_1005d850 + index*4); only index 0 observed in crimsonland.exe (FUN_0041e8d0/1e8f0).
High score record (0x48 bytes) — metadata 0x20..0x37¶
The high score record embeds run metadata used for duplicate detection and ranking. These
fields are compared in highscore_record_equals before a score can replace an existing entry.
| Offset | Address | Meaning | Evidence |
|---|---|---|---|
0x20 |
DAT_00487060 |
Survival/time metric (ms) | highscore_rank_index compares survival_elapsed_ms to DAT_00482b30 for mode ⅔ ranking; highscore_record_equals compares this dword. |
0x24 |
DAT_00487064 |
Score/XP snapshot | Copied from player_experience each frame; highscore_rank_index compares against DAT_00482b34 for non‑survival modes; included in highscore_record_equals. |
0x28 |
DAT_00487068 |
Game mode id | Set from config_game_mode in high‑score screens; also used to pick which metric to rank in highscore_load_table. |
0x29 |
DAT_00487069 |
Quest stage major | Set from quest_stage_major and used in quest high‑score path naming. |
0x2a |
DAT_0048706a |
Quest stage minor | Set from quest_stage_minor and used in quest high‑score path naming. |
0x2b |
DAT_0048706b |
Most‑used weapon id | Set to the max‑usage index in DAT_0048708c before save. |
0x2c |
DAT_0048706c |
Shots fired | Incremented on projectile spawns; clamped against hits; compared in highscore_record_equals. |
0x30 |
DAT_00487070 |
Shots hit | Incremented on projectile hit paths (creature hitbox size 16.0); clamped to shots fired; compared in highscore_record_equals. |
0x34 |
DAT_00487074 |
Creature kill count | Incremented on creature death paths; compared in highscore_record_equals. |
High score record (0x48 bytes) — tail bytes 0x40..0x47¶
Score entries are 0x48 bytes (DAT_00482b10 array, DAT_00487040 active record). The
tail bytes are validated against the current date and the full‑version flag.
| Offset | Address | Meaning | Evidence |
|---|---|---|---|
0x40 |
DAT_00487080 |
Day‑of‑month | Written via param_1 + 0x10 (word index → +0x40) in highscore_write_record; compared to local_system_day (DAT_00495ace) in highscore_load_table mode 3. |
0x41 |
DAT_00487081 |
Date checksum (week‑of‑year) | highscore_date_checksum result stored at param_1 + 0x41; compared in mode 2. |
0x42 |
DAT_00487082 |
Month (1–12) | Stored from local_system_time._2_1_ (DAT_00495ac8); compared to local_system_time._2_2_. |
0x43 |
DAT_00487083 |
Year‑2000 | Stored as (char)local_system_time + '0' (DAT_00495ac8, low byte wraps); compared to year - 2000. |
0x44 |
DAT_00487084 |
Score flags | Bit 0 gates update vs append (and load gating in highscore_load_table); bit 1 is set to 2 when replacing an existing record and bypasses the load gate; bit 2 marks the entry selected for display after duplicate reduction. |
0x45 |
DAT_00487085 |
Full‑version marker | Set to 0x75 ('u') when DAT_00480791 != 0; checked in quest‑mode load to accept full/limited records. |
0x46 |
DAT_00487040 + 0x46 |
Sentinel 0x7c ('|') |
Initialized in highscore_load_table default‑record loop. |
0x47 |
DAT_00487040 + 0x47 |
Sentinel 0xff |
Initialized in highscore_load_table default‑record loop. |
Checksum helper (highscore_date_checksum):
- Inputs: year, month, day (from local_system_time + local_system_day).
- Returns a week‑of‑year style checksum (1..53) used when config_highscore_date_mode == 2.
- Used during both record write (highscore_write_record) and validation (highscore_load_table).
High score validation (highscore_load_table):
- Records only proceed to date checks if config_score_load_gate is set, or the record flags
have bit 0 clear, or bit 1 set.
- Mode 3: day + month + year must match (local_system_day, local_system_time).
- Mode 2: checksum from highscore_date_checksum(year, month, day) must match the stored checksum byte
(highscore_date_checksum at DAT_00487081), and year must match.
- Mode 1: month + year must match; other mode values skip the date check.
Quest progression counters (high confidence)¶
quest_stage_major(DAT_00487004) tracks the current quest episode/tier.- Evidence: increments after every 10 minor stages (
if 10 < quest_stage_minorthenquest_stage_major++,quest_stage_minor -= 10) during quest summary flow. - Initialized to
1inFUN_004120b0alongside high‑score state reset. quest_stage_minor(DAT_00487008) tracks the quest mission within the episode.- Evidence: used in quest string lookups and final‑mission checks (
major == 5 && minor == 10). - Incremented on quest results screen when the player chooses “Play Next”.
- Persistence:
quest_stage_major/minorare runtime-only (reset on startup) and only used to select metadata and to build per‑quest high‑score filenames (scores5\\quest*.hi). Quest unlock progress is saved separately ingame_status_blobviaquest_unlock_indexandquest_unlock_index_full(see below). quest_play_counts(DAT_00485618) increments on quest start (game_state_id == 9,_config_game_mode == 3) using the[major * 10 + minor]index.quest_unlock_index(DAT_00487034) stores the max quest unlock index (computed asquest_stage_major * 10 + quest_stage_minor - 10). It is updated on quest completion and persisted viagame_save_status/game_load_status.quest_unlock_index_full(DAT_00487038) stores the full‑version unlock index (same calculation) and is only updated whenconfig_full_versionis set.quest_meta_cursor(DAT_004c3650) tracks the quest metadata entry last written byFUN_00430a20duringquest_database_init.quest_monster_vision_meta(DAT_004c3658) points to a specific quest metadata entry used to force the Monster Vision perk inperks_generate_choices.
Quest unlock table (perk/weapon rewards)¶
Quest metadata includes two reward fields:
- quest_unlock_perk_id (DAT_00484750, offset +0x20) — perk unlock for a quest (stride 0x2c).
- quest_unlock_weapon_id (DAT_00484754, offset +0x24) — weapon unlock for a quest (stride 0x2c).
Indexing: quest_index = (quest_stage_major - 1) * 10 + (quest_stage_minor - 1).
Values below are initialized in quest_database_init (FUN_00439230).
Tier 1 - Quest 1: weapon Assault Rifle (id 0x02) - Quest 2: weapon Shotgun (id 0x03) - Quest 3: perk Uranium Filled Bullets (perk_id_uranium_filled_bullets, id 0x1c) - Quest 4: weapon Flamethrower (id 0x08) - Quest 5: perk Doctor (perk_id_doctor, id 0x1d) - Quest 6: weapon Submachine Gun (id 0x05) - Quest 7: perk Monster Vision (perk_id_monster_vision, id 0x1e) - Quest 8: weapon Gauss Gun (id 0x06) - Quest 9: perk Hot Tempered (perk_id_hot_tempered, id 0x1f) - Quest 10: weapon Rocket Launcher (id 0x0c)
Tier 2 - Quest 1: perk Bonus Economist (perk_id_bonus_economist, id 0x20) - Quest 2: weapon Plasma Rifle (id 0x09) - Quest 3: perk Thick Skinned (perk_id_thick_skinned, id 0x21) - Quest 4: weapon Ion Rifle (id 0x15) - Quest 5: perk Barrel Greaser (perk_id_barrel_greaser, id 0x22) - Quest 6: weapon Mean Minigun (id 0x07) - Quest 7: perk Ammunition Within (perk_id_ammunition_within, id 0x23) - Quest 8: weapon Sawed-off Shotgun (id 0x04) - Quest 9: perk Veins Of Poison (perk_id_veins_of_poison, id 0x24) - Quest 10: weapon Plasma Minigun (id 0x0b)
Tier 3 - Quest 1: perk Toxic Avenger (perk_id_toxic_avenger, id 0x25) - Quest 2: weapon Multi-Plasma (id 0x0a) - Quest 3: perk Regeneration (perk_id_regeneration, id 0x26) - Quest 4: weapon Seeker Rockets (id 0x0d) - Quest 5: perk Pyromaniac (perk_id_pyromaniac, id 0x27) - Quest 6: weapon Blow Torch (id 0x0f) - Quest 7: perk Ninja (perk_id_ninja, id 0x28) - Quest 8: weapon Rocket Minigun (id 0x12) - Quest 9: perk Highlander (perk_id_highlander, id 0x29) - Quest 10: weapon Jackhammer (id 0x14)
Tier 4 - Quest 1: perk Jinxed (perk_id_jinxed, id 0x2a) - Quest 2: weapon Pulse Gun (id 0x13) - Quest 3: perk Perk Master (perk_id_perk_master, id 0x2b) - Quest 4: weapon Plasma Shotgun (id 0x0e) - Quest 5: perk Reflex Boosted (perk_id_reflex_boosted, id 0x2c) - Quest 6: weapon Mini-Rocket Swarmers (id 0x11) - Quest 7: perk Greater Regeneration (perk_id_greater_regeneration, id 0x2d) - Quest 8: weapon Ion Minigun (id 0x16) - Quest 9: perk Breathing Room (perk_id_breathing_room, id 0x2e) - Quest 10: weapon Ion Cannon (id 0x17)
Tier 5 - Quest 1: weapon Ion Shotgun (id 0x1f) - Quest 2: perk Death Clock (perk_id_death_clock, id 0x2f) - Quest 3: perk My Favourite Weapon (perk_id_my_favourite_weapon, id 0x30) - Quest 4: weapon Gauss Shotgun (id 0x1e) - Quest 5: perk Bandage (perk_id_bandage, id 0x31) - Quest 6: perk Angry Reloader (perk_id_angry_reloader, id 0x32) - Quest 7: no unlock - Quest 8: perk Ion Gun Master (perk_id_ion_gun_master, id 0x33) - Quest 9: perk Stationary Reloader (perk_id_stationary_reloader, id 0x34) - Quest 10: weapon Plasma Cannon (id 0x1c)
Quest metadata struct (0x2c bytes)¶
Quest metadata entries live at quest_selected_meta (DAT_00484730) with a stride of 0x2c.
Fields below are high‑confidence; unknown offsets are omitted.
| Offset | Field | Meaning | Evidence |
|---|---|---|---|
0x00 |
quest_meta_tier |
Tier/episode number | Set to param_2 in FUN_00430a20 (called by quest_database_init). |
0x04 |
quest_meta_index |
Quest number within tier | Set to param_3 in FUN_00430a20. |
0x08 |
quest_meta_time_limit_ms |
Quest time limit in ms | Written per quest in quest_database_init (values like 120000, 300000, 480000). |
0x0c |
quest_meta_name |
Quest display name pointer | Set to strdup of the quest title in FUN_00430a20. |
0x10 |
quest_meta_terrain_id |
Terrain texture index (layer A) | Used by terrain_generate(desc) via *(int *)(desc + 0x10) to index DAT_0048f548. Set in FUN_00430a20 (tiers 1–4: 2 * (tier - 1), tier 5: quest_index & 3). |
0x14 |
quest_meta_terrain_id_b |
Terrain texture index (layer B) | Used by terrain_generate(desc) via *(int *)(desc + 0x14). Set in FUN_00430a20 (tiers 1–4: odd id for quests 1–5, even id for quests 6–10; tier 5: 1). |
0x18 |
quest_meta_terrain_id_c |
Terrain texture index (layer C) | Used by terrain_generate(desc) via *(int *)(desc + 0x18). Set in FUN_00430a20 (tiers 1–4: even id for quests 1–5, odd id for quests 6–10; tier 5: 3). |
0x1c |
quest_selected_builder |
Quest builder function pointer | Assigned after each FUN_00430a20 call in quest_database_init. |
0x20 |
quest_unlock_perk_id |
Perk unlock id | Used by perks_rebuild_available. |
0x24 |
quest_unlock_weapon_id |
Weapon unlock id | Used by weapon_refresh_available. |
0x28 |
quest_start_weapon_id |
Starting weapon id | Used by quest_start_selected to equip both players. |
Record match + display selection:
- highscore_record_equals is the equality predicate used during save‑file replacement; it compares the
player name plus metadata fields at offsets 0x20..0x34 (ints + a byte) and does not look
at the flags byte.
- After loading/sorting, highscore_load_table sets flag bit 2 on the single best record per name
(or all records when a name slot is selected), so the UI can filter displayed entries.
Init timing note:
- qpc_timestamp_scratch (DAT_00495ad6) is only used as a temporary QPC storage during
early init (QueryPerformanceCounter in game_startup_init); it sits near the date scratch
globals but is not part of the high‑score checksum path.
Renderer backend selection (medium confidence)¶
FUN_004566d3->renderer_select_backend- Evidence: copies a function table, reads config
DisableD3DXPSGP, and switches between multiple vtable variants (FUN_004567b0,FUN_004568c0,FUN_00456aa5).
Math helpers (high confidence)¶
FUN_00452ef0->float_near_equal- Evidence: returns 1 when
|a-b| < 1.1920929e-07(FLT_EPSILON) and guards against NaNs.
Texture loading helpers (high confidence)¶
FUN_0042a670->texture_get_or_load- Evidence: calls Grim
get_texture_handle(0xc0); if missing, callsload_texture(0xb4), logs success/failure, and re-queries handle. FUN_0042a700->texture_get_or_load_alt- Evidence: identical body to
texture_get_or_load; primary callers pass.jazassets.
CRT errno accessors (high confidence)¶
FUN_00465d93->crt_errno_ptr(_errno-style accessor)FUN_00465d9c->crt_doserrno_ptr(__doserrno-style accessor)FUN_00465d20->crt_dosmaperr(Win32 error -> errno mapper)- Evidence:
- Both call
crt_get_thread_data()and return pointer offsets (+2,+3). crt_dosmaperrstores Win32 errors into*crt_doserrno_ptrand maps to*crt_errno_ptrvia the error table atDAT_0047b7c0.- File I/O wrappers set these directly on failure:
FUN_004655bf(FlushFileBuffers) storesGetLastError()in*FUN_00465d9cand sets*FUN_00465d93 = 9(EBADF).FUN_004656b7(WriteFile) andFUN_00466064(ReadFile) callcrt_dosmaperrafterGetLastError()for non-trivial errors.FUN_0046645e(SetFilePointer) mapsGetLastError()throughcrt_dosmaperr.
CRT lock/unlock helpers (high confidence)¶
FUN_0046586b->crt_lock- Evidence: calls
InitializeCriticalSection,EnterCriticalSection, and__amsg_exitin the lock path; invoked bycrt_exit_lockand many CRT wrappers. FUN_004658cc->crt_unlock- Evidence: calls
LeaveCriticalSection; invoked bycrt_exit_unlockand many CRT wrappers. FUN_00463da5->crt_lock_file- Evidence: uses
crt_lockfor small-stream table entries or aFILE-embedded critical section. FUN_00463df7->crt_unlock_file- Evidence: inverse of
crt_lock_file, callscrt_unlockorLeaveCriticalSection. FUN_0046acf8->crt_lock_fh- Evidence: initializes per-file handle critical sections and enters the lock.
FUN_0046ad57->crt_unlock_fh- Evidence: leaves the per-file handle critical section.
CRT ctype helpers (high confidence)¶
FUN_00463c74->crt_isctype- Evidence: uses
PTR_DAT_0047b1c0table for single-byte and falls back toGetStringTypeA/Wfor multi-byte characters. FUN_00462fd0->crt_isalpha- Evidence: calls
crt_isctypewith mask0x103(alpha/upper/lower). FUN_00462ffe->crt_isspace- Evidence: calls
crt_isctypewith mask0x8(space).
CRT exit/stdio helpers (high confidence)¶
FUN_00460d08->crt_onexit- Evidence: takes exit callback, grows onexit table (
DAT_004db4f4/DAT_004db4f0) viaFUN_004626aa, stores pointer, and wraps withcrt_exit_lock/crt_exit_unlock. FUN_00460d86->crt_atexit- Evidence: calls
crt_onexitand returns0on success,-1on failure. FUN_00460dc7->crt_free- Evidence: thin wrapper around
FUN_004625c1(CRT heap free). FUN_004625c1->crt_free_base- Evidence: checks heap mode (
DAT_004da3a8), locks heap, frees via small-block helpers, and falls back toHeapFree. FUN_00460e5d->crt_fclose- Evidence: if
_flag & 0x40not set, locks stream, calls__fclose_lk, unlocks; otherwise clears_flag. FUN_0046100e->crt_fsopen- Evidence: parses mode string, passes share flag to
FUN_0046adbd, populatesFILEfields. FUN_0046103f->crt_fopen- Evidence: forwards to
crt_fsopenwith share mode0x40(_SH_DENYNO). FUN_004615ae->crt_fwrite- Evidence: wraps
crt_fwrite_nolockwithcrt_lock_file/crt_unlock_file. FUN_004615dd->crt_fwrite_nolock- Evidence: writes buffers directly to file handle, uses
crt_flsbuffor single-byte writes. FUN_00461af7->crt_fread- Evidence: wraps
crt_fread_nolockwithcrt_lock_file/crt_unlock_file. FUN_00461b26->crt_fread_nolock- Evidence: reads buffers directly from file handle and sets EOF/error flags.
FUN_00461d91->crt_fseek- Evidence: wraps
crt_fseek_nolockwithcrt_lock_file/crt_unlock_file. FUN_00461dbd->crt_fseek_nolock- Evidence: validates stream flags, flushes, and seeks via
crt_lseek. FUN_004616e7->crt_sprintf- Evidence: uses CRT output core
FUN_00464380with an unbounded count (0x7fffffff) and terminates with\0on success. FUN_00464268->crt_flsbuf- Evidence: flushes/allocates stream buffers, handles append seeks, and writes a single char;
used by
crt_fwrite/crt_sprintfwhen buffers underflow. FUN_00464b1e->crt_putc_nolock- Evidence: decrements buffer count, calls
crt_flsbufon underflow, otherwise writes byte and updates the output counter (printf output helper). FUN_00464b53->crt_putc_repeat_nolock- Evidence: loops count times calling
crt_putc_nolock, used for space/zero padding in printf. FUN_00464b84->crt_putc_buffer_nolock- Evidence: emits a string buffer via
crt_putc_nolock, stops on error. FUN_004663f9->crt_lseek- Evidence: validates handle, locks via
crt_lock_fh, then callscrt_lseek_nolock. FUN_0046645e->crt_lseek_nolock- Evidence: calls
SetFilePointer, clears EOF flag on success, usescrt_dosmaperron error. FUN_0046dd16->crt_chsize- Evidence: uses
crt_lseek_nolockto get size, truncates viaSetEndOfFileor extends by writing zero-filled blocks, then restores the file offset.
Grim/libpng helpers (high confidence)¶
FUN_1001e114->png_error- Evidence: calls
png_ptr->error_fnwhen set and thenlongjmp(png_ptr, 1). FUN_1001e132->png_warning- Evidence: calls
png_ptr->warning_fnwhen set. FUN_1002047c->png_read_data- Evidence: dispatches to
read_data_fnor raisespng_erroron NULL. FUN_10020583->png_reset_crc- Evidence: seeds
png_ptr->crcviacrc32(0, NULL, 0). FUN_1002059b->png_calculate_crc- Evidence: updates CRC unless skip flags indicate the chunk is ignored.
FUN_10024741->png_malloc- Evidence: malloc wrapper that calls
png_erroron OOM. FUN_10024777->png_free- Evidence: free wrapper with
(png_ptr, ptr)signature. FUN_10024734->png_free_ptr- Evidence: simple free wrapper used for png buffers and the main png_ptr.
FUN_10024807->png_crc_read- Evidence: calls
png_read_datathenpng_calculate_crcon the same buffer. FUN_10024821->png_crc_error- Evidence: reads the stored CRC and compares it against
png_ptr->crc. FUN_1002487f->png_check_chunk_name- Evidence: validates 4-letter chunk type and errors on invalid characters.
FUN_100250d7->png_crc_finish- Evidence: consumes remaining chunk bytes, checks CRC, and raises error/warning.
Grim pixel/format helpers (high confidence)¶
FUN_1000aaa6->grim_format_info_lookup- Evidence: walks the D3D format descriptor table (
DAT_1004c3b0) and returns the entry for the requested format id, falling back to a default descriptor. FUN_100174a8->grim_apply_color_key- Evidence: iterates RGBA float pixels and zeroes those that match the current color key
(
this+0x1c..0x28), used after converting pixel buffers.
Audio SFX helpers (medium confidence)¶
FUN_0043d120->sfx_play- Evidence: validates entry in
DAT_004c84e4, checks cooldownDAT_004c3c80, sets sample rate viabonus_reflex_boost_timerintoDAT_00477d28, chooses a voice (FUN_0043be60), calls vtable +0x40 with pan 0, then sets volume withFUN_0043bfa0. FUN_0043d260->sfx_play_panned- Evidence: same as
sfx_play, but converts an FPU value to pan (__ftol), clamps to[-10000, 10000], and passes pan to vtable +0x40. FUN_0043d550->sfx_mute_all- Evidence: sets
DAT_004c8450[sfx]=1and recursively mutes all other unmuted ids usingsfx_is_unmuted. FUN_0043d7c0->sfx_is_unmuted- Evidence: returns true when
DAT_004cc8d6is set and the per-id mute flag is clear. FUN_0043d460->sfx_play_exclusive- Evidence: mutes other ids, optionally selects a random variant, and ensures the chosen id is
unmuted with its volume set in
DAT_004c404c. FUN_0043d5b0->sfx_update_mute_fades- Evidence: ramps per-id volume toward
DAT_004807b0when unmuted and fades to zero when muted, stopping voices viaFUN_0043bf60. FUN_0043c9c0->audio_init_music- Evidence: loads
music.paq, logs status, and registers track ids:DAT_004c4030=music_intro.oggDAT_004c4034=music_shortie_monk.oggDAT_004c4038=music_crimson_theme.oggDAT_004c4044=music_crimsonquest.oggDAT_004c403c/_DAT_004c4040= subsequent track ids (+1/+2).
FUN_0043caa0->audio_init_sfx- Evidence: loads
sfx.paqand registers the sound effect ids. - See SFX ID map for the extracted id-to-file mapping.
- See SFX usage for the most referenced SFX ids in the decompiled code.
- See SFX label suggestions for suggested data labels (ApplyDataMap applies data labels).
FUN_0043c740->sfx_load_sample- Evidence: allocates a free slot in
DAT_004c84e4, loads.ogg/.wavdata, and returns the sample id. FUN_0043c700->sfx_release_sample- Evidence: releases an sfx entry by id via
sfx_release_entry. FUN_0043c090->sfx_release_entry- Evidence: frees sample buffers/voices and clears entry state.
FUN_0043c8d0->music_load_track- Evidence: allocates a free track in
DAT_004c4250, loads the tune, and returns the id. FUN_0043c960->music_queue_track- Evidence: appends a track id into
DAT_004cc6d0playlist array. FUN_0043c980->music_release_track- Evidence: releases a music entry by id via
sfx_release_entry. FUN_0043cf90->sfx_system_init- Evidence: initializes the Grim SFX system and clears
DAT_004c3c80/DAT_004c3e80tables. FUN_0043d070->sfx_release_all- Evidence: iterates
DAT_004c84d0entries and callssfx_release_entry. FUN_0043d0d0->music_release_all- Evidence: iterates
DAT_004c4250entries and callssfx_release_entry. FUN_0043d110->audio_shutdown_all- Evidence: calls
sfx_release_all,music_release_all, and the audio backend shutdown helper.
Global var access (medium confidence)¶
FUN_0042fcf0->perk_count_get- Evidence: returns
(&player_perk_counts)[perk_id](DAT_00490968) directly; used to track perk picks and gating.
Save/load helpers (medium confidence)¶
FUN_0042a980->reg_read_dword_default- Evidence: wraps
RegQueryValueExAforREG_DWORDand writes fallback on failure. FUN_0042a9c0->reg_write_dword- Evidence: wraps
RegSetValueExAwithREG_DWORD. FUN_00412a10->game_sequence_load- Evidence: reads the
sequenceregistry value and updatesDAT_00485794. FUN_00412a80->game_save_status- Evidence: writes registry values (
sequence,dataPathId,transferFailed) and saves agame.cfg-style status file; logsGAME_SaveStatus OK/FAILED. FUN_00412c10->game_load_status- Evidence: loads the status file, validates checksum/size, and regenerates it on failure;
logs
GAME_LoadStatus ....
Effect spawn helper (medium confidence)¶
FUN_0042de80->effect_init_entry- Evidence: zeros/sets default fields on a single entry and initializes per-quad color slots.
FUN_0042df10->effect_defaults_reset- Evidence: resets global template values (
DAT_004ab1*) used by effect spawners. FUN_0042e080->effect_free- Evidence: pushes the entry back onto
effect_free_list_headfree list and clears live flag. FUN_0042e0a0->effect_select_texture- Evidence: maps effect id through
effect_id_size_code/effect_id_frameand calls Grim vtable +0x104 with texture page bitmasks. FUN_0042e120->effect_spawn- Evidence: pops an entry from the pool
effect_free_list_head, copies templateeffect_template_vel_x, writes position fromparam_2, tags the effect id, and assigns quad UVs from atlas tableseffect_id_size_code/effect_id_frameplus arrayseffect_uv16_u,effect_uv8_u,effect_uv4_u,effect_uv2_u. FUN_0042e710->effects_update- Evidence: iterates pool entries, advances timers/positions with
DAT_00480840, and callseffect_freewhen expired. FUN_0042e820->effects_render- Evidence: sets render state, iterates effects, computes rotated quad vertices, and submits via Grim vtable +0x134.
FUN_00427700->fx_queue_add_random- Evidence: chooses a random effect id
3..7, random grayscale color/size, and pushes an entry viafx_queue_add; usesfx_queue_random_color_*scratch globals. FUN_0042ec80->effect_spawn_freeze_shard- Evidence: configures the effect template and spawns a random
8..10variant with velocity based on(angle + pi); used by freeze/shatter logic. FUN_0042ee00->effect_spawn_freeze_shatter- Evidence: spawns four
effect_id 0xebursts at 90° offsets plus extraeffect_spawn_freeze_shardcalls.
Perk database + selection (medium confidence)¶
FUN_0042fd90->perks_init_database- Evidence: assigns perk id constants (
DAT_004c2b**/DAT_004c2c**) and fills the perk name/description tables viaFUN_0042fd00. - See Perk ID map for the extracted id-to-name mapping.
FUN_0042fb10->perk_can_offer- Evidence: checks mode gates and perk flags, then returns a nonzero byte if the perk is eligible.
FUN_0042fbd0->perk_select_random- Evidence: randomizes an id from the perk table, calls
perk_can_offer, and logs a failure when selection runs too long. FUN_0042fc30->perks_rebuild_available- Evidence: resets
DAT_004c2c4cflags and re-enables base/unlocked perks. - Table layout (stride
0x14):name@DAT_004c2c40,desc@DAT_004c2c44,flags@DAT_004c2c48,available@DAT_004c2c4c,prereq@DAT_004c2c50. - Flag bits (inferred):
0x1allows perks when_DAT_00480360 == 3.0x2allows perks when_DAT_0048035c == 2(two-player mode).0x4marks stackable perks (random selection accepts them even if already taken).
- Prereq field is checked via
perk_count_getand gates perks like Toxic Avenger (requires Veins of Poison), Ninja (requires Dodger), Perk Master (requires Perk Expert), and Greater Regeneration (requires Regeneration). FUN_004055e0->perk_apply- Evidence: called after selecting a perk in the UI, increments
perk_count_gettable, and executes the perk-specific effects (exp, health, weapon changes, perk spawns). FUN_004045a0->perks_generate_choices- Evidence: fills
DAT_004807e8with randomly selected perks usingperk_select_random, enforces uniqueness, and applies special-case handling for mode8(fixed perk list). - Perk prompt UI gates (high confidence):
perk_prompt_timer(DAT_0048f524) ramps 0..200 while perks are pending and feeds the prompt alpha plus the transform matrix (perk_prompt_transform_*atDAT_0048f510..DAT_0048f51c).perk_prompt_origin_x/y(DAT_0048f224/DAT_0048f228) anchor the prompt bounds for hover/click tests;perk_prompt_bounds_min_*(DAT_0048f248/DAT_0048f24c) andperk_prompt_bounds_max_*(DAT_0048f280/DAT_0048f284) define the relative rectangle.perk_prompt_hover_active(DAT_0048f500) flips when the cursor enters/leaves the perk prompt bounds and gates whether the click target is active.perk_prompt_pulse(DAT_0048f504) ramps0..1000(decays when not hovered, accelerates when hovered) and is forced to1000when the perk pick key is pressed.perk_choices_dirty(DAT_00486fb0) is set after perk selection and on reset, then cleared the first timeperks_generate_choicesruns before switching to state6.
Tutorial prompt (medium confidence)¶
FUN_00408530->tutorial_prompt_dialog- Evidence: renders the tutorial message panel and uses button UI for "Repeat tutorial",
"Play a game", and "Skip tutorial"; click handlers restart the tutorial (clears perk count
table
player_perk_counts(DAT_00490968) and resets timers) or exit to game (setsgame_state_pending(DAT_00487274), flushes input, and resetsDAT_00486fe0). - Signature (inferred):
void tutorial_prompt_dialog(char *text, float alpha) alphacomes fromtutorial_timeline_update(0..1), controls the prompt fade, and is used to scale the button visuals; the decompiler currently shows it as acharbecause the call site passesSUB41of a float.
Tutorial timeline (medium confidence)¶
FUN_00408990->tutorial_timeline_update- Evidence: loads the tutorial string table, advances
DAT_00486fd8stage index whenDAT_00486fe0counts up from-1000, and renders each stage viatutorial_prompt_dialog. - Timers:
DAT_00486fdcaccumulates per-frame time (DAT_00480844), gates stage 0 auto-advance and is used to fade stage 5 after 5 seconds.DAT_00486fe0is a stage transition/fade timer: it counts up from-1000toward-1to advance the stage, then counts up from0to1000before snapping back to-1. The absolute value is scaled by0.001to derive the prompt alpha.
- Stage transitions observed:
- Stage 0: after
DAT_00486fdc > 6000andDAT_00486fe0 == -1, clearsDAT_004808a8, resetsDAT_004712fc, and setsDAT_00486fe0 = -1000. - Stage 1: waits for any movement key active (
grim_is_key_activevia vtable +0x80), then spawns bonus pickups (FUN_0042ef60) and setsDAT_00486fe0 = -1000. - Stage 2: waits until all 16 bonus slots in
bonus_pool(DAT_00482948) clear, then setsDAT_00486fe0 = -1000. - Stage 3: waits for input in
player_fire_key(DAT_00490bec) key slots, spawns arrow markers (FUN_00430af0), then setsDAT_00486fe0 = -1000. - Stage 4: waits for
creatures_none_active(), spawns arrow markers, setsDAT_00486fdc = 1000, then setsDAT_00486fe0 = -1000. - Stage 5: increments
DAT_004808a8on repeatedcreatures_none_active()events, spawns markers/bonuses, and after 8 iterations setsplayer_experience(DAT_0049095c) to 3000 andDAT_00486fe0 = -1000. - Stage 6: waits for
perk_pending_count(DAT_00486fac) < 1, spawns markers, then setsDAT_00486fe0 = -1000.
- Stage 0: after
- Stage 7: waits for
creatures_none_active()with no active bonus slots, then setsDAT_00486fe0 = -1000. -
Stage text table (array indexed by
DAT_00486fd8, base islocal_38):Stage Text 0 This is the nuke powerup, picking it up causes a huge\nexposion harming all monsters nearby! 1 Reflex Boost powerup slows down time giving you a chance to react better 2 (empty string, DAT_00472718)3 (empty string, DAT_00472718)4 In this tutorial you'll learn how to play Crimsonland 5 First learn to move by pushing the arrow keys. 6 Now pick up the bonuses by walking over them 7 Now learn to shoot and move at the same time.\nClick the left Mouse button to shoot. 8 Now, move the mouse to aim at the monsters -
Secondary hint overlay:
DAT_004712fcincrements when the current bonus object (DAT_004808ac) flips inactive with flag0x400, andDAT_004808b4ramps the hint alpha (up/down at 3x delta, clamped 0..1000).- The hint text is fetched from the same stack string block (
afStack_5c[DAT_004712fc + 2]); entries that point toDAT_00472718are skipped because the string starts with0xa7(-0x59), matching the guard byte check.
- Additional strings in the same stack block include perk tutorial lines
("It will help you to move and shoot...", Perks intro, Perks description, "Great! Now you are ready to start"),
plus speed/weapon/x2 powerup blurbs (
local_44/local_40/local_3c). - Helper:
FUN_00428210->creatures_none_active- Evidence: scans the creature table at
DAT_0049bf38for any active entries, setsDAT_0048700c, and returns low byte1only when the table is empty.
- Evidence: scans the creature table at
- Stage index wraps to 0 when
DAT_00486fd8reaches 9; counters are initialized inFUN_00412dc0(DAT_00486fd8 = -1,DAT_00486fe0 = -1000) and reset bytutorial_prompt_dialog.
UI button helpers (medium confidence)¶
FUN_004034a0->ui_mouse_inside_rect- Evidence: checks mouse coordinates (
DAT_004871ec/DAT_004871f0) againstxy + (w, h)and returns 1 when inside andDAT_004871ccis clear. FUN_0043d830->ui_focus_update- Evidence: tracks a rolling list of focus candidates in
DAT_004ccbd0, responds to key input to move focus, and returns nonzero when the provided id matches the focused entry. FUN_0043d940->ui_focus_draw- Evidence: draws a small highlight quad near the focused item location using the UI renderer.
FUN_0043e830->ui_button_update- Evidence: draws the small/medium button textures, updates hover/press timers using
ui_mouse_inside_rect, and returns nonzero when the button is activated.
Button struct (size 0x18, used by DAT_0047f5f8 / DAT_00480250 / DAT_004807d0):
| Offset | Field | Notes |
|---|---|---|
| 0x00 | label |
char * text pointer passed to grim_measure_text_width. |
| 0x04 | hovered |
low byte set from ui_mouse_inside_rect. |
| 0x05 | activated |
set to 1 when ui_button_update triggers; cleared otherwise. |
| 0x06 | enabled |
when 0, disables hover/press and decays the hover timer. |
| 0x08 | hover_t |
0..1000 hover animation timer (ramps ±4/±6 per frame). |
| 0x0c | press_t |
0..1000 press flash timer (decays by 6 per frame). |
| 0x10 | alpha |
base alpha scale (1.0 default). |
| 0x14 | flags |
byte flags; 0x15 is checked to force a wide button. |
| 0x15 | force_wide |
overrides width selection for short labels. |
Quest timeline (medium confidence)¶
FUN_0043a790->quest_start_selected- Evidence: resets quest state, selects quest metadata at
DAT_00484730, queues perk state, and runs the quest builder atDAT_0048474c(orquest_build_fallbackwhen null). FUN_00434250->quest_spawn_timeline_update- Evidence: walks the quest spawn table (
DAT_004857a8, countDAT_00482b08), checks trigger time vsDAT_00486fd0, and spawns each entry withFUN_00430af0using a 0x28 spacing offset. FUN_00434220->quest_spawn_table_empty- Evidence: returns 1 when all spawn entries have been cleared (no pending spawns).
FUN_004343e0->quest_build_fallback- Evidence: logs a fallback warning and writes two default entries (spawn id
0x40, counts 10/0x14, trigger times 500/5000). FUN_004343c0->quest_database_advance_slot- Evidence: increments quest index, wraps every 10, and advances the tier.
FUN_00439230->quest_database_init- Evidence: populates the quest metadata table (
DAT_00484730) with names, durations, and builder function pointers.
Creature table (partial)¶
FUN_00428140->creature_alloc_slot- Evidence: scans
DAT_0049bf38in0x98-byte strides foractive == 0, clears flags/seed fields, incrementsDAT_00486fb4, and returns the slot index (or0x180on failure). - Layout (entry size
0x98, baseDAT_0049bf38, pool size0x180):
| Offset | Field | Evidence |
|---|---|---|
| 0x00 | active (byte) | checked for zero in most creature loops; set to 1 on spawn, cleared on death. |
| 0x14 | pos_x | set in FUN_00428240, used in distance checks and targeting. |
| 0x18 | pos_y | set in FUN_00428240, used in distance checks and targeting. |
| 0x1c | vel_x | computed from heading/speed and passed to FUN_0041e400 for movement. |
| 0x20 | vel_y | computed from heading/speed and passed to FUN_0041e400 for movement. |
| 0x24 | health | checked as > 0 for valid targets and in perk kill logic (<= 500). |
| 0x28 | max_health | set from health on spawn; used when splitting (clone health is max_health * 0.25). |
| 0x2c | heading (radians) | set from rand % 0x13a * 0.01 on spawn; eased toward desired heading via FUN_0041f430. |
| 0x30 | desired heading | computed from target position and stored each frame. |
| 0x34 | collision radius (?) | used in collision tests in FUN_00420600. |
| 0x38 | hit flash timer | decremented each frame; set by FUN_004207c0 on damage. |
| 0x50 | target_x | target position derived from player/formation/linked enemy. |
| 0x54 | target_y | target position derived from player/formation/linked enemy. |
| 0x60 | attack cooldown | decremented each frame; gates projectile spawns for some flags. |
| 0x6c | type id (spawn param) | written from param_3 in FUN_00428240. |
| 0x70 | target player index | toggled between players based on distance; indexes player pos arrays. |
| 0x78 | link index / state timer | used as linked creature index in several AI modes; also incremented as a timer when 0x80 flag is set. |
| 0x8c | flags | bit tests 0x4/0x8/0x400 guard behaviors in update/split logic. |
| 0x90 | AI mode | selects movement pattern (cases 0/⅓/⅘/6/⅞ in update loop). |
| 0x94 | anim phase | accumulates and wraps (31/15) to drive sprite animation timing. |
See Creature struct for the expanded field map and cross-links.
Projectile pool (partial)¶
FUN_00420440->projectile_spawn- Evidence: allocates a slot in
projectile_pool(DAT_004926b8), initializes angle/pos/type/owner, and callers store the return index. FUN_00420b90->projectile_update- Evidence: iterates
0x60projectile entries, advances movement, checks collisions against creatures/players, spawns hit effects, and clears expired entries. FUN_004205d0->projectile_reset_pools- Evidence: clears
projectile_pool(DAT_004926b8,0x40stride) andparticle_pool(DAT_00493eb8,0x38stride). FUN_00420600->creatures_apply_radius_damage- Evidence: loops active creatures, checks distance vs radius + size, and calls
FUN_004207c0. FUN_004206a0->creature_find_in_radius- Evidence: returns the first creature index within
radiusstarting atstart_index(or-1). FUN_00420730->player_find_in_radius- Evidence: scans the player health table (
player_health,DAT_004908d4), skipping the owner id, and returns the first player within range. - Layout (entry size
0x40, baseprojectile_pool(DAT_004926b8), pool size0x60):
| Offset | Field | Evidence |
|---|---|---|
| 0x00 | active (byte) | Set on spawn; cleared when lifetime expires. |
| 0x08 | pos_x | Spawn position and update movement use. |
| 0x0c | pos_y | Spawn position and update movement use. |
| 0x20 | type id | Spawn parameter, drives branch logic. |
| 0x24 | life timer | Decrements by DAT_00480840, clearing when <= 0. |
| 0x34 | hit radius | Used for creature collision checks. |
| 0x3c | owner id | Used to skip the shooter in hit tests. |
See Projectile struct for the expanded field map and notes.
Effects pools (medium confidence)¶
FUN_00420130->fx_spawn_particle- Evidence: allocates a
0x38-byte entry inparticle_pool(DAT_00493eb8), sets position, angle, and velocity (speed ~90), and returns the slot index. FUN_00420240->fx_spawn_particle_slow- Evidence: same pool as
fx_spawn_particle, but speed ~30 and sets style id8. FUN_00420360->fx_spawn_secondary_projectile- Evidence: allocates a
0x2c-byte entry insecondary_projectile_pool(DAT_00495ad8) with type id, velocity, and optional nearest-creature target whentype_id == 2. FUN_0041fbb0->fx_spawn_sprite- Evidence: allocates a
0x2c-byte entry insprite_effect_pool(DAT_00496820) with position, velocity, tint, and a scalar parameter used by the renderer. - Layouts and fields are tracked in Effects pools.
Bonus / pickup pool (medium confidence)¶
FUN_0041f580->bonus_alloc_slot- Evidence: scans
bonus_pool(DAT_00482948) in0x1c-byte strides and returns the first entry with type0(or the sentinelbonus_pool_sentinel/DAT_00490630when full). FUN_0041f5b0->bonus_spawn_at- Evidence: clamps position to arena bounds, writes entry fields (type, lifetime, size, position,
duration override), and spawns a pickup effect via
FUN_0042e120. FUN_0040a320->bonus_update- Evidence: decrements bonus lifetimes, checks player proximity, calls
bonus_applyon pickup, and clears entries whentime_leftexpires. FUN_004295f0->bonus_render- Evidence: renders bonus icons from
DAT_0048f7f0, scales/fades by timer, and draws label text viabonus_label_for_entrywhen players are nearby. FUN_00429580->bonus_label_for_entry- Evidence: returns a formatted label string for bonus entries (weapon/score cases use a formatter).
FUN_00409890->bonus_apply- Evidence: applies bonus effects based on entry type (
param_2[0]), spawns effects viaFUN_0042e120, and plays bonus SFX (FUN_0043d260). - See Bonus ID map for the id-to-name table and default amounts.
- Layout (entry size
0x1c, basebonus_pool(DAT_00482948), 16 entries):
| Offset | Field | Evidence |
|---|---|---|
| 0x00 | type id (0 = free) | bonus_alloc_slot scans for 0; render/update skip 0. |
| 0x04 | state flag (bonus_state) |
bonus_update sets to 1 after pickup and accelerates lifetime decay. |
| 0x08 | time_left (bonus_time_left) |
decremented each frame in bonus_update; set to 0.5 on pickup; expiry clears type to 0. |
| 0x0c | time_max (bonus_time_max) |
set to 10.0 on spawn; used for fade/flash in bonus_render. |
| 0x10 | pos_x (bonus_pos_x) |
set on spawn; used for distance checks. |
| 0x14 | pos_y (bonus_pos_y) |
set on spawn; used for distance checks. |
| 0x18 | amount/duration (bonus_amount) |
used by bonus_apply when applying certain bonus types. |
Game mode selector (partial)¶
_DAT_00480360holds the current game mode. See Game mode map for the observed values and evidence.FUN_00412960->game_mode_label- Evidence: returns a label string based on
_DAT_00480360(Survival, Quests, Typ-o-Shooter, etc.).
Survival mode (partial)¶
FUN_00407cd0->survival_update- Evidence: runs only when
_DAT_00480360 == 1, advances scripted spawn stages, and callssurvival_spawn_creaturewhen the spawn timer elapses. FUN_00407510->survival_spawn_creature- Evidence: allocates a creature slot, assigns spawn position, and selects a type based on
DAT_0049095cthresholds before seeding speed/health and flags. - Key state:
DAT_00486fc4acts as the spawn cooldown accumulator; it is decremented byplayer_count * frame_dt, and when it drops below zero a burst of spawns is scheduled.DAT_00487060is the survival elapsed timer (ms). It is incremented each frame and is used to scale spawn cadence and HUD timers.DAT_00487190is the scripted spawn stage index (0..10) that gates bonus/marker spawns byDAT_00490964milestones.player_experience(DAT_0049095c) is the survival XP/progression score (HUD labelXp, displayed via the smoothedDAT_00490300) and is used for creature type/health scaling insurvival_spawn_creature.player_level(DAT_00490964) is the survival level/milestone counter (drawn as%din the HUD) that gates scripted spawns insurvival_update; it increments whenplayer_experiencesurpasses a periodic threshold.- The HUD shows
Xp, the smoothed XP value, and aProgresslabel with a bar fed byplayer_experience/player_level(DAT_0049095c/DAT_00490964) and a 1-second timer derived fromcrt_ci_pow().