From 94f178c26148f1be3095aa313ac8b43b6cfaef2c Mon Sep 17 00:00:00 2001 From: Pedro Cruz Date: Thu, 9 May 2024 09:19:32 -0300 Subject: [PATCH 1/2] fix: beds (#2611) --- src/items/bed.cpp | 24 ++++++++++++++++++------ src/items/bed.hpp | 2 ++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/items/bed.cpp b/src/items/bed.cpp index d093dcc5fd9..4b38be3b474 100644 --- a/src/items/bed.cpp +++ b/src/items/bed.cpp @@ -94,12 +94,7 @@ bool BedItem::canUse(std::shared_ptr player) { return false; } - auto partName = itemType.name; - auto nextPartname = nextBedItem->getName(); - auto firstPart = keepFirstWordOnly(partName); - auto nextPartOf = keepFirstWordOnly(nextPartname); - g_logger().debug("First bed part name {}, second part name {}", firstPart, nextPartOf); - if (!isMovable() || !nextBedItem->isMovable() || firstPart != nextPartOf) { + if (!isMovable() || !nextBedItem->isMovable() || !isBedComplete(nextBedItem)) { return false; } @@ -122,6 +117,23 @@ bool BedItem::canUse(std::shared_ptr player) { return true; } +bool BedItem::isBedComplete(std::shared_ptr nextBedItem) { + const ItemType &it = Item::items[id]; + + if (nextBedItem == nullptr) { + return false; + } + + auto partName = it.name; + auto nextPartname = nextBedItem->getName(); + auto firstPart = keepFirstWordOnly(partName); + auto nextPartOf = keepFirstWordOnly(nextPartname); + + g_logger().debug("First bed part id {} name {}, second part id {} name {}", it.id, firstPart, nextBedItem->getID(), nextPartOf); + + return it.bedPartOf == nextBedItem->getID(); +} + bool BedItem::trySleep(std::shared_ptr player) { if (!house || player->isRemoved()) { return false; diff --git a/src/items/bed.hpp b/src/items/bed.hpp index 59c0c66f68c..2aeb6e38e5b 100644 --- a/src/items/bed.hpp +++ b/src/items/bed.hpp @@ -39,6 +39,8 @@ class BedItem final : public Item { bool canUse(std::shared_ptr player); + bool isBedComplete(std::shared_ptr nextBedItem); + bool trySleep(std::shared_ptr player); bool sleep(std::shared_ptr player); void wakeUp(std::shared_ptr player); From 09765f8b2cac1b14cb1313d7b4cb1e9295238b61 Mon Sep 17 00:00:00 2001 From: Pedro Cruz Date: Thu, 9 May 2024 09:19:56 -0300 Subject: [PATCH 2/2] feat: cyclopedia item summary (#2601) --- src/creatures/players/player.cpp | 54 +++++++++- src/creatures/players/player.hpp | 14 ++- src/game/game.cpp | 11 +- src/server/network/protocol/protocolgame.cpp | 105 +++++++++++++++++-- src/server/network/protocol/protocolgame.hpp | 2 +- 5 files changed, 170 insertions(+), 16 deletions(-) diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 8b889ac200b..0ddb407687b 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -3930,7 +3930,7 @@ bool Player::removeItemCountById(uint16_t itemId, uint32_t itemAmount, bool remo return false; } -ItemsTierCountList Player::getInventoryItemsId() const { +ItemsTierCountList Player::getInventoryItemsId(bool ignoreStoreInbox /* false */) const { ItemsTierCountList itemMap; for (int32_t i = CONST_SLOT_FIRST; i <= CONST_SLOT_LAST; i++) { std::shared_ptr item = inventory[i]; @@ -3938,8 +3938,14 @@ ItemsTierCountList Player::getInventoryItemsId() const { continue; } - (itemMap[item->getID()])[item->getTier()] += Item::countByType(item, -1); - if (std::shared_ptr container = item->getContainer()) { + const bool isStoreInbox = item->getID() == ITEM_STORE_INBOX; + + if (!isStoreInbox) { + (itemMap[item->getID()])[item->getTier()] += Item::countByType(item, -1); + } + + const auto &container = item->getContainer(); + if (container && (!isStoreInbox || !ignoreStoreInbox)) { for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) { auto containerItem = *it; (itemMap[containerItem->getID()])[containerItem->getTier()] += Item::countByType(containerItem, -1); @@ -4038,6 +4044,48 @@ double_t Player::calculateDamageReduction(double_t currentTotal, int16_t resista return (100 - currentTotal) / 100.0 * resistance + currentTotal; } +ItemsTierCountList Player::getStoreInboxItemsId() const { + ItemsTierCountList itemMap; + const auto &container = getStoreInbox(); + if (container) { + for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) { + std::shared_ptr item = *it; + (itemMap[item->getID()])[item->getTier()] += Item::countByType(item, -1); + } + } + + return itemMap; +} + +ItemsTierCountList Player::getDepotChestItemsId() const { + ItemsTierCountList itemMap; + + for (const auto &[index, depot] : depotChests) { + const std::shared_ptr &container = depot->getContainer(); + for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) { + std::shared_ptr item = *it; + (itemMap[item->getID()])[item->getTier()] += Item::countByType(item, -1); + } + } + + return itemMap; +} + +ItemsTierCountList Player::getDepotInboxItemsId() const { + ItemsTierCountList itemMap; + + const std::shared_ptr &inbox = getInbox(); + const std::shared_ptr &container = inbox->getContainer(); + if (container) { + for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) { + const auto &item = *it; + (itemMap[item->getID()])[item->getTier()] += Item::countByType(item, -1); + } + } + + return itemMap; +} + std::vector> Player::getAllInventoryItems(bool ignoreEquiped /*= false*/, bool ignoreItemWithTier /* false*/) const { std::vector> itemVector; for (int i = CONST_SLOT_FIRST; i <= CONST_SLOT_LAST; ++i) { diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index ca9c944bb2e..7d0291c4a3f 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -1641,9 +1641,9 @@ class Player final : public Creature, public Cylinder, public Bankable { } } void sendCyclopediaCharacterAchievements(uint16_t secretsUnlocked, std::vector> achievementsUnlocked); - void sendCyclopediaCharacterItemSummary() { + void sendCyclopediaCharacterItemSummary(const ItemsTierCountList &inventoryItems, const ItemsTierCountList &storeInboxItems, const StashItemList &supplyStashItems, const ItemsTierCountList &depotBoxItems, const ItemsTierCountList &inboxItems) { if (client) { - client->sendCyclopediaCharacterItemSummary(); + client->sendCyclopediaCharacterItemSummary(inventoryItems, storeInboxItems, supplyStashItems, depotBoxItems, inboxItems); } } void sendCyclopediaCharacterOutfitsMounts() { @@ -2581,6 +2581,13 @@ class Player final : public Creature, public Cylinder, public Bankable { // Get specific inventory item from itemid std::vector> getInventoryItemsFromId(uint16_t itemId, bool ignore = true) const; + // this get all player store inbox items and return as ItemsTierCountList + ItemsTierCountList getStoreInboxItemsId() const; + // this get all player depot chest items and return as ItemsTierCountList + ItemsTierCountList getDepotChestItemsId() const; + // this get all player depot inbox items and return as ItemsTierCountList + ItemsTierCountList getDepotInboxItemsId() const; + // This get all player inventory items std::vector> getAllInventoryItems(bool ignoreEquiped = false, bool ignoreItemWithTier = false) const; @@ -2677,8 +2684,7 @@ class Player final : public Creature, public Cylinder, public Bankable { size_t getLastIndex() const override; uint32_t getItemTypeCount(uint16_t itemId, int32_t subType = -1) const override; void stashContainer(StashContainerList itemDict); - ItemsTierCountList getInventoryItemsId() const; - // todo ItemsTierCountList getStoreInboxItemsId() const; + ItemsTierCountList getInventoryItemsId(bool ignoreStoreInbox = false) const; // This function is a override function of base class std::map &getAllItemTypeCount(std::map &countMap) const override; diff --git a/src/game/game.cpp b/src/game/game.cpp index 18c46668a4f..fe52310e6b4 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -8307,9 +8307,16 @@ void Game::playerCyclopediaCharacterInfo(std::shared_ptr player, uint32_ case CYCLOPEDIA_CHARACTERINFO_ACHIEVEMENTS: player->achiev()->sendUnlockedSecretAchievements(); break; - case CYCLOPEDIA_CHARACTERINFO_ITEMSUMMARY: - player->sendCyclopediaCharacterItemSummary(); + case CYCLOPEDIA_CHARACTERINFO_ITEMSUMMARY: { + const ItemsTierCountList &inventoryItems = player->getInventoryItemsId(true); + const ItemsTierCountList &storeInboxItems = player->getStoreInboxItemsId(); + const StashItemList &supplyStashItems = player->getStashItems(); + const ItemsTierCountList &depotBoxItems = player->getDepotChestItemsId(); + const ItemsTierCountList &inboxItems = player->getDepotInboxItemsId(); + + player->sendCyclopediaCharacterItemSummary(inventoryItems, storeInboxItems, supplyStashItems, depotBoxItems, inboxItems); break; + } case CYCLOPEDIA_CHARACTERINFO_OUTFITSMOUNTS: player->sendCyclopediaCharacterOutfitsMounts(); break; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 3b133d68893..73b639885e6 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -3699,7 +3699,7 @@ void ProtocolGame::sendCyclopediaCharacterAchievements(uint16_t secretsUnlocked, writeToOutputBuffer(msg); } -void ProtocolGame::sendCyclopediaCharacterItemSummary() { +void ProtocolGame::sendCyclopediaCharacterItemSummary(const ItemsTierCountList &inventoryItems, const ItemsTierCountList &storeInboxItems, const StashItemList &supplyStashItems, const ItemsTierCountList &depotBoxItems, const ItemsTierCountList &inboxItems) { if (!player || oldProtocol) { return; } @@ -3709,11 +3709,104 @@ void ProtocolGame::sendCyclopediaCharacterItemSummary() { msg.addByte(CYCLOPEDIA_CHARACTERINFO_ITEMSUMMARY); msg.addByte(0x00); // 0x00 Here means 'no error' - msg.add(0); // inventoryItems.size() - msg.add(0); // storeInboxItems.size() - msg.add(0); // supplyStashItems.size() - msg.add(0); // depotBoxItems.size() - msg.add(0); // inboxItems.size() + uint16_t inventoryItemsCount = 0; + const auto startInventory = msg.getBufferPosition(); + msg.skipBytes(2); + + for (const auto &inventoryItems_it : inventoryItems) { + for (const auto &[itemTier, itemCount] : inventoryItems_it.second) { + const ItemType &it = Item::items[inventoryItems_it.first]; + msg.add(inventoryItems_it.first); // Item ID + if (it.upgradeClassification > 0) { + msg.addByte(itemTier); + } + msg.add(itemCount); + + ++inventoryItemsCount; + } + } + + const auto endInventory = msg.getBufferPosition(); + + msg.setBufferPosition(startInventory); + msg.add(inventoryItemsCount); + + msg.setBufferPosition(endInventory); + + uint16_t storeInboxItemsCount = 0; + const auto startStoreInbox = msg.getBufferPosition(); + msg.skipBytes(2); + + for (const auto &storeInboxItems_it : storeInboxItems) { + for (const auto &[itemTier, itemCount] : storeInboxItems_it.second) { + const ItemType &it = Item::items[storeInboxItems_it.first]; + msg.add(storeInboxItems_it.first); // Item ID + if (it.upgradeClassification > 0) { + msg.addByte(itemTier); + } + msg.add(itemCount); + + ++storeInboxItemsCount; + } + } + + const auto endStoreInbox = msg.getBufferPosition(); + + msg.setBufferPosition(startStoreInbox); + msg.add(storeInboxItemsCount); + + msg.setBufferPosition(endStoreInbox); + + msg.add(supplyStashItems.size()); + + for (const auto &[itemId, itemCount] : supplyStashItems) { + msg.add(itemId); + msg.add(itemCount); + } + + uint16_t depotBoxItemsCount = 0; + const auto startDepotBox = msg.getBufferPosition(); + msg.skipBytes(2); + + for (const auto &depotBoxItems_it : depotBoxItems) { + for (const auto &[itemTier, itemCount] : depotBoxItems_it.second) { + const ItemType &it = Item::items[depotBoxItems_it.first]; + msg.add(depotBoxItems_it.first); // Item ID + if (it.upgradeClassification > 0) { + msg.addByte(itemTier); + } + msg.add(itemCount); + + ++depotBoxItemsCount; + } + } + + const auto endDepotBox = msg.getBufferPosition(); + + msg.setBufferPosition(startDepotBox); + msg.add(depotBoxItemsCount); + + msg.setBufferPosition(endDepotBox); + + uint16_t inboxItemsCount = 0; + const auto startInbox = msg.getBufferPosition(); + msg.skipBytes(2); + + for (const auto &inboxItems_it : inboxItems) { + for (const auto &[itemTier, itemCount] : inboxItems_it.second) { + const ItemType &it = Item::items[inboxItems_it.first]; + msg.add(inboxItems_it.first); // Item ID + if (it.upgradeClassification > 0) { + msg.addByte(itemTier); + } + msg.add(itemCount); + + ++inboxItemsCount; + } + } + + msg.setBufferPosition(startInbox); + msg.add(inboxItemsCount); writeToOutputBuffer(msg); } diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index 7aea8ff805d..19e62c428e9 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -317,7 +317,7 @@ class ProtocolGame final : public Protocol { void sendCyclopediaCharacterRecentDeaths(uint16_t page, uint16_t pages, const std::vector &entries); void sendCyclopediaCharacterRecentPvPKills(uint16_t page, uint16_t pages, const std::vector &entries); void sendCyclopediaCharacterAchievements(uint16_t secretsUnlocked, std::vector> achievementsUnlocked); - void sendCyclopediaCharacterItemSummary(); + void sendCyclopediaCharacterItemSummary(const ItemsTierCountList &inventoryItems, const ItemsTierCountList &storeInboxItems, const StashItemList &supplyStashItems, const ItemsTierCountList &depotBoxItems, const ItemsTierCountList &inboxItems); void sendCyclopediaCharacterOutfitsMounts(); void sendCyclopediaCharacterStoreSummary(); void sendCyclopediaCharacterInspection();