mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-06 07:45:36 +00:00
Implement Lua bindings for sound system
This commit is contained in:
parent
18f3e937cb
commit
7ce9fc25c5
21 changed files with 605 additions and 51 deletions
|
@ -61,7 +61,7 @@ add_openmw_dir (mwscript
|
|||
add_openmw_dir (mwlua
|
||||
luamanagerimp object worldview userdataserializer luaevents engineevents objectvariant
|
||||
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings
|
||||
camerabindings uibindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
||||
camerabindings uibindings soundbindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
||||
types/types types/door types/item types/actor types/container types/lockable types/weapon types/npc types/creature types/player types/activator types/book types/lockpick types/probe types/apparatus types/potion types/ingredient types/misc types/repair types/armor types/light types/static types/clothing types/levelledlist types/terminal
|
||||
worker magicbindings
|
||||
)
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace MWSound
|
|||
NoScaling = 1 << 4, /* Don't scale audio with simulation time */
|
||||
NoEnvNoScaling = NoEnv | NoScaling,
|
||||
LoopNoEnv = Loop | NoEnv,
|
||||
LoopNoEnvNoScaling = Loop | NoEnv | NoScaling,
|
||||
LoopRemoveAtDistance = Loop | RemoveAtDistance
|
||||
};
|
||||
|
||||
|
@ -117,11 +118,11 @@ namespace MWBase
|
|||
|
||||
virtual void say(const MWWorld::ConstPtr& reference, const std::string& filename) = 0;
|
||||
///< Make an actor say some text.
|
||||
/// \param filename name of a sound file in "Sound/" in the data directory.
|
||||
/// \param filename name of a sound file in the VFS
|
||||
|
||||
virtual void say(const std::string& filename) = 0;
|
||||
///< Say some text, without an actor ref
|
||||
/// \param filename name of a sound file in "Sound/" in the data directory.
|
||||
/// \param filename name of a sound file in the VFS
|
||||
|
||||
virtual bool sayActive(const MWWorld::ConstPtr& reference = MWWorld::ConstPtr()) const = 0;
|
||||
///< Is actor not speaking?
|
||||
|
@ -155,6 +156,12 @@ namespace MWBase
|
|||
///< Play a sound, independently of 3D-position
|
||||
///< @param offset Number of seconds into the sound to start playback.
|
||||
|
||||
virtual Sound* playSound(std::string_view fileName, float volume, float pitch, Type type = Type::Sfx,
|
||||
PlayMode mode = PlayMode::Normal, float offset = 0)
|
||||
= 0;
|
||||
///< Play a sound, independently of 3D-position
|
||||
///< @param offset Number of seconds into the sound to start playback.
|
||||
|
||||
virtual Sound* playSound3D(const MWWorld::ConstPtr& reference, const ESM::RefId& soundId, float volume,
|
||||
float pitch, Type type = Type::Sfx, PlayMode mode = PlayMode::Normal, float offset = 0)
|
||||
= 0;
|
||||
|
@ -162,6 +169,13 @@ namespace MWBase
|
|||
///< Play_NoTrack is specified.
|
||||
///< @param offset Number of seconds into the sound to start playback.
|
||||
|
||||
virtual Sound* playSound3D(const MWWorld::ConstPtr& reference, std::string_view fileName, float volume,
|
||||
float pitch, Type type = Type::Sfx, PlayMode mode = PlayMode::Normal, float offset = 0)
|
||||
= 0;
|
||||
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless
|
||||
///< Play_NoTrack is specified.
|
||||
///< @param offset Number of seconds into the sound to start playback.
|
||||
|
||||
virtual Sound* playSound3D(const osg::Vec3f& initialPos, const ESM::RefId& soundId, float volume, float pitch,
|
||||
Type type = Type::Sfx, PlayMode mode = PlayMode::Normal, float offset = 0)
|
||||
= 0;
|
||||
|
@ -172,7 +186,10 @@ namespace MWBase
|
|||
///< Stop the given sound from playing
|
||||
|
||||
virtual void stopSound3D(const MWWorld::ConstPtr& reference, const ESM::RefId& soundId) = 0;
|
||||
///< Stop the given object from playing the given sound,
|
||||
///< Stop the given object from playing the given sound.
|
||||
|
||||
virtual void stopSound3D(const MWWorld::ConstPtr& reference, std::string_view fileName) = 0;
|
||||
///< Stop the given object from playing the given sound.
|
||||
|
||||
virtual void stopSound3D(const MWWorld::ConstPtr& reference) = 0;
|
||||
///< Stop the given object from playing all sounds.
|
||||
|
@ -190,6 +207,10 @@ namespace MWBase
|
|||
///< Is the given sound currently playing on the given object?
|
||||
/// If you want to check if sound played with playSound is playing, use empty Ptr
|
||||
|
||||
virtual bool getSoundPlaying(const MWWorld::ConstPtr& reference, std::string_view fileName) const = 0;
|
||||
///< Is the given sound currently playing on the given object?
|
||||
/// If you want to check if sound played with playSound is playing, use empty Ptr
|
||||
|
||||
virtual void pauseSounds(MWSound::BlockerType blocker, int types = int(Type::Mask)) = 0;
|
||||
///< Pauses all currently playing sounds, including music.
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <components/interpreter/defines.hpp>
|
||||
#include <components/interpreter/interpreter.hpp>
|
||||
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
|
||||
#include <components/settings/values.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -650,7 +652,7 @@ namespace MWDialogue
|
|||
if (Settings::gui().mSubtitles)
|
||||
winMgr->messageBox(info->mResponse);
|
||||
if (!info->mSound.empty())
|
||||
sndMgr->say(actor, info->mSound);
|
||||
sndMgr->say(actor, Misc::ResourceHelpers::correctSoundPath(info->mSound));
|
||||
if (!info->mResultScript.empty())
|
||||
executeScript(info->mResultScript, actor);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/fallback/fallback.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -656,7 +657,7 @@ namespace MWGui
|
|||
+= MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen);
|
||||
mGenerateClassQuestionDialog->setVisible(true);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->say(step.mSound);
|
||||
MWBase::Environment::get().getSoundManager()->say(Misc::ResourceHelpers::correctSoundPath(step.mSound));
|
||||
}
|
||||
|
||||
void CharacterCreation::selectGeneratedClass()
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "nearbybindings.hpp"
|
||||
#include "objectbindings.hpp"
|
||||
#include "postprocessingbindings.hpp"
|
||||
#include "soundbindings.hpp"
|
||||
#include "types/types.hpp"
|
||||
#include "uibindings.hpp"
|
||||
|
||||
|
@ -123,6 +124,7 @@ namespace MWLua
|
|||
{ std::move(eventName), LuaUtil::serialize(eventData, context.mSerializer) });
|
||||
};
|
||||
api["contentFiles"] = initContentFilesBindings(lua->sol());
|
||||
api["sound"] = initCoreSoundBindings(context);
|
||||
api["getFormId"] = [](std::string_view contentFile, unsigned int index) -> std::string {
|
||||
const std::vector<std::string>& contentList = MWBase::Environment::get().getWorld()->getContentFiles();
|
||||
for (size_t i = 0; i < contentList.size(); ++i)
|
||||
|
@ -324,6 +326,7 @@ namespace MWLua
|
|||
std::map<std::string, sol::object> initPlayerPackages(const Context& context)
|
||||
{
|
||||
return {
|
||||
{ "openmw.ambient", initAmbientPackage(context) },
|
||||
{ "openmw.camera", initCameraPackage(context.mLua->sol()) },
|
||||
{ "openmw.debug", initDebugPackage(context) },
|
||||
{ "openmw.input", initInputPackage(context) },
|
||||
|
|
159
apps/openmw/mwlua/soundbindings.cpp
Normal file
159
apps/openmw/mwlua/soundbindings.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
#include "soundbindings.hpp"
|
||||
#include "luabindings.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "luamanagerimp.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
struct PlaySoundArgs
|
||||
{
|
||||
bool mScale = true;
|
||||
bool mLoop = false;
|
||||
float mVolume = 1.f;
|
||||
float mPitch = 1.f;
|
||||
float mTimeOffset = 0.f;
|
||||
};
|
||||
|
||||
PlaySoundArgs getPlaySoundArgs(const sol::optional<sol::table>& options)
|
||||
{
|
||||
PlaySoundArgs args;
|
||||
|
||||
if (options.has_value())
|
||||
{
|
||||
args.mLoop = options->get_or("loop", false);
|
||||
args.mVolume = options->get_or("volume", 1.f);
|
||||
args.mPitch = options->get_or("pitch", 1.f);
|
||||
args.mTimeOffset = options->get_or("timeOffset", 0.f);
|
||||
args.mScale = options->get_or("scale", true);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
MWSound::PlayMode getPlayMode(const PlaySoundArgs& args, bool is3D)
|
||||
{
|
||||
if (is3D)
|
||||
{
|
||||
if (args.mLoop)
|
||||
return MWSound::PlayMode::LoopRemoveAtDistance;
|
||||
return MWSound::PlayMode::Normal;
|
||||
}
|
||||
|
||||
if (args.mLoop && !args.mScale)
|
||||
return MWSound::PlayMode::LoopNoEnvNoScaling;
|
||||
else if (args.mLoop)
|
||||
return MWSound::PlayMode::LoopNoEnv;
|
||||
else if (!args.mScale)
|
||||
return MWSound::PlayMode::NoEnvNoScaling;
|
||||
return MWSound::PlayMode::NoEnv;
|
||||
}
|
||||
|
||||
sol::table initAmbientPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
|
||||
api["playSound"] = [](std::string_view soundId, const sol::optional<sol::table>& options) {
|
||||
auto args = getPlaySoundArgs(options);
|
||||
auto playMode = getPlayMode(args, false);
|
||||
ESM::RefId sound = ESM::RefId::deserializeText(soundId);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound(
|
||||
sound, args.mVolume, args.mPitch, MWSound::Type::Sfx, playMode, args.mTimeOffset);
|
||||
};
|
||||
api["playSoundFile"] = [](std::string_view fileName, const sol::optional<sol::table>& options) {
|
||||
auto args = getPlaySoundArgs(options);
|
||||
auto playMode = getPlayMode(args, false);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound(
|
||||
fileName, args.mVolume, args.mPitch, MWSound::Type::Sfx, playMode, args.mTimeOffset);
|
||||
};
|
||||
|
||||
api["stopSound"] = [](std::string_view soundId) {
|
||||
ESM::RefId sound = ESM::RefId::deserializeText(soundId);
|
||||
MWBase::Environment::get().getSoundManager()->stopSound3D(MWWorld::Ptr(), sound);
|
||||
};
|
||||
api["stopSoundFile"] = [](std::string_view fileName) {
|
||||
MWBase::Environment::get().getSoundManager()->stopSound3D(MWWorld::Ptr(), fileName);
|
||||
};
|
||||
|
||||
api["isSoundPlaying"] = [](std::string_view soundId) {
|
||||
ESM::RefId sound = ESM::RefId::deserializeText(soundId);
|
||||
return MWBase::Environment::get().getSoundManager()->getSoundPlaying(MWWorld::Ptr(), sound);
|
||||
};
|
||||
api["isSoundFilePlaying"] = [](std::string_view fileName) {
|
||||
return MWBase::Environment::get().getSoundManager()->getSoundPlaying(MWWorld::Ptr(), fileName);
|
||||
};
|
||||
|
||||
return LuaUtil::makeReadOnly(api);
|
||||
}
|
||||
|
||||
sol::table initCoreSoundBindings(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
|
||||
api["playSound3d"]
|
||||
= [](std::string_view soundId, const Object& object, const sol::optional<sol::table>& options) {
|
||||
auto args = getPlaySoundArgs(options);
|
||||
auto playMode = getPlayMode(args, true);
|
||||
|
||||
ESM::RefId sound = ESM::RefId::deserializeText(soundId);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(
|
||||
object.ptr(), sound, args.mVolume, args.mPitch, MWSound::Type::Sfx, playMode, args.mTimeOffset);
|
||||
};
|
||||
api["playSoundFile3d"]
|
||||
= [](std::string_view fileName, const Object& object, const sol::optional<sol::table>& options) {
|
||||
auto args = getPlaySoundArgs(options);
|
||||
auto playMode = getPlayMode(args, true);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->playSound3D(object.ptr(), fileName, args.mVolume,
|
||||
args.mPitch, MWSound::Type::Sfx, playMode, args.mTimeOffset);
|
||||
};
|
||||
|
||||
api["stopSound3d"] = [](std::string_view soundId, const Object& object) {
|
||||
ESM::RefId sound = ESM::RefId::deserializeText(soundId);
|
||||
MWBase::Environment::get().getSoundManager()->stopSound3D(object.ptr(), sound);
|
||||
};
|
||||
api["stopSoundFile3d"] = [](std::string_view fileName, const Object& object) {
|
||||
MWBase::Environment::get().getSoundManager()->stopSound3D(object.ptr(), fileName);
|
||||
};
|
||||
|
||||
api["isSoundPlaying"] = [](std::string_view soundId, const Object& object) {
|
||||
ESM::RefId sound = ESM::RefId::deserializeText(soundId);
|
||||
return MWBase::Environment::get().getSoundManager()->getSoundPlaying(object.ptr(), sound);
|
||||
};
|
||||
api["isSoundFilePlaying"] = [](std::string_view fileName, const Object& object) {
|
||||
return MWBase::Environment::get().getSoundManager()->getSoundPlaying(object.ptr(), fileName);
|
||||
};
|
||||
|
||||
api["say"] = sol::overload(
|
||||
[luaManager = context.mLuaManager](
|
||||
std::string_view fileName, const Object& object, sol::optional<std::string_view> text) {
|
||||
MWBase::Environment::get().getSoundManager()->say(object.ptr(), std::string(fileName));
|
||||
if (text)
|
||||
luaManager->addUIMessage(*text);
|
||||
},
|
||||
[luaManager = context.mLuaManager](std::string_view fileName, sol::optional<std::string_view> text) {
|
||||
MWBase::Environment::get().getSoundManager()->say(std::string(fileName));
|
||||
if (text)
|
||||
luaManager->addUIMessage(*text);
|
||||
});
|
||||
api["stopSay"] = sol::overload(
|
||||
[](const Object& object) {
|
||||
const MWWorld::Ptr& objPtr = object.ptr();
|
||||
MWBase::Environment::get().getSoundManager()->stopSay(objPtr);
|
||||
},
|
||||
[]() { MWBase::Environment::get().getSoundManager()->stopSay(MWWorld::ConstPtr()); });
|
||||
api["isSayActive"] = sol::overload(
|
||||
[](const Object& object) {
|
||||
const MWWorld::Ptr& objPtr = object.ptr();
|
||||
return MWBase::Environment::get().getSoundManager()->sayActive(objPtr);
|
||||
},
|
||||
[]() { return MWBase::Environment::get().getSoundManager()->sayActive(MWWorld::ConstPtr()); });
|
||||
|
||||
return LuaUtil::makeReadOnly(api);
|
||||
}
|
||||
}
|
15
apps/openmw/mwlua/soundbindings.hpp
Normal file
15
apps/openmw/mwlua/soundbindings.hpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef MWLUA_SOUNDBINDINGS_H
|
||||
#define MWLUA_SOUNDBINDINGS_H
|
||||
|
||||
#include <sol/forward.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initCoreSoundBindings(const Context&);
|
||||
|
||||
sol::table initAmbientPackage(const Context& context);
|
||||
}
|
||||
|
||||
#endif // MWLUA_SOUNDBINDINGS_H
|
|
@ -5,6 +5,7 @@
|
|||
#include <components/interpreter/interpreter.hpp>
|
||||
#include <components/interpreter/opcodes.hpp>
|
||||
#include <components/interpreter/runtime.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/settings/values.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -38,7 +39,7 @@ namespace MWScript
|
|||
std::string_view text = runtime.getStringLiteral(runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->say(ptr, file);
|
||||
MWBase::Environment::get().getSoundManager()->say(ptr, Misc::ResourceHelpers::correctSoundPath(file));
|
||||
|
||||
if (Settings::gui().mSubtitles)
|
||||
context.messageBox(text);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/esm3/loadsoun.hpp>
|
||||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/vfs/pathutil.hpp>
|
||||
|
||||
|
@ -61,6 +62,35 @@ namespace MWSound
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::lookup(std::string_view fileName) const
|
||||
{
|
||||
auto soundId = ESM::RefId::stringRefId(fileName);
|
||||
return lookup(soundId);
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::loadSfx(Sound_Buffer* sfx)
|
||||
{
|
||||
if (sfx->getHandle() != nullptr)
|
||||
return sfx;
|
||||
|
||||
auto [handle, size] = mOutput->loadSound(sfx->getResourceName());
|
||||
if (handle == nullptr)
|
||||
return {};
|
||||
|
||||
sfx->mHandle = handle;
|
||||
|
||||
mBufferCacheSize += size;
|
||||
if (mBufferCacheSize > mBufferCacheMax)
|
||||
{
|
||||
unloadUnused();
|
||||
if (!mUnusedBuffers.empty() && mBufferCacheSize > mBufferCacheMax)
|
||||
Log(Debug::Warning) << "No unused sound buffers to free, using " << mBufferCacheSize << " bytes!";
|
||||
}
|
||||
mUnusedBuffers.push_front(sfx);
|
||||
|
||||
return sfx;
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::load(const ESM::RefId& soundId)
|
||||
{
|
||||
if (mBufferNameMap.empty())
|
||||
|
@ -81,25 +111,23 @@ namespace MWSound
|
|||
sfx = insertSound(soundId, *sound);
|
||||
}
|
||||
|
||||
if (sfx->getHandle() == nullptr)
|
||||
return loadSfx(sfx);
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::load(std::string_view fileName)
|
||||
{
|
||||
auto soundId = ESM::RefId::stringRefId(fileName);
|
||||
|
||||
Sound_Buffer* sfx;
|
||||
const auto it = mBufferNameMap.find(soundId);
|
||||
if (it != mBufferNameMap.end())
|
||||
sfx = it->second;
|
||||
else
|
||||
{
|
||||
auto [handle, size] = mOutput->loadSound(sfx->getResourceName());
|
||||
if (handle == nullptr)
|
||||
return {};
|
||||
|
||||
sfx->mHandle = handle;
|
||||
|
||||
mBufferCacheSize += size;
|
||||
if (mBufferCacheSize > mBufferCacheMax)
|
||||
{
|
||||
unloadUnused();
|
||||
if (!mUnusedBuffers.empty() && mBufferCacheSize > mBufferCacheMax)
|
||||
Log(Debug::Warning) << "No unused sound buffers to free, using " << mBufferCacheSize << " bytes!";
|
||||
}
|
||||
mUnusedBuffers.push_front(sfx);
|
||||
sfx = insertSound(fileName);
|
||||
}
|
||||
|
||||
return sfx;
|
||||
return loadSfx(sfx);
|
||||
}
|
||||
|
||||
void SoundBufferPool::clear()
|
||||
|
@ -113,6 +141,24 @@ namespace MWSound
|
|||
mUnusedBuffers.clear();
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::insertSound(std::string_view fileName)
|
||||
{
|
||||
static const AudioParams audioParams
|
||||
= makeAudioParams(MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>());
|
||||
|
||||
float volume = 1.f;
|
||||
float min = std::max(audioParams.mAudioDefaultMinDistance * audioParams.mAudioMinDistanceMult, 1.f);
|
||||
float max = std::max(min, audioParams.mAudioDefaultMaxDistance * audioParams.mAudioMaxDistanceMult);
|
||||
|
||||
min = std::max(min, 1.0f);
|
||||
max = std::max(min, max);
|
||||
|
||||
Sound_Buffer& sfx = mSoundBuffers.emplace_back(fileName, volume, min, max);
|
||||
|
||||
mBufferNameMap.emplace(ESM::RefId::stringRefId(fileName), &sfx);
|
||||
return &sfx;
|
||||
}
|
||||
|
||||
Sound_Buffer* SoundBufferPool::insertSound(const ESM::RefId& soundId, const ESM::Sound& sound)
|
||||
{
|
||||
static const AudioParams audioParams
|
||||
|
@ -132,7 +178,8 @@ namespace MWSound
|
|||
min = std::max(min, 1.0f);
|
||||
max = std::max(min, max);
|
||||
|
||||
Sound_Buffer& sfx = mSoundBuffers.emplace_back("Sound/" + sound.mSound, volume, min, max);
|
||||
Sound_Buffer& sfx
|
||||
= mSoundBuffers.emplace_back(Misc::ResourceHelpers::correctSoundPath(sound.mSound), volume, min, max);
|
||||
VFS::Path::normalizeFilenameInPlace(sfx.mResourceName);
|
||||
|
||||
mBufferNameMap.emplace(soundId, &sfx);
|
||||
|
|
|
@ -69,10 +69,17 @@ namespace MWSound
|
|||
/// minRange, and maxRange)
|
||||
Sound_Buffer* lookup(const ESM::RefId& soundId) const;
|
||||
|
||||
/// Lookup a sound by file name for its sound data (resource name, local volume,
|
||||
/// minRange, and maxRange)
|
||||
Sound_Buffer* lookup(std::string_view fileName) const;
|
||||
|
||||
/// Lookup a soundId for its sound data (resource name, local volume,
|
||||
/// minRange, and maxRange), and ensure it's ready for use.
|
||||
Sound_Buffer* load(const ESM::RefId& soundId);
|
||||
|
||||
// Lookup for a sound by file name, and ensure it's ready for use.
|
||||
Sound_Buffer* load(std::string_view fileName);
|
||||
|
||||
void use(Sound_Buffer& sfx)
|
||||
{
|
||||
if (sfx.mUses++ == 0)
|
||||
|
@ -92,6 +99,8 @@ namespace MWSound
|
|||
void clear();
|
||||
|
||||
private:
|
||||
Sound_Buffer* loadSfx(Sound_Buffer* sfx);
|
||||
|
||||
Sound_Output* mOutput;
|
||||
std::deque<Sound_Buffer> mSoundBuffers;
|
||||
std::unordered_map<ESM::RefId, Sound_Buffer*> mBufferNameMap;
|
||||
|
@ -102,6 +111,7 @@ namespace MWSound
|
|||
std::deque<Sound_Buffer*> mUnusedBuffers;
|
||||
|
||||
inline Sound_Buffer* insertSound(const ESM::RefId& soundId, const ESM::Sound& sound);
|
||||
inline Sound_Buffer* insertSound(std::string_view fileName);
|
||||
|
||||
inline void unloadUnused();
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <components/misc/resourcehelpers.hpp>
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/vfs/manager.hpp>
|
||||
#include <components/vfs/pathutil.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
@ -36,6 +37,7 @@ namespace MWSound
|
|||
constexpr float sMinUpdateInterval = 1.0f / 30.0f;
|
||||
constexpr float sSfxFadeInDuration = 1.0f;
|
||||
constexpr float sSfxFadeOutDuration = 1.0f;
|
||||
constexpr float sSoundCullDistance = 2000.f;
|
||||
|
||||
WaterSoundUpdaterSettings makeWaterSoundUpdaterSettings()
|
||||
{
|
||||
|
@ -357,7 +359,7 @@ namespace MWSound
|
|||
if (!mOutput->isInitialized())
|
||||
return;
|
||||
|
||||
DecoderPtr decoder = loadVoice("Sound/" + filename);
|
||||
DecoderPtr decoder = loadVoice(filename);
|
||||
if (!decoder)
|
||||
return;
|
||||
|
||||
|
@ -389,7 +391,7 @@ namespace MWSound
|
|||
if (!mOutput->isInitialized())
|
||||
return;
|
||||
|
||||
DecoderPtr decoder = loadVoice("Sound/" + filename);
|
||||
DecoderPtr decoder = loadVoice(filename);
|
||||
if (!decoder)
|
||||
return;
|
||||
|
||||
|
@ -486,14 +488,22 @@ namespace MWSound
|
|||
return mOutput->getStreamDelay(stream);
|
||||
}
|
||||
|
||||
Sound* SoundManager::playSound(
|
||||
const ESM::RefId& soundId, float volume, float pitch, Type type, PlayMode mode, float offset)
|
||||
bool SoundManager::remove3DSoundAtDistance(PlayMode mode, const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
if (!mOutput->isInitialized())
|
||||
return nullptr;
|
||||
return true;
|
||||
|
||||
Sound_Buffer* sfx = mSoundBuffers.load(soundId);
|
||||
if (!sfx)
|
||||
const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3());
|
||||
const float squaredDist = (mListenerPos - objpos).length2();
|
||||
if ((mode & PlayMode::RemoveAtDistance) && squaredDist > sSoundCullDistance * sSoundCullDistance)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Sound* SoundManager::playSound(Sound_Buffer* sfx, float volume, float pitch, Type type, PlayMode mode, float offset)
|
||||
{
|
||||
if (!mOutput->isInitialized())
|
||||
return nullptr;
|
||||
|
||||
// Only one copy of given sound can be played at time, so stop previous copy
|
||||
|
@ -517,25 +527,45 @@ namespace MWSound
|
|||
return result;
|
||||
}
|
||||
|
||||
Sound* SoundManager::playSound3D(const MWWorld::ConstPtr& ptr, const ESM::RefId& soundId, float volume, float pitch,
|
||||
Sound* SoundManager::playSound(
|
||||
std::string_view fileName, float volume, float pitch, Type type, PlayMode mode, float offset)
|
||||
{
|
||||
if (!mOutput->isInitialized())
|
||||
return nullptr;
|
||||
|
||||
std::string normalizedName = VFS::Path::normalizeFilename(fileName);
|
||||
Sound_Buffer* sfx = mSoundBuffers.load(normalizedName);
|
||||
if (!sfx)
|
||||
return nullptr;
|
||||
|
||||
return playSound(sfx, volume, pitch, type, mode, offset);
|
||||
}
|
||||
|
||||
Sound* SoundManager::playSound(
|
||||
const ESM::RefId& soundId, float volume, float pitch, Type type, PlayMode mode, float offset)
|
||||
{
|
||||
if (!mOutput->isInitialized())
|
||||
return nullptr;
|
||||
|
||||
Sound_Buffer* sfx = mSoundBuffers.load(soundId);
|
||||
if (!sfx)
|
||||
return nullptr;
|
||||
|
||||
return playSound(sfx, volume, pitch, type, mode, offset);
|
||||
}
|
||||
|
||||
Sound* SoundManager::playSound3D(const MWWorld::ConstPtr& ptr, Sound_Buffer* sfx, float volume, float pitch,
|
||||
Type type, PlayMode mode, float offset)
|
||||
{
|
||||
if (!mOutput->isInitialized())
|
||||
return nullptr;
|
||||
|
||||
const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3());
|
||||
const float squaredDist = (mListenerPos - objpos).length2();
|
||||
if ((mode & PlayMode::RemoveAtDistance) && squaredDist > 2000 * 2000)
|
||||
return nullptr;
|
||||
|
||||
// Look up the sound in the ESM data
|
||||
Sound_Buffer* sfx = mSoundBuffers.load(soundId);
|
||||
if (!sfx)
|
||||
return nullptr;
|
||||
|
||||
// Only one copy of given sound can be played at time on ptr, so stop previous copy
|
||||
stopSound(sfx, ptr);
|
||||
|
||||
const osg::Vec3f objpos(ptr.getRefData().getPosition().asVec3());
|
||||
const float squaredDist = (mListenerPos - objpos).length2();
|
||||
|
||||
bool played;
|
||||
SoundPtr sound = getSoundRef();
|
||||
if (!(mode & PlayMode::NoPlayerLocal) && ptr == MWMechanics::getPlayer())
|
||||
|
@ -578,6 +608,35 @@ namespace MWSound
|
|||
return result;
|
||||
}
|
||||
|
||||
Sound* SoundManager::playSound3D(const MWWorld::ConstPtr& ptr, const ESM::RefId& soundId, float volume, float pitch,
|
||||
Type type, PlayMode mode, float offset)
|
||||
{
|
||||
if (remove3DSoundAtDistance(mode, ptr))
|
||||
return nullptr;
|
||||
|
||||
// Look up the sound in the ESM data
|
||||
Sound_Buffer* sfx = mSoundBuffers.load(soundId);
|
||||
if (!sfx)
|
||||
return nullptr;
|
||||
|
||||
return playSound3D(ptr, sfx, volume, pitch, type, mode, offset);
|
||||
}
|
||||
|
||||
Sound* SoundManager::playSound3D(const MWWorld::ConstPtr& ptr, std::string_view fileName, float volume, float pitch,
|
||||
Type type, PlayMode mode, float offset)
|
||||
{
|
||||
if (remove3DSoundAtDistance(mode, ptr))
|
||||
return nullptr;
|
||||
|
||||
// Look up the sound
|
||||
std::string normalizedName = VFS::Path::normalizeFilename(fileName);
|
||||
Sound_Buffer* sfx = mSoundBuffers.load(normalizedName);
|
||||
if (!sfx)
|
||||
return nullptr;
|
||||
|
||||
return playSound3D(ptr, sfx, volume, pitch, type, mode, offset);
|
||||
}
|
||||
|
||||
Sound* SoundManager::playSound3D(const osg::Vec3f& initialPos, const ESM::RefId& soundId, float volume, float pitch,
|
||||
Type type, PlayMode mode, float offset)
|
||||
{
|
||||
|
@ -644,6 +703,13 @@ namespace MWSound
|
|||
stopSound(sfx, ptr);
|
||||
}
|
||||
|
||||
void SoundManager::stopSound3D(const MWWorld::ConstPtr& ptr, std::string_view fileName)
|
||||
{
|
||||
std::string normalizedName = VFS::Path::normalizeFilename(fileName);
|
||||
auto soundId = ESM::RefId::stringRefId(normalizedName);
|
||||
stopSound3D(ptr, soundId);
|
||||
}
|
||||
|
||||
void SoundManager::stopSound3D(const MWWorld::ConstPtr& ptr)
|
||||
{
|
||||
SoundMap::iterator snditer = mActiveSounds.find(ptr.mRef);
|
||||
|
@ -700,6 +766,13 @@ namespace MWSound
|
|||
}
|
||||
}
|
||||
|
||||
bool SoundManager::getSoundPlaying(const MWWorld::ConstPtr& ptr, std::string_view fileName) const
|
||||
{
|
||||
std::string normalizedName = VFS::Path::normalizeFilename(fileName);
|
||||
auto soundId = ESM::RefId::stringRefId(normalizedName);
|
||||
return getSoundPlaying(ptr, soundId);
|
||||
}
|
||||
|
||||
bool SoundManager::getSoundPlaying(const MWWorld::ConstPtr& ptr, const ESM::RefId& soundId) const
|
||||
{
|
||||
SoundMap::const_iterator snditer = mActiveSounds.find(ptr.mRef);
|
||||
|
@ -849,8 +922,8 @@ namespace MWSound
|
|||
|
||||
void SoundManager::cull3DSound(SoundBase* sound)
|
||||
{
|
||||
// Hard-coded distance of 2000.0f is from vanilla Morrowind
|
||||
const float maxDist = sound->getDistanceCull() ? 2000.0f : sound->getMaxDistance();
|
||||
// Hard-coded distance is from an original engine
|
||||
const float maxDist = sound->getDistanceCull() ? sSoundCullDistance : sound->getMaxDistance();
|
||||
const float squaredMaxDist = maxDist * maxDist;
|
||||
|
||||
const osg::Vec3f pos = sound->getPosition();
|
||||
|
|
|
@ -132,6 +132,13 @@ namespace MWSound
|
|||
|
||||
void cull3DSound(SoundBase* sound);
|
||||
|
||||
bool remove3DSoundAtDistance(PlayMode mode, const MWWorld::ConstPtr& ptr) const;
|
||||
|
||||
Sound* playSound(Sound_Buffer* sfx, float volume, float pitch, Type type = Type::Sfx,
|
||||
PlayMode mode = PlayMode::Normal, float offset = 0);
|
||||
Sound* playSound3D(const MWWorld::ConstPtr& ptr, Sound_Buffer* sfx, float volume, float pitch, Type type,
|
||||
PlayMode mode, float offset);
|
||||
|
||||
void updateSounds(float duration);
|
||||
void updateRegionSound(float duration);
|
||||
void updateWaterSound();
|
||||
|
@ -183,11 +190,11 @@ namespace MWSound
|
|||
|
||||
void say(const MWWorld::ConstPtr& reference, const std::string& filename) override;
|
||||
///< Make an actor say some text.
|
||||
/// \param filename name of a sound file in "Sound/" in the data directory.
|
||||
/// \param filename name of a sound file in the VFS
|
||||
|
||||
void say(const std::string& filename) override;
|
||||
///< Say some text, without an actor ref
|
||||
/// \param filename name of a sound file in "Sound/" in the data directory.
|
||||
/// \param filename name of a sound file in the VFS
|
||||
|
||||
bool sayActive(const MWWorld::ConstPtr& reference = MWWorld::ConstPtr()) const override;
|
||||
///< Is actor not speaking?
|
||||
|
@ -219,12 +226,23 @@ namespace MWSound
|
|||
///< Play a sound, independently of 3D-position
|
||||
///< @param offset Number of seconds into the sound to start playback.
|
||||
|
||||
Sound* playSound(std::string_view fileName, float volume, float pitch, Type type = Type::Sfx,
|
||||
PlayMode mode = PlayMode::Normal, float offset = 0) override;
|
||||
///< Play a sound, independently of 3D-position
|
||||
///< @param offset Number of seconds into the sound to start playback.
|
||||
|
||||
Sound* playSound3D(const MWWorld::ConstPtr& reference, const ESM::RefId& soundId, float volume, float pitch,
|
||||
Type type = Type::Sfx, PlayMode mode = PlayMode::Normal, float offset = 0) override;
|
||||
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless
|
||||
///< Play_NoTrack is specified.
|
||||
///< @param offset Number of seconds into the sound to start playback.
|
||||
|
||||
Sound* playSound3D(const MWWorld::ConstPtr& reference, std::string_view fileName, float volume, float pitch,
|
||||
Type type = Type::Sfx, PlayMode mode = PlayMode::Normal, float offset = 0) override;
|
||||
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless
|
||||
///< Play_NoTrack is specified.
|
||||
///< @param offset Number of seconds into the sound to start playback.
|
||||
|
||||
Sound* playSound3D(const osg::Vec3f& initialPos, const ESM::RefId& soundId, float volume, float pitch,
|
||||
Type type, PlayMode mode, float offset = 0) override;
|
||||
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated using
|
||||
|
@ -236,7 +254,10 @@ namespace MWSound
|
|||
/// @note no-op if \a sound is null
|
||||
|
||||
void stopSound3D(const MWWorld::ConstPtr& reference, const ESM::RefId& soundId) override;
|
||||
///< Stop the given object from playing the given sound,
|
||||
///< Stop the given object from playing the given sound.
|
||||
|
||||
void stopSound3D(const MWWorld::ConstPtr& reference, std::string_view fileName) override;
|
||||
///< Stop the given object from playing the given sound.
|
||||
|
||||
void stopSound3D(const MWWorld::ConstPtr& reference) override;
|
||||
///< Stop the given object from playing all sounds.
|
||||
|
@ -253,6 +274,9 @@ namespace MWSound
|
|||
bool getSoundPlaying(const MWWorld::ConstPtr& reference, const ESM::RefId& soundId) const override;
|
||||
///< Is the given sound currently playing on the given object?
|
||||
|
||||
bool getSoundPlaying(const MWWorld::ConstPtr& reference, std::string_view fileName) const override;
|
||||
///< Is the given sound currently playing on the given object?
|
||||
|
||||
void pauseSounds(MWSound::BlockerType blocker, int types = int(Type::Mask)) override;
|
||||
///< Pauses all currently playing sounds, including music.
|
||||
|
||||
|
|
|
@ -151,6 +151,11 @@ std::string Misc::ResourceHelpers::correctMeshPath(const std::string& resPath, c
|
|||
return "meshes\\" + resPath;
|
||||
}
|
||||
|
||||
std::string Misc::ResourceHelpers::correctSoundPath(const std::string& resPath)
|
||||
{
|
||||
return "sound\\" + resPath;
|
||||
}
|
||||
|
||||
std::string_view Misc::ResourceHelpers::meshPathForESM3(std::string_view resPath)
|
||||
{
|
||||
constexpr std::string_view prefix = "meshes";
|
||||
|
|
|
@ -35,6 +35,9 @@ namespace Misc
|
|||
// Adds "meshes\\".
|
||||
std::string correctMeshPath(const std::string& resPath, const VFS::Manager* vfs);
|
||||
|
||||
// Adds "sound\\".
|
||||
std::string correctSoundPath(const std::string& resPath);
|
||||
|
||||
// Removes "meshes\\".
|
||||
std::string_view meshPathForESM3(std::string_view resPath);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ Lua API reference
|
|||
openmw_self
|
||||
openmw_nearby
|
||||
openmw_input
|
||||
openmw_ambient
|
||||
openmw_ui
|
||||
openmw_camera
|
||||
openmw_postprocessing
|
||||
|
|
5
docs/source/reference/lua-scripting/openmw_ambient.rst
Normal file
5
docs/source/reference/lua-scripting/openmw_ambient.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
Package openmw.ambient
|
||||
======================
|
||||
|
||||
.. raw:: html
|
||||
:file: generated_html/openmw_ambient.html
|
|
@ -21,6 +21,8 @@
|
|||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||
|:ref:`openmw.nearby <Package openmw.nearby>` | by local scripts | | Read-only access to the nearest area of the game world. |
|
||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||
|:ref:`openmw.ambient <Package openmw.ambient>` | by player scripts | | Controls background sounds for given player. |
|
||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||
|:ref:`openmw.input <Package openmw.input>` | by player scripts | | User input. |
|
||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||
|:ref:`openmw.ui <Package openmw.ui>` | by player scripts | | Controls :ref:`user interface <User interface reference>`. |
|
||||
|
|
|
@ -9,6 +9,7 @@ set(LUA_API_FILES
|
|||
math.doclua
|
||||
string.doclua
|
||||
table.doclua
|
||||
openmw/ambient.lua
|
||||
openmw/async.lua
|
||||
openmw/core.lua
|
||||
openmw/nearby.lua
|
||||
|
|
75
files/lua_api/openmw/ambient.lua
Normal file
75
files/lua_api/openmw/ambient.lua
Normal file
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
-- `openmw.ambient` controls background sounds, specific to given player (2D-sounds).
|
||||
-- Can be used only by local scripts, that are attached to a player.
|
||||
-- @module ambient
|
||||
-- @usage local ambient = require('openmw.ambient')
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Play a 2D sound
|
||||
-- @function [parent=#ambient] playSound
|
||||
-- @param #string soundId ID of Sound record to play
|
||||
-- @param #table options An optional table with additional optional arguments. Can contain:
|
||||
--
|
||||
-- * `timeOffset` - a floating point number >= 0, to some time (in second) from beginning of sound file (default: 0);
|
||||
-- * `volume` - a floating point number >= 0, to set a sound volume (default: 1);
|
||||
-- * `pitch` - a floating point number >= 0, to set a sound pitch (default: 1);
|
||||
-- * `scale` - a boolean, to set if sound pitch should be scaled by simulation time scaling (default: true);
|
||||
-- * `loop` - a boolean, to set if sound should be repeated when it ends (default: false);
|
||||
-- @usage local params = {
|
||||
-- timeOffset=0.1
|
||||
-- volume=0.3,
|
||||
-- scale=false,
|
||||
-- pitch=1.0,
|
||||
-- loop=true
|
||||
-- };
|
||||
-- ambient.playSound("shock bolt", params)
|
||||
|
||||
---
|
||||
-- Play a 2D sound file
|
||||
-- @function [parent=#ambient] playSoundFile
|
||||
-- @param #string fileName Path to sound file in VFS
|
||||
-- @param #table options An optional table with additional optional arguments. Can contain:
|
||||
--
|
||||
-- * `timeOffset` - a floating point number >= 0, to some time (in second) from beginning of sound file (default: 0);
|
||||
-- * `volume` - a floating point number >= 0, to set a sound volume (default: 1);
|
||||
-- * `pitch` - a floating point number >= 0, to set a sound pitch (default: 1);
|
||||
-- * `scale` - a boolean, to set if sound pitch should be scaled by simulation time scaling (default: true);
|
||||
-- * `loop` - a boolean, to set if sound should be repeated when it ends (default: false);
|
||||
-- @usage local params = {
|
||||
-- timeOffset=0.1
|
||||
-- volume=0.3,
|
||||
-- scale=false,
|
||||
-- pitch=1.0,
|
||||
-- loop=true
|
||||
-- };
|
||||
-- ambient.playSoundFile("Sound\\test.mp3", params)
|
||||
|
||||
---
|
||||
-- Stop a sound
|
||||
-- @function [parent=#ambient] stopSound
|
||||
-- @param #string soundId ID of Sound record to stop
|
||||
-- @usage ambient.stopSound("shock bolt");
|
||||
|
||||
---
|
||||
-- Stop a sound file
|
||||
-- @function [parent=#ambient] stopSoundFile
|
||||
-- @param #string fileName Path to sound file in VFS
|
||||
-- @usage ambient.stopSoundFile("Sound\\test.mp3");
|
||||
|
||||
---
|
||||
-- Check if sound is playing
|
||||
-- @function [parent=#ambient] isSoundPlaying
|
||||
-- @param #string soundId ID of Sound record to check
|
||||
-- @return #boolean
|
||||
-- @usage local isPlaying = ambient.isSoundPlaying("shock bolt");
|
||||
|
||||
---
|
||||
-- Check if sound file is playing
|
||||
-- @function [parent=#ambient] isSoundFilePlaying
|
||||
-- @param #string fileName Path to sound file in VFS
|
||||
-- @return #boolean
|
||||
-- @usage local isPlaying = ambient.isSoundFilePlaying("Sound\\test.mp3");
|
||||
|
||||
return nil
|
|
@ -737,4 +737,110 @@
|
|||
-- @field #number magnitudeBase
|
||||
-- @field #number magnitudeModifier
|
||||
|
||||
---
|
||||
-- Play a 3D sound, attached to object
|
||||
-- @function [parent=#core] playSound3d
|
||||
-- @param #string soundId ID of Sound record to play
|
||||
-- @param #GameObject object Object to which we attach the sound
|
||||
-- @param #table options An optional table with additional optional arguments. Can contain:
|
||||
--
|
||||
-- * `timeOffset` - a floating point number >= 0, to some time (in second) from beginning of sound file (default: 0);
|
||||
-- * `volume` - a floating point number >= 0, to set a sound volume (default: 1);
|
||||
-- * `pitch` - a floating point number >= 0, to set a sound pitch (default: 1);
|
||||
-- * `loop` - a boolean, to set if sound should be repeated when it ends (default: false);
|
||||
-- @usage local params = {
|
||||
-- timeOffset=0.1
|
||||
-- volume=0.3,
|
||||
-- loop=false,
|
||||
-- pitch=1.0
|
||||
-- };
|
||||
-- core.sound.playSound3d("shock bolt", object, params)
|
||||
|
||||
---
|
||||
-- Play a 3D sound file, attached to object
|
||||
-- @function [parent=#core] playSoundFile3d
|
||||
-- @param #string fileName Path to sound file in VFS
|
||||
-- @param #GameObject object Object to which we attach the sound
|
||||
-- @param #table options An optional table with additional optional arguments. Can contain:
|
||||
--
|
||||
-- * `timeOffset` - a floating point number >= 0, to some time (in second) from beginning of sound file (default: 0);
|
||||
-- * `volume` - a floating point number >= 0, to set a sound volume (default: 1);
|
||||
-- * `pitch` - a floating point number >= 0, to set a sound pitch (default: 1);
|
||||
-- * `loop` - a boolean, to set if sound should be repeated when it ends (default: false);
|
||||
-- @usage local params = {
|
||||
-- timeOffset=0.1
|
||||
-- volume=0.3,
|
||||
-- loop=false,
|
||||
-- pitch=1.0
|
||||
-- };
|
||||
-- core.sound.playSoundFile3d("Sound\\test.mp3", object, params)
|
||||
|
||||
---
|
||||
-- Stop a 3D sound, attached to object
|
||||
-- @function [parent=#core] stopSound3d
|
||||
-- @param #string soundId ID of Sound record to stop
|
||||
-- @param #GameObject object Object on which we want to stop sound
|
||||
-- @usage core.sound.stopSound("shock bolt", object);
|
||||
|
||||
---
|
||||
-- Stop a 3D sound file, attached to object
|
||||
-- @function [parent=#core] stopSoundFile3d
|
||||
-- @param #string fileName Path to sound file in VFS
|
||||
-- @param #GameObject object Object on which we want to stop sound
|
||||
-- @usage core.sound.stopSoundFile("Sound\\test.mp3", object);
|
||||
|
||||
---
|
||||
-- Check if sound is playing on given object
|
||||
-- @function [parent=#core] isSoundPlaying
|
||||
-- @param #string soundId ID of Sound record to check
|
||||
-- @param #GameObject object Object on which we want to check sound
|
||||
-- @return #boolean
|
||||
-- @usage local isPlaying = core.sound.isSoundPlaying("shock bolt", object);
|
||||
|
||||
---
|
||||
-- Check if sound file is playing on given object
|
||||
-- @function [parent=#core] isSoundFilePlaying
|
||||
-- @param #string fileName Path to sound file in VFS
|
||||
-- @param #GameObject object Object on which we want to check sound
|
||||
-- @return #boolean
|
||||
-- @usage local isPlaying = core.sound.isSoundFilePlaying("Sound\\test.mp3", object);
|
||||
|
||||
---
|
||||
-- Play an animated voiceover. Has two overloads:
|
||||
--
|
||||
-- * With an "object" argument: play sound for given object, with speaking animation if possible equipment slots.
|
||||
-- * Without an "object" argument: play sound globally, without object
|
||||
-- @function [parent=#core] say
|
||||
-- @param #string fileName Path to sound file in VFS
|
||||
-- @param #GameObject object Object on which we want to play an animated voiceover (optional)
|
||||
-- @param #string text Subtitle text (optional)
|
||||
-- @usage -- play voiceover for object and print messagebox
|
||||
-- core.sound.say("Sound\\Vo\\Misc\\voice.mp3", object, "Subtitle text")
|
||||
-- @usage -- play voiceover globally and print messagebox
|
||||
-- core.sound.say("Sound\\Vo\\Misc\\voice.mp3", "Subtitle text")
|
||||
-- @usage -- play voiceover for object without messagebox
|
||||
-- core.sound.say("Sound\\Vo\\Misc\\voice.mp3", object)
|
||||
-- @usage -- play voiceover globally without messagebox
|
||||
-- core.sound.say("Sound\\Vo\\Misc\\voice.mp3")
|
||||
|
||||
---
|
||||
-- Stop animated voiceover
|
||||
-- @function [parent=#core] stopSay
|
||||
-- @param #string fileName Path to sound file in VFS
|
||||
-- @param #GameObject object Object on which we want to stop an animated voiceover (optional)
|
||||
-- @usage -- stop voice for given object
|
||||
-- core.sound.stopSay(object);
|
||||
-- @usage -- stop global voice
|
||||
-- core.sound.stopSay();
|
||||
|
||||
---
|
||||
-- Check if animated voiceover is playing
|
||||
-- @function [parent=#core] isSayActive
|
||||
-- @param #GameObject object Object on which we want to check an animated voiceover (optional)
|
||||
-- @return #boolean
|
||||
-- @usage -- check voice for given object
|
||||
-- local isActive = isSayActive(object);
|
||||
-- @usage -- check global voice
|
||||
-- local isActive = isSayActive();
|
||||
|
||||
return nil
|
||||
|
|
|
@ -127,10 +127,10 @@
|
|||
---
|
||||
-- Get equipment.
|
||||
-- Has two overloads:
|
||||
-- 1) With a single argument: returns a table `slot` -> @{openmw.core#GameObject} of currently equipped items.
|
||||
-- See @{#EQUIPMENT_SLOT}. Returns empty table if the actor doesn't have
|
||||
-- equipment slots.
|
||||
-- 2) With two arguments: returns an item equipped to the given slot.
|
||||
--
|
||||
-- * With a single argument: returns a table `slot` -> @{openmw.core#GameObject} of currently equipped items.
|
||||
-- See @{#EQUIPMENT_SLOT}. Returns empty table if the actor doesn't have equipment slots.
|
||||
-- * With two arguments: returns an item equipped to the given slot.
|
||||
-- @function [parent=#Actor] getEquipment
|
||||
-- @param openmw.core#GameObject actor
|
||||
-- @param #number slot Optional number of the equipment slot
|
||||
|
|
Loading…
Reference in a new issue