diff --git a/desktop_version/lang/en/strings.xml b/desktop_version/lang/en/strings.xml
index c545f900..a4f701b6 100644
--- a/desktop_version/lang/en/strings.xml
+++ b/desktop_version/lang/en/strings.xml
@@ -46,9 +46,7 @@
-
-
@@ -135,19 +133,30 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/desktop_version/src/ButtonGlyphs.cpp b/desktop_version/src/ButtonGlyphs.cpp
index 4abbf4ed..229a0e32 100644
--- a/desktop_version/src/ButtonGlyphs.cpp
+++ b/desktop_version/src/ButtonGlyphs.cpp
@@ -272,7 +272,7 @@ const char* BUTTONGLYPHS_get_wasd_text(void)
return loc::gettext("Press left/right to move");
}
-static const char* sdlbutton_to_glyph(const SDL_GameControllerButton button)
+const char* BUTTONGLYPHS_sdlbutton_to_glyph(const SDL_GameControllerButton button)
{
if (button > SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)
{
@@ -292,7 +292,7 @@ static const char* glyph_for_vector(
return NULL;
}
- return sdlbutton_to_glyph(buttons[index]);
+ return BUTTONGLYPHS_sdlbutton_to_glyph(buttons[index]);
}
const char* BUTTONGLYPHS_get_button(const ActionSet actionset, const Action action, int binding)
diff --git a/desktop_version/src/ButtonGlyphs.h b/desktop_version/src/ButtonGlyphs.h
index bef8f805..78416117 100644
--- a/desktop_version/src/ButtonGlyphs.h
+++ b/desktop_version/src/ButtonGlyphs.h
@@ -20,6 +20,7 @@ void BUTTONGLYPHS_keyboard_set_active(bool active);
void BUTTONGLYPHS_update_layout(SDL_GameController *c);
const char* BUTTONGLYPHS_get_wasd_text(void);
+const char* BUTTONGLYPHS_sdlbutton_to_glyph(SDL_GameControllerButton button);
const char* BUTTONGLYPHS_get_button(ActionSet actionset, Action action, int binding);
char* BUTTONGLYPHS_get_all_gamepad_buttons(
diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp
index d5b734f7..196c4d54 100644
--- a/desktop_version/src/Game.cpp
+++ b/desktop_version/src/Game.cpp
@@ -254,6 +254,10 @@ void Game::init(void)
levelpage=0;
playcustomlevel=0;
+ gpmenu_lastbutton = SDL_CONTROLLER_BUTTON_INVALID;
+ gpmenu_confirming = false;
+ gpmenu_showremove = false;
+
silence_settings_error = false;
deathcounts = 0;
@@ -7009,7 +7013,7 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
option(loc::gettext("bind restart"));
option(loc::gettext("bind interact"), separate_interact);
option(loc::gettext("return"));
- menuyoff = 0;
+ menuyoff = 12;
maxspacing = 10;
break;
case Menu::language:
diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h
index 05817b05..b053d1b4 100644
--- a/desktop_version/src/Game.h
+++ b/desktop_version/src/Game.h
@@ -404,6 +404,10 @@ public:
int creditposx, creditposy, creditposdelay;
int oldcreditposx;
+ SDL_GameControllerButton gpmenu_lastbutton;
+ bool gpmenu_confirming;
+ bool gpmenu_showremove;
+
bool silence_settings_error;
diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp
index ef298851..4ee34af7 100644
--- a/desktop_version/src/Input.cpp
+++ b/desktop_version/src/Input.cpp
@@ -35,6 +35,37 @@ static void updatebuttonmappings(int bind)
) {
if (key.isDown(i))
{
+ if (!game.gpmenu_confirming || i != game.gpmenu_lastbutton)
+ {
+ game.gpmenu_confirming = true;
+ game.gpmenu_lastbutton = i;
+
+ // Is this button already in the list for this action?
+ std::vector* vec = NULL;
+ switch (bind)
+ {
+ case 1: vec = &game.controllerButton_flip; break;
+ case 2: vec = &game.controllerButton_map; break;
+ case 3: vec = &game.controllerButton_esc; break;
+ case 4: vec = &game.controllerButton_restart; break;
+ case 5: vec = &game.controllerButton_interact; break;
+ default: return;
+ }
+
+ game.gpmenu_showremove = false;
+ for (size_t j = 0; j < vec->size(); j += 1)
+ {
+ if (i == (*vec)[j])
+ {
+ game.gpmenu_showremove = true;
+ break;
+ }
+ }
+
+ return;
+ }
+ game.gpmenu_confirming = false;
+
bool dupe = false;
switch (bind)
{
@@ -46,13 +77,14 @@ static void updatebuttonmappings(int bind)
if (i == game.controllerButton_flip[j])
{
dupe = true;
+ game.controllerButton_flip.erase(game.controllerButton_flip.begin() + j);
}
}
if (!dupe)
{
game.controllerButton_flip.push_back(i);
- music.playef(Sound_VIRIDIAN);
}
+ music.playef(Sound_VIRIDIAN);
for (j = 0; j < game.controllerButton_map.size(); j += 1)
{
if (i == game.controllerButton_map[j])
@@ -91,13 +123,14 @@ static void updatebuttonmappings(int bind)
if (i == game.controllerButton_map[j])
{
dupe = true;
+ game.controllerButton_map.erase(game.controllerButton_map.begin() + j);
}
}
if (!dupe)
{
game.controllerButton_map.push_back(i);
- music.playef(Sound_VIRIDIAN);
}
+ music.playef(Sound_VIRIDIAN);
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
{
if (i == game.controllerButton_flip[j])
@@ -136,13 +169,14 @@ static void updatebuttonmappings(int bind)
if (i == game.controllerButton_esc[j])
{
dupe = true;
+ game.controllerButton_esc.erase(game.controllerButton_esc.begin() + j);
}
}
if (!dupe)
{
game.controllerButton_esc.push_back(i);
- music.playef(Sound_VIRIDIAN);
}
+ music.playef(Sound_VIRIDIAN);
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
{
if (i == game.controllerButton_flip[j])
@@ -181,13 +215,14 @@ static void updatebuttonmappings(int bind)
if (i == game.controllerButton_restart[j])
{
dupe = true;
+ game.controllerButton_restart.erase(game.controllerButton_restart.begin() + j);
}
}
if (!dupe)
{
game.controllerButton_restart.push_back(i);
- music.playef(Sound_VIRIDIAN);
}
+ music.playef(Sound_VIRIDIAN);
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
{
if (i == game.controllerButton_flip[j])
@@ -226,13 +261,14 @@ static void updatebuttonmappings(int bind)
if (i == game.controllerButton_interact[j])
{
dupe = true;
+ game.controllerButton_interact.erase(game.controllerButton_interact.begin() + j);
}
}
if (!dupe)
{
game.controllerButton_interact.push_back(i);
- music.playef(Sound_VIRIDIAN);
}
+ music.playef(Sound_VIRIDIAN);
for (j = 0; j < game.controllerButton_flip.size(); j += 1)
{
if (i == game.controllerButton_flip[j])
@@ -2526,6 +2562,11 @@ void titleinput(void)
{
game.currentmenuoption++;
}
+
+ if (game.currentmenuname == Menu::controller && (game.press_left || game.press_right))
+ {
+ game.gpmenu_confirming = false;
+ }
}
else
{
diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp
index 428172cb..771927bf 100644
--- a/desktop_version/src/Render.cpp
+++ b/desktop_version/src/Render.cpp
@@ -691,9 +691,6 @@ static void menurender(void)
}
case Menu::controller:
{
- font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("Game Pad"), tr, tg, tb);
- font::print_wrap(PR_CEN, -1, 55, loc::gettext("Change controller options."), tr, tg, tb);
-
int spacing = font::height(0);
spacing = SDL_max(spacing, 10);
@@ -701,12 +698,15 @@ static void menurender(void)
{
case 0:
{
- font::print(PR_RTL_XFLIP, 32, 75, loc::gettext("Low"), tr, tg, tb);
- font::print(PR_CEN, -1, 75, loc::gettext("Medium"), tr, tg, tb);
- font::print(PR_RIGHT | PR_RTL_XFLIP, 288, 75, loc::gettext("High"), tr, tg, tb);
+ font::print(PR_2X | PR_CEN, -1, 30, loc::gettext("Stick Sensitivity"), tr, tg, tb);
+ font::print_wrap(PR_CEN, -1, 55, loc::gettext("Change the sensitivity of the analog stick."), tr, tg, tb);
+
+ font::print(PR_RTL_XFLIP, 32, 95, loc::gettext("Low"), tr, tg, tb);
+ font::print(PR_CEN, -1, 95, loc::gettext("Medium"), tr, tg, tb);
+ font::print(PR_RIGHT | PR_RTL_XFLIP, 288, 95, loc::gettext("High"), tr, tg, tb);
char slider[SCREEN_WIDTH_CHARS + 1];
slider_get(slider, sizeof(slider), key.sensitivity, 5, 240);
- font::print(PR_CEN, -1, 75+spacing, slider, tr, tg, tb);
+ font::print(PR_CEN, -1, 95+spacing, slider, tr, tg, tb);
break;
}
case 1:
@@ -715,38 +715,117 @@ static void menurender(void)
case 4:
case 5:
{
- char buffer_a[SCREEN_WIDTH_CHARS + 1];
- char buffer_b[SCREEN_WIDTH_CHARS + 1];
+ const char* title = "";
+ switch (game.currentmenuoption)
+ {
+ case 1: title = loc::gettext("Bind Flip"); break;
+ case 2: title = loc::gettext("Bind Enter"); break;
+ case 3: title = loc::gettext("Bind Menu"); break;
+ case 4: title = loc::gettext("Bind Restart"); break;
+ case 5: title = loc::gettext("Bind Interact"); break;
+ }
+ font::print(PR_2X | PR_CEN, -1, 30, title, tr, tg, tb);
- SDL_snprintf(buffer_a, sizeof(buffer_a), "%s%s",
- loc::gettext("Flip is bound to: "),
- BUTTONGLYPHS_get_all_gamepad_buttons(buffer_b, sizeof(buffer_b), ActionSet_InGame, Action_InGame_ACTION)
- );
- font::print(PR_CEN, -1, 75, buffer_a, tr, tg, tb);
+ if (game.currentmenuoption == 5 && !game.separate_interact)
+ {
+ font::print_wrap(
+ PR_CEN, -1, 55,
+ loc::gettext("Interact is currently Enter!|See speedrunner options."),
+ tr, tg, tb
+ );
+ }
+ else if (!game.gpmenu_confirming)
+ {
+ font::print_wrap(
+ PR_CEN | PR_BRIGHTNESS(255 - help.glow*2), -1, 55,
+ loc::gettext("Press a button...|(or press ↑↓)"),
+ tr, tg, tb
+ );
+ }
+ else
+ {
+ char expl[SCREEN_WIDTH_CHARS*3 + 1];
+ const char* expl_template;
- SDL_snprintf(buffer_a, sizeof(buffer_a), "%s%s",
- loc::gettext("Enter is bound to: "),
- BUTTONGLYPHS_get_all_gamepad_buttons(buffer_b, sizeof(buffer_b), ActionSet_InGame, Action_InGame_Map)
- );
- font::print(PR_CEN, -1, 75+spacing, buffer_a, tr, tg, tb);
+ if (game.gpmenu_showremove)
+ {
+ expl_template = loc::gettext("Remove {button}?|Press again to confirm");
+ }
+ else
+ {
+ expl_template = loc::gettext("Add {button}?|Press again to confirm");
+ }
- SDL_snprintf(buffer_a, sizeof(buffer_a), "%s%s",
- loc::gettext("Menu is bound to: "),
- BUTTONGLYPHS_get_all_gamepad_buttons(buffer_b, sizeof(buffer_b), ActionSet_InGame, Action_InGame_Esc)
- );
- font::print(PR_CEN, -1, 75+spacing*2, buffer_a, tr, tg, tb);
+ vformat_buf(
+ expl, sizeof(expl),
+ expl_template,
+ "button:str",
+ BUTTONGLYPHS_sdlbutton_to_glyph(game.gpmenu_lastbutton)
+ );
- SDL_snprintf(buffer_a, sizeof(buffer_a), "%s%s",
- loc::gettext("Restart is bound to: "),
- BUTTONGLYPHS_get_all_gamepad_buttons(buffer_b, sizeof(buffer_b), ActionSet_InGame, Action_InGame_Restart)
- );
- font::print(PR_CEN, -1, 75+spacing*3, buffer_a, tr, tg, tb);
+ font::print_wrap(PR_CEN, -1, 55, expl, tr, tg, tb);
+ }
+
+ for (int bind = 1; bind <= 5; bind++)
+ {
+ char buffer_a[SCREEN_WIDTH_CHARS + 1];
+ char buffer_b[SCREEN_WIDTH_CHARS + 1];
+
+ const char* lbl;
+ ActionSet actionset;
+ int action;
+
+ switch (bind)
+ {
+ case 1:
+ lbl = loc::gettext("Flip is bound to: ");
+ actionset = ActionSet_InGame;
+ action = Action_InGame_ACTION;
+ break;
+ case 2:
+ lbl = loc::gettext("Enter is bound to: ");
+ actionset = ActionSet_InGame;
+ action = Action_InGame_Map;
+ break;
+ case 3:
+ lbl = loc::gettext("Menu is bound to: ");
+ actionset = ActionSet_InGame;
+ action = Action_InGame_Esc;
+ break;
+ case 4:
+ lbl = loc::gettext("Restart is bound to: ");
+ actionset = ActionSet_InGame;
+ action = Action_InGame_Restart;
+ break;
+ default:
+ lbl = loc::gettext("Interact is bound to: ");
+ actionset = ActionSet_InGame;
+ action = Action_InGame_Interact;
+ }
+
+ SDL_snprintf(
+ buffer_a, sizeof(buffer_a), "%s%s", lbl,
+ BUTTONGLYPHS_get_all_gamepad_buttons(buffer_b, sizeof(buffer_b), actionset, action)
+ );
+
+ int brightness = 255;
+ if (bind == 5 && !game.separate_interact)
+ {
+ brightness = 128;
+ }
+ else if (game.gpmenu_confirming && game.currentmenuoption == bind)
+ {
+ brightness = 255 - help.glow*2;
+ }
+
+ font::print(
+ PR_CEN | PR_BRIGHTNESS(brightness),
+ -1, 85 + (spacing * (bind-1)),
+ buffer_a,
+ tr, tg, tb
+ );
+ }
- SDL_snprintf(buffer_a, sizeof(buffer_a), "%s%s",
- loc::gettext("Interact is bound to: "),
- BUTTONGLYPHS_get_all_gamepad_buttons(buffer_b, sizeof(buffer_b), ActionSet_InGame, Action_InGame_Interact)
- );
- font::print(PR_CEN | PR_BRIGHTNESS(game.separate_interact ? 255 : 128), -1, 75+spacing*4, buffer_a, tr, tg, tb);
break;
}
}