diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/Bindings.cpp | 35 | ||||
-rw-r--r-- | source/Bindings.h | 2 | ||||
-rw-r--r-- | source/Entities/ProjectileEntity.h | 2 | ||||
-rw-r--r-- | source/Item.cpp | 9 | ||||
-rw-r--r-- | source/Item.h | 3 | ||||
-rw-r--r-- | source/Mobs/Monster.cpp | 74 | ||||
-rw-r--r-- | source/Mobs/Sheep.cpp | 15 | ||||
-rw-r--r-- | source/Mobs/Wolf.cpp | 133 | ||||
-rw-r--r-- | source/Mobs/Wolf.h | 40 | ||||
-rw-r--r-- | source/Protocol/Protocol17x.cpp | 6 | ||||
-rw-r--r-- | source/Root.cpp | 4 | ||||
-rw-r--r-- | source/Simulator/FloodyFluidSimulator.cpp | 2 | ||||
-rw-r--r-- | source/UI/SlotArea.cpp | 90 | ||||
-rw-r--r-- | source/UI/SlotArea.h | 12 | ||||
-rw-r--r-- | source/UI/Window.cpp | 49 | ||||
-rw-r--r-- | source/UI/Window.h | 6 |
16 files changed, 402 insertions, 80 deletions
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/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 359b0241b..28dd76935 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -83,7 +83,7 @@ protected: /// True if the projectile has hit the ground and is stuck there bool m_IsInGround; - + // cEntity overrides: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; 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/Monster.cpp b/source/Mobs/Monster.cpp index 167a07486..8a5717e27 100644 --- a/source/Mobs/Monster.cpp +++ b/source/Mobs/Monster.cpp @@ -624,61 +624,73 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily) cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType) { + cFastRandom Random; cMonster * toReturn = NULL; - cFastRandom RandomDerps; // Create the mob entity switch (a_MobType) { case mtMagmaCube: - case mtSlime: toReturn = new cSlime (RandomDerps.NextInt(2) + 1); break; // Size parameter - case mtSheep: toReturn = new cSheep (RandomDerps.NextInt(15)); break; // Colour parameter - case mtZombie: toReturn = new cZombie (false); break; // TODO: Infected zombie parameter + case mtSlime: + { + toReturn = new cSlime (Random.NextInt(2) + 1); + break; + } case mtSkeleton: { // TODO: Actual detection of spawning in Nether - toReturn = new cSkeleton(RandomDerps.NextInt(1) == 0 ? false : true); + toReturn = new cSkeleton(Random.NextInt(1) == 0 ? false : true); break; } case mtVillager: { - int VilType = RandomDerps.NextInt(6); - if (VilType == 6) { VilType = 0; } // Give farmers a better chance of spawning + int VillagerType = Random.NextInt(6); + if (VillagerType == 6) + { + // Give farmers a better chance of spawning + VillagerType = 0; + } - toReturn = new cVillager(cVillager::eVillagerType(VilType)); // Type (blacksmith, butcher, etc.) parameter + toReturn = new cVillager((cVillager::eVillagerType)VillagerType); break; } case mtHorse: { // Horses take a type (species), a colour, and a style (dots, stripes, etc.) - int HseType = RandomDerps.NextInt(7); - int HseColor = RandomDerps.NextInt(6); - int HseStyle = RandomDerps.NextInt(6); - int HseTameTimes = RandomDerps.NextInt(6) + 1; + int HorseType = Random.NextInt(7); + int HorseColor = Random.NextInt(6); + int HorseStyle = Random.NextInt(6); + int HorseTameTimes = Random.NextInt(6) + 1; - if ((HseType == 5) || (HseType == 6) || (HseType == 7)) { HseType = 0; } // Increase chances of normal horse (zero) + if ((HorseType == 5) || (HorseType == 6) || (HorseType == 7)) + { + // Increase chances of normal horse (zero) + HorseType = 0; + } - toReturn = new cHorse(HseType, HseColor, HseStyle, HseTameTimes); + toReturn = new cHorse(HorseType, HorseColor, HorseStyle, HorseTameTimes); break; } - case mtBat: toReturn = new cBat(); break; - case mtBlaze: toReturn = new cBlaze(); break; - case mtCaveSpider: toReturn = new cCavespider(); break; - case mtChicken: toReturn = new cChicken(); break; - case mtCow: toReturn = new cCow(); break; - case mtCreeper: toReturn = new cCreeper(); break; - case mtEnderman: toReturn = new cEnderman(); break; - case mtGhast: toReturn = new cGhast(); break; - case mtMooshroom: toReturn = new cMooshroom(); break; - case mtOcelot: toReturn = new cOcelot(); break; - case mtPig: toReturn = new cPig(); break; - case mtSilverfish: toReturn = new cSilverfish(); break; - case mtSpider: toReturn = new cSpider(); break; - case mtSquid: toReturn = new cSquid(); break; - case mtWitch: toReturn = new cWitch(); break; - case mtWolf: toReturn = new cWolf(); break; - case mtZombiePigman: toReturn = new cZombiePigman(); break; + case mtBat: toReturn = new cBat(); break; + case mtBlaze: toReturn = new cBlaze(); break; + case mtCaveSpider: toReturn = new cCavespider(); break; + case mtChicken: toReturn = new cChicken(); break; + case mtCow: toReturn = new cCow(); break; + case mtCreeper: toReturn = new cCreeper(); break; + case mtEnderman: toReturn = new cEnderman(); break; + case mtGhast: toReturn = new cGhast(); break; + case mtMooshroom: toReturn = new cMooshroom(); break; + case mtOcelot: toReturn = new cOcelot(); break; + case mtPig: toReturn = new cPig(); break; + case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter + case mtSilverfish: toReturn = new cSilverfish(); break; + case mtSpider: toReturn = new cSpider(); break; + case mtSquid: toReturn = new cSquid(); break; + case mtWitch: toReturn = new cWitch(); break; + case mtWolf: toReturn = new cWolf(); break; + case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter + case mtZombiePigman: toReturn = new cZombiePigman(); break; default: { ASSERT(!"Unhandled mob type whilst trying to spawn mob!"); 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 2ccf9230f..628b8e071 100644 --- a/source/Protocol/Protocol17x.cpp +++ b/source/Protocol/Protocol17x.cpp @@ -504,7 +504,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); } @@ -565,7 +565,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()); @@ -1788,6 +1788,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/Simulator/FloodyFluidSimulator.cpp b/source/Simulator/FloodyFluidSimulator.cpp index 66954092d..d204a1f8b 100644 --- a/source/Simulator/FloodyFluidSimulator.cpp +++ b/source/Simulator/FloodyFluidSimulator.cpp @@ -224,7 +224,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i ItemTypeToString(NewBlock).c_str() ); a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0); - m_World.BroadcastSoundEffect("random.fizz", a_RelX * 8, a_RelY * 8, a_RelZ * 8, 0.5f, 1.5f); + m_World.BroadcastSoundEffect("random.fizz", a_RelX * 8, a_RelY * 8, a_RelZ * 8, 0.5f, 1.5f); return; } } diff --git a/source/UI/SlotArea.cpp b/source/UI/SlotArea.cpp index 82e87e126..7fd7cd996 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: @@ -336,6 +404,20 @@ void cSlotAreaCrafting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction +void cSlotAreaCrafting::DblClicked(cPlayer & a_Player, int a_SlotNum) +{ + if (a_SlotNum == 0) + { + // Dbl-clicking the crafting result slot shouldn't collect items to hand + return; + } + super::DblClicked(a_Player, a_SlotNum); +} + + + + + void cSlotAreaCrafting::OnPlayerRemoved(cPlayer & a_Player) { // Toss all items on the crafting grid: diff --git a/source/UI/SlotArea.h b/source/UI/SlotArea.h index 943452feb..b1944d901 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; @@ -212,6 +221,7 @@ public: // cSlotAreaTemporary overrides: virtual void Clicked (cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + virtual void DblClicked (cPlayer & a_Player, int a_SlotNum); virtual void OnPlayerRemoved(cPlayer & a_Player) override; // Distributing items into this area is completely disabled diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp index 1f023cb03..f5c62692f 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; @@ -583,7 +628,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int // Modify the item at the slot cItem AtSlot(*Area->GetSlot(LocalSlotNum, a_Player)); - int MaxStack = ItemHandler(AtSlot.m_ItemType)->GetMaxStackSize(); + int MaxStack = AtSlot.GetMaxStackSize(); if (AtSlot.IsEmpty()) { // Empty, just move all of it there: @@ -592,7 +637,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int Area->SetSlot(LocalSlotNum, a_Player, ToStore); NumDistributed += ToStore.m_ItemCount; } - else + else if (AtSlot.IsStackableWith(a_Item)) { // Occupied, add and cap at MaxStack: int CanStore = std::min(a_NumToEachSlot, (int)MaxStack - AtSlot.m_ItemCount); 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); |