diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index dc25b4f652..202af249f5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -57,6 +57,8 @@ namespace ESM struct ItemLevList; struct TimeStamp; struct RefId; + struct CellVariant; + } namespace MWPhysics @@ -179,7 +181,7 @@ namespace MWBase /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. - virtual std::string_view getCellName(const ESM::Cell* cell) const = 0; + virtual std::string_view getCellName(const ESM::CellVariant& cell) const = 0; virtual void removeRefScript(MWWorld::RefData* ref) = 0; //< Remove the script attached to ref from mLocalScripts diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 075b2cffa8..56fbdeabe6 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -307,7 +307,7 @@ namespace MWClass const osg::Vec2i index = MWWorld::positionToCellIndex(door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1]); const ESM::Cell* cell = world->getStore().get().search(index.x(), index.y()); - dest = world->getCellName(cell); + dest = world->getCellName(ESM::CellVariant(cell)); } return "#{sCell=" + std::string{ dest } + "}"; diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index c79059d022..c64489bae5 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -705,7 +705,7 @@ namespace MWGui ESM::Position markedPosition; MWBase::Environment::get().getWorld()->getPlayer().getMarkedPosition(markedCell, markedPosition); if (markedCell && markedCell->isExterior() == !mInterior - && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->mName, mPrefix))) + && (!mInterior || Misc::StringUtils::ciEqual(markedCell->getCell()->getEditorName(), mPrefix))) { MarkerUserData markerPos(mLocalMapRender); MyGUI::ImageBox* markerWidget = mLocalMap->createWidget("ImageBox", diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 49ef0bb4dc..e9d92e7c7a 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -200,7 +200,7 @@ namespace MWGui MWWorld::Ptr player = world->getPlayerPtr(); if (mSleeping && player.getCell()->isExterior()) { - const ESM::RefId& regionstr = player.getCell()->getCell()->mRegion; + const ESM::RefId& regionstr = player.getCell()->getCell()->getRegion(); if (!regionstr.empty()) { const ESM::Region* region = world->getStore().get().find(regionstr); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 6b4e7a58c3..b31b0adaf2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -954,20 +954,21 @@ namespace MWGui mMap->setCellName(name); mHud->setCellName(name); + auto cellCommon = cell->getCellVariant().getCommon(); - if (cell->getCell()->isExterior()) + if (cellCommon->isExterior()) { - if (!cell->getCell()->mName.empty()) - mMap->addVisitedLocation(name, cell->getCell()->getGridX(), cell->getCell()->getGridY()); + if (!cellCommon->getEditorName().empty()) + mMap->addVisitedLocation(name, cellCommon->getGridX(), cellCommon->getGridY()); - mMap->cellExplored(cell->getCell()->getGridX(), cell->getCell()->getGridY()); + mMap->cellExplored(cellCommon->getGridX(), cellCommon->getGridY()); - setActiveMap(cell->getCell()->getGridX(), cell->getCell()->getGridY(), false); + setActiveMap(cellCommon->getGridX(), cellCommon->getGridY(), false); } else { - mMap->setCellPrefix(cell->getCell()->mName); - mHud->setCellPrefix(cell->getCell()->mName); + mMap->setCellPrefix(std::string(cellCommon->getEditorName())); + mHud->setCellPrefix(std::string(cellCommon->getEditorName())); osg::Vec3f worldPos; if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos)) diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 931142d371..a1d4b3991d 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -1,5 +1,6 @@ #include "luabindings.hpp" +#include #include #include "../mwworld/cellstore.hpp" @@ -29,35 +30,35 @@ namespace MWLua cellT[sol::meta_function::equal_to] = [](const CellT& a, const CellT& b) { return a.mStore == b.mStore; }; cellT[sol::meta_function::to_string] = [](const CellT& c) { - const ESM::Cell* cell = c.mStore->getCell(); + auto cell = c.mStore->getCell(); std::stringstream res; if (cell->isExterior()) res << "exterior(" << cell->getGridX() << ", " << cell->getGridY() << ")"; else - res << "interior(" << cell->mName << ")"; + res << "interior(" << cell->getEditorName() << ")"; return res.str(); }; - cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mName; }); + cellT["name"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getEditorName(); }); cellT["region"] - = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->mRegion.getRefIdString(); }); + = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getRegion().getRefIdString(); }); cellT["gridX"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridX(); }); cellT["gridY"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->getGridY(); }); cellT["hasWater"] = sol::readonly_property([](const CellT& c) { return c.mStore->getCell()->hasWater(); }); cellT["hasSky"] = sol::readonly_property([](const CellT& c) { - return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; + return c.mStore->getCell()->isExterior() || (c.mStore->getCell()->isQuasiExterior()) != 0; }); cellT["isExterior"] = sol::readonly_property([](const CellT& c) { return c.mStore->isExterior(); }); // deprecated, use cell:hasTag("QuasiExterior") instead - cellT["isQuasiExterior"] = sol::readonly_property( - [](const CellT& c) { return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; }); + cellT["isQuasiExterior"] + = sol::readonly_property([](const CellT& c) { return (c.mStore->getCell()->isQuasiExterior()) != 0; }); cellT["hasTag"] = [](const CellT& c, std::string_view tag) -> bool { if (tag == "NoSleep") - return (c.mStore->getCell()->mData.mFlags & ESM::Cell::NoSleep) != 0; + return (c.mStore->getCell()->noSleep()) != 0; else if (tag == "QuasiExterior") - return (c.mStore->getCell()->mData.mFlags & ESM::Cell::QuasiEx) != 0; + return (c.mStore->getCell()->isQuasiExterior()) != 0; return false; }; diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 655fa1978a..6cdfff0fea 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -176,12 +176,12 @@ namespace MWLua // TODO: change AiEscort implementation to accept ptr instead of a non-unique refId. const ESM::RefId& refId = target.ptr().getCellRef().getRefId(); int gameHoursDuration = static_cast(std::ceil(duration / 3600.0)); - const ESM::Cell* esmCell = cell.mStore->getCell(); + const ESM::CellCommon* esmCell = cell.mStore->getCell(); if (esmCell->isExterior()) ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr); else ai.stack(MWMechanics::AiEscort( - refId, esmCell->mName, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), + refId, esmCell->getEditorName(), gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr); }; selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration) { diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 8d919b5aec..e41885c8d1 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -274,8 +274,8 @@ namespace MWMechanics .find("fInteriorHeadTrackMult") ->mValue.getFloat(); float maxDistance = fMaxHeadTrackDistance; - const ESM::Cell* currentCell = actor.getCell()->getCell(); - if (!currentCell->isExterior() && !(currentCell->mData.mFlags & ESM::Cell::QuasiEx)) + auto currentCell = actor.getCell()->getCell(); + if (!currentCell->isExterior() && !(currentCell->isQuasiExterior())) maxDistance *= fInteriorHeadTrackMult; const osg::Vec3f actor1Pos(actorRefData.getPosition().asVec3()); diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5ab2974def..d9358a0e56 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -357,12 +357,12 @@ namespace MWMechanics case AiCombatStorage::FleeState_Idle: { float triggerDist = getMaxAttackDistance(target); - - if (storage.mLOS && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) + auto cell3 = storage.mCell->getCellVariant().getEsm3(); + if (cell3 && storage.mLOS + && (triggerDist >= 1000 || getDistanceMinusHalfExtents(actor, target) <= triggerDist)) { const ESM::Pathgrid* pathgrid - = MWBase::Environment::get().getWorld()->getStore().get().search( - *storage.mCell->getCell()); + = MWBase::Environment::get().getWorld()->getStore().get().search(*cell3); bool runFallback = true; diff --git a/apps/openmw/mwmechanics/aifollow.cpp b/apps/openmw/mwmechanics/aifollow.cpp index 12b19611e0..6185535a67 100644 --- a/apps/openmw/mwmechanics/aifollow.cpp +++ b/apps/openmw/mwmechanics/aifollow.cpp @@ -174,7 +174,8 @@ namespace MWMechanics return true; } } - else if (Misc::StringUtils::ciEqual(mCellId, actor.getCell()->getCell()->mName)) // Cell to travel to + else if (Misc::StringUtils::ciEqual( + mCellId, actor.getCell()->getCell()->getEditorName())) // Cell to travel to { mRemainingDuration = mDuration; return true; diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 25ba126ee8..1233e16a39 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -411,7 +411,7 @@ bool MWMechanics::AiPackage::doesPathNeedRecalc(const osg::Vec3f& newDest, const bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position) { - const ESM::Cell* playerCell(getPlayer().getCell()->getCell()); + const ESM::Cell* playerCell(getPlayer().getCell()->getCellVariant().getEsm3()); if (playerCell->isExterior()) { // get actor's distance from origin of center cell diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 58b8a13b13..6043759b3e 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -271,9 +271,10 @@ namespace MWMechanics } // Initialization to discover & store allowed node points for this actor. - if (storage.mPopulateAvailableNodes) + auto cell3 = actor.getCell()->getCellVariant().getEsm3(); + if (cell3 && storage.mPopulateAvailableNodes) { - getAllowedNodes(actor, actor.getCell()->getCell(), storage); + getAllowedNodes(actor, cell3, storage); } auto& prng = MWBase::Environment::get().getWorld()->getPrng(); @@ -721,8 +722,9 @@ namespace MWMechanics return; AiWanderStorage& storage = state.get(); - if (storage.mPopulateAvailableNodes) - getAllowedNodes(actor, actor.getCell()->getCell(), storage); + auto cell3 = actor.getCell()->getCellVariant().getEsm3(); + if (cell3 && storage.mPopulateAvailableNodes) + getAllowedNodes(actor, cell3, storage); if (storage.mAllowedNodes.empty()) return; @@ -800,8 +802,11 @@ namespace MWMechanics void AiWander::getNeighbouringNodes( ESM::Pathgrid::Point dest, const MWWorld::CellStore* currentCell, ESM::Pathgrid::PointList& points) { + auto cell3 = currentCell->getCellVariant().getEsm3(); + if (!cell3) + return; const ESM::Pathgrid* pathgrid - = MWBase::Environment::get().getWorld()->getStore().get().search(*currentCell->getCell()); + = MWBase::Environment::get().getWorld()->getStore().get().search(*cell3); if (pathgrid == nullptr || pathgrid->mPoints.empty()) return; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9b5a7aed42..f956367321 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -12,6 +12,7 @@ namespace ESM { struct Cell; + struct CellCommon; namespace AiSequence { struct AiWander; @@ -158,6 +159,8 @@ namespace MWMechanics GroupIndex_MaxIdle = 9 }; + /// convert point from local (i.e. cell) to world coordinates + void ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::CellCommon* cell); void setCurrentNodeToClosestAllowedNode(AiWanderStorage& storage); void addNonPathGridAllowedPoints(const ESM::Pathgrid* pathGrid, int pointIndex, AiWanderStorage& storage, diff --git a/apps/openmw/mwmechanics/pathgrid.cpp b/apps/openmw/mwmechanics/pathgrid.cpp index 6cac10c1be..ceaf513937 100644 --- a/apps/openmw/mwmechanics/pathgrid.cpp +++ b/apps/openmw/mwmechanics/pathgrid.cpp @@ -104,8 +104,10 @@ namespace MWMechanics if (mIsGraphConstructed) return true; - mCell = cell->getCell(); - mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*cell->getCell()); + mCell = cell->getCellVariant().getEsm3(); + if (!mCell) + return false; + mPathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*mCell); if (!mPathgrid) return false; diff --git a/apps/openmw/mwmechanics/spelleffects.cpp b/apps/openmw/mwmechanics/spelleffects.cpp index c32701c310..66b572f1d3 100644 --- a/apps/openmw/mwmechanics/spelleffects.cpp +++ b/apps/openmw/mwmechanics/spelleffects.cpp @@ -489,7 +489,7 @@ namespace MWMechanics { std::string_view dest; if (!markedCell->isExterior()) - dest = markedCell->getCell()->mName; + dest = markedCell->getCell()->getEditorName(); MWWorld::ActionTeleport action(dest, markedPosition, false); action.execute(target); if (!caster.isEmpty()) diff --git a/apps/openmw/mwrender/fogmanager.cpp b/apps/openmw/mwrender/fogmanager.cpp index cfbad67076..6b56bc81a2 100644 --- a/apps/openmw/mwrender/fogmanager.cpp +++ b/apps/openmw/mwrender/fogmanager.cpp @@ -2,7 +2,9 @@ #include +#include #include +#include #include #include #include @@ -38,13 +40,17 @@ namespace MWRender DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog"); } - void FogManager::configure(float viewDistance, const ESM::Cell* cell) + void FogManager::configure(float viewDistance, const ESM::CellVariant& cell) { - osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); + auto cell3 = cell.getEsm3(); + auto cell4 = cell.getEsm4(); + osg::Vec4f color = SceneUtil::colourFromRGB(cell3 ? cell3->mAmbi.mFog : cell4->mLighting.fogColor); + + const float fogDensity = cell3 ? cell3->mAmbi.mFogDensity : cell4->mLighting.fogPower; if (mDistantFog) { - float density = std::max(0.2f, cell->mAmbi.mFogDensity); + float density = std::max(0.2f, fogDensity); mLandFogStart = DLInteriorFogEnd * (1.0f - density) + DLInteriorFogStart * density; mLandFogEnd = DLInteriorFogEnd; mUnderwaterFogStart = DLUnderwaterFogStart; @@ -52,7 +58,7 @@ namespace MWRender mFogColor = color; } else - configure(viewDistance, cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color); + configure(viewDistance, fogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color); } void FogManager::configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, diff --git a/apps/openmw/mwrender/fogmanager.hpp b/apps/openmw/mwrender/fogmanager.hpp index 6f91e2ff30..a1759d5963 100644 --- a/apps/openmw/mwrender/fogmanager.hpp +++ b/apps/openmw/mwrender/fogmanager.hpp @@ -5,7 +5,7 @@ namespace ESM { - struct Cell; + struct CellVariant; } namespace MWRender @@ -15,7 +15,7 @@ namespace MWRender public: FogManager(); - void configure(float viewDistance, const ESM::Cell* cell); + void configure(float viewDistance, const ESM::CellVariant& cell); void configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& color); diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 115ab80560..85d8f7a295 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -102,7 +102,10 @@ namespace MWRender void Pathgrid::enableCellPathgrid(const MWWorld::CellStore* store) { MWBase::World* world = MWBase::Environment::get().getWorld(); - const ESM::Pathgrid* pathgrid = world->getStore().get().search(*store->getCell()); + auto cell3 = store->getCellVariant().getEsm3(); + if (!cell3) + return; + const ESM::Pathgrid* pathgrid = world->getStore().get().search(*cell3); if (!pathgrid) return; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ad55dd5c04..7f03d4707c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -739,14 +740,24 @@ namespace MWRender mSky->setMoonColour(red); } - void RenderingManager::configureAmbient(const ESM::Cell* cell) + void RenderingManager::configureAmbient(const ESM::CellVariant& cell) { - bool isInterior = !cell->isExterior() && !(cell->mData.mFlags & ESM::Cell::QuasiEx); + bool isInterior = !cell.getCommon()->isExterior() && !cell.getCommon()->isQuasiExterior(); bool needsAdjusting = false; if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP) needsAdjusting = isInterior; - auto ambient = SceneUtil::colourFromRGB(cell->mAmbi.mAmbient); + osg::Vec4f ambient; + auto cell3 = cell.getEsm3(); + auto cell4 = cell.getEsm4(); + if (cell3) + { + ambient = SceneUtil::colourFromRGB(cell3->mAmbi.mAmbient); + } + else + { + ambient = SceneUtil::colourFromRGB(cell4->mLighting.ambient); + } if (needsAdjusting) { @@ -770,7 +781,9 @@ namespace MWRender setAmbientColour(ambient); - osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); + osg::Vec4f diffuse = cell3 ? SceneUtil::colourFromRGB(cell3->mAmbi.mSunlight) + : SceneUtil::colourFromRGB(cell4->mLighting.directional); + setSunColour(diffuse, diffuse, 1.f); const osg::Vec4f interiorSunPos = osg::Vec4f(-0.15f, 0.15f, 1.f, 0.f); @@ -890,7 +903,7 @@ namespace MWRender return false; } - void RenderingManager::configureFog(const ESM::Cell* cell) + void RenderingManager::configureFog(const ESM::CellVariant& cell) { mFog->configure(mViewDistance, cell); } @@ -1424,7 +1437,7 @@ namespace MWRender mMinimumAmbientLuminance = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f); if (MWMechanics::getPlayer().isInCell()) - configureAmbient(MWMechanics::getPlayer().getCell()->getCell()); + configureAmbient(MWMechanics::getPlayer().getCell()->getCellVariant()); } else if (it->first == "Shaders" && (it->second == "light bounds multiplier" || it->second == "maximum light distance" diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index ff1d96adcc..e4791df71a 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -43,6 +43,7 @@ namespace ESM { struct Cell; struct RefNum; + struct CellVariant; } namespace Terrain @@ -140,8 +141,8 @@ namespace MWRender void setSunColour(const osg::Vec4f& diffuse, const osg::Vec4f& specular, float sunVis); void setNight(bool isNight) { mNight = isNight; } - void configureAmbient(const ESM::Cell* cell); - void configureFog(const ESM::Cell* cell); + void configureAmbient(const ESM::CellVariant& cell); + void configureFog(const ESM::CellVariant& cell); void configureFog( float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f& colour); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 513b0eb261..f77a6641b2 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -772,7 +772,8 @@ namespace MWRender bool wasInterior = mInterior; if (!isInterior) { - mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); + mWaterNode->setPosition( + getSceneNodeCoordinates(store->getCell()->getGridX(), store->getCell()->getGridY())); mInterior = false; } else diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index f7e3524d8c..06f889d58a 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -766,14 +766,14 @@ namespace MWSound { MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); - const ESM::Cell* cell = player.getCell()->getCell(); + auto cell = player.getCell()->getCell(); if (!cell->isExterior()) return; if (mCurrentRegionSound && mOutput->isSoundPlaying(mCurrentRegionSound)) return; - if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->mRegion, *world)) + if (const auto next = mRegionSoundSelector.getNextRandom(duration, cell->getRegion(), *world)) mCurrentRegionSound = playSound(*next, 1.0f, 1.0f); } @@ -781,7 +781,7 @@ namespace MWSound { MWBase::World* world = MWBase::Environment::get().getWorld(); const MWWorld::ConstPtr player = world->getPlayerPtr(); - const ESM::Cell* curcell = player.getCell()->getCell(); + const ESM::Cell* curcell = player.getCell()->getCellVariant().getEsm3(); const auto update = mWaterSoundUpdater.update(player, *world); WaterSoundAction action; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 0e69961758..0fe281dcc6 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -505,7 +505,7 @@ namespace MWWorld return false; } - CellStore::CellStore(CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) + CellStore::CellStore(ESM::CellVariant cell, const MWWorld::ESMStore& esmStore, ESM::ReadersCache& readers) : mStore(esmStore) , mReaders(readers) , mCellVariant(cell) @@ -526,12 +526,12 @@ namespace MWWorld CellStore::~CellStore() = default; CellStore::CellStore(CellStore&&) = default; - const ESM::Cell* CellStore::getCell() const + const ESM::CellCommon* CellStore::getCell() const { - return mCell; + return mCellVariant.getCommon(); } - CellVariant CellStore::getCellVariant() const + ESM::CellVariant CellStore::getCellVariant() const { return mCellVariant; } @@ -1087,8 +1087,11 @@ namespace MWWorld auto cell4Left = mCellVariant.getEsm4(); auto cell4Right = right.mCellVariant.getEsm4(); + auto cell3Left = mCellVariant.getEsm3(); + auto cell3Right = right.mCellVariant.getEsm3(); + if (!cell4Left && !cell4Right) - return getCell()->getCellId() == right.getCell()->getCellId(); + return cell3Left->getCellId() == cell3Right->getCellId(); else if (cell4Left && cell4Right) return cell4Left->mId == cell4Right->mId; else @@ -1299,4 +1302,5 @@ namespace MWWorld } return {}; } + } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 76b2485cd4..76b822d8b8 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,11 +9,13 @@ #include #include #include +#include #include #include "cellreflist.hpp" #include "livecellref.hpp" +#include #include #include #include @@ -49,6 +51,7 @@ namespace ESM struct Static; struct Weapon; struct BodyPart; + struct CellCommon; } namespace ESM4 @@ -64,39 +67,6 @@ namespace MWWorld class ESMStore; struct CellStoreImp; - struct CellVariant - { - std::variant mVariant; - - CellVariant(const ESM4::Cell* cell) - : mVariant(cell) - { - } - - CellVariant(const ESM::Cell* cell) - : mVariant(cell) - { - } - - bool isEsm4() const { return getEsm4(); } - - const ESM4::Cell* getEsm4() const - { - auto cell4 = std::get_if(&mVariant); - if (cell4) - return *cell4; - return nullptr; - } - - const ESM::Cell* getEsm3() const - { - auto cell3 = std::get_if(&mVariant); - if (cell3) - return *cell3; - return nullptr; - } - }; - using CellStoreTuple = std::tuple, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, CellRefList, @@ -129,7 +99,7 @@ namespace MWWorld std::unique_ptr mFogState; const ESM::Cell* mCell; - CellVariant mCellVariant; + ESM::CellVariant mCellVariant; State mState; bool mHasState; std::vector mIds; @@ -224,12 +194,12 @@ namespace MWWorld } /// @param readerList The readers to use for loading of the cell on-demand. - CellStore(CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); + CellStore(ESM::CellVariant cell, const MWWorld::ESMStore& store, ESM::ReadersCache& readers); CellStore(CellStore&&); ~CellStore(); - const ESM::Cell* getCell() const; - CellVariant getCellVariant() const; + const ESM::CellCommon* getCell() const; + ESM::CellVariant getCellVariant() const; std::string_view getEditorName() const; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b776a76856..6c817f3b56 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -317,8 +317,8 @@ namespace MWWorld { if (mActiveCells.find(cell) == mActiveCells.end()) return; - - Log(Debug::Info) << "Unloading cell " << cell->getCell()->getDescription(); + std::string description = cell->getCell()->getDescription(); + Log(Debug::Info) << "Unloading cell " << description; ListAndResetObjectsVisitor visitor; @@ -355,8 +355,12 @@ namespace MWWorld if (cell->getCell()->hasWater()) mNavigator.removeWater(osg::Vec2i(cellX, cellY), navigatorUpdateGuard); - if (const auto pathgrid = mWorld.getStore().get().search(*cell->getCell())) - mNavigator.removePathgrid(*pathgrid); + auto cell3 = cell->getCellVariant().getEsm3(); + if (cell3) + { + if (const auto pathgrid = mWorld.getStore().get().search(*cell3)) + mNavigator.removePathgrid(*pathgrid); + } MWBase::Environment::get().getMechanicsManager()->drop(cell); @@ -383,14 +387,11 @@ namespace MWWorld Log(Debug::Info) << "Loading cell " << cell->getEditorName(); auto cell3 = cell->getCellVariant().getEsm3(); - int cellX = 0; - int cellY = 0; + const int cellX = cell->getCellVariant().getCommon()->getGridX(); + const int cellY = cell->getCellVariant().getCommon()->getGridY(); if (cell3 != nullptr) { - int cellX = cell3->getGridX(); - int cellY = cell3->getGridY(); - if (cell3->isExterior()) { osg::ref_ptr land = mRendering.getLandManager()->getLand(cellX, cellY); @@ -472,8 +473,10 @@ namespace MWWorld else mPhysics->disableWater(); - if (cell3 && !cell->isExterior() && !(cell3->mData.mFlags & ESM::Cell::QuasiEx)) - mRendering.configureAmbient(cell3); + const auto cellVariant = cell->getCellVariant(); + + if (!cell->isExterior() && !cellVariant.getCommon()->isQuasiExterior()) + mRendering.configureAmbient(cellVariant); mPreloader->notifyLoaded(cell); } @@ -549,7 +552,7 @@ namespace MWWorld mNavigator.setWorldspace( Misc::StringUtils::lowerCase( - mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->mCellId.mWorldspace), + mWorld.getWorldModel().getExterior(playerCellX, playerCellY)->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); mNavigator.updateBounds(pos, navigatorUpdateGuard.get()); @@ -672,7 +675,7 @@ namespace MWWorld CellStore* cell = mWorld.getWorldModel().getExterior(it->mData.mX, it->mData.mY); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); const osg::Vec3f position = osg::Vec3f(it->mData.mX + 0.5f, it->mData.mY + 0.5f, 0) * Constants::CellSizeInUnits; mNavigator.updateBounds(position, navigatorUpdateGuard.get()); @@ -730,7 +733,7 @@ namespace MWWorld CellStore* cell = mWorld.getWorldModel().getInterior(it->mName); mNavigator.setWorldspace( - Misc::StringUtils::lowerCase(cell->getCell()->mCellId.mWorldspace), navigatorUpdateGuard.get()); + Misc::StringUtils::lowerCase(cell->getCell()->getCellId().mWorldspace), navigatorUpdateGuard.get()); ESM::Position position; mWorld.findInteriorPosition(it->mName, position); mNavigator.updateBounds(position.asVec3(), navigatorUpdateGuard.get()); @@ -746,7 +749,7 @@ namespace MWWorld { assert(!(*iter)->getCell()->isExterior()); - if (it->mName == (*iter)->getCell()->mName) + if (it->mName == (*iter)->getCell()->getEditorName()) { unloadCell(*iter, navigatorUpdateGuard.get()); break; @@ -898,7 +901,7 @@ namespace MWWorld changePlayerCell(cell, position, adjustPlayerPos); // adjust fog - mRendering.configureFog(mCurrentCell->getCell()); + mRendering.configureFog(mCurrentCell->getCellVariant()); // Sky system mWorld.adjustSky(); @@ -914,7 +917,7 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag( - cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx); + cell->getCellVariant().getCommon()->isQuasiExterior()); } void Scene::changeToExteriorCell(const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d4d74dd5ec..b7ddd6e924 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -704,7 +704,7 @@ namespace MWWorld if (!paused || mFastForward) { // Add new transitions when either the player's current external region changes. - if (updateWeatherTime() || updateWeatherRegion(player.getCell()->getCell()->mRegion)) + if (updateWeatherTime() || updateWeatherRegion(player.getCell()->getCell()->getRegion())) { auto it = mRegions.find(mCurrentRegion); if (it != mRegions.end()) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index cec624898d..1b4a37b1eb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include @@ -634,18 +634,22 @@ namespace MWWorld { if (!cell) cell = mWorldScene->getCurrentCell(); - return getCellName(cell->getCell()); + return getCellName(cell->getCellVariant()); } - std::string_view World::getCellName(const ESM::Cell* cell) const + std::string_view World::getCellName(const ESM::CellVariant& cell) const { - if (cell) + auto cellCommon = cell.getCommon(); + if (cellCommon) { - if (!cell->isExterior() || !cell->mName.empty()) - return cell->mName; + if (!cellCommon->isExterior() || !cellCommon->getEditorName().empty()) + return cellCommon->getEditorName(); - if (const ESM::Region* region = mStore.get().search(cell->mRegion)) + if (cell.getEsm3()) + { + const ESM::Region* region = mStore.get().search(cell.getEsm3()->mRegion); return region->mName; + } } return mStore.get().find("sDefaultCellname")->mValue.getString(); @@ -1139,7 +1143,7 @@ namespace MWWorld { if (!newCell->isExterior()) { - changeToInteriorCell(newCell->getCell()->mName, pos, false); + changeToInteriorCell(newCell->getCell()->getEditorName(), pos, false); removeContainerScripts(getPlayerPtr()); } else @@ -1400,7 +1404,7 @@ namespace MWWorld esmPos.pos[2] = traced.z(); std::string_view cell; if (!actor.getCell()->isExterior()) - cell = actor.getCell()->getCell()->mName; + cell = actor.getCell()->getCell()->getEditorName(); MWWorld::ActionTeleport(cell, esmPos, false).execute(actor); } } @@ -1988,10 +1992,7 @@ namespace MWWorld const CellStore* currentCell = mWorldScene->getCurrentCell(); if (currentCell) { - if (!(currentCell->getCell()->mData.mFlags & ESM::Cell::QuasiEx)) - return false; - else - return true; + return currentCell->getCell()->isQuasiExterior(); } return false; } @@ -2312,7 +2313,7 @@ namespace MWWorld if (!cell) return false; - if (!(cell->getCell()->hasWater())) + if (!(cell->getCellVariant().getCommon()->hasWater())) { return false; } @@ -2468,8 +2469,7 @@ namespace MWWorld || isFlying(player)) return Rest_PlayerIsInAir; - if ((currentCell->getCell()->mData.mFlags & ESM::Cell::NoSleep) - || player.getClass().getNpcStats(player).isWerewolf()) + if (currentCell->getCell()->noSleep() || player.getClass().getNpcStats(player).isWerewolf()) return Rest_OnlyWaiting; return Rest_Allowed; @@ -2840,7 +2840,7 @@ namespace MWWorld { pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - const ESM::Cell* ext = nullptr; + const ESM::CellCommon* ext = nullptr; try { ext = mWorldModel.getCell(nameId)->getCell(); @@ -3247,9 +3247,11 @@ namespace MWWorld } else { - uint32_t ambient = cell->getCell()->mAmbi.mAmbient; + auto cellVariant = cell->getCellVariant(); + uint32_t ambient = cellVariant.getEsm3() ? cellVariant.getEsm3()->mAmbi.mAmbient + : cellVariant.getEsm4()->mLighting.ambient; int ambientTotal = (ambient & 0xff) + ((ambient >> 8) & 0xff) + ((ambient >> 16) & 0xff); - return !(cell->getCell()->mData.mFlags & ESM::Cell::NoSleep) && ambientTotal <= 201; + return !cell->getCell()->noSleep() && ambientTotal <= 201; } } @@ -3328,7 +3330,7 @@ namespace MWWorld std::set nextCells; MWWorld::ConstPtr closestMarker; - nextCells.insert(ptr.getCell()->getCell()->mName); + nextCells.insert(ptr.getCell()->getCell()->getEditorName()); while (!nextCells.empty()) { currentCells = nextCells; @@ -3423,7 +3425,7 @@ namespace MWWorld std::string_view cellName = ""; if (!closestMarker.mCell->isExterior()) - cellName = closestMarker.mCell->getCell()->mName; + cellName = closestMarker.mCell->getCell()->getEditorName(); MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition(), false); action.execute(ptr); @@ -3436,7 +3438,7 @@ namespace MWWorld { mPlayer->setTeleported(false); - const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->mRegion; + const ESM::RefId& playerRegion = getPlayerPtr().getCell()->getCell()->getRegion(); mWeatherManager->playerTeleported(playerRegion, isExterior); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index df2ee69fbf..809daf95d8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -269,7 +269,7 @@ namespace MWWorld /// /// \note If cell==0, the cell the player is currently in will be used instead to /// generate a name. - std::string_view getCellName(const ESM::Cell* cell) const override; + std::string_view getCellName(const ESM::CellVariant& cell) const override; void removeRefScript(MWWorld::RefData* ref) override; //< Remove the script attached to ref from mLocalScripts diff --git a/apps/openmw/mwworld/worldmodel.cpp b/apps/openmw/mwworld/worldmodel.cpp index ac754eae60..1dc935af3b 100644 --- a/apps/openmw/mwworld/worldmodel.cpp +++ b/apps/openmw/mwworld/worldmodel.cpp @@ -67,7 +67,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) auto result = mInteriors.find(cell->mName); if (result == mInteriors.end()) - result = mInteriors.emplace(cell->mName, CellStore(cell, mStore, mReaders)).first; + result = mInteriors.emplace(cell->mName, CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; return &result->second; } @@ -78,7 +78,8 @@ MWWorld::CellStore* MWWorld::WorldModel::getCellStore(const ESM::Cell* cell) if (result == mExteriors.end()) result = mExteriors - .emplace(std::make_pair(cell->getGridX(), cell->getGridY()), CellStore(cell, mStore, mReaders)) + .emplace(std::make_pair(cell->getGridX(), cell->getGridY()), + CellStore(ESM::CellVariant(cell), mStore, mReaders)) .first; return &result->second; @@ -185,7 +186,7 @@ MWWorld::CellStore* MWWorld::WorldModel::getExterior(int x, int y) cell = MWBase::Environment::get().getWorld()->createRecord(record); } - result = mExteriors.emplace(std::make_pair(x, y), CellStore(cell, mStore, mReaders)).first; + result = mExteriors.emplace(std::make_pair(x, y), CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; } if (result->second.getState() != CellStore::State_Loaded) @@ -207,11 +208,11 @@ MWWorld::CellStore* MWWorld::WorldModel::getInterior(std::string_view name) if (!cell4) { const ESM::Cell* cell = mStore.get().find(name); - result = mInteriors.emplace(name, CellStore(cell, mStore, mReaders)).first; + result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell), mStore, mReaders)).first; } else { - result = mInteriors.emplace(name, CellStore(cell4, mStore, mReaders)).first; + result = mInteriors.emplace(name, CellStore(ESM::CellVariant(cell4), mStore, mReaders)).first; } } @@ -261,14 +262,14 @@ const ESM::Cell* MWWorld::WorldModel::getESMCellByName(std::string_view name) return cell; } -MWWorld::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name) +ESM::CellVariant MWWorld::WorldModel::getCellByName(std::string_view name) { const ESM::Cell* cellEsm3 = getESMCellByName(name); - return cellEsm3; + return ESM::CellVariant(cellEsm3); if (!cellEsm3) { const ESM4::Cell* cellESM4 = mStore.get().searchCellName(name); - return cellESM4; + return ESM::CellVariant(cellESM4); } } diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 9caada64c0..aa21eedc2d 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -51,7 +51,7 @@ namespace MWWorld WorldModel& operator=(const WorldModel&); const ESM::Cell* getESMCellByName(std::string_view name); - CellVariant getCellByName(std::string_view name); + ESM::CellVariant getCellByName(std::string_view name); CellStore* getCellStore(const ESM::Cell* cell); Ptr getPtrAndCache(const ESM::RefId& name, CellStore& cellStore); diff --git a/apps/openmw_test_suite/mwworld/test_store.cpp b/apps/openmw_test_suite/mwworld/test_store.cpp index d2163520f7..795a9932ae 100644 --- a/apps/openmw_test_suite/mwworld/test_store.cpp +++ b/apps/openmw_test_suite/mwworld/test_store.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -316,7 +317,7 @@ static void testRecNameIntCount(const MWWorld::Store& store, const MWWorld::E const unsigned int recordIdCount = std::apply([](auto&&... x) { return (hasSameRecordId(x, T::sRecordId) + ...); }, stores); ASSERT_EQ(recordIdCount, static_cast(1)) - << "The same RecNameInt is used twice ESM::REC_" << MWWorld::getRecNameString(T::sRecordId).toStringView(); + << "The same RecNameInt is used twice ESM::REC_" << ESM::getRecNameString(T::sRecordId).toStringView(); } } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f863f246d0..9c7e6e61a5 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -80,7 +80,7 @@ add_component_dir (to_utf8 to_utf8 ) -add_component_dir(esm attr common defs esmcommon records util luascripts format refid) +add_component_dir(esm attr common defs esmcommon records util luascripts format refid cellcommon) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/cellcommon.cpp b/components/esm/cellcommon.cpp new file mode 100644 index 0000000000..42c93f0b83 --- /dev/null +++ b/components/esm/cellcommon.cpp @@ -0,0 +1,15 @@ +#include +#include +#include + +namespace ESM +{ + const ESM::CellCommon* CellVariant::getCommon() const + { + auto cell3 = getEsm3(); + if (cell3) + return cell3; + else + return getEsm4(); + } +} diff --git a/components/esm/cellcommon.hpp b/components/esm/cellcommon.hpp new file mode 100644 index 0000000000..ec2d0559ec --- /dev/null +++ b/components/esm/cellcommon.hpp @@ -0,0 +1,68 @@ +#ifndef COMPONENTS_ESM_CELLCOMMON +#define COMPONENTS_ESM_CELLCOMMON +#include +#include +#include + +namespace ESM4 +{ + struct Cell; +} + +namespace ESM +{ + struct Cell; + struct CellId; + struct RefId; + // Common interface for esm3 and esm4 cells + struct CellCommon + { + virtual int getGridX() const = 0; + virtual int getGridY() const = 0; + virtual bool isExterior() const = 0; + virtual bool isQuasiExterior() const = 0; + virtual bool hasWater() const = 0; + virtual bool noSleep() const { return false; } + virtual const ESM::CellId& getCellId() const = 0; + virtual const ESM::RefId& getRegion() const = 0; + virtual std::string_view getEditorName() const = 0; + virtual std::string getDescription() const = 0; + }; + + struct CellVariant + { + std::variant mVariant; + + explicit CellVariant(const ESM4::Cell* cell) + : mVariant(cell) + { + } + + explicit CellVariant(const ESM::Cell* cell) + : mVariant(cell) + { + } + + bool isEsm4() const { return getEsm4(); } + + const ESM4::Cell* getEsm4() const + { + auto cell4 = std::get_if(&mVariant); + if (cell4) + return *cell4; + return nullptr; + } + + const ESM::Cell* getEsm3() const + { + auto cell3 = std::get_if(&mVariant); + if (cell3) + return *cell3; + return nullptr; + } + + const ESM::CellCommon* getCommon() const; + }; +} + +#endif diff --git a/components/esm3/cellid.cpp b/components/esm3/cellid.cpp index a63a1bfad6..f5318cbbd7 100644 --- a/components/esm3/cellid.cpp +++ b/components/esm3/cellid.cpp @@ -31,7 +31,7 @@ namespace ESM bool operator==(const CellId& left, const CellId& right) { - return left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged + return left.mWorld == right.mWorld && left.mWorldspace == right.mWorldspace && left.mPaged == right.mPaged && (!left.mPaged || (left.mIndex.mX == right.mIndex.mX && left.mIndex.mY == right.mIndex.mY)); } diff --git a/components/esm3/cellid.hpp b/components/esm3/cellid.hpp index 33db9e7432..8d2418790f 100644 --- a/components/esm3/cellid.hpp +++ b/components/esm3/cellid.hpp @@ -17,6 +17,7 @@ namespace ESM int mY; }; + ESM::RefId mWorld; std::string mWorldspace; CellIndex mIndex; bool mPaged; diff --git a/components/esm3/loadcell.hpp b/components/esm3/loadcell.hpp index 3cf1834dfa..7518d81b3c 100644 --- a/components/esm3/loadcell.hpp +++ b/components/esm3/loadcell.hpp @@ -7,6 +7,7 @@ #include "cellid.hpp" #include "cellref.hpp" +#include "components/esm/cellcommon.hpp" #include "components/esm/defs.hpp" #include "components/esm/esmcommon.hpp" #include "components/esm/refid.hpp" @@ -65,7 +66,7 @@ namespace ESM (using ESMReader::getContext()) and jumping back into place whenever we need to load a given cell. */ - struct Cell + struct Cell : public CellCommon { constexpr static RecNameInts sRecordId = REC_CELL; @@ -150,13 +151,14 @@ namespace ESM void save(ESMWriter& esm, bool isDeleted = false) const; void saveTempMarker(ESMWriter& esm, int tempCount) const; - bool isExterior() const { return !(mData.mFlags & Interior); } + bool isExterior() const override { return !(mData.mFlags & Interior); } + bool isQuasiExterior() const override { return mData.mFlags & QuasiEx; } - int getGridX() const { return mData.mX; } + int getGridX() const override { return mData.mX; } - int getGridY() const { return mData.mY; } + int getGridY() const override { return mData.mY; } - bool hasWater() const { return ((mData.mFlags & HasWater) != 0) || isExterior(); } + bool hasWater() const override { return ((mData.mFlags & HasWater) != 0) || isExterior(); } bool hasAmbient() const { return mHasAmbi; } @@ -169,7 +171,7 @@ namespace ESM // exactly. void restore(ESMReader& esm, int iCtx) const; - std::string getDescription() const; + std::string getDescription() const override; ///< Return a short string describing the cell (mostly used for debugging/logging purpose) /* Get the next reference in this cell, if any. Returns false when @@ -191,7 +193,10 @@ namespace ESM void blank(); ///< Set record to default state (does not touch the ID/index). - const CellId& getCellId() const; + const CellId& getCellId() const override; + const ESM::RefId& getRegion() const override { return mRegion; } + bool noSleep() const override { return mData.mFlags & ESM::Cell::NoSleep; } + std::string_view getEditorName() const override { return mName; } }; } #endif diff --git a/components/esm4/loadcell.cpp b/components/esm4/loadcell.cpp index 0b829d657f..22d6a46865 100644 --- a/components/esm4/loadcell.cpp +++ b/components/esm4/loadcell.cpp @@ -39,6 +39,7 @@ // #include "writer.hpp" #include +#include // TODO: Try loading only EDID and XCLC (along with mFormId, mFlags and mParent) // @@ -77,6 +78,12 @@ void ESM4::Cell::load(ESM4::Reader& reader) std::uint32_t esmVer = reader.esmVersion(); bool isFONV = esmVer == ESM::VER_132 || esmVer == ESM::VER_133 || esmVer == ESM::VER_134; + mCellId.mWorldspace = Misc::StringUtils::lowerCase(mEditorId); + mCellId.mWorld = ESM::RefId::sEmpty; + mCellId.mIndex.mX = getGridX(); + mCellId.mIndex.mX = getGridY(); + mCellId.mPaged = isExterior(); + while (reader.getSubRecordHeader()) { const ESM4::SubRecordHeader& subHdr = reader.subRecordHeader(); diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 49e5d048b0..5be37cad11 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -34,8 +34,10 @@ #include "formid.hpp" #include "lighting.hpp" +#include #include #include +#include namespace ESM4 { @@ -60,7 +62,7 @@ namespace ESM4 // Unlike TES3, multiple cells can have the same exterior co-ordinates. // The cells need to be organised under world spaces. - struct Cell + struct Cell final : public ESM::CellCommon { FormId mParent; // world formId (for grouping cells), from the loading sequence @@ -94,12 +96,24 @@ namespace ESM4 CellGroup* mCellGroup; + ESM::CellId mCellId; + void load(ESM4::Reader& reader); // void save(ESM4::Writer& writer) const; void blank(); static constexpr ESM::RecNameInts sRecordId = ESM::REC_CELL4; + + int getGridX() const override { return mX; } + int getGridY() const override { return mY; } + bool isExterior() const override { return false; /*unimplemented for now*/ } + virtual bool isQuasiExterior() const override { return false; /*unimplemented for now*/ } + virtual bool hasWater() const override { return false; /*unimplemented for now*/ } + const ESM::CellId& getCellId() const override { return mCellId; } + const ESM::RefId& getRegion() const override { return ESM::RefId::sEmpty; } + std::string_view getEditorName() const override { return mEditorId; } + std::string getDescription() const override { return mEditorId; }; }; } diff --git a/components/misc/coordinateconverter.hpp b/components/misc/coordinateconverter.hpp index 9adc7a92d7..bc9ef6d427 100644 --- a/components/misc/coordinateconverter.hpp +++ b/components/misc/coordinateconverter.hpp @@ -17,8 +17,8 @@ namespace Misc { } - explicit CoordinateConverter(const ESM::Cell* cell) - : CoordinateConverter(cell->isExterior(), cell->mData.mX, cell->mData.mY) + explicit CoordinateConverter(const ESM::CellCommon* cell) + : CoordinateConverter(cell->isExterior(), cell->getGridX(), cell->getGridY()) { }