diff --git a/source/UI/SlotArea.cpp b/source/UI/SlotArea.cpp index 82e87e126..ae493762a 100644 --- a/source/UI/SlotArea.cpp +++ b/source/UI/SlotArea.cpp @@ -50,15 +50,20 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA return; } - if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) + switch (a_ClickAction) { - if (!a_Player.IsDraggingItem()) + case caShiftLeftClick: + case caShiftRightClick: { ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); return; } - LOGD("Shift clicked, but the player is dragging an item: %s", ItemToFullString(a_Player.GetDraggingItem()).c_str()); - return; + + case caDblClick: + { + DblClicked(a_Player, a_SlotNum); + return; + } } cItem Slot(*GetSlot(a_SlotNum, a_Player)); @@ -182,6 +187,36 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ +void cSlotArea::DblClicked(cPlayer & a_Player, int a_SlotNum) +{ + cItem & Dragging = a_Player.GetDraggingItem(); + if (Dragging.IsEmpty()) + { + // Move the item in the dblclicked slot into hand: + Dragging = *GetSlot(a_SlotNum, a_Player); + cItem EmptyItem; + SetSlot(a_SlotNum, a_Player, EmptyItem); + } + if (Dragging.IsEmpty()) + { + LOGD("%s DblClicked with an empty hand over empty slot, ignoring", a_Player.GetName().c_str()); + return; + } + + // Add as many items from the surrounding area into hand as possible: + // First skip full stacks, then if there's still space, process full stacks as well: + if (!m_ParentWindow.CollectItemsToHand(Dragging, *this, a_Player, false)) + { + m_ParentWindow.CollectItemsToHand(Dragging, *this, a_Player, true); + } + + m_ParentWindow.BroadcastWholeWindow(); // We need to broadcast, in case the window was a chest opened by multiple players +} + + + + + void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) { for (int i = 0; i < m_NumSlots; i++) @@ -220,6 +255,39 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ +bool cSlotArea::CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks) +{ + int NumSlots = GetNumSlots(); + for (int i = 0; i < NumSlots; i++) + { + const cItem & SlotItem = *GetSlot(i, a_Player); + if (!SlotItem.IsStackableWith(a_Dragging)) + { + continue; + } + int ToMove = a_Dragging.GetMaxStackSize() - a_Dragging.m_ItemCount; + if (ToMove > SlotItem.m_ItemCount) + { + ToMove = SlotItem.m_ItemCount; + } + a_Dragging.m_ItemCount += ToMove; + cItem NewSlot(SlotItem); + NewSlot.m_ItemCount -= ToMove; + SetSlot(i, a_Player, NewSlot); + if (!NewSlot.IsEmpty()) + { + // There are leftovers in the slot, so a_Dragging must be full + return true; + } + } // for i - Slots[] + // a_Dragging may be full if there were exactly the number of items needed to fill it + return a_Dragging.IsFullStack(); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaChest: diff --git a/source/UI/SlotArea.h b/source/UI/SlotArea.h index 943452feb..4964e9986 100644 --- a/source/UI/SlotArea.h +++ b/source/UI/SlotArea.h @@ -40,9 +40,12 @@ public: /// Called when a player clicks in the window. Parameters taken from the click packet. virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem); - /// Called from Clicked if it is a valid shiftclick + /// Called from Clicked when the action is a shiftclick (left or right) virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem); + /// Called from Clicked when the action is a caDblClick + virtual void DblClicked(cPlayer & a_Player, int a_SlotNum); + /// Called when a new player opens the same parent window. The window already tracks the player. CS-locked. virtual void OnPlayerAdded(cPlayer & a_Player) {} ; @@ -57,6 +60,12 @@ public: */ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots); + /// Called on DblClicking to collect all stackable items into hand. + /// The items are accumulated in a_Dragging and removed from the slots immediately. + /// If a_CollectFullStacks is false, slots with full stacks are skipped while collecting. + /// Returns true if full stack has been collected in a_Dragging, false if there's space remaining to fill. + virtual bool CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks); + protected: int m_NumSlots; cWindow & m_ParentWindow; diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp index 1f023cb03..a09f5d682 100644 --- a/source/UI/Window.cpp +++ b/source/UI/Window.cpp @@ -386,6 +386,51 @@ void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea +bool cWindow::CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks) +{ + // First ask the slot areas from a_Area till the end of list: + bool ShouldCollect = false; + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + if (&a_Area == *itr) + { + ShouldCollect = true; + } + if (!ShouldCollect) + { + continue; + } + if ((*itr)->CollectItemsToHand(a_Dragging, a_Player, a_CollectFullStacks)) + { + // a_Dragging is full + return true; + } + } + + // a_Dragging still not full, ask slot areas before a_Area in the list: + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + if (*itr == &a_Area) + { + // All areas processed + return false; + } + if ((*itr)->CollectItemsToHand(a_Dragging, a_Player, a_CollectFullStacks)) + { + // a_Dragging is full + return true; + } + } + // Shouldn't reach here + // a_Area is expected to be part of m_SlotAreas[], so the "return false" in the loop above should have returned already + ASSERT(!"This branch should not be reached"); + return false; +} + + + + + void cWindow::SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum) { int SlotBase = 0; diff --git a/source/UI/Window.h b/source/UI/Window.h index 6927cd3ac..c44b900d7 100644 --- a/source/UI/Window.h +++ b/source/UI/Window.h @@ -156,6 +156,12 @@ public: */ void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply); + /// Called on DblClicking to collect all stackable items from all areas into hand, starting with the specified area. + /// The items are accumulated in a_Dragging and removed from the SlotAreas immediately. + /// If a_CollectFullStacks is false, slots with full stacks in the area are skipped while collecting. + /// Returns true if full stack has been collected, false if there's space remaining to fill. + bool CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks); + /// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum);