mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 18:59:57 +00:00
Rework music system
This commit is contained in:
parent
090da90302
commit
e1cae5a029
24 changed files with 189 additions and 47 deletions
|
@ -75,6 +75,7 @@
|
|||
Feature #3537: Shader-based water ripples
|
||||
Feature #5492: Let rain and snow collide with statics
|
||||
Feature #6149: Dehardcode Lua API_REVISION
|
||||
Feature #6152: Playing music via lua scripts
|
||||
Feature #6447: Add LOD support to Object Paging
|
||||
Feature #6491: Add support for Qt6
|
||||
Feature #6556: Lua API for sounds
|
||||
|
@ -99,6 +100,7 @@
|
|||
Feature #7477: NegativeLight Magic Effect flag
|
||||
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
|
||||
Feature #7546: Start the game on Fredas
|
||||
Feature #7568: Uninterruptable scripted music
|
||||
Task #5896: Do not use deprecated MyGUI properties
|
||||
Task #7113: Move from std::atoi to std::from_char
|
||||
Task #7117: Replace boost::scoped_array with std::vector
|
||||
|
|
|
@ -61,7 +61,7 @@ add_openmw_dir (mwscript
|
|||
add_openmw_dir (mwlua
|
||||
luamanagerimp object objectlists userdataserializer luaevents engineevents objectvariant
|
||||
context globalscripts localscripts playerscripts luabindings objectbindings cellbindings mwscriptbindings
|
||||
camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings postprocessingbindings stats debugbindings
|
||||
camerabindings vfsbindings musicbindings 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 factionbindings
|
||||
)
|
||||
|
|
|
@ -26,6 +26,11 @@ namespace ESM
|
|||
class ESMWriter;
|
||||
}
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
enum class MusicType;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class Ptr;
|
||||
|
@ -282,6 +287,9 @@ namespace MWBase
|
|||
virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
||||
virtual MWMechanics::GreetingState getGreetingState(const MWWorld::Ptr& ptr) const = 0;
|
||||
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
||||
|
||||
virtual MWSound::MusicType getMusicType() const = 0;
|
||||
virtual void setMusicType(MWSound::MusicType type) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,14 @@ namespace MWSound
|
|||
MaxCount
|
||||
};
|
||||
|
||||
enum class MusicType
|
||||
{
|
||||
Special,
|
||||
Explore,
|
||||
Battle,
|
||||
Scripted
|
||||
};
|
||||
|
||||
class Sound;
|
||||
class Stream;
|
||||
struct Sound_Decoder;
|
||||
|
@ -104,9 +112,13 @@ namespace MWBase
|
|||
virtual void stopMusic() = 0;
|
||||
///< Stops music if it's playing
|
||||
|
||||
virtual void streamMusic(const std::string& filename) = 0;
|
||||
virtual void streamMusic(
|
||||
const std::string& filename, MWSound::MusicType type = MWSound::MusicType::Scripted, float fade = 1.f)
|
||||
= 0;
|
||||
///< Play a soundifle
|
||||
/// \param filename name of a sound file in "Music/" in the data directory.
|
||||
/// \param filename name of a sound file in the data directory.
|
||||
/// \param type music type.
|
||||
/// \param fade time in seconds to fade out current track before start this one.
|
||||
|
||||
virtual bool isMusicPlaying() = 0;
|
||||
///< Returns true if music is playing
|
||||
|
|
|
@ -214,7 +214,8 @@ namespace MWGui
|
|||
center();
|
||||
|
||||
// Play LevelUp Music
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Triumph.mp3");
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(
|
||||
"Music/Special/MW_Triumph.mp3", MWSound::MusicType::Special);
|
||||
}
|
||||
|
||||
void LevelupDialog::onOkButtonClicked(MyGUI::Widget* sender)
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "factionbindings.hpp"
|
||||
#include "inputbindings.hpp"
|
||||
#include "magicbindings.hpp"
|
||||
#include "musicbindings.hpp"
|
||||
#include "nearbybindings.hpp"
|
||||
#include "objectbindings.hpp"
|
||||
#include "postprocessingbindings.hpp"
|
||||
|
@ -392,6 +393,7 @@ namespace MWLua
|
|||
{ "openmw.input", initInputPackage(context) },
|
||||
{ "openmw.postprocessing", initPostprocessingPackage(context) },
|
||||
{ "openmw.ui", initUserInterfacePackage(context) },
|
||||
{ "openmw.music", initMusicPackage(context) },
|
||||
};
|
||||
}
|
||||
|
||||
|
|
24
apps/openmw/mwlua/musicbindings.cpp
Normal file
24
apps/openmw/mwlua/musicbindings.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "musicbindings.hpp"
|
||||
#include "luabindings.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
|
||||
#include "context.hpp"
|
||||
#include "luamanagerimp.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initMusicPackage(const Context& context)
|
||||
{
|
||||
sol::table api(context.mLua->sol(), sol::create);
|
||||
api["streamMusic"] = [](std::string_view fileName) {
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(std::string(fileName));
|
||||
};
|
||||
|
||||
api["stopMusic"] = []() { MWBase::Environment::get().getSoundManager()->stopMusic(); };
|
||||
|
||||
return LuaUtil::makeReadOnly(api);
|
||||
}
|
||||
}
|
13
apps/openmw/mwlua/musicbindings.hpp
Normal file
13
apps/openmw/mwlua/musicbindings.hpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef MWLUA_MUSICBINDINGS_H
|
||||
#define MWLUA_MUSICBINDINGS_H
|
||||
|
||||
#include <sol/forward.hpp>
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace MWLua
|
||||
{
|
||||
sol::table initMusicPackage(const Context&);
|
||||
}
|
||||
|
||||
#endif // MWLUA_MUSICBINDINGS_H
|
|
@ -1285,7 +1285,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
void Actors::updateCombatMusic()
|
||||
bool Actors::playerHasHostiles() const
|
||||
{
|
||||
const MWWorld::Ptr player = getPlayer();
|
||||
const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
|
||||
|
@ -1315,19 +1315,7 @@ namespace MWMechanics
|
|||
}
|
||||
}
|
||||
|
||||
// check if we still have any player enemies to switch music
|
||||
if (mCurrentMusic != MusicType::Explore && !hasHostiles
|
||||
&& !(player.getClass().getCreatureStats(player).isDead()
|
||||
&& MWBase::Environment::get().getSoundManager()->isMusicPlaying()))
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
mCurrentMusic = MusicType::Explore;
|
||||
}
|
||||
else if (mCurrentMusic != MusicType::Battle && hasHostiles)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle"));
|
||||
mCurrentMusic = MusicType::Battle;
|
||||
}
|
||||
return hasHostiles;
|
||||
}
|
||||
|
||||
void Actors::predictAndAvoidCollisions(float duration) const
|
||||
|
@ -1735,8 +1723,6 @@ namespace MWMechanics
|
|||
killDeadActors();
|
||||
updateSneaking(playerCharacter, duration);
|
||||
}
|
||||
|
||||
updateCombatMusic();
|
||||
}
|
||||
|
||||
void Actors::notifyDied(const MWWorld::Ptr& actor)
|
||||
|
@ -1806,7 +1792,8 @@ namespace MWMechanics
|
|||
// player's death animation is over
|
||||
MWBase::Environment::get().getStateManager()->askLoadRecent();
|
||||
// Play Death Music if it was the player dying
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic("Special/MW_Death.mp3");
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(
|
||||
"Music/Special/MW_Death.mp3", MWSound::MusicType::Special);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -74,9 +74,6 @@ namespace MWMechanics
|
|||
void dropActors(const MWWorld::CellStore* cellStore, const MWWorld::Ptr& ignore);
|
||||
///< Deregister all actors (except for \a ignore) in the given cell.
|
||||
|
||||
void updateCombatMusic();
|
||||
///< Update combat music state
|
||||
|
||||
void update(float duration, bool paused);
|
||||
///< Update actor stats and store desired velocity vectors in \a movement
|
||||
|
||||
|
@ -159,19 +156,14 @@ namespace MWMechanics
|
|||
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
|
||||
bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
bool playerHasHostiles() const;
|
||||
|
||||
int getGreetingTimer(const MWWorld::Ptr& ptr) const;
|
||||
float getAngleToPlayer(const MWWorld::Ptr& ptr) const;
|
||||
GreetingState getGreetingState(const MWWorld::Ptr& ptr) const;
|
||||
bool isTurningToPlayer(const MWWorld::Ptr& ptr) const;
|
||||
|
||||
private:
|
||||
enum class MusicType
|
||||
{
|
||||
Title,
|
||||
Explore,
|
||||
Battle
|
||||
};
|
||||
|
||||
std::map<ESM::RefId, int> mDeathCount;
|
||||
std::list<Actor> mActors;
|
||||
std::map<const MWWorld::LiveCellRefBase*, std::list<Actor>::iterator> mIndex;
|
||||
|
@ -182,7 +174,6 @@ namespace MWMechanics
|
|||
float mTimerUpdateHello = 0;
|
||||
float mSneakTimer = 0; // Times update of sneak icon
|
||||
float mSneakSkillTimer = 0; // Times sneak skill progress from "avoid notice"
|
||||
MusicType mCurrentMusic = MusicType::Title;
|
||||
|
||||
void updateVisibility(const MWWorld::Ptr& ptr, CharacterController& ctrl) const;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "../mwbase/dialoguemanager.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/soundmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -257,6 +258,7 @@ namespace MWMechanics
|
|||
, mClassSelected(false)
|
||||
, mRaceSelected(false)
|
||||
, mAI(true)
|
||||
, mMusicType(MWSound::MusicType::Special)
|
||||
{
|
||||
// buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
|
||||
}
|
||||
|
@ -340,6 +342,8 @@ namespace MWMechanics
|
|||
|
||||
mActors.update(duration, paused);
|
||||
mObjects.update(duration, paused);
|
||||
|
||||
updateMusicState();
|
||||
}
|
||||
|
||||
void MechanicsManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||
|
@ -1572,6 +1576,31 @@ namespace MWMechanics
|
|||
return (Misc::Rng::roll0to99(prng) >= target);
|
||||
}
|
||||
|
||||
void MechanicsManager::updateMusicState()
|
||||
{
|
||||
bool musicPlaying = MWBase::Environment::get().getSoundManager()->isMusicPlaying();
|
||||
|
||||
// Can not interrupt scripted music by built-in playlists
|
||||
if (mMusicType == MWSound::MusicType::Scripted && musicPlaying)
|
||||
return;
|
||||
|
||||
const MWWorld::Ptr& player = MWMechanics::getPlayer();
|
||||
bool hasHostiles = mActors.playerHasHostiles();
|
||||
|
||||
// check if we still have any player enemies to switch music
|
||||
if (mMusicType != MWSound::MusicType::Explore && !hasHostiles
|
||||
&& !(player.getClass().getCreatureStats(player).isDead() && musicPlaying))
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
||||
mMusicType = MWSound::MusicType::Explore;
|
||||
}
|
||||
else if (mMusicType != MWSound::MusicType::Battle && hasHostiles)
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle"));
|
||||
mMusicType = MWSound::MusicType::Battle;
|
||||
}
|
||||
}
|
||||
|
||||
void MechanicsManager::startCombat(const MWWorld::Ptr& ptr, const MWWorld::Ptr& target)
|
||||
{
|
||||
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
#include "npcstats.hpp"
|
||||
#include "objects.hpp"
|
||||
|
||||
namespace MWSound
|
||||
{
|
||||
enum class MusicType;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class CellStore;
|
||||
|
@ -33,6 +38,8 @@ namespace MWMechanics
|
|||
typedef std::map<ESM::RefId, OwnerMap> StolenItemsMap;
|
||||
StolenItemsMap mStolenItems;
|
||||
|
||||
MWSound::MusicType mMusicType;
|
||||
|
||||
public:
|
||||
void buildPlayer();
|
||||
///< build player according to stored class/race/birthsign information. Will
|
||||
|
@ -232,7 +239,11 @@ namespace MWMechanics
|
|||
GreetingState getGreetingState(const MWWorld::Ptr& ptr) const override;
|
||||
bool isTurningToPlayer(const MWWorld::Ptr& ptr) const override;
|
||||
|
||||
MWSound::MusicType getMusicType() const override { return mMusicType; }
|
||||
void setMusicType(MWSound::MusicType type) override { mMusicType = type; }
|
||||
|
||||
private:
|
||||
void updateMusicState();
|
||||
bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||
bool canReportCrime(
|
||||
const MWWorld::Ptr& actor, const MWWorld::Ptr& victim, std::set<MWWorld::Ptr>& playerFollowers);
|
||||
|
|
|
@ -63,10 +63,11 @@ namespace MWScript
|
|||
public:
|
||||
void execute(Interpreter::Runtime& runtime) override
|
||||
{
|
||||
std::string sound{ runtime.getStringLiteral(runtime[0].mInteger) };
|
||||
std::string music{ runtime.getStringLiteral(runtime[0].mInteger) };
|
||||
runtime.pop();
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(sound);
|
||||
MWBase::Environment::get().getSoundManager()->streamMusic(
|
||||
Misc::ResourceHelpers::correctMusicPath(music));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <components/vfs/pathutil.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
|
@ -250,7 +251,7 @@ namespace MWSound
|
|||
if (filename.empty())
|
||||
return;
|
||||
|
||||
Log(Debug::Info) << "Playing " << filename;
|
||||
Log(Debug::Info) << "Playing \"" << filename << "\"";
|
||||
mLastPlayedMusic = filename;
|
||||
|
||||
DecoderPtr decoder = getDecoder();
|
||||
|
@ -260,7 +261,7 @@ namespace MWSound
|
|||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
Log(Debug::Error) << "Failed to load audio from " << filename << ": " << e.what();
|
||||
Log(Debug::Error) << "Failed to load audio from \"" << filename << "\": " << e.what();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -274,7 +275,7 @@ namespace MWSound
|
|||
mOutput->streamSound(decoder, mMusic.get());
|
||||
}
|
||||
|
||||
void SoundManager::advanceMusic(const std::string& filename)
|
||||
void SoundManager::advanceMusic(const std::string& filename, float fadeOut)
|
||||
{
|
||||
if (!isMusicPlaying())
|
||||
{
|
||||
|
@ -284,7 +285,7 @@ namespace MWSound
|
|||
|
||||
mNextMusic = filename;
|
||||
|
||||
mMusic->setFadeout(1.f);
|
||||
mMusic->setFadeout(fadeOut);
|
||||
}
|
||||
|
||||
void SoundManager::startRandomTitle()
|
||||
|
@ -319,16 +320,30 @@ namespace MWSound
|
|||
tracklist.pop_back();
|
||||
}
|
||||
|
||||
void SoundManager::streamMusic(const std::string& filename)
|
||||
{
|
||||
advanceMusic("Music/" + filename);
|
||||
}
|
||||
|
||||
bool SoundManager::isMusicPlaying()
|
||||
{
|
||||
return mMusic && mOutput->isStreamPlaying(mMusic.get());
|
||||
}
|
||||
|
||||
void SoundManager::streamMusic(const std::string& filename, MusicType type, float fade)
|
||||
{
|
||||
const auto mechanicsManager = MWBase::Environment::get().getMechanicsManager();
|
||||
|
||||
// Can not interrupt scripted music by built-in playlists
|
||||
if (mechanicsManager->getMusicType() == MusicType::Scripted && type != MusicType::Scripted
|
||||
&& type != MusicType::Special)
|
||||
return;
|
||||
|
||||
std::string normalizedName = VFS::Path::normalizeFilename(filename);
|
||||
|
||||
mechanicsManager->setMusicType(type);
|
||||
advanceMusic(normalizedName, fade);
|
||||
if (type == MWSound::MusicType::Battle)
|
||||
mCurrentPlaylist = "Battle";
|
||||
else if (type == MWSound::MusicType::Explore)
|
||||
mCurrentPlaylist = "Explore";
|
||||
}
|
||||
|
||||
void SoundManager::playPlaylist(const std::string& playlist)
|
||||
{
|
||||
if (mCurrentPlaylist == playlist)
|
||||
|
@ -337,7 +352,8 @@ namespace MWSound
|
|||
if (mMusicFiles.find(playlist) == mMusicFiles.end())
|
||||
{
|
||||
std::vector<std::string> filelist;
|
||||
for (const auto& name : mVFS->getRecursiveDirectoryIterator("Music/" + playlist + '/'))
|
||||
auto playlistPath = Misc::ResourceHelpers::correctMusicPath(playlist) + '/';
|
||||
for (const auto& name : mVFS->getRecursiveDirectoryIterator(playlistPath))
|
||||
filelist.push_back(name);
|
||||
|
||||
mMusicFiles[playlist] = filelist;
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace MWSound
|
|||
StreamPtr playVoice(DecoderPtr decoder, const osg::Vec3f& pos, bool playlocal);
|
||||
|
||||
void streamMusicFull(const std::string& filename);
|
||||
void advanceMusic(const std::string& filename);
|
||||
void advanceMusic(const std::string& filename, float fadeOut = 1.f);
|
||||
void startRandomTitle();
|
||||
|
||||
void cull3DSound(SoundBase* sound);
|
||||
|
@ -176,9 +176,12 @@ namespace MWSound
|
|||
void stopMusic() override;
|
||||
///< Stops music if it's playing
|
||||
|
||||
void streamMusic(const std::string& filename) override;
|
||||
void streamMusic(const std::string& filename, MWSound::MusicType type = MWSound::MusicType::Scripted,
|
||||
float fade = 1.f) override;
|
||||
///< Play a soundifle
|
||||
/// \param filename name of a sound file in "Music/" in the data directory.
|
||||
/// \param filename name of a sound file in the data directory.
|
||||
/// \param type music type.
|
||||
/// \param fade time in seconds to fade out current track before start this one.
|
||||
|
||||
bool isMusicPlaying() override;
|
||||
///< Returns true if music is playing
|
||||
|
|
|
@ -391,8 +391,11 @@ namespace MWWorld
|
|||
{
|
||||
std::string_view video = Fallback::Map::getString("Movies_New_Game");
|
||||
if (!video.empty())
|
||||
{
|
||||
MWBase::Environment::get().getSoundManager()->stopMusic();
|
||||
MWBase::Environment::get().getWindowManager()->playVideo(video, true);
|
||||
}
|
||||
}
|
||||
|
||||
// enable collision
|
||||
if (!mPhysics->toggleCollisionMode())
|
||||
|
|
|
@ -156,6 +156,11 @@ std::string Misc::ResourceHelpers::correctSoundPath(const std::string& resPath)
|
|||
return "sound\\" + resPath;
|
||||
}
|
||||
|
||||
std::string Misc::ResourceHelpers::correctMusicPath(const std::string& resPath)
|
||||
{
|
||||
return "music\\" + resPath;
|
||||
}
|
||||
|
||||
std::string_view Misc::ResourceHelpers::meshPathForESM3(std::string_view resPath)
|
||||
{
|
||||
constexpr std::string_view prefix = "meshes";
|
||||
|
|
|
@ -38,6 +38,9 @@ namespace Misc
|
|||
// Adds "sound\\".
|
||||
std::string correctSoundPath(const std::string& resPath);
|
||||
|
||||
// Adds "music\\".
|
||||
std::string correctMusicPath(const std::string& resPath);
|
||||
|
||||
// Removes "meshes\\".
|
||||
std::string_view meshPathForESM3(std::string_view resPath);
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ Lua API reference
|
|||
openmw_nearby
|
||||
openmw_input
|
||||
openmw_ambient
|
||||
openmw_music
|
||||
openmw_ui
|
||||
openmw_camera
|
||||
openmw_postprocessing
|
||||
|
|
7
docs/source/reference/lua-scripting/openmw_music.rst
Normal file
7
docs/source/reference/lua-scripting/openmw_music.rst
Normal file
|
@ -0,0 +1,7 @@
|
|||
Package openmw.music
|
||||
====================
|
||||
|
||||
.. include:: version.rst
|
||||
|
||||
.. raw:: html
|
||||
:file: generated_html/openmw_music.html
|
|
@ -27,6 +27,8 @@
|
|||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||
|:ref:`openmw.input <Package openmw.input>` | by player scripts | | User input. |
|
||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||
|:ref:`openmw.music <Package openmw.music>` | by player scripts | | Music system. |
|
||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||
|:ref:`openmw.ui <Package openmw.ui>` | by player scripts | | Controls :ref:`user interface <User interface reference>`. |
|
||||
+------------------------------------------------------------+--------------------+---------------------------------------------------------------+
|
||||
|:ref:`openmw.camera <Package openmw.camera>` | by player scripts | | Controls camera. |
|
||||
|
|
|
@ -77,6 +77,7 @@ local env = {
|
|||
nearby = require('openmw.nearby'),
|
||||
self = require('openmw.self'),
|
||||
input = require('openmw.input'),
|
||||
music = require('openmw.music'),
|
||||
ui = require('openmw.ui'),
|
||||
camera = require('openmw.camera'),
|
||||
aux_util = require('openmw_aux.util'),
|
||||
|
|
|
@ -13,6 +13,7 @@ set(LUA_API_FILES
|
|||
openmw/async.lua
|
||||
openmw/core.lua
|
||||
openmw/debug.lua
|
||||
openmw/music.lua
|
||||
openmw/nearby.lua
|
||||
openmw/postprocessing.lua
|
||||
openmw/self.lua
|
||||
|
|
19
files/lua_api/openmw/music.lua
Normal file
19
files/lua_api/openmw/music.lua
Normal file
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
-- `openmw.music` provides access to music system.
|
||||
-- @module music
|
||||
-- @usage local music = require('openmw.music')
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Play a sound file as a music track
|
||||
-- @function [parent=#music] streamMusic
|
||||
-- @param #string fileName Path to file in VFS
|
||||
-- @usage music.streamMusic("Music\\Test\\Test.mp3");
|
||||
|
||||
---
|
||||
-- Stop to play current music
|
||||
-- @function [parent=#music] stopMusic
|
||||
-- @usage music.stopMusic();
|
||||
|
||||
return nil
|
Loading…
Reference in a new issue