From 18b04ab93f31e4701351dc35f847f2763d75c5e0 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 11 Aug 2012 19:54:57 +0000 Subject: Added partial shift+click handling to the survival inventory git-svn-id: http://mc-server.googlecode.com/svn/trunk@730 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cInventory.cpp | 104 +++++++++++++++++-- source/cInventory.h | 7 ++ source/cSurvivalInventory.cpp | 177 ++++++++++++++++++++++++++++++--- source/cSurvivalInventory.h | 28 +++++- source/cWindow.cpp | 72 +++++++++++--- source/cWindow.h | 8 +- source/packets/cPacket_WindowClick.cpp | 12 +-- source/packets/cPacket_WindowClick.h | 8 +- 8 files changed, 366 insertions(+), 50 deletions(-) (limited to 'source') diff --git a/source/cInventory.cpp b/source/cInventory.cpp index 8a0c06472..1f4405470 100644 --- a/source/cInventory.cpp +++ b/source/cInventory.cpp @@ -14,6 +14,8 @@ #include "packets/cPacket_WholeInventory.h" #include "packets/cPacket_InventorySlot.h" +#include "items/Item.h" + @@ -46,10 +48,11 @@ cInventory::cInventory(cPlayer* a_Owner) m_EquippedItem = new cItem(); m_EquippedSlot = 0; - if( !GetWindow() ) + if (GetWindow() == NULL) { - cWindow* Window = new cWindow( this, false, cWindow::Inventory, 0); + cWindow * Window = new cWindow( this, false, cWindow::Inventory, 0); Window->SetSlots(m_Slots, c_NumSlots); + Window->Open(*a_Owner); OpenWindow(Window); } } @@ -180,6 +183,7 @@ cItem * cInventory::GetSlotsForType( int a_Type ) +/* int cInventory::GetSlotCountForType( int a_Type ) { switch (a_Type) @@ -192,6 +196,7 @@ int cInventory::GetSlotCountForType( int a_Type ) } return 0; } +*/ @@ -249,10 +254,37 @@ cItem & cInventory::GetEquippedItem() -void cInventory::SendWholeInventory( cClientHandle* a_Client ) +void cInventory::SendWholeInventory(cClientHandle * a_Client) +{ + cPacket_WholeInventory Inventory(this); + a_Client->Send(Inventory); +} + + + + + +void cInventory::SendWholeInventoryToAll(void) { - cPacket_WholeInventory Inventory( this ); - a_Client->Send( Inventory ); + cWindow * Window = GetWindow(); + if (Window == NULL) + { + return; + } + + class cSender : + public cItemCallback + { + cInventory * m_Inventory; + public: + cSender(cInventory * a_Inventory) : m_Inventory(a_Inventory) {} + virtual bool Item(cClientHandle * a_Client) override + { + m_Inventory->SendWholeInventory(a_Client); + return false; + } + } Sender(this); + Window->ForEachClient(Sender); } @@ -262,8 +294,12 @@ void cInventory::SendWholeInventory( cClientHandle* a_Client ) void cInventory::SendSlot( int a_SlotNum ) { cItem* Item = GetSlot( a_SlotNum ); - if( Item ) + if (Item != NULL) { + if (Item->IsEmpty()) + { + Item->Empty(); + } cPacket_InventorySlot InventorySlot; InventorySlot.m_ItemCount = Item->m_ItemCount; InventorySlot.m_ItemID = (short) Item->m_ItemID; @@ -278,6 +314,62 @@ void cInventory::SendSlot( int a_SlotNum ) +int cInventory::HowManyCanFit(ENUM_ITEM_ID a_ItemType, short a_ItemDamage, int a_BeginSlot, int a_EndSlot) +{ + int res = 0; + for (int i = a_BeginSlot; i <= a_EndSlot; i++) + { + if ( + m_Slots[i].IsEmpty() || + ((m_Slots[i].m_ItemID == a_ItemType) && (m_Slots[i].m_ItemHealth == a_ItemDamage)) + ) + { + int MaxCount = ItemHandler(a_ItemType)->GetMaxStackSize(); + ASSERT(m_Slots[i].m_ItemCount <= MaxCount); + res += MaxCount - m_Slots[i].m_ItemCount; + } + } // for i - m_Slots[] + return res; +} + + + + + +int cInventory::MoveItem(ENUM_ITEM_ID a_ItemType, short a_ItemDamage, int a_Count, int a_BeginSlot, int a_EndSlot) +{ + int res = 0; + for (int i = a_BeginSlot; i <= a_EndSlot; i++) + { + if ( + m_Slots[i].IsEmpty() || + ((m_Slots[i].m_ItemID == a_ItemType) && (m_Slots[i].m_ItemHealth == a_ItemDamage)) + ) + { + int MaxCount = ItemHandler(a_ItemType)->GetMaxStackSize(); + ASSERT(m_Slots[i].m_ItemCount <= MaxCount); + int NumToMove = std::min(a_Count, MaxCount); + m_Slots[i].m_ItemCount += NumToMove; + m_Slots[i].m_ItemHealth = a_ItemDamage; + m_Slots[i].m_ItemID = a_ItemType; + SendSlot(i); + res += NumToMove; + a_Count -= NumToMove; + if (a_Count <= 0) + { + // No more items to distribute + return res; + } + } + } // for i - m_Slots[] + // No more space to distribute to + return res; +} + + + + + bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size, bool* a_bChangedSlots, int a_Mode /* = 0 */ ) { // Fill already present stacks diff --git a/source/cInventory.h b/source/cInventory.h index 2336df57f..6f824f0f5 100644 --- a/source/cInventory.h +++ b/source/cInventory.h @@ -41,6 +41,7 @@ public: bool LoadFromJson(Json::Value & a_Value); void SendWholeInventory( cClientHandle* a_Client ); + void SendWholeInventoryToAll(void); cItem* GetSlot( int a_SlotNum ); //tolua_export cItem* GetSlots() { return m_Slots; } @@ -53,6 +54,12 @@ public: virtual void Clicked( cPacket* a_ClickPacket ) = 0; void SendSlot( int a_SlotNum ); //tolua_export + + /// Returns how many items of the specified type would fit into the slot range specified + int HowManyCanFit(ENUM_ITEM_ID a_ItemType, short a_ItemDamage, int a_BeginSlot, int a_EndSlot); + + /// Moves items, fitting them into the slot range specified, up to a_Count items. Returns the number of items moved + int MoveItem(ENUM_ITEM_ID a_ItemType, short a_ItemDamage, int a_Count, int a_BeginSlot, int a_EndSlot); static const unsigned int c_NumSlots = 45; static const unsigned int c_MainSlots = 27; diff --git a/source/cSurvivalInventory.cpp b/source/cSurvivalInventory.cpp index 5ed91cf70..62808a17d 100644 --- a/source/cSurvivalInventory.cpp +++ b/source/cSurvivalInventory.cpp @@ -14,36 +14,53 @@ -cSurvivalInventory::~cSurvivalInventory() +cSurvivalInventory::cSurvivalInventory(cPlayer* a_Owner) + : cInventory(a_Owner) { - } -cSurvivalInventory::cSurvivalInventory(cPlayer* a_Owner) - : cInventory(a_Owner) + + + + +cSurvivalInventory::~cSurvivalInventory() { - } + + + + void cSurvivalInventory::Clicked( cPacket* a_ClickPacket ) { - cPacket_WindowClick *Packet = reinterpret_cast(a_ClickPacket); + cPacket_WindowClick * Packet = reinterpret_cast(a_ClickPacket); + + if ( + Packet->m_IsShiftPressed && // Shift pressed + (GetWindow() != NULL) && // Window is valid + (GetWindow()->GetDraggingItem()->IsEmpty()) // Not dragging anything + ) + { + ShiftClicked(Packet); + return; + } + bool bDontCook = false; - if( GetWindow() ) + if (GetWindow()) { // Override for craft result slot - if( Packet->m_SlotNum == (short)c_CraftOffset ) + if (Packet->m_SlotNum == (short)c_CraftOffset) { - LOG("In craft slot: %i x %i !!", m_Slots[c_CraftOffset].m_ItemID, m_Slots[c_CraftOffset].m_ItemCount ); - cItem* DraggingItem = GetWindow()->GetDraggingItem(); - if( DraggingItem->IsEmpty() ) + LOGD("In craft slot: %i x %i !!", m_Slots[c_CraftOffset].m_ItemID, m_Slots[c_CraftOffset].m_ItemCount ); + cItem * DraggingItem = GetWindow()->GetDraggingItem(); + if (DraggingItem->IsEmpty()) { *DraggingItem = m_Slots[c_CraftOffset]; m_Slots[c_CraftOffset].Empty(); } - else if( DraggingItem->Equals( m_Slots[c_CraftOffset] ) ) + else if (DraggingItem->Equals(m_Slots[c_CraftOffset])) { - if( DraggingItem->m_ItemCount + m_Slots[c_CraftOffset].m_ItemCount <= 64 ) + if (DraggingItem->m_ItemCount + m_Slots[c_CraftOffset].m_ItemCount <= 64) { DraggingItem->m_ItemCount += m_Slots[c_CraftOffset].m_ItemCount; m_Slots[0].Empty(); @@ -57,7 +74,7 @@ void cSurvivalInventory::Clicked( cPacket* a_ClickPacket ) { bDontCook = true; } - LOG("Dragging Dish %i", DraggingItem->m_ItemCount ); + LOGD("Dragging Dish %i", DraggingItem->m_ItemCount ); } else { @@ -66,6 +83,7 @@ void cSurvivalInventory::Clicked( cPacket* a_ClickPacket ) } else { + ASSERT(!"No inventory window! WTF?"); LOG("No Inventory window! WTF"); } @@ -91,5 +109,134 @@ void cSurvivalInventory::Clicked( cPacket* a_ClickPacket ) LOGD("%s cooked: %i x %i !!", m_Owner->GetName().c_str(), m_Slots[c_CraftOffset].m_ItemID, m_Slots[c_CraftOffset].m_ItemCount ); SendWholeInventory( m_Owner->GetClientHandle() ); } - SendSlot( 0 ); + SendSlot(0); } + + + + + +void cSurvivalInventory::ShiftClicked(cPacket_WindowClick * a_ClickPacket) +{ + ASSERT((GetWindow() == NULL) || (GetWindow()->GetDraggingItem()->IsEmpty())); // Cannot handle shift-click if dragging something + + short Slot = a_ClickPacket->m_SlotNum; + if (Slot == SLOT_CRAFTING_RESULT) + { + ShiftClickedCraftingResult(Slot); + } + else if ((Slot >= SLOT_CRAFTING_MIN) && (Slot <= SLOT_CRAFTING_MAX)) + { + ShiftClickedCraftingGrid(Slot); + } + else if ((Slot >= SLOT_ARMOR_MIN) && (Slot <= SLOT_ARMOR_MAX)) + { + ShiftClickedArmor(Slot); + } + else if ((Slot >= SLOT_HOTBAR_MIN) && (Slot <= SLOT_HOTBAR_MAX)) + { + ShiftClickedHotbar(Slot); + } + else + { + ShiftClickedInventory(Slot); + } + // Because the client tries to guess our actions, not always right, send the whole inventory: + SendWholeInventoryToAll(); +} + + + + + +void cSurvivalInventory::ShiftClickedCraftingResult(short a_Slot) +{ + // TODO +} + + + + + +void cSurvivalInventory::ShiftClickedCraftingGrid(short a_Slot) +{ + // Move the item from the crafting grid into the main inventory: + cItem * Item = GetSlot(a_Slot); + if ((Item == NULL) || Item->IsEmpty()) + { + return; + } + Item->m_ItemCount -= MoveItem(Item->m_ItemID, Item->m_ItemHealth, Item->m_ItemCount, SLOT_INVENTORY_MIN, SLOT_INVENTORY_MAX); + SendSlot(a_Slot); +} + + + + + +void cSurvivalInventory::ShiftClickedArmor(short a_Slot) +{ + // Move the item from the armor slot into the main inventory: + cItem * Item = GetSlot(a_Slot); + if ((Item == NULL) || Item->IsEmpty()) + { + return; + } + Item->m_ItemCount -= MoveItem(Item->m_ItemID, Item->m_ItemHealth, Item->m_ItemCount, SLOT_INVENTORY_MIN, SLOT_INVENTORY_MAX); + SendSlot(a_Slot); +} + + + + + +void cSurvivalInventory::ShiftClickedHotbar(short a_Slot) +{ + // Move the item from the hotbar into the main inventory: + cItem * Item = GetSlot(a_Slot); + if ((Item == NULL) || Item->IsEmpty()) + { + return; + } + Item->m_ItemCount -= MoveItem(Item->m_ItemID, Item->m_ItemHealth, Item->m_ItemCount, SLOT_INVENTORY_MIN, SLOT_INVENTORY_MAX); + SendSlot(a_Slot); +} + + + + + +void cSurvivalInventory::ShiftClickedInventory(short a_Slot) +{ + // Move the item from the main inventory into armor slot if it is armor, or the hotbar otherwise: + cItem * Item = GetSlot(a_Slot); + if ((Item == NULL) || Item->IsEmpty()) + { + return; + } + if (ItemCategory::IsHelmet(Item->m_ItemID)) + { + Item->m_ItemCount -= MoveItem(Item->m_ItemID, Item->m_ItemHealth, Item->m_ItemCount, SLOT_ARMOR_HELMET, SLOT_ARMOR_HELMET); + } + else if (ItemCategory::IsChestPlate(Item->m_ItemID)) + { + Item->m_ItemCount -= MoveItem(Item->m_ItemID, Item->m_ItemHealth, Item->m_ItemCount, SLOT_ARMOR_CHESTPLATE, SLOT_ARMOR_CHESTPLATE); + } + else if (ItemCategory::IsLeggings(Item->m_ItemID)) + { + Item->m_ItemCount -= MoveItem(Item->m_ItemID, Item->m_ItemHealth, Item->m_ItemCount, SLOT_ARMOR_LEGGINGS, SLOT_ARMOR_LEGGINGS); + } + else if (ItemCategory::IsBoots(Item->m_ItemID)) + { + Item->m_ItemCount -= MoveItem(Item->m_ItemID, Item->m_ItemHealth, Item->m_ItemCount, SLOT_ARMOR_BOOTS, SLOT_ARMOR_BOOTS); + } + else + { + Item->m_ItemCount -= MoveItem(Item->m_ItemID, Item->m_ItemHealth, Item->m_ItemCount, SLOT_HOTBAR_MIN, SLOT_HOTBAR_MAX); + } + SendSlot(a_Slot); +} + + + + diff --git a/source/cSurvivalInventory.h b/source/cSurvivalInventory.h index 2061de2b0..cdab62e93 100644 --- a/source/cSurvivalInventory.h +++ b/source/cSurvivalInventory.h @@ -10,11 +10,37 @@ class cSurvivalInventory //tolua_export : public cInventory { //tolua_export + + enum + { + SLOT_CRAFTING_RESULT = 0, + SLOT_CRAFTING_MIN = 1, + SLOT_CRAFTING_MAX = 4, + SLOT_ARMOR_MIN = 5, + SLOT_ARMOR_HELMET = 5, + SLOT_ARMOR_CHESTPLATE = 6, + SLOT_ARMOR_LEGGINGS = 7, + SLOT_ARMOR_BOOTS = 8, + SLOT_ARMOR_MAX = 8, + SLOT_INVENTORY_MIN = 9, + SLOT_INVENTORY_MAX = 35, + SLOT_HOTBAR_MIN = 36, + SLOT_HOTBAR_MAX = 44, + } ; + + void ShiftClickedCraftingResult(short a_Slot); + void ShiftClickedCraftingGrid (short a_Slot); + void ShiftClickedArmor (short a_Slot); + void ShiftClickedHotbar (short a_Slot); + void ShiftClickedInventory (short a_Slot); + public: cSurvivalInventory(cPlayer* a_Owner); ~cSurvivalInventory(); - virtual void Clicked( cPacket* a_ClickPacket ); + virtual void Clicked(cPacket * a_ClickPacket) override; + + void ShiftClicked(cPacket_WindowClick * a_ClickPacket); }; //tolua_export diff --git a/source/cWindow.cpp b/source/cWindow.cpp index f2c66420e..a7eceac27 100644 --- a/source/cWindow.cpp +++ b/source/cWindow.cpp @@ -86,36 +86,42 @@ cItem* cWindow::GetDraggingItem( cPlayer * a_Player /* = 0 */ ) void cWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player ) { - if( a_ClickPacket->m_WindowID != m_WindowID ) + if (a_ClickPacket->m_WindowID != m_WindowID) { LOG("WRONG WINDOW ID! (exp %d, got %d)", m_WindowID, a_ClickPacket->m_WindowID); return; } - if( m_bInventoryVisible ) + if (m_bInventoryVisible) { - cWindow* Window = a_Player.GetInventory().GetWindow(); - if( Window ) + cWindow * Window = a_Player.GetInventory().GetWindow(); + if (Window != NULL) { m_DraggingItem = Window->GetDraggingItem(); } } bool bAsync = false; - if( a_ClickPacket->m_SlotNum == -999 ) // Outside window click + if (a_ClickPacket->m_SlotNum == -999) // Outside window click { - if( a_ClickPacket->m_RightMouse ) + if (a_ClickPacket->m_RightMouse) + { a_Player.TossItem( true ); + } else + { a_Player.TossItem( true, m_DraggingItem->m_ItemCount ); + } } - else if( GetSlot( a_ClickPacket->m_SlotNum ) != 0 ) + else if (GetSlot(a_ClickPacket->m_SlotNum) != NULL) { - cItem* Item = GetSlot( a_ClickPacket->m_SlotNum ); - if( a_ClickPacket->m_ItemID != Item->m_ItemID - || a_ClickPacket->m_ItemCount != Item->m_ItemCount - || a_ClickPacket->m_ItemUses != Item->m_ItemHealth ) + cItem * Item = GetSlot(a_ClickPacket->m_SlotNum); + if ( + (a_ClickPacket->m_ItemID != Item->m_ItemID) || + (a_ClickPacket->m_ItemCount != Item->m_ItemCount) || + (a_ClickPacket->m_ItemUses != Item->m_ItemHealth) + ) { - if( !((a_ClickPacket->m_ItemID == -1 || a_ClickPacket->m_ItemID == 0) && (Item->m_ItemID == -1 || Item->m_ItemID == 0 )) ) + if (!((a_ClickPacket->m_ItemID == -1 || a_ClickPacket->m_ItemID == 0) && (Item->m_ItemID == -1 || Item->m_ItemID == 0 )) ) { LOGD("My ID: %i Their ID: %i", Item->m_ItemID, a_ClickPacket->m_ItemID ); LOGD("My Count: %i Their Count: %i", Item->m_ItemCount, a_ClickPacket->m_ItemCount ); @@ -124,13 +130,13 @@ void cWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player ) } } } - if( m_DraggingItem && a_ClickPacket->m_SlotNum > -1 && a_ClickPacket->m_SlotNum < m_NumSlots ) + if (m_DraggingItem && (a_ClickPacket->m_SlotNum > -1) && (a_ClickPacket->m_SlotNum < m_NumSlots)) { - if( a_ClickPacket->m_RightMouse == 0 ) + if (a_ClickPacket->m_RightMouse == 0) { - if( !m_DraggingItem->Equals( m_Slots[a_ClickPacket->m_SlotNum] ) ) + if (!m_DraggingItem->Equals(m_Slots[a_ClickPacket->m_SlotNum])) { - cItem tmp( *m_DraggingItem ); + cItem tmp(*m_DraggingItem); *m_DraggingItem = m_Slots[a_ClickPacket->m_SlotNum]; m_Slots[a_ClickPacket->m_SlotNum] = tmp; // Switch contents } @@ -283,6 +289,40 @@ void cWindow::OwnerDestroyed() +bool cWindow::ForEachPlayer(cItemCallback & 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 & 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::Destroy() { LOGD("Destroying window %p (type %d)", this, m_WindowType); diff --git a/source/cWindow.h b/source/cWindow.h index 9d62dc43a..303c9e503 100644 --- a/source/cWindow.h +++ b/source/cWindow.h @@ -78,7 +78,13 @@ public: const AString & GetWindowTitle() const { return m_WindowTitle; } void SetWindowTitle( const std::string & a_WindowTitle ) { m_WindowTitle = a_WindowTitle; } - void OwnerDestroyed(); + 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 & 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 & a_Callback); private: diff --git a/source/packets/cPacket_WindowClick.cpp b/source/packets/cPacket_WindowClick.cpp index ac3191c28..05be3c53c 100644 --- a/source/packets/cPacket_WindowClick.cpp +++ b/source/packets/cPacket_WindowClick.cpp @@ -12,13 +12,11 @@ int cPacket_WindowClick::Parse(const char * a_Data, int a_Size) { int TotalBytes = 0; - HANDLE_PACKET_READ(ReadByte, m_WindowID, TotalBytes); - HANDLE_PACKET_READ(ReadShort, m_SlotNum, TotalBytes); - HANDLE_PACKET_READ(ReadByte, m_RightMouse, TotalBytes); - HANDLE_PACKET_READ(ReadShort, m_NumClicks, TotalBytes); - HANDLE_PACKET_READ(ReadBool, m_Bool, TotalBytes); - - // LOG("WindowClick: WindowID: %i; FromSlot: %i; Right/Le: %i; NumClick: %i", m_Type, m_SlotNum, m_RightMouse, m_NumClicks ); + HANDLE_PACKET_READ(ReadByte, m_WindowID, TotalBytes); + HANDLE_PACKET_READ(ReadShort, m_SlotNum, TotalBytes); + HANDLE_PACKET_READ(ReadByte, m_RightMouse, TotalBytes); + HANDLE_PACKET_READ(ReadShort, m_NumClicks, TotalBytes); + HANDLE_PACKET_READ(ReadBool, m_IsShiftPressed, TotalBytes); cPacket_ItemData Item; diff --git a/source/packets/cPacket_WindowClick.h b/source/packets/cPacket_WindowClick.h index e9abd80df..93dc5dc2e 100644 --- a/source/packets/cPacket_WindowClick.h +++ b/source/packets/cPacket_WindowClick.h @@ -15,7 +15,7 @@ public: , m_SlotNum( 0 ) , m_RightMouse( 0 ) , m_NumClicks( 0 ) - , m_Bool( false ) + , m_IsShiftPressed( false ) , m_ItemID( 0 ) , m_ItemCount( 0 ) , m_ItemUses( 0 ) @@ -33,9 +33,9 @@ public: // 9-35 = inventory // 36-44 = Hot bar - char m_RightMouse; // 0 = Left 1 = Right mb - short m_NumClicks; // Num clicks - bool m_Bool; // Shift pressed when clicked? + char m_RightMouse; // 0 = Left 1 = Right mb + short m_NumClicks; // Num clicks + bool m_IsShiftPressed; // Shift pressed when clicked? // Below = item short m_ItemID; // if this is -1 the next stuff dont exist -- cgit v1.2.3