diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 8ae563e12..ddf841744 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -309,14 +309,19 @@ namespace MWBase virtual void update (float duration, bool paused) = 0; - virtual bool placeObject(const MWWorld::Ptr& object, float cursorX, float cursorY) = 0; - ///< place an object into the gameworld at the specified cursor position + virtual bool placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 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 /// @return true if the object was placed, or false if it was rejected because the position is too far away - virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object) = 0; + virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount) = 0; + ///< copy and place an object into the gameworld at the given actor's position + /// @param actor giving the dropped object position + /// @param object + /// @param number of objects to place virtual bool canPlaceObject (float cursorX, float cursorY) = 0; ///< @return true if it is possible to place on object at specified cursor location @@ -408,6 +413,8 @@ namespace MWBase virtual bool toggleGodMode() = 0; virtual void castSpell (const MWWorld::Ptr& actor) = 0; + + virtual void updateAnimParts(const MWWorld::Ptr& ptr) = 0; }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 6247191a9..67f79c40b 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -219,7 +219,6 @@ namespace MWClass MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell); - newPtr.getRefData ().setCount(1); newPtr.getCellRef().mGoldValue = goldAmount; } else { MWWorld::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 08683a668..2f9e63d13 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -11,6 +11,7 @@ #include "../mwworld/actiontake.hpp" #include "../mwworld/actionapply.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/player.hpp" #include "../mwworld/nullaction.hpp" @@ -164,10 +165,11 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - ptr.getRefData().setCount (ptr.getRefData().getCount()-1); - MWWorld::Ptr actor = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + // remove used potion (assume it is present in inventory) + ptr.getContainerStore()->remove(ptr, 1, actor); + boost::shared_ptr action ( new MWWorld::ActionApply (actor, ref->mBase->mId)); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index bc869e5fe..5d864752f 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -100,6 +100,9 @@ namespace MWGui finish(); targetView->update(); + + // We need to update the view since an other item could be auto-equipped. + mSourceView->update(); } void DragAndDrop::finish() diff --git a/apps/openmw/mwgui/containeritemmodel.cpp b/apps/openmw/mwgui/containeritemmodel.cpp index eff8fbcc1..6b0fbd890 100644 --- a/apps/openmw/mwgui/containeritemmodel.cpp +++ b/apps/openmw/mwgui/containeritemmodel.cpp @@ -94,9 +94,7 @@ void ContainerItemModel::removeItem (const ItemStack& item, size_t count) { if (stacks(*it, item.mBase)) { - int refCount = it->getRefData().getCount(); - it->getRefData().setCount(std::max(0, refCount - toRemove)); - toRemove -= refCount; + toRemove -= store.remove(*it, toRemove, *source); if (toRemove <= 0) return; } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index e7b9f9c01..f0843834d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -243,21 +243,16 @@ namespace MWGui float mouseX = cursorPosition.left / float(viewSize.width); float mouseY = cursorPosition.top / float(viewSize.height); - int origCount = object.getRefData().getCount(); - object.getRefData().setCount(mDragAndDrop->mDraggedCount); - if (world->canPlaceObject(mouseX, mouseY)) - world->placeObject(object, mouseX, mouseY); + world->placeObject(object, mouseX, mouseY, mDragAndDrop->mDraggedCount); else - world->dropObjectOnGround(world->getPlayer().getPlayer(), object); + world->dropObjectOnGround(world->getPlayer().getPlayer(), object, mDragAndDrop->mDraggedCount); MWBase::Environment::get().getWindowManager()->changePointer("arrow"); std::string sound = MWWorld::Class::get(object).getDownSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - object.getRefData().setCount(origCount); - // remove object from the container it was coming from mDragAndDrop->mSourceModel->removeItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount); mDragAndDrop->finish(); diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 62a5a75f0..712e1b6c6 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -52,18 +52,12 @@ void InventoryItemModel::copyItem (const ItemStack& item, size_t count) void InventoryItemModel::removeItem (const ItemStack& item, size_t count) { MWWorld::ContainerStore& store = MWWorld::Class::get(mActor).getContainerStore(mActor); + int removed = store.remove(item.mBase, count, mActor); - for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it) - { - if (*it == item.mBase) - { - if (it->getRefData().getCount() < static_cast(count)) - throw std::runtime_error("Not enough items in the stack to remove"); - it->getRefData().setCount(it->getRefData().getCount() - count); - return; - } - } - throw std::runtime_error("Item to remove not found in container store"); + if (removed == 0) + throw std::runtime_error("Item to remove not found in container store"); + else if (removed < count) + throw std::runtime_error("Not enough items in the stack to remove"); } void InventoryItemModel::update() diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 4f616b312..0ae633aa0 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -145,10 +145,38 @@ namespace MWGui const ItemStack& item = mTradeModel->getItem(index); - unequipItem(item.mBase); - MWWorld::Ptr object = item.mBase; int count = item.mCount; + + if (item.mType == ItemStack::Type_Equipped) + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + MWWorld::Ptr newStack = *invStore.unequipItem(item.mBase, mPtr); + + // The unequipped item was re-stacked. We have to update the index + // since the item pointed does not exist anymore. + if (item.mBase != newStack) + { + // newIndex will store the index of the ItemStack the item was stacked on + int newIndex = -1; + for (size_t i=0; i < mTradeModel->getItemCount(); ++i) + { + if (mTradeModel->getItem(i).mBase == newStack) + { + newIndex = i; + break; + } + } + + if (newIndex == -1) + throw std::runtime_error("Can't find restacked item"); + + index = newIndex; + object = mTradeModel->getItem(index).mBase; + } + + } + bool shift = MyGUI::InputManager::getInstance().isShiftPressed(); if (MyGUI::InputManager::getInstance().isControlPressed()) count = 1; @@ -375,27 +403,6 @@ namespace MWGui return MWWorld::Ptr(); } - void InventoryWindow::unequipItem(const MWWorld::Ptr& item) - { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - - for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) - { - MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); - if (it != invStore.end() && *it == item) - { - invStore.equip(slot, invStore.end()); - std::string script = MWWorld::Class::get(*it).getScript(*it); - - // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared - if(script != "") - (*it).getRefData().getLocals().setVarByInt(script, "onpcequip", 0); - - return; - } - } - } - void InventoryWindow::updateEncumbranceBar() { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 35140437d..78d00fd1e 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -103,7 +103,6 @@ namespace MWGui void onAvatarClicked(MyGUI::Widget* _sender); void onPinToggled(); - void unequipItem(const MWWorld::Ptr& item); void updateEncumbranceBar(); void notifyContentChanged(); }; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 94141b1a0..c17923608 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -202,30 +202,17 @@ namespace MWGui void TradeWindow::addOrRemoveGold(int amount) { - bool goldFound = false; - MWWorld::Ptr gold; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); - for (MWWorld::ContainerStoreIterator it = playerStore.begin(); - it != playerStore.end(); ++it) + if (amount > 0) { - if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) - { - goldFound = true; - gold = *it; - } - } - if (goldFound) - { - gold.getRefData().setCount(gold.getRefData().getCount() + amount); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001", amount); + playerStore.add(ref.getPtr(), player); } else { - assert(amount > 0); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001"); - ref.getPtr().getRefData().setCount(amount); - playerStore.add(ref.getPtr(), player); + playerStore.remove("gold_001", - amount, player); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 39276e964..175d33462 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -244,7 +244,7 @@ namespace MWMechanics heldIter->getClass().setRemainingUsageTime(*heldIter, timeRemaining); else { - heldIter->getRefData().setCount(0); // remove it + inventoryStore.remove(*heldIter, 1, ptr); // remove it return; } } @@ -253,7 +253,7 @@ namespace MWMechanics // Both NPC and player lights extinguish in water. if(MWBase::Environment::get().getWorld()->isSwimming(ptr)) { - heldIter->getRefData().setCount(0); // remove it + inventoryStore.remove(*heldIter, 1, ptr); // remove it // ...But, only the player makes a sound. if(isPlayer) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index adfd6d5fc..ab35dbdb1 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -240,7 +240,8 @@ void MWMechanics::Alchemy::removeIngredients() for (TIngredientsContainer::iterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) if (!iter->isEmpty()) { - iter->getRefData().setCount (iter->getRefData().getCount()-1); + iter->getContainerStore()->remove(*iter, 1, mAlchemist); + if (iter->getRefData().getCount()<1) { needsUpdate = true; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 4e26b5027..5d148d110 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -14,7 +14,6 @@ namespace MWMechanics Enchanting::Enchanting() : mCastStyle(ESM::Enchantment::CastOnce) , mSelfEnchanting(false) - , mOldItemCount(0) {} void Enchanting::setOldItem(MWWorld::Ptr oldItem) @@ -24,7 +23,6 @@ namespace MWMechanics { mObjectType = mOldItemPtr.getTypeName(); mOldItemId = mOldItemPtr.getCellRef().mRefID; - mOldItemCount = mOldItemPtr.getRefData().getCount(); } else { @@ -55,17 +53,18 @@ namespace MWMechanics bool Enchanting::create() { - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); - mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + store.remove(mSoulGemPtr, 1, player); //Exception for Azura Star, new one will be added after enchanting if(boost::iequals(mSoulGemPtr.get()->mBase->mId, "Misc_SoulGem_Azura")) { MWWorld::ManualRef azura (MWBase::Environment::get().getWorld()->getStore(), "Misc_SoulGem_Azura"); - MWWorld::Class::get (player).getContainerStore (player).add (azura.getPtr(), player); + store.add(azura.getPtr(), player); } if(mSelfEnchanting) @@ -84,16 +83,18 @@ namespace MWMechanics enchantment.mData.mCost = getEnchantPoints(); enchantment.mEffects = mEffectList; + // Create a new item + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId, 1); + const MWWorld::Ptr& newItemPtr = ref.getPtr(); + + // Apply the enchantment const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment); + MWWorld::Class::get(newItemPtr).applyEnchantment(newItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName); - MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName); + // Add the new item to player inventory and remove the old one + store.add(newItemPtr, player); + store.remove(mOldItemPtr, 1, player); - mOldItemPtr.getRefData().setCount(1); - - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); - ref.getPtr().getRefData().setCount (mOldItemCount-1); - - MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr(), player); if(!mSelfEnchanting) payForEnchantment(); @@ -299,20 +300,9 @@ namespace MWMechanics void Enchanting::payForEnchantment() const { - MWWorld::Ptr gold; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + const MWWorld::Ptr& player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); - for (MWWorld::ContainerStoreIterator it = store.begin(); - it != store.end(); ++it) - { - if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) - { - gold = *it; - } - } - - gold.getRefData().setCount(gold.getRefData().getCount() - getEnchantPrice()); + store.remove("gold_001", getEnchantPrice(), player); } } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index a25fd43ab..988ce41fc 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -22,7 +22,6 @@ namespace MWMechanics std::string mNewItemName; std::string mObjectType; std::string mOldItemId; - int mOldItemCount; public: Enchanting(); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8c13db790..54b02fb52 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -159,7 +159,7 @@ namespace MWMechanics // auto-equip again. we need this for when the race is changed to a beast race MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); for (int i=0; igetPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + + store.remove(mTool, 1, player); std::string message = MWBase::Environment::get().getWorld()->getStore().get() .find("sNotifyMessage51")->getString(); @@ -93,8 +96,6 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair) MWBase::Environment::get().getWindowManager()->messageBox((boost::format(message) % MWWorld::Class::get(mTool).getName(mTool)).str()); // try to find a new tool of the same ID - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) { diff --git a/apps/openmw/mwmechanics/security.cpp b/apps/openmw/mwmechanics/security.cpp index d19da6e2a..c373e83f5 100644 --- a/apps/openmw/mwmechanics/security.cpp +++ b/apps/openmw/mwmechanics/security.cpp @@ -2,6 +2,7 @@ #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -61,7 +62,7 @@ namespace MWMechanics lockpick.getCellRef().mCharge = lockpick.get()->mBase->mData.mUses; --lockpick.getCellRef().mCharge; if (!lockpick.getCellRef().mCharge) - lockpick.getRefData().setCount(0); + lockpick.getContainerStore()->remove(lockpick, 1, mActor); } void Security::probeTrap(const MWWorld::Ptr &trap, const MWWorld::Ptr &probe, @@ -103,7 +104,7 @@ namespace MWMechanics probe.getCellRef().mCharge = probe.get()->mBase->mData.mUses; --probe.getCellRef().mCharge; if (!probe.getCellRef().mCharge) - probe.getRefData().setCount(0); + probe.getContainerStore()->remove(probe, 1, mActor); } } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 93425191d..817a2d236 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -327,6 +327,19 @@ void RenderingManager::rebuildPtr(const MWWorld::Ptr &ptr) } } +void RenderingManager::updateAnimParts(const MWWorld::Ptr& ptr) +{ + NpcAnimation *anim = NULL; + + if(ptr.getRefData().getHandle() == "player") + anim = mPlayerAnimation; + else if(MWWorld::Class::get(ptr).isActor()) + anim = dynamic_cast(mActors.getAnimation(ptr)); + + if(anim) + anim->updateParts(); +} + void RenderingManager::update (float duration, bool paused) { MWBase::World *world = MWBase::Environment::get().getWorld(); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 2d0813912..8913e0a78 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -141,6 +141,9 @@ public: /// and equipment. void rebuildPtr(const MWWorld::Ptr &ptr); + /// Update actor model parts. + void updateAnimParts(const MWWorld::Ptr &ptr); + void update (float duration, bool paused); void setAmbientColour(const Ogre::ColourValue& colour); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 2f3ef2d79..d3ed50838 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -53,10 +53,8 @@ namespace MWScript if (count == 0) return; - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), item, count); - ref.getPtr().getRefData().setCount (count); - // Configure item's script variables std::string script = MWWorld::Class::get(ref.getPtr()).getScript(ref.getPtr()); if (script != "") @@ -136,41 +134,18 @@ namespace MWScript return; MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); - + std::string itemName = ""; - // originalCount holds the total number of items to remove, count holds the remaining number of items to remove - Interpreter::Type_Integer originalCount = count; + int numRemoved = store.remove(item, count, ptr); - for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; - ++iter) - { - if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) - { - itemName = MWWorld::Class::get(*iter).getName(*iter); - - if (iter->getRefData().getCount()<=count) - { - count -= iter->getRefData().getCount(); - iter->getRefData().setCount (0); - } - else - { - iter->getRefData().setCount (iter->getRefData().getCount()-count); - count = 0; - } - } - } - // Spawn a messagebox (only for items removed from player's inventory) - if (ptr == MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer()) + if ((numRemoved > 0) + && (ptr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer())) { // The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory std::string msgBox; - int numRemoved = (originalCount - count); - if (numRemoved == 0) - return; - + if(numRemoved > 1) { msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}"); diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 4ae1136e2..35f7a4044 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -348,9 +348,7 @@ namespace MWScript const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); store.get().find(creature); // This line throws an exception if it can't find the creature - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), gem); - - ref.getPtr().getRefData().setCount (1); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), gem, 1); ref.getPtr().getCellRef().mSoul = creature; @@ -374,18 +372,7 @@ namespace MWScript MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); - - for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) - { - if (::Misc::StringUtils::ciEqual(iter->getCellRef().mSoul, soul)) - { - if (iter->getRefData().getCount() <= 1) - iter->getRefData().setCount (0); - else - iter->getRefData().setCount (iter->getRefData().getCount() - 1); - break; - } - } + store.remove(soul, 1, ptr); } }; @@ -415,24 +402,18 @@ namespace MWScript MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); + int toRemove = amount; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter) { if (::Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) { - if(iter->getRefData().getCount() <= amount) - { - MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); - iter->getRefData().setCount(0); - } - else - { - int original = iter->getRefData().getCount(); - iter->getRefData().setCount(amount); - MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); - iter->getRefData().setCount(original - amount); - } + int removed = store.remove(*iter, toRemove, ptr); + MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, removed); - break; + toRemove -= removed; + + if (toRemove <= 0) + break; } } } @@ -458,20 +439,8 @@ namespace MWScript { if (::Misc::StringUtils::ciEqual(iter->getCellRef().mSoul, soul)) { - - if(iter->getRefData().getCount() <= 1) - { - MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); - iter->getRefData().setCount(0); - } - else - { - int original = iter->getRefData().getCount(); - iter->getRefData().setCount(1); - MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter); - iter->getRefData().setCount(original - 1); - } - + MWBase::Environment::get().getWorld()->dropObjectOnGround(ptr, *iter, 1); + store.remove(*iter, 1, ptr); break; } } @@ -541,12 +510,7 @@ namespace MWScript runtime.pop(); if (parameter == 1) - { - if (ptr.isInCell()) - MWBase::Environment::get().getWorld()->deleteObject (ptr); - else - ptr.getRefData().setCount(0); - } + MWBase::Environment::get().getWorld()->deleteObject(ptr); } }; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6246daee2..4b60f47ce 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -450,62 +450,16 @@ namespace MWScript } }; - template - class OpPlaceAtPc : public Interpreter::Opcode0 + template + class OpPlaceAt : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { - std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - - Interpreter::Type_Integer count = runtime[0].mInteger; - runtime.pop(); - Interpreter::Type_Float distance = runtime[0].mFloat; - runtime.pop(); - Interpreter::Type_Integer direction = runtime[0].mInteger; - runtime.pop(); - - if (count<0) - throw std::runtime_error ("count must be non-negative"); - - // no-op - if (count == 0) - return; - - ESM::Position ipos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition(); - Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); - Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); - if(direction == 0) pos = pos + distance*rot.yAxis(); - else if(direction == 1) pos = pos - distance*rot.yAxis(); - else if(direction == 2) pos = pos - distance*rot.xAxis(); - else if(direction == 3) pos = pos + distance*rot.xAxis(); - else throw std::runtime_error ("direction must be 0,1,2 or 3"); - - ipos.pos[0] = pos.x; - ipos.pos[1] = pos.y; - ipos.pos[2] = pos.z; - ipos.rot[0] = 0; - ipos.rot[1] = 0; - ipos.rot[2] = 0; - - MWWorld::CellStore* store = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); - ref.getPtr().getCellRef().mPos = ipos; - ref.getPtr().getRefData().setCount(count); - MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos); - } - }; - - template - class OpPlaceAtMe : public Interpreter::Opcode0 - { - public: - - virtual void execute (Interpreter::Runtime& runtime) - { - MWWorld::Ptr me = R()(runtime); + MWWorld::Ptr actor = pc + ? MWBase::Environment::get().getWorld()->getPlayer().getPlayer() + : R()(runtime); std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); @@ -524,7 +478,7 @@ namespace MWScript if (count == 0) return; - ESM::Position ipos = me.getRefData().getPosition(); + ESM::Position ipos = actor.getRefData().getPosition(); Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); if(direction == 0) pos = pos + distance*rot.yAxis(); @@ -540,12 +494,12 @@ namespace MWScript ipos.rot[1] = 0; ipos.rot[2] = 0; - MWWorld::CellStore* store = me.getCell(); - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + // create item + MWWorld::CellStore* store = actor.getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), itemID, count); ref.getPtr().getCellRef().mPos = ipos; - ref.getPtr().getRefData().setCount(count); - MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos); + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos); } }; @@ -730,9 +684,9 @@ namespace MWScript interpreter.installSegment5(Compiler::Transformation::opcodePositionCellExplicit,new OpPositionCell); interpreter.installSegment5(Compiler::Transformation::opcodePlaceItemCell,new OpPlaceItemCell); interpreter.installSegment5(Compiler::Transformation::opcodePlaceItem,new OpPlaceItem); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtPc,new OpPlaceAtPc); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMe,new OpPlaceAtMe); - interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMeExplicit,new OpPlaceAtMe); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtPc,new OpPlaceAt); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMe,new OpPlaceAt); + interpreter.installSegment5(Compiler::Transformation::opcodePlaceAtMeExplicit,new OpPlaceAt); interpreter.installSegment5(Compiler::Transformation::opcodeModScale,new OpModScale); interpreter.installSegment5(Compiler::Transformation::opcodeModScaleExplicit,new OpModScale); interpreter.installSegment5(Compiler::Transformation::opcodeRotate,new OpRotate); diff --git a/apps/openmw/mwworld/actioneat.cpp b/apps/openmw/mwworld/actioneat.cpp index 63efff738..470eeda2b 100644 --- a/apps/openmw/mwworld/actioneat.cpp +++ b/apps/openmw/mwworld/actioneat.cpp @@ -11,6 +11,8 @@ #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwworld/containerstore.hpp" + #include "esmstore.hpp" #include "class.hpp" @@ -18,8 +20,8 @@ namespace MWWorld { void ActionEat::executeImp (const Ptr& actor) { - // remove used item - getTarget().getRefData().setCount (getTarget().getRefData().getCount()-1); + // remove used item (assume the item is present in inventory) + getTarget().getContainerStore()->remove(getTarget(), 1, actor); // check for success const MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (actor).getCreatureStats (actor); diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 0f1a85dda..38033340c 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -32,10 +32,10 @@ namespace MWWorld case 0: return; case 2: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedLeft, actor); break; case 3: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, actor); break; } @@ -64,7 +64,7 @@ namespace MWWorld // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) { - invStore.equip(*slot, it); + invStore.equip(*slot, it, actor); equipped = true; break; } @@ -72,7 +72,7 @@ namespace MWWorld if (invStore.getSlot(*slot) == invStore.end()) { // slot is not occupied - invStore.equip(*slot, it); + invStore.equip(*slot, it, actor); equipped = true; break; } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index c6768f5fd..c041beffa 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -77,22 +77,31 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() return ContainerStoreIterator (this); } -bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) +bool MWWorld::ContainerStore::stacks(const Ptr& stack, const Ptr& item) { - /// \todo add current enchantment charge here when it is implemented - if ( Misc::StringUtils::ciEqual(ptr1.getCellRef().mRefID, ptr2.getCellRef().mRefID) - && MWWorld::Class::get(ptr1).getScript(ptr1) == "" // item with a script never stacks - && MWWorld::Class::get(ptr1).getEnchantment(ptr1) == "" // item with enchantment never stacks (we could revisit this later, but for now it makes selecting items in the spell window much easier) - && ptr1.getCellRef().mOwner == ptr2.getCellRef().mOwner - && ptr1.getCellRef().mSoul == ptr2.getCellRef().mSoul - // item that is already partly used up never stacks - && (!MWWorld::Class::get(ptr1).hasItemHealth(ptr1) || ptr1.getCellRef().mCharge == -1 - || MWWorld::Class::get(ptr1).getItemMaxHealth(ptr1) == ptr1.getCellRef().mCharge) - && (!MWWorld::Class::get(ptr2).hasItemHealth(ptr2) || ptr2.getCellRef().mCharge == -1 - || MWWorld::Class::get(ptr2).getItemMaxHealth(ptr2) == ptr2.getCellRef().mCharge)) - return true; + const MWWorld::Class& cls1 = MWWorld::Class::get(stack); + const MWWorld::Class& cls2 = MWWorld::Class::get(item); - return false; + /// \todo add current enchantment charge here when it is implemented + return stack != item // an item never stacks onto itself + && Misc::StringUtils::ciEqual(stack.getCellRef().mRefID, item.getCellRef().mRefID) + && stack.getCellRef().mOwner == item.getCellRef().mOwner + && stack.getCellRef().mSoul == item.getCellRef().mSoul + + // item with a script never stacks + && cls1.getScript(stack) == "" + && cls2.getScript(item) == "" + + // item with enchantment never stacks (we could revisit this later, + // but for now it makes selecting items in the spell window much easier) + && cls1.getEnchantment(stack) == "" + && cls2.getEnchantment(item) == "" + + // item that is already partly used up never stacks + && (!cls1.hasItemHealth(stack) || stack.getCellRef().mCharge == -1 + || cls1.getItemMaxHealth(stack) == stack.getCellRef().mCharge) + && (!cls2.hasItemHealth(item) || item.getCellRef().mCharge == -1 + || cls2.getItemMaxHealth(item) == item.getCellRef().mCharge); } MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr, const Ptr& actorPtr) @@ -140,22 +149,20 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100")) { - MWWorld::ManualRef ref(esmStore, "Gold_001"); - int count = MWWorld::Class::get(ptr).getValue(ptr) * ptr.getRefData().getCount(); - ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { if (Misc::StringUtils::ciEqual((*iter).get()->mRef.mRefID, "gold_001")) { - (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); + iter->getRefData().setCount(iter->getRefData().getCount() + count); flagAsModified(); return iter; } } - return addImpl(ref.getPtr()); + MWWorld::ManualRef ref(esmStore, "Gold_001", count); + return addNewStack(ref.getPtr()); } // determine whether to stack or not @@ -171,10 +178,10 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) } } // if we got here, this means no stacking - return addImpl(ptr); + return addNewStack(ptr); } -MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Ptr& ptr) { ContainerStoreIterator it = begin(); @@ -198,6 +205,40 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr return it; } +int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor) +{ + int toRemove = count; + + for (ContainerStoreIterator iter(begin()); iter != end() && toRemove > 0; ++iter) + if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, itemId)) + toRemove -= remove(*iter, toRemove, actor); + + // number of removed items + return count - toRemove; +} + +int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor) +{ + assert(this == item.getContainerStore()); + + int toRemove = count; + RefData& itemRef = item.getRefData(); + + if (itemRef.getCount() <= toRemove) + { + toRemove -= itemRef.getCount(); + itemRef.setCount(0); + } + else + { + itemRef.setCount(itemRef.getCount() - toRemove); + toRemove = 0; + } + + // number of removed items + return count - toRemove; +} + void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const MWWorld::ESMStore& store) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); @@ -216,7 +257,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: try { - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id, count); if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { @@ -266,7 +307,6 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: } else { - ref.getPtr().getRefData().setCount (count); ref.getPtr().getCellRef().mOwner = owner; addImp (ref.getPtr()); } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 9a11f1603..2cdefd2f4 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -75,14 +75,25 @@ namespace MWWorld /// /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. + int remove(const std::string& itemId, int count, const Ptr& actor); + ///< Remove \a count item(s) designated by \a itemId from this container. + /// + /// @return the number of items actually removed + + virtual int remove(const Ptr& item, int count, const Ptr& actor); + ///< Remove \a count item(s) designated by \a item from this inventory. + /// + /// @return the number of items actually removed + protected: - ContainerStoreIterator addImpl (const Ptr& ptr); - ///< Add the item to this container (no stacking) + ContainerStoreIterator addNewStack (const Ptr& ptr); + ///< Add the item to this container (do not try to stack it onto existing items) public: - virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); + virtual bool stacks (const Ptr& stack, const Ptr& item); ///< @return true if the two specified objects can stack with each other + /// @note stack is the item that is already in this container void fill (const ESM::InventoryList& items, const std::string& owner, const MWWorld::ESMStore& store); ///< Insert items into *this. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 98cb6d347..dc2d0cab1 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -8,6 +8,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwmechanics/npcstats.hpp" @@ -40,6 +41,7 @@ void MWWorld::InventoryStore::initSlots (TSlots& slots) MWWorld::InventoryStore::InventoryStore() : mMagicEffectsUpToDate (false) , mSelectedEnchantItem(end()) + , mActorModelUpdateEnabled (true) { initSlots (mSlots); } @@ -80,7 +82,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, return retVal; } -void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& iterator) +void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& iterator, const Ptr& actor) { if (slot<0 || slot>=static_cast (mSlots.size())) throw std::runtime_error ("slot number out of range"); @@ -97,19 +99,8 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite throw std::runtime_error ("invalid slot"); } - // restack item previously in this slot (if required) if (mSlots[slot] != end()) - { - for (MWWorld::ContainerStoreIterator iter (begin()); iter!=end(); ++iter) - { - if (stacks(*iter, *mSlots[slot])) - { - iter->getRefData().setCount( iter->getRefData().getCount() + mSlots[slot]->getRefData().getCount() ); - mSlots[slot]->getRefData().setCount(0); - break; - } - } - } + unequipSlot(slot, actor); // unstack item pointed to by iterator if required if (iterator!=end() && !slots.second && iterator->getRefData().getCount() > 1) // if slots.second is true, item can stay stacked when equipped @@ -117,30 +108,21 @@ void MWWorld::InventoryStore::equip (int slot, const ContainerStoreIterator& ite // add the item again with a count of count-1, then set the count of the original (that will be equipped) to 1 int count = iterator->getRefData().getCount(); iterator->getRefData().setCount(count-1); - addImpl(*iterator); + addNewStack(*iterator); iterator->getRefData().setCount(1); } mSlots[slot] = iterator; flagAsModified(); + + updateActorModel(actor); } void MWWorld::InventoryStore::unequipAll(const MWWorld::Ptr& actor) { for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) - { - MWWorld::ContainerStoreIterator it = getSlot(slot); - if (it != end()) - { - equip(slot, end()); - std::string script = MWWorld::Class::get(*it).getScript(*it); - - // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared - if((actor.getRefData().getHandle() == "player") && (script != "")) - (*it).getRefData().getLocals().setVarByInt(script, "onpcequip", 0); - } - } + unequipSlot(slot, actor); } MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) @@ -169,6 +151,9 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) TSlots slots; initSlots (slots); + // Disable model update during auto-equip + mActorModelUpdateEnabled = false; + for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) { Ptr test = *iter; @@ -224,10 +209,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) case 0: continue; case 2: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedLeft, npc); break; case 3: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, npc); break; } @@ -239,7 +224,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) // add the item again with a count of count-1, then set the count of the original (that will be equipped) to 1 int count = iter->getRefData().getCount(); iter->getRefData().setCount(count-1); - addImpl(*iter); + addNewStack(*iter); iter->getRefData().setCount(1); } } @@ -257,9 +242,12 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) changed = true; } + mActorModelUpdateEnabled = true; + if (changed) { mSlots.swap (slots); + updateActorModel(npc); flagAsModified(); } } @@ -297,20 +285,22 @@ void MWWorld::InventoryStore::flagAsModified() mMagicEffectsUpToDate = false; } -bool MWWorld::InventoryStore::stacks(const Ptr& ptr1, const Ptr& ptr2) +bool MWWorld::InventoryStore::stacks(const Ptr& stack, const Ptr& item) { - bool canStack = MWWorld::ContainerStore::stacks(ptr1, ptr2); + bool canStack = MWWorld::ContainerStore::stacks(stack, item); if (!canStack) return false; - // don't stack if the item being checked against is currently equipped. + // don't stack if 'stack' (the item being checked against) is currently equipped. for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter) { - if (*iter != end() && ptr1 == **iter) - return false; - if (*iter != end() && ptr2 == **iter) - return false; + if (*iter != end() && stack == **iter) + { + bool stackWhenEquipped = MWWorld::Class::get(**iter).getEquipmentSlots(**iter).second; + if (!stackWhenEquipped) + return false; + } } return true; @@ -325,3 +315,105 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem( { return mSelectedEnchantItem; } + +int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor) +{ + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + if (mSlots[slot] == end()) + continue; + + if (*mSlots[slot] == item) + { + // restacking is disabled cause it may break removal + unequipSlot(slot, actor, false); + break; + } + } + + int retCount = ContainerStore::remove(item, count, actor); + + // If an armor/clothing item is removed, try to find a replacement, + // but not for the player nor werewolves. + if ((actor.getRefData().getHandle() != "player") + && !(MWWorld::Class::get(actor).getNpcStats(actor).isWerewolf())) + { + std::string type = item.getTypeName(); + if ((type == typeid(ESM::Armor).name()) || (type == typeid(ESM::Clothing).name())) + autoEquip(actor); + } + + return retCount; +} + +MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, const MWWorld::Ptr& actor, bool restack) +{ + ContainerStoreIterator it = getSlot(slot); + + if (it != end()) + { + ContainerStoreIterator retval = it; + + if (restack) { + // restack item previously in this slot + for (MWWorld::ContainerStoreIterator iter (begin()); iter != end(); ++iter) + { + if (stacks(*iter, *it)) + { + iter->getRefData().setCount(iter->getRefData().getCount() + it->getRefData().getCount()); + it->getRefData().setCount(0); + retval = iter; + break; + } + } + } + + // empty this slot + mSlots[slot] = end(); + + if (actor.getRefData().getHandle() == "player") + { + // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared + const std::string& script = Class::get(*it).getScript(*it); + if (script != "") + (*it).getRefData().getLocals().setVarByInt(script, "onpcequip", 0); + + // Update HUD icon when removing player weapon or selected enchanted item. + // We have to check for both as the weapon could also be the enchanted item. + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) + { + // weapon + MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon(); + } + if ((mSelectedEnchantItem != end()) && (mSelectedEnchantItem == it)) + { + // enchanted item + MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); + } + } + + updateActorModel(actor); + + return retval; + } + + return it; +} + +MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipItem(const MWWorld::Ptr& item, const MWWorld::Ptr& actor) +{ + for (int slot=0; slotupdateAnimParts(actor); +} diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index f0cba0f9f..c4ad51777 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -45,6 +45,7 @@ namespace MWWorld mutable MWMechanics::MagicEffects mMagicEffects; mutable bool mMagicEffectsUpToDate; + bool mActorModelUpdateEnabled; typedef std::vector TSlots; @@ -57,6 +58,8 @@ namespace MWWorld void initSlots (TSlots& slots); + void updateActorModel (const Ptr& actor); + public: InventoryStore(); @@ -76,7 +79,7 @@ namespace MWWorld /// /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. - void equip (int slot, const ContainerStoreIterator& iterator); + void equip (int slot, const ContainerStoreIterator& iterator, const Ptr& actor); ///< \note \a iterator can be an end-iterator void setSelectedEnchantItem(const ContainerStoreIterator& iterator); @@ -104,10 +107,29 @@ namespace MWWorld ///< \attention This function is internal to the world model and should not be called from /// outside. - virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); + virtual bool stacks (const Ptr& stack, const Ptr& item); ///< @return true if the two specified objects can stack with each other - /// @note ptr1 is the item that is already in this container + /// @note stack is the item that is already in this container (it may be equipped) + virtual int remove(const Ptr& item, int count, const Ptr& actor); + ///< Remove \a count item(s) designated by \a item from this inventory. + /// + /// @return the number of items actually removed + + ContainerStoreIterator unequipSlot(int slot, const Ptr& actor, bool restack = true); + ///< Unequip \a slot. + /// + /// @return an iterator to the item that was previously in the slot + /// (if \a restack is true, the item can be re-stacked so its count + /// may differ from when it was equipped). + + ContainerStoreIterator unequipItem(const Ptr& item, const Ptr& actor); + ///< Unequip an item identified by its Ptr. An exception is thrown + /// if the item is not currently equipped. + /// + /// @return an iterator to the item that was previously in the slot + /// (it can be re-stacked so its count may be different than when it + /// was equipped). }; } diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 6616165fa..1cdcd8484 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -37,7 +37,7 @@ namespace MWWorld public: - ManualRef (const MWWorld::ESMStore& store, const std::string& name) + ManualRef (const MWWorld::ESMStore& store, const std::string& name, const int count=1) { // create if (!create (store.get(), name) && @@ -74,6 +74,7 @@ namespace MWWorld cellRef.mTeleport = false; cellRef.mLockLevel = 0; cellRef.mReferenceBlocked = 0; + mPtr.getRefData().setCount(count); } const Ptr& getPtr() const diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 642f5412c..d5701efc5 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -73,6 +73,11 @@ namespace MWWorld void setLocals (const ESM::Script& script); void setCount (int count); + /// Set object count (an object pile is a simple object with a count >1). + /// + /// \warning Do not call setCount() to add or remove objects from a + /// container or an actor's inventory. Call ContainerStore::add() or + /// ContainerStore::remove() instead. MWScript::Locals& getLocals(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 3ea9f7282..be71bebee 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -837,12 +837,13 @@ namespace MWWorld void World::deleteObject (const Ptr& ptr) { - if (ptr.getRefData().getCount()>0) + if (ptr.getRefData().getCount() > 0) { - ptr.getRefData().setCount (0); + ptr.getRefData().setCount(0); - if (mWorldScene->getActiveCells().find (ptr.getCell())!=mWorldScene->getActiveCells().end() && - ptr.getRefData().isEnabled()) + if (ptr.isInCell() + && mWorldScene->getActiveCells().find(ptr.getCell()) != mWorldScene->getActiveCells().end() + && ptr.getRefData().isEnabled()) { mWorldScene->removeObjectFromScene (ptr); mLocalScripts.remove (ptr); @@ -1477,7 +1478,7 @@ namespace MWWorld item.getRefData().getLocals().setVarByInt(script, "onpcdrop", 1); } - bool World::placeObject (const Ptr& object, float cursorX, float cursorY) + bool World::placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) { std::pair result = mPhysics->castRay(cursorX, cursorY); @@ -1502,9 +1503,14 @@ namespace MWWorld pos.rot[0] = 0; pos.rot[1] = 0; + // copy the object and set its count + int origCount = object.getRefData().getCount(); + object.getRefData().setCount(amount); Ptr dropped = copyObjectToCell(object, *cell, pos); + object.getRefData().setCount(origCount); + + // only the player place items in the world, so no need to check actor PCDropped(dropped); - object.getRefData().setCount(0); return true; } @@ -1549,7 +1555,7 @@ namespace MWWorld return dropped; } - void World::dropObjectOnGround (const Ptr& actor, const Ptr& object) + void World::dropObjectOnGround (const Ptr& actor, const Ptr& object, int amount) { MWWorld::Ptr::CellStore* cell = actor.getCell(); @@ -1570,10 +1576,14 @@ namespace MWWorld mPhysics->castRay(orig, dir, len); pos.pos[2] = hit.second.z; + // copy the object and set its count + int origCount = object.getRefData().getCount(); + object.getRefData().setCount(amount); Ptr dropped = copyObjectToCell(object, *cell, pos); + object.getRefData().setCount(origCount); + if(actor == mPlayer->getPlayer()) // Only call if dropped by player PCDropped(dropped); - object.getRefData().setCount(0); } void World::processChangedSettings(const Settings::CategorySettingVector& settings) @@ -1939,7 +1949,6 @@ namespace MWWorld if(werewolf) { ManualRef ref(getStore(), "WerewolfRobe"); - ref.getPtr().getRefData().setCount(1); // Configure item's script variables std::string script = Class::get(ref.getPtr()).getScript(ref.getPtr()); @@ -1951,18 +1960,11 @@ namespace MWWorld // Not sure this is right InventoryStore &inv = Class::get(actor).getInventoryStore(actor); - inv.equip(InventoryStore::Slot_Robe, inv.add(ref.getPtr(), actor)); + inv.equip(InventoryStore::Slot_Robe, inv.add(ref.getPtr(), actor), actor); } else { - ContainerStore &store = Class::get(actor).getContainerStore(actor); - - const std::string item = "WerewolfRobe"; - for(ContainerStoreIterator iter(store.begin());iter != store.end();++iter) - { - if(Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) - iter->getRefData().setCount(0); - } + Class::get(actor).getContainerStore(actor).remove("WerewolfRobe", 1, actor); } if(actor.getRefData().getHandle() == "player") @@ -2133,4 +2135,9 @@ namespace MWWorld // TODO: RT_Range, RT_Touch } } + + void World::updateAnimParts(const Ptr& actor) + { + mRendering->updateAnimParts(actor); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 49f26998d..602d8d5e7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -354,14 +354,19 @@ namespace MWWorld virtual void update (float duration, bool paused); - virtual bool placeObject (const Ptr& object, float cursorX, float cursorY); - ///< place an object into the gameworld at the specified cursor position + virtual bool placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount); + ///< 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 /// @return true if the object was placed, or false if it was rejected because the position is too far away - virtual void dropObjectOnGround (const Ptr& actor, const Ptr& object); + virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount); + ///< copy and place an object into the gameworld at the given actor's position + /// @param actor giving the dropped object position + /// @param object + /// @param number of objects to place virtual bool canPlaceObject(float cursorX, float cursorY); ///< @return true if it is possible to place on object at specified cursor location @@ -468,6 +473,8 @@ namespace MWWorld virtual bool toggleGodMode(); virtual void castSpell (const MWWorld::Ptr& actor); + + virtual void updateAnimParts(const MWWorld::Ptr& ptr); }; }