diff --git a/dist/popnhax/popnhax.xml b/dist/popnhax/popnhax.xml index 4a00eb4..c6f277d 100644 --- a/dist/popnhax/popnhax.xml +++ b/dist/popnhax/popnhax.xml @@ -88,6 +88,12 @@ 0 + + + 0 + + 0 + 0 diff --git a/popnhax/config.h b/popnhax/config.h index 46ad314..3026879 100644 --- a/popnhax/config.h +++ b/popnhax/config.h @@ -37,6 +37,8 @@ struct popnhax_config { bool tachi_scorehook_skip_omni; bool tachi_rivals; bool autopin; + bool attract_ex; + bool attract_full; bool patch_db; bool disable_multiboot; diff --git a/popnhax/dllmain.cc b/popnhax/dllmain.cc index 2131207..1f6ecab 100644 --- a/popnhax/dllmain.cc +++ b/popnhax/dllmain.cc @@ -221,6 +221,10 @@ PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_U16, struct popnhax_config, high_framerate_ "/popnhax/high_framerate_fps") PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, autopin, "/popnhax/autopin") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, attract_ex, + "/popnhax/attract_ex") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, attract_full, + "/popnhax/attract_full") /* removed options are now hidden as optional */ PSMAP_MEMBER_OPT(PSMAP_PROPERTY_TYPE_U8, struct popnhax_config, survival_gauge, "/popnhax/survival_gauge", 0) @@ -5464,7 +5468,7 @@ void play_firststep() { __asm("cmp edi, dword ptr [eax]\n"); __asm("jl p1_end\n"); // elapsed time < Timing -> return - // E2はロング消えたあとのバグ?早GOODだけ入ることがあるのを再現… + // E2はロング消えたあとのバグ?早GOODだけ入ることがあるの 再現… __asm("movzx ecx, word ptr [eax+0x04]\n"); __asm("push edx\n"); __asm("push ecx\n"); @@ -7966,6 +7970,66 @@ static bool patch_half_timer_speed() return true; } +void (*real_attract)(void); +void hook_ex_attract() +{ + __asm("push ebx\n"); + __asm("mov ebx, eax\n"); + __asm("add ebx, 2\n"); + __asm("mov byte ptr [ebx], 3\n"); //force EX chart_num + __asm("add ebx, 8\n"); + __asm("mov byte ptr [ebx], 40\n"); // force x4.0 multiplier + __asm("pop ebx\n"); + real_attract(); +} + +static bool patch_ex_attract() +{ + DWORD dllSize = 0; + char *data = getDllData(g_game_dll_fn, &dllSize); + + { + int64_t pattern_offset = search(data, dllSize, "\x81\xE7\x01\x00\x00\x80\x79\x05\x4F", 9, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_ex: cannot find attract mode song info\n"); + return false; + } + + uint64_t patch_addr = (int64_t)data + pattern_offset; + + MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_ex_attract, + (void **)&real_attract); + } + LOG("popnhax: attract mode will play EX charts at 4.0x hispeed\n"); + return true; +} + +static bool patch_full_attract() +{ + DWORD dllSize = 0; + char *data = getDllData(g_game_dll_fn, &dllSize); + + { + int64_t pattern_offset = search(data, dllSize, "\xB8\xD0\x07\x00\x00\x66\xA3", 7, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_full: cannot find attract mode timer set function\n"); + return false; + } + + uint32_t timer_addr = *(uint32_t*)((int64_t)data + pattern_offset + 7); + uint8_t new_pattern[9] = "\x66\x83\x05\x00\x00\x00\x00\xFF"; + memcpy(new_pattern+3, &timer_addr, 4); + + if (!find_and_patch_hex(g_game_dll_fn, (char*)new_pattern, 8, 7, "\x00", 1)) + { + LOG("popnhax: attract_full: cannot stop attract mode song timer\n"); + return false; + } + } + LOG("popnhax: attract mode will play full songs\n"); + return true; +} + static bool patch_afp_framerate(uint16_t fps) { DWORD framerate = fps; @@ -8503,6 +8567,15 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv patch_autopin(); } + if (config.attract_ex) + { + patch_ex_attract(); + } + if (config.attract_full) + { + patch_full_attract(); + } + if (config.time_rate) patch_get_time(config.time_rate/100.);