#include "p4io.h" #include "util/logging.h" #include "util/detour.h" #include "misc/eamuse.h" #include "acio/icca/icca.h" #include "rawinput/rawinput.h" #include "io.h" namespace games::otoca { // button mapping static size_t MAPPING[] { ~0u, Buttons::Test, Buttons::Service, Buttons::CoinMech, ~0u, Buttons::LeverUp, Buttons::LeverDown, Buttons::LeverLeft, Buttons::LeverRight, Buttons::ButtonLeft, Buttons::ButtonRight, ~0u, ~0u, }; static uint8_t INPUT_STATE[std::size(MAPPING)] {}; static uint8_t *CARD_DATA = nullptr; static int __cdecl P4io_Boot_step() { return 1; } static int __cdecl P4ioInputIsOn(int input_no) { if (input_no < (int) std::size(MAPPING)) { return INPUT_STATE[input_no] > 0 && INPUT_STATE[input_no] < 3; } return 0; } static bool __cdecl P4ioInputIsOnTrg(int input_no) { if (input_no < (int) std::size(MAPPING)) { return INPUT_STATE[input_no] == 1; } return 0; } static bool __cdecl P4ioInputIsOffTrg(int input_no) { if (input_no < (int) std::size(MAPPING)) { return INPUT_STATE[input_no] == 3; } return 0; } static void __cdecl P4ioInput_Polling() { auto &buttons = get_buttons(); for (size_t i = 0; i < std::size(MAPPING); i++) { if (MAPPING[i] != ~0u) { // reset release event if (INPUT_STATE[i] == 3) { INPUT_STATE[i] = 0; } // apply new button state auto state = GameAPI::Buttons::getState(RI_MGR, buttons.at(MAPPING[i])); if (state && INPUT_STATE[i] < 2) { INPUT_STATE[i]++; } else if (!state && INPUT_STATE[i] > 0 && INPUT_STATE[i] < 3) { INPUT_STATE[i] = 3; } } } } static int __cdecl P4ioOutputPolling(uint32_t data) { auto &lights = get_lights(); GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::LeftButton), (data & 1) ? 1.f : 0.f); GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::RightButton), (data & 2) ? 1.f : 0.f); RI_MGR->devices_flush_output(); return 0; } static int __cdecl P4ioCoinCount() { return eamuse_coin_get_stock(); } static bool __cdecl P4ioInputIsICCardHold() { bool kb_insert_press = false; // eamio keypress kb_insert_press |= eamuse_get_keypad_state(0) & (1 << EAM_IO_INSERT); // check for card if (CARD_DATA == nullptr && (eamuse_card_insert_consume(1, 0) || kb_insert_press)) { auto card = new uint8_t[8]; if (!eamuse_get_card(1, 0, card)) { // invalid card found delete[] card; } else { CARD_DATA = card; } } // check if hold return CARD_DATA != nullptr; } static void __cdecl P4ioInputIsICCardRead(uint8_t *data) { if (CARD_DATA != nullptr) { memcpy(data, CARD_DATA, 8); } } void p4io_hook() { detour::iat_try("?P4io_Boot_step@@YA?AW4P4IO_STATUS@@XZ", P4io_Boot_step); detour::iat_try("?P4ioInputIsOn@@YAHH@Z", P4ioInputIsOn); detour::iat_try("?P4ioInputIsOnTrg@@YAHH@Z", P4ioInputIsOnTrg); detour::iat_try("?P4ioInputIsOffTrg@@YAHH@Z", P4ioInputIsOffTrg); detour::iat_try("?P4ioInput_Polling@@YAXXZ", P4ioInput_Polling); detour::iat_try("?P4ioOutputPolling@@YAHU_P4IO_POLLING_DATA_t@@@Z", P4ioOutputPolling); detour::iat_try("?P4ioCoinCount@@YAHXZ", P4ioCoinCount); detour::iat_try("?P4ioInputIsICCardHold@@YA_NXZ", (void*) P4ioInputIsICCardHold); detour::iat_try("?P4ioInputIsICCardRead@@YAXPAU_P4IO_ICCARDDATA@@@Z", P4ioInputIsICCardRead); } }