|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <cstddef>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <forward_list>
|
|
|
|
|
#include <optional>
|
|
|
|
|
#include <string_view>
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
|
|
|
#include <SDL_version.h>
|
|
|
|
|
|
|
|
|
|
#include "controls/controller.h"
|
|
|
|
|
#include "controls/controller_buttons.h"
|
|
|
|
|
#include "controls/game_controls.h"
|
|
|
|
|
#include "engine/sound_defs.hpp"
|
|
|
|
|
#include "pack.h"
|
|
|
|
|
#include "utils/enum_traits.h"
|
|
|
|
|
|
|
|
|
|
namespace devilution {
|
|
|
|
|
|
|
|
|
|
enum class StartUpGameMode : uint8_t {
|
|
|
|
|
/** @brief If hellfire is present, asks the user what game they want to start. */
|
|
|
|
|
Ask = 0,
|
|
|
|
|
Hellfire = 1,
|
|
|
|
|
Diablo = 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class StartUpIntro : uint8_t {
|
|
|
|
|
Off = 0,
|
|
|
|
|
Once = 1,
|
|
|
|
|
On = 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** @brief Defines what splash screen should be shown at startup. */
|
|
|
|
|
enum class StartUpSplash : uint8_t {
|
|
|
|
|
/** @brief Show no splash screen. */
|
|
|
|
|
None = 0,
|
|
|
|
|
/** @brief Show only TitleDialog. */
|
|
|
|
|
TitleDialog = 1,
|
|
|
|
|
/** @brief Show Logo and TitleDialog. */
|
|
|
|
|
LogoAndTitleDialog = 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class ScalingQuality : uint8_t {
|
|
|
|
|
NearestPixel,
|
|
|
|
|
BilinearFiltering,
|
|
|
|
|
AnisotropicFiltering,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class Resampler : uint8_t {
|
|
|
|
|
#ifdef DEVILUTIONX_RESAMPLER_SPEEX
|
|
|
|
|
Speex = 0,
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef DVL_AULIB_SUPPORTS_SDL_RESAMPLER
|
|
|
|
|
SDL,
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::string_view ResamplerToString(Resampler resampler);
|
|
|
|
|
std::optional<Resampler> ResamplerFromString(std::string_view resampler);
|
|
|
|
|
|
|
|
|
|
enum class FloatingNumbers : uint8_t {
|
|
|
|
|
/** @brief Show no floating numbers. */
|
|
|
|
|
Off = 0,
|
|
|
|
|
/** @brief Show floating numbers at random angles. */
|
|
|
|
|
Random = 1,
|
|
|
|
|
/** @brief Show floating numbers vertically only. */
|
|
|
|
|
Vertical = 2,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class OptionEntryType : uint8_t {
|
|
|
|
|
Boolean,
|
|
|
|
|
List,
|
|
|
|
|
Key,
|
|
|
|
|
PadButton,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class OptionEntryFlags : uint8_t {
|
|
|
|
|
/** @brief No special logic. */
|
|
|
|
|
None = 0,
|
|
|
|
|
/** @brief Shouldn't be shown in settings dialog. */
|
|
|
|
|
Invisible = 1 << 0,
|
|
|
|
|
/** @brief Need to restart the current running game (single- or multiplayer) to take effect. */
|
|
|
|
|
CantChangeInGame = 1 << 1,
|
|
|
|
|
/** @brief Need to restart the current running multiplayer game to take effect. */
|
|
|
|
|
CantChangeInMultiPlayer = 1 << 2,
|
|
|
|
|
/** @brief Option is only relevant for Hellfire. */
|
|
|
|
|
OnlyHellfire = 1 << 3,
|
|
|
|
|
/** @brief Option is only relevant for Diablo. */
|
|
|
|
|
OnlyDiablo = 1 << 4,
|
|
|
|
|
/** @brief After option is changed the UI needs to be recreated. */
|
|
|
|
|
RecreateUI = 1 << 5,
|
|
|
|
|
/** @brief diablo.mpq must be present. */
|
|
|
|
|
NeedDiabloMpq = 1 << 6,
|
|
|
|
|
/** @brief hellfire.mpq must be present. */
|
|
|
|
|
NeedHellfireMpq = 1 << 7,
|
|
|
|
|
};
|
|
|
|
|
use_enum_as_flags(OptionEntryFlags);
|
|
|
|
|
|
|
|
|
|
class OptionEntryBase {
|
|
|
|
|
public:
|
|
|
|
|
OptionEntryBase(std::string_view key, OptionEntryFlags flags, const char *name, const char *description)
|
|
|
|
|
: flags(flags)
|
|
|
|
|
, key(key)
|
|
|
|
|
, name(name)
|
|
|
|
|
, description(description)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
[[nodiscard]] virtual std::string_view GetName() const;
|
|
|
|
|
[[nodiscard]] std::string_view GetDescription() const;
|
|
|
|
|
[[nodiscard]] virtual OptionEntryType GetType() const = 0;
|
|
|
|
|
[[nodiscard]] OptionEntryFlags GetFlags() const;
|
|
|
|
|
|
|
|
|
|
void SetValueChangedCallback(std::function<void()> callback);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] virtual std::string_view GetValueDescription() const = 0;
|
|
|
|
|
virtual void LoadFromIni(std::string_view category) = 0;
|
|
|
|
|
virtual void SaveToIni(std::string_view category) const = 0;
|
|
|
|
|
|
|
|
|
|
OptionEntryFlags flags;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
std::string_view key;
|
|
|
|
|
const char *name;
|
|
|
|
|
const char *description;
|
|
|
|
|
void NotifyValueChanged();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::function<void()> callback;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class OptionEntryBoolean : public OptionEntryBase {
|
|
|
|
|
public:
|
|
|
|
|
OptionEntryBoolean(std::string_view key, OptionEntryFlags flags, const char *name, const char *description, bool defaultValue)
|
|
|
|
|
: OptionEntryBase(key, flags, name, description)
|
|
|
|
|
, defaultValue(defaultValue)
|
|
|
|
|
, value(defaultValue)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
[[nodiscard]] bool operator*() const
|
|
|
|
|
{
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
void SetValue(bool value);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] OptionEntryType GetType() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetValueDescription() const override;
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
bool defaultValue;
|
|
|
|
|
bool value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class OptionEntryListBase : public OptionEntryBase {
|
|
|
|
|
public:
|
|
|
|
|
[[nodiscard]] virtual size_t GetListSize() const = 0;
|
|
|
|
|
[[nodiscard]] virtual std::string_view GetListDescription(size_t index) const = 0;
|
|
|
|
|
[[nodiscard]] virtual size_t GetActiveListIndex() const = 0;
|
|
|
|
|
virtual void SetActiveListIndex(size_t index) = 0;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] OptionEntryType GetType() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetValueDescription() const override;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
OptionEntryListBase(std::string_view key, OptionEntryFlags flags, const char *name, const char *description)
|
|
|
|
|
: OptionEntryBase(key, flags, name, description)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class OptionEntryEnumBase : public OptionEntryListBase {
|
|
|
|
|
public:
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] size_t GetListSize() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetListDescription(size_t index) const override;
|
|
|
|
|
[[nodiscard]] size_t GetActiveListIndex() const override;
|
|
|
|
|
void SetActiveListIndex(size_t index) override;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
OptionEntryEnumBase(std::string_view key, OptionEntryFlags flags, const char *name, const char *description, int defaultValue)
|
|
|
|
|
: OptionEntryListBase(key, flags, name, description)
|
|
|
|
|
, defaultValue(defaultValue)
|
|
|
|
|
, value(defaultValue)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] int GetValueInternal() const
|
|
|
|
|
{
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
void SetValueInternal(int value);
|
|
|
|
|
|
|
|
|
|
void AddEntry(int value, std::string_view name);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
int defaultValue;
|
|
|
|
|
int value;
|
|
|
|
|
std::vector<std::string_view> entryNames;
|
|
|
|
|
std::vector<int> entryValues;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
class OptionEntryEnum : public OptionEntryEnumBase {
|
|
|
|
|
public:
|
|
|
|
|
OptionEntryEnum(std::string_view key, OptionEntryFlags flags, const char *name, const char *description, T defaultValue, std::initializer_list<std::pair<T, std::string_view>> entries)
|
|
|
|
|
: OptionEntryEnumBase(key, flags, name, description, static_cast<int>(defaultValue))
|
|
|
|
|
{
|
|
|
|
|
for (auto &&[key, value] : entries) {
|
|
|
|
|
AddEntry(static_cast<int>(key), value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[[nodiscard]] T operator*() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<T>(GetValueInternal());
|
|
|
|
|
}
|
|
|
|
|
void SetValue(T value)
|
|
|
|
|
{
|
|
|
|
|
SetValueInternal(static_cast<int>(value));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class OptionEntryIntBase : public OptionEntryListBase {
|
|
|
|
|
public:
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] size_t GetListSize() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetListDescription(size_t index) const override;
|
|
|
|
|
[[nodiscard]] size_t GetActiveListIndex() const override;
|
|
|
|
|
void SetActiveListIndex(size_t index) override;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
OptionEntryIntBase(std::string_view key, OptionEntryFlags flags, const char *name, const char *description, int defaultValue)
|
|
|
|
|
: OptionEntryListBase(key, flags, name, description)
|
|
|
|
|
, defaultValue(defaultValue)
|
|
|
|
|
, value(defaultValue)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] int GetValueInternal() const
|
|
|
|
|
{
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
void SetValueInternal(int value);
|
|
|
|
|
|
|
|
|
|
void AddEntry(int value);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
int defaultValue;
|
|
|
|
|
int value;
|
|
|
|
|
mutable std::vector<std::string> entryNames;
|
|
|
|
|
std::vector<int> entryValues;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
class OptionEntryInt : public OptionEntryIntBase {
|
|
|
|
|
public:
|
|
|
|
|
OptionEntryInt(std::string_view key, OptionEntryFlags flags, const char *name, const char *description, T defaultValue, std::initializer_list<T> entries)
|
|
|
|
|
: OptionEntryIntBase(key, flags, name, description, static_cast<int>(defaultValue))
|
|
|
|
|
{
|
|
|
|
|
for (auto entry : entries) {
|
|
|
|
|
AddEntry(static_cast<int>(entry));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
OptionEntryInt(std::string_view key, OptionEntryFlags flags, const char *name, const char *description, T defaultValue)
|
|
|
|
|
: OptionEntryInt(key, flags, name, description, defaultValue, { defaultValue })
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
[[nodiscard]] T operator*() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<T>(GetValueInternal());
|
|
|
|
|
}
|
|
|
|
|
void SetValue(T value)
|
|
|
|
|
{
|
|
|
|
|
SetValueInternal(static_cast<int>(value));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class OptionEntryLanguageCode : public OptionEntryListBase {
|
|
|
|
|
public:
|
|
|
|
|
OptionEntryLanguageCode();
|
|
|
|
|
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] size_t GetListSize() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetListDescription(size_t index) const override;
|
|
|
|
|
[[nodiscard]] size_t GetActiveListIndex() const override;
|
|
|
|
|
void SetActiveListIndex(size_t index) override;
|
|
|
|
|
|
|
|
|
|
std::string_view operator*() const
|
|
|
|
|
{
|
|
|
|
|
return szCode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OptionEntryLanguageCode &operator=(std::string_view code)
|
|
|
|
|
{
|
|
|
|
|
assert(code.size() < 6);
|
|
|
|
|
memcpy(szCode, code.data(), code.size());
|
|
|
|
|
szCode[code.size()] = '\0';
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/** @brief Language code (ISO-15897) for text. */
|
|
|
|
|
char szCode[6];
|
|
|
|
|
mutable std::vector<std::pair<std::string, std::string>> languages;
|
|
|
|
|
|
|
|
|
|
void CheckLanguagesAreInitialized() const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class OptionEntryResolution : public OptionEntryListBase {
|
|
|
|
|
public:
|
|
|
|
|
OptionEntryResolution();
|
|
|
|
|
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] size_t GetListSize() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetListDescription(size_t index) const override;
|
|
|
|
|
[[nodiscard]] size_t GetActiveListIndex() const override;
|
|
|
|
|
void SetActiveListIndex(size_t index) override;
|
|
|
|
|
void InvalidateList();
|
|
|
|
|
|
|
|
|
|
Size operator*() const
|
|
|
|
|
{
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/** @brief View size. */
|
|
|
|
|
Size size;
|
|
|
|
|
mutable std::vector<std::pair<Size, std::string>> resolutions;
|
|
|
|
|
|
|
|
|
|
void CheckResolutionsAreInitialized() const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class OptionEntryResampler : public OptionEntryListBase {
|
|
|
|
|
public:
|
|
|
|
|
OptionEntryResampler();
|
|
|
|
|
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] size_t GetListSize() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetListDescription(size_t index) const override;
|
|
|
|
|
[[nodiscard]] size_t GetActiveListIndex() const override;
|
|
|
|
|
void SetActiveListIndex(size_t index) override;
|
|
|
|
|
|
|
|
|
|
Resampler operator*() const
|
|
|
|
|
{
|
|
|
|
|
return resampler_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void UpdateDependentOptions() const;
|
|
|
|
|
|
|
|
|
|
Resampler resampler_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class OptionEntryAudioDevice : public OptionEntryListBase {
|
|
|
|
|
public:
|
|
|
|
|
OptionEntryAudioDevice();
|
|
|
|
|
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] size_t GetListSize() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetListDescription(size_t index) const override;
|
|
|
|
|
[[nodiscard]] size_t GetActiveListIndex() const override;
|
|
|
|
|
void SetActiveListIndex(size_t index) override;
|
|
|
|
|
|
|
|
|
|
std::string operator*() const
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < GetListSize(); i++) {
|
|
|
|
|
std::string_view deviceName = GetDeviceName(i);
|
|
|
|
|
if (deviceName == deviceName_)
|
|
|
|
|
return deviceName_;
|
|
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::string_view GetDeviceName(size_t index) const;
|
|
|
|
|
|
|
|
|
|
std::string deviceName_;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct OptionCategoryBase {
|
|
|
|
|
OptionCategoryBase(std::string_view key, const char *name, const char *description)
|
|
|
|
|
: key(key)
|
|
|
|
|
, name(name)
|
|
|
|
|
, description(description)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] std::string_view GetKey() const;
|
|
|
|
|
[[nodiscard]] std::string_view GetName() const;
|
|
|
|
|
[[nodiscard]] std::string_view GetDescription() const;
|
|
|
|
|
|
|
|
|
|
virtual std::vector<OptionEntryBase *> GetEntries() = 0;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
std::string_view key;
|
|
|
|
|
const char *name;
|
|
|
|
|
const char *description;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct StartUpOptions : OptionCategoryBase {
|
|
|
|
|
StartUpOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
OptionEntryEnum<StartUpGameMode> gameMode;
|
|
|
|
|
OptionEntryBoolean shareware;
|
|
|
|
|
/** @brief Play game intro video on diablo startup. */
|
|
|
|
|
OptionEntryEnum<StartUpIntro> diabloIntro;
|
|
|
|
|
/** @brief Play game intro video on hellfire startup. */
|
|
|
|
|
OptionEntryEnum<StartUpIntro> hellfireIntro;
|
|
|
|
|
OptionEntryEnum<StartUpSplash> splash;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct DiabloOptions : OptionCategoryBase {
|
|
|
|
|
DiabloOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
/** @brief Remembers what singleplayer hero/save was last used. */
|
|
|
|
|
OptionEntryInt<std::uint32_t> lastSinglePlayerHero;
|
|
|
|
|
/** @brief Remembers what multiplayer hero/save was last used. */
|
|
|
|
|
OptionEntryInt<std::uint32_t> lastMultiplayerHero;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct HellfireOptions : OptionCategoryBase {
|
|
|
|
|
HellfireOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
/** @brief Cornerstone of the world item. */
|
|
|
|
|
char szItem[sizeof(ItemPack) * 2 + 1];
|
|
|
|
|
/** @brief Remembers what singleplayer hero/save was last used. */
|
|
|
|
|
OptionEntryInt<std::uint32_t> lastSinglePlayerHero;
|
|
|
|
|
/** @brief Remembers what multiplayer hero/save was last used. */
|
|
|
|
|
OptionEntryInt<std::uint32_t> lastMultiplayerHero;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct AudioOptions : OptionCategoryBase {
|
|
|
|
|
AudioOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
/** @brief Movie and SFX volume. */
|
|
|
|
|
OptionEntryInt<int> soundVolume;
|
|
|
|
|
/** @brief Music volume. */
|
|
|
|
|
OptionEntryInt<int> musicVolume;
|
|
|
|
|
/** @brief Player emits sound when walking. */
|
|
|
|
|
OptionEntryBoolean walkingSound;
|
|
|
|
|
/** @brief Automatically equipping items on pickup emits the equipment sound. */
|
|
|
|
|
OptionEntryBoolean autoEquipSound;
|
|
|
|
|
/** @brief Picking up items emits the items pickup sound. */
|
|
|
|
|
OptionEntryBoolean itemPickupSound;
|
|
|
|
|
|
|
|
|
|
/** @brief Output sample rate (Hz). */
|
|
|
|
|
OptionEntryInt<std::uint32_t> sampleRate;
|
|
|
|
|
/** @brief The number of output channels (1 or 2) */
|
|
|
|
|
OptionEntryInt<std::uint8_t> channels;
|
|
|
|
|
/** @brief Buffer size (number of frames per channel) */
|
|
|
|
|
OptionEntryInt<std::uint32_t> bufferSize;
|
|
|
|
|
/** @brief Resampler implementation. */
|
|
|
|
|
OptionEntryResampler resampler;
|
|
|
|
|
/** @brief Quality of the resampler, from 0 (lowest) to 10 (highest). Available for the speex resampler only. */
|
|
|
|
|
OptionEntryInt<std::uint8_t> resamplingQuality;
|
|
|
|
|
/** @brief Audio device. */
|
|
|
|
|
OptionEntryAudioDevice device;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct GraphicsOptions : OptionCategoryBase {
|
|
|
|
|
GraphicsOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
OptionEntryResolution resolution;
|
|
|
|
|
/** @brief Run in fullscreen or windowed mode. */
|
|
|
|
|
OptionEntryBoolean fullscreen;
|
|
|
|
|
#if !defined(USE_SDL1) || defined(__3DS__)
|
|
|
|
|
/** @brief Expand the aspect ratio to match the screen. */
|
|
|
|
|
OptionEntryBoolean fitToScreen;
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef USE_SDL1
|
|
|
|
|
/** @brief Scale the image after rendering. */
|
|
|
|
|
OptionEntryBoolean upscale;
|
|
|
|
|
/** @brief See SDL_HINT_RENDER_SCALE_QUALITY. */
|
|
|
|
|
OptionEntryEnum<ScalingQuality> scaleQuality;
|
|
|
|
|
/** @brief Only scale by values divisible by the width and height. */
|
|
|
|
|
OptionEntryBoolean integerScaling;
|
|
|
|
|
/** @brief Enable vsync on the output. */
|
|
|
|
|
OptionEntryBoolean vSync;
|
|
|
|
|
#endif
|
|
|
|
|
/** @brief Gamma correction level. */
|
|
|
|
|
OptionEntryInt<int> gammaCorrection;
|
|
|
|
|
/** @brief Zoom on start. */
|
|
|
|
|
OptionEntryBoolean zoom;
|
|
|
|
|
/** @brief Enable color cycling animations. */
|
|
|
|
|
OptionEntryBoolean colorCycling;
|
|
|
|
|
/** @brief Use alternate nest palette. */
|
|
|
|
|
OptionEntryBoolean alternateNestArt;
|
|
|
|
|
#if SDL_VERSION_ATLEAST(2, 0, 0)
|
|
|
|
|
/** @brief Use a hardware cursor (SDL2 only). */
|
|
|
|
|
OptionEntryBoolean hardwareCursor;
|
|
|
|
|
/** @brief Use a hardware cursor for items. */
|
|
|
|
|
OptionEntryBoolean hardwareCursorForItems;
|
|
|
|
|
/** @brief Maximum width / height for the hardware cursor. Larger cursors fall back to software. */
|
|
|
|
|
OptionEntryInt<int> hardwareCursorMaxSize;
|
|
|
|
|
#endif
|
|
|
|
|
/** @brief Enable FPS Limiter. */
|
|
|
|
|
OptionEntryBoolean limitFPS;
|
|
|
|
|
/** @brief Show FPS, even without the -f command line flag. */
|
|
|
|
|
OptionEntryBoolean showFPS;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct GameplayOptions : OptionCategoryBase {
|
|
|
|
|
GameplayOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
/** @brief Gameplay ticks per second. */
|
|
|
|
|
OptionEntryInt<int> tickRate;
|
|
|
|
|
/** @brief Enable double walk speed when in town. */
|
|
|
|
|
OptionEntryBoolean runInTown;
|
|
|
|
|
/** @brief Do not let the mouse leave the application window. */
|
|
|
|
|
OptionEntryBoolean grabInput;
|
|
|
|
|
/** @brief Enable the Theo quest. */
|
|
|
|
|
OptionEntryBoolean theoQuest;
|
|
|
|
|
/** @brief Enable the cow quest. */
|
|
|
|
|
OptionEntryBoolean cowQuest;
|
|
|
|
|
/** @brief Will players still damage other players in non-PvP mode. */
|
|
|
|
|
OptionEntryBoolean friendlyFire;
|
|
|
|
|
/** @brief Enables the full/uncut singleplayer version of quests. */
|
|
|
|
|
OptionEntryBoolean multiplayerFullQuests;
|
|
|
|
|
/** @brief Enable the bard hero class. */
|
|
|
|
|
OptionEntryBoolean testBard;
|
|
|
|
|
/** @brief Enable the babarian hero class. */
|
|
|
|
|
OptionEntryBoolean testBarbarian;
|
|
|
|
|
/** @brief Show the current level progress. */
|
|
|
|
|
OptionEntryBoolean experienceBar;
|
|
|
|
|
/** @brief Show item graphics to the left of item descriptions in store menus. */
|
|
|
|
|
OptionEntryBoolean showItemGraphicsInStores;
|
|
|
|
|
/** @brief Display current/max health values on health globe. */
|
|
|
|
|
OptionEntryBoolean showHealthValues;
|
|
|
|
|
/** @brief Display current/max mana values on mana globe. */
|
|
|
|
|
OptionEntryBoolean showManaValues;
|
|
|
|
|
/** @brief Show enemy health at the top of the screen. */
|
|
|
|
|
OptionEntryBoolean enemyHealthBar;
|
|
|
|
|
/** @brief Automatically pick up gold when walking over it. */
|
|
|
|
|
OptionEntryBoolean autoGoldPickup;
|
|
|
|
|
/** @brief Auto-pickup elixirs */
|
|
|
|
|
OptionEntryBoolean autoElixirPickup;
|
|
|
|
|
/** @brief Auto-pickup oils */
|
|
|
|
|
OptionEntryBoolean autoOilPickup;
|
|
|
|
|
/** @brief Enable or Disable auto-pickup in town */
|
|
|
|
|
OptionEntryBoolean autoPickupInTown;
|
|
|
|
|
/** @brief Recover mana when talking to Adria. */
|
|
|
|
|
OptionEntryBoolean adriaRefillsMana;
|
|
|
|
|
/** @brief Automatically attempt to equip weapon-type items when picking them up. */
|
|
|
|
|
OptionEntryBoolean autoEquipWeapons;
|
|
|
|
|
/** @brief Automatically attempt to equip armor-type items when picking them up. */
|
|
|
|
|
OptionEntryBoolean autoEquipArmor;
|
|
|
|
|
/** @brief Automatically attempt to equip helm-type items when picking them up. */
|
|
|
|
|
OptionEntryBoolean autoEquipHelms;
|
|
|
|
|
/** @brief Automatically attempt to equip shield-type items when picking them up. */
|
|
|
|
|
OptionEntryBoolean autoEquipShields;
|
|
|
|
|
/** @brief Automatically attempt to equip jewelry-type items when picking them up. */
|
|
|
|
|
OptionEntryBoolean autoEquipJewelry;
|
|
|
|
|
/** @brief Only enable 2/3 quests in each game session */
|
|
|
|
|
OptionEntryBoolean randomizeQuests;
|
|
|
|
|
/** @brief Indicates whether or not monster type (Animal, Demon, Undead) is shown along with other monster information. */
|
|
|
|
|
OptionEntryBoolean showMonsterType;
|
|
|
|
|
/** @brief Displays item labels for items on the ground. */
|
|
|
|
|
OptionEntryBoolean showItemLabels;
|
|
|
|
|
/** @brief Refill belt from inventory, or rather, use potions/scrolls from inventory first when belt item is consumed. */
|
|
|
|
|
OptionEntryBoolean autoRefillBelt;
|
|
|
|
|
/** @brief Locally disable clicking on shrines which permanently cripple character. */
|
|
|
|
|
OptionEntryBoolean disableCripplingShrines;
|
|
|
|
|
/** @brief Spell hotkeys instantly cast the spell. */
|
|
|
|
|
OptionEntryBoolean quickCast;
|
|
|
|
|
/** @brief Number of Healing potions to pick up automatically */
|
|
|
|
|
OptionEntryInt<int> numHealPotionPickup;
|
|
|
|
|
/** @brief Number of Full Healing potions to pick up automatically */
|
|
|
|
|
OptionEntryInt<int> numFullHealPotionPickup;
|
|
|
|
|
/** @brief Number of Mana potions to pick up automatically */
|
|
|
|
|
OptionEntryInt<int> numManaPotionPickup;
|
|
|
|
|
/** @brief Number of Full Mana potions to pick up automatically */
|
|
|
|
|
OptionEntryInt<int> numFullManaPotionPickup;
|
|
|
|
|
/** @brief Number of Rejuvenating potions to pick up automatically */
|
|
|
|
|
OptionEntryInt<int> numRejuPotionPickup;
|
|
|
|
|
/** @brief Number of Full Rejuvenating potions to pick up automatically */
|
|
|
|
|
OptionEntryInt<int> numFullRejuPotionPickup;
|
|
|
|
|
/** @brief Enable floating numbers. */
|
|
|
|
|
OptionEntryEnum<FloatingNumbers> enableFloatingNumbers;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ControllerOptions : OptionCategoryBase {
|
|
|
|
|
ControllerOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
/** @brief SDL Controller mapping, see SDL_GameControllerDB. */
|
|
|
|
|
char szMapping[1024];
|
|
|
|
|
/** @brief Configure gamepad joysticks deadzone */
|
|
|
|
|
float fDeadzone;
|
|
|
|
|
#ifdef __vita__
|
|
|
|
|
/** @brief Enable input via rear touchpad */
|
|
|
|
|
bool bRearTouch;
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct NetworkOptions : OptionCategoryBase {
|
|
|
|
|
NetworkOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
/** @brief Optionally bind to a specific network interface. */
|
|
|
|
|
char szBindAddress[129];
|
|
|
|
|
/** @brief Most recently entered ZeroTier Game ID. */
|
|
|
|
|
char szPreviousZTGame[129];
|
|
|
|
|
/** @brief Most recently entered Hostname in join dialog. */
|
|
|
|
|
char szPreviousHost[129];
|
|
|
|
|
/** @brief What network port to use. */
|
|
|
|
|
OptionEntryInt<uint16_t> port;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ChatOptions : OptionCategoryBase {
|
|
|
|
|
ChatOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
/** @brief Quick chat messages. */
|
|
|
|
|
std::vector<std::string> szHotKeyMsgs[QUICK_MESSAGE_OPTIONS];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct LanguageOptions : OptionCategoryBase {
|
|
|
|
|
LanguageOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
OptionEntryLanguageCode code;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
constexpr uint32_t KeymapperMouseButtonMask = 1 << 31;
|
|
|
|
|
|
|
|
|
|
/** The Keymapper maps keys to actions. */
|
|
|
|
|
struct KeymapperOptions : OptionCategoryBase {
|
|
|
|
|
/**
|
|
|
|
|
* Action represents an action that can be triggered using a keyboard
|
|
|
|
|
* shortcut.
|
|
|
|
|
*/
|
|
|
|
|
class Action final : public OptionEntryBase {
|
|
|
|
|
public:
|
|
|
|
|
// OptionEntryBase::key may be referencing Action::dynamicKey.
|
|
|
|
|
// The implicit copy constructor would copy that reference instead of referencing the copy.
|
|
|
|
|
Action(const Action &) = delete;
|
|
|
|
|
|
|
|
|
|
Action(std::string_view key, const char *name, const char *description, uint32_t defaultKey, std::function<void()> actionPressed, std::function<void()> actionReleased, std::function<bool()> enable, unsigned index);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] std::string_view GetName() const override;
|
|
|
|
|
[[nodiscard]] OptionEntryType GetType() const override
|
|
|
|
|
{
|
|
|
|
|
return OptionEntryType::Key;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] std::string_view GetValueDescription() const override;
|
|
|
|
|
|
|
|
|
|
bool SetValue(int value);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
uint32_t defaultKey;
|
|
|
|
|
std::function<void()> actionPressed;
|
|
|
|
|
std::function<void()> actionReleased;
|
|
|
|
|
std::function<bool()> enable;
|
|
|
|
|
uint32_t boundKey = SDLK_UNKNOWN;
|
|
|
|
|
unsigned dynamicIndex;
|
|
|
|
|
std::string dynamicKey;
|
|
|
|
|
mutable std::string dynamicName;
|
|
|
|
|
|
|
|
|
|
friend struct KeymapperOptions;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
KeymapperOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
void AddAction(
|
|
|
|
|
std::string_view key, const char *name, const char *description, uint32_t defaultKey,
|
|
|
|
|
std::function<void()> actionPressed,
|
|
|
|
|
std::function<void()> actionReleased = nullptr,
|
|
|
|
|
std::function<bool()> enable = nullptr,
|
|
|
|
|
unsigned index = 0);
|
|
|
|
|
void CommitActions();
|
|
|
|
|
void KeyPressed(uint32_t key) const;
|
|
|
|
|
void KeyReleased(SDL_Keycode key) const;
|
|
|
|
|
bool IsTextEntryKey(SDL_Keycode vkey) const;
|
|
|
|
|
bool IsNumberEntryKey(SDL_Keycode vkey) const;
|
|
|
|
|
std::string_view KeyNameForAction(std::string_view actionName) const;
|
|
|
|
|
uint32_t KeyForAction(std::string_view actionName) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::forward_list<Action> actions;
|
|
|
|
|
std::unordered_map<uint32_t, std::reference_wrapper<Action>> keyIDToAction;
|
|
|
|
|
std::unordered_map<uint32_t, std::string> keyIDToKeyName;
|
|
|
|
|
std::unordered_map<std::string, uint32_t> keyNameToKeyID;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** The Padmapper maps gamepad buttons to actions. */
|
|
|
|
|
struct PadmapperOptions : OptionCategoryBase {
|
|
|
|
|
/**
|
|
|
|
|
* Action represents an action that can be triggered using a gamepad
|
|
|
|
|
* button combo.
|
|
|
|
|
*/
|
|
|
|
|
class Action final : public OptionEntryBase {
|
|
|
|
|
public:
|
|
|
|
|
Action(std::string_view key, const char *name, const char *description, ControllerButtonCombo defaultInput, std::function<void()> actionPressed, std::function<void()> actionReleased, std::function<bool()> enable, unsigned index);
|
|
|
|
|
|
|
|
|
|
// OptionEntryBase::key may be referencing Action::dynamicKey.
|
|
|
|
|
// The implicit copy constructor would copy that reference instead of referencing the copy.
|
|
|
|
|
Action(const Action &) = delete;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] std::string_view GetName() const override;
|
|
|
|
|
[[nodiscard]] OptionEntryType GetType() const override
|
|
|
|
|
{
|
|
|
|
|
return OptionEntryType::PadButton;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LoadFromIni(std::string_view category) override;
|
|
|
|
|
void SaveToIni(std::string_view category) const override;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] std::string_view GetValueDescription() const override;
|
|
|
|
|
[[nodiscard]] std::string_view GetValueDescription(bool useShortName) const;
|
|
|
|
|
|
|
|
|
|
bool SetValue(ControllerButtonCombo value);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
ControllerButtonCombo defaultInput;
|
|
|
|
|
std::function<void()> actionPressed;
|
|
|
|
|
std::function<void()> actionReleased;
|
|
|
|
|
std::function<bool()> enable;
|
|
|
|
|
ControllerButtonCombo boundInput {};
|
|
|
|
|
mutable GamepadLayout boundInputDescriptionType = GamepadLayout::Generic;
|
|
|
|
|
mutable std::string boundInputDescription;
|
|
|
|
|
mutable std::string boundInputShortDescription;
|
|
|
|
|
unsigned dynamicIndex;
|
|
|
|
|
std::string dynamicKey;
|
|
|
|
|
mutable std::string dynamicName;
|
|
|
|
|
|
|
|
|
|
void UpdateValueDescription() const;
|
|
|
|
|
std::string_view Shorten(std::string_view buttonName) const;
|
|
|
|
|
|
|
|
|
|
friend struct PadmapperOptions;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
PadmapperOptions();
|
|
|
|
|
std::vector<OptionEntryBase *> GetEntries() override;
|
|
|
|
|
|
|
|
|
|
void AddAction(
|
|
|
|
|
std::string_view key, const char *name, const char *description, ControllerButtonCombo defaultInput,
|
|
|
|
|
std::function<void()> actionPressed,
|
|
|
|
|
std::function<void()> actionReleased = nullptr,
|
|
|
|
|
std::function<bool()> enable = nullptr,
|
|
|
|
|
unsigned index = 0);
|
|
|
|
|
void CommitActions();
|
|
|
|
|
void ButtonPressed(ControllerButton button);
|
|
|
|
|
void ButtonReleased(ControllerButton button, bool invokeAction = true);
|
|
|
|
|
void ReleaseAllActiveButtons();
|
|
|
|
|
bool IsActive(std::string_view actionName) const;
|
|
|
|
|
std::string_view ActionNameTriggeredByButtonEvent(ControllerButtonEvent ctrlEvent) const;
|
|
|
|
|
std::string_view InputNameForAction(std::string_view actionName, bool useShortName = false) const;
|
|
|
|
|
ControllerButtonCombo ButtonComboForAction(std::string_view actionName) const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::forward_list<Action> actions;
|
|
|
|
|
std::array<const Action *, enum_size<ControllerButton>::value> buttonToReleaseAction;
|
|
|
|
|
std::array<std::string, enum_size<ControllerButton>::value> buttonToButtonName;
|
|
|
|
|
std::unordered_map<std::string, ControllerButton> buttonNameToButton;
|
|
|
|
|
bool committed = false;
|
|
|
|
|
|
|
|
|
|
const Action *FindAction(ControllerButton button) const;
|
|
|
|
|
bool CanDeferToMovementHandler(const Action &action) const;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct Options {
|
|
|
|
|
StartUpOptions StartUp;
|
|
|
|
|
DiabloOptions Diablo;
|
|
|
|
|
HellfireOptions Hellfire;
|
|
|
|
|
AudioOptions Audio;
|
|
|
|
|
GameplayOptions Gameplay;
|
|
|
|
|
GraphicsOptions Graphics;
|
|
|
|
|
ControllerOptions Controller;
|
|
|
|
|
NetworkOptions Network;
|
|
|
|
|
ChatOptions Chat;
|
|
|
|
|
LanguageOptions Language;
|
|
|
|
|
KeymapperOptions Keymapper;
|
|
|
|
|
PadmapperOptions Padmapper;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] std::vector<OptionCategoryBase *> GetCategories()
|
|
|
|
|
{
|
|
|
|
|
return {
|
|
|
|
|
&Language,
|
|
|
|
|
&StartUp,
|
|
|
|
|
&Graphics,
|
|
|
|
|
&Audio,
|
|
|
|
|
&Diablo,
|
|
|
|
|
&Hellfire,
|
|
|
|
|
&Gameplay,
|
|
|
|
|
&Controller,
|
|
|
|
|
&Network,
|
|
|
|
|
&Chat,
|
|
|
|
|
&Keymapper,
|
|
|
|
|
&Padmapper,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern DVL_API_FOR_TEST Options sgOptions;
|
|
|
|
|
|
|
|
|
|
bool HardwareCursorSupported();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Save game configurations to ini file
|
|
|
|
|
*/
|
|
|
|
|
void SaveOptions();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Load game configurations from ini file
|
|
|
|
|
*/
|
|
|
|
|
void LoadOptions();
|
|
|
|
|
|
|
|
|
|
} // namespace devilution
|