diff --git a/docs/controls.md b/docs/controls.md index bbdf1d9b..d48c2467 100644 --- a/docs/controls.md +++ b/docs/controls.md @@ -151,7 +151,7 @@ The log says which it is when a gamepad is taken: `input: HD rumble available fo ## Sprint button -On 1.1.1, `NX2NAVI_SPRINT_BUTTON` (`sprint_button`, the *Sprint button* row on the Controls tab, live) gives a button that makes Link sprint without rolling first: `b` (the bottom face button), `l`, `r`, `l3` or `r3`, or `off` (the default). `NX2NAVI_SPRINT_MODE` (`sprint_mode`, the *Sprint mode* row) is `toggle` (the default: a press starts the sprint, the next press ends it) or `hold` (Link sprints while the button is held). Link sprints while his input flags hold the dash input; the set `sprint` of `recomp/patches-v111.txt` calls `runtime/sprint.c` after Link's movement update and the stance update that follows load those flags, and the host functions add the dash input while the sprint is on, so the game's own sprint runs with its speed, animation and camera. A toggled sprint goes on through jumps, slides and landings and ends when Link's state is anything else (an attack, a roll, an item, swimming, climbing, a cutscene), when ZL is held, or after four frames standing still (ninety after a press made while standing, before Link has moved). During play (Link's update ran within the last eight controller polls) the button is kept from the game, so it does not also fire its own action; the bottom button is kept only while Link moves, so it attacks as usual otherwise. In the settings menu, a menu of the game or a cutscene every button keeps its role. The set runs only while a button is chosen, so with the sprint button off its sites cost nothing. `NX2NAVI_SPRINT_PATCH=0` (or a mod whose code patches the same sites) keeps the patch set off and hides the rows. +On 1.1.1, `NX2NAVI_SPRINT_BUTTON` (`sprint_button`, the *Sprint button* row on the Controls tab, live) gives a button that makes Link sprint without rolling first: `l3` (the left stick's click, which has no other use), `b` (the game's B button, the bottom face button of the Nintendo layout), or `off` (the default). `NX2NAVI_SPRINT_MODE` (`sprint_mode`, the *Sprint mode* row) is `toggle` (the default: a press starts the sprint, the next press ends it) or `hold` (Link sprints while the button is held). Link sprints while his input flags hold the dash input; the set `sprint` of `recomp/patches-v111.txt` calls `runtime/sprint.c` after Link's movement update and the stance update that follows load those flags, and the host functions add the dash input while the sprint is on, so the game's own sprint runs with its speed, animation and camera. A toggled sprint goes on through jumps, slides and landings and ends when Link's state is anything else (an attack, a roll, an item, swimming, climbing, a cutscene), when ZL is held, or after four frames standing still (ninety after a press made while standing, before Link has moved). During play (Link's update ran within the last eight controller polls) the button is kept from the game, so it does not also fire its own action; B is kept only while Link moves, so it attacks as usual otherwise. In the settings menu, a menu of the game or a cutscene every button keeps its role. The set runs only while a button is chosen, so with the sprint button off its sites cost nothing. `NX2NAVI_SPRINT_PATCH=0` (or a mod whose code patches the same sites) keeps the patch set off and hides the rows. ## Nintendo Switch 2 controllers diff --git a/nx2navi.ini.example b/nx2navi.ini.example index ec849051..51580c15 100644 --- a/nx2navi.ini.example +++ b/nx2navi.ini.example @@ -820,11 +820,11 @@ # Gamepad motion controls (0 = off) and vibration (0 = off). # motion = 1 # rumble = 1 -# Sprint button (game 1.1.1): Link sprints without rolling first. off (the default), b (the bottom face button: it -# sprints only while Link moves and attacks as usual otherwise), l, r, l3 or r3. During play the button only sprints: -# L or R no longer uses its item, R3 no longer resets the camera. sprint_mode: toggle (press to sprint and again to -# stop; the sprint also ends when Link stops, attacks, rolls, targets, uses an item, swims or climbs) or hold. The -# Controls tab's Sprint rows set both; changes take effect at once. +# Sprint button (game 1.1.1): Link sprints without rolling first. off (the default), l3 (the left stick's click, which +# has no other use) or b (the game's B button, the bottom one of the Nintendo layout: it sprints only while Link moves +# and attacks as usual otherwise). sprint_mode: toggle (press to sprint and again to stop; the sprint also ends when +# Link stops, attacks, rolls, targets, uses an item, swims or climbs) or hold. The Controls tab's Sprint rows set +# both; changes take effect at once. # sprint_button = off # sprint_mode = toggle # Rumble strength in percent (0 to 300; 0 = off) and the exponent on the amplitude (0.2 to 1.5; lower = weak pulses diff --git a/runtime/cfg.c b/runtime/cfg.c index c4a3db86..c56c396a 100644 --- a/runtime/cfg.c +++ b/runtime/cfg.c @@ -243,8 +243,9 @@ static const CfgMeta metas[] = { {"MICROPHONE", "1", "0|1", RESTART}, // ov_audio_input.c mic_on: 0 refuses the game's input streams {"AUDIO_RAMP", "1", "0|1", RESTART}, // audio_mixer.c accumulate_ramp: a changed volume is reached across the frame {"AUDIO_CATCHUP", "1", "0|1", RESTART}, // audren.c render_thread: frames owed after a stall are rendered and dropped - // sprint.c: the sprint button (b the bottom face button) and toggle or hold; the Controls tab's Sprint rows (1.1.1) - {"SPRINT_BUTTON", "off", "off|b|l|r|l3|r3", LIVE}, {"SPRINT_MODE", "toggle", "toggle|hold", LIVE}, + // sprint.c: the sprint button (b the game's B, l3 the left stick's click) and toggle or hold; the Controls tab's + // Sprint rows (1.1.1) + {"SPRINT_BUTTON", "off", "off|b|l3", LIVE}, {"SPRINT_MODE", "toggle", "toggle|hold", LIVE}, {"MOTION", "1", "0|1", LIVE}, {"RUMBLE_STRENGTH", "130", "0..300", LIVE}, {"RUMBLE_CURVE", "0.6", "0.2..1.5", LIVE}, {"RUMBLE_TRIGGERS", "0", "0|1", LIVE}, {"PAD_LAYOUT", "nintendo", "auto|nintendo|xbox|playstation", LIVE}, {"DS3", "0", "0|1", LIVE}, // input_ds3_win.c ds3_read: read a DualShock 3 directly; off: no HID scan diff --git a/runtime/sprint.c b/runtime/sprint.c index a968ffcf..b76b26fb 100644 --- a/runtime/sprint.c +++ b/runtime/sprint.c @@ -3,11 +3,11 @@ // below right after the game loads those flags, and they OR the bit in while the sprint button's sprint is on, so the // game's own sprint runs: its speed, animation, camera and every rule that ends it. // -// Settings (live): sprint_button picks the button (off, b the bottom face button, l, r, l3, r3); sprint_mode is toggle -// (a press starts the sprint, the next press or Link's state ends it) or hold (sprint while the button is held). During -// gameplay the button is kept from the game (sprint_pad, called by ov_input.c npad_states), so it does not also fire -// its own action: L or R its item, R3 the camera reset. The bottom button is kept only while Link moves (Walk, Jump, -// Land, Fall, Clamber), so it attacks as usual otherwise. +// Settings (live): sprint_button picks the button (off, b the game's B button, the bottom face button of the Nintendo +// layout, or l3 the left stick's click, which has no other use); sprint_mode is toggle (a press starts the sprint, the +// next press or Link's state ends it) or hold (sprint while the button is held). During gameplay the button is kept +// from the game (sprint_pad, called by ov_input.c npad_states), so it does not also fire its own action. B is kept only +// while Link moves (Walk, Jump, Land, Fall, Clamber), so it attacks as usual otherwise. // // Link's state: the id at [[[[Link +0x18] +0x270] +0x188] +0x1c0] +0x28 (+0x4c when that reads 0x11a, a state that // wraps another), the same field main+0x4aed50 compares with 1 (Walk) before the game starts a sprint. @@ -24,9 +24,9 @@ #include "patches.h" #endif -enum { BTN_OFF, BTN_B, BTN_L, BTN_R, BTN_L3, BTN_R3 }; -static const char *const button_names[] = {"off", "b", "l", "r", "l3", "r3"}; -static const uint64_t button_bits[] = {0, 1u << 1, 1u << 6, 1u << 7, 1u << 4, 1u << 5}; // HidNpadButton bits +enum { BTN_OFF, BTN_B, BTN_L3 }; +static const char *const button_names[] = {"off", "b", "l3"}; +static const uint64_t button_bits[] = {0, 1u << 1, 1u << 4}; // HidNpadButton bits #define BUTTON_ZL (1u << 8) #define DASH_INPUT 0x10u diff --git a/runtime/ui/menu.cpp b/runtime/ui/menu.cpp index fb1e3721..00c5f6f9 100644 --- a/runtime/ui/menu.cpp +++ b/runtime/ui/menu.cpp @@ -1635,10 +1635,9 @@ static void tab_controls(float scale) { // The sprint button (sprint.c), where the game version has the patch set sprint; both rows are live. The names // follow the values in their cfg.c order. if (sprint_available()) { - static const UiTextId sprint_button[] = {UI_MENU_SPRINT_OFF, UI_MENU_SPRINT_B, UI_MENU_SPRINT_L, - UI_MENU_SPRINT_R, UI_MENU_SPRINT_L3, UI_MENU_SPRINT_R3}; + static const UiTextId sprint_button[] = {UI_MENU_SPRINT_OFF, UI_MENU_SPRINT_B, UI_MENU_SPRINT_L3}; static const UiTextId sprint_mode[] = {UI_MENU_SPRINT_TOGGLE, UI_MENU_SPRINT_HOLD}; - opt_choice("NX2NAVI_SPRINT_BUTTON", UI_MENU_SPRINT_BUTTON, sprint_button, 6, UI_MENU_SPRINT_BUTTON_DESC); + opt_choice("NX2NAVI_SPRINT_BUTTON", UI_MENU_SPRINT_BUTTON, sprint_button, 3, UI_MENU_SPRINT_BUTTON_DESC); opt_choice("NX2NAVI_SPRINT_MODE", UI_MENU_SPRINT_MODE, sprint_mode, 2, UI_MENU_SPRINT_MODE_DESC); } opt_slider("NX2NAVI_RUMBLE_STRENGTH", UI_MENU_RUMBLE_STRENGTH, 0, 300, UI_MENU_RUMBLE_STRENGTH_DESC, 10, "%.0f %%"); diff --git a/runtime/ui_text.c b/runtime/ui_text.c index 7e2cfd35..caca4a25 100644 --- a/runtime/ui_text.c +++ b/runtime/ui_text.c @@ -327,11 +327,11 @@ static const char *const text_en[UI_TEXT_COUNT] = { [UI_MENU_MOTION] = "Motion controls", [UI_MENU_MOTION_DESC] = "Aim with the controller's gyro.", [UI_MENU_SPRINT_BUTTON] = "Sprint button", - [UI_MENU_SPRINT_BUTTON_DESC] = "A button that makes Link sprint without rolling first. During play it only " - "sprints: L or R no longer uses its item, R3 no longer resets the camera. The " - "bottom button sprints only while Link moves and attacks as usual otherwise.", - [UI_MENU_SPRINT_OFF] = "Off", [UI_MENU_SPRINT_B] = "Bottom button", [UI_MENU_SPRINT_L] = "L", - [UI_MENU_SPRINT_R] = "R", [UI_MENU_SPRINT_L3] = "L3 (left stick)", [UI_MENU_SPRINT_R3] = "R3 (right stick)", + [UI_MENU_SPRINT_BUTTON_DESC] = "A button that makes Link sprint without rolling first. L3, the left stick's " + "click, has no other use. The game's B button sprints only while Link moves and " + "attacks as usual otherwise.", + [UI_MENU_SPRINT_OFF] = "Off", [UI_MENU_SPRINT_B] = "Bottom button (Nintendo B)", + [UI_MENU_SPRINT_L3] = "L3 (left stick)", [UI_MENU_SPRINT_MODE] = "Sprint mode", [UI_MENU_SPRINT_MODE_DESC] = "Toggle: press once to sprint and again to stop. The sprint goes on through jumps " "and ends when Link stops, attacks, rolls, targets, uses an item, swims or climbs. " diff --git a/runtime/ui_text.h b/runtime/ui_text.h index 6ce81061..049492d9 100644 --- a/runtime/ui_text.h +++ b/runtime/ui_text.h @@ -105,9 +105,8 @@ typedef enum { // Controls UI_MENU_MOTION, UI_MENU_MOTION_DESC, - UI_MENU_SPRINT_BUTTON, UI_MENU_SPRINT_BUTTON_DESC, UI_MENU_SPRINT_OFF, UI_MENU_SPRINT_B, UI_MENU_SPRINT_L, - UI_MENU_SPRINT_R, UI_MENU_SPRINT_L3, UI_MENU_SPRINT_R3, UI_MENU_SPRINT_MODE, UI_MENU_SPRINT_MODE_DESC, - UI_MENU_SPRINT_TOGGLE, UI_MENU_SPRINT_HOLD, + UI_MENU_SPRINT_BUTTON, UI_MENU_SPRINT_BUTTON_DESC, UI_MENU_SPRINT_OFF, UI_MENU_SPRINT_B, UI_MENU_SPRINT_L3, + UI_MENU_SPRINT_MODE, UI_MENU_SPRINT_MODE_DESC, UI_MENU_SPRINT_TOGGLE, UI_MENU_SPRINT_HOLD, UI_MENU_RUMBLE_STRENGTH, UI_MENU_RUMBLE_STRENGTH_DESC, UI_MENU_RUMBLE_CURVE, UI_MENU_RUMBLE_CURVE_DESC, UI_MENU_RUMBLE_TRIGGERS, UI_MENU_RUMBLE_TRIGGERS_DESC, diff --git a/tests/sprint_check.c b/tests/sprint_check.c index 9896e2e7..e2ce2f59 100644 --- a/tests/sprint_check.c +++ b/tests/sprint_check.c @@ -183,12 +183,16 @@ int main(int argc, char **argv) { frame(0, ATTACK, link); assert(frame(BB, ATTACK, link) == BB && !dashing()); // not moving: an attack as usual - // hold on L: sprint while held; L never reaches the game during play, R does - reset("l", "hold"); - assert(frame(LL, WALK, link) == 0 && dashing()); - assert(frame(LL, WAIT_ID, link) == 0 && dashing()); + // hold on L3: sprint while held; L3 never reaches the game during play, other buttons do + reset("l3", "hold"); + assert(frame(L3, WALK, link) == 0 && dashing()); + assert(frame(L3, WAIT_ID, link) == 0 && dashing()); assert(frame(0, WALK, link) == 0 && !dashing()); - assert(frame(1u << 7, WALK, link) == (1u << 7) && !dashing()); + assert(frame(LL, WALK, link) == LL && !dashing()); + + // a button the setting no longer offers is off + reset("r3", "toggle"); + assert(frame(1u << 5, WALK, link) == (1u << 5) && !dashing() && !set_on); // hold on the bottom button: starts only while moving, keeps going while held reset("b", "hold");