恍兮惚兮 987a4ebd52 .
2024-12-03 19:51:33 +08:00

622 lines
26 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "vita3k.h"
namespace
{
auto isVirtual = true;
auto idxDescriptor = isVirtual == true ? 2 : 1;
auto idxEntrypoint = idxDescriptor + 1;
std::string Vita3KGameID;
uintptr_t getDoJitAddress()
{
// Vita3K\external\dynarmic\src\dynarmic\backend\x64\emit_x64.h
// BlockDescriptor EmitX64::RegisterBlock(const IR::LocationDescriptor& location_descriptor, CodePtr entrypoint, size_t size);
BYTE RegisterBlockSig1[] = {0x40, 0x55, 0x53, 0x56, 0x57, 0x41, 0x54, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8D, 0x6C, 0x24, 0xE9, 0x48, 0x81, 0xEC, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, XX, XX, XX, XX, XX, 0x48, 0x33, 0xC4, 0x48, 0x89, 0x45, 0x07, 0x4D, 0x8B, 0xF1, 0x49, 0x8B, 0xF0, 0x48, 0x8B, 0xFA, 0x48, 0x8B, 0xD9, 0x4C, 0x8B, 0x7D, 0x77, 0x48, 0x8B, 0x01, 0x48, 0x8D, 0x55, 0xC7, 0xFF, 0x50, 0x10};
auto first = MemDbg::findBytes(RegisterBlockSig1, sizeof(RegisterBlockSig1), processStartAddress, processStopAddress);
if (first)
return first;
BYTE PatchBlockSig1[] = {0x4C, 0x8B, 0xDC, 0x49, 0x89, 0x5B, 0x10, 0x49, 0x89, 0x6B, 0x18, 0x56, 0x57, 0x41, 0x54, 0x41, 0x56, 0x41, 0x57};
BYTE PatchBlockSig2[] = {0x4C, 0x8B, 0xDC, 0x49, 0x89, 0x5B, XX, 0x49, 0x89, 0x6B, XX, 0x56, 0x57, 0x41, 0x54, 0x41, 0x56, 0x41, 0x57};
first = MemDbg::findBytes(PatchBlockSig1, sizeof(PatchBlockSig1), processStartAddress, processStopAddress);
if (!first)
first = MemDbg::findBytes(PatchBlockSig2, sizeof(PatchBlockSig2), processStartAddress, processStopAddress); // 0.1.9 3339
if (first)
{
idxDescriptor = 1;
idxEntrypoint = 2;
return first;
}
return 0;
}
struct emfuncinfo
{
uint64_t type;
int argidx;
int padding;
decltype(HookParam::text_fun) hookfunc;
decltype(HookParam::filter_fun) filterfun;
const char *_id;
};
std::unordered_map<uintptr_t, emfuncinfo> emfunctionhooks;
}
namespace
{
void trygetgameinwindowtitle()
{
HookParam hp;
hp.address = 0x3000;
hp.text_fun = [](hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
{
static std::wstring last;
// vita3k Vulkan模式GetWindowText会卡住
auto getSecondSubstring = [](const std::wstring &str) -> std::wstring
{
size_t firstPos = str.find(L'|');
if (firstPos == std::wstring::npos)
return L"";
size_t nextPos = str.find(L'|', firstPos + 1);
if (nextPos == std::wstring::npos)
return L"";
size_t start = firstPos + 1;
size_t end = nextPos;
return str.substr(start, end - start);
};
auto wininfos = get_proc_windows();
for (auto &&info : wininfos)
{
auto game = getSecondSubstring(info.title);
if (!game.size())
continue;
std::wregex reg1(L"\\((.*?)\\)");
std::wsmatch match;
if (!std::regex_search(game, match, reg1))
return;
auto curr = match[1].str();
if (last == curr)
return;
Vita3KGameID = wcasta(curr);
last = curr;
return HostInfo(HOSTINFO::EmuGameName, WideStringToString(game).c_str());
}
};
hp.type = DIRECT_READ;
NewHook(hp, "Vita3KGameInfo");
}
}
bool vita3k::attach_function()
{
ConsoleOutput("[Compatibility] Vita3k 0.1.9 3339+");
auto DoJitPtr = getDoJitAddress();
if (DoJitPtr == 0)
return false;
trygetgameinwindowtitle();
spDefault.isjithook = true;
spDefault.minAddress = 0;
spDefault.maxAddress = -1;
HookParam hp;
hp.address = DoJitPtr;
hp.text_fun = [](hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
{
auto descriptor = *argidx(stack, idxDescriptor + 1); // r8
auto entrypoint = *argidx(stack, idxEntrypoint + 1); // r9
auto em_address = *(uint32_t *)descriptor;
if (em_address < 0x80000000)
em_address += 0x80000000; // 0.1.9 3339
if (!entrypoint)
return;
// ConsoleOutput("%p",em_address);
jitaddraddr(em_address, entrypoint, JITTYPE::VITA3K);
[&]()
{
if (emfunctionhooks.find(em_address) == emfunctionhooks.end())
return;
auto op = emfunctionhooks.at(em_address);
if (Vita3KGameID.size() && (op._id != Vita3KGameID))
return;
HookParam hpinternal;
hpinternal.address = entrypoint;
hpinternal.emu_addr = em_address; // 用于生成hcode
hpinternal.type = USING_STRING | NO_CONTEXT | BREAK_POINT | op.type;
hpinternal.text_fun = op.hookfunc;
hpinternal.filter_fun = op.filterfun;
hpinternal.argidx = op.argidx;
hpinternal.padding = op.padding;
hpinternal.jittype = JITTYPE::VITA3K;
NewHook(hpinternal, op._id);
}();
delayinsertNewHook(em_address);
};
return NewHook(hp, "vita3kjit");
}
namespace
{
void FPCSG01023(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("<br>"), "");
s = std::regex_replace(s, std::regex("%CF11F"), "");
s = std::regex_replace(s, std::regex("%CFFFF"), "");
s = std::regex_replace(s, std::regex("%K%P"), "");
s = std::regex_replace(s, std::regex("%K%N"), "");
s = std::regex_replace(s, std::regex("\n"), "");
buffer->from(s);
}
template <int idx>
void FPCSG01282(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("(\\n)+"), " ");
s = std::regex_replace(s, std::regex("\\d$|^@[a-z]+|#.*?#|\\$"), "");
static std::string last;
if (last == s)
return buffer->clear();
last = s;
buffer->from(s);
}
template <int index>
void ReadU16TextAndLenDW(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
{
auto address = VITA3K::emu_arg(stack)[index];
buffer->from(address + 0xC, (*(DWORD *)(address + 0x8)) * 2);
}
void FPCSG00410(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
s = std::regex_replace(s, std::regex("#n"), " ");
// .replaceAll("④", "!?").replaceAll("②", "!!").replaceAll("⑥", "。").replaceAll("⑪", "【")
// .replaceAll("⑫", "】").replaceAll("⑤", "、").replaceAll("①", "・・・")
strReplace(s, "\x87\x43", "!?");
strReplace(s, "\x87\x41", "!!");
strReplace(s, "\x87\x45", "\x81\x42");
strReplace(s, "\x87\x4a", "\x81\x79");
strReplace(s, "\x87\x4b", "\x81\x7a");
strReplace(s, "\x87\x44", "\x81\x41");
strReplace(s, "\x87\x40", "\x81\x45\x81\x45\x81\x45");
buffer->from(s);
}
void FPCSG00448(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("(#n)+"), "");
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
s = std::regex_replace(s, std::regex("#Pos[\\s\\S]*?\\]"), "");
buffer->from(s);
}
void FPCSG01008(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("#Ruby\\[([^,]+)\\.([^\\]]+)\\]."), "$1");
s = std::regex_replace(s, std::regex("(#n)+"), " ");
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
buffer->from(s);
}
void TPCSG00903(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
{
auto address = VITA3K::emu_arg(stack)[0];
buffer->from(address + 0x1C, (*(DWORD *)(address + 0x14)));
}
void FPCSG00903(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("\\\\n"), " ");
buffer->from(s);
}
void FPCSG01180(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex(R"(\\n)"), " ");
s = std::regex_replace(s, std::regex(R"(,.*$)"), " ");
buffer->from(s);
}
void FPCSG00839(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strW();
s = std::regex_replace(s, std::wregex(L"\\[[^\\]]+."), L"");
s = std::regex_replace(s, std::wregex(L"\\\\k|\\\\x|%C|%B|%p-1;"), L"");
s = std::regex_replace(s, std::wregex(L"#[0-9a-fA-F]+;([^%#]+)(%r)?"), L"$1");
s = std::regex_replace(s, std::wregex(L"\\\\n"), L"");
static std::wstring last;
if (last.find(s) != last.npos)
return buffer->clear();
last = s;
buffer->from(s);
}
void FPCSG00751(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("@[a-z]"), "");
// s = std::regex_replace(s, std::regex(""), "");
strReplace(s, "\x81\x90", "");
buffer->from(s);
}
void FPCSG00401(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex(R"([\s])"), "");
s = std::regex_replace(s, std::regex(R"(\c)"), "");
s = std::regex_replace(s, std::regex(R"(\\n)"), "");
buffer->from(s);
}
void PCSG00787(TextBuffer *buffer, HookParam *)
{
CharFilter(buffer, '\n');
}
void FPCSG00912(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("%N"), "");
buffer->from(s);
}
void FPCSG00706(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strW();
s = std::regex_replace(s, std::wregex(L"<br>"), L"");
buffer->from(s);
}
void FPCSG00696(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
//.replace(/㌔/g, '⁉')
//.replace(/㍉/g, '!!')
strReplace(s, "\x87\x60", "");
strReplace(s, "\x87\x5f", "");
buffer->from(s);
}
void FPCSG00389(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("(#n)+"), "");
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
buffer->from(s);
}
void FPCSG00216(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("[\\s]"), "");
s = std::regex_replace(s, std::regex("(#n)+"), "");
s = std::regex_replace(s, std::regex("#[A-Za-z]+\\[(\\d*[.])?\\d+\\]"), "");
s = std::regex_replace(s, std::regex("#Pos\\[[\\s\\S]*?\\]"), "");
buffer->from(s);
}
void FPCSG00405(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex("[\\s]"), "");
buffer->from(s);
}
void PCSG00776(TextBuffer *buffer, HookParam *hp)
{
auto ws = StringToWideString(buffer->viewA(), 932).value();
strReplace(ws, L"\x02", L"");
Trim(ws);
buffer->from(WideStringToString(ws));
}
void PCSG00912(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
{
auto address = VITA3K::emu_arg(stack)[1];
std::string final_string = "";
BYTE pattern[] = {0x47, 0xff, 0xff};
auto results = MemDbg::findBytes(pattern, sizeof(pattern), address, address + 0x50);
if (!results)
return;
address = results + 5;
while (true)
{
std::string text = (char *)address;
final_string += text;
address = address + (text.size() + 1);
auto bytes = (BYTE *)address;
if (!(bytes[0] == 0x48 && bytes[1] == 0xFF && bytes[2] == 0xFF))
break;
address = address + (3);
bytes = (BYTE *)address;
if (!(bytes[0] == 0x47 && bytes[1] == 0xFF && bytes[2] == 0xFF))
break;
address = address + (5);
}
buffer->from(final_string);
}
void TPCSG00291(hook_stack *stack, HookParam *hp, TextBuffer *buffer, uintptr_t *split)
{
auto a2 = VITA3K::emu_arg(stack)[0];
auto vm = *(DWORD *)(a2 + (0x28));
vm = *(DWORD *)VITA3K::emu_addr(stack, vm);
vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 8);
uintptr_t address = VITA3K::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 *)VITA3K::emu_addr(stack, vm);
vm = *(DWORD *)VITA3K::emu_addr(stack, vm + 0xC);
p = VITA3K::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();
}
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
}
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;
}
return s;
}(p);
if (b > 0)
{
fm--;
return;
}
if (s == pre)
return;
pre = std::move(s);
buffer->from(pre);
}
void FPCSG00468(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex(u8R"(\\n( )*|\\k)"), "");
s = std::regex_replace(s, std::regex(R"(\[|\*[^\]]+])"), "");
s = std::regex_replace(s, std::regex(u8"×"), "");
buffer->from(s);
}
void FPCSG00808(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex(R"(^\s+|\s+$)"), "");
s = std::regex_replace(s, std::regex(R"(\s*(#n)*\s*)"), "");
s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), "");
buffer->from(s);
}
void F010088B01A8FC000(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
static std::string last;
s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), "");
s = std::regex_replace(s, std::regex(u8" "), "");
if (last == s)
return buffer->clear();
last = s;
buffer->from(s);
}
void FPCSG00815(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex(R"(\s*(#n)*\s*)"), "");
s = std::regex_replace(s, std::regex(R"(#\w+(\[.+?\])?)"), "");
buffer->from(s);
}
void FPCSG00855(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex(u8R"(#n( )*)"), "");
s = std::regex_replace(s, std::regex(R"(#\w.+?])"), "");
buffer->from(s);
}
template <int idx>
void FPCSG00855_2(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
static std::string last;
if (last == s)
return buffer->clear();
last = s;
strReplace(s, u8"Χ", u8"");
strReplace(s, u8"Δ", u8"");
strReplace(s, u8"Λ", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"", u8"");
strReplace(s, u8"П", u8"");
strReplace(s, u8"Ц", u8"");
buffer->from(s);
FPCSG00855(buffer, hp);
}
void FPCSG00477(TextBuffer *buffer, HookParam *hp)
{
auto ws = StringToWideString(buffer->viewA(), 932).value();
ws = std::regex_replace(ws, std::wregex(LR"(#n\u3000*)"), L"");
ws = std::regex_replace(ws, std::wregex(LR"(#\w.+?])"), L"");
buffer->from(WideStringToString(ws, 932));
}
void FPCSG00852(TextBuffer *buffer, HookParam *hp)
{
auto ws = StringToWideString(buffer->viewA(), 932).value();
strReplace(ws, L"^", L"");
buffer->from(WideStringToString(ws, 932));
}
void FPCSG01066(TextBuffer *buffer, HookParam *hp)
{
auto s = buffer->strA();
s = std::regex_replace(s, std::regex(u8R"(\n( )*)"), "");
buffer->from(s);
}
void FPCSG01075(TextBuffer *buffer, HookParam *hp)
{
FPCSG00808(buffer, hp);
auto s = buffer->strA();
static std::string last;
if (last == s)
return buffer->clear();
last = s;
}
auto _ = []()
{
emfunctionhooks = {
// 追放選挙
{0x8002e176, {0, 0, 0, 0, FPCSG01023, "PCSG01023"}}, // dialogue+name,sjis
// 死神と少女
{0x800204ba, {0, 2, 0, 0, FPCSG01282<0>, "PCSG01282"}}, // dialogueNVL,sjis
{0x8000f00e, {0, 1, 0, 0, FPCSG01282<1>, "PCSG01282"}}, // dialogue main
{0x80011f1a, {0, 0, 0, 0, FPCSG01282<2>, "PCSG01282"}}, // Name
{0x8001ebac, {0, 1, 0, 0, FPCSG01282<3>, "PCSG01282"}}, // choices
// 神凪ノ杜 五月雨綴り
{0x828bb50c, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, 0, "PCSG01268"}}, // dialogue
{0x828ba9b6, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, 0, "PCSG01268"}}, // name
{0x8060D376, {CODEC_UTF8, 0, 0, 0, 0, "PCSG01268"}}, // vita3k v0.2.0 can't find 0x828bb50c && 0x828ba9b6, unknown reason.
// 参千世界遊戯 ~MultiUniverse Myself~
{0x8005ae24, {0, 0, 0, 0, 0, "PCSG01194"}}, // dialouge+name,sjis,need remap jis char,to complex
// Marginal #4 Road to Galaxy
{0x8002ff90, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG01008"}}, // text
// MARGINAL#4 IDOL OF SUPERNOVA
{0x800718f8, {0, 0, 0, 0, FPCSG00448, "PCSG00448"}}, // dialogue,sjis
// BLACK WOLVES SAGA -Weiβ und Schwarz-
{0x800581a2, {CODEC_UTF8, 0, 0, 0, FPCSG01008, "PCSG00935"}}, // text
// New Game! The Challenge Stage!
{0x8012674c, {CODEC_UTF8, 0, 0, TPCSG00903, FPCSG00903, "PCSG00903"}},
// 喧嘩番長乙女
{0x80009722, {CODEC_UTF16, 0, 0, 0, FPCSG00839, "PCSG00839"}},
// アルカナ・ファミリア -La storia della Arcana Famiglia- Ancora
{0x80070e30, {0, 2, 0, 0, FPCSG00751, "PCSG00751"}}, // all,sjis
{0x80070cdc, {0, 1, 0, 0, FPCSG00751, "PCSG00751"}}, // text
// もし、この世界に神様がいるとするならば。
{0x80c1f270, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, FPCSG00706, "PCSG00706"}}, // dialogue
{0x80d48bfc, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<1>, FPCSG00706, "PCSG00706"}}, // Dictionary1
{0x80d48c20, {CODEC_UTF16, 0, 0, ReadU16TextAndLenDW<0>, FPCSG00706, "PCSG00706"}}, // Dictionary2
// アンジェーリーク ルトゥール
{0x8008bd1a, {0, 1, 0, 0, FPCSG00696, "PCSG00696"}}, // text1,sjis
{0x8008cd48, {0, 0, 0, 0, FPCSG00696, "PCSG00696"}}, // text2
{0x8008f75a, {0, 0, 0, 0, FPCSG00696, "PCSG00696"}}, // choice
// 月に寄りそう乙女の作法
{0x8002aefa, {0, 2, 0, 0, 0, "PCSG00648"}}, // dialogue,sjis
// 熱血異能部活譚 Trigger Kiss
{0x8004e44a, {0, 0, 0, 0, FPCSG00410, "PCSG00410"}}, // dialogue,sjis
// バイナリースター
{0x80058606, {0, 1, 0xd, 0, FPCSG00389, "PCSG00389"}}, // dialogue,sjis
// アマガミ
{0x80070658, {0, 0, 0, TPCSG00291, 0, "PCSG00291"}},
// るいは智を呼ぶ
{0x81003db0, {CODEC_UTF8, 1, 0, 0, FPCSG00839, "PCSG00216"}}, // dialogue
// レンドフルール
{0x8001bff2, {0, 0, 0, 0, FPCSG00405, "PCSG00405"}}, // dialogue,sjis
// Muv-Luv
{0x80118f10, {0, 5, 0, 0, PCSG00776, "PCSG00776"}}, // dialogue, choices
{0x80126e7e, {0, 0, 0, 0, PCSG00776, "PCSG00776"}}, // dialogue
// Re:BIRTHDAY SONG恋を唄う死神
{0x80033af6, {0, 0, 2, 0, 0, "PCSG00911"}}, // dialogue
// Un:BIRTHDAY SONG ~愛を唄う死神~
{0x80038538, {0, 0, 0, PCSG00912, 0, "PCSG00912"}},
{0x80033d66, {0, 3, 4, 0, FPCSG00912, "PCSG00912"}},
// ソラ*ユメ
{0x8000bad4, {0, 1, 0, 0, FPCSG00401, "PCSG00401"}},
// 天涯ニ舞ウ、粋ナ花
{0x8006808e, {CODEC_UTF8, 0, 0, 0, FPCSG01180, "PCSG01180"}},
{0x80089408, {CODEC_UTF8, 0, 0, 0, FPCSG01180, "PCSG01180"}},
// 黒蝶のサイケデリカ
{0x80043538, {CODEC_UTF8, 1, 0, 0, FPCSG00468, "PCSG00468"}},
// 灰鷹のサイケデリカ
{0x80022c06, {CODEC_UTF8, 4, 0, 0, FPCSG00468, "PCSG00812"}},
// 悠久のティアブレイド -Lost Chronicle-
{0x8003542a, {CODEC_UTF8, 10, 0, 0, FPCSG00808, "PCSG00808"}},
{0x8002a95a, {CODEC_UTF8, 6, 0, 0, FPCSG00808, "PCSG00808"}},
{0x801a98aa, {CODEC_UTF8, 9, 0, 0, FPCSG00808, "PCSG00808"}},
{0x801a42bc, {CODEC_UTF8, 9, 0, 0, FPCSG00808, "PCSG00808"}},
{0x801a42d0, {CODEC_UTF8, 7, 0, 0, FPCSG00808, "PCSG00808"}},
// 悠久のティアブレイド -Fragments of Memory-
{0x80035f44, {CODEC_UTF8, 10, 0, 0, FPCSG01075, "PCSG01075"}},
{0x8000d868, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
{0x8004598e, {CODEC_UTF8, 0, 0, 0, FPCSG01075, "PCSG01075"}},
{0x801b1d16, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
{0x801ac31e, {CODEC_UTF8, 9, 0, 0, FPCSG01075, "PCSG01075"}},
{0x801ac33a, {CODEC_UTF8, 7, 0, 0, FPCSG01075, "PCSG01075"}},
{0x801b879a, {CODEC_UTF8, 5, 0, 0, FPCSG01075, "PCSG01075"}},
{0x8009f570, {CODEC_UTF8, 5, 0, 0, FPCSG01075, "PCSG01075"}},
// マジきゅんっ!ルネッサンス
{0x8008375a, {0, 1, 0, 0, FPCSG00852, "PCSG00852"}},
{0x8001c194, {0, 1, 0, 0, FPCSG00852, "PCSG00852"}},
// 蝶々事件ラブソディック
{0x8008dea2, {CODEC_UTF8, 4, 0, 0, FPCSG01066, "PCSG01066"}},
{0x8008eb38, {CODEC_UTF8, 0, 0, 0, FPCSG01066, "PCSG01066"}},
// 百華夜光
{0x80032b30, {0, 8, 0, 0, 0, "PCSG00477"}},
{0x80019c5a, {0, 5, 0, 0, 0, "PCSG00477"}},
{0x80031a46, {0, 6, 0, 0, 0, "PCSG00477"}},
{0x8003a49a, {0, 0, 0, 0, FPCSG00477, "PCSG00477"}},
{0x80182532, {0, 7, 0, 0, FPCSG00477, "PCSG00477"}},
{0x8017d1da, {0, 5, 0, 0, 0, "PCSG00477"}},
{0x8017d478, {0, 4, 0, 0, 0, "PCSG00477"}},
{0x8017a6aa, {0, 6, 0, 0, 0, "PCSG00477"}},
// 花朧 ~戦国伝乱奇~
{0x80037600, {CODEC_UTF8, 6, 0, 0, FPCSG00855, "PCSG00855"}},
{0x80036580, {CODEC_UTF8, 6, 0, 0, FPCSG00855, "PCSG00855"}},
{0x801a2ada, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<0>, "PCSG00855"}},
{0x801a2ba8, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<1>, "PCSG00855"}},
{0x801a2d9e, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<2>, "PCSG00855"}},
{0x801a2e68, {CODEC_UTF8, 0, 0, 0, FPCSG00855_2<3>, "PCSG00855"}},
// サイキックエモーション ムー
{0x80035948, {CODEC_UTF8, 9, 0, 0, FPCSG00815, "PCSG00815"}},
{0x80034580, {CODEC_UTF8, 6, 0, 0, FPCSG00815, "PCSG00815"}},
// Code:Realize ~白銀の奇跡~
{0x80015bcc, {CODEC_UTF8, 0, 0x1c, 0, F010088B01A8FC000, "PCSG01110"}},
{0x80038e76, {CODEC_UTF8, 8, 0, 0, F010088B01A8FC000, "PCSG01110"}},
// オメルタ CODE:TYCOON 戒
{0x800BC462, {0, 3, 0, 0, F010088B01A8FC000, "PCSG00789"}},
// 紅色天井艶妖綺譚 二藍
{0x8003F554, {0, 4, 0, 0, FPCSG00852, "PCSG01221"}},
// 絶対迷宮 秘密のおやゆび姫
{0x8003F554, {0, 5, 0, 0, 0, "PCSG00611"}},
// 鏡界の白雪
{0x810286C8, {CODEC_UTF8, 0, 0, 0, PCSG00787, "PCSG00787"}}, // VPK版手动复制安装
{0x8002BB78, {CODEC_UTF8, 0, 0, 0, PCSG00787, "PCSG00787"}}, // zip安装版
// ニセコイ ヨメイリ!?
{0x8189e60c, {CODEC_UTF8, 4, 0, 0, 0, "PCSG00397"}},
};
return 1;
}();
}