Merge branch 'lua_weather_bindings' into 'master'

lua - add weatherbindings to openmw.core (#6976)

See merge request OpenMW/openmw!4526
This commit is contained in:
Skyhasacat 2025-07-26 15:01:32 +00:00
commit 9f10269ecc
15 changed files with 448 additions and 22 deletions

View File

@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 50)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_LUA_API_REVISION 82)
set(OPENMW_LUA_API_REVISION 83)
set(OPENMW_POSTPROCESSING_API_REVISION 3)
set(OPENMW_VERSION_COMMITHASH "")

View File

@ -63,7 +63,7 @@ add_openmw_dir (mwlua
context menuscripts globalscripts localscripts playerscripts luabindings objectbindings cellbindings coremwscriptbindings
mwscriptbindings camerabindings vfsbindings uibindings soundbindings inputbindings nearbybindings dialoguebindings
postprocessingbindings stats recordstore debugbindings corebindings worldbindings worker landbindings magicbindings factionbindings
classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings markupbindings
classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings markupbindings weatherbindings
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

View File

@ -22,6 +22,7 @@
namespace osg
{
class Vec3f;
class Vec4f;
class Matrixf;
class Quat;
class Image;
@ -93,6 +94,7 @@ namespace MWWorld
class RefData;
class Cell;
class DateTimeManager;
class Weather;
typedef std::vector<std::pair<MWWorld::Ptr, MWMechanics::Movement>> PtrMovementList;
}
@ -216,9 +218,21 @@ namespace MWBase
virtual void changeWeather(const ESM::RefId& region, const unsigned int id) = 0;
virtual int getCurrentWeather() const = 0;
virtual void changeWeather(const ESM::RefId& region, const ESM::RefId& id) = 0;
virtual int getNextWeather() const = 0;
virtual const std::vector<MWWorld::Weather>& getAllWeather() const = 0;
virtual int getCurrentWeatherScriptId() const = 0;
virtual const MWWorld::Weather& getCurrentWeather() const = 0;
virtual const MWWorld::Weather* getWeather(size_t index) const = 0;
virtual const MWWorld::Weather* getWeather(const ESM::RefId& id) const = 0;
virtual int getNextWeatherScriptId() const = 0;
virtual const MWWorld::Weather* getNextWeather() const = 0;
virtual float getWeatherTransition() const = 0;
@ -478,6 +492,7 @@ namespace MWBase
// Allow NPCs to use torches?
virtual bool useTorches() const = 0;
virtual const osg::Vec4f& getSunLightPosition() const = 0;
virtual float getSunVisibility() const = 0;
virtual float getSunPercentage() const = 0;

View File

@ -501,7 +501,7 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
case ESM::DialogueCondition::Function_Weather:
return MWBase::Environment::get().getWorld()->getCurrentWeather();
return MWBase::Environment::get().getWorld()->getCurrentWeatherScriptId();
case ESM::DialogueCondition::Function_Reputation:
if (!mActor.getClass().isNpc())

View File

@ -27,6 +27,7 @@
#include "magicbindings.hpp"
#include "soundbindings.hpp"
#include "stats.hpp"
#include "weatherbindings.hpp"
namespace MWLua
{
@ -104,6 +105,9 @@ namespace MWLua
api["land"] = context.cachePackage("openmw_core_land", [context]() { return initCoreLandBindings(context); });
api["weather"]
= context.cachePackage("openmw_core_weather", [context]() { return initCoreWeatherBindings(context); });
api["factions"]
= context.cachePackage("openmw_core_factions", [context]() { return initCoreFactionBindings(context); });
api["dialogue"]

View File

@ -0,0 +1,185 @@
#include "weatherbindings.hpp"
#include <osg/Vec4f>
#include <components/esm3/loadregn.hpp>
#include <components/lua/util.hpp>
#include <components/misc/color.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/resourcesystem.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/weather.hpp"
#include "context.hpp"
namespace
{
class WeatherStore
{
public:
const MWWorld::Weather* get(size_t index) const
{
return MWBase::Environment::get().getWorld()->getWeather(index);
}
const MWWorld::Weather* get(const ESM::RefId& id) const
{
return MWBase::Environment::get().getWorld()->getWeather(id);
}
size_t size() const { return MWBase::Environment::get().getWorld()->getAllWeather().size(); }
};
Misc::Color color(const osg::Vec4f& color)
{
return Misc::Color(color.r(), color.g(), color.b(), color.a());
}
}
namespace MWLua
{
sol::table initCoreWeatherBindings(const Context& context)
{
sol::state_view lua = context.sol();
sol::table api(lua, sol::create);
auto vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
auto weatherT = lua.new_usertype<MWWorld::Weather>("Weather");
weatherT[sol::meta_function::to_string]
= [](const MWWorld::Weather& w) -> std::string { return "Weather[" + w.mName + "]"; };
weatherT["name"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mName; });
weatherT["windSpeed"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mWindSpeed; });
weatherT["cloudSpeed"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mCloudSpeed; });
weatherT["cloudTexture"] = sol::readonly_property([vfs](const MWWorld::Weather& w) {
return Misc::ResourceHelpers::correctTexturePath(w.mCloudTexture, vfs);
});
weatherT["cloudsMaximumPercent"]
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mCloudsMaximumPercent; });
weatherT["isStorm"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mIsStorm; });
weatherT["stormDirection"]
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mStormDirection; });
weatherT["glareView"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mGlareView; });
weatherT["rainSpeed"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainSpeed; });
weatherT["rainEntranceSpeed"]
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainEntranceSpeed; });
weatherT["rainEffect"] = sol::readonly_property([](const MWWorld::Weather& w) -> sol::optional<std::string> {
if (w.mRainEffect.empty())
return sol::nullopt;
return w.mRainEffect;
});
weatherT["rainMaxRaindrops"]
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainMaxRaindrops; });
weatherT["rainDiameter"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainDiameter; });
weatherT["rainThreshold"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainThreshold; });
weatherT["rainMaxHeight"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainMaxHeight; });
weatherT["rainMinHeight"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainMinHeight; });
weatherT["rainLoopSoundID"]
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mRainLoopSoundID.serializeText(); });
weatherT["thunderSoundID"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
sol::table result(lua, sol::create);
for (const auto& soundId : w.mThunderSoundID)
result.add(soundId.serializeText());
return result;
});
weatherT["sunDiscSunsetColor"]
= sol::readonly_property([](const MWWorld::Weather& w) { return color(w.mSunDiscSunsetColor); });
weatherT["ambientLoopSoundID"]
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mAmbientLoopSoundID.serializeText(); });
weatherT["ambientColor"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
sol::table result(lua, sol::create);
result["sunrise"] = color(w.mAmbientColor.getSunriseValue());
result["day"] = color(w.mAmbientColor.getDayValue());
result["sunset"] = color(w.mAmbientColor.getSunsetValue());
result["night"] = color(w.mAmbientColor.getNightValue());
return result;
});
weatherT["fogColor"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
sol::table result(lua, sol::create);
result["sunrise"] = color(w.mFogColor.getSunriseValue());
result["day"] = color(w.mFogColor.getDayValue());
result["sunset"] = color(w.mFogColor.getSunsetValue());
result["night"] = color(w.mFogColor.getNightValue());
return result;
});
weatherT["skyColor"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
sol::table result(lua, sol::create);
result["sunrise"] = color(w.mSkyColor.getSunriseValue());
result["day"] = color(w.mSkyColor.getDayValue());
result["sunset"] = color(w.mSkyColor.getSunsetValue());
result["night"] = color(w.mSkyColor.getNightValue());
return result;
});
weatherT["sunColor"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
sol::table result(lua, sol::create);
result["sunrise"] = color(w.mSunColor.getSunriseValue());
result["day"] = color(w.mSunColor.getDayValue());
result["sunset"] = color(w.mSunColor.getSunsetValue());
result["night"] = color(w.mSunColor.getNightValue());
return result;
});
weatherT["landFogDepth"] = sol::readonly_property([lua](const MWWorld::Weather& w) {
sol::table result(lua, sol::create);
result["sunrise"] = w.mLandFogDepth.getSunriseValue();
result["day"] = w.mLandFogDepth.getDayValue();
result["sunset"] = w.mLandFogDepth.getSunsetValue();
result["night"] = w.mLandFogDepth.getNightValue();
return result;
});
weatherT["particleEffect"]
= sol::readonly_property([](const MWWorld::Weather& w) -> sol::optional<std::string> {
if (w.mParticleEffect.empty())
return sol::nullopt;
return w.mParticleEffect;
});
weatherT["distantLandFogFactor"]
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mDL.FogFactor; });
weatherT["distantLandFogOffset"]
= sol::readonly_property([](const MWWorld::Weather& w) { return w.mDL.FogOffset; });
weatherT["scriptId"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mScriptId; });
weatherT["recordId"] = sol::readonly_property([](const MWWorld::Weather& w) { return w.mId.serializeText(); });
api["getCurrent"] = []() { return MWBase::Environment::get().getWorld()->getCurrentWeather(); };
api["getNext"]
= []() -> const MWWorld::Weather* { return MWBase::Environment::get().getWorld()->getNextWeather(); };
api["getTransition"] = []() { return MWBase::Environment::get().getWorld()->getWeatherTransition(); };
api["changeWeather"] = [](std::string_view regionId, const MWWorld::Weather& weather) {
ESM::RefId region = ESM::RefId::deserializeText(regionId);
MWBase::Environment::get().getESMStore()->get<ESM::Region>().find(region);
MWBase::Environment::get().getWorld()->changeWeather(region, weather.mId);
};
sol::usertype<WeatherStore> storeT = lua.new_usertype<WeatherStore>("WeatherWorldStore");
storeT[sol::meta_function::to_string]
= [](const WeatherStore& store) { return "{" + std::to_string(store.size()) + " Weather records}"; };
storeT[sol::meta_function::length] = [](const WeatherStore& store) { return store.size(); };
storeT[sol::meta_function::index] = sol::overload(
[](const WeatherStore& store, size_t index) -> const MWWorld::Weather* {
return store.get(LuaUtil::fromLuaIndex(index));
},
[](const WeatherStore& store, std::string_view id) -> const MWWorld::Weather* {
return store.get(ESM::RefId::deserializeText(id));
});
storeT[sol::meta_function::ipairs] = lua["ipairsForArray"].template get<sol::function>();
storeT[sol::meta_function::pairs] = lua["ipairsForArray"].template get<sol::function>();
// Provide access to the store.
api["records"] = WeatherStore{};
api["getCurrentSunLightDirection"] = []() {
osg::Vec4f sunPos = MWBase::Environment::get().getWorld()->getSunLightPosition();
// normalize to get the direction towards the sun
sunPos.normalize();
// and invert it to get the direction of the sun light
return -sunPos;
};
api["getCurrentSunVisibility"] = []() { return MWBase::Environment::get().getWorld()->getSunVisibility(); };
api["getCurrentSunPercentage"] = []() { return MWBase::Environment::get().getWorld()->getSunPercentage(); };
api["getCurrentWindSpeed"] = []() { return MWBase::Environment::get().getWorld()->getWindSpeed(); };
api["getCurrentStormDirection"] = []() { return MWBase::Environment::get().getWorld()->getStormDirection(); };
return LuaUtil::makeReadOnly(api);
}
}

View File

@ -0,0 +1,14 @@
#ifndef MWLUA_WEATHERBINDINGS_H
#define MWLUA_WEATHERBINDINGS_H
#include <sol/forward.hpp>
namespace MWLua
{
struct Context;
sol::table initCoreWeatherBindings(const Context&);
}
#endif // MWLUA_WEATHERBINDINGS_H

View File

@ -943,8 +943,8 @@ namespace MWRender
stateUpdater->setIsUnderwater(isUnderwater);
stateUpdater->setFogColor(fogColor);
stateUpdater->setGameHour(world->getTimeStamp().getHour());
stateUpdater->setWeatherId(world->getCurrentWeather());
stateUpdater->setNextWeatherId(world->getNextWeather());
stateUpdater->setWeatherId(world->getCurrentWeatherScriptId());
stateUpdater->setNextWeatherId(world->getNextWeatherScriptId());
stateUpdater->setWeatherTransition(world->getWeatherTransition());
stateUpdater->setWindSpeed(world->getWindSpeed());
stateUpdater->setSkyColor(mSky->getSkyColor());

View File

@ -139,6 +139,7 @@ namespace MWRender
int skyGetSecundaPhase() const;
void skySetMoonColour(bool red);
const osg::Vec4f& getSunLightPosition() const { return mSunLight->getPosition(); }
void setSunDirection(const osg::Vec3f& direction);
void setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular, float sunVis);
void setNight(bool isNight) { mNight = isNight; }

View File

@ -71,7 +71,7 @@ namespace MWScript
public:
void execute(Interpreter::Runtime& runtime) override
{
runtime.push(MWBase::Environment::get().getWorld()->getCurrentWeather());
runtime.push(MWBase::Environment::get().getWorld()->getCurrentWeatherScriptId());
}
};

View File

@ -1,5 +1,6 @@
#include "weather.hpp"
#include <components/esm/stringrefid.hpp>
#include <components/settings/values.hpp>
#include <components/misc/rng.hpp>
@ -141,9 +142,12 @@ namespace MWWorld
return direction;
}
Weather::Weather(const std::string& name, float stormWindSpeed, float rainSpeed, float dlFactor, float dlOffset,
const std::string& particleEffect)
: mCloudTexture(Fallback::Map::getString("Weather_" + name + "_Cloud_Texture"))
Weather::Weather(ESM::RefId id, int scriptId, const std::string& name, float stormWindSpeed, float rainSpeed,
float dlFactor, float dlOffset, const std::string& particleEffect)
: mId(id)
, mScriptId(scriptId)
, mName(name)
, mCloudTexture(Fallback::Map::getString("Weather_" + name + "_Cloud_Texture"))
, mSkyColor(Fallback::Map::getColour("Weather_" + name + "_Sky_Sunrise_Color"),
Fallback::Map::getColour("Weather_" + name + "_Sky_Day_Color"),
Fallback::Map::getColour("Weather_" + name + "_Sky_Sunset_Color"),
@ -676,6 +680,41 @@ namespace MWWorld
stopSounds();
}
const Weather* WeatherManager::getWeather(size_t index) const
{
if (index < mWeatherSettings.size())
return &mWeatherSettings[index];
return nullptr;
}
const Weather* WeatherManager::getWeather(const ESM::RefId& id) const
{
auto it = std::find_if(
mWeatherSettings.begin(), mWeatherSettings.end(), [id](const auto& weather) { return weather.mId == id; });
if (it != mWeatherSettings.end())
return &*it;
return nullptr;
}
void WeatherManager::changeWeather(const ESM::RefId& regionID, const ESM::RefId& weatherID)
{
auto wIt = std::find_if(mWeatherSettings.begin(), mWeatherSettings.end(),
[weatherID](const auto& weather) { return weather.mId == weatherID; });
if (wIt != mWeatherSettings.end())
{
auto rIt = mRegions.find(regionID);
if (rIt != mRegions.end())
{
rIt->second.setWeather(std::distance(mWeatherSettings.begin(), wIt));
regionalWeatherChanged(rIt->first, rIt->second);
}
}
}
void WeatherManager::changeWeather(const ESM::RefId& regionID, const unsigned int weatherID)
{
// In Morrowind, this seems to have the following behavior, when applied to the current region:
@ -1053,8 +1092,9 @@ namespace MWWorld
const std::string& name, float dlFactor, float dlOffset, const std::string& particleEffect)
{
static const float fStromWindSpeed = mStore.get<ESM::GameSetting>().find("fStromWindSpeed")->mValue.getFloat();
Weather weather(name, fStromWindSpeed, mRainSpeed, dlFactor, dlOffset, particleEffect);
ESM::StringRefId id(name);
Weather weather(
id, mWeatherSettings.size(), name, fStromWindSpeed, mRainSpeed, dlFactor, dlOffset, particleEffect);
mWeatherSettings.push_back(weather);
}

View File

@ -109,6 +109,11 @@ namespace MWWorld
T getValue(const float gameHour, const TimeOfDaySettings& timeSettings, const std::string& prefix) const;
const T& getSunriseValue() const { return mSunriseValue; }
const T& getDayValue() const { return mDayValue; }
const T& getSunsetValue() const { return mSunsetValue; }
const T& getNightValue() const { return mNightValue; }
private:
T mSunriseValue, mDayValue, mSunsetValue, mNightValue;
};
@ -119,9 +124,12 @@ namespace MWWorld
public:
static osg::Vec3f defaultDirection();
Weather(const std::string& name, float stormWindSpeed, float rainSpeed, float dlFactor, float dlOffset,
const std::string& particleEffect);
Weather(const ESM::RefId id, const int scriptId, const std::string& name, float stormWindSpeed, float rainSpeed,
float dlFactor, float dlOffset, const std::string& particleEffect);
ESM::RefId mId;
int mScriptId;
std::string mName;
std::string mCloudTexture;
// Sky (atmosphere) color
@ -289,11 +297,12 @@ namespace MWWorld
~WeatherManager();
/**
* Change the weather in the specified region
* Change the weather in the specified region by id of the weather
* @param region that should be changed
* @param ID of the weather setting to shift to
*/
void changeWeather(const ESM::RefId& regionID, const unsigned int weatherID);
void changeWeather(const ESM::RefId& regionID, const ESM::RefId& weatherID);
void modRegion(const ESM::RefId& regionID, const std::vector<uint8_t>& chances);
void playerTeleported(const ESM::RefId& playerRegion, bool isExterior);
@ -316,8 +325,23 @@ namespace MWWorld
void advanceTime(double hours, bool incremental);
const std::vector<Weather>& getAllWeather() { return mWeatherSettings; }
const Weather& getWeather() { return mWeatherSettings[mCurrentWeather]; }
const Weather* getWeather(size_t index) const;
const Weather* getWeather(const ESM::RefId& id) const;
int getWeatherID() const { return mCurrentWeather; }
const Weather* getNextWeather()
{
if (mNextWeather > -1)
return &mWeatherSettings[mNextWeather];
return nullptr;
}
int getNextWeatherID() const { return mNextWeather; }
float getTransitionFactor() const { return mTransitionFactor; }

