From 945ce3e4bceb2af7510ce79ab3723b52c701a978 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Tue, 5 May 2026 18:44:11 -0400 Subject: [PATCH] Alternate RMLUI Menu Sounds (#686) * Alternate RMLUI Menu Sounds Those fit more the game I feel like. * swapped tab sounds * pressing A on tab button plays the OK sound * Fix tab sound + Added menu sounds to prelaunch menu * Centralize UI sound definitions * Improvements * Add "Play" button sound * Use kSoundItemFocus in prelaunch * Oops * Update play/enable/disable sounds --------- Co-authored-by: MelonSpeedruns Co-authored-by: Luke Street --- src/dusk/ui/achievements.cpp | 4 +- src/dusk/ui/bool_button.cpp | 2 +- src/dusk/ui/button.cpp | 1 - src/dusk/ui/controller_config.cpp | 2 + src/dusk/ui/document.cpp | 9 +-- src/dusk/ui/editor.cpp | 93 +++++++++++++++++++++++++------ src/dusk/ui/modal.cpp | 4 +- src/dusk/ui/number_button.cpp | 2 +- src/dusk/ui/overlay.cpp | 6 +- src/dusk/ui/pane.cpp | 2 +- src/dusk/ui/popup.cpp | 8 ++- src/dusk/ui/prelaunch.cpp | 3 + src/dusk/ui/preset.cpp | 2 +- src/dusk/ui/settings.cpp | 5 ++ src/dusk/ui/tab_bar.cpp | 7 ++- src/dusk/ui/ui.hpp | 25 +++++++++ src/dusk/ui/window.cpp | 10 +++- src/dusk/ui/window.hpp | 1 + 18 files changed, 142 insertions(+), 44 deletions(-) diff --git a/src/dusk/ui/achievements.cpp b/src/dusk/ui/achievements.cpp index 93993bb380..67e36eb4f4 100644 --- a/src/dusk/ui/achievements.cpp +++ b/src/dusk/ui/achievements.cpp @@ -65,7 +65,7 @@ public: btn.on_nav_command([this, key = std::string(a.key)](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm) { if (mConfirming) { - mDoAud_seStartMenu(Z2SE_SY_CURSOR_OK); + mDoAud_seStartMenu(kSoundClick); AchievementSystem::get().clearOne(key.c_str()); resetConfirm(); } else { @@ -158,7 +158,7 @@ AchievementsWindow::AchievementsWindow() { clearAllBtn.on_nav_command([clearAllPtr, confirmingAll](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm) { if (*confirmingAll) { - mDoAud_seStartMenu(Z2SE_SY_CURSOR_OK); + mDoAud_seStartMenu(kSoundClick); AchievementSystem::get().clearAll(); *confirmingAll = false; clearAllPtr->set_text("Clear All Achievements"); diff --git a/src/dusk/ui/bool_button.cpp b/src/dusk/ui/bool_button.cpp index ca4d3f96d8..2ed088542a 100644 --- a/src/dusk/ui/bool_button.cpp +++ b/src/dusk/ui/bool_button.cpp @@ -36,7 +36,7 @@ bool BoolButton::handle_nav_command(NavCommand cmd) { if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || cmd == NavCommand::Right) { const bool newValue = !mGetValue(); mSetValue(newValue); - mDoAud_seStartMenu(newValue ? Z2SE_SY_CURSOR_OK : Z2SE_SY_CURSOR_CANCEL); + mDoAud_seStartMenu(newValue ? kSoundItemEnable : kSoundItemDisable); return true; } return false; diff --git a/src/dusk/ui/button.cpp b/src/dusk/ui/button.cpp index ac27b03d5a..fb11571af4 100644 --- a/src/dusk/ui/button.cpp +++ b/src/dusk/ui/button.cpp @@ -37,7 +37,6 @@ Button& Button::on_pressed(ButtonCallback callback) { // TODO: convert this to a FluentComponent method? on_nav_command([callback = std::move(callback)](Rml::Event&, NavCommand cmd) { if (cmd == NavCommand::Confirm) { - mDoAud_seStartMenu(Z2SE_SY_CURSOR_OK); callback(); return true; } diff --git a/src/dusk/ui/controller_config.cpp b/src/dusk/ui/controller_config.cpp index 9a3238725e..038248d7d0 100644 --- a/src/dusk/ui/controller_config.cpp +++ b/src/dusk/ui/controller_config.cpp @@ -322,6 +322,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { .isSelected = [port] { return PADGetIndexForPort(port) < 0; }, }) .on_pressed([this, port] { + mDoAud_seStartMenu(kSoundItemChange); cancel_pending_binding(); PADClearPort(port); PADSerializeMappings(); @@ -335,6 +336,7 @@ void ControllerConfigWindow::render_page(Pane& pane, int port, Page page) { [port, i] { return PADGetIndexForPort(port) == static_cast(i); }, }) .on_pressed([this, port, i] { + mDoAud_seStartMenu(kSoundItemChange); cancel_pending_binding(); PADSetPortForIndex(i, port); PADSerializeMappings(); diff --git a/src/dusk/ui/document.cpp b/src/dusk/ui/document.cpp index 9d581d21ca..a7bcc3f9ed 100644 --- a/src/dusk/ui/document.cpp +++ b/src/dusk/ui/document.cpp @@ -44,15 +44,8 @@ Document::Document(const Rml::String& source) : mDocument(load_document(source)) if (cmd == NavCommand::None) { return; } - auto* prevFocused = mDocument->GetFocusLeafNode(); if (handle_nav_command(event, cmd)) { event.StopPropagation(); - return; - } - if ((cmd == NavCommand::Up || cmd == NavCommand::Down) && - mDocument->GetFocusLeafNode() != prevFocused) - { - mDoAud_seStartMenu(Z2SE_SY_NAME_CURSOR); } }); } @@ -113,7 +106,7 @@ bool Document::visible() const { bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) { if (cmd == NavCommand::Menu) { - mDoAud_seStartMenu(visible() ? Z2SE_SY_MENU_OUT : Z2SE_SY_MENU_IN); + mDoAud_seStartMenu(visible() ? kSoundMenuClose : kSoundMenuOpen); toggle(); return true; } diff --git a/src/dusk/ui/editor.cpp b/src/dusk/ui/editor.cpp index 1ba44f0a27..fd42409ed2 100644 --- a/src/dusk/ui/editor.cpp +++ b/src/dusk/ui/editor.cpp @@ -185,7 +185,10 @@ void populate_stage_picker(Pane& pane, std::function getStageFile return getStageFile() == stageFile; }, }) - .on_pressed([setStageFile, stageFile = map.mapFile] { setStageFile(stageFile); }); + .on_pressed([setStageFile, stageFile = map.mapFile] { + mDoAud_seStartMenu(kSoundItemChange); + setStageFile(stageFile); + }); } } } @@ -741,11 +744,13 @@ void populate_toggle_group(Pane& pane, const std::vector& entries) pane.clear(); pane.add_section("Actions"); pane.add_button("Select All").on_pressed([entries] { + mDoAud_seStartMenu(kSoundItemChange); for (const auto& entry : entries) { entry.setSelected(true); } }); pane.add_button("Select None").on_pressed([entries] { + mDoAud_seStartMenu(kSoundItemChange); for (const auto& entry : entries) { entry.setSelected(false); } @@ -758,6 +763,7 @@ void populate_toggle_group(Pane& pane, const std::vector& entries) .isSelected = entry.isSelected, }) .on_pressed([isSelected = entry.isSelected, setSelected = entry.setSelected] { + mDoAud_seStartMenu(kSoundItemChange); setSelected(!isSelected()); }); } @@ -878,7 +884,10 @@ void populate_item_slot_picker(Pane& pane, int slot) { pane.clear(); pane.add_section("Actions"); pane.add_button(fmt::format("Default ({})", get_item_name(get_slot_default(slot)))) - .on_pressed([slot] { dComIfGs_setItem(slot, get_slot_default(slot)); }); + .on_pressed([slot] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setItem(slot, get_slot_default(slot)); + }); pane.add_section("Items"); pane.add_button( @@ -886,7 +895,10 @@ void populate_item_slot_picker(Pane& pane, int slot) { .text = "None", .isSelected = [slot] { return get_player_item()->mItems[slot] == dItemNo_NONE_e; }, }) - .on_pressed([slot] { dComIfGs_setItem(slot, dItemNo_NONE_e); }); + .on_pressed([slot] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setItem(slot, dItemNo_NONE_e); + }); for (const auto& [itemId, item] : itemMap) { if (item.m_type != ITEMTYPE_EQUIP_e) { continue; @@ -896,15 +908,24 @@ void populate_item_slot_picker(Pane& pane, int slot) { .text = item.m_name, .isSelected = [slot, itemId] { return get_player_item()->mItems[slot] == itemId; }, }) - .on_pressed([slot, itemId] { dComIfGs_setItem(slot, static_cast(itemId)); }); + .on_pressed([slot, itemId] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setItem(slot, static_cast(itemId)); + }); } } void populate_item_flag_picker(Pane& pane) { pane.clear(); pane.add_section("Actions"); - pane.add_button("Select All").on_pressed([] { set_all_item_first_bits(true); }); - pane.add_button("Clear None").on_pressed([] { set_all_item_first_bits(false); }); + pane.add_button("Select All").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + set_all_item_first_bits(true); + }); + pane.add_button("Clear None").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + set_all_item_first_bits(false); + }); pane.add_section("Items"); for (const auto& [itemId, item] : itemMap) { @@ -916,7 +937,10 @@ void populate_item_flag_picker(Pane& pane) { .text = item.m_name, .isSelected = [itemId] { return dComIfGs_isItemFirstBit(static_cast(itemId)); }, }) - .on_pressed([itemId] { toggle_item_first_bit(static_cast(itemId)); }); + .on_pressed([itemId] { + mDoAud_seStartMenu(kSoundItemChange); + toggle_item_first_bit(static_cast(itemId)); + }); } } @@ -927,13 +951,19 @@ void populate_select_item_picker(Pane& pane, u8& selectItemData) { .text = "None", .isSelected = [&selectItemData] { return selectItemData == dItemNo_NONE_e; }, }) - .on_pressed([&selectItemData] { selectItemData = dItemNo_NONE_e; }); + .on_pressed([&selectItemData] { + mDoAud_seStartMenu(kSoundItemChange); + selectItemData = dItemNo_NONE_e; + }); for (int i = 0; i < 24; i++) { pane.add_button({ .text = item_label_for_slot(i), .isSelected = [i, &selectItemData] { return selectItemData == i; }, }) - .on_pressed([i, &selectItemData] { selectItemData = i; }); + .on_pressed([i, &selectItemData] { + mDoAud_seStartMenu(kSoundItemChange); + selectItemData = i; + }); } } @@ -946,6 +976,7 @@ void populate_select_clothes_picker(Pane& pane) { .isSelected = [id] { return get_player_status()->mSelectEquip[0] == id; }, }) .on_pressed([id] { + mDoAud_seStartMenu(kSoundItemChange); dMeter2Info_setCloth(id, false); daPy_getPlayerActorClass()->setClothesChange(0); }); @@ -964,7 +995,10 @@ void populate_select_equip_picker(Pane& pane, u8& equip, const std::arraygetWalletSize() == i; }, }) - .on_pressed([i] { get_player_status()->setWalletSize(i); }); + .on_pressed([i] { + mDoAud_seStartMenu(kSoundItemChange); + get_player_status()->setWalletSize(i); + }); } } @@ -1002,7 +1039,10 @@ void populate_form_picker(Pane& pane) { .text = formNames[i], .isSelected = [i] { return get_player_status()->getTransformStatus() == i; }, }) - .on_pressed([i] { get_player_status()->setTransformStatus(i); }); + .on_pressed([i] { + mDoAud_seStartMenu(kSoundItemChange); + get_player_status()->setTransformStatus(i); + }); } } @@ -1013,7 +1053,10 @@ void add_toggle_button(Pane& pane, ToggleEntry entry) { .text = entry.text, .isSelected = isSelected, }) - .on_pressed([isSelected, setSelected] { setSelected(!isSelected()); }); + .on_pressed([isSelected, setSelected] { + mDoAud_seStartMenu(kSoundItemChange); + setSelected(!isSelected()); + }); } template @@ -1126,8 +1169,14 @@ void populate_collect_clothes_picker(Pane& pane) { void populate_poe_souls_picker(Pane& pane) { pane.clear(); pane.add_section("Actions"); - pane.add_button("All 60").on_pressed([] { dComIfGs_setPohSpiritNum(60); }); - pane.add_button("Clear").on_pressed([] { dComIfGs_setPohSpiritNum(0); }); + pane.add_button("All 60").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setPohSpiritNum(60); + }); + pane.add_button("Clear").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); + dComIfGs_setPohSpiritNum(0); + }); pane.add_section("Value"); pane.add_child(NumberButton::Props{ @@ -1143,10 +1192,12 @@ void populate_max_life_picker(Pane& pane) { pane.clear(); pane.add_section("Actions"); pane.add_button("3 Hearts").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); dComIfGs_setMaxLife(15); dComIfGs_setLife(12); }); pane.add_button("20 Hearts").on_pressed([] { + mDoAud_seStartMenu(kSoundItemChange); dComIfGs_setMaxLife(100); dComIfGs_setLife(80); }); @@ -1257,7 +1308,10 @@ void populate_target_type_picker(Pane& pane) { .text = targetTypeNames[type], .isSelected = [type] { return get_player_config()->getAttentionType() == type; }, }) - .on_pressed([type] { get_player_config()->setAttentionType(type); }); + .on_pressed([type] { + mDoAud_seStartMenu(kSoundItemChange); + get_player_config()->setAttentionType(type); + }); } } @@ -1269,7 +1323,10 @@ void populate_sound_mode_picker(Pane& pane) { .text = soundModeNames[mode], .isSelected = [mode] { return get_player_config()->getSound() == mode; }, }) - .on_pressed([mode] { get_player_config()->setSound(mode); }); + .on_pressed([mode] { + mDoAud_seStartMenu(kSoundItemChange); + get_player_config()->setSound(mode); + }); } } @@ -1594,6 +1651,7 @@ EditorWindow::EditorWindow() { leftPane.add_section("Item Wheel"); leftPane.register_control(leftPane.add_button("Default All").on_pressed([&rightPane] { + mDoAud_seStartMenu(kSoundItemChange); for (int slot = 0; slot < 24; ++slot) { dComIfGs_setItem(slot, get_slot_default(slot)); } @@ -1601,6 +1659,7 @@ EditorWindow::EditorWindow() { }), rightPane, {}); leftPane.register_control(leftPane.add_button("Clear All").on_pressed([&rightPane] { + mDoAud_seStartMenu(kSoundItemChange); for (int slot = 0; slot < 24; ++slot) { dComIfGs_setItem(slot, dItemNo_NONE_e); } diff --git a/src/dusk/ui/modal.cpp b/src/dusk/ui/modal.cpp index 93ea060b51..cd46f68528 100644 --- a/src/dusk/ui/modal.cpp +++ b/src/dusk/ui/modal.cpp @@ -44,7 +44,7 @@ void Modal::dismiss() { bool Modal::handle_nav_command(Rml::Event& event, NavCommand cmd) { if (cmd == NavCommand::Cancel || cmd == NavCommand::Menu) { - mDoAud_seStartMenu(Z2SE_SY_CURSOR_CANCEL); + mDoAud_seStartMenu(kSoundWindowClose); dismiss(); return true; } @@ -63,7 +63,7 @@ bool Modal::handle_nav_command(Rml::Event& event, NavCommand cmd) { if (mButtons[i]->contains(target)) { const int next = i + direction; if (next >= 0 && next < static_cast(mButtons.size()) && mButtons[next]->focus()) { - mDoAud_seStartMenu(Z2SE_SY_NAME_CURSOR); + mDoAud_seStartMenu(kSoundItemFocus); return true; } return false; diff --git a/src/dusk/ui/number_button.cpp b/src/dusk/ui/number_button.cpp index f891b4275b..ab5095cf3f 100644 --- a/src/dusk/ui/number_button.cpp +++ b/src/dusk/ui/number_button.cpp @@ -59,7 +59,7 @@ bool NumberButton::handle_nav_command(NavCommand cmd) { mGetValue() + (cmd == NavCommand::Right ? mStep : -mStep), mMin, mMax); if (newValue != mGetValue()) { mSetValue(newValue); - mDoAud_seStartMenu(Z2SE_SY_NAME_CURSOR); + mDoAud_seStartMenu(kSoundItemChange); } return true; } diff --git a/src/dusk/ui/overlay.cpp b/src/dusk/ui/overlay.cpp index 837f8a5c5a..dd6f0f54d7 100644 --- a/src/dusk/ui/overlay.cpp +++ b/src/dusk/ui/overlay.cpp @@ -149,7 +149,7 @@ void SteppedCarousel::apply(int value) { if (nextValue == currentValue) { return; } - mDoAud_seStartMenu(Z2SE_SY_NAME_CURSOR); + mDoAud_seStartMenu(kSoundItemChange); if (mProps.onChange) { mProps.onChange(nextValue); } @@ -216,6 +216,7 @@ Overlay::Overlay(OverlayProps props) returnButton.root()->SetClass("return", true); auto& resetButton = add_component