Add OpenMW commits up to 4 Jul 2020
# Conflicts: # .travis.yml # CI/before_script.linux.sh # apps/openmw/engine.cpp # apps/openmw/mwbase/windowmanager.hpp # apps/openmw/mwgui/charactercreation.cpp # apps/openmw/mwgui/windowmanagerimp.hpp # apps/openmw/mwmechanics/character.cpppull/593/head
commit
5eb7eb8d88
@ -0,0 +1,209 @@
|
||||
#include "statswatcher.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/spellutil.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
// mWatchedTimeToStartDrowning = -1 for correct drowning state check,
|
||||
// if stats.getTimeToStartDrowning() == 0 already on game start
|
||||
StatsWatcher::StatsWatcher()
|
||||
: mWatchedLevel(-1), mWatchedTimeToStartDrowning(-1), mWatchedStatsEmpty(true)
|
||||
{
|
||||
}
|
||||
|
||||
void StatsWatcher::watchActor(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
mWatched = ptr;
|
||||
}
|
||||
|
||||
void StatsWatcher::update()
|
||||
{
|
||||
if (mWatched.isEmpty())
|
||||
return;
|
||||
|
||||
MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
|
||||
const MWMechanics::NpcStats &stats = mWatched.getClass().getNpcStats(mWatched);
|
||||
for (int i = 0;i < ESM::Attribute::Length;++i)
|
||||
{
|
||||
if (stats.getAttribute(i) != mWatchedAttributes[i] || mWatchedStatsEmpty)
|
||||
{
|
||||
std::stringstream attrname;
|
||||
attrname << "AttribVal"<<(i+1);
|
||||
|
||||
mWatchedAttributes[i] = stats.getAttribute(i);
|
||||
setValue(attrname.str(), stats.getAttribute(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (stats.getHealth() != mWatchedHealth || mWatchedStatsEmpty)
|
||||
{
|
||||
static const std::string hbar("HBar");
|
||||
mWatchedHealth = stats.getHealth();
|
||||
setValue(hbar, stats.getHealth());
|
||||
}
|
||||
if (stats.getMagicka() != mWatchedMagicka || mWatchedStatsEmpty)
|
||||
{
|
||||
static const std::string mbar("MBar");
|
||||
mWatchedMagicka = stats.getMagicka();
|
||||
setValue(mbar, stats.getMagicka());
|
||||
}
|
||||
if (stats.getFatigue() != mWatchedFatigue || mWatchedStatsEmpty)
|
||||
{
|
||||
static const std::string fbar("FBar");
|
||||
mWatchedFatigue = stats.getFatigue();
|
||||
setValue(fbar, stats.getFatigue());
|
||||
}
|
||||
|
||||
float timeToDrown = stats.getTimeToStartDrowning();
|
||||
|
||||
if (timeToDrown != mWatchedTimeToStartDrowning)
|
||||
{
|
||||
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||
.find("fHoldBreathTime")->mValue.getFloat();
|
||||
|
||||
mWatchedTimeToStartDrowning = timeToDrown;
|
||||
|
||||
if(timeToDrown >= fHoldBreathTime || timeToDrown == -1.0) // -1.0 is a special value during initialization
|
||||
winMgr->setDrowningBarVisibility(false);
|
||||
else
|
||||
{
|
||||
winMgr->setDrowningBarVisibility(true);
|
||||
winMgr->setDrowningTimeLeft(stats.getTimeToStartDrowning(), fHoldBreathTime);
|
||||
}
|
||||
}
|
||||
|
||||
//Loop over ESM::Skill::SkillEnum
|
||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||
{
|
||||
if(stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty)
|
||||
{
|
||||
mWatchedSkills[i] = stats.getSkill(i);
|
||||
setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (stats.getLevel() != mWatchedLevel || mWatchedStatsEmpty)
|
||||
{
|
||||
mWatchedLevel = stats.getLevel();
|
||||
setValue("level", mWatchedLevel);
|
||||
}
|
||||
|
||||
if (mWatched.getClass().isNpc())
|
||||
{
|
||||
const ESM::NPC *watchedRecord = mWatched.get<ESM::NPC>()->mBase;
|
||||
|
||||
if (watchedRecord->mName != mWatchedName || mWatchedStatsEmpty)
|
||||
{
|
||||
mWatchedName = watchedRecord->mName;
|
||||
setValue("name", watchedRecord->mName);
|
||||
}
|
||||
|
||||
if (watchedRecord->mRace != mWatchedRace || mWatchedStatsEmpty)
|
||||
{
|
||||
mWatchedRace = watchedRecord->mRace;
|
||||
const ESM::Race *race = MWBase::Environment::get().getWorld()->getStore()
|
||||
.get<ESM::Race>().find(watchedRecord->mRace);
|
||||
setValue("race", race->mName);
|
||||
}
|
||||
|
||||
if (watchedRecord->mClass != mWatchedClass || mWatchedStatsEmpty)
|
||||
{
|
||||
mWatchedClass = watchedRecord->mClass;
|
||||
const ESM::Class *cls = MWBase::Environment::get().getWorld()->getStore()
|
||||
.get<ESM::Class>().find(watchedRecord->mClass);
|
||||
setValue("class", cls->mName);
|
||||
|
||||
MWBase::WindowManager::SkillList majorSkills (5);
|
||||
MWBase::WindowManager::SkillList minorSkills (5);
|
||||
|
||||
for (int i=0; i<5; ++i)
|
||||
{
|
||||
minorSkills[i] = cls->mData.mSkills[i][0];
|
||||
majorSkills[i] = cls->mData.mSkills[i][1];
|
||||
}
|
||||
|
||||
configureSkills(majorSkills, minorSkills);
|
||||
}
|
||||
}
|
||||
|
||||
mWatchedStatsEmpty = false;
|
||||
|
||||
// Update the equipped weapon icon
|
||||
MWWorld::InventoryStore& inv = mWatched.getClass().getInventoryStore(mWatched);
|
||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if (weapon == inv.end())
|
||||
winMgr->unsetSelectedWeapon();
|
||||
else
|
||||
winMgr->setSelectedWeapon(*weapon);
|
||||
|
||||
// Update the selected spell icon
|
||||
MWWorld::ContainerStoreIterator enchantItem = inv.getSelectedEnchantItem();
|
||||
if (enchantItem != inv.end())
|
||||
winMgr->setSelectedEnchantItem(*enchantItem);
|
||||
else
|
||||
{
|
||||
const std::string& spell = winMgr->getSelectedSpell();
|
||||
if (!spell.empty())
|
||||
winMgr->setSelectedSpell(spell, int(MWMechanics::getSpellSuccessChance(spell, mWatched)));
|
||||
else
|
||||
winMgr->unsetSelectedSpell();
|
||||
}
|
||||
}
|
||||
|
||||
void StatsWatcher::addListener(StatsListener* listener)
|
||||
{
|
||||
mListeners.insert(listener);
|
||||
}
|
||||
|
||||
void StatsWatcher::removeListener(StatsListener* listener)
|
||||
{
|
||||
mListeners.erase(listener);
|
||||
}
|
||||
|
||||
void StatsWatcher::setValue(const std::string& id, const MWMechanics::AttributeValue& value)
|
||||
{
|
||||
for (StatsListener* listener : mListeners)
|
||||
listener->setValue(id, value);
|
||||
}
|
||||
|
||||
void StatsWatcher::setValue(ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
|
||||
{
|
||||
/// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we
|
||||
/// allow custom skills.
|
||||
for (StatsListener* listener : mListeners)
|
||||
listener->setValue(parSkill, value);
|
||||
}
|
||||
|
||||
void StatsWatcher::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
|
||||
{
|
||||
for (StatsListener* listener : mListeners)
|
||||
listener->setValue(id, value);
|
||||
}
|
||||
|
||||
void StatsWatcher::setValue(const std::string& id, const std::string& value)
|
||||
{
|
||||
for (StatsListener* listener : mListeners)
|
||||
listener->setValue(id, value);
|
||||
}
|
||||
|
||||
void StatsWatcher::setValue(const std::string& id, int value)
|
||||
{
|
||||
for (StatsListener* listener : mListeners)
|
||||
listener->setValue(id, value);
|
||||
}
|
||||
|
||||
void StatsWatcher::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
|
||||
{
|
||||
for (StatsListener* listener : mListeners)
|
||||
listener->configureSkills(major, minor);
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
#ifndef MWGUI_STATSWATCHER_H
|
||||
#define MWGUI_STATSWATCHER_H
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <components/esm/attr.hpp>
|
||||
#include <components/esm/loadskil.hpp>
|
||||
|
||||
#include "../mwmechanics/stat.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class StatsListener
|
||||
{
|
||||
public:
|
||||
/// Set value for the given ID.
|
||||
virtual void setValue(const std::string& id, const MWMechanics::AttributeValue& value) {}
|
||||
virtual void setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value) {}
|
||||
virtual void setValue(const std::string& id, const std::string& value) {}
|
||||
virtual void setValue(const std::string& id, int value) {}
|
||||
virtual void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) {}
|
||||
virtual void configureSkills(const std::vector<int>& major, const std::vector<int>& minor) {}
|
||||
};
|
||||
|
||||
class StatsWatcher
|
||||
{
|
||||
MWWorld::Ptr mWatched;
|
||||
|
||||
MWMechanics::AttributeValue mWatchedAttributes[ESM::Attribute::Length];
|
||||
MWMechanics::SkillValue mWatchedSkills[ESM::Skill::Length];
|
||||
|
||||
MWMechanics::DynamicStat<float> mWatchedHealth;
|
||||
MWMechanics::DynamicStat<float> mWatchedMagicka;
|
||||
MWMechanics::DynamicStat<float> mWatchedFatigue;
|
||||
|
||||
std::string mWatchedName;
|
||||
std::string mWatchedRace;
|
||||
std::string mWatchedClass;
|
||||
|
||||
int mWatchedLevel;
|
||||
|
||||
float mWatchedTimeToStartDrowning;
|
||||
|
||||
bool mWatchedStatsEmpty;
|
||||
|
||||
std::set<StatsListener*> mListeners;
|
||||
|
||||
void setValue(const std::string& id, const MWMechanics::AttributeValue& value);
|
||||
void setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value);
|
||||
void setValue(const std::string& id, const std::string& value);
|
||||
void setValue(const std::string& id, int value);
|
||||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
|
||||
void configureSkills(const std::vector<int>& major, const std::vector<int>& minor);
|
||||
|
||||
public:
|
||||
StatsWatcher();
|
||||
|
||||
void update();
|
||||
void addListener(StatsListener* listener);
|
||||
void removeListener(StatsListener* listener);
|
||||
|
||||
void watchActor(const MWWorld::Ptr& ptr);
|
||||
MWWorld::Ptr getWatchedActor() const { return mWatched; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,71 @@
|
||||
#include "regionsoundselector.hpp"
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
namespace
|
||||
{
|
||||
int addChance(int result, const ESM::Region::SoundRef &v)
|
||||
{
|
||||
return result + v.mChance;
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<std::string> RegionSoundSelector::getNextRandom(float duration, const std::string& regionName,
|
||||
const MWBase::World& world)
|
||||
{
|
||||
mTimePassed += duration;
|
||||
|
||||
if (mTimePassed < mTimeToNextEnvSound)
|
||||
return {};
|
||||
|
||||
const float a = Misc::Rng::rollClosedProbability();
|
||||
// NOTE: We should use the "Minimum Time Between Environmental Sounds" and
|
||||
// "Maximum Time Between Environmental Sounds" fallback settings here.
|
||||
mTimeToNextEnvSound = 5.0f * a + 15.0f * (1.0f - a);
|
||||
mTimePassed = 0;
|
||||
|
||||
if (mLastRegionName != regionName)
|
||||
{
|
||||
mLastRegionName = regionName;
|
||||
mSumChance = 0;
|
||||
}
|
||||
|
||||
const ESM::Region* const region = world.getStore().get<ESM::Region>().search(mLastRegionName);
|
||||
|
||||
if (region == nullptr)
|
||||
return {};
|
||||
|
||||
if (mSumChance == 0)
|
||||
{
|
||||
mSumChance = std::accumulate(region->mSoundList.begin(), region->mSoundList.end(), 0, addChance);
|
||||
if (mSumChance == 0)
|
||||
return {};
|
||||
}
|
||||
|
||||
const int r = Misc::Rng::rollDice(mSumChance);
|
||||
int pos = 0;
|
||||
|
||||
const auto isSelected = [&] (const ESM::Region::SoundRef& sound)
|
||||
{
|
||||
if (r - pos < sound.mChance)
|
||||
return true;
|
||||
pos += sound.mChance;
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto it = std::find_if(region->mSoundList.begin(), region->mSoundList.end(), isSelected);
|
||||
|
||||
if (it == region->mSoundList.end())
|
||||
return {};
|
||||
|
||||
return it->mSound;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
#ifndef GAME_SOUND_REGIONSOUNDSELECTOR_H
|
||||
#define GAME_SOUND_REGIONSOUNDSELECTOR_H
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
class World;
|
||||
}
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
class RegionSoundSelector
|
||||
{
|
||||
public:
|
||||
boost::optional<std::string> getNextRandom(float duration, const std::string& regionName,
|
||||
const MWBase::World& world);
|
||||
|
||||
private:
|
||||
float mTimeToNextEnvSound = 0.0f;
|
||||
int mSumChance = 0;
|
||||
std::string mLastRegionName;
|
||||
float mTimePassed = 0.0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
#ifndef GAME_SOUND_TYPE_H
|
||||
#define GAME_SOUND_TYPE_H
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
Sfx = 1 << 4, /* Normal SFX sound */
|
||||
Voice = 1 << 5, /* Voice sound */
|
||||
Foot = 1 << 6, /* Footstep sound */
|
||||
Music = 1 << 7, /* Music track */
|
||||
Movie = 1 << 8, /* Movie audio track */
|
||||
Mask = Sfx | Voice | Foot | Music | Movie
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,56 @@
|
||||
#include "volumesettings.hpp"
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
namespace
|
||||
{
|
||||
float clamp(float value)
|
||||
{
|
||||
return std::max(0.0f, std::min(1.0f, value));
|
||||
}
|
||||
}
|
||||
|
||||
VolumeSettings::VolumeSettings()
|
||||
: mMasterVolume(clamp(Settings::Manager::getFloat("master volume", "Sound"))),
|
||||
mSFXVolume(clamp(Settings::Manager::getFloat("sfx volume", "Sound"))),
|
||||
mMusicVolume(clamp(Settings::Manager::getFloat("music volume", "Sound"))),
|
||||
mVoiceVolume(clamp(Settings::Manager::getFloat("voice volume", "Sound"))),
|
||||
mFootstepsVolume(clamp(Settings::Manager::getFloat("footsteps volume", "Sound")))
|
||||
{
|
||||
}
|
||||
|
||||
float VolumeSettings::getVolumeFromType(Type type) const
|
||||
{
|
||||
float volume = mMasterVolume;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case Type::Sfx:
|
||||
volume *= mSFXVolume;
|
||||
break;
|
||||
case Type::Voice:
|
||||
volume *= mVoiceVolume;
|
||||
break;
|
||||
case Type::Foot:
|
||||
volume *= mFootstepsVolume;
|
||||
break;
|
||||
case Type::Music:
|
||||
volume *= mMusicVolume;
|
||||
break;
|
||||
case Type::Movie:
|
||||
case Type::Mask:
|
||||
break;
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
void VolumeSettings::update()
|
||||
{
|
||||
*this = VolumeSettings();
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
#ifndef GAME_SOUND_VOLUMESETTINGS_H
|
||||
#define GAME_SOUND_VOLUMESETTINGS_H
|
||||
|
||||
#include "type.hpp"
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
class VolumeSettings
|
||||
{
|
||||
public:
|
||||
VolumeSettings();
|
||||
|
||||
float getVolumeFromType(Type type) const;
|
||||
|
||||
void update();
|
||||
|
||||
private:
|
||||
float mMasterVolume;
|
||||
float mSFXVolume;
|
||||
float mMusicVolume;
|
||||
float mVoiceVolume;
|
||||
float mFootstepsVolume;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,71 @@
|
||||
#include "watersoundupdater.hpp"
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
#include <components/esm/loadcell.hpp>
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
WaterSoundUpdater::WaterSoundUpdater(const WaterSoundUpdaterSettings& settings)
|
||||
: mSettings(settings)
|
||||
{
|
||||
}
|
||||
|
||||
WaterSoundUpdate WaterSoundUpdater::update(const MWWorld::ConstPtr& player, const MWBase::World& world) const
|
||||
{
|
||||
WaterSoundUpdate result;
|
||||
|
||||
result.mId = player.getCell()->isExterior() ? mSettings.mNearWaterOutdoorID : mSettings.mNearWaterIndoorID;
|
||||
result.mVolume = std::min(1.0f, getVolume(player, world));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float WaterSoundUpdater::getVolume(const MWWorld::ConstPtr& player, const MWBase::World& world) const
|
||||
{
|
||||
if (mListenerUnderwater)
|
||||
return 1.0f;
|
||||
|
||||
const MWWorld::CellStore& cell = *player.getCell();
|
||||
|
||||
if (!cell.getCell()->hasWater())
|
||||
return 0.0f;
|
||||
|
||||
const osg::Vec3f pos = player.getRefData().getPosition().asVec3();
|
||||
const float dist = std::abs(cell.getWaterLevel() - pos.z());
|
||||
|
||||
if (cell.isExterior() && dist < mSettings.mNearWaterOutdoorTolerance)
|
||||
{
|
||||
if (mSettings.mNearWaterPoints <= 1)
|
||||
return (mSettings.mNearWaterOutdoorTolerance - dist) / mSettings.mNearWaterOutdoorTolerance;
|
||||
|
||||
const float step = mSettings.mNearWaterRadius * 2.0f / (mSettings.mNearWaterPoints - 1);
|
||||
|
||||
int underwaterPoints = 0;
|
||||
|
||||
for (int x = 0; x < mSettings.mNearWaterPoints; x++)
|
||||
{
|
||||
for (int y = 0; y < mSettings.mNearWaterPoints; y++)
|
||||
{
|
||||
const float terrainX = pos.x() - mSettings.mNearWaterRadius + x * step;
|
||||
const float terrainY = pos.y() - mSettings.mNearWaterRadius + y * step;
|
||||
const float height = world.getTerrainHeightAt(osg::Vec3f(terrainX, terrainY, 0.0f));
|
||||
|
||||
if (height < 0)
|
||||
underwaterPoints++;
|
||||
}
|
||||
}
|
||||
|
||||
return underwaterPoints * 2.0f / (mSettings.mNearWaterPoints * mSettings.mNearWaterPoints);
|
||||
}
|
||||
|
||||
if (!cell.isExterior() && dist < mSettings.mNearWaterIndoorTolerance)
|
||||
return (mSettings.mNearWaterIndoorTolerance - dist) / mSettings.mNearWaterIndoorTolerance;
|
||||
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
#ifndef GAME_SOUND_WATERSOUNDUPDATER_H
|
||||
#define GAME_SOUND_WATERSOUNDUPDATER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace MWBase
|
||||
{
|
||||
class World;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class ConstPtr;
|
||||
}
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
struct WaterSoundUpdaterSettings
|
||||
{
|
||||
int mNearWaterRadius;
|
||||
int mNearWaterPoints;
|
||||
float mNearWaterIndoorTolerance;
|
||||
float mNearWaterOutdoorTolerance;
|
||||
std::string mNearWaterIndoorID;
|
||||
std::string mNearWaterOutdoorID;
|
||||
};
|
||||
|
||||
struct WaterSoundUpdate
|
||||
{
|
||||
std::string mId;
|
||||
float mVolume;
|
||||
};
|
||||
|
||||
class WaterSoundUpdater
|
||||
{
|
||||
public:
|
||||
explicit WaterSoundUpdater(const WaterSoundUpdaterSettings& settings);
|
||||
|
||||
WaterSoundUpdate update(const MWWorld::ConstPtr& player, const MWBase::World& world) const;
|
||||
|
||||
void setUnderwater(bool value)
|
||||
{
|
||||
mListenerUnderwater = value;
|
||||
}
|
||||
|
||||
private:
|
||||
const WaterSoundUpdaterSettings mSettings;
|
||||
bool mListenerUnderwater = false;
|
||||
|
||||
float getVolume(const MWWorld::ConstPtr& player, const MWBase::World& world) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue