Merge pull request #292 from OpenMW/master

Add OpenMW commits up to 18 Sep 2017
pull/295/head
David Cernat 7 years ago committed by GitHub
commit 4d4eb1bb9f

@ -24,7 +24,7 @@ void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main)
main->addWidget (list);
QFontMetrics metrics (QApplication::font());
QFontMetrics metrics (QApplication::font(list));
int maxWidth = 1;

@ -3,6 +3,7 @@
#include <MyGUI_ListBox.h>
#include <MyGUI_ImageBox.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ScrollView.h>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -244,6 +245,11 @@ namespace MWGui
}
}
}
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
mSpellArea->setVisibleVScroll(false);
mSpellArea->setCanvasSize(MyGUI::IntSize(mSpellArea->getWidth(), std::max(mSpellArea->getHeight(), coord.top)));
mSpellArea->setVisibleVScroll(true);
mSpellArea->setViewOffset(MyGUI::IntPoint(0, 0));
}
}

@ -47,7 +47,7 @@ namespace MWGui
void updateSpells();
MyGUI::ListBox* mBirthList;
MyGUI::Widget* mSpellArea;
MyGUI::ScrollView* mSpellArea;
MyGUI::ImageBox* mBirthImage;
std::vector<MyGUI::Widget*> mSpellItems;

@ -750,7 +750,9 @@ namespace MWGui
lastId = item.getCellRef().getRefId();
if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() && isRightHandWeapon(item))
if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() &&
isRightHandWeapon(item) &&
item.getClass().canBeEquipped(item, player).first)
{
found = true;
break;

@ -1988,8 +1988,9 @@ namespace MWMechanics
{
std::string id = reader.getHString();
int count;
reader.getHNT (count, "COUN");
mDeathCount[id] = count;
reader.getHNT(count, "COUN");
if (MWBase::Environment::get().getWorld()->getStore().find(id))
mDeathCount[id] = count;
}
}
}

@ -1822,20 +1822,11 @@ void CharacterController::update(float duration)
if(sneak || inwater || flying)
vec.z() = 0.0f;
if (inwater || flying)
cls.getCreatureStats(mPtr).land();
bool inJump = true;
if(!onground && !flying && !inwater)
{
// In the air (either getting up —ascending part of jump— or falling).
if (world->isSlowFalling(mPtr))
{
// SlowFalling spell effect is active, do not keep previous fall height
cls.getCreatureStats(mPtr).land();
}
forcestateupdate = (mJumpState != JumpState_InAir);
jumpstate = JumpState_InAir;
@ -1881,7 +1872,7 @@ void CharacterController::update(float duration)
}
}
}
else if(mJumpState == JumpState_InAir)
else if(mJumpState == JumpState_InAir && !inwater && !flying)
{
forcestateupdate = true;
jumpstate = JumpState_Landing;
@ -1964,9 +1955,6 @@ void CharacterController::update(float duration)
movestate = mMovementState;
}
if (onground)
cls.getCreatureStats(mPtr).land();
if(movestate != CharState_None && movestate != CharState_TurnLeft && movestate != CharState_TurnRight)
clearAnimQueue();

@ -1404,14 +1404,16 @@ namespace MWPhysics
// Slow fall reduces fall speed by a factor of (effect magnitude / 200)
float slowFall = 1.f - std::max(0.f, std::min(1.f, effects.get(ESM::MagicEffect::SlowFall).getMagnitude() * 0.005f));
bool flying = world->isFlying(iter->first);
bool wasOnGround = physicActor->getOnGround();
osg::Vec3f position = physicActor->getPosition();
float oldHeight = position.z();
bool positionChanged = false;
for (int i=0; i<numSteps; ++i)
{
position = MovementSolver::move(position, physicActor->getPtr(), physicActor, iter->second, physicsDt,
world->isFlying(iter->first),
waterlevel, slowFall, mCollisionWorld, mStandingCollisions);
flying, waterlevel, slowFall, mCollisionWorld, mStandingCollisions);
if (position != physicActor->getPosition())
positionChanged = true;
physicActor->setPosition(position); // always set even if unchanged to make sure interpolation is correct
@ -1424,8 +1426,11 @@ namespace MWPhysics
float heightDiff = position.z() - oldHeight;
if (heightDiff < 0)
iter->first.getClass().getCreatureStats(iter->first).addToFallHeight(-heightDiff);
MWMechanics::CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
if ((wasOnGround && physicActor->getOnGround()) || flying || world->isSwimming(iter->first) || slowFall < 1)
stats.land();
else if (heightDiff < 0)
stats.addToFallHeight(-heightDiff);
mMovementResults.push_back(std::make_pair(iter->first, interpolated));
}

