Browse Source

Fix proximity cue tempo + interact cue

access
mojsior 2 months ago
parent
commit
31eccf43b6
  1. 73
      Source/utils/proximity_audio.cpp

73
Source/utils/proximity_audio.cpp

@ -144,6 +144,40 @@ struct InteractTarget {
return static_cast<uint32_t>(std::lround(interval));
}
void StopCueSound(const CueSound &cue)
{
for (const auto &variant : cue.variants) {
if (variant != nullptr && variant->DSB.IsLoaded())
variant->DSB.Stop();
}
}
void StopAllCuesExcept(const CueSound *cueToKeep)
{
const auto stopIfOther = [cueToKeep](const std::optional<CueSound> &cue) {
if (cue && &*cue != cueToKeep)
StopCueSound(*cue);
};
stopIfOther(WeaponItemCue);
stopIfOther(ArmorItemCue);
stopIfOther(GoldItemCue);
stopIfOther(ChestCue);
stopIfOther(DoorCue);
stopIfOther(MonsterCue);
stopIfOther(InteractCue);
}
[[nodiscard]] bool IsAnyOtherCuePlaying(const CueSound *cueToIgnore)
{
const auto isOtherPlaying = [cueToIgnore](const std::optional<CueSound> &cue) {
return cue && cue->IsAnyPlaying() && &*cue != cueToIgnore;
};
return isOtherPlaying(WeaponItemCue) || isOtherPlaying(ArmorItemCue) || isOtherPlaying(GoldItemCue) || isOtherPlaying(ChestCue) || isOtherPlaying(DoorCue)
|| isOtherPlaying(MonsterCue) || isOtherPlaying(InteractCue);
}
std::optional<CueSound> TryLoadCueSound(std::initializer_list<std::string_view> candidatePaths)
{
if (!gbSndInited)
@ -204,7 +238,20 @@ void EnsureCuesLoaded()
MonsterCue = TryLoadCueSound({ "audio\\monster.ogg", "..\\audio\\monster.ogg", "audio\\monster.wav", "..\\audio\\monster.wav", "audio\\monster.mp3", "..\\audio\\monster.mp3" });
InteractCue = TryLoadCueSound({ "audio\\interactispossible.ogg", "..\\audio\\interactispossible.ogg", "audio\\interactispossible.wav", "..\\audio\\interactispossible.wav", "audio\\interactispossible.mp3", "..\\audio\\interactispossible.mp3" });
InteractCue = TryLoadCueSound({
"audio\\interactispossible.ogg",
"audio\\interactionispossible.ogg",
"..\\audio\\interactispossible.ogg",
"..\\audio\\interactionispossible.ogg",
"audio\\interactispossible.wav",
"audio\\interactionispossible.wav",
"..\\audio\\interactispossible.wav",
"..\\audio\\interactionispossible.wav",
"audio\\interactispossible.mp3",
"audio\\interactionispossible.mp3",
"..\\audio\\interactispossible.mp3",
"..\\audio\\interactionispossible.mp3",
});
loaded = true;
}
@ -223,8 +270,8 @@ void EnsureCuesLoaded()
if (!gbSndInited || !gbSoundOn)
return false;
// Proximity cues are meant to guide the player; overlapping the same cue can create audio glitches/noise.
if (cue.IsAnyPlaying())
// Allow the same cue to restart (for tempo control), but don't overlap different cue types.
if (IsAnyOtherCuePlaying(&cue))
return false;
int logVolume = 0;
@ -242,6 +289,15 @@ void EnsureCuesLoaded()
if (snd == nullptr || !snd->DSB.IsLoaded())
return false;
// Restart the cue if it's already playing so we can control tempo based on distance.
// Stop all variants to avoid overlaps when pitch levels are enabled.
if (cue.IsAnyPlaying()) {
for (const auto &variant : cue.variants) {
if (variant != nullptr && variant->DSB.IsLoaded())
variant->DSB.Stop();
}
}
snd_play_snd(snd, logVolume, logPan);
return true;
}
@ -554,6 +610,13 @@ std::optional<InteractTarget> FindInteractTargetInRange(const Player &player, Po
}
}
// Make the interact cue reliably audible even when another proximity cue is playing.
// (The new distance-based tempo restarts cues frequently.)
StopAllCuesExcept(InteractCue ? &*InteractCue : nullptr);
if (!InteractCue || !InteractCue->IsLoaded())
return true;
if (!PlayCueAt(*InteractCue, target->position, /*distance=*/0, /*maxDistance=*/1))
return true;
(void)now;
@ -578,10 +641,6 @@ void UpdateProximityAudioCues()
const uint32_t now = SDL_GetTicks();
const Point playerPosition { MyPlayer->position.future };
// Don't start another cue while one is playing (helps avoid overlap-related stutter/noise).
if (IsAnyCuePlaying())
return;
// Keep cues readable and reduce overlap/glitches by playing at most one per tick (priority order).
if (UpdateInteractCue(playerPosition, now))
return;

Loading…
Cancel
Save