#include "../tdkpin_turn_state.h" #include #include uint8_t g_player_count; uint8_t g_current_player; uint8_t g_gameplay_transition_pending; int32_t g_ball_x_milli; int32_t g_ball_y_milli; static uint8_t g_stack[0x400]; static uint8_t g_object[0x0c00]; static uint8_t g_dgroup[0x5000]; static Win16FarPtr g_receiver; static unsigned g_restore_previous_calls; static unsigned g_restore_record_b_calls; static unsigned g_dynamic_record_calls; static unsigned g_sound_calls; static unsigned g_load_highscores_calls; static unsigned g_insert_score_calls; static unsigned g_transition_calls; static unsigned g_show_highscore_calls; static unsigned g_collision_refresh_calls; static unsigned g_item_refresh_calls; static unsigned g_restore_item_calls; static unsigned g_draw_item_calls; static unsigned g_status_calls; static unsigned g_redraw_calls; static unsigned g_reset_ball_calls; static unsigned g_restore_b_calls; static unsigned g_present_calls; static unsigned g_marker_refresh_calls; static unsigned g_get_dc_calls; static unsigned g_release_dc_calls; static uint16_t g_last_item_count; static uint8_t g_last_status_player; void tdkpin_restore_previous_ball_region( uint16_t caller_bp, uint8_t suppress_present) { assert(caller_bp == 0x0100 && suppress_present == 0); g_restore_previous_calls++; } void tdkpin_restore_record_b(uint16_t caller_bp, uint16_t id) { assert(caller_bp == 0x0100 && id == 1020); g_restore_record_b_calls++; } void tdkpin_update_dynamic_ball_record( uint16_t ignored_static_link, int32_t displacement) { assert(ignored_static_link == 0x0100 && displacement == 1); g_dynamic_record_calls++; } BorlandReal48 borland_i32_to_real48(int32_t value) { assert(value == 1000); return (BorlandReal48){{0x81, 1, 2, 3, 4, 5}}; } BorlandReal48 borland_real48_multiply( BorlandReal48 left, BorlandReal48 right) { static const uint8_t expected_left[6] = {0x81, 1, 2, 3, 4, 5}; static const uint8_t expected_right[6] = { 0x80, 0xcd, 0xcc, 0xcc, 0xcc, 0x4c}; assert(memcmp(left.bytes, expected_left, 6) == 0); assert(memcmp(right.bytes, expected_right, 6) == 0); return (BorlandReal48){{0x82, 6, 7, 8, 9, 10}}; } int32_t borland_real48_round_to_i32(BorlandReal48 value) { static const uint8_t expected[6] = {0x82, 6, 7, 8, 9, 10}; assert(memcmp(value.bytes, expected, 6) == 0); return 800; } void tdkpin_play_sound_if_not_tilted(uint16_t sound_number) { assert(sound_number == 8); g_sound_calls++; } void tdkpin_load_highscores(uint16_t ignored_static_link) { assert(ignored_static_link == 0x0100); g_load_highscores_calls++; } void tdkpin_insert_current_score(uint16_t caller_bp) { assert(caller_bp == 0x0100); g_insert_score_calls++; } void tdkpin_set_gameplay_transition_flags(uint16_t caller_bp) { assert(caller_bp == 0x0100); g_transition_calls++; } void tdkpin_show_highscore_windows(uint16_t caller_bp) { assert(caller_bp == 0x0100); g_show_highscore_calls++; } void tdkpin_refresh_collision_record(uint16_t caller_bp, uint16_t id) { assert(caller_bp == 0x0100); assert(id == g_collision_refresh_calls + 1); g_collision_refresh_calls++; } void tdkpin_refresh_player_item(uint16_t caller_bp, uint16_t item) { assert(caller_bp == 0x0100); assert(item == g_item_refresh_calls + 1); g_item_refresh_calls++; } void tdkpin_restore_record_or_item_a(uint16_t caller_bp, uint16_t id) { assert(caller_bp == 0x0100); assert(id == 1001 + g_restore_item_calls); g_restore_item_calls++; } HDC16 GetDC16(HWND16 window) { assert(window == 0x2222); g_get_dc_calls++; return 0x3333; } INT16 ReleaseDC16(HWND16 window, HDC16 dc) { assert(window == 0x2222 && dc == 0x3333); g_release_dc_calls++; return 1; } void tdkpin_draw_item_status(int16_t item, HDC16 dc) { assert(dc == 0x3333); g_last_item_count = (uint16_t)item; g_draw_item_calls++; } void tdkpin_update_status_display(uint8_t player, HDC16 dc) { assert(dc == 0x3333); g_last_status_player = player; g_status_calls++; } void tdkpin_redraw_all_players(uint16_t caller_bp) { assert(caller_bp == 0x0100); g_redraw_calls++; } void tdkpin_reset_ball_state(uint16_t caller_bp) { assert(caller_bp == 0x0100); g_reset_ball_calls++; } void tdkpin_restore_background_region_b( INT16 height, INT16 width, INT16 y, INT16 x, HDC16 dc) { assert(height == 20 && width == 148 && y == 243 && x == 84); assert(dc == 0x3333); g_restore_b_calls++; } void tdkpin_present_background_region( INT16 height, INT16 width, INT16 y, INT16 x, HDC16 dc) { assert(height == 20 && width == 148 && y == 243 && x == 84); assert(dc == 0x3333); g_present_calls++; } void tdkpin_refresh_player_progress_markers(uint16_t caller_bp) { assert(caller_bp == 0x0100); g_marker_refresh_calls++; } _Noreturn void win16_integer_divide_fault(void) { __builtin_trap(); } static void reset_counters(void) { g_restore_previous_calls = 0; g_restore_record_b_calls = 0; g_dynamic_record_calls = 0; g_sound_calls = 0; g_load_highscores_calls = 0; g_insert_score_calls = 0; g_transition_calls = 0; g_show_highscore_calls = 0; g_collision_refresh_calls = 0; g_item_refresh_calls = 0; g_restore_item_calls = 0; g_draw_item_calls = 0; g_status_calls = 0; g_redraw_calls = 0; g_reset_ball_calls = 0; g_restore_b_calls = 0; g_present_calls = 0; g_marker_refresh_calls = 0; g_get_dc_calls = 0; g_release_dc_calls = 0; g_last_item_count = 0; g_last_status_player = 0; } static void prepare_fixture(void) { memset(g_stack, 0, sizeof(g_stack)); memset(g_object, 0, sizeof(g_object)); memset(g_dgroup, 0, sizeof(g_dgroup)); win16_reset_segment_bindings(); win16_bind_segment(0x7000, g_stack, sizeof(g_stack), true); win16_bind_segment(0x7100, g_object, sizeof(g_object), true); win16_bind_segment(0x7200, g_dgroup, sizeof(g_dgroup), true); win16_set_dgroup_selector(0x7200); win16_set_stack_state(0x7000, 0); g_receiver = win16_make_far_pointer(0x7100, 0); win16_write_stack_u16(0x0106, win16_far_offset(g_receiver)); win16_write_stack_u16(0x0108, win16_far_selector(g_receiver)); win16_write_u16(g_receiver, 4, 0x2222); g_player_count = 3; g_current_player = 1; g_ball_x_milli = 0; g_ball_y_milli = 0; reset_counters(); } static Win16FarPtr record(uint16_t id) { return win16_dgroup_pointer((uint16_t)(0x095b + id * 0x53u)); } static void test_special_respawn(void) { prepare_fixture(); g_current_player = 2; win16_write_u16(win16_dgroup_pointer(0x399a), 0, 7); win16_write_u32(win16_dgroup_pointer(0x3969), 0, 0x11112222u); win16_write_u32(win16_dgroup_pointer(0x396d), 0, 0x33334444u); win16_write_u8(win16_far_add_offset(g_receiver, 0x04a3), 1); win16_write_u32(g_receiver, 0x56, 1000); win16_write_u32(g_receiver, 0x0bca, 0xaaaaaaaau); tdkpin_finish_ball_or_advance_player(0x0100); assert(g_restore_previous_calls == 1); assert(g_restore_record_b_calls == 1 && g_dynamic_record_calls == 1); assert((uint32_t)g_ball_x_milli == 0x11112222u); assert((uint32_t)g_ball_y_milli == 0x33334444u); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bc2)) == 0x11112222u); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bc6)) == 0x33334444u); assert(win16_read_u8(win16_far_add_offset(g_receiver, 0x04a3)) == 0); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0baa)) == 0); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bae)) == 800); assert(win16_read_u32(win16_far_add_offset(g_receiver, 0x0bca)) == 0); assert(win16_read_u16(win16_dgroup_pointer(0x399a)) == 0); assert(win16_read_u8(win16_dgroup_pointer(0x0875)) == 1); assert(win16_read_u8(win16_dgroup_pointer(0x41f9)) == 1); assert(win16_read_u8(win16_far_add_offset(g_receiver, 0x61)) == 1); assert(g_sound_calls == 0 && g_redraw_calls == 0); } static void seed_collision_and_player_three_mirrors(void) { for (uint16_t id = 1; id <= 175; id++) { win16_write_u8( win16_far_add_offset(record(id), 0x34), (uint8_t)(id & 1u)); win16_write_u16(record(id), 0x43, (uint16_t)(0x1000 + id)); win16_write_u8( win16_far_add_offset(g_receiver, (uint16_t)( 0x0061 + 3u * 0x00afu + id)), (uint8_t)(0x80u | (id & 1u))); win16_write_u16( g_receiver, (uint16_t)(0x036c + 3u * 0x015eu + id * 2u), (uint16_t)(0x2000 + id)); } } static void test_advance_to_live_player(void) { prepare_fixture(); win16_write_u8(win16_dgroup_pointer(0x0874), 1); win16_write_u16(win16_dgroup_pointer(0x0821), 0, 2); win16_write_u16(win16_dgroup_pointer(0x0823), 0, 0); win16_write_u16(win16_dgroup_pointer(0x0825), 0, 3); win16_write_u8(win16_dgroup_pointer(0x0819), 4); seed_collision_and_player_three_mirrors(); for (uint16_t item = 1; item <= 3; item++) { win16_write_u8(win16_far_add_offset( g_receiver, (uint16_t)(0x046c + 3u * 0x14u + item)), 1); } tdkpin_finish_ball_or_advance_player(0x0100); assert(g_sound_calls == 1 && g_restore_previous_calls == 1); assert(g_current_player == 3); for (uint16_t id = 1; id <= 175; id++) { assert(win16_read_u8(win16_far_add_offset( g_receiver, (uint16_t)(0x0061 + 0x00afu + id))) == (uint8_t)(id & 1u)); assert(win16_read_u16(win16_far_add_offset( g_receiver, (uint16_t)(0x036c + 0x015eu + id * 2u))) == (uint16_t)(0x1000 + id)); assert(win16_read_u8(win16_far_add_offset(record(id), 0x34)) == (uint8_t)(0x80u | (id & 1u))); assert(win16_read_u16(win16_far_add_offset(record(id), 0x43)) == (uint16_t)(0x2000 + id)); } assert(g_collision_refresh_calls == 175 && g_item_refresh_calls == 20); assert(g_restore_item_calls == 3); assert(g_draw_item_calls == 1 && g_last_item_count == 3); assert(g_status_calls == 1 && g_last_status_player == 3); assert(g_redraw_calls == 1 && g_reset_ball_calls == 1); assert(win16_read_u16(win16_dgroup_pointer(0x0825)) == 2); assert(g_restore_b_calls == 1 && g_present_calls == 1); assert(g_marker_refresh_calls == 1); assert(g_get_dc_calls == 2 && g_release_dc_calls == 2); } static void test_game_over_path(void) { prepare_fixture(); win16_write_u8(win16_dgroup_pointer(0x0874), 1); win16_write_u16(win16_dgroup_pointer(0x0821), 0, 0); win16_write_u16(win16_dgroup_pointer(0x0823), 0, 0); g_player_count = 2; tdkpin_finish_ball_or_advance_player(0x0100); assert(g_load_highscores_calls == 1 && g_insert_score_calls == 1); assert(g_current_player == 0 && g_transition_calls == 1); assert(g_show_highscore_calls == 1); assert(g_collision_refresh_calls == 0 && g_redraw_calls == 0); assert(win16_read_u8(win16_far_add_offset(g_receiver, 0x0bda)) == 0); assert(win16_read_u8(win16_far_add_offset(g_receiver, 0x0bdb)) == 0); } int main(void) { test_special_respawn(); test_advance_to_live_player(); test_game_over_path(); return 0; }