mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2025-07-07 11:35:00 +00:00
Add confirmation and removal to bindings menu
This makes the following improvements to the gamepad bindings menu: - The menu now shows a hint that you can press a button while any of the bind options are selected (or that you can navigate away from those options) - Instead of button presses immediately setting a binding, they now ask for confirmation: press the same button a second time to confirm - You can now remove a binding, the same way you add it (this has the same type of confirmation) - This menu used to be inconsistent with pretty much every other menu in the game by showing a permanent title and description for the menu itself ("Game Pad", "Change controller options.") rather than showing a title and description for the currently selected option. This inconsistency is now fixed.
This commit is contained in:
parent
75035047ad
commit
d730528118
7 changed files with 182 additions and 44 deletions
|
@ -46,9 +46,7 @@
|
|||
<string english="unlock secret lab" translation="" explanation="menu option"/>
|
||||
<string english="game pad" translation="" explanation="menu option"/>
|
||||
<string english="Game Pad Options" translation="" explanation="title" max="20"/>
|
||||
<string english="Game Pad" translation="" explanation="title" max="20"/>
|
||||
<string english="Rebind your controller's buttons and adjust sensitivity." translation="" explanation="" max="38*5"/>
|
||||
<string english="Change controller options." translation="" explanation="" max="38*2"/>
|
||||
<string english="language" translation="" explanation="menu option"/>
|
||||
<string english="Language" translation="" explanation="title" max="20"/>
|
||||
<string english="Change the language." translation="" explanation="" max="38*2"/>
|
||||
|
@ -135,19 +133,30 @@
|
|||
<string english="disable cutscenes" translation="" explanation="menu option"/>
|
||||
<string english="enable cutscenes" translation="" explanation="menu option"/>
|
||||
<string english="analog stick sensitivity" translation="" explanation="menu option"/>
|
||||
<string english="Stick Sensitivity" translation="" explanation="title" max="20"/>
|
||||
<string english="Change the sensitivity of the analog stick." translation="" explanation="" max="38*3"/>
|
||||
<string english="Low" translation="" explanation="analog stick sensitivity, game pad menu"/>
|
||||
<string english="Medium" translation="" explanation="analog stick sensitivity, game pad menu"/>
|
||||
<string english="High" translation="" explanation="analog stick sensitivity, game pad menu"/>
|
||||
<string english="bind flip" translation="" explanation="menu option"/>
|
||||
<string english="Bind Flip" translation="" explanation="title" max="20"/>
|
||||
<string english="bind enter" translation="" explanation="menu option"/>
|
||||
<string english="Bind Enter" translation="" explanation="title" max="20"/>
|
||||
<string english="bind menu" translation="" explanation="menu option"/>
|
||||
<string english="Bind Menu" translation="" explanation="title" max="20"/>
|
||||
<string english="bind restart" translation="" explanation="menu option. In-game death key to restart at checkpoint"/>
|
||||
<string english="Bind Restart" translation="" explanation="title" max="20"/>
|
||||
<string english="bind interact" translation="" explanation="menu option"/>
|
||||
<string english="Bind Interact" translation="" explanation="title" max="20"/>
|
||||
<string english="Flip is bound to: " translation="" explanation="controller binds, bound to A, B, X, Y, etc. These strings end with a space!" max="32"/>
|
||||
<string english="Enter is bound to: " translation="" explanation="controller binds, bound to A, B, X, Y, etc. These strings end with a space!" max="32"/>
|
||||
<string english="Menu is bound to: " translation="" explanation="controller binds, bound to A, B, X, Y, etc. These strings end with a space!" max="32"/>
|
||||
<string english="Restart is bound to: " translation="" explanation="in-game death key to restart at checkpoint. Controller binds, bound to A, B, X, Y, etc. These strings end with a space!" max="32"/>
|
||||
<string english="Interact is bound to: " translation="" explanation="controller binds, bound to A, B, X, Y, etc. These strings end with a space!" max="32"/>
|
||||
<string english="Press a button...|(or press ↑↓)" translation="" explanation="the arrows represent up/down buttons, or stick movement... So: press a controller button, or navigate away" max="38*2"/>
|
||||
<string english="Add {button}?|Press again to confirm" translation="" explanation="Bind the X button to this action? Press X again to really add it" max="38*2"/>
|
||||
<string english="Remove {button}?|Press again to confirm" translation="" explanation="Remove the binding of the X button for this action? Press X again to really remove it" max="38*2"/>
|
||||
<string english="Interact is currently Enter!|See speedrunner options." translation="" explanation="the Interact action can't be configured now because it's the same as the Enter action. There's an option in the Speedrunner options to split it off" max="38*2"/>
|
||||
<string english="ERROR: No language files found." translation="" explanation="" max="38*3"/>
|
||||
<string english="Language folder:" translation="" explanation="" max="39"/>
|
||||
<string english="Repository language folder:" translation="" explanation="Language folder from the Git repository" max="39"/>
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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<SDL_GameControllerButton>* 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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue