Update to spice2x-25-04-25 (pre-apply)

> broken commit
This commit is contained in:
[ ]
2025-05-07 00:25:31 +09:00
parent 04dee88276
commit c94de456b5
543 changed files with 78491 additions and 91698 deletions
+3
View File
@@ -70,6 +70,9 @@ void acio::attach() {
libraryhook_hook_library("libacioex.dll", acio::DLL_INSTANCE);
libraryhook_hook_library("libacio_ex.dll", acio::DLL_INSTANCE);
libraryhook_hook_library("libacio_old.dll", acio::DLL_INSTANCE);
// libacioEx.dll for Road Fighters 3D
// needed as comparisons in LoadLibrary hooks are case-sensitive
libraryhook_hook_library("libacioEx.dll", acio::DLL_INSTANCE);
libraryhook_enable(avs::game::DLL_INSTANCE);
// get hook mode
+288 -2
View File
@@ -2,6 +2,7 @@
#include "avs/game.h"
#include "games/ddr/io.h"
#include "games/ddr/ddr.h"
#include "games/sdvx/sdvx.h"
#include "games/sdvx/io.h"
#include "games/drs/io.h"
@@ -9,6 +10,7 @@
#include "misc/eamuse.h"
#include "util/logging.h"
#include "util/utils.h"
#include "util/tapeled.h"
using namespace GameAPI;
@@ -399,6 +401,148 @@ static long __cdecl ac_io_bi2a_control_led_bright(size_t index, uint8_t brightne
if (light.light2 >= 0) {
Lights::writeLight(RI_MGR, lights[light.light2], brightness / light.max);
}
// DANCERUSH
} else if (avs::game::is_model("REC")) {
/*
* Control R G B
* ==============================
* CARD UNIT 13 14 15
* TITLE PANEL 28 29 30
* MONITOR SIDE LEFT (tape LED - see ac_io_bi2a_control_tapeled_bright)
* MONITOR SIDE RIGHT (tape LED - see ac_io_bi2a_control_tapeled_bright)
*
* Values go up to 127.
*
* Control Index
* ==================
* 1P LEFT 11
* 1P RIGHT 12
* 1P UP 9
* 1P DOWN 10
* 1P START 8
* 2P LEFT 19
* 2P RIGHT 20
* 2P UP 17
* 2P DOWN 18
* 2P START 16
*
* Values go up to 127.
*/
static const struct {
int light;
float max;
} mapping[] = {
{ -1, 0 }, // 0
{ -1, 0 }, // 1
{ -1, 0 }, // 2
{ -1, 0 }, // 3
{ -1, 0 }, // 4
{ -1, 0 }, // 5
{ -1, 0 }, // 6
{ -1, 0 }, // 7
{ games::drs::Lights::P1_START, 127 }, // 8
{ games::drs::Lights::P1_MENU_UP, 127 }, // 9
{ games::drs::Lights::P1_MENU_DOWN, 127 }, // 10
{ games::drs::Lights::P1_MENU_LEFT, 127 }, // 11
{ games::drs::Lights::P1_MENU_RIGHT, 127 }, // 12
{ games::drs::Lights::CARD_READER_R, 127 }, // 13
{ games::drs::Lights::CARD_READER_G, 127 }, // 14
{ games::drs::Lights::CARD_READER_B, 127 }, // 15
{ games::drs::Lights::P2_START, 127 }, // 16
{ games::drs::Lights::P2_MENU_UP, 127 }, // 17
{ games::drs::Lights::P2_MENU_DOWN, 127 }, // 18
{ games::drs::Lights::P2_MENU_LEFT, 127 }, // 19
{ games::drs::Lights::P2_MENU_RIGHT, 127 }, // 20
{ -1, 0 }, // 21
{ -1, 0 }, // 22
{ -1, 0 }, // 23
{ -1, 0 }, // 24
{ -1, 0 }, // 25
{ -1, 0 }, // 26
{ -1, 0 }, // 27
{ games::drs::Lights::TITLE_PANEL_R, 127 }, // 28
{ games::drs::Lights::TITLE_PANEL_G, 127 }, // 29
{ games::drs::Lights::TITLE_PANEL_B, 127 }, // 30
};
// ignore index out of range
if (index > std::size(mapping)) {
return true;
}
// get lights
auto &lights = games::drs::get_lights();
// get light from mapping
auto light = mapping[index];
// write lights
if (light.light >= 0) {
Lights::writeLight(RI_MGR, lights[light.light], brightness / light.max);
} else {
log_warning("drs", "light unset {} {}", index, (int) brightness);
}
// DanceDanceRevolution
} else if (avs::game::is_model("MDX")) {
static const struct {
int light;
float max;
} mapping[] = {
{ -1, 0 }, // 0
{ -1, 0 }, // 1
{ -1, 0 }, // 2
{ -1, 0 }, // 3
{ -1, 0 }, // 4
{ -1, 0 }, // 5
{ -1, 0 }, // 6
{ -1, 0 }, // 7
{ games::ddr::Lights::GOLD_P1_MENU_START, 127 }, // 8
{ games::ddr::Lights::GOLD_P1_MENU_UP, 127 }, // 9
{ games::ddr::Lights::GOLD_P1_MENU_DOWN, 127 }, // 10
{ games::ddr::Lights::GOLD_P1_MENU_LEFT, 127 }, // 11
{ games::ddr::Lights::GOLD_P1_MENU_RIGHT, 127 }, // 12
{ games::ddr::Lights::GOLD_P1_CARD_UNIT_R, 127 }, // 13
{ games::ddr::Lights::GOLD_P1_CARD_UNIT_G, 127 }, // 14
{ games::ddr::Lights::GOLD_P1_CARD_UNIT_B, 127 }, // 15
{ games::ddr::Lights::GOLD_P2_MENU_START, 127 }, // 16
{ games::ddr::Lights::GOLD_P2_MENU_UP, 127 }, // 17
{ games::ddr::Lights::GOLD_P2_MENU_DOWN, 127 }, // 18
{ games::ddr::Lights::GOLD_P2_MENU_LEFT, 127 }, // 19
{ games::ddr::Lights::GOLD_P2_MENU_RIGHT, 127 }, // 20
{ games::ddr::Lights::GOLD_P2_CARD_UNIT_R, 0 }, // 21
{ games::ddr::Lights::GOLD_P2_CARD_UNIT_G, 0 }, // 22
{ games::ddr::Lights::GOLD_P2_CARD_UNIT_B, 0 }, // 23
{ -1, 0 }, // 24
{ -1, 0 }, // 25
{ -1, 0 }, // 26
{ -1, 0 }, // 27
{ games::ddr::Lights::GOLD_TITLE_PANEL_LEFT, 0 }, // 28
{ games::ddr::Lights::GOLD_TITLE_PANEL_CENTER, 0 }, // 29
{ games::ddr::Lights::GOLD_TITLE_PANEL_RIGHT, 0 }, // 30
{ games::ddr::Lights::GOLD_P1_WOOFER_CORNER, 0 }, // 31
{ games::ddr::Lights::GOLD_P2_WOOFER_CORNER, 0 } // 32
};
// ignore index out of range
if (index > std::size(mapping)) {
return true;
}
// get lights
auto &lights = games::ddr::get_lights();
// get light from mapping
auto light = mapping[index];
// write lights
if (light.light >= 0) {
Lights::writeLight(RI_MGR, lights[light.light], brightness / light.max);
}
}
// return success
@@ -443,7 +587,7 @@ static bool __cdecl ac_io_bi2a_tapeled_init_is_finished() {
static bool __cdecl ac_io_bi2a_control_tapeled_rec_set(uint8_t* data, size_t x_sz, size_t y_sz) {
// check dimensions
if (x_sz != 38 || y_sz != 49) {
if (x_sz != DRS_TAPELED_COLS || y_sz != DRS_TAPELED_ROWS) {
log_fatal("drs", "DRS tapeled wrong dimensions");
}
@@ -458,9 +602,151 @@ static bool __cdecl ac_io_bi2a_control_tapeled_rec_set(uint8_t* data, size_t x_s
return true;
}
// TODO: this controls the upright RGB bars on the sides
// TODO: DRS tape lights
static bool __cdecl ac_io_bi2a_control_tapeled_bright(size_t off1, size_t off2,
uint8_t r, uint8_t g, uint8_t b, uint8_t bank) {
if (!tapeledutils::is_enabled()) {
return true;
}
if (avs::game::is_model("MDX")) {
/*
* r, g, b values range from [0-255]
* bank always seems to be [0]
*
* [off1.off2] [LEDs] [tape name]
* 0.0 25 P1 Foot Up (0.0 to 0.24, inclusive)
* 0.25 25 P1 Foot Right
* 1.0 25 P1 Foot Left
* 1.25 25 P1 Foot Down
*
* 2.0 25 P2 Foot Up
* 2.25 25 P2 Foot Right
* 3.0 25 P2 Foot Left
* 3.25 25 P2 Foot Down
*
* 5.0 50 Top Panel
* 6.0 50 Monitor side left
* 7.0 50 Monitor side right
*/
// In order to set the data that can be output via Spice API, we first
// need to figure out which device in our buffers this data belongs to
int device = -1;
if (off1 == 0) {
if (off2 < 25) device = 0; // P1 Foot Up
else device = 1; // P1 Foot Right
} else if (off1 == 1) {
if (off2 < 25) device = 2; // P1 Foot Left
else device = 3; // P1 Foot Down
} else if (off1 == 2) {
if (off2 < 25) device = 4; // P2 Foot Up
else device = 5; // P2 Foot Right
} else if (off1 == 3) {
if (off2 < 25) device = 6; // P2 Foot Left
else device = 7; // P2 Foot Down
} else if (off1 >= 5 && off1 <= 7) {
device = off1 + 3; // Top Panel / Monitor Side Left / Monitor Side Right
}
if (device != -1) {
// We subtract 25 from off2 to get the device's LED index, if it's for one of the
// arrow panels that is on the latter half of the logical strip
size_t subtractor = 0;
if (off1 <= 3 && off2 >= 25) {
subtractor = 25;
}
size_t led_index = off2 - subtractor;
games::ddr::DDR_TAPELEDS[device][led_index][0] = r;
games::ddr::DDR_TAPELEDS[device][led_index][1] = g;
games::ddr::DDR_TAPELEDS[device][led_index][2] = b;
}
static struct TapeLedMapping {
bool split; // true == 50 LEDs for one light, false == 25 for two lights
uint8_t index_r0, index_g0, index_b0;
uint8_t index_r1, index_g1, index_b1;
size_t index_for_avg0 = UINT8_MAX;
size_t index_for_avg1 = UINT8_MAX;
TapeLedMapping(
uint8_t index_r0, uint8_t index_g0, uint8_t index_b0,
uint8_t index_r1, uint8_t index_g1, uint8_t index_b1)
: index_r0(index_r0), index_g0(index_g0), index_b0(index_b0),
index_r1(index_r1), index_g1(index_g1), index_b1(index_b1) {
split = (index_r1 != UINT8_MAX);
if (split) {
index_for_avg0 = tapeledutils::get_led_index_using_avg_algo(25);
index_for_avg1 = index_for_avg0 + 25;
} else {
index_for_avg0 = tapeledutils::get_led_index_using_avg_algo(50);
index_for_avg1 = -1;
}
}
} mapping[] = {
{
games::ddr::Lights::GOLD_P1_FOOT_UP_AVG_R, games::ddr::Lights::GOLD_P1_FOOT_UP_AVG_G, games::ddr::Lights::GOLD_P1_FOOT_UP_AVG_B,
games::ddr::Lights::GOLD_P1_FOOT_RIGHT_AVG_R, games::ddr::Lights::GOLD_P1_FOOT_RIGHT_AVG_G, games::ddr::Lights::GOLD_P1_FOOT_RIGHT_AVG_B
},
{
games::ddr::Lights::GOLD_P1_FOOT_LEFT_AVG_R, games::ddr::Lights::GOLD_P1_FOOT_LEFT_AVG_G, games::ddr::Lights::GOLD_P1_FOOT_LEFT_AVG_B,
games::ddr::Lights::GOLD_P1_FOOT_DOWN_AVG_R, games::ddr::Lights::GOLD_P1_FOOT_DOWN_AVG_G, games::ddr::Lights::GOLD_P1_FOOT_DOWN_AVG_B
},
{
games::ddr::Lights::GOLD_P2_FOOT_UP_AVG_R, games::ddr::Lights::GOLD_P2_FOOT_UP_AVG_G, games::ddr::Lights::GOLD_P2_FOOT_UP_AVG_B,
games::ddr::Lights::GOLD_P2_FOOT_RIGHT_AVG_R, games::ddr::Lights::GOLD_P2_FOOT_RIGHT_AVG_G, games::ddr::Lights::GOLD_P2_FOOT_RIGHT_AVG_B
},
{
games::ddr::Lights::GOLD_P2_FOOT_LEFT_AVG_R, games::ddr::Lights::GOLD_P2_FOOT_LEFT_AVG_G, games::ddr::Lights::GOLD_P2_FOOT_LEFT_AVG_B,
games::ddr::Lights::GOLD_P2_FOOT_DOWN_AVG_R, games::ddr::Lights::GOLD_P2_FOOT_DOWN_AVG_G, games::ddr::Lights::GOLD_P2_FOOT_DOWN_AVG_B
},
{
games::ddr::Lights::GOLD_TOP_PANEL_AVG_R, games::ddr::Lights::GOLD_TOP_PANEL_AVG_G, games::ddr::Lights::GOLD_TOP_PANEL_AVG_B,
UINT8_MAX, UINT8_MAX, UINT8_MAX
},
{
UINT8_MAX, UINT8_MAX, UINT8_MAX,
UINT8_MAX, UINT8_MAX, UINT8_MAX
},
{
games::ddr::Lights::GOLD_MONITOR_SIDE_LEFT_AVG_R, games::ddr::Lights::GOLD_MONITOR_SIDE_LEFT_AVG_G, games::ddr::Lights::GOLD_MONITOR_SIDE_LEFT_AVG_B,
UINT8_MAX, UINT8_MAX, UINT8_MAX
},
{
games::ddr::Lights::GOLD_MONITOR_SIDE_RIGHT_AVG_R, games::ddr::Lights::GOLD_MONITOR_SIDE_RIGHT_AVG_G, games::ddr::Lights::GOLD_MONITOR_SIDE_RIGHT_AVG_B,
UINT8_MAX, UINT8_MAX, UINT8_MAX
},
};
if (off1 < std::size(mapping)) {
auto &map = mapping[off1];
size_t off2_match = -1;
if (!map.split || off2 < 25) {
off2_match = map.index_for_avg0;
} else {
off2_match = map.index_for_avg1;
}
if (off2_match == off2 && map.index_r0 != UINT8_MAX) {
auto &lights = games::ddr::get_lights();
if (!map.split || off2 < 25) {
Lights::writeLight(RI_MGR, lights[map.index_r0], r / 255.f);
Lights::writeLight(RI_MGR, lights[map.index_g0], g / 255.f);
Lights::writeLight(RI_MGR, lights[map.index_b0], b / 255.f);
} else {
Lights::writeLight(RI_MGR, lights[map.index_r1], r / 255.f);
Lights::writeLight(RI_MGR, lights[map.index_g1], g / 255.f);
Lights::writeLight(RI_MGR, lights[map.index_b1], b / 255.f);
}
}
}
}
return true;
}
+20
View File
@@ -33,6 +33,11 @@ static int __cdecl ac_io_bmpu_control_1p_start_led_off() {
if (avs::game::is_model("KDM")) {
auto &lights = games::dea::get_lights();
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P1Start), 0.f);
// MUSECA
} else if (avs::game::is_model("PIX")) {
auto &lights = games::museca::get_lights();
Lights::writeLight(RI_MGR, lights.at(games::museca::Lights::Start), 0.f);
}
return 1;
@@ -44,6 +49,11 @@ static int __cdecl ac_io_bmpu_control_1p_start_led_on() {
if (avs::game::is_model("KDM")) {
auto &lights = games::dea::get_lights();
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P1Start), 1.f);
// MUSECA
} else if (avs::game::is_model("PIX")) {
auto &lights = games::museca::get_lights();
Lights::writeLight(RI_MGR, lights.at(games::museca::Lights::Start), 1.f);
}
return 1;
@@ -55,6 +65,11 @@ static int __cdecl ac_io_bmpu_control_2p_start_led_off() {
if (avs::game::is_model("KDM")) {
auto &lights = games::dea::get_lights();
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P2Start), 0.f);
// MUSECA
} else if (avs::game::is_model("PIX")) {
auto &lights = games::museca::get_lights();
Lights::writeLight(RI_MGR, lights.at(games::museca::Lights::Keypad), 0.f);
}
return 1;
@@ -66,6 +81,11 @@ static int __cdecl ac_io_bmpu_control_2p_start_led_on() {
if (avs::game::is_model("KDM")) {
auto &lights = games::dea::get_lights();
Lights::writeLight(RI_MGR, lights.at(games::dea::Lights::P2Start), 1.f);
// MUSECA
} else if (avs::game::is_model("PIX")) {
auto &lights = games::museca::get_lights();
Lights::writeLight(RI_MGR, lights.at(games::museca::Lights::Keypad), 1.f);
}
return 1;
+47 -12
View File
@@ -25,6 +25,13 @@ struct ICCA_STATUS {
uint32_t key_edge;
uint32_t key_level;
};
struct ICCA_STATUS_LA9 {
uint8_t status_code;
uint8_t card_in;
uint8_t uid[8];
uint8_t error;
uint8_t uid2[8];
};
static_assert(sizeof(struct ICCA_STATUS) == 24, "ICCA_STATUS must be 24 bytes");
enum ICCA_WORKFLOW {
@@ -52,6 +59,7 @@ struct ICCA_UNIT {
char key_serial = 0;
bool uid_skip = false;
bool initialized = false;
int felica_retries = 0;
};
static ICCA_UNIT ICCA_UNITS[2] {};
static bool IS_LAST_CARD_FELICA = false;
@@ -88,14 +96,25 @@ static inline void update_card(int unit_id) {
// eamio keypress
int index = unit_id > 0 && icca_get_active_count() > 1 ? 1 : 0;
bool kb_insert_press = (eamuse_get_keypad_state(index) & (1 << EAM_IO_INSERT)) > 0;
static bool kb_insert_press_old[2] = {false, false};
// get unit
ICCA_UNIT *unit = &ICCA_UNITS[unit_id];
const bool card_presented = eamuse_card_insert_consume(icca_get_active_count(), unit_id);
const bool key_pressed = (kb_insert_press && !kb_insert_press_old[unit_id]);
// beatstream and nostalgia have logic that requires ac_io_icca_get_uid_felica to return the
// exact same card number multiple times in a row in order for the card number to be read...
// for whatever reason setting this to 3-4 doesn't work the very first time the game boots up
// so we use 10 just to be safe
const bool need_felica_retries = avs::game::is_model({"NBT", "PAN"});
if (need_felica_retries && (card_presented || key_pressed)) {
unit->felica_retries = 10;
}
// check for card insert
static bool kb_insert_press_old[2] = {false, false};
if (eamuse_card_insert_consume(icca_get_active_count(), unit_id) ||
(kb_insert_press && !kb_insert_press_old[unit_id])) {
if (card_presented || key_pressed || (0 < unit->felica_retries)) {
if (!unit->card_cmd_pressed) {
unit->card_cmd_pressed = true;
if (unit->state == GET_USERID || unit->state == CLOSE_EJECT || unit->state == STEP) {
@@ -288,17 +307,29 @@ static char __cdecl ac_io_icca_get_status(void *a1, void *a2) {
// funny workaround
if (acio::ICCA_COMPAT_ACTIVE) {
if (avs::game::is_model("LA9")) {
auto p = (ICCA_STATUS*) status;
// the struct is different (28 bytes instead of 24) but nobody ain't got time for that
auto p = (ICCA_STATUS*) status;
p->error = p->key_level << 16;
p->front_sensor = p->uid[0];
p->rear_sensor = p->uid[1];
for (size_t i = 2; i < sizeof(p->uid); i++) {
p->uid[i - 2] = p->uid[i];
ICCA_STATUS_LA9 p_la9;
p_la9.status_code = unit->state;
p_la9.card_in = unit->card_in;
memcpy(p_la9.uid, p->uid, sizeof(p_la9.uid));
p_la9.error = p->error;
memcpy(p_la9.uid2, p->uid, sizeof(p_la9.uid));
memcpy(status, &p_la9, sizeof(ICCA_STATUS_LA9));
} else {
// the struct is different (28 bytes instead of 24) but nobody ain't got time for that
auto p = (ICCA_STATUS*) status;
p->error = p->key_level << 16;
p->front_sensor = p->uid[0];
p->rear_sensor = p->uid[1];
for (size_t i = 2; i < sizeof(p->uid); i++) {
p->uid[i - 2] = p->uid[i];
}
p->uid[sizeof(p->uid) - 2] = 0;
p->uid[sizeof(p->uid) - 1] = 0;
}
p->uid[sizeof(p->uid) - 2] = 0;
p->uid[sizeof(p->uid) - 1] = 0;
}
return 1;
@@ -330,6 +361,10 @@ static char __cdecl ac_io_icca_get_uid_felica(int unit_id, char *card) {
card[8] = (char) (felica ? 1 : 0);
IS_LAST_CARD_FELICA = felica;
if (0 < unit->felica_retries) {
unit->felica_retries--;
}
// check for error
return unit->state != ERR_GETUID;
}
+68 -16
View File
@@ -16,13 +16,26 @@ static uint8_t COUNTER = 0;
// buffers
#pragma pack(push, 1)
static struct {
uint8_t STATUS_BUFFER_17[7][STATUS_BUFFER_SIZE] {};
uint8_t STATUS_BUFFER_18[7][STATUS_BUFFER_SIZE] {};
uint8_t STATUS_BUFFER_P1[7][STATUS_BUFFER_SIZE] {};
uint8_t STATUS_BUFFER_P2[7][STATUS_BUFFER_SIZE] {};
} BUFFERS {};
#pragma pack(pop)
static bool STATUS_BUFFER_FREEZE = false;
typedef uint64_t (__cdecl *ARK_GET_TICK_TIME64_T)();
static uint64_t arkGetTickTime64() {
static ARK_GET_TICK_TIME64_T getTickTime64 =
(ARK_GET_TICK_TIME64_T)GetProcAddress(avs::game::DLL_INSTANCE, "arkGetTickTime64");
if (getTickTime64 == nullptr) {
// this works on 32-bit versions of avs, but not on 64.
// it's better than nothing though.
return timeGetTime();
}
return getTickTime64();
}
/*
* Implementations
*/
@@ -33,13 +46,13 @@ static bool __cdecl ac_io_mdxf_get_control_status_buffer(int node, void *buffer,
if (avs::game::is_model("MDX")) {
// get buffer index
auto i = (COUNTER + a3) % std::size(BUFFERS.STATUS_BUFFER_17);
auto i = (COUNTER + a3) % std::size(BUFFERS.STATUS_BUFFER_P1);
// copy buffer
if (node == 17) {
memcpy(buffer, BUFFERS.STATUS_BUFFER_17[i], STATUS_BUFFER_SIZE);
} else if (node == 18) {
memcpy(buffer, BUFFERS.STATUS_BUFFER_18[i], STATUS_BUFFER_SIZE);
if (node == 17 || node == 25) {
memcpy(buffer, BUFFERS.STATUS_BUFFER_P1[i], STATUS_BUFFER_SIZE);
} else if (node == 18 || node == 26) {
memcpy(buffer, BUFFERS.STATUS_BUFFER_P2[i], STATUS_BUFFER_SIZE);
} else {
// fill with zeros on unknown node
@@ -52,16 +65,49 @@ static bool __cdecl ac_io_mdxf_get_control_status_buffer(int node, void *buffer,
return true;
}
static bool __cdecl ac_io_mdxf_set_output_level(unsigned int a1, unsigned int a2, uint8_t a3) {
// TODO(felix): DDR BIO2 lights
static bool __cdecl ac_io_mdxf_set_output_level(unsigned int a1, unsigned int a2, uint8_t value) {
if (avs::game::is_model("MDX")) {
static const struct {
int a2[4];
} mapping[] = {
{
// a1 == 17
{
games::ddr::Lights::GOLD_P1_STAGE_UP_RIGHT,
games::ddr::Lights::GOLD_P1_STAGE_DOWN_LEFT,
games::ddr::Lights::GOLD_P1_STAGE_UP_LEFT,
games::ddr::Lights::GOLD_P1_STAGE_DOWN_RIGHT
}
},
{
// a1 == 18
{
games::ddr::Lights::GOLD_P2_STAGE_UP_RIGHT,
games::ddr::Lights::GOLD_P2_STAGE_DOWN_LEFT,
games::ddr::Lights::GOLD_P2_STAGE_UP_LEFT,
games::ddr::Lights::GOLD_P2_STAGE_DOWN_RIGHT
}
}
};
if ((a1 == 17 || a1 == 18) && (a2 < 4)) {
// get light from mapping
const auto light = mapping[a1 - 17].a2[a2];
// get lights
auto &lights = games::ddr::get_lights();
// write lights
GameAPI::Lights::writeLight(RI_MGR, lights[light], value / 128.f);
}
}
return true;
}
static bool __cdecl ac_io_mdxf_update_control_status_buffer(int node) {
// increase counter
COUNTER = (COUNTER + 1) % std::size(BUFFERS.STATUS_BUFFER_17);
COUNTER = (COUNTER + 1) % std::size(BUFFERS.STATUS_BUFFER_P1);
// check freeze
if (STATUS_BUFFER_FREEZE) {
@@ -72,10 +118,12 @@ static bool __cdecl ac_io_mdxf_update_control_status_buffer(int node) {
uint8_t *buffer = nullptr;
switch (node) {
case 17:
buffer = BUFFERS.STATUS_BUFFER_17[COUNTER];
case 25:
buffer = BUFFERS.STATUS_BUFFER_P1[COUNTER];
break;
case 18:
buffer = BUFFERS.STATUS_BUFFER_18[COUNTER];
case 26:
buffer = BUFFERS.STATUS_BUFFER_P2[COUNTER];
break;
default:
@@ -92,13 +140,13 @@ static bool __cdecl ac_io_mdxf_update_control_status_buffer(int node) {
// FOOT UP = bit 36-39 = byte 4, bit 4-7
// FOOT RIGHT = bit 40-43 = byte 5, bit 0-3
// FOOT LEFT = bit 44-47 = byte 5, bit 4-7
static const size_t buttons_17[] = {
static const size_t buttons_p1[] = {
games::ddr::Buttons::P1_PANEL_UP,
games::ddr::Buttons::P1_PANEL_DOWN,
games::ddr::Buttons::P1_PANEL_LEFT,
games::ddr::Buttons::P1_PANEL_RIGHT,
};
static const size_t buttons_18[] = {
static const size_t buttons_p2[] = {
games::ddr::Buttons::P2_PANEL_UP,
games::ddr::Buttons::P2_PANEL_DOWN,
games::ddr::Buttons::P2_PANEL_LEFT,
@@ -109,13 +157,17 @@ static bool __cdecl ac_io_mdxf_update_control_status_buffer(int node) {
const size_t *button_map = nullptr;
switch (node) {
case 17:
button_map = &buttons_17[0];
case 25:
button_map = &buttons_p1[0];
break;
case 18:
button_map = &buttons_18[0];
case 26:
button_map = &buttons_p2[0];
break;
}
*(uint64_t*)&buffer[0x18] = arkGetTickTime64();
// get buttons
auto &buttons = games::ddr::get_buttons();
+1
View File
@@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <string>
#include <windows.h>
+110 -9
View File
@@ -6,6 +6,11 @@
#include "util/logging.h"
#include "avs/game.h"
// std::min
#ifdef min
#undef min
#endif
using namespace GameAPI;
// static stuff
@@ -79,6 +84,32 @@ static bool __cdecl ac_io_panb_start_auto_input() {
return true;
}
static uint8_t panb_get_button_velocity(Button button, Button button_soft, Button button_medium, Button button_hard) {
const auto velocity = Buttons::getVelocity(RI_MGR, button);
const auto velocity_soft = Buttons::getVelocity(RI_MGR, button_soft);
const auto velocity_medium = Buttons::getVelocity(RI_MGR, button_medium);
const auto velocity_hard = Buttons::getVelocity(RI_MGR, button_hard);
// note that the digital values have been obtained via trial-and-error in recital mode
// based on Op3:
// * soft presses glow blue, should trigger Elegant in blue sections
// * hard presses glow red/orange, should trigger Elegant in yellow sections
// * default (medium) presses glow green, triggers Elegant in both blue and yellow sections
// digital-only values
if (velocity_hard > 0.f) {
// do NOT use 15 here!! 14 properly registers as a hard press, but 15 does not
return 14;
} else if (velocity_medium > 0.f) {
return 11;
} else if (velocity_soft > 0.f) {
return 1;
}
// digital or midi (velocity-sensitive) values
return std::min((uint8_t)(velocity * 15.999f), (uint8_t)14);
}
static bool __cdecl ac_io_panb_update_control_status_buffer() {
// check freeze
@@ -107,6 +138,7 @@ static bool __cdecl ac_io_panb_update_control_status_buffer() {
auto &analogs = games::nost::get_analogs();
// mappings
// "normal" buttons - these are velocity sensitive (digital or MIDI)
static const size_t button_mapping[] = {
games::nost::Buttons::Key1, games::nost::Buttons::Key2,
games::nost::Buttons::Key3, games::nost::Buttons::Key4,
@@ -123,6 +155,60 @@ static bool __cdecl ac_io_panb_update_control_status_buffer() {
games::nost::Buttons::Key25, games::nost::Buttons::Key26,
games::nost::Buttons::Key27, games::nost::Buttons::Key28,
};
// soft (digital) button - always registers as soft press
static const size_t soft_button_mapping[] = {
games::nost::Buttons::Key1Soft, games::nost::Buttons::Key2Soft,
games::nost::Buttons::Key3Soft, games::nost::Buttons::Key4Soft,
games::nost::Buttons::Key5Soft, games::nost::Buttons::Key6Soft,
games::nost::Buttons::Key7Soft, games::nost::Buttons::Key8Soft,
games::nost::Buttons::Key9Soft, games::nost::Buttons::Key10Soft,
games::nost::Buttons::Key11Soft, games::nost::Buttons::Key12Soft,
games::nost::Buttons::Key13Soft, games::nost::Buttons::Key14Soft,
games::nost::Buttons::Key15Soft, games::nost::Buttons::Key16Soft,
games::nost::Buttons::Key17Soft, games::nost::Buttons::Key18Soft,
games::nost::Buttons::Key19Soft, games::nost::Buttons::Key20Soft,
games::nost::Buttons::Key21Soft, games::nost::Buttons::Key22Soft,
games::nost::Buttons::Key23Soft, games::nost::Buttons::Key24Soft,
games::nost::Buttons::Key25Soft, games::nost::Buttons::Key26Soft,
games::nost::Buttons::Key27Soft, games::nost::Buttons::Key28Soft,
};
// medium (digital) button - always registers as medium press
static const size_t medium_button_mapping[] = {
games::nost::Buttons::Key1Medium, games::nost::Buttons::Key2Medium,
games::nost::Buttons::Key3Medium, games::nost::Buttons::Key4Medium,
games::nost::Buttons::Key5Medium, games::nost::Buttons::Key6Medium,
games::nost::Buttons::Key7Medium, games::nost::Buttons::Key8Medium,
games::nost::Buttons::Key9Medium, games::nost::Buttons::Key10Medium,
games::nost::Buttons::Key11Medium, games::nost::Buttons::Key12Medium,
games::nost::Buttons::Key13Medium, games::nost::Buttons::Key14Medium,
games::nost::Buttons::Key15Medium, games::nost::Buttons::Key16Medium,
games::nost::Buttons::Key17Medium, games::nost::Buttons::Key18Medium,
games::nost::Buttons::Key19Medium, games::nost::Buttons::Key20Medium,
games::nost::Buttons::Key21Medium, games::nost::Buttons::Key22Medium,
games::nost::Buttons::Key23Medium, games::nost::Buttons::Key24Medium,
games::nost::Buttons::Key25Medium, games::nost::Buttons::Key26Medium,
games::nost::Buttons::Key27Medium, games::nost::Buttons::Key28Medium,
};
// hard (digital) button - always registers as hard press
static const size_t hard_button_mapping[] = {
games::nost::Buttons::Key1Hard, games::nost::Buttons::Key2Hard,
games::nost::Buttons::Key3Hard, games::nost::Buttons::Key4Hard,
games::nost::Buttons::Key5Hard, games::nost::Buttons::Key6Hard,
games::nost::Buttons::Key7Hard, games::nost::Buttons::Key8Hard,
games::nost::Buttons::Key9Hard, games::nost::Buttons::Key10Hard,
games::nost::Buttons::Key11Hard, games::nost::Buttons::Key12Hard,
games::nost::Buttons::Key13Hard, games::nost::Buttons::Key14Hard,
games::nost::Buttons::Key15Hard, games::nost::Buttons::Key16Hard,
games::nost::Buttons::Key17Hard, games::nost::Buttons::Key18Hard,
games::nost::Buttons::Key19Hard, games::nost::Buttons::Key20Hard,
games::nost::Buttons::Key21Hard, games::nost::Buttons::Key22Hard,
games::nost::Buttons::Key23Hard, games::nost::Buttons::Key24Hard,
games::nost::Buttons::Key25Hard, games::nost::Buttons::Key26Hard,
games::nost::Buttons::Key27Hard, games::nost::Buttons::Key28Hard,
};
static const size_t analog_mapping[] = {
games::nost::Analogs::Key1, games::nost::Analogs::Key2,
games::nost::Analogs::Key3, games::nost::Analogs::Key4,
@@ -148,23 +234,38 @@ static bool __cdecl ac_io_panb_update_control_status_buffer() {
uint8_t state1 = 0;
// check analogs
//
// while 15 is technically allowed by the I/O board & is recognized correctly in test
// menu, when you play recital mode, 15 fails to register Elegant in yellow sections.
// therefore, cap the value at 14. tested with Nostroller.
auto &analog0 = analogs.at(analog_mapping[key_pair * 2 + 0]);
auto &analog1 = analogs.at(analog_mapping[key_pair * 2 + 1]);
if (analog0.isSet()) {
state0 = (uint8_t) (Analogs::getState(RI_MGR, analog0) * 15.999f);
state0 = std::min((uint8_t)(Analogs::getState(RI_MGR, analog0) * 15.999f), (uint8_t)14);
}
if (analog1.isSet()) {
state1 = (uint8_t) (Analogs::getState(RI_MGR, analog1) * 15.999f);
state1 = std::min((uint8_t)(Analogs::getState(RI_MGR, analog1) * 15.999f), (uint8_t)14);
}
// check buttons
auto velocity0 = Buttons::getVelocity(RI_MGR, buttons.at(button_mapping[key_pair * 2 + 0]));
auto velocity1 = Buttons::getVelocity(RI_MGR, buttons.at(button_mapping[key_pair * 2 + 1]));
if (velocity0 > 0.f) {
state0 = (uint8_t) (velocity0 * 15.999f);
// check digital buttons
const auto button0 = panb_get_button_velocity(
buttons.at(button_mapping[key_pair * 2 + 0]),
buttons.at(soft_button_mapping[key_pair * 2 + 0]),
buttons.at(medium_button_mapping[key_pair * 2 + 0]),
buttons.at(hard_button_mapping[key_pair * 2 + 0])
);
if (button0 > 0) {
state0 = button0;
}
if (velocity1 > 0.f) {
state1 = (uint8_t) (velocity1 * 15.999f);
const auto button1 = panb_get_button_velocity(
buttons.at(button_mapping[key_pair * 2 + 1]),
buttons.at(soft_button_mapping[key_pair * 2 + 1]),
buttons.at(medium_button_mapping[key_pair * 2 + 1]),
buttons.at(hard_button_mapping[key_pair * 2 + 1])
);
if (button1 > 0) {
state1 = button1;
}
// build value