mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-25 16:30:15 +00:00
Implement bank, guild bank, and auction house systems
Add 27 new opcodes, packet builders/parsers, handler methods, inventory extension with 28 bank slots + 7 bank bags, and UI windows for personal bank, guild bank (6 tabs x 98 slots), and auction house (browse/sell/bid). Fix Classic gossip parser to omit boxMoney/boxText fields not present in Vanilla protocol, fix gossip icon labels with text-based NPC type detection, and add Turtle WoW opcode mappings for bank and auction interactions.
This commit is contained in:
parent
0d4a9c38f7
commit
381d896348
14 changed files with 1839 additions and 15 deletions
|
|
@ -785,6 +785,51 @@ public:
|
|||
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_; }
|
||||
|
||||
// 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
|
||||
bool isTrainerWindowOpen() const { return trainerWindowOpen_; }
|
||||
const TrainerListData& getTrainerSpells() const { return currentTrainerList_; }
|
||||
|
|
@ -1010,6 +1055,20 @@ private:
|
|||
void handleArenaTeamEvent(network::Packet& packet);
|
||||
void handleArenaError(network::Packet& packet);
|
||||
|
||||
// ---- Bank handlers ----
|
||||
void handleShowBank(network::Packet& packet);
|
||||
void handleBuyBankSlotResult(network::Packet& packet);
|
||||
|
||||
// ---- Guild Bank handlers ----
|
||||
void handleGuildBankList(network::Packet& packet);
|
||||
|
||||
// ---- Auction House handlers ----
|
||||
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);
|
||||
|
||||
// ---- Mail handlers ----
|
||||
void handleShowMailbox(network::Packet& packet);
|
||||
void handleMailListResult(network::Packet& packet);
|
||||
|
|
@ -1360,6 +1419,31 @@ private:
|
|||
bool showMailCompose_ = false;
|
||||
bool hasNewMail_ = false;
|
||||
|
||||
// Bank
|
||||
bool bankOpen_ = false;
|
||||
uint64_t bankerGuid_ = 0;
|
||||
std::array<uint64_t, 28> bankSlotGuids_{};
|
||||
std::array<uint64_t, 7> bankBagSlotGuids_{};
|
||||
|
||||
// Guild Bank
|
||||
bool guildBankOpen_ = false;
|
||||
uint64_t guildBankerGuid_ = 0;
|
||||
GuildBankData guildBankData_;
|
||||
uint8_t guildBankActiveTab_ = 0;
|
||||
|
||||
// Auction House
|
||||
bool auctionOpen_ = false;
|
||||
uint64_t auctioneerGuid_ = 0;
|
||||
uint32_t auctionHouseId_ = 0;
|
||||
AuctionListResult auctionBrowseResults_;
|
||||
AuctionListResult auctionOwnerResults_;
|
||||
AuctionListResult auctionBidderResults_;
|
||||
int auctionActiveTab_ = 0; // 0=Browse, 1=Bids, 2=Auctions
|
||||
float auctionSearchDelayTimer_ = 0.0f;
|
||||
// Routing: which result vector to populate from next SMSG_AUCTION_LIST_RESULT
|
||||
enum class AuctionResultTarget { BROWSE, OWNER, BIDDER };
|
||||
AuctionResultTarget pendingAuctionTarget_ = AuctionResultTarget::BROWSE;
|
||||
|
||||
// Vendor
|
||||
bool vendorWindowOpen = false;
|
||||
ListInventoryData currentVendorItems;
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ public:
|
|||
static constexpr int NUM_EQUIP_SLOTS = 23;
|
||||
static constexpr int NUM_BAG_SLOTS = 4;
|
||||
static constexpr int MAX_BAG_SIZE = 36;
|
||||
static constexpr int BANK_SLOTS = 28;
|
||||
static constexpr int BANK_BAG_SLOTS = 7;
|
||||
|
||||
Inventory();
|
||||
|
||||
|
|
@ -76,6 +78,19 @@ public:
|
|||
const ItemSlot& getBagSlot(int bagIndex, int slotIndex) const;
|
||||
bool setBagSlot(int bagIndex, int slotIndex, const ItemDef& item);
|
||||
|
||||
// Bank slots (28 main + 7 bank bags)
|
||||
const ItemSlot& getBankSlot(int index) const;
|
||||
bool setBankSlot(int index, const ItemDef& item);
|
||||
bool clearBankSlot(int index);
|
||||
|
||||
const ItemSlot& getBankBagSlot(int bagIndex, int slotIndex) const;
|
||||
bool setBankBagSlot(int bagIndex, int slotIndex, const ItemDef& item);
|
||||
int getBankBagSize(int bagIndex) const;
|
||||
void setBankBagSize(int bagIndex, int size);
|
||||
|
||||
uint8_t getPurchasedBankBagSlots() const { return purchasedBankBagSlots_; }
|
||||
void setPurchasedBankBagSlots(uint8_t count) { purchasedBankBagSlots_ = count; }
|
||||
|
||||
// Utility
|
||||
int findFreeBackpackSlot() const;
|
||||
bool addItem(const ItemDef& item);
|
||||
|
|
@ -92,6 +107,11 @@ private:
|
|||
std::array<ItemSlot, MAX_BAG_SIZE> slots{};
|
||||
};
|
||||
std::array<BagData, NUM_BAG_SLOTS> bags{};
|
||||
|
||||
// Bank
|
||||
std::array<ItemSlot, BANK_SLOTS> bankSlots_{};
|
||||
std::array<BagData, BANK_BAG_SLOTS> bankBags_{};
|
||||
uint8_t purchasedBankBagSlots_ = 0;
|
||||
};
|
||||
|
||||
const char* getQualityName(ItemQuality quality);
|
||||
|
|
|
|||
|
|
@ -382,6 +382,39 @@ enum class LogicalOpcode : uint16_t {
|
|||
SMSG_RECEIVED_MAIL,
|
||||
MSG_QUERY_NEXT_MAIL_TIME,
|
||||
|
||||
// ---- Bank ----
|
||||
CMSG_BANKER_ACTIVATE,
|
||||
SMSG_SHOW_BANK,
|
||||
CMSG_BUY_BANK_SLOT,
|
||||
SMSG_BUY_BANK_SLOT_RESULT,
|
||||
CMSG_AUTOBANK_ITEM,
|
||||
CMSG_AUTOSTORE_BANK_ITEM,
|
||||
|
||||
// ---- Guild Bank ----
|
||||
CMSG_GUILD_BANKER_ACTIVATE,
|
||||
CMSG_GUILD_BANK_QUERY_TAB,
|
||||
SMSG_GUILD_BANK_LIST,
|
||||
CMSG_GUILD_BANK_SWAP_ITEMS,
|
||||
CMSG_GUILD_BANK_BUY_TAB,
|
||||
CMSG_GUILD_BANK_UPDATE_TAB,
|
||||
CMSG_GUILD_BANK_DEPOSIT_MONEY,
|
||||
CMSG_GUILD_BANK_WITHDRAW_MONEY,
|
||||
|
||||
// ---- Auction House ----
|
||||
MSG_AUCTION_HELLO,
|
||||
CMSG_AUCTION_SELL_ITEM,
|
||||
CMSG_AUCTION_REMOVE_ITEM,
|
||||
CMSG_AUCTION_LIST_ITEMS,
|
||||
CMSG_AUCTION_LIST_OWNER_ITEMS,
|
||||
CMSG_AUCTION_PLACE_BID,
|
||||
SMSG_AUCTION_COMMAND_RESULT,
|
||||
SMSG_AUCTION_LIST_RESULT,
|
||||
SMSG_AUCTION_OWNER_LIST_RESULT,
|
||||
SMSG_AUCTION_BIDDER_LIST_RESULT,
|
||||
SMSG_AUCTION_OWNER_NOTIFICATION,
|
||||
SMSG_AUCTION_BIDDER_NOTIFICATION,
|
||||
CMSG_AUCTION_LIST_BIDDER_ITEMS,
|
||||
|
||||
// Sentinel
|
||||
COUNT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ enum class UF : uint16_t {
|
|||
PLAYER_QUEST_LOG_START,
|
||||
PLAYER_FIELD_INV_SLOT_HEAD,
|
||||
PLAYER_FIELD_PACK_SLOT_1,
|
||||
PLAYER_FIELD_BANK_SLOT_1,
|
||||
PLAYER_FIELD_BANKBAG_SLOT_1,
|
||||
PLAYER_SKILL_INFO_START,
|
||||
PLAYER_EXPLORED_ZONES_START,
|
||||
|
||||
|
|
|
|||
|
|
@ -2262,5 +2262,213 @@ public:
|
|||
static network::Packet build(uint64_t mailboxGuid, uint32_t mailId);
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Bank System
|
||||
// ============================================================
|
||||
|
||||
/** CMSG_BANKER_ACTIVATE packet builder */
|
||||
class BankerActivatePacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid);
|
||||
};
|
||||
|
||||
/** CMSG_BUY_BANK_SLOT packet builder */
|
||||
class BuyBankSlotPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid);
|
||||
};
|
||||
|
||||
/** CMSG_AUTOBANK_ITEM packet builder (deposit item to bank) */
|
||||
class AutoBankItemPacket {
|
||||
public:
|
||||
static network::Packet build(uint8_t srcBag, uint8_t srcSlot);
|
||||
};
|
||||
|
||||
/** CMSG_AUTOSTORE_BANK_ITEM packet builder (withdraw item from bank) */
|
||||
class AutoStoreBankItemPacket {
|
||||
public:
|
||||
static network::Packet build(uint8_t srcBag, uint8_t srcSlot);
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Guild Bank System
|
||||
// ============================================================
|
||||
|
||||
struct GuildBankItemSlot {
|
||||
uint8_t slotId = 0;
|
||||
uint32_t itemEntry = 0;
|
||||
uint32_t stackCount = 1;
|
||||
uint32_t enchantId = 0;
|
||||
uint32_t randomPropertyId = 0;
|
||||
};
|
||||
|
||||
struct GuildBankTab {
|
||||
std::string tabName;
|
||||
std::string tabIcon;
|
||||
std::vector<GuildBankItemSlot> items;
|
||||
};
|
||||
|
||||
struct GuildBankData {
|
||||
uint64_t money = 0;
|
||||
uint8_t tabId = 0;
|
||||
int32_t withdrawAmount = -1; // -1 = unlimited
|
||||
std::vector<GuildBankTab> tabs; // Only populated on fullUpdate
|
||||
std::vector<GuildBankItemSlot> tabItems; // Current tab items
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_BANKER_ACTIVATE packet builder */
|
||||
class GuildBankerActivatePacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_BANK_QUERY_TAB packet builder */
|
||||
class GuildBankQueryTabPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid, uint8_t tabId, bool fullUpdate);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_BANK_BUY_TAB packet builder */
|
||||
class GuildBankBuyTabPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid, uint8_t tabId);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_BANK_DEPOSIT_MONEY packet builder */
|
||||
class GuildBankDepositMoneyPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid, uint32_t amount);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_BANK_WITHDRAW_MONEY packet builder */
|
||||
class GuildBankWithdrawMoneyPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid, uint32_t amount);
|
||||
};
|
||||
|
||||
/** CMSG_GUILD_BANK_SWAP_ITEMS packet builder */
|
||||
class GuildBankSwapItemsPacket {
|
||||
public:
|
||||
// Bank to inventory
|
||||
static network::Packet buildBankToInventory(uint64_t guid, uint8_t tabId, uint8_t bankSlot,
|
||||
uint8_t destBag, uint8_t destSlot, uint32_t splitCount = 0);
|
||||
// Inventory to bank
|
||||
static network::Packet buildInventoryToBank(uint64_t guid, uint8_t tabId, uint8_t bankSlot,
|
||||
uint8_t srcBag, uint8_t srcSlot, uint32_t splitCount = 0);
|
||||
};
|
||||
|
||||
/** SMSG_GUILD_BANK_LIST parser */
|
||||
class GuildBankListParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, GuildBankData& data);
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
// Auction House System
|
||||
// ============================================================
|
||||
|
||||
struct AuctionEntry {
|
||||
uint32_t auctionId = 0;
|
||||
uint32_t itemEntry = 0;
|
||||
uint32_t stackCount = 1;
|
||||
uint32_t enchantId = 0;
|
||||
uint32_t randomPropertyId = 0;
|
||||
uint32_t suffixFactor = 0;
|
||||
uint64_t ownerGuid = 0;
|
||||
uint32_t startBid = 0;
|
||||
uint32_t minBidIncrement = 0;
|
||||
uint32_t buyoutPrice = 0;
|
||||
uint32_t timeLeftMs = 0;
|
||||
uint64_t bidderGuid = 0;
|
||||
uint32_t currentBid = 0;
|
||||
};
|
||||
|
||||
struct AuctionListResult {
|
||||
std::vector<AuctionEntry> auctions;
|
||||
uint32_t totalCount = 0;
|
||||
uint32_t searchDelay = 0;
|
||||
};
|
||||
|
||||
struct AuctionCommandResult {
|
||||
uint32_t auctionId = 0;
|
||||
uint32_t action = 0; // 0=create, 1=cancel, 2=bid, 3=buyout
|
||||
uint32_t errorCode = 0; // 0=success
|
||||
uint32_t bidError = 0; // secondary error for bid actions
|
||||
};
|
||||
|
||||
struct AuctionHelloData {
|
||||
uint64_t auctioneerGuid = 0;
|
||||
uint32_t auctionHouseId = 0;
|
||||
uint8_t enabled = 1;
|
||||
};
|
||||
|
||||
/** MSG_AUCTION_HELLO packet builder */
|
||||
class AuctionHelloPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid);
|
||||
};
|
||||
|
||||
/** MSG_AUCTION_HELLO parser (server response) */
|
||||
class AuctionHelloParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, AuctionHelloData& data);
|
||||
};
|
||||
|
||||
/** CMSG_AUCTION_LIST_ITEMS packet builder */
|
||||
class AuctionListItemsPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t guid, uint32_t offset,
|
||||
const std::string& searchName,
|
||||
uint8_t levelMin, uint8_t levelMax,
|
||||
uint32_t invTypeMask, uint32_t itemClass,
|
||||
uint32_t itemSubClass, uint32_t quality,
|
||||
uint8_t usableOnly, uint8_t exactMatch);
|
||||
};
|
||||
|
||||
/** CMSG_AUCTION_SELL_ITEM packet builder */
|
||||
class AuctionSellItemPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t auctioneerGuid, uint64_t itemGuid,
|
||||
uint32_t stackCount, uint32_t bid,
|
||||
uint32_t buyout, uint32_t duration);
|
||||
};
|
||||
|
||||
/** CMSG_AUCTION_PLACE_BID packet builder */
|
||||
class AuctionPlaceBidPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t auctioneerGuid, uint32_t auctionId, uint32_t amount);
|
||||
};
|
||||
|
||||
/** CMSG_AUCTION_REMOVE_ITEM packet builder */
|
||||
class AuctionRemoveItemPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t auctioneerGuid, uint32_t auctionId);
|
||||
};
|
||||
|
||||
/** CMSG_AUCTION_LIST_OWNER_ITEMS packet builder */
|
||||
class AuctionListOwnerItemsPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t auctioneerGuid, uint32_t offset);
|
||||
};
|
||||
|
||||
/** CMSG_AUCTION_LIST_BIDDER_ITEMS packet builder */
|
||||
class AuctionListBidderItemsPacket {
|
||||
public:
|
||||
static network::Packet build(uint64_t auctioneerGuid, uint32_t offset,
|
||||
const std::vector<uint32_t>& outbiddedIds = {});
|
||||
};
|
||||
|
||||
/** SMSG_AUCTION_LIST_RESULT parser (shared for browse/owner/bidder) */
|
||||
class AuctionListResultParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, AuctionListResult& data);
|
||||
};
|
||||
|
||||
/** SMSG_AUCTION_COMMAND_RESULT parser */
|
||||
class AuctionCommandResultParser {
|
||||
public:
|
||||
static bool parse(network::Packet& packet, AuctionCommandResult& data);
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
} // namespace wowee
|
||||
|
|
|
|||
|
|
@ -187,6 +187,9 @@ private:
|
|||
void renderChatBubbles(game::GameHandler& gameHandler);
|
||||
void renderMailWindow(game::GameHandler& gameHandler);
|
||||
void renderMailComposeWindow(game::GameHandler& gameHandler);
|
||||
void renderBankWindow(game::GameHandler& gameHandler);
|
||||
void renderGuildBankWindow(game::GameHandler& gameHandler);
|
||||
void renderAuctionHouseWindow(game::GameHandler& gameHandler);
|
||||
|
||||
/**
|
||||
* Inventory screen
|
||||
|
|
@ -254,6 +257,19 @@ private:
|
|||
char mailBodyBuffer_[2048] = "";
|
||||
int mailComposeMoney_[3] = {0, 0, 0}; // gold, silver, copper
|
||||
|
||||
// Auction house UI state
|
||||
char auctionSearchName_[256] = "";
|
||||
int auctionLevelMin_ = 0;
|
||||
int auctionLevelMax_ = 0;
|
||||
int auctionQuality_ = 0;
|
||||
int auctionSellDuration_ = 2; // 0=12h, 1=24h, 2=48h
|
||||
int auctionSellBid_[3] = {0, 0, 0}; // gold, silver, copper
|
||||
int auctionSellBuyout_[3] = {0, 0, 0}; // gold, silver, copper
|
||||
int auctionSelectedItem_ = -1;
|
||||
|
||||
// Guild bank money input
|
||||
int guildBankMoneyInput_[3] = {0, 0, 0}; // gold, silver, copper
|
||||
|
||||
// Left-click targeting: distinguish click from camera drag
|
||||
glm::vec2 leftClickPressPos_ = glm::vec2(0.0f);
|
||||
bool leftClickWasPress_ = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue