Add extractor for Crusader's EUSECODE.FLX container
- Implemented a Python script to extract data from the EUSECODE.FLX file format. - Defined data structures for candidate entries and extracted chunks using dataclasses. - Added functions to read and parse the FLX table, extract candidate data, and generate human-readable output files. - Included functionality for analyzing extracted data, including generating summaries, descriptors, and event family reports. - Implemented utilities for calculating printable ratios, zero ratios, and identifying text-like data. - Added support for writing various output formats, including JSON, TSV, and Markdown.
This commit is contained in:
parent
3d4c4933ec
commit
3daffbf113
58 changed files with 30295 additions and 2504 deletions
333
docs/raw-porting-progress.md
Normal file
333
docs/raw-porting-progress.md
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
# Crusader: No Remorse — Raw Import Porting Progress & Gameplay Batches
|
||||
|
||||
This file covers the raw `CRUSADER-RAW.EXE` porting batches: seg091 RNG helpers, the 0x4588 runtime callback lifecycle batches, and raw 0007 gameplay analysis batches.
|
||||
|
||||
---
|
||||
|
||||
## Raw seg091 Boundary Recovery (init/context + RNG helpers)
|
||||
|
||||
Conservative PyGhidra boundary repair created the missing seg091 functions in `CRUSADER-RAW.EXE`:
|
||||
- `000a:44fd` = `seg091_func_00fd`, body `000a:44fd-000a:454c`
|
||||
- `000a:454d` = `seg091_func_014d`, body `000a:454d-000a:45fd`
|
||||
- `000a:48a0` = `rng_advance_state`, body `000a:48a0-000a:48e2`
|
||||
- `000a:48ff` = `rng_next_modulo`, body `000a:48ff-000a:4912`
|
||||
|
||||
Additional adjacent helper identified directly in the raw import:
|
||||
- `000a:48e3` = `rng_set_seed`
|
||||
|
||||
Verified behavior:
|
||||
- `rng_set_seed` writes the 32-bit RNG seed/state pair at `0x4584:0x4586` and forces the low word odd.
|
||||
- `rng_advance_state` updates the same 32-bit state with a simple multiply/add step.
|
||||
- `rng_next_modulo` advances the RNG state and returns the result modulo the requested bound, or `0` when the bound is zero.
|
||||
- `seg091_func_00fd` shares runtime flag `0x44a4` with `runtime_init_or_abort`; if the flag is clear it sets it and dispatches through an unresolved far thunk.
|
||||
- `seg091_func_014d` shares flag `0x44a4`; it checks an optional long argument against the global context/cookie at `0x45a6`, zeroes the pointed byte when the argument is null, then dispatches through an unresolved far thunk.
|
||||
|
||||
---
|
||||
|
||||
## Raw 0x4588 Runtime Callback Lifecycle Batch
|
||||
|
||||
New conservative runtime-callback lifecycle renames (direct analysis):
|
||||
- `000a:4913` = `runtime_callback_object_init_once`
|
||||
- `000a:4a56` = `runtime_callback_object_teardown_once`
|
||||
- `0009:b1c3` = `runtime_callback_object_phase_finalize`
|
||||
|
||||
Boundary repair applied with MCP edit-plan API:
|
||||
- Rebuilt `000a:b988` as `sprite_node_get_or_traverse` with full body `000a:b988-000a:bab5`.
|
||||
|
||||
Verified callback-object behavior:
|
||||
- `runtime_callback_object_init_once` sets one-time guard `0x4594`, snapshots state words (`0x458c`/`0x4590`) via `video_bios_state_snapshot`, installs the object FAR pointer at `0x4588`, and ensures fallback buffer allocation at `0x45a6`.
|
||||
- `runtime_callback_object_teardown_once` sets one-time guard `0x4595`, clears `0x4588`, conditionally emits vtable `+0x0c` callback when current/previous state differ, then calls vtable `+0x04` release path.
|
||||
- `runtime_callback_object_phase_finalize` invokes vtable `+0x08` twice and sweeps table entries via `allocator_head_finalize_sweep`.
|
||||
- Large caller `FUN_000d_9afd` contains both additional vtable `+0x0c` callsites (`000d:9d5e` and `000d:a3b7`) and remains the best next target for concrete subsystem naming.
|
||||
|
||||
## Raw 0x4588 Follow-up Batch (allocator/video helper clarification)
|
||||
|
||||
New conservative helper renames:
|
||||
- `0009:a961` = `allocator_head_finalize_sweep`
|
||||
- `000a:4a1f` = `video_bios_state_snapshot`
|
||||
|
||||
Verified behavior:
|
||||
- `allocator_head_finalize_sweep` performs per-head chain compaction/finalize work over allocator table entries used by `runtime_callback_object_phase_finalize`.
|
||||
- `video_bios_state_snapshot` executes BIOS video interrupts (`INT 10h` with `AX=4F03` and `AX=1130,BH=3`) and returns packed state in `DX:AX`; callers store/compare this pair around callback emissions.
|
||||
|
||||
## Raw 0x4588 Follow-up Batch 2 (cleanup + mode-state wrapper)
|
||||
|
||||
New conservative structural renames:
|
||||
- `000a:4972` = `video_mode_set_and_record_state`
|
||||
- `000d:9afd` = `entity_cleanup_resources_and_dispatch`
|
||||
|
||||
Verified behavior:
|
||||
- `video_mode_set_and_record_state` stores requested mode/state to `0x4590`, handles VBE-style mode values (`0x101`/`0x103`/`0x105`) via helper checks, and falls back to `INT 10h` mode path for other values.
|
||||
- `entity_cleanup_resources_and_dispatch` is a large teardown/finalize path for an entity-like object: it clears flags, frees multiple owned buffers/palette handles, performs conditional callback dispatch through `0x4588` vtable `+0x0c`, then destroys object word-list structures.
|
||||
|
||||
## Raw 0x4588 Follow-up Batch 3 (cleanup-callee helper classification)
|
||||
|
||||
New conservative helper renames:
|
||||
- `0009:7853` = `palette_buffer_alloc_and_init_256`
|
||||
- `0009:1c3a` = `file_handle_alloc_init_and_open`
|
||||
- `0009:1d6a` = `file_handle_open_with_mode`
|
||||
- `0009:8d7b` = `surface_release_internal`
|
||||
- `0009:8e0a` = `surface_release_and_maybe_free`
|
||||
- `000d:9231` = `sprite_redraw_global_if_active`
|
||||
|
||||
Verified behavior:
|
||||
- `palette_buffer_alloc_and_init_256` ensures a caller-provided far buffer exists, allocates/initializes a `0x100`-entry palette/work block, and fills it from static table data.
|
||||
- `file_handle_alloc_init_and_open` allocates a handle structure on demand, seeds sentinels, then delegates to `file_handle_open_with_mode`.
|
||||
- `file_handle_open_with_mode` performs path/open initialization with optional pre-delete behavior and stores DOS open result metadata into the handle structure.
|
||||
- `surface_release_and_maybe_free` wraps `surface_release_internal` and conditionally frees memory when `(flags & 1) != 0`.
|
||||
- `sprite_redraw_global_if_active` redraws the global sprite/object pointer at `0x4f38` only when the global gate byte `0x68e5` is enabled.
|
||||
|
||||
## Raw 0x4588 Follow-up Batch 4 (function-object recovery around `000d:7e00`)
|
||||
|
||||
Missing function objects recovered:
|
||||
- `000d:7e00-000d:8077` created and renamed to `entity_dispatch_entry_init_runtime_state`
|
||||
- `000d:8078-000d:819f` renamed to `entity_dispatch_entry_release_runtime_state`
|
||||
- `0003:a880-0003:a896` created as `FUN_0003_a880` (arithmetic helper)
|
||||
- `0003:b8e2-0003:bb39` created and renamed to `far_buffer_alloc_with_mode_flags`
|
||||
|
||||
Verified behavior:
|
||||
- `entity_dispatch_entry_init_runtime_state` initializes runtime fields (`+0x41/+0x42/+0x44`), clears and allocates paired work/palette buffers (`+0x46/+0x48` and `+0x4a/+0x4c`), applies event/setup calls through seg061 helpers, then finalizes activation.
|
||||
- `entity_dispatch_entry_release_runtime_state` frees the same paired buffers, propagates active-state changes via global `0x6828`, and destroys embedded word-list members.
|
||||
- `far_buffer_alloc_with_mode_flags` is a low-level far-buffer utility that allocates/reuses a destination pointer and dispatches mode-dependent copy/fill behavior via an internal flag table.
|
||||
|
||||
## Raw 0x4588 Follow-up Batch 5 (seg061/064/076 helper stabilization)
|
||||
|
||||
New conservative helper renames:
|
||||
- `0009:6ec7` = `vga_palette_read`
|
||||
- `0008:d3ba` = `timer_entity_enable_wrapper`
|
||||
|
||||
Additional evidence-preserving decompiler comments added on: `0008:eb43`, `0008:ebe7`, `0008:eac8`, `0008:ec23`.
|
||||
|
||||
Verified behavior:
|
||||
- `vga_palette_read` mirrors `vga_palette_write` and reads DAC entries through ports `0x3c7/0x3c9` into a far palette buffer.
|
||||
- `timer_entity_enable_wrapper` is a thin forwarder to `timer_entity_enable` and is widely used in lifecycle/setup paths.
|
||||
- The seg064 gate helpers (`0008:eb43`/`0008:ebe7`/`0008:ec23`) control one-shot global flag transitions at `0x3b72/0x3b73`, then dispatch via unresolved thunk paths.
|
||||
|
||||
Callback callsite clarification:
|
||||
- `entity_cleanup_resources_and_dispatch` vtable `+0x0c` call at `000d:9d5e` passes object fields `+0x12d/+0x12f`.
|
||||
- Matching vtable `+0x0c` call at `000d:a3b7` passes object fields `+0x74f/+0x751`.
|
||||
|
||||
## Raw 0x4588 Follow-up Batch 6 (constructor lane naming + callback globals)
|
||||
|
||||
New conservative helper renames:
|
||||
- `0008:d27e` = `entity_set_update_period_and_reschedule`
|
||||
- `0009:7905` = `palette_buffer_alloc_copy_from_source`
|
||||
|
||||
Verified behavior:
|
||||
- `entity_set_update_period_and_reschedule` stores timing/update-period fields (`+0x36/+0x38/+0x3a`), clears deferred fields (`+0x3c/+0x3e`), then triggers timer recompute/reschedule helpers.
|
||||
- `palette_buffer_alloc_copy_from_source` allocates/replaces destination palette buffer metadata and copies RGB triplets from a source far pointer (`entry_count * 3` bytes).
|
||||
|
||||
Global data labels promoted:
|
||||
- `g_active_dispatch_entry_farptr` at `0x6828`
|
||||
- callback-state/object globals at `0x4588/0x458c/0x4590/0x4594/0x4595/0x45a6`
|
||||
- dispatch callback-table pointer at `0x39ca`
|
||||
|
||||
---
|
||||
|
||||
## Raw 0007 Gameplay Helper Batch (entity/tile aux state)
|
||||
|
||||
New conservative gameplay-side helper renames (direct analysis from field writes and call structure):
|
||||
- `0007:85f6` = `entity_sync_tile_aux_state`
|
||||
- `0007:8865` = `entity_sync_tile_aux_if_linked`
|
||||
- `0007:8709` = `entity_mark_dirty_and_sync_tile_aux`
|
||||
|
||||
Verified behavior:
|
||||
- `entity_sync_tile_aux_state` reads entity tile index at `+0x4`, toggles bit `0x04` in tile record `+0x59` based on entity byte `+0x54`, and copies entity word `+0x55` into tile record `+0x0d`.
|
||||
- `entity_sync_tile_aux_if_linked` only performs the sync when entity link/pointer `+0x50/+0x52` is non-null.
|
||||
- `entity_mark_dirty_and_sync_tile_aux` calls the linked-sync helper, sets entity flag bit `0x04` at `+0x42`, then calls through `0000:ffff` with args `(SS:&tile_index, entity[+0x57])` — annotated as `entity_tile_type_notify(tile_index_ptr, type_byte)`.
|
||||
|
||||
New entity field found: `entity[+0x57]` (byte) = entity type/class byte (passed to tile-type notification).
|
||||
|
||||
## Raw 0007 Gameplay Helper Batch (facing/direction)
|
||||
|
||||
New gameplay helper rename:
|
||||
- `0007:8bd9` = `entity_set_facing_direction`
|
||||
|
||||
Verified behavior:
|
||||
- Updates entity facing byte `+0x38` using incoming direction/event code values (notably `0x10/0x11/0x12`) with parity-aware adjustment.
|
||||
- Uses entity flags at `+0x4d` to select increment/decrement behavior for clockwise/counterclockwise facing updates.
|
||||
|
||||
## Raw 0007 Gameplay Helper Deep Dive: `snap_entity_to_ground`
|
||||
|
||||
- Function: `0007:2207` = `snap_entity_to_ground`
|
||||
- Caller in gameplay flow: `spawn_entity_checked` (`0007:22de`, call at `0007:2366`)
|
||||
- Purpose (high confidence): pre-spawn position adjustment for a small allow-list of entity types so they land on valid ground/height context before normal spawn allocation.
|
||||
|
||||
#### Variable replacement pass (applied in Ghidra)
|
||||
|
||||
- `param_1` → `entity_type`
|
||||
- `local_48` → `snap_entity_type_table`
|
||||
- `local_34` → `snap_dispatch_seg_table`
|
||||
- `local_20` → `snap_dispatch_off_table`
|
||||
- `local_c` → `entity_type_cursor`
|
||||
- `local_4` → `dispatch_index`
|
||||
|
||||
#### What the function does structurally
|
||||
|
||||
1. Copies three 10-entry static tables into stack-local scratch buffers: from `0x2910` (off), `0x2924` (seg), `0x2938` (entity type IDs).
|
||||
2. Performs a linear scan across 10 entity IDs in `snap_entity_type_table`.
|
||||
3. If `entity_type` matches an entry, it calls into the real callee (`world_to_screen_coords` at `0004:e7bd` after the far-call repair pass) with spawn coordinate-derived arguments.
|
||||
4. If no table entry matches, it exits without modifying the request.
|
||||
|
||||
#### Entity ID allow-list
|
||||
|
||||
Exactly 10 entity IDs: `0x31c`, `0x31f`, `0x320`, `0x321`, `0x322`, `0x323`, `0x324`, `0x325`, `0x326`, `0x327`.
|
||||
|
||||
#### Working pseudocode (behavioral)
|
||||
|
||||
```c
|
||||
void snap_entity_to_ground(entity_type, spawn_x, spawn_y, spawn_layer) {
|
||||
copy_10_words(local_off_table, DATA_2910);
|
||||
copy_10_words(local_seg_table, DATA_2924);
|
||||
copy_10_words(local_type_table, DATA_2938);
|
||||
|
||||
for (dispatch_index = 0; dispatch_index < 10; dispatch_index++) {
|
||||
if (local_type_table[dispatch_index] == entity_type) {
|
||||
// Repaired: CALLF 0004:e7bd = world_to_screen_coords
|
||||
call_thunk_with_spawn_context(spawn_x, spawn_y, ...);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Raw 0007 Gameplay Helper Follow-up: AI sweep + checked spawn path
|
||||
|
||||
### `spawn_entity_checked` (`0007:22de`) refinements
|
||||
|
||||
- Function signature expanded to 7 arguments: `entity_type`, `spawn_flags_a`, `spawn_flags_b`, `spawn_flags_c`, `spawn_x`, `spawn_y`, `spawn_layer_arg`
|
||||
- New comments added:
|
||||
- `0007:22f8`: allow-list gate for ground-snap mode (`0x27fe != 0` + entity IDs `0x31c..0x327` subset)
|
||||
- `0007:2366`: explicit `snap_entity_to_ground(entity_type, &spawn_x, &spawn_y, &spawn_layer)` handoff
|
||||
- `0007:247e`: fallback path that calls core `entity_spawn` with original arguments
|
||||
|
||||
### `entity_ai_update_loop` (`0007:0fb6`) structural recovery
|
||||
|
||||
- Reads player entity FAR pointer from global `0x2de4`.
|
||||
- Copies player world position fields (`+0x40`, `+0x42`) into globals `0x27e7` / `0x27e9` (AI focus position cache).
|
||||
- Iterates entity IDs from `2` through `255` and dispatches per-entity processing through two sequential thunked calls per entity.
|
||||
- After the NE far-call repair pass, the first call at `0007:101c` now decompiles directly as `entity_resolve_slot_ptr` (`0005:0466`) instead of `CALLF 0000:ffff`.
|
||||
|
||||
Repaired call chain helpers now exposed:
|
||||
- `0005:42c8` = `entity_projected_bbox_overlaps_viewport` — projects entity slot via `world_to_screen_coords`, derives sprite/flag context, tests against the active viewport rectangle at global `0x4014`.
|
||||
- `0005:3cf5` = `entity_class_has_flag2000` — class-word flag test over `entity_get_class_word(slot) & 0x2000`.
|
||||
- `0005:ff2d` = `entity_class_get_flag8` — returns bit `0x08` from entity-class detail byte `0x7e1e[type*0x79 + 0x59]`.
|
||||
- `0006:1305` = `entity_class_get_word_02` — raw accessor for word `+0x02` in the `0x7e1e` class-detail record.
|
||||
- `0006:0ca4` = `entity_class_get_word_0a` — raw accessor for word `+0x0a` in the same class-detail record.
|
||||
- `0006:11a1` = `entity_class_clear_flag8_and_dispatch` — clears bit `0x08` in class-detail byte `+0x59`, then performs follow-up entity/type checks and callback dispatch.
|
||||
|
||||
Dispatch call sites annotated:
|
||||
- `0007:101c`: `entity_slot_fetch(SS:&entity_id)` — resolves entity slot/pointer from loop ID
|
||||
- `0007:1093`: `entity_tick_dispatch(SS:&entity_id, g_0x27c8)` — per-entity AI tick with global `0x27c8` mode/context word
|
||||
|
||||
Global `0x27c8` confirmed as the current targeted/current entity handle.
|
||||
|
||||
## Raw 0007 Gameplay Logic: animation / range / command globals
|
||||
|
||||
### `is_player_in_range` (`0007:0f79`)
|
||||
|
||||
- Prototype: `int is_player_in_range(int entity_x, int entity_y)`
|
||||
- Reads player world position from `g_player_entity_farptr` (`0x2de4`, fields `+0x40` (x) and `+0x42` (y)`).
|
||||
- Computes unsigned delta from AI focus globals `g_ai_focus_pos_x` (`0x27e7`) / `g_ai_focus_pos_y` (`0x27e9`).
|
||||
- Returns 1 if player Y delta == 0 AND player X delta < 0xF0 (240 world units), else 0.
|
||||
|
||||
### `entity_animation_frame_update` (`0007:26e2`)
|
||||
|
||||
- Prototype: `void entity_animation_frame_update(int *entity_ptr)`
|
||||
- Key globals: `g_anim_tick_counter` (`0x3a00`), `g_anim_tick_overdrive_flag` (`0x3a02`), `g_speed_double_flag` (`0x27fd`).
|
||||
- Entity struct fields confirmed:
|
||||
- `[0x1b]` (byte `+0x36`) = frame_min; `[0x1c]` (byte `+0x38`) = frame_max; `[0x1d]` (byte `+0x3a`) = current_frame
|
||||
- `[0x1e]` (byte `+0x3c`) = loop_flag (0 = animation disabled)
|
||||
- `[0x1f]` (byte `+0x3e`) = reverse_direction_flag / double-speed flag
|
||||
- `+0x3f` (word) = completion handle/sentinel (`-1` = none, `0x2802` = player entity)
|
||||
- `+0x00` (far ptr) = vtable pointer
|
||||
|
||||
Disassembly comments added:
|
||||
- `0007:27dc`: `entity_completion_callback(handle)` — fires when loop wraps; skips player handle
|
||||
- `0007:27fd`: vtable indirect `entity->vtable[+8](entity, 0, 0)` — `on_loop_complete` virtual method
|
||||
- `0007:281e`: `notify_frame_progress(handle, current_frame)` — per-frame notification
|
||||
- `0007:2851`: `entity_sprite_advance(entity_far_ptr, advance_amount, 0)`
|
||||
|
||||
### `entity_command_dispatch` (`0007:0990`)
|
||||
|
||||
- Prototype: `void entity_command_dispatch(int entity_handle, int target_seg, int command_type, byte absolute_pos_flag)`
|
||||
- When `absolute_pos_flag == 0`: computes player-relative delta using `g_player_entity_farptr` and stores result into `g_player_delta_x` (`0x27f5`) and `g_player_delta_y` (`0x27f7`).
|
||||
- Clears cached origin globals `g_cmd_effect_origin_x` (`0x27f1`) and `g_cmd_effect_origin_y` (`0x27f3`) after use.
|
||||
|
||||
### Enemy spawn helper cluster
|
||||
|
||||
Existing raw names align with prior standalone seg001 notes:
|
||||
- `0007:505d` = `map_find_spawn_point` (`seg001 + 0x6aed`)
|
||||
- `0007:5259` = `enemy_spawn_with_target` (`seg001 + 0x6ce9`)
|
||||
- `0007:5275` = `enemy_spawn_no_target` (`seg001 + 0x6d05`)
|
||||
- `0007:5291` = `enemy_spawn_at_position` (`seg001 + 0x6d21`)
|
||||
|
||||
### Global map additions (renamed in Ghidra)
|
||||
|
||||
| Address | Name | Evidence |
|
||||
|---------|------|---------|
|
||||
| `0x27c8` | `g_current_entity_handle` | Compared directly by `entity_is_type_match`; captured by `entity_ai_update_loop`, `map_find_spawn_point`, and `enemy_spawn_at_position` |
|
||||
| `0x2de4` | `g_player_entity_farptr` | FAR ptr to player entity; `+0x40`/`+0x42` are world X/Y |
|
||||
| `0x27e7` | `g_ai_focus_pos_x` | Set by `entity_ai_update_loop` from player entity `+0x40` |
|
||||
| `0x27e9` | `g_ai_focus_pos_y` | Set by `entity_ai_update_loop` from player entity `+0x42` |
|
||||
| `0x27f1` | `g_cmd_effect_origin_x` | Cached effect origin X, cleared after delta in `entity_command_dispatch` |
|
||||
| `0x27f3` | `g_cmd_effect_origin_y` | Cached effect origin Y |
|
||||
| `0x27f5` | `g_player_delta_x` | Player X delta from last effect origin |
|
||||
| `0x27f7` | `g_player_delta_y` | Player Y delta from last effect origin |
|
||||
| `0x27fd` | `g_speed_double_flag` | 0 = normal, 1 = double speed animation |
|
||||
| `0x27fe` | `g_ground_snap_mode_flag` | Non-zero = ground-snap prepass active for placements |
|
||||
| `0x27d0` | `g_entity_update_max_id` | Max entity ID used by `entity_ai_update_loop` sweep |
|
||||
| `0x3a00` | `g_anim_tick_counter` | Animation tick counter for frame-advance step budget |
|
||||
| `0x3a02` | `g_anim_tick_overdrive_flag` | 0 = normal, non-zero = force max frame advance step |
|
||||
| `0x2802` | `g_player_entity_handle` | Player entity handle (used as sentinel in animation completion checks) |
|
||||
|
||||
---
|
||||
|
||||
## seg043 Standalone Boundary Recovery
|
||||
|
||||
Direct disassembly of `NE_segments/seg043_code_off_75A00_len_336F.bin` shows the first non-zero bytes at offset `0x0090`; offsets `0x0000..0x008f` are all zero.
|
||||
|
||||
First three clean 16-bit prologues:
|
||||
- `seg043:0090` → raw `0007:5a90`
|
||||
- `seg043:017a` → raw `0007:5b7a`
|
||||
- `seg043:021c` → raw `0007:5c1c`
|
||||
|
||||
Repair status: applied in `CRUSADER-RAW.EXE` via the local PyGhidra toolkit:
|
||||
- `0007:5a90` = `seg043_func_0090` with body `0007:5a90..0007:5b79`
|
||||
- `0007:5b7a` = `entity_set_at_target_update_facing` with body `0007:5b7a..0007:5c1b`
|
||||
- `0007:5c1c` = `seg043_func_021c` with body `0007:5c1c..0007:5c80`
|
||||
|
||||
Verified behavior:
|
||||
- `entity_set_at_target_update_facing` sets entity `+0x3a` to 1, calls `entity_set_facing_direction`, clears class-detail bit `0x10` at `0x7e1e[type*0x79+0x59]`, then continues into downstream dispatch.
|
||||
- `0007:5a90` allocates an object when the incoming far pointer is null (literal `0x98`), runs a far setup helper using DS:`0x4b48..0x4b4e` and the second incoming far pointer, writes `0x4c13` at the object base, calls `entity_set_at_target_update_facing`.
|
||||
- `0007:5c1c` optionally calls a virtual method through `[object->vtable + 0x4c]` when `object+0x44/+0x46` is non-null, then dispatches one or two downstream far helpers using `object+0x48`.
|
||||
|
||||
Additional resolved call targets inside the missing seg043 block (from relocation data):
|
||||
- `0007:5a8a` → `entity_set_event_type_checked`
|
||||
- `0007:5a98` → `FUN_0008_cc01` (timer-related flag/event helper)
|
||||
- `0007:5b36` → `entity_get_type_word`
|
||||
- `0007:5b44` → `saveslot_read_entry_flags`
|
||||
- `0007:5bb8` → `entity_is_type_match`
|
||||
- `0007:5c49` → `entity_class_get_flag20`
|
||||
- `0007:5c8b` → `mem_alloc_far`
|
||||
|
||||
## Additional Raw 0007 Helpers
|
||||
|
||||
### Entity Class Flag Helper
|
||||
- `0006:02cc` = `entity_class_get_flag20` — Returns `((class_detail[type*0x79 + 0x59] & 0x20) >> 5)`.
|
||||
|
||||
### Animation Start Frame Helper
|
||||
- `0007:71b2` = `entity_set_anim_start_frame_from_flags` — Reads entity `+0x4b` flags. If bit 1 set: uses type table `+0x59 & 4` (attack active) to select last frame (`+0x39 - 1`), zero, or half-frame (`+0x39 >> 1`). Writes computed value to type table `+0x10`.
|
||||
|
||||
### Combat Helper
|
||||
- `0007:894b` = `entity_check_attack_flags_and_dispatch` — Guards on entity `+0x4b` bit 1 AND target object `+5` bits `0x1c`. If both set: dispatches thunk attack event.
|
||||
|
||||
### Vtable Dispatch Helpers
|
||||
- `0007:8920` = `entity_call_vtable_slot0c` — Calls `(*param_1)[vtable+0xc]()`.
|
||||
- `0007:8cb8` = `entity_call_vtable_slot08` — Calls `(*param_1)[vtable+0x8]()`.
|
||||
- `0007:ccf1` = `entity_call_vtable_slot28` — Calls `(*param_1)[vtable+0x28]()`.
|
||||
|
||||
### Active Flag / Counter
|
||||
- `0007:8854` = `entity_set_active_flag` — Sets entity `+0x40 = 1` (active); increments global `0x2800`.
|
||||
|
||||
### Dispatch Table Lookup
|
||||
- `0007:8508` = `entity_table_lookup_and_dispatch` — Searches 1-entry table at `0x2b46` for `(param_3, param_4)` key pair; on match, calls the entry's function pointer at `[2]`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue