LunaHook-mirror/LunaHook/engines/ppsspp/specialgames.hpp

413 lines
13 KiB
C++
Raw Normal View History

2024-10-03 14:53:59 +08:00
#include <queue>
#include "emujitarg.hpp"
namespace ppsspp
{
bool ULJS00403_filter(void *data, size_t *len, HookParam *hp)
{
std::string result = std::string((char *)data, *len);
std::regex newlinePattern(R"((\\n)+)");
result = std::regex_replace(result, newlinePattern, " ");
std::regex pattern(R"((\\d$|^\@[a-z]+|#.*?#|\$))");
result = std::regex_replace(result, pattern, "");
return write_string_overwrite(data, len, result);
2024-03-27 12:56:52 +08:00
}
2024-10-03 14:53:59 +08:00
void ULJS00339(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto a2 = PPSSPP::emu_arg(stack)[0];
auto vm = *(DWORD *)(a2 + (0x28));
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm);
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 8);
uintptr_t address = PPSSPP::emu_addr(stack, vm);
auto len1 = *(DWORD *)(address + 4);
auto p = address + 0x20;
if (len1 > 4 && *(WORD *)(p + 2) == 0)
{
auto p1 = *(DWORD *)(address + 8);
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm);
vm = *(DWORD *)PPSSPP::emu_addr(stack, vm + 0xC);
p = PPSSPP::emu_addr(stack, vm);
}
static int fm = 0;
static std::string pre;
auto b = fm;
auto s = [](uintptr_t address)
{
auto frist = *(WORD *)address;
auto lo = frist & 0xFF; // uppercase: 41->5A
auto hi = frist >> 8;
if (hi == 0 && (lo > 0x5a || lo < 0x41) /* T,W,? */)
{
return std::string();
2024-03-27 12:56:52 +08:00
}
2024-10-03 14:53:59 +08:00
std::string s;
int i = 0;
WORD c;
char buf[3] = {0};
while ((c = *(WORD *)(address + i)) != 0)
{
// reverse endian: ShiftJIS BE => LE
buf[0] = c >> 8;
buf[1] = c & 0xFF;
if (c == 0x815e /* */)
{
s += ' '; // single line
2024-03-27 12:56:52 +08:00
}
2024-10-03 14:53:59 +08:00
else if (buf[0] == 0)
{
//// UTF16 LE turned BE: 5700=>0057, 3100, 3500
//// 4e00 6d00=>PLAYER
// do nothing
if (buf[1] == 0x4e)
{
s += "PLAYER";
fm++;
}
}
else
{
s += buf;
}
i += 2;
2024-03-27 12:56:52 +08:00
}
2024-10-03 14:53:59 +08:00
return s;
}(p);
if (b > 0)
{
fm--;
return;
2024-03-27 12:56:52 +08:00
}
2024-10-03 14:53:59 +08:00
if (s == pre)
return;
pre = s;
write_string_new(data, len, s);
2024-03-27 12:56:52 +08:00
}
2024-10-03 14:53:59 +08:00
bool NPJH50909_filter(void *data, size_t *len, HookParam *hp)
{
std::string result = std::string((char *)data, *len);
auto ws = StringToWideString(result, 932).value();
// Remove single line markers
ws = std::regex_replace(ws, std::wregex(L"(\\%N)+"), L" ");
// Remove scale marker
ws = std::regex_replace(ws, std::wregex(L"\\%\\@\\%\\d+"), L"");
// Reformat name
std::wsmatch match;
if (std::regex_search(ws, match, std::wregex(L"(^[^「]+)「")))
{
std::wstring name = match[1].str();
ws = std::regex_replace(ws, std::wregex(L"^[^「]+"), L"");
ws = name + L"\n" + ws;
}
return write_string_overwrite(data, len, WideStringToString(ws, 932));
}
bool ULJM06119_filter(void *data, size_t *len, HookParam *hp)
{
std::string s = std::string((char *)data, *len);
std::regex pattern(R"(/\[[^\]]+./g)");
s = std::regex_replace(s, pattern, "");
std::regex tagPattern(R"(/\\k|\\x|%C|%B)");
s = std::regex_replace(s, tagPattern, "");
std::regex colorPattern(R"(/\%\d+\#[0-9a-fA-F]*\;)");
s = std::regex_replace(s, colorPattern, "");
std::regex newlinePattern(R"(/\n+)");
s = std::regex_replace(s, newlinePattern, " ");
return write_string_overwrite(data, len, s);
}
bool ULJM06036_filter(void *data, size_t *len, HookParam *hp)
{
std::wstring result = std::wstring((wchar_t *)data, *len / 2);
std::wregex pattern(LR"(<R([^\/]+).([^>]+).>)");
result = std::regex_replace(result, pattern, L"$2");
std::wregex tagPattern(LR"(<[A-Z]+>)");
result = std::regex_replace(result, tagPattern, L"");
return write_string_overwrite(data, len, result);
}
namespace Corda
{
std::string readBinaryString(uintptr_t address, bool *haveName)
{
*haveName = false;
if ((*(WORD *)address & 0xF0FF) == 0x801b)
{
*haveName = true;
address = address + 2; // (1)
2024-03-27 12:56:52 +08:00
}
2024-10-03 14:53:59 +08:00
std::string s;
int i = 0;
uint8_t c;
while ((c = *(uint8_t *)(address + i)) != 0)
{
if (c == 0x1b)
{
if (*haveName)
return s; // (1) skip junk after name
c = *(uint8_t *)(address + (i + 1));
if (c == 0x7f)
i += 5;
else
i += 2;
}
else if (c == 0x0a)
{
s += '\n';
i += 1;
}
else if (c == 0x20)
{
s += ' ';
i += 1;
}
else
{
auto len = 1 + (IsDBCSLeadByteEx(932, *(BYTE *)(address + i)));
s += std::string((char *)(address + i), len);
i += len; // encoder.encode(c).byteLength;
}
2024-03-27 12:56:52 +08:00
}
2024-10-03 14:53:59 +08:00
return s;
2024-03-27 12:56:52 +08:00
}
}
2024-10-03 14:53:59 +08:00
void ULJM05428(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
auto address = PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s = Corda::readBinaryString(address, &haveNamve);
*split = haveNamve;
write_string_new(data, len, s);
}
void ULJM05054(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
if (hp->emu_addr != 0x886162c)
{
auto addr = PPSSPP::emu_arg(stack)[0] + 0x3c;
*data = addr;
*len = strlen((char *)addr);
return;
2024-04-13 14:10:16 +08:00
}
2024-10-03 14:53:59 +08:00
auto address = PPSSPP::emu_arg(stack)[1];
bool haveNamve;
auto s = Corda::readBinaryString(address, &haveNamve);
*split = haveNamve;
write_string_new(data, len, s);
}
bool ULJM05943F(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
std::regex pattern1("#n+");
std::string replacement1 = " ";
std::string result1 = std::regex_replace(s, pattern1, replacement1);
std::regex pattern2("#[A-Za-z]+\\[(\\d*\\.)?\\d+\\]+");
std::string replacement2 = "";
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
return write_string_overwrite(data, len, result2);
}
bool FULJM05603(LPVOID data, size_t *size, HookParam *)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t *>(size);
2024-04-13 14:10:16 +08:00
2024-10-03 14:53:59 +08:00
StringCharReplacer(text, len, "%N", 2, ' ');
StringFilter(text, len, "%K", 2);
StringFilter(text, len, "%P", 2);
return true;
}
namespace NPJH50530
{
std::string current;
bool T(LPVOID data, size_t *size, HookParam *)
{
current = std::string((char *)data, *size);
return true;
}
bool N(LPVOID data, size_t *size, HookParam *)
{
auto current1 = std::string((char *)data, *size);
return current != current1;
}
2024-04-13 14:10:16 +08:00
}
2024-10-03 14:53:59 +08:00
bool FNPJH50243(LPVOID data, size_t *size, HookParam *)
{
auto s = std::wstring((wchar_t *)data, *size / 2);
s = std::regex_replace(s, std::wregex(LR"(<(.*?)\|(.*?)>)"), L"$1");
return write_string_overwrite(data, size, s);
}
2024-10-08 18:30:22 +08:00
bool FNPJH50459(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex(R"(#SCL\((.*?)\)(.*?)#ECL)"), "$2");
strReplace(s, "\n\r\n", "\n");
return write_string_overwrite(data, len, s);
}
2024-10-11 18:42:53 +08:00
bool FNPJH50127(void *data, size_t *len, HookParam *hp)
{
StringCharReplacer((char *)data, len, "\\n", 2, '\n');
return true;
}
2024-10-08 15:58:42 +08:00
bool FULJM05690(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
s = std::regex_replace(s, std::regex("#Kana[(.*?),(.*?)]"), "");
strReplace(s, "#n", "\n");
return write_string_overwrite(data, len, s);
}
2024-10-03 14:53:59 +08:00
bool FULJM05889(LPVOID data, size_t *size, HookParam *)
{
auto text = reinterpret_cast<LPSTR>(data);
auto len = reinterpret_cast<size_t *>(size);
for (size_t i = 0; i < *len;)
{
if (IsDBCSLeadByteEx(932, (text[i])))
{
i += 2;
continue;
}
if (text[i] == '^')
text[i] = '\n';
i += 1;
}
return true;
}
bool NPJH50619F(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
std::regex pattern1("[\\r\\n]+");
std::string replacement1 = "";
std::string result1 = std::regex_replace(s, pattern1, replacement1);
std::regex pattern2("^(.*?)\\)+");
std::string replacement2 = "";
std::string result2 = std::regex_replace(result1, pattern2, replacement2);
std::regex pattern3("#ECL+");
std::string replacement3 = "";
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
std::regex pattern4("(#.+?\\))+");
std::string replacement4 = "";
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
return write_string_overwrite(data, len, result4);
}
bool NPJH50505F(void *data, size_t *len, HookParam *hp)
{
auto s = std::string((char *)data, *len);
std::regex pattern2("#RUBS(#[A-Z0-9]+)*[^#]+");
std::string replacement2 = "";
std::string result2 = std::regex_replace(s, pattern2, replacement2);
std::regex pattern3("#FAMILY");
std::string replacement3 = "$FAMILY";
std::string result3 = std::regex_replace(result2, pattern3, replacement3);
std::regex pattern4("#GIVE");
std::string replacement4 = "$GIVE";
std::string result4 = std::regex_replace(result3, pattern4, replacement4);
std::regex pattern5("(#[A-Z0-9\\-]+)+");
std::string replacement5 = "";
std::string result5 = std::regex_replace(result4, pattern5, replacement5);
std::regex pattern6("\\n+");
std::string replacement6 = " ";
std::string result6 = std::regex_replace(result5, pattern6, replacement6);
return write_string_overwrite(data, len, result6);
}
void QNPJH50909(hook_stack *stack, HookParam *hp, uintptr_t *data, uintptr_t *split, size_t *len)
{
uintptr_t addr = PPSSPP::emu_addr(stack, 0x08975110);
*data = addr + 0x20;
*len = *(DWORD *)(addr + 0x14) * 2;
if (0x6e87 == *(WORD *)*data)
*len = 0;
if (0x000a == *(WORD *)*data)
*len = 0;
}
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks = {
// Shinigami to Shoujo
{0x883bf34, {0, 1, 0, 0, ULJS00403_filter, "ULJS00403"}},
// Amagami
{0x0886775c, {0, 0, 0, ULJS00339, 0, "ULJS00339"}}, // String.length()
// Sekai de Ichiban Dame na Koi
{0x8814adc, {0, 0, 0, 0, NPJH50909_filter, "ULJM05878"}}, // name + dialouge
{0x8850b2c, {0, 0, 0, 0, NPJH50909_filter, "ULJM05878"}}, // onscreen toast
// Dunamis15
{0x0891D72C, {CODEC_UTF8, 0, 0, 0, ULJM06119_filter, "ULJM06119"}},
// Princess Evangile Portable
{0x88506d0, {CODEC_UTF16, 2, 0, 0, ULJM06036_filter, "ULJM06036"}}, // [0x88506d0(2)...0x088507C0(?)] // name text text (line doubled)
// Kin'iro no Corda 2f
{0x89b59dc, {0, 0, 0, ULJM05428, 0, "ULJM05428"}},
// Kin'iro no Corda
{0x886162c, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // dialogue: 0x886162c (x1), 0x889d5fc-0x889d520(a2) fullLine
{0x8899e90, {0, 0, 0, ULJM05054, 0, "ULJM05054"}}, // name 0x88da57c, 0x8899ca4 (x0, oneTime), 0x8899e90
// Sol Trigger
{0x8952cfc, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // dialog
{0x884aad4, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // description
{0x882e1b0, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // system
{0x88bb108, {CODEC_UTF8, 2, 0, 0, NPJH50619F, "NPJH50619"}}, // battle tutorial
{0x89526a0, {CODEC_UTF8, 0, 0, 0, NPJH50619F, "NPJH50619"}}, // battle info
{0x88bcef8, {CODEC_UTF8, 1, 0, 0, NPJH50619F, "NPJH50619"}}, // battle talk
// Fate/EXTRA CCC
{0x8958490, {0, 0, 0, 0, NPJH50505F, "NPJH50505"}},
// Kamigami no Asobi InFinite
{0x088630f8, {0, 0, 0, QNPJH50909, 0, "NPJH50909"}}, // text, choice (debounce trailing 400ms), TODO: better hook
{0x0887813c, {0, 3, 4, 0, 0, "NPJH50909"}}, // Question YN
// Gekka Ryouran Romance
{0x88eeba4, {0, 0, 0, 0, ULJM05943F, "ULJM05943"}}, // a0 - monologue text
{0x8875e0c, {0, 1, 6, 0, ULJM05943F, "ULJM05943"}}, // a1 - dialogue text
// My Merry May with be
{0x886F014, {0, 3, 0, 0, FULJM05603, "ULJM05603"}},
// Corpse Party -The Anthology- Sachiko no Ren'ai Yuugi ♥ Hysteric Birthday 2U - Regular Edition
{0x88517C8, {0, 1, 0, 0, FULJM05603, "ULJM06114"}},
// Himawari_no_Kyoukai_to_Nagai_Natsuyasumi_Extra_Vacation_JPN_PSP-MOEMOE
{0x881c444, {FULL_STRING, 0, 0, 0, 0, "ULJM06321"}}, // name+text,sjit,FULL_STRING to split name and text
// ましろ色シンフォニー *mutsu-no-hana
{0x8868AB8, {0, 0, 0, 0, FULJM05889, "ULJM05889"}},
// シャイニング・ブレイド
{0x8AA3B70, {0, 0xC, 0, 0, NPJH50530::T, "NPJH50530"}}, // text only
{0x884DB44, {0, 1, 0, 0, NPJH50530::N, "NPJH50530"}}, // text+name
// ティアーズ・トゥ・ティアラ 外伝 アヴァロンの謎
{0x890A4BC, {CODEC_UTF16, 1, 0, 0, FNPJH50243, "NPJH50243"}},
// 薔薇ノ木ニ薔薇ノ花咲ク
{0x881E560, {0, 1, 0, 0, 0, "ULJM05802"}},
2024-10-08 15:58:42 +08:00
// D.C. Girl's Symphony Pocket ~ダ・カーポ~ ガールズシンフォニーポケット
{0x883C77C, {0, 0, 0, 0, FULJM05690, "ULJM05690"}},
// Ever17 -the out of infinity- Premium Edition
{0x881AD64, {0, 0xd, 0, 0, 0, "ULJM05437"}},
// 時の鐘とシンデレラHalloween Wedding
{0x882A650, {0, 1, 0, 0, 0, "ULJM06023"}},
// 0時の鐘とシンデレラHalloween Wedding (instance: 2)
{0x8855CA0, {0, 1, 0, 0, 0, "ULJM06272"}},
2024-10-08 18:30:22 +08:00
// セブンスドラゴン2020
{0x88847A0, {CODEC_UTF8, 1, 0, 0, FNPJH50459, "NPJH50459"}},
// セブンスドラゴン2020-Ⅱ
{0x8889CCC, {CODEC_UTF8, 1, 0, 0, FNPJH50459, "NPJH50716"}}, // 会有两三条后续文本都被一次性提取到。
2024-10-08 18:44:49 +08:00
// マイナスエイト
{0x88DC218, {0, 0, 0, 0, FULJM05690, "ULJM06341"}},
2024-10-11 18:42:53 +08:00
// Tokimeki Memorial 4
{0x899a510, {0, 2, 0, 0, FNPJH50127, "NPJH50127"}},
{0x88719dc, {0, 1, 0, 0, FNPJH50127, "NPJH50127"}},
2024-10-03 14:53:59 +08:00
};
2024-03-27 12:56:52 +08:00
}