diff --git a/texthook/engine/engine.cc b/texthook/engine/engine.cc index bb4d080..8f3e9be 100644 --- a/texthook/engine/engine.cc +++ b/texthook/engine/engine.cc @@ -15230,6 +15230,152 @@ bool InsertPONScripterHook() return false; } +void ONScripterruCommonFilter(char *text, size_t *len) +{ + StringCharReplacer(text, len, "{n}", 3, ' '); + + if (cpp_strnstr(text, "{c:", *len)) { + StringFilterBetween(text, len, "{c:", 3, ":", 1); + } + if (cpp_strnstr(text, "{e:", *len)) { + StringFilterBetween(text, len, "{e:", 3, ":", 1); + } + if (cpp_strnstr(text, "{f:", *len)) { + StringFilterBetween(text, len, "{f:", 3, ":", 1); + } + if (cpp_strnstr(text, "{i:", *len)) { + StringFilter(text, len, "{i:", 3); + } + if (cpp_strnstr(text, "{p:", *len)) { + StringFilterBetween(text, len, "{p:", 3, "}", 1); + } + CharFilter(text, len, '}'); + + if (cpp_strnstr(text, "[", *len)) { + StringFilterBetween(text, len, "[", 1, "]", 1); + } + +} + +bool ONScripterru1Filter(LPVOID data, DWORD *size, HookParam *, BYTE) +{ + auto text = reinterpret_cast(data); + auto len = reinterpret_cast(size); + + if ( *len == 0 || text[0] == ':' || text[1] == '{') + return false; + + ONScripterruCommonFilter(text, len); + CharFilter(text, len, '`'); + + return true; +} + +bool InsertONScripterruHook1() +{ + //by Blu3train + /* + * Sample games: + * Umineko Project (all text displayed) + */ + const BYTE bytes[] = { + 0x90, // nop + 0x55, // push ebp << hook here + 0x57, // push edi + 0x31, 0xED, // xor ebp,ebp + 0x56, // push esi + 0x53, // push ebx + 0x83, 0xEC, 0x3C // sub esp,3C + }; + + ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStopAddress); + if (!addr) { + ConsoleOutput("vnreng:ONScripter-RU 1: pattern not found"); + return false; + } + + HookParam hp = {}; + hp.address = addr + 1; + hp.offset = pusha_eax_off -4; + hp.type = USING_STRING | USING_UTF8; + hp.filter_fun = ONScripterru1Filter; + ConsoleOutput("vnreng: INSERT ONScripter-RU 1"); + NewHook(hp, "ONScripter-RU1"); + + return true; + +} + +void StringBetween(char *str, size_t *size, const char *fr, size_t frlen, const char *to, size_t tolen) +{ + size_t len = *size, + curlen; + + char *start = cpp_strnstr(str, fr, len); + if (!*start) + return; + //start += frlen; + char *end = cpp_strnstr((start += frlen), to, len - (start - str)); + if (!*end) + return; + ::memmove(str, start, end - start); + + *size = end - start; + //str[*size] = '\0'; +} + +bool ONScripterru2Filter(LPVOID data, DWORD *size, HookParam *, BYTE) +{ + auto text = reinterpret_cast(data); + auto len = reinterpret_cast(size); + + StringBetween(text, len, "`", 1, "`", 1); + + ONScripterruCommonFilter(text, len); + + return true; +} + +bool InsertONScripterruHook2() +{ + //by Blu3train + /* + * Sample games: + * Umineko Project (partial text displayed) + */ + const BYTE bytes[] = { + 0x0F, 0xB6, 0x04, 0x18, // movzx eax,byte ptr [eax+ebx] << hook here + 0x89, 0x74, 0x24, 0x04, // mov [esp+04],esi + 0x43, // inc ebx + 0x89, 0x44, 0x24, 0x08 // mov [esp+08],eax + }; + + ULONG range = min(processStopAddress - processStartAddress, MAX_REL_ADDR); + ULONG addr = MemDbg::findBytes(bytes, sizeof(bytes), processStartAddress, processStartAddress + range); + if (!addr) { + ConsoleOutput("vnreng:ONScripter-RU 2: pattern not found"); + return false; + } + + HookParam hp = {}; + hp.address = addr; + hp.offset = pusha_eax_off -4; + hp.split = -0x1C -4; + hp.type = USING_STRING | USING_UTF8 | USING_SPLIT | KNOWN_UNSTABLE; + //hp.type = USING_STRING | USING_UTF8 | USING_SPLIT; + hp.filter_fun = ONScripterru2Filter; + ConsoleOutput("vnreng: INSERT ONScripter-RU 2"); + NewHook(hp, "ONScripter-RU2"); + + return true; +} + +bool InsertONScripterruHooks() +{ + bool ok = InsertONScripterruHook1(); + return InsertONScripterruHook2() || ok; +} + bool PONScripterFilter(LPVOID data, DWORD *size, HookParam *, BYTE) { auto text = reinterpret_cast(data); diff --git a/texthook/engine/engine.h b/texthook/engine/engine.h index c765642..07d3983 100644 --- a/texthook/engine/engine.h +++ b/texthook/engine/engine.h @@ -157,6 +157,7 @@ bool InsertWillPlusHook(); // WillPlus: Rio.arc bool InsertWolfHook(); // Wolf: Data.wolf bool InsertYukaSystemHooks(); // YukaSystem2: *.ykc bool InsertYurisHook(); // YU-RIS: *.ypf +bool InsertONScripterruHooks(); // ONScripter-RU: resource string bool InsertSakanaGLHook(); // SakanaGL: sakanagl.dll bool InsertDebonosuWorksHook(); // DebonosuWorks: resource string bool InsertLucaSystemHook(); // LucaSystem: *.iga diff --git a/texthook/engine/match32.cc b/texthook/engine/match32.cc index b14fd66..7060d7e 100644 --- a/texthook/engine/match32.cc +++ b/texthook/engine/match32.cc @@ -81,6 +81,12 @@ bool DeterminePCEngine() return true; } + if (Util::SearchResourceString(L"ONScripter-RU") || Util::SearchResourceString(L"onscripter-ru.exe")) + { + InsertONScripterruHooks(); + return true; + } + // PC games PcHooks::hookGDIFunctions(); PcHooks::hookGDIPlusFunctions();