#pragma once #include "game/world_packets.hpp" #include "game/opcode_table.hpp" #include "game/inventory.hpp" #include "game/handler_types.hpp" #include "network/packet.hpp" #include #include #include #include #include #include #include #include #include namespace wowee { namespace game { class GameHandler; class InventoryHandler { public: using PacketHandler = std::function; using DispatchTable = std::unordered_map; explicit InventoryHandler(GameHandler& owner); void registerOpcodes(DispatchTable& table); // ---- Item text (books / readable items) ---- bool isItemTextOpen() const { return itemTextOpen_; } const std::string& getItemText() const { return itemText_; } void closeItemText() { itemTextOpen_ = false; } void queryItemText(uint64_t itemGuid); // ---- Trade ---- enum class TradeStatus : uint8_t { None = 0, PendingIncoming, Open, Accepted, Complete }; static constexpr int TRADE_SLOT_COUNT = 6; struct TradeSlot { uint32_t itemId = 0; uint32_t displayId = 0; uint32_t stackCount = 0; uint64_t itemGuid = 0; }; TradeStatus getTradeStatus() const { return tradeStatus_; } bool hasPendingTradeRequest() const { return tradeStatus_ == TradeStatus::PendingIncoming; } bool isTradeOpen() const { return tradeStatus_ == TradeStatus::Open; } const std::string& getTradePeerName() const { return tradePeerName_; } const std::array& getMyTradeSlots() const { return myTradeSlots_; } const std::array& getPeerTradeSlots() const { return peerTradeSlots_; } uint64_t getMyTradeGold() const { return myTradeGold_; } uint64_t getPeerTradeGold() const { return peerTradeGold_; } void acceptTradeRequest(); void declineTradeRequest(); void acceptTrade(); void cancelTrade(); void setTradeItem(uint8_t tradeSlot, uint8_t srcBag, uint8_t srcSlot); void clearTradeItem(uint8_t tradeSlot); void setTradeGold(uint64_t amount); // ---- Loot ---- void lootTarget(uint64_t targetGuid); void lootItem(uint8_t slotIndex); void closeLoot(); bool isLootWindowOpen() const { return lootWindowOpen_; } const LootResponseData& getCurrentLoot() const { return currentLoot_; } void setAutoLoot(bool enabled) { autoLoot_ = enabled; } bool isAutoLoot() const { return autoLoot_; } void setAutoSellGrey(bool enabled) { autoSellGrey_ = enabled; } bool isAutoSellGrey() const { return autoSellGrey_; } void setAutoRepair(bool enabled) { autoRepair_ = enabled; } bool isAutoRepair() const { return autoRepair_; } // Master loot candidates (from SMSG_LOOT_MASTER_LIST) const std::vector& getMasterLootCandidates() const { return masterLootCandidates_; } bool hasMasterLootCandidates() const { return !masterLootCandidates_.empty(); } void lootMasterGive(uint8_t lootSlot, uint64_t targetGuid); // Group loot roll (aliased from handler_types.hpp) using LootRollEntry = game::LootRollEntry; bool hasPendingLootRoll() const { return pendingLootRollActive_; } const LootRollEntry& getPendingLootRoll() const { return pendingLootRoll_; } void sendLootRoll(uint64_t objectGuid, uint32_t slot, uint8_t rollType); // ---- Equipment Sets (aliased from handler_types.hpp) ---- using EquipmentSetInfo = game::EquipmentSetInfo; const std::vector& getEquipmentSets() const { return equipmentSetInfo_; } bool supportsEquipmentSets() const; void useEquipmentSet(uint32_t setId); void saveEquipmentSet(const std::string& name, const std::string& iconName = "INV_Misc_QuestionMark", uint64_t existingGuid = 0, uint32_t setIndex = 0xFFFFFFFF); void deleteEquipmentSet(uint64_t setGuid); // ---- Vendor ---- struct BuybackItem { uint64_t itemGuid = 0; ItemDef item; uint32_t count = 1; }; void openVendor(uint64_t npcGuid); void closeVendor(); void buyItem(uint64_t vendorGuid, uint32_t itemId, uint32_t slot, uint32_t count); void sellItem(uint64_t vendorGuid, uint64_t itemGuid, uint32_t count); void sellItemBySlot(int backpackIndex); void sellItemInBag(int bagIndex, int slotIndex); void buyBackItem(uint32_t buybackSlot); void repairItem(uint64_t vendorGuid, uint64_t itemGuid); void repairAll(uint64_t vendorGuid, bool useGuildBank = false); const std::deque& getBuybackItems() const { return buybackItems_; } void autoEquipItemBySlot(int backpackIndex); void autoEquipItemInBag(int bagIndex, int slotIndex); void useItemBySlot(int backpackIndex); void useItemInBag(int bagIndex, int slotIndex); void openItemBySlot(int backpackIndex); void openItemInBag(int bagIndex, int slotIndex); void destroyItem(uint8_t bag, uint8_t slot, uint8_t count = 1); void splitItem(uint8_t srcBag, uint8_t srcSlot, uint8_t count); void swapContainerItems(uint8_t srcBag, uint8_t srcSlot, uint8_t dstBag, uint8_t dstSlot); void swapBagSlots(int srcBagIndex, int dstBagIndex); void unequipToBackpack(EquipSlot equipSlot); void useItemById(uint32_t itemId); bool isVendorWindowOpen() const { return vendorWindowOpen_; } const ListInventoryData& getVendorItems() const { return currentVendorItems_; } void setVendorCanRepair(bool v) { currentVendorItems_.canRepair = v; } uint64_t getVendorGuid() const { return currentVendorItems_.vendorGuid; } // ---- Mail ---- static constexpr int MAIL_MAX_ATTACHMENTS = 12; struct MailAttachSlot { uint64_t itemGuid = 0; game::ItemDef item; uint8_t srcBag = 0xFF; uint8_t srcSlot = 0; bool occupied() const { return itemGuid != 0; } }; bool isMailboxOpen() const { return mailboxOpen_; } const std::vector& getMailInbox() const { return mailInbox_; } int getSelectedMailIndex() const { return selectedMailIndex_; } void setSelectedMailIndex(int idx) { selectedMailIndex_ = idx; } bool isMailComposeOpen() const { return showMailCompose_; } void openMailCompose() { showMailCompose_ = true; clearMailAttachments(); } void closeMailCompose() { showMailCompose_ = false; clearMailAttachments(); } bool hasNewMail() const { return hasNewMail_; } void closeMailbox(); void sendMail(const std::string& recipient, const std::string& subject, const std::string& body, uint64_t money, uint64_t cod = 0); bool attachItemFromBackpack(int backpackIndex); bool attachItemFromBag(int bagIndex, int slotIndex); bool detachMailAttachment(int attachIndex); void clearMailAttachments(); const std::array& getMailAttachments() const { return mailAttachments_; } int getMailAttachmentCount() const; void mailTakeMoney(uint32_t mailId); void mailTakeItem(uint32_t mailId, uint32_t itemGuidLow); void mailDelete(uint32_t mailId); void mailMarkAsRead(uint32_t mailId); void refreshMailList(); // ---- Bank ---- void openBank(uint64_t guid); void closeBank(); void buyBankSlot(); void depositItem(uint8_t srcBag, uint8_t srcSlot); void withdrawItem(uint8_t srcBag, uint8_t srcSlot); bool isBankOpen() const { return bankOpen_; } uint64_t getBankerGuid() const { return bankerGuid_; } int getEffectiveBankSlots() const { return effectiveBankSlots_; } int getEffectiveBankBagSlots() const { return effectiveBankBagSlots_; } // ---- Guild Bank ---- void openGuildBank(uint64_t guid); void closeGuildBank(); void queryGuildBankTab(uint8_t tabId); void buyGuildBankTab(); void depositGuildBankMoney(uint32_t amount); void withdrawGuildBankMoney(uint32_t amount); void guildBankWithdrawItem(uint8_t tabId, uint8_t bankSlot, uint8_t destBag, uint8_t destSlot); void guildBankDepositItem(uint8_t tabId, uint8_t bankSlot, uint8_t srcBag, uint8_t srcSlot); bool isGuildBankOpen() const { return guildBankOpen_; } const GuildBankData& getGuildBankData() const { return guildBankData_; } uint8_t getGuildBankActiveTab() const { return guildBankActiveTab_; } void setGuildBankActiveTab(uint8_t tab) { guildBankActiveTab_ = tab; } // ---- Auction House ---- void openAuctionHouse(uint64_t guid); void closeAuctionHouse(); void auctionSearch(const std::string& name, uint8_t levelMin, uint8_t levelMax, uint32_t quality, uint32_t itemClass, uint32_t itemSubClass, uint32_t invTypeMask, uint8_t usableOnly, uint32_t offset = 0); void auctionSellItem(uint64_t itemGuid, uint32_t stackCount, uint32_t bid, uint32_t buyout, uint32_t duration); void auctionPlaceBid(uint32_t auctionId, uint32_t amount); void auctionBuyout(uint32_t auctionId, uint32_t buyoutPrice); void auctionCancelItem(uint32_t auctionId); void auctionListOwnerItems(uint32_t offset = 0); void auctionListBidderItems(uint32_t offset = 0); bool isAuctionHouseOpen() const { return auctionOpen_; } uint64_t getAuctioneerGuid() const { return auctioneerGuid_; } const AuctionListResult& getAuctionBrowseResults() const { return auctionBrowseResults_; } const AuctionListResult& getAuctionOwnerResults() const { return auctionOwnerResults_; } const AuctionListResult& getAuctionBidderResults() const { return auctionBidderResults_; } int getAuctionActiveTab() const { return auctionActiveTab_; } void setAuctionActiveTab(int tab) { auctionActiveTab_ = tab; } float getAuctionSearchDelay() const { return auctionSearchDelayTimer_; } // ---- Trainer ---- struct TrainerTab { std::string name; std::vector spells; }; bool isTrainerWindowOpen() const { return trainerWindowOpen_; } const TrainerListData& getTrainerSpells() const { return currentTrainerList_; } void trainSpell(uint32_t spellId); void closeTrainer(); const std::vector& getTrainerTabs() const { return trainerTabs_; } void resetTradeState(); // ---- Methods moved from GameHandler ---- void initiateTrade(uint64_t targetGuid); uint32_t getTempEnchantRemainingMs(uint32_t slot) const; void addMoneyCopper(uint32_t amount); // ---- Inventory field / rebuild methods (moved from GameHandler) ---- void queryItemInfo(uint32_t entry, uint64_t guid); uint64_t resolveOnlineItemGuid(uint32_t itemId) const; void detectInventorySlotBases(const std::map& fields); bool applyInventoryFields(const std::map& fields); void extractContainerFields(uint64_t containerGuid, const std::map& fields); void rebuildOnlineInventory(); void maybeDetectVisibleItemLayout(); void updateOtherPlayerVisibleItems(uint64_t guid, const std::map& fields); void emitOtherPlayerEquipment(uint64_t guid); void emitAllOtherPlayerEquipment(); void handleItemQueryResponse(network::Packet& packet); private: // --- Packet handlers --- void handleLootResponse(network::Packet& packet); void handleLootReleaseResponse(network::Packet& packet); void handleLootRemoved(network::Packet& packet); void handleListInventory(network::Packet& packet); void handleTrainerList(network::Packet& packet); void handleItemTextQueryResponse(network::Packet& packet); void handleTradeStatus(network::Packet& packet); void handleTradeStatusExtended(network::Packet& packet); void handleLootRoll(network::Packet& packet); void handleLootRollWon(network::Packet& packet); void handleShowBank(network::Packet& packet); void handleBuyBankSlotResult(network::Packet& packet); void handleGuildBankList(network::Packet& packet); void handleAuctionHello(network::Packet& packet); void handleAuctionListResult(network::Packet& packet); void handleAuctionOwnerListResult(network::Packet& packet); void handleAuctionBidderListResult(network::Packet& packet); void handleAuctionCommandResult(network::Packet& packet); void handleShowMailbox(network::Packet& packet); void handleMailListResult(network::Packet& packet); void handleSendMailResult(network::Packet& packet); void handleReceivedMail(network::Packet& packet); void handleQueryNextMailTime(network::Packet& packet); void handleEquipmentSetList(network::Packet& packet); void categorizeTrainerSpells(); void handleTrainerBuySucceeded(network::Packet& packet); void handleTrainerBuyFailed(network::Packet& packet); GameHandler& owner_; // ---- Item text state ---- bool itemTextOpen_ = false; std::string itemText_; // ---- Trade state ---- TradeStatus tradeStatus_ = TradeStatus::None; uint64_t tradePeerGuid_= 0; std::string tradePeerName_; std::array myTradeSlots_{}; std::array peerTradeSlots_{}; uint64_t myTradeGold_ = 0; uint64_t peerTradeGold_ = 0; // ---- Loot state ---- bool lootWindowOpen_ = false; bool autoLoot_ = false; bool autoSellGrey_ = false; bool autoRepair_ = false; LootResponseData currentLoot_; std::vector masterLootCandidates_; // Group loot roll state bool pendingLootRollActive_ = false; LootRollEntry pendingLootRoll_; struct LocalLootState { LootResponseData data; bool moneyTaken = false; bool itemAutoLootSent = false; }; std::unordered_map localLootState_; struct PendingLootRetry { uint64_t guid = 0; float timer = 0.0f; uint8_t remainingRetries = 0; bool sendLoot = false; }; std::vector pendingGameObjectLootRetries_; struct PendingLootOpen { uint64_t guid = 0; float timer = 0.0f; }; std::vector pendingGameObjectLootOpens_; uint64_t lastInteractedGoGuid_ = 0; uint64_t pendingLootMoneyGuid_ = 0; uint32_t pendingLootMoneyAmount_ = 0; float pendingLootMoneyNotifyTimer_ = 0.0f; std::unordered_map recentLootMoneyAnnounceCooldowns_; // ---- Vendor state ---- bool vendorWindowOpen_ = false; ListInventoryData currentVendorItems_; std::deque buybackItems_; std::unordered_map pendingSellToBuyback_; int pendingBuybackSlot_ = -1; uint32_t pendingBuybackWireSlot_ = 0; uint32_t pendingBuyItemId_ = 0; uint32_t pendingBuyItemSlot_ = 0; // ---- Mail state ---- bool mailboxOpen_ = false; uint64_t mailboxGuid_ = 0; std::vector mailInbox_; int selectedMailIndex_ = -1; bool showMailCompose_ = false; bool hasNewMail_ = false; std::array mailAttachments_{}; // ---- Bank state ---- bool bankOpen_ = false; uint64_t bankerGuid_ = 0; std::array bankSlotGuids_{}; std::array bankBagSlotGuids_{}; int effectiveBankSlots_ = 28; int effectiveBankBagSlots_ = 7; // ---- Guild Bank state ---- bool guildBankOpen_ = false; uint64_t guildBankerGuid_ = 0; GuildBankData guildBankData_; uint8_t guildBankActiveTab_ = 0; // ---- Auction House state ---- bool auctionOpen_ = false; uint64_t auctioneerGuid_ = 0; uint32_t auctionHouseId_ = 0; AuctionListResult auctionBrowseResults_; AuctionListResult auctionOwnerResults_; AuctionListResult auctionBidderResults_; int auctionActiveTab_ = 0; float auctionSearchDelayTimer_ = 0.0f; struct AuctionSearchParams { std::string name; uint8_t levelMin = 0, levelMax = 0; uint32_t quality = 0xFFFFFFFF; uint32_t itemClass = 0xFFFFFFFF; uint32_t itemSubClass = 0xFFFFFFFF; uint32_t invTypeMask = 0; uint8_t usableOnly = 0; uint32_t offset = 0; }; AuctionSearchParams lastAuctionSearch_; enum class AuctionResultTarget { BROWSE, OWNER, BIDDER }; AuctionResultTarget pendingAuctionTarget_ = AuctionResultTarget::BROWSE; // ---- Trainer state ---- bool trainerWindowOpen_ = false; TrainerListData currentTrainerList_; std::vector trainerTabs_; // ---- Equipment set state ---- struct EquipmentSet { uint64_t setGuid = 0; uint32_t setId = 0; std::string name; std::string iconName; uint32_t ignoreSlotMask = 0; std::array itemGuids{}; }; std::vector equipmentSets_; std::string pendingSaveSetName_; std::string pendingSaveSetIcon_; std::vector equipmentSetInfo_; }; } // namespace game } // namespace wowee