diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 566853fc7..de5f15d64 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -279,7 +279,11 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0; - ///< place an object in a "safe" location (ie not in the void, etc). + ///< Place an object. Makes a copy of the Ptr. + + virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) = 0; + ///< Place an object in a safe place next to \a referenceObject. \a direction and \a distance specify the wanted placement + /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is obstructed). virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const = 0; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 7d9877168..e9e13e74f 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -492,15 +492,6 @@ namespace MWScript { public: - osg::Vec3f getSpawnPosition(const osg::Vec3f& origin, const osg::Quat& orientation, int direction, float distance) - { - if(direction == 0) return origin + (orientation * osg::Vec3f(0,1,0)) * distance; - else if(direction == 1) return origin - (orientation * osg::Vec3f(0,1,0)) * distance; - else if(direction == 2) return origin - (orientation * osg::Vec3f(1,0,0)) * distance; - else if(direction == 3) return origin + (orientation * osg::Vec3f(1,0,0)) * distance; - else return origin; - } - virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr actor = pc @@ -523,52 +514,12 @@ namespace MWScript if (!actor.isInCell()) throw std::runtime_error ("actor is not in a cell"); - ESM::Position ipos = actor.getRefData().getPosition(); - osg::Vec3f pos(ipos.asVec3()); - osg::Quat rot(ipos.rot[2], osg::Vec3f(0,0,-1)); - - for (int i=0; i<4; ++i) - { - // check if spawn point is safe, fall back to another direction if not - osg::Vec3f spawnPoint = getSpawnPosition(ipos.asVec3(), rot, direction, distance); - spawnPoint.z() += 30; // move up a little to account for slopes, will snap down later - - if (!MWBase::Environment::get().getWorld()->castRay(spawnPoint.x(), spawnPoint.y(), spawnPoint.z(), - pos.x(), pos.y(), pos.z() + 20)) - { - // safe - ipos.pos[0] = spawnPoint.x(); - ipos.pos[1] = spawnPoint.y(); - ipos.pos[2] = spawnPoint.z(); - break; - } - direction = (direction+1) % 4; - } - - if (actor.getClass().isActor()) - { - // TODO: should this depend on the 'direction' parameter? - ipos.rot[0] = 0; - ipos.rot[1] = 0; - ipos.rot[2] = 0; - } - else - { - ipos.rot[0] = actor.getRefData().getPosition().rot[0]; - ipos.rot[1] = actor.getRefData().getPosition().rot[1]; - ipos.rot[2] = actor.getRefData().getPosition().rot[2]; - } - - for (int i=0; igetStore(), itemID, 1); - ref.getPtr().getCellRef().setPosition(ipos); - MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(),store,ipos); - placed.getClass().adjustPosition(placed, true); // snap to ground + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), actor, actor.getCell(), direction, distance); } } }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3a4b0109c..be2baf737 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1330,6 +1330,43 @@ namespace MWWorld return copyObjectToCell(ptr,cell,pos,ptr.getRefData().getCount(),false); } + MWWorld::Ptr World::safePlaceObject(const ConstPtr &ptr, const ConstPtr &referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance) + { + ESM::Position ipos = referenceObject.getRefData().getPosition(); + osg::Vec3f pos(ipos.asVec3()); + osg::Quat orientation(ipos.rot[2], osg::Vec3f(0,0,-1)); + + for (int i=0; i<4; ++i) + { + // check if spawn point is safe, fall back to another direction if not + osg::Vec3f spawnPoint = pos; + if (direction == 0) spawnPoint = pos + (orientation * osg::Vec3f(0,1,0)) * distance; + else if(direction == 1) spawnPoint = pos - (orientation * osg::Vec3f(0,1,0)) * distance; + else if(direction == 2) spawnPoint = pos - (orientation * osg::Vec3f(1,0,0)) * distance; + else if(direction == 3) spawnPoint = pos + (orientation * osg::Vec3f(1,0,0)) * distance; + spawnPoint.z() += 30; // move up a little to account for slopes, will snap down later + + if (!castRay(spawnPoint.x(), spawnPoint.y(), spawnPoint.z(), + pos.x(), pos.y(), pos.z() + 20)) + { + // safe + ipos.pos[0] = spawnPoint.x(); + ipos.pos[1] = spawnPoint.y(); + ipos.pos[2] = spawnPoint.z(); + break; + } + direction = (direction+1) % 4; + } + + ipos.rot[0] = referenceObject.getRefData().getPosition().rot[0]; + ipos.rot[1] = referenceObject.getRefData().getPosition().rot[1]; + ipos.rot[2] = referenceObject.getRefData().getPosition().rot[2]; + + MWWorld::Ptr placed = copyObjectToCell(ptr, referenceCell, ipos, ptr.getRefData().getCount(), false); + placed.getClass().adjustPosition(placed, true); // snap to ground + return placed; + } + void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const { const int cellSize = 8192; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 9f21135e5..d1298a39b 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -368,7 +368,11 @@ namespace MWWorld virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& ptr, MWWorld::CellStore* cell, ESM::Position pos); - ///< place an object. Makes a copy of the Ptr. + ///< Place an object. Makes a copy of the Ptr. + + virtual MWWorld::Ptr safePlaceObject (const MWWorld::ConstPtr& ptr, const MWWorld::ConstPtr& referenceObject, MWWorld::CellStore* referenceCell, int direction, float distance); + ///< Place an object in a safe place next to \a referenceObject. \a direction and \a distance specify the wanted placement + /// relative to \a referenceObject (but the object may be placed somewhere else if the wanted location is obstructed). virtual float getMaxActivationDistance();