diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 36241b02d2..4950a8c40b 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -678,7 +678,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/creaturelevlist.cpp b/apps/openmw/mwclass/creaturelevlist.cpp index dd346306e9..461cf07276 100644 --- a/apps/openmw/mwclass/creaturelevlist.cpp +++ b/apps/openmw/mwclass/creaturelevlist.cpp @@ -148,7 +148,7 @@ namespace MWClass manualRef.getPtr().getCellRef().setPosition(ptr.getCellRef().getPosition()); manualRef.getPtr().getCellRef().setScale(ptr.getCellRef().getScale()); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject( - manualRef.getPtr(), ptr.getCell(), ptr.getCellRef().getPosition()); + manualRef.getPtr(), ptr.getCell(), ptr.getRefData().getPosition()); customData.mSpawnActorId = placed.getClass().getCreatureStats(placed).getActorId(); customData.mSpawn = false; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 91601513a8..f1514a4ffe 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1323,7 +1323,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 d857288979..46a72c0848 100644 --- a/apps/openmw/mwlua/cellbindings.cpp +++ b/apps/openmw/mwlua/cellbindings.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -199,6 +200,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..ef25dadfab 100644 --- a/apps/openmw/mwlua/objectbindings.cpp +++ b/apps/openmw/mwlua/objectbindings.cpp @@ -11,6 +11,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/localscripts.hpp" #include "../mwworld/player.hpp" #include "../mwworld/scene.hpp" #include "../mwworld/worldmodel.hpp" @@ -77,20 +78,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,15 +109,38 @@ 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()) { - auto& stats = ptr.getClass().getCreatureStats(ptr); + auto& stats = cls.getCreatureStats(ptr); stats.land(false); stats.setTeleported(true); } - MWWorld::Ptr newPtr = world->moveObject(ptr, destCell, pos); - world->rotateObject(newPtr, rot, MWBase::RotationFlag_none); + const MWWorld::CellStore* srcCell = ptr.getCell(); + MWWorld::Ptr newPtr; + if (srcCell == &wm->getDraftCell()) + { + newPtr = cls.moveToCell(ptr, *destCell, toPos(pos, rot)); + ptr.getCellRef().unsetRefNum(); + ptr.getRefData().setLuaScripts(nullptr); + ptr.getRefData().setCount(0); + ESM::RefId script = cls.getScript(newPtr); + if (!script.empty()) + world->getLocalScripts().add(script, newPtr); + world->addContainerScripts(newPtr, newPtr.getCell()); + } + else + { + newPtr = world->moveObject(ptr, destCell, pos); + if (srcCell == destCell) + { + ESM::RefId script = cls.getScript(newPtr); + if (!script.empty()) + world->getLocalScripts().add(script, newPtr); + } + 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 a13accf7c8..c7d0ae3165 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -1236,13 +1236,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 true; + }); } } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2543f24aa7..13409ab169 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -263,7 +263,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/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