From 641f34a3c9f45718f14deac16ea837282917ec7e Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Mon, 25 Sep 2023 21:01:32 +0200 Subject: [PATCH] Treat teleportation out of the draft cell as object creation --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/misc.cpp | 3 ++- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwlua/cellbindings.cpp | 4 ++++ apps/openmw/mwlua/objectbindings.cpp | 29 ++++++++++++++++++++++------ apps/openmw/mwworld/cellstore.cpp | 11 +++++------ apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/class.cpp | 3 ++- files/lua_api/openmw/world.lua | 1 + 9 files changed, 40 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index df1ada96f4..9b705b805f 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -692,7 +692,7 @@ namespace MWClass if (newPtr.getRefData().getCustomData()) { MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); - newPtr.getContainerStore()->setPtr(newPtr); + newPtr.getClass().getContainerStore(newPtr).setPtr(newPtr); } return newPtr; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 6c517e3dde..c5f9de23b1 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -205,7 +205,8 @@ namespace MWClass newPtr = MWWorld::Ptr(cell.insert(ref), &cell); newPtr.getRefData().setCount(count); } - newPtr.getCellRef().unsetRefNum(); + if (ptr.getCell() != &MWBase::Environment::get().getWorldModel()->getDraftCell()) + newPtr.getCellRef().unsetRefNum(); newPtr.getRefData().setLuaScripts(nullptr); MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); return newPtr; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 1e7dae3600..27d72c61b7 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1338,7 +1338,7 @@ namespace MWClass if (newPtr.getRefData().getCustomData()) { MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); - newPtr.getContainerStore()->setPtr(newPtr); + newPtr.getClass().getContainerStore(newPtr).setPtr(newPtr); } return newPtr; } diff --git a/apps/openmw/mwlua/cellbindings.cpp b/apps/openmw/mwlua/cellbindings.cpp index 48c7141ab8..9e779b0da4 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,9 @@ namespace MWLua case ESM::REC_STAT: cell.mStore->template forEachType(visitor); break; + case ESM::REC_LEVC: + cell.mStore->template forEachType(visitor); + break; case ESM::REC_ACTI4: cell.mStore->template forEachType(visitor); diff --git a/apps/openmw/mwlua/objectbindings.cpp b/apps/openmw/mwlua/objectbindings.cpp index ee746001ae..c607dc9d14 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -77,20 +77,25 @@ namespace MWLua return &wm->getExterior(ESM::positionToExteriorCellLocation(pos.x(), pos.y(), worldspace)); } - void teleportPlayer( - MWWorld::CellStore* destCell, const osg::Vec3f& pos, const osg::Vec3f& rot, bool placeOnGround) + ESM::Position toPos(const osg::Vec3f& pos, const osg::Vec3f& rot) { - MWBase::World* world = MWBase::Environment::get().getWorld(); ESM::Position esmPos; static_assert(sizeof(esmPos) == sizeof(osg::Vec3f) * 2); std::memcpy(esmPos.pos, &pos, sizeof(osg::Vec3f)); std::memcpy(esmPos.rot, &rot, sizeof(osg::Vec3f)); + return esmPos; + } + + void teleportPlayer( + MWWorld::CellStore* destCell, const osg::Vec3f& pos, const osg::Vec3f& rot, bool placeOnGround) + { + MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr ptr = world->getPlayerPtr(); auto& stats = ptr.getClass().getCreatureStats(ptr); stats.land(true); stats.setTeleported(true); world->getPlayer().setTeleported(true); - world->changeToCell(destCell->getCell()->getId(), esmPos, false); + world->changeToCell(destCell->getCell()->getId(), toPos(pos, rot), false); MWWorld::Ptr newPtr = world->getPlayerPtr(); world->moveObject(newPtr, pos); world->rotateObject(newPtr, rot); @@ -103,6 +108,7 @@ namespace MWLua const osg::Vec3f& rot, bool placeOnGround) { MWBase::World* world = MWBase::Environment::get().getWorld(); + MWWorld::WorldModel* wm = MWBase::Environment::get().getWorldModel(); const MWWorld::Class& cls = ptr.getClass(); if (cls.isActor()) { @@ -110,8 +116,19 @@ namespace MWLua stats.land(false); stats.setTeleported(true); } - MWWorld::Ptr newPtr = world->moveObject(ptr, destCell, pos); - world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); + MWWorld::Ptr newPtr; + if (ptr.getCell() == &wm->getDraftCell()) + { + newPtr = world->placeObject(ptr, destCell, toPos(pos, rot)); + ptr.getCellRef().unsetRefNum(); + ptr.getRefData().setLuaScripts(nullptr); + ptr.getRefData().setCount(0); + } + else + { + newPtr = world->moveObject(ptr, destCell, pos); + world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); + } if (placeOnGround) world->adjustPosition(newPtr, true); if (cls.isDoor()) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index f7ec3ddcba..a41fbb150a 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1235,13 +1235,12 @@ namespace MWWorld clearCorpse(ptr, mStore); ptr.getClass().respawn(ptr); } - for (CellRefList::List::iterator it(get().mList.begin()); - it != get().mList.end(); ++it) - { - Ptr ptr = getCurrentPtr(&*it); + forEachType([](Ptr ptr) { // no need to clearCorpse, handled as part of get() - ptr.getClass().respawn(ptr); - } + if (!ptr.getRefData().isDeleted()) + ptr.getClass().respawn(ptr); + return false; + }); } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 23bd071ff1..94d0fd6d67 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -262,7 +262,7 @@ namespace MWWorld /// unintended behaviour. \attention This function also lists deleted (count 0) objects! \return Iteration /// completed? template - bool forEachType(Visitor& visitor) + bool forEachType(Visitor&& visitor) { if (mState != State_Loaded) return false; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index de3c2b011d..c5e30fc5c3 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -372,7 +372,8 @@ namespace MWWorld MWWorld::Ptr Class::copyToCell(const ConstPtr& ptr, CellStore& cell, int count) const { Ptr newPtr = copyToCellImpl(ptr, cell); - newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference + if (ptr.getCell() != &MWBase::Environment::get().getWorldModel()->getDraftCell()) + newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference newPtr.getRefData().setCount(count); newPtr.getRefData().setLuaScripts(nullptr); MWBase::Environment::get().getWorldModel()->registerPtr(newPtr); diff --git a/files/lua_api/openmw/world.lua b/files/lua_api/openmw/world.lua index c55860ee26..97f596e4a6 100644 --- a/files/lua_api/openmw/world.lua +++ b/files/lua_api/openmw/world.lua @@ -134,6 +134,7 @@ --- -- Create a new instance of the given record. -- After creation the object is in the disabled state. Use :teleport to place to the world or :moveInto to put it into a container or an inventory. +-- Note that dynamically created creatures, NPCs, and container inventories will not respawn. -- @function [parent=#world] createObject -- @param #string recordId Record ID in lowercase -- @param #number count (optional, 1 by default) The number of objects in stack