From 7917e39a11140ac5eea1ad279889d816e21d2f8d Mon Sep 17 00:00:00 2001 From: Bobby Smith <33353403+bslenul@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:56:33 +0100 Subject: [PATCH] Add a button to quickly swap between Memory<->Rumble Paks --- .../emulate_game_controller_via_libretro.c | 2 + libretro/libretro.c | 132 +++++++++++++++++- libretro/libretro_core_options.h | 20 +++ 3 files changed, 151 insertions(+), 3 deletions(-) diff --git a/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c b/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c index 45cd2c124..f57ceb6ba 100644 --- a/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c +++ b/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c @@ -86,6 +86,7 @@ static void inputGetKeys_default_descriptor(void) { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "C-Up" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "Z Trigger" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R Shoulder" },\ + { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Memory/Rumble Pak Swap" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "L Shoulder" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },\ @@ -117,6 +118,7 @@ static void inputGetKeys_default_descriptor(void) { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "Z Trigger" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R Shoulder" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L Shoulder" },\ + { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Memory/Rumble Pak Swap" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },\ { PAD, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },\ diff --git a/libretro/libretro.c b/libretro/libretro.c index f235be81b..784338e2f 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -124,6 +124,10 @@ int d_cbutton; int u_cbutton; bool alternate_mapping; +static bool swap_pak_enabled[4] = {false}; +static int swap_pak_hold[4] = {0}; +static int swap_pak_delay = 0; + static uint8_t* game_data = NULL; static uint32_t game_size = 0; @@ -764,6 +768,25 @@ void update_controllers() else if (!strcmp(pk1var.value, "transfer")) p1_pak = PLUGIN_TRANSFER_PAK; + // This is for the 'Memory/Rumble Pak Swap' button that lets you swap + // between Memory and Rumble Pak on-the-fly. + // Initialize to Memory Pak, then it's handled by pak_swapping(). + // As long as swap_pak_enabled is true we just keep the current value + // from controller[port].control->Plugin, or else the Pak would be + // reinitialized to Memory Pak every time core options are refreshed. + if (!strcmp(pk1var.value, "memory/rumble (swappable)")) + { + if (swap_pak_enabled[0]) + p1_pak = controller[0].control->Plugin; + else + { + swap_pak_enabled[0] = true; + p1_pak = PLUGIN_MEMPAK; + } + } + else + swap_pak_enabled[0] = false; + // If controller struct is not initialised yet, set pad_pak_types instead // which will be looked at when initialising the controllers. if (controller[0].control) @@ -783,6 +806,19 @@ void update_controllers() else if (!strcmp(pk2var.value, "transfer")) p2_pak = PLUGIN_TRANSFER_PAK; + if (!strcmp(pk2var.value, "memory/rumble (swappable)")) + { + if (swap_pak_enabled[1]) + p2_pak = controller[1].control->Plugin; + else + { + swap_pak_enabled[1] = true; + p2_pak = PLUGIN_MEMPAK; + } + } + else + swap_pak_enabled[1] = false; + if (controller[1].control) controller[1].control->Plugin = p2_pak; else @@ -800,6 +836,19 @@ void update_controllers() else if (!strcmp(pk3var.value, "transfer")) p3_pak = PLUGIN_TRANSFER_PAK; + if (!strcmp(pk3var.value, "memory/rumble (swappable)")) + { + if (swap_pak_enabled[2]) + p3_pak = controller[2].control->Plugin; + else + { + swap_pak_enabled[2] = true; + p3_pak = PLUGIN_MEMPAK; + } + } + else + swap_pak_enabled[2] = false; + if (controller[2].control) controller[2].control->Plugin = p3_pak; else @@ -817,6 +866,19 @@ void update_controllers() else if (!strcmp(pk4var.value, "transfer")) p4_pak = PLUGIN_TRANSFER_PAK; + if (!strcmp(pk4var.value, "memory/rumble (swappable)")) + { + if (swap_pak_enabled[3]) + p4_pak = controller[3].control->Plugin; + else + { + swap_pak_enabled[3] = true; + p4_pak = PLUGIN_MEMPAK; + } + } + else + swap_pak_enabled[3] = false; + if (controller[3].control) controller[3].control->Plugin = p4_pak; else @@ -824,6 +886,56 @@ void update_controllers() } } +static void pak_swapping(void) +{ + unsigned port; + + for (port = 0; port < 4; port++) + { + if (swap_pak_enabled[port] && controller[port].control->Present) + { + bool pressed; + + if (alternate_mapping) + pressed = input_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3); + else + pressed = input_cb(port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT); + + if (pressed) + { + if (swap_pak_hold[port] >= swap_pak_delay) + { + struct retro_message msg; + char swap_msg[64]; + const char *pak_name; + + swap_pak_hold[port] = -1; + + if (controller[port].control->Plugin == PLUGIN_MEMPAK) + { + controller[port].control->Plugin = PLUGIN_RAW; + pak_name = "Rumble"; + } + else + { + controller[port].control->Plugin = PLUGIN_MEMPAK; + pak_name = "Memory"; + } + + snprintf(swap_msg, sizeof(swap_msg), "Player %d Controller Pak: %s Pak", port + 1, pak_name); + msg.msg = swap_msg; + msg.frames = 120; + environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg); + } + else if (swap_pak_hold[port] != -1) + swap_pak_hold[port]++; + } + else + swap_pak_hold[port] = 0; + } + } +} + static void update_variables(bool startup) { struct retro_variable var; @@ -1731,6 +1843,20 @@ static void update_variables(bool startup) } #endif // HAVE_THR_AL + var.key = CORE_NAME "-pak-swap-delay"; + var.value = NULL; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "no delay")) + swap_pak_delay = 0; + else if (!strcmp(var.value, "1s hold")) + swap_pak_delay = 60; + else if (!strcmp(var.value, "2s hold")) + swap_pak_delay = 120; + else if (!strcmp(var.value, "3s hold")) + swap_pak_delay = 180; + } + update_controllers(); // Hide irrelevant options @@ -1985,10 +2111,8 @@ void retro_run (void) libretro_swap_buffer = false; static bool updated = false; - if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) { + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated) update_variables(false); - update_controllers(); - } if(current_rdp_type == RDP_PLUGIN_GLIDEN64) { @@ -2038,6 +2162,8 @@ void retro_run (void) // screen_pitch will be 0 for GLN video_cb(NULL, retro_screen_width, retro_screen_height, screen_pitch); } + + pak_swapping(); } void retro_reset (void) diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index b1805dbef..25ede1c45 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -1656,6 +1656,7 @@ struct retro_core_option_v2_definition option_defs_us[] = { {"memory", NULL}, {"rumble", NULL}, {"transfer", NULL}, + {"memory/rumble (swappable)", NULL}, { NULL, NULL }, }, "memory" @@ -1672,6 +1673,7 @@ struct retro_core_option_v2_definition option_defs_us[] = { {"memory", NULL}, {"rumble", NULL}, {"transfer", NULL}, + {"memory/rumble (swappable)", NULL}, { NULL, NULL }, }, "none" @@ -1688,6 +1690,7 @@ struct retro_core_option_v2_definition option_defs_us[] = { {"memory", NULL}, {"rumble", NULL}, {"transfer", NULL}, + {"memory/rumble (swappable)", NULL}, { NULL, NULL }, }, "none" @@ -1704,10 +1707,27 @@ struct retro_core_option_v2_definition option_defs_us[] = { {"memory", NULL}, {"rumble", NULL}, {"transfer", NULL}, + {"memory/rumble (swappable)", NULL}, { NULL, NULL }, }, "none" }, + { + CORE_NAME "-pak-swap-delay", + "Memory/Rumble Pak Swap Activation Delay", + NULL, + "Select if the 'Memory/Rumble Pak Swap' button should perform the swap on press or on hold. NOTE: only works if the player's Pak is set to 'memory/rumble (swappable)'", + NULL, + "input", + { + {"no delay", "Press to swap"}, + {"1s hold", "Hold 1 second to swap"}, + {"2s hold", "Hold 2 seconds to swap"}, + {"3s hold", "Hold 3 seconds to swap"}, + { NULL, NULL }, + }, + "no delay" + }, { NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL }, };