View File

@ -1868,14 +1868,43 @@ namespace MWWorld
return ESM::Cell::sDefaultWorldspaceId;
}
int World::getCurrentWeather() const
const std::vector<MWWorld::Weather>& World::getAllWeather() const
{
return mWeatherManager->getWeatherID();
return mWeatherManager->getAllWeather();
}
int World::getNextWeather() const
int World::getCurrentWeatherScriptId() const
{
return mWeatherManager->getNextWeatherID();
return mWeatherManager->getWeather().mScriptId;
}
const MWWorld::Weather& World::getCurrentWeather() const
{
return mWeatherManager->getWeather();
}
const MWWorld::Weather* World::getWeather(size_t index) const
{
return mWeatherManager->getWeather(index);
}
const MWWorld::Weather* World::getWeather(const ESM::RefId& id) const
{
return mWeatherManager->getWeather(id);
}
int World::getNextWeatherScriptId() const
{
auto next = mWeatherManager->getNextWeather();
if (next == nullptr)
return -1;
return next->mScriptId;
}
const MWWorld::Weather* World::getNextWeather() const
{
return mWeatherManager->getNextWeather();
}
float World::getWeatherTransition() const
@ -1893,6 +1922,11 @@ namespace MWWorld
mWeatherManager->changeWeather(region, id);
}
void World::changeWeather(const ESM::RefId& region, const ESM::RefId& id)
{
mWeatherManager->changeWeather(region, id);
}
void World::modRegion(const ESM::RefId& regionid, const std::vector<uint8_t>& chances)
{
mWeatherManager->modRegion(regionid, chances);
@ -3133,6 +3167,11 @@ namespace MWWorld
}
}
const osg::Vec4f& World::getSunLightPosition() const
{
return mRendering->getSunLightPosition();
}
float World::getSunVisibility() const
{
return mWeatherManager->getSunVisibility();

View File

@ -317,9 +317,16 @@ namespace MWWorld
void changeWeather(const ESM::RefId& region, const unsigned int id) override;
int getCurrentWeather() const override;
void changeWeather(const ESM::RefId& region, const ESM::RefId& id) override;
int getNextWeather() const override;
const std::vector<MWWorld::Weather>& getAllWeather() const override;
int getCurrentWeatherScriptId() const override;
const MWWorld::Weather& getCurrentWeather() const override;
const MWWorld::Weather* getWeather(size_t index) const override;
const MWWorld::Weather* getWeather(const ESM::RefId& id) const override;
int getNextWeatherScriptId() const override;
const MWWorld::Weather* getNextWeather() const override;
float getWeatherTransition() const override;
@ -573,6 +580,7 @@ namespace MWWorld
// Allow NPCs to use torches?
bool useTorches() const override;
const osg::Vec4f& getSunLightPosition() const override;
float getSunVisibility() const override;
float getSunPercentage() const override;

View File

@ -1198,4 +1198,100 @@
-- @field #string id MWScript id
-- @field #string text MWScript content
--- @{#Weather}: Weather
-- @field [parent=#core] #Weather weather
--- List of all @{#WeatherRecord}s.
-- @field [parent=#Weather] #list<#WeatherRecord> records A read-only list of all @{#WeatherRecord}s in the world database, may be indexed by recordId.
-- Implements [iterables#List](iterables.html#List) of #WeatherRecord.
-- @usage local weather = core.weather.records['Cloudy'] -- get by id
-- @usage local weather = core.weather.records[1] -- get by index
-- @usage -- Print all storms
-- for _, weather in pairs(core.weather.records) do
-- if weather.isStorm then
-- print(weather.name)
-- end
-- end
---
-- Get the current weather
-- @function [parent=#Weather] getCurrent
-- @return #WeatherData
---
-- Get the next weather if any
-- @function [parent=#Weather] getNext
-- @return #any can be nil
---
-- Get current weather transition value
-- @function [parent=#Weather] getTransition
-- @return #number
---
-- Change the weather
-- @function [parent=#Weather] changeWeather
-- @param #string regionId
-- @param #WeatherData The weather to change to
---
-- Get the current direction of the light of the sun.
-- @function [parent=#Weather] getCurrentSunLightDirection
-- @return openmw.util#Vector4
---
-- Get the current sun visibility taking weather transition into account.
-- @function [parent=#Weather] getCurrentSunVisibility
-- @return #number
---
-- Get the current sun percentage taking weather transition into account.
-- @function [parent=#Weather] getCurrentSunPercentage
-- @return #number
---
-- Get the current wind speed taking weather transition into account.
-- @function [parent=#Weather] getCurrentWindSpeed
-- @return #number
---
-- Get the current storm direction taking weather transition into account.
-- @function [parent=#Weather] getCurrentStormDirection
-- @return openmw.util#Vector3
---
-- Weather data
-- @type WeatherRecord
-- @extends #userdata
-- @field #string recordId
-- @field #number scriptId
-- @field #string name
-- @field #number windSpeed
-- @field #number cloudSpeed
-- @field #string cloudTexture
-- @field #number cloudsMaximumPercent
-- @field #boolean isStorm
-- @field openmw.util#Vector3 stormDirection
-- @field #number glareView
-- @field #number rainSpeed
-- @field #number rainEntranceSpeed
-- @field #string rainEffect Will return nil if weather has no rainEffect
-- @field #number rainMaxRaindrops
-- @field #number rainDiameter
-- @field #number rainMaxHeight
-- @field #number rainMinHeight
-- @field #string rainLoopSoundID
-- @field #table thunderSoundID An array containing the recordIds of the thunder sounds
-- @field #string ambientLoopSoundID
-- @field #string particleEffect Will return nil if weather has no particleEffect
-- @field #number distantLandFogFactor
-- @field #number distantLandFogOffset
-- @field openmw.util#Color sunDiscSunsetColor
-- @field #table landFogDepth A table with the keys "sunrise", "day", "sunset" and "night"
-- @field #table skyColor A table with the keys "sunrise", "day", "sunset" and "night". Each is a @{openmw.util#Color}.
-- @field #table ambientColor A table with the keys "sunrise", "day", "sunset" and "night". Each is a @{openmw.util#Color}.
-- @field #table fogColor A table with the keys "sunrise", "day", "sunset" and "night". Each is a @{openmw.util#Color}.
-- @field #table sunColor A table with the keys "sunrise", "day", "sunset" and "night". Each is a @{openmw.util#Color}.
return nil