2026-02-02 12:24:50 -08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <array>
|
feat: capture and display all item stat types in tooltips
Previously only the 5 primary stats (Str/Agi/Sta/Int/Spi) were stored,
discarding hit rating, crit, haste, attack power, spell power, resilience,
expertise, armor penetration, MP5, and many others.
Changes:
- Add ItemDef::ExtraStat and ItemQueryResponseData::ExtraStat arrays
- All three expansion parsers (WotLK/TBC/Classic) now capture non-primary
stat type/value pairs into extraStats instead of silently dropping them
- All 5 rebuildOnlineInventory paths propagate extraStats to ItemDef
- Tooltip now renders each extra stat on its own line with a name lookup
covering all common WotLK stat types (hit, crit, haste, AP, SP, etc.)
- Also fix Classic/TBC bag-content and bank-bag paths that were missing
bindType, description propagation from previous commits
2026-03-10 17:00:24 -07:00
|
|
|
#include <vector>
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
namespace wowee {
|
|
|
|
|
namespace game {
|
|
|
|
|
|
|
|
|
|
enum class ItemQuality : uint8_t {
|
|
|
|
|
POOR = 0, // Grey
|
|
|
|
|
COMMON = 1, // White
|
|
|
|
|
UNCOMMON = 2, // Green
|
|
|
|
|
RARE = 3, // Blue
|
|
|
|
|
EPIC = 4, // Purple
|
|
|
|
|
LEGENDARY = 5, // Orange
|
2026-03-13 10:22:34 -07:00
|
|
|
ARTIFACT = 6, // Yellow (unused in 3.3.5a but valid quality value)
|
|
|
|
|
HEIRLOOM = 7, // Yellow/gold (WotLK bind-on-account heirlooms)
|
2026-02-02 12:24:50 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class EquipSlot : uint8_t {
|
|
|
|
|
HEAD = 0, NECK, SHOULDERS, SHIRT, CHEST,
|
|
|
|
|
WAIST, LEGS, FEET, WRISTS, HANDS,
|
|
|
|
|
RING1, RING2, TRINKET1, TRINKET2,
|
|
|
|
|
BACK, MAIN_HAND, OFF_HAND, RANGED, TABARD,
|
|
|
|
|
BAG1, BAG2, BAG3, BAG4,
|
|
|
|
|
NUM_SLOTS // = 23
|
|
|
|
|
};
|
|
|
|
|
|
feat(animation): 452 named constants, 30-phase character animation state machine
Add animation_ids.hpp/cpp with all 452 WoW animation ID constants (anim::STAND,
anim::RUN, anim::FIRE_BOW, ... anim::FLY_BACKWARDS, etc.), nameFromId() O(1)
lookup, and flyVariant() compact 218-element ground→FLY_* resolver.
Expand AnimationController into a full state machine with 20+ named states:
spell cast (directed→omni→cast fallback chain, instant one-shot release),
hit reactions (WOUND/CRIT/DODGE/BLOCK/SHIELD_BLOCK), stun, wounded idle,
stealth animation substitution, loot, fishing channel, sit/sleep/kneel
down→loop→up transitions, sheathe/unsheathe combat enter/exit, ranged weapons
(BOW/GUN/CROSSBOW/THROWN with reload states), game object OPEN/CLOSE/DESTROY,
vehicle enter/exit, mount flight directionals (FLY_LEFT/RIGHT/UP/DOWN/BACKWARDS),
emote state variants, off-hand/pierce/dual-wield alternation, NPC
birth/spawn/drown/rise, sprint aura override, totem idle, NPC greeting/farewell.
Add spell_defines.hpp with SpellEffect (~45 constants) and SpellMissInfo
(12 constants) namespaces; replace all magic numbers in spell_handler.cpp.
Add GAMEOBJECT_BYTES_1 to update field table (all 4 expansion JSONs) and wire
GameObjectStateCallback. Add DBC cross-validation on world entry.
Expand tools/_ANIM_NAMES from ~35 to 452 entries in m2_viewer.py and
asset_pipeline_gui.py. Add tests/test_animation_ids.cpp.
Bug fixes included:
- Stand state 1 was animating READY_2H(27) — fixed to SITTING(97)
- Spell casts ended freeze-frame — add one-shot release animation
- NPC 2H swing probe chain missing ATTACK_2H_LOOSE (polearm/staff)
- Chair sits (states 2/4/5/6) incorrectly played floor-sit transition
- STOP(3) used for all spell casts — replaced with model-aware chain
2026-04-04 23:02:53 +03:00
|
|
|
// WoW InventoryType field values (from ItemDisplayInfo / Item.dbc / CMSG_ITEM_QUERY)
|
|
|
|
|
// Used in ItemDef::inventoryType and equipment update packets.
|
|
|
|
|
namespace InvType {
|
|
|
|
|
constexpr uint8_t NON_EQUIP = 0; // Not equippable / unarmed
|
|
|
|
|
constexpr uint8_t HEAD = 1;
|
|
|
|
|
constexpr uint8_t NECK = 2;
|
|
|
|
|
constexpr uint8_t SHOULDERS = 3;
|
|
|
|
|
constexpr uint8_t SHIRT = 4;
|
|
|
|
|
constexpr uint8_t CHEST = 5; // Chest armor
|
|
|
|
|
constexpr uint8_t WAIST = 6;
|
|
|
|
|
constexpr uint8_t LEGS = 7;
|
|
|
|
|
constexpr uint8_t FEET = 8;
|
|
|
|
|
constexpr uint8_t WRISTS = 9;
|
|
|
|
|
constexpr uint8_t HANDS = 10;
|
|
|
|
|
constexpr uint8_t FINGER = 11; // Ring
|
|
|
|
|
constexpr uint8_t TRINKET = 12;
|
|
|
|
|
constexpr uint8_t ONE_HAND = 13; // One-handed weapon (sword, mace, dagger, fist)
|
|
|
|
|
constexpr uint8_t SHIELD = 14;
|
|
|
|
|
constexpr uint8_t RANGED_BOW = 15; // Bow
|
|
|
|
|
constexpr uint8_t BACK = 16; // Cloak
|
|
|
|
|
constexpr uint8_t TWO_HAND = 17; // Two-handed weapon (also polearm/staff by inventoryType alone)
|
|
|
|
|
constexpr uint8_t BAG = 18;
|
|
|
|
|
constexpr uint8_t TABARD = 19;
|
|
|
|
|
constexpr uint8_t ROBE = 20; // Chest (robe variant)
|
|
|
|
|
constexpr uint8_t MAIN_HAND = 21; // Main-hand only weapon
|
|
|
|
|
constexpr uint8_t OFF_HAND = 22; // Off-hand (held-in-off-hand items, not weapons)
|
|
|
|
|
constexpr uint8_t HOLDABLE = 23; // Off-hand holdable (books, orbs)
|
|
|
|
|
constexpr uint8_t AMMO = 24;
|
|
|
|
|
constexpr uint8_t THROWN = 25;
|
|
|
|
|
constexpr uint8_t RANGED_GUN = 26; // Gun / Crossbow / Wand
|
|
|
|
|
} // namespace InvType
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
struct ItemDef {
|
|
|
|
|
uint32_t itemId = 0;
|
|
|
|
|
std::string name;
|
|
|
|
|
std::string subclassName; // "Sword", "Mace", "Shield", etc.
|
|
|
|
|
ItemQuality quality = ItemQuality::COMMON;
|
|
|
|
|
uint8_t inventoryType = 0;
|
|
|
|
|
uint32_t stackCount = 1;
|
|
|
|
|
uint32_t maxStack = 1;
|
|
|
|
|
uint32_t bagSlots = 0;
|
2026-02-18 03:50:47 -08:00
|
|
|
float damageMin = 0.0f;
|
|
|
|
|
float damageMax = 0.0f;
|
|
|
|
|
uint32_t delayMs = 0;
|
2026-02-02 12:24:50 -08:00
|
|
|
// Stats
|
|
|
|
|
int32_t armor = 0;
|
|
|
|
|
int32_t stamina = 0;
|
|
|
|
|
int32_t strength = 0;
|
|
|
|
|
int32_t agility = 0;
|
|
|
|
|
int32_t intellect = 0;
|
|
|
|
|
int32_t spirit = 0;
|
|
|
|
|
uint32_t displayInfoId = 0;
|
2026-02-06 16:04:25 -08:00
|
|
|
uint32_t sellPrice = 0;
|
2026-03-10 16:21:09 -07:00
|
|
|
uint32_t curDurability = 0;
|
|
|
|
|
uint32_t maxDurability = 0;
|
2026-03-10 16:26:20 -07:00
|
|
|
uint32_t itemLevel = 0;
|
|
|
|
|
uint32_t requiredLevel = 0;
|
2026-03-10 16:47:55 -07:00
|
|
|
uint32_t bindType = 0; // 0=none, 1=BoP, 2=BoE, 3=BoU, 4=BoQ
|
|
|
|
|
std::string description; // Flavor/lore text shown in tooltip (italic yellow)
|
feat: capture and display all item stat types in tooltips
Previously only the 5 primary stats (Str/Agi/Sta/Int/Spi) were stored,
discarding hit rating, crit, haste, attack power, spell power, resilience,
expertise, armor penetration, MP5, and many others.
Changes:
- Add ItemDef::ExtraStat and ItemQueryResponseData::ExtraStat arrays
- All three expansion parsers (WotLK/TBC/Classic) now capture non-primary
stat type/value pairs into extraStats instead of silently dropping them
- All 5 rebuildOnlineInventory paths propagate extraStats to ItemDef
- Tooltip now renders each extra stat on its own line with a name lookup
covering all common WotLK stat types (hit, crit, haste, AP, SP, etc.)
- Also fix Classic/TBC bag-content and bank-bag paths that were missing
bindType, description propagation from previous commits
2026-03-10 17:00:24 -07:00
|
|
|
// Generic stat pairs for non-primary stats (hit, crit, haste, AP, SP, etc.)
|
|
|
|
|
struct ExtraStat { uint32_t statType = 0; int32_t statValue = 0; };
|
|
|
|
|
std::vector<ExtraStat> extraStats;
|
2026-03-10 17:05:04 -07:00
|
|
|
uint32_t startQuestId = 0; // Non-zero: item begins a quest
|
2026-02-02 12:24:50 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ItemSlot {
|
|
|
|
|
ItemDef item;
|
|
|
|
|
bool empty() const { return item.itemId == 0; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class Inventory {
|
|
|
|
|
public:
|
|
|
|
|
static constexpr int BACKPACK_SLOTS = 16;
|
2026-03-14 08:42:25 -07:00
|
|
|
static constexpr int KEYRING_SLOTS = 32;
|
2026-03-30 14:01:34 -07:00
|
|
|
// WoW slot layout: 0-22 are equipment (head, neck, ... tabard, mainhand, offhand, ranged, ammo).
|
|
|
|
|
// Backpack inventory starts at slot 23 in bag 0xFF, so packet slot = NUM_EQUIP_SLOTS + backpackIndex.
|
2026-02-02 12:24:50 -08:00
|
|
|
static constexpr int NUM_EQUIP_SLOTS = 23;
|
2026-03-30 14:20:39 -07:00
|
|
|
// Bag containers occupy equipment slots 19-22 (bag1, bag2, bag3, bag4).
|
|
|
|
|
// Packet bag byte = FIRST_BAG_EQUIP_SLOT + bagIndex.
|
|
|
|
|
static constexpr int FIRST_BAG_EQUIP_SLOT = 19;
|
2026-02-02 12:24:50 -08:00
|
|
|
static constexpr int NUM_BAG_SLOTS = 4;
|
|
|
|
|
static constexpr int MAX_BAG_SIZE = 36;
|
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.
2026-02-16 21:11:18 -08:00
|
|
|
static constexpr int BANK_SLOTS = 28;
|
|
|
|
|
static constexpr int BANK_BAG_SLOTS = 7;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
Inventory();
|
|
|
|
|
|
|
|
|
|
// Backpack
|
|
|
|
|
const ItemSlot& getBackpackSlot(int index) const;
|
|
|
|
|
bool setBackpackSlot(int index, const ItemDef& item);
|
|
|
|
|
bool clearBackpackSlot(int index);
|
|
|
|
|
int getBackpackSize() const { return BACKPACK_SLOTS; }
|
|
|
|
|
|
|
|
|
|
// Equipment
|
|
|
|
|
const ItemSlot& getEquipSlot(EquipSlot slot) const;
|
|
|
|
|
bool setEquipSlot(EquipSlot slot, const ItemDef& item);
|
|
|
|
|
bool clearEquipSlot(EquipSlot slot);
|
|
|
|
|
|
2026-03-14 08:42:25 -07:00
|
|
|
// Keyring
|
|
|
|
|
const ItemSlot& getKeyringSlot(int index) const;
|
|
|
|
|
bool setKeyringSlot(int index, const ItemDef& item);
|
|
|
|
|
bool clearKeyringSlot(int index);
|
|
|
|
|
int getKeyringSize() const { return KEYRING_SLOTS; }
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Extra bags
|
|
|
|
|
int getBagSize(int bagIndex) const;
|
2026-02-13 22:14:34 -08:00
|
|
|
void setBagSize(int bagIndex, int size);
|
2026-02-02 12:24:50 -08:00
|
|
|
const ItemSlot& getBagSlot(int bagIndex, int slotIndex) const;
|
|
|
|
|
bool setBagSlot(int bagIndex, int slotIndex, const ItemDef& item);
|
2026-02-17 01:00:04 -08:00
|
|
|
bool clearBagSlot(int bagIndex, int slotIndex);
|
2026-02-02 12:24:50 -08: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.
2026-02-16 21:11:18 -08:00
|
|
|
// 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);
|
2026-02-26 13:38:29 -08:00
|
|
|
bool clearBankBagSlot(int bagIndex, int slotIndex);
|
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.
2026-02-16 21:11:18 -08:00
|
|
|
int getBankBagSize(int bagIndex) const;
|
|
|
|
|
void setBankBagSize(int bagIndex, int size);
|
2026-02-26 13:38:29 -08:00
|
|
|
const ItemSlot& getBankBagItem(int bagIndex) const;
|
|
|
|
|
void setBankBagItem(int bagIndex, const ItemDef& item);
|
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.
2026-02-16 21:11:18 -08:00
|
|
|
|
|
|
|
|
uint8_t getPurchasedBankBagSlots() const { return purchasedBankBagSlots_; }
|
|
|
|
|
void setPurchasedBankBagSlots(uint8_t count) { purchasedBankBagSlots_ = count; }
|
|
|
|
|
|
2026-02-19 22:34:22 -08:00
|
|
|
// Swap two bag slots (equip items + contents)
|
|
|
|
|
void swapBagContents(int bagA, int bagB);
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Utility
|
|
|
|
|
int findFreeBackpackSlot() const;
|
|
|
|
|
bool addItem(const ItemDef& item);
|
|
|
|
|
|
2026-03-17 23:29:50 -07:00
|
|
|
// Sort all bag slots (backpack + equip bags) by quality desc → itemId asc → stackCount desc.
|
|
|
|
|
// Purely client-side: reorders the local inventory struct without server interaction.
|
|
|
|
|
void sortBags();
|
|
|
|
|
|
feat: server-synced bag sort, fix world map continent bounds, update docs
Inventory sort: clicking "Sort Bags" now generates CMSG_SWAP_ITEM packets
to move items server-side (one swap per frame to avoid race conditions).
Client-side sort runs immediately for visual preview; server swaps follow.
New Inventory::computeSortSwaps() computes minimal swap sequence using
selection-sort permutation on quality→itemId→stackCount comparator.
World map: fix continent bounds derivation that used intersection (max/min)
instead of union (min/max) of child zone bounds, causing continent views
to display zoomed-in/clipped.
Update README.md and docs/status.md with current features, release info,
and known gaps (v1.8.2-preview, 664 opcode handlers, NPC voices, bag
independence, CharSections auto-detect, quest GO server limitation).
2026-03-24 09:24:09 -07:00
|
|
|
// A single swap operation using WoW bag/slot addressing (for CMSG_SWAP_ITEM).
|
|
|
|
|
struct SwapOp {
|
|
|
|
|
uint8_t srcBag;
|
|
|
|
|
uint8_t srcSlot;
|
|
|
|
|
uint8_t dstBag;
|
|
|
|
|
uint8_t dstSlot;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Compute the CMSG_SWAP_ITEM operations needed to reach sorted order.
|
|
|
|
|
// Does NOT modify the inventory — caller is responsible for sending packets.
|
|
|
|
|
std::vector<SwapOp> computeSortSwaps() const;
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Test data
|
|
|
|
|
void populateTestItems();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::array<ItemSlot, BACKPACK_SLOTS> backpack{};
|
2026-03-14 08:42:25 -07:00
|
|
|
std::array<ItemSlot, KEYRING_SLOTS> keyring_{};
|
2026-02-02 12:24:50 -08:00
|
|
|
std::array<ItemSlot, NUM_EQUIP_SLOTS> equipment{};
|
|
|
|
|
|
|
|
|
|
struct BagData {
|
|
|
|
|
int size = 0;
|
2026-02-26 13:38:29 -08:00
|
|
|
ItemSlot bagItem; // The bag item itself (for icon/name/tooltip)
|
2026-02-02 12:24:50 -08:00
|
|
|
std::array<ItemSlot, MAX_BAG_SIZE> slots{};
|
|
|
|
|
};
|
|
|
|
|
std::array<BagData, NUM_BAG_SLOTS> bags{};
|
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.
2026-02-16 21:11:18 -08:00
|
|
|
|
|
|
|
|
// Bank
|
|
|
|
|
std::array<ItemSlot, BANK_SLOTS> bankSlots_{};
|
|
|
|
|
std::array<BagData, BANK_BAG_SLOTS> bankBags_{};
|
|
|
|
|
uint8_t purchasedBankBagSlots_ = 0;
|
2026-02-02 12:24:50 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char* getQualityName(ItemQuality quality);
|
|
|
|
|
const char* getEquipSlotName(EquipSlot slot);
|
|
|
|
|
|
|
|
|
|
} // namespace game
|
|
|
|
|
} // namespace wowee
|