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

@ -15,6 +15,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/scriptmanager.hpp" #include "../mwbase/scriptmanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -23,6 +24,7 @@
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwmechanics/aicast.hpp" #include "../mwmechanics/aicast.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
@ -469,6 +471,9 @@ namespace MWScript
std::string gem = runtime.getStringLiteral (runtime[0].mInteger); std::string gem = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
if (!ptr.getClass().hasInventoryStore(ptr))
return;
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); 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 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) for (unsigned int i=0; i<arg0; ++i)
runtime.pop(); 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) for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
{ {
if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), soul)) if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), soul))
@ -534,16 +542,18 @@ namespace MWScript
if (amount == 0) if (amount == 0)
return; return;
// Prefer dropping unequipped items first; re-stack if possible by unequipping items before dropping them. if (!ptr.getClass().isActor())
MWWorld::InventoryStore *invStorePtr = 0; return;
if (ptr.getClass().hasInventoryStore(ptr)) {
invStorePtr = &ptr.getClass().getInventoryStore(ptr);
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) for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{ {
MWWorld::ConstContainerStoreIterator it = invStorePtr->getSlot (slot); MWWorld::ConstContainerStoreIterator it = store.getSlot (slot);
if (it != invStorePtr->end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) if (it != store.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item))
{ {
numNotEquipped -= it->getRefData().getCount(); numNotEquipped -= it->getRefData().getCount();
} }
@ -551,37 +561,48 @@ namespace MWScript
for (int slot = 0; slot < MWWorld::InventoryStore::Slots && amount > numNotEquipped; ++slot) for (int slot = 0; slot < MWWorld::InventoryStore::Slots && amount > numNotEquipped; ++slot)
{ {
MWWorld::ContainerStoreIterator it = invStorePtr->getSlot (slot); MWWorld::ContainerStoreIterator it = store.getSlot (slot);
if (it != invStorePtr->end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) if (it != store.end() && ::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item))
{ {
int numToRemove = it->getRefData().getCount(); int numToRemove = std::min(amount - numNotEquipped, it->getRefData().getCount());
if (numToRemove > amount - numNotEquipped) store.unequipItemQuantity(*it, ptr, numToRemove);
{
numToRemove = amount - numNotEquipped;
}
invStorePtr->unequipItemQuantity(*it, ptr, numToRemove);
numNotEquipped += numToRemove; numNotEquipped += numToRemove;
} }
} }
}
int toRemove = amount; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
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)))
{ {
int removed = store.remove(*iter, toRemove, ptr); if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item) && !store.isEquipped(*iter))
MWWorld::Ptr dropped = MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); {
dropped.getCellRef().setOwner(""); 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) if (amount <= 0)
break; 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); std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); 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) for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
{ {

Loading…
Cancel
Save