From d58545ca39f293fc7ac154a277cf0efe1b20f009 Mon Sep 17 00:00:00 2001 From: SkyHasACat Date: Sat, 5 Jul 2025 07:25:56 -0500 Subject: [PATCH] Add region bindings --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwlua/corebindings.cpp | 3 + apps/openmw/mwlua/regionbindings.cpp | 92 ++++++++++++++++++++++++++++ apps/openmw/mwlua/regionbindings.hpp | 13 ++++ files/lua_api/openmw/core.lua | 29 +++++++++ 5 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwlua/regionbindings.cpp create mode 100644 apps/openmw/mwlua/regionbindings.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index df6bf27eeb..9a5669c870 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -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 weatherbindings + classbindings itemdata inputprocessor animationbindings birthsignbindings racebindings markupbindings weatherbindings regionbindings 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 diff --git a/apps/openmw/mwlua/corebindings.cpp b/apps/openmw/mwlua/corebindings.cpp index 282a9f970b..4d02c5f1f6 100644 --- a/apps/openmw/mwlua/corebindings.cpp +++ b/apps/openmw/mwlua/corebindings.cpp @@ -27,6 +27,7 @@ #include "luaevents.hpp" #include "magicbindings.hpp" #include "soundbindings.hpp" +#include "regionbindings.hpp" #include "stats.hpp" #include "weatherbindings.hpp" @@ -111,6 +112,8 @@ namespace MWLua api["factions"] = context.cachePackage("openmw_core_factions", [context]() { return initCoreFactionBindings(context); }); + api["regions"] + = context.cachePackage("openmw_core_regions", [context]() { return initCoreRegionBindings(context); }); api["dialogue"] = context.cachePackage("openmw_core_dialogue", [context]() { return initCoreDialogueBindings(context); }); api["l10n"] = context.cachePackage("openmw_core_l10n", diff --git a/apps/openmw/mwlua/regionbindings.cpp b/apps/openmw/mwlua/regionbindings.cpp new file mode 100644 index 0000000000..ce2757995d --- /dev/null +++ b/apps/openmw/mwlua/regionbindings.cpp @@ -0,0 +1,92 @@ +#include "regionbindings.hpp" +#include "recordstore.hpp" + +#include +#include +#include +#include + +#include "idcollectionbindings.hpp" + +namespace +{ + struct RegionSoundRef + { + ESM::RefId mSoundId; + uint8_t mChance; + + RegionSoundRef(const ESM::Region::SoundRef& ref) + : mSoundId(ref.mSound) + , mChance(ref.mChance) + { + } + }; +} + +namespace sol +{ + template <> + struct is_automagical : std::false_type + { + }; + template <> + struct is_automagical> : std::false_type + { + }; +} + +namespace MWLua +{ + sol::table initCoreRegionBindings(const Context& context) + { + sol::state_view lua = context.sol(); + sol::table regions(lua, sol::create); + addRecordFunctionBinding(regions, context); + + // Region record + auto regionT = lua.new_usertype("ESM3_Region"); + regionT[sol::meta_function::to_string] + = [](const ESM::Region& rec) -> std::string { return "ESM3_Region[" + rec.mId.toDebugString() + "]"; }; + regionT["id"] = sol::readonly_property([](const ESM::Region& rec) { return rec.mId.serializeText(); }); + regionT["name"] = sol::readonly_property([](const ESM::Region& rec) -> std::string_view { return rec.mName; }); + regionT["mapColor"] = sol::readonly_property([](const ESM::Region& rec) -> Misc::Color { + uint32_t c = rec.mMapColor; + float r = ((c >> 16) & 0xFF) / 255.f; + float g = ((c >> 8) & 0xFF) / 255.f; + float b = (c & 0xFF) / 255.f; + return Misc::Color(r, g, b, 1.f); // assume alpha = 1.0 + }); + regionT["sleepList"] + = sol::readonly_property([](const ESM::Region& rec) { return rec.mSleepList.serializeText(); }); + + regionT["weatherProbabilities"] = sol::readonly_property([lua = lua.lua_state()](const ESM::Region& rec) { + static const std::array WeatherNames + = { "clear", "cloudy", "foggy", "overcast", "rain", "thunder", "ash", "blight", "snow", "blizzard" }; + + sol::table res(lua, sol::create); + for (size_t i = 0; i < rec.mData.mProbabilities.size(); ++i) + { + res[i + 1] = rec.mData.mProbabilities[i]; // Numeric index (Lua-style 1-based) + res[WeatherNames[i]] = rec.mData.mProbabilities[i]; // Named index + } + return res; + }); + + regionT["sounds"] = sol::readonly_property([lua = lua.lua_state()](const ESM::Region& rec) { + sol::table res(lua, sol::create); + for (const auto& soundRef : rec.mSoundList) + res.add(RegionSoundRef(soundRef)); + return res; + }); + + auto soundRefT = lua.new_usertype("ESM3_RegionSoundRef"); + soundRefT[sol::meta_function::to_string] = [](const RegionSoundRef& ref) -> std::string { + return "ESM3_RegionSoundRef[" + ref.mSoundId.toDebugString() + "]"; + }; + soundRefT["soundId"] + = sol::readonly_property([](const RegionSoundRef& ref) { return ref.mSoundId.serializeText(); }); + soundRefT["chance"] = sol::readonly_property([](const RegionSoundRef& ref) { return ref.mChance; }); + + return LuaUtil::makeReadOnly(regions); + } +} diff --git a/apps/openmw/mwlua/regionbindings.hpp b/apps/openmw/mwlua/regionbindings.hpp new file mode 100644 index 0000000000..4474e516a5 --- /dev/null +++ b/apps/openmw/mwlua/regionbindings.hpp @@ -0,0 +1,13 @@ +#ifndef MWLUA_REGIONBINDINGS_H +#define MWLUA_REGIONBINDINGS_H + +#include + +#include "context.hpp" + +namespace MWLua +{ + sol::table initCoreRegionBindings(const Context& context); +} + +#endif // MWLUA_REGIONBINDINGS_H diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index c1b888bd43..688a1d92ba 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -1159,6 +1159,35 @@ -- Always nil for journal records or if there is no value set. -- @field [parent=#DialogueRecordInfo] #string resultScript +--- @{#Regions}: Regions +-- @field [parent=#core] #Regions regions + +--- +-- A read-only list of all @{#RegionRecord}s in the world database. +-- @field [parent=#Regions] #list<#RegionRecord> records +-- @usage local record = core.regions.records['bitter coast region'] +-- @usage local record = core.regions.records[1] + +--- +-- Region data record +-- @type RegionRecord +-- @field #string id Region ID +-- @field #string name Region display name +-- @field openmw.util#Color mapColor Map color for this region. +-- @field #string sleepList A list of leveled creature list used when sleeping outdoors in this region +-- @field #list<#RegionSoundRef> sounds A read-only list of ambient sounds played randomly in this region +-- @field #table weatherProbabilities A table mapping weather types to their probability (0–100), should sum to 100. +-- Supports both numeric indices (1–10) and string keys: +-- `"clear"`, `"cloudy"`, `"foggy"`, `"overcast"`, `"rain"`, `"thunder"`, `"ash"`, `"blight"`, `"snow"`, `"blizzard"` +-- @usage print(region.weatherProbabilities[1]) -- access by index +-- @usage print(region.weatherProbabilities["rain"]) -- access by name + +--- +-- Region sound reference +-- @type RegionSoundRef +-- @field #string soundId Sound record ID +-- @field #number chance Probability that this sound plays periodically in the region + --- @{#Factions}: Factions -- @field [parent=#core] #Factions factions