@ -530,8 +530,10 @@ namespace MWRender
void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr)
{
if(mPlayerAnimation.get())
{
setupPlayer(ptr);
mPlayerAnimation->updatePtr(ptr);
}
mCamera->attachTo(ptr);
}
@ -834,6 +836,7 @@ namespace MWRender
player.getRefData().setBaseNode(mPlayerNode);
mWater->removeEmitter(player);
mWater->addEmitter(player);
}

@ -192,12 +192,11 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
{ AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 },
}};
auto fmt = std::find_if(fmtlist.cbegin(), fmtlist.cend(),
[chans,type](const FormatEntry &fmt) -> bool
{ return fmt.chans == chans && fmt.type == type; }
);
if(fmt != fmtlist.cend())
return fmt->format;
for(auto &fmt : fmtlist)
{
if(fmt.chans == chans && fmt.type == type)
return fmt.format;
}
if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
@ -209,18 +208,16 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
{ "AL_FORMAT_71CHN16", ChannelConfig_7point1, SampleType_Int16 },
{ "AL_FORMAT_71CHN8", ChannelConfig_7point1, SampleType_UInt8 },
}};
ALenum format = AL_NONE;
std::find_if(mcfmtlist.cbegin(), mcfmtlist.cend(),
[&format,chans,type](const FormatEntryExt &fmt) -> bool
for(auto &fmt : mcfmtlist)
{
if(fmt.chans == chans && fmt.type == type)
{
if(fmt.chans == chans && fmt.type == type)
format = alGetEnumValue(fmt.name);
return format != 0 && format != -1;
ALenum format = alGetEnumValue(fmt.name);
if(format != 0 && format != -1)
return format;
}
);
if(format != 0 && format != -1)
return format;
}
}
if(alIsExtensionPresent("AL_EXT_FLOAT32"))
{
@ -228,18 +225,16 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
{ "AL_FORMAT_MONO_FLOAT32", ChannelConfig_Mono, SampleType_Float32 },
{ "AL_FORMAT_STEREO_FLOAT32", ChannelConfig_Stereo, SampleType_Float32 },
}};
ALenum format = AL_NONE;
std::find_if(fltfmtlist.cbegin(), fltfmtlist.cend(),
[&format,chans,type](const FormatEntryExt &fmt) -> bool
for(auto &fmt : fltfmtlist)
{
if(fmt.chans == chans && fmt.type == type)
{
if(fmt.chans == chans && fmt.type == type)
format = alGetEnumValue(fmt.name);
return format != 0 && format != -1;
ALenum format = alGetEnumValue(fmt.name);
if(format != 0 && format != -1)
return format;
}
);
if(format != 0 && format != -1)
return format;
}
if(alIsExtensionPresent("AL_EXT_MCFORMATS"))
{
@ -249,16 +244,15 @@ static ALenum getALFormat(ChannelConfig chans, SampleType type)
{ "AL_FORMAT_71CHN32", ChannelConfig_7point1, SampleType_Float32 },
}};
std::find_if(fltmcfmtlist.cbegin(), fltmcfmtlist.cend(),
[&format,chans,type](const FormatEntryExt &fmt) -> bool
for(auto &fmt : fltmcfmtlist)
{
if(fmt.chans == chans && fmt.type == type)
{
if(fmt.chans == chans && fmt.type == type)
format = alGetEnumValue(fmt.name);
return format != 0 && format != -1;
ALenum format = alGetEnumValue(fmt.name);
if(format != 0 && format != -1)
return format;
}
);
if(format != 0 && format != -1)
return format;
}
}
}
@ -547,11 +541,11 @@ ALint OpenAL_SoundStream::refillQueue()
std::vector<char> data(mBufferSize);
for(;!mIsFinished && (ALuint)queued < mBuffers.size();++queued)
{
size_t got = mDecoder->read(&data[0], data.size());
size_t got = mDecoder->read(data.data(), data.size());
if(got < data.size())
{
mIsFinished = true;
std::memset(&data[got], mSilence, data.size()-got);
std::fill(data.begin()+got, data.end(), mSilence);
}
if(got > 0)
{
@ -559,7 +553,7 @@ ALint OpenAL_SoundStream::refillQueue()
mLoudnessAnalyzer->analyzeLoudness(data);
ALuint bufid = mBuffers[mCurrentBufIdx];
alBufferData(bufid, mFormat, &data[0], data.size(), mSampleRate);
alBufferData(bufid, mFormat, data.data(), data.size(), mSampleRate);
alSourceQueueBuffers(mSource, 1, &bufid);
mCurrentBufIdx = (mCurrentBufIdx+1) % mBuffers.size();
}
@ -594,25 +588,33 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
{
deinit();
std::cout<< "Initializing OpenAL..." <<std::endl;
mDevice = alcOpenDevice(devname.c_str());
if(!mDevice)
if(!mDevice && !devname.empty())
{
if(devname.empty())
std::cerr<< "Failed to open default audio device" <<std::endl;
else
std::cerr<< "Failed to open \""<<devname<<"\"" <<std::endl;
return false;
std::cerr<< "Failed to open \""<<devname<<"\", trying default" <<std::endl;
mDevice = alcOpenDevice(nullptr);
}
else
if(!mDevice)
{
const ALCchar *name = NULL;
if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT"))
name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER);
if(alcGetError(mDevice) != AL_NO_ERROR || !name)
name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER);
std::cout << "Opened \""<<name<<"\"" << std::endl;
std::cerr<< "Failed to open default audio device" <<std::endl;
return false;
}
const ALCchar *name = nullptr;
if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT"))
name = alcGetString(mDevice, ALC_ALL_DEVICES_SPECIFIER);
if(alcGetError(mDevice) != AL_NO_ERROR || !name)
name = alcGetString(mDevice, ALC_DEVICE_SPECIFIER);
std::cout<< "Opened \""<<name<<"\"" <<std::endl;
ALCint major=0, minor=0;
alcGetIntegerv(mDevice, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(mDevice, ALC_MINOR_VERSION, 1, &minor);
std::cout<< " ALC Version: "<<major<<"."<<minor<<"\n"<<
" ALC Extensions: "<<alcGetString(mDevice, ALC_EXTENSIONS) <<std::endl;
ALC.EXT_EFX = alcIsExtensionPresent(mDevice, "ALC_EXT_EFX");
ALC.SOFT_HRTF = alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF");
@ -643,7 +645,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
}
if(index < 0)
std::cerr<< "Failed to find HRTF name \""<<hrtfname<<"\", using default" <<std::endl;
std::cerr<< "Failed to find HRTF \""<<hrtfname<<"\", using default" <<std::endl;
else
{
attrs.push_back(ALC_HRTF_ID_SOFT);
@ -665,6 +667,11 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
return false;
}
std::cout<< " Vendor: "<<alGetString(AL_VENDOR)<<"\n"<<
" Renderer: "<<alGetString(AL_RENDERER)<<"\n"<<
" Version: "<<alGetString(AL_VERSION)<<"\n"<<
" Extensions: "<<alGetString(AL_EXTENSIONS)<<std::endl;
if(!ALC.SOFT_HRTF)
std::cout<< "HRTF status unavailable" <<std::endl;
else
@ -698,7 +705,7 @@ bool OpenAL_Output::init(const std::string &devname, const std::string &hrtfname
{
ALuint src = 0;
alGenSources(1, &src);
if(getALError() != AL_NO_ERROR)
if(alGetError() != AL_NO_ERROR)
break;
mFreeSources.push_back(src);
}
@ -824,8 +831,8 @@ void OpenAL_Output::deinit()
{
mStreamThread->removeAll();
for(size_t i = 0;i < mFreeSources.size();i++)
alDeleteSources(1, &mFreeSources[i]);
for(ALuint source : mFreeSources)
alDeleteSources(1, &source);
mFreeSources.clear();
if(mEffectSlot)
@ -934,7 +941,7 @@ void OpenAL_Output::setHrtf(const std::string &hrtfname, HrtfMode hrtfmode)
}
Sound_Handle OpenAL_Output::loadSound(const std::string &fname)
std::pair<Sound_Handle,size_t> OpenAL_Output::loadSound(const std::string &fname)
{
getALError();
@ -959,27 +966,31 @@ Sound_Handle OpenAL_Output::loadSound(const std::string &fname)
decoder->getInfo(&srate, &chans, &type);
format = getALFormat(chans, type);
if(!format) return nullptr;
if(!format) return std::make_pair(nullptr, 0);
decoder->readAll(data);
decoder->close();
ALint size;
ALuint buf = 0;
alGenBuffers(1, &buf);
alBufferData(buf, format, &data[0], data.size(), srate);
alBufferData(buf, format, data.data(), data.size(), srate);
alGetBufferi(buf, AL_SIZE, &size);
if(getALError() != AL_NO_ERROR)
{
if(buf && alIsBuffer(buf))
alDeleteBuffers(1, &buf);
getALError();
return nullptr;
return std::make_pair(nullptr, 0);
}
return MAKE_PTRID(buf);
return std::make_pair(MAKE_PTRID(buf), size);
}
void OpenAL_Output::unloadSound(Sound_Handle data)
size_t OpenAL_Output::unloadSound(Sound_Handle data)
{
ALuint buffer = GET_PTRID(data);
if(!buffer) return 0;
// Make sure no sources are playing this buffer before unloading it.
SoundVec::const_iterator iter = mActiveSounds.begin();
for(;iter != mActiveSounds.end();++iter)
@ -996,19 +1007,11 @@ void OpenAL_Output::unloadSound(Sound_Handle data)
alSourcei(source, AL_BUFFER, 0);
}
}
alDeleteBuffers(1, &buffer);
getALError();
}
size_t OpenAL_Output::getSoundDataSize(Sound_Handle data) const
{
ALuint buffer = GET_PTRID(data);
ALint size = 0;
alGetBufferi(buffer, AL_SIZE, &size);
alDeleteBuffers(1, &buffer);
getALError();
return (ALuint)size;
return size;
}
@ -1368,23 +1371,19 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi
if(mWaterFilter)
{
ALuint filter = (env == Env_Underwater) ? mWaterFilter : AL_FILTER_NULL;
std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(),
[filter](const SoundVec::value_type &item) -> void
{
if(item->getUseEnv())
alSourcei(GET_PTRID(item->mHandle), AL_DIRECT_FILTER, filter);
}
);
std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(),
[filter](const StreamVec::value_type &item) -> void
{
if(item->getUseEnv())
alSourcei(
reinterpret_cast<OpenAL_SoundStream*>(item->mHandle)->mSource,
AL_DIRECT_FILTER, filter
);
}
);
for(Sound *sound : mActiveSounds)
{
if(sound->getUseEnv())
alSourcei(GET_PTRID(sound->mHandle), AL_DIRECT_FILTER, filter);
}
for(Stream *sound : mActiveStreams)
{
if(sound->getUseEnv())
alSourcei(
reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle)->mSource,
AL_DIRECT_FILTER, filter
);
}
}
// Update the environment effect
if(mEffectSlot)
@ -1403,23 +1402,19 @@ void OpenAL_Output::updateListener(const osg::Vec3f &pos, const osg::Vec3f &atdi
void OpenAL_Output::pauseSounds(int types)
{
std::vector<ALuint> sources;
std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(),
[types,&sources](const SoundVec::value_type &sound) -> void
{
if(sound && sound->mHandle && (types&sound->getPlayType()))
sources.push_back(GET_PTRID(sound->mHandle));
}
);
std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(),
[types,&sources](const StreamVec::value_type &stream) -> void
for(Sound *sound : mActiveSounds)
{
if((types&sound->getPlayType()))
sources.push_back(GET_PTRID(sound->mHandle));
}
for(Stream *sound : mActiveStreams)
{
if((types&sound->getPlayType()))
{
if(stream && stream->mHandle && (types&stream->getPlayType()))
{
OpenAL_SoundStream *strm = reinterpret_cast<OpenAL_SoundStream*>(stream->mHandle);
sources.push_back(strm->mSource);
}
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
sources.push_back(stream->mSource);
}
);
}
if(!sources.empty())
{
alSourcePausev(sources.size(), sources.data());
@ -1430,23 +1425,19 @@ void OpenAL_Output::pauseSounds(int types)
void OpenAL_Output::resumeSounds(int types)
{
std::vector<ALuint> sources;
std::for_each(mActiveSounds.cbegin(), mActiveSounds.cend(),
[types,&sources](const SoundVec::value_type &sound) -> void
{
if(sound && sound->mHandle && (types&sound->getPlayType()))
sources.push_back(GET_PTRID(sound->mHandle));
}
);
std::for_each(mActiveStreams.cbegin(), mActiveStreams.cend(),
[types,&sources](const StreamVec::value_type &stream) -> void
for(Sound *sound : mActiveSounds)
{
if((types&sound->getPlayType()))
sources.push_back(GET_PTRID(sound->mHandle));
}
for(Stream *sound : mActiveStreams)
{
if((types&sound->getPlayType()))
{
if(stream && stream->mHandle && (types&stream->getPlayType()))
{
OpenAL_SoundStream *strm = reinterpret_cast<OpenAL_SoundStream*>(stream->mHandle);
sources.push_back(strm->mSource);
}
OpenAL_SoundStream *stream = reinterpret_cast<OpenAL_SoundStream*>(sound->mHandle);
sources.push_back(stream->mSource);
}
);
}
if(!sources.empty())
{
alSourcePlayv(sources.size(), sources.data());

@ -66,9 +66,8 @@ namespace MWSound
virtual std::vector<std::string> enumerateHrtf();
virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode);
virtual Sound_Handle loadSound(const std::string &fname);
virtual void unloadSound(Sound_Handle data);
virtual size_t getSoundDataSize(Sound_Handle data) const;
virtual std::pair<Sound_Handle,size_t> loadSound(const std::string &fname);
virtual size_t unloadSound(Sound_Handle data);
virtual bool playSound(Sound *sound, Sound_Handle data, float offset);
virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset);

@ -36,9 +36,8 @@ namespace MWSound
virtual std::vector<std::string> enumerateHrtf() = 0;
virtual void setHrtf(const std::string &hrtfname, HrtfMode hrtfmode) = 0;
virtual Sound_Handle loadSound(const std::string &fname) = 0;
virtual void unloadSound(Sound_Handle data) = 0;
virtual size_t getSoundDataSize(Sound_Handle data) const = 0;
virtual std::pair<Sound_Handle,size_t> loadSound(const std::string &fname) = 0;
virtual size_t unloadSound(Sound_Handle data) = 0;
virtual bool playSound(Sound *sound, Sound_Handle data, float offset) = 0;
virtual bool playSound3D(Sound *sound, Sound_Handle data, float offset) = 0;

@ -26,11 +26,7 @@
#include "sound.hpp"
#include "openal_output.hpp"
#define SOUND_OUT "OpenAL"
#include "ffmpeg_decoder.hpp"
#ifndef SOUND_IN
#define SOUND_IN "FFmpeg"
#endif
namespace MWSound
@ -84,45 +80,35 @@ namespace MWSound
mBufferCacheMin = std::min(mBufferCacheMin*1024*1024, mBufferCacheMax);
if(!useSound)
{
std::cout<< "Sound disabled." <<std::endl;
return;
}
std::string hrtfname = Settings::Manager::getString("hrtf", "Sound");
int hrtfstate = Settings::Manager::getInt("hrtf enable", "Sound");
HrtfMode hrtfmode = hrtfstate < 0 ? HrtfMode::Auto :
hrtfstate > 0 ? HrtfMode::Enable : HrtfMode::Disable;
std::cout << "Sound output: " << SOUND_OUT << std::endl;
std::cout << "Sound decoder: " << SOUND_IN << std::endl;
std::vector<std::string> names = mOutput->enumerate();
std::cout <<"Enumerated output devices:\n";
std::for_each(names.cbegin(), names.cend(),
[](const std::string &name) -> void
{ std::cout <<" "<<name<<"\n"; }
);
std::cout.flush();
std::string devname = Settings::Manager::getString("device", "Sound");
bool inited = mOutput->init(devname, hrtfname, hrtfmode);
if(!inited && !devname.empty())
{
std::cerr<< "Failed to initialize device \""<<devname<<"\", trying default" <<std::endl;
inited = mOutput->init(std::string(), hrtfname, hrtfmode);
}
if(!inited)
if(!mOutput->init(devname, hrtfname, hrtfmode))
{
std::cerr<< "Failed to initialize default audio device, sound disabled" <<std::endl;
std::cerr<< "Failed to initialize audio output, sound disabled" <<std::endl;
return;
}
std::vector<std::string> names = mOutput->enumerate();
std::cout <<"Enumerated output devices:\n";
for(const std::string &name : names)
std::cout <<" "<<name<<"\n";
std::cout.flush();
names = mOutput->enumerateHrtf();
if(!names.empty())
{
std::cout<< "Enumerated HRTF names:\n";
std::for_each(names.cbegin(), names.cend(),
[](const std::string &name) -> void
{ std::cout<< " "<<name<<"\n"; }
);
for(const std::string &name : names)
std::cout <<" "<<name<<"\n";
std::cout.flush();
}
}
@ -130,12 +116,11 @@ namespace MWSound
SoundManager::~SoundManager()
{
clear();
SoundBufferList::element_type::iterator sfxiter = mSoundBuffers->begin();
for(;sfxiter != mSoundBuffers->end();++sfxiter)
for(Sound_Buffer &sfx : *mSoundBuffers)
{
if(sfxiter->mHandle)
mOutput->unloadSound(sfxiter->mHandle);
sfxiter->mHandle = 0;
if(sfx.mHandle)
mOutput->unloadSound(sfx.mHandle);
sfx.mHandle = 0;
}
mUnusedBuffers.clear();
mOutput.reset();
@ -200,9 +185,23 @@ namespace MWSound
// minRange, and maxRange), and ensure it's ready for use.
Sound_Buffer *SoundManager::loadSound(const std::string &soundId)
{
#ifdef __GNUC__
#define LIKELY(x) __builtin_expect((bool)(x), true)
#define UNLIKELY(x) __builtin_expect((bool)(x), false)
#else
#define LIKELY(x) (bool)(x)
#define UNLIKELY(x) (bool)(x)
#endif
if(UNLIKELY(mBufferNameMap.empty()))
{
MWBase::World *world = MWBase::Environment::get().getWorld();
for(const ESM::Sound &sound : world->getStore().get<ESM::Sound>())
insertSound(Misc::StringUtils::lowerCase(sound.mId), &sound);
}
Sound_Buffer *sfx;
NameBufferMap::const_iterator snd = mBufferNameMap.find(soundId);
if(snd != mBufferNameMap.end())
if(LIKELY(snd != mBufferNameMap.end()))
sfx = snd->second;
else
{
@ -211,13 +210,16 @@ namespace MWSound
if(!sound) return nullptr;
sfx = insertSound(soundId, sound);
}
#undef LIKELY
#undef UNLIKELY
if(!sfx->mHandle)
{
sfx->mHandle = mOutput->loadSound(sfx->mResourceName);
size_t size;
std::tie(sfx->mHandle, size) = mOutput->loadSound(sfx->mResourceName);
if(!sfx->mHandle) return nullptr;
mBufferCacheSize += mOutput->getSoundDataSize(sfx->mHandle);
mBufferCacheSize += size;
if(mBufferCacheSize > mBufferCacheMax)
{
do {
@ -228,8 +230,8 @@ namespace MWSound
}
Sound_Buffer *unused = mUnusedBuffers.back();
mBufferCacheSize -= mOutput->getSoundDataSize(unused->mHandle);
mOutput->unloadSound(unused->mHandle);
size = mOutput->unloadSound(unused->mHandle);
mBufferCacheSize -= size;
unused->mHandle = 0;
mUnusedBuffers.pop_back();
@ -678,11 +680,10 @@ namespace MWSound
if(snditer != mActiveSounds.end())
{
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
for(SoundBufferRefPair &snd : snditer->second)
{
if(sndidx->second == sfx)
mOutput->finishSound(sndidx->first);
if(snd.second == sfx)
mOutput->finishSound(snd.first);
}
}
}
@ -692,33 +693,28 @@ namespace MWSound
SoundMap::iterator snditer = mActiveSounds.find(ptr);
if(snditer != mActiveSounds.end())
{
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
mOutput->finishSound(sndidx->first);
for(SoundBufferRefPair &snd : snditer->second)
mOutput->finishSound(snd.first);
}
SaySoundMap::iterator sayiter = mActiveSaySounds.find(ptr);
if(sayiter != mActiveSaySounds.end())
mOutput->finishStream(sayiter->second);
}
void SoundManager::stopSound(const MWWorld::CellStore *cell)
{
SoundMap::iterator snditer = mActiveSounds.begin();
for(;snditer != mActiveSounds.end();++snditer)
for(SoundMap::value_type &snd : mActiveSounds)
{
if(snditer->first != MWWorld::ConstPtr() &&
snditer->first != MWMechanics::getPlayer() &&
snditer->first.getCell() == cell)
if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
{
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
mOutput->finishSound(sndidx->first);
for(SoundBufferRefPair &sndbuf : snd.second)
mOutput->finishSound(sndbuf.first);
}
}
SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
for(;sayiter != mActiveSaySounds.end();++sayiter)
for(SaySoundMap::value_type &snd : mActiveSaySounds)
{
if(sayiter->first != MWWorld::ConstPtr() &&
sayiter->first != MWMechanics::getPlayer() &&
sayiter->first.getCell() == cell)
mOutput->finishStream(sayiter->second);
if(!snd.first.isEmpty() && snd.first != MWMechanics::getPlayer() && snd.first.getCell() == cell)
mOutput->finishStream(snd.second);
}
}
@ -728,11 +724,10 @@ namespace MWSound
if(snditer != mActiveSounds.end())
{
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
for(SoundBufferRefPair &sndbuf : snditer->second)
{
if(sndidx->second == sfx)
mOutput->finishSound(sndidx->first);
if(sndbuf.second == sfx)
mOutput->finishSound(sndbuf.first);
}
}
}
@ -744,11 +739,10 @@ namespace MWSound
if(snditer != mActiveSounds.end())
{
Sound_Buffer *sfx = loadSound(Misc::StringUtils::lowerCase(soundId));
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
for(SoundBufferRefPair &sndbuf : snditer->second)
{
if(sndidx->second == sfx)
sndidx->first->setFadeout(duration);
if(sndbuf.second == sfx)
sndbuf.first->setFadeout(duration);
}
}
}
@ -759,12 +753,10 @@ namespace MWSound
if(snditer != mActiveSounds.end())
{
Sound_Buffer *sfx = lookupSound(Misc::StringUtils::lowerCase(soundId));
SoundBufferRefPairList::const_iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
{
if(sndidx->second == sfx && mOutput->isSoundPlaying(sndidx->first))
return true;
}
return std::find_if(snditer->second.cbegin(), snditer->second.cend(),
[this,sfx](const SoundBufferRefPair &snd) -> bool
{ return snd.second == sfx && mOutput->isSoundPlaying(snd.first); }
) != snditer->second.cend();
}
return false;
}
@ -823,10 +815,8 @@ namespace MWSound
if(total == 0)
{
std::for_each(regn->mSoundList.cbegin(), regn->mSoundList.cend(),
[](const ESM::Region::SoundRef &sndref) -> void
{ total += (int)sndref.mChance; }
);
for(const ESM::Region::SoundRef &sndref : regn->mSoundList)
total += (int)sndref.mChance;
if(total == 0)
return;
}
@ -834,20 +824,15 @@ namespace MWSound
int r = Misc::Rng::rollDice(total);
int pos = 0;
std::find_if_not(regn->mSoundList.cbegin(), regn->mSoundList.cend(),
[&pos, r, this](const ESM::Region::SoundRef &sndref) -> bool
for(const ESM::Region::SoundRef &sndref : regn->mSoundList)
{
if(r - pos < sndref.mChance)
{
if(r - pos < sndref.mChance)
{
playSound(sndref.mSound.toString(), 1.0f, 1.0f);
// Played this sound, stop iterating
return false;
}
pos += sndref.mChance;
// Not this sound, keep iterating
return true;
playSound(sndref.mSound.toString(), 1.0f, 1.0f);
break;
}
);
pos += sndref.mChance;
}
}
void SoundManager::updateWaterSound(float /*duration*/)
@ -1135,28 +1120,23 @@ namespace MWSound
if(!mOutput->isInitialized())
return;
mOutput->startUpdate();
SoundMap::iterator snditer = mActiveSounds.begin();
for(;snditer != mActiveSounds.end();++snditer)
for(SoundMap::value_type &snd : mActiveSounds)
{
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
for(SoundBufferRefPair &sndbuf : snd.second)
{
Sound *sound = sndidx->first;
Sound *sound = sndbuf.first;
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateSound(sound);
}
}
SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
for(;sayiter != mActiveSaySounds.end();++sayiter)
for(SaySoundMap::value_type &snd : mActiveSaySounds)
{
Stream *sound = sayiter->second;
Stream *sound = snd.second;
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound);
}
TrackList::iterator trkiter = mActiveTracks.begin();
for(;trkiter != mActiveTracks.end();++trkiter)
for(Stream *sound : mActiveTracks)
{
Stream *sound = *trkiter;
sound->setBaseVolume(volumeFromType(sound->getPlayType()));
mOutput->updateStream(sound);
}
@ -1262,36 +1242,35 @@ namespace MWSound
void SoundManager::clear()
{
SoundMap::iterator snditer = mActiveSounds.begin();
for(;snditer != mActiveSounds.end();++snditer)
stopMusic();
for(SoundMap::value_type &snd : mActiveSounds)
{
SoundBufferRefPairList::iterator sndidx = snditer->second.begin();
for(;sndidx != snditer->second.end();++sndidx)
for(SoundBufferRefPair &sndbuf : snd.second)
{
mOutput->finishSound(sndidx->first);
mUnusedSounds.push_back(sndidx->first);
Sound_Buffer *sfx = sndidx->second;
mOutput->finishSound(sndbuf.first);
mUnusedSounds.push_back(sndbuf.first);
Sound_Buffer *sfx = sndbuf.second;
if(sfx->mUses-- == 1)
mUnusedBuffers.push_front(sfx);
}
}
mActiveSounds.clear();
SaySoundMap::iterator sayiter = mActiveSaySounds.begin();
for(;sayiter != mActiveSaySounds.end();++sayiter)
mUnderwaterSound = nullptr;
mNearWaterSound = nullptr;
for(SaySoundMap::value_type &snd : mActiveSaySounds)
{
mOutput->finishStream(sayiter->second);
mUnusedStreams.push_back(sayiter->second);
mOutput->finishStream(snd.second);
mUnusedStreams.push_back(snd.second);
}
mActiveSaySounds.clear();
TrackList::iterator trkiter = mActiveTracks.begin();
for(;trkiter != mActiveTracks.end();++trkiter)
for(Stream *sound : mActiveTracks)
{
mOutput->finishStream(*trkiter);
mUnusedStreams.push_back(*trkiter);
mOutput->finishStream(sound);
mUnusedStreams.push_back(sound);
}
mActiveTracks.clear();
mUnderwaterSound = nullptr;
mNearWaterSound = nullptr;
stopMusic();
}
}

