Browse Source

Add melee monster TTS and audio cues volume

access
mojsior 2 months ago
parent
commit
114b5793ee
  1. 75
      Source/diablo.cpp
  2. 51
      Source/engine/sound.cpp
  3. 9
      Source/engine/sound.h
  4. 11
      Source/engine/sound_pool.cpp
  5. 11
      Source/engine/sound_stubs.cpp
  6. 221
      Source/gamemenu.cpp
  7. 36
      Source/options.cpp
  8. 22
      Source/options.h

75
Source/diablo.cpp

@ -1901,6 +1901,80 @@ void UpdateBossHealthAnnouncements()
} }
} }
void UpdateAttackableMonsterAnnouncements()
{
static std::optional<int> LastAttackableMonsterId;
if (MyPlayer == nullptr) {
LastAttackableMonsterId = std::nullopt;
return;
}
if (leveltype == DTYPE_TOWN) {
LastAttackableMonsterId = std::nullopt;
return;
}
if (MyPlayerIsDead || MyPlayer->_pmode == PM_DEATH || MyPlayer->hasNoLife()) {
LastAttackableMonsterId = std::nullopt;
return;
}
if (InGameMenu() || invflag) {
LastAttackableMonsterId = std::nullopt;
return;
}
const Player &player = *MyPlayer;
const Point playerPosition = player.position.tile;
int bestRotations = 5;
std::optional<int> bestId;
for (size_t i = 0; i < ActiveMonsterCount; i++) {
const int monsterId = static_cast<int>(ActiveMonsters[i]);
const Monster &monster = Monsters[monsterId];
if (monster.isInvalid)
continue;
if ((monster.flags & MFLAG_HIDDEN) != 0)
continue;
if (monster.hitPoints <= 0)
continue;
if (monster.isPlayerMinion())
continue;
if (!monster.isPossibleToHit())
continue;
const Point monsterPosition = monster.position.tile;
if (playerPosition.WalkingDistance(monsterPosition) > 1)
continue;
const int d1 = static_cast<int>(player._pdir);
const int d2 = static_cast<int>(GetDirection(playerPosition, monsterPosition));
int rotations = std::abs(d1 - d2);
if (rotations > 4)
rotations = 4 - (rotations % 4);
if (!bestId || rotations < bestRotations || (rotations == bestRotations && monsterId < *bestId)) {
bestRotations = rotations;
bestId = monsterId;
}
}
if (!bestId) {
LastAttackableMonsterId = std::nullopt;
return;
}
if (LastAttackableMonsterId && *LastAttackableMonsterId == *bestId)
return;
LastAttackableMonsterId = *bestId;
const std::string_view name = Monsters[*bestId].name();
if (!name.empty())
SpeakText(name, /*force=*/true);
}
void GameLogic() void GameLogic()
{ {
if (!ProcessInput()) { if (!ProcessInput()) {
@ -1929,6 +2003,7 @@ void GameLogic()
ProcessVisionList(); ProcessVisionList();
UpdateBossHealthAnnouncements(); UpdateBossHealthAnnouncements();
UpdateProximityAudioCues(); UpdateProximityAudioCues();
UpdateAttackableMonsterAnnouncements();
} else { } else {
gGameLogicStep = GameLogicStep::ProcessTowners; gGameLogicStep = GameLogicStep::ProcessTowners;
ProcessTowners(); ProcessTowners();

51
Source/engine/sound.cpp

@ -244,11 +244,12 @@ TSnd::~TSnd()
DSB.Release(); DSB.Release();
} }
void snd_init() void snd_init()
{ {
GetOptions().Audio.soundVolume.SetValue(CapVolume(*GetOptions().Audio.soundVolume)); GetOptions().Audio.soundVolume.SetValue(CapVolume(*GetOptions().Audio.soundVolume));
gbSoundOn = *GetOptions().Audio.soundVolume > VOLUME_MIN; GetOptions().Audio.audioCuesVolume.SetValue(CapVolume(*GetOptions().Audio.audioCuesVolume));
sgbSaveSoundOn = gbSoundOn; gbSoundOn = *GetOptions().Audio.soundVolume > VOLUME_MIN;
sgbSaveSoundOn = gbSoundOn;
GetOptions().Audio.musicVolume.SetValue(CapVolume(*GetOptions().Audio.musicVolume)); GetOptions().Audio.musicVolume.SetValue(CapVolume(*GetOptions().Audio.musicVolume));
gbMusicOn = *GetOptions().Audio.musicVolume > VOLUME_MIN; gbMusicOn = *GetOptions().Audio.musicVolume > VOLUME_MIN;
@ -381,21 +382,31 @@ int sound_get_or_set_music_volume(int volume)
return *GetOptions().Audio.musicVolume; return *GetOptions().Audio.musicVolume;
} }
int sound_get_or_set_sound_volume(int volume) int sound_get_or_set_sound_volume(int volume)
{ {
if (volume == 1) if (volume == 1)
return *GetOptions().Audio.soundVolume; return *GetOptions().Audio.soundVolume;
GetOptions().Audio.soundVolume.SetValue(volume); GetOptions().Audio.soundVolume.SetValue(volume);
return *GetOptions().Audio.soundVolume; return *GetOptions().Audio.soundVolume;
} }
void music_mute() int sound_get_or_set_audio_cues_volume(int volume)
{ {
if (music.IsLoaded()) if (volume == 1)
music.Mute(); return *GetOptions().Audio.audioCuesVolume;
}
GetOptions().Audio.audioCuesVolume.SetValue(volume);
return *GetOptions().Audio.audioCuesVolume;
}
void music_mute()
{
if (music.IsLoaded())
music.Mute();
}
void music_unmute() void music_unmute()
{ {

9
Source/engine/sound.h

@ -73,10 +73,11 @@ _music_id GetLevelMusic(dungeon_type dungeonType);
void music_stop(); void music_stop();
void music_start(_music_id nTrack); void music_start(_music_id nTrack);
void sound_disable_music(bool disable); void sound_disable_music(bool disable);
int sound_get_or_set_music_volume(int volume); int sound_get_or_set_music_volume(int volume);
int sound_get_or_set_sound_volume(int volume); int sound_get_or_set_sound_volume(int volume);
void music_mute(); int sound_get_or_set_audio_cues_volume(int volume);
void music_unmute(); void music_mute();
void music_unmute();
/* data */ /* data */

11
Source/engine/sound_pool.cpp

@ -116,7 +116,16 @@ struct SoundPool::Impl {
if (sample.IsPlaying()) if (sample.IsPlaying())
sample.Stop(); sample.Stop();
return sample.PlayWithVolumeAndPan(logVolume, sound_get_or_set_sound_volume(/*volume=*/1), logPan); const int soundVolume = sound_get_or_set_sound_volume(/*volume=*/1);
const int cuesVolume = sound_get_or_set_audio_cues_volume(/*volume=*/1);
const int range = VOLUME_MAX - VOLUME_MIN;
const int soundOffset = std::clamp(soundVolume - VOLUME_MIN, 0, range);
const int cuesOffset = std::clamp(cuesVolume - VOLUME_MIN, 0, range);
const int combinedOffset = (soundOffset * cuesOffset + range / 2) / range;
const int combinedVolume = VOLUME_MIN + combinedOffset;
return sample.PlayWithVolumeAndPan(logVolume, combinedVolume, logPan);
} }
}; };

11
Source/engine/sound_stubs.cpp

@ -18,10 +18,11 @@ void snd_deinit() { }
void music_stop() { } void music_stop() { }
void music_start(_music_id nTrack) { } void music_start(_music_id nTrack) { }
void sound_disable_music(bool disable) { } void sound_disable_music(bool disable) { }
int sound_get_or_set_music_volume(int volume) { return 0; } int sound_get_or_set_music_volume(int volume) { return 0; }
int sound_get_or_set_sound_volume(int volume) { return 0; } int sound_get_or_set_sound_volume(int volume) { return 0; }
void music_mute() { } int sound_get_or_set_audio_cues_volume(int volume) { return 0; }
void music_unmute() { } void music_mute() { }
_music_id GetLevelMusic(dungeon_type dungeonType) { return TMUSIC_TOWN; } void music_unmute() { }
_music_id GetLevelMusic(dungeon_type dungeonType) { return TMUSIC_TOWN; }
} // namespace devilution } // namespace devilution

