mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-18 13:12:50 +00:00
Preserve refnum when dropping items from inventory to ground.
This commit is contained in:
parent
fbe6a398f8
commit
8c3c5238d7
@ -337,14 +337,17 @@ namespace MWBase
|
||||
///< Toggle a render mode.
|
||||
///< \return Resulting mode
|
||||
|
||||
virtual MWWorld::Ptr placeObject(const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) = 0;
|
||||
virtual MWWorld::Ptr placeObject(
|
||||
const MWWorld::Ptr& object, float cursorX, float cursorY, int amount, bool copy = true)
|
||||
= 0;
|
||||
///< copy and place an object into the gameworld at the specified cursor position
|
||||
/// @param object
|
||||
/// @param cursor X (relative 0-1)
|
||||
/// @param cursor Y (relative 0-1)
|
||||
/// @param number of objects to place
|
||||
|
||||
virtual MWWorld::Ptr dropObjectOnGround(const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount)
|
||||
virtual MWWorld::Ptr dropObjectOnGround(
|
||||
const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount, bool copy = true)
|
||||
= 0;
|
||||
///< copy and place an object into the gameworld at the given actor's position
|
||||
/// @param actor giving the dropped object position
|
||||
|
@ -25,6 +25,14 @@ namespace MWGui
|
||||
{
|
||||
}
|
||||
|
||||
MWWorld::Ptr CompanionItemModel::addItem(const ItemStack& item, size_t count, bool allowAutoEquip)
|
||||
{
|
||||
if (hasProfit(mActor))
|
||||
modifyProfit(mActor, item.mBase.getClass().getValue(item.mBase) * count);
|
||||
|
||||
return InventoryItemModel::addItem(item, count, allowAutoEquip);
|
||||
}
|
||||
|
||||
MWWorld::Ptr CompanionItemModel::copyItem(const ItemStack& item, size_t count, bool allowAutoEquip)
|
||||
{
|
||||
if (hasProfit(mActor))
|
||||
|
@ -13,6 +13,7 @@ namespace MWGui
|
||||
public:
|
||||
CompanionItemModel(const MWWorld::Ptr& actor);
|
||||
|
||||
MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override;
|
||||
MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override;
|
||||
void removeItem(const ItemStack& item, size_t count) override;
|
||||
|
||||
|
@ -45,20 +45,31 @@ namespace MWGui
|
||||
{
|
||||
}
|
||||
virtual ~WorldItemModel() override {}
|
||||
MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override
|
||||
|
||||
MWWorld::Ptr dropItemImpl(const ItemStack& item, size_t count, bool copy)
|
||||
{
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
|
||||
MWWorld::Ptr dropped;
|
||||
if (world->canPlaceObject(mLeft, mTop))
|
||||
dropped = world->placeObject(item.mBase, mLeft, mTop, count);
|
||||
dropped = world->placeObject(item.mBase, mLeft, mTop, count, copy);
|
||||
else
|
||||
dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count);
|
||||
dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count, copy);
|
||||
dropped.getCellRef().setOwner(ESM::RefId());
|
||||
|
||||
return dropped;
|
||||
}
|
||||
|
||||
MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override
|
||||
{
|
||||
return dropItemImpl(item, count, false);
|
||||
}
|
||||
|
||||
MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override
|
||||
{
|
||||
return dropItemImpl(item, count, true);
|
||||
}
|
||||
|
||||
void removeItem(const ItemStack& item, size_t count) override
|
||||
{
|
||||
throw std::runtime_error("removeItem not implemented");
|
||||
|
@ -46,13 +46,29 @@ namespace MWGui
|
||||
return -1;
|
||||
}
|
||||
|
||||
MWWorld::Ptr InventoryItemModel::copyItem(const ItemStack& item, size_t count, bool allowAutoEquip)
|
||||
MWWorld::Ptr InventoryItemModel::addItem(const ItemStack& item, size_t count, bool allowAutoEquip)
|
||||
{
|
||||
if (item.mBase.getContainerStore() == &mActor.getClass().getContainerStore(mActor))
|
||||
throw std::runtime_error("Item to copy needs to be from a different container!");
|
||||
throw std::runtime_error("Item to add needs to be from a different container!");
|
||||
return *mActor.getClass().getContainerStore(mActor).add(item.mBase, count, allowAutoEquip);
|
||||
}
|
||||
|
||||
MWWorld::Ptr InventoryItemModel::copyItem(const ItemStack& item, size_t count, bool allowAutoEquip)
|
||||
{
|
||||
// TODO: This does not copy the item, but adds it directly. This will duplicate the item's
|
||||
// refnum and other ref data unless the caller handles that.
|
||||
return addItem(item, count, allowAutoEquip);
|
||||
}
|
||||
|
||||
MWWorld::Ptr InventoryItemModel::unstackItem(const ItemStack& item, size_t count)
|
||||
{
|
||||
MWWorld::ContainerStore& store = mActor.getClass().getContainerStore(mActor);
|
||||
auto it = store.unstack(item.mBase, count);
|
||||
if (it != store.end())
|
||||
return *it;
|
||||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
void InventoryItemModel::removeItem(const ItemStack& item, size_t count)
|
||||
{
|
||||
int removed = 0;
|
||||
|
@ -17,7 +17,9 @@ namespace MWGui
|
||||
|
||||
bool onTakeItem(const MWWorld::Ptr& item, int count) override;
|
||||
|
||||
MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override;
|
||||
MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override;
|
||||
MWWorld::Ptr unstackItem(const ItemStack& item, size_t count) override;
|
||||
void removeItem(const ItemStack& item, size_t count) override;
|
||||
|
||||
/// Move items from this model to \a otherModel.
|
||||
|
@ -57,13 +57,25 @@ namespace MWGui
|
||||
|
||||
MWWorld::Ptr ItemModel::moveItem(const ItemStack& item, size_t count, ItemModel* otherModel)
|
||||
{
|
||||
// TODO(#6148): moving an item should preserve RefNum and Lua scripts (unless the item stack is merged with
|
||||
// already existing stack).
|
||||
MWWorld::Ptr ret = otherModel->copyItem(item, count);
|
||||
MWWorld::Ptr ret = otherModel->addItem(item, count);
|
||||
// Unstacking here ensures that new a refnum is assigned to the leftover stack if there is a leftover.
|
||||
// Otherwise we end up with duplicated instances.
|
||||
unstackItem(item, count);
|
||||
removeItem(item, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
MWWorld::Ptr ItemModel::addItem(const ItemStack& item, size_t count, bool allowAutoEquip)
|
||||
{
|
||||
return copyItem(item, count, allowAutoEquip);
|
||||
}
|
||||
|
||||
MWWorld::Ptr ItemModel::unstackItem(const ItemStack& item, size_t count)
|
||||
{
|
||||
// By default does nothing
|
||||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
bool ItemModel::allowedToUseItems() const
|
||||
{
|
||||
return true;
|
||||
@ -143,6 +155,16 @@ namespace MWGui
|
||||
return mSourceModel->onTakeItem(item, count);
|
||||
}
|
||||
|
||||
MWWorld::Ptr ProxyItemModel::unstackItem(const ItemStack& item, size_t count)
|
||||
{
|
||||
return mSourceModel->unstackItem(item, count);
|
||||
}
|
||||
|
||||
MWWorld::Ptr ProxyItemModel::addItem(const ItemStack& item, size_t count, bool allowAutoEquip)
|
||||
{
|
||||
return mSourceModel->addItem(item, count, allowAutoEquip);
|
||||
}
|
||||
|
||||
bool ProxyItemModel::usesContainer(const MWWorld::Ptr& container)
|
||||
{
|
||||
return mSourceModel->usesContainer(container);
|
||||
|
@ -65,6 +65,11 @@ namespace MWGui
|
||||
/// @note Derived implementations may return an empty Ptr if the move was unsuccessful.
|
||||
virtual MWWorld::Ptr moveItem(const ItemStack& item, size_t count, ItemModel* otherModel);
|
||||
|
||||
/// Unstacks items from this model and returns a ptr to the new remainder stack.
|
||||
/// @note Returns en empty ptr if there is no remainder or the item model does not support unstacking.
|
||||
virtual MWWorld::Ptr unstackItem(const ItemStack& item, size_t count);
|
||||
|
||||
virtual MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true);
|
||||
virtual MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) = 0;
|
||||
virtual void removeItem(const ItemStack& item, size_t count) = 0;
|
||||
|
||||
@ -95,6 +100,8 @@ namespace MWGui
|
||||
bool onDropItem(const MWWorld::Ptr& item, int count) override;
|
||||
bool onTakeItem(const MWWorld::Ptr& item, int count) override;
|
||||
|
||||
MWWorld::Ptr unstackItem(const ItemStack& item, size_t count) override;
|
||||
MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override;
|
||||
MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool allowAutoEquip = true) override;
|
||||
void removeItem(const ItemStack& item, size_t count) override;
|
||||
ModelIndex getIndex(const ItemStack& item) override;
|
||||
|
@ -2001,7 +2001,7 @@ namespace MWWorld
|
||||
item.getRefData().getLocals().setVarByInt(script, "onpcdrop", 1);
|
||||
}
|
||||
|
||||
MWWorld::Ptr World::placeObject(const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount)
|
||||
MWWorld::Ptr World::placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY, int amount, bool copy)
|
||||
{
|
||||
const float maxDist = 200.f;
|
||||
|
||||
@ -2022,7 +2022,8 @@ namespace MWWorld
|
||||
pos.rot[1] = 0;
|
||||
|
||||
// copy the object and set its count
|
||||
Ptr dropped = copyObjectToCell(object, cell, pos, amount, true);
|
||||
Ptr dropped = copy ? copyObjectToCell(object, cell, pos, amount, true)
|
||||
: moveObjectToCell(object, cell, pos, amount, true);
|
||||
|
||||
// only the player place items in the world, so no need to check actor
|
||||
PCDropped(dropped);
|
||||
@ -2062,30 +2063,65 @@ namespace MWWorld
|
||||
|
||||
MWWorld::Ptr dropped = object.getClass().copyToCell(object, *cell, pos, count);
|
||||
|
||||
addObjectToCell(dropped, cell, pos, adjustPos);
|
||||
|
||||
return dropped;
|
||||
}
|
||||
|
||||
Ptr World::moveObjectToCell(const Ptr& object, CellStore* cell, ESM::Position pos, int count, bool adjustPos)
|
||||
{
|
||||
if (!cell)
|
||||
throw std::runtime_error("moveObjectToCell(): cannot move object to null cell");
|
||||
if (cell->isExterior())
|
||||
{
|
||||
const ESM::ExteriorCellLocation index
|
||||
= ESM::positionToExteriorCellLocation(pos.pos[0], pos.pos[1], cell->getCell()->getWorldSpace());
|
||||
cell = &mWorldModel.getExterior(index);
|
||||
}
|
||||
|
||||
MWWorld::Ptr dropped = object.getClass().moveToCell(object, *cell);
|
||||
dropped.getRefData().setCount(count);
|
||||
dropped.getRefData().setPosition(pos);
|
||||
|
||||
addObjectToCell(dropped, cell, pos, adjustPos);
|
||||
|
||||
return dropped;
|
||||
}
|
||||
|
||||
void World::addObjectToCell(const Ptr& object, CellStore* cell, ESM::Position pos, bool adjustPos)
|
||||
{
|
||||
if (!cell)
|
||||
throw std::runtime_error("addObjectToCell(): cannot add object to null cell");
|
||||
if (cell->isExterior())
|
||||
{
|
||||
const ESM::ExteriorCellLocation index
|
||||
= ESM::positionToExteriorCellLocation(pos.pos[0], pos.pos[1], cell->getCell()->getWorldSpace());
|
||||
cell = &mWorldModel.getExterior(index);
|
||||
}
|
||||
|
||||
// Reset some position values that could be uninitialized if this item came from a container
|
||||
dropped.getCellRef().setPosition(pos);
|
||||
dropped.getCellRef().unsetRefNum();
|
||||
object.getCellRef().setPosition(pos);
|
||||
|
||||
if (mWorldScene->isCellActive(*cell))
|
||||
{
|
||||
if (dropped.getRefData().isEnabled())
|
||||
if (object.getRefData().isEnabled())
|
||||
{
|
||||
mWorldScene->addObjectToScene(dropped);
|
||||
mWorldScene->addObjectToScene(object);
|
||||
}
|
||||
const auto& script = dropped.getClass().getScript(dropped);
|
||||
const auto& script = object.getClass().getScript(object);
|
||||
if (!script.empty())
|
||||
{
|
||||
mLocalScripts.add(script, dropped);
|
||||
mLocalScripts.add(script, object);
|
||||
}
|
||||
addContainerScripts(dropped, cell);
|
||||
addContainerScripts(object, cell);
|
||||
}
|
||||
|
||||
if (!object.getClass().isActor() && adjustPos && dropped.getRefData().getBaseNode())
|
||||
if (!object.getClass().isActor() && adjustPos && object.getRefData().getBaseNode())
|
||||
{
|
||||
// Adjust position so the location we wanted ends up in the middle of the object bounding box
|
||||
osg::ComputeBoundsVisitor computeBounds;
|
||||
computeBounds.setTraversalMask(~MWRender::Mask_ParticleSystem);
|
||||
dropped.getRefData().getBaseNode()->accept(computeBounds);
|
||||
object.getRefData().getBaseNode()->accept(computeBounds);
|
||||
osg::BoundingBox bounds = computeBounds.getBoundingBox();
|
||||
if (bounds.valid())
|
||||
{
|
||||
@ -2096,14 +2132,12 @@ namespace MWWorld
|
||||
pos.pos[0] -= adjust.x();
|
||||
pos.pos[1] -= adjust.y();
|
||||
pos.pos[2] -= adjust.z();
|
||||
moveObject(dropped, pos.asVec3());
|
||||
moveObject(object, pos.asVec3());
|
||||
}
|
||||
}
|
||||
|
||||
return dropped;
|
||||
}
|
||||
|
||||
MWWorld::Ptr World::dropObjectOnGround(const Ptr& actor, const ConstPtr& object, int amount)
|
||||
MWWorld::Ptr World::dropObjectOnGround(const Ptr& actor, const Ptr& object, int amount, bool copy)
|
||||
{
|
||||
MWWorld::CellStore* cell = actor.getCell();
|
||||
|
||||
@ -2123,7 +2157,8 @@ namespace MWWorld
|
||||
pos.pos[2] = result.mHitPointWorld.z();
|
||||
|
||||
// copy the object and set its count
|
||||
Ptr dropped = copyObjectToCell(object, cell, pos, amount, true);
|
||||
Ptr dropped = copy ? copyObjectToCell(object, cell, pos, amount, true)
|
||||
: moveObjectToCell(object, cell, pos, amount, true);
|
||||
|
||||
if (actor == mPlayer->getPlayer()) // Only call if dropped by player
|
||||
PCDropped(dropped);
|
||||
|
@ -143,6 +143,8 @@ namespace MWWorld
|
||||
|
||||
void updateWeather(float duration, bool paused = false);
|
||||
|
||||
void addObjectToCell(const Ptr& ptr, CellStore* cell, ESM::Position pos, bool adjustPos);
|
||||
Ptr moveObjectToCell(const Ptr& ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos);
|
||||
Ptr copyObjectToCell(const ConstPtr& ptr, CellStore* cell, ESM::Position pos, int count, bool adjustPos);
|
||||
|
||||
void updateSoundListener();
|
||||
@ -425,7 +427,8 @@ namespace MWWorld
|
||||
|
||||
void updateWindowManager();
|
||||
|
||||
MWWorld::Ptr placeObject(const MWWorld::ConstPtr& object, float cursorX, float cursorY, int amount) override;
|
||||
MWWorld::Ptr placeObject(
|
||||
const MWWorld::Ptr& object, float cursorX, float cursorY, int amount, bool copy = true) override;
|
||||
///< copy and place an object into the gameworld at the specified cursor position
|
||||
/// @param object
|
||||
/// @param cursor X (relative 0-1)
|
||||
@ -433,7 +436,7 @@ namespace MWWorld
|
||||
/// @param number of objects to place
|
||||
|
||||
MWWorld::Ptr dropObjectOnGround(
|
||||
const MWWorld::Ptr& actor, const MWWorld::ConstPtr& object, int amount) override;
|
||||
const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount, bool copy = true) override;
|
||||
///< copy and place an object into the gameworld at the given actor's position
|
||||
/// @param actor giving the dropped object position
|
||||
/// @param object
|
||||
|
Loading…
x
Reference in New Issue
Block a user