@ -34,21 +34,19 @@ namespace Misc
if (i < m.size())
{
int precision = 0;
bool precisionSet = false;
int precision = -1;
if (m[i] == '.')
{
precision = 0;
while (++i < m.size() && m[i] >= '0' && m[i] <= '9')
{
precision = precision * 10 + (m[i] - '0');
precisionSet = true;
}
}
if (i < m.size())
{
width = (widthSet) ? width : -1;
precision = (precisionSet) ? precision : -1;
if (m[i] == 'S' || m[i] == 's')
visitedPlaceholder(StringPlaceholder, pad, width, precision);

@ -304,3 +304,42 @@ already checked. Load a game and make your way to Seyda Neen - or start a new ga
Check whether Arrille has one (or more) for sale, and whether Fargoth give you one
when you return his healing ring.
Placing in a chest
******************
For this example we will use the small chest intended for lockpick practice,
located in the Census and Excise Office in Seyda Neen.
First we need the ID of the chest - this can be obtained either by clicking on it in the console
in the game, or by applying a similar process in the CS -
World/Cells
Select "Seyda Neen, Census and Excise Office"
Right-click and select "View"
Use mouse wheel to zoom in/out, and mouse plus WASD keys to navigate
Click on the small chest
Either way, you should find the ID, which is "chest_small_02_lockprac".
Open the Objects table (World/Objects) and scroll down to find this item.
Alternatively use the Edit/Search facility, selecting ID rather than text,
enter "lockprac" (without the quotes) into the search box, press "Search",
which should return two rows, then select the "Container" one rather than the "Instance"
Right-click and "Edit Record".
Right-click the "Content" section and select "Add a row"
Set the Item ID of the new row to be your new ring - simplest way is probably to open the Objects
table if it's not already open, sort on the "Modified" column which should bring the ring,
with its status of "Added" to the top, then drag and drop to the chest row.
Increase the Count to 1.
Save the addon, then test to ensure it works - e.g. start a new game and lockpick the chest.

@ -11,7 +11,9 @@
</Widget>
<!-- Spell list -->
<Widget type="Widget" skin="" position="8 160 519 178" align="Left Top" name="SpellArea"/>
<Widget type="ScrollView" skin="MW_ScrollView" position="8 160 507 170" align="Left Top" name="SpellArea">
<Property key="CanvasAlign" value="Left"/>
</Widget>>
<!-- Dialog buttons -->
<Widget type="HBox" position="0 338 511 24">

Loading…
Cancel
Save