diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index 112aa8146..fe46ed770 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -291,6 +291,23 @@ const cFurnaceRecipe::cRecipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_In +bool cFurnaceRecipe::IsFuel(const cItem & a_Item) const +{ + for (FuelList::const_iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr) + { + const cFuel & Fuel = *itr; + if ((Fuel.In->m_ItemType == a_Item.m_ItemType) && (Fuel.In->m_ItemCount <= a_Item.m_ItemCount)) + { + return true; + } + } + return false; +} + + + + + int cFurnaceRecipe::GetBurnTime(const cItem & a_Fuel) const { int BestFuel = 0; diff --git a/src/FurnaceRecipe.h b/src/FurnaceRecipe.h index 936ef706d..912b6aba2 100644 --- a/src/FurnaceRecipe.h +++ b/src/FurnaceRecipe.h @@ -34,6 +34,9 @@ public: /** Returns a recipe for the specified input, nullptr if no recipe found */ const cRecipe * GetRecipeFrom(const cItem & a_Ingredient) const; + + /** Returns true if the item is a fuel, false if not. */ + bool IsFuel(const cItem & a_Item) const; /** Returns the amount of time that the specified fuel burns, in ticks */ int GetBurnTime(const cItem & a_Fuel) const; diff --git a/src/UI/AnvilWindow.h b/src/UI/AnvilWindow.h index 97dd792d3..fd5c77871 100644 --- a/src/UI/AnvilWindow.h +++ b/src/UI/AnvilWindow.h @@ -55,6 +55,24 @@ public: a_PosZ = m_BlockZ; } + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Anvil Slot + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + } + else + { + // Inventory or Hotbar + AreasInOrder.push_back(m_SlotAreas[0]); /* Anvil */ + } + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + protected: cSlotAreaAnvil * m_AnvilSlotArea; AString m_RepairedItemName; diff --git a/src/UI/BeaconWindow.h b/src/UI/BeaconWindow.h index 0ea5a7e6a..a2ec50f02 100644 --- a/src/UI/BeaconWindow.h +++ b/src/UI/BeaconWindow.h @@ -26,14 +26,48 @@ public: cWindow(wtBeacon, "Beacon"), m_Beacon(a_Beacon) { - m_ShouldDistributeToHotbarFirst = true; m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); } + cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; } + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Beacon Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + if (cSlotAreaBeacon::IsPlaceableItem(a_ItemStack.m_ItemType) && (a_ItemStack.m_ItemCount == 1)) + { + AreasInOrder.push_back(m_SlotAreas[0]); /* Beacon */ + } + + if (a_ClickedArea == m_SlotAreas[1]) + { + // Inventory Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + } + else + { + // Hotbar Area + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + } + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } + + // cWindow Overrides: virtual void OpenedByPlayer(cPlayer & a_Player) override { diff --git a/src/UI/ChestWindow.h b/src/UI/ChestWindow.h index f4f5e8f29..852ec28ef 100644 --- a/src/UI/ChestWindow.h +++ b/src/UI/ChestWindow.h @@ -56,8 +56,6 @@ public: m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); - m_ShouldDistributeToHotbarFirst = false; - // Play the opening sound: m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); @@ -109,6 +107,25 @@ public: cWindow::OpenedByPlayer(a_Player); } + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Chest Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Hotbar or Inventory + AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } protected: cWorld * m_World; diff --git a/src/UI/CraftingWindow.h b/src/UI/CraftingWindow.h index 9107d8d08..f5a0328f2 100644 --- a/src/UI/CraftingWindow.h +++ b/src/UI/CraftingWindow.h @@ -28,6 +28,41 @@ public: m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); } + + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Crafting Area + if (a_Slot == 0) + { + // Result Slot + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + } + else + { + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + } + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, (a_Slot == 0)); + } + else if (a_ClickedArea == m_SlotAreas[1]) + { + // Inventory Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + else + { + // Hotbar + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } }; diff --git a/src/UI/DropSpenserWindow.h b/src/UI/DropSpenserWindow.h index 7602a4d25..ef8e2d0cd 100644 --- a/src/UI/DropSpenserWindow.h +++ b/src/UI/DropSpenserWindow.h @@ -25,11 +25,30 @@ public: cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) : cWindow(wtDropSpenser, (a_DropSpenser->GetBlockType() == E_BLOCK_DISPENSER) ? "Dispenser" : "Dropper") { - m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); } + + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // DropSpenser Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Inventory or Hotbar + AreasInOrder.push_back(m_SlotAreas[0]); /* DropSpenser */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } }; diff --git a/src/UI/EnchantingWindow.h b/src/UI/EnchantingWindow.h index 9e42c1f4f..a6386ffe2 100644 --- a/src/UI/EnchantingWindow.h +++ b/src/UI/EnchantingWindow.h @@ -70,6 +70,25 @@ public: return m_PropertyValue[a_Property]; } + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Enchanting Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Inventory or Hotbar + AreasInOrder.push_back(m_SlotAreas[0]); /* Enchanting */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } + cSlotArea * m_SlotArea; protected: diff --git a/src/UI/EnderChestWindow.h b/src/UI/EnderChestWindow.h index 597fab9f9..4c7dd2495 100644 --- a/src/UI/EnderChestWindow.h +++ b/src/UI/EnderChestWindow.h @@ -29,7 +29,6 @@ public: m_BlockY(a_EnderChest->GetPosY()), m_BlockZ(a_EnderChest->GetPosZ()) { - m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaEnderChest(a_EnderChest, *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); @@ -50,6 +49,25 @@ public: m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1); } + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Chest Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Hotbar or Inventory + AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } + protected: cWorld * m_World; int m_BlockX, m_BlockY, m_BlockZ; // Position of the enderchest, for the window-close packet diff --git a/src/UI/FurnaceWindow.h b/src/UI/FurnaceWindow.h index a40bd05bd..fb0a50656 100644 --- a/src/UI/FurnaceWindow.h +++ b/src/UI/FurnaceWindow.h @@ -10,6 +10,7 @@ #pragma once #include "Window.h" +#include "../Root.h" @@ -24,11 +25,55 @@ public: cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) : cWindow(wtFurnace, "Furnace") { - m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); } + + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Furnace Area + if (a_Slot == 2) + { + // Result Slot + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Furnace Input/Fuel Slot + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } + else + { + cFurnaceRecipe * FurnaceRecipes = cRoot::Get()->GetFurnaceRecipe(); + if ((FurnaceRecipes->GetRecipeFrom(a_ItemStack) != nullptr) || (FurnaceRecipes->IsFuel(a_ItemStack))) + { + // The item is a valid input item or fuel + AreasInOrder.push_back(m_SlotAreas[0]); /* Furnace Area */ + } + else if (a_ClickedArea == m_SlotAreas[1]) + { + // Inventory Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + } + else + { + // Hotbar Area + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + } + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } }; diff --git a/src/UI/HopperWindow.h b/src/UI/HopperWindow.h index 5c3aa3874..4aa03c605 100644 --- a/src/UI/HopperWindow.h +++ b/src/UI/HopperWindow.h @@ -25,11 +25,30 @@ public: cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) : super(wtHopper, "Hopper") { - m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaItemGrid(a_Hopper->GetContents(), *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); } + + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Hopper Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true); + } + else + { + // Inventory or Hotbar + AreasInOrder.push_back(m_SlotAreas[0]); /* Hopper */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } }; diff --git a/src/UI/InventoryWindow.h b/src/UI/InventoryWindow.h index af44dec98..a6ea7c793 100644 --- a/src/UI/InventoryWindow.h +++ b/src/UI/InventoryWindow.h @@ -30,6 +30,50 @@ public: m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); } + + + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override + { + cSlotAreas AreasInOrder; + + if (a_ClickedArea == m_SlotAreas[0]) + { + // Crafting Area + if (a_Slot == 0) + { + // Result Slot + AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */ + } + else + { + AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */ + } + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, (a_Slot == 0)); + } + else if (a_ClickedArea == m_SlotAreas[1]) + { + // Armor Area + AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */ + AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + else if (a_ClickedArea == m_SlotAreas[2]) + { + // Inventory Area + AreasInOrder.push_back(m_SlotAreas[1]); /* Armor */ + AreasInOrder.push_back(m_SlotAreas[3]); /* Hotbar */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + else + { + // Hotbar + AreasInOrder.push_back(m_SlotAreas[1]); /* Armor */ + AreasInOrder.push_back(m_SlotAreas[2]); /* Inventory */ + super::DistributeStack(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false); + } + } protected: cPlayer & m_Player; diff --git a/src/UI/MinecartWithChestWindow.h b/src/UI/MinecartWithChestWindow.h index bf136a43d..57e9beedf 100644 --- a/src/UI/MinecartWithChestWindow.h +++ b/src/UI/MinecartWithChestWindow.h @@ -26,7 +26,6 @@ public: cWindow(wtChest, "Minecart with Chest"), m_ChestCart(a_ChestCart) { - m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaMinecartWithChest(a_ChestCart, *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 6d810ce9b..37683a8e5 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -207,7 +207,7 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ { // Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover: cItem Slot(*GetSlot(a_SlotNum, a_Player)); - m_ParentWindow.DistributeStack(Slot, a_Player, this, true); + m_ParentWindow.DistributeStack(Slot, a_SlotNum, a_Player, this, true); if (Slot.IsEmpty()) { // Empty the slot completely, the client doesn't like left-over ItemType with zero count @@ -342,31 +342,31 @@ void cSlotArea::OnPlayerRemoved(cPlayer & a_Player) -void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { for (int i = 0; i < m_NumSlots; i++) { - const cItem * Slot = GetSlot(i, a_Player); + int SlotNum = (a_BackFill) ? (m_NumSlots - 1 - i) : i; + + const cItem * Slot = GetSlot(SlotNum, a_Player); if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) { // Different items continue; } - int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; + char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; if (NumFit <= 0) { // Full stack already continue; } - if (NumFit > a_ItemStack.m_ItemCount) - { - NumFit = a_ItemStack.m_ItemCount; - } + NumFit = std::min(NumFit, a_ItemStack.m_ItemCount); + if (a_ShouldApply) { cItem NewSlot(a_ItemStack); NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; - SetSlot(i, a_Player, NewSlot); + SetSlot(SlotNum, a_Player, NewSlot); } a_ItemStack.m_ItemCount -= NumFit; if (a_ItemStack.IsEmpty()) @@ -591,12 +591,13 @@ void cSlotAreaCrafting::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & -void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaCrafting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { UNUSED(a_ItemStack); UNUSED(a_Player); UNUSED(a_ShouldApply); UNUSED(a_KeepEmptySlots); + UNUSED(a_BackFill); } @@ -658,7 +659,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player) { // Try distributing the result. If it fails, bail out: cItem ResultCopy(Result); - m_ParentWindow.DistributeStack(ResultCopy, a_Player, this, false); + m_ParentWindow.DistributeStack(ResultCopy, 0, a_Player, this, false); if (!ResultCopy.IsEmpty()) { // Couldn't distribute all of it. Bail out @@ -667,7 +668,7 @@ void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player) // Distribute the result, this time for real: ResultCopy = Result; - m_ParentWindow.DistributeStack(ResultCopy, a_Player, this, true); + m_ParentWindow.DistributeStack(ResultCopy, 0, a_Player, this, true); // Remove the ingredients from the crafting grid and update the recipe: cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); @@ -896,7 +897,7 @@ void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem return; } - m_ParentWindow.DistributeStack(Slot, a_Player, this, true); + m_ParentWindow.DistributeStack(Slot, a_SlotNum, a_Player, this, true); if (Slot.IsEmpty()) { Slot.Empty(); @@ -912,31 +913,31 @@ void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem -void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { for (int i = 0; i < 2; i++) { - const cItem * Slot = GetSlot(i, a_Player); + int SlotNum = (a_BackFill) ? (2 - 1 - i) : i; + + const cItem * Slot = GetSlot(SlotNum, a_Player); if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) { // Different items continue; } - int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; + char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; if (NumFit <= 0) { // Full stack already continue; } - if (NumFit > a_ItemStack.m_ItemCount) - { - NumFit = a_ItemStack.m_ItemCount; - } + NumFit = std::min(NumFit, a_ItemStack.m_ItemCount); + if (a_ShouldApply) { cItem NewSlot(a_ItemStack); NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; - SetSlot(i, a_Player, NewSlot); + SetSlot(SlotNum, a_Player, NewSlot); } a_ItemStack.m_ItemCount -= NumFit; if (a_ItemStack.IsEmpty()) @@ -1053,7 +1054,7 @@ void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player) cItem SecondInput(*GetSlot(1, a_Player)); cItem Output(*GetSlot(2, a_Player)); - if (Input.IsEmpty() && !Output.IsEmpty()) + if (Input.IsEmpty()) { Output.Empty(); SetSlot(2, a_Player, Output); @@ -1337,7 +1338,7 @@ void cSlotAreaBeacon::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ -void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaBeacon::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { const cItem * Slot = GetSlot(0, a_Player); if (!Slot->IsEmpty() || !IsPlaceableItem(a_ItemStack.m_ItemType) || (a_ItemStack.m_ItemCount != 1)) @@ -1504,7 +1505,7 @@ void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickActio -void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) +void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots, bool a_BackFill) { const cItem * Slot = GetSlot(0, a_Player); if (!Slot->IsEmpty()) @@ -1834,38 +1835,50 @@ void cSlotAreaFurnace::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a -void cSlotAreaFurnace::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaFurnace::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { - for (int i = 0; i < 2; i++) + int SlotNum; + cFurnaceRecipe * FurnaceRecipes = cRoot::Get()->GetFurnaceRecipe(); + + if (FurnaceRecipes->GetRecipeFrom(a_ItemStack) != nullptr) { - const cItem * Slot = GetSlot(i, a_Player); - if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) - { - // Different items - continue; - } - int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; - if (NumFit <= 0) - { - // Full stack already - continue; - } - if (NumFit > a_ItemStack.m_ItemCount) - { - NumFit = a_ItemStack.m_ItemCount; - } - if (a_ShouldApply) - { - cItem NewSlot(a_ItemStack); - NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; - SetSlot(i, a_Player, NewSlot); - } - a_ItemStack.m_ItemCount -= NumFit; - if (a_ItemStack.IsEmpty()) - { - return; - } - } // for i - Slots + SlotNum = 0; + } + else if (FurnaceRecipes->IsFuel(a_ItemStack)) + { + SlotNum = 1; + } + else + { + return; + } + + const cItem * Slot = GetSlot(SlotNum, a_Player); + if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) + { + // Different items + return; + } + + char NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; + if (NumFit <= 0) + { + // Full stack already + return; + } + NumFit = std::min(NumFit, a_ItemStack.m_ItemCount); + + if (a_ShouldApply) + { + cItem NewSlot(a_ItemStack); + NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; + SetSlot(SlotNum, a_Player, NewSlot); + } + a_ItemStack.m_ItemCount -= NumFit; + if (a_ItemStack.IsEmpty()) + { + return; + } } @@ -2014,7 +2027,7 @@ void cSlotAreaInventoryBase::SetSlot(int a_SlotNum, cPlayer & a_Player, const cI //////////////////////////////////////////////////////////////////////////////// // cSlotAreaArmor: -void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) { if (ItemCategory::IsHelmet(a_ItemStack.m_ItemType) && GetSlot(0, a_Player)->IsEmpty()) { diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 7c8a2c858..e39d372c9 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -71,7 +71,7 @@ public: if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes) If a_KeepEmptySlots is true, empty slots will be skipped and won't be filled */ - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots); + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill); /// Called on DblClicking to collect all stackable items into hand. /// The items are accumulated in a_Dragging and removed from the slots immediately. @@ -156,7 +156,7 @@ public: } /** Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) */ - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; /** 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) override; @@ -244,7 +244,7 @@ public: virtual void SetSlot (int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; // Distributing items into this area is completely disabled - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; protected: @@ -288,7 +288,7 @@ public: // cSlotArea overrides: virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) override; - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; // cSlotAreaTemporary overrides: virtual void OnPlayerRemoved(cPlayer & a_Player) override; @@ -324,10 +324,10 @@ public: cSlotAreaBeacon(cBeaconEntity * a_Beacon, cWindow & a_ParentWindow); virtual ~cSlotAreaBeacon(); - bool IsPlaceableItem(short a_ItemType); + static bool IsPlaceableItem(short a_ItemType); virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override; virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; @@ -352,7 +352,7 @@ public: // cSlotArea overrides: virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; // cSlotAreaTemporary overrides: @@ -437,7 +437,7 @@ public: virtual ~cSlotAreaFurnace(); virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots, bool a_BackFill) override; virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override; virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override; diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index dc7558d8e..0cb501a65 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -32,7 +32,6 @@ cWindow::cWindow(WindowType a_WindowType, const AString & a_WindowTitle) : m_WindowType(a_WindowType), m_WindowTitle(a_WindowTitle), m_IsDestroyed(false), - m_ShouldDistributeToHotbarFirst(true), m_Owner(nullptr) { if (a_WindowType == wtInventory) @@ -392,43 +391,38 @@ bool cWindow::ForEachClient(cItemCallback & a_Callback) -void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply) +void cWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) { - // Ask each slot area to take as much of the stack as it can. - // First ask only slots that already have the same kind of item - // Then ask any remaining slots - for (int Pass = 0; Pass < 2; ++Pass) + cSlotAreas Areas; + for (auto Area : m_SlotAreas) { - if (m_ShouldDistributeToHotbarFirst) + if (Area != a_ClickedArea) { - // First distribute into the hotbar: - if (a_ExcludeArea != m_SlotAreas.back()) - { - m_SlotAreas.back()->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0)); - if (a_ItemStack.IsEmpty()) - { - // Distributed it all - return; - } - } + Areas.push_back(Area); } - - // The distribute to all other areas: - cSlotAreas::iterator end = m_ShouldDistributeToHotbarFirst ? (m_SlotAreas.end() - 1) : m_SlotAreas.end(); - for (cSlotAreas::iterator itr = m_SlotAreas.begin(); itr != end; ++itr) + } + + DistributeStack(a_ItemStack, a_Player, Areas, a_ShouldApply, false); +} + + + + + +void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotAreas & a_AreasInOrder, bool a_ShouldApply, bool a_BackFill) +{ + for (size_t i = 0; i < 2; i++) + { + for (cSlotAreas::iterator itr = a_AreasInOrder.begin(); itr != a_AreasInOrder.end(); ++itr) { - if (*itr == a_ExcludeArea) - { - continue; - } - (*itr)->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0)); + (*itr)->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (i == 0), a_BackFill); if (a_ItemStack.IsEmpty()) { // Distributed it all return; } - } // for itr - m_SlotAreas[] - } // for Pass - repeat twice + } + } } diff --git a/src/UI/Window.h b/src/UI/Window.h index e3af73c46..9d9a5d7e8 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -155,12 +155,14 @@ public: if a_ShouldApply is true, the changes are written into the slots; if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes) */ - void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply); + virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply); + + void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotAreas & a_AreasInOrder, bool a_ShouldApply, bool a_BackFill); - /// 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. + /** 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 @@ -177,7 +179,6 @@ protected: cPlayerList m_OpenedBy; bool m_IsDestroyed; - bool m_ShouldDistributeToHotbarFirst; ///< If set (default), shift+click tries to distribute to hotbar first, then other areas. False for doublechests cWindowOwner * m_Owner;