Files
esuo1198_TaikoArcadeLoader/src/patches/versions/JPN39.cpp
T

460 lines
22 KiB
C++

// ReSharper disable CppTooWideScopeInitStatement
#include "helpers.h"
#include "../patches.h"
#include <map>
namespace patches::JPN39 {
int language = 0;
FAST_HOOK_DYNAMIC (char, AMFWTerminate, i64) {
LogMessage (LogLevel::HOOKS, "AMFWTerminate was called");
return 0;
}
FAST_HOOK_DYNAMIC (i64, curl_easy_setopt, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5) {
LogMessage (LogLevel::HOOKS, "Garmc curl_easy_setopt was called");
originalcurl_easy_setopt.call<i64> (a1, 64, 0, 0, 0);
originalcurl_easy_setopt.call<i64> (a1, 81, 0, 0, 0);
return originalcurl_easy_setopt.call<i64> (a1, a2, a3, a4, a5);
}
FAST_HOOK_DYNAMIC (void, garmc_logger_log, i64 a1, int a2, void *a3, char a4) {
// remove garmc log
return;
}
FUNCTION_PTR (i64, GetPlayDataManagerRef, ASLR (0x140024AC0), i64);
i64 lua_State = 0;
FAST_HOOK (i64, luaL_newstate, PROC_ADDRESS ("lua51.dll", "luaL_newstate")) { return lua_State = originalluaL_newstate.call<i64> (); }
FUNCTION_PTR (void, lua_settop, PROC_ADDRESS ("lua51.dll", "lua_settop"), i64, i32);
FUNCTION_PTR (void, lua_replace, PROC_ADDRESS ("lua51.dll", "lua_replace"), i64, i32);
FUNCTION_PTR (void, lua_pushcclosure, PROC_ADDRESS ("lua51.dll", "lua_pushcclosure"), i64, i64, i32);
FUNCTION_PTR (void, lua_pushboolean, PROC_ADDRESS ("lua51.dll", "lua_pushboolean"), i64, i32);
FUNCTION_PTR (const char *, lua_pushstring, PROC_ADDRESS ("lua51.dll", "lua_pushstring"), i64, const char *);
FUNCTION_PTR (i32, lua_toboolean, PROC_ADDRESS ("lua51.dll", "lua_toboolean"), i64, i32);
FUNCTION_PTR (const char *, lua_tolstring, PROC_ADDRESS ("lua51.dll", "lua_tolstring"), u64, i32, size_t *);
FUNCTION_PTR (i32, lua_pcall, PROC_ADDRESS ("lua51.dll", "lua_pcall"), i64, i32, i32, i32);
FUNCTION_PTR (i32, luaL_loadstring, PROC_ADDRESS ("lua51.dll", "luaL_loadstring"), i64, const char *);
#define LUA_MULTRET (-1)
#define luaL_dostring(L, s) (luaL_loadstring (L, s) || lua_pcall (L, 0, LUA_MULTRET, 0))
FUNCTION_PTR (u64, RefTestModeMain, ASLR (0x1400337C0), u64);
FUNCTION_PTR (u64, RefPlayDataManager, ASLR (0x140024AC0), u64);
FUNCTION_PTR (i64, GetUserCount, ASLR (0x1403F1020), u64);
i64
lua_pushbool (const i64 a1, const bool val) {
lua_settop (a1, 0);
lua_pushboolean (a1, val);
return 1;
}
u64 appAccessor = 0;
u64 componentAccessor = 0;
FAST_HOOK (i64, DeviceCheck, ASLR (0x140464FC0), i64 a1, i64 a2, i64 a3) {
LogMessage (LogLevel::HOOKS, "DeviceCheck was called");
TestMode::SetupAccessor (a3, RefTestModeMain);
componentAccessor = a2;
appAccessor = a3;
return originalDeviceCheck.fastcall<i64> (a1, a2, a3);
}
i64
GetPlayererCount () {
if (appAccessor) {
if (const u64 playDataManager = RefPlayDataManager (appAccessor)) return GetUserCount (playDataManager);
}
return -1;
}
boolean
HaveCardPlayer () {
if (appAccessor) {
if (const u64 playDataManager = RefPlayDataManager (appAccessor)) {
int p1PlayerType = *(i32 *)(*(i64 *)(playDataManager + 9920) + 4);
int p2PlayerType = *(i32 *)(*(i64 *)(playDataManager + 9928) + 4);
return p1PlayerType == 2 || p2PlayerType == 2;
}
}
return false;
}
TestMode::Value *unlockSongs = TestMode::CreateValue (L"ModUnlockSongs");
FAST_HOOK (bool, IsSongRelease, ASLR (0x1403F4510), i64 a1, i64 a2, int a3) {
if (unlockSongs->Read () == 1) return true;
return originalIsSongRelease.fastcall<bool> (a1, a2, a3);
}
FAST_HOOK (bool, IsSongReleasePlayer, ASLR (0x1403F45F0), i64 a1, u64 a2, i32 a3) {
if (unlockSongs->Read () == 2) return true;
return originalIsSongReleasePlayer.fastcall<bool> (a1, a2, a3);
}
MID_HOOK (DifficultyPanelCrown, ASLR (0x1403F2A25), SafetyHookContext &ctx) {
if (unlockSongs->Read () != 1) return;
ctx.r15 |= 1;
}
TestMode::Value *tournmentMode = TestMode::CreateValue (L"TournamentMode");
TestMode::Value *mode024 = TestMode::CreateValue (L"ModModeCollabo024");
TestMode::Value *mode025 = TestMode::CreateValue (L"ModModeCollabo025");
TestMode::Value *mode026 = TestMode::CreateValue (L"ModModeCollabo026");
TestMode::Value *modeApril001 = TestMode::CreateValue (L"ModModeAprilFool001");
FAST_HOOK (i64, AvailableMode_Collabo024, ASLR (0x1402DE710), i64 a1) {
LogMessage (LogLevel::HOOKS, "AvailableMode_Collabo024 was called");
const int tournamentMode = tournmentMode->Read ();
if (tournamentMode == 1) return originalAvailableMode_Collabo024.fastcall<i64> (a1);
const int status = mode024->Read ();
if (status == 1 && GetPlayererCount () == 1) return lua_pushbool (a1, true);
else if (status == 2 && GetPlayererCount () == 1 && HaveCardPlayer ()) return lua_pushbool (a1, true);
return originalAvailableMode_Collabo024.fastcall<i64> (a1);
}
FAST_HOOK (i64, AvailableMode_Collabo025, ASLR (0x1402DE6B0), i64 a1) {
LogMessage (LogLevel::HOOKS, "AvailableMode_Collabo025 was called");
const int tournamentMode = tournmentMode->Read ();
if (tournamentMode == 1) return originalAvailableMode_Collabo025.fastcall<i64> (a1);
const int status = mode025->Read ();
if (status == 1 && GetPlayererCount () == 1) return lua_pushbool (a1, true);
else if (status == 2 && GetPlayererCount () == 1 && HaveCardPlayer ()) return lua_pushbool (a1, true);
return originalAvailableMode_Collabo025.fastcall<i64> (a1);
}
FAST_HOOK (i64, AvailableMode_Collabo026, ASLR (0x1402DE670), i64 a1) {
LogMessage (LogLevel::HOOKS, "AvailableMode_Collabo026 was called");
const int tournamentMode = tournmentMode->Read ();
if (tournamentMode == 1) return originalAvailableMode_Collabo026.fastcall<i64> (a1);
const int status = mode026->Read ();
if (status == 1 && GetPlayererCount () == 1) return lua_pushbool (a1, true);
else if (status == 2 && GetPlayererCount () == 1 && HaveCardPlayer ()) return lua_pushbool (a1, true);
return originalAvailableMode_Collabo026.fastcall<i64> (a1);
}
FAST_HOOK (i64, AvailableMode_AprilFool001, ASLR (0x1402DE5B0), i64 a1) {
LogMessage (LogLevel::HOOKS, "AvailableMode_AprilFool001 was called");
const int tournamentMode = tournmentMode->Read ();
if (tournamentMode == 1) return originalAvailableMode_AprilFool001.fastcall<i64> (a1);
const int status = modeApril001->Read ();
if (status == 1) return lua_pushbool (a1, true);
else if (status == 2 && HaveCardPlayer ()) return lua_pushbool (a1, true);
return originalAvailableMode_AprilFool001.fastcall<i64> (a1);
}
TestMode::Value *freezeTimer = TestMode::CreateValue (L"ModFreezeTimer");
i64 __fastcall lua_freeze_timer (const i64 a1) {
LogMessage (LogLevel::HOOKS, "lua_freeze_timer was called");
const int tournamentMode = tournmentMode->Read ();
if (tournamentMode == 1) return lua_pushbool (a1, true);
const int status = freezeTimer-> Read ();
if (status == 1) return lua_pushbool (a1, true);
return lua_pushbool (a1, false);
}
MID_HOOK (FreezeTimer, ASLR (0x14019FF51), SafetyHookContext &ctx) {
LogMessage (LogLevel::HOOKS, "FreezeTimer was called");
const auto a1 = ctx.rdi;
const int v9 = static_cast<int> (ctx.rax + 1);
lua_pushcclosure (a1, reinterpret_cast<i64> (&lua_freeze_timer), v9);
ctx.rip = ASLR (0x14019FF65);
}
void
ExecuteSendResultData () {
luaL_dostring(lua_State, R"(
local currentGameMode = PlayDataManager.GetPlayMode()
if currentGameMode == GameMode.kEnso then
if g_entryType == 0 then
NetAccess.SendResultData(0)
elseif g_entryType == 1 then
NetAccess.SendResultData(1)
else
NetAccess.SendResultData(0)
NetAccess.SendResultData(1)
end
elseif currentGameMode == GameMode.kAI then
if g_joinSide_ == 1 then
NetAccess.SendAiResultData(0)
elseif g_joinSide_ == 2 then
NetAccess.SendAiResultData(1)
end
elseif currentGameMode == GameMode.kCollabo025 then
if g_joinSide_ == 1 then
NetAccess.SendCollabo025AiResultData(0)
elseif g_joinSide_ == 2 then
NetAccess.SendCollabo025AiResultData(1)
end
elseif currentGameMode == GameMode.kCollabo026 then
if g_joinSide_ == 1 then
NetAccess.SendCollabo026AiResultData(0)
elseif g_joinSide_ == 2 then
NetAccess.SendCollabo026AiResultData(1)
end
elseif currentGameMode == GameMode.kAprilFool001 then
if g_entryType == 0 then
NetAccess.SendAprilFoolResultData(0)
elseif g_entryType == 1 then
NetAccess.SendAprilFoolResultData(1)
else
NetAccess.SendAprilFoolResultData(0)
NetAccess.SendAprilFoolResultData(1)
end
end
QR.StartQRExecAll(SceneType.kResult)
)"
);
}
SCENE_RESULT_HOOK (SceneResultInitialize_Enso, ASLR (0x140411FD0));
SCENE_RESULT_HOOK (SceneResultInitialize_AI, ASLR (0x140411FD0));
SCENE_RESULT_HOOK (SceneResultInitialize_Collabo025, ASLR (0x140411FD0));
SCENE_RESULT_HOOK (SceneResultInitialize_Collabo026, ASLR (0x140411FD0));
SCENE_RESULT_HOOK (SceneResultInitialize_AprilFool, ASLR (0x140411FD0));
SEND_RESULT_HOOK (SendResultData_Enso, ASLR (0x1401817B0));
SEND_RESULT_HOOK (SendResultData_AI, ASLR (0x1401755E0));
SEND_RESULT_HOOK (SendResultData_Collabo025_026, ASLR (0x140179A00));
SEND_RESULT_HOOK (SendResultData_AprilFool, ASLR (0x140177800));
CHANGE_RESULT_SIZE_HOOK (ChangeResultDataSize_Enso, ASLR (0x140180074), rax);
CHANGE_RESULT_SIZE_HOOK (ChangeResultDataSize_AI, ASLR (0x140173774), rax);
CHANGE_RESULT_SIZE_HOOK (ChangeResultDataSize_Collabo025_026, ASLR (0x140178244), rax);
CHANGE_RESULT_SIZE_HOOK (ChangeResultDataSize_AprilFool, ASLR (0x140176044), rax);
CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_Enso, ASLR (0x14018074B), rax, 0x34, 0x07);
CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_AI, ASLR (0x140173EDD), r13, 0x24, 0x08);
CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_Collabo025_026, ASLR (0x1401789AD), r13, 0x24, 0x08);
CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_AprilFool, ASLR (0x140176716), rax, 0x34, 0x06);
MID_HOOK (CountLockedCrown, ASLR (0x1403F2A25), SafetyHookContext &ctx) {
LogMessage (LogLevel::HOOKS, "CountLockedCrown was called");
ctx.r15 |= 1;
}
int loaded_fail_count = 0;
FAST_HOOK (char, LoadedBankAll, ASLR (0x1404EC2F0), u64 a1) {
LogMessage (LogLevel::HOOKS, "LoadedBankAll was called");
char result = originalLoadedBankAll.fastcall<char> (a1);
if (result) {
loaded_fail_count = 0;
return 1;
} else if (loaded_fail_count > 60) {
LogMessage (LogLevel::WARN, "LoadBankAll Guardian!!!");
loaded_fail_count = 0;
return 1;
} else {
loaded_fail_count += 1;
return 0;
}
}
float soundRate = 1.0F;
FAST_HOOK (i32, SetMasterVolumeSpeaker, ASLR (0x140160330), i32 a1) {
LogMessage (LogLevel::HOOKS, "SetMasterVolumeSpeaker was called");
patches::Audio::SetVolumeRate (a1 <= 100 ? 1.0f : a1 / 100.0f);
return originalSetMasterVolumeSpeaker.fastcall<i32> (a1 > 100 ? 100 : a1);
}
TestMode::Value *attractDemo = TestMode::CreateValue (L"AttractDemoItem");
MID_HOOK (AttractDemo, ASLR (0x14045A720), SafetyHookContext &ctx) {
if (attractDemo->Read () == 1) ctx.r14 = 0;
}
// HOOK (DWORD*, AcquireMostCompatibleDisplayMode, ASLR (0x14064C870), i64 a1, DWORD *a2, DWORD *a3) {
// LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]);
// a3[2] = (DWORD)(int)120.0f;
// LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]);
// return originalAcquireMostCompatibleDisplayMode (a1, a2, a3);
// }
constexpr i32 datatableBufferSize = 1024 * 1024 * 12;
uint8_t *datatableBuffer[3] = { nullptr };
std::vector<SafetyHookMid> datatable_patch = {};
#define DATATABLE_PATCH_REGISTER(location, reg, value, skip) { datatable_patch.push_back(safetyhook::create_mid(location, [](SafetyHookContext &ctx) {ctx.reg = (uintptr_t)(value); ctx.rip = location + skip;})); }
void
ReplaceDatatableBufferAddresses () {
LogMessage (LogLevel::INFO, "Set Datatable Size to 12MB");
for (int i = 0; i < 3; i ++) datatableBuffer[i] = (uint8_t *)malloc (datatableBufferSize);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABE26), r8, datatableBufferSize, 6);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABE3A), r8, datatableBufferSize, 6);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABF79), r8, datatableBufferSize, 6);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABE40), rcx, datatableBuffer[0], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABEB1), rdi, datatableBuffer[0], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABEDB), rdi, datatableBuffer[0], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABF4C), rdi, datatableBuffer[0], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABE2C), rcx, datatableBuffer[1], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABF5B), rcx, datatableBuffer[1], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABF8E), r8 , datatableBuffer[1], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABF7F), rcx, datatableBuffer[2], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABF95), rcx, datatableBuffer[2], 7);
DATATABLE_PATCH_REGISTER (ASLR (0x1400ABFBF), rdx, datatableBuffer[2], 7);
}
void
Init () {
LogMessage (LogLevel::INFO, "Init JPN39 patches");
i32 xRes = 1920;
i32 yRes = 1080;
bool vsync = false;
bool unlockSongs = true;
auto configPath = std::filesystem::current_path () / "config.toml";
std::unique_ptr<toml_table_t, void (*) (toml_table_t *)> config_ptr (openConfig (configPath), toml_free);
if (config_ptr) {
if (auto patches = openConfigSection (config_ptr.get (), "patches")) {
unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs);
}
if (auto graphics = openConfigSection (config_ptr.get (), "graphics")) {
if (auto res = openConfigSection (graphics, "res")) {
xRes = static_cast<i32> (readConfigInt (res, "x", xRes));
yRes = static_cast<i32> (readConfigInt (res, "y", yRes));
}
vsync = readConfigBool (graphics, "vsync", vsync);
}
}
// Hook to get AppAccessor and ComponentAccessor
INSTALL_FAST_HOOK (DeviceCheck);
INSTALL_FAST_HOOK (luaL_newstate);
// INSTALL_HOOK (AcquireMostCompatibleDisplayMode);
// Apply common config patch
WRITE_MEMORY (ASLR (0x140494533), i32, xRes);
WRITE_MEMORY (ASLR (0x14049453A), i32, yRes);
if (!vsync) WRITE_MEMORY (ASLR (0x14064C7E9), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90);
// Bypass errors
WRITE_MEMORY (ASLR (0x140041A00), u8, 0xC3);
// Use TLS v1.2
WRITE_MEMORY (ASLR (0x140580459), u8, 0x10);
// Disable F/G check
WRITE_MEMORY (ASLR (0x140CD4858), char, "./");
// Move various files to current directory
WRITE_MEMORY (ASLR (0x140C8AB60), char, "./"); // F:/
WRITE_MEMORY (ASLR (0x140C8AB5C), char, "./"); // G:/
WRITE_MEMORY (ASLR (0x140CD4DC0), char, ".\\Setting1.bin");
WRITE_MEMORY (ASLR (0x140CD4DB0), char, ".\\Setting2.bin");
WRITE_MEMORY (ASLR (0x140C95B40), char, ".\\TournamentData\\PlayData\\TournamentPlayData.dat");
WRITE_MEMORY (ASLR (0x140C95B78), char, ".\\TournamentData\\PlayData\\TournamentPlayData.dat");
WRITE_MEMORY (ASLR (0x140C95BB0), char, ".\\TournamentData\\InfoData\\TournamentInfoData.dat");
WRITE_MEMORY (ASLR (0x140C95BE8), char, ".\\TournamentData\\InfoData\\TournamentInfoData.dat");
WRITE_MEMORY (ASLR (0x140CC0508), char, ".\\Garmc\\BillingData\\GarmcBillingData.dat");
WRITE_MEMORY (ASLR (0x140CC0538), char, ".\\Garmc\\BillingData\\GarmcBillingData.dat");
WRITE_MEMORY (ASLR (0x140CC0660), char, ".\\Garmc\\BillingData\\GarmcOBillingData.dat");
WRITE_MEMORY (ASLR (0x140CC0690), char, ".\\Garmc\\BillingData\\GarmcOBillingData.dat");
WRITE_MEMORY (ASLR (0x140CC05E0), char, ".\\Garmc\\BillingNetIdLocationId\\GarmcBillingNetIdLocationId.dat");
WRITE_MEMORY (ASLR (0x140CC0620), char, ".\\Garmc\\BillingNetIdLocationId\\GarmcBillingNetIdLocationId.dat");
WRITE_MEMORY (ASLR (0x140CC0830), char, ".\\Garmc\\BillingNetIdLocationId\\GarmcOBillingNetIdLocationId.dat");
WRITE_MEMORY (ASLR (0x140CC0880), char, ".\\Garmc\\BillingNetIdLocationId\\GarmcOBillingNetIdLocationId.dat");
WRITE_MEMORY (ASLR (0x140CC06C0), char, ".\\Garmc\\ErrorLogData\\GarmcErrorLogData.dat");
WRITE_MEMORY (ASLR (0x140CC06F0), char, ".\\Garmc\\ErrorLogData\\GarmcErrorLogData.dat");
WRITE_MEMORY (ASLR (0x140CC0580), char, ".\\Garmc\\ErrorLogData\\GarmcOErrorLogData.dat");
WRITE_MEMORY (ASLR (0x140CC05B0), char, ".\\Garmc\\ErrorLogData\\GarmcOErrorLogData.dat");
// Remove datatable size limit
ReplaceDatatableBufferAddresses ();
// Unlock Songs
TestMode::RegisterItem (
L"<select-item label=\"UNLOCK SONGS\" param-offset-x=\"35\" replace-text=\"0:OFF, 1:ON, "
L"2:FORCE\" group=\"Setting\" id=\"ModUnlockSongs\" max=\"2\" min=\"0\" default=\"1\"/>",
[&]() {
INSTALL_FAST_HOOK (IsSongRelease);
INSTALL_FAST_HOOK (IsSongReleasePlayer);
INSTALL_MID_HOOK (DifficultyPanelCrown);
}
);
// Freeze Timer
TestMode::RegisterItem (
L"<select-item label=\"FREEZE TIMER\" param-offset-x=\"35\" replace-text=\"0:OFF, 1:ON\" "
L"group=\"Setting\" id=\"ModFreezeTimer\" max=\"1\" min=\"0\" default=\"0\"/>",
[&] { INSTALL_MID_HOOK (FreezeTimer); }
);
// Mode Unlock
// TestMode::Menu *modeUnlock = TestMode::CreateMenu (L"MODE UNLOCK", L"ModeUnlockMenu");
TestMode::RegisterItem (
L"<select-item label=\"KIMETSU MODE\" param-offset-x=\"35\" replace-text=\"0:DEFAULT, 1:ENABLE, "
L"2:CARD ONLY\" group=\"Setting\" id=\"ModModeCollabo024\" max=\"2\" min=\"0\" default=\"0\"/>",
[&] { INSTALL_FAST_HOOK (AvailableMode_Collabo024); }//, modeUnlock
);
TestMode::RegisterItem (
L"<select-item label=\"ONE PIECE MODE\" param-offset-x=\"35\" replace-text=\"0:DEFAULT, "
L"1:ENABLE, 2:CARD ONLY\" group=\"Setting\" id=\"ModModeCollabo025\" max=\"2\" min=\"0\" default=\"0\"/>",
[&] { INSTALL_FAST_HOOK (AvailableMode_Collabo025); }//, modeUnlock
);
TestMode::RegisterItem (
L"<select-item label=\"AI SOSHINA MODE\" param-offset-x=\"35\" replace-text=\"0:DEFAULT, "
L"1:ENABLE, 2:CARD ONLY\" group=\"Setting\" id=\"ModModeCollabo026\" max=\"2\" min=\"0\" default=\"0\"/>",
[&] { INSTALL_FAST_HOOK (AvailableMode_Collabo026); }//, modeUnlock
);
TestMode::RegisterItem (
L"<select-item label=\"AOHARU MODE\" param-offset-x=\"35\" replace-text=\"0:DEFAULT, 1:ENABLE, "
L"2:CARD ONLY\" group=\"Setting\" id=\"ModModeAprilFool001\" max=\"2\" min=\"0\" default=\"0\"/>",
[&] { INSTALL_FAST_HOOK (AvailableMode_AprilFool001); }//, modeUnlock
);
// TestMode::RegisterItem (modeUnlock);
// InstantResult
TestMode::RegisterItem (
L"<select-item label=\"INSTANT RESULT\" param-offset-x=\"35\" replace-text=\"0:OFF, 1:ON\" "
L"group=\"Setting\" id=\"ModInstantResult\" max=\"1\" min=\"0\" default=\"0\"/>",
[&] {
INSTALL_FAST_HOOK (SceneResultInitialize_Enso);
INSTALL_FAST_HOOK (SceneResultInitialize_AI);
INSTALL_FAST_HOOK (SceneResultInitialize_Collabo025);
INSTALL_FAST_HOOK (SceneResultInitialize_Collabo026);
INSTALL_FAST_HOOK (SceneResultInitialize_AprilFool);
INSTALL_FAST_HOOK (SendResultData_Enso);
INSTALL_FAST_HOOK (SendResultData_AI);
INSTALL_FAST_HOOK (SendResultData_Collabo025_026);
INSTALL_FAST_HOOK (SendResultData_AprilFool);
INSTALL_MID_HOOK (ChangeResultDataSize_Enso);
INSTALL_MID_HOOK (ChangeResultDataSize_AI);
INSTALL_MID_HOOK (ChangeResultDataSize_Collabo025_026);
INSTALL_MID_HOOK (ChangeResultDataSize_AprilFool);
INSTALL_MID_HOOK (ChangeResultDataIndex_Enso);
INSTALL_MID_HOOK (ChangeResultDataIndex_AI);
INSTALL_MID_HOOK (ChangeResultDataIndex_Collabo025_026);
INSTALL_MID_HOOK (ChangeResultDataIndex_AprilFool);
}
);
// Unlimit Volume
TestMode::RegisterModify (
L"/root/menu[@id='SoundTestMenu']/layout[@type='Center']/select-item[@id='OutputLevelSpeakerItem']",
[&] (const pugi::xml_node &node) {
TestMode::Append (node, L"label", L"*");
node.attribute (L"max").set_value (L"300");
node.attribute (L"delta").set_value (L"1");
},
[&] () { INSTALL_FAST_HOOK (SetMasterVolumeSpeaker); }
);
TestMode::RegisterItemAfter(
L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='AttractMovieItem']",
L"<select-item label=\"ATTRACT DEMO\" disable=\"True/LanguageItem:0\" param-offset-x=\"35\" "
L"replace-text=\"0:ON, 1:OFF\" group=\"Setting\" id=\"AttractDemoItem\" max=\"1\" min=\"0\" default=\"0\"/>",
[&](){ INSTALL_MID_HOOK (AttractDemo); }
);
// Instant Result
// TestMode::RegisterModify(
// L"/root/menu[@id='GameOptionsMenu']/layout[@type='Center']/select-item[@id='NumberOfStageItem']",
// [&](pugi::xml_node &node) { TestMode::Append(node, L"label", L"*"); node.attribute(L"max").set_value(L"99"); },
// [&](){}
// );
// Fix normal song play after passing through silent song
// INSTALL_MID_HOOK (GenNus3bankId);
INSTALL_FAST_HOOK (LoadedBankAll);
// Disable live check
auto amHandle = reinterpret_cast<u64> (GetModuleHandle ("AMFrameWork.dll"));
INSTALL_FAST_HOOK_DYNAMIC (AMFWTerminate, reinterpret_cast<void *> (amHandle + 0x42DE0));
// Move various files to current directory
WRITE_MEMORY (amHandle + 0x15252, u8, 0xEB); // CreditLogPathA
WRITE_MEMORY (amHandle + 0x15419, u8, 0xEB); // CreditLogPathB
WRITE_MEMORY (amHandle + 0x416DA, u8, 0xEB); // ErrorLogPathA
WRITE_MEMORY (amHandle + 0x41859, u8, 0xEB); // ErrorLogPathB
WRITE_MEMORY (amHandle + 0x41C21, u8, 0xEB); // CommonLogPathA
WRITE_MEMORY (amHandle + 0x41DA5, u8, 0xEB); // CommonLogPathB
WRITE_NOP (amHandle + 0x420F1, 0x05); // BackupDataPathA
WRITE_NOP (amHandle + 0x42167, 0x05); // BackupDataPathB
// Redirect garmc requests
auto garmcHandle = reinterpret_cast<u64> (GetModuleHandle ("garmc.dll"));
INSTALL_FAST_HOOK_DYNAMIC (curl_easy_setopt, reinterpret_cast<void *> (garmcHandle + 0x1FBBB0));
INSTALL_FAST_HOOK_DYNAMIC (garmc_logger_log, reinterpret_cast<void *> (garmcHandle + 0x13AB70));
}
} // namespace patches::JPN39