From e53f907a5366d1631ae9a6a68ccf2560c20316b4 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 13 May 2023 15:26:39 +0200 Subject: [PATCH 1/4] Set CharacterController::mSmoothedSpeed to zero after teleporting. --- apps/openmw/mwlua/objectbindings.cpp | 10 ++++++++-- apps/openmw/mwmechanics/character.cpp | 8 +++++++- apps/openmw/mwmechanics/creaturestats.hpp | 5 +++++ apps/openmw/mwscript/transformationextensions.cpp | 9 +++++---- apps/openmw/mwworld/actionteleport.cpp | 4 +++- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 6ab6776d7a..0906c44a53 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -74,7 +74,9 @@ namespace MWLua std::memcpy(esmPos.pos, &pos, sizeof(osg::Vec3f)); std::memcpy(esmPos.rot, &rot, sizeof(osg::Vec3f)); MWWorld::Ptr ptr = world->getPlayerPtr(); - ptr.getClass().getCreatureStats(ptr).land(false); + auto& stats = ptr.getClass().getCreatureStats(ptr); + stats.land(true); + stats.setTeleported(true); world->getPlayer().setTeleported(true); world->changeToCell(destCell->getCell()->getId(), esmPos, true); } @@ -85,7 +87,11 @@ namespace MWLua MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::Class& cls = ptr.getClass(); if (cls.isActor()) - cls.getCreatureStats(ptr).land(false); + { + auto& stats = ptr.getClass().getCreatureStats(ptr); + stats.land(false); + stats.setTeleported(true); + } MWWorld::Ptr newPtr = world->moveObject(ptr, destCell, pos); world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); if (!newPtr.getRefData().isEnabled()) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index b7a28241a3..f891a5ab72 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1862,7 +1862,7 @@ namespace MWMechanics float scale = mPtr.getCellRef().getScale(); static const bool normalizeSpeed = Settings::Manager::getBool("normalise race speed", "Game"); - if (!normalizeSpeed && mPtr.getClass().isNpc()) + if (!normalizeSpeed && cls.isNpc()) { const ESM::NPC* npc = mPtr.get()->mBase; const ESM::Race* race = world->getStore().get().find(npc->mRace); @@ -1870,6 +1870,12 @@ namespace MWMechanics scale *= weight; } + if (cls.isActor() && cls.getCreatureStats(mPtr).wasTeleported()) + { + mSmoothedSpeed = osg::Vec2f(); + cls.getCreatureStats(mPtr).setTeleported(false); + } + if (!cls.isActor()) updateAnimQueue(); else if (!cls.getCreatureStats(mPtr).isDead()) diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 0ded000469..9d1830fe03 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -85,6 +85,8 @@ namespace MWMechanics // The difference between view direction and lower body direction. float mSideMovementAngle; + bool mTeleported = false; + private: std::multimap mSummonedCreatures; // @@ -288,6 +290,9 @@ namespace MWMechanics float getSideMovementAngle() const { return mSideMovementAngle; } void setSideMovementAngle(float angle) { mSideMovementAngle = angle; } + + bool wasTeleported() const { return mTeleported; } + void setTeleported(bool v) { mTeleported = v; } }; } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index fd091711c8..bf9fe14298 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -21,6 +21,7 @@ #include "../mwworld/worldmodel.hpp" #include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -389,10 +390,10 @@ namespace MWScript bool isPlayer = ptr == MWMechanics::getPlayer(); auto world = MWBase::Environment::get().getWorld(); auto worldModel = MWBase::Environment::get().getWorldModel(); + if (ptr.getClass().isActor()) + ptr.getClass().getCreatureStats(ptr).setTeleported(true); if (isPlayer) - { world->getPlayer().setTeleported(true); - } MWWorld::CellStore* store = nullptr; try @@ -463,10 +464,10 @@ namespace MWScript bool isPlayer = ptr == MWMechanics::getPlayer(); auto world = MWBase::Environment::get().getWorld(); + if (ptr.getClass().isActor()) + ptr.getClass().getCreatureStats(ptr).setTeleported(true); if (isPlayer) - { world->getPlayer().setTeleported(true); - } const ESM::ExteriorCellLocation cellIndex = ESM::positionToCellIndex(x, y, ESM::Cell::sDefaultWorldspaceId); diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 926e958e95..2aaa16cd0b 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -47,7 +47,9 @@ namespace MWWorld { MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::WorldModel* worldModel = MWBase::Environment::get().getWorldModel(); - actor.getClass().getCreatureStats(actor).land(actor == world->getPlayerPtr()); + auto& stats = actor.getClass().getCreatureStats(actor); + stats.land(actor == world->getPlayerPtr()); + stats.setTeleported(true); Ptr teleported; if (actor == world->getPlayerPtr()) From 2725a9d7f4c94e16baf5e891f62308f60286456e Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 13 May 2023 16:50:56 +0200 Subject: [PATCH 2/4] Add option "onGround=true/false" in Lua teleporting --- apps/openmw/mwlua/objectbindings.cpp | 39 ++++++++++++++++++++-------- files/lua_api/openmw/core.lua | 8 +++++- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 0906c44a53..55f18a01ac 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -66,7 +66,8 @@ namespace MWLua return &wm->getCellByPosition(pos, cell); } - void teleportPlayer(MWWorld::CellStore* destCell, const osg::Vec3f& pos, const osg::Vec3f& rot) + void teleportPlayer( + MWWorld::CellStore* destCell, const osg::Vec3f& pos, const osg::Vec3f& rot, bool placeOnGround) { MWBase::World* world = MWBase::Environment::get().getWorld(); ESM::Position esmPos; @@ -78,11 +79,16 @@ namespace MWLua stats.land(true); stats.setTeleported(true); world->getPlayer().setTeleported(true); - world->changeToCell(destCell->getCell()->getId(), esmPos, true); + world->changeToCell(destCell->getCell()->getId(), esmPos, false); + MWWorld::Ptr newPtr = world->getPlayerPtr(); + world->moveObject(newPtr, pos); + world->rotateObject(newPtr, rot); + if (placeOnGround) + world->adjustPosition(newPtr, true); } - void teleportNotPlayer( - const MWWorld::Ptr& ptr, MWWorld::CellStore* destCell, const osg::Vec3f& pos, const osg::Vec3f& rot) + void teleportNotPlayer(const MWWorld::Ptr& ptr, MWWorld::CellStore* destCell, const osg::Vec3f& pos, + const osg::Vec3f& rot, bool placeOnGround) { MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::Class& cls = ptr.getClass(); @@ -94,6 +100,8 @@ namespace MWLua } MWWorld::Ptr newPtr = world->moveObject(ptr, destCell, pos); world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); + if (placeOnGround) + world->adjustPosition(newPtr, true); if (!newPtr.getRefData().isEnabled()) world->enable(newPtr); } @@ -349,38 +357,47 @@ namespace MWLua }); }; objectT["teleport"] = [removeFn, context](const GObject& object, const sol::object& cellOrName, - const osg::Vec3f& pos, const sol::optional& optRot) { + const osg::Vec3f& pos, const sol::object& options) { MWWorld::CellStore* cell = findCell(cellOrName, pos); MWWorld::Ptr ptr = object.ptr(); int count = ptr.getRefData().getCount(); if (count == 0) throw std::runtime_error("Object is either removed or already in the process of teleporting"); - osg::Vec3f rot = optRot ? *optRot : ptr.getRefData().getPosition().asRotationVec3(); + osg::Vec3f rot = ptr.getRefData().getPosition().asRotationVec3(); + bool placeOnGround = false; + if (options.is()) + rot = options.as(); + else if (options != sol::nil) + { + sol::table t = LuaUtil::cast(options); + rot = LuaUtil::getValueOrDefault(t["rotation"], rot); + placeOnGround = LuaUtil::getValueOrDefault(t["onGround"], placeOnGround); + } if (ptr.getContainerStore()) { DelayedRemovalFn delayedRemovalFn = *removeFn(ptr, count); context.mLuaManager->addAction( - [object, cell, pos, rot, count, delayedRemovalFn] { + [object, cell, pos, rot, count, delayedRemovalFn, placeOnGround] { MWWorld::Ptr oldPtr = object.ptr(); oldPtr.getRefData().setCount(count); MWWorld::Ptr newPtr = oldPtr.getClass().moveToCell(oldPtr, *cell); oldPtr.getRefData().setCount(0); newPtr.getRefData().disable(); - teleportNotPlayer(newPtr, cell, pos, rot); + teleportNotPlayer(newPtr, cell, pos, rot, placeOnGround); delayedRemovalFn(oldPtr); }, "TeleportFromContainerAction"); } else if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) context.mLuaManager->addTeleportPlayerAction( - [cell, pos, rot] { teleportPlayer(cell, pos, rot); }); + [cell, pos, rot, placeOnGround] { teleportPlayer(cell, pos, rot, placeOnGround); }); else { ptr.getRefData().setCount(0); context.mLuaManager->addAction( - [object, cell, pos, rot, count] { + [object, cell, pos, rot, count, placeOnGround] { object.ptr().getRefData().setCount(count); - teleportNotPlayer(object.ptr(), cell, pos, rot); + teleportNotPlayer(object.ptr(), cell, pos, rot, placeOnGround); }, "TeleportAction"); } diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 0312ba8706..a472b8ac88 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -177,7 +177,13 @@ -- @param #any cellOrName A cell to define the destination worldspace; can be either #Cell, or cell name, or an empty string (empty string means the default exterior worldspace). -- If the worldspace has multiple cells (i.e. an exterior), the destination cell is calculated using `position`. -- @param openmw.util#Vector3 position New position. --- @param openmw.util#Vector3 rotation (optional) New rotation. If missing, then the current rotation is used. +-- @param #TeleportOptions options (optional) Either table @{#TeleportOptions} or @{openmw.util#Vector3} rotation. + +--- +-- Either table with options or @{openmw.util#Vector3} rotation. +-- @type TeleportOptions +-- @field openmw.util#Vector3 rotation New rotation; if missing, then the current rotation is used. +-- @field #boolean onGround If true, adjust destination position to the ground. --- -- Moves object into a container or an inventory. Enables if was disabled. From ce7f6f31c9923347b21bcab3f97465ee62021310 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 13 May 2023 19:30:18 +0200 Subject: [PATCH 3/4] Additional Lua bindings for cells --- apps/openmw/mwlua/cellbindings.cpp | 9 +++- apps/openmw/mwlua/luabindings.cpp | 70 +++++++++++++++++++++++++++--- apps/openmw/mwworld/store.hpp | 8 ++++ apps/openmw/mwworld/worldmodel.cpp | 28 +++++++----- apps/openmw/mwworld/worldmodel.hpp | 8 ++-- files/lua_api/openmw/core.lua | 1 + files/lua_api/openmw/world.lua | 6 +++ 7 files changed, 105 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 2021bca728..35f9af0f2b 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -33,7 +33,8 @@ namespace MWLua auto cell = c.mStore->getCell(); std::stringstream res; if (cell->isExterior()) - res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")"; + res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ", " + << cell->getWorldSpace().toDebugString() << ")"; else res << "interior(" << cell->getNameId() << ")"; return res.str(); @@ -42,6 +43,8 @@ namespace MWLua cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getNameId(); }); cellT["region"] = sol::readonly_property( [](const CellT& c) -> std::string { return c.mStore->getCell()->getRegion().serializeText(); }); + cellT["worldSpaceId"] = sol::readonly_property( + [](const CellT& c) -> std::string { return c.mStore->getCell()->getWorldSpace().serializeText(); }); cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); }); cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); }); cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); }); @@ -67,13 +70,15 @@ namespace MWLua if (!ptr.isInCell()) return false; MWWorld::CellStore* cell = ptr.getCell(); - return cell == c.mStore || (cell->isExterior() && c.mStore->isExterior()); + return cell == c.mStore || (cell->getCell()->getWorldSpace() == c.mStore->getCell()->getWorldSpace()); }; if constexpr (std::is_same_v) { // only for global scripts cellT["getAll"] = [ids = getPackageToTypeTable(context.mLua->sol())]( const CellT& cell, sol::optional type) { + if (cell.mStore->getState() != MWWorld::CellStore::State_Loaded) + cell.mStore->load(); ObjectIdList res = std::make_shared>(); auto visitor = [&](const MWWorld::Ptr& ptr) { if (ptr.getRefData().isDeleted()) diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 0084c4a901..0f32cba562 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -34,6 +34,21 @@ #include "types/types.hpp" #include "uibindings.hpp" +namespace MWLua +{ + struct CellsStore + { + }; +} + +namespace sol +{ + template <> + struct is_automagical : std::false_type + { + }; +} + namespace MWLua { @@ -68,7 +83,7 @@ namespace MWLua { auto* lua = context.mLua; sol::table api(lua->sol(), sol::create); - api["API_REVISION"] = 37; + api["API_REVISION"] = 38; api["quit"] = [lua]() { Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback(); MWBase::Environment::get().getStateManager()->requestQuit(); @@ -106,17 +121,58 @@ namespace MWLua return LuaUtil::makeReadOnly(api); } + static void addCellGetters(sol::table& api, const Context& context) + { + api["getCellByName"] = [](std::string_view name) { + return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(name, /*forceLoad=*/false) }; + }; + api["getExteriorCell"] = [](int x, int y, sol::object cellOrName) { + ESM::RefId worldspace; + if (cellOrName.is()) + worldspace = cellOrName.as().mStore->getCell()->getWorldSpace(); + else if (cellOrName.is() && !cellOrName.as().empty()) + worldspace = MWBase::Environment::get() + .getWorldModel() + ->getCell(cellOrName.as()) + .getCell() + ->getWorldSpace(); + else + worldspace = ESM::Cell::sDefaultWorldspaceId; + return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior( + ESM::ExteriorCellLocation(x, y, worldspace), /*forceLoad=*/false) }; + }; + + const MWWorld::Store* cells3Store = &MWBase::Environment::get().getESMStore()->get(); + const MWWorld::Store* cells4Store = &MWBase::Environment::get().getESMStore()->get(); + sol::usertype cells = context.mLua->sol().new_usertype("Cells"); + cells[sol::meta_function::length] + = [cells3Store, cells4Store](const CellsStore&) { return cells3Store->getSize() + cells4Store->getSize(); }; + cells[sol::meta_function::index] = [cells3Store, cells4Store](const CellsStore&, size_t index) -> GCell { + index--; // Translate from Lua's 1-based indexing. + if (index < cells3Store->getSize()) + { + const ESM::Cell* cellRecord = cells3Store->at(index); + return GCell{ &MWBase::Environment::get().getWorldModel()->getCell( + cellRecord->mId, /*forceLoad=*/false) }; + } + else + { + const ESM4::Cell* cellRecord = cells4Store->at(index - cells3Store->getSize()); + return GCell{ &MWBase::Environment::get().getWorldModel()->getCell( + cellRecord->mId, /*forceLoad=*/false) }; + } + }; + cells[sol::meta_function::pairs] = context.mLua->sol()["ipairsForArray"].template get(); + cells[sol::meta_function::ipairs] = context.mLua->sol()["ipairsForArray"].template get(); + api["cells"] = CellsStore{}; + } + static sol::table initWorldPackage(const Context& context) { sol::table api(context.mLua->sol(), sol::create); WorldView* worldView = context.mWorldView; addTimeBindings(api, context, true); - api["getCellByName"] - = [](std::string_view name) { return GCell{ &MWBase::Environment::get().getWorldModel()->getCell(name) }; }; - api["getExteriorCell"] = [](int x, int y) { - return GCell{ &MWBase::Environment::get().getWorldModel()->getExterior( - ESM::ExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId)) }; - }; + addCellGetters(api, context); api["activeActors"] = GObjectList{ worldView->getActorsInScene() }; api["createObject"] = [](std::string_view recordId, sol::optional count) -> GObject { // Doesn't matter which cell to use because the new object will be in disabled state. diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 662fc2b558..75c41af25e 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -413,6 +413,14 @@ namespace MWWorld size_t getExtSize() const; size_t getIntSize() const; + const ESM::Cell* at(size_t index) const + { + if (index < mSharedInt.size()) + return mSharedInt.at(index); + else + return mSharedExt.at(index - mSharedInt.size()); + } + void listIdentifier(std::vector& list) const override; ESM::Cell* insert(const ESM::Cell& cell); diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index e9b1cf1300..4f53dd329c 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -160,7 +160,7 @@ MWWorld::WorldModel::WorldModel(const MWWorld::ESMStore& store, ESM::ReadersCach { } -MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellLocation cellIndex) +MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellLocation cellIndex, bool forceLoad) { std::map::iterator result; @@ -211,7 +211,7 @@ MWWorld::CellStore& MWWorld::WorldModel::getExterior(ESM::ExteriorCellLocation c result = mExteriors.emplace(cellIndex, cellStore).first; } } - if (result->second->getState() != CellStore::State_Loaded) + if (forceLoad && result->second->getState() != CellStore::State_Loaded) { result->second->load(); } @@ -234,22 +234,20 @@ MWWorld::CellStore* MWWorld::WorldModel::getInteriorOrNull(std::string_view name return nullptr; // Cell not found result = mInteriors.emplace(name, newCellStore).first; } - - if (result->second->getState() != CellStore::State_Loaded) - result->second->load(); - return result->second; } -MWWorld::CellStore& MWWorld::WorldModel::getInterior(std::string_view name) +MWWorld::CellStore& MWWorld::WorldModel::getInterior(std::string_view name, bool forceLoad) { CellStore* res = getInteriorOrNull(name); if (res == nullptr) throw std::runtime_error("Interior not found: '" + std::string(name) + "'"); + if (forceLoad && res->getState() != CellStore::State_Loaded) + res->load(); return *res; } -MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) +MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id, bool forceLoad) { auto result = mCells.find(id); if (result != mCells.end()) @@ -257,7 +255,8 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) if (const auto* exteriorId = id.getIf()) return getExterior( - ESM::ExteriorCellLocation(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId)); + ESM::ExteriorCellLocation(exteriorId->getX(), exteriorId->getY(), ESM::Cell::sDefaultWorldspaceId), + forceLoad); const ESM4::Cell* cell4 = mStore.get().search(id); CellStore* newCellStore = nullptr; @@ -281,17 +280,21 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(const ESM::RefId& id) { mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore); } - if (newCellStore->getState() != CellStore::State_Loaded) + if (forceLoad && newCellStore->getState() != CellStore::State_Loaded) { newCellStore->load(); } return *newCellStore; } -MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name) +MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name, bool forceLoad) { if (CellStore* res = getInteriorOrNull(name)) // first try interiors + { + if (forceLoad && res->getState() != CellStore::State_Loaded) + res->load(); return *res; + } // try named exteriors const ESM::Cell* cell = mStore.get().searchExtByName(name); @@ -319,7 +322,8 @@ MWWorld::CellStore& MWWorld::WorldModel::getCell(std::string_view name) if (!cell) throw std::runtime_error(std::string("Can't find cell with name ") + std::string(name)); - return getExterior(ESM::ExteriorCellLocation(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId)); + return getExterior( + ESM::ExteriorCellLocation(cell->getGridX(), cell->getGridY(), ESM::Cell::sDefaultWorldspaceId), forceLoad); } MWWorld::CellStore& MWWorld::WorldModel::getCellByPosition( diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index b90a063c69..1048a27e84 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -65,10 +65,10 @@ namespace MWWorld void clear(); - CellStore& getExterior(ESM::ExteriorCellLocation cellIndex); - CellStore& getInterior(std::string_view name); - CellStore& getCell(std::string_view name); // interior or named exterior - CellStore& getCell(const ESM::RefId& Id); + CellStore& getExterior(ESM::ExteriorCellLocation cellIndex, bool forceLoad = true); + CellStore& getInterior(std::string_view name, bool forceLoad = true); + CellStore& getCell(std::string_view name, bool forceLoad = true); // interior or named exterior + CellStore& getCell(const ESM::RefId& Id, bool forceLoad = true); // Returns the cell that is in the same worldspace as `cellInSameWorldSpace` // (in case of nullptr - default exterior worldspace) and contains given position. diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index a472b8ac88..b9c56f8a8e 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -225,6 +225,7 @@ -- @field #boolean isQuasiExterior (DEPRECATED, use `hasTag("QuasiExterior")`) Whether the cell is a quasi exterior (like interior but with the sky and the wheather). -- @field #number gridX Index of the cell by X (only for exteriors). -- @field #number gridY Index of the cell by Y (only for exteriors). +-- @field #string worldSpaceId Id of the world space. -- @field #boolean hasWater True if the cell contains water. -- @field #boolean hasSky True if in this cell sky should be rendered. diff --git a/files/lua_api/openmw/world.lua b/files/lua_api/openmw/world.lua index ad18c2193e..732ce1e938 100644 --- a/files/lua_api/openmw/world.lua +++ b/files/lua_api/openmw/world.lua @@ -21,8 +21,14 @@ -- @function [parent=#world] getExteriorCell -- @param #number gridX -- @param #number gridY +-- @param #any cellOrName (optional) other cell or cell name in the same exterior world space -- @return openmw.core#Cell +--- +-- List of all cells +-- @field [parent=#world] #list cells +-- @usage for i, cell in ipairs(world.cells) do print(cell) end + --- -- Simulation time in seconds. -- The number of simulation seconds passed in the game world since starting a new game. From 711363884839e31554ea18f1df346331011f8ac0 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 13 May 2023 20:39:00 +0200 Subject: [PATCH 4/4] Fix animation of teleported non-teleporting doors. --- apps/openmw/mwlua/objectbindings.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index 55f18a01ac..d5c896378c 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -102,6 +102,11 @@ namespace MWLua world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); if (placeOnGround) world->adjustPosition(newPtr, true); + if (cls.isDoor()) + { // Change "original position and rotation" because without it teleported animated doors don't work + // properly. + newPtr.getCellRef().setPosition(newPtr.getRefData().getPosition()); + } if (!newPtr.getRefData().isEnabled()) world->enable(newPtr); }