summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormborland <matt.borland1@gmail.com>2013-11-11 00:33:58 +0100
committermborland <matt.borland1@gmail.com>2013-11-11 00:33:58 +0100
commit3710d423acba9546adf441782eb6a17a081c9320 (patch)
tree9ad19a165d324101fd3c8a3c42665d397d77ee08
parentVC2013 (diff)
parentFixed cRoot::FindAndDoWithPlayer(). (diff)
downloadcuberite-3710d423acba9546adf441782eb6a17a081c9320.tar
cuberite-3710d423acba9546adf441782eb6a17a081c9320.tar.gz
cuberite-3710d423acba9546adf441782eb6a17a081c9320.tar.bz2
cuberite-3710d423acba9546adf441782eb6a17a081c9320.tar.lz
cuberite-3710d423acba9546adf441782eb6a17a081c9320.tar.xz
cuberite-3710d423acba9546adf441782eb6a17a081c9320.tar.zst
cuberite-3710d423acba9546adf441782eb6a17a081c9320.zip
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua1
-rw-r--r--Tools/ProtoProxy/Connection.cpp4
-rw-r--r--source/Bindings.cpp35
-rw-r--r--source/Bindings.h2
-rw-r--r--source/Item.cpp9
-rw-r--r--source/Item.h3
-rw-r--r--source/Mobs/Sheep.cpp15
-rw-r--r--source/Mobs/Wolf.cpp133
-rw-r--r--source/Mobs/Wolf.h40
-rw-r--r--source/Protocol/Protocol17x.cpp18
-rw-r--r--source/Root.cpp4
-rw-r--r--source/UI/SlotArea.cpp76
-rw-r--r--source/UI/SlotArea.h11
-rw-r--r--source/UI/Window.cpp45
-rw-r--r--source/UI/Window.h6
15 files changed, 348 insertions, 54 deletions
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 %d, pitch %d>", 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,19 +62,119 @@ 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;
+ 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);
+ }
}
- else
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+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)
{
- m_bIsSitting = true;
+ 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);
+ }
+ }
}
}
- 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;
-
- 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; }
-
-private:
-
- bool m_bIsSitting;
- bool m_bIsTame;
- bool m_bIsBegging;
- bool m_bIsAngry;
-
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+ // 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; }
+
+ // 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; }
+
+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);