Make Drop and soulgem instruction behavior closer to vanilla (bug #4999)

pull/541/head
Capostrophic 6 years ago
parent c3cebbfaf6
commit b42f981200

@ -82,6 +82,7 @@
Bug #4984: "Friendly hits" feature should be used only for player's followers
Bug #4989: Object dimension-dependent VFX scaling behavior is inconsistent
Bug #4990: Dead bodies prevent you from hitting
Bug #4999: Drop instruction behaves differently from vanilla
Bug #5004: Werewolves shield their eyes during storm
Feature #1774: Handle AvoidNode
Feature #2229: Improve pathfinding AI

@ -15,6 +15,7 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
@ -23,6 +24,7 @@
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwmechanics/aicast.hpp"
#include "../mwmechanics/npcstats.hpp"
@ -469,6 +471,9 @@ namespace MWScript
std::string gem = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
if (!ptr.getClass().hasInventoryStore(ptr))
return;
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
store.get<ESM::Creature>().find(creature); // This line throws an exception if it can't find the creature
@ -499,7 +504,10 @@ namespace MWScript
for (unsigned int i=0; i<arg0; ++i)
runtime.pop();
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr);
if (!ptr.getClass().hasInventoryStore(ptr))
return;
MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{
if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), soul))
@ -534,16 +542,18 @@ namespace MWScript
if (amount == 0)
return;
// Prefer dropping unequipped items first; re-stack if possible by unequipping items before dropping them.
MWWorld::InventoryStore *invStorePtr = 0;
if (ptr.getClass().hasInventoryStore(ptr)) {
invStorePtr = &ptr.getClass().getInventoryStore(ptr);
if (!ptr.getClass().isActor())
return;
int numNotEquipped = invStorePtr->count(item);
if (ptr.getClass().hasInventoryStore(ptr))
{
// Prefer dropping unequipped items first; re-stack if possible by unequipping items before dropping them.
MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
int numNotEquipped = store.count(item);
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ConstContainerStoreIterator it = invStorePtr->getSlot (slot);
if (it != invStorePtr->end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item))
MWWorld::ConstContainerStoreIterator it = store.getSlot (slot);
if (it != store.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item))
{
numNotEquipped -= it->getRefData().getCount();
}
@ -551,37 +561,48 @@ namespace MWScript
for (int slot = 0; slot < MWWorld::InventoryStore::Slots && amount > numNotEquipped; ++slot)
{
MWWorld::ContainerStoreIterator it = invStorePtr->getSlot (slot);
if (it != invStorePtr->end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item))
MWWorld::ContainerStoreIterator it = store.getSlot (slot);
if (it != store.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item))
{
int numToRemove = it->getRefData().getCount();
if (numToRemove > amount - numNotEquipped)
{
numToRemove = amount - numNotEquipped;
}
invStorePtr->unequipItemQuantity(*it, ptr, numToRemove);
int numToRemove = std::min(amount - numNotEquipped, it->getRefData().getCount());
store.unequipItemQuantity(*it, ptr, numToRemove);
numNotEquipped += numToRemove;
}
}
}
int toRemove = amount;
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr);
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
{
if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)
&& (!invStorePtr || !invStorePtr->isEquipped(*iter)))
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
{
int removed = store.remove(*iter, toRemove, ptr);
MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed);
dropped.getCellRef().setOwner("");
if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item) && !store.isEquipped(*iter))
{
int removed = store.remove(*iter, amount, ptr);
MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed);
dropped.getCellRef().setOwner("");
toRemove -= removed;
amount -= removed;
if (toRemove <= 0)
break;
if (amount <= 0)
break;
}
}
}
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), item, 1);
MWWorld::Ptr itemPtr(ref.getPtr());
if (amount > 0)
{
if (itemPtr.getClass().getScript(itemPtr).empty())
{
MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, itemPtr, amount);
}
else
{
// Dropping one item per time to prevent making stacks of scripted items
for (int i = 0; i < amount; i++)
MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, itemPtr, 1);
}
}
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, itemPtr.getClass().getDownSoundId(itemPtr), 1.f, 1.f);
}
};
@ -598,8 +619,10 @@ namespace MWScript
std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::ContainerStore& store = ptr.getClass().getContainerStore (ptr);
if (!ptr.getClass().hasInventoryStore(ptr))
return;
MWWorld::InventoryStore& store = ptr.getClass().getInventoryStore(ptr);
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
{

Loading…
Cancel
Save