From e8316c7e9a6c2c975e04bf6d7b0b4929ebf445b9 Mon Sep 17 00:00:00 2001 From: Misa Date: Sun, 11 Apr 2021 17:43:17 -0700 Subject: [PATCH] Implement music and sound volume sliders This adds music and volume sliders to the audio options. To use the sliders, you navigate to the given option, then press ACTION, and your selection will be transferred to the slider. Pressing left or right will move the slider accordingly. Then you can press ACTION to confirm the volume is what you want and deselect it, or you can press Esc to cancel the volume change, and it will revert to the previous volume; both actions will write your settings to disk. Most of this commit is just adding infrastructure to support having sliders in menus (without copy-pasting code), which is a totally completely new user interface that has never been used before in this game. If we're going to be adding something new, I want to make sure that it at least is done the RIGHT way. Closes #706. --- desktop_version/src/Game.cpp | 1 + desktop_version/src/Game.h | 8 +++ desktop_version/src/Graphics.cpp | 2 +- desktop_version/src/Input.cpp | 99 +++++++++++++++++++++++++++++--- desktop_version/src/Music.h | 3 + desktop_version/src/Render.cpp | 64 ++++++++++++++++++++- 6 files changed, 166 insertions(+), 11 deletions(-) diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index ded3a09b..2a01900e 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -383,6 +383,7 @@ void Game::init(void) ingame_editormode = false; #endif kludge_ingametemp = Menu::mainmenu; + slidermode = SLIDER_NONE; disablepause = false; inputdelay = false; diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h index e91a1a38..21a4ca87 100644 --- a/desktop_version/src/Game.h +++ b/desktop_version/src/Game.h @@ -84,6 +84,13 @@ namespace Menu }; } +enum SLIDERMODE +{ + SLIDER_NONE, + SLIDER_MUSICVOLUME, + SLIDER_SOUNDVOLUME +}; + struct MenuStackFrame { int option; @@ -259,6 +266,7 @@ public: int currentmenuoption ; enum Menu::MenuName currentmenuname; enum Menu::MenuName kludge_ingametemp; + enum SLIDERMODE slidermode; int current_credits_list_index; int menuxoff, menuyoff; int menuspacing; diff --git a/desktop_version/src/Graphics.cpp b/desktop_version/src/Graphics.cpp index 33c1221c..fe4fdfbb 100644 --- a/desktop_version/src/Graphics.cpp +++ b/desktop_version/src/Graphics.cpp @@ -1475,7 +1475,7 @@ void Graphics::drawmenu( int cr, int cg, int cb, bool levelmenu /*= false*/ ) SDL_strlcpy(tempstring, opt.text, sizeof(tempstring)); char buffer[MENU_TEXT_BYTES]; - if ((int) i == game.currentmenuoption) + if ((int) i == game.currentmenuoption && game.slidermode == SLIDER_NONE) { if (opt.active) { diff --git a/desktop_version/src/Input.cpp b/desktop_version/src/Input.cpp index 5313f9bb..01ddc152 100644 --- a/desktop_version/src/Input.cpp +++ b/desktop_version/src/Input.cpp @@ -200,6 +200,56 @@ static void startmode(const int mode) fadetomodedelay = 16; } +static int* user_changing_volume = NULL; +static int previous_volume = 0; + +static void initvolumeslider(const int menuoption) +{ + switch (menuoption) + { + case 0: + game.slidermode = SLIDER_MUSICVOLUME; + user_changing_volume = &music.user_music_volume; + break; + case 1: + game.slidermode = SLIDER_SOUNDVOLUME; + user_changing_volume = &music.user_sound_volume; + break; + default: + SDL_assert(0 && "Unhandled volume slider option!"); + game.slidermode = SLIDER_NONE; + user_changing_volume = NULL; + return; + } + previous_volume = *user_changing_volume; +} + +static void deinitvolumeslider(void) +{ + user_changing_volume = NULL; + game.savestatsandsettings_menu(); + game.slidermode = SLIDER_NONE; +} + +static void slidermodeinput(void) +{ + if (user_changing_volume == NULL) + { + SDL_assert(0 && "user_changing_volume is NULL!"); + return; + } + + if (game.press_left) + { + *user_changing_volume -= USER_VOLUME_STEP; + } + else if (game.press_right) + { + *user_changing_volume += USER_VOLUME_STEP; + } + *user_changing_volume = clamp(*user_changing_volume, 0, USER_VOLUME_MAX); +} + static void menuactionpress(void) { switch (game.currentmenuname) @@ -786,10 +836,16 @@ static void menuactionpress(void) switch (game.currentmenuoption) { case 0: - /* Not implemented */ - break; case 1: - /* Not implemented */ + music.playef(11); + if (game.slidermode == SLIDER_NONE) + { + initvolumeslider(game.currentmenuoption); + } + else + { + deinitvolumeslider(); + } break; case 2: if (!music.mmmmmm) @@ -1641,7 +1697,27 @@ void titleinput(void) } else { - if (game.ingame_titlemode + if (game.slidermode != SLIDER_NONE) + { + switch (game.slidermode) + { + /* Cancel volume change. */ + case SLIDER_MUSICVOLUME: + case SLIDER_SOUNDVOLUME: + if (user_changing_volume == NULL) + { + SDL_assert(0 && "user_changing_volume is NULL!"); + break; + } + *user_changing_volume = previous_volume; + deinitvolumeslider(); + break; + default: + SDL_assert(0 && "Unhandled slider mode!"); + break; + } + } + else if (game.ingame_titlemode && game.currentmenuname == Menu::options) { game.returntoingame(); @@ -1656,13 +1732,20 @@ void titleinput(void) if(game.menustart) { - if (game.press_left) + if (game.slidermode == SLIDER_NONE) { - game.currentmenuoption--; + if (game.press_left) + { + game.currentmenuoption--; + } + else if (game.press_right) + { + game.currentmenuoption++; + } } - else if (game.press_right) + else { - game.currentmenuoption++; + slidermodeinput(); } } diff --git a/desktop_version/src/Music.h b/desktop_version/src/Music.h index 7ba45ff2..593b339e 100644 --- a/desktop_version/src/Music.h +++ b/desktop_version/src/Music.h @@ -11,6 +11,9 @@ /* The amount of "space" for the scale of the user-set volume. */ #define USER_VOLUME_MAX 256 +/* It is advised that USER_VOLUME_MAX be divisible by this. */ +#define USER_VOLUME_STEP 32 + class musicclass { public: diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp index 25970783..e1913901 100644 --- a/desktop_version/src/Render.cpp +++ b/desktop_version/src/Render.cpp @@ -46,6 +46,62 @@ static inline void drawslowdowntext(void) } } +static void volumesliderrender(void) +{ + char buffer[40 + 1]; + + char slider[20 + 1]; + int slider_length; + + const char symbol[] = "[]"; + int symbol_length; + + int offset; + int num_positions; + + const int* volume_ptr; + + switch (game.currentmenuoption) + { + case 0: + volume_ptr = &music.user_music_volume; + break; + case 1: + volume_ptr = &music.user_sound_volume; + break; + default: + SDL_assert(0 && "Unhandled volume slider menu option!"); + return; + } + + VVV_fillstring(slider, sizeof(slider), '.'); + slider_length = sizeof(slider) - 1; + + symbol_length = sizeof(symbol) - 1; + + num_positions = slider_length - symbol_length + 1; + + offset = num_positions * (*volume_ptr) / USER_VOLUME_MAX; + offset = clamp(offset, 0, slider_length - symbol_length); + + /* SDL_strlcpy null-terminates, which would end the string in the middle of + * it, which we don't want! + */ + SDL_memcpy(&slider[offset], symbol, symbol_length); + + if (game.slidermode == SLIDER_NONE) + { + SDL_strlcpy(buffer, slider, sizeof(buffer)); + } + else + { + /* Draw selection brackets. */ + SDL_snprintf(buffer, sizeof(buffer), "[ %s ]", slider); + } + + graphics.Print(-1, 85, buffer, tr, tg, tb, true); +} + static void menurender(void) { int temp = 50; @@ -281,10 +337,14 @@ static void menurender(void) switch (game.currentmenuoption) { case 0: - /* Not implemented */ + graphics.bigprint(-1, 30, "Music Volume", tr, tg, tb, true); + graphics.Print(-1, 65, "Change the volume of the music.", tr, tg, tb, true); + volumesliderrender(); break; case 1: - /* Not implemented */ + graphics.bigprint(-1, 30, "Sound Volume", tr, tg, tb, true); + graphics.Print(-1, 65, "Change the volume of sound effects.", tr, tg, tb, true); + volumesliderrender(); break; case 2: if (!music.mmmmmm)