mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-01 05:09:41 +00:00
Dest Door and teleport use ESM::RefId
This changes a lot of files as a consequence. Still buggy, moving to exterior doesn't bring to the right place yet coc "seyda neen" doesn't work. SO I broke somehting when fetching a cell from a name
This commit is contained in:
parent
96e42d1666
commit
3f678c3b0a
26 changed files with 258 additions and 170 deletions
|
@ -114,7 +114,7 @@ namespace MWBase
|
|||
{
|
||||
std::string name;
|
||||
float x, y; // world position
|
||||
ESM::CellId dest;
|
||||
ESM::RefId dest;
|
||||
};
|
||||
|
||||
World() {}
|
||||
|
@ -260,6 +260,9 @@ namespace MWBase
|
|||
virtual void changeToCell(
|
||||
const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true)
|
||||
= 0;
|
||||
virtual void changeToCell(
|
||||
const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent = true)
|
||||
= 0;
|
||||
///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes
|
||||
|
||||
virtual MWWorld::Ptr getFacedObject() = 0;
|
||||
|
@ -514,13 +517,16 @@ namespace MWBase
|
|||
virtual bool screenshot360(osg::Image* image) = 0;
|
||||
|
||||
/// Find default position inside exterior cell specified by name
|
||||
/// \return false if exterior with given name not exists, true otherwise
|
||||
virtual bool findExteriorPosition(std::string_view name, ESM::Position& pos) = 0;
|
||||
/// \return invalid RefId if exterior with given name not exists, the cell's RefId otherwise
|
||||
virtual ESM::RefId findExteriorPosition(std::string_view 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(std::string_view name, ESM::Position& pos) = 0;
|
||||
/// \return invalid RefId if interior with given name not exists, the cell's RefId otherwise
|
||||
virtual ESM::RefId findInteriorPosition(std::string_view name, ESM::Position& pos) = 0;
|
||||
|
||||
/// Find default position inside interior or exterior cell specified by name
|
||||
/// \return invalid RefId if interior with given name not exists, the cell's RefId otherwise
|
||||
virtual ESM::RefId findCellPosition(std::string_view cellName, ESM::Position& pos) = 0;
|
||||
/// Enables or disables use of teleport spell effects (recall, intervention, etc).
|
||||
virtual void enableTeleporting(bool enable) = 0;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwworld/failedaction.hpp"
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include "../mwworld/worldmodel.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
#include "../mwgui/ustring.hpp"
|
||||
|
@ -298,16 +299,8 @@ namespace MWClass
|
|||
|
||||
std::string Door::getDestination(const MWWorld::LiveCellRef<ESM::Door>& door)
|
||||
{
|
||||
std::string_view dest = door.mRef.getDestCell();
|
||||
if (dest.empty())
|
||||
{
|
||||
// door leads to exterior, use cell name (if any), otherwise translated region name
|
||||
auto world = MWBase::Environment::get().getWorld();
|
||||
const osg::Vec2i index
|
||||
= MWWorld::positionToCellIndex(door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1]);
|
||||
const ESM::Cell* cell = world->getStore().get<ESM::Cell>().search(index.x(), index.y());
|
||||
dest = world->getCellName(cell);
|
||||
}
|
||||
std::string_view dest
|
||||
= MWBase::Environment::get().getWorldModel()->getCell(door.mRef.getDestCell())->getCell()->getDisplayName();
|
||||
|
||||
return "#{sCell=" + std::string{ dest } + "}";
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ namespace MWGui
|
|||
return mMarkers.end();
|
||||
}
|
||||
|
||||
CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::CellId& cellId) const
|
||||
CustomMarkerCollection::RangeType CustomMarkerCollection::getMarkers(const ESM::RefId& cellId) const
|
||||
{
|
||||
return mMarkers.equal_range(cellId);
|
||||
}
|
||||
|
@ -356,8 +356,8 @@ namespace MWGui
|
|||
cellId.mWorldspace = (mInterior ? mPrefix : ESM::CellId::sDefaultWorldspace);
|
||||
cellId.mIndex.mX = mCurX + dX;
|
||||
cellId.mIndex.mY = mCurY + dY;
|
||||
|
||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId);
|
||||
ESM::RefId cellRefId = cellId.getCellRefId();
|
||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId);
|
||||
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second;
|
||||
++it)
|
||||
{
|
||||
|
@ -885,16 +885,19 @@ namespace MWGui
|
|||
|
||||
mEditingMarker.mWorldX = worldPos.x();
|
||||
mEditingMarker.mWorldY = worldPos.y();
|
||||
ESM::CellId clickedId;
|
||||
|
||||
mEditingMarker.mCell.mPaged = !mInterior;
|
||||
clickedId.mPaged = !mInterior;
|
||||
if (mInterior)
|
||||
mEditingMarker.mCell.mWorldspace = LocalMapBase::mPrefix;
|
||||
clickedId.mWorldspace = LocalMapBase::mPrefix;
|
||||
else
|
||||
{
|
||||
mEditingMarker.mCell.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
mEditingMarker.mCell.mIndex.mX = x;
|
||||
mEditingMarker.mCell.mIndex.mY = y;
|
||||
clickedId.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
clickedId.mIndex.mX = x;
|
||||
clickedId.mIndex.mY = y;
|
||||
}
|
||||
mEditingMarker.mCell = clickedId.getCellRefId();
|
||||
mEditingMarker.mCellId = clickedId;
|
||||
|
||||
mEditNoteDialog.setVisible(true);
|
||||
mEditNoteDialog.showDeleteButton(false);
|
||||
|
@ -1125,7 +1128,8 @@ namespace MWGui
|
|||
cellId.mIndex.mY = y;
|
||||
cellId.mWorldspace = ESM::CellId::sDefaultWorldspace;
|
||||
cellId.mPaged = true;
|
||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellId);
|
||||
ESM::RefId cellRefId = cellId.getCellRefId();
|
||||
CustomMarkerCollection::RangeType markers = mCustomMarkers.getMarkers(cellRefId);
|
||||
std::vector<std::string> destNotes;
|
||||
for (CustomMarkerCollection::ContainerType::const_iterator it = markers.first; it != markers.second; ++it)
|
||||
destNotes.push_back(it->second.mNote);
|
||||
|
|
|
@ -56,14 +56,14 @@ namespace MWGui
|
|||
|
||||
size_t size() const;
|
||||
|
||||
typedef std::multimap<ESM::CellId, ESM::CustomMarker> ContainerType;
|
||||
typedef std::multimap<ESM::RefId, ESM::CustomMarker> ContainerType;
|
||||
|
||||
typedef std::pair<ContainerType::const_iterator, ContainerType::const_iterator> RangeType;
|
||||
|
||||
ContainerType::const_iterator begin() const;
|
||||
ContainerType::const_iterator end() const;
|
||||
|
||||
RangeType getMarkers(const ESM::CellId& cellId) const;
|
||||
RangeType getMarkers(const ESM::RefId& cellId) const;
|
||||
|
||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||
EventHandle_Void eventMarkersChanged;
|
||||
|
|
|
@ -195,9 +195,15 @@ namespace MWGui
|
|||
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenOut(1);
|
||||
ESM::CellId cellId;
|
||||
osg::Vec2i posCell = MWWorld::positionToCellIndex(pos.pos[0], pos.pos[1]);
|
||||
cellId.mPaged = !interior;
|
||||
cellId.mWorldspace = Misc::StringUtils::lowerCase(cellname);
|
||||
cellId.mIndex.mX = posCell.x();
|
||||
cellId.mIndex.mY = posCell.y();
|
||||
|
||||
// Teleports any followers, too.
|
||||
MWWorld::ActionTeleport action(interior ? cellname : "", pos, true);
|
||||
MWWorld::ActionTeleport action(cellId.getCellRefId(), pos, true);
|
||||
action.execute(player);
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenOut(0);
|
||||
|
|
|
@ -36,8 +36,7 @@ namespace MWLua
|
|||
const MWWorld::CellRef& cellRef = doorPtr(o).getCellRef();
|
||||
if (!cellRef.getTeleport())
|
||||
return sol::nil;
|
||||
MWWorld::CellStore* cell = MWBase::Environment::get().getWorldModel()->getCellByPosition(
|
||||
cellRef.getDoorDest().asVec3(), cellRef.getDestCell());
|
||||
MWWorld::CellStore* cell = MWBase::Environment::get().getWorldModel()->getCell(cellRef.getDestCell());
|
||||
assert(cell);
|
||||
return o.getCell(lua, cell);
|
||||
};
|
||||
|
|
|
@ -487,9 +487,9 @@ namespace MWMechanics
|
|||
world->getPlayer().getMarkedPosition(markedCell, markedPosition);
|
||||
if (markedCell)
|
||||
{
|
||||
std::string_view dest;
|
||||
ESM::RefId dest;
|
||||
if (!markedCell->isExterior())
|
||||
dest = markedCell->getCell()->getNameId();
|
||||
dest = markedCell->getCell()->getId();
|
||||
MWWorld::ActionTeleport action(dest, markedPosition, false);
|
||||
action.execute(target);
|
||||
if (!caster.isEmpty())
|
||||
|
|
|
@ -92,20 +92,10 @@ namespace MWScript
|
|||
ESM::Position pos;
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Ptr playerPtr = world->getPlayerPtr();
|
||||
|
||||
if (world->findExteriorPosition(cell, pos))
|
||||
{
|
||||
MWWorld::ActionTeleport({}, pos, false).execute(playerPtr);
|
||||
ESM::RefId cellId = world->findCellPosition(cell, pos);
|
||||
MWWorld::ActionTeleport(cellId, pos, false).execute(playerPtr);
|
||||
world->adjustPosition(playerPtr, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change to interior even if findInteriorPosition()
|
||||
// yields false. In this case position will be zero-point.
|
||||
world->findInteriorPosition(cell, pos);
|
||||
MWWorld::ActionTeleport(cell, pos, false).execute(playerPtr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class OpCOE : public Interpreter::Opcode0
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
namespace MWWorld
|
||||
{
|
||||
ActionTeleport::ActionTeleport(std::string_view cellName, const ESM::Position& position, bool teleportFollowers)
|
||||
ActionTeleport::ActionTeleport(ESM::RefId cellId, const ESM::Position& position, bool teleportFollowers)
|
||||
: Action(true)
|
||||
, mCellName(cellName)
|
||||
, mCellId(cellId)
|
||||
, mPosition(position)
|
||||
, mTeleportFollowers(teleportFollowers)
|
||||
{
|
||||
|
@ -33,7 +33,9 @@ namespace MWWorld
|
|||
{
|
||||
// Find any NPCs that are following the actor and teleport them with him
|
||||
std::set<MWWorld::Ptr> followers;
|
||||
getFollowers(actor, followers, mCellName.empty(), true);
|
||||
|
||||
bool toExterior = MWBase::Environment::get().getWorldModel()->getCell(mCellId)->isExterior();
|
||||
getFollowers(actor, followers, toExterior, true);
|
||||
|
||||
for (std::set<MWWorld::Ptr>::iterator it = followers.begin(); it != followers.end(); ++it)
|
||||
teleport(*it);
|
||||
|
@ -52,10 +54,8 @@ namespace MWWorld
|
|||
if (actor == world->getPlayerPtr())
|
||||
{
|
||||
world->getPlayer().setTeleported(true);
|
||||
if (mCellName.empty())
|
||||
world->changeToExteriorCell(mPosition, true);
|
||||
else
|
||||
world->changeToInteriorCell(mCellName, mPosition, true);
|
||||
if (!mCellId.empty())
|
||||
world->changeToCell(mCellId, mPosition, true);
|
||||
teleported = world->getPlayerPtr();
|
||||
}
|
||||
else
|
||||
|
@ -65,15 +65,9 @@ namespace MWWorld
|
|||
actor.getClass().getCreatureStats(actor).getAiSequence().stopCombat();
|
||||
return;
|
||||
}
|
||||
else if (mCellName.empty())
|
||||
{
|
||||
const osg::Vec2i index = positionToCellIndex(mPosition.pos[0], mPosition.pos[1]);
|
||||
teleported = world->moveObject(
|
||||
actor, worldModel->getExterior(index.x(), index.y()), mPosition.asVec3(), true, true);
|
||||
}
|
||||
|
||||
else
|
||||
teleported
|
||||
= world->moveObject(actor, worldModel->getInterior(mCellName), mPosition.asVec3(), true, true);
|
||||
teleported = world->moveObject(actor, worldModel->getCell(mCellId), mPosition.asVec3(), true, true);
|
||||
}
|
||||
|
||||
if (!world->isWaterWalkingCastableOnTarget(teleported) && MWMechanics::hasWaterWalking(teleported))
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace MWWorld
|
|||
{
|
||||
class ActionTeleport : public Action
|
||||
{
|
||||
std::string mCellName;
|
||||
ESM::RefId mCellId;
|
||||
ESM::Position mPosition;
|
||||
bool mTeleportFollowers;
|
||||
|
||||
|
@ -26,7 +26,7 @@ namespace MWWorld
|
|||
public:
|
||||
/// If cellName is empty, an exterior cell is assumed.
|
||||
/// @param teleportFollowers Whether to teleport any following actors of the target actor as well.
|
||||
ActionTeleport(std::string_view cellName, const ESM::Position& position, bool teleportFollowers);
|
||||
ActionTeleport(ESM::RefId cellId, const ESM::Position& position, bool teleportFollowers);
|
||||
|
||||
/// @param includeHostiles If true, include hostile followers (which won't actually be teleported) in the
|
||||
/// output,
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
#include <cassert>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/esm3/cellid.hpp>
|
||||
#include <components/esm3/objectstate.hpp>
|
||||
|
||||
#include <apps/openmw/mwworld/cellutils.hpp>
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
CellRef::CellRef(const ESM::CellRef& ref)
|
||||
|
@ -67,11 +70,53 @@ namespace MWWorld
|
|||
|
||||
static const std::string emptyString = "";
|
||||
|
||||
const std::string& CellRef::getDestCell() const
|
||||
ESM::Position CellRef::getDoorDest() const
|
||||
{
|
||||
return std::visit(ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& /*ref*/) -> const std::string& { return emptyString; },
|
||||
[&](const ESM::CellRef& ref) -> const std::string& { return ref.mDestCell; },
|
||||
|
||||
auto esm3Visit = [&](const ESM::CellRef& ref) -> ESM::Position {
|
||||
// So the destinaion pos is always in relationship to the destination cells origin, interior or exterior
|
||||
// alike
|
||||
ESM::Position pos = ref.mDoorDest;
|
||||
if (ref.mDestCell.empty()) // Exterior cell case
|
||||
{
|
||||
const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]);
|
||||
pos.pos[0] -= index.x() * Constants::CellSizeInUnits;
|
||||
pos.pos[1] -= index.y() * Constants::CellSizeInUnits;
|
||||
}
|
||||
|
||||
return pos;
|
||||
};
|
||||
|
||||
return std::visit(
|
||||
ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& ref) { return ref.mDoor.destPos; },
|
||||
esm3Visit,
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
||||
ESM::RefId CellRef::getDestCell() const
|
||||
{
|
||||
auto esm3Visit = [&](const ESM::CellRef& ref) -> ESM::RefId {
|
||||
if (!ref.mDestCell.empty())
|
||||
{
|
||||
return ESM::RefId::stringRefId(ref.mDestCell);
|
||||
}
|
||||
else
|
||||
{
|
||||
const osg::Vec2i index = positionToCellIndex(ref.mDoorDest.pos[0], ref.mDoorDest.pos[1]);
|
||||
ESM::CellId CellId;
|
||||
CellId.mPaged = true;
|
||||
CellId.mIndex.mX = index.x();
|
||||
CellId.mIndex.mY = index.y();
|
||||
return CellId.getCellRefId();
|
||||
}
|
||||
};
|
||||
|
||||
return std::visit(
|
||||
ESM::VisitOverload{
|
||||
[&](const ESM4::Reference& ref) -> ESM::RefId { return ESM::RefId::sEmpty; },
|
||||
esm3Visit,
|
||||
},
|
||||
mCellRef.mVariant);
|
||||
}
|
||||
|
|
|
@ -61,18 +61,10 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
// Teleport location for the door, if this is a teleporting door.
|
||||
const ESM::Position& getDoorDest() const
|
||||
{
|
||||
struct Visitor
|
||||
{
|
||||
const ESM::Position& operator()(const ESM::CellRef& ref) { return ref.mDoorDest; }
|
||||
const ESM::Position& operator()(const ESM4::Reference& ref) { return ref.mDoor.destPos; }
|
||||
};
|
||||
return std::visit(Visitor(), mCellRef.mVariant);
|
||||
}
|
||||
ESM::Position getDoorDest() const;
|
||||
|
||||
// Destination cell for doors (optional)
|
||||
const std::string& getDestCell() const;
|
||||
ESM::RefId getDestCell() const;
|
||||
|
||||
// Scale applied to mesh
|
||||
float getScale() const
|
||||
|
|
|
@ -1081,7 +1081,7 @@ namespace MWWorld
|
|||
ESM::CellId movedTo;
|
||||
refnum.load(reader, true, "MVRF");
|
||||
movedTo.load(reader);
|
||||
|
||||
ESM::RefId movedToId = movedTo.getCellRefId();
|
||||
if (refnum.hasContentFile())
|
||||
{
|
||||
auto iter = contentFileMap.find(refnum.mContentFile);
|
||||
|
@ -1098,7 +1098,7 @@ namespace MWWorld
|
|||
continue;
|
||||
}
|
||||
|
||||
CellStore* otherCell = callback->getCellStore(movedTo);
|
||||
CellStore* otherCell = callback->getCellStore(movedToId);
|
||||
|
||||
if (otherCell == nullptr)
|
||||
{
|
||||
|
|
|
@ -291,7 +291,7 @@ namespace MWWorld
|
|||
struct GetCellStoreCallback
|
||||
{
|
||||
///@note must return nullptr if the cell is not found
|
||||
virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0;
|
||||
virtual CellStore* getCellStore(const ESM::RefId& cellId) = 0;
|
||||
virtual ~GetCellStoreCallback() = default;
|
||||
};
|
||||
|
||||
|
|
|
@ -367,7 +367,7 @@ namespace MWWorld
|
|||
|
||||
try
|
||||
{
|
||||
mCellStore = MWBase::Environment::get().getWorldModel()->getCell(player.mCellId);
|
||||
mCellStore = MWBase::Environment::get().getWorldModel()->getCellFromCellId(player.mCellId);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -404,7 +404,7 @@ namespace MWWorld
|
|||
if (player.mHasMark)
|
||||
{
|
||||
mMarkedPosition = player.mMarkedPosition;
|
||||
mMarkedCell = MWBase::Environment::get().getWorldModel()->getCell(player.mMarkedCell);
|
||||
mMarkedCell = MWBase::Environment::get().getWorldModel()->getCellFromCellId(player.mMarkedCell);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1129,15 +1129,7 @@ namespace MWWorld
|
|||
{
|
||||
try
|
||||
{
|
||||
if (!door.getCellRef().getDestCell().empty())
|
||||
preloadCell(mWorld.getWorldModel().getInterior(door.getCellRef().getDestCell()));
|
||||
else
|
||||
{
|
||||
osg::Vec3f pos = door.getCellRef().getDoorDest().asVec3();
|
||||
const osg::Vec2i cellIndex = positionToCellIndex(pos.x(), pos.y());
|
||||
preloadCell(mWorld.getWorldModel().getExterior(cellIndex.x(), cellIndex.y()), true);
|
||||
exteriorPositions.emplace_back(pos, gridCenterToBounds(getNewGridCenter(pos)));
|
||||
}
|
||||
preloadCell(mWorld.getWorldModel().getCell(door.getCellRef().getDestCell()));
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
|
|
|
@ -471,7 +471,7 @@ namespace MWWorld
|
|||
const ESM::Cell* Store<ESM::Cell>::search(const ESM::RefId& cellId) const
|
||||
{
|
||||
auto foundCellIt = mCells.find(cellId);
|
||||
if (foundCellIt == mCells.end())
|
||||
if (foundCellIt != mCells.end())
|
||||
return &foundCellIt->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -353,7 +353,7 @@ namespace MWWorld
|
|||
if (bypass && !mStartCell.empty())
|
||||
{
|
||||
ESM::Position pos;
|
||||
if (findExteriorPosition(mStartCell, pos))
|
||||
if (findExteriorPosition(mStartCell, pos).empty())
|
||||
{
|
||||
changeToExteriorCell(pos, true);
|
||||
adjustPosition(getPlayerPtr(), false);
|
||||
|
@ -1000,6 +1000,31 @@ namespace MWWorld
|
|||
mCurrentDate->setup(mGlobalVariables);
|
||||
}
|
||||
|
||||
void World::changeToCell(
|
||||
const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)
|
||||
{
|
||||
const MWWorld::Cell* destinationCell = getWorldModel().getCell(cellId)->getCell();
|
||||
bool exteriorCell = destinationCell->isExterior();
|
||||
|
||||
mPhysics->clearQueuedMovement();
|
||||
mDiscardMovements = true;
|
||||
|
||||
if (changeEvent && mCurrentWorldSpace != destinationCell->getNameId())
|
||||
{
|
||||
// changed worldspace
|
||||
mProjectileManager->clear();
|
||||
mRendering->notifyWorldSpaceChanged();
|
||||
mCurrentWorldSpace = destinationCell->getNameId();
|
||||
}
|
||||
removeContainerScripts(getPlayerPtr());
|
||||
if (exteriorCell)
|
||||
mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent);
|
||||
else
|
||||
mWorldScene->changeToInteriorCell(destinationCell->getNameId(), position, adjustPlayerPos, changeEvent);
|
||||
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
|
||||
mRendering->getCamera()->instantTransition();
|
||||
}
|
||||
|
||||
float World::getMaxActivationDistance() const
|
||||
{
|
||||
if (mActivationDistanceOverride >= 0)
|
||||
|
@ -1420,9 +1445,9 @@ namespace MWWorld
|
|||
esmPos.pos[0] = traced.x();
|
||||
esmPos.pos[1] = traced.y();
|
||||
esmPos.pos[2] = traced.z();
|
||||
std::string_view cell;
|
||||
ESM::RefId cell;
|
||||
if (!actor.getCell()->isExterior())
|
||||
cell = actor.getCell()->getCell()->getNameId();
|
||||
cell = actor.getCell()->getCell()->getId();
|
||||
MWWorld::ActionTeleport(cell, esmPos, false).execute(actor);
|
||||
}
|
||||
}
|
||||
|
@ -2060,24 +2085,7 @@ namespace MWWorld
|
|||
{
|
||||
World::DoorMarker newMarker;
|
||||
newMarker.name = MWClass::Door::getDestination(ref);
|
||||
|
||||
ESM::CellId cellid;
|
||||
if (!ref.mRef.getDestCell().empty())
|
||||
{
|
||||
cellid.mWorldspace = ref.mRef.getDestCell();
|
||||
cellid.mPaged = false;
|
||||
cellid.mIndex.mX = 0;
|
||||
cellid.mIndex.mY = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cellid.mPaged = true;
|
||||
const osg::Vec2i index
|
||||
= positionToCellIndex(ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[1]);
|
||||
cellid.mIndex.mX = index.x();
|
||||
cellid.mIndex.mY = index.y();
|
||||
}
|
||||
newMarker.dest = cellid;
|
||||
newMarker.dest = ref.mRef.getDestCell();
|
||||
|
||||
ESM::Position pos = ref.mData.getPosition();
|
||||
|
||||
|
@ -2764,7 +2772,7 @@ namespace MWWorld
|
|||
physicActor->enableCollisionBody(enable);
|
||||
}
|
||||
|
||||
bool World::findInteriorPosition(std::string_view name, ESM::Position& pos)
|
||||
ESM::RefId World::findInteriorPosition(std::string_view name, ESM::Position& pos)
|
||||
{
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
pos.pos[0] = pos.pos[1] = pos.pos[2] = 0;
|
||||
|
@ -2772,8 +2780,9 @@ namespace MWWorld
|
|||
MWWorld::CellStore* cellStore = mWorldModel.getInterior(name);
|
||||
|
||||
if (!cellStore)
|
||||
return false;
|
||||
return ESM::RefId::sEmpty;
|
||||
|
||||
ESM::RefId cellId = cellStore->getCell()->getId();
|
||||
std::vector<const MWWorld::CellRef*> sortedDoors;
|
||||
for (const MWWorld::LiveCellRef<ESM::Door>& door : cellStore->getReadOnlyDoors().mList)
|
||||
{
|
||||
|
@ -2794,32 +2803,21 @@ namespace MWWorld
|
|||
for (const MWWorld::CellRef* door : sortedDoors)
|
||||
{
|
||||
MWWorld::CellStore* source = nullptr;
|
||||
source = mWorldModel.getCell(door->getDestCell());
|
||||
|
||||
// door to exterior
|
||||
if (door->getDestCell().empty())
|
||||
{
|
||||
ESM::Position doorDest = door->getDoorDest();
|
||||
const osg::Vec2i index = positionToCellIndex(doorDest.pos[0], doorDest.pos[1]);
|
||||
source = mWorldModel.getExterior(index.x(), index.y());
|
||||
}
|
||||
// door to interior
|
||||
else
|
||||
{
|
||||
source = mWorldModel.getInterior(door->getDestCell());
|
||||
}
|
||||
if (source)
|
||||
{
|
||||
// Find door leading to our current teleport door
|
||||
// and use its destination to position inside cell.
|
||||
for (const MWWorld::LiveCellRef<ESM::Door>& destDoor : source->getReadOnlyDoors().mList)
|
||||
{
|
||||
if (name == destDoor.mRef.getDestCell())
|
||||
if (ESM::RefId::stringRefId(name) == destDoor.mRef.getDestCell())
|
||||
{
|
||||
/// \note Using _any_ door pointed to the interior,
|
||||
/// not the one pointed to current door.
|
||||
pos = destDoor.mRef.getDoorDest();
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
return true;
|
||||
return cellId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2831,7 +2829,7 @@ namespace MWWorld
|
|||
// found the COC position?
|
||||
pos = stat4.mRef.getPosition();
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
return true;
|
||||
return cellId;
|
||||
}
|
||||
}
|
||||
// Fall back to the first static location.
|
||||
|
@ -2840,7 +2838,7 @@ namespace MWWorld
|
|||
{
|
||||
pos = statics4.begin()->mRef.getPosition();
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
return true;
|
||||
return cellId;
|
||||
}
|
||||
// Fall back to the first static location.
|
||||
const MWWorld::CellRefList<ESM::Static>::List& statics = cellStore->getReadOnlyStatics().mList;
|
||||
|
@ -2848,13 +2846,24 @@ namespace MWWorld
|
|||
{
|
||||
pos = statics.begin()->mRef.getPosition();
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
return true;
|
||||
return cellId;
|
||||
}
|
||||
|
||||
return false;
|
||||
return ESM::RefId::sEmpty;
|
||||
}
|
||||
|
||||
bool World::findExteriorPosition(std::string_view nameId, ESM::Position& pos)
|
||||
ESM::RefId World::findCellPosition(std::string_view cellName, ESM::Position& pos)
|
||||
{
|
||||
ESM::RefId foundCell = findInteriorPosition(cellName, pos);
|
||||
if (foundCell.empty())
|
||||
{
|
||||
return findInteriorPosition(cellName, pos);
|
||||
}
|
||||
|
||||
return foundCell;
|
||||
}
|
||||
|
||||
ESM::RefId World::findExteriorPosition(std::string_view nameId, ESM::Position& pos)
|
||||
{
|
||||
pos.rot[0] = pos.rot[1] = pos.rot[2] = 0;
|
||||
|
||||
|
@ -2863,7 +2872,7 @@ namespace MWWorld
|
|||
{
|
||||
ext = mWorldModel.getCell(nameId)->getCell();
|
||||
if (!ext->isExterior())
|
||||
return false;
|
||||
return ESM::RefId::sEmpty;
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
|
@ -2895,10 +2904,10 @@ namespace MWWorld
|
|||
// Note: Z pos will be adjusted by adjustPosition later
|
||||
pos.pos[2] = 0;
|
||||
|
||||
return true;
|
||||
return ext->getId();
|
||||
}
|
||||
|
||||
return false;
|
||||
return ESM::RefId::sEmpty;
|
||||
}
|
||||
|
||||
void World::enableTeleporting(bool enable)
|
||||
|
@ -3289,10 +3298,10 @@ namespace MWWorld
|
|||
|
||||
// Search for a 'nearest' exterior, counting each cell between the starting
|
||||
// cell and the exterior as a distance of 1. Will fail for isolated interiors.
|
||||
std::set<std::string_view> checkedCells;
|
||||
std::set<std::string_view> currentCells;
|
||||
std::set<std::string_view> nextCells;
|
||||
nextCells.insert(cell->getCell()->getNameId());
|
||||
std::set<ESM::RefId> checkedCells;
|
||||
std::set<ESM::RefId> currentCells;
|
||||
std::set<ESM::RefId> nextCells;
|
||||
nextCells.insert(cell->getCell()->getId());
|
||||
|
||||
while (!nextCells.empty())
|
||||
{
|
||||
|
@ -3300,7 +3309,7 @@ namespace MWWorld
|
|||
nextCells.clear();
|
||||
for (const auto& currentCell : currentCells)
|
||||
{
|
||||
MWWorld::CellStore* next = mWorldModel.getInterior(currentCell);
|
||||
MWWorld::CellStore* next = mWorldModel.getCell(currentCell);
|
||||
if (!next)
|
||||
continue;
|
||||
|
||||
|
@ -3318,7 +3327,7 @@ namespace MWWorld
|
|||
}
|
||||
else
|
||||
{
|
||||
const std::string_view dest = ref.mRef.getDestCell();
|
||||
ESM::RefId dest = ref.mRef.getDestCell();
|
||||
if (!checkedCells.count(dest) && !currentCells.count(dest))
|
||||
nextCells.insert(dest);
|
||||
}
|
||||
|
@ -3342,19 +3351,19 @@ namespace MWWorld
|
|||
// Search for a 'nearest' marker, counting each cell between the starting
|
||||
// cell and the exterior as a distance of 1. If an exterior is found, jump
|
||||
// to the nearest exterior marker, without further interior searching.
|
||||
std::set<std::string_view> checkedCells;
|
||||
std::set<std::string_view> currentCells;
|
||||
std::set<std::string_view> nextCells;
|
||||
std::set<ESM::RefId> checkedCells;
|
||||
std::set<ESM::RefId> currentCells;
|
||||
std::set<ESM::RefId> nextCells;
|
||||
MWWorld::ConstPtr closestMarker;
|
||||
|
||||
nextCells.insert(ptr.getCell()->getCell()->getNameId());
|
||||
nextCells.insert(ptr.getCell()->getCell()->getId());
|
||||
while (!nextCells.empty())
|
||||
{
|
||||
currentCells = nextCells;
|
||||
nextCells.clear();
|
||||
for (const auto& cell : currentCells)
|
||||
{
|
||||
MWWorld::CellStore* next = mWorldModel.getInterior(cell);
|
||||
MWWorld::CellStore* next = mWorldModel.getCell(cell);
|
||||
checkedCells.insert(cell);
|
||||
if (!next)
|
||||
continue;
|
||||
|
@ -3440,11 +3449,11 @@ namespace MWWorld
|
|||
return;
|
||||
}
|
||||
|
||||
std::string_view cellName = "";
|
||||
ESM::RefId cellId;
|
||||
if (!closestMarker.mCell->isExterior())
|
||||
cellName = closestMarker.mCell->getCell()->getNameId();
|
||||
cellId = closestMarker.mCell->getCell()->getId();
|
||||
|
||||
MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false);
|
||||
MWWorld::ActionTeleport action(cellId, closestMarker.getRefData().getPosition(), false);
|
||||
action.execute(ptr);
|
||||
}
|
||||
|
||||
|
@ -3646,13 +3655,13 @@ namespace MWWorld
|
|||
Log(Debug::Warning) << "Failed to confiscate items: no closest prison marker found.";
|
||||
return;
|
||||
}
|
||||
std::string_view prisonName = prisonMarker.getCellRef().getDestCell();
|
||||
ESM::RefId prisonName = prisonMarker.getCellRef().getDestCell();
|
||||
if (prisonName.empty())
|
||||
{
|
||||
Log(Debug::Warning) << "Failed to confiscate items: prison marker not linked to prison interior";
|
||||
return;
|
||||
}
|
||||
MWWorld::CellStore* prison = mWorldModel.getInterior(prisonName);
|
||||
MWWorld::CellStore* prison = mWorldModel.getCell(prisonName);
|
||||
if (!prison)
|
||||
{
|
||||
Log(Debug::Warning) << "Failed to confiscate items: failed to load cell " << prisonName;
|
||||
|
|
|
@ -351,6 +351,9 @@ namespace MWWorld
|
|||
|
||||
void changeToCell(const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos,
|
||||
bool changeEvent = true) override;
|
||||
|
||||
void changeToCell(const ESM::RefId& cellId, const ESM::Position& position, bool adjustPlayerPos,
|
||||
bool changeEvent = true) override;
|
||||
///< @param changeEvent If false, do not trigger cell change flag or detect worldspace changes
|
||||
|
||||
MWWorld::Ptr getFacedObject() override;
|
||||
|
@ -601,12 +604,12 @@ namespace MWWorld
|
|||
|
||||
/// Find center of exterior cell above land surface
|
||||
/// \return false if exterior with given name not exists, true otherwise
|
||||
bool findExteriorPosition(std::string_view nameId, ESM::Position& pos) override;
|
||||
ESM::RefId findExteriorPosition(std::string_view nameId, ESM::Position& pos) override;
|
||||
|
||||
/// Find position in interior cell near door entrance
|
||||
/// \return false if interior with given name not exists, true otherwise
|
||||
bool findInteriorPosition(std::string_view name, ESM::Position& pos) override;
|
||||
|
||||
ESM::RefId findInteriorPosition(std::string_view name, ESM::Position& pos) override;
|
||||
ESM::RefId findCellPosition(std::string_view cellName, ESM::Position& pos) override;
|
||||
/// Enables or disables use of teleport spell effects (recall, intervention, etc).
|
||||
void enableTeleporting(bool enable) override;
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name)
|
|||
return result->second;
|
||||
}
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id)
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCellFromCellId(const ESM::CellId& id)
|
||||
{
|
||||
if (id.mPaged)
|
||||
return getExterior(id.mIndex.mX, id.mIndex.mY);
|
||||
|
@ -234,6 +234,52 @@ MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::CellId& id)
|
|||
return getInterior(id.mWorldspace);
|
||||
}
|
||||
|
||||
MWWorld::CellStore* MWWorld::WorldModel::getCell(const ESM::RefId& id)
|
||||
{
|
||||
auto result = mCells.find(id);
|
||||
if (result != mCells.end())
|
||||
return &result->second;
|
||||
|
||||
// TODO: in the future replace that with elsid's refId variant that can be a osg::Vec2i
|
||||
const std::string& idString = id.getRefIdString();
|
||||
if (idString[0] == '#' && idString.find(',')) // That is an exterior cell Id
|
||||
{
|
||||
int x, y;
|
||||
std::stringstream stringStream = std::stringstream(idString);
|
||||
char sharp = '#';
|
||||
char comma = ',';
|
||||
stringStream >> sharp >> x >> comma >> y;
|
||||
return getExterior(x, y);
|
||||
}
|
||||
|
||||
const ESM4::Cell* cell4 = mStore.get<ESM4::Cell>().search(id);
|
||||
CellStore* newCellStore = nullptr;
|
||||
if (!cell4)
|
||||
{
|
||||
const ESM::Cell* cell = mStore.get<ESM::Cell>().search(id);
|
||||
newCellStore = &mCells.emplace(cell->mId, CellStore(MWWorld::Cell(*cell), mStore, mReaders)).first->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
newCellStore = &mCells.emplace(cell4->mId, CellStore(MWWorld::Cell(*cell4), mStore, mReaders)).first->second;
|
||||
}
|
||||
if (newCellStore->getCell()->isExterior())
|
||||
{
|
||||
std::pair<int, int> coord
|
||||
= std::make_pair(newCellStore->getCell()->getGridX(), newCellStore->getCell()->getGridY());
|
||||
mExteriors.emplace(coord, newCellStore).first;
|
||||
}
|
||||
else
|
||||
{
|
||||
mInteriors.emplace(newCellStore->getCell()->getNameId(), newCellStore).first;
|
||||
}
|
||||
if (newCellStore->getState() != CellStore::State_Loaded)
|
||||
{
|
||||
newCellStore->load();
|
||||
}
|
||||
return newCellStore;
|
||||
}
|
||||
|
||||
const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name)
|
||||
{
|
||||
const ESM::Cell* cell = mStore.get<ESM::Cell>().search(name); // first try interiors
|
||||
|
@ -428,7 +474,7 @@ public:
|
|||
|
||||
MWWorld::WorldModel& mWorldModel;
|
||||
|
||||
MWWorld::CellStore* getCellStore(const ESM::CellId& cellId) override
|
||||
MWWorld::CellStore* getCellStore(const ESM::RefId& cellId) override
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -452,7 +498,7 @@ bool MWWorld::WorldModel::readRecord(ESM::ESMReader& reader, uint32_t type, cons
|
|||
|
||||
try
|
||||
{
|
||||
cellStore = getCell(state.mId);
|
||||
cellStore = getCell(state.mId.getCellRefId());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
|
|
@ -70,7 +70,8 @@ namespace MWWorld
|
|||
CellStore* getExterior(int x, int y);
|
||||
CellStore* getInterior(std::string_view name);
|
||||
CellStore* getCell(std::string_view name); // interior or named exterior
|
||||
CellStore* getCell(const ESM::CellId& Id);
|
||||
CellStore* getCell(const ESM::RefId& Id);
|
||||
CellStore* getCellFromCellId(const ESM::CellId& Id);
|
||||
|
||||
// If cellNameInSameWorldSpace is an interior - returns this interior.
|
||||
// Otherwise returns exterior cell for given position in the same world space.
|
||||
|
|
|
@ -33,6 +33,18 @@ namespace ESM
|
|||
esm.writeHNT("CIDX", mIndex, 8);
|
||||
}
|
||||
|
||||
ESM::RefId CellId::getCellRefId() const
|
||||
{
|
||||
if (mPaged)
|
||||
{
|
||||
return ESM::RefId::stringRefId("#" + std::to_string(mIndex.mX) + "," + std::to_string(mIndex.mY));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ESM::RefId::stringRefId(mWorldspace);
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const CellId& left, const CellId& right)
|
||||
{
|
||||
return left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace ESM
|
|||
|
||||
void load(ESMReader& esm);
|
||||
void save(ESMWriter& esm) const;
|
||||
ESM::RefId getCellRefId() const;
|
||||
};
|
||||
|
||||
bool operator==(const CellId& left, const CellId& right);
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace ESM
|
|||
{
|
||||
esm.writeHNT("POSX", mWorldX);
|
||||
esm.writeHNT("POSY", mWorldY);
|
||||
mCell.save(esm);
|
||||
mCellId.save(esm);
|
||||
if (!mNote.empty())
|
||||
esm.writeHNString("NOTE", mNote);
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ namespace ESM
|
|||
{
|
||||
esm.getHNT(mWorldX, "POSX");
|
||||
esm.getHNT(mWorldY, "POSY");
|
||||
mCell.load(esm);
|
||||
mCellId.load(esm);
|
||||
mCell = mCellId.getCellRefId();
|
||||
mNote = esm.getHNOString("NOTE");
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ namespace ESM
|
|||
float mWorldX;
|
||||
float mWorldY;
|
||||
|
||||
CellId mCell;
|
||||
RefId mCell;
|
||||
CellId mCellId; // The CellId representation for saving/loading
|
||||
|
||||
std::string mNote;
|
||||
|
||||
|
|
|
@ -59,14 +59,7 @@ namespace ESM
|
|||
|
||||
const ESM::RefId& Cell::updateId()
|
||||
{
|
||||
if (isExterior())
|
||||
{
|
||||
mId = ESM::RefId::stringRefId("#" + std::to_string(mData.mX) + "," + std::to_string(mData.mY));
|
||||
}
|
||||
else
|
||||
{
|
||||
mId = ESM::RefId::stringRefId(mName);
|
||||
}
|
||||
mId = mCellId.getCellRefId();
|
||||
return mId;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue