#include "maple_cfg.h" #include "maple_helper.h" #include "maple_if.h" #include "hw/naomi/naomi_cart.h" #include "cfg/option.h" #include "stdclass.h" #include "serialize.h" MapleInputState mapleInputState[4]; extern bool maple_ddt_pending_reset; extern std::vector>> mapleDmaOut; void (*MapleConfigMap::UpdateVibration)(u32 port, float power, float inclination, u32 duration_ms); static u8 GetBtFromSgn(s8 val) { return val+128; } u32 awave_button_mapping[32] = { AWAVE_BTN2_KEY, // DC_BTN_C AWAVE_BTN1_KEY, // DC_BTN_B AWAVE_BTN0_KEY, // DC_BTN_A AWAVE_START_KEY, // DC_BTN_START AWAVE_UP_KEY, // DC_DPAD_UP AWAVE_DOWN_KEY, // DC_DPAD_DOWN AWAVE_LEFT_KEY, // DC_DPAD_LEFT AWAVE_RIGHT_KEY, // DC_DPAD_RIGHT AWAVE_BTN4_KEY, // DC_BTN_Z (duplicated) AWAVE_BTN4_KEY, // DC_BTN_Y AWAVE_BTN3_KEY, // DC_BTN_X AWAVE_COIN_KEY, // DC_BTN_D AWAVE_SERVICE_KEY, // DC_DPAD2_UP AWAVE_TEST_KEY, // DC_DPAD2_DOWN 0, // DC_DPAD2_LEFT 0, // DC_DPAD2_RIGHT }; u32 awavelg_button_mapping[32] = { AWAVE_BTN1_KEY, // DC_BTN_C AWAVE_BTN0_KEY, // DC_BTN_B AWAVE_TRIGGER_KEY, // DC_BTN_A AWAVE_START_KEY, // DC_BTN_START AWAVE_UP_KEY, // DC_DPAD_UP AWAVE_DOWN_KEY, // DC_DPAD_DOWN AWAVE_LEFT_KEY, // DC_DPAD_LEFT AWAVE_RIGHT_KEY, // DC_DPAD_RIGHT AWAVE_BTN4_KEY, // DC_BTN_Z AWAVE_BTN3_KEY, // DC_BTN_Y AWAVE_BTN2_KEY, // DC_BTN_X AWAVE_COIN_KEY, // DC_BTN_D AWAVE_SERVICE_KEY, // DC_DPAD2_UP AWAVE_TEST_KEY, // DC_DPAD2_DOWN 0, // DC_DPAD2_LEFT 0, // DC_DPAD2_RIGHT AWAVE_BTN0_KEY // DC_BTN_RELOAD (not needed for AW, mapped to BTN0 = pump) }; inline u32 MapleConfigMap::playerNum() { return dev->player_num; } void MapleConfigMap::SetVibration(float power, float inclination, u32 duration_ms) { UpdateVibration(playerNum(), power, inclination, duration_ms); } void MapleConfigMap::GetInput(PlainJoystickState* pjs) { const MapleInputState& inputState = mapleInputState[playerNum()]; if (settings.platform.system == DC_PLATFORM_DREAMCAST) { pjs->kcode = inputState.kcode; pjs->joy[PJAI_X1] = GetBtFromSgn(inputState.fullAxes[PJAI_X1]); pjs->joy[PJAI_Y1] = GetBtFromSgn(inputState.fullAxes[PJAI_Y1]); pjs->trigger[PJTI_R] = inputState.halfAxes[PJTI_R]; pjs->trigger[PJTI_L] = inputState.halfAxes[PJTI_L]; } else if (settings.platform.system == DC_PLATFORM_ATOMISWAVE) { #ifdef LIBRETRO pjs->kcode = inputState.kcode; #else const u32* mapping = settings.input.JammaSetup == JVS::LightGun ? awavelg_button_mapping : awave_button_mapping; pjs->kcode = ~0; for (u32 i = 0; i < ARRAY_SIZE(awave_button_mapping); i++) { if ((inputState.kcode & (1 << i)) == 0) pjs->kcode &= ~mapping[i]; } #endif if (NaomiGameInputs != NULL) { for (u32 axis = 0; axis < PJAI_Count; axis++) { if (NaomiGameInputs->axes[axis].name != NULL) { if (NaomiGameInputs->axes[axis].type == Full) { switch (NaomiGameInputs->axes[axis].axis) { case 0: pjs->joy[axis] = GetBtFromSgn(inputState.fullAxes[PJAI_X1]); break; case 1: pjs->joy[axis] = GetBtFromSgn(inputState.fullAxes[PJAI_Y1]); break; case 2: pjs->joy[axis] = GetBtFromSgn(inputState.fullAxes[PJAI_X2]); break; case 3: pjs->joy[axis] = GetBtFromSgn(inputState.fullAxes[PJAI_Y2]); break; default: pjs->joy[axis] = 0x80; break; } } else { switch (NaomiGameInputs->axes[axis].axis) { case 4: pjs->joy[axis] = inputState.halfAxes[PJTI_R]; break; case 5: pjs->joy[axis] = inputState.halfAxes[PJTI_L]; break; default: pjs->joy[axis] = 0; break; } } if (NaomiGameInputs->axes[axis].inverted) pjs->joy[axis] = pjs->joy[axis] == 0 ? 0xff : 0x100 - pjs->joy[axis]; } else { pjs->joy[axis] = 0x80; } } } else { pjs->joy[PJAI_X1] = GetBtFromSgn(inputState.fullAxes[PJAI_X1]); pjs->joy[PJAI_Y1] = GetBtFromSgn(inputState.fullAxes[PJAI_Y1]); pjs->joy[PJAI_X2] = inputState.halfAxes[PJTI_R]; pjs->joy[PJAI_Y2] = inputState.halfAxes[PJTI_L]; } } } void MapleConfigMap::SetImage(u8 *img) { push_vmu_screen(dev->bus_id, dev->bus_port, img); } void MapleConfigMap::GetAbsCoordinates(int& x, int& y) { const MapleInputState& inputState = mapleInputState[playerNum()]; x = inputState.absPos.x; y = inputState.absPos.y; } void MapleConfigMap::GetMouseInput(u8& buttons, int& x, int& y, int& wheel) { const MapleInputState& inputState = mapleInputState[playerNum()]; buttons = inputState.mouseButtons; x = inputState.relPos.x; y = inputState.relPos.y * (invertMouseY ? -1 : 1); wheel = inputState.relPos.wheel; } void MapleConfigMap::GetKeyboardInput(u8& shift, u8 keys[6]) { const MapleInputState& inputState = mapleInputState[playerNum()]; shift = inputState.keyboard.shift; memcpy(keys, inputState.keyboard.key, sizeof(inputState.keyboard.key)); } bool maple_atomiswave_coin_chute(int slot) { #ifdef LIBRETRO return mapleInputState[slot].kcode & AWAVE_COIN_KEY; #else for (int i = 0; i < 16; i++) { if ((mapleInputState[slot].kcode & (1 << i)) == 0 && awave_button_mapping[i] == AWAVE_COIN_KEY) return true; } return false; #endif } static void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num = -1) { delete MapleDevices[bus][port]; maple_device* dev = maple_Create(type); dev->Setup(maple_GetAddress(bus, port), player_num); dev->config = new MapleConfigMap(dev); dev->OnSetup(); MapleDevices[bus][port] = dev; } static void createNaomiDevices() { mcfg_DestroyDevices(); mcfg_Create(MDT_NaomiJamma, 0, 5); if (settings.input.JammaSetup == JVS::Keyboard) { mcfg_Create(MDT_Keyboard, 1, 5, 0); mcfg_Create(MDT_Keyboard, 2, 5, 1); } else { // Connect VMU B1 mcfg_Create(MDT_SegaController, 1, 5); mcfg_Create(MDT_SegaVMU, 1, 0); // Connect VMU C1 mcfg_Create(MDT_SegaController, 2, 5); mcfg_Create(MDT_SegaVMU, 2, 0); } } static void createAtomiswaveDevices() { mcfg_DestroyDevices(); // Looks like two controllers needs to be on bus 0 and 1 for digital inputs // Then other devices on port 2 and 3 for analog axes, light guns, ... mcfg_Create(MDT_SegaController, 0, 5); mcfg_Create(MDT_SegaController, 1, 5); if (NaomiGameInputs != NULL && NaomiGameInputs->axes[0].name != NULL) { // Game needs analog axes mcfg_Create(MDT_SegaController, 2, 5, 0); mcfg_Create(MDT_SegaController, 3, 5, 1); // Faster Than Speed needs 1 std controller on port 0 (digital inputs) and one on port 2 (analog axes) // Maximum Speed same } else if (settings.input.JammaSetup == JVS::FourPlayers) { // 4 players mcfg_Create(MDT_SegaController, 2, 5); mcfg_Create(MDT_SegaController, 3, 5); } else if (settings.input.JammaSetup == JVS::LightGun) { // Clay Challenge needs 2 std controllers on port 0 & 1 (digital in) and light guns on port 2 & 3 // Sports Shooting same mcfg_Create(MDT_LightGun, 2, 5, 0); mcfg_Create(MDT_LightGun, 3, 5, 1); } else if (settings.input.JammaSetup == JVS::SegaMarineFishing || settings.input.JammaSetup == JVS::RotaryEncoders) { // Sega Bass Fishing Challenge needs a mouse (track-ball) on port 2 // Waiwai drive needs two track-balls mcfg_Create(MDT_Mouse, 2, 5, 0); mcfg_Create(MDT_Mouse, 3, 5, 1); if (settings.content.gameId == "DRIVE") { MapleDevices[2][5]->config->invertMouseY = true; MapleDevices[3][5]->config->invertMouseY = true; } } } static void createDreamcastDevices() { for (int bus = 0; bus < MAPLE_PORTS; ++bus) { switch (config::MapleMainDevices[bus]) { case MDT_SegaController: mcfg_Create(MDT_SegaController, bus, 5); if (config::MapleExpansionDevices[bus][0] != MDT_None) mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); if (config::MapleExpansionDevices[bus][1] != MDT_None) mcfg_Create(config::MapleExpansionDevices[bus][1], bus, 1); break; case MDT_Keyboard: mcfg_Create(MDT_Keyboard, bus, 5); break; case MDT_Mouse: mcfg_Create(MDT_Mouse, bus, 5); break; case MDT_LightGun: mcfg_Create(MDT_LightGun, bus, 5); if (config::MapleExpansionDevices[bus][0] != MDT_None) mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); break; case MDT_TwinStick: mcfg_Create(MDT_TwinStick, bus, 5); if (config::MapleExpansionDevices[bus][0] != MDT_None) mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); break; case MDT_AsciiStick: mcfg_Create(MDT_AsciiStick, bus, 5); if (config::MapleExpansionDevices[bus][0] != MDT_None) mcfg_Create(config::MapleExpansionDevices[bus][0], bus, 0); break; case MDT_None: break; default: WARN_LOG(MAPLE, "Invalid device type %d for port %d", (MapleDeviceType)config::MapleMainDevices[bus], bus); break; } } } static void vmuDigest() { if (!config::GGPOEnable) return; MD5Sum md5; for (int i = 0; i < MAPLE_PORTS; i++) for (int j = 0; j < 6; j++) { const maple_device* device = MapleDevices[i][j]; if (device != nullptr) { size_t size; const void *data = device->getData(size); if (data != nullptr) md5.add(data, size); } } md5.getDigest(settings.network.md5.vmu); } void mcfg_CreateDevices() { switch (settings.platform.system) { case DC_PLATFORM_DREAMCAST: createDreamcastDevices(); break; case DC_PLATFORM_NAOMI: createNaomiDevices(); break; case DC_PLATFORM_ATOMISWAVE: createAtomiswaveDevices(); break; default: die("Unknown system"); break; } vmuDigest(); } void mcfg_DestroyDevices() { for (int i = 0; i < MAPLE_PORTS; i++) for (int j=0;j<=5;j++) { if (MapleDevices[i][j] != NULL) { delete MapleDevices[i][j]; MapleDevices[i][j] = NULL; } } } void mcfg_SerializeDevices(Serializer& ser) { ser << maple_ddt_pending_reset; ser << (u32)mapleDmaOut.size(); for (const auto& pair : mapleDmaOut) { ser << pair.first; // u32 address ser << (u32)pair.second.size(); ser.serialize(pair.second.data(), pair.second.size()); } for (int i = 0; i < MAPLE_PORTS; i++) for (int j = 0; j < 6; j++) { u8 deviceType = MDT_None; maple_device* device = MapleDevices[i][j]; if (device != nullptr) deviceType = device->get_device_type(); ser << deviceType; if (device != nullptr) device->serialize(ser); } } void mcfg_DeserializeDevices(Deserializer& deser) { mcfg_DestroyDevices(); u8 eeprom[sizeof(maple_naomi_jamma::eeprom)]; if (deser.version() < Deserializer::V23) { deser >> eeprom; deser.skip(128); // Unused eeprom space deser.skip(); // EEPROM_loaded } deser >> maple_ddt_pending_reset; mapleDmaOut.clear(); if (deser.version() >= Deserializer::V23) { u32 size; deser >> size; for (u32 i = 0; i < size; i++) { u32 address; deser >> address; u32 dataSize; deser >> dataSize; mapleDmaOut.emplace_back(address, std::vector(dataSize)); deser.deserialize(mapleDmaOut.back().second.data(), dataSize); } } for (int i = 0; i < MAPLE_PORTS; i++) for (int j = 0; j < 6; j++) { u8 deviceType; deser >> deviceType; if (deviceType != MDT_None) { mcfg_Create((MapleDeviceType)deviceType, i, j); MapleDevices[i][j]->deserialize(deser); } } if (deser.version() < Deserializer::V23 && EEPROM != nullptr) memcpy(EEPROM, eeprom, sizeof(eeprom)); }