/* Complete game-window setup and collision/table construction at 1000:0270. */ #include "tdkpin_game_setup.h" #include "tdkpin_application.h" #include "tdkpin_command_line.h" #include "tdkpin_heap.h" #include "tdkpin_palette.h" #include "tdkpin_shortstrings.h" #include "tdkpin_strings.h" #include "tdkpin_system_timer.h" #include "tdkpin_window_placement.h" #include #include "tdkpin_game_setup_collision_data.inc" typedef struct { uint16_t word_0; uint16_t word_2; uint16_t word_4; uint16_t word_6; } SetupWordQuad; static const SetupWordQuad g_game_setup_word_quads[20] = { {0x0067, 0x0130, 0x0079, 0x0143}, {0x0077, 0x0118, 0x0089, 0x012b}, {0x0094, 0x0110, 0x00a6, 0x0123}, {0x00b1, 0x0118, 0x00c3, 0x012b}, {0x00c1, 0x012f, 0x00d3, 0x0142}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0000, 0x0014, 0x0000, 0x0014}, {0x0057, 0x0044, 0x0067, 0x0054}, {0x0069, 0x0029, 0x007b, 0x0039}, {0x008a, 0x0033, 0x009a, 0x0043}, {0x008a, 0x0053, 0x009a, 0x0063}, {0x006a, 0x005e, 0x007a, 0x006e}, {0x0009, 0x000e, 0x0019, 0x001e}, }; static void write_far(Win16FarPtr base, uint16_t offset, Win16FarPtr value) { win16_write_u32(base, offset, value); } static void fail_setup( Win16FarPtr window, Win16FarPtr text, HWND16 owner, bool close_window) { Win16FarPtr message_box = win16_read_far_pointer( win16_dgroup_pointer(0x0666), 0); (void)win16_call_message_box_far( message_box, owner, text, win16_dgroup_pointer(0x02aa), 0x2010); if (close_window && window != 0) { object_windows_close_if_allowed(window); } borland_runtime_exit(0); } static void initialize_base_state(Win16FarPtr window) { win16_write_u8(win16_dgroup_pointer(0x07cf), 0); win16_write_u8(win16_dgroup_pointer(0x0874), 0); win16_write_u8(win16_dgroup_pointer(0x0875), 0); win16_write_u16(window, 0x41, 0); win16_write_u16(window, 0x43, 0); win16_write_u16(window, 0x45, 0); win16_write_u16(window, 0x47, 0); if (borland_heap_free_space() < UINT32_C(0x00400000)) { fail_setup(window, win16_dgroup_pointer(0x0260), 0, true); } object_windows_setup_window(window); HCURSOR16 cursor = LoadCursor16(0, win16_make_far_pointer(0, 0x7f02)); (void)SetCursor16(cursor); HWND16 handle = win16_read_u16(win16_far_add_offset(window, 4)); tdkpin_realize_nocollapse_palette(handle); tdkpin_load_palette_resource( win16_dgroup_pointer(0x4450), win16_make_far_pointer(0, 999), win16_read_u16(win16_dgroup_pointer(0x06fe))); tdkpin_create_palette_from_rgb_table(); win16_write_u8(win16_dgroup_pointer(0x07cc), 1); win16_write_u16(window, 0x4d, 0); win16_write_u16(window, 0x4f, 0); win16_write_u8(win16_far_add_offset(window, 0x51), 0); win16_write_u8(win16_far_add_offset(window, 0x0bd8), 0); win16_write_u32(win16_dgroup_pointer(0x0720), 0, GetTickCount16()); win16_write_u16(window, 0x0be3, 0); win16_write_u8(win16_dgroup_pointer(0x07c7), 0); win16_write_u8(win16_dgroup_pointer(0x07c8), 0); win16_write_u16(win16_dgroup_pointer(0x086d), 0, 10); win16_write_u16(win16_dgroup_pointer(0x086f), 0, 10); win16_write_u8(win16_dgroup_pointer(0x0873), 0); win16_write_u8(win16_dgroup_pointer(0x07ca), 0); win16_write_u8(win16_dgroup_pointer(0x07cb), 0); win16_write_u8(win16_dgroup_pointer(0x07c9), 1); win16_write_u32(window, 0x0bca, 0); win16_write_u8(win16_far_add_offset(window, 0x0bd9), 0); win16_write_u32(window, 0x0bc2, 325000); win16_write_u32(window, 0x0bc6, 413000); win16_write_u32(win16_dgroup_pointer(0x07d3), 0, 325000); win16_write_u32(win16_dgroup_pointer(0x07d7), 0, 413000); win16_write_u8(win16_far_add_offset(window, 0x0bdd), 0); win16_write_u8(win16_far_add_offset(window, 0x0bdf), 0); win16_write_u8(win16_far_add_offset(window, 0x0bdc), 0); win16_write_u8(win16_far_add_offset(window, 0x0be0), 0); win16_write_u8(win16_far_add_offset(window, 0x0be1), 0); win16_write_u8(win16_far_add_offset(window, 0x0be2), 0); win16_write_u8(win16_dgroup_pointer(0x07c5), 0); win16_write_u8(win16_far_add_offset(window, 0x0bde), 1); win16_write_u8(win16_dgroup_pointer(0x07d0), 0); win16_write_u8(win16_dgroup_pointer(0x07d1), 0); win16_write_u8(win16_far_add_offset(window, 0x61), 1); win16_write_u16(win16_dgroup_pointer(0x086b), 0, 99); win16_write_u16(win16_dgroup_pointer(0x0869), 0, 0); win16_write_u16(win16_dgroup_pointer(0x0876), 0, 0); win16_write_u16(win16_dgroup_pointer(0x0878), 0, 0); win16_write_u16(win16_dgroup_pointer(0x087a), 0, 0); win16_write_u16(win16_dgroup_pointer(0x087c), 0, 0); } static void initialize_player_defaults(Win16FarPtr window) { for (uint16_t item = 1; item <= 20; item++) { for (uint16_t player = 1; player <= 4; player++) { win16_write_u8( win16_far_add_offset(window, (uint16_t)( 0x047b + (player - 1u) * 0x14u + item)), 0); } } for (uint16_t player = 1; player <= 4; player++) { win16_write_u32( win16_dgroup_pointer((uint16_t)(0x097e + player * 4u)), 0, 0); win16_write_u32( win16_dgroup_pointer((uint16_t)(0x098e + player * 4u)), 0, 0); win16_write_u8( win16_dgroup_pointer((uint16_t)(0x09a1 + player)), 1); win16_write_u16( win16_dgroup_pointer((uint16_t)(0x09a4 + player * 2u)), 0, 0); win16_write_u16( win16_dgroup_pointer((uint16_t)(0x081f + player * 2u)), 0, 0xffff); win16_write_u8( win16_dgroup_pointer((uint16_t)(0x0816 + player)), 1); win16_write_u32( win16_dgroup_pointer((uint16_t)(0x0835 + player * 4u)), 0, 1); win16_write_u8( win16_dgroup_pointer((uint16_t)(0x081a + player)), 1); } static const uint32_t thresholds[4] = { 140000u, 650000u, 1300000u, 4000000u}; for (uint16_t index = 0; index < 4; index++) { win16_write_u32( win16_dgroup_pointer((uint16_t)(0x0829 + index * 4u)), 0, thresholds[index]); } } static void initialize_ball_projection(Win16FarPtr window) { win16_write_u32(window, 0x0baa, 0); win16_write_u32(window, 0x0bae, 0); win16_write_u16(window, 0x0bce, 0); win16_write_u16(window, 0x0bd0, 0); win16_write_u16(window, 0x0bd2, 0); int32_t pixel_x = borland_divide_i32(325500, 1000).quotient; int32_t pixel_y = borland_divide_i32(413500, 1000).quotient; win16_write_u32(window, 0x0ba2, (uint32_t)pixel_x); win16_write_u32(window, 0x0ba6, (uint32_t)pixel_y); win16_write_u32(window, 0x0bb2, 0); win16_write_u32(window, 0x0bb6, 0); win16_write_u8(win16_far_add_offset(window, 0x0bda), 0); win16_write_u8(win16_far_add_offset(window, 0x0bdb), 0); win16_write_u32(window, 0x0bd4, 0); } static void build_ini_file_name(Win16FarPtr result) { uint8_t parameter_bytes[256]; uint8_t module_name_bytes[103]; Win16FarPtr parameter = win16_stack_pointer(parameter_bytes); Win16FarPtr module_name = win16_stack_pointer(module_name_bytes); borland_parameter_string(0, parameter); (void)borland_short_to_c_string(module_name, parameter); borland_parameter_string(0, parameter); uint16_t dot = borland_short_position( win16_relocated_code_pointer(1, 0x026e), parameter); (void)borland_far_strncpy(result, module_name, dot); (void)borland_far_strcat(result, win16_dgroup_pointer(0x02c3)); } static void initialize_profile_and_timer(Win16FarPtr window) { uint8_t ini_file_bytes[101]; Win16FarPtr ini_file = win16_stack_pointer(ini_file_bytes); build_ini_file_name(ini_file); uint16_t language = GetPrivateProfileInt16( win16_dgroup_pointer(0x02c7), win16_dgroup_pointer(0x02d0), 1, ini_file); if (language < 1 || language > 5) { language = 1; } win16_write_u16(win16_dgroup_pointer(0x07cd), 0, language); uint16_t speed_word = GetPrivateProfileInt16( win16_dgroup_pointer(0x02c7), win16_dgroup_pointer(0x02d9), 3, ini_file); uint8_t speed = (uint8_t)speed_word; if (speed < 1 || speed > 5) { speed = 3; } win16_write_u8(win16_far_add_offset(window, 0x60), speed); win16_write_u32(window, 0x5a, 15); win16_write_u32(window, 0x56, 3800); static const uint16_t delay_by_speed[5] = {50, 40, 30, 20, 10}; static const uint16_t step_by_speed[5] = {5, 4, 3, 2, 1}; uint16_t delay = delay_by_speed[speed - 1u]; win16_write_u16( win16_dgroup_pointer(0x0871), 0, step_by_speed[speed - 1u]); Win16FarPtr timer = tdkpin_system_timer_construct( 0, 0x05c0, 0, 1, delay, win16_read_u16(win16_far_add_offset(window, 4))); write_far(window, 0x49, timer); if (timer == 0) { fail_setup(window, win16_dgroup_pointer(0x02df), win16_read_u16(win16_far_add_offset(window, 4)), false); } } static void initialize_collision_and_quad_tables(void) { for (uint16_t index = 0; index < 177; index++) { tdkpin_initialize_collision_record(&g_game_setup_collision_calls[index]); } for (uint16_t index = 0; index < 20; index++) { const SetupWordQuad *quad = &g_game_setup_word_quads[index]; tdkpin_set_word_quad( quad->word_6, quad->word_4, quad->word_2, quad->word_0, (uint16_t)(index + 1u)); } } static void initialize_collision_mirrors(Win16FarPtr window) { for (uint16_t id = 1; id <= 175; id++) { Win16FarPtr record = win16_dgroup_pointer((uint16_t)( 0x095b + id * 0x53u)); win16_write_u8( win16_far_add_offset(window, (uint16_t)(0x03cc + id)), win16_read_u8(win16_far_add_offset(record, 0x34))); win16_write_u16( window, (uint16_t)(0x0a42 + id * 2u), win16_read_u16(win16_far_add_offset(record, 0x43))); win16_write_u8(win16_far_add_offset(window, (uint16_t)(0x61 + id)), 0); } } /* 1000:0270 -- complete TDKPIN game-window setup. */ void tdkpin_setup_game_window(Win16FarPtr window) { initialize_base_state(window); initialize_player_defaults(window); initialize_ball_projection(window); initialize_profile_and_timer(window); initialize_collision_and_quad_tables(); initialize_collision_mirrors(window); }