/** * @file gamemenu.cpp * * Implementation of the in-game menu functions. */ #include "gamemenu.h" #include "cursor.h" #include "error.h" #include "gmenu.h" #include "init.h" #include "loadsave.h" #include "options.h" #include "pfile.h" #include "utils/language.h" #ifndef NOSOUND #include "sound.h" #endif namespace devilution { namespace { // Forward-declare menu handlers, used by the global menu structs below. void gamemenu_previous(bool bActivate); void gamemenu_new_game(bool bActivate); void gamemenu_restart_town(bool bActivate); void gamemenu_options(bool bActivate); void gamemenu_music_volume(bool bActivate); void gamemenu_sound_volume(bool bActivate); void gamemenu_gamma(bool bActivate); void gamemenu_speed(bool bActivate); /** Contains the game menu items of the single player menu. */ TMenuItem sgSingleMenu[] = { // clang-format off // dwFlags, pszStr, fnMenu { GMENU_ENABLED, N_("Save Game"), &gamemenu_save_game }, { GMENU_ENABLED, N_("Options"), &gamemenu_options }, { GMENU_ENABLED, N_("New Game"), &gamemenu_new_game }, { GMENU_ENABLED, N_("Load Game"), &gamemenu_load_game }, { GMENU_ENABLED, N_("Quit Game"), &gamemenu_quit_game }, { GMENU_ENABLED, nullptr, nullptr } // clang-format on }; /** Contains the game menu items of the multi player menu. */ TMenuItem sgMultiMenu[] = { // clang-format off // dwFlags, pszStr, fnMenu { GMENU_ENABLED, N_("Options"), &gamemenu_options }, { GMENU_ENABLED, N_("New Game"), &gamemenu_new_game }, { GMENU_ENABLED, N_("Restart In Town"), &gamemenu_restart_town }, { GMENU_ENABLED, N_("Quit Game"), &gamemenu_quit_game }, { GMENU_ENABLED, nullptr, nullptr }, // clang-format on }; TMenuItem sgOptionsMenu[] = { // clang-format off // dwFlags, pszStr, fnMenu { GMENU_ENABLED | GMENU_SLIDER, nullptr, &gamemenu_music_volume }, { GMENU_ENABLED | GMENU_SLIDER, nullptr, &gamemenu_sound_volume }, { GMENU_ENABLED | GMENU_SLIDER, N_("Gamma"), &gamemenu_gamma }, { GMENU_ENABLED | GMENU_SLIDER, N_("Speed"), &gamemenu_speed }, { GMENU_ENABLED , N_("Previous Menu"), &gamemenu_previous }, { GMENU_ENABLED , nullptr, nullptr }, // clang-format on }; /** Specifies the menu names for music enabled and disabled. */ const char *const music_toggle_names[] = { N_("Music"), N_("Music Disabled"), }; /** Specifies the menu names for sound enabled and disabled. */ const char *const sound_toggle_names[] = { N_("Sound"), N_("Sound Disabled"), }; void gamemenu_update_single() { gmenu_enable(&sgSingleMenu[3], gbValidSaveFile); bool enable = plr[myplr]._pmode != PM_DEATH && !deathflag; gmenu_enable(&sgSingleMenu[0], enable); } void gamemenu_update_multi() { gmenu_enable(&sgMultiMenu[2], deathflag); } void gamemenu_previous(bool bActivate) { gamemenu_on(); } void gamemenu_new_game(bool bActivate) { for (auto &player : plr) { player._pmode = PM_QUIT; player._pInvincible = true; } deathflag = false; force_redraw = 255; scrollrt_draw_game_screen(true); CornerStone.activated = false; gbRunGame = false; gamemenu_off(); } void gamemenu_restart_town(bool bActivate) { NetSendCmd(true, CMD_RETOWN); } void gamemenu_sound_music_toggle(const char *const *names, TMenuItem *menu_item, int volume) { #ifndef NOSOUND if (gbSndInited) { menu_item->dwFlags |= GMENU_ENABLED | GMENU_SLIDER; menu_item->pszStr = names[0]; gmenu_slider_steps(menu_item, VOLUME_STEPS); gmenu_slider_set(menu_item, VOLUME_MIN, VOLUME_MAX, volume); return; } #endif menu_item->dwFlags &= ~(GMENU_ENABLED | GMENU_SLIDER); menu_item->pszStr = names[1]; } static int gamemenu_slider_music_sound(TMenuItem *menu_item) { return gmenu_slider_get(menu_item, VOLUME_MIN, VOLUME_MAX); } void gamemenu_get_music() { gamemenu_sound_music_toggle(music_toggle_names, sgOptionsMenu, sound_get_or_set_music_volume(1)); } void gamemenu_get_sound() { gamemenu_sound_music_toggle(sound_toggle_names, &sgOptionsMenu[1], sound_get_or_set_sound_volume(1)); } void gamemenu_get_gamma() { gmenu_slider_steps(&sgOptionsMenu[2], 15); gmenu_slider_set(&sgOptionsMenu[2], 30, 100, UpdateGamma(0)); } void gamemenu_get_speed() { if (gbIsMultiplayer) { sgOptionsMenu[3].dwFlags &= ~(GMENU_ENABLED | GMENU_SLIDER); if (sgGameInitInfo.nTickRate >= 50) sgOptionsMenu[3].pszStr = _("Speed: Fastest"); else if (sgGameInitInfo.nTickRate >= 40) sgOptionsMenu[3].pszStr = _("Speed: Faster"); else if (sgGameInitInfo.nTickRate >= 30) sgOptionsMenu[3].pszStr = _("Speed: Fast"); else if (sgGameInitInfo.nTickRate == 20) sgOptionsMenu[3].pszStr = _("Speed: Normal"); return; } sgOptionsMenu[3].dwFlags |= GMENU_ENABLED | GMENU_SLIDER; sgOptionsMenu[3].pszStr = _("Speed"); gmenu_slider_steps(&sgOptionsMenu[3], 46); gmenu_slider_set(&sgOptionsMenu[3], 20, 50, sgGameInitInfo.nTickRate); } static int gamemenu_slider_gamma() { return gmenu_slider_get(&sgOptionsMenu[2], 30, 100); } void gamemenu_options(bool bActivate) { gamemenu_get_music(); gamemenu_get_sound(); gamemenu_get_gamma(); gamemenu_get_speed(); gmenu_set_items(sgOptionsMenu, nullptr); } void gamemenu_music_volume(bool bActivate) { int volume; #ifndef NOSOUND if (bActivate) { if (gbMusicOn) { gbMusicOn = false; music_stop(); sound_get_or_set_music_volume(VOLUME_MIN); } else { gbMusicOn = true; sound_get_or_set_music_volume(VOLUME_MAX); int lt; if (currlevel >= 17) { if (currlevel > 20) lt = TMUSIC_L5; else lt = TMUSIC_L6; } else lt = leveltype; music_start(lt); } } else { volume = gamemenu_slider_music_sound(&sgOptionsMenu[0]); sound_get_or_set_music_volume(volume); if (volume == VOLUME_MIN) { if (gbMusicOn) { gbMusicOn = false; music_stop(); } } else if (!gbMusicOn) { gbMusicOn = true; int lt; if (currlevel >= 17) { if (currlevel > 20) lt = TMUSIC_L5; else lt = TMUSIC_L6; } else lt = leveltype; music_start(lt); } } #endif gamemenu_get_music(); } void gamemenu_sound_volume(bool bActivate) { #ifndef NOSOUND int volume; if (bActivate) { if (gbSoundOn) { gbSoundOn = false; sound_stop(); sound_get_or_set_sound_volume(VOLUME_MIN); } else { gbSoundOn = true; sound_get_or_set_sound_volume(VOLUME_MAX); } } else { volume = gamemenu_slider_music_sound(&sgOptionsMenu[1]); sound_get_or_set_sound_volume(volume); if (volume == VOLUME_MIN) { if (gbSoundOn) { gbSoundOn = false; sound_stop(); } } else if (!gbSoundOn) { gbSoundOn = true; } } PlaySFX(IS_TITLEMOV); gamemenu_get_sound(); #endif } void gamemenu_gamma(bool bActivate) { int gamma; if (bActivate) { gamma = UpdateGamma(0); if (gamma == 30) gamma = 100; else gamma = 30; } else { gamma = gamemenu_slider_gamma(); } UpdateGamma(gamma); gamemenu_get_gamma(); } void gamemenu_speed(bool bActivate) { if (bActivate) { if (sgGameInitInfo.nTickRate != 20) sgGameInitInfo.nTickRate = 20; else sgGameInitInfo.nTickRate = 50; gmenu_slider_set(&sgOptionsMenu[3], 20, 50, sgGameInitInfo.nTickRate); } else { sgGameInitInfo.nTickRate = gmenu_slider_get(&sgOptionsMenu[3], 20, 50); } sgOptions.Gameplay.nTickRate = sgGameInitInfo.nTickRate; gnTickDelay = 1000 / sgGameInitInfo.nTickRate; } } // namespace void gamemenu_quit_game(bool bActivate) { gamemenu_new_game(bActivate); gbRunGameResult = false; } void gamemenu_load_game(bool bActivate) { WNDPROC saveProc = SetWindowProc(DisableInputWndProc); gamemenu_off(); NewCursor(CURSOR_NONE); InitDiabloMsg(EMSG_LOADING); force_redraw = 255; DrawAndBlit(); LoadGame(false); ClrDiabloMsg(); CornerStone.activated = false; PaletteFadeOut(8); deathflag = false; force_redraw = 255; DrawAndBlit(); LoadPWaterPalette(); PaletteFadeIn(8); NewCursor(CURSOR_HAND); interface_msg_pump(); SetWindowProc(saveProc); } void gamemenu_save_game(bool bActivate) { if (pcurs != CURSOR_HAND) { return; } if (plr[myplr]._pmode == PM_DEATH || deathflag) { gamemenu_off(); return; } WNDPROC saveProc = SetWindowProc(DisableInputWndProc); NewCursor(CURSOR_NONE); gamemenu_off(); InitDiabloMsg(EMSG_SAVING); force_redraw = 255; DrawAndBlit(); SaveGame(); ClrDiabloMsg(); force_redraw = 255; NewCursor(CURSOR_HAND); if (CornerStone.activated) { items_427A72(); } interface_msg_pump(); SetWindowProc(saveProc); } void gamemenu_on() { if (!gbIsMultiplayer) { gmenu_set_items(sgSingleMenu, gamemenu_update_single); } else { gmenu_set_items(sgMultiMenu, gamemenu_update_multi); } PressEscKey(); } void gamemenu_off() { gmenu_set_items(nullptr, nullptr); } void gamemenu_handle_previous() { if (gmenu_is_active()) gamemenu_off(); else gamemenu_on(); } } // namespace devilution