#include "../tdkpin_game_assets.h" #include #include static uint8_t g_dgroup[0x5000]; static uint8_t g_window_bytes[0x0c00]; HINSTANCE16 g_win16_instance; static Win16FarPtr g_window; static uint16_t g_dat_ids[40]; static unsigned g_dat_count; static uint16_t g_bitmap_ids[8]; static unsigned g_bitmap_count; static uint8_t g_stages[40]; static unsigned g_stage_count; static int32_t g_drawn_scores[8]; static unsigned g_draw_score_count; static unsigned g_select_palette_calls; static unsigned g_unrealize_calls; static unsigned g_realize_calls; static unsigned g_drain_calls; static unsigned g_sound_calls; static unsigned g_create_dc_calls; static unsigned g_create_bitmap_calls; static unsigned g_select_object_calls; static unsigned g_blit_calls; static unsigned g_delete_object_calls; static unsigned g_delete_dc_calls; static unsigned g_client_rect_calls; static unsigned g_get_dc_calls; static unsigned g_release_dc_calls; static unsigned g_cursor_calls; static unsigned g_status_calls; static uint8_t g_status_player; static Win16FarPtr dgroup_at(uint16_t offset) { return win16_make_far_pointer(0x5000, offset); } static void reset_calls(void) { g_dat_count = 0; g_bitmap_count = 0; g_stage_count = 0; g_draw_score_count = 0; g_select_palette_calls = 0; g_unrealize_calls = 0; g_realize_calls = 0; g_drain_calls = 0; g_sound_calls = 0; g_create_dc_calls = 0; g_create_bitmap_calls = 0; g_select_object_calls = 0; g_blit_calls = 0; g_delete_object_calls = 0; g_delete_dc_calls = 0; g_client_rect_calls = 0; g_get_dc_calls = 0; g_release_dc_calls = 0; g_cursor_calls = 0; g_status_calls = 0; g_status_player = 0; } HPALETTE16 SelectPalette16( HDC16 dc, HPALETTE16 palette, BOOL16 force_background) { assert(dc == 0x1111 && force_background == 0); g_select_palette_calls++; if (g_select_palette_calls == 1) { assert(palette == 0x2222); return 0x3333; } assert(palette == 0x3333); return 0x2222; } BOOL16 UnrealizeObject16(HGDIOBJ16 object) { assert(object == 0x2222); g_unrealize_calls++; return 1; } UINT16 RealizePalette16(HDC16 dc) { assert(dc == 0x1111); g_realize_calls++; return 256; } void tdkpin_drain_messages_except_input(void) { g_drain_calls++; } HBITMAP16 tdkpin_load_bitmap_resource( Win16FarPtr resource_name, HINSTANCE16 instance) { assert(instance == g_win16_instance); assert(win16_far_selector(resource_name) == 0); uint16_t id = win16_far_offset(resource_name); g_dat_ids[g_dat_count++] = id; return (HBITMAP16)(0x1000 + g_dat_count); } HDC16 CreateCompatibleDC16(HDC16 dc) { assert(dc == 0x1111); g_create_dc_calls++; return (HDC16)(0x4000 + g_create_dc_calls); } HGDIOBJ16 SelectObject16(HDC16 dc, HGDIOBJ16 object) { (void)dc; assert(object != 0); g_select_object_calls++; return (HGDIOBJ16)(0x5000 + g_select_object_calls); } BOOL16 BitBlt16( HDC16 destination, INT16 destination_x, INT16 destination_y, INT16 width, INT16 height, HDC16 source, INT16 source_x, INT16 source_y, uint32_t raster_operation) { assert(destination != 0 && source != 0); (void)destination_x; (void)destination_y; (void)width; (void)height; assert(source_x == 0 && source_y == 0); assert(raster_operation == 0x00cc0020 || raster_operation == 0x00c60088 || raster_operation == 0x00ee0086); if (raster_operation != 0x00cc0020) { assert(destination == 0x1111); assert(destination_x == 10 && destination_y == 20); assert(width == 29 && height == 39); } g_blit_calls++; return 1; } BOOL16 DeleteObject16(HGDIOBJ16 object) { assert(object != 0); g_delete_object_calls++; return 1; } void tdkpin_draw_loading_stage(Win16FarPtr caller_bp, uint8_t stage) { assert(win16_read_u16(win16_far_add_offset(caller_bp, 0x0e)) == 0x1111); if (stage >= 2) { assert(win16_read_u16(win16_far_add_offset(caller_bp, 0xfffe)) != 0); } g_stages[g_stage_count++] = stage; } void tdkpin_initialize_sounds(void) { g_sound_calls++; } HBITMAP16 LoadBitmap16(HINSTANCE16 instance, Win16FarPtr resource) { assert(instance == g_win16_instance && win16_far_selector(resource) == 0); uint16_t id = win16_far_offset(resource); g_bitmap_ids[g_bitmap_count++] = id; return (HBITMAP16)(0x2000 + id); } HCURSOR16 LoadCursor16(HINSTANCE16 instance, Win16FarPtr resource) { assert(instance == 0 && resource == win16_make_far_pointer(0, 0x7f00)); g_cursor_calls++; return 0x7777; } HCURSOR16 SetCursor16(HCURSOR16 cursor) { assert(cursor == 0x7777); return 0; } BOOL16 GetClientRect16(HWND16 window, Win16FarPtr rectangle) { assert(window == 0x8888); win16_write_u16(rectangle, 0, 0); win16_write_u16(rectangle, 2, 0); win16_write_u16(rectangle, 4, 640); win16_write_u16(rectangle, 6, 460); g_client_rect_calls++; return 1; } HBITMAP16 CreateCompatibleBitmap16(HDC16 dc, INT16 width, INT16 height) { assert(dc == 0x1111 && width == 641 && height == 461); g_create_bitmap_calls++; return 0x6666; } BOOL16 DeleteDC16(HDC16 dc) { assert(dc != 0); g_delete_dc_calls++; return 1; } HDC16 GetDC16(HWND16 window) { assert(window == 0x8888); g_get_dc_calls++; return 0x9999; } INT16 ReleaseDC16(HWND16 window, HDC16 dc) { assert(window == 0x8888 && dc == 0x9999); g_release_dc_calls++; return 1; } int32_t borland_multiply_i32(int32_t left, int32_t right) { return left * right; } void tdkpin_draw_score(HDC16 destination, int32_t value_or_player) { assert(destination == 0x9999); g_drawn_scores[g_draw_score_count++] = value_or_player; } void tdkpin_update_status_display(uint8_t player, HDC16 destination) { assert(destination == 0x9999); g_status_player = player; g_status_calls++; } static void assert_dat_ids(void) { static const uint16_t expected[] = { 995, 994, 998, 998, 400, 401, 402, 403, 404, 405, 406, 407, 701, 702, 703, 704, 801, 802, 803, 804, 805, 806, 807, 808, 809, 900, 997, 901, 600, }; assert(g_dat_count == sizeof(expected) / sizeof(expected[0])); assert(memcmp(g_dat_ids, expected, sizeof(expected)) == 0); } static void test_asset_loading(void) { reset_calls(); win16_write_u8(dgroup_at(0x07cc), 1); win16_write_u8(win16_far_add_offset(g_window, 0x0bd8), 1); tdkpin_initialize_assets_and_redraw(g_window, 0xbeef, 0xcafe, 0x1111); assert_dat_ids(); assert(g_bitmap_count == 3); assert(g_bitmap_ids[0] == 500 && g_bitmap_ids[1] == 102 && g_bitmap_ids[2] == 101); assert(g_stage_count == 34); for (unsigned index = 0; index < 34; index++) { assert(g_stages[index] == index + 2); } assert(g_sound_calls == 1 && g_drain_calls == 1); assert(g_select_palette_calls == 2 && g_cursor_calls == 1); assert(win16_read_u8(dgroup_at(0x07cc)) == 0); assert(win16_read_u16(win16_far_add_offset(g_window, 0x54)) == 0x2066); assert(win16_read_u16(win16_far_add_offset(g_window, 0x52)) == 0x2065); assert(g_get_dc_calls == 0); } static void test_redraw(void) { reset_calls(); win16_write_u8(dgroup_at(0x07cc), 0); win16_write_u8(win16_far_add_offset(g_window, 0x0bd8), 0); win16_write_u8(win16_far_add_offset(g_window, 0x0bde), 0); win16_write_u32(g_window, 0x0ba2, 10); win16_write_u32(g_window, 0x0ba6, 20); win16_write_u16(g_window, 0x54, 0xaaaa); win16_write_u16(g_window, 0x52, 0xbbbb); win16_write_u8(dgroup_at(0x07d1), 2); win16_write_u8(dgroup_at(0x09a3), 3); win16_write_u32(dgroup_at(0x098e), 8, 10); win16_write_u32(dgroup_at(0x097e), 4, 0); win16_write_u32(dgroup_at(0x097e), 8, 42); win16_write_u32(dgroup_at(0x097e), 12, (uint32_t)-1); win16_write_u32(dgroup_at(0x097e), 16, 5); tdkpin_initialize_assets_and_redraw(g_window, 1, 2, 0x1111); assert(g_dat_count == 0 && g_bitmap_count == 0 && g_stage_count == 0); assert(g_client_rect_calls == 2 && g_get_dc_calls == 1 && g_release_dc_calls == 1); assert(g_draw_score_count == 3); assert(g_drawn_scores[0] == 30 && g_drawn_scores[1] == 2 && g_drawn_scores[2] == 4); assert(g_status_calls == 1 && g_status_player == 2); assert(g_blit_calls == 5 && g_select_object_calls == 7); assert(win16_read_u8(dgroup_at(0x07cb)) == 1); assert(win16_read_u8(win16_far_add_offset(g_window, 0x0bd9)) == 0); assert(g_select_palette_calls == 2 && g_cursor_calls == 1); } static void test_already_redrawn_palette_behavior(void) { reset_calls(); win16_write_u8(dgroup_at(0x07cc), 0); win16_write_u8(win16_far_add_offset(g_window, 0x0bd8), 1); tdkpin_initialize_assets_and_redraw(g_window, 0, 0, 0x1111); assert(g_select_palette_calls == 1); assert(g_unrealize_calls == 1 && g_realize_calls == 1 && g_drain_calls == 1); assert(g_cursor_calls == 0 && g_get_dc_calls == 0); } int main(void) { uint8_t stack_marker; uintptr_t stack_base = (uintptr_t)&stack_marker - 0x8000; win16_reset_segment_bindings(); win16_bind_segment(0x5000, g_dgroup, sizeof(g_dgroup), true); win16_bind_segment(0x6000, g_window_bytes, sizeof(g_window_bytes), true); win16_bind_segment(0x7000, (void *)stack_base, 0x10000, true); win16_set_dgroup_selector(0x5000); g_window = win16_make_far_pointer(0x6000, 0); g_win16_instance = 0x4444; win16_write_u16(dgroup_at(0x444e), 0, 0x2222); win16_write_u16(dgroup_at(0x085b), 0, 0xaaaa); win16_write_u16(g_window, 4, 0x8888); test_asset_loading(); test_redraw(); test_already_redrawn_palette_behavior(); return 0; }