diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 9f303ff0e..b238a3b6c 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -2020,6 +2020,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); SetMaxPlayers = { Params = "number", Notes = "Sets the max amount of players who can join." }, GetNumPlayers = { Return = "number", Notes = "Returns the amount of players online." }, GetServerID = { Return = "string", Notes = "Returns the ID of the server?" }, + IsHardcore = { Params = "", Return = "bool", Notes = "Returns true if the server is hardcore (players get banned on death)." }, }, Constants = { diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index 9821c9056..385caa2ce 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -2205,8 +2205,8 @@ bool cConnection::HandleServerSpawnNamedEntity(void) CreateHexDump(HexDump, Metadata.data(), Metadata.size(), 32); Log("Received a PACKET_SPAWN_NAMED_ENTITY from the server:"); Log(" EntityID = %u (0x%x)", EntityID, EntityID); - Log(" UUID = %s", EntityUUID.c_str()); - Log(" Name = %s", EntityName.c_str()); + Log(" UUID = \"%s\"", EntityUUID.c_str()); + Log(" Name = \"%s\"", EntityName.c_str()); Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Rotation = ", Yaw, Pitch); Log(" CurrentItem = %d", CurrentItem); diff --git a/source/Bindings.cpp b/source/Bindings.cpp index bc96bd098..5e1fc4c8e 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/09/13 19:50:08. +** Generated automatically by tolua++-1.0.92 on 11/10/13 18:40:47. */ #ifndef __cplusplus @@ -15845,6 +15845,38 @@ static int tolua_AllToLua_cItem_IsFullStack00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: GetMaxStackSize of class cItem */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cItem_GetMaxStackSize00 +static int tolua_AllToLua_cItem_GetMaxStackSize00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cItem",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cItem* self = (const cItem*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetMaxStackSize'", NULL); +#endif + { + char tolua_ret = (char) self->GetMaxStackSize(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetMaxStackSize'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* get function: m_ItemType of class cItem */ #ifndef TOLUA_DISABLE_tolua_get_cItem_m_ItemType static int tolua_get_cItem_m_ItemType(lua_State* tolua_S) @@ -30521,6 +30553,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"IsDamageable",tolua_AllToLua_cItem_IsDamageable00); tolua_function(tolua_S,"IsStackableWith",tolua_AllToLua_cItem_IsStackableWith00); tolua_function(tolua_S,"IsFullStack",tolua_AllToLua_cItem_IsFullStack00); + tolua_function(tolua_S,"GetMaxStackSize",tolua_AllToLua_cItem_GetMaxStackSize00); tolua_variable(tolua_S,"m_ItemType",tolua_get_cItem_m_ItemType,tolua_set_cItem_m_ItemType); tolua_variable(tolua_S,"m_ItemCount",tolua_get_cItem_m_ItemCount,tolua_set_cItem_m_ItemCount); tolua_variable(tolua_S,"m_ItemDamage",tolua_get_cItem_m_ItemDamage,tolua_set_cItem_m_ItemDamage); diff --git a/source/Bindings.h b/source/Bindings.h index b1c0d55cb..c0e1f288c 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 11/09/13 19:50:08. +** Generated automatically by tolua++-1.0.92 on 11/10/13 18:40:47. */ /* Exported function */ diff --git a/source/Item.cpp b/source/Item.cpp index 5e0beb028..25664e4df 100644 --- a/source/Item.cpp +++ b/source/Item.cpp @@ -122,6 +122,15 @@ bool cItem::IsFullStack(void) const +char cItem::GetMaxStackSize(void) const +{ + return ItemHandler(m_ItemType)->GetMaxStackSize(); +} + + + + + /// Returns the cItemHandler responsible for this item type cItemHandler * cItem::GetHandler(void) const { diff --git a/source/Item.h b/source/Item.h index fee861050..c60d0542c 100644 --- a/source/Item.h +++ b/source/Item.h @@ -132,6 +132,9 @@ public: /// Returns true if the item is stacked up to its maximum stacking. bool IsFullStack(void) const; + + /// Returns the maximum amount of stacked items of this type. + char GetMaxStackSize(void) const; // tolua_end diff --git a/source/Mobs/Sheep.cpp b/source/Mobs/Sheep.cpp index 703482ddb..bda4ccff8 100644 --- a/source/Mobs/Sheep.cpp +++ b/source/Mobs/Sheep.cpp @@ -33,7 +33,6 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer) - void cSheep::OnRightClicked(cPlayer & a_Player) { if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared)) @@ -51,9 +50,13 @@ void cSheep::OnRightClicked(cPlayer & a_Player) Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor)); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10); } + if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - a_Player.GetEquippedItem().m_ItemDamage)) + { + m_WoolColor = 15 - a_Player.GetEquippedItem().m_ItemDamage; + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + } + m_World->BroadcastEntityMetadata(*this); + } } - - - - - diff --git a/source/Mobs/Wolf.cpp b/source/Mobs/Wolf.cpp index 2baeb4b7b..b9db53c7f 100644 --- a/source/Mobs/Wolf.cpp +++ b/source/Mobs/Wolf.cpp @@ -11,10 +11,12 @@ cWolf::cWolf(void) : super("Wolf", mtWolf, "mob.wolf.hurt", "mob.wolf.death", 0.6, 0.8), - m_bIsAngry(false), - m_bIsTame(false), - m_bIsSitting(false), - m_bIsBegging(false) + m_IsAngry(false), + m_IsTame(false), + m_IsSitting(false), + m_IsBegging(false), + m_Owner(""), + m_CollarColor(14) { } @@ -25,9 +27,9 @@ cWolf::cWolf(void) : void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI) { super::DoTakeDamage(a_TDI); - if (!m_bIsTame) + if (!m_IsTame) { - m_bIsAngry = true; + m_IsAngry = true; } m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face } @@ -38,7 +40,7 @@ void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI) void cWolf::OnRightClicked(cPlayer & a_Player) { - if ((!m_bIsTame) && (!m_bIsAngry)) + if (!IsTame() && !IsAngry()) { if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_BONE) { @@ -47,10 +49,11 @@ void cWolf::OnRightClicked(cPlayer & a_Player) a_Player.GetInventory().RemoveOneEquippedItem(); } - if (m_World->GetTickRandomNumber(10) == 5) + if (m_World->GetTickRandomNumber(7) == 0) { SetMaxHealth(20); - m_bIsTame = true; + SetIsTame(true); + SetOwner(a_Player.GetName()); m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMED); } else @@ -59,15 +62,26 @@ void cWolf::OnRightClicked(cPlayer & a_Player) } } } - else if (m_bIsTame) + else if (IsTame()) { - if (m_bIsSitting) + if (a_Player.GetName() == m_Owner) // Is the player the owner of the dog? { - m_bIsSitting = false; - } - else - { - m_bIsSitting = true; + if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_DYE) + { + m_CollarColor = 15 - a_Player.GetEquippedItem().m_ItemDamage; + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + } + } + else if (IsSitting()) + { + SetIsSitting(false); + } + else + { + SetIsSitting(true); + } } } @@ -77,3 +91,92 @@ void cWolf::OnRightClicked(cPlayer & a_Player) + +void cWolf::Tick(float a_Dt, cChunk & a_Chunk) +{ + if (!IsAngry()) + { + cMonster::Tick(a_Dt, a_Chunk); + } + else + { + super::Tick(a_Dt, a_Chunk); + } + + if (IsSitting()) + { + m_bMovingToDestination = false; + } + + cPlayer * a_Closest_Player = FindClosestPlayer(); + if (a_Closest_Player != NULL) + { + switch (a_Closest_Player->GetEquippedItem().m_ItemType) + { + case E_ITEM_BONE: + case E_ITEM_RAW_BEEF: + case E_ITEM_STEAK: + case E_ITEM_RAW_CHICKEN: + case E_ITEM_COOKED_CHICKEN: + case E_ITEM_ROTTEN_FLESH: + { + if (!IsBegging()) + { + SetIsBegging(true); + m_World->BroadcastEntityMetadata(*this); + } + Vector3f a_NewDestination = a_Closest_Player->GetPosition(); + a_NewDestination.y = a_NewDestination.y + 1; // Look at the head of the player, not his feet. + m_Destination = Vector3f(a_NewDestination); + m_bMovingToDestination = false; + break; + } + default: + { + if (IsBegging()) + { + SetIsBegging(false); + m_World->BroadcastEntityMetadata(*this); + } + } + } + } + + class cCallback : + public cPlayerListCallback + { + virtual bool Item(cPlayer * Player) override + { + OwnerCoords = Player->GetPosition(); + return false; + } + public: + Vector3f OwnerCoords; + } Callback; + m_World->DoWithPlayer(m_Owner, Callback); + Vector3f OwnerCoords = Callback.OwnerCoords; + + if (IsTame()) + { + if (m_Owner != "") + { + double Distance = (OwnerCoords - GetPosition()).Length(); + if (Distance < 3) + { + m_bMovingToDestination = false; + } + else if ((Distance > 30) && (!IsSitting())) + { + TeleportToCoords(OwnerCoords.x, OwnerCoords.y, OwnerCoords.z); + } + else + { + m_Destination = OwnerCoords; + } + } + } +} + + + + diff --git a/source/Mobs/Wolf.h b/source/Mobs/Wolf.h index 98074ba11..d51d4e78a 100644 --- a/source/Mobs/Wolf.h +++ b/source/Mobs/Wolf.h @@ -2,6 +2,7 @@ #pragma once #include "PassiveAggressiveMonster.h" +#include "../Entities/Entity.h" @@ -19,19 +20,32 @@ public: virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void OnRightClicked(cPlayer & a_Player) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - bool IsSitting(void) const { return m_bIsSitting; } - bool IsTame(void) const { return m_bIsTame; } - bool IsBegging(void) const { return m_bIsBegging; } - bool IsAngry(void) const { return m_bIsAngry; } + // Get functions + bool IsSitting (void) const { return m_IsSitting; } + bool IsTame (void) const { return m_IsTame; } + bool IsBegging (void) const { return m_IsBegging; } + bool IsAngry (void) const { return m_IsAngry; } + AString GetOwner (void) const { return m_Owner; } + int GetCollarColor(void) const { return m_CollarColor; } -private: + // Set functions + void SetIsSitting (bool a_IsSitting) { m_IsSitting = a_IsSitting; } + void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; } + void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; } + void SetIsAngry (bool a_IsAngry) { m_IsAngry = a_IsAngry; } + void SetOwner (AString a_NewOwner) { m_Owner = a_NewOwner; } + void SetCollarColor(int a_CollarColor) { m_CollarColor = a_CollarColor; } - bool m_bIsSitting; - bool m_bIsTame; - bool m_bIsBegging; - bool m_bIsAngry; +protected: + bool m_IsSitting; + bool m_IsTame; + bool m_IsBegging; + bool m_IsAngry; + AString m_Owner; + int m_CollarColor; } ; diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp index 9e230bafd..78a55ccc0 100644 --- a/source/Protocol/Protocol17x.cpp +++ b/source/Protocol/Protocol17x.cpp @@ -215,7 +215,7 @@ void cProtocol172::SendDestroyEntity(const cEntity & a_Entity) void cProtocol172::SendDisconnect(const AString & a_Reason) { cPacketizer Pkt(*this, 0x40); - Pkt.WriteString(a_Reason); + Pkt.WriteString(EscapeString(a_Reason)); } @@ -490,7 +490,7 @@ void cProtocol172::SendPlayerAbilities(void) void cProtocol172::SendPlayerAnimation(const cPlayer & a_Player, char a_Animation) { cPacketizer Pkt(*this, 0x0b); // Animation packet - Pkt.WriteInt(a_Player.GetUniqueID()); + Pkt.WriteVarInt(a_Player.GetUniqueID()); Pkt.WriteChar(a_Animation); } @@ -503,7 +503,7 @@ void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) cPacketizer Pkt(*this, 0x38); // Playerlist Item packet Pkt.WriteString(a_Player.GetName()); Pkt.WriteBool(a_IsOnline); - Pkt.WriteShort(a_Player.GetClientHandle()->GetPing()); + Pkt.WriteShort(a_IsOnline ? a_Player.GetClientHandle()->GetPing() : 0); } @@ -564,7 +564,7 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) { // Called to spawn another player for the client cPacketizer Pkt(*this, 0x0c); // Spawn Player packet - Pkt.WriteInt(a_Player.GetUniqueID()); + Pkt.WriteVarInt(a_Player.GetUniqueID()); Pkt.WriteString(Printf("%d", a_Player.GetUniqueID())); // TODO: Proper UUID Pkt.WriteString(a_Player.GetName()); Pkt.WriteFPInt(a_Player.GetPosX()); @@ -615,11 +615,9 @@ void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src { cPacketizer Pkt(*this, 0x28); // Effect packet Pkt.WriteInt(a_EffectID); - Pkt.WriteInt(a_SrcX); - // TODO: Check if this is really an int - // wiki.vg says it's a byte, but that wouldn't cover the entire range needed (Y location * 8 = 0..2048) - Pkt.WriteInt(a_SrcY); - Pkt.WriteInt(a_SrcZ); + Pkt.WriteInt(a_SrcX / 8); + Pkt.WriteByte(a_SrcY / 8); + Pkt.WriteInt(a_SrcZ / 8); Pkt.WriteInt(a_Data); Pkt.WriteBool(false); } @@ -1754,6 +1752,8 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) WriteFloat((float)(a_Mob.GetHealth())); WriteByte(0x13); WriteByte(Wolf.IsBegging() ? 1 : 0); + WriteByte(0x14); + WriteByte(Wolf.GetCollarColor()); break; } diff --git a/source/Root.cpp b/source/Root.cpp index 4760c3ef1..701832be7 100644 --- a/source/Root.cpp +++ b/source/Root.cpp @@ -547,9 +547,9 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac } if (Rating == NameLength) // Perfect match { - return false; + return true; } - return true; + return false; } public: diff --git a/source/UI/SlotArea.cpp b/source/UI/SlotArea.cpp index 82e87e126..ae493762a 100644 --- a/source/UI/SlotArea.cpp +++ b/source/UI/SlotArea.cpp @@ -50,15 +50,20 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA return; } - if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) + switch (a_ClickAction) { - if (!a_Player.IsDraggingItem()) + case caShiftLeftClick: + case caShiftRightClick: { ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); return; } - LOGD("Shift clicked, but the player is dragging an item: %s", ItemToFullString(a_Player.GetDraggingItem()).c_str()); - return; + + case caDblClick: + { + DblClicked(a_Player, a_SlotNum); + return; + } } cItem Slot(*GetSlot(a_SlotNum, a_Player)); @@ -182,6 +187,36 @@ void cSlotArea::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ +void cSlotArea::DblClicked(cPlayer & a_Player, int a_SlotNum) +{ + cItem & Dragging = a_Player.GetDraggingItem(); + if (Dragging.IsEmpty()) + { + // Move the item in the dblclicked slot into hand: + Dragging = *GetSlot(a_SlotNum, a_Player); + cItem EmptyItem; + SetSlot(a_SlotNum, a_Player, EmptyItem); + } + if (Dragging.IsEmpty()) + { + LOGD("%s DblClicked with an empty hand over empty slot, ignoring", a_Player.GetName().c_str()); + return; + } + + // Add as many items from the surrounding area into hand as possible: + // First skip full stacks, then if there's still space, process full stacks as well: + if (!m_ParentWindow.CollectItemsToHand(Dragging, *this, a_Player, false)) + { + m_ParentWindow.CollectItemsToHand(Dragging, *this, a_Player, true); + } + + m_ParentWindow.BroadcastWholeWindow(); // We need to broadcast, in case the window was a chest opened by multiple players +} + + + + + void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) { for (int i = 0; i < m_NumSlots; i++) @@ -220,6 +255,39 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ +bool cSlotArea::CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks) +{ + int NumSlots = GetNumSlots(); + for (int i = 0; i < NumSlots; i++) + { + const cItem & SlotItem = *GetSlot(i, a_Player); + if (!SlotItem.IsStackableWith(a_Dragging)) + { + continue; + } + int ToMove = a_Dragging.GetMaxStackSize() - a_Dragging.m_ItemCount; + if (ToMove > SlotItem.m_ItemCount) + { + ToMove = SlotItem.m_ItemCount; + } + a_Dragging.m_ItemCount += ToMove; + cItem NewSlot(SlotItem); + NewSlot.m_ItemCount -= ToMove; + SetSlot(i, a_Player, NewSlot); + if (!NewSlot.IsEmpty()) + { + // There are leftovers in the slot, so a_Dragging must be full + return true; + } + } // for i - Slots[] + // a_Dragging may be full if there were exactly the number of items needed to fill it + return a_Dragging.IsFullStack(); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaChest: diff --git a/source/UI/SlotArea.h b/source/UI/SlotArea.h index 943452feb..4964e9986 100644 --- a/source/UI/SlotArea.h +++ b/source/UI/SlotArea.h @@ -40,9 +40,12 @@ public: /// Called when a player clicks in the window. Parameters taken from the click packet. virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem); - /// Called from Clicked if it is a valid shiftclick + /// Called from Clicked when the action is a shiftclick (left or right) virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem); + /// Called from Clicked when the action is a caDblClick + virtual void DblClicked(cPlayer & a_Player, int a_SlotNum); + /// Called when a new player opens the same parent window. The window already tracks the player. CS-locked. virtual void OnPlayerAdded(cPlayer & a_Player) {} ; @@ -57,6 +60,12 @@ public: */ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots); + /// Called on DblClicking to collect all stackable items into hand. + /// The items are accumulated in a_Dragging and removed from the slots immediately. + /// If a_CollectFullStacks is false, slots with full stacks are skipped while collecting. + /// Returns true if full stack has been collected in a_Dragging, false if there's space remaining to fill. + virtual bool CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks); + protected: int m_NumSlots; cWindow & m_ParentWindow; diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp index 1f023cb03..a09f5d682 100644 --- a/source/UI/Window.cpp +++ b/source/UI/Window.cpp @@ -386,6 +386,51 @@ void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea +bool cWindow::CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks) +{ + // First ask the slot areas from a_Area till the end of list: + bool ShouldCollect = false; + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + if (&a_Area == *itr) + { + ShouldCollect = true; + } + if (!ShouldCollect) + { + continue; + } + if ((*itr)->CollectItemsToHand(a_Dragging, a_Player, a_CollectFullStacks)) + { + // a_Dragging is full + return true; + } + } + + // a_Dragging still not full, ask slot areas before a_Area in the list: + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + if (*itr == &a_Area) + { + // All areas processed + return false; + } + if ((*itr)->CollectItemsToHand(a_Dragging, a_Player, a_CollectFullStacks)) + { + // a_Dragging is full + return true; + } + } + // Shouldn't reach here + // a_Area is expected to be part of m_SlotAreas[], so the "return false" in the loop above should have returned already + ASSERT(!"This branch should not be reached"); + return false; +} + + + + + void cWindow::SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum) { int SlotBase = 0; diff --git a/source/UI/Window.h b/source/UI/Window.h index 6927cd3ac..c44b900d7 100644 --- a/source/UI/Window.h +++ b/source/UI/Window.h @@ -156,6 +156,12 @@ public: */ void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply); + /// Called on DblClicking to collect all stackable items from all areas into hand, starting with the specified area. + /// The items are accumulated in a_Dragging and removed from the SlotAreas immediately. + /// If a_CollectFullStacks is false, slots with full stacks in the area are skipped while collecting. + /// Returns true if full stack has been collected, false if there's space remaining to fill. + bool CollectItemsToHand(cItem & a_Dragging, cSlotArea & a_Area, cPlayer & a_Player, bool a_CollectFullStacks); + /// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum);