diff options
Diffstat (limited to 'src/UI')
-rw-r--r-- | src/UI/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/UI/SlotArea.cpp | 390 | ||||
-rw-r--r-- | src/UI/SlotArea.h | 39 | ||||
-rw-r--r-- | src/UI/Window.cpp | 60 | ||||
-rw-r--r-- | src/UI/Window.h | 34 |
5 files changed, 512 insertions, 12 deletions
diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt index cef2a9f35..5b5b8cc18 100644 --- a/src/UI/CMakeLists.txt +++ b/src/UI/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(UI ${SOURCE}) diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 88977e005..87b4032e0 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -13,6 +13,8 @@ #include "Window.h" #include "../CraftingRecipes.h" #include "../Root.h" +#include "../FastRandom.h" +#include "../BlockArea.h" @@ -145,6 +147,7 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA FreeSlots = 0; } int Filling = (FreeSlots > DraggingItem.m_ItemCount) ? DraggingItem.m_ItemCount : FreeSlots; + Slot.m_ItemCount += (char)Filling; DraggingItem.m_ItemCount -= (char)Filling; if (DraggingItem.m_ItemCount <= 0) @@ -167,7 +170,6 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA { m_ParentWindow.BroadcastWholeWindow(); } - } @@ -483,6 +485,7 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player) // Get the current recipe: cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); + const cItem & Result = Recipe.GetResult(); cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1; cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize); @@ -490,16 +493,16 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player) // If possible, craft: if (DraggingItem.IsEmpty()) { - DraggingItem = Recipe.GetResult(); + DraggingItem = Result; Recipe.ConsumeIngredients(Grid); Grid.CopyToItems(PlayerSlots); } - else if (DraggingItem.IsEqual(Recipe.GetResult())) + else if (DraggingItem.IsEqual(Result)) { - cItemHandler * Handler = ItemHandler(Recipe.GetResult().m_ItemType); - if (DraggingItem.m_ItemCount + Recipe.GetResult().m_ItemCount <= Handler->GetMaxStackSize()) + cItemHandler * Handler = ItemHandler(Result.m_ItemType); + if (DraggingItem.m_ItemCount + Result.m_ItemCount <= Handler->GetMaxStackSize()) { - DraggingItem.m_ItemCount += Recipe.GetResult().m_ItemCount; + DraggingItem.m_ItemCount += Result.m_ItemCount; Recipe.ConsumeIngredients(Grid); Grid.CopyToItems(PlayerSlots); } @@ -593,6 +596,307 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cSlotAreaEnchanting: + +cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) : + cSlotAreaTemporary(1, a_ParentWindow) +{ + a_ParentWindow.m_SlotArea = this; +} + + + + + +void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + switch (a_ClickAction) + { + case caShiftLeftClick: + case caShiftRightClick: + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + + case caDblClick: + { + DblClicked(a_Player, a_SlotNum); + return; + } + default: + { + break; + } + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + switch (a_ClickAction) + { + case caRightClick: + { + // Right-clicked + if (DraggingItem.IsEmpty()) + { + DraggingItem = Slot.CopyOne(); + Slot.Empty(); + break; + } + + if (Slot.IsEmpty()) + { + Slot = DraggingItem.CopyOne(); + DraggingItem.m_ItemCount -= 1; + if (DraggingItem.m_ItemCount <= 0) + { + DraggingItem.Empty(); + } + } + else if ((!DraggingItem.IsEqual(Slot)) && (DraggingItem.m_ItemCount == 1)) + { + // Swap contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + break; + } + + case caLeftClick: + { + // Left-clicked + if (DraggingItem.IsEmpty()) + { + DraggingItem = Slot.CopyOne(); + Slot.Empty(); + break; + } + + if (DraggingItem.IsEqual(Slot)) + { + // Do nothing + break; + } + + if (!Slot.IsEmpty()) + { + if (DraggingItem.m_ItemCount == 1) + { + // Swap contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + } + else + { + Slot = DraggingItem.CopyOne(); + DraggingItem.m_ItemCount -= 1; + if (DraggingItem.m_ItemCount <= 0) + { + DraggingItem.Empty(); + } + } + break; + } + default: + { + LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction)); + m_ParentWindow.BroadcastWholeWindow(); + return; + } + } // switch (a_ClickAction + + SetSlot(a_SlotNum, a_Player, Slot); + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } + UpdateResult(a_Player); +} + + + + + +void cSlotAreaEnchanting::DblClicked(cPlayer & a_Player, int a_SlotNum) +{ + cItem & Dragging = a_Player.GetDraggingItem(); + if ((!Dragging.IsEmpty()) || (a_SlotNum != 0)) + { + return; + } + + cItem Item = *GetSlot(0, a_Player); + if (!m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, false)) + { + m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, true); + } +} + + + + + +void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) +{ + const cItem * Slot = GetSlot(0, a_Player); + if (!Slot->IsEmpty()) + { + return; + } + + if (a_Apply) + { + SetSlot(0, a_Player, a_ItemStack.CopyOne()); + } + a_ItemStack.m_ItemCount -= 1; + if (a_ItemStack.m_ItemCount <= 0) + { + a_ItemStack.Empty(); + } + + UpdateResult(a_Player); +} + + + + + +void cSlotAreaEnchanting::OnPlayerRemoved(cPlayer & a_Player) +{ + // Toss the item in the enchanting slot + TossItems(a_Player, 0, 1); + + super::OnPlayerRemoved(a_Player); +} + + + + + +void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player) +{ + cItem Item = *GetSlot(0, a_Player); + + if (Item.IsEmpty() || !Item.m_Enchantments.IsEmpty()) + { + m_ParentWindow.SetProperty(0, 0, a_Player); + m_ParentWindow.SetProperty(1, 0, a_Player); + m_ParentWindow.SetProperty(2, 0, a_Player); + } + else if (cItem::IsEnchantable(Item.m_ItemType) || Item.m_ItemType == E_ITEM_BOOK) + { + int Bookshelves = std::min(GetBookshelvesCount(a_Player.GetWorld()), 15); + + cFastRandom Random; + int base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves)); + int topSlot = std::max(base / 3, 1); + int middleSlot = (base * 2) / 3 + 1; + int bottomSlot = std::max(base, Bookshelves * 2); + + m_ParentWindow.SetProperty(0, topSlot, a_Player); + m_ParentWindow.SetProperty(1, middleSlot, a_Player); + m_ParentWindow.SetProperty(2, bottomSlot, a_Player); + } + else + { + m_ParentWindow.SetProperty(0, 0, a_Player); + m_ParentWindow.SetProperty(1, 0, a_Player); + m_ParentWindow.SetProperty(2, 0, a_Player); + } +} + + + + + +int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World) +{ + int PosX, PosY, PosZ; + ((cEnchantingWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ); + + int Bookshelves = 0; + cBlockArea Area; + Area.Read(a_World, PosX - 2, PosX + 2, PosY, PosY + 1, PosZ - 2, PosZ + 2); + + static const struct + { + int m_BookX, m_BookY, m_BookZ; // Coords to check for bookcases + int m_AirX, m_AirY, m_AirZ; // Coords to check for air; if not air, the bookcase won't be counted + } CheckCoords[] = + { + { 0, 0, 0, 1, 0, 1 }, // Bookcase at {0, 0, 0}, air at {1, 0, 1} + { 0, 0, 1, 1, 0, 1 }, // Bookcase at {0, 0, 1}, air at {1, 0, 1} + { 0, 0, 2, 1, 0, 2 }, // Bookcase at {0, 0, 2}, air at {1, 0, 2} + { 0, 0, 3, 1, 0, 3 }, // Bookcase at {0, 0, 3}, air at {1, 0, 3} + { 0, 0, 4, 1, 0, 3 }, // Bookcase at {0, 0, 4}, air at {1, 0, 3} + { 1, 0, 4, 1, 0, 3 }, // Bookcase at {1, 0, 4}, air at {1, 0, 3} + { 2, 0, 4, 2, 0, 3 }, // Bookcase at {2, 0, 4}, air at {2, 0, 3} + { 3, 0, 4, 3, 0, 3 }, // Bookcase at {3, 0, 4}, air at {3, 0, 3} + { 4, 0, 4, 3, 0, 3 }, // Bookcase at {4, 0, 4}, air at {3, 0, 3} + { 4, 0, 3, 3, 0, 3 }, // Bookcase at {4, 0, 3}, air at {3, 0, 3} + { 4, 0, 2, 3, 0, 2 }, // Bookcase at {4, 0, 2}, air at {3, 0, 2} + { 4, 0, 1, 3, 0, 1 }, // Bookcase at {4, 0, 1}, air at {3, 0, 1} + { 4, 0, 0, 3, 0, 1 }, // Bookcase at {4, 0, 0}, air at {3, 0, 1} + { 3, 0, 0, 3, 0, 1 }, // Bookcase at {3, 0, 0}, air at {3, 0, 1} + { 2, 0, 0, 2, 0, 1 }, // Bookcase at {2, 0, 0}, air at {2, 0, 1} + { 1, 0, 0, 1, 0, 1 }, // Bookcase at {1, 0, 0}, air at {1, 0, 1} + + { 0, 1, 0, 1, 1, 1 }, // Bookcase at {0, 1, 0}, air at {1, 1, 1} + { 0, 1, 1, 1, 1, 1 }, // Bookcase at {0, 1, 1}, air at {1, 1, 1} + { 0, 1, 2, 1, 1, 2 }, // Bookcase at {0, 1, 2}, air at {1, 1, 2} + { 0, 1, 3, 1, 1, 3 }, // Bookcase at {0, 1, 3}, air at {1, 1, 3} + { 0, 1, 4, 1, 1, 3 }, // Bookcase at {0, 1, 4}, air at {1, 1, 3} + { 1, 1, 4, 1, 1, 3 }, // Bookcase at {1, 1, 4}, air at {1, 1, 3} + { 2, 1, 4, 2, 1, 3 }, // Bookcase at {2, 1, 4}, air at {2, 1, 3} + { 3, 1, 4, 3, 1, 3 }, // Bookcase at {3, 1, 4}, air at {3, 1, 3} + { 4, 1, 4, 3, 1, 3 }, // Bookcase at {4, 1, 4}, air at {3, 1, 3} + { 4, 1, 3, 3, 1, 3 }, // Bookcase at {4, 1, 3}, air at {3, 1, 3} + { 4, 1, 2, 3, 1, 2 }, // Bookcase at {4, 1, 2}, air at {3, 1, 2} + { 4, 1, 1, 3, 1, 1 }, // Bookcase at {4, 1, 1}, air at {3, 1, 1} + { 4, 1, 0, 3, 1, 1 }, // Bookcase at {4, 1, 0}, air at {3, 1, 1} + { 3, 1, 0, 3, 1, 1 }, // Bookcase at {3, 1, 0}, air at {3, 1, 1} + { 2, 1, 0, 2, 1, 1 }, // Bookcase at {2, 1, 0}, air at {2, 1, 1} + { 1, 1, 0, 1, 1, 1 }, // Bookcase at {1, 1, 0}, air at {1, 1, 1} + }; + + for (size_t i = 0; i < ARRAYCOUNT(CheckCoords); i++) + { + if ( + (Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot + (Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place + ) + { + Bookshelves++; + } + } // for i - CheckCoords + + return Bookshelves; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaEnderChest: cSlotAreaEnderChest::cSlotAreaEnderChest(cEnderChestEntity * a_EnderChest, cWindow & a_ParentWindow) : @@ -787,6 +1091,80 @@ void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bo +void cSlotAreaArmor::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + + // Armors haven't a dbl click + if (a_ClickAction == caDblClick) + { + return; + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + if ((a_ClickAction != caRightClick) && (a_ClickAction != caLeftClick)) + { + LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction)); + m_ParentWindow.BroadcastWholeWindow(); + return; + } + + if (DraggingItem.IsEmpty() || CanPlaceInSlot(a_SlotNum, DraggingItem)) + { + // Swap contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + + SetSlot(a_SlotNum, a_Player, Slot); + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } +} + + + + + +bool cSlotAreaArmor::CanPlaceInSlot(int a_SlotNum, const cItem & a_Item) +{ + switch (a_SlotNum) + { + case 0: return ItemCategory::IsHelmet (a_Item.m_ItemType); + case 1: return ItemCategory::IsChestPlate(a_Item.m_ItemType); + case 2: return ItemCategory::IsLeggings (a_Item.m_ItemType); + case 3: return ItemCategory::IsBoots (a_Item.m_ItemType); + } + return false; +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaItemGrid: diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 25b367cff..254722822 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -19,6 +19,8 @@ class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; class cCraftingRecipe; +class cEnchantingWindow; +class cWorld; @@ -66,7 +68,7 @@ public: /// If a_CollectFullStacks is false, slots with full stacks are skipped while collecting. /// Returns true if full stack has been collected in a_Dragging, false if there's space remaining to fill. virtual bool CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks); - + protected: int m_NumSlots; cWindow & m_ParentWindow; @@ -143,8 +145,13 @@ public: { } - // Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) + /** 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; + + /** 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; + + bool CanPlaceInSlot(int a_SlotNum, const cItem & a_Item); } ; @@ -252,6 +259,34 @@ protected: +class cSlotAreaEnchanting : + public cSlotAreaTemporary +{ + typedef cSlotAreaTemporary super; + +public: + cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow); + + // cSlotArea overrides: + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + virtual void DblClicked(cPlayer & a_Player, int a_SlotNum) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + + // cSlotAreaTemporary overrides: + virtual void OnPlayerRemoved(cPlayer & a_Player) override; + + /* Get the count of bookshelves who stand in the near of the enchanting table */ + int GetBookshelvesCount(cWorld * a_World); + +protected: + /** Handles a click in the item slot. */ + void UpdateResult(cPlayer & a_Player); +}; + + + + + class cSlotAreaChest : public cSlotArea { diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index aae7b99a3..0a78578fc 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -805,6 +805,66 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cEnchantingWindow: + +cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : + cWindow(wtEnchantment, "Enchant"), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) +{ + m_SlotAreas.push_back(new cSlotAreaEnchanting(*this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cEnchantingWindow::SetProperty(int a_Property, int a_Value) +{ + m_PropertyValue[a_Property] = a_Value; + + super::SetProperty(a_Property, a_Value); +} + + + + + +void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player) +{ + m_PropertyValue[a_Property] = a_Value; + + super::SetProperty(a_Property, a_Value, a_Player); +} + + + + + +int cEnchantingWindow::GetPropertyValue(int a_Property) +{ + return m_PropertyValue[a_Property]; +} + + + + + +void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) +{ + a_PosX = m_BlockX; + a_PosY = m_BlockY; + a_PosZ = m_BlockZ; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cChestWindow: cChestWindow::cChestWindow(cChestEntity * a_Chest) : diff --git a/src/UI/Window.h b/src/UI/Window.h index 030182888..1ca67bfd8 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -136,11 +136,11 @@ public: void SetWindowTitle(const AString & a_WindowTitle ) { m_WindowTitle = a_WindowTitle; } /// Sends the UpdateWindowProperty (0x69) packet to all clients of the window - void SetProperty(int a_Property, int a_Value); + virtual void SetProperty(int a_Property, int a_Value); /// Sends the UpdateWindowPropert(0x69) packet to the specified player - void SetProperty(int a_Property, int a_Value, cPlayer & a_Player); - + virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player); + // tolua_end void OwnerDestroyed(void); @@ -165,7 +165,7 @@ public: /// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum); - + protected: cSlotAreas m_SlotAreas; @@ -231,6 +231,32 @@ public: +class cEnchantingWindow : + public cWindow +{ + typedef cWindow super; +public: + cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); + virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player) override; + virtual void SetProperty(int a_Property, int a_Value) override; + + /** Return the Value of a Property */ + int GetPropertyValue(int a_Property); + + /** Set the Position Values to the Position of the Enchantment Table */ + void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); + + cSlotArea * m_SlotArea; + +protected: + int m_PropertyValue[3]; + int m_BlockX, m_BlockY, m_BlockZ; +}; + + + + + class cFurnaceWindow : public cWindow { |