|
|
|
@ -246,7 +246,7 @@ namespace MWWorld
|
|
|
|
|
if (findExteriorPosition (mStartCell, pos))
|
|
|
|
|
{
|
|
|
|
|
changeToExteriorCell (pos, true);
|
|
|
|
|
fixPosition(getPlayerPtr());
|
|
|
|
|
adjustPosition(getPlayerPtr(), false);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -1353,13 +1353,37 @@ namespace MWWorld
|
|
|
|
|
|
|
|
|
|
void World::fixPosition(const Ptr &actor)
|
|
|
|
|
{
|
|
|
|
|
const float dist = 8000;
|
|
|
|
|
osg::Vec3f pos (actor.getRefData().getPosition().asVec3());
|
|
|
|
|
pos.z() += dist;
|
|
|
|
|
const float distance = 128.f;
|
|
|
|
|
ESM::Position esmPos = actor.getRefData().getPosition();
|
|
|
|
|
osg::Quat orientation(esmPos.rot[2], osg::Vec3f(0,0,-1));
|
|
|
|
|
osg::Vec3f pos (esmPos.asVec3());
|
|
|
|
|
|
|
|
|
|
osg::Vec3f traced = mPhysics->traceDown(actor, pos, dist*1.1f);
|
|
|
|
|
int direction = 0;
|
|
|
|
|
int fallbackDirections[4] = {direction, (direction+3)%4, (direction+2)%4, (direction+1)%4};
|
|
|
|
|
|
|
|
|
|
osg::Vec3f targetPos = pos;
|
|
|
|
|
for (int i=0; i<4; ++i)
|
|
|
|
|
{
|
|
|
|
|
direction = fallbackDirections[i];
|
|
|
|
|
if (direction == 0) targetPos = pos + (orientation * osg::Vec3f(0,1,0)) * distance;
|
|
|
|
|
else if(direction == 1) targetPos = pos - (orientation * osg::Vec3f(0,1,0)) * distance;
|
|
|
|
|
else if(direction == 2) targetPos = pos - (orientation * osg::Vec3f(1,0,0)) * distance;
|
|
|
|
|
else if(direction == 3) targetPos = pos + (orientation * osg::Vec3f(1,0,0)) * distance;
|
|
|
|
|
|
|
|
|
|
// destination is free
|
|
|
|
|
if (!castRay(pos.x(), pos.y(), pos.z(), targetPos.x(), targetPos.y(), targetPos.z()))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
targetPos.z() += distance / 2.f; // move up a bit to get out from geometry, will snap down later
|
|
|
|
|
osg::Vec3f traced = mPhysics->traceDown(actor, targetPos, Constants::CellSizeInUnits);
|
|
|
|
|
if (traced != pos)
|
|
|
|
|
moveObject(actor, actor.getCell(), traced.x(), traced.y(), traced.z());
|
|
|
|
|
{
|
|
|
|
|
esmPos.pos[0] = traced.x();
|
|
|
|
|
esmPos.pos[1] = traced.y();
|
|
|
|
|
esmPos.pos[2] = traced.z();
|
|
|
|
|
MWWorld::ActionTeleport("", esmPos, false).execute(actor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust)
|
|
|
|
@ -1429,7 +1453,7 @@ namespace MWWorld
|
|
|
|
|
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
|
|
|
|
|
adjustPosition(placed, true); // snap to ground
|
|
|
|
|
return placed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2604,31 +2628,52 @@ namespace MWWorld
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<const MWWorld::CellRef *> sortedDoors;
|
|
|
|
|
const DoorList &doors = cellStore->getReadOnlyDoors().mList;
|
|
|
|
|
for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) {
|
|
|
|
|
if (!it->mRef.getTeleport()) {
|
|
|
|
|
for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (!it->mRef.getTeleport())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sortedDoors.push_back(&it->mRef);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort teleporting doors alphabetically, first by ID, then by destination cell to make search consistent
|
|
|
|
|
std::sort(sortedDoors.begin(), sortedDoors.end(), [] (const MWWorld::CellRef *lhs, const MWWorld::CellRef *rhs)
|
|
|
|
|
{
|
|
|
|
|
if (lhs->getRefId() != rhs->getRefId())
|
|
|
|
|
return lhs->getRefId() < rhs->getRefId();
|
|
|
|
|
|
|
|
|
|
return lhs->getDestCell() < rhs->getDestCell();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (std::vector<const MWWorld::CellRef *>::const_iterator it = sortedDoors.begin(); it != sortedDoors.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
MWWorld::CellStore *source = 0;
|
|
|
|
|
|
|
|
|
|
// door to exterior
|
|
|
|
|
if (it->mRef.getDestCell().empty()) {
|
|
|
|
|
if ((*it)->getDestCell().empty())
|
|
|
|
|
{
|
|
|
|
|
int x, y;
|
|
|
|
|
ESM::Position doorDest = it->mRef.getDoorDest();
|
|
|
|
|
ESM::Position doorDest = (*it)->getDoorDest();
|
|
|
|
|
positionToIndex(doorDest.pos[0], doorDest.pos[1], x, y);
|
|
|
|
|
source = getExterior(x, y);
|
|
|
|
|
}
|
|
|
|
|
// door to interior
|
|
|
|
|
else {
|
|
|
|
|
source = getInterior(it->mRef.getDestCell());
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
source = getInterior((*it)->getDestCell());
|
|
|
|
|
}
|
|
|
|
|
if (0 != source) {
|
|
|
|
|
if (0 != source)
|
|
|
|
|
{
|
|
|
|
|
// Find door leading to our current teleport door
|
|
|
|
|
// and use its destination to position inside cell.
|
|
|
|
|
const DoorList &destinationDoors = source->getReadOnlyDoors().mList;
|
|
|
|
|
for (DoorList::const_iterator jt = destinationDoors.begin(); jt != destinationDoors.end(); ++jt) {
|
|
|
|
|
if (it->mRef.getTeleport() &&
|
|
|
|
|
for (DoorList::const_iterator jt = destinationDoors.begin(); jt != destinationDoors.end(); ++jt)
|
|
|
|
|
{
|
|
|
|
|
if ((*it)->getTeleport() &&
|
|
|
|
|
Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell()))
|
|
|
|
|
{
|
|
|
|
|
/// \note Using _any_ door pointed to the interior,
|
|
|
|
|