diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 81fad8d48..a1244b116 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -25,6 +25,7 @@ #include "../mwmechanics/actorutil.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwmechanics/pickpocket.hpp" #include "../mwmechanics/creaturestats.hpp" @@ -303,57 +304,74 @@ namespace MWGui void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) { - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + if(mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop) + return; + + // transfer everything into the player's inventory + ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); + mModel->update(); + + // unequip all items to avoid unequipping/reequipping + if (mPtr.getClass().hasInventoryStore(mPtr)) { - // transfer everything into the player's inventory - ItemModel* playerModel = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getModel(); - mModel->update(); + MWWorld::InventoryStore& invStore = mPtr.getClass().getInventoryStore(mPtr); for (size_t i=0; igetItemCount(); ++i) { - if (i==0) - { - // play the sound of the first object - MWWorld::Ptr item = mModel->getItem(i).mBase; - std::string sound = item.getClass().getUpSoundId(item); - MWBase::Environment::get().getWindowManager()->playSound(sound); - } - const ItemStack& item = mModel->getItem(i); + if (invStore.isEquipped(item.mBase) == false) + continue; - if (!onTakeItem(item, item.mCount)) - break; + invStore.unequipItem(item.mBase, mPtr); + } + } + + mModel->update(); - mModel->moveItem(item, item.mCount, playerModel); + for (size_t i=0; igetItemCount(); ++i) + { + if (i==0) + { + // play the sound of the first object + MWWorld::Ptr item = mModel->getItem(i).mBase; + std::string sound = item.getClass().getUpSoundId(item); + MWBase::Environment::get().getWindowManager()->playSound(sound); } - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + const ItemStack& item = mModel->getItem(i); - /* - Start of tes3mp addition + if (!onTakeItem(item, item.mCount)) + break; - Send an ID_CONTAINER packet every time the Take All button is used on - a container - */ - mwmp::WorldEvent *worldEvent = mwmp::Main::get().getNetworking()->getWorldEvent(); - worldEvent->reset(); - worldEvent->cell = *mPtr.getCell()->getCell(); - worldEvent->action = mwmp::BaseEvent::SET; - - mwmp::WorldObject worldObject; - worldObject.refId = mPtr.getCellRef().getRefId(); - worldObject.refNumIndex = mPtr.getCellRef().getRefNum().mIndex; - worldObject.mpNum = mPtr.getCellRef().getMpNum(); - worldEvent->addObject(worldObject); - - mwmp::Main::get().getNetworking()->getWorldPacket(ID_CONTAINER)->setEvent(worldEvent); - mwmp::Main::get().getNetworking()->getWorldPacket(ID_CONTAINER)->Send(); - - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_CONTAINER about\n- Ptr cellRef: %s, %i\n- cell: %s", - worldObject.refId.c_str(), worldObject.refNumIndex, worldEvent->cell.getDescription().c_str()); - /* - End of tes3mp addition - */ + mModel->moveItem(item, item.mCount, playerModel); } + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + + /* + Start of tes3mp addition + + Send an ID_CONTAINER packet every time the Take All button is used on + a container + */ + mwmp::WorldEvent *worldEvent = mwmp::Main::get().getNetworking()->getWorldEvent(); + worldEvent->reset(); + worldEvent->cell = *mPtr.getCell()->getCell(); + worldEvent->action = mwmp::BaseEvent::SET; + + mwmp::WorldObject worldObject; + worldObject.refId = mPtr.getCellRef().getRefId(); + worldObject.refNumIndex = mPtr.getCellRef().getRefNum().mIndex; + worldObject.mpNum = mPtr.getCellRef().getMpNum(); + worldEvent->addObject(worldObject); + + mwmp::Main::get().getNetworking()->getWorldPacket(ID_CONTAINER)->setEvent(worldEvent); + mwmp::Main::get().getNetworking()->getWorldPacket(ID_CONTAINER)->Send(); + + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_CONTAINER about\n- Ptr cellRef: %s, %i\n- cell: %s", + worldObject.refId.c_str(), worldObject.refNumIndex, worldEvent->cell.getDescription().c_str()); + /* + End of tes3mp addition + */ } void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/inventoryitemmodel.cpp b/apps/openmw/mwgui/inventoryitemmodel.cpp index 2fe540f22..222243ec1 100644 --- a/apps/openmw/mwgui/inventoryitemmodel.cpp +++ b/apps/openmw/mwgui/inventoryitemmodel.cpp @@ -1,5 +1,10 @@ #include "inventoryitemmodel.hpp" +#include + +#include "../mwmechanics/actorutil.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" @@ -45,16 +50,33 @@ MWWorld::Ptr InventoryItemModel::copyItem (const ItemStack& item, size_t count, return *mActor.getClass().getContainerStore(mActor).add(item.mBase, count, mActor, setNewOwner); } - void InventoryItemModel::removeItem (const ItemStack& item, size_t count) { - MWWorld::ContainerStore& store = mActor.getClass().getContainerStore(mActor); - int removed = store.remove(item.mBase, count, mActor); + int removed = 0; + // Re-equipping makes sense only if a target has inventory + if (mActor.getClass().hasInventoryStore(mActor)) + { + MWWorld::InventoryStore& store = mActor.getClass().getInventoryStore(mActor); + removed = store.remove(item.mBase, count, mActor, true); + } + else + { + MWWorld::ContainerStore& store = mActor.getClass().getContainerStore(mActor); + removed = store.remove(item.mBase, count, mActor); + } + + std::stringstream error; if (removed == 0) - throw std::runtime_error("Item to remove not found in container store"); + { + error << "Item '" << item.mBase.getCellRef().getRefId() << "' was not found in container store to remove"; + throw std::runtime_error(error.str()); + } else if (removed < static_cast(count)) - throw std::runtime_error("Not enough items in the stack to remove"); + { + error << "Not enough items '" << item.mBase.getCellRef().getRefId() << "' in the stack to remove (" << static_cast(count) << " requested, " << removed << " found)"; + throw std::runtime_error(error.str()); + } } MWWorld::Ptr InventoryItemModel::moveItem(const ItemStack &item, size_t count, ItemModel *otherModel) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index c11535676..3db7d080b 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -1061,6 +1061,9 @@ namespace MWGui mGlobalMapOverlayTexture.reset(new osgMyGUI::OSGTexture(mGlobalMapRender->getOverlayTexture())); mGlobalMapOverlay->setRenderItemTexture(mGlobalMapOverlayTexture.get()); mGlobalMapOverlay->getSubWidgetMain()->_setUVSet(MyGUI::FloatRect(0.f, 0.f, 1.f, 1.f)); + + // Redraw children in proper order + mGlobalMap->getParent()->_updateChilds(); } } diff --git a/apps/openmw/mwgui/sortfilteritemmodel.cpp b/apps/openmw/mwgui/sortfilteritemmodel.cpp index 68d95fb88..45aa261df 100644 --- a/apps/openmw/mwgui/sortfilteritemmodel.cpp +++ b/apps/openmw/mwgui/sortfilteritemmodel.cpp @@ -59,15 +59,91 @@ namespace if (mSortByType && left.mType != right.mType) return left.mType < right.mType; - if (left.mBase.getTypeName() == right.mBase.getTypeName()) + float result = 0; + + // compare items by type + std::string leftName = left.mBase.getTypeName(); + std::string rightName = right.mBase.getTypeName(); + + if (leftName != rightName) + return compareType(leftName, rightName); + + // compare items by name + leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase)); + rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase)); + + result = leftName.compare(rightName); + if (result != 0) + return result < 0; + + // compare items by enchantment: + // 1. enchanted items showed before non-enchanted + // 2. item with lesser charge percent comes after items with more charge percent + // 3. item with constant effect comes before items with non-constant effects + int leftChargePercent = -1; + int rightChargePercent = -1; + leftName = left.mBase.getClass().getEnchantment(left.mBase); + rightName = right.mBase.getClass().getEnchantment(right.mBase); + + if (!leftName.empty()) { - std::string leftName = Misc::StringUtils::lowerCase(left.mBase.getClass().getName(left.mBase)); - std::string rightName = Misc::StringUtils::lowerCase(right.mBase.getClass().getName(right.mBase)); + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().search(leftName); + if (ench) + { + if (ench->mData.mType == ESM::Enchantment::ConstantEffect) + leftChargePercent = 101; + else + leftChargePercent = (left.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 + : static_cast(left.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + } + } - return leftName.compare(rightName) < 0; + if (!rightName.empty()) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get().search(rightName); + if (ench) + { + if (ench->mData.mType == ESM::Enchantment::ConstantEffect) + rightChargePercent = 101; + else + rightChargePercent = (right.mBase.getCellRef().getEnchantmentCharge() == -1) ? 100 + : static_cast(right.mBase.getCellRef().getEnchantmentCharge() / static_cast(ench->mData.mCharge) * 100); + } + } + + result = leftChargePercent - rightChargePercent; + if (result != 0) + return result > 0; + + // compare items by condition + if (left.mBase.getClass().hasItemHealth(left.mBase) && right.mBase.getClass().hasItemHealth(right.mBase)) + { + result = left.mBase.getClass().getItemHealth(left.mBase) - right.mBase.getClass().getItemHealth(right.mBase); + if (result != 0) + return result > 0; } - else - return compareType(left.mBase.getTypeName(), right.mBase.getTypeName()); + + // compare items by remaining usage time + result = left.mBase.getClass().getRemainingUsageTime(left.mBase) - right.mBase.getClass().getRemainingUsageTime(right.mBase); + if (result != 0) + return result > 0; + + // compare items by value + result = left.mBase.getClass().getValue(left.mBase) - right.mBase.getClass().getValue(right.mBase); + if (result != 0) + return result > 0; + + // compare items by weight + result = left.mBase.getClass().getWeight(left.mBase) - right.mBase.getClass().getWeight(right.mBase); + if (result != 0) + return result > 0; + + // compare items by Id + leftName = left.mBase.getCellRef().getRefId(); + rightName = right.mBase.getCellRef().getRefId(); + + result = leftName.compare(rightName); + return result < 0; } }; } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index df8f486ef..f745fbf67 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -235,6 +235,9 @@ namespace MWMechanics gem->getContainerStore()->unstack(*gem, caster); gem->getCellRef().setSoul(mCreature.getCellRef().getRefId()); + // Restack the gem with other gems with the same soul + gem->getContainerStore()->restack(*gem); + mTrapped = true; if (caster == getPlayer()) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f820d96e0..6a9a06c38 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1176,6 +1176,11 @@ bool CharacterController::updateWeaponState() priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; + + // We should not play equipping animation and sound during weapon->weapon transition + bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell && + mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell; + if(weaptype != mWeaponType && mHitState != CharState_KnockDown && mHitState != CharState_KnockOut && mHitState != CharState_Hit) { @@ -1198,13 +1203,16 @@ bool CharacterController::updateWeaponState() else { getWeaponGroup(weaptype, weapgroup); - mAnimation->showWeapons(false); mAnimation->setWeaponGroup(weapgroup); - mAnimation->play(weapgroup, priorityWeapon, - MWRender::Animation::BlendMask_All, true, - 1.0f, "equip start", "equip stop", 0.0f, 0); - mUpperBodyState = UpperCharState_EquipingWeap; + if (!isStillWeapon) + { + mAnimation->showWeapons(false); + mAnimation->play(weapgroup, priorityWeapon, + MWRender::Animation::BlendMask_All, true, + 1.0f, "equip start", "equip stop", 0.0f, 0); + mUpperBodyState = UpperCharState_EquipingWeap; + } if(isWerewolf) { @@ -1218,7 +1226,7 @@ bool CharacterController::updateWeaponState() } } - if(!soundid.empty()) + if(!soundid.empty() && !isStillWeapon) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 0c2e38db6..88372eb76 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -165,8 +165,7 @@ namespace MWScript if (::Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), item)) itemName = iter->getClass().getName(*iter); - // Actors should not equip a replacement when items are removed with RemoveItem - int numRemoved = store.remove(item, count, ptr, false); + int numRemoved = store.remove(item, count, ptr); // Spawn a messagebox (only for items removed from player's inventory) if ((numRemoved > 0) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index eef10b905..cd04a425b 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -408,13 +408,13 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addNewStack (const Cons return it; } -int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement) +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().getRefId(), itemId)) - toRemove -= remove(*iter, toRemove, actor, equipReplacement); + toRemove -= remove(*iter, toRemove, actor); flagAsModified(); @@ -422,7 +422,7 @@ int MWWorld::ContainerStore::remove(const std::string& itemId, int count, const return count - toRemove; } -int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) +int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor) { assert(this == item.getContainerStore()); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index f27ff1db9..dbb82cbda 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -142,12 +142,12 @@ namespace MWWorld ContainerStoreIterator add(const std::string& id, int count, const Ptr& actorPtr); ///< Utility to construct a ManualRef and call add(ptr, count, actorPtr, true) - int remove(const std::string& itemId, int count, const Ptr& actor, bool equipReplacement = true); + 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, bool equipReplacement = true); + 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 diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index f672aca71..8fb1dc2ab 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -678,6 +678,11 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem( return mSelectedEnchantItem; } +int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor) +{ + return remove(item, count, actor, false); +} + int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement) { int retCount = ContainerStore::remove(item, count, actor); diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index 90f7f7788..851abf408 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -177,7 +177,8 @@ namespace MWWorld virtual bool stacks (const ConstPtr& ptr1, const ConstPtr& ptr2) const; ///< @return true if the two specified objects can stack with each other - virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement = true); + virtual int remove(const Ptr& item, int count, const Ptr& actor); + virtual int remove(const Ptr& item, int count, const Ptr& actor, bool equipReplacement); ///< Remove \a count item(s) designated by \a item from this inventory. /// /// @return the number of items actually removed diff --git a/components/widgets/box.cpp b/components/widgets/box.cpp index 0ce8ce951..eeddc22dd 100644 --- a/components/widgets/box.cpp +++ b/components/widgets/box.cpp @@ -171,9 +171,11 @@ namespace Gui total_width += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } @@ -191,19 +193,19 @@ namespace Gui continue; bool vstretch = w->getUserString ("VStretch") == "true"; - int max_height = getSize().height - mPadding*2; + int max_height = getClientCoord().height - mPadding*2; int height = vstretch ? max_height : sizes[i].first.height; MyGUI::IntCoord widgetCoord; widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + widgetCoord.top = mPadding + (getClientCoord().height-mPadding*2 - height) / 2; int width = 0; if (sizes[i].second) { if (h_stretched_count == 0) throw std::logic_error("unexpected"); - width = sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count; + width = sizes[i].first.width + (getClientCoord().width-mPadding*2 - total_width)/h_stretched_count; } else width = sizes[i].first.width; @@ -317,13 +319,14 @@ namespace Gui total_height += mSpacing; } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + if (mAutoResize && (total_width+mPadding*2 != getClientCoord().width || total_height+mPadding*2 != getClientCoord().height)) { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + int xmargin = getSize().width - getClientCoord().width; + int ymargin = getSize().height - getClientCoord().height; + setSize(MyGUI::IntSize(total_width+mPadding*2 + xmargin, total_height+mPadding*2 + ymargin)); return; } - int curY = 0; for (unsigned int i = 0; i < count; ++i) { @@ -337,19 +340,19 @@ namespace Gui continue; bool hstretch = w->getUserString ("HStretch") == "true"; - int maxWidth = getSize().width - mPadding*2; + int maxWidth = getClientCoord().width - mPadding*2; int width = hstretch ? maxWidth : sizes[i].first.width; MyGUI::IntCoord widgetCoord; widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + widgetCoord.left = mPadding + (getClientCoord().width-mPadding*2 - width) / 2; int height = 0; if (sizes[i].second) { if (v_stretched_count == 0) throw std::logic_error("unexpected"); - height = sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count; + height = sizes[i].first.height + (getClientCoord().height-mPadding*2 - total_height)/v_stretched_count; } else height = sizes[i].first.height; diff --git a/files/mygui/openmw_chargen_class_description.layout b/files/mygui/openmw_chargen_class_description.layout index 43b0518fd..906ca2352 100644 --- a/files/mygui/openmw_chargen_class_description.layout +++ b/files/mygui/openmw_chargen_class_description.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_dialogue_window.layout b/files/mygui/openmw_dialogue_window.layout index a85bd5b02..1ed399572 100644 --- a/files/mygui/openmw_dialogue_window.layout +++ b/files/mygui/openmw_dialogue_window.layout @@ -4,7 +4,7 @@ - + diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index 8fe25a5dc..366b0c4c6 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -32,19 +32,19 @@ - + - + - - + + - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index e53493bb1..a1c4f608b 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -8,27 +8,27 @@ - + - + - + - + - + @@ -36,11 +36,11 @@ - + - + @@ -48,11 +48,11 @@ - + - + diff --git a/files/mygui/openmw_jail_screen.layout b/files/mygui/openmw_jail_screen.layout index ef37c73d8..76aa05b86 100644 --- a/files/mygui/openmw_jail_screen.layout +++ b/files/mygui/openmw_jail_screen.layout @@ -1,14 +1,14 @@ - + - + - + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index 89b35d05e..69df20022 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -4,13 +4,13 @@ - + - + - +