mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
Add Polaris Chord Support (#361)
## Link to GitHub Issue, if one exists n/a ## Description of change Adds support for Polaris Chord ## Testing Tested with XIF:J:A:A:2024122300. IO/ICCA works, game successfully connects to server and is playable.
This commit is contained in:
@@ -443,6 +443,9 @@ set(SOURCE_FILES ${SOURCE_FILES}
|
|||||||
games/mfg/mfg.cpp
|
games/mfg/mfg.cpp
|
||||||
games/mfg/io.cpp
|
games/mfg/io.cpp
|
||||||
games/mfg/bi2a_hook.cpp
|
games/mfg/bi2a_hook.cpp
|
||||||
|
games/pc/pc.cpp
|
||||||
|
games/pc/io.cpp
|
||||||
|
games/pc/bi2x_hook.cpp
|
||||||
|
|
||||||
# hooks
|
# hooks
|
||||||
hooks/audio/audio.cpp
|
hooks/audio/audio.cpp
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ bool ICCADevice::parse_msg(MessageData *msg_in,
|
|||||||
// send version data
|
// send version data
|
||||||
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
|
auto msg = this->create_msg(msg_in, MSG_VERSION_SIZE);
|
||||||
if (
|
if (
|
||||||
avs::game::is_model({"LDJ", "TBS", "UJK"}) ||
|
avs::game::is_model({"LDJ", "TBS", "UJK", "XIF"}) ||
|
||||||
// SDVX Valkyrie cabinet mode
|
// SDVX Valkyrie cabinet mode
|
||||||
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))
|
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))
|
||||||
) {
|
) {
|
||||||
@@ -521,7 +521,7 @@ void ICCADevice::update_status(int unit) {
|
|||||||
buffer[10] = felica ? 0x01 : 0x00;
|
buffer[10] = felica ? 0x01 : 0x00;
|
||||||
|
|
||||||
} else if (
|
} else if (
|
||||||
avs::game::is_model({"LDJ", "TBS"}) ||
|
avs::game::is_model({"LDJ", "TBS", "XIF"}) ||
|
||||||
// SDVX Valkyrie cabinet mode
|
// SDVX Valkyrie cabinet mode
|
||||||
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))) {
|
(avs::game::is_model("KFC") && (avs::game::SPEC[0] == 'G' || avs::game::SPEC[0] == 'H'))) {
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
#include "ccj/io.h"
|
#include "ccj/io.h"
|
||||||
#include "qks/io.h"
|
#include "qks/io.h"
|
||||||
#include "mfg/io.h"
|
#include "mfg/io.h"
|
||||||
|
#include "pc/io.h"
|
||||||
|
|
||||||
namespace games {
|
namespace games {
|
||||||
|
|
||||||
@@ -313,6 +314,15 @@ namespace games {
|
|||||||
buttons.insert({ mfg, mfg::get_buttons() });
|
buttons.insert({ mfg, mfg::get_buttons() });
|
||||||
buttons_help.insert({ mfg, mfg::get_buttons_help() });
|
buttons_help.insert({ mfg, mfg::get_buttons_help() });
|
||||||
file_hints[mfg].emplace_back("game/MFGClient_Data");
|
file_hints[mfg].emplace_back("game/MFGClient_Data");
|
||||||
|
|
||||||
|
// Polaris Chord
|
||||||
|
const std::string pc("Polaris Chord");
|
||||||
|
games.push_back(pc);
|
||||||
|
buttons.insert({ pc, pc::get_buttons() });
|
||||||
|
buttons_help.insert({ pc, pc::get_buttons_help() });
|
||||||
|
analogs.insert({ pc, pc::get_analogs() });
|
||||||
|
lights.insert({ pc, pc::get_lights() });
|
||||||
|
file_hints[pc].emplace_back("game/svm_Data");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &get_games() {
|
const std::vector<std::string> &get_games() {
|
||||||
|
|||||||
@@ -0,0 +1,566 @@
|
|||||||
|
#include "bi2x_hook.h"
|
||||||
|
|
||||||
|
#include "util/execexe.h"
|
||||||
|
#include "util/logging.h"
|
||||||
|
#include "rawinput/rawinput.h"
|
||||||
|
#include "misc/eamuse.h"
|
||||||
|
#include "games/io.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "util/tapeled.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* class definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct AIO_SCI_COMM {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_NMGR_IOB2 {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1 {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__SETTING {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_WRFIRM {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__INPUT
|
||||||
|
{
|
||||||
|
uint8_t DevIoCounter;
|
||||||
|
uint8_t bExIoAErr;
|
||||||
|
uint8_t bExIoBErr;
|
||||||
|
uint8_t bPcPowerOn;
|
||||||
|
uint8_t bPcPowerCheck;
|
||||||
|
uint8_t bCoin1Jam;
|
||||||
|
uint8_t bCoin2Jam;
|
||||||
|
uint8_t bCoin3Jam;
|
||||||
|
uint8_t bCoin4Jam;
|
||||||
|
uint8_t Coin1Count;
|
||||||
|
uint8_t Coin2Count;
|
||||||
|
uint8_t Coin3Count;
|
||||||
|
uint8_t Coin4Count;
|
||||||
|
uint16_t AnalogCh1;
|
||||||
|
uint16_t AnalogCh2;
|
||||||
|
uint16_t AnalogCh3;
|
||||||
|
uint16_t AnalogCh4;
|
||||||
|
uint8_t CN8_8;
|
||||||
|
uint8_t CN8_9;
|
||||||
|
uint8_t CN8_10;
|
||||||
|
uint8_t CN9_8;
|
||||||
|
uint8_t CN9_9;
|
||||||
|
uint8_t CN9_10;
|
||||||
|
uint8_t CN11_11;
|
||||||
|
uint8_t CN11_12;
|
||||||
|
uint8_t CN11_13;
|
||||||
|
uint8_t CN11_14;
|
||||||
|
uint8_t CN11_15;
|
||||||
|
uint8_t CN11_16;
|
||||||
|
uint8_t CN11_17;
|
||||||
|
uint8_t CN11_18;
|
||||||
|
uint8_t CN11_19;
|
||||||
|
uint8_t CN11_20;
|
||||||
|
uint8_t CN12_11;
|
||||||
|
uint8_t CN12_12;
|
||||||
|
uint8_t CN12_13;
|
||||||
|
uint8_t CN12_14;
|
||||||
|
uint8_t CN12_15;
|
||||||
|
uint8_t CN12_16;
|
||||||
|
uint8_t CN12_17;
|
||||||
|
uint8_t CN12_18;
|
||||||
|
uint8_t CN12_19;
|
||||||
|
uint8_t CN12_20;
|
||||||
|
uint8_t CN12_21;
|
||||||
|
uint8_t CN12_22;
|
||||||
|
uint8_t CN12_23;
|
||||||
|
uint8_t CN12_24;
|
||||||
|
uint8_t CN15_3;
|
||||||
|
uint8_t CN15_4;
|
||||||
|
uint8_t CN15_5;
|
||||||
|
uint8_t CN15_6;
|
||||||
|
uint8_t CN15_7;
|
||||||
|
uint8_t CN15_8;
|
||||||
|
uint8_t CN15_9;
|
||||||
|
uint8_t CN15_10;
|
||||||
|
uint8_t CN15_11;
|
||||||
|
uint8_t CN15_12;
|
||||||
|
uint8_t CN15_13;
|
||||||
|
uint8_t CN15_14;
|
||||||
|
uint8_t CN15_15;
|
||||||
|
uint8_t CN15_16;
|
||||||
|
uint8_t CN15_17;
|
||||||
|
uint8_t CN15_18;
|
||||||
|
uint8_t CN15_19;
|
||||||
|
uint8_t CN15_20;
|
||||||
|
uint8_t CN19_8;
|
||||||
|
uint8_t CN19_9;
|
||||||
|
uint8_t CN19_10;
|
||||||
|
uint8_t CN19_11;
|
||||||
|
uint8_t CN19_12;
|
||||||
|
uint8_t CN19_13;
|
||||||
|
uint8_t CN19_14;
|
||||||
|
uint8_t CN19_15;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__INPUTDATA {
|
||||||
|
uint8_t data[247];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__OUTPUTDATA {
|
||||||
|
uint8_t data[48];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__ICNPIN {
|
||||||
|
uint16_t Ain[4];
|
||||||
|
uint64_t CnPin;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AIO_IOB2_BI2X_AC1__DEVSTATUS {
|
||||||
|
uint8_t InputCounter;
|
||||||
|
uint8_t OutputCounter;
|
||||||
|
uint8_t IoResetCounter;
|
||||||
|
uint8_t TapeLedCounter;
|
||||||
|
uint8_t TapeLedRate[8];
|
||||||
|
AIO_IOB2_BI2X_AC1__INPUT Input;
|
||||||
|
AIO_IOB2_BI2X_AC1__INPUTDATA InputData;
|
||||||
|
AIO_IOB2_BI2X_AC1__OUTPUTDATA OutputData;
|
||||||
|
AIO_IOB2_BI2X_AC1__ICNPIN ICnPinHist[20];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
typedef AIO_IOB2_BI2X_AC1* (__fastcall *aioIob2Bi2xAC1_Create_t)(AIO_NMGR_IOB2 *i_pNodeMgr, uint32_t i_DevId,
|
||||||
|
AIO_IOB2_BI2X_AC1__SETTING *i_Setting);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_GetDeviceStatus_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl,
|
||||||
|
AIO_IOB2_BI2X_AC1__DEVSTATUS *o_DevStatus);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetWatchDogTimer_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint8_t i_Count);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_AddCounter_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_Counter,
|
||||||
|
uint32_t i_Count);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetOutputData_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_CnPin,
|
||||||
|
uint8_t i_Data);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2xAC1_SetTapeLedDataPart_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_TapeLedCh,
|
||||||
|
uint32_t i_Offset, uint8_t *i_pData,
|
||||||
|
uint32_t i_cntTapeLed, bool i_bReverse);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_SetTapeLedDataGroup_t)(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_bfGroup);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_SetTapeLedDataLimit_t)(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_Channel,
|
||||||
|
uint8_t i_Scale, uint8_t i_Limit);
|
||||||
|
typedef AIO_IOB2_BI2X_WRFIRM *(__fastcall *aioIob2Bi2x_CreateWriteFirmContext_t)(uint32_t i_SerialNumber,
|
||||||
|
uint32_t i_bfIob);
|
||||||
|
typedef AIO_SCI_COMM* (__fastcall *aioIob2Bi2x_OpenSciUsbCdc_t)(uint32_t i_SerialNumber);
|
||||||
|
typedef void (__fastcall *aioIob2Bi2x_DestroyWriteFirmContext_t)(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm);
|
||||||
|
typedef int32_t (__fastcall *aioIob2Bi2x_WriteFirmGetState_t)(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm);
|
||||||
|
typedef bool (__fastcall *aioIob2Bi2x_WriteFirmIsCompleted_t)(int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioIob2Bi2x_WriteFirmIsError_t)(int32_t i_State);
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
typedef AIO_NMGR_IOB2 *(__fastcall *aioNMgrIob2_Create_t)(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode);
|
||||||
|
typedef void (__fastcall *aioNMgrIob_BeginManage_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
typedef void (__fastcall *aioSci_Destroy_t)(AIO_SCI_COMM *i_pNodeMgr);
|
||||||
|
typedef void (__fastcall *aioNodeMgr_Destroy_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
typedef int32_t (__fastcall *aioNodeMgr_GetState_t)(AIO_NMGR_IOB2 *i_pNodeMgr);
|
||||||
|
typedef bool (__fastcall *aioNodeMgr_IsReady_t)(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioNodeMgr_IsError_t)(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State);
|
||||||
|
typedef void (__fastcall *aioNodeCtl_Destroy_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl);
|
||||||
|
typedef int32_t (__fastcall *aioNodeCtl_GetState_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl);
|
||||||
|
typedef bool (__fastcall *aioNodeCtl_IsReady_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State);
|
||||||
|
typedef bool (__fastcall *aioNodeCtl_IsError_t)(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function pointers
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
static aioIob2Bi2xAC1_Create_t aioIob2Bi2xAC1_Create_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_GetDeviceStatus_t aioIob2Bi2xAC1_GetDeviceStatus_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetWatchDogTimer_t aioIob2Bi2xAC1_SetWatchDogTimer_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_AddCounter_t aioIob2Bi2xAC1_AddCounter_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetOutputData_t aioIob2Bi2xAC1_SetOutputData_orig = nullptr;
|
||||||
|
static aioIob2Bi2xAC1_SetTapeLedDataPart_t aioIob2Bi2xAC1_SetTapeLedDataPart_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_SetTapeLedDataGroup_t aioIob2Bi2x_SetTapeLedDataGroup_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_SetTapeLedDataLimit_t aioIob2Bi2x_SetTapeLedDataLimit_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_OpenSciUsbCdc_t aioIob2Bi2x_OpenSciUsbCdc_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_CreateWriteFirmContext_t aioIob2Bi2x_CreateWriteFirmContext_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_DestroyWriteFirmContext_t aioIob2Bi2x_DestroyWriteFirmContext_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmGetState_t aioIob2Bi2x_WriteFirmGetState_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmIsCompleted_t aioIob2Bi2x_WriteFirmIsCompleted_orig = nullptr;
|
||||||
|
static aioIob2Bi2x_WriteFirmIsError_t aioIob2Bi2x_WriteFirmIsError_orig = nullptr;
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
static aioNMgrIob2_Create_t aioNMgrIob2_Create_orig = nullptr;
|
||||||
|
static aioNMgrIob_BeginManage_t aioNMgrIob_BeginManage_orig = nullptr;
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
static aioSci_Destroy_t aioSci_Destroy_orig = nullptr;
|
||||||
|
static aioNodeMgr_Destroy_t aioNodeMgr_Destroy_orig = nullptr;
|
||||||
|
static aioNodeMgr_GetState_t aioNodeMgr_GetState_orig = nullptr;
|
||||||
|
static aioNodeMgr_IsReady_t aioNodeMgr_IsReady_orig = nullptr;
|
||||||
|
static aioNodeMgr_IsError_t aioNodeMgr_IsError_orig = nullptr;
|
||||||
|
static aioNodeCtl_Destroy_t aioNodeCtl_Destroy_orig = nullptr;
|
||||||
|
static aioNodeCtl_GetState_t aioNodeCtl_GetState_orig = nullptr;
|
||||||
|
static aioNodeCtl_IsReady_t aioNodeCtl_IsReady_orig = nullptr;
|
||||||
|
static aioNodeCtl_IsError_t aioNodeCtl_IsError_orig = nullptr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_AC1 *aioIob2Bi2xAc1;
|
||||||
|
static AIO_SCI_COMM *aioSciComm;
|
||||||
|
static AIO_NMGR_IOB2 *aioNmgrIob2;
|
||||||
|
static AIO_IOB2_BI2X_WRFIRM *aioIob2Bi2xWrfirm;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_AC1* __fastcall aioIob2Bi2xAC1_Create(AIO_NMGR_IOB2 *i_pNodeMgr, uint32_t i_DevId,
|
||||||
|
AIO_IOB2_BI2X_AC1__SETTING *i_Setting) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
log_info("bi2x_hook", "aioIob2Bi2xAC1_Create hook hit");
|
||||||
|
aioIob2Bi2xAc1 = new AIO_IOB2_BI2X_AC1;
|
||||||
|
return aioIob2Bi2xAc1;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2xAC1_Create_orig(i_pNodeMgr, i_DevId, i_Setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_GetDeviceStatus(AIO_IOB2_BI2X_AC1 *i_pNodeCtl,
|
||||||
|
AIO_IOB2_BI2X_AC1__DEVSTATUS *o_DevStatus) {
|
||||||
|
RI_MGR->devices_flush_output();
|
||||||
|
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_GetDeviceStatus_orig(i_pNodeCtl, o_DevStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(o_DevStatus, 0x00, sizeof(AIO_IOB2_BI2X_AC1__DEVSTATUS));
|
||||||
|
|
||||||
|
auto &buttons = get_buttons();
|
||||||
|
o_DevStatus->Input.CN8_8 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Test]);
|
||||||
|
o_DevStatus->Input.CN8_9 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Service]);
|
||||||
|
o_DevStatus->Input.CN8_10 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::CoinMech]);
|
||||||
|
o_DevStatus->Input.CN15_10 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Headphone]);
|
||||||
|
o_DevStatus->Input.CN15_12 = 0xFF; // Recorder off
|
||||||
|
|
||||||
|
o_DevStatus->Input.CN12_11 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button1]);
|
||||||
|
o_DevStatus->Input.CN12_12 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button2]);
|
||||||
|
o_DevStatus->Input.CN12_13 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button3]);
|
||||||
|
o_DevStatus->Input.CN12_14 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button4]);
|
||||||
|
o_DevStatus->Input.CN12_15 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button5]);
|
||||||
|
o_DevStatus->Input.CN12_16 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button6]);
|
||||||
|
o_DevStatus->Input.CN12_17 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button7]);
|
||||||
|
o_DevStatus->Input.CN12_18 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button8]);
|
||||||
|
o_DevStatus->Input.CN12_19 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button9]);
|
||||||
|
o_DevStatus->Input.CN12_20 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button10]);
|
||||||
|
o_DevStatus->Input.CN12_21 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button11]);
|
||||||
|
o_DevStatus->Input.CN12_22 = !GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::Button12]);
|
||||||
|
|
||||||
|
auto &analogs = get_analogs();
|
||||||
|
if (analogs[Analogs::FaderL].isSet()) {
|
||||||
|
float val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderL]) - 0.5f) * 2;
|
||||||
|
o_DevStatus->Input.CN15_7 = val < 0.2f;
|
||||||
|
o_DevStatus->Input.CN15_6 = val > -0.85f && val < 0.35f;
|
||||||
|
o_DevStatus->Input.CN15_5 = val > -0.6f && val < 0.6f;
|
||||||
|
o_DevStatus->Input.CN15_4 = val > -0.35f && val < 0.85f;
|
||||||
|
o_DevStatus->Input.CN15_3 = val > -0.2f;
|
||||||
|
} else {
|
||||||
|
o_DevStatus->Input.CN15_7 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Left]);
|
||||||
|
o_DevStatus->Input.CN15_3 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderL_Right]);
|
||||||
|
o_DevStatus->Input.CN15_5 = !o_DevStatus->Input.CN15_7 && !o_DevStatus->Input.CN15_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (analogs[Analogs::FaderR].isSet()) {
|
||||||
|
float val = (GameAPI::Analogs::getState(RI_MGR, analogs[Analogs::FaderR]) - 0.5f) * 2;
|
||||||
|
o_DevStatus->Input.CN11_20 = val < 0.2f;
|
||||||
|
o_DevStatus->Input.CN11_19 = val > -0.85f && val < 0.35f;
|
||||||
|
o_DevStatus->Input.CN9_10 = val > -0.6f && val < 0.6f;
|
||||||
|
o_DevStatus->Input.CN9_9 = val > -0.35f && val < 0.85f;
|
||||||
|
o_DevStatus->Input.CN9_8 = val > -0.2f;
|
||||||
|
} else {
|
||||||
|
o_DevStatus->Input.CN11_20 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Left]);
|
||||||
|
o_DevStatus->Input.CN9_8 = GameAPI::Buttons::getState(RI_MGR, buttons[Buttons::FaderR_Right]);
|
||||||
|
o_DevStatus->Input.CN9_10 = !o_DevStatus->Input.CN11_20 && !o_DevStatus->Input.CN9_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
o_DevStatus->Input.Coin1Count = eamuse_coin_get_stock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_SetWatchDogTimer(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint8_t i_Count) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetWatchDogTimer_orig(i_pNodeCtl, i_Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_AddCounter(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_Counter, uint32_t i_Count) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1 && i_Count == 0) {
|
||||||
|
eamuse_coin_set_stock((uint16_t) i_Count);
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2xAC1_AddCounter_orig(i_pNodeCtl, i_Counter, i_Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_SetOutputData(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_CnPin, uint8_t i_Data) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetOutputData_orig(i_pNodeCtl, i_CnPin, i_Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i_CnPin == 0x1) {
|
||||||
|
eamuse_coin_set_block(i_Data == 0xFF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &lights = get_lights();
|
||||||
|
if (i_CnPin == 0x11) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_R), i_Data / 255.0f);
|
||||||
|
} else if (i_CnPin == 0x12) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_G), i_Data / 255.0f);
|
||||||
|
} else if (i_CnPin == 0x13) {
|
||||||
|
GameAPI::Lights::writeLight(RI_MGR, lights.at(Lights::IC_READER_B), i_Data / 255.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2xAC1_SetTapeLedDataPart(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, uint32_t i_TapeLedCh,
|
||||||
|
uint32_t i_Offset, uint8_t *i_pData,
|
||||||
|
uint32_t i_cntTapeLed, bool i_bReverse) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2xAC1_SetTapeLedDataPart_orig(i_pNodeCtl, i_TapeLedCh, i_Offset, i_pData, i_cntTapeLed, i_bReverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO implement tape led
|
||||||
|
// there are >200 lights in total, adding each one separately probably isn't the best idea...
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2x_SetTapeLedDataGroup(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_bfGroup) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2x_SetTapeLedDataGroup_orig(i_pNodeCtl, i_bfGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall aioIob2Bi2x_SetTapeLedDataLimit(AIO_IOB2_BI2X_AC1* i_pNodeCtl, uint32_t i_Channel,
|
||||||
|
uint8_t i_Scale, uint8_t i_Limit) {
|
||||||
|
if (i_pNodeCtl != aioIob2Bi2xAc1) {
|
||||||
|
return aioIob2Bi2x_SetTapeLedDataLimit_orig(i_pNodeCtl, i_Channel, i_Scale, i_Limit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AIO_SCI_COMM *__fastcall aioIob2Bi2x_OpenSciUsbCdc(uint32_t i_SerialNumber) {
|
||||||
|
aioSciComm = new AIO_SCI_COMM;
|
||||||
|
return aioSciComm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AIO_IOB2_BI2X_WRFIRM *__fastcall aioIob2Bi2x_CreateWriteFirmContext(
|
||||||
|
uint32_t i_SerialNumber, uint32_t i_bfIob) {
|
||||||
|
|
||||||
|
aioIob2Bi2xWrfirm = new AIO_IOB2_BI2X_WRFIRM;
|
||||||
|
return aioIob2Bi2xWrfirm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioIob2Bi2x_DestroyWriteFirmContext(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm) {
|
||||||
|
if (i_pWrFirm == aioIob2Bi2xWrfirm) {
|
||||||
|
delete aioIob2Bi2xWrfirm;
|
||||||
|
aioIob2Bi2xWrfirm = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_DestroyWriteFirmContext_orig(i_pWrFirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioIob2Bi2x_WriteFirmGetState(AIO_IOB2_BI2X_WRFIRM *i_pWrFirm) {
|
||||||
|
if (i_pWrFirm == aioIob2Bi2xWrfirm) {
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmGetState_orig(i_pWrFirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioIob2Bi2x_WriteFirmIsCompleted(int32_t i_State) {
|
||||||
|
if (aioIob2Bi2xWrfirm != nullptr) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmIsCompleted_orig(i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioIob2Bi2x_WriteFirmIsError(int32_t i_State) {
|
||||||
|
if (aioIob2Bi2xWrfirm != nullptr) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioIob2Bi2x_WriteFirmIsError_orig(i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
|
||||||
|
static AIO_NMGR_IOB2 *__fastcall aioNMgrIob2_Create(AIO_SCI_COMM *i_pSci, uint32_t i_bfMode) {
|
||||||
|
if (i_pSci == aioSciComm) {
|
||||||
|
aioNmgrIob2 = new AIO_NMGR_IOB2;
|
||||||
|
return aioNmgrIob2;
|
||||||
|
} else {
|
||||||
|
return aioNMgrIob2_Create_orig(i_pSci, i_bfMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNMgrIob_BeginManage(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr != aioNmgrIob2) {
|
||||||
|
return aioNMgrIob_BeginManage_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
|
||||||
|
static void __fastcall aioSci_Destroy(AIO_SCI_COMM *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioSciComm) {
|
||||||
|
delete aioSciComm;
|
||||||
|
} else {
|
||||||
|
return aioSci_Destroy_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNodeMgr_Destroy(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
delete aioNmgrIob2;
|
||||||
|
aioNmgrIob2 = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_Destroy_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioNodeMgr_GetState(AIO_NMGR_IOB2 *i_pNodeMgr) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_GetState_orig(i_pNodeMgr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeMgr_IsReady(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_IsReady_orig(i_pNodeMgr, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeMgr_IsError(AIO_NMGR_IOB2 *i_pNodeMgr, int32_t i_State) {
|
||||||
|
if (i_pNodeMgr == aioNmgrIob2) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioNodeMgr_IsError_orig(i_pNodeMgr, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall aioNodeCtl_Destroy(AIO_IOB2_BI2X_AC1 *i_pNodeCtl) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
delete aioIob2Bi2xAc1;
|
||||||
|
aioIob2Bi2xAc1 = nullptr;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_Destroy_orig(i_pNodeCtl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t __fastcall aioNodeCtl_GetState(AIO_IOB2_BI2X_AC1 *i_pNodeCtl) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_GetState_orig(i_pNodeCtl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeCtl_IsReady(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_IsReady_orig(i_pNodeCtl, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool __fastcall aioNodeCtl_IsError(AIO_IOB2_BI2X_AC1 *i_pNodeCtl, int32_t i_State) {
|
||||||
|
if (i_pNodeCtl == aioIob2Bi2xAc1) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return aioNodeCtl_IsError_orig(i_pNodeCtl, i_State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bi2x_hook_init() {
|
||||||
|
// avoid double init
|
||||||
|
static bool initialized = false;
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// announce
|
||||||
|
log_info("bi2x_hook", "init");
|
||||||
|
|
||||||
|
// libaio-iob2_video.dll
|
||||||
|
const auto libaioIob2VideoDll = "libaio-iob2_video.dll";
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_Create",
|
||||||
|
aioIob2Bi2xAC1_Create, &aioIob2Bi2xAC1_Create_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_GetDeviceStatus",
|
||||||
|
aioIob2Bi2xAC1_GetDeviceStatus, &aioIob2Bi2xAC1_GetDeviceStatus_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetWatchDogTimer",
|
||||||
|
aioIob2Bi2xAC1_SetWatchDogTimer, &aioIob2Bi2xAC1_SetWatchDogTimer_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_AddCounter",
|
||||||
|
aioIob2Bi2xAC1_AddCounter, &aioIob2Bi2xAC1_AddCounter_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetOutputData",
|
||||||
|
aioIob2Bi2xAC1_SetOutputData, &aioIob2Bi2xAC1_SetOutputData_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2xAC1_SetTapeLedDataPart",
|
||||||
|
aioIob2Bi2xAC1_SetTapeLedDataPart, &aioIob2Bi2xAC1_SetTapeLedDataPart_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_SetTapeLedDataGroup",
|
||||||
|
aioIob2Bi2x_SetTapeLedDataGroup, &aioIob2Bi2x_SetTapeLedDataGroup_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_SetTapeLedDataLimit",
|
||||||
|
aioIob2Bi2x_SetTapeLedDataLimit, &aioIob2Bi2x_SetTapeLedDataLimit_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_OpenSciUsbCdc",
|
||||||
|
aioIob2Bi2x_OpenSciUsbCdc, &aioIob2Bi2x_OpenSciUsbCdc_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_CreateWriteFirmContext",
|
||||||
|
aioIob2Bi2x_CreateWriteFirmContext, &aioIob2Bi2x_CreateWriteFirmContext_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_DestroyWriteFirmContext",
|
||||||
|
aioIob2Bi2x_DestroyWriteFirmContext, &aioIob2Bi2x_DestroyWriteFirmContext_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmGetState",
|
||||||
|
aioIob2Bi2x_WriteFirmGetState, &aioIob2Bi2x_WriteFirmGetState_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmIsCompleted",
|
||||||
|
aioIob2Bi2x_WriteFirmIsCompleted, &aioIob2Bi2x_WriteFirmIsCompleted_orig);
|
||||||
|
execexe::trampoline_try(libaioIob2VideoDll, "aioIob2Bi2x_WriteFirmIsError",
|
||||||
|
aioIob2Bi2x_WriteFirmIsError, &aioIob2Bi2x_WriteFirmIsError_orig);
|
||||||
|
|
||||||
|
// libaio-iob.dll
|
||||||
|
const auto libaioIobDll = "libaio-iob.dll";
|
||||||
|
execexe::trampoline_try(libaioIobDll, "aioNMgrIob2_Create",
|
||||||
|
aioNMgrIob2_Create, &aioNMgrIob2_Create_orig);
|
||||||
|
execexe::trampoline_try(libaioIobDll, "aioNMgrIob_BeginManage",
|
||||||
|
aioNMgrIob_BeginManage, &aioNMgrIob_BeginManage_orig);
|
||||||
|
|
||||||
|
// libaio.dll
|
||||||
|
const auto libaioDll = "libaio.dll";
|
||||||
|
execexe::trampoline_try(libaioDll, "aioSci_Destroy",
|
||||||
|
aioSci_Destroy, &aioSci_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_Destroy",
|
||||||
|
aioNodeMgr_Destroy, &aioNodeMgr_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_GetState",
|
||||||
|
aioNodeMgr_GetState, &aioNodeMgr_GetState_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_IsReady",
|
||||||
|
aioNodeMgr_IsReady, &aioNodeMgr_IsReady_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeMgr_IsError",
|
||||||
|
aioNodeMgr_IsError, &aioNodeMgr_IsError_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_Destroy",
|
||||||
|
aioNodeCtl_Destroy, &aioNodeCtl_Destroy_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_GetState",
|
||||||
|
aioNodeCtl_GetState, &aioNodeCtl_GetState_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_IsReady",
|
||||||
|
aioNodeCtl_IsReady, &aioNodeCtl_IsReady_orig);
|
||||||
|
execexe::trampoline_try(libaioDll, "aioNodeCtl_IsError",
|
||||||
|
aioNodeCtl_IsError, &aioNodeCtl_IsError_orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
void bi2x_hook_init();
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "io.h"
|
||||||
|
|
||||||
|
std::vector<Button> &games::pc::get_buttons() {
|
||||||
|
static std::vector<Button> buttons;
|
||||||
|
|
||||||
|
if (buttons.empty()) {
|
||||||
|
buttons = GameAPI::Buttons::getButtons("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Buttons::sortButtons(
|
||||||
|
&buttons,
|
||||||
|
"Service",
|
||||||
|
"Test",
|
||||||
|
"Coin Mech",
|
||||||
|
"Button 1",
|
||||||
|
"Button 2",
|
||||||
|
"Button 3",
|
||||||
|
"Button 4",
|
||||||
|
"Button 5",
|
||||||
|
"Button 6",
|
||||||
|
"Button 7",
|
||||||
|
"Button 8",
|
||||||
|
"Button 9",
|
||||||
|
"Button 10",
|
||||||
|
"Button 11",
|
||||||
|
"Button 12",
|
||||||
|
"Fader-L Left",
|
||||||
|
"Fader-L Right",
|
||||||
|
"Fader-R Left",
|
||||||
|
"Fader-R Right",
|
||||||
|
"Headphone"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string games::pc::get_buttons_help() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Analog> &games::pc::get_analogs() {
|
||||||
|
static std::vector<Analog> analogs;
|
||||||
|
|
||||||
|
if (analogs.empty()) {
|
||||||
|
analogs = GameAPI::Analogs::getAnalogs("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Analogs::sortAnalogs(
|
||||||
|
&analogs,
|
||||||
|
"Fader-L",
|
||||||
|
"Fader-R"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return analogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Light> &games::pc::get_lights() {
|
||||||
|
static std::vector<Light> lights;
|
||||||
|
|
||||||
|
if (lights.empty()) {
|
||||||
|
lights = GameAPI::Lights::getLights("Polaris Chord");
|
||||||
|
|
||||||
|
GameAPI::Lights::sortLights(
|
||||||
|
&lights,
|
||||||
|
"IC Reader R",
|
||||||
|
"IC Reader G",
|
||||||
|
"IC Reader B"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lights;
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "cfg/api.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
namespace Buttons {
|
||||||
|
enum {
|
||||||
|
Service,
|
||||||
|
Test,
|
||||||
|
CoinMech,
|
||||||
|
Button1,
|
||||||
|
Button2,
|
||||||
|
Button3,
|
||||||
|
Button4,
|
||||||
|
Button5,
|
||||||
|
Button6,
|
||||||
|
Button7,
|
||||||
|
Button8,
|
||||||
|
Button9,
|
||||||
|
Button10,
|
||||||
|
Button11,
|
||||||
|
Button12,
|
||||||
|
FaderL_Left,
|
||||||
|
FaderL_Right,
|
||||||
|
FaderR_Left,
|
||||||
|
FaderR_Right,
|
||||||
|
Headphone
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Analogs {
|
||||||
|
enum {
|
||||||
|
FaderL,
|
||||||
|
FaderR,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Lights {
|
||||||
|
typedef enum {
|
||||||
|
IC_READER_R,
|
||||||
|
IC_READER_G,
|
||||||
|
IC_READER_B,
|
||||||
|
} pc_lights_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getters
|
||||||
|
std::vector<Button> &get_buttons();
|
||||||
|
std::string get_buttons_help();
|
||||||
|
std::vector<Analog> &get_analogs();
|
||||||
|
std::vector<Light> &get_lights();
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#include "pc.h"
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
|
||||||
|
#include "bi2x_hook.h"
|
||||||
|
#include "util/fileutils.h"
|
||||||
|
#include "util/unity_player.h"
|
||||||
|
#include "util/execexe.h"
|
||||||
|
#include "acioemu/handle.h"
|
||||||
|
#include "misc/wintouchemu.h"
|
||||||
|
#include "hooks/graphics/graphics.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
std::string PC_INJECT_ARGS = "";
|
||||||
|
bool PC_NO_IO = false;
|
||||||
|
|
||||||
|
static acioemu::ACIOHandle *acioHandle = nullptr;
|
||||||
|
static std::wstring portName = L"COM1";
|
||||||
|
|
||||||
|
void PCGame::attach() {
|
||||||
|
Game::attach();
|
||||||
|
|
||||||
|
// add card reader
|
||||||
|
acioHandle = new acioemu::ACIOHandle(portName.c_str(), 1);
|
||||||
|
devicehook_init_trampoline();
|
||||||
|
devicehook_add(acioHandle);
|
||||||
|
|
||||||
|
execexe::init();
|
||||||
|
execexe::init_deferred([] () {
|
||||||
|
execexe::init_port_hook(portName, acioHandle);
|
||||||
|
execexe::load_library("libaio.dll");
|
||||||
|
execexe::load_library("libaio-iob.dll");
|
||||||
|
execexe::load_library("libaio-iob_video.dll");
|
||||||
|
execexe::load_library("libaio-iob2_video.dll");
|
||||||
|
execexe::load_library("win10actlog.dll");
|
||||||
|
|
||||||
|
if (!PC_NO_IO) {
|
||||||
|
bi2x_hook_init();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (GRAPHICS_SHOW_CURSOR) {
|
||||||
|
unity_utils::force_show_cursor(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
unity_utils::set_args(
|
||||||
|
std::format("{} {}{}",
|
||||||
|
GetCommandLineA(),
|
||||||
|
PC_INJECT_ARGS,
|
||||||
|
unity_utils::get_unity_player_args()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PCGame::detach() {
|
||||||
|
Game::detach();
|
||||||
|
|
||||||
|
devicehook_dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "games/game.h"
|
||||||
|
|
||||||
|
namespace games::pc {
|
||||||
|
extern std::string PC_INJECT_ARGS;
|
||||||
|
extern bool PC_NO_IO;
|
||||||
|
|
||||||
|
class PCGame : public games::Game {
|
||||||
|
public:
|
||||||
|
PCGame() : Game("Polaris Chord") {}
|
||||||
|
|
||||||
|
virtual void attach() override;
|
||||||
|
virtual void detach() override;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -61,6 +61,7 @@
|
|||||||
#include "games/ccj/trackball.h"
|
#include "games/ccj/trackball.h"
|
||||||
#include "games/qks/qks.h"
|
#include "games/qks/qks.h"
|
||||||
#include "games/mfg/mfg.h"
|
#include "games/mfg/mfg.h"
|
||||||
|
#include "games/pc/pc.h"
|
||||||
#include "games/museca/museca.h"
|
#include "games/museca/museca.h"
|
||||||
#include "hooks/avshook.h"
|
#include "hooks/avshook.h"
|
||||||
#include "hooks/audio/audio.h"
|
#include "hooks/audio/audio.h"
|
||||||
@@ -222,6 +223,7 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
bool attach_ccj = false;
|
bool attach_ccj = false;
|
||||||
bool attach_qks = false;
|
bool attach_qks = false;
|
||||||
bool attach_mfg = false;
|
bool attach_mfg = false;
|
||||||
|
bool attach_pc = false;
|
||||||
bool attach_museca = false;
|
bool attach_museca = false;
|
||||||
bool show_cursor_if_no_touch = false;
|
bool show_cursor_if_no_touch = false;
|
||||||
|
|
||||||
@@ -623,6 +625,9 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::LoadMFGModule].value_bool()) {
|
if (options[launcher::Options::LoadMFGModule].value_bool()) {
|
||||||
attach_mfg = true;
|
attach_mfg = true;
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::LoadPCModule].value_bool()) {
|
||||||
|
attach_pc = true;
|
||||||
|
}
|
||||||
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
if (options[launcher::Options::LoadMusecaModule].value_bool()) {
|
||||||
attach_museca = true;
|
attach_museca = true;
|
||||||
}
|
}
|
||||||
@@ -1101,6 +1106,12 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
if (options[launcher::Options::MFGNoIO].is_active()) {
|
if (options[launcher::Options::MFGNoIO].is_active()) {
|
||||||
games::mfg::MFG_NO_IO = options[launcher::Options::MFGNoIO].value_bool();
|
games::mfg::MFG_NO_IO = options[launcher::Options::MFGNoIO].value_bool();
|
||||||
}
|
}
|
||||||
|
if (options[launcher::Options::PCArgs].is_active()) {
|
||||||
|
games::pc::PC_INJECT_ARGS = options[launcher::Options::PCArgs].value_text();
|
||||||
|
}
|
||||||
|
if (options[launcher::Options::PCNoIO].is_active()) {
|
||||||
|
games::pc::PC_NO_IO = options[launcher::Options::PCNoIO].value_bool();
|
||||||
|
}
|
||||||
if (options[launcher::Options::spice2x_EnableSMXStage].value_bool()) {
|
if (options[launcher::Options::spice2x_EnableSMXStage].value_bool()) {
|
||||||
rawinput::ENABLE_SMX_STAGE = true;
|
rawinput::ENABLE_SMX_STAGE = true;
|
||||||
}
|
}
|
||||||
@@ -1722,6 +1733,16 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Polaris Chord
|
||||||
|
if (check_dll("kamunity.dll") && fileutils::dir_exists("game/svm_Data")) {
|
||||||
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
|
attach_io = true;
|
||||||
|
attach_pc = true;
|
||||||
|
launcher::signal::USE_VEH_WORKAROUND = true;
|
||||||
|
show_cursor_if_no_touch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Busou Shinki: Armored Princess Battle Conductor
|
// Busou Shinki: Armored Princess Battle Conductor
|
||||||
if (check_dll("kamunity.dll") && fileutils::file_exists("game/bsac_app.exe")) {
|
if (check_dll("kamunity.dll") && fileutils::file_exists("game/bsac_app.exe")) {
|
||||||
avs::game::DLL_NAME = "kamunity.dll";
|
avs::game::DLL_NAME = "kamunity.dll";
|
||||||
@@ -1874,6 +1895,10 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
avs::core::set_default_heap_size("kamunity.dll");
|
avs::core::set_default_heap_size("kamunity.dll");
|
||||||
games.push_back(new games::mfg::MFGGame());
|
games.push_back(new games::mfg::MFGGame());
|
||||||
}
|
}
|
||||||
|
if (attach_pc) {
|
||||||
|
avs::core::HEAP_SIZE = 536870912; // 512MB
|
||||||
|
games.push_back(new games::pc::PCGame());
|
||||||
|
}
|
||||||
|
|
||||||
// apply user heap size, if defined
|
// apply user heap size, if defined
|
||||||
if (user_heap_size > 0) {
|
if (user_heap_size > 0) {
|
||||||
|
|||||||
@@ -1072,6 +1072,15 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Mahjong Fight Girl",
|
.game_name = "Mahjong Fight Girl",
|
||||||
.category = "Game Options (Advanced)",
|
.category = "Game Options (Advanced)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// LoadPCModule
|
||||||
|
.title = "Force Load Polaris Chord",
|
||||||
|
.name = "pc",
|
||||||
|
.desc = "manually enable Polaris Chord module",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// LoadMusecaModule
|
// LoadMusecaModule
|
||||||
.title = "Force Load Museca",
|
.title = "Force Load Museca",
|
||||||
@@ -1794,6 +1803,24 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
|
|||||||
.game_name = "Mahjong Fight Girl",
|
.game_name = "Mahjong Fight Girl",
|
||||||
.category = "Game Options (Advanced)"
|
.category = "Game Options (Advanced)"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.title = "PC Arguments Override",
|
||||||
|
.name = "pcargs",
|
||||||
|
.desc = "Command line arguments passed to the game.",
|
||||||
|
.type = OptionType::Text,
|
||||||
|
.setting_name = "",
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options (Advanced)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.title = "PC Disable IO Emulation",
|
||||||
|
.name = "pcnoio",
|
||||||
|
.desc = "Disables BI2X hooks for PC",
|
||||||
|
.type = OptionType::Bool,
|
||||||
|
.setting_name = "",
|
||||||
|
.game_name = "Polaris Chord",
|
||||||
|
.category = "Game Options (Advanced)"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// spice2x_LightsOverallBrightness
|
// spice2x_LightsOverallBrightness
|
||||||
.title = "Lights Brightness Adjustment",
|
.title = "Lights Brightness Adjustment",
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ namespace launcher {
|
|||||||
LoadCCJModule,
|
LoadCCJModule,
|
||||||
LoadQKSModule,
|
LoadQKSModule,
|
||||||
LoadMFGModule,
|
LoadMFGModule,
|
||||||
|
LoadPCModule,
|
||||||
LoadMusecaModule,
|
LoadMusecaModule,
|
||||||
PathToModules,
|
PathToModules,
|
||||||
ScreenshotFolder,
|
ScreenshotFolder,
|
||||||
@@ -202,6 +203,8 @@ namespace launcher {
|
|||||||
MFGArgs,
|
MFGArgs,
|
||||||
MFGCabType,
|
MFGCabType,
|
||||||
MFGNoIO,
|
MFGNoIO,
|
||||||
|
PCArgs,
|
||||||
|
PCNoIO,
|
||||||
spice2x_LightsOverallBrightness,
|
spice2x_LightsOverallBrightness,
|
||||||
spice2x_WindowBorder,
|
spice2x_WindowBorder,
|
||||||
spice2x_WindowSize,
|
spice2x_WindowSize,
|
||||||
|
|||||||
@@ -659,6 +659,8 @@ void eamuse_autodetect_game() {
|
|||||||
eamuse_set_game("QuizKnock STADIUM");
|
eamuse_set_game("QuizKnock STADIUM");
|
||||||
else if (avs::game::is_model("VFG"))
|
else if (avs::game::is_model("VFG"))
|
||||||
eamuse_set_game("Mahjong Fight Girl");
|
eamuse_set_game("Mahjong Fight Girl");
|
||||||
|
else if (avs::game::is_model("XIF"))
|
||||||
|
eamuse_set_game("Polaris Chord");
|
||||||
else {
|
else {
|
||||||
log_warning("eamuse", "unknown game model: {}", avs::game::MODEL);
|
log_warning("eamuse", "unknown game model: {}", avs::game::MODEL);
|
||||||
eamuse_set_game("unknown");
|
eamuse_set_game("unknown");
|
||||||
|
|||||||
@@ -14,11 +14,13 @@ namespace execexe {
|
|||||||
static decltype(&CreateFileA) execexe_CreateFileA = nullptr;
|
static decltype(&CreateFileA) execexe_CreateFileA = nullptr;
|
||||||
static decltype(&CreateFileW) execexe_CreateFileW = nullptr;
|
static decltype(&CreateFileW) execexe_CreateFileW = nullptr;
|
||||||
static decltype(&CloseHandle) execexe_CloseHandle = nullptr;
|
static decltype(&CloseHandle) execexe_CloseHandle = nullptr;
|
||||||
|
static uint64_t (*execexe_PreLoadLibraries)(const char *) = nullptr;
|
||||||
|
|
||||||
static std::wstring plugins_dir;
|
static std::wstring plugins_dir;
|
||||||
static acioemu::ACIOHandle *acio = nullptr;
|
static acioemu::ACIOHandle *acio = nullptr;
|
||||||
static std::wstring port_name;
|
static std::wstring port_name;
|
||||||
static bool port_opened = false;
|
static bool port_opened = false;
|
||||||
|
static std::function<void()> deferred_function = nullptr;
|
||||||
|
|
||||||
static HANDLE WINAPI execexe_CreateFileA_hook(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
static HANDLE WINAPI execexe_CreateFileA_hook(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||||
@@ -62,6 +64,24 @@ namespace execexe {
|
|||||||
return execexe_CloseHandle(hObject);
|
return execexe_CloseHandle(hObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t execexe_PreLoadLibraries_hook(const char *libs) {
|
||||||
|
static bool init = false;
|
||||||
|
|
||||||
|
uint64_t result = execexe_PreLoadLibraries(libs);
|
||||||
|
if (init) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
init = true;
|
||||||
|
log_info("execexe", "execexe_PreLoadLibraries hook hit");
|
||||||
|
|
||||||
|
if (deferred_function) {
|
||||||
|
deferred_function();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
HMODULE init() {
|
HMODULE init() {
|
||||||
execexe_module = libutils::load_library("execexe.dll");
|
execexe_module = libutils::load_library("execexe.dll");
|
||||||
execexe_LoadLibraryW = libutils::get_proc<decltype(&LoadLibraryW)>(execexe_module, MAKEINTRESOURCE(34));
|
execexe_LoadLibraryW = libutils::get_proc<decltype(&LoadLibraryW)>(execexe_module, MAKEINTRESOURCE(34));
|
||||||
@@ -70,6 +90,7 @@ namespace execexe {
|
|||||||
execexe_CloseHandle = libutils::get_proc<decltype(&CloseHandle)>(execexe_module, MAKEINTRESOURCE(7));
|
execexe_CloseHandle = libutils::get_proc<decltype(&CloseHandle)>(execexe_module, MAKEINTRESOURCE(7));
|
||||||
execexe_CreateFileA = libutils::get_proc<decltype(&CreateFileA)>(execexe_module, MAKEINTRESOURCE(9));
|
execexe_CreateFileA = libutils::get_proc<decltype(&CreateFileA)>(execexe_module, MAKEINTRESOURCE(9));
|
||||||
execexe_CreateFileW = libutils::get_proc<decltype(&CreateFileW)>(execexe_module, MAKEINTRESOURCE(11));
|
execexe_CreateFileW = libutils::get_proc<decltype(&CreateFileW)>(execexe_module, MAKEINTRESOURCE(11));
|
||||||
|
execexe_PreLoadLibraries = libutils::get_proc<decltype(execexe_PreLoadLibraries)>(execexe_module, MAKEINTRESOURCE(48));
|
||||||
|
|
||||||
auto module_path = libutils::module_file_name(nullptr);
|
auto module_path = libutils::module_file_name(nullptr);
|
||||||
module_path = module_path.replace_extension("");
|
module_path = module_path.replace_extension("");
|
||||||
@@ -79,6 +100,15 @@ namespace execexe {
|
|||||||
return execexe_module;
|
return execexe_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void init_deferred(std::function<void()> init_func) {
|
||||||
|
if (deferred_function) {
|
||||||
|
log_fatal("execexe", "deferred init function is already set");
|
||||||
|
}
|
||||||
|
deferred_function = std::move(init_func);
|
||||||
|
detour::trampoline("execexe.dll", MAKEINTRESOURCE(48),
|
||||||
|
execexe_PreLoadLibraries_hook, &execexe_PreLoadLibraries);
|
||||||
|
}
|
||||||
|
|
||||||
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle) {
|
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle) {
|
||||||
static bool init = false;
|
static bool init = false;
|
||||||
if (init)
|
if (init)
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "acioemu/handle.h"
|
#include "acioemu/handle.h"
|
||||||
|
|
||||||
namespace execexe {
|
namespace execexe {
|
||||||
HMODULE init();
|
HMODULE init();
|
||||||
|
void init_deferred(std::function<void()> init_func);
|
||||||
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle);
|
void init_port_hook(const std::wstring &portName, acioemu::ACIOHandle *acioHandle);
|
||||||
HMODULE load_library(const char *module_name, bool fatal = true);
|
HMODULE load_library(const char *module_name, bool fatal = true);
|
||||||
FARPROC get_proc(HMODULE module, const char *proc_name, bool fatal = true);
|
FARPROC get_proc(HMODULE module, const char *proc_name, bool fatal = true);
|
||||||
|
|||||||
Reference in New Issue
Block a user