diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 3d55ad987..6cee36b40 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -281,13 +281,13 @@ namespace MWBase virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; - virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z, bool moveToActive=false) = 0; + virtual MWWorld::Ptr moveObject (const MWWorld::Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false) = 0; ///< @return an updated Ptr in case the Ptr's cell changes virtual MWWorld::Ptr moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z, bool movePhysics=true) = 0; ///< @return an updated Ptr - virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec) = 0; + virtual MWWorld::Ptr moveObjectBy(const MWWorld::Ptr &ptr, osg::Vec3f vec, bool moveToActive) = 0; ///< @return an updated Ptr virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0; diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 776212ede..f9adc9bc6 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -3,8 +3,6 @@ #include #include -#include -#include #include #include #include @@ -181,6 +179,7 @@ bool Actor::setPosition(const osg::Vec3f& position) if (mSkipSimulation) return false; bool hasChanged = mPosition != position || mPositionOffset.length() != 0 || mWorldPositionChanged; + updateWorldPosition(); applyOffsetChange(); mPreviousPosition = mPosition; mPosition = position; @@ -197,15 +196,6 @@ void Actor::applyOffsetChange() { if (mPositionOffset.length() == 0) return; - if (mPositionOffset.z() != 0) - { - // Often, offset are set in sequence x, y, z - // We don't want actors to be moved under the ground - // Check terrain height at new coordinate and update z offset if necessary - const auto pos = mWorldPosition + mPositionOffset; - const auto terrainHeight = mPtr.getCell()->isExterior() ? MWBase::Environment::get().getWorld()->getTerrainHeightAt(pos) : -std::numeric_limits::max(); - mPositionOffset.z() = std::max(pos.z(), terrainHeight) - mWorldPosition.z(); - } mWorldPosition += mPositionOffset; mPosition += mPositionOffset; mPreviousPosition += mPositionOffset; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6b92378c7..ba211503e 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -32,7 +32,7 @@ namespace MWScript std::vector actors; MWBase::Environment::get().getWorld()->getActorsStandingOn (ptr, actors); for (auto& actor : actors) - MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff); + MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff, false); } template @@ -284,6 +284,17 @@ namespace MWScript } else if(axis == "z") { + // We should not place actors under ground + if (ptr.getClass().isActor()) + { + float terrainHeight = -std::numeric_limits::max(); + if (ptr.getCell()->isExterior()) + terrainHeight = MWBase::Environment::get().getWorld()->getTerrainHeightAt(curPos); + + if (pos < terrainHeight) + pos = terrainHeight; + } + newPos[2] = pos; } else @@ -292,7 +303,7 @@ namespace MWScript } dynamic_cast(runtime.getContext()).updatePtr(ptr, - MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos)); + MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true)); } }; @@ -428,7 +439,7 @@ namespace MWScript } else { - ptr = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z, true); + ptr = MWBase::Environment::get().getWorld()->moveObject(ptr, x, y, z, true, true); } dynamic_cast(runtime.getContext()).updatePtr(base,ptr); @@ -715,7 +726,7 @@ namespace MWScript // This approach can be used to create elevators. moveStandingActors(ptr, diff); dynamic_cast(runtime.getContext()).updatePtr(ptr, - MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff)); + MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false)); } }; @@ -751,7 +762,7 @@ namespace MWScript // This approach can be used to create elevators. moveStandingActors(ptr, diff); dynamic_cast(runtime.getContext()).updatePtr(ptr, - MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff)); + MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false)); } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3b50dd6aa..5b9afa4fe 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -862,19 +862,6 @@ namespace MWWorld if (reference == getPlayerPtr()) throw std::runtime_error("can not disable player object"); - // A common pattern to teleport NPC in scripts is a sequence of SetPos/Disable/Enable - // Disable/Enable create a new physics actor, and so the SetPos call is lost - // Call moveObject so that the newly created physics actor will have up-to-date position - if (reference.getClass().isActor()) - { - auto* physactor = mPhysics->getActor(reference); - if (physactor) - { - physactor->applyOffsetChange(); - const auto position = physactor->getSimulationPosition(); - moveObject(reference, position.x(), position.y(), position.z(), true); - } - } reference.getRefData().disable(); if (reference.getCellRef().getRefNum().hasContentFile()) @@ -1251,7 +1238,7 @@ namespace MWWorld return newPtr; } - MWWorld::Ptr World::moveObjectImp(const Ptr& ptr, float x, float y, float z, bool movePhysics, bool moveToActive) + MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z, bool movePhysics, bool moveToActive) { int cellX, cellY; positionToIndex(x, y, cellX, cellY); @@ -1266,21 +1253,14 @@ namespace MWWorld return moveObject(ptr, cell, x, y, z, movePhysics); } - MWWorld::Ptr World::moveObject (const Ptr& ptr, float x, float y, float z, bool moveToActive) - { - return moveObjectImp(ptr, x, y, z, true, moveToActive); - } - - MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, osg::Vec3f vec) + MWWorld::Ptr World::moveObjectBy(const Ptr& ptr, osg::Vec3f vec, bool moveToActive) { auto* actor = mPhysics->getActor(ptr); if (actor) - { actor->adjustPosition(vec); - return ptr; - } + osg::Vec3f newpos = ptr.getRefData().getPosition().asVec3() + vec; - return moveObject(ptr, newpos.x(), newpos.y(), newpos.z()); + return moveObject(ptr, newpos.x(), newpos.y(), newpos.z(), false, moveToActive && ptr != getPlayerPtr()); } void World::scaleObject (const Ptr& ptr, float scale) @@ -1546,7 +1526,7 @@ namespace MWWorld auto* physactor = mPhysics->getActor(actor); assert(physactor); const auto position = physactor->getSimulationPosition(); - moveObjectImp(actor, position.x(), position.y(), position.z(), false); + moveObject(actor, position.x(), position.y(), position.z(), false, false); } } @@ -1556,7 +1536,7 @@ namespace MWWorld auto* physactor = mPhysics->getActor(*player); assert(physactor); const auto position = physactor->getSimulationPosition(); - moveObjectImp(*player, position.x(), position.y(), position.z(), false); + moveObject(*player, position.x(), position.y(), position.z(), false, false); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 929e035e9..33b23e065 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -138,9 +138,6 @@ namespace MWWorld void rotateObjectImp (const Ptr& ptr, const osg::Vec3f& rot, MWBase::RotationFlags flags); - Ptr moveObjectImp (const Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false); - ///< @return an updated Ptr in case the Ptr's cell changes - Ptr copyObjectToCell(const ConstPtr &ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos); void updateSoundListener(); @@ -376,13 +373,13 @@ namespace MWWorld void undeleteObject (const Ptr& ptr) override; - MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z, bool moveToActive=false) override; + MWWorld::Ptr moveObject (const Ptr& ptr, float x, float y, float z, bool movePhysics=true, bool moveToActive=false) override; ///< @return an updated Ptr in case the Ptr's cell changes MWWorld::Ptr moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z, bool movePhysics=true) override; ///< @return an updated Ptr - MWWorld::Ptr moveObjectBy(const Ptr& ptr, osg::Vec3f vec) override; + MWWorld::Ptr moveObjectBy(const Ptr& ptr, osg::Vec3f vec, bool moveToActive) override; ///< @return an updated Ptr void scaleObject (const Ptr& ptr, float scale) override;