diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index d87f0de37d..386e0b913b 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -501,7 +501,7 @@ namespace MWLua }); }; objectT["setTransform"] = [context](const GObject& object, const osg::Vec3f& newPos, - sol::object newRotObj, sol::optional terrainClampOpt) { + const sol::object& newRotObj, sol::optional terrainClampOpt) { bool terrainClamp = terrainClampOpt.value_or(true); MWWorld::Ptr ptr = object.ptr(); if (ptr.getCellRef().getCount() == 0 || !ptr.isInCell()) @@ -522,11 +522,7 @@ namespace MWLua finalPos.z() = terrainHeight; } - osg::Vec3f rotVec = ptr.getRefData().getPosition().asRotationVec3(); - if (newRotObj != sol::nil) - { - rotVec = toEulerRotation(newRotObj, ptr.getClass().isActor()); - } + osg::Vec3f rotVec = toEulerRotation(newRotObj, ptr.getClass().isActor()); context.mLuaManager->addAction( [object, finalPos, rotVec] { @@ -536,6 +532,50 @@ namespace MWLua }, "SetTransformAction"); }; + objectT["setPosition"] + = [context](const GObject& object, const osg::Vec3f& newPos, sol::optional terrainClampOpt) { + bool terrainClamp = terrainClampOpt.value_or(true); + MWWorld::Ptr ptr = object.ptr(); + if (ptr.getCellRef().getCount() == 0 || !ptr.isInCell()) + throw std::runtime_error("Object is either removed or in the process of teleporting"); + + osg::Vec3f finalPos = newPos; + + if (terrainClamp && ptr.getClass().isActor()) + { + float terrainHeight = -std::numeric_limits::max(); + if (ptr.getCell()->isExterior()) + { + terrainHeight = MWBase::Environment::get().getWorld()->getTerrainHeightAt( + finalPos, ptr.getCell()->getCell()->getWorldSpace()); + } + + if (finalPos.z() < terrainHeight) + finalPos.z() = terrainHeight; + } + + context.mLuaManager->addAction( + [object, finalPos] { + auto world = MWBase::Environment::get().getWorld(); + world->moveObject(object.ptr(), finalPos, true, false); + }, + "SetPositionAction"); + }; + objectT["setRotation"] = [context](const GObject& object, const sol::object& newRotObj) { + MWWorld::Ptr ptr = object.ptr(); + if (ptr.getCellRef().getCount() == 0 || !ptr.isInCell()) + throw std::runtime_error("Object is either removed or in the process of teleporting"); + + // newRotObj must always be valid + osg::Vec3f rotVec = toEulerRotation(newRotObj, ptr.getClass().isActor()); + + context.mLuaManager->addAction( + [object, rotVec] { + auto world = MWBase::Environment::get().getWorld(); + world->rotateObject(object.ptr(), rotVec, MWBase::RotationFlag_none); + }, + "SetRotationAction"); + }; objectT["teleport"] = [removeFn, context](const GObject& object, const sol::object& cellOrName, const osg::Vec3f& pos, const sol::object& options) { MWWorld::CellStore* cell = findCell(cellOrName, pos); diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 64c9717aab..17064a402a 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -242,9 +242,28 @@ -- @function [parent=#GameObject] setTransform -- @param self -- @param openmw.util#Vector3 position New position. --- @param openmw.util#Transform rotation New rotation; if missing, then the current rotation is used. +-- @param openmw.util#Transform rotation New rotation. -- @param #boolean terrainClamp (optional, true by default) If true, actors will be restricted to positions above the terrain. +--- +-- Moves an object to a given position. +-- Can be called only from a global script. +-- The effect is not immediate: the position will be updated only in the next frame. +-- If both rotation and position need to be updated, use setTransform. +-- @function [parent=#GameObject] setPosition +-- @param self +-- @param openmw.util#Vector3 position New position. +-- @param #boolean terrainClamp (optional, true by default) If true, actors will be restricted to positions above the terrain. + +--- +-- Rotates an object to a given rotation. +-- Can be called only from a global script. +-- The effect is not immediate: the rotation will be updated only in the next frame. +-- If both rotation and position need to be updated, use setTransform. +-- @function [parent=#GameObject] setRotation +-- @param self +-- @param openmw.util#Transform rotation New rotation. + --- -- Moves object to given cell and position. -- Can be called only from a global script.