diff --git a/solution/ed_voice/ed_voice.vcxproj b/solution/ed_voice/ed_voice.vcxproj index 0e01602..c9304b2 100644 --- a/solution/ed_voice/ed_voice.vcxproj +++ b/solution/ed_voice/ed_voice.vcxproj @@ -55,6 +55,7 @@ + @@ -72,6 +73,7 @@ + diff --git a/solution/ed_voice/ed_voice.vcxproj.filters b/solution/ed_voice/ed_voice.vcxproj.filters index 8b6cfdf..d7af0c6 100644 --- a/solution/ed_voice/ed_voice.vcxproj.filters +++ b/solution/ed_voice/ed_voice.vcxproj.filters @@ -228,5 +228,11 @@ src\player + + src\asm + + + src\startup + \ No newline at end of file diff --git a/src/ed_voice/asm/asm.h b/src/ed_voice/asm/asm.h index 2a4efa6..3ba4fdd 100644 --- a/src/ed_voice/asm/asm.h +++ b/src/ed_voice/asm/asm.h @@ -9,6 +9,14 @@ void textse(); void dlgse(); } // namespace asm_tits +namespace asm_titsl { + void text(); + void ldat(); + void dcdat(); + void textse(); + void dlgse(); +} // namespace asm_titsl + namespace asm_sora { void text(); void ldat(); diff --git a/src/ed_voice/asm/asm_tits.cpp b/src/ed_voice/asm/asm_tits.cpp index 0bd3428..b82eb4f 100644 --- a/src/ed_voice/asm/asm_tits.cpp +++ b/src/ed_voice/asm/asm_tits.cpp @@ -13,7 +13,7 @@ __declspec(naked) void asm_tits::text() { jmp common fc: - push ebx + push esi common: call bridge::Play @@ -28,8 +28,12 @@ __declspec(naked) void asm_tits::text() { __declspec(naked) void asm_tits::ldat() { __asm { - call bridge::LoadDat + push edx + push ecx + call bridge::LoadDatF test eax, eax + pop ecx + pop edx je short next ret @@ -40,12 +44,14 @@ __declspec(naked) void asm_tits::ldat() { __declspec(naked) void asm_tits::dcdat() { __asm { - push edi - push ebx + pushad + push edx + push ecx push 0 call bridge::DecompressDat add esp, 12 test eax, eax + popad je short next ret @@ -69,22 +75,20 @@ __declspec(naked) void asm_tits::textse() { __declspec(naked) void asm_tits::dlgse() { __asm { + pushad + call bridge::Stop + popad + cmp dword ptr[global.sigs.no_dlgse], 0 - je short next + je short jump mov dword ptr[global.sigs.no_dlgse], 0 cmp dword ptr[global.config.disable_dialog_se], 0 - je short next + je short jump - pushad - call bridge::Stop - popad - jmp dword ptr[global.addrs.dlgse_jmp] + ret - next : - pushad - call bridge::Stop - popad - jmp dword ptr[global.addrs.dlgse_next] + jump : + jmp dword ptr[global.addrs.dlgse_jmp] } } diff --git a/src/ed_voice/asm/asm_titsl.cpp b/src/ed_voice/asm/asm_titsl.cpp new file mode 100644 index 0000000..2087322 --- /dev/null +++ b/src/ed_voice/asm/asm_titsl.cpp @@ -0,0 +1,90 @@ +#include "asm/asm.h" +#include "bridge/bridge.h" +#include "global/global.h" + +__declspec(naked) void asm_titsl::text() { + __asm { + jne short next + pushad + + cmp dword ptr[global.info.game], GameTitsFC + je short fc + push edi + jmp common + + fc: + push ebx + + common: + call bridge::Play + + popad + jmp dword ptr[global.addrs.text_next] + + next : + jmp dword ptr[global.addrs.text_jmp] + } +} + +__declspec(naked) void asm_titsl::ldat() { + __asm { + call bridge::LoadDat + test eax, eax + je short next + ret + + next : + jmp dword ptr[global.addrs.ldat_next]; + } +} + +__declspec(naked) void asm_titsl::dcdat() { + __asm { + push edi + push ebx + push 0 + call bridge::DecompressDat + add esp, 12 + test eax, eax + je short next + ret + + next : + jmp dword ptr[global.addrs.dcdat_next] + } +} + +__declspec(naked) void asm_titsl::textse() { + __asm { + cmp dword ptr[global.sigs.no_textse], 0 + je short next + cmp dword ptr[global.config.disable_text_se], 0 + je short next + jmp dword ptr[global.addrs.textse_jmp] + + next : + jmp dword ptr[global.addrs.textse_next] + } +} + +__declspec(naked) void asm_titsl::dlgse() { + __asm { + cmp dword ptr[global.sigs.no_dlgse], 0 + je short next + mov dword ptr[global.sigs.no_dlgse], 0 + cmp dword ptr[global.config.disable_dialog_se], 0 + je short next + + pushad + call bridge::Stop + popad + jmp dword ptr[global.addrs.dlgse_jmp] + + next : + pushad + call bridge::Stop + popad + jmp dword ptr[global.addrs.dlgse_next] + } +} + diff --git a/src/ed_voice/bridge/bridge.h b/src/ed_voice/bridge/bridge.h index 777b358..8dda8cf 100644 --- a/src/ed_voice/bridge/bridge.h +++ b/src/ed_voice/bridge/bridge.h @@ -7,6 +7,7 @@ int __stdcall Play(void* b); int __cdecl Stop(); int __cdecl LoadDat(void*, void* buff, int idx, unsigned offset, unsigned size); +int __cdecl LoadDatF(void* buff, int idx, void*, unsigned offset, unsigned size); int __cdecl LoadDat2(void*, void* buff, int idx); int __cdecl DecompressDat(void*, void** uncompressed, void** compressed); diff --git a/src/ed_voice/bridge/bridge_dat.cpp b/src/ed_voice/bridge/bridge_dat.cpp index 587df92..ba86f5c 100644 --- a/src/ed_voice/bridge/bridge_dat.cpp +++ b/src/ed_voice/bridge/bridge_dat.cpp @@ -75,6 +75,10 @@ inline const char* GetDir(int idx) { } // namespace +int __cdecl bridge::LoadDatF(void* buff, int idx, void*, unsigned offset, unsigned size) { + return bridge::LoadDat(nullptr, buff, idx, offset, size); +} + int __cdecl bridge::LoadDat(void*, void* buff, int idx, unsigned offset, unsigned size) { const char* dir = GetDir(idx); if (!dir) { diff --git a/src/ed_voice/startup/scan_group_common.h b/src/ed_voice/startup/scan_group_common.h index 13d0711..f389c57 100644 --- a/src/ed_voice/startup/scan_group_common.h +++ b/src/ed_voice/startup/scan_group_common.h @@ -72,6 +72,8 @@ class ScanGroupCommon : public ScanGroup { strings_.push_back(std::make_unique(kCodeBackupBlockSize)); code_bak_ = (byte*)strings_.back().get(); code_bak_remian = kCodeBackupBlockSize; + utils::MemProtection proction_bak; + utils::ChangeMemProtection(code_bak_, kCodeBackupBlockSize, utils::kMemProtectionRWE, &proction_bak); } bool InSection(const char* sec_name, byte* begin, std::size_t length) const { @@ -83,7 +85,11 @@ class ScanGroupCommon : public ScanGroup { return false; } const auto& sec = it->second; - return begin >= sec.start && begin + length <= sec.end; + if (length > sec.size) { + return false; + } + return (unsigned long long)begin >= (unsigned long long)sec.start + && (unsigned long long)begin <= (unsigned long long)sec.end - length; } byte* GetCodeBackupBlock(std::size_t length) { @@ -228,21 +234,6 @@ class ScanGroupCommon : public ScanGroup { ScanGroupCommon& operator=(const ScanGroupCommon&) = delete; }; // ScanGroupCommon -class PieceCommon : public ScanGroupCommon::BasicPiece { -public: - PieceCommon(std::string_view pattern, ScanGroupCommon::PatternType pattern_type, - ScanGroupCommon* group) - : ScanGroupCommon::BasicPiece(pattern, pattern_type), Group{ group } { - } - - bool InSection(byte* p, std::size_t len) { - - } - -protected: - ScanGroupCommon* const Group; -}; - } // namespace startup #define DEFINE_GROUP_BEGIN(GroupName_) \ diff --git a/src/ed_voice/startup/scan_group_tits.cpp b/src/ed_voice/startup/scan_group_tits.cpp index 46a5fd5..177660a 100644 --- a/src/ed_voice/startup/scan_group_tits.cpp +++ b/src/ed_voice/startup/scan_group_tits.cpp @@ -30,24 +30,31 @@ DEFINE_APPLY_BEGIN() void** addr = *(void***)(results.front() + 17); global.addrs.pHwnd = addr; LOG("pHwnd = 0x%08X", (unsigned)global.addrs.pHwnd); -DEFINE_APPLY_END(true) -DEFINE_PIECE_END(Hwnd) + DEFINE_APPLY_END(true) + DEFINE_PIECE_END(Hwnd) -DEFINE_PIECE_BEGIN(Tits, Text, ".text", PatternType::Bytes, - "80 F9 23 0F 85 ?? ?? ?? ?? ?? ?? ?? ??") + DEFINE_PIECE_BEGIN(Tits, Text, ".text", PatternType::Bytes, + "23 " "0F 85 ?? ?? ?? ??") + const utils::MemMatcher matcher_fc = utils::MemMatcher( + "80 F9 23", PatternType::Bytes); + const utils::MemMatcher matcher_sc = utils::MemMatcher( + "8B 74 24 20 E9 ?? ?? ?? ?? 3C 23", PatternType::Bytes); + const utils::MemMatcher matcher_3rd = utils::MemMatcher( + "89 B3 ?? ?? ?? ?? E9 ?? ?? ?? ?? 3C 23", PatternType::Bytes); DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) - byte* dst = utils::GetCallJmpDest(b + 3, 6); - bool rst = Group->InSection(".text", dst, 1); + byte* dst = utils::GetCallJmpDest(b + 1, 6); + bool rst = Group->InSection(".text", dst, 1) + && (matcher_fc.Match(b - 2) || matcher_sc.Match(b - 10) || matcher_3rd.Match(b - 12)); DEFINE_ADDITIONAL_MATCH_END(rst) DEFINE_CHECK_RESULTS_BEGIN() bool rst = !GetResults().empty(); DEFINE_CHECK_RESULTS_END(rst) DEFINE_APPLY_BEGIN() const auto& results = GetResults(); - byte* p = results.front() + 3; + byte* p = results.back() + 1; bool rst = Group->RedirectWithJmp( p, 6, asm_tits::text, &global.addrs.text_next, &global.addrs.text_jmp); - if (*(p + 9) == 0x43) { + if (*(p + 9) == 0x46) { global.info.game = GameTitsFC; } else { global.info.game = GameTitsSC3rd; @@ -65,32 +72,45 @@ DEFINE_PIECE_BEGIN(Tits, Ldat, ".text", PatternType::Bytes, const utils::MemMatcher matcher_en = utils::MemMatcher( "81 EC 84 02 00 00", PatternType::Bytes); DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) - bool rst = (matcher_cn.Match(b - 0x19) || matcher_en.Match(b - 0x19)) - && REF_STRING(".text", b + 1, ".rdata", L"ED6_DT%02x.DAT"); + bool rst = REF_STRING(".text", b + 1, ".rdata", L"ED6_DT%02x.DAT"); + if (rst) { + for (int i = 5; i <= 0x20; i++) { + if (matcher_cn.Match(b - i) || matcher_en.Match(b - i)) { + rst = true; + break; + } + } + } DEFINE_ADDITIONAL_MATCH_END(rst) DEFINE_CHECK_RESULTS_BEGIN() bool rst = !GetResults().empty(); DEFINE_CHECK_RESULTS_END(rst) DEFINE_APPLY_BEGIN() const auto& results = GetResults(); - byte* p = results.front() - 0x19; + byte* p = results.front(); bool rst = false; - if (*p == 0x81) { - rst = Group->BackupCode(p, 6, asm_tits::ldat, &global.addrs.ldat_next); - } else { - rst = Group->RedirectWithJmp(p, 5, asm_tits::ldat, nullptr, &global.addrs.ldat_next); + for (int i = 5; i <= 0x20; i++) { + if (matcher_cn.Match(p - i)) { + rst = Group->RedirectWithJmp(p - i, 5, asm_tits::ldat, nullptr, &global.addrs.ldat_next); + LOG("Apply at 0x%08X", unsigned(p - i)); + LOG("ldat_next = 0x%08X", (unsigned)global.addrs.ldat_next); + break; + } else if (matcher_en.Match(p - i)) { + rst = Group->BackupCode(p - i, 6, asm_tits::ldat, &global.addrs.ldat_next); + LOG("Apply at 0x%08X", unsigned(p - i)); + LOG("ldat_next = 0x%08X", (unsigned)global.addrs.ldat_next); + break; + } } - LOG("Apply at 0x%08X", unsigned(p)); - LOG("ldat_next = 0x%08X", (unsigned)global.addrs.ldat_next); DEFINE_APPLY_END(rst) DEFINE_PIECE_END(Ldat) DEFINE_PIECE_BEGIN(Tits, Dcdat, ".text", PatternType::Bytes, - "89 44 24 04 8B 07 56") + "57 8B D9 C7 44 24 18 00 00 00 00") const utils::MemMatcher matcher_cn = utils::MemMatcher( "E9 ?? ?? ?? ??", PatternType::Bytes); const utils::MemMatcher matcher_en = utils::MemMatcher( - "83 EC 18 8B 03", PatternType::Bytes); + "83 EC 18 53 56", PatternType::Bytes); DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) bool rst = matcher_cn.Match(b - 5) || matcher_en.Match(b - 5); DEFINE_ADDITIONAL_MATCH_END(rst) @@ -112,7 +132,7 @@ DEFINE_APPLY_END(rst) DEFINE_PIECE_END(Dcdat) DEFINE_PIECE_BEGIN(Tits, Pdirs, ".text", PatternType::Bytes, - "C1 E9 10 8B 3C 8D ?? ?? ?? 00") + "8D 0C C0 8B 04 95 ?? ?? ?? 00") DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) bool rst = Group->InSection(".data", *(byte**)(b + 6), sizeof(byte*) * 0x20) && REF_STRING(".data", *(byte**)(b + 6) + 6 * sizeof(byte*), "", "CH20000 ._CH") @@ -132,11 +152,9 @@ DEFINE_APPLY_END(rst) DEFINE_PIECE_END(Pdirs) DEFINE_PIECE_BEGIN(Tits, Textse, ".text", PatternType::Bytes, - "57 " "FF D2 " "80 3D ?? ?? ?? ?? 00 " "75 11") + "74 1E " "80 3D ?? ?? ?? ?? 00 " "75 ?? " "6A 00") DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) - bool rst = Group->InSection(".data", *(byte**)(b + 5), sizeof(byte*)) - && Group->InSection(".text", b + 0x2C, sizeof(byte*)) - && *(b + 0x2C) == 0xC3; + bool rst = Group->InSection(".data", *(byte**)(b + 4), sizeof(byte*)); DEFINE_ADDITIONAL_MATCH_END(rst) DEFINE_CHECK_RESULTS_BEGIN() bool rst = !GetResults().empty(); @@ -144,18 +162,18 @@ DEFINE_CHECK_RESULTS_END(rst) DEFINE_APPLY_BEGIN() const auto& results = GetResults(); byte* p = results.front(); - global.addrs.textse_jmp = utils::GetCallJmpDest(p + 10, 2); - bool rst = Group->BackupCode(p + 12, 6, asm_tits::textse, &global.addrs.textse_next); - LOG("Apply at 0x%08X", unsigned(p + 12)); + global.addrs.textse_jmp = utils::GetCallJmpDest(p + 9, 2); + bool rst = Group->BackupCode(p + 2, 7, asm_tits::textse, &global.addrs.textse_next); + LOG("Apply at 0x%08X", unsigned(p + 2)); LOG("textse_jmp = 0x%08X", (unsigned)global.addrs.textse_jmp); LOG("textse_next = 0x%08X", (unsigned)global.addrs.textse_next); DEFINE_APPLY_END(rst) DEFINE_PIECE_END(Textse) DEFINE_PIECE_BEGIN(Tits, Dlgse, ".text", PatternType::Bytes, - "57 " "FF D0 " "80 3D ?? ?? ?? ?? 00 " "75 11") + "6A 00 " "89 86 ?? ?? ?? ?? " "E8 ?? ?? ?? ?? " "83 C4 0C") DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) - bool rst = Group->InSection(".data", *(byte**)(b + 5), sizeof(byte*)); + bool rst = true; DEFINE_ADDITIONAL_MATCH_END(rst) DEFINE_CHECK_RESULTS_BEGIN() bool rst = !GetResults().empty(); @@ -163,15 +181,14 @@ DEFINE_CHECK_RESULTS_END(rst) DEFINE_APPLY_BEGIN() const auto& results = GetResults(); byte* p = results.front(); - global.addrs.dlgse_jmp = utils::GetCallJmpDest(p + 10, 2); - bool rst = Group->BackupCode(p + 3, 7, asm_tits::dlgse, &global.addrs.dlgse_next); - LOG("Apply at 0x%08X", unsigned(p + 3)); + bool rst = Group->RedirectWithCall(p + 8, 5, asm_tits::dlgse, &global.addrs.dlgse_next, &global.addrs.dlgse_jmp); + LOG("Apply at 0x%08X", unsigned(p + 8)); LOG("dlgse_jmp = 0x%08X", (unsigned)global.addrs.dlgse_jmp); LOG("dlgse_next = 0x%08X", (unsigned)global.addrs.dlgse_next); DEFINE_APPLY_END(rst) DEFINE_PIECE_END(Dlgse) -DEFINE_PIECE_BEGIN(Tits, Strpatch, ".text", PatternType::Bytes, "68 ?? ?? ?? 00") +DEFINE_PIECE_BEGIN(Tits, Strpatch, ".text", PatternType::Bytes, "?? ?? ?? ?? 00") const startup::PatchingStrings strs_map_ = startup::LoadPatchingStrings(); mutable std::unordered_map to_patch_; DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) @@ -203,7 +220,7 @@ DEFINE_APPLY_BEGIN() DEFINE_APPLY_END(true) DEFINE_PIECE_END(Strpatch) -DEFINE_PIECE_BEGIN(Tits, Strpatch2, ".text", PatternType::Bytes, "68 ?? ?? ?? 00") +DEFINE_PIECE_BEGIN(Tits, Strpatch2, ".text", PatternType::Bytes, "?? ?? ?? ?? 00") const startup::RefPatchingStrings strs_map_ = startup::LoadRefPatchingStrings("voice/scena/Z_POKER9._DT"); mutable int diff = std::numeric_limits::max(); @@ -244,15 +261,20 @@ DEFINE_APPLY_BEGIN() LOG("%d Strings Patched.", count); #ifdef LOG if (!GetResults().empty()) { - std::string zero; + std::string zero, mul; for (const auto& kv : cnts) { if (kv.second == 0) { zero += std::to_string(kv.first) + ","; + } else if (kv.second > 1) { + mul += std::to_string(kv.first) + ","; } } if (!zero.empty()) { LOG("These strings loaded, but not used: \n%s", zero.c_str()); } + if (!mul.empty()) { + LOG("These strings used more than once: \n%s", mul.c_str()); + } } #endif DEFINE_APPLY_END(true) diff --git a/src/ed_voice/startup/scan_group_titsl.cpp b/src/ed_voice/startup/scan_group_titsl.cpp new file mode 100644 index 0000000..6d46260 --- /dev/null +++ b/src/ed_voice/startup/scan_group_titsl.cpp @@ -0,0 +1,278 @@ +#include "startup/scan_group_common.h" + +#include + +#include "asm/asm.h" +#include "global/global.h" +#include "startup/string_patch.h" +#include "utils/log.h" +#include "utils/mem.h" +#include "utils/section_info.h" + +namespace { + +DEFINE_GROUP_BEGIN(Titsl) + +DEFINE_PIECE_BEGIN(Titsl, Hwnd, ".text", PatternType::Bytes, + "68 ?? ?? ?? 00 " + "68 00 00 04 00 " + "FF ?? ?? ?? ?? 00 " + "A3 ?? ?? ?? 00 " + "85 C0") +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + bool rst = REF_STRING(".text", b + 1, ".rdata", L"Falcom"); +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = !GetResults().empty(); +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + const auto& results = GetResults(); + void** addr = *(void***)(results.front() + 17); + global.addrs.pHwnd = addr; + LOG("pHwnd = 0x%08X", (unsigned)global.addrs.pHwnd); +DEFINE_APPLY_END(true) +DEFINE_PIECE_END(Hwnd) + +DEFINE_PIECE_BEGIN(Titsl, Text, ".text", PatternType::Bytes, + "80 F9 23 0F 85 ?? ?? ?? ?? ?? ?? ?? ??") +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + byte* dst = utils::GetCallJmpDest(b + 3, 6); + bool rst = Group->InSection(".text", dst, 1); +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = !GetResults().empty(); +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + const auto& results = GetResults(); + byte* p = results.front() + 3; + bool rst = Group->RedirectWithJmp( + p, 6, asm_titsl::text, &global.addrs.text_next, &global.addrs.text_jmp); + if (*(p + 9) == 0x43) { + global.info.game = GameTitsFC; + } else { + global.info.game = GameTitsSC3rd; + } + LOG("Apply at 0x%08X", unsigned(p)); + LOG("text_next = 0x%08X", (unsigned)global.addrs.text_next); + LOG("text_jmp = 0x%08X", (unsigned)global.addrs.text_jmp); +DEFINE_APPLY_END(rst) +DEFINE_PIECE_END(Text) + +DEFINE_PIECE_BEGIN(Titsl, Ldat, ".text", PatternType::Bytes, + "68 ?? ?? ?? ??") + const utils::MemMatcher matcher_cn = utils::MemMatcher( + "E9 ?? ?? ?? ?? 90", PatternType::Bytes); + const utils::MemMatcher matcher_en = utils::MemMatcher( + "81 EC 84 02 00 00", PatternType::Bytes); +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + bool rst = (matcher_cn.Match(b - 0x19) || matcher_en.Match(b - 0x19)) + && REF_STRING(".text", b + 1, ".rdata", L"ED6_DT%02x.DAT"); +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = !GetResults().empty(); +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + const auto& results = GetResults(); + byte* p = results.front() - 0x19; + bool rst = false; + if (*p == 0x81) { + rst = Group->BackupCode(p, 6, asm_titsl::ldat, &global.addrs.ldat_next); + } else { + rst = Group->RedirectWithJmp(p, 5, asm_titsl::ldat, nullptr, &global.addrs.ldat_next); + } + LOG("Apply at 0x%08X", unsigned(p)); + LOG("ldat_next = 0x%08X", (unsigned)global.addrs.ldat_next); +DEFINE_APPLY_END(rst) +DEFINE_PIECE_END(Ldat) + +DEFINE_PIECE_BEGIN(Titsl, Dcdat, ".text", PatternType::Bytes, + "89 44 24 04 8B 07 56") + const utils::MemMatcher matcher_cn = utils::MemMatcher( + "E9 ?? ?? ?? ??", PatternType::Bytes); + const utils::MemMatcher matcher_en = utils::MemMatcher( + "83 EC 18 8B 03", PatternType::Bytes); +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + bool rst = matcher_cn.Match(b - 5) || matcher_en.Match(b - 5); +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = !GetResults().empty(); +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + const auto& results = GetResults(); + byte* p = results.front() - 5; + bool rst = false; + if (*p == 0x83) { + rst = Group->BackupCode(p, 5, asm_titsl::dcdat, &global.addrs.dcdat_next); + } else { + rst = Group->RedirectWithJmp(p, 5, asm_titsl::dcdat, nullptr, &global.addrs.dcdat_next); + } + LOG("Apply at 0x%08X", unsigned(p)); + LOG("dcdat_next = 0x%08X", (unsigned)global.addrs.dcdat_next); +DEFINE_APPLY_END(rst) +DEFINE_PIECE_END(Dcdat) + +DEFINE_PIECE_BEGIN(Titsl, Pdirs, ".text", PatternType::Bytes, + "C1 E9 10 8B 3C 8D ?? ?? ?? 00") +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + bool rst = Group->InSection(".data", *(byte**)(b + 6), sizeof(byte*) * 0x20) + && REF_STRING(".data", *(byte**)(b + 6) + 6 * sizeof(byte*), "", "CH20000 ._CH") + && REF_STRING(".data", *(byte**)(b + 6) + 7 * sizeof(byte*), "", "CH00000 ._CH") + && REF_STRING(".data", *(byte**)(b + 6) + 9 * sizeof(byte*), "", "CH10000 ._CH"); +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = !GetResults().empty(); +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + const auto& results = GetResults(); + byte* p = results.front(); + global.addrs.pdirs = *(byte**)(p + 6); + LOG("pdirs = 0x%08X", (unsigned)global.addrs.pdirs); + bool rst = true; +DEFINE_APPLY_END(rst) +DEFINE_PIECE_END(Pdirs) + +DEFINE_PIECE_BEGIN(Titsl, Textse, ".text", PatternType::Bytes, + "57 " "FF D2 " "80 3D ?? ?? ?? ?? 00 " "75 11") +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + bool rst = Group->InSection(".data", *(byte**)(b + 5), sizeof(byte*)) + && Group->InSection(".text", b + 0x2C, sizeof(byte*)) + && *(b + 0x2C) == 0xC3; +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = !GetResults().empty(); +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + const auto& results = GetResults(); + byte* p = results.front(); + global.addrs.textse_jmp = utils::GetCallJmpDest(p + 10, 2); + bool rst = Group->BackupCode(p + 12, 6, asm_titsl::textse, &global.addrs.textse_next); + LOG("Apply at 0x%08X", unsigned(p + 12)); + LOG("textse_jmp = 0x%08X", (unsigned)global.addrs.textse_jmp); + LOG("textse_next = 0x%08X", (unsigned)global.addrs.textse_next); +DEFINE_APPLY_END(rst) +DEFINE_PIECE_END(Textse) + +DEFINE_PIECE_BEGIN(Titsl, Dlgse, ".text", PatternType::Bytes, + "57 " "FF D0 " "80 3D ?? ?? ?? ?? 00 " "75 11") +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + bool rst = Group->InSection(".data", *(byte**)(b + 5), sizeof(byte*)); +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = !GetResults().empty(); +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + const auto& results = GetResults(); + byte* p = results.front(); + global.addrs.dlgse_jmp = utils::GetCallJmpDest(p + 10, 2); + bool rst = Group->BackupCode(p + 3, 7, asm_titsl::dlgse, &global.addrs.dlgse_next); + LOG("Apply at 0x%08X", unsigned(p + 3)); + LOG("dlgse_jmp = 0x%08X", (unsigned)global.addrs.dlgse_jmp); + LOG("dlgse_next = 0x%08X", (unsigned)global.addrs.dlgse_next); +DEFINE_APPLY_END(rst) +DEFINE_PIECE_END(Dlgse) + +DEFINE_PIECE_BEGIN(Titsl, Strpatch, ".text", PatternType::Bytes, "68 ?? ?? ?? 00") + const startup::PatchingStrings strs_map_ = startup::LoadPatchingStrings(); + mutable std::unordered_map to_patch_; +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + bool rst = false; + for (auto it = strs_map_.cbegin(); it != strs_map_.cend(); ++it) { + if (REF_STRING(".text", b + 1, ".rdata", it->first)) { + to_patch_[b] = it; + rst = true; + } + } +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = true; +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + int count = 0; + for (const auto& kv : to_patch_) { + LOG("Patch at: 0x%08X", (unsigned)kv.first); + LOG("String old: %s", kv.second->first.c_str()); + LOG("String new: %s", kv.second->second.c_str()); + if (Group->RefPatchString(kv.first + 1, kv.second->second)) { + LOG("Patch Succeeded."); + count++; + } else { + LOG("Patch Failed."); + } + } + LOG("%d Strings Patched.", count); +DEFINE_APPLY_END(true) +DEFINE_PIECE_END(Strpatch) + +DEFINE_PIECE_BEGIN(Titsl, Strpatch2, ".text", PatternType::Bytes, "68 ?? ?? ?? 00") + const startup::RefPatchingStrings strs_map_ + = startup::LoadRefPatchingStrings("voice/scena/Z_POKER9._DT"); + mutable int diff = std::numeric_limits::max(); +DEFINE_ADDITIONAL_MATCH_BEGIN(b, e) + bool rst = false; + if (!std::get<2>(strs_map_).empty()) { + if (GetResults().empty()) { + if (REF_STRING(".text", b + 1, ".rdata", std::get<1>(strs_map_))) { + diff = (byte*)std::get<0>(strs_map_) - *(byte**)(b + 1); + rst = true; + } + } else { + rst = std::get<2>(strs_map_).count(*(int*)(b + 1) + diff); + } + } +DEFINE_ADDITIONAL_MATCH_END(rst) +DEFINE_CHECK_RESULTS_BEGIN() + bool rst = true; +DEFINE_CHECK_RESULTS_END(rst) +DEFINE_APPLY_BEGIN() + int count = 0; +#ifdef LOG + std::unordered_map cnts; + for (const auto& kv : std::get<2>(strs_map_)) { + cnts[kv.first] = 0; + } +#endif + for (byte* b : GetResults()) { + int offset = *(int*)(b + 1) + diff; + const std::string& s = std::get<2>(strs_map_).find(offset)->second; + if (Group->RefPatchString(b + 1, s)) { + count++; +#ifdef LOG + cnts[offset]++; +#endif + } + } + LOG("%d Strings Patched.", count); +#ifdef LOG + if (!GetResults().empty()) { + std::string zero; + for (const auto& kv : cnts) { + if (kv.second == 0) { + zero += std::to_string(kv.first) + ","; + } + } + if (!zero.empty()) { + LOG("These strings loaded, but not used: \n%s", zero.c_str()); + } + } +#endif +DEFINE_APPLY_END(true) +DEFINE_PIECE_END(Strpatch2) + +ADD_PIECES_BEGIN() +ADD_PIECE(Hwnd) +ADD_PIECE(Text) +ADD_PIECE(Ldat) +ADD_PIECE(Dcdat) +ADD_PIECE(Pdirs) +ADD_PIECE(Textse) +ADD_PIECE(Dlgse) +ADD_PIECE(Strpatch) +ADD_PIECE(Strpatch2) +ADD_PIECES_END() + +DEFINE_GROUP_END() +} // namespace + +namespace startup { +DEFINE_STATIC_GET_GROUP(Titsl); +} // namespace startup diff --git a/src/ed_voice/startup/scan_groups_dcl.h b/src/ed_voice/startup/scan_groups_dcl.h index d5d6ce6..b11cd9b 100644 --- a/src/ed_voice/startup/scan_groups_dcl.h +++ b/src/ed_voice/startup/scan_groups_dcl.h @@ -15,12 +15,14 @@ namespace startup { DECLARE_SCAN_GROUP(Tits); +DECLARE_SCAN_GROUP(Titsl); DECLARE_SCAN_GROUP(Za); DECLARE_SCAN_GROUP(Sora); } // namespace startup #define GET_SCAN_GROUP_FUN_LIST { \ GET_SCAN_GROUP_FUN(Tits), \ + GET_SCAN_GROUP_FUN(Titsl), \ GET_SCAN_GROUP_FUN(Sora), \ GET_SCAN_GROUP_FUN(Za), \ } diff --git a/src/ed_voice/startup/string_patch.cpp b/src/ed_voice/startup/string_patch.cpp index 932fd7b..8816658 100644 --- a/src/ed_voice/startup/string_patch.cpp +++ b/src/ed_voice/startup/string_patch.cpp @@ -11,6 +11,7 @@ constexpr struct { const char* str_old; const char* str_new; } kDirectPatchingStrings[] = { + {"%c#2C\n#56IEarth Sepith x%d,\n#57IWater Sepith x%d,\n#58IFire Sepith x%d,\n#59IWind Sepith x%d,\n#62ITime Sepith x%d,\n#60ISpace Sepith x%d,\n#0and#2C #61IMirage Sepith x%d#0.", "%c#2C\n#56IEarth Sepith x%d,\n#57IWater Sepith x%d,\n#58IFire Sepith x%d,\n#59IWind Sepith x%d,\n#62ITime Sepith x%d,\n#60ISpace Sepith x%d,\n#0Cand#2C #61IMirage Sepith x%d#0C."} };