#include "pcm.h" #include "acio/icca/icca.h" #include "io.h" #include "misc/wintouchemu.h" #include "util/detour.h" #include "util/utils.h" #include "util/libutils.h" #include "util/time.h" namespace games::pcm { uint32_t *(__cdecl *GsIo_GetState_orig)(uint32_t *state); static double BILL_IN_TIME = 0; static double BILL_DELAY = 2.0; static int bill_kind = 0; static int __cdecl BillVali_GetEscrowBillKind() { return bill_kind; } static int __cdecl BillVali_GetCurrentStep() { return 0; } static int __cdecl BillVali_GetError() { return 1; } static char __cdecl BillVali_IsEscrowNow() { auto &buttons = games::pcm::get_buttons(); if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert1000YenBill])) { log_misc("pcm", "1000 yen bill inserted"); bill_kind = 1; return true; } if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert2000YenBill])) { log_misc("pcm", "2000 yen bill inserted"); bill_kind = 2; return true; } if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert5000YenBill])) { log_misc("pcm", "5000 yen bill inserted"); bill_kind = 3; return true; } if (GameAPI::Buttons::getState(RI_MGR, buttons[games::pcm::Buttons::Insert10000YenBill])) { log_misc("pcm", "10000 yen bill inserted"); bill_kind = 4; return true; } return false; } static bool __cdecl BillVali_IsIdling() { return true; } static bool __cdecl BillVali_IsReady() { return true; } static bool __cdecl BillVali_IsWaiting() { return BILL_IN_TIME == 0; } static int __cdecl BillVali_GetReceivedBill() { if (BILL_IN_TIME == 0 && BillVali_IsEscrowNow()) { BILL_IN_TIME = get_performance_seconds(); } else if ((BILL_IN_TIME != 0) && ((BILL_IN_TIME + BILL_DELAY) <= get_performance_seconds())) { BILL_IN_TIME = 0; switch (bill_kind) { case 1: return 1; case 2: return 2; case 3: return 5; case 4: return 10; default: return 0; } } return 0; } static bool __cdecl BillVali_ReceiveBill(int) { return true; } static bool __cdecl BillVali_ReceiveCancel() { return true; } static bool __cdecl BillVali_SetAcceptBill(int) { return true; } static uint32_t* __cdecl GsIo_GetState_hook(uint32_t *state) { GsIo_GetState_orig(state); // "bill validator is happy" flag :] *state |= 4; return state; } PCMGame::PCMGame() : Game("Charge Machine") {} void PCMGame::attach() { Game::attach(); // system.dll doesn't get loaded until later so load it now for hooking. HMODULE system = libutils::try_library("system.dll"); // fix ICCA acio::ICCA_COMPAT_ACTIVE = true; // apply hooks detour::trampoline("system.dll", "?GetState@GsIo@@SA?BVSTATE@1@XZ", GsIo_GetState_hook, &GsIo_GetState_orig); detour::inline_hook(BillVali_GetCurrentStep, libutils::try_proc( system, "?GetCurrentStep@GsBillVali@@SAHXZ")); detour::inline_hook(BillVali_GetError, libutils::try_proc( system, "?GetError@GsBillVali@@SAHXZ")); detour::inline_hook(BillVali_GetReceivedBill, libutils::try_proc( system, "?GetReceivedBill@GsBillVali@@SAHXZ")); detour::inline_hook(BillVali_IsEscrowNow, libutils::try_proc( system, "?IsEscrowNow@GsBillVali@@SA_NXZ")); detour::inline_hook(BillVali_IsIdling, libutils::try_proc( system, "?IsIdling@GsBillVali@@SA_NXZ")); detour::inline_hook(BillVali_IsWaiting, libutils::try_proc( system, "?IsWaiting@GsBillVali@@SA_NXZ")); detour::inline_hook(BillVali_IsReady, libutils::try_proc( system, "?IsReady@GsBillVali@@SA_NXZ")); detour::inline_hook(BillVali_ReceiveBill, libutils::try_proc( system, "?ReceiveBill@GsBillVali@@SA_NH@Z")); detour::inline_hook(BillVali_ReceiveCancel, libutils::try_proc( system, "?ReceiveCancel@GsBillVali@@SAHXZ")); detour::inline_hook(BillVali_GetEscrowBillKind, libutils::try_proc( system, "?GetEscrowBillKind@GsBillVali@@SAHXZ")); detour::inline_hook(BillVali_SetAcceptBill, libutils::try_proc( system, "?SetAcceptBill@GsBillVali@@SA_NH@Z")); } }