Files
tdkpin/original/reconstructed/tdkpin_asset_initializer.c
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
Replace the partial mechanics transcriptions with a separate, readable C11
reconstruction of the complete Win16 image while preserving the original raw
Ghidra export as immutable evidence. Cover all ordinary and overlapping entry
points, Borland runtime behavior, Win16 imports, segmented data, callbacks,
resources, indirect control flow, physics, rendering, persistence, and
startup/shutdown lifecycles.

Add deterministic extraction and audit tooling plus address-linked ledgers for
functions, imports, DGROUP ranges and objects, relocations, resources, and
callbacks. The final gate records zero raw, partial, restored, unknown,
blocked, or unclassified required units. Keep the semantic-fidelity boundary
explicit: the portable C is not claimed to reproduce a byte-identical Borland
NE build.

Add strict focused harnesses for every reconstructed C unit, exact resource
round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source
or Cargo metadata is changed in this phase.

Test Plan:
- `bash original/tools/test_reconstructed_c.sh` -- passed
- `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit
- `python3 original/tools/audit_reconstruction.py --require-complete` -- passed
- `git diff --cached --check` -- passed
- `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
2026-08-23 16:41:17 +02:00

279 lines
11 KiB
C

/* One-time TDKPIN asset loading and subsequent board redraw. */
#include "tdkpin_game_assets.h"
#include "tdkpin_arithmetic.h"
#include "tdkpin_message_pump.h"
#include "tdkpin_palette.h"
#include "tdkpin_render.h"
#include "tdkpin_sound.h"
enum {
DGROUP_INSTANCE = 0x06fe,
DGROUP_SCENE_READY = 0x07cb,
DGROUP_ASSETS_PENDING = 0x07cc,
DGROUP_CURRENT_PLAYER = 0x07d1,
DGROUP_BACKGROUND_BITMAP = 0x085b,
DGROUP_BACKGROUND_OVERLAY_B = 0x085d,
DGROUP_BACKGROUND_OVERLAY_A = 0x085f,
DGROUP_DIGIT_BITMAP = 0x0861,
DGROUP_CLAW_BITMAP = 0x0863,
DGROUP_BOARD_DECORATION_BITMAP = 0x0865,
DGROUP_DISPLAYED_STATUS_LEVEL = 0x086b,
DGROUP_SPRITE_BITMAPS = 0x430b,
DGROUP_STATUS_BITMAPS_BASE = 0x4319,
DGROUP_ITEM_BITMAPS_BASE = 0x4321,
DGROUP_PALETTE = 0x444e,
DGROUP_PLAYER_SCORE_INDEX_BASE = 0x097e,
DGROUP_SCORE_FACTOR_VALUES_BASE = 0x098e,
DGROUP_SCORE_FACTORS_BASE = 0x09a1,
WINDOW_HANDLE_OFFSET = 4,
WINDOW_MASK_BITMAP_OFFSET = 0x52,
WINDOW_IMAGE_BITMAP_OFFSET = 0x54,
WINDOW_TRANSIENT_1_OFFSET = 0x4d,
WINDOW_TRANSIENT_2_OFFSET = 0x4f,
WINDOW_X_VALUE_OFFSET = 0x0ba2,
WINDOW_Y_VALUE_OFFSET = 0x0ba6,
WINDOW_ALREADY_REDRAWN_OFFSET = 0x0bd8,
WINDOW_REDRAW_BUSY_OFFSET = 0x0bd9,
WINDOW_HIDE_OBJECT_OFFSET = 0x0bde,
WIN16_SRCCOPY = 0x00cc0020,
WIN16_MASK_ROP = 0x00c60088,
WIN16_IMAGE_ROP = 0x00ee0086,
WIN16_IDC_ARROW = 0x7f00,
};
static HBITMAP16 load_dat(uint16_t resource_id)
{
return tdkpin_load_bitmap_resource(
win16_make_far_pointer(0, resource_id), g_win16_instance);
}
static void write_dgroup_handle(uint16_t offset, HBITMAP16 bitmap)
{
win16_write_u16(win16_dgroup_pointer(offset), 0, bitmap);
}
static void draw_loading_stage(
Win16FarPtr progress_frame, uint8_t stage)
{
tdkpin_draw_loading_stage(progress_frame, stage);
}
/* 1000:53c5..5618 — one-time exact resource/handle publication sequence. */
static void load_all_assets(
HDC16 destination,
Win16FarPtr progress_frame)
{
HBITMAP16 splash = load_dat(995);
HDC16 splash_dc = CreateCompatibleDC16(destination);
HGDIOBJ16 previous_splash = SelectObject16(splash_dc, splash);
(void)BitBlt16(
destination, 0, 0, 640, 480,
splash_dc, 0, 0, WIN16_SRCCOPY);
(void)SelectObject16(splash_dc, previous_splash);
(void)DeleteObject16(splash_dc);
(void)DeleteObject16(splash);
HBITMAP16 loading_bitmap = load_dat(994);
win16_write_u16(progress_frame, 0xfffe, loading_bitmap);
draw_loading_stage(progress_frame, 2);
tdkpin_initialize_sounds();
draw_loading_stage(progress_frame, 3);
draw_loading_stage(progress_frame, 4);
write_dgroup_handle(DGROUP_BACKGROUND_OVERLAY_B, load_dat(998));
draw_loading_stage(progress_frame, 5);
write_dgroup_handle(DGROUP_BACKGROUND_BITMAP, load_dat(998));
draw_loading_stage(progress_frame, 6);
write_dgroup_handle(
DGROUP_DIGIT_BITMAP,
LoadBitmap16(g_win16_instance, win16_make_far_pointer(0, 500)));
for (uint16_t index = 0; index < 8; index++) {
draw_loading_stage(progress_frame, (uint8_t)(index + 7));
write_dgroup_handle(
(uint16_t)(DGROUP_SPRITE_BITMAPS + index * 2),
load_dat((uint16_t)(400 + index)));
}
for (uint16_t index = 1; index <= 4; index++) {
draw_loading_stage(progress_frame, (uint8_t)(index + 14));
write_dgroup_handle(
(uint16_t)(DGROUP_STATUS_BITMAPS_BASE + index * 2),
load_dat((uint16_t)(700 + index)));
}
for (uint16_t index = 1; index <= 9; index++) {
draw_loading_stage(progress_frame, (uint8_t)(index + 18));
write_dgroup_handle(
(uint16_t)(DGROUP_ITEM_BITMAPS_BASE + index * 2),
load_dat((uint16_t)(800 + index)));
}
(void)loading_bitmap;
}
static bool positive_i32_at(Win16FarPtr object, uint16_t offset)
{
return (int32_t)win16_read_u32(win16_far_add_offset(object, offset)) > 0;
}
/* 1000:5619..58e2 — transient board redraw and score/status publication. */
static void redraw_scene(
Win16FarPtr window,
HDC16 destination,
HPALETTE16 previous_palette)
{
if (win16_read_u8(
win16_far_add_offset(window, WINDOW_ALREADY_REDRAWN_OFFSET)) != 0) {
return;
}
win16_write_u8(
win16_far_add_offset(window, WINDOW_REDRAW_BUSY_OFFSET), 1);
HDC16 background_dc = CreateCompatibleDC16(destination);
HDC16 surface_dc = CreateCompatibleDC16(destination);
RECT16 rectangle;
(void)GetClientRect16(
win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET)),
win16_stack_pointer(&rectangle));
HBITMAP16 surface = CreateCompatibleBitmap16(
destination,
(INT16)(rectangle.right + 1),
(INT16)(rectangle.bottom + 1));
HGDIOBJ16 old_background = SelectObject16(
background_dc,
win16_read_u16(win16_dgroup_pointer(DGROUP_BACKGROUND_BITMAP)));
HGDIOBJ16 old_surface = SelectObject16(surface_dc, surface);
(void)BitBlt16(
surface_dc, 0, 0, rectangle.right, rectangle.bottom,
background_dc, 0, 0, WIN16_SRCCOPY);
(void)BitBlt16(
background_dc, 0, 0, rectangle.right, rectangle.bottom,
surface_dc, 0, 0, WIN16_SRCCOPY);
(void)BitBlt16(
destination, 0, 0, rectangle.right, rectangle.bottom,
surface_dc, 0, 0, WIN16_SRCCOPY);
(void)SelectObject16(surface_dc, old_surface);
(void)DeleteObject16(surface);
(void)DeleteDC16(surface_dc);
(void)SelectObject16(background_dc, old_background);
if (positive_i32_at(window, WINDOW_X_VALUE_OFFSET) &&
positive_i32_at(window, WINDOW_Y_VALUE_OFFSET) &&
win16_read_u8(
win16_far_add_offset(window, WINDOW_HIDE_OBJECT_OFFSET)) == 0) {
uint16_t x = win16_read_u16(
win16_far_add_offset(window, WINDOW_X_VALUE_OFFSET));
uint16_t y = win16_read_u16(
win16_far_add_offset(window, WINDOW_Y_VALUE_OFFSET));
uint16_t width = (uint16_t)(
win16_read_u32(win16_far_add_offset(window, WINDOW_X_VALUE_OFFSET)) + 19);
uint16_t height = (uint16_t)(
win16_read_u32(win16_far_add_offset(window, WINDOW_Y_VALUE_OFFSET)) + 19);
HGDIOBJ16 previous = SelectObject16(
background_dc,
win16_read_u16(win16_far_add_offset(
window, WINDOW_IMAGE_BITMAP_OFFSET)));
(void)BitBlt16(
destination, (INT16)x, (INT16)y, (INT16)width, (INT16)height,
background_dc, 0, 0, WIN16_MASK_ROP);
(void)SelectObject16(
background_dc,
win16_read_u16(win16_far_add_offset(
window, WINDOW_MASK_BITMAP_OFFSET)));
(void)BitBlt16(
destination, (INT16)x, (INT16)y, (INT16)width, (INT16)height,
background_dc, 0, 0, WIN16_IMAGE_ROP);
(void)SelectObject16(background_dc, previous);
}
(void)DeleteDC16(background_dc);
win16_write_u16(window, WINDOW_TRANSIENT_1_OFFSET, 0);
win16_write_u16(window, WINDOW_TRANSIENT_2_OFFSET, 0);
win16_write_u8(
win16_far_add_offset(window, WINDOW_REDRAW_BUSY_OFFSET), 0);
(void)SelectPalette16(destination, previous_palette, 0);
HCURSOR16 arrow = LoadCursor16(
0, win16_make_far_pointer(0, WIN16_IDC_ARROW));
(void)SetCursor16(arrow);
(void)GetClientRect16(
win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET)),
win16_stack_pointer(&rectangle));
HWND16 handle =
win16_read_u16(win16_far_add_offset(window, WINDOW_HANDLE_OFFSET));
HDC16 window_dc = GetDC16(handle);
uint8_t current_player = win16_read_u8(
win16_dgroup_pointer(DGROUP_CURRENT_PLAYER));
uint8_t factor = win16_read_u8(win16_dgroup_pointer(
(uint16_t)(DGROUP_SCORE_FACTORS_BASE + current_player)));
int32_t factor_value = (int32_t)win16_read_u32(win16_dgroup_pointer(
(uint16_t)(DGROUP_SCORE_FACTOR_VALUES_BASE + current_player * 4)));
tdkpin_draw_score(
window_dc, borland_multiply_i32(factor, factor_value));
for (uint16_t player = 1; player <= 4; player++) {
int32_t score = (int32_t)win16_read_u32(win16_dgroup_pointer(
(uint16_t)(DGROUP_PLAYER_SCORE_INDEX_BASE + player * 4)));
if (score > 0) {
tdkpin_draw_score(window_dc, player);
}
}
win16_write_u16(
win16_dgroup_pointer(DGROUP_DISPLAYED_STATUS_LEVEL), 0, 99);
tdkpin_update_status_display(current_player, window_dc);
(void)ReleaseDC16(handle, window_dc);
win16_write_u8(win16_dgroup_pointer(DGROUP_SCENE_READY), 1);
}
/*
* 1000:5390 — exact public entry. Two middle words are ABI-preserved but unused.
*/
void tdkpin_initialize_assets_and_redraw(
Win16FarPtr window,
uint16_t ignored_1,
uint16_t ignored_2,
HDC16 destination)
{
(void)ignored_1;
(void)ignored_2;
HPALETTE16 palette =
win16_read_u16(win16_dgroup_pointer(DGROUP_PALETTE));
HPALETTE16 previous_palette = SelectPalette16(destination, palette, 0);
(void)UnrealizeObject16(palette);
(void)RealizePalette16(destination);
tdkpin_drain_messages_except_input();
uint8_t progress_storage[64] = {0};
Win16FarPtr progress_frame =
win16_stack_pointer(progress_storage + 24);
win16_write_u16(progress_frame, 0x0e, destination);
if (win16_read_u8(
win16_dgroup_pointer(DGROUP_ASSETS_PENDING)) != 0) {
load_all_assets(destination, progress_frame);
HBITMAP16 loading_bitmap =
win16_read_u16(win16_far_add_offset(progress_frame, 0xfffe));
draw_loading_stage(progress_frame, 28);
win16_write_u16(
window, WINDOW_IMAGE_BITMAP_OFFSET,
LoadBitmap16(g_win16_instance, win16_make_far_pointer(0, 102)));
draw_loading_stage(progress_frame, 29);
write_dgroup_handle(DGROUP_CLAW_BITMAP, load_dat(900));
draw_loading_stage(progress_frame, 30);
win16_write_u16(
window, WINDOW_MASK_BITMAP_OFFSET,
LoadBitmap16(g_win16_instance, win16_make_far_pointer(0, 101)));
draw_loading_stage(progress_frame, 31);
write_dgroup_handle(DGROUP_BACKGROUND_OVERLAY_A, load_dat(997));
draw_loading_stage(progress_frame, 32);
write_dgroup_handle(DGROUP_BOARD_DECORATION_BITMAP, load_dat(901));
draw_loading_stage(progress_frame, 33);
write_dgroup_handle(0x0859, load_dat(600));
draw_loading_stage(progress_frame, 34);
win16_write_u8(win16_dgroup_pointer(DGROUP_ASSETS_PENDING), 0);
draw_loading_stage(progress_frame, 35);
(void)DeleteObject16(loading_bitmap);
(void)SelectPalette16(destination, previous_palette, 0);
HCURSOR16 arrow = LoadCursor16(
0, win16_make_far_pointer(0, WIN16_IDC_ARROW));
(void)SetCursor16(arrow);
}
redraw_scene(window, destination, previous_palette);
}