diff --git a/src/client/PerlinWorldRender.cpp b/src/client/PerlinWorldRender.cpp index 8effdb5..de9ee7d 100644 --- a/src/client/PerlinWorldRender.cpp +++ b/src/client/PerlinWorldRender.cpp @@ -1691,15 +1691,11 @@ namespace perlin { this->input.SetKeyboard(keyboard); } const bool pressed = this->input.IsMouseDown(0); - const bool onButton = hud->Overlay().OverlayHoverIsButton(); - if (pressed && !uiClickWasDown && onButton && !chat.IsOpen()) { - std::string clickName = "random.click"; - float clickVolume = 1.0f, clickPitch = 1.0f; - hud->Overlay().OverlayHoverSound(clickName, clickVolume, clickPitch); - if (!clickName.empty()) - sounds.PlayNamed(clickName, {camera.x, camera.y, camera.z}, clickVolume, clickPitch, - false); - } + std::string clickName; + float clickVolume = 1.0f, clickPitch = 1.0f; + if (pressed && !uiClickWasDown && !chat.IsOpen() && + hud->Overlay().OverlayHoverClickSound(clickName, clickVolume, clickPitch)) + sounds.PlayNamed(clickName, {camera.x, camera.y, camera.z}, clickVolume, clickPitch, false); uiClickWasDown = pressed; } DrawModTint(fbW, fbH); diff --git a/src/client/ui/RmlBackend.cpp b/src/client/ui/RmlBackend.cpp index 8740c2d..943c9b9 100644 --- a/src/client/ui/RmlBackend.cpp +++ b/src/client/ui/RmlBackend.cpp @@ -949,33 +949,29 @@ namespace perlin::ui { return {}; } - bool RmlBackend::OverlayHoverIsButton() const { + bool RmlBackend::OverlayHoverClickSound(std::string& name, float& volume, float& pitch) const { if (!context || !overlay) return false; - static const char* const kClickable[] = {"btn", "sbtn", "rbtn", "pg", "row", - "ticon", "go", "acc", "bt"}; + static const char* const kNative[] = {"btn", "sbtn", "rbtn", "pg", "row", "ticon", "go", "acc"}; for (Rml::Element* e = context->GetHoverElement(); e && e->GetOwnerDocument() == overlay; e = e->GetParentNode()) { if (e->IsClassSet("off")) return false; - for (const char* name : kClickable) - if (e->IsClassSet(name)) + if (e->HasAttribute("snd")) { + name = e->GetAttribute("snd", ""); + volume = e->GetAttribute("vol", 1.0f); + pitch = e->GetAttribute("pit", 1.0f); + return !name.empty(); + } + // json ui control without sound_name (container slots, sliders, edit boxes): the game stays silent + if (e->IsClassSet("bt")) + return false; + for (const char* cls : kNative) + if (e->IsClassSet(cls)) { + name = "random.click"; + volume = pitch = 1.0f; return true; - } - return false; - } - - bool RmlBackend::OverlayHoverSound(std::string& name, float& volume, float& pitch) const { - if (!context || !overlay) - return false; - for (Rml::Element* e = context->GetHoverElement(); e && e->GetOwnerDocument() == overlay; - e = e->GetParentNode()) { - if (!e->HasAttribute("snd")) - continue; - name = e->GetAttribute("snd", ""); - volume = e->GetAttribute("vol", 1.0f); - pitch = e->GetAttribute("pit", 1.0f); - return true; + } } return false; } diff --git a/src/client/ui/RmlBackend.hpp b/src/client/ui/RmlBackend.hpp index 0dae0db..0a7e472 100644 --- a/src/client/ui/RmlBackend.hpp +++ b/src/client/ui/RmlBackend.hpp @@ -40,8 +40,8 @@ namespace perlin::ui { bool HasOverlay() const { return overlay != nullptr; } void MouseMove(float guiX, float guiY); std::string OverlayHover() const; - bool OverlayHoverIsButton() const; - bool OverlayHoverSound(std::string& name, float& volume, float& pitch) const; + // sound to play for a click on the hovered overlay element; false when it makes none + bool OverlayHoverClickSound(std::string& name, float& volume, float& pitch) const; std::string HoverLink() const; void Update(); void Render(); diff --git a/src/client/ui/RmlEmit.cpp b/src/client/ui/RmlEmit.cpp index 24c34b7..f36c27d 100644 --- a/src/client/ui/RmlEmit.cpp +++ b/src/client/ui/RmlEmit.cpp @@ -442,16 +442,23 @@ namespace perlin::ui { } } + namespace { + // sound_name after inheritance: common.button and toggles declare random.click, container slot buttons none + std::string SoundAttrs(const LNode& n) { + const Json* sn = n.Get("sound_name"); + if (!sn || !sn->IsString()) + return {}; + return " snd=\"" + EscapeRml(sn->string) + "\" vol=\"" + Num(static_cast(n.Num("sound_volume", 1.0))) + + "\" pit=\"" + Num(static_cast(n.Num("sound_pitch", 1.0))) + "\""; + } + } + void RmlEmitter::VisitButton(const LNode& n, RmlWriter& out) { const std::string command = ButtonCommand(n); const std::string defName = n.Str("default_control"), hoverName = n.Str("hover_control"), pressedName = n.Str("pressed_control"), lockedName = n.Str("locked_control"); const bool hasHover = FindKid(n, hoverName) != nullptr && (!command.empty() || inSlot); - std::string soundAttrs; - if (const Json* sn = n.Get("sound_name"); sn && sn->IsString()) - soundAttrs = " snd=\"" + EscapeRml(sn->string) + "\" vol=\"" + - Num(static_cast(n.Num("sound_volume", 1.0))) + "\" pit=\"" + - Num(static_cast(n.Num("sound_pitch", 1.0))) + "\""; + const std::string soundAttrs = SoundAttrs(n); out.BeginBox(n.ax, n.ay, n.w, n.h, TopLayer(n), command.empty() && !inSlot ? "" : "bt", command, false, 0.0f, command.empty() && !inSlot ? std::string() : soundAttrs); for (const auto& kid : n.kids) { @@ -515,7 +522,8 @@ namespace perlin::ui { states.push_back(std::move(name)); const std::string command = WidgetCommand(n); const bool hasHover = !hover.empty() && FindKid(n, hover) != nullptr && !command.empty(); - out.BeginBox(n.ax, n.ay, n.w, n.h, TopLayer(n), command.empty() ? "" : "bt", command, false); + out.BeginBox(n.ax, n.ay, n.w, n.h, TopLayer(n), command.empty() ? "" : "bt", command, false, 0.0f, + command.empty() ? std::string() : SoundAttrs(n)); for (const auto& kid : n.kids) { if (!kid->visible) continue;