mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
Fix minimap mute behavior and shallow-water swim trigger
This commit is contained in:
parent
dddd2a71ca
commit
e778e21f6f
3 changed files with 121 additions and 29 deletions
|
|
@ -223,6 +223,7 @@ void ActivitySoundManager::rebuildHardLandClipsForProfile(const std::string& rac
|
||||||
|
|
||||||
bool ActivitySoundManager::playOneShot(const std::vector<Sample>& clips, float volume, float pitchLo, float pitchHi) {
|
bool ActivitySoundManager::playOneShot(const std::vector<Sample>& clips, float volume, float pitchLo, float pitchHi) {
|
||||||
if (clips.empty()) return false;
|
if (clips.empty()) return false;
|
||||||
|
if (volumeScale <= 0.0001f || volume <= 0.0001f) return true; // Intentionally muted
|
||||||
reapProcesses();
|
reapProcesses();
|
||||||
if (oneShotPid != INVALID_PROCESS) return false;
|
if (oneShotPid != INVALID_PROCESS) return false;
|
||||||
|
|
||||||
|
|
@ -236,7 +237,7 @@ bool ActivitySoundManager::playOneShot(const std::vector<Sample>& clips, float v
|
||||||
std::uniform_real_distribution<float> pitchDist(pitchLo, pitchHi);
|
std::uniform_real_distribution<float> pitchDist(pitchLo, pitchHi);
|
||||||
float pitch = pitchDist(rng);
|
float pitch = pitchDist(rng);
|
||||||
volume *= volumeScale;
|
volume *= volumeScale;
|
||||||
if (volume < 0.1f) volume = 0.1f;
|
if (volume <= 0.0001f) return true; // Intentionally muted
|
||||||
if (volume > 1.2f) volume = 1.2f;
|
if (volume > 1.2f) volume = 1.2f;
|
||||||
std::string filter = "asetrate=44100*" + std::to_string(pitch) +
|
std::string filter = "asetrate=44100*" + std::to_string(pitch) +
|
||||||
",aresample=44100,volume=" + std::to_string(volume);
|
",aresample=44100,volume=" + std::to_string(volume);
|
||||||
|
|
|
||||||
|
|
@ -369,14 +369,42 @@ void CameraController::update(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!externalFollow_) {
|
if (!externalFollow_) {
|
||||||
// Check for water at current position — simple submersion test.
|
// Enter swim only when water is deep enough (waist-deep+),
|
||||||
// If the player's feet are meaningfully below the water surface, swim.
|
// not for shallow wading.
|
||||||
std::optional<float> waterH;
|
std::optional<float> waterH;
|
||||||
if (waterRenderer) {
|
if (waterRenderer) {
|
||||||
waterH = waterRenderer->getWaterHeightAt(targetPos.x, targetPos.y);
|
waterH = waterRenderer->getWaterHeightAt(targetPos.x, targetPos.y);
|
||||||
}
|
}
|
||||||
bool inWater = waterH && (targetPos.z < (*waterH - 0.3f));
|
constexpr float MAX_SWIM_DEPTH_FROM_SURFACE = 12.0f;
|
||||||
// Keep swimming through water-data gaps (chunk boundaries).
|
constexpr float MIN_SWIM_WATER_DEPTH = 1.0f;
|
||||||
|
bool inWater = false;
|
||||||
|
if (waterH && targetPos.z < *waterH) {
|
||||||
|
std::optional<uint16_t> waterType;
|
||||||
|
if (waterRenderer) {
|
||||||
|
waterType = waterRenderer->getWaterTypeAt(targetPos.x, targetPos.y);
|
||||||
|
}
|
||||||
|
bool isOcean = false;
|
||||||
|
if (waterType && *waterType != 0) {
|
||||||
|
isOcean = (((*waterType - 1) % 4) == 1);
|
||||||
|
}
|
||||||
|
bool depthAllowed = isOcean || ((*waterH - targetPos.z) <= MAX_SWIM_DEPTH_FROM_SURFACE);
|
||||||
|
if (depthAllowed) {
|
||||||
|
std::optional<float> terrainH;
|
||||||
|
std::optional<float> wmoH;
|
||||||
|
std::optional<float> m2H;
|
||||||
|
if (terrainManager) terrainH = terrainManager->getHeightAt(targetPos.x, targetPos.y);
|
||||||
|
if (wmoRenderer) wmoH = wmoRenderer->getFloorHeight(targetPos.x, targetPos.y, targetPos.z + 2.0f);
|
||||||
|
if (m2Renderer) m2H = m2Renderer->getFloorHeight(targetPos.x, targetPos.y, targetPos.z + 1.0f);
|
||||||
|
auto floorH = selectHighestFloor(terrainH, wmoH, m2H);
|
||||||
|
|
||||||
|
// Prefer measured depth from floor; if floor sample is missing,
|
||||||
|
// fall back to feet-to-surface depth.
|
||||||
|
float depthFromFeet = (*waterH - targetPos.z);
|
||||||
|
inWater = (floorH && ((*waterH - *floorH) >= MIN_SWIM_WATER_DEPTH)) ||
|
||||||
|
(!floorH && (depthFromFeet >= MIN_SWIM_WATER_DEPTH));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Keep swimming through water-data gaps at chunk boundaries.
|
||||||
if (!inWater && swimming && !waterH) {
|
if (!inWater && swimming && !waterH) {
|
||||||
inWater = true;
|
inWater = true;
|
||||||
}
|
}
|
||||||
|
|
@ -1122,7 +1150,7 @@ void CameraController::update(float deltaTime) {
|
||||||
if (wmoRenderer) wmoH = wmoRenderer->getFloorHeight(newPos.x, newPos.y, feetZ + 2.0f);
|
if (wmoRenderer) wmoH = wmoRenderer->getFloorHeight(newPos.x, newPos.y, feetZ + 2.0f);
|
||||||
if (m2Renderer && !externalFollow_) m2H = m2Renderer->getFloorHeight(newPos.x, newPos.y, feetZ + 1.0f);
|
if (m2Renderer && !externalFollow_) m2H = m2Renderer->getFloorHeight(newPos.x, newPos.y, feetZ + 1.0f);
|
||||||
auto floorH = selectHighestFloor(terrainH, wmoH, m2H);
|
auto floorH = selectHighestFloor(terrainH, wmoH, m2H);
|
||||||
constexpr float MIN_SWIM_WATER_DEPTH = 1.8f;
|
constexpr float MIN_SWIM_WATER_DEPTH = 1.0f;
|
||||||
inWater = (floorH && ((*waterH - *floorH) >= MIN_SWIM_WATER_DEPTH)) || (isOcean && !floorH);
|
inWater = (floorH && ((*waterH - *floorH) >= MIN_SWIM_WATER_DEPTH)) || (isOcean && !floorH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,8 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
||||||
if (!volumeSettingsApplied_) {
|
if (!volumeSettingsApplied_) {
|
||||||
auto* renderer = core::Application::getInstance().getRenderer();
|
auto* renderer = core::Application::getInstance().getRenderer();
|
||||||
if (renderer && renderer->getUiSoundManager()) {
|
if (renderer && renderer->getUiSoundManager()) {
|
||||||
float masterScale = static_cast<float>(pendingMasterVolume) / 100.0f;
|
float masterScale = soundMuted_ ? 0.0f : static_cast<float>(pendingMasterVolume) / 100.0f;
|
||||||
|
audio::AudioEngine::instance().setMasterVolume(soundMuted_ ? 0.0f : masterScale);
|
||||||
if (auto* music = renderer->getMusicManager()) {
|
if (auto* music = renderer->getMusicManager()) {
|
||||||
music->setVolume(static_cast<int>(pendingMusicVolume * masterScale));
|
music->setVolume(static_cast<int>(pendingMusicVolume * masterScale));
|
||||||
}
|
}
|
||||||
|
|
@ -5690,7 +5691,8 @@ void GameScreen::renderSettingsWindow() {
|
||||||
// Helper lambda to apply audio settings
|
// Helper lambda to apply audio settings
|
||||||
auto applyAudioSettings = [&]() {
|
auto applyAudioSettings = [&]() {
|
||||||
if (!renderer) return;
|
if (!renderer) return;
|
||||||
float masterScale = static_cast<float>(pendingMasterVolume) / 100.0f;
|
float masterScale = soundMuted_ ? 0.0f : static_cast<float>(pendingMasterVolume) / 100.0f;
|
||||||
|
audio::AudioEngine::instance().setMasterVolume(soundMuted_ ? 0.0f : masterScale);
|
||||||
if (auto* music = renderer->getMusicManager()) {
|
if (auto* music = renderer->getMusicManager()) {
|
||||||
music->setVolume(static_cast<int>(pendingMusicVolume * masterScale));
|
music->setVolume(static_cast<int>(pendingMusicVolume * masterScale));
|
||||||
}
|
}
|
||||||
|
|
@ -6193,33 +6195,94 @@ void GameScreen::renderMinimapMarkers(game::GameHandler& gameHandler) {
|
||||||
IM_COL32(0, 0, 0, 255), marker);
|
IM_COL32(0, 0, 0, 255), marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add zoom + mute buttons at the bottom edge of the minimap
|
auto applyMuteState = [&]() {
|
||||||
ImGui::SetNextWindowPos(ImVec2(centerX - 45, centerY + mapRadius - 30), ImGuiCond_Always);
|
auto* activeRenderer = core::Application::getInstance().getRenderer();
|
||||||
ImGui::SetNextWindowSize(ImVec2(90, 24), ImGuiCond_Always);
|
float masterScale = soundMuted_ ? 0.0f : static_cast<float>(pendingMasterVolume) / 100.0f;
|
||||||
|
audio::AudioEngine::instance().setMasterVolume(masterScale);
|
||||||
|
if (!activeRenderer) return;
|
||||||
|
if (auto* music = activeRenderer->getMusicManager()) {
|
||||||
|
music->setVolume(static_cast<int>(pendingMusicVolume * masterScale));
|
||||||
|
}
|
||||||
|
if (auto* ambient = activeRenderer->getAmbientSoundManager()) {
|
||||||
|
ambient->setVolumeScale(pendingAmbientVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
if (auto* ui = activeRenderer->getUiSoundManager()) {
|
||||||
|
ui->setVolumeScale(pendingUiVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
if (auto* combat = activeRenderer->getCombatSoundManager()) {
|
||||||
|
combat->setVolumeScale(pendingCombatVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
if (auto* spell = activeRenderer->getSpellSoundManager()) {
|
||||||
|
spell->setVolumeScale(pendingSpellVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
if (auto* movement = activeRenderer->getMovementSoundManager()) {
|
||||||
|
movement->setVolumeScale(pendingMovementVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
if (auto* footstep = activeRenderer->getFootstepManager()) {
|
||||||
|
footstep->setVolumeScale(pendingFootstepVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
if (auto* npcVoice = activeRenderer->getNpcVoiceManager()) {
|
||||||
|
npcVoice->setVolumeScale(pendingNpcVoiceVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
if (auto* mount = activeRenderer->getMountSoundManager()) {
|
||||||
|
mount->setVolumeScale(pendingMountVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
if (auto* activity = activeRenderer->getActivitySoundManager()) {
|
||||||
|
activity->setVolumeScale(pendingActivityVolume / 100.0f * masterScale);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Speaker mute button at the minimap top-right corner
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(centerX + mapRadius - 26.0f, centerY - mapRadius + 4.0f), ImGuiCond_Always);
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(22.0f, 22.0f), ImGuiCond_Always);
|
||||||
|
ImGuiWindowFlags muteFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||||
|
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoBackground;
|
||||||
|
if (ImGui::Begin("##MinimapMute", nullptr, muteFlags)) {
|
||||||
|
ImDrawList* draw = ImGui::GetWindowDrawList();
|
||||||
|
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||||
|
ImVec2 size(20.0f, 20.0f);
|
||||||
|
if (ImGui::InvisibleButton("##MinimapMuteButton", size)) {
|
||||||
|
soundMuted_ = !soundMuted_;
|
||||||
|
if (soundMuted_) {
|
||||||
|
preMuteVolume_ = audio::AudioEngine::instance().getMasterVolume();
|
||||||
|
}
|
||||||
|
applyMuteState();
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
bool hovered = ImGui::IsItemHovered();
|
||||||
|
ImU32 bg = soundMuted_ ? IM_COL32(135, 42, 42, 230) : IM_COL32(38, 38, 38, 210);
|
||||||
|
if (hovered) bg = soundMuted_ ? IM_COL32(160, 58, 58, 230) : IM_COL32(65, 65, 65, 220);
|
||||||
|
ImU32 fg = IM_COL32(255, 255, 255, 245);
|
||||||
|
draw->AddRectFilled(p, ImVec2(p.x + size.x, p.y + size.y), bg, 4.0f);
|
||||||
|
draw->AddRect(ImVec2(p.x + 0.5f, p.y + 0.5f), ImVec2(p.x + size.x - 0.5f, p.y + size.y - 0.5f),
|
||||||
|
IM_COL32(255, 255, 255, 42), 4.0f);
|
||||||
|
draw->AddRectFilled(ImVec2(p.x + 4.0f, p.y + 8.0f), ImVec2(p.x + 7.0f, p.y + 12.0f), fg, 1.0f);
|
||||||
|
draw->AddTriangleFilled(ImVec2(p.x + 7.0f, p.y + 7.0f),
|
||||||
|
ImVec2(p.x + 7.0f, p.y + 13.0f),
|
||||||
|
ImVec2(p.x + 11.8f, p.y + 10.0f), fg);
|
||||||
|
if (soundMuted_) {
|
||||||
|
draw->AddLine(ImVec2(p.x + 13.5f, p.y + 6.2f), ImVec2(p.x + 17.2f, p.y + 13.8f), fg, 1.8f);
|
||||||
|
draw->AddLine(ImVec2(p.x + 17.2f, p.y + 6.2f), ImVec2(p.x + 13.5f, p.y + 13.8f), fg, 1.8f);
|
||||||
|
} else {
|
||||||
|
draw->PathArcTo(ImVec2(p.x + 11.8f, p.y + 10.0f), 3.6f, -0.7f, 0.7f, 12);
|
||||||
|
draw->PathStroke(fg, 0, 1.4f);
|
||||||
|
draw->PathArcTo(ImVec2(p.x + 11.8f, p.y + 10.0f), 5.5f, -0.7f, 0.7f, 12);
|
||||||
|
draw->PathStroke(fg, 0, 1.2f);
|
||||||
|
}
|
||||||
|
if (hovered) ImGui::SetTooltip(soundMuted_ ? "Unmute" : "Mute");
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
// Zoom buttons at the bottom edge of the minimap
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(centerX - 22, centerY + mapRadius - 30), ImGuiCond_Always);
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(44, 24), ImGuiCond_Always);
|
||||||
ImGuiWindowFlags zoomFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
ImGuiWindowFlags zoomFlags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
|
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
|
||||||
ImGuiWindowFlags_NoBackground;
|
ImGuiWindowFlags_NoBackground;
|
||||||
if (ImGui::Begin("##MinimapZoom", nullptr, zoomFlags)) {
|
if (ImGui::Begin("##MinimapZoom", nullptr, zoomFlags)) {
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
|
||||||
|
|
||||||
// Mute toggle button: red tint when muted
|
|
||||||
if (soundMuted_) ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.7f, 0.15f, 0.15f, 0.9f));
|
|
||||||
if (ImGui::SmallButton(soundMuted_ ? "[M]" : " M ")) {
|
|
||||||
soundMuted_ = !soundMuted_;
|
|
||||||
auto& engine = audio::AudioEngine::instance();
|
|
||||||
if (soundMuted_) {
|
|
||||||
preMuteVolume_ = engine.getMasterVolume();
|
|
||||||
engine.setMasterVolume(0.0f);
|
|
||||||
} else {
|
|
||||||
engine.setMasterVolume(preMuteVolume_);
|
|
||||||
}
|
|
||||||
saveSettings();
|
|
||||||
}
|
|
||||||
if (soundMuted_) ImGui::PopStyleColor();
|
|
||||||
if (ImGui::IsItemHovered()) ImGui::SetTooltip(soundMuted_ ? "Unmute" : "Mute");
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::SmallButton("-")) {
|
if (ImGui::SmallButton("-")) {
|
||||||
if (minimap) minimap->zoomOut();
|
if (minimap) minimap->zoomOut();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue