summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/LuaWindow.cpp18
-rw-r--r--src/Bindings/LuaWindow.h1
-rw-r--r--src/Bindings/ManualBindings_Network.cpp35
-rw-r--r--src/BlockEntities/BeaconEntity.cpp3
-rw-r--r--src/BlockEntities/ChestEntity.cpp2
-rw-r--r--src/BlockEntities/DropSpenserEntity.cpp1
-rw-r--r--src/BlockEntities/EnderChestEntity.cpp2
-rw-r--r--src/BlockEntities/FurnaceEntity.cpp2
-rw-r--r--src/BlockEntities/HopperEntity.cpp1
-rw-r--r--src/Blocks/BlockAnvil.h1
-rw-r--r--src/Blocks/BlockEnchantmentTable.h2
-rw-r--r--src/Blocks/BlockWorkbench.h2
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/ChunkData.cpp2
-rw-r--r--src/ClientHandle.cpp3
-rw-r--r--src/Entities/Minecart.cpp1
-rw-r--r--src/Entities/Player.cpp2
-rw-r--r--src/FurnaceRecipe.cpp16
-rw-r--r--src/FurnaceRecipe.h3
-rw-r--r--src/OSSupport/CMakeLists.txt1
-rw-r--r--src/OSSupport/Network.h3
-rw-r--r--src/OSSupport/NetworkInterfaceEnum.cpp185
-rw-r--r--src/UI/AnvilWindow.cpp83
-rw-r--r--src/UI/AnvilWindow.h45
-rw-r--r--src/UI/BeaconWindow.cpp76
-rw-r--r--src/UI/BeaconWindow.h40
-rw-r--r--src/UI/CMakeLists.txt23
-rw-r--r--src/UI/ChestWindow.cpp141
-rw-r--r--src/UI/ChestWindow.h45
-rw-r--r--src/UI/CraftingWindow.cpp61
-rw-r--r--src/UI/CraftingWindow.h31
-rw-r--r--src/UI/DropSpenserWindow.cpp46
-rw-r--r--src/UI/DropSpenserWindow.h32
-rw-r--r--src/UI/EnchantingWindow.cpp100
-rw-r--r--src/UI/EnchantingWindow.h44
-rw-r--r--src/UI/EnderChestWindow.cpp71
-rw-r--r--src/UI/EnderChestWindow.h38
-rw-r--r--src/UI/FurnaceWindow.cpp74
-rw-r--r--src/UI/FurnaceWindow.h32
-rw-r--r--src/UI/HopperWindow.cpp48
-rw-r--r--src/UI/HopperWindow.h32
-rw-r--r--src/UI/InventoryWindow.cpp73
-rw-r--r--src/UI/InventoryWindow.h34
-rw-r--r--src/UI/MinecartWithChestWindow.h67
-rw-r--r--src/UI/SlotArea.cpp130
-rw-r--r--src/UI/SlotArea.h22
-rw-r--r--src/UI/Window.cpp437
-rw-r--r--src/UI/Window.h204
48 files changed, 1612 insertions, 707 deletions
diff --git a/src/Bindings/LuaWindow.cpp b/src/Bindings/LuaWindow.cpp
index 35730878d..d4014059b 100644
--- a/src/Bindings/LuaWindow.cpp
+++ b/src/Bindings/LuaWindow.cpp
@@ -167,6 +167,24 @@ void cLuaWindow::Destroy(void)
+void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer& a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ cSlotAreas Areas;
+ for (auto Area : m_SlotAreas)
+ {
+ if (Area != a_ClickedArea)
+ {
+ Areas.push_back(Area);
+ }
+ }
+
+ super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
+}
+
+
+
+
+
void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{
if (a_ItemGrid != &m_Contents)
diff --git a/src/Bindings/LuaWindow.h b/src/Bindings/LuaWindow.h
index dab99a2e2..76530d99d 100644
--- a/src/Bindings/LuaWindow.h
+++ b/src/Bindings/LuaWindow.h
@@ -84,6 +84,7 @@ protected:
// cWindow overrides:
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
virtual void Destroy(void) override;
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
// cItemGrid::cListener overrides:
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
diff --git a/src/Bindings/ManualBindings_Network.cpp b/src/Bindings/ManualBindings_Network.cpp
index a628eb9ca..628cda7f0 100644
--- a/src/Bindings/ManualBindings_Network.cpp
+++ b/src/Bindings/ManualBindings_Network.cpp
@@ -129,6 +129,30 @@ static int tolua_cNetwork_CreateUDPEndpoint(lua_State * L)
+/** Binds cNetwork::EnumLocalIPAddresses */
+static int tolua_cNetwork_EnumLocalIPAddresses(lua_State * L)
+{
+ // Function signature:
+ // cNetwork:EnumLocalIPAddresses() -> {string, ...}
+
+ cLuaState S(L);
+ if (
+ !S.CheckParamUserTable(1, "cNetwork") ||
+ !S.CheckParamEnd(2)
+ )
+ {
+ return 0;
+ }
+
+ // Push the enumerated addresses:
+ S.Push(cNetwork::EnumLocalIPAddresses());
+ return 1;
+}
+
+
+
+
+
/** Binds cNetwork::HostnameToIP */
static int tolua_cNetwork_HostnameToIP(lua_State * L)
{
@@ -903,11 +927,12 @@ void ManualBindings::BindNetwork(lua_State * tolua_S)
// Fill in the functions (alpha-sorted):
tolua_beginmodule(tolua_S, "cNetwork");
- tolua_function(tolua_S, "Connect", tolua_cNetwork_Connect);
- tolua_function(tolua_S, "CreateUDPEndpoint", tolua_cNetwork_CreateUDPEndpoint);
- tolua_function(tolua_S, "HostnameToIP", tolua_cNetwork_HostnameToIP);
- tolua_function(tolua_S, "IPToHostname", tolua_cNetwork_IPToHostname);
- tolua_function(tolua_S, "Listen", tolua_cNetwork_Listen);
+ tolua_function(tolua_S, "Connect", tolua_cNetwork_Connect);
+ tolua_function(tolua_S, "CreateUDPEndpoint", tolua_cNetwork_CreateUDPEndpoint);
+ tolua_function(tolua_S, "EnumLocalIPAddresses", tolua_cNetwork_EnumLocalIPAddresses);
+ tolua_function(tolua_S, "HostnameToIP", tolua_cNetwork_HostnameToIP);
+ tolua_function(tolua_S, "IPToHostname", tolua_cNetwork_IPToHostname);
+ tolua_function(tolua_S, "Listen", tolua_cNetwork_Listen);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cServerHandle");
diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp
index 37ce7a8ab..fb3940ce9 100644
--- a/src/BlockEntities/BeaconEntity.cpp
+++ b/src/BlockEntities/BeaconEntity.cpp
@@ -4,6 +4,7 @@
#include "BeaconEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
+#include "../UI/BeaconWindow.h"
@@ -289,7 +290,7 @@ void cBeaconEntity::UsedBy(cPlayer * a_Player)
OpenWindow(new cBeaconWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
-
+
if (Window != nullptr)
{
// if (a_Player->GetWindow() != Window)
diff --git a/src/BlockEntities/ChestEntity.cpp b/src/BlockEntities/ChestEntity.cpp
index 0cd9c66e0..3821f9aab 100644
--- a/src/BlockEntities/ChestEntity.cpp
+++ b/src/BlockEntities/ChestEntity.cpp
@@ -4,7 +4,7 @@
#include "ChestEntity.h"
#include "../Item.h"
#include "../Entities/Player.h"
-#include "../UI/Window.h"
+#include "../UI/ChestWindow.h"
diff --git a/src/BlockEntities/DropSpenserEntity.cpp b/src/BlockEntities/DropSpenserEntity.cpp
index 5e98506f1..039f5d360 100644
--- a/src/BlockEntities/DropSpenserEntity.cpp
+++ b/src/BlockEntities/DropSpenserEntity.cpp
@@ -8,6 +8,7 @@
#include "DropSpenserEntity.h"
#include "../Entities/Player.h"
#include "../Chunk.h"
+#include "../UI/DropSpenserWindow.h"
diff --git a/src/BlockEntities/EnderChestEntity.cpp b/src/BlockEntities/EnderChestEntity.cpp
index e18490a1e..ab5c5a2de 100644
--- a/src/BlockEntities/EnderChestEntity.cpp
+++ b/src/BlockEntities/EnderChestEntity.cpp
@@ -4,7 +4,7 @@
#include "EnderChestEntity.h"
#include "../Item.h"
#include "../Entities/Player.h"
-#include "../UI/Window.h"
+#include "../UI/EnderChestWindow.h"
diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp
index cc5a00af7..2621b560b 100644
--- a/src/BlockEntities/FurnaceEntity.cpp
+++ b/src/BlockEntities/FurnaceEntity.cpp
@@ -2,7 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "FurnaceEntity.h"
-#include "../UI/Window.h"
+#include "../UI/FurnaceWindow.h"
#include "../Entities/Player.h"
#include "../Root.h"
#include "../Chunk.h"
diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp
index c2d6cabbb..bfd4b8322 100644
--- a/src/BlockEntities/HopperEntity.cpp
+++ b/src/BlockEntities/HopperEntity.cpp
@@ -9,6 +9,7 @@
#include "../Entities/Player.h"
#include "../Entities/Pickup.h"
#include "../Bindings/PluginManager.h"
+#include "../UI/HopperWindow.h"
#include "ChestEntity.h"
#include "FurnaceEntity.h"
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h
index 20514580e..abfa0f782 100644
--- a/src/Blocks/BlockAnvil.h
+++ b/src/Blocks/BlockAnvil.h
@@ -4,6 +4,7 @@
#include "BlockHandler.h"
#include "../World.h"
#include "../Entities/Player.h"
+#include "../UI/AnvilWindow.h"
diff --git a/src/Blocks/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h
index 81d2cb9a0..40001f356 100644
--- a/src/Blocks/BlockEnchantmentTable.h
+++ b/src/Blocks/BlockEnchantmentTable.h
@@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
-#include "../UI/Window.h"
+#include "../UI/EnchantingWindow.h"
#include "../Entities/Player.h"
diff --git a/src/Blocks/BlockWorkbench.h b/src/Blocks/BlockWorkbench.h
index 699badaf2..e40e15606 100644
--- a/src/Blocks/BlockWorkbench.h
+++ b/src/Blocks/BlockWorkbench.h
@@ -2,7 +2,7 @@
#pragma once
#include "BlockHandler.h"
-#include "../UI/Window.h"
+#include "../UI/CraftingWindow.h"
#include "../Entities/Player.h"
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c39f5f6e6..b91c4f65a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -9,7 +9,7 @@ include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include
set(FOLDERS
OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings
- WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs
+ WorldStorage Mobs Entities Simulator BlockEntities UI Generating/Prefabs
Noise
)
@@ -318,7 +318,7 @@ if (NOT MSVC)
target_link_libraries(${EXECUTABLE}
OSSupport HTTPServer Bindings Items Blocks Noise
Protocol Generating Generating_Prefabs WorldStorage
- Mobs Entities Simulator UI BlockEntities PolarSSL++
+ Mobs Entities Simulator BlockEntities UI PolarSSL++
)
endif ()
if (WIN32)
diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp
index 57b27c5e0..80f40d39e 100644
--- a/src/ChunkData.cpp
+++ b/src/ChunkData.cpp
@@ -361,7 +361,7 @@ void cChunkData::CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx, size_t a_Lengt
}
else
{
- memset(&a_Dest[(i * SectionBlockCount) - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy);
+ memset(&a_Dest[(i * SectionBlockCount) + StartPos - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy);
}
}
}
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 2e0e86653..4fbce2b67 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -12,6 +12,9 @@
#include "BlockEntities/CommandBlockEntity.h"
#include "BlockEntities/SignEntity.h"
#include "UI/Window.h"
+#include "UI/AnvilWindow.h"
+#include "UI/BeaconWindow.h"
+#include "UI/EnchantingWindow.h"
#include "Item.h"
#include "Mobs/Monster.h"
#include "ChatColor.h"
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index 776f957f4..a32926838 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -11,6 +11,7 @@
#include "../Chunk.h"
#include "Player.h"
#include "../BoundingBox.h"
+#include "../UI/MinecartWithChestWindow.h"
#define NO_SPEED 0.0
#define MAX_SPEED 8
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 0d36d0b23..c89e7b87c 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -5,7 +5,7 @@
#include <unordered_map>
#include "../ChatColor.h"
#include "../Server.h"
-#include "../UI/Window.h"
+#include "../UI/InventoryWindow.h"
#include "../UI/WindowOwner.h"
#include "../World.h"
#include "../Bindings/PluginManager.h"
diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp
index 112aa8146..ea952a852 100644
--- a/src/FurnaceRecipe.cpp
+++ b/src/FurnaceRecipe.cpp
@@ -291,6 +291,22 @@ const cFurnaceRecipe::cRecipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_In
+bool cFurnaceRecipe::IsFuel(const cItem & a_Item) const
+{
+ for (auto & Fuel : m_pState->Fuel)
+ {
+ 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/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index 81b37ef0e..0d3c9a63e 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -13,6 +13,7 @@ SET (SRCS
HostnameLookup.cpp
IPLookup.cpp
IsThread.cpp
+ NetworkInterfaceEnum.cpp
NetworkSingleton.cpp
Semaphore.cpp
ServerHandleImpl.cpp
diff --git a/src/OSSupport/Network.h b/src/OSSupport/Network.h
index 5dd596223..95a935bbe 100644
--- a/src/OSSupport/Network.h
+++ b/src/OSSupport/Network.h
@@ -318,6 +318,9 @@ public:
If a_Port is 0, the OS is free to assign any port number it likes to the endpoint.
Returns the endpoint object that can be interacted with. */
static cUDPEndpointPtr CreateUDPEndpoint(UInt16 a_Port, cUDPEndpoint::cCallbacks & a_Callbacks);
+
+ /** Returns all local IP addresses for network interfaces currently available. */
+ static AStringVector EnumLocalIPAddresses(void);
};
diff --git a/src/OSSupport/NetworkInterfaceEnum.cpp b/src/OSSupport/NetworkInterfaceEnum.cpp
new file mode 100644
index 000000000..c4af1e93c
--- /dev/null
+++ b/src/OSSupport/NetworkInterfaceEnum.cpp
@@ -0,0 +1,185 @@
+
+// NetworkInterfaceEnum.cpp
+
+// Implements the cNetwork::EnumLocalIPAddresses() interface enumeration function
+
+#include "Globals.h"
+#include "Network.h"
+#include "event2/util.h"
+#ifdef _WIN32
+ #include <IPHlpApi.h>
+ #pragma comment(lib, "IPHLPAPI.lib")
+#else // _WIN32
+ #include <sys/types.h>
+ #include <ifaddrs.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+#endif // else _WIN32
+
+
+
+
+
+#ifdef SELF_TEST
+
+static class cEnumIPAddressTest
+{
+public:
+ cEnumIPAddressTest(void)
+ {
+ printf("Enumerating all IP addresses...\n");
+ auto IPs = cNetwork::EnumLocalIPAddresses();
+ for (auto & ip: IPs)
+ {
+ printf(" %s\n", ip.c_str());
+ }
+ printf("Done.\n");
+ }
+} g_EnumIPAddressTest;
+
+#endif // SELF_TEST
+
+
+
+
+
+#ifdef _WIN32
+
+/** Converts the SOCKET_ADDRESS structure received from the OS into an IP address string. */
+static AString PrintAddress(SOCKET_ADDRESS & a_Addr)
+{
+ char IP[128];
+ switch (a_Addr.lpSockaddr->sa_family)
+ {
+ case AF_INET:
+ {
+ auto sin = reinterpret_cast<const sockaddr_in *>(a_Addr.lpSockaddr);
+ evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin_addr), IP, sizeof(IP));
+ break;
+ }
+ case AF_INET6:
+ {
+ auto sin = reinterpret_cast<const sockaddr_in6 *>(a_Addr.lpSockaddr);
+ evutil_inet_ntop(a_Addr.lpSockaddr->sa_family, &(sin->sin6_addr), IP, sizeof(IP));
+ break;
+ }
+ default:
+ {
+ IP[0] = 0;
+ break;
+ }
+ }
+ return IP;
+}
+
+#else // _WIN32
+
+static AString PrintAddress(ifaddrs * InterfaceAddress)
+{
+ switch (InterfaceAddress->ifa_addr->sa_family)
+ {
+ case AF_INET:
+ { // IPv4
+ char AddressBuffer[INET_ADDRSTRLEN];
+ sockaddr_in InternetSocket;
+
+ std::memcpy(&InternetSocket, InterfaceAddress->ifa_addr, sizeof(InternetSocket));
+ inet_ntop(AF_INET, &InternetSocket.sin_addr, AddressBuffer, INET_ADDRSTRLEN);
+ return AddressBuffer;
+ }
+ case AF_INET6:
+ { // IPv6
+ char AddressBuffer[INET6_ADDRSTRLEN];
+ sockaddr_in6 InternetSocket;
+
+ std::memcpy(&InternetSocket, InterfaceAddress->ifa_addr, sizeof(InternetSocket));
+ inet_ntop(AF_INET6, &InternetSocket.sin6_addr, AddressBuffer, INET6_ADDRSTRLEN);
+ return AddressBuffer;
+ }
+ default:
+ {
+ LOG("Unknown address family: %i", InterfaceAddress->ifa_addr->sa_family);
+ return "";
+ }
+ }
+}
+
+#endif // else _WIN32
+
+
+
+
+
+AStringVector cNetwork::EnumLocalIPAddresses(void)
+{
+ AStringVector res;
+
+ #ifdef _WIN32
+
+ // Query the OS for all adapters' addresses:
+ char buffer[64 KiB]; // A buffer backing the address list
+ PIP_ADAPTER_ADDRESSES pAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(&buffer);
+ ULONG outBufLen = sizeof(buffer);
+ DWORD dwRetVal = GetAdaptersAddresses(
+ AF_UNSPEC,
+ GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, nullptr,
+ pAddresses, &outBufLen
+ );
+ if (dwRetVal != ERROR_SUCCESS)
+ {
+ LOG("GetAdaptersAddresses() failed: %u", dwRetVal);
+ return res;
+ }
+
+ // Enumerate all active adapters
+ for (auto pCurrAddresses = pAddresses; pCurrAddresses != nullptr; pCurrAddresses = pCurrAddresses->Next)
+ {
+ if (pCurrAddresses->OperStatus != IfOperStatusUp)
+ {
+ // Adapter not active, skip it:
+ continue;
+ }
+
+ // Collect all IP addresses on this adapter:
+ for (auto pUnicast = pCurrAddresses->FirstUnicastAddress; pUnicast != nullptr; pUnicast = pUnicast->Next)
+ {
+ auto Address = PrintAddress(pUnicast->Address);
+ if (!Address.empty())
+ {
+ res.push_back(Address);
+ }
+ } // for pUnicast
+ } // for pCurrAddresses
+
+ #else // _WIN32
+
+ struct ifaddrs * ifAddrStruct = nullptr;
+ getifaddrs(&ifAddrStruct);
+
+ for (auto ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next)
+ {
+ if (ifa->ifa_addr == nullptr)
+ {
+ continue;
+ }
+
+ auto Address = PrintAddress(ifa);
+ if (!Address.empty())
+ {
+ res.emplace_back(Address);
+ }
+ }
+
+ if (ifAddrStruct != nullptr)
+ {
+ freeifaddrs(ifAddrStruct);
+ }
+
+ #endif // else _WIN32
+
+ return res;
+}
+
+
+
+
diff --git a/src/UI/AnvilWindow.cpp b/src/UI/AnvilWindow.cpp
new file mode 100644
index 000000000..daa35cf47
--- /dev/null
+++ b/src/UI/AnvilWindow.cpp
@@ -0,0 +1,83 @@
+
+// AnvilWindow.cpp
+
+// Representing the UI window for the anvil block
+
+#include "Globals.h"
+#include "AnvilWindow.h"
+#include "SlotArea.h"
+
+
+
+
+cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtAnvil, "Repair"),
+ m_RepairedItemName(""),
+ m_BlockX(a_BlockX),
+ m_BlockY(a_BlockY),
+ m_BlockZ(a_BlockZ)
+{
+ m_AnvilSlotArea = new cSlotAreaAnvil(*this);
+ m_SlotAreas.push_back(m_AnvilSlotArea);
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+AString cAnvilWindow::GetRepairedItemName(void) const
+{
+ return m_RepairedItemName;
+}
+
+
+
+
+
+void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player)
+{
+ m_RepairedItemName = a_Name;
+ if (a_Player != nullptr)
+ {
+ m_AnvilSlotArea->UpdateResult(*a_Player);
+ }
+}
+
+
+
+
+
+void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
+{
+ a_PosX = m_BlockX;
+ a_PosY = m_BlockY;
+ a_PosZ = m_BlockZ;
+}
+
+
+
+
+
+void cAnvilWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+}
+
+
+
+
diff --git a/src/UI/AnvilWindow.h b/src/UI/AnvilWindow.h
new file mode 100644
index 000000000..e23c744fe
--- /dev/null
+++ b/src/UI/AnvilWindow.h
@@ -0,0 +1,45 @@
+
+// AnvilWindow.h
+
+// Representing the UI window for the anvil block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cAnvilWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /** Gets the repaired item name. */
+ AString GetRepairedItemName(void) const;
+
+ /** Set the repaired item name. */
+ void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player);
+
+ /** Gets the Position from the Anvil */
+ void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+protected:
+ cSlotAreaAnvil * m_AnvilSlotArea;
+ AString m_RepairedItemName;
+ int m_BlockX, m_BlockY, m_BlockZ;
+};
+
+
+
+
diff --git a/src/UI/BeaconWindow.cpp b/src/UI/BeaconWindow.cpp
new file mode 100644
index 000000000..c1efa78ad
--- /dev/null
+++ b/src/UI/BeaconWindow.cpp
@@ -0,0 +1,76 @@
+
+// BeaconWindow.cpp
+
+// Representing the UI window for the beacon block
+
+#include "Globals.h"
+#include "BeaconWindow.h"
+#include "SlotArea.h"
+#include "../BlockEntities/BeaconEntity.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) :
+ cWindow(wtBeacon, "Beacon"),
+ m_Beacon(a_Beacon)
+{
+ m_SlotAreas.push_back(new cSlotAreaBeacon(m_Beacon, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cBeaconWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
+
+void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player)
+{
+ super::OpenedByPlayer(a_Player);
+
+ a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel());
+ a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryEffect());
+ a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryEffect());
+}
+
+
+
+
diff --git a/src/UI/BeaconWindow.h b/src/UI/BeaconWindow.h
new file mode 100644
index 000000000..fa28b41ba
--- /dev/null
+++ b/src/UI/BeaconWindow.h
@@ -0,0 +1,40 @@
+
+// BeaconWindow.h
+
+// Representing the UI window for the beacon block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cBeaconWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon);
+
+ 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;
+
+ // cWindow Overrides:
+ virtual void OpenedByPlayer(cPlayer & a_Player) override;
+
+protected:
+ cBeaconEntity * m_Beacon;
+};
+
+
+
+
diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt
index 2b094ef1d..ef4afc40a 100644
--- a/src/UI/CMakeLists.txt
+++ b/src/UI/CMakeLists.txt
@@ -6,11 +6,32 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
SET (SRCS
SlotArea.cpp
- Window.cpp)
+ Window.cpp
+ AnvilWindow.cpp
+ BeaconWindow.cpp
+ ChestWindow.cpp
+ CraftingWindow.cpp
+ DropSpenserWindow.cpp
+ EnchantingWindow.cpp
+ EnderChestWindow.cpp
+ FurnaceWindow.cpp
+ HopperWindow.cpp
+ InventoryWindow.cpp)
SET (HDRS
SlotArea.h
Window.h
+ AnvilWindow.h
+ BeaconWindow.h
+ ChestWindow.h
+ CraftingWindow.h
+ DropSpenserWindow.h
+ EnchantingWindow.h
+ EnderChestWindow.h
+ FurnaceWindow.h
+ HopperWindow.h
+ InventoryWindow.h
+ MinecartWithChestWindow.h
WindowOwner.h)
if(NOT MSVC)
diff --git a/src/UI/ChestWindow.cpp b/src/UI/ChestWindow.cpp
new file mode 100644
index 000000000..3766b132d
--- /dev/null
+++ b/src/UI/ChestWindow.cpp
@@ -0,0 +1,141 @@
+
+// ChestWindow.cpp
+
+// Representing the UI window for the chest block
+
+#include "Globals.h"
+#include "ChestWindow.h"
+#include "../BlockEntities/ChestEntity.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cChestWindow::cChestWindow(cChestEntity * a_Chest) :
+ cWindow(wtChest, (a_Chest->GetBlockType() == E_BLOCK_CHEST) ? "Chest" : "Trapped Chest"),
+ m_World(a_Chest->GetWorld()),
+ m_BlockX(a_Chest->GetPosX()),
+ m_BlockY(a_Chest->GetPosY()),
+ m_BlockZ(a_Chest->GetPosZ()),
+ m_PrimaryChest(a_Chest),
+ m_SecondaryChest(nullptr)
+{
+ m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+
+ // Play the opening sound:
+ m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+
+ // Send out the chest-open packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_Chest->GetBlockType());
+}
+
+
+
+
+
+cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) :
+ cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"),
+ m_World(a_PrimaryChest->GetWorld()),
+ m_BlockX(a_PrimaryChest->GetPosX()),
+ m_BlockY(a_PrimaryChest->GetPosY()),
+ m_BlockZ(a_PrimaryChest->GetPosZ()),
+ m_PrimaryChest(a_PrimaryChest),
+ m_SecondaryChest(a_SecondaryChest)
+{
+ m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+
+ // Play the opening sound:
+ m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+
+ // Send out the chest-open packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_PrimaryChest->GetBlockType());
+}
+
+
+
+
+
+cChestWindow::~cChestWindow()
+{
+ // Send out the chest-close packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, m_PrimaryChest->GetBlockType());
+
+ m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+}
+
+
+
+
+
+bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
+{
+ int ChunkX, ChunkZ;
+
+ m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1);
+ cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
+ m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
+
+ if (m_SecondaryChest != nullptr)
+ {
+ m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1);
+ cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
+ m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
+ }
+
+ cWindow::ClosedByPlayer(a_Player, a_CanRefuse);
+ return true;
+}
+
+
+
+
+
+void cChestWindow::OpenedByPlayer(cPlayer & a_Player)
+{
+ int ChunkX, ChunkZ;
+
+ m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1);
+ cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
+ m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
+
+ if (m_SecondaryChest != nullptr)
+ {
+ m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1);
+ cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
+ m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
+ }
+
+ cWindow::OpenedByPlayer(a_Player);
+}
+
+
+
+
+
+void cChestWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Hotbar or Inventory
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/ChestWindow.h b/src/UI/ChestWindow.h
new file mode 100644
index 000000000..a3b20cdd9
--- /dev/null
+++ b/src/UI/ChestWindow.h
@@ -0,0 +1,45 @@
+
+// ChestWindow.h
+
+// Representing the UI window for the chest block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cChestWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cChestWindow(cChestEntity * a_Chest);
+
+ cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest);
+
+ ~cChestWindow();
+
+ virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
+
+ virtual void OpenedByPlayer(cPlayer & a_Player) override;
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+protected:
+ cWorld * m_World;
+ int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet
+ cChestEntity * m_PrimaryChest;
+ cChestEntity * m_SecondaryChest;
+};
+
+
+
+
diff --git a/src/UI/CraftingWindow.cpp b/src/UI/CraftingWindow.cpp
new file mode 100644
index 000000000..ca44056f9
--- /dev/null
+++ b/src/UI/CraftingWindow.cpp
@@ -0,0 +1,61 @@
+
+// CraftingWindow.cpp
+
+// Representing the UI window for the crafting block
+
+#include "Globals.h"
+#include "CraftingWindow.h"
+#include "SlotArea.h"
+
+
+
+
+cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtWorkbench, "Crafting Table")
+{
+ m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cCraftingWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+ else
+ {
+ // Hotbar
+ AreasInOrder.push_back(m_SlotAreas[1]); /* Inventory */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/CraftingWindow.h b/src/UI/CraftingWindow.h
new file mode 100644
index 000000000..01b2da73a
--- /dev/null
+++ b/src/UI/CraftingWindow.h
@@ -0,0 +1,31 @@
+
+// CraftingWindow.h
+
+// Representing the UI window for the crafting block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cCraftingWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+};
+
+
+
+
diff --git a/src/UI/DropSpenserWindow.cpp b/src/UI/DropSpenserWindow.cpp
new file mode 100644
index 000000000..aeb7c64b7
--- /dev/null
+++ b/src/UI/DropSpenserWindow.cpp
@@ -0,0 +1,46 @@
+
+// DropSpenserWindow.cpp
+
+// Representing the UI window for the dropper/dispenser block
+
+#include "Globals.h"
+#include "DropSpenserWindow.h"
+
+
+
+
+
+cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) :
+ cWindow(wtDropSpenser, (a_DropSpenser->GetBlockType() == E_BLOCK_DISPENSER) ? "Dispenser" : "Dropper")
+{
+ m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cDropSpenserWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Inventory or Hotbar
+ AreasInOrder.push_back(m_SlotAreas[0]); /* DropSpenser */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/DropSpenserWindow.h b/src/UI/DropSpenserWindow.h
new file mode 100644
index 000000000..edff936e5
--- /dev/null
+++ b/src/UI/DropSpenserWindow.h
@@ -0,0 +1,32 @@
+
+// DropSpenserWindow.h
+
+// Representing the UI window for the dropper/dispenser block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+#include "../BlockEntities/DropSpenserEntity.h"
+
+
+
+
+
+class cDropSpenserWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+};
+
+
+
+
diff --git a/src/UI/EnchantingWindow.cpp b/src/UI/EnchantingWindow.cpp
new file mode 100644
index 000000000..fe21ee83d
--- /dev/null
+++ b/src/UI/EnchantingWindow.cpp
@@ -0,0 +1,100 @@
+
+// EnchantingWindow.cpp
+
+// Representing the UI window for the enchanting block
+
+#include "Globals.h"
+#include "EnchantingWindow.h"
+#include "SlotArea.h"
+
+
+
+
+
+cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
+ cWindow(wtEnchantment, "Enchant"),
+ m_SlotArea(),
+ m_BlockX(a_BlockX),
+ m_BlockY(a_BlockY),
+ m_BlockZ(a_BlockZ)
+{
+ m_SlotArea = new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ);
+ m_SlotAreas.push_back(m_SlotArea);
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cEnchantingWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player)
+{
+ if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
+ {
+ ASSERT(!"a_Property is invalid");
+ return;
+ }
+
+ m_PropertyValue[a_Property] = a_Value;
+ super::SetProperty(a_Property, a_Value, a_Player);
+}
+
+
+
+
+
+
+void cEnchantingWindow::SetProperty(short a_Property, short a_Value)
+{
+ if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
+ {
+ ASSERT(!"a_Property is invalid");
+ return;
+ }
+
+ m_PropertyValue[a_Property] = a_Value;
+ super::SetProperty(a_Property, a_Value);
+}
+
+
+
+
+
+short cEnchantingWindow::GetPropertyValue(short a_Property)
+{
+ if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
+ {
+ ASSERT(!"a_Property is invalid");
+ return 0;
+ }
+
+ return m_PropertyValue[a_Property];
+}
+
+
+
+
+
+void cEnchantingWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Inventory or Hotbar
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Enchanting */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/EnchantingWindow.h b/src/UI/EnchantingWindow.h
new file mode 100644
index 000000000..bf805c6c8
--- /dev/null
+++ b/src/UI/EnchantingWindow.h
@@ -0,0 +1,44 @@
+
+// EnchantingWindow.h
+
+// Representing the UI window for the enchanting block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cEnchantingWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ virtual void SetProperty(short a_Property, short a_Value, cPlayer & a_Player) override;
+
+ virtual void SetProperty(short a_Property, short a_Value) override;
+
+ /** Return the value of a property */
+ short GetPropertyValue(short a_Property);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+ cSlotArea * m_SlotArea;
+
+protected:
+ short m_PropertyValue[3];
+ int m_BlockX, m_BlockY, m_BlockZ;
+};
+
+
+
+
diff --git a/src/UI/EnderChestWindow.cpp b/src/UI/EnderChestWindow.cpp
new file mode 100644
index 000000000..a5484468f
--- /dev/null
+++ b/src/UI/EnderChestWindow.cpp
@@ -0,0 +1,71 @@
+
+// EnderChestWindow.cpp
+
+// Representing the UI window for the enderchest block
+
+#include "Globals.h"
+#include "../World.h"
+#include "EnderChestWindow.h"
+#include "SlotArea.h"
+
+
+
+
+
+cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) :
+ cWindow(wtChest, "Ender Chest"),
+ m_World(a_EnderChest->GetWorld()),
+ m_BlockX(a_EnderChest->GetPosX()),
+ m_BlockY(a_EnderChest->GetPosY()),
+ m_BlockZ(a_EnderChest->GetPosZ())
+{
+ m_SlotAreas.push_back(new cSlotAreaEnderChest(a_EnderChest, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+
+ // Play the opening sound:
+ m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+
+ // Send out the chest-open packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST);
+}
+
+
+
+
+
+cEnderChestWindow::~cEnderChestWindow()
+{
+ // Send out the chest-close packet:
+ m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST);
+
+ // Play the closing sound
+ m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
+}
+
+
+
+
+
+void cEnderChestWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Hotbar or Inventory
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/EnderChestWindow.h b/src/UI/EnderChestWindow.h
new file mode 100644
index 000000000..006a490bf
--- /dev/null
+++ b/src/UI/EnderChestWindow.h
@@ -0,0 +1,38 @@
+
+// EnderChestWindow.h
+
+// Representing the UI window for the enderchest block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+#include "../BlockEntities/EnderChestEntity.h"
+
+
+
+
+
+class cEnderChestWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cEnderChestWindow(cEnderChestEntity * a_EnderChest);
+
+ ~cEnderChestWindow();
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+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.cpp b/src/UI/FurnaceWindow.cpp
new file mode 100644
index 000000000..132439ff3
--- /dev/null
+++ b/src/UI/FurnaceWindow.cpp
@@ -0,0 +1,74 @@
+
+// FurnaceWindow.cpp
+
+// Representing the UI window for the furnace block
+
+#include "Globals.h"
+#include "FurnaceWindow.h"
+#include "SlotArea.h"
+#include "../FurnaceRecipe.h"
+#include "../Root.h"
+
+
+
+
+
+cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) :
+ cWindow(wtFurnace, "Furnace")
+{
+ m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cFurnaceWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(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::DistributeStackToAreas(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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/FurnaceWindow.h b/src/UI/FurnaceWindow.h
new file mode 100644
index 000000000..845505f8e
--- /dev/null
+++ b/src/UI/FurnaceWindow.h
@@ -0,0 +1,32 @@
+
+// FurnaceWindow.h
+
+// Representing the UI window for the furnace block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cFurnaceWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+};
+
+
+
+
diff --git a/src/UI/HopperWindow.cpp b/src/UI/HopperWindow.cpp
new file mode 100644
index 000000000..79f0767e8
--- /dev/null
+++ b/src/UI/HopperWindow.cpp
@@ -0,0 +1,48 @@
+
+// HopperWindow.cpp
+
+// Representing the UI window for the hopper block
+
+#include "Globals.h"
+#include "../BlockEntities/HopperEntity.h"
+#include "HopperWindow.h"
+#include "../BlockEntities/DropperEntity.h"
+
+
+
+
+
+cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) :
+ super(wtHopper, "Hopper")
+{
+ m_SlotAreas.push_back(new cSlotAreaItemGrid(a_Hopper->GetContents(), *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cHopperWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Inventory or Hotbar
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Hopper */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/HopperWindow.h b/src/UI/HopperWindow.h
new file mode 100644
index 000000000..2dec08666
--- /dev/null
+++ b/src/UI/HopperWindow.h
@@ -0,0 +1,32 @@
+
+// HopperWindow.h
+
+// Representing the UI window for the hopper block
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cHopperWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+};
+
+
+
+
diff --git a/src/UI/InventoryWindow.cpp b/src/UI/InventoryWindow.cpp
new file mode 100644
index 000000000..0f876e559
--- /dev/null
+++ b/src/UI/InventoryWindow.cpp
@@ -0,0 +1,73 @@
+
+// InventoryWindow.cpp
+
+// Representing the UI window for the player inventory
+
+#include "Globals.h"
+#include "InventoryWindow.h"
+#include "SlotArea.h"
+
+
+
+
+
+cInventoryWindow::cInventoryWindow(cPlayer & a_Player) :
+ cWindow(wtInventory, "Inventory"),
+ m_Player(a_Player)
+{
+ m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers
+ m_SlotAreas.push_back(new cSlotAreaArmor(*this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+}
+
+
+
+
+
+void cInventoryWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
+{
+ 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::DistributeStackToAreas(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::DistributeStackToAreas(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::DistributeStackToAreas(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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+}
+
+
+
+
diff --git a/src/UI/InventoryWindow.h b/src/UI/InventoryWindow.h
new file mode 100644
index 000000000..10952d37f
--- /dev/null
+++ b/src/UI/InventoryWindow.h
@@ -0,0 +1,34 @@
+
+// InventoryWindow.h
+
+// Representing the UI window for the player inventory
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+
+
+
+
+
+class cInventoryWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cInventoryWindow(cPlayer & a_Player);
+
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) override;
+
+protected:
+ cPlayer & m_Player;
+};
+
+
+
+
diff --git a/src/UI/MinecartWithChestWindow.h b/src/UI/MinecartWithChestWindow.h
new file mode 100644
index 000000000..a2b5283a6
--- /dev/null
+++ b/src/UI/MinecartWithChestWindow.h
@@ -0,0 +1,67 @@
+
+// MinecartWithChestWindow.h
+
+// Representing the UI window for the minecart chest entity
+
+
+
+
+
+#pragma once
+
+#include "Window.h"
+#include "../Entities/Minecart.h"
+
+
+
+
+
+class cMinecartWithChestWindow :
+ public cWindow
+{
+ typedef cWindow super;
+
+public:
+ cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart) :
+ cWindow(wtChest, "Minecart with Chest"),
+ m_ChestCart(a_ChestCart)
+ {
+ m_SlotAreas.push_back(new cSlotAreaMinecartWithChest(a_ChestCart, *this));
+ m_SlotAreas.push_back(new cSlotAreaInventory(*this));
+ m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
+
+ a_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestopen", a_ChestCart->GetPosX(), a_ChestCart->GetPosY(), a_ChestCart->GetPosZ(), 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::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, true);
+ }
+ else
+ {
+ // Hotbar or Inventory
+ AreasInOrder.push_back(m_SlotAreas[0]); /* Chest */
+ super::DistributeStackToAreas(a_ItemStack, a_Player, AreasInOrder, a_ShouldApply, false);
+ }
+ }
+
+
+ ~cMinecartWithChestWindow()
+ {
+ m_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestclosed", m_ChestCart->GetPosX(), m_ChestCart->GetPosY(), m_ChestCart->GetPosZ(), 1, 1);
+ }
+
+private:
+ cMinecartWithChest * m_ChestCart;
+};
+
+
+
+
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index e784569d9..37683a8e5 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -1,3 +1,4 @@
+
// SlotArea.cpp
// Implements the cSlotArea class and its descendants
@@ -12,6 +13,7 @@
#include "../BlockEntities/FurnaceEntity.h"
#include "../Entities/Minecart.h"
#include "../Items/ItemHandler.h"
+#include "AnvilWindow.h"
#include "Window.h"
#include "../CraftingRecipes.h"
#include "../Root.h"
@@ -205,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
@@ -340,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())
@@ -589,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);
}
@@ -656,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
@@ -665,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);
@@ -769,7 +772,7 @@ void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Play
////////////////////////////////////////////////////////////////////////////////
// cSlotAreaAnvil:
-cSlotAreaAnvil::cSlotAreaAnvil(cAnvilWindow & a_ParentWindow) :
+cSlotAreaAnvil::cSlotAreaAnvil(cWindow & a_ParentWindow) :
cSlotAreaTemporary(3, a_ParentWindow),
m_MaximumCost(0),
m_StackSizeToBeUsedInRepair(0)
@@ -894,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();
@@ -910,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())
@@ -1051,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);
@@ -1335,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))
@@ -1390,13 +1393,12 @@ void cSlotAreaBeacon::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
////////////////////////////////////////////////////////////////////////////////
// cSlotAreaEnchanting:
-cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) :
+cSlotAreaEnchanting::cSlotAreaEnchanting(cWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ) :
cSlotAreaTemporary(1, a_ParentWindow),
m_BlockX(a_BlockX),
m_BlockY(a_BlockY),
m_BlockZ(a_BlockZ)
{
- a_ParentWindow.m_SlotArea = this;
}
@@ -1503,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())
@@ -1833,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;
+ }
}
@@ -2013,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 1eeeb9836..e39d372c9 100644
--- a/src/UI/SlotArea.h
+++ b/src/UI/SlotArea.h
@@ -17,12 +17,10 @@ class cWindow;
class cPlayer;
class cBeaconEntity;
class cChestEntity;
-class cDropSpenserEntity;
class cEnderChestEntity;
class cFurnaceEntity;
class cMinecartWithChest;
class cCraftingRecipe;
-class cEnchantingWindow;
class cWorld;
@@ -73,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.
@@ -158,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;
@@ -246,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:
@@ -285,12 +283,12 @@ class cSlotAreaAnvil :
typedef cSlotAreaTemporary super;
public:
- cSlotAreaAnvil(cAnvilWindow & a_ParentWindow);
+ cSlotAreaAnvil(cWindow & a_ParentWindow);
// 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;
@@ -326,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;
@@ -350,11 +348,11 @@ class cSlotAreaEnchanting :
typedef cSlotAreaTemporary super;
public:
- cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ);
+ cSlotAreaEnchanting(cWindow & a_ParentWindow, int a_BlockX, int a_BlockY, int a_BlockZ);
// 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:
@@ -439,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 1598dd3e7..bb2e2a807 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,23 @@ bool cWindow::ForEachClient(cItemCallback<cClientHandle> & a_Callback)
-void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply)
+void cWindow::DistributeStackToAreas(cItem & a_ItemStack, cPlayer & a_Player, cSlotAreas & a_AreasInOrder, bool a_ShouldApply, bool a_BackFill)
{
- // 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)
+ /* 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 (size_t Pass = 0; Pass < 2; Pass++)
{
- if (m_ShouldDistributeToHotbarFirst)
+ for (auto SlotArea : a_AreasInOrder)
{
- // 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;
- }
- }
- }
-
- // 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)
- {
- if (*itr == a_ExcludeArea)
- {
- continue;
- }
- (*itr)->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0));
+ SlotArea->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0), a_BackFill);
if (a_ItemStack.IsEmpty())
{
// Distributed it all
return;
}
- } // for itr - m_SlotAreas[]
- } // for Pass - repeat twice
+ }
+ }
}
@@ -779,401 +758,3 @@ void cWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player)
-
-////////////////////////////////////////////////////////////////////////////////
-// cInventoryWindow:
-
-cInventoryWindow::cInventoryWindow(cPlayer & a_Player) :
- cWindow(wtInventory, "Inventory"),
- m_Player(a_Player)
-{
- m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers
- m_SlotAreas.push_back(new cSlotAreaArmor(*this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cCraftingWindow:
-
-cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
- cWindow(wtWorkbench, "Crafting Table")
-{
- m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cAnvilWindow:
-
-cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
- cWindow(wtAnvil, "Repair"),
- m_RepairedItemName(""),
- m_BlockX(a_BlockX),
- m_BlockY(a_BlockY),
- m_BlockZ(a_BlockZ)
-{
- m_AnvilSlotArea = new cSlotAreaAnvil(*this);
- m_SlotAreas.push_back(m_AnvilSlotArea);
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player)
-{
- m_RepairedItemName = a_Name;
-
- if (a_Player != nullptr)
- {
- m_AnvilSlotArea->UpdateResult(*a_Player);
- }
-}
-
-
-
-
-
-void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
-{
- a_PosX = m_BlockX;
- a_PosY = m_BlockY;
- a_PosZ = m_BlockZ;
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cBeaconWindow:
-
-cBeaconWindow::cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon) :
- 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));
-}
-
-
-
-
-
-void cBeaconWindow::OpenedByPlayer(cPlayer & a_Player)
-{
- super::OpenedByPlayer(a_Player);
-
- a_Player.GetClientHandle()->SendWindowProperty(*this, 0, m_Beacon->GetBeaconLevel());
- a_Player.GetClientHandle()->SendWindowProperty(*this, 1, m_Beacon->GetPrimaryEffect());
- a_Player.GetClientHandle()->SendWindowProperty(*this, 2, m_Beacon->GetSecondaryEffect());
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cEnchantingWindow:
-
-cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) :
- cWindow(wtEnchantment, "Enchant"),
- m_SlotArea(),
- m_BlockX(a_BlockX),
- m_BlockY(a_BlockY),
- m_BlockZ(a_BlockZ)
-{
- m_SlotAreas.push_back(new cSlotAreaEnchanting(*this, m_BlockX, m_BlockY, m_BlockZ));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-}
-
-
-
-
-
-void cEnchantingWindow::SetProperty(short a_Property, short a_Value)
-{
- if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
- {
- ASSERT(!"a_Property is invalid");
- return;
- }
-
- m_PropertyValue[a_Property] = a_Value;
- super::SetProperty(a_Property, a_Value);
-}
-
-
-
-
-
-void cEnchantingWindow::SetProperty(short a_Property, short a_Value, cPlayer & a_Player)
-{
- if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
- {
- ASSERT(!"a_Property is invalid");
- return;
- }
-
- m_PropertyValue[a_Property] = a_Value;
- super::SetProperty(a_Property, a_Value, a_Player);
-}
-
-
-
-
-
-short cEnchantingWindow::GetPropertyValue(short a_Property)
-{
- if ((a_Property < 0) || ((size_t)a_Property >= ARRAYCOUNT(m_PropertyValue)))
- {
- ASSERT(!"a_Property is invalid");
- return 0;
- }
-
- return m_PropertyValue[a_Property];
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cChestWindow:
-
-cChestWindow::cChestWindow(cChestEntity * a_Chest) :
- cWindow(wtChest, (a_Chest->GetBlockType() == E_BLOCK_CHEST) ? "Chest" : "Trapped Chest"),
- m_World(a_Chest->GetWorld()),
- m_BlockX(a_Chest->GetPosX()),
- m_BlockY(a_Chest->GetPosY()),
- m_BlockZ(a_Chest->GetPosZ()),
- m_PrimaryChest(a_Chest),
- m_SecondaryChest(nullptr)
-{
- m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this));
- m_SlotAreas.push_back(new cSlotAreaInventory(*this));
- m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
-
- // Play the opening sound:
- m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-
- // Send out the chest-open packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_Chest->GetBlockType());
-}
-
-
-
-
-
-cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) :
- cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"),
- m_World(a_PrimaryChest->GetWorld()),
- m_BlockX(a_PrimaryChest->GetPosX()),
- m_BlockY(a_PrimaryChest->GetPosY()),
- m_BlockZ(a_PrimaryChest->GetPosZ()),
- m_PrimaryChest(a_PrimaryChest),
- m_SecondaryChest(a_SecondaryChest)
-{
- m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this));
- 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);
-
- // Send out the chest-open packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_PrimaryChest->GetBlockType());
-}
-
-
-
-
-
-void cChestWindow::OpenedByPlayer(cPlayer & a_Player)
-{
- int ChunkX, ChunkZ;
-
- m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1);
- cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
- m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
-
- if (m_SecondaryChest != nullptr)
- {
- m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1);
- cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
- m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
- }
-
- cWindow::OpenedByPlayer(a_Player);
-}
-
-
-
-
-
-bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
-{
- int ChunkX, ChunkZ;
-
- m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1);
- cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
- m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
-
- if (m_SecondaryChest != nullptr)
- {
- m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1);
- cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
- m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
- }
-
- cWindow::ClosedByPlayer(a_Player, a_CanRefuse);
- return true;
-}
-
-
-
-
-
-cChestWindow::~cChestWindow()
-{
- // Send out the chest-close packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, m_PrimaryChest->GetBlockType());
-
- m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cMinecartWithChestWindow:
-
-cMinecartWithChestWindow::cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart) :
- 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));
-
- a_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestopen", a_ChestCart->GetPosX(), a_ChestCart->GetPosY(), a_ChestCart->GetPosZ(), 1, 1);
-}
-
-
-
-
-
-cMinecartWithChestWindow::~cMinecartWithChestWindow()
-{
- m_ChestCart->GetWorld()->BroadcastSoundEffect("random.chestclosed", m_ChestCart->GetPosX(), m_ChestCart->GetPosY(), m_ChestCart->GetPosZ(), 1, 1);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cDropSpenserWindow:
-
-cDropSpenserWindow::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));
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cEnderChestWindow:
-
-cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) :
- cWindow(wtChest, "Ender Chest"),
- m_World(a_EnderChest->GetWorld()),
- m_BlockX(a_EnderChest->GetPosX()),
- 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));
-
- // Play the opening sound:
- m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-
- // Send out the chest-open packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST);
-}
-
-
-
-
-
-cEnderChestWindow::~cEnderChestWindow()
-{
- // Send out the chest-close packet:
- m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST);
-
- // Play the closing sound
- m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cHopperWindow:
-
-cHopperWindow::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));
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cFurnaceWindow:
-
-cFurnaceWindow::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));
-}
-
-
-
-
diff --git a/src/UI/Window.h b/src/UI/Window.h
index e62176d50..9821aade1 100644
--- a/src/UI/Window.h
+++ b/src/UI/Window.h
@@ -19,7 +19,6 @@ class cPlayer;
class cWindowOwner;
class cClientHandle;
class cChestEntity;
-class cDropSpenserEntity;
class cEnderChestEntity;
class cFurnaceEntity;
class cHopperEntity;
@@ -154,14 +153,19 @@ public:
/** Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is distributed!
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) */
+ virtual void DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply) = 0;
+
+ /** Called from DistributeStack() to distribute the stack into a_AreasInOrder; Modifies a_ItemStack as it is distributed!
+ 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);
+ If a_BackFill is true, the areas will be filled from the back (right side). (Example: Empty Hotbar -> Item get in slot 8, not slot 0) */
+ void DistributeStackToAreas(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
@@ -178,7 +182,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;
@@ -219,188 +222,3 @@ protected:
-
-class cCraftingWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
-} ;
-
-
-
-
-
-class cAnvilWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
-
- /** Gets the repaired item name. */
- AString GetRepairedItemName(void) const { return m_RepairedItemName; }
-
- /** Set the repaired item name. */
- void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player);
-
- /** Gets the Position from the Anvil */
- void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ);
-
-protected:
- cSlotAreaAnvil * m_AnvilSlotArea;
- AString m_RepairedItemName;
- int m_BlockX, m_BlockY, m_BlockZ;
-} ;
-
-
-
-
-
-class cBeaconWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cBeaconWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconEntity * a_Beacon);
-
- cBeaconEntity * GetBeaconEntity(void) const { return m_Beacon; }
-
- // cWindow Overrides:
- virtual void OpenedByPlayer(cPlayer & a_Player) override;
-
-protected:
- cBeaconEntity * m_Beacon;
-} ;
-
-
-
-
-
-class cEnchantingWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ);
- virtual void SetProperty(short a_Property, short a_Value, cPlayer & a_Player) override;
- virtual void SetProperty(short a_Property, short a_Value) override;
-
- /** Return the Value of a Property */
- short GetPropertyValue(short a_Property);
-
- cSlotArea * m_SlotArea;
-
-protected:
- short m_PropertyValue[3];
- int m_BlockX, m_BlockY, m_BlockZ;
-};
-
-
-
-
-
-class cFurnaceWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace);
-} ;
-
-
-
-
-
-class cDropSpenserWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_Dispenser);
-} ;
-
-
-
-
-
-class cHopperWindow :
- public cWindow
-{
- typedef cWindow super;
-public:
- cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper);
-} ;
-
-
-
-
-
-class cChestWindow :
- public cWindow
-{
-public:
- cChestWindow(cChestEntity * a_Chest);
- cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest);
- ~cChestWindow();
-
- virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
- virtual void OpenedByPlayer(cPlayer & a_Player) override;
-
-protected:
- cWorld * m_World;
- int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet
- cChestEntity * m_PrimaryChest;
- cChestEntity * m_SecondaryChest;
-} ;
-
-
-
-
-
-class cMinecartWithChestWindow :
- public cWindow
-{
-public:
- cMinecartWithChestWindow(cMinecartWithChest * a_ChestCart);
- ~cMinecartWithChestWindow();
-private:
- cMinecartWithChest * m_ChestCart;
-};
-
-
-
-
-
-class cEnderChestWindow :
- public cWindow
-{
-public:
- cEnderChestWindow(cEnderChestEntity * a_EnderChest);
- ~cEnderChestWindow();
-
-protected:
- cWorld * m_World;
- int m_BlockX, m_BlockY, m_BlockZ; // Position of the enderchest, for the window-close packet
-};
-
-
-
-
-
-class cInventoryWindow :
- public cWindow
-{
-public:
- cInventoryWindow(cPlayer & a_Player);
-
-protected:
- cPlayer & m_Player;
-
-} ;
-
-
-
-
-