221
Source/gamemenu.cpp

@ -39,11 +39,12 @@ namespace {
// Forward-declare menu handlers, used by the global menu structs below. // Forward-declare menu handlers, used by the global menu structs below.
void GamemenuPrevious(bool bActivate); void GamemenuPrevious(bool bActivate);
void GamemenuNewGame(bool bActivate); void GamemenuNewGame(bool bActivate);
void GamemenuOptions(bool bActivate); void GamemenuOptions(bool bActivate);
void GamemenuMusicVolume(bool bActivate); void GamemenuMusicVolume(bool bActivate);
void GamemenuSoundVolume(bool bActivate); void GamemenuSoundVolume(bool bActivate);
void GamemenuBrightness(bool bActivate); void GamemenuAudioCuesVolume(bool bActivate);
void GamemenuSpeed(bool bActivate); void GamemenuBrightness(bool bActivate);
void GamemenuSpeed(bool bActivate);
/** Contains the game menu items of the single player menu. */ /** Contains the game menu items of the single player menu. */
TMenuItem sgSingleMenu[] = { TMenuItem sgSingleMenu[] = {
@ -67,27 +68,33 @@ TMenuItem sgMultiMenu[] = {
{ GMENU_ENABLED, nullptr, nullptr }, { GMENU_ENABLED, nullptr, nullptr },
// clang-format on // clang-format on
}; };
TMenuItem sgOptionsMenu[] = { TMenuItem sgOptionsMenu[] = {
// clang-format off // clang-format off
// dwFlags, pszStr, fnMenu // dwFlags, pszStr, fnMenu
{ GMENU_ENABLED | GMENU_SLIDER, nullptr, &GamemenuMusicVolume }, { GMENU_ENABLED | GMENU_SLIDER, nullptr, &GamemenuMusicVolume },
{ GMENU_ENABLED | GMENU_SLIDER, nullptr, &GamemenuSoundVolume }, { GMENU_ENABLED | GMENU_SLIDER, nullptr, &GamemenuSoundVolume },
{ GMENU_ENABLED | GMENU_SLIDER, N_("Gamma"), &GamemenuBrightness }, { GMENU_ENABLED | GMENU_SLIDER, nullptr, &GamemenuAudioCuesVolume },
{ GMENU_ENABLED | GMENU_SLIDER, N_("Speed"), &GamemenuSpeed }, { GMENU_ENABLED | GMENU_SLIDER, N_("Gamma"), &GamemenuBrightness },
{ GMENU_ENABLED , N_("Previous Menu"), &GamemenuPrevious }, { GMENU_ENABLED | GMENU_SLIDER, N_("Speed"), &GamemenuSpeed },
{ GMENU_ENABLED , nullptr, nullptr }, { GMENU_ENABLED , N_("Previous Menu"), &GamemenuPrevious },
// clang-format on { GMENU_ENABLED , nullptr, nullptr },
}; // clang-format on
/** Specifies the menu names for music enabled and disabled. */ };
const char *const MusicToggleNames[] = { /** Specifies the menu names for music enabled and disabled. */
N_("Music"), const char *const MusicToggleNames[] = {
N_("Music Disabled"), N_("Music"),
N_("Music Disabled"),
}; };
/** Specifies the menu names for sound enabled and disabled. */ /** Specifies the menu names for sound enabled and disabled. */
const char *const SoundToggleNames[] = { const char *const SoundToggleNames[] = {
N_("Sound"), N_("Sound"),
N_("Sound Disabled"), N_("Sound Disabled"),
}; };
/** Specifies the menu names for navigation audio cues enabled and disabled. */
const char *const AudioCuesToggleNames[] = {
N_("Audio Cues"),
N_("Audio Cues Disabled"),
};
void GamemenuUpdateSingle() void GamemenuUpdateSingle()
{ {
@ -144,52 +151,58 @@ void GamemenuGetMusic()
GamemenuSoundMusicToggle(MusicToggleNames, sgOptionsMenu, sound_get_or_set_music_volume(1)); GamemenuSoundMusicToggle(MusicToggleNames, sgOptionsMenu, sound_get_or_set_music_volume(1));
} }
void GamemenuGetSound() void GamemenuGetSound()
{ {
GamemenuSoundMusicToggle(SoundToggleNames, &sgOptionsMenu[1], sound_get_or_set_sound_volume(1)); GamemenuSoundMusicToggle(SoundToggleNames, &sgOptionsMenu[1], sound_get_or_set_sound_volume(1));
} }
void GamemenuGetBrightness() void GamemenuGetAudioCues()
{ {
gmenu_slider_steps(&sgOptionsMenu[2], 21); GamemenuSoundMusicToggle(AudioCuesToggleNames, &sgOptionsMenu[2], sound_get_or_set_audio_cues_volume(1));
gmenu_slider_set(&sgOptionsMenu[2], 0, 100, UpdateBrightness(-1)); }
}
void GamemenuGetBrightness()
void GamemenuGetSpeed() {
{ gmenu_slider_steps(&sgOptionsMenu[3], 21);
if (gbIsMultiplayer) { gmenu_slider_set(&sgOptionsMenu[3], 0, 100, UpdateBrightness(-1));
sgOptionsMenu[3].removeFlags(GMENU_ENABLED | GMENU_SLIDER); }
if (sgGameInitInfo.nTickRate >= 50)
sgOptionsMenu[3].pszStr = _("Speed: Fastest").data(); void GamemenuGetSpeed()
else if (sgGameInitInfo.nTickRate >= 40) {
sgOptionsMenu[3].pszStr = _("Speed: Faster").data(); if (gbIsMultiplayer) {
else if (sgGameInitInfo.nTickRate >= 30) sgOptionsMenu[4].removeFlags(GMENU_ENABLED | GMENU_SLIDER);
sgOptionsMenu[3].pszStr = _("Speed: Fast").data(); if (sgGameInitInfo.nTickRate >= 50)
else if (sgGameInitInfo.nTickRate == 20) sgOptionsMenu[4].pszStr = _("Speed: Fastest").data();
sgOptionsMenu[3].pszStr = _("Speed: Normal").data(); else if (sgGameInitInfo.nTickRate >= 40)
return; sgOptionsMenu[4].pszStr = _("Speed: Faster").data();
} else if (sgGameInitInfo.nTickRate >= 30)
sgOptionsMenu[4].pszStr = _("Speed: Fast").data();
sgOptionsMenu[3].addFlags(GMENU_ENABLED | GMENU_SLIDER); else if (sgGameInitInfo.nTickRate == 20)
sgOptionsMenu[4].pszStr = _("Speed: Normal").data();
sgOptionsMenu[3].pszStr = _("Speed").data(); return;
gmenu_slider_steps(&sgOptionsMenu[3], 46); }
gmenu_slider_set(&sgOptionsMenu[3], 20, 50, sgGameInitInfo.nTickRate);
} sgOptionsMenu[4].addFlags(GMENU_ENABLED | GMENU_SLIDER);
int GamemenuSliderBrightness() sgOptionsMenu[4].pszStr = _("Speed").data();
{ gmenu_slider_steps(&sgOptionsMenu[4], 46);
return gmenu_slider_get(&sgOptionsMenu[2], 0, 100); gmenu_slider_set(&sgOptionsMenu[4], 20, 50, sgGameInitInfo.nTickRate);
} }
void GamemenuOptions(bool /*bActivate*/) int GamemenuSliderBrightness()
{ {
GamemenuGetMusic(); return gmenu_slider_get(&sgOptionsMenu[3], 0, 100);
GamemenuGetSound(); }
GamemenuGetBrightness();
GamemenuGetSpeed(); void GamemenuOptions(bool /*bActivate*/)
gmenu_set_items(sgOptionsMenu, nullptr); {
} GamemenuGetMusic();
GamemenuGetSound();
GamemenuGetAudioCues();
GamemenuGetBrightness();
GamemenuGetSpeed();
gmenu_set_items(sgOptionsMenu, nullptr);
}
void GamemenuMusicVolume(bool bActivate) void GamemenuMusicVolume(bool bActivate)
{ {
@ -220,10 +233,10 @@ void GamemenuMusicVolume(bool bActivate)
GamemenuGetMusic(); GamemenuGetMusic();
} }
void GamemenuSoundVolume(bool bActivate) void GamemenuSoundVolume(bool bActivate)
{ {
if (bActivate) { if (bActivate) {
if (gbSoundOn) { if (gbSoundOn) {
gbSoundOn = false; gbSoundOn = false;
sound_stop(); sound_stop();
sound_get_or_set_sound_volume(VOLUME_MIN); sound_get_or_set_sound_volume(VOLUME_MIN);
@ -243,35 +256,49 @@ void GamemenuSoundVolume(bool bActivate)
gbSoundOn = true; gbSoundOn = true;
} }
} }
PlaySFX(SfxID::MenuMove); PlaySFX(SfxID::MenuMove);
GamemenuGetSound(); GamemenuGetSound();
} }
void GamemenuBrightness(bool bActivate) void GamemenuAudioCuesVolume(bool bActivate)
{ {
int brightness; if (bActivate) {
if (bActivate) { const int volume = sound_get_or_set_audio_cues_volume(1) == VOLUME_MIN ? VOLUME_MAX : VOLUME_MIN;
sound_get_or_set_audio_cues_volume(volume);
} else {
const int volume = GamemenuSliderMusicSound(&sgOptionsMenu[2]);
sound_get_or_set_audio_cues_volume(volume);
}
PlaySFX(SfxID::MenuMove);
GamemenuGetAudioCues();
}
void GamemenuBrightness(bool bActivate)
{
int brightness;
if (bActivate) {
brightness = UpdateBrightness(-1); brightness = UpdateBrightness(-1);
brightness = (brightness == 0) ? 100 : 0; brightness = (brightness == 0) ? 100 : 0;
} else { } else {
brightness = GamemenuSliderBrightness(); brightness = GamemenuSliderBrightness();
} }
UpdateBrightness(brightness); UpdateBrightness(brightness);
GamemenuGetBrightness(); GamemenuGetBrightness();
} }
void GamemenuSpeed(bool bActivate) void GamemenuSpeed(bool bActivate)
{ {
if (bActivate) { if (bActivate) {
if (sgGameInitInfo.nTickRate != 20) if (sgGameInitInfo.nTickRate != 20)
sgGameInitInfo.nTickRate = 20; sgGameInitInfo.nTickRate = 20;
else else
sgGameInitInfo.nTickRate = 50; sgGameInitInfo.nTickRate = 50;
gmenu_slider_set(&sgOptionsMenu[3], 20, 50, sgGameInitInfo.nTickRate); gmenu_slider_set(&sgOptionsMenu[4], 20, 50, sgGameInitInfo.nTickRate);
} else { } else {
sgGameInitInfo.nTickRate = gmenu_slider_get(&sgOptionsMenu[3], 20, 50); sgGameInitInfo.nTickRate = gmenu_slider_get(&sgOptionsMenu[4], 20, 50);
} }
GetOptions().Gameplay.tickRate.SetValue(sgGameInitInfo.nTickRate); GetOptions().Gameplay.tickRate.SetValue(sgGameInitInfo.nTickRate);
gnTickDelay = 1000 / sgGameInitInfo.nTickRate; gnTickDelay = 1000 / sgGameInitInfo.nTickRate;

36
Source/options.cpp

@ -508,28 +508,30 @@ std::vector<OptionEntryBase *> HellfireOptions::GetEntries()
}; };
} }
AudioOptions::AudioOptions() AudioOptions::AudioOptions()
: OptionCategoryBase("Audio", N_("Audio"), N_("Audio Settings")) : OptionCategoryBase("Audio", N_("Audio"), N_("Audio Settings"))
, soundVolume("Sound Volume", OptionEntryFlags::Invisible, "Sound Volume", "Movie and SFX volume.", VOLUME_MAX) , soundVolume("Sound Volume", OptionEntryFlags::Invisible, "Sound Volume", "Movie and SFX volume.", VOLUME_MAX)
, musicVolume("Music Volume", OptionEntryFlags::Invisible, "Music Volume", "Music Volume.", VOLUME_MAX) , audioCuesVolume("Audio Cues Volume", OptionEntryFlags::Invisible, "Audio Cues Volume", "Navigation audio cues volume.", VOLUME_MAX)
, walkingSound("Walking Sound", OptionEntryFlags::None, N_("Walking Sound"), N_("Player emits sound when walking."), true) , musicVolume("Music Volume", OptionEntryFlags::Invisible, "Music Volume", "Music Volume.", VOLUME_MAX)
, autoEquipSound("Auto Equip Sound", OptionEntryFlags::None, N_("Auto Equip Sound"), N_("Automatically equipping items on pickup emits the equipment sound."), false) , walkingSound("Walking Sound", OptionEntryFlags::None, N_("Walking Sound"), N_("Player emits sound when walking."), true)
, itemPickupSound("Item Pickup Sound", OptionEntryFlags::None, N_("Item Pickup Sound"), N_("Picking up items emits the items pickup sound."), false) , autoEquipSound("Auto Equip Sound", OptionEntryFlags::None, N_("Auto Equip Sound"), N_("Automatically equipping items on pickup emits the equipment sound."), false)
, sampleRate("Sample Rate", OptionEntryFlags::CantChangeInGame, N_("Sample Rate"), N_("Output sample rate (Hz)."), DEFAULT_AUDIO_SAMPLE_RATE, { 22050, 44100, 48000 }) , itemPickupSound("Item Pickup Sound", OptionEntryFlags::None, N_("Item Pickup Sound"), N_("Picking up items emits the items pickup sound."), false)
, sampleRate("Sample Rate", OptionEntryFlags::CantChangeInGame, N_("Sample Rate"), N_("Output sample rate (Hz)."), DEFAULT_AUDIO_SAMPLE_RATE, { 22050, 44100, 48000 })
, channels("Channels", OptionEntryFlags::CantChangeInGame, N_("Channels"), N_("Number of output channels."), DEFAULT_AUDIO_CHANNELS, { 1, 2 }) , channels("Channels", OptionEntryFlags::CantChangeInGame, N_("Channels"), N_("Number of output channels."), DEFAULT_AUDIO_CHANNELS, { 1, 2 })
, bufferSize("Buffer Size", OptionEntryFlags::CantChangeInGame, N_("Buffer Size"), N_("Buffer size (number of frames per channel)."), DEFAULT_AUDIO_BUFFER_SIZE, { 1024, 2048, 5120 }) , bufferSize("Buffer Size", OptionEntryFlags::CantChangeInGame, N_("Buffer Size"), N_("Buffer size (number of frames per channel)."), DEFAULT_AUDIO_BUFFER_SIZE, { 1024, 2048, 5120 })
, resamplingQuality("Resampling Quality", OptionEntryFlags::CantChangeInGame, N_("Resampling Quality"), N_("Quality of the resampler, from 0 (lowest) to 5 (highest)."), DEFAULT_AUDIO_RESAMPLING_QUALITY, { 0, 1, 2, 3, 4, 5 }) , resamplingQuality("Resampling Quality", OptionEntryFlags::CantChangeInGame, N_("Resampling Quality"), N_("Quality of the resampler, from 0 (lowest) to 5 (highest)."), DEFAULT_AUDIO_RESAMPLING_QUALITY, { 0, 1, 2, 3, 4, 5 })
{ {
} }
std::vector<OptionEntryBase *> AudioOptions::GetEntries() std::vector<OptionEntryBase *> AudioOptions::GetEntries()
{ {
// clang-format off // clang-format off
return { return {
&soundVolume, &soundVolume,
&musicVolume, &audioCuesVolume,
&walkingSound, &musicVolume,
&autoEquipSound, &walkingSound,
&itemPickupSound, &autoEquipSound,
&itemPickupSound,
&sampleRate, &sampleRate,
&channels, &channels,
&bufferSize, &bufferSize,

22
Source/options.h

@ -481,16 +481,18 @@ struct HellfireOptions : OptionCategoryBase {
OptionEntryInt<std::uint32_t> lastMultiplayerHero; OptionEntryInt<std::uint32_t> lastMultiplayerHero;
}; };
struct AudioOptions : OptionCategoryBase { struct AudioOptions : OptionCategoryBase {
AudioOptions(); AudioOptions();
std::vector<OptionEntryBase *> GetEntries() override; std::vector<OptionEntryBase *> GetEntries() override;
/** @brief Movie and SFX volume. */ /** @brief Movie and SFX volume. */
OptionEntryInt<int> soundVolume; OptionEntryInt<int> soundVolume;
/** @brief Music volume. */ /** @brief Navigation audio cues volume. */
OptionEntryInt<int> musicVolume; OptionEntryInt<int> audioCuesVolume;
/** @brief Player emits sound when walking. */ /** @brief Music volume. */
OptionEntryBoolean walkingSound; OptionEntryInt<int> musicVolume;
/** @brief Player emits sound when walking. */
OptionEntryBoolean walkingSound;
/** @brief Automatically equipping items on pickup emits the equipment sound. */ /** @brief Automatically equipping items on pickup emits the equipment sound. */
OptionEntryBoolean autoEquipSound; OptionEntryBoolean autoEquipSound;
/** @brief Picking up items emits the items pickup sound. */ /** @brief Picking up items emits the items pickup sound. */

Loading…
Cancel
Save