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; } }