diff options
author | worktycho <work.tycho@gmail.com> | 2013-12-09 18:51:12 +0100 |
---|---|---|
committer | worktycho <work.tycho@gmail.com> | 2013-12-09 18:51:12 +0100 |
commit | 843605d59ebc128be0a578dc6f45ef8c05da6e79 (patch) | |
tree | 3ffebc6ba27baf7a9e1d4bc51501ffeea9b14226 /source/UI | |
parent | merged makefile changes (diff) | |
parent | Fix Undefined behavior at Bindings/LuaWindow line 32 (diff) | |
download | cuberite-843605d59ebc128be0a578dc6f45ef8c05da6e79.tar cuberite-843605d59ebc128be0a578dc6f45ef8c05da6e79.tar.gz cuberite-843605d59ebc128be0a578dc6f45ef8c05da6e79.tar.bz2 cuberite-843605d59ebc128be0a578dc6f45ef8c05da6e79.tar.lz cuberite-843605d59ebc128be0a578dc6f45ef8c05da6e79.tar.xz cuberite-843605d59ebc128be0a578dc6f45ef8c05da6e79.tar.zst cuberite-843605d59ebc128be0a578dc6f45ef8c05da6e79.zip |
Diffstat (limited to 'source/UI')
-rw-r--r-- | source/UI/SlotArea.cpp | 815 | ||||
-rw-r--r-- | source/UI/SlotArea.h | 303 | ||||
-rw-r--r-- | source/UI/Window.cpp | 841 | ||||
-rw-r--r-- | source/UI/Window.h | 288 | ||||
-rw-r--r-- | source/UI/WindowOwner.h | 125 |
5 files changed, 0 insertions, 2372 deletions
diff --git a/source/UI/SlotArea.cpp b/source/UI/SlotArea.cpp deleted file mode 100644 index 9213d4ff8..000000000 --- a/source/UI/SlotArea.cpp +++ /dev/null @@ -1,815 +0,0 @@ - -// SlotArea.cpp - -// Implements the cSlotArea class and its descendants - -#include "Globals.h" -#include "SlotArea.h" -#include "../Entities/Player.h" -#include "../BlockEntities/ChestEntity.h" -#include "../BlockEntities/DropSpenserEntity.h" -#include "../BlockEntities/FurnaceEntity.h" -#include "../Items/ItemHandler.h" -#include "Window.h" -#include "../CraftingRecipes.h" -#include "../Root.h" - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotArea: - -cSlotArea::cSlotArea(int a_NumSlots, cWindow & a_ParentWindow) : - m_NumSlots(a_NumSlots), - m_ParentWindow(a_ParentWindow) -{ -} - - - - - -void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) -{ - /* - LOGD("Slot area with %d slots clicked at slot number %d, clicked item %s, slot item %s", - GetNumSlots(), a_SlotNum, - ItemToFullString(a_ClickedItem).c_str(), - ItemToFullString(*GetSlot(a_SlotNum, a_Player)).c_str() - ); - */ - - 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)) - { - if (!a_Player.IsDraggingItem()) - { - ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); - return; - } - LOGD("Shift clicked, but the player is dragging an item: %s", ItemToFullString(a_Player.GetDraggingItem()).c_str()); - return; - } - - 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: - { - if (DraggingItem.m_ItemType <= 0) // Empty-handed? - { - DraggingItem.m_ItemCount = (char)(((float)Slot.m_ItemCount) / 2.f + 0.5f); - Slot.m_ItemCount -= DraggingItem.m_ItemCount; - DraggingItem.m_ItemType = Slot.m_ItemType; - DraggingItem.m_ItemDamage = Slot.m_ItemDamage; - - if (Slot.m_ItemCount <= 0) - { - Slot.Empty(); - } - } - else if ((Slot.m_ItemType <= 0) || DraggingItem.IsEqual(Slot)) - { - // Drop one item in slot - cItemHandler * Handler = ItemHandler(Slot.m_ItemType); - if ((DraggingItem.m_ItemCount > 0) && (Slot.m_ItemCount < Handler->GetMaxStackSize())) - { - Slot.m_ItemType = DraggingItem.m_ItemType; - Slot.m_ItemCount++; - Slot.m_ItemDamage = DraggingItem.m_ItemDamage; - DraggingItem.m_ItemCount--; - } - if (DraggingItem.m_ItemCount <= 0) - { - DraggingItem.Empty(); - } - } - else if (!DraggingItem.IsEqual(Slot)) - { - // Swap contents - cItem tmp(DraggingItem); - DraggingItem = Slot; - Slot = tmp; - } - break; - } - - case caLeftClick: - { - // Left-clicked - if (!DraggingItem.IsEqual(Slot)) - { - // Switch contents - cItem tmp(DraggingItem); - DraggingItem = Slot; - Slot = tmp; - } - else - { - // Same type, add items: - cItemHandler * Handler = ItemHandler(DraggingItem.m_ItemType); - int FreeSlots = Handler->GetMaxStackSize() - Slot.m_ItemCount; - if (FreeSlots < 0) - { - ASSERT(!"Bad item stack size - where did we get more items in a slot than allowed?"); - 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) - { - 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(); - } - -} - - - - - -void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) -{ - // 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); - if (Slot.IsEmpty()) - { - // Empty the slot completely, the cilent doesn't like left-over ItemType with zero count - Slot.Empty(); - } - SetSlot(a_SlotNum, a_Player, Slot); - - // Some clients try to guess our actions and not always right (armor slots in 1.2.5), so we fix them: - m_ParentWindow.BroadcastWholeWindow(); -} - - - - - -void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) -{ - for (int i = 0; i < m_NumSlots; i++) - { - const cItem * Slot = GetSlot(i, a_Player); - if (!Slot->IsStackableWith(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_Apply) - { - 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 -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotAreaChest: - -cSlotAreaChest::cSlotAreaChest(cChestEntity * a_Chest, cWindow & a_ParentWindow) : - cSlotArea(27, a_ParentWindow), - m_Chest(a_Chest) -{ -} - - - - - -const cItem * cSlotAreaChest::GetSlot(int a_SlotNum, cPlayer & a_Player) const -{ - // a_SlotNum ranges from 0 to 26, use that to index the chest entity's inventory directly: - return &(m_Chest->GetSlot(a_SlotNum)); -} - - - - - -void cSlotAreaChest::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) -{ - m_Chest->SetSlot(a_SlotNum, a_Item); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotAreaDoubleChest: - -cSlotAreaDoubleChest::cSlotAreaDoubleChest(cChestEntity * a_TopChest, cChestEntity * a_BottomChest, cWindow & a_ParentWindow) : - cSlotArea(54, a_ParentWindow), - m_TopChest(a_TopChest), - m_BottomChest(a_BottomChest) -{ -} - - - - - -const cItem * cSlotAreaDoubleChest::GetSlot(int a_SlotNum, cPlayer & a_Player) const -{ - // a_SlotNum ranges from 0 to 53, use that to index the correct chest's inventory: - if (a_SlotNum < 27) - { - return &(m_TopChest->GetSlot(a_SlotNum)); - } - else - { - return &(m_BottomChest->GetSlot(a_SlotNum - 27)); - } -} - - - - - -void cSlotAreaDoubleChest::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) -{ - if (a_SlotNum < 27) - { - m_TopChest->SetSlot(a_SlotNum, a_Item); - } - else - { - m_BottomChest->SetSlot(a_SlotNum - 27, a_Item); - } -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotAreaCrafting: - -cSlotAreaCrafting::cSlotAreaCrafting(int a_GridSize, cWindow & a_ParentWindow) : - cSlotAreaTemporary(1 + a_GridSize * a_GridSize, a_ParentWindow), - m_GridSize(a_GridSize) -{ - ASSERT((a_GridSize == 2) || (a_GridSize == 3)); -} - - - - - -void cSlotAreaCrafting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) -{ - // Override for craft result slot - if (a_SlotNum == 0) - { - if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) - { - ShiftClickedResult(a_Player); - } - else - { - ClickedResult(a_Player); - } - return; - } - super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem); - UpdateRecipe(a_Player); -} - - - - - -void cSlotAreaCrafting::OnPlayerRemoved(cPlayer & a_Player) -{ - // Toss all items on the crafting grid: - TossItems(a_Player, 1, m_NumSlots); - - // Remove the current recipe from the player -> recipe map: - for (cRecipeMap::iterator itr = m_Recipes.begin(), end = m_Recipes.end(); itr != end; ++itr) - { - if (itr->first == a_Player.GetUniqueID()) - { - // Remove the player from the recipe map: - m_Recipes.erase(itr); - return; - } - } // for itr - m_Recipes[] - // Player not found - that is acceptable -} - - - - - -void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player) -{ - const cItem * ResultSlot = GetSlot(0, a_Player); - cItem & DraggingItem = a_Player.GetDraggingItem(); - - // Get the current recipe: - cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); - - cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1; - cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize); - - // If possible, craft: - if (DraggingItem.IsEmpty()) - { - DraggingItem = Recipe.GetResult(); - Recipe.ConsumeIngredients(Grid); - Grid.CopyToItems(PlayerSlots); - } - else if (DraggingItem.IsEqual(Recipe.GetResult())) - { - cItemHandler * Handler = ItemHandler(Recipe.GetResult().m_ItemType); - if (DraggingItem.m_ItemCount + Recipe.GetResult().m_ItemCount <= Handler->GetMaxStackSize()) - { - DraggingItem.m_ItemCount += Recipe.GetResult().m_ItemCount; - Recipe.ConsumeIngredients(Grid); - Grid.CopyToItems(PlayerSlots); - } - } - - // Get the new recipe and update the result slot: - UpdateRecipe(a_Player); - - // We're done. Send all changes to the client and bail out: - m_ParentWindow.BroadcastWholeWindow(); -} - - - - - -void cSlotAreaCrafting::ShiftClickedResult(cPlayer & a_Player) -{ - cItem Result(*GetSlot(0, a_Player)); - if (Result.IsEmpty()) - { - return; - } - cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1; - do - { - // Try distributing the result. If it fails, bail out: - cItem ResultCopy(Result); - m_ParentWindow.DistributeStack(ResultCopy, a_Player, this, false); - if (!ResultCopy.IsEmpty()) - { - // Couldn't distribute all of it. Bail out - return; - } - - // Distribute the result, this time for real: - ResultCopy = Result; - m_ParentWindow.DistributeStack(ResultCopy, a_Player, this, true); - - // Remove the ingredients from the crafting grid and update the recipe: - cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); - cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize); - Recipe.ConsumeIngredients(Grid); - Grid.CopyToItems(PlayerSlots); - UpdateRecipe(a_Player); - if (!Recipe.GetResult().IsEqual(Result)) - { - // The recipe has changed, bail out - return; - } - } while (true); -} - - - - - -void cSlotAreaCrafting::UpdateRecipe(cPlayer & a_Player) -{ - cCraftingGrid Grid(GetPlayerSlots(a_Player) + 1, m_GridSize, m_GridSize); - cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); - cRoot::Get()->GetCraftingRecipes()->GetRecipe(&a_Player, Grid, Recipe); - SetSlot(0, a_Player, Recipe.GetResult()); - m_ParentWindow.SendSlot(a_Player, this, 0); -} - - - - - -cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player) -{ - for (cRecipeMap::iterator itr = m_Recipes.begin(), end = m_Recipes.end(); itr != end; ++itr) - { - if (itr->first == a_Player.GetUniqueID()) - { - return itr->second; - } - } // for itr - m_Recipes[] - - // Not found. Add a new one: - cCraftingGrid Grid(GetPlayerSlots(a_Player) + 1, m_GridSize, m_GridSize); - cCraftingRecipe Recipe(Grid); - cRoot::Get()->GetCraftingRecipes()->GetRecipe(&a_Player, Grid, Recipe); - m_Recipes.push_back(std::make_pair(a_Player.GetUniqueID(), Recipe)); - return m_Recipes.back().second; -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotAreaFurnace: - -cSlotAreaFurnace::cSlotAreaFurnace(cFurnaceEntity * a_Furnace, cWindow & a_ParentWindow) : - cSlotArea(3, a_ParentWindow), - m_Furnace(a_Furnace) -{ - m_Furnace->GetContents().AddListener(*this); -} - - - - - -cSlotAreaFurnace::~cSlotAreaFurnace() -{ - m_Furnace->GetContents().RemoveListener(*this); -} - - - - - -void cSlotAreaFurnace::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) -{ - super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem); - - if (m_Furnace == NULL) - { - LOGERROR("cSlotAreaFurnace::Clicked(): m_Furnace == NULL"); - ASSERT(!"cSlotAreaFurnace::Clicked(): m_Furnace == NULL"); - return; - } -} - - - - - -const cItem * cSlotAreaFurnace::GetSlot(int a_SlotNum, cPlayer & a_Player) const -{ - // a_SlotNum ranges from 0 to 2, query the items from the underlying furnace: - return &(m_Furnace->GetSlot(a_SlotNum)); -} - - - - - -void cSlotAreaFurnace::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) -{ - m_Furnace->SetSlot(a_SlotNum, a_Item); -} - - - - - -void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) -{ - // Something has changed in the window, broadcast the entire window to all clients - ASSERT(a_ItemGrid == &(m_Furnace->GetContents())); - - m_ParentWindow.BroadcastWholeWindow(); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotAreaInventoryBase: - -cSlotAreaInventoryBase::cSlotAreaInventoryBase(int a_NumSlots, int a_SlotOffset, cWindow & a_ParentWindow) : - cSlotArea(a_NumSlots, a_ParentWindow), - m_SlotOffset(a_SlotOffset) -{ -} - - - - - -void cSlotAreaInventoryBase::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) -{ - if ((a_Player.GetGameMode() == eGameMode_Creative) && (m_ParentWindow.GetWindowType() == cWindow::Inventory)) - { - // Creative inventory must treat a_ClickedItem as a DraggedItem instead, replacing the inventory slot with it - SetSlot(a_SlotNum, a_Player, a_ClickedItem); - return; - } - - // Survival inventory and all other windows' inventory has the same handling as normal slot areas - super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem); - return; -} - - - - - -const cItem * cSlotAreaInventoryBase::GetSlot(int a_SlotNum, cPlayer & a_Player) const -{ - // a_SlotNum ranges from 0 to 35, map that to the player's inventory slots according to the internal offset - return &a_Player.GetInventory().GetSlot(a_SlotNum + m_SlotOffset); -} - - - - - -void cSlotAreaInventoryBase::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) -{ - a_Player.GetInventory().SetSlot(a_SlotNum + m_SlotOffset, a_Item); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotAreaArmor: - -void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) -{ - if (ItemCategory::IsHelmet(a_ItemStack.m_ItemType) && GetSlot(0, a_Player)->IsEmpty()) - { - if (a_ShouldApply) - { - SetSlot(0, a_Player, a_ItemStack.CopyOne()); - } - a_ItemStack.m_ItemCount -= 1; - } - else if (ItemCategory::IsChestPlate(a_ItemStack.m_ItemType) && GetSlot(1, a_Player)->IsEmpty()) - { - if (a_ShouldApply) - { - SetSlot(1, a_Player, a_ItemStack.CopyOne()); - } - a_ItemStack.m_ItemCount -= 1; - } - else if (ItemCategory::IsLeggings(a_ItemStack.m_ItemType) && GetSlot(2, a_Player)->IsEmpty()) - { - if (a_ShouldApply) - { - SetSlot(2, a_Player, a_ItemStack.CopyOne()); - } - a_ItemStack.m_ItemCount -= 1; - } - else if (ItemCategory::IsBoots(a_ItemStack.m_ItemType) && GetSlot(3, a_Player)->IsEmpty()) - { - if (a_ShouldApply) - { - SetSlot(3, a_Player, a_ItemStack.CopyOne()); - } - a_ItemStack.m_ItemCount -= 1; - } -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotAreaItemGrid: - -cSlotAreaItemGrid::cSlotAreaItemGrid(cItemGrid & a_ItemGrid, cWindow & a_ParentWindow) : - super(a_ItemGrid.GetNumSlots(), a_ParentWindow), - m_ItemGrid(a_ItemGrid) -{ - m_ItemGrid.AddListener(*this); -} - - - - - -cSlotAreaItemGrid::~cSlotAreaItemGrid() -{ - m_ItemGrid.RemoveListener(*this); -} - - - - - -const cItem * cSlotAreaItemGrid::GetSlot(int a_SlotNum, cPlayer & a_Player) const -{ - return &m_ItemGrid.GetSlot(a_SlotNum); -} - - - - - -void cSlotAreaItemGrid::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) -{ - m_ItemGrid.SetSlot(a_SlotNum, a_Item); -} - - - - - -void cSlotAreaItemGrid::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) -{ - ASSERT(a_ItemGrid == &m_ItemGrid); - m_ParentWindow.BroadcastSlot(this, a_SlotNum); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSlotAreaTemporary: - -cSlotAreaTemporary::cSlotAreaTemporary(int a_NumSlots, cWindow & a_ParentWindow) : - cSlotArea(a_NumSlots, a_ParentWindow) -{ -} - - - - - -const cItem * cSlotAreaTemporary::GetSlot(int a_SlotNum, cPlayer & a_Player) const -{ - cItemMap::const_iterator itr = m_Items.find(a_Player.GetUniqueID()); - if (itr == m_Items.end()) - { - LOGERROR("cSlotAreaTemporary: player \"%s\" not found for slot %d!", a_Player.GetName().c_str(), a_SlotNum); - ASSERT(!"cSlotAreaTemporary: player not found!"); - - // Player not found, this should not happen, ever! Return NULL, but things may break by this. - return NULL; - } - - if (a_SlotNum >= (int)(itr->second.size())) - { - LOGERROR("cSlotAreaTemporary: asking for more slots than actually stored!"); - ASSERT(!"cSlotAreaTemporary: asking for more slots than actually stored!"); - return NULL; - } - - return &(itr->second[a_SlotNum]); -} - - - - - -void cSlotAreaTemporary::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) -{ - cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID()); - if (itr == m_Items.end()) - { - // Player not found - LOGWARNING("cSlotAreaTemporary: player not found!"); - return; - } - - if (a_SlotNum >= (int)(itr->second.size())) - { - LOGERROR("cSlotAreaTemporary: asking for more slots than actually stored!"); - return; - } - - itr->second[a_SlotNum] = a_Item; -} - - - - - -void cSlotAreaTemporary::OnPlayerAdded(cPlayer & a_Player) -{ - ASSERT(m_Items.find(a_Player.GetUniqueID()) == m_Items.end()); // The player shouldn't be in the itemmap, otherwise we probably have a leak - m_Items[a_Player.GetUniqueID()].resize(m_NumSlots); // Make the vector the specified size of empty items -} - - - - - -void cSlotAreaTemporary::OnPlayerRemoved(cPlayer & a_Player) -{ - cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID()); - ASSERT(itr != m_Items.end()); // The player should be in the list, otherwise a call to OnPlayerAdded() was mismatched - m_Items.erase(itr); -} - - - - - -void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End) -{ - cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID()); - if (itr == m_Items.end()) - { - LOGWARNING("Player tossing items (%s) not found in the item map", a_Player.GetName().c_str()); - return; - } - - cItems Drops; - for (int i = a_Begin; i < a_End; i++) - { - cItem & Item = itr->second[i]; - if (!Item.IsEmpty()) - { - Drops.push_back(Item); - } - Item.Empty(); - } // for i - itr->second[] - - double vX = 0, vY = 0, vZ = 0; - EulerToVector(-a_Player.GetRotation(), a_Player.GetPitch(), vZ, vX, vY); - vY = -vY * 2 + 1.f; - a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 2, vY * 2, vZ * 2); -} - - - - - -cItem * cSlotAreaTemporary::GetPlayerSlots(cPlayer & a_Player) -{ - cItemMap::iterator itr = m_Items.find(a_Player.GetUniqueID()); - if (itr == m_Items.end()) - { - return NULL; - } - return &(itr->second[0]); -} - - - - diff --git a/source/UI/SlotArea.h b/source/UI/SlotArea.h deleted file mode 100644 index 943452feb..000000000 --- a/source/UI/SlotArea.h +++ /dev/null @@ -1,303 +0,0 @@ - -// SlotArea.h - -// Interfaces to the cSlotArea class representing a contiguous area of slots in a UI window - - - - -#pragma once - -#include "../Inventory.h" - - - -class cWindow; -class cPlayer; -class cChestEntity; -class cDropSpenserEntity; -class cFurnaceEntity; -class cCraftingRecipe; - - - - - -class cSlotArea -{ -public: - cSlotArea(int a_NumSlots, cWindow & a_ParentWindow); - virtual ~cSlotArea() {} // force a virtual destructor in all subclasses - - int GetNumSlots(void) const { return m_NumSlots; } - - /// Called to retrieve an item in the specified slot for the specified player. Must return a valid cItem. - virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const = 0; - - /// Called to set an item in the specified slot for the specified player - virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) = 0; - - /// Called when a player clicks in the window. Parameters taken from the click packet. - virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem); - - /// Called from Clicked if it is a valid shiftclick - virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem); - - /// Called when a new player opens the same parent window. The window already tracks the player. CS-locked. - virtual void OnPlayerAdded(cPlayer & a_Player) {} ; - - /// Called when one of the players closes the parent window. The window already doesn't track the player. CS-locked. - virtual void OnPlayerRemoved(cPlayer & a_Player) {} ; - - /** Called to store as much of a_ItemStack in the area as possible. a_ItemStack is modified to reflect the change. - The default implementation searches each slot for available space and distributes the stack there. - 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) - 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); - -protected: - int m_NumSlots; - cWindow & m_ParentWindow; -} ; - - - - - -/// Handles any part of the inventory, using parameters in constructor to distinguish between the parts -class cSlotAreaInventoryBase : - public cSlotArea -{ - typedef cSlotArea super; - -public: - cSlotAreaInventoryBase(int a_NumSlots, int a_SlotOffset, cWindow & a_ParentWindow); - - // Creative inventory's click handling is somewhat different from survival inventory's, handle that here: - virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) 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; - -protected: - int m_SlotOffset; // Index that this area's slot 0 has in the underlying cInventory -} ; - - - - - -/// Handles the main inventory of each player, excluding the armor and hotbar -class cSlotAreaInventory : - public cSlotAreaInventoryBase -{ - typedef cSlotAreaInventoryBase super; - -public: - cSlotAreaInventory(cWindow & a_ParentWindow) : - cSlotAreaInventoryBase(cInventory::invInventoryCount, cInventory::invInventoryOffset, a_ParentWindow) - { - } -} ; - - - - - -/// Handles the hotbar of each player -class cSlotAreaHotBar : - public cSlotAreaInventoryBase -{ - typedef cSlotAreaInventoryBase super; - -public: - cSlotAreaHotBar(cWindow & a_ParentWindow) : - cSlotAreaInventoryBase(cInventory::invHotbarCount, cInventory::invHotbarOffset, a_ParentWindow) - { - } -} ; - - - - - -/// Handles the armor area of the player's inventory -class cSlotAreaArmor : - public cSlotAreaInventoryBase -{ -public: - cSlotAreaArmor(cWindow & a_ParentWindow) : - cSlotAreaInventoryBase(cInventory::invArmorCount, cInventory::invArmorOffset, a_ParentWindow) - { - } - - // 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; -} ; - - - - - -/// Handles any slot area that is representing a cItemGrid; same items for all the players -class cSlotAreaItemGrid : - public cSlotArea, - public cItemGrid::cListener -{ - typedef cSlotArea super; - -public: - cSlotAreaItemGrid(cItemGrid & a_ItemGrid, cWindow & a_ParentWindow); - - virtual ~cSlotAreaItemGrid(); - - 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; - -protected: - cItemGrid & m_ItemGrid; - - // cItemGrid::cListener overrides: - virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; -} ; - - - - - -/** A cSlotArea with items layout that is private to each player and is temporary, such as -a crafting grid or an enchantment table. -This common ancestor stores the items in a per-player map. It also implements tossing items from the map. -*/ -class cSlotAreaTemporary : - public cSlotArea -{ - typedef cSlotArea super; - -public: - cSlotAreaTemporary(int a_NumSlots, cWindow & a_ParentWindow); - - // cSlotArea overrides: - 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; - virtual void OnPlayerAdded (cPlayer & a_Player) override; - virtual void OnPlayerRemoved(cPlayer & a_Player) override; - - /// Tosses the player's items in slots [a_Begin, a_End) (ie. incl. a_Begin, but excl. a_End) - void TossItems(cPlayer & a_Player, int a_Begin, int a_End); - -protected: - typedef std::map<int, std::vector<cItem> > cItemMap; // Maps EntityID -> items - - cItemMap m_Items; - - /// Returns the pointer to the slot array for the player specified. - cItem * GetPlayerSlots(cPlayer & a_Player); -} ; - - - - - -class cSlotAreaCrafting : - public cSlotAreaTemporary -{ - typedef cSlotAreaTemporary super; - -public: - /// a_GridSize is allowed to be only 2 or 3 - cSlotAreaCrafting(int a_GridSize, cWindow & a_ParentWindow); - - // cSlotAreaTemporary overrides: - virtual void Clicked (cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; - virtual void OnPlayerRemoved(cPlayer & a_Player) 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 {} - -protected: - /// Maps player's EntityID -> current recipe; not a std::map because cCraftingGrid needs proper constructor params - typedef std::list<std::pair<int, cCraftingRecipe> > cRecipeMap; - - int m_GridSize; - cRecipeMap m_Recipes; - - /// Handles a click in the result slot. Crafts using the current recipe, if possible - void ClickedResult(cPlayer & a_Player); - - /// Handles a shift-click in the result slot. Crafts using the current recipe until it changes or no more space for result. - void ShiftClickedResult(cPlayer & a_Player); - - /// Updates the current recipe and result slot based on the ingredients currently in the crafting grid of the specified player - void UpdateRecipe(cPlayer & a_Player); - - /// Retrieves the recipe for the specified player from the map, or creates one if not found - cCraftingRecipe & GetRecipeForPlayer(cPlayer & a_Player); -} ; - - - - - -class cSlotAreaChest : - public cSlotArea -{ -public: - cSlotAreaChest(cChestEntity * a_Chest, cWindow & a_ParentWindow); - - 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; - -protected: - cChestEntity * m_Chest; -} ; - - - - - -class cSlotAreaDoubleChest : - public cSlotArea -{ -public: - cSlotAreaDoubleChest(cChestEntity * a_TopChest, cChestEntity * a_BottomChest, cWindow & a_ParentWindow); - - 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; - -protected: - cChestEntity * m_TopChest; - cChestEntity * m_BottomChest; -} ; - - - - - -class cSlotAreaFurnace : - public cSlotArea, - public cItemGrid::cListener -{ - typedef cSlotArea super; - -public: - cSlotAreaFurnace(cFurnaceEntity * a_Furnace, cWindow & a_ParentWindow); - - virtual ~cSlotAreaFurnace(); - - virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) 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; - -protected: - cFurnaceEntity * m_Furnace; - - // cItemGrid::cListener overrides: - virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; -} ; - - - - diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp deleted file mode 100644 index 2794abe22..000000000 --- a/source/UI/Window.cpp +++ /dev/null @@ -1,841 +0,0 @@ -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Window.h" -#include "WindowOwner.h" -#include "SlotArea.h" -#include "../Item.h" -#include "../ClientHandle.h" -#include "../Entities/Player.h" -#include "../Entities/Pickup.h" -#include "../Inventory.h" -#include "../Items/ItemHandler.h" -#include "../BlockEntities/ChestEntity.h" -#include "../BlockEntities/DropSpenserEntity.h" -#include "../BlockEntities/HopperEntity.h" - - - - - -char cWindow::m_WindowIDCounter = 1; - - - - - -cWindow::cWindow(cWindow::WindowType a_WindowType, const AString & a_WindowTitle) : - m_WindowID((++m_WindowIDCounter) % 127), - m_WindowType(a_WindowType), - m_WindowTitle(a_WindowTitle), - m_Owner(NULL), - m_IsDestroyed(false), - m_ShouldDistributeToHotbarFirst(true) -{ - if (a_WindowType == Inventory) - { - m_WindowID = 0; - } -} - - - - - -cWindow::~cWindow() -{ - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - delete *itr; - } - m_SlotAreas.clear(); -} - - - - - -int cWindow::GetNumSlots(void) const -{ - int res = 0; - for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - res += (*itr)->GetNumSlots(); - } // for itr - m_SlotAreas[] - return res; -} - - - - - -const cItem * cWindow::GetSlot(cPlayer & a_Player, int a_SlotNum) const -{ - // Return the item at the specified slot for the specified player - int LocalSlotNum = 0; - const cSlotArea * Area = GetSlotArea(a_SlotNum, LocalSlotNum); - if (Area == NULL) - { - LOGWARNING("%s: requesting item from an invalid SlotArea (SlotNum %d), returning NULL.", __FUNCTION__, a_SlotNum); - return NULL; - } - return Area->GetSlot(LocalSlotNum, a_Player); -} - - - - - -void cWindow::SetSlot(cPlayer & a_Player, int a_SlotNum, const cItem & a_Item) -{ - // Set the item to the specified slot for the specified player - int LocalSlotNum = 0; - cSlotArea * Area = GetSlotArea(a_SlotNum, LocalSlotNum); - if (Area == NULL) - { - LOGWARNING("%s: requesting write to an invalid SlotArea (SlotNum %d), ignoring.", __FUNCTION__, a_SlotNum); - return; - } - Area->SetSlot(LocalSlotNum, a_Player, a_Item); -} - - - - - -bool cWindow::IsSlotInPlayerMainInventory(int a_SlotNum) const -{ - // Returns true if the specified slot is in the Player Main Inventory slotarea - // The player main inventory is always 27 slots, 9 slots from the end of the inventory - return ((a_SlotNum >= GetNumSlots() - 36) && (a_SlotNum < GetNumSlots() - 9)); -} - - - - - -bool cWindow::IsSlotInPlayerHotbar(int a_SlotNum) const -{ - // Returns true if the specified slot is in the Player Hotbar slotarea - // The hotbar is always the last 9 slots - return ((a_SlotNum >= GetNumSlots() - 9) && (a_SlotNum < GetNumSlots())); -} - - - - - -bool cWindow::IsSlotInPlayerInventory(int a_SlotNum) const -{ - // Returns true if the specified slot is in the Player Main Inventory or Hotbar slotareas. Note that returns false for Armor. - // The player combined inventory is always the last 36 slots - return ((a_SlotNum >= GetNumSlots() - 36) && (a_SlotNum < GetNumSlots())); -} - - - - - -void cWindow::GetSlots(cPlayer & a_Player, cItems & a_Slots) const -{ - a_Slots.clear(); - a_Slots.reserve(GetNumSlots()); - for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - int NumSlots = (*itr)->GetNumSlots(); - for (int i = 0; i < NumSlots; i++) - { - - const cItem * Item = (*itr)->GetSlot(i, a_Player); - if (Item == NULL) - { - a_Slots.push_back(cItem()); - } - else - { - a_Slots.push_back(*Item); - } - } - } // for itr - m_SlotAreas[] -} - - - - - -void cWindow::Clicked( - cPlayer & a_Player, - int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, - const cItem & a_ClickedItem -) -{ - if (a_WindowID != m_WindowID) - { - LOGWARNING("%s: Wrong window ID (exp %d, got %d) received from \"%s\"; ignoring click.", __FUNCTION__, m_WindowID, a_WindowID, a_Player.GetName().c_str()); - return; - } - - switch (a_ClickAction) - { - case caRightClickOutside: - { - // Toss one of the dragged items: - a_Player.TossItem(true); - return; - } - case caLeftClickOutside: - { - // Toss all dragged items: - a_Player.TossItem(true, a_Player.GetDraggingItem().m_ItemCount); - return; - } - case caLeftClickOutsideHoldNothing: - case caRightClickOutsideHoldNothing: - { - // Nothing needed - return; - } - case caLeftPaintBegin: OnPaintBegin (a_Player); return; - case caRightPaintBegin: OnPaintBegin (a_Player); return; - case caLeftPaintProgress: OnPaintProgress(a_Player, a_SlotNum); return; - case caRightPaintProgress: OnPaintProgress(a_Player, a_SlotNum); return; - case caLeftPaintEnd: OnLeftPaintEnd (a_Player); return; - case caRightPaintEnd: OnRightPaintEnd(a_Player); return; - } - - if (a_SlotNum < 0) - { - // TODO: Other click actions with irrelevant slot number (FS #371) - return; - } - - int LocalSlotNum = a_SlotNum; - int idx = 0; - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - if (LocalSlotNum < (*itr)->GetNumSlots()) - { - (*itr)->Clicked(a_Player, LocalSlotNum, a_ClickAction, a_ClickedItem); - return; - } - LocalSlotNum -= (*itr)->GetNumSlots(); - idx++; - } - - LOGWARNING("Slot number higher than available window slots: %d, max %d received from \"%s\"; ignoring.", - a_SlotNum, GetNumSlots(), a_Player.GetName().c_str() - ); -} - - - - - -void cWindow::OpenedByPlayer(cPlayer & a_Player) -{ - { - cCSLock Lock(m_CS); - // If player is already in OpenedBy remove player first - m_OpenedBy.remove(&a_Player); - // Then add player - m_OpenedBy.push_back(&a_Player); - - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - (*itr)->OnPlayerAdded(a_Player); - } // for itr - m_SlotAreas[] - } - - a_Player.GetClientHandle()->SendWindowOpen(m_WindowID, m_WindowType, m_WindowTitle, GetNumSlots() - c_NumInventorySlots); -} - - - - - -bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) -{ - // Checks whether the player is still holding an item - if (a_Player.IsDraggingItem()) - { - LOGD("Player holds item! Dropping it..."); - a_Player.TossItem(true, a_Player.GetDraggingItem().m_ItemCount); - } - - cClientHandle * ClientHandle = a_Player.GetClientHandle(); - if (ClientHandle != NULL) - { - ClientHandle->SendWindowClose(*this); - } - - { - cCSLock Lock(m_CS); - - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - (*itr)->OnPlayerRemoved(a_Player); - } // for itr - m_SlotAreas[] - - m_OpenedBy.remove(&a_Player); - - if ((m_WindowType != Inventory) && m_OpenedBy.empty()) - { - Destroy(); - } - } - if (m_IsDestroyed) - { - delete this; - } - - return true; -} - - - - - -void cWindow::OwnerDestroyed() -{ - m_Owner = NULL; - // Close window for each player. Note that the last one needs special handling - while (m_OpenedBy.size() > 1) - { - (*m_OpenedBy.begin() )->CloseWindow(); - } - (*m_OpenedBy.begin() )->CloseWindow(); -} - - - - - -bool cWindow::ForEachPlayer(cItemCallback<cPlayer> & a_Callback) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr) - { - if (a_Callback.Item(*itr)) - { - return false; - } - } // for itr - m_OpenedBy[] - return true; -} - - - - - -bool cWindow::ForEachClient(cItemCallback<cClientHandle> & a_Callback) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr) - { - if (a_Callback.Item((*itr)->GetClientHandle())) - { - return false; - } - } // for itr - m_OpenedBy[] - return true; -} - - - - - -void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply) -{ - // Ask each slot area to take as much of the stack as it can. - // First ask only slots that already have the same kind of item - // Then ask any remaining slots - for (int Pass = 0; Pass < 2; ++Pass) - { - if (m_ShouldDistributeToHotbarFirst) - { - // 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)); - if (a_ItemStack.IsEmpty()) - { - // Distributed it all - return; - } - } // for itr - m_SlotAreas[] - } // for Pass - repeat twice -} - - - - - -void cWindow::SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum) -{ - int SlotBase = 0; - bool Found = false; - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - if (*itr == a_SlotArea) - { - Found = true; - break; - } - SlotBase += (*itr)->GetNumSlots(); - } // for itr - m_SlotAreas[] - if (!Found) - { - LOGERROR("cWindow::SendSlot(): unknown a_SlotArea"); - ASSERT(!"cWindow::SendSlot(): unknown a_SlotArea"); - return; - } - - a_Player.GetClientHandle()->SendInventorySlot( - m_WindowID, a_RelativeSlotNum + SlotBase, *(a_SlotArea->GetSlot(a_RelativeSlotNum, a_Player)) - ); -} - - - - - -void cWindow::Destroy(void) -{ - if (m_Owner != NULL) - { - m_Owner->CloseWindow(); - m_Owner = NULL; - } - m_IsDestroyed = true; -} - - - - - -cSlotArea * cWindow::GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum) -{ - if ((a_GlobalSlotNum < 0) || (a_GlobalSlotNum >= GetNumSlots())) - { - LOGWARNING("%s: requesting an invalid SlotNum: %d out of %d slots", __FUNCTION__, a_GlobalSlotNum, GetNumSlots() - 1); - ASSERT(!"Invalid SlotNum"); - return NULL; - } - - // Iterate through all the SlotAreas, find the correct one - int LocalSlotNum = a_GlobalSlotNum; - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - if (LocalSlotNum < (*itr)->GetNumSlots()) - { - a_LocalSlotNum = LocalSlotNum; - return *itr; - } - LocalSlotNum -= (*itr)->GetNumSlots(); - } // for itr - m_SlotAreas[] - - // We shouldn't be here - the check at the beginnning should prevent this. Log and assert - LOGWARNING("%s: GetNumSlots() is out of sync: %d; LocalSlotNum = %d", __FUNCTION__, GetNumSlots(), LocalSlotNum); - ASSERT(!"Invalid GetNumSlots"); - return NULL; -} - - - - - -const cSlotArea * cWindow::GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum) const -{ - if ((a_GlobalSlotNum < 0) || (a_GlobalSlotNum >= GetNumSlots())) - { - LOGWARNING("%s: requesting an invalid SlotNum: %d out of %d slots", __FUNCTION__, a_GlobalSlotNum, GetNumSlots() - 1); - ASSERT(!"Invalid SlotNum"); - return NULL; - } - - // Iterate through all the SlotAreas, find the correct one - int LocalSlotNum = a_GlobalSlotNum; - for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - if (LocalSlotNum < (*itr)->GetNumSlots()) - { - a_LocalSlotNum = LocalSlotNum; - return *itr; - } - LocalSlotNum -= (*itr)->GetNumSlots(); - } // for itr - m_SlotAreas[] - - // We shouldn't be here - the check at the beginnning should prevent this. Log and assert - LOGWARNING("%s: GetNumSlots() is out of sync: %d; LocalSlotNum = %d", __FUNCTION__, GetNumSlots(), LocalSlotNum); - ASSERT(!"Invalid GetNumSlots"); - return NULL; -} - - - - - -void cWindow::OnPaintBegin(cPlayer & a_Player) -{ - // Prepares the internal structures for inventory painting from the specified player - a_Player.ClearInventoryPaintSlots(); -} - - - - - -void cWindow::OnPaintProgress(cPlayer & a_Player, int a_SlotNum) -{ - // Add the slot to the internal structures for inventory painting by the specified player - a_Player.AddInventoryPaintSlot(a_SlotNum); -} - - - - - -void cWindow::OnLeftPaintEnd(cPlayer & a_Player) -{ - // Process the entire action stored in the internal structures for inventory painting - // distribute as many items as possible - - const cSlotNums & SlotNums = a_Player.GetInventoryPaintSlots(); - cItem ToDistribute(a_Player.GetDraggingItem()); - int ToEachSlot = (int)ToDistribute.m_ItemCount / SlotNums.size(); - - int NumDistributed = DistributeItemToSlots(a_Player, ToDistribute, ToEachSlot, SlotNums); - - // Remove the items distributed from the dragging item: - a_Player.GetDraggingItem().m_ItemCount -= NumDistributed; - if (a_Player.GetDraggingItem().m_ItemCount == 0) - { - a_Player.GetDraggingItem().Empty(); - } - - SendWholeWindow(*a_Player.GetClientHandle()); -} - - - - - -void cWindow::OnRightPaintEnd(cPlayer & a_Player) -{ - // Process the entire action stored in the internal structures for inventory painting - // distribute one item into each slot - - const cSlotNums & SlotNums = a_Player.GetInventoryPaintSlots(); - cItem ToDistribute(a_Player.GetDraggingItem()); - - int NumDistributed = DistributeItemToSlots(a_Player, ToDistribute, 1, SlotNums); - - // Remove the items distributed from the dragging item: - a_Player.GetDraggingItem().m_ItemCount -= NumDistributed; - if (a_Player.GetDraggingItem().m_ItemCount == 0) - { - a_Player.GetDraggingItem().Empty(); - } - - SendWholeWindow(*a_Player.GetClientHandle()); -} - - - - - -int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int a_NumToEachSlot, const cSlotNums & a_SlotNums) -{ - if ((size_t)(a_Item.m_ItemCount) < a_SlotNums.size()) - { - LOGWARNING("%s: Distributing less items (%d) than slots (%u)", __FUNCTION__, (int)a_Item.m_ItemCount, a_SlotNums.size()); - // This doesn't seem to happen with the 1.5.1 client, so we don't worry about it for now - return 0; - } - - // Distribute to individual slots, keep track of how many items were actually distributed (full stacks etc.) - int NumDistributed = 0; - for (cSlotNums::const_iterator itr = a_SlotNums.begin(), end = a_SlotNums.end(); itr != end; ++itr) - { - int LocalSlotNum = 0; - cSlotArea * Area = GetSlotArea(*itr, LocalSlotNum); - if (Area == NULL) - { - LOGWARNING("%s: Bad SlotArea for slot %d", __FUNCTION__, *itr); - continue; - } - - // Modify the item at the slot - cItem AtSlot(*Area->GetSlot(LocalSlotNum, a_Player)); - int MaxStack = ItemHandler(AtSlot.m_ItemType)->GetMaxStackSize(); - if (AtSlot.IsEmpty()) - { - // Empty, just move all of it there: - cItem ToStore(a_Item); - ToStore.m_ItemCount = std::min(a_NumToEachSlot, (int)MaxStack); - Area->SetSlot(LocalSlotNum, a_Player, ToStore); - NumDistributed += ToStore.m_ItemCount; - } - else - { - // Occupied, add and cap at MaxStack: - int CanStore = std::min(a_NumToEachSlot, (int)MaxStack - AtSlot.m_ItemCount); - AtSlot.m_ItemCount += CanStore; - Area->SetSlot(LocalSlotNum, a_Player, AtSlot); - NumDistributed += CanStore; - } - } // for itr - SlotNums[] - return NumDistributed; -} - - - - - -void cWindow::BroadcastSlot(cSlotArea * a_Area, int a_LocalSlotNum) -{ - // Translate local slot num into global slot num: - int SlotNum = 0; - bool HasFound = false; - for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - if (a_Area == *itr) - { - SlotNum += a_LocalSlotNum; - HasFound = true; - break; - } - SlotNum += (*itr)->GetNumSlots(); - } // for itr - m_SlotAreas[] - if (!HasFound) - { - LOGWARNING("%s: Invalid slot area parameter", __FUNCTION__); - ASSERT(!"Invalid slot area"); - return; - } - - // Broadcast the update packet: - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr) - { - (*itr)->GetClientHandle()->SendInventorySlot(m_WindowID, SlotNum, *a_Area->GetSlot(a_LocalSlotNum, **itr)); - } // for itr - m_OpenedBy[] -} - - - - - -void cWindow::SendWholeWindow(cClientHandle & a_Client) -{ - a_Client.SendWholeInventory(*this); -} - - - - - -void cWindow::BroadcastWholeWindow(void) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr) - { - SendWholeWindow(*(*itr)->GetClientHandle()); - } // for itr - m_OpenedBy[] -} - - - - - -void cWindow::BroadcastProgress(int a_Progressbar, int a_Value) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr) - { - (*itr)->GetClientHandle()->SendWindowProperty(*this, a_Progressbar, a_Value); - } // for itr - m_OpenedBy[] -} - - - - - -void cWindow::SetProperty(int a_Property, int a_Value) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr) - { - (*itr)->GetClientHandle()->SendWindowProperty(*this, a_Property, a_Value); - } // for itr - m_OpenedBy[] -} - - - - - -void cWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player) -{ - a_Player.GetClientHandle()->SendWindowProperty(*this, a_Property, a_Value); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cInventoryWindow: - -cInventoryWindow::cInventoryWindow(cPlayer & a_Player) : - cWindow(cWindow::Inventory, "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(cWindow::Workbench, "Crafting Table") -{ - m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cChestWindow: - -cChestWindow::cChestWindow(cChestEntity * a_Chest) : - cWindow(cWindow::Chest, "Chest"), - m_World(a_Chest->GetWorld()), - m_BlockX(a_Chest->GetPosX()), - m_BlockY(a_Chest->GetPosY()), - m_BlockZ(a_Chest->GetPosZ()) -{ - 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", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1); - - // Send out the chest-open packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_CHEST); -} - - - - - -cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) : - cWindow(cWindow::Chest, "Double Chest"), - m_World(a_PrimaryChest->GetWorld()), - m_BlockX(a_PrimaryChest->GetPosX()), - m_BlockY(a_PrimaryChest->GetPosY()), - m_BlockZ(a_PrimaryChest->GetPosZ()) -{ - 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", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1); - - // Send out the chest-open packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_CHEST); -} - - - - - -cChestWindow::~cChestWindow() -{ - // Send out the chest-close packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_CHEST); - - m_World->BroadcastSoundEffect("random.chestclosed", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cDropSpenserWindow: - -cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) : - cWindow(cWindow::DropSpenser, "Dropspenser") -{ - 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)); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cHopperWindow: - -cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) : - super(cWindow::Hopper, "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(cWindow::Furnace, "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/source/UI/Window.h b/source/UI/Window.h deleted file mode 100644 index aa7e9d0d0..000000000 --- a/source/UI/Window.h +++ /dev/null @@ -1,288 +0,0 @@ - -// Window.h - -// Interfaces to the cWindow class representing a UI window for a specific block - - - - - -#pragma once - -#include "../ItemGrid.h" - - - - - -class cPlayer; -class cWindowOwner; -class cClientHandle; -class cChestEntity; -class cDropSpenserEntity; -class cFurnaceEntity; -class cHopperEntity; -class cSlotArea; -class cWorld; - -typedef std::list<cPlayer *> cPlayerList; -typedef std::vector<cSlotArea *> cSlotAreas; - - - - - -// tolua_begin - -/** -Represents a UI window. - -Each window has a list of players that are currently using it -When there's no player using a window, it is destroyed. -A window consists of several areas of slots with similar functionality - for example the crafting grid area, or -the inventory area. Each area knows what its slots are (GetSlot() function) and can handle mouse clicks. -The window acts only as a top-level container for those areas, redirecting the click events to the correct areas. -Inventory painting, introduced in 1.5, is handled by the window, too -*/ -class cWindow -{ -public: - enum WindowType - { - Inventory = -1, // This value is never actually sent to a client - Chest = 0, - Workbench = 1, - Furnace = 2, - DropSpenser = 3, // Dropper or Dispenser - Enchantment = 4, - Brewery = 5, - NPCTrade = 6, - Beacon = 7, - Anvil = 8, - Hopper = 9, - }; - - // tolua_end - - static const int c_NumInventorySlots = 36; - - cWindow(WindowType a_WindowType, const AString & a_WindowTitle); - virtual ~cWindow(); - - char GetWindowID(void) const { return m_WindowID; } // tolua_export - int GetWindowType(void) const { return m_WindowType; } // tolua_export - - cWindowOwner * GetOwner(void) { return m_Owner; } - void SetOwner( cWindowOwner * a_Owner ) { m_Owner = a_Owner; } - - int GetNumSlots(void) const; - - // tolua_begin - - /// Returns the item at the specified slot for the specified player. Returns NULL if invalid SlotNum requested - const cItem * GetSlot(cPlayer & a_Player, int a_SlotNum) const; - - /// Sets the item to the specified slot for the specified player - void SetSlot(cPlayer & a_Player, int a_SlotNum, const cItem & a_Item); - - /// Returns true if the specified slot is in the Player Main Inventory slotarea - bool IsSlotInPlayerMainInventory(int a_SlotNum) const; - - /// Returns true if the specified slot is in the Player Hotbar slotarea - bool IsSlotInPlayerHotbar(int a_SlotNum) const; - - /// Returns true if the specified slot is in the Player Main Inventory or Hotbar slotareas. Note that returns false for Armor. - bool IsSlotInPlayerInventory(int a_SlotNum) const; - - // tolua_end - - /// Fills a_Slots with the slots read from m_SlotAreas[], for the specified player - void GetSlots(cPlayer & a_Player, cItems & a_Slots) const; - - /// Handles a click event from a player - void Clicked( - cPlayer & a_Player, int a_WindowID, - short a_SlotNum, eClickAction a_ClickAction, - const cItem & a_ClickedItem - ); - - void OpenedByPlayer(cPlayer & a_Player); - - /// Called when a player closes this window; notifies all slot areas. Returns true if close accepted - virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse); - - /// Sends the specified slot's contents to all clients of this window; the slot is specified as local in an area - void BroadcastSlot(cSlotArea * a_Area, int a_LocalSlotNum); - - /// Sends the contents of the whole window to the specified client - void SendWholeWindow(cClientHandle & a_Client); - - /// Sends the contents of the whole window to all clients of this window. - void BroadcastWholeWindow(void); - - /// Sends the progressbar to all clients of this window (same as SetProperty) - void BroadcastProgress(int a_Progressbar, int a_Value); - - // tolua_begin - - const AString & GetWindowTitle() const { return m_WindowTitle; } - 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); - - /// Sends the UpdateWindowPropert(0x69) packet to the specified player - void SetProperty(int a_Property, int a_Value, cPlayer & a_Player); - - // tolua_end - - void OwnerDestroyed(void); - - /// Calls the callback safely for each player that has this window open; returns true if all players have been enumerated - bool ForEachPlayer(cItemCallback<cPlayer> & a_Callback); - - /// Calls the callback safely for each client that has this window open; returns true if all clients have been enumerated - bool ForEachClient(cItemCallback<cClientHandle> & a_Callback); - - /** 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) - */ - void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply); - - /// 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; - - char m_WindowID; - int m_WindowType; - AString m_WindowTitle; - - cCriticalSection m_CS; - 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; - - static char m_WindowIDCounter; - - /// Sets the internal flag as "destroyed"; notifies the owner that the window is destroying - virtual void Destroy(void); - - /** Returns the correct slot area for the specified window-global SlotNum - Also returns the area-local SlotNum corresponding to the GlobalSlotNum - If the global SlotNum is out of range, returns NULL - */ - cSlotArea * GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum); - - /** Returns the correct slot area for the specified window-global SlotNum - Also returns the area-local SlotNum corresponding to the GlobalSlotNum - If the global SlotNum is out of range, returns NULL. - Const version. - */ - const cSlotArea * GetSlotArea(int a_GlobalSlotNum, int & a_LocalSlotNum) const; - - /// Prepares the internal structures for inventory painting from the specified player - void OnPaintBegin(cPlayer & a_Player); - - /// Adds the slot to the internal structures for inventory painting by the specified player - void OnPaintProgress(cPlayer & a_Player, int a_SlotNum); - - /// Processes the entire action stored in the internal structures for inventory painting; distributes as many items as possible - void OnLeftPaintEnd(cPlayer & a_Player); - - /// Processes the entire action stored in the internal structures for inventory painting; distributes one item into each slot - void OnRightPaintEnd(cPlayer & a_Player); - - /// Distributes a_NumToEachSlot items into the slots specified in a_SlotNums; returns the total number of items distributed - int DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int a_NumToEachSlot, const cSlotNums & a_SlotNums); -} ; // tolua_export - - - - - -class cCraftingWindow : - public cWindow -{ - typedef cWindow super; -public: - cCraftingWindow(int a_BlockX, int a_BlockY, int a_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(); - -protected: - cWorld * m_World; - int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet -} ; - - - - - -class cInventoryWindow : - public cWindow -{ -public: - cInventoryWindow(cPlayer & a_Player); - -protected: - cPlayer & m_Player; - -} ; - - - - - diff --git a/source/UI/WindowOwner.h b/source/UI/WindowOwner.h deleted file mode 100644 index d41abf66d..000000000 --- a/source/UI/WindowOwner.h +++ /dev/null @@ -1,125 +0,0 @@ - -#pragma once - -#include "../BlockEntities/BlockEntity.h" -#include "../Entities/Entity.h" -#include "Window.h" - -/* -Being a descendant of cWindowOwner means that the class can own one window. That window can be -queried, opened by other players, closed by players and finally destroyed. -Also, a cWindowOwner can be queried for the block coords where the window is displayed. That will be used -for entities / players in motion to close their windows when they get too far away from the window "source". -*/ - - - - - -// class cWindow; - - - - - -/** -Base class for the window owning -*/ -class cWindowOwner -{ -public: - cWindowOwner() : - m_Window(NULL) - { - } - - void CloseWindow(void) - { - m_Window = NULL; - } - - void OpenWindow(cWindow * a_Window) - { - m_Window = a_Window; - m_Window->SetOwner(this); - } - - cWindow * GetWindow(void) const - { - return m_Window; - } - - /// Returns the block position at which the element owning the window is - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) = 0; - -private: - cWindow * m_Window; -} ; - - - - - -/** -Window owner that is associated with a block entity (chest, furnace, ...) -*/ -class cBlockEntityWindowOwner : - public cWindowOwner -{ -public: - cBlockEntityWindowOwner(void) : - m_BlockEntity(NULL) - { - } - - void SetBlockEntity(cBlockEntity * a_BlockEntity) - { - m_BlockEntity = a_BlockEntity; - } - - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) override - { - a_BlockX = m_BlockEntity->GetPosX(); - a_BlockY = m_BlockEntity->GetPosY(); - a_BlockZ = m_BlockEntity->GetPosZ(); - } - -private: - cBlockEntity * m_BlockEntity; -} ; - - - - - -/** -Window owner that is associated with an entity (chest minecart) -*/ -class cEntityWindowOwner : - public cWindowOwner -{ -public: - cEntityWindowOwner(void) : - m_Entity(NULL) - { - } - - void SetEntity(cEntity * a_Entity) - { - m_Entity = a_Entity; - } - - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) override - { - a_BlockX = (int)floor(m_Entity->GetPosX() + 0.5); - a_BlockY = (int)floor(m_Entity->GetPosY() + 0.5); - a_BlockZ = (int)floor(m_Entity->GetPosZ() + 0.5); - } - -private: - cEntity * m_Entity; -} ; - - - - |