diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 2918f5d8b..1050c1717 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -432,19 +432,14 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) { // load cell ESM::Position pos; - pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - pos.pos[2] = 0; + MWBase::World *world = MWBase::Environment::get().getWorld(); - if (const ESM::Cell *exterior = MWBase::Environment::get().getWorld()->getExterior (mCellName)) - { - MWBase::Environment::get().getWorld()->indexToPosition (exterior->mData.mX, exterior->mData.mY, - pos.pos[0], pos.pos[1], true); - MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); + if (world->findExteriorPosition(mCellName, pos)) { + world->changeToExteriorCell (pos); } - else - { - pos.pos[0] = pos.pos[1] = 0; - MWBase::Environment::get().getWorld()->changeToInteriorCell (mCellName, pos); + else { + world->findInteriorPosition(mCellName, pos); + world->changeToInteriorCell (mCellName, pos); } } else diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cf41f97df..6ef1a6c2b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -363,6 +363,14 @@ namespace MWBase virtual void playVideo(const std::string& name, bool allowSkipping) = 0; virtual void stopVideo() = 0; virtual void frameStarted (float dt) = 0; + + /// Find default position inside exterior cell specified by name + /// \return false if exterior with given name not exists, true otherwise + virtual bool findExteriorPosition(const std::string &name, ESM::Position &pos) = 0; + + /// Find default position inside interior cell specified by name + /// \return false if interior with given name not exists, true otherwise + virtual bool findInteriorPosition(const std::string &name, ESM::Position &pos) = 0; }; } diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index a4a738ca7..d2e11c19f 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -40,19 +40,16 @@ namespace MWScript runtime.pop(); ESM::Position pos; - pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - pos.pos[2] = 0; + MWBase::World *world = MWBase::Environment::get().getWorld(); - if (const ESM::Cell *exterior = MWBase::Environment::get().getWorld()->getExterior (cell)) - { - MWBase::Environment::get().getWorld()->indexToPosition (exterior->mData.mX, exterior->mData.mY, - pos.pos[0], pos.pos[1], true); - MWBase::Environment::get().getWorld()->changeToExteriorCell (pos); + if (world->findExteriorPosition(cell, pos)) { + world->changeToExteriorCell(pos); } - else - { - pos.pos[0] = pos.pos[1] = 0; - MWBase::Environment::get().getWorld()->changeToInteriorCell (cell, pos); + else { + // Change to interior even if findInteriorPosition() + // yields false. In this case position will be zero-point. + world->findInteriorPosition(cell, pos); + world->changeToInteriorCell(cell, pos); } } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 22facdcaf..09fde684d 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -378,6 +378,7 @@ namespace MWWorld world->rotateObject(world->getPlayer().getPlayer(), x, y, z); MWWorld::Class::get(world->getPlayer().getPlayer()).adjustPosition(world->getPlayer().getPlayer()); + world->getFader()->fadeIn(0.5f); return; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 06cf0099e..5c7a40050 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1745,4 +1745,80 @@ namespace MWWorld physicActor->disableCollisionBody(); } } + + bool World::findInteriorPosition(const std::string &name, ESM::Position &pos) + { + typedef MWWorld::CellRefList::List DoorList; + + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + pos.pos[0] = pos.pos[1] = pos.pos[2] = 0; + + MWWorld::CellStore *cellStore = getInterior(name); + + if (0 == cellStore) { + return false; + } + const DoorList &doors = cellStore->mDoors.mList; + for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) { + if (!it->mRef.mTeleport) { + continue; + } + + MWWorld::CellStore *source = 0; + + // door to exterior + if (it->mRef.mDestCell.empty()) { + int x, y; + const float *pos = it->mRef.mDoorDest.pos; + positionToIndex(pos[0], pos[1], x, y); + source = getExterior(x, y); + } + // door to interior + else { + source = getInterior(it->mRef.mDestCell); + } + if (0 != source) { + // Find door leading to our current teleport door + // and use it destination to position inside cell. + const DoorList &doors = source->mDoors.mList; + for (DoorList::const_iterator jt = doors.begin(); jt != doors.end(); ++jt) { + if (it->mRef.mTeleport && + Misc::StringUtils::ciEqual(name, jt->mRef.mDestCell)) + { + /// \note Using _any_ door pointed to the interior, + /// not the one pointed to current door. + pos = jt->mRef.mDoorDest; + return true; + } + } + } + } + return false; + } + + bool World::findExteriorPosition(const std::string &name, ESM::Position &pos) + { + pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; + + if (const ESM::Cell *ext = getExterior(name)) { + int x = ext->getGridX(); + int y = ext->getGridY(); + indexToPosition(x, y, pos.pos[0], pos.pos[1], true); + + ESM::Land* land = getStore().get().search(x, y); + if (land) { + if (!land->isDataLoaded(ESM::Land::DATA_VHGT)) { + land->loadData(ESM::Land::DATA_VHGT); + } + pos.pos[2] = land->mLandData->mHeights[ESM::Land::LAND_NUM_VERTS / 2 + 1]; + } + else { + std::cerr << "Land data for cell at (" << x << ", " << y << ") not found\n"; + pos.pos[2] = 0; + } + + return true; + } + return false; + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5cf3a24bf..9e9d76bd5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -412,6 +412,14 @@ namespace MWWorld virtual void playVideo(const std::string& name, bool allowSkipping); virtual void stopVideo(); virtual void frameStarted (float dt); + + /// Find center of exterior cell above land surface + /// \return false if exterior with given name not exists, true otherwise + virtual bool findExteriorPosition(const std::string &name, ESM::Position &pos); + + /// Find position in interior cell near door entrance + /// \return false if interior with given name not exists, true otherwise + virtual bool findInteriorPosition(const std::string &name, ESM::Position &pos); }; }