From 2127361148d4ea5531a115cc92131a3f956ca528 Mon Sep 17 00:00:00 2001
From: Andrei Karas <akaras@inbox.ru>
Date: Mon, 2 Nov 2015 18:10:42 +0300
Subject: Allow add items to npc inventory from same slot multiple times.

Added items automatically removed from inventory item amounts.
---
 src/gui/widgets/itemcontainer.cpp | 10 +++++---
 src/gui/windows/npcdialog.cpp     | 18 +++++++++++++-
 src/gui/windows/npcdialog.h       |  2 ++
 src/inventory.cpp                 | 51 +++++++++++++++++++++++++++++++++------
 src/inventory.h                   |  9 ++++++-
 5 files changed, 78 insertions(+), 12 deletions(-)

(limited to 'src')

diff --git a/src/gui/widgets/itemcontainer.cpp b/src/gui/widgets/itemcontainer.cpp
index 650911f9d..975b865d9 100644
--- a/src/gui/widgets/itemcontainer.cpp
+++ b/src/gui/widgets/itemcontainer.cpp
@@ -789,9 +789,13 @@ void ItemContainer::mouseReleased(MouseEvent &event)
             inventory = PlayerInfo::getInventory();
             if (inventory)
             {
-                mInventory->addVirtualItem(
-                    inventory->getItem(dragDrop.getTag()),
-                    getSlotByXY(event.getX(), event.getY()));
+                Item *const item = inventory->getItem(dragDrop.getTag());
+                if (mInventory->addVirtualItem(
+                    item,
+                    getSlotByXY(event.getX(), event.getY())))
+                {
+                    inventory->virtualRemove(item, 1);
+                }
             }
             return;
         }
diff --git a/src/gui/windows/npcdialog.cpp b/src/gui/windows/npcdialog.cpp
index 406e90c1a..539662f51 100644
--- a/src/gui/windows/npcdialog.cpp
+++ b/src/gui/windows/npcdialog.cpp
@@ -30,6 +30,7 @@
 #include "soundmanager.h"
 
 #include "being/being.h"
+#include "being/playerinfo.h"
 
 #include "gui/gui.h"
 #include "gui/viewport.h"
@@ -367,6 +368,7 @@ void NpcDialog::action(const ActionEvent &event)
                 }
                 case NPC_INPUT_ITEM:
                 {
+                    restoreVirtuals();
                     if (!PacketLimiter::limitPackets(
                         PacketType::PACKET_NPC_INPUT))
                     {
@@ -414,6 +416,7 @@ void NpcDialog::action(const ActionEvent &event)
                 }
                 case NPC_INPUT_ITEM_INDEX:
                 {
+                    restoreVirtuals();
                     if (!PacketLimiter::limitPackets(
                         PacketType::PACKET_NPC_INPUT))
                     {
@@ -517,6 +520,7 @@ void NpcDialog::action(const ActionEvent &event)
     }
     else if (eventId == "close")
     {
+        restoreVirtuals();
         if (mActionState == NPC_ACTION_INPUT)
         {
             switch (mInputState)
@@ -541,7 +545,12 @@ void NpcDialog::action(const ActionEvent &event)
     else if (eventId == "add")
     {
         if (inventoryWindow)
-            mInventory->addVirtualItem(inventoryWindow->getSelectedItem(), 0);
+        {
+            Item *const item = inventoryWindow->getSelectedItem();
+            Inventory *const inventory = PlayerInfo::getInventory();
+            if (mInventory->addVirtualItem(item, 0) && inventory)
+                inventory->virtualRemove(item, 1);
+        }
     }
     else if (eventId.find("skin_") == 0)
     {
@@ -1244,3 +1253,10 @@ void NpcDialog::createSkinControls()
         button->adjustSize();
     }
 }
+
+void NpcDialog::restoreVirtuals()
+{
+    Inventory *const inventory = PlayerInfo::getInventory();
+    if (inventory)
+        inventory->restoreVirtuals();
+}
diff --git a/src/gui/windows/npcdialog.h b/src/gui/windows/npcdialog.h
index ffe021bc6..584cbb6fe 100644
--- a/src/gui/windows/npcdialog.h
+++ b/src/gui/windows/npcdialog.h
@@ -248,6 +248,8 @@ class NpcDialog final : public Window,
 
         void deleteSkinControls();
 
+        void restoreVirtuals();
+
         BeingId mNpcId;
 
         int mDefaultInt;
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 61434754f..29df424e1 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -55,6 +55,7 @@ namespace
 
 Inventory::Inventory(const InventoryType::Type type, const int size1) :
     mInventoryListeners(),
+    mVirtualRemove(),
     mType(type),
     mSize(size1 == -1 ? static_cast<unsigned>(
           inventoryHandler->getSize(type))
@@ -364,18 +365,15 @@ int Inventory::findIndexByTag(const int tag) const
     return -1;
 }
 
-void Inventory::addVirtualItem(const Item *const item,
+bool Inventory::addVirtualItem(const Item *const item,
                                int index)
 {
     if (item && !PlayerInfo::isItemProtected(item->getId()))
     {
-        if (findIndexByTag(item->getInvIndex()) != -1)
-            return;
-
-        if (index >= 0 &&
-            index < static_cast<int>(mSize) &&
-            mItems[index] == nullptr)
+        if (index >= 0 && index < static_cast<int>(mSize))
         {
+            if (mItems[index] != nullptr)
+                return false;
             setItem(index,
                 item->getId(),
                 item->getType(),
@@ -401,8 +399,47 @@ void Inventory::addVirtualItem(const Item *const item,
                 Equipm_false,
                 Equipped_false);
         }
+        if (index == -1)
+            return false;
+
         Item *const item2 = getItem(index);
         if (item2)
             item2->setTag(item->getInvIndex());
+        return true;
+    }
+    return false;
+}
+
+void Inventory::virtualRemove(Item *const item,
+                              const int amount)
+{
+    if (!item || item->mQuantity < amount)
+        return;
+
+    const int index = item->getInvIndex();
+    const IntMapCIter it = mVirtualRemove.find(index);
+    if (it == mVirtualRemove.end())
+        mVirtualRemove[index] = amount;
+    else
+        mVirtualRemove[index] += amount;
+    item->mQuantity -= amount;
+}
+
+void Inventory::restoreVirtuals()
+{
+    const int sz = static_cast<int>(mSize);
+
+    logger->log("Inventory::restoreVirtuals 1");
+    FOR_EACH (IntMapCIter, it, mVirtualRemove)
+    {
+        logger->log("Inventory::restoreVirtuals 2");
+        const int index = (*it).first;
+        if (index < 0 || index >= sz)
+            continue;
+        Item *const item = mItems[index];
+        if (!item)
+            continue;
+        item->mQuantity += (*it).second;
     }
+    mVirtualRemove.clear();
 }
diff --git a/src/inventory.h b/src/inventory.h
index 1d1f49ebe..995a8ef52 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -35,6 +35,8 @@
 
 #include "enums/being/gender.h"
 
+#include "utils/intmap.h"
+
 #include <list>
 #include <string>
 
@@ -174,15 +176,20 @@ class Inventory final
 
         int findIndexByTag(const int tag) const;
 
-        void addVirtualItem(const Item *const item,
+        bool addVirtualItem(const Item *const item,
                             int index);
 
+        void virtualRemove(Item *const item,
+                           const int amount);
+
+        void restoreVirtuals();
     protected:
         typedef std::list<InventoryListener*> InventoryListenerList;
         InventoryListenerList mInventoryListeners;
 
         void distributeSlotsChangedEvent();
 
+        IntMap mVirtualRemove;
         InventoryType::Type mType;
         unsigned mSize; /**< The max number of inventory items */
         Item **mItems;  /**< The holder of items */
-- 
cgit v1.2.3-70-g09d2