2026-02-02 12:24:50 -08:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "game/world_packets.hpp"
|
|
|
|
|
#include "game/character.hpp"
|
2026-02-12 22:56:36 -08:00
|
|
|
#include "game/opcode_table.hpp"
|
|
|
|
|
#include "game/update_field_table.hpp"
|
2026-02-02 12:24:50 -08:00
|
|
|
#include "game/inventory.hpp"
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
#include "game/spell_defines.hpp"
|
|
|
|
|
#include "game/group_defines.hpp"
|
2026-02-08 00:59:40 -08:00
|
|
|
#include <glm/glm.hpp>
|
2026-02-02 12:24:50 -08:00
|
|
|
#include <memory>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
2026-02-04 11:31:08 -08:00
|
|
|
#include <deque>
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
#include <array>
|
2026-02-02 12:24:50 -08:00
|
|
|
#include <functional>
|
|
|
|
|
#include <cstdint>
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
#include <unordered_map>
|
|
|
|
|
#include <unordered_set>
|
2026-02-07 14:21:50 -08:00
|
|
|
#include <map>
|
2026-02-12 00:04:53 -08:00
|
|
|
#include <optional>
|
2026-02-12 00:45:24 -08:00
|
|
|
#include <algorithm>
|
2026-02-20 02:19:17 -08:00
|
|
|
#include <chrono>
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-10 21:29:10 -08:00
|
|
|
namespace wowee::game {
|
|
|
|
|
class TransportManager;
|
2026-02-12 02:09:15 -08:00
|
|
|
class WardenCrypto;
|
2026-02-14 02:00:15 -08:00
|
|
|
class WardenMemory;
|
2026-02-14 19:20:32 -08:00
|
|
|
class WardenModule;
|
2026-02-12 02:43:20 -08:00
|
|
|
class WardenModuleManager;
|
2026-02-12 22:56:36 -08:00
|
|
|
class PacketParsers;
|
2026-02-10 21:29:10 -08:00
|
|
|
}
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
namespace wowee {
|
|
|
|
|
namespace network { class WorldSocket; class Packet; }
|
|
|
|
|
|
|
|
|
|
namespace game {
|
|
|
|
|
|
2026-02-07 14:21:50 -08:00
|
|
|
struct PlayerSkill {
|
|
|
|
|
uint32_t skillId = 0;
|
|
|
|
|
uint16_t value = 0;
|
|
|
|
|
uint16_t maxValue = 0;
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-06 20:10:10 -08:00
|
|
|
/**
|
|
|
|
|
* Quest giver status values (WoW 3.3.5a)
|
|
|
|
|
*/
|
|
|
|
|
enum class QuestGiverStatus : uint8_t {
|
|
|
|
|
NONE = 0,
|
|
|
|
|
UNAVAILABLE = 1,
|
|
|
|
|
INCOMPLETE = 5, // ? (gray)
|
|
|
|
|
REWARD_REP = 6,
|
|
|
|
|
AVAILABLE_LOW = 7, // ! (gray, low-level)
|
|
|
|
|
AVAILABLE = 8, // ! (yellow)
|
|
|
|
|
REWARD = 10 // ? (yellow)
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* World connection state
|
|
|
|
|
*/
|
|
|
|
|
enum class WorldState {
|
|
|
|
|
DISCONNECTED, // Not connected
|
|
|
|
|
CONNECTING, // TCP connection in progress
|
|
|
|
|
CONNECTED, // Connected, waiting for challenge
|
|
|
|
|
CHALLENGE_RECEIVED, // Received SMSG_AUTH_CHALLENGE
|
|
|
|
|
AUTH_SENT, // Sent CMSG_AUTH_SESSION, encryption initialized
|
|
|
|
|
AUTHENTICATED, // Received SMSG_AUTH_RESPONSE success
|
|
|
|
|
READY, // Ready for character/world operations
|
|
|
|
|
CHAR_LIST_REQUESTED, // CMSG_CHAR_ENUM sent
|
|
|
|
|
CHAR_LIST_RECEIVED, // SMSG_CHAR_ENUM received
|
|
|
|
|
ENTERING_WORLD, // CMSG_PLAYER_LOGIN sent
|
|
|
|
|
IN_WORLD, // In game world
|
|
|
|
|
FAILED // Connection or authentication failed
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* World connection callbacks
|
|
|
|
|
*/
|
|
|
|
|
using WorldConnectSuccessCallback = std::function<void()>;
|
|
|
|
|
using WorldConnectFailureCallback = std::function<void(const std::string& reason)>;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* GameHandler - Manages world server connection and game protocol
|
|
|
|
|
*
|
|
|
|
|
* Handles:
|
|
|
|
|
* - Connection to world server
|
|
|
|
|
* - Authentication with session key from auth server
|
|
|
|
|
* - RC4 header encryption
|
|
|
|
|
* - Character enumeration
|
|
|
|
|
* - World entry
|
|
|
|
|
* - Game packets
|
|
|
|
|
*/
|
|
|
|
|
class GameHandler {
|
|
|
|
|
public:
|
Implement complete talent system with dual spec support
Network Protocol:
- Add SMSG_TALENTS_INFO (0x4C0) packet parsing for talent data
- Add CMSG_LEARN_TALENT (0x251) to request learning talents
- Add MSG_TALENT_WIPE_CONFIRM (0x2AB) opcode for spec switching
- Parse talent spec, unspent points, and learned talent ranks
DBC Parsing:
- Load Talent.dbc: talent grid positions, ranks, prerequisites, spell IDs
- Load TalentTab.dbc: talent tree definitions with correct field indices
- Fix localized string field handling (17 fields per string)
- Load Spell.dbc and SpellIcon.dbc for talent icons and tooltips
- Class mask filtering using bitwise operations (1 << (class - 1))
UI Implementation:
- Complete talent tree UI with tabbed interface for specs
- Display talent icons from spell data with proper tinting/borders
- Enhanced tooltips: spell name, rank, current/next descriptions, prereqs
- Visual states: green (maxed), yellow (partial), white (available), gray (locked)
- Tier unlock system (5 points per tier requirement)
- Rank overlay on icons with shadow text
- Click to learn talents with validation
Dual Spec Support:
- Store unspent points and learned talents per spec (0 and 1)
- Track active spec and display its talents
- Spec switching UI with buttons for Spec 1/Spec 2
- Handle both SMSG_TALENTS_INFO packets from server at login
- Display unspent points for both specs in header
- Independent talent trees for each specialization
2026-02-10 02:00:13 -08:00
|
|
|
// Talent data structures (must be public for use in templates)
|
|
|
|
|
struct TalentEntry {
|
|
|
|
|
uint32_t talentId = 0;
|
|
|
|
|
uint32_t tabId = 0; // Which talent tree
|
|
|
|
|
uint8_t row = 0; // Tier (0-10)
|
|
|
|
|
uint8_t column = 0; // Column (0-3)
|
|
|
|
|
uint32_t rankSpells[5] = {}; // Spell IDs for ranks 1-5
|
|
|
|
|
uint32_t prereqTalent[3] = {}; // Required talents
|
|
|
|
|
uint8_t prereqRank[3] = {}; // Required ranks
|
|
|
|
|
uint8_t maxRank = 0; // Number of ranks (1-5)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct TalentTabEntry {
|
|
|
|
|
uint32_t tabId = 0;
|
|
|
|
|
std::string name;
|
|
|
|
|
uint32_t classMask = 0; // Which classes can use this tab
|
|
|
|
|
uint8_t orderIndex = 0; // Display order (0-2)
|
|
|
|
|
std::string backgroundFile; // Texture path
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
GameHandler();
|
|
|
|
|
~GameHandler();
|
|
|
|
|
|
2026-02-12 22:56:36 -08:00
|
|
|
/** Access the active opcode table (wire ↔ logical mapping). */
|
|
|
|
|
const OpcodeTable& getOpcodeTable() const { return opcodeTable_; }
|
|
|
|
|
OpcodeTable& getOpcodeTable() { return opcodeTable_; }
|
|
|
|
|
const UpdateFieldTable& getUpdateFieldTable() const { return updateFieldTable_; }
|
|
|
|
|
UpdateFieldTable& getUpdateFieldTable() { return updateFieldTable_; }
|
|
|
|
|
PacketParsers* getPacketParsers() { return packetParsers_.get(); }
|
|
|
|
|
void setPacketParsers(std::unique_ptr<PacketParsers> parsers);
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Connect to world server
|
|
|
|
|
*
|
|
|
|
|
* @param host World server hostname/IP
|
|
|
|
|
* @param port World server port (default 8085)
|
|
|
|
|
* @param sessionKey 40-byte session key from auth server
|
|
|
|
|
* @param accountName Account name (will be uppercased)
|
|
|
|
|
* @param build Client build number (default 12340 for 3.3.5a)
|
|
|
|
|
* @return true if connection initiated
|
|
|
|
|
*/
|
|
|
|
|
bool connect(const std::string& host,
|
|
|
|
|
uint16_t port,
|
|
|
|
|
const std::vector<uint8_t>& sessionKey,
|
|
|
|
|
const std::string& accountName,
|
2026-02-13 01:51:49 -08:00
|
|
|
uint32_t build = 12340,
|
|
|
|
|
uint32_t realmId = 0);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Disconnect from world server
|
|
|
|
|
*/
|
|
|
|
|
void disconnect();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if connected to world server
|
|
|
|
|
*/
|
|
|
|
|
bool isConnected() const;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get current connection state
|
|
|
|
|
*/
|
|
|
|
|
WorldState getState() const { return state; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Request character list from server
|
|
|
|
|
* Must be called when state is READY or AUTHENTICATED
|
|
|
|
|
*/
|
|
|
|
|
void requestCharacterList();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get list of characters (available after CHAR_LIST_RECEIVED state)
|
|
|
|
|
*/
|
|
|
|
|
const std::vector<Character>& getCharacters() const { return characters; }
|
|
|
|
|
|
2026-02-05 14:13:48 -08:00
|
|
|
void createCharacter(const CharCreateData& data);
|
2026-02-06 03:24:46 -08:00
|
|
|
void deleteCharacter(uint64_t characterGuid);
|
2026-02-05 14:13:48 -08:00
|
|
|
|
|
|
|
|
using CharCreateCallback = std::function<void(bool success, const std::string& message)>;
|
|
|
|
|
void setCharCreateCallback(CharCreateCallback cb) { charCreateCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-06 03:24:46 -08:00
|
|
|
using CharDeleteCallback = std::function<void(bool success)>;
|
|
|
|
|
void setCharDeleteCallback(CharDeleteCallback cb) { charDeleteCallback_ = std::move(cb); }
|
2026-02-06 18:34:45 -08:00
|
|
|
uint8_t getLastCharDeleteResult() const { return lastCharDeleteResult_; }
|
2026-02-06 03:24:46 -08:00
|
|
|
|
2026-02-17 13:59:29 -08:00
|
|
|
using CharLoginFailCallback = std::function<void(const std::string& reason)>;
|
|
|
|
|
void setCharLoginFailCallback(CharLoginFailCallback cb) { charLoginFailCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Select and log in with a character
|
|
|
|
|
* @param characterGuid GUID of character to log in with
|
|
|
|
|
*/
|
|
|
|
|
void selectCharacter(uint64_t characterGuid);
|
2026-02-05 14:35:12 -08:00
|
|
|
void setActiveCharacterGuid(uint64_t guid) { activeCharacterGuid_ = guid; }
|
|
|
|
|
uint64_t getActiveCharacterGuid() const { return activeCharacterGuid_; }
|
|
|
|
|
const Character* getActiveCharacter() const;
|
|
|
|
|
const Character* getFirstCharacter() const;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get current player movement info
|
|
|
|
|
*/
|
|
|
|
|
const MovementInfo& getMovementInfo() const { return movementInfo; }
|
2026-02-08 03:24:12 -08:00
|
|
|
uint32_t getCurrentMapId() const { return currentMapId_; }
|
2026-02-08 03:39:02 -08:00
|
|
|
bool getHomeBind(uint32_t& mapId, glm::vec3& pos) const {
|
|
|
|
|
if (!hasHomeBind_) return false;
|
|
|
|
|
mapId = homeBindMapId_;
|
|
|
|
|
pos = homeBindPos_;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Send a movement packet
|
2026-02-20 02:50:59 -08:00
|
|
|
* @param opcode Movement opcode (MSG_MOVE_START_FORWARD, etc.)
|
2026-02-02 12:24:50 -08:00
|
|
|
*/
|
|
|
|
|
void sendMovement(Opcode opcode);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update player position
|
|
|
|
|
* @param x X coordinate
|
|
|
|
|
* @param y Y coordinate
|
|
|
|
|
* @param z Z coordinate
|
|
|
|
|
*/
|
|
|
|
|
void setPosition(float x, float y, float z);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update player orientation
|
|
|
|
|
* @param orientation Facing direction in radians
|
|
|
|
|
*/
|
|
|
|
|
void setOrientation(float orientation);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get entity manager (for accessing entities in view)
|
|
|
|
|
*/
|
|
|
|
|
EntityManager& getEntityManager() { return entityManager; }
|
|
|
|
|
const EntityManager& getEntityManager() const { return entityManager; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Send a chat message
|
|
|
|
|
* @param type Chat type (SAY, YELL, WHISPER, etc.)
|
|
|
|
|
* @param message Message text
|
|
|
|
|
* @param target Target name (for whispers, empty otherwise)
|
|
|
|
|
*/
|
|
|
|
|
void sendChatMessage(ChatType type, const std::string& message, const std::string& target = "");
|
2026-02-14 14:30:09 -08:00
|
|
|
void sendTextEmote(uint32_t textEmoteId, uint64_t targetGuid = 0);
|
|
|
|
|
void joinChannel(const std::string& channelName, const std::string& password = "");
|
|
|
|
|
void leaveChannel(const std::string& channelName);
|
|
|
|
|
const std::vector<std::string>& getJoinedChannels() const { return joinedChannels_; }
|
|
|
|
|
std::string getChannelByIndex(int index) const;
|
2026-02-14 18:27:59 -08:00
|
|
|
int getChannelIndex(const std::string& channelName) const;
|
|
|
|
|
|
|
|
|
|
// Chat auto-join settings (set by UI before autoJoinDefaultChannels)
|
|
|
|
|
struct ChatAutoJoin {
|
|
|
|
|
bool general = true;
|
|
|
|
|
bool trade = true;
|
|
|
|
|
bool localDefense = true;
|
|
|
|
|
bool lfg = true;
|
2026-02-16 21:16:25 -08:00
|
|
|
bool local = true;
|
2026-02-14 18:27:59 -08:00
|
|
|
};
|
|
|
|
|
ChatAutoJoin chatAutoJoin;
|
2026-02-14 14:30:09 -08:00
|
|
|
|
|
|
|
|
// Chat bubble callback: (senderGuid, message, isYell)
|
|
|
|
|
using ChatBubbleCallback = std::function<void(uint64_t, const std::string&, bool)>;
|
|
|
|
|
void setChatBubbleCallback(ChatBubbleCallback cb) { chatBubbleCallback_ = std::move(cb); }
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-14 15:11:43 -08:00
|
|
|
// Emote animation callback: (entityGuid, animationId)
|
|
|
|
|
using EmoteAnimCallback = std::function<void(uint64_t, uint32_t)>;
|
|
|
|
|
void setEmoteAnimCallback(EmoteAnimCallback cb) { emoteAnimCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Get chat history (recent messages)
|
|
|
|
|
* @param maxMessages Maximum number of messages to return (0 = all)
|
|
|
|
|
* @return Vector of chat messages
|
|
|
|
|
*/
|
2026-02-04 11:31:08 -08:00
|
|
|
const std::deque<MessageChatData>& getChatHistory() const { return chatHistory; }
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a locally-generated chat message (e.g., emote feedback)
|
|
|
|
|
*/
|
|
|
|
|
void addLocalChatMessage(const MessageChatData& msg);
|
|
|
|
|
|
2026-02-05 14:01:26 -08:00
|
|
|
// Money (copper)
|
|
|
|
|
uint64_t getMoneyCopper() const { return playerMoneyCopper_; }
|
|
|
|
|
|
2026-02-19 17:45:09 -08:00
|
|
|
// Server-authoritative armor (UNIT_FIELD_RESISTANCES[0])
|
|
|
|
|
int32_t getArmorRating() const { return playerArmorRating_; }
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Inventory
|
|
|
|
|
Inventory& getInventory() { return inventory; }
|
|
|
|
|
const Inventory& getInventory() const { return inventory; }
|
2026-02-06 03:13:42 -08:00
|
|
|
bool consumeOnlineEquipmentDirty() { bool d = onlineEquipDirty_; onlineEquipDirty_ = false; return d; }
|
2026-03-04 19:47:01 -08:00
|
|
|
void resetEquipmentDirtyTracking() { lastEquipDisplayIds_ = {}; onlineEquipDirty_ = true; }
|
2026-02-12 14:55:27 -08:00
|
|
|
void unequipToBackpack(EquipSlot equipSlot);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
// Targeting
|
|
|
|
|
void setTarget(uint64_t guid);
|
|
|
|
|
void clearTarget();
|
|
|
|
|
uint64_t getTargetGuid() const { return targetGuid; }
|
|
|
|
|
std::shared_ptr<Entity> getTarget() const;
|
|
|
|
|
bool hasTarget() const { return targetGuid != 0; }
|
|
|
|
|
void tabTarget(float playerX, float playerY, float playerZ);
|
|
|
|
|
|
2026-02-07 13:44:36 -08:00
|
|
|
// Focus targeting
|
|
|
|
|
void setFocus(uint64_t guid);
|
|
|
|
|
void clearFocus();
|
|
|
|
|
uint64_t getFocusGuid() const { return focusGuid; }
|
|
|
|
|
std::shared_ptr<Entity> getFocus() const;
|
|
|
|
|
bool hasFocus() const { return focusGuid != 0; }
|
|
|
|
|
|
|
|
|
|
// Advanced targeting
|
|
|
|
|
void targetLastTarget();
|
|
|
|
|
void targetEnemy(bool reverse = false);
|
|
|
|
|
void targetFriend(bool reverse = false);
|
|
|
|
|
|
2026-02-07 12:37:13 -08:00
|
|
|
// Inspection
|
|
|
|
|
void inspectTarget();
|
|
|
|
|
|
2026-02-07 12:43:32 -08:00
|
|
|
// Server info commands
|
|
|
|
|
void queryServerTime();
|
|
|
|
|
void requestPlayedTime();
|
|
|
|
|
void queryWho(const std::string& playerName = "");
|
|
|
|
|
|
Add /roll and friend management commands
Roll Command:
- Add /roll, /random, /rnd commands for random number generation
- Support multiple formats: /roll, /roll 100, /roll 1-100, /roll 10 50
- Broadcasts rolls to party/raid with "[Name] rolls X (min-max)" format
- Cap max roll at 10,000 to prevent abuse
- Use MSG_RANDOM_ROLL (0x1FB) bidirectional opcode
Friend Commands:
- Add /friend add <name>, /addfriend <name> to add friends
- Add /friend remove <name>, /removefriend <name> to remove friends
- Support aliases: /delfriend, /remfriend
- Maintain local friends cache mapping names to GUIDs for lookups
- Display status messages for all friend actions:
- Friend added/removed confirmations
- Friend online/offline notifications
- Error messages (not found, already friends, list full, ignoring)
Social Opcodes:
- Add CMSG_ADD_FRIEND (0x69) and SMSG_FRIEND_STATUS (0x68)
- Add CMSG_DEL_FRIEND (0x6A) for friend removal
- Add CMSG_SET_CONTACT_NOTES (0x6B) for friend notes (future use)
- Add CMSG_ADD_IGNORE (0x6C) and CMSG_DEL_IGNORE (0x6D) (future use)
Implementation:
- Add RandomRollPacket builder and RandomRollParser for roll data
- Add AddFriendPacket and DelFriendPacket builders
- Add FriendStatusParser to handle server friend status updates
- Add friendsCache map to store friend name-to-GUID mappings
- Add handleRandomRoll() and handleFriendStatus() packet handlers
- Comprehensive slash command parsing with multiple formats and aliases
2026-02-07 12:51:30 -08:00
|
|
|
// Social commands
|
|
|
|
|
void addFriend(const std::string& playerName, const std::string& note = "");
|
|
|
|
|
void removeFriend(const std::string& playerName);
|
|
|
|
|
void setFriendNote(const std::string& playerName, const std::string& note);
|
2026-02-07 12:58:11 -08:00
|
|
|
void addIgnore(const std::string& playerName);
|
|
|
|
|
void removeIgnore(const std::string& playerName);
|
Add /roll and friend management commands
Roll Command:
- Add /roll, /random, /rnd commands for random number generation
- Support multiple formats: /roll, /roll 100, /roll 1-100, /roll 10 50
- Broadcasts rolls to party/raid with "[Name] rolls X (min-max)" format
- Cap max roll at 10,000 to prevent abuse
- Use MSG_RANDOM_ROLL (0x1FB) bidirectional opcode
Friend Commands:
- Add /friend add <name>, /addfriend <name> to add friends
- Add /friend remove <name>, /removefriend <name> to remove friends
- Support aliases: /delfriend, /remfriend
- Maintain local friends cache mapping names to GUIDs for lookups
- Display status messages for all friend actions:
- Friend added/removed confirmations
- Friend online/offline notifications
- Error messages (not found, already friends, list full, ignoring)
Social Opcodes:
- Add CMSG_ADD_FRIEND (0x69) and SMSG_FRIEND_STATUS (0x68)
- Add CMSG_DEL_FRIEND (0x6A) for friend removal
- Add CMSG_SET_CONTACT_NOTES (0x6B) for friend notes (future use)
- Add CMSG_ADD_IGNORE (0x6C) and CMSG_DEL_IGNORE (0x6D) (future use)
Implementation:
- Add RandomRollPacket builder and RandomRollParser for roll data
- Add AddFriendPacket and DelFriendPacket builders
- Add FriendStatusParser to handle server friend status updates
- Add friendsCache map to store friend name-to-GUID mappings
- Add handleRandomRoll() and handleFriendStatus() packet handlers
- Comprehensive slash command parsing with multiple formats and aliases
2026-02-07 12:51:30 -08:00
|
|
|
|
|
|
|
|
// Random roll
|
|
|
|
|
void randomRoll(uint32_t minRoll = 1, uint32_t maxRoll = 100);
|
|
|
|
|
|
2026-02-26 17:56:11 -08:00
|
|
|
// Battleground
|
|
|
|
|
bool hasPendingBgInvite() const;
|
|
|
|
|
void acceptBattlefield(uint32_t queueSlot = 0xFFFFFFFF);
|
|
|
|
|
|
2026-02-07 12:58:11 -08:00
|
|
|
// Logout commands
|
|
|
|
|
void requestLogout();
|
|
|
|
|
void cancelLogout();
|
|
|
|
|
|
|
|
|
|
// Stand state
|
|
|
|
|
void setStandState(uint8_t state); // 0=stand, 1=sit, 2=sit_chair, 3=sleep, 4=sit_low_chair, 5=sit_medium_chair, 6=sit_high_chair, 7=dead, 8=kneel, 9=submerged
|
Implement SMSG_STANDSTATE_UPDATE and SMSG_ITEM_PUSH_RESULT handlers
SMSG_STANDSTATE_UPDATE:
- Parse uint8 stand state from server confirmation packet
- Store in standState_ member (0=stand, 7=dead, 8=kneel, etc.)
- Expose getStandState(), isSitting(), isDead(), isKneeling() accessors
SMSG_ITEM_PUSH_RESULT:
- Parse full WotLK 3.3.5a payload: guid, received, created, showInChat,
bagSlot, itemSlot, itemId, suffixFactor, randomPropertyId, count, totalCount
- Show "Received: <name> x<count>" chat notification when showInChat=1
- Queue item info lookup via queryItemInfo so name resolves asap
2026-03-09 12:58:52 -07:00
|
|
|
uint8_t getStandState() const { return standState_; }
|
|
|
|
|
bool isSitting() const { return standState_ >= 1 && standState_ <= 6; }
|
|
|
|
|
bool isDead() const { return standState_ == 7; }
|
|
|
|
|
bool isKneeling() const { return standState_ == 8; }
|
2026-02-07 12:58:11 -08:00
|
|
|
|
2026-02-07 13:03:21 -08:00
|
|
|
// Display toggles
|
|
|
|
|
void toggleHelm();
|
|
|
|
|
void toggleCloak();
|
|
|
|
|
|
|
|
|
|
// Follow/Assist
|
|
|
|
|
void followTarget();
|
|
|
|
|
void assistTarget();
|
|
|
|
|
|
Add Tier 3 commands: guild management, PvP, ready check, and duel forfeit
- Guild commands: /ginfo, /groster, /gmotd, /gpromote, /gdemote, /gquit, /ginvite
- PvP toggle: /pvp to toggle PvP flag
- Ready check system: /readycheck, /ready, /notready for group coordination
- Duel forfeit: /yield, /forfeit, /surrender to cancel active duels
2026-02-07 13:09:12 -08:00
|
|
|
// PvP
|
|
|
|
|
void togglePvp();
|
|
|
|
|
|
|
|
|
|
// Guild commands
|
|
|
|
|
void requestGuildInfo();
|
|
|
|
|
void requestGuildRoster();
|
|
|
|
|
void setGuildMotd(const std::string& motd);
|
|
|
|
|
void promoteGuildMember(const std::string& playerName);
|
|
|
|
|
void demoteGuildMember(const std::string& playerName);
|
|
|
|
|
void leaveGuild();
|
|
|
|
|
void inviteToGuild(const std::string& playerName);
|
2026-02-13 21:39:48 -08:00
|
|
|
void kickGuildMember(const std::string& playerName);
|
2026-02-16 20:16:14 -08:00
|
|
|
void disbandGuild();
|
|
|
|
|
void setGuildLeader(const std::string& name);
|
|
|
|
|
void setGuildPublicNote(const std::string& name, const std::string& note);
|
|
|
|
|
void setGuildOfficerNote(const std::string& name, const std::string& note);
|
2026-02-13 21:39:48 -08:00
|
|
|
void acceptGuildInvite();
|
|
|
|
|
void declineGuildInvite();
|
|
|
|
|
void queryGuildInfo(uint32_t guildId);
|
2026-02-25 14:44:44 -08:00
|
|
|
void createGuild(const std::string& guildName);
|
|
|
|
|
void addGuildRank(const std::string& rankName);
|
|
|
|
|
void deleteGuildRank();
|
|
|
|
|
void requestPetitionShowlist(uint64_t npcGuid);
|
|
|
|
|
void buyPetition(uint64_t npcGuid, const std::string& guildName);
|
2026-02-13 21:39:48 -08:00
|
|
|
|
|
|
|
|
// Guild state accessors
|
2026-02-14 15:05:18 -08:00
|
|
|
bool isInGuild() const {
|
|
|
|
|
if (!guildName_.empty()) return true;
|
|
|
|
|
const Character* ch = getActiveCharacter();
|
|
|
|
|
return ch && ch->hasGuild();
|
|
|
|
|
}
|
2026-02-13 21:39:48 -08:00
|
|
|
const std::string& getGuildName() const { return guildName_; }
|
|
|
|
|
const GuildRosterData& getGuildRoster() const { return guildRoster_; }
|
|
|
|
|
bool hasGuildRoster() const { return hasGuildRoster_; }
|
2026-02-16 20:16:14 -08:00
|
|
|
const std::vector<std::string>& getGuildRankNames() const { return guildRankNames_; }
|
2026-02-13 21:39:48 -08:00
|
|
|
bool hasPendingGuildInvite() const { return pendingGuildInvite_; }
|
|
|
|
|
const std::string& getPendingGuildInviterName() const { return pendingGuildInviterName_; }
|
|
|
|
|
const std::string& getPendingGuildInviteGuildName() const { return pendingGuildInviteGuildName_; }
|
2026-02-25 14:44:44 -08:00
|
|
|
const GuildInfoData& getGuildInfoData() const { return guildInfoData_; }
|
|
|
|
|
const GuildQueryResponseData& getGuildQueryData() const { return guildQueryData_; }
|
|
|
|
|
bool hasGuildInfoData() const { return guildInfoData_.isValid(); }
|
|
|
|
|
bool hasPetitionShowlist() const { return showPetitionDialog_; }
|
|
|
|
|
void clearPetitionDialog() { showPetitionDialog_ = false; }
|
|
|
|
|
uint32_t getPetitionCost() const { return petitionCost_; }
|
|
|
|
|
uint64_t getPetitionNpcGuid() const { return petitionNpcGuid_; }
|
Add Tier 3 commands: guild management, PvP, ready check, and duel forfeit
- Guild commands: /ginfo, /groster, /gmotd, /gpromote, /gdemote, /gquit, /ginvite
- PvP toggle: /pvp to toggle PvP flag
- Ready check system: /readycheck, /ready, /notready for group coordination
- Duel forfeit: /yield, /forfeit, /surrender to cancel active duels
2026-02-07 13:09:12 -08:00
|
|
|
|
|
|
|
|
// Ready check
|
|
|
|
|
void initiateReadyCheck();
|
|
|
|
|
void respondToReadyCheck(bool ready);
|
|
|
|
|
|
|
|
|
|
// Duel
|
|
|
|
|
void forfeitDuel();
|
|
|
|
|
|
2026-02-07 13:17:01 -08:00
|
|
|
// AFK/DND status
|
|
|
|
|
void toggleAfk(const std::string& message = "");
|
|
|
|
|
void toggleDnd(const std::string& message = "");
|
|
|
|
|
void replyToLastWhisper(const std::string& message);
|
|
|
|
|
std::string getLastWhisperSender() const { return lastWhisperSender_; }
|
|
|
|
|
void setLastWhisperSender(const std::string& name) { lastWhisperSender_ = name; }
|
|
|
|
|
|
2026-02-07 13:28:46 -08:00
|
|
|
// Party/Raid management
|
|
|
|
|
void uninvitePlayer(const std::string& playerName);
|
|
|
|
|
void leaveParty();
|
|
|
|
|
void setMainTank(uint64_t targetGuid);
|
|
|
|
|
void setMainAssist(uint64_t targetGuid);
|
|
|
|
|
void clearMainTank();
|
|
|
|
|
void clearMainAssist();
|
|
|
|
|
void requestRaidInfo();
|
|
|
|
|
|
2026-02-07 13:36:50 -08:00
|
|
|
// Combat and Trade
|
|
|
|
|
void proposeDuel(uint64_t targetGuid);
|
|
|
|
|
void initiateTrade(uint64_t targetGuid);
|
|
|
|
|
void stopCasting();
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 1: Name queries ----
|
|
|
|
|
void queryPlayerName(uint64_t guid);
|
|
|
|
|
void queryCreatureInfo(uint32_t entry, uint64_t guid);
|
2026-02-08 00:59:40 -08:00
|
|
|
void queryGameObjectInfo(uint32_t entry, uint64_t guid);
|
2026-02-14 20:20:43 -08:00
|
|
|
const GameObjectQueryResponseData* getCachedGameObjectInfo(uint32_t entry) const {
|
|
|
|
|
auto it = gameObjectInfoCache_.find(entry);
|
|
|
|
|
return (it != gameObjectInfoCache_.end()) ? &it->second : nullptr;
|
|
|
|
|
}
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
std::string getCachedPlayerName(uint64_t guid) const;
|
|
|
|
|
std::string getCachedCreatureName(uint32_t entry) const;
|
|
|
|
|
|
|
|
|
|
// ---- Phase 2: Combat ----
|
|
|
|
|
void startAutoAttack(uint64_t targetGuid);
|
|
|
|
|
void stopAutoAttack();
|
|
|
|
|
bool isAutoAttacking() const { return autoAttacking; }
|
2026-02-20 03:38:12 -08:00
|
|
|
bool hasAutoAttackIntent() const { return autoAttackRequested_; }
|
|
|
|
|
bool isInCombat() const { return autoAttacking || !hostileAttackers_.empty(); }
|
|
|
|
|
bool isInCombatWith(uint64_t guid) const {
|
|
|
|
|
return guid != 0 &&
|
|
|
|
|
((autoAttacking && autoAttackTarget == guid) ||
|
|
|
|
|
(hostileAttackers_.count(guid) > 0));
|
|
|
|
|
}
|
|
|
|
|
uint64_t getAutoAttackTargetGuid() const { return autoAttackTarget; }
|
2026-02-06 18:34:45 -08:00
|
|
|
bool isAggressiveTowardPlayer(uint64_t guid) const { return hostileAttackers_.count(guid) > 0; }
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
const std::vector<CombatTextEntry>& getCombatText() const { return combatText; }
|
|
|
|
|
void updateCombatText(float deltaTime);
|
|
|
|
|
|
|
|
|
|
// ---- Phase 3: Spells ----
|
|
|
|
|
void castSpell(uint32_t spellId, uint64_t targetGuid = 0);
|
|
|
|
|
void cancelCast();
|
|
|
|
|
void cancelAura(uint32_t spellId);
|
2026-02-26 10:41:29 -08:00
|
|
|
void dismissPet();
|
|
|
|
|
bool hasPet() const { return petGuid_ != 0; }
|
|
|
|
|
uint64_t getPetGuid() const { return petGuid_; }
|
2026-02-17 15:13:54 -08:00
|
|
|
const std::unordered_set<uint32_t>& getKnownSpells() const { return knownSpells; }
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
bool isCasting() const { return casting; }
|
2026-02-19 03:31:49 -08:00
|
|
|
bool isGameObjectInteractionCasting() const {
|
|
|
|
|
return casting && currentCastSpellId == 0 && pendingGameObjectInteractGuid_ != 0;
|
|
|
|
|
}
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
uint32_t getCurrentCastSpellId() const { return currentCastSpellId; }
|
|
|
|
|
float getCastProgress() const { return castTimeTotal > 0 ? (castTimeTotal - castTimeRemaining) / castTimeTotal : 0.0f; }
|
|
|
|
|
float getCastTimeRemaining() const { return castTimeRemaining; }
|
|
|
|
|
|
Implement complete talent system with dual spec support
Network Protocol:
- Add SMSG_TALENTS_INFO (0x4C0) packet parsing for talent data
- Add CMSG_LEARN_TALENT (0x251) to request learning talents
- Add MSG_TALENT_WIPE_CONFIRM (0x2AB) opcode for spec switching
- Parse talent spec, unspent points, and learned talent ranks
DBC Parsing:
- Load Talent.dbc: talent grid positions, ranks, prerequisites, spell IDs
- Load TalentTab.dbc: talent tree definitions with correct field indices
- Fix localized string field handling (17 fields per string)
- Load Spell.dbc and SpellIcon.dbc for talent icons and tooltips
- Class mask filtering using bitwise operations (1 << (class - 1))
UI Implementation:
- Complete talent tree UI with tabbed interface for specs
- Display talent icons from spell data with proper tinting/borders
- Enhanced tooltips: spell name, rank, current/next descriptions, prereqs
- Visual states: green (maxed), yellow (partial), white (available), gray (locked)
- Tier unlock system (5 points per tier requirement)
- Rank overlay on icons with shadow text
- Click to learn talents with validation
Dual Spec Support:
- Store unspent points and learned talents per spec (0 and 1)
- Track active spec and display its talents
- Spec switching UI with buttons for Spec 1/Spec 2
- Handle both SMSG_TALENTS_INFO packets from server at login
- Display unspent points for both specs in header
- Independent talent trees for each specialization
2026-02-10 02:00:13 -08:00
|
|
|
// Talents
|
|
|
|
|
uint8_t getActiveTalentSpec() const { return activeTalentSpec_; }
|
|
|
|
|
uint8_t getUnspentTalentPoints() const { return unspentTalentPoints_[activeTalentSpec_]; }
|
|
|
|
|
uint8_t getUnspentTalentPoints(uint8_t spec) const { return spec < 2 ? unspentTalentPoints_[spec] : 0; }
|
|
|
|
|
const std::unordered_map<uint32_t, uint8_t>& getLearnedTalents() const { return learnedTalents_[activeTalentSpec_]; }
|
|
|
|
|
const std::unordered_map<uint32_t, uint8_t>& getLearnedTalents(uint8_t spec) const {
|
|
|
|
|
static std::unordered_map<uint32_t, uint8_t> empty;
|
|
|
|
|
return spec < 2 ? learnedTalents_[spec] : empty;
|
|
|
|
|
}
|
|
|
|
|
uint8_t getTalentRank(uint32_t talentId) const {
|
|
|
|
|
auto it = learnedTalents_[activeTalentSpec_].find(talentId);
|
|
|
|
|
return (it != learnedTalents_[activeTalentSpec_].end()) ? it->second : 0;
|
|
|
|
|
}
|
|
|
|
|
void learnTalent(uint32_t talentId, uint32_t requestedRank);
|
|
|
|
|
void switchTalentSpec(uint8_t newSpec);
|
|
|
|
|
|
|
|
|
|
// Talent DBC access
|
|
|
|
|
const TalentEntry* getTalentEntry(uint32_t talentId) const {
|
|
|
|
|
auto it = talentCache_.find(talentId);
|
|
|
|
|
return (it != talentCache_.end()) ? &it->second : nullptr;
|
|
|
|
|
}
|
|
|
|
|
const TalentTabEntry* getTalentTabEntry(uint32_t tabId) const {
|
|
|
|
|
auto it = talentTabCache_.find(tabId);
|
|
|
|
|
return (it != talentTabCache_.end()) ? &it->second : nullptr;
|
|
|
|
|
}
|
|
|
|
|
const std::unordered_map<uint32_t, TalentEntry>& getAllTalents() const { return talentCache_; }
|
|
|
|
|
const std::unordered_map<uint32_t, TalentTabEntry>& getAllTalentTabs() const { return talentTabCache_; }
|
|
|
|
|
void loadTalentDbc();
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// Action bar
|
|
|
|
|
static constexpr int ACTION_BAR_SLOTS = 12;
|
|
|
|
|
std::array<ActionBarSlot, ACTION_BAR_SLOTS>& getActionBar() { return actionBar; }
|
|
|
|
|
const std::array<ActionBarSlot, ACTION_BAR_SLOTS>& getActionBar() const { return actionBar; }
|
|
|
|
|
void setActionBarSlot(int slot, ActionBarSlot::Type type, uint32_t id);
|
|
|
|
|
|
Fix vendor buying, improve character select, parallelize WMO culling, and optimize collision
- Fix CMSG_BUY_ITEM count field from uint8 to uint32 (server silently dropped undersized packets)
- Character select screen: remember last selected character, two-column layout with details panel, double-click to enter world, responsive window sizing
- Fix stale character data between logins by replacing static init flag with per-character GUID tracking
- Parallelize WMO visibility culling across worker threads (same pattern as M2 renderer)
- Optimize WMO collision queries with world-space group bounds early rejection in getFloorHeight, checkWallCollision, isInsideWMO, and raycastBoundingBoxes
- Reduce camera ground samples from 5 to 3 movement-aligned probes
- Add WMO interior lighting, unlit materials, vertex color multiply, and alpha blending support
2026-02-07 15:29:19 -08:00
|
|
|
void saveCharacterConfig();
|
|
|
|
|
void loadCharacterConfig();
|
|
|
|
|
static std::string getCharacterConfigDir();
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// Auras
|
|
|
|
|
const std::vector<AuraSlot>& getPlayerAuras() const { return playerAuras; }
|
|
|
|
|
const std::vector<AuraSlot>& getTargetAuras() const { return targetAuras; }
|
|
|
|
|
|
2026-02-07 00:00:06 -08:00
|
|
|
// NPC death callback (for animations)
|
|
|
|
|
using NpcDeathCallback = std::function<void(uint64_t guid)>;
|
|
|
|
|
void setNpcDeathCallback(NpcDeathCallback cb) { npcDeathCallback_ = std::move(cb); }
|
|
|
|
|
|
Add comprehensive NPC voice system with interaction and combat sounds
Implements full NPC voice interaction system supporting 6 different sound categories
for all playable races/genders. System loads ~450+ voice clips from MPQ archives.
Voice Categories:
- Greeting: Play on NPC right-click interaction
- Farewell: Play when closing gossip/dialog windows
- Vendor: Play when opening merchant/vendor windows
- Pissed: Play after clicking NPC 5+ times (spam protection)
- Aggro: Play when NPC enters combat with player
- Flee: Play when NPC is fleeing (ready for low-health triggers)
Features:
- Race/gender detection from NPC display IDs via CreatureDisplayInfoExtra.dbc
- Intelligent click tracking for pissed sounds
- Combat sounds use player character vocal files for humanoid NPCs
- Cooldown system prevents voice spam (2s default, combat sounds bypass)
- Generic fallback voices for unsupported NPC types
- 3D positional audio support
Voice Support:
- All playable races: Human, Dwarf, Gnome, Night Elf, Orc, Tauren, Troll, Undead
- Male and female variants for each race
- StandardNPC sounds for social interactions
- Character vocal sounds for combat
Technical Changes:
- Refactored NpcVoiceManager to support multiple sound categories
- Added callbacks: NpcFarewell, NpcVendor, NpcAggro
- Extended voice loading to parse both StandardNPC and Character vocal paths
- Integrated with GameHandler for gossip, vendor, and combat events
- Added detailed voice detection logging for debugging
Also includes:
- Sound manifest files added to docs/ for reference
- Blacksmith hammer pitch increased to 1.6x (was 1.4x)
- Blacksmith volume reduced 30% to 0.25 (was 0.35)
2026-02-09 16:03:51 -08:00
|
|
|
using NpcAggroCallback = std::function<void(uint64_t guid, const glm::vec3& position)>;
|
|
|
|
|
void setNpcAggroCallback(NpcAggroCallback cb) { npcAggroCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-07 00:00:06 -08:00
|
|
|
// NPC respawn callback (health 0 → >0, resets animation to idle)
|
|
|
|
|
using NpcRespawnCallback = std::function<void(uint64_t guid)>;
|
|
|
|
|
void setNpcRespawnCallback(NpcRespawnCallback cb) { npcRespawnCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-05 14:01:26 -08:00
|
|
|
// Melee swing callback (for driving animation/SFX)
|
|
|
|
|
using MeleeSwingCallback = std::function<void()>;
|
|
|
|
|
void setMeleeSwingCallback(MeleeSwingCallback cb) { meleeSwingCallback_ = std::move(cb); }
|
2026-02-05 12:01:03 -08:00
|
|
|
|
2026-02-07 00:00:06 -08:00
|
|
|
// NPC swing callback (plays attack animation on NPC)
|
|
|
|
|
using NpcSwingCallback = std::function<void(uint64_t guid)>;
|
|
|
|
|
void setNpcSwingCallback(NpcSwingCallback cb) { npcSwingCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-09 01:29:44 -08:00
|
|
|
// NPC greeting callback (plays voice line when NPC is clicked)
|
|
|
|
|
using NpcGreetingCallback = std::function<void(uint64_t guid, const glm::vec3& position)>;
|
|
|
|
|
void setNpcGreetingCallback(NpcGreetingCallback cb) { npcGreetingCallback_ = std::move(cb); }
|
|
|
|
|
|
Add comprehensive NPC voice system with interaction and combat sounds
Implements full NPC voice interaction system supporting 6 different sound categories
for all playable races/genders. System loads ~450+ voice clips from MPQ archives.
Voice Categories:
- Greeting: Play on NPC right-click interaction
- Farewell: Play when closing gossip/dialog windows
- Vendor: Play when opening merchant/vendor windows
- Pissed: Play after clicking NPC 5+ times (spam protection)
- Aggro: Play when NPC enters combat with player
- Flee: Play when NPC is fleeing (ready for low-health triggers)
Features:
- Race/gender detection from NPC display IDs via CreatureDisplayInfoExtra.dbc
- Intelligent click tracking for pissed sounds
- Combat sounds use player character vocal files for humanoid NPCs
- Cooldown system prevents voice spam (2s default, combat sounds bypass)
- Generic fallback voices for unsupported NPC types
- 3D positional audio support
Voice Support:
- All playable races: Human, Dwarf, Gnome, Night Elf, Orc, Tauren, Troll, Undead
- Male and female variants for each race
- StandardNPC sounds for social interactions
- Character vocal sounds for combat
Technical Changes:
- Refactored NpcVoiceManager to support multiple sound categories
- Added callbacks: NpcFarewell, NpcVendor, NpcAggro
- Extended voice loading to parse both StandardNPC and Character vocal paths
- Integrated with GameHandler for gossip, vendor, and combat events
- Added detailed voice detection logging for debugging
Also includes:
- Sound manifest files added to docs/ for reference
- Blacksmith hammer pitch increased to 1.6x (was 1.4x)
- Blacksmith volume reduced 30% to 0.25 (was 0.35)
2026-02-09 16:03:51 -08:00
|
|
|
using NpcFarewellCallback = std::function<void(uint64_t guid, const glm::vec3& position)>;
|
|
|
|
|
void setNpcFarewellCallback(NpcFarewellCallback cb) { npcFarewellCallback_ = std::move(cb); }
|
|
|
|
|
|
|
|
|
|
using NpcVendorCallback = std::function<void(uint64_t guid, const glm::vec3& position)>;
|
|
|
|
|
void setNpcVendorCallback(NpcVendorCallback cb) { npcVendorCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-07 00:00:06 -08:00
|
|
|
// XP tracking
|
2026-02-05 12:07:58 -08:00
|
|
|
uint32_t getPlayerXp() const { return playerXp_; }
|
|
|
|
|
uint32_t getPlayerNextLevelXp() const { return playerNextLevelXp_; }
|
2026-02-06 23:52:16 -08:00
|
|
|
uint32_t getPlayerLevel() const { return serverPlayerLevel_; }
|
2026-02-11 18:25:04 -08:00
|
|
|
const std::vector<uint32_t>& getPlayerExploredZoneMasks() const { return playerExploredZones_; }
|
|
|
|
|
bool hasPlayerExploredZoneMasks() const { return hasPlayerExploredZones_; }
|
2026-02-06 16:53:09 -08:00
|
|
|
static uint32_t killXp(uint32_t playerLevel, uint32_t victimLevel);
|
2026-02-05 12:07:58 -08:00
|
|
|
|
2026-02-10 19:30:45 -08:00
|
|
|
// Server time (for deterministic moon phases, etc.)
|
|
|
|
|
float getGameTime() const { return gameTime_; }
|
|
|
|
|
float getTimeSpeed() const { return timeSpeed_; }
|
|
|
|
|
|
2026-02-17 17:59:41 -08:00
|
|
|
// Weather state (updated by SMSG_WEATHER)
|
|
|
|
|
// weatherType: 0=clear, 1=rain, 2=snow, 3=storm/fog
|
|
|
|
|
uint32_t getWeatherType() const { return weatherType_; }
|
|
|
|
|
float getWeatherIntensity() const { return weatherIntensity_; }
|
|
|
|
|
bool isRaining() const { return weatherType_ == 1 && weatherIntensity_ > 0.05f; }
|
|
|
|
|
bool isSnowing() const { return weatherType_ == 2 && weatherIntensity_ > 0.05f; }
|
|
|
|
|
|
2026-02-07 14:21:50 -08:00
|
|
|
// Player skills
|
|
|
|
|
const std::map<uint32_t, PlayerSkill>& getPlayerSkills() const { return playerSkills_; }
|
|
|
|
|
const std::string& getSkillName(uint32_t skillId) const;
|
|
|
|
|
uint32_t getSkillCategory(uint32_t skillId) const;
|
|
|
|
|
|
2026-02-05 21:28:21 -08:00
|
|
|
// World entry callback (online mode - triggered when entering world)
|
|
|
|
|
// Parameters: mapId, x, y, z (canonical WoW coordinates)
|
|
|
|
|
using WorldEntryCallback = std::function<void(uint32_t mapId, float x, float y, float z)>;
|
|
|
|
|
void setWorldEntryCallback(WorldEntryCallback cb) { worldEntryCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-07 16:59:20 -08:00
|
|
|
// Unstuck callback (resets player Z to floor height)
|
|
|
|
|
using UnstuckCallback = std::function<void()>;
|
|
|
|
|
void setUnstuckCallback(UnstuckCallback cb) { unstuckCallback_ = std::move(cb); }
|
|
|
|
|
void unstuck();
|
2026-02-08 03:24:12 -08:00
|
|
|
void setUnstuckGyCallback(UnstuckCallback cb) { unstuckGyCallback_ = std::move(cb); }
|
|
|
|
|
void unstuckGy();
|
2026-03-07 22:03:28 -08:00
|
|
|
void setUnstuckHearthCallback(UnstuckCallback cb) { unstuckHearthCallback_ = std::move(cb); }
|
|
|
|
|
void unstuckHearth();
|
2026-02-08 03:32:00 -08:00
|
|
|
using BindPointCallback = std::function<void(uint32_t mapId, float x, float y, float z)>;
|
|
|
|
|
void setBindPointCallback(BindPointCallback cb) { bindPointCallback_ = std::move(cb); }
|
2026-02-07 16:59:20 -08:00
|
|
|
|
2026-02-05 21:55:52 -08:00
|
|
|
// Creature spawn callback (online mode - triggered when creature enters view)
|
|
|
|
|
// Parameters: guid, displayId, x, y, z (canonical), orientation
|
|
|
|
|
using CreatureSpawnCallback = std::function<void(uint64_t guid, uint32_t displayId, float x, float y, float z, float orientation)>;
|
|
|
|
|
void setCreatureSpawnCallback(CreatureSpawnCallback cb) { creatureSpawnCallback_ = std::move(cb); }
|
|
|
|
|
|
|
|
|
|
// Creature despawn callback (online mode - triggered when creature leaves view)
|
|
|
|
|
using CreatureDespawnCallback = std::function<void(uint64_t guid)>;
|
|
|
|
|
void setCreatureDespawnCallback(CreatureDespawnCallback cb) { creatureDespawnCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-13 19:40:54 -08:00
|
|
|
// Player spawn callback (online mode - triggered when a player enters view).
|
|
|
|
|
// Players need appearance data so the renderer can build the right body/hair textures.
|
|
|
|
|
using PlayerSpawnCallback = std::function<void(uint64_t guid,
|
|
|
|
|
uint32_t displayId,
|
|
|
|
|
uint8_t raceId,
|
|
|
|
|
uint8_t genderId,
|
|
|
|
|
uint32_t appearanceBytes,
|
|
|
|
|
uint8_t facialFeatures,
|
|
|
|
|
float x, float y, float z, float orientation)>;
|
|
|
|
|
void setPlayerSpawnCallback(PlayerSpawnCallback cb) { playerSpawnCallback_ = std::move(cb); }
|
|
|
|
|
|
|
|
|
|
using PlayerDespawnCallback = std::function<void(uint64_t guid)>;
|
|
|
|
|
void setPlayerDespawnCallback(PlayerDespawnCallback cb) { playerDespawnCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-13 20:10:19 -08:00
|
|
|
// Online player equipment visuals callback.
|
|
|
|
|
// Sends a best-effort view of equipped items for players in view using ItemDisplayInfo IDs.
|
|
|
|
|
// Arrays are indexed by EquipSlot (0..18). Values are 0 when unknown/unavailable.
|
|
|
|
|
using PlayerEquipmentCallback = std::function<void(uint64_t guid,
|
|
|
|
|
const std::array<uint32_t, 19>& displayInfoIds,
|
|
|
|
|
const std::array<uint8_t, 19>& inventoryTypes)>;
|
|
|
|
|
void setPlayerEquipmentCallback(PlayerEquipmentCallback cb) { playerEquipmentCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-07 19:44:03 -08:00
|
|
|
// GameObject spawn callback (online mode - triggered when gameobject enters view)
|
2026-02-11 00:54:38 -08:00
|
|
|
// Parameters: guid, entry, displayId, x, y, z (canonical), orientation
|
|
|
|
|
using GameObjectSpawnCallback = std::function<void(uint64_t guid, uint32_t entry, uint32_t displayId, float x, float y, float z, float orientation)>;
|
2026-02-07 19:44:03 -08:00
|
|
|
void setGameObjectSpawnCallback(GameObjectSpawnCallback cb) { gameObjectSpawnCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-12 00:04:53 -08:00
|
|
|
// GameObject move callback (online mode - triggered when gameobject position updates)
|
|
|
|
|
// Parameters: guid, x, y, z (canonical), orientation
|
|
|
|
|
using GameObjectMoveCallback = std::function<void(uint64_t guid, float x, float y, float z, float orientation)>;
|
|
|
|
|
void setGameObjectMoveCallback(GameObjectMoveCallback cb) { gameObjectMoveCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-07 19:44:03 -08:00
|
|
|
// GameObject despawn callback (online mode - triggered when gameobject leaves view)
|
|
|
|
|
using GameObjectDespawnCallback = std::function<void(uint64_t guid)>;
|
|
|
|
|
void setGameObjectDespawnCallback(GameObjectDespawnCallback cb) { gameObjectDespawnCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-23 05:39:02 -08:00
|
|
|
using GameObjectCustomAnimCallback = std::function<void(uint64_t guid, uint32_t animId)>;
|
|
|
|
|
void setGameObjectCustomAnimCallback(GameObjectCustomAnimCallback cb) { gameObjectCustomAnimCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-06 14:24:38 -08:00
|
|
|
// Faction hostility map (populated from FactionTemplate.dbc by Application)
|
|
|
|
|
void setFactionHostileMap(std::unordered_map<uint32_t, bool> map) { factionHostileMap_ = std::move(map); }
|
|
|
|
|
|
2026-02-06 13:47:03 -08:00
|
|
|
// Creature move callback (online mode - triggered by SMSG_MONSTER_MOVE)
|
|
|
|
|
// Parameters: guid, x, y, z (canonical), duration_ms (0 = instant)
|
|
|
|
|
using CreatureMoveCallback = std::function<void(uint64_t guid, float x, float y, float z, uint32_t durationMs)>;
|
|
|
|
|
void setCreatureMoveCallback(CreatureMoveCallback cb) { creatureMoveCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-08 00:59:40 -08:00
|
|
|
// Transport move callback (online mode - triggered when transport position updates)
|
|
|
|
|
// Parameters: guid, x, y, z (canonical), orientation
|
|
|
|
|
using TransportMoveCallback = std::function<void(uint64_t guid, float x, float y, float z, float orientation)>;
|
|
|
|
|
void setTransportMoveCallback(TransportMoveCallback cb) { transportMoveCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-11 00:54:38 -08:00
|
|
|
// Transport spawn callback (online mode - triggered when transport GameObject is first detected)
|
|
|
|
|
// Parameters: guid, entry, displayId, x, y, z (canonical), orientation
|
|
|
|
|
using TransportSpawnCallback = std::function<void(uint64_t guid, uint32_t entry, uint32_t displayId, float x, float y, float z, float orientation)>;
|
|
|
|
|
void setTransportSpawnCallback(TransportSpawnCallback cb) { transportSpawnCallback_ = std::move(cb); }
|
|
|
|
|
|
|
|
|
|
// Notify that a transport has been spawned (called after WMO instance creation)
|
|
|
|
|
void notifyTransportSpawned(uint64_t guid, uint32_t entry, uint32_t displayId, float x, float y, float z, float orientation) {
|
|
|
|
|
if (transportSpawnCallback_) {
|
|
|
|
|
transportSpawnCallback_(guid, entry, displayId, x, y, z, orientation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-08 00:59:40 -08:00
|
|
|
// Transport state for player-on-transport
|
|
|
|
|
bool isOnTransport() const { return playerTransportGuid_ != 0; }
|
|
|
|
|
uint64_t getPlayerTransportGuid() const { return playerTransportGuid_; }
|
|
|
|
|
glm::vec3 getPlayerTransportOffset() const { return playerTransportOffset_; }
|
2026-02-11 00:54:38 -08:00
|
|
|
|
|
|
|
|
// Check if a GUID is a known transport
|
|
|
|
|
bool isTransportGuid(uint64_t guid) const { return transportGuids_.count(guid) > 0; }
|
2026-02-12 00:04:53 -08:00
|
|
|
bool hasServerTransportUpdate(uint64_t guid) const { return serverUpdatedTransportGuids_.count(guid) > 0; }
|
2026-02-10 21:29:10 -08:00
|
|
|
glm::vec3 getComposedWorldPosition(); // Compose transport transform * local offset
|
|
|
|
|
TransportManager* getTransportManager() { return transportManager_.get(); }
|
|
|
|
|
void setPlayerOnTransport(uint64_t transportGuid, const glm::vec3& localOffset) {
|
|
|
|
|
playerTransportGuid_ = transportGuid;
|
|
|
|
|
playerTransportOffset_ = localOffset;
|
2026-02-12 00:45:24 -08:00
|
|
|
playerTransportStickyGuid_ = transportGuid;
|
|
|
|
|
playerTransportStickyTimer_ = 8.0f;
|
|
|
|
|
movementInfo.transportGuid = transportGuid;
|
2026-02-10 21:29:10 -08:00
|
|
|
}
|
2026-03-06 23:01:11 -08:00
|
|
|
void setPlayerTransportOffset(const glm::vec3& offset) {
|
|
|
|
|
playerTransportOffset_ = offset;
|
|
|
|
|
}
|
2026-02-10 21:29:10 -08:00
|
|
|
void clearPlayerTransport() {
|
2026-02-12 00:45:24 -08:00
|
|
|
if (playerTransportGuid_ != 0) {
|
|
|
|
|
playerTransportStickyGuid_ = playerTransportGuid_;
|
|
|
|
|
playerTransportStickyTimer_ = std::max(playerTransportStickyTimer_, 1.5f);
|
|
|
|
|
}
|
2026-02-10 21:29:10 -08:00
|
|
|
playerTransportGuid_ = 0;
|
|
|
|
|
playerTransportOffset_ = glm::vec3(0.0f);
|
2026-02-12 00:45:24 -08:00
|
|
|
movementInfo.transportGuid = 0;
|
2026-02-10 21:29:10 -08:00
|
|
|
}
|
2026-02-08 00:59:40 -08:00
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// Cooldowns
|
|
|
|
|
float getSpellCooldown(uint32_t spellId) const;
|
|
|
|
|
|
|
|
|
|
// Player GUID
|
|
|
|
|
uint64_t getPlayerGuid() const { return playerGuid; }
|
Implement complete talent system with dual spec support
Network Protocol:
- Add SMSG_TALENTS_INFO (0x4C0) packet parsing for talent data
- Add CMSG_LEARN_TALENT (0x251) to request learning talents
- Add MSG_TALENT_WIPE_CONFIRM (0x2AB) opcode for spec switching
- Parse talent spec, unspent points, and learned talent ranks
DBC Parsing:
- Load Talent.dbc: talent grid positions, ranks, prerequisites, spell IDs
- Load TalentTab.dbc: talent tree definitions with correct field indices
- Fix localized string field handling (17 fields per string)
- Load Spell.dbc and SpellIcon.dbc for talent icons and tooltips
- Class mask filtering using bitwise operations (1 << (class - 1))
UI Implementation:
- Complete talent tree UI with tabbed interface for specs
- Display talent icons from spell data with proper tinting/borders
- Enhanced tooltips: spell name, rank, current/next descriptions, prereqs
- Visual states: green (maxed), yellow (partial), white (available), gray (locked)
- Tier unlock system (5 points per tier requirement)
- Rank overlay on icons with shadow text
- Click to learn talents with validation
Dual Spec Support:
- Store unspent points and learned talents per spec (0 and 1)
- Track active spec and display its talents
- Spec switching UI with buttons for Spec 1/Spec 2
- Handle both SMSG_TALENTS_INFO packets from server at login
- Display unspent points for both specs in header
- Independent talent trees for each specialization
2026-02-10 02:00:13 -08:00
|
|
|
uint8_t getPlayerClass() const {
|
|
|
|
|
const Character* ch = getActiveCharacter();
|
|
|
|
|
return ch ? static_cast<uint8_t>(ch->characterClass) : 0;
|
|
|
|
|
}
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
void setPlayerGuid(uint64_t guid) { playerGuid = guid; }
|
|
|
|
|
|
2026-02-06 17:27:20 -08:00
|
|
|
// Player death state
|
|
|
|
|
bool isPlayerDead() const { return playerDead_; }
|
2026-02-07 23:12:24 -08:00
|
|
|
bool isPlayerGhost() const { return releasedSpirit_; }
|
|
|
|
|
bool showDeathDialog() const { return playerDead_ && !releasedSpirit_; }
|
|
|
|
|
bool showResurrectDialog() const { return resurrectRequestPending_; }
|
2026-02-06 17:27:20 -08:00
|
|
|
void releaseSpirit();
|
2026-02-07 23:12:24 -08:00
|
|
|
void acceptResurrect();
|
|
|
|
|
void declineResurrect();
|
2026-02-06 17:27:20 -08:00
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 4: Group ----
|
|
|
|
|
void inviteToGroup(const std::string& playerName);
|
|
|
|
|
void acceptGroupInvite();
|
|
|
|
|
void declineGroupInvite();
|
|
|
|
|
void leaveGroup();
|
|
|
|
|
bool isInGroup() const { return !partyData.isEmpty(); }
|
|
|
|
|
const GroupListData& getPartyData() const { return partyData; }
|
|
|
|
|
bool hasPendingGroupInvite() const { return pendingGroupInvite; }
|
|
|
|
|
const std::string& getPendingInviterName() const { return pendingInviterName; }
|
|
|
|
|
|
2026-03-09 13:36:23 -07:00
|
|
|
// ---- Instance lockouts ----
|
|
|
|
|
struct InstanceLockout {
|
|
|
|
|
uint32_t mapId = 0;
|
|
|
|
|
uint32_t difficulty = 0; // 0=normal,1=heroic/10man,2=25man,3=25man heroic
|
|
|
|
|
uint64_t resetTime = 0; // Unix timestamp of instance reset
|
|
|
|
|
bool locked = false;
|
|
|
|
|
bool extended = false;
|
|
|
|
|
};
|
|
|
|
|
const std::vector<InstanceLockout>& getInstanceLockouts() const { return instanceLockouts_; }
|
|
|
|
|
|
2026-03-09 13:30:23 -07:00
|
|
|
// ---- LFG / Dungeon Finder ----
|
|
|
|
|
enum class LfgState : uint8_t {
|
|
|
|
|
None = 0,
|
|
|
|
|
RoleCheck = 1,
|
|
|
|
|
Queued = 2,
|
|
|
|
|
Proposal = 3,
|
|
|
|
|
Boot = 4,
|
|
|
|
|
InDungeon = 5,
|
|
|
|
|
FinishedDungeon= 6,
|
|
|
|
|
RaidBrowser = 7,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// roles bitmask: 0x02=tank, 0x04=healer, 0x08=dps; pass LFGDungeonEntry ID
|
|
|
|
|
void lfgJoin(uint32_t dungeonId, uint8_t roles);
|
|
|
|
|
void lfgLeave();
|
|
|
|
|
void lfgAcceptProposal(uint32_t proposalId, bool accept);
|
|
|
|
|
void lfgTeleport(bool toLfgDungeon = true);
|
|
|
|
|
LfgState getLfgState() const { return lfgState_; }
|
|
|
|
|
bool isLfgQueued() const { return lfgState_ == LfgState::Queued; }
|
|
|
|
|
bool isLfgInDungeon() const { return lfgState_ == LfgState::InDungeon; }
|
2026-03-09 13:47:07 -07:00
|
|
|
uint32_t getLfgDungeonId() const { return lfgDungeonId_; }
|
|
|
|
|
uint32_t getLfgProposalId() const { return lfgProposalId_; }
|
|
|
|
|
int32_t getLfgAvgWaitSec() const { return lfgAvgWaitSec_; }
|
|
|
|
|
uint32_t getLfgTimeInQueueMs() const { return lfgTimeInQueueMs_; }
|
2026-03-09 13:30:23 -07:00
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 5: Loot ----
|
|
|
|
|
void lootTarget(uint64_t guid);
|
|
|
|
|
void lootItem(uint8_t slotIndex);
|
|
|
|
|
void closeLoot();
|
2026-02-06 18:34:45 -08:00
|
|
|
void activateSpiritHealer(uint64_t npcGuid);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
bool isLootWindowOpen() const { return lootWindowOpen; }
|
|
|
|
|
const LootResponseData& getCurrentLoot() const { return currentLoot; }
|
2026-02-17 16:31:00 -08:00
|
|
|
void setAutoLoot(bool enabled) { autoLoot_ = enabled; }
|
|
|
|
|
bool isAutoLoot() const { return autoLoot_; }
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
|
|
|
|
// NPC Gossip
|
|
|
|
|
void interactWithNpc(uint64_t guid);
|
2026-02-07 19:44:03 -08:00
|
|
|
void interactWithGameObject(uint64_t guid);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
void selectGossipOption(uint32_t optionId);
|
2026-02-06 11:45:35 -08:00
|
|
|
void selectGossipQuest(uint32_t questId);
|
2026-02-06 11:59:51 -08:00
|
|
|
void acceptQuest();
|
|
|
|
|
void declineQuest();
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
void closeGossip();
|
|
|
|
|
bool isGossipWindowOpen() const { return gossipWindowOpen; }
|
|
|
|
|
const GossipMessageData& getCurrentGossip() const { return currentGossip; }
|
2026-02-06 11:59:51 -08:00
|
|
|
bool isQuestDetailsOpen() const { return questDetailsOpen; }
|
|
|
|
|
const QuestDetailsData& getQuestDetails() const { return currentQuestDetails; }
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
2026-02-06 21:50:15 -08:00
|
|
|
// Quest turn-in
|
|
|
|
|
bool isQuestRequestItemsOpen() const { return questRequestItemsOpen_; }
|
|
|
|
|
const QuestRequestItemsData& getQuestRequestItems() const { return currentQuestRequestItems_; }
|
|
|
|
|
void completeQuest(); // Send CMSG_QUESTGIVER_COMPLETE_QUEST
|
|
|
|
|
void closeQuestRequestItems();
|
|
|
|
|
|
|
|
|
|
bool isQuestOfferRewardOpen() const { return questOfferRewardOpen_; }
|
|
|
|
|
const QuestOfferRewardData& getQuestOfferReward() const { return currentQuestOfferReward_; }
|
|
|
|
|
void chooseQuestReward(uint32_t rewardIndex); // Send CMSG_QUESTGIVER_CHOOSE_REWARD
|
|
|
|
|
void closeQuestOfferReward();
|
|
|
|
|
|
2026-02-06 13:47:03 -08:00
|
|
|
// Quest log
|
|
|
|
|
struct QuestLogEntry {
|
|
|
|
|
uint32_t questId = 0;
|
|
|
|
|
std::string title;
|
|
|
|
|
std::string objectives;
|
|
|
|
|
bool complete = false;
|
2026-02-10 01:24:37 -08:00
|
|
|
// Objective kill counts: objectiveIndex -> (current, required)
|
|
|
|
|
std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> killCounts;
|
2026-02-18 04:06:14 -08:00
|
|
|
// Quest item progress: itemId -> current count
|
|
|
|
|
std::unordered_map<uint32_t, uint32_t> itemCounts;
|
2026-02-19 00:56:24 -08:00
|
|
|
// Server-authoritative quest item requirements from REQUEST_ITEMS
|
|
|
|
|
std::unordered_map<uint32_t, uint32_t> requiredItemCounts;
|
2026-02-06 13:47:03 -08:00
|
|
|
};
|
|
|
|
|
const std::vector<QuestLogEntry>& getQuestLog() const { return questLog_; }
|
|
|
|
|
void abandonQuest(uint32_t questId);
|
2026-02-19 00:30:21 -08:00
|
|
|
bool requestQuestQuery(uint32_t questId, bool force = false);
|
2026-02-19 00:56:24 -08:00
|
|
|
bool isQuestQueryPending(uint32_t questId) const {
|
|
|
|
|
return pendingQuestQueryIds_.count(questId) > 0;
|
|
|
|
|
}
|
|
|
|
|
void clearQuestQueryPending(uint32_t questId) { pendingQuestQueryIds_.erase(questId); }
|
2026-02-18 23:30:38 -08:00
|
|
|
const std::unordered_map<uint32_t, uint32_t>& getWorldStates() const { return worldStates_; }
|
|
|
|
|
std::optional<uint32_t> getWorldState(uint32_t key) const {
|
|
|
|
|
auto it = worldStates_.find(key);
|
|
|
|
|
if (it == worldStates_.end()) return std::nullopt;
|
|
|
|
|
return it->second;
|
|
|
|
|
}
|
|
|
|
|
uint32_t getWorldStateMapId() const { return worldStateMapId_; }
|
|
|
|
|
uint32_t getWorldStateZoneId() const { return worldStateZoneId_; }
|
|
|
|
|
|
|
|
|
|
struct FactionStandingInit {
|
|
|
|
|
uint8_t flags = 0;
|
|
|
|
|
int32_t standing = 0;
|
|
|
|
|
};
|
|
|
|
|
const std::vector<FactionStandingInit>& getInitialFactions() const { return initialFactions_; }
|
|
|
|
|
uint32_t getLastContactListMask() const { return lastContactListMask_; }
|
|
|
|
|
uint32_t getLastContactListCount() const { return lastContactListCount_; }
|
|
|
|
|
bool isServerMovementAllowed() const { return serverMovementAllowed_; }
|
2026-02-06 13:47:03 -08:00
|
|
|
|
2026-02-06 20:10:10 -08:00
|
|
|
// Quest giver status (! and ? markers)
|
|
|
|
|
QuestGiverStatus getQuestGiverStatus(uint64_t guid) const {
|
|
|
|
|
auto it = npcQuestStatus_.find(guid);
|
|
|
|
|
return (it != npcQuestStatus_.end()) ? it->second : QuestGiverStatus::NONE;
|
|
|
|
|
}
|
|
|
|
|
const std::unordered_map<uint64_t, QuestGiverStatus>& getNpcQuestStatuses() const { return npcQuestStatus_; }
|
|
|
|
|
|
2026-02-19 21:13:13 -08:00
|
|
|
// Charge callback — fires when player casts a charge spell toward target
|
|
|
|
|
// Parameters: targetGuid, targetX, targetY, targetZ (canonical WoW coordinates)
|
|
|
|
|
using ChargeCallback = std::function<void(uint64_t targetGuid, float x, float y, float z)>;
|
|
|
|
|
void setChargeCallback(ChargeCallback cb) { chargeCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-17 17:23:42 -08:00
|
|
|
// Level-up callback — fires when the player gains a level (newLevel > 1)
|
|
|
|
|
using LevelUpCallback = std::function<void(uint32_t newLevel)>;
|
|
|
|
|
void setLevelUpCallback(LevelUpCallback cb) { levelUpCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-19 20:36:25 -08:00
|
|
|
// Other player level-up callback — fires when another player gains a level
|
|
|
|
|
using OtherPlayerLevelUpCallback = std::function<void(uint64_t guid, uint32_t newLevel)>;
|
|
|
|
|
void setOtherPlayerLevelUpCallback(OtherPlayerLevelUpCallback cb) { otherPlayerLevelUpCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-03-09 13:53:42 -07:00
|
|
|
// Achievement earned callback — fires when SMSG_ACHIEVEMENT_EARNED is received
|
|
|
|
|
using AchievementEarnedCallback = std::function<void(uint32_t achievementId)>;
|
|
|
|
|
void setAchievementEarnedCallback(AchievementEarnedCallback cb) { achievementEarnedCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-07 17:59:40 -08:00
|
|
|
// Mount state
|
|
|
|
|
using MountCallback = std::function<void(uint32_t mountDisplayId)>; // 0 = dismount
|
|
|
|
|
void setMountCallback(MountCallback cb) { mountCallback_ = std::move(cb); }
|
2026-02-08 21:32:38 -08:00
|
|
|
|
|
|
|
|
// Taxi terrain precaching callback
|
|
|
|
|
using TaxiPrecacheCallback = std::function<void(const std::vector<glm::vec3>&)>;
|
|
|
|
|
void setTaxiPrecacheCallback(TaxiPrecacheCallback cb) { taxiPrecacheCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-08 22:05:38 -08:00
|
|
|
// Taxi orientation callback (for mount rotation: yaw, pitch, roll in radians)
|
|
|
|
|
using TaxiOrientationCallback = std::function<void(float yaw, float pitch, float roll)>;
|
2026-02-08 22:00:33 -08:00
|
|
|
void setTaxiOrientationCallback(TaxiOrientationCallback cb) { taxiOrientationCallback_ = std::move(cb); }
|
|
|
|
|
|
|
|
|
|
// Callback for when taxi flight is about to start (after mounting delay, before movement begins)
|
|
|
|
|
using TaxiFlightStartCallback = std::function<void()>;
|
|
|
|
|
void setTaxiFlightStartCallback(TaxiFlightStartCallback cb) { taxiFlightStartCallback_ = std::move(cb); }
|
|
|
|
|
|
2026-02-07 17:59:40 -08:00
|
|
|
bool isMounted() const { return currentMountDisplayId_ != 0; }
|
2026-02-07 21:00:05 -08:00
|
|
|
bool isHostileAttacker(uint64_t guid) const { return hostileAttackers_.count(guid) > 0; }
|
2026-02-07 17:59:40 -08:00
|
|
|
float getServerRunSpeed() const { return serverRunSpeed_; }
|
|
|
|
|
void dismount();
|
|
|
|
|
|
2026-02-07 16:59:20 -08:00
|
|
|
// Taxi / Flight Paths
|
|
|
|
|
bool isTaxiWindowOpen() const { return taxiWindowOpen_; }
|
|
|
|
|
void closeTaxi();
|
|
|
|
|
void activateTaxi(uint32_t destNodeId);
|
|
|
|
|
bool isOnTaxiFlight() const { return onTaxiFlight_; }
|
2026-02-11 19:28:15 -08:00
|
|
|
bool isTaxiMountActive() const { return taxiMountActive_; }
|
2026-02-11 21:14:35 -08:00
|
|
|
bool isTaxiActivationPending() const { return taxiActivatePending_; }
|
|
|
|
|
void forceClearTaxiAndMovementState();
|
2026-02-07 16:59:20 -08:00
|
|
|
const ShowTaxiNodesData& getTaxiData() const { return currentTaxiData_; }
|
|
|
|
|
uint32_t getTaxiCurrentNode() const { return currentTaxiData_.nearestNode; }
|
|
|
|
|
|
|
|
|
|
struct TaxiNode {
|
|
|
|
|
uint32_t id = 0;
|
|
|
|
|
uint32_t mapId = 0;
|
|
|
|
|
float x = 0, y = 0, z = 0;
|
|
|
|
|
std::string name;
|
2026-02-08 03:05:38 -08:00
|
|
|
uint32_t mountDisplayIdAlliance = 0;
|
|
|
|
|
uint32_t mountDisplayIdHorde = 0;
|
2026-02-07 16:59:20 -08:00
|
|
|
};
|
|
|
|
|
struct TaxiPathEdge {
|
|
|
|
|
uint32_t pathId = 0;
|
|
|
|
|
uint32_t fromNode = 0, toNode = 0;
|
|
|
|
|
uint32_t cost = 0;
|
|
|
|
|
};
|
2026-02-08 21:32:38 -08:00
|
|
|
struct TaxiPathNode {
|
|
|
|
|
uint32_t id = 0;
|
|
|
|
|
uint32_t pathId = 0;
|
|
|
|
|
uint32_t nodeIndex = 0;
|
|
|
|
|
uint32_t mapId = 0;
|
|
|
|
|
float x = 0, y = 0, z = 0;
|
|
|
|
|
};
|
2026-02-07 16:59:20 -08:00
|
|
|
const std::unordered_map<uint32_t, TaxiNode>& getTaxiNodes() const { return taxiNodes_; }
|
2026-02-07 19:04:15 -08:00
|
|
|
uint32_t getTaxiCostTo(uint32_t destNodeId) const;
|
2026-02-07 16:59:20 -08:00
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// Vendor
|
|
|
|
|
void openVendor(uint64_t npcGuid);
|
2026-02-06 11:59:51 -08:00
|
|
|
void closeVendor();
|
Fix vendor buying, improve character select, parallelize WMO culling, and optimize collision
- Fix CMSG_BUY_ITEM count field from uint8 to uint32 (server silently dropped undersized packets)
- Character select screen: remember last selected character, two-column layout with details panel, double-click to enter world, responsive window sizing
- Fix stale character data between logins by replacing static init flag with per-character GUID tracking
- Parallelize WMO visibility culling across worker threads (same pattern as M2 renderer)
- Optimize WMO collision queries with world-space group bounds early rejection in getFloorHeight, checkWallCollision, isInsideWMO, and raycastBoundingBoxes
- Reduce camera ground samples from 5 to 3 movement-aligned probes
- Add WMO interior lighting, unlit materials, vertex color multiply, and alpha blending support
2026-02-07 15:29:19 -08:00
|
|
|
void buyItem(uint64_t vendorGuid, uint32_t itemId, uint32_t slot, uint32_t count);
|
2026-02-06 19:50:22 -08:00
|
|
|
void sellItem(uint64_t vendorGuid, uint64_t itemGuid, uint32_t count);
|
2026-02-06 13:47:03 -08:00
|
|
|
void sellItemBySlot(int backpackIndex);
|
2026-02-17 01:00:04 -08:00
|
|
|
void sellItemInBag(int bagIndex, int slotIndex);
|
2026-02-19 05:28:13 -08:00
|
|
|
struct BuybackItem {
|
|
|
|
|
uint64_t itemGuid = 0;
|
|
|
|
|
ItemDef item;
|
|
|
|
|
uint32_t count = 1;
|
|
|
|
|
};
|
|
|
|
|
void buyBackItem(uint32_t buybackSlot);
|
|
|
|
|
const std::deque<BuybackItem>& getBuybackItems() const { return buybackItems_; }
|
2026-02-06 18:34:45 -08:00
|
|
|
void autoEquipItemBySlot(int backpackIndex);
|
2026-02-17 01:00:04 -08:00
|
|
|
void autoEquipItemInBag(int bagIndex, int slotIndex);
|
2026-02-06 18:34:45 -08:00
|
|
|
void useItemBySlot(int backpackIndex);
|
2026-02-17 01:00:04 -08:00
|
|
|
void useItemInBag(int bagIndex, int slotIndex);
|
2026-02-19 06:34:06 -08:00
|
|
|
void destroyItem(uint8_t bag, uint8_t slot, uint8_t count = 1);
|
2026-02-17 01:00:04 -08:00
|
|
|
void swapContainerItems(uint8_t srcBag, uint8_t srcSlot, uint8_t dstBag, uint8_t dstSlot);
|
2026-02-19 22:34:22 -08:00
|
|
|
void swapBagSlots(int srcBagIndex, int dstBagIndex);
|
2026-02-06 19:17:35 -08:00
|
|
|
void useItemById(uint32_t itemId);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
bool isVendorWindowOpen() const { return vendorWindowOpen; }
|
|
|
|
|
const ListInventoryData& getVendorItems() const { return currentVendorItems; }
|
2026-02-08 14:33:39 -08:00
|
|
|
|
2026-02-15 14:00:41 -08:00
|
|
|
// Mail
|
|
|
|
|
bool isMailboxOpen() const { return mailboxOpen_; }
|
|
|
|
|
const std::vector<MailMessage>& getMailInbox() const { return mailInbox_; }
|
|
|
|
|
int getSelectedMailIndex() const { return selectedMailIndex_; }
|
|
|
|
|
void setSelectedMailIndex(int idx) { selectedMailIndex_ = idx; }
|
|
|
|
|
bool isMailComposeOpen() const { return showMailCompose_; }
|
2026-02-25 14:11:09 -08:00
|
|
|
void openMailCompose() { showMailCompose_ = true; clearMailAttachments(); }
|
|
|
|
|
void closeMailCompose() { showMailCompose_ = false; clearMailAttachments(); }
|
2026-02-16 18:46:44 -08:00
|
|
|
bool hasNewMail() const { return hasNewMail_; }
|
2026-02-15 14:00:41 -08:00
|
|
|
void closeMailbox();
|
|
|
|
|
void sendMail(const std::string& recipient, const std::string& subject,
|
|
|
|
|
const std::string& body, uint32_t money, uint32_t cod = 0);
|
2026-02-25 14:11:09 -08:00
|
|
|
|
|
|
|
|
// Mail attachments (max 12 per WotLK)
|
|
|
|
|
static constexpr int MAIL_MAX_ATTACHMENTS = 12;
|
|
|
|
|
struct MailAttachSlot {
|
|
|
|
|
uint64_t itemGuid = 0;
|
|
|
|
|
game::ItemDef item;
|
|
|
|
|
uint8_t srcBag = 0xFF; // source container for return
|
|
|
|
|
uint8_t srcSlot = 0;
|
|
|
|
|
bool occupied() const { return itemGuid != 0; }
|
|
|
|
|
};
|
|
|
|
|
bool attachItemFromBackpack(int backpackIndex);
|
|
|
|
|
bool attachItemFromBag(int bagIndex, int slotIndex);
|
|
|
|
|
bool detachMailAttachment(int attachIndex);
|
|
|
|
|
void clearMailAttachments();
|
|
|
|
|
const std::array<MailAttachSlot, 12>& getMailAttachments() const { return mailAttachments_; }
|
|
|
|
|
int getMailAttachmentCount() const;
|
2026-02-15 14:00:41 -08:00
|
|
|
void mailTakeMoney(uint32_t mailId);
|
|
|
|
|
void mailTakeItem(uint32_t mailId, uint32_t itemIndex);
|
|
|
|
|
void mailDelete(uint32_t mailId);
|
|
|
|
|
void mailMarkAsRead(uint32_t mailId);
|
|
|
|
|
void refreshMailList();
|
|
|
|
|
|
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
|
|
|
|
|
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_; }
|
2026-02-26 11:12:34 -08:00
|
|
|
int getEffectiveBankSlots() const { return effectiveBankSlots_; }
|
|
|
|
|
int getEffectiveBankBagSlots() const { return effectiveBankBagSlots_; }
|
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
|
|
|
|
|
|
|
|
// 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_; }
|
|
|
|
|
|
2026-02-08 14:33:39 -08:00
|
|
|
// Trainer
|
|
|
|
|
bool isTrainerWindowOpen() const { return trainerWindowOpen_; }
|
|
|
|
|
const TrainerListData& getTrainerSpells() const { return currentTrainerList_; }
|
|
|
|
|
void trainSpell(uint32_t spellId);
|
|
|
|
|
void closeTrainer();
|
|
|
|
|
const std::string& getSpellName(uint32_t spellId) const;
|
|
|
|
|
const std::string& getSpellRank(uint32_t spellId) const;
|
2026-02-08 14:46:01 -08:00
|
|
|
const std::string& getSkillLineName(uint32_t spellId) const;
|
|
|
|
|
|
|
|
|
|
struct TrainerTab {
|
|
|
|
|
std::string name;
|
|
|
|
|
std::vector<const TrainerSpell*> spells;
|
|
|
|
|
};
|
|
|
|
|
const std::vector<TrainerTab>& getTrainerTabs() const { return trainerTabs_; }
|
2026-02-06 11:59:51 -08:00
|
|
|
const ItemQueryResponseData* getItemInfo(uint32_t itemId) const {
|
|
|
|
|
auto it = itemInfoCache_.find(itemId);
|
|
|
|
|
return (it != itemInfoCache_.end()) ? &it->second : nullptr;
|
|
|
|
|
}
|
2026-02-14 15:58:54 -08:00
|
|
|
// Request item info from server if not already cached/pending
|
|
|
|
|
void ensureItemInfo(uint32_t entry) {
|
|
|
|
|
if (entry == 0 || itemInfoCache_.count(entry) || pendingItemQueries_.count(entry)) return;
|
|
|
|
|
queryItemInfo(entry, 0);
|
|
|
|
|
}
|
2026-02-06 13:47:03 -08:00
|
|
|
uint64_t getBackpackItemGuid(int index) const {
|
|
|
|
|
if (index < 0 || index >= static_cast<int>(backpackSlotGuids_.size())) return 0;
|
|
|
|
|
return backpackSlotGuids_[index];
|
|
|
|
|
}
|
|
|
|
|
uint64_t getVendorGuid() const { return currentVendorItems.vendorGuid; }
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Set callbacks
|
|
|
|
|
*/
|
|
|
|
|
void setOnSuccess(WorldConnectSuccessCallback callback) { onSuccess = callback; }
|
|
|
|
|
void setOnFailure(WorldConnectFailureCallback callback) { onFailure = callback; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update - call regularly (e.g., each frame)
|
|
|
|
|
*
|
|
|
|
|
* @param deltaTime Time since last update in seconds
|
|
|
|
|
*/
|
|
|
|
|
void update(float deltaTime);
|
|
|
|
|
|
2026-02-14 19:27:35 -08:00
|
|
|
/**
|
|
|
|
|
* Reset DBC-backed caches so they reload from new expansion data.
|
|
|
|
|
* Called by Application when the expansion profile changes.
|
|
|
|
|
*/
|
|
|
|
|
void resetDbcCaches();
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
private:
|
2026-02-07 20:51:53 -08:00
|
|
|
void autoTargetAttacker(uint64_t attackerGuid);
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Handle incoming packet from world server
|
|
|
|
|
*/
|
|
|
|
|
void handlePacket(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle SMSG_AUTH_CHALLENGE from server
|
|
|
|
|
*/
|
|
|
|
|
void handleAuthChallenge(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle SMSG_AUTH_RESPONSE from server
|
|
|
|
|
*/
|
|
|
|
|
void handleAuthResponse(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle SMSG_CHAR_ENUM from server
|
|
|
|
|
*/
|
|
|
|
|
void handleCharEnum(network::Packet& packet);
|
|
|
|
|
|
2026-02-17 13:59:29 -08:00
|
|
|
/**
|
|
|
|
|
* Handle SMSG_CHARACTER_LOGIN_FAILED from server
|
|
|
|
|
*/
|
|
|
|
|
void handleCharLoginFailed(network::Packet& packet);
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Handle SMSG_LOGIN_VERIFY_WORLD from server
|
|
|
|
|
*/
|
|
|
|
|
void handleLoginVerifyWorld(network::Packet& packet);
|
|
|
|
|
|
2026-02-12 02:09:15 -08:00
|
|
|
/**
|
|
|
|
|
* Handle SMSG_CLIENTCACHE_VERSION from server
|
|
|
|
|
*/
|
|
|
|
|
void handleClientCacheVersion(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle SMSG_TUTORIAL_FLAGS from server
|
|
|
|
|
*/
|
|
|
|
|
void handleTutorialFlags(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle SMSG_WARDEN_DATA gate packet from server.
|
|
|
|
|
* We do not implement anti-cheat exchange for third-party realms.
|
|
|
|
|
*/
|
|
|
|
|
void handleWardenData(network::Packet& packet);
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Handle SMSG_ACCOUNT_DATA_TIMES from server
|
|
|
|
|
*/
|
|
|
|
|
void handleAccountDataTimes(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle SMSG_MOTD from server
|
|
|
|
|
*/
|
|
|
|
|
void handleMotd(network::Packet& packet);
|
|
|
|
|
|
2026-02-20 00:28:51 -08:00
|
|
|
/** Handle SMSG_NOTIFICATION (vanilla/classic server notification string) */
|
|
|
|
|
void handleNotification(network::Packet& packet);
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Handle SMSG_PONG from server
|
|
|
|
|
*/
|
|
|
|
|
void handlePong(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle SMSG_UPDATE_OBJECT from server
|
|
|
|
|
*/
|
|
|
|
|
void handleUpdateObject(network::Packet& packet);
|
|
|
|
|
|
2026-02-05 21:55:52 -08:00
|
|
|
/**
|
|
|
|
|
* Handle SMSG_COMPRESSED_UPDATE_OBJECT from server
|
|
|
|
|
*/
|
|
|
|
|
void handleCompressedUpdateObject(network::Packet& packet);
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Handle SMSG_DESTROY_OBJECT from server
|
|
|
|
|
*/
|
|
|
|
|
void handleDestroyObject(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handle SMSG_MESSAGECHAT from server
|
|
|
|
|
*/
|
|
|
|
|
void handleMessageChat(network::Packet& packet);
|
2026-02-14 14:30:09 -08:00
|
|
|
void handleTextEmote(network::Packet& packet);
|
|
|
|
|
void handleChannelNotify(network::Packet& packet);
|
|
|
|
|
void autoJoinDefaultChannels();
|
2026-02-02 12:24:50 -08:00
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 1 handlers ----
|
|
|
|
|
void handleNameQueryResponse(network::Packet& packet);
|
|
|
|
|
void handleCreatureQueryResponse(network::Packet& packet);
|
2026-02-08 00:59:40 -08:00
|
|
|
void handleGameObjectQueryResponse(network::Packet& packet);
|
2026-02-20 23:31:30 -08:00
|
|
|
void handleGameObjectPageText(network::Packet& packet);
|
|
|
|
|
void handlePageTextQueryResponse(network::Packet& packet);
|
2026-02-06 03:11:43 -08:00
|
|
|
void handleItemQueryResponse(network::Packet& packet);
|
2026-02-13 20:26:55 -08:00
|
|
|
void handleInspectResults(network::Packet& packet);
|
2026-02-06 03:11:43 -08:00
|
|
|
void queryItemInfo(uint32_t entry, uint64_t guid);
|
|
|
|
|
void rebuildOnlineInventory();
|
2026-02-13 20:10:19 -08:00
|
|
|
void maybeDetectVisibleItemLayout();
|
|
|
|
|
void updateOtherPlayerVisibleItems(uint64_t guid, const std::map<uint16_t, uint32_t>& fields);
|
|
|
|
|
void emitOtherPlayerEquipment(uint64_t guid);
|
|
|
|
|
void emitAllOtherPlayerEquipment();
|
2026-02-06 18:34:45 -08:00
|
|
|
void detectInventorySlotBases(const std::map<uint16_t, uint32_t>& fields);
|
|
|
|
|
bool applyInventoryFields(const std::map<uint16_t, uint32_t>& fields);
|
2026-02-13 22:14:34 -08:00
|
|
|
void extractContainerFields(uint64_t containerGuid, const std::map<uint16_t, uint32_t>& fields);
|
2026-02-06 18:52:28 -08:00
|
|
|
uint64_t resolveOnlineItemGuid(uint32_t itemId) const;
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
|
|
|
|
// ---- Phase 2 handlers ----
|
|
|
|
|
void handleAttackStart(network::Packet& packet);
|
|
|
|
|
void handleAttackStop(network::Packet& packet);
|
|
|
|
|
void handleAttackerStateUpdate(network::Packet& packet);
|
|
|
|
|
void handleSpellDamageLog(network::Packet& packet);
|
|
|
|
|
void handleSpellHealLog(network::Packet& packet);
|
|
|
|
|
|
|
|
|
|
// ---- Phase 3 handlers ----
|
|
|
|
|
void handleInitialSpells(network::Packet& packet);
|
|
|
|
|
void handleCastFailed(network::Packet& packet);
|
|
|
|
|
void handleSpellStart(network::Packet& packet);
|
|
|
|
|
void handleSpellGo(network::Packet& packet);
|
|
|
|
|
void handleSpellCooldown(network::Packet& packet);
|
|
|
|
|
void handleCooldownEvent(network::Packet& packet);
|
2026-03-09 13:53:42 -07:00
|
|
|
void handleAchievementEarned(network::Packet& packet);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
void handleAuraUpdate(network::Packet& packet, bool isAll);
|
|
|
|
|
void handleLearnedSpell(network::Packet& packet);
|
2026-02-10 01:24:37 -08:00
|
|
|
void handleSupercededSpell(network::Packet& packet);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
void handleRemovedSpell(network::Packet& packet);
|
2026-02-10 01:24:37 -08:00
|
|
|
void handleUnlearnSpells(network::Packet& packet);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
Implement complete talent system with dual spec support
Network Protocol:
- Add SMSG_TALENTS_INFO (0x4C0) packet parsing for talent data
- Add CMSG_LEARN_TALENT (0x251) to request learning talents
- Add MSG_TALENT_WIPE_CONFIRM (0x2AB) opcode for spec switching
- Parse talent spec, unspent points, and learned talent ranks
DBC Parsing:
- Load Talent.dbc: talent grid positions, ranks, prerequisites, spell IDs
- Load TalentTab.dbc: talent tree definitions with correct field indices
- Fix localized string field handling (17 fields per string)
- Load Spell.dbc and SpellIcon.dbc for talent icons and tooltips
- Class mask filtering using bitwise operations (1 << (class - 1))
UI Implementation:
- Complete talent tree UI with tabbed interface for specs
- Display talent icons from spell data with proper tinting/borders
- Enhanced tooltips: spell name, rank, current/next descriptions, prereqs
- Visual states: green (maxed), yellow (partial), white (available), gray (locked)
- Tier unlock system (5 points per tier requirement)
- Rank overlay on icons with shadow text
- Click to learn talents with validation
Dual Spec Support:
- Store unspent points and learned talents per spec (0 and 1)
- Track active spec and display its talents
- Spec switching UI with buttons for Spec 1/Spec 2
- Handle both SMSG_TALENTS_INFO packets from server at login
- Display unspent points for both specs in header
- Independent talent trees for each specialization
2026-02-10 02:00:13 -08:00
|
|
|
// ---- Talent handlers ----
|
|
|
|
|
void handleTalentsInfo(network::Packet& packet);
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 4 handlers ----
|
|
|
|
|
void handleGroupInvite(network::Packet& packet);
|
|
|
|
|
void handleGroupDecline(network::Packet& packet);
|
|
|
|
|
void handleGroupList(network::Packet& packet);
|
|
|
|
|
void handleGroupUninvite(network::Packet& packet);
|
|
|
|
|
void handlePartyCommandResult(network::Packet& packet);
|
2026-02-26 10:25:55 -08:00
|
|
|
void handlePartyMemberStats(network::Packet& packet, bool isFull);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
2026-02-13 21:39:48 -08:00
|
|
|
// ---- Guild handlers ----
|
|
|
|
|
void handleGuildInfo(network::Packet& packet);
|
|
|
|
|
void handleGuildRoster(network::Packet& packet);
|
|
|
|
|
void handleGuildQueryResponse(network::Packet& packet);
|
|
|
|
|
void handleGuildEvent(network::Packet& packet);
|
|
|
|
|
void handleGuildInvite(network::Packet& packet);
|
|
|
|
|
void handleGuildCommandResult(network::Packet& packet);
|
2026-02-25 14:44:44 -08:00
|
|
|
void handlePetitionShowlist(network::Packet& packet);
|
2026-02-26 10:41:29 -08:00
|
|
|
void handlePetSpells(network::Packet& packet);
|
2026-02-25 14:44:44 -08:00
|
|
|
void handleTurnInPetitionResults(network::Packet& packet);
|
2026-02-13 21:39:48 -08:00
|
|
|
|
2026-02-05 14:13:48 -08:00
|
|
|
// ---- Character creation handler ----
|
|
|
|
|
void handleCharCreateResponse(network::Packet& packet);
|
|
|
|
|
|
2026-02-05 12:07:58 -08:00
|
|
|
// ---- XP handler ----
|
|
|
|
|
void handleXpGain(network::Packet& packet);
|
|
|
|
|
|
2026-02-06 13:47:03 -08:00
|
|
|
// ---- Creature movement handler ----
|
|
|
|
|
void handleMonsterMove(network::Packet& packet);
|
2026-02-18 03:15:25 -08:00
|
|
|
void handleCompressedMoves(network::Packet& packet);
|
2026-02-11 00:54:38 -08:00
|
|
|
void handleMonsterMoveTransport(network::Packet& packet);
|
2026-02-06 13:47:03 -08:00
|
|
|
|
2026-02-13 18:59:09 -08:00
|
|
|
// ---- Other player movement (MSG_MOVE_* from server) ----
|
|
|
|
|
void handleOtherPlayerMovement(network::Packet& packet);
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 5 handlers ----
|
|
|
|
|
void handleLootResponse(network::Packet& packet);
|
|
|
|
|
void handleLootReleaseResponse(network::Packet& packet);
|
|
|
|
|
void handleLootRemoved(network::Packet& packet);
|
|
|
|
|
void handleGossipMessage(network::Packet& packet);
|
2026-02-19 02:53:44 -08:00
|
|
|
void handleQuestgiverQuestList(network::Packet& packet);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
void handleGossipComplete(network::Packet& packet);
|
2026-02-06 11:59:51 -08:00
|
|
|
void handleQuestDetails(network::Packet& packet);
|
2026-02-06 21:50:15 -08:00
|
|
|
void handleQuestRequestItems(network::Packet& packet);
|
|
|
|
|
void handleQuestOfferReward(network::Packet& packet);
|
2026-02-20 17:14:13 -08:00
|
|
|
void clearPendingQuestAccept(uint32_t questId);
|
|
|
|
|
void triggerQuestAcceptResync(uint32_t questId, uint64_t npcGuid, const char* reason);
|
|
|
|
|
bool hasQuestInLog(uint32_t questId) const;
|
2026-02-20 23:20:02 -08:00
|
|
|
int findQuestLogSlotIndexFromServer(uint32_t questId) const;
|
2026-02-20 17:14:13 -08:00
|
|
|
void addQuestToLocalLogIfMissing(uint32_t questId, const std::string& title, const std::string& objectives);
|
|
|
|
|
bool resyncQuestLogFromServerSlots(bool forceQueryMetadata);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
void handleListInventory(network::Packet& packet);
|
2026-02-05 14:01:26 -08:00
|
|
|
void addMoneyCopper(uint32_t amount);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
2026-02-07 16:59:20 -08:00
|
|
|
// ---- Teleport handler ----
|
|
|
|
|
void handleTeleportAck(network::Packet& packet);
|
2026-02-08 03:05:38 -08:00
|
|
|
void handleNewWorld(network::Packet& packet);
|
2026-02-07 16:59:20 -08:00
|
|
|
|
Add missing movement ACK responses to avoid server stalls
Implement generic handlers for force speed changes (walk, run back,
swim, swim back, flight, flight back, turn rate, pitch rate),
movement flag toggles (CAN_FLY, HOVER, feather fall, water walk),
and knockback ACKs. Fix SMSG_TIME_SYNC_REQ to respond with
CMSG_TIME_SYNC_RESP instead of silently dropping.
2026-02-26 03:02:51 -08:00
|
|
|
// ---- Movement ACK handlers ----
|
2026-02-07 17:59:40 -08:00
|
|
|
void handleForceRunSpeedChange(network::Packet& packet);
|
Add missing movement ACK responses to avoid server stalls
Implement generic handlers for force speed changes (walk, run back,
swim, swim back, flight, flight back, turn rate, pitch rate),
movement flag toggles (CAN_FLY, HOVER, feather fall, water walk),
and knockback ACKs. Fix SMSG_TIME_SYNC_REQ to respond with
CMSG_TIME_SYNC_RESP instead of silently dropping.
2026-02-26 03:02:51 -08:00
|
|
|
void handleForceSpeedChange(network::Packet& packet, const char* name, Opcode ackOpcode, float* speedStorage);
|
2026-02-20 03:14:48 -08:00
|
|
|
void handleForceMoveRootState(network::Packet& packet, bool rooted);
|
Add missing movement ACK responses to avoid server stalls
Implement generic handlers for force speed changes (walk, run back,
swim, swim back, flight, flight back, turn rate, pitch rate),
movement flag toggles (CAN_FLY, HOVER, feather fall, water walk),
and knockback ACKs. Fix SMSG_TIME_SYNC_REQ to respond with
CMSG_TIME_SYNC_RESP instead of silently dropping.
2026-02-26 03:02:51 -08:00
|
|
|
void handleForceMoveFlagChange(network::Packet& packet, const char* name, Opcode ackOpcode, uint32_t flag, bool set);
|
|
|
|
|
void handleMoveKnockBack(network::Packet& packet);
|
2026-02-07 17:59:40 -08:00
|
|
|
|
2026-02-26 17:56:11 -08:00
|
|
|
// ---- Area trigger detection ----
|
|
|
|
|
void loadAreaTriggerDbc();
|
|
|
|
|
void checkAreaTriggers();
|
|
|
|
|
|
2026-03-09 13:36:23 -07:00
|
|
|
// ---- Instance lockout handler ----
|
|
|
|
|
void handleRaidInstanceInfo(network::Packet& packet);
|
|
|
|
|
|
2026-03-09 13:30:23 -07:00
|
|
|
// ---- LFG / Dungeon Finder handlers ----
|
|
|
|
|
void handleLfgJoinResult(network::Packet& packet);
|
|
|
|
|
void handleLfgQueueStatus(network::Packet& packet);
|
|
|
|
|
void handleLfgProposalUpdate(network::Packet& packet);
|
|
|
|
|
void handleLfgRoleCheckUpdate(network::Packet& packet);
|
|
|
|
|
void handleLfgUpdatePlayer(network::Packet& packet);
|
|
|
|
|
void handleLfgPlayerReward(network::Packet& packet);
|
|
|
|
|
void handleLfgBootProposalUpdate(network::Packet& packet);
|
|
|
|
|
void handleLfgTeleportDenied(network::Packet& packet);
|
|
|
|
|
|
2026-02-07 23:47:43 -08:00
|
|
|
// ---- Arena / Battleground handlers ----
|
|
|
|
|
void handleBattlefieldStatus(network::Packet& packet);
|
2026-02-26 17:56:11 -08:00
|
|
|
void handleInstanceDifficulty(network::Packet& packet);
|
2026-02-07 23:47:43 -08:00
|
|
|
void handleArenaTeamCommandResult(network::Packet& packet);
|
|
|
|
|
void handleArenaTeamQueryResponse(network::Packet& packet);
|
|
|
|
|
void handleArenaTeamInvite(network::Packet& packet);
|
|
|
|
|
void handleArenaTeamEvent(network::Packet& packet);
|
|
|
|
|
void handleArenaError(network::Packet& packet);
|
|
|
|
|
|
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 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);
|
|
|
|
|
|
2026-02-15 14:00:41 -08:00
|
|
|
// ---- Mail handlers ----
|
|
|
|
|
void handleShowMailbox(network::Packet& packet);
|
|
|
|
|
void handleMailListResult(network::Packet& packet);
|
|
|
|
|
void handleSendMailResult(network::Packet& packet);
|
|
|
|
|
void handleReceivedMail(network::Packet& packet);
|
2026-02-16 18:46:44 -08:00
|
|
|
void handleQueryNextMailTime(network::Packet& packet);
|
2026-02-15 14:00:41 -08:00
|
|
|
|
2026-02-07 16:59:20 -08:00
|
|
|
// ---- Taxi handlers ----
|
|
|
|
|
void handleShowTaxiNodes(network::Packet& packet);
|
|
|
|
|
void handleActivateTaxiReply(network::Packet& packet);
|
|
|
|
|
void loadTaxiDbc();
|
|
|
|
|
|
2026-02-07 12:43:32 -08:00
|
|
|
// ---- Server info handlers ----
|
|
|
|
|
void handleQueryTimeResponse(network::Packet& packet);
|
|
|
|
|
void handlePlayedTime(network::Packet& packet);
|
|
|
|
|
void handleWho(network::Packet& packet);
|
|
|
|
|
|
Add /roll and friend management commands
Roll Command:
- Add /roll, /random, /rnd commands for random number generation
- Support multiple formats: /roll, /roll 100, /roll 1-100, /roll 10 50
- Broadcasts rolls to party/raid with "[Name] rolls X (min-max)" format
- Cap max roll at 10,000 to prevent abuse
- Use MSG_RANDOM_ROLL (0x1FB) bidirectional opcode
Friend Commands:
- Add /friend add <name>, /addfriend <name> to add friends
- Add /friend remove <name>, /removefriend <name> to remove friends
- Support aliases: /delfriend, /remfriend
- Maintain local friends cache mapping names to GUIDs for lookups
- Display status messages for all friend actions:
- Friend added/removed confirmations
- Friend online/offline notifications
- Error messages (not found, already friends, list full, ignoring)
Social Opcodes:
- Add CMSG_ADD_FRIEND (0x69) and SMSG_FRIEND_STATUS (0x68)
- Add CMSG_DEL_FRIEND (0x6A) for friend removal
- Add CMSG_SET_CONTACT_NOTES (0x6B) for friend notes (future use)
- Add CMSG_ADD_IGNORE (0x6C) and CMSG_DEL_IGNORE (0x6D) (future use)
Implementation:
- Add RandomRollPacket builder and RandomRollParser for roll data
- Add AddFriendPacket and DelFriendPacket builders
- Add FriendStatusParser to handle server friend status updates
- Add friendsCache map to store friend name-to-GUID mappings
- Add handleRandomRoll() and handleFriendStatus() packet handlers
- Comprehensive slash command parsing with multiple formats and aliases
2026-02-07 12:51:30 -08:00
|
|
|
// ---- Social handlers ----
|
|
|
|
|
void handleFriendStatus(network::Packet& packet);
|
|
|
|
|
void handleRandomRoll(network::Packet& packet);
|
|
|
|
|
|
2026-02-07 12:58:11 -08:00
|
|
|
// ---- Logout handlers ----
|
|
|
|
|
void handleLogoutResponse(network::Packet& packet);
|
|
|
|
|
void handleLogoutComplete(network::Packet& packet);
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
void addCombatText(CombatTextEntry::Type type, int32_t amount, uint32_t spellId, bool isPlayerSource);
|
2026-02-05 13:22:15 -08:00
|
|
|
void addSystemChatMessage(const std::string& message);
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
/**
|
|
|
|
|
* Send CMSG_PING to server (heartbeat)
|
|
|
|
|
*/
|
|
|
|
|
void sendPing();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Send CMSG_AUTH_SESSION to server
|
|
|
|
|
*/
|
|
|
|
|
void sendAuthSession();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate random client seed
|
|
|
|
|
*/
|
|
|
|
|
uint32_t generateClientSeed();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Change state with logging
|
|
|
|
|
*/
|
|
|
|
|
void setState(WorldState newState);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fail connection with reason
|
|
|
|
|
*/
|
|
|
|
|
void fail(const std::string& reason);
|
2026-02-12 00:04:53 -08:00
|
|
|
void updateAttachedTransportChildren(float deltaTime);
|
|
|
|
|
void setTransportAttachment(uint64_t childGuid, ObjectType type, uint64_t transportGuid,
|
|
|
|
|
const glm::vec3& localOffset, bool hasLocalOrientation,
|
|
|
|
|
float localOrientation);
|
|
|
|
|
void clearTransportAttachment(uint64_t childGuid);
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-12 22:56:36 -08:00
|
|
|
// Opcode translation table (expansion-specific wire ↔ logical mapping)
|
|
|
|
|
OpcodeTable opcodeTable_;
|
|
|
|
|
|
|
|
|
|
// Update field table (expansion-specific field index mapping)
|
|
|
|
|
UpdateFieldTable updateFieldTable_;
|
|
|
|
|
|
|
|
|
|
// Packet parsers (expansion-specific binary format handling)
|
|
|
|
|
std::unique_ptr<PacketParsers> packetParsers_;
|
|
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Network
|
|
|
|
|
std::unique_ptr<network::WorldSocket> socket;
|
|
|
|
|
|
|
|
|
|
// State
|
|
|
|
|
WorldState state = WorldState::DISCONNECTED;
|
|
|
|
|
|
|
|
|
|
// Authentication data
|
|
|
|
|
std::vector<uint8_t> sessionKey; // 40-byte session key from auth server
|
|
|
|
|
std::string accountName; // Account name
|
|
|
|
|
uint32_t build = 12340; // Client build (3.3.5a)
|
2026-02-13 01:51:49 -08:00
|
|
|
uint32_t realmId_ = 0; // Realm ID from auth REALM_LIST (used in WotLK AUTH_SESSION)
|
2026-02-02 12:24:50 -08:00
|
|
|
uint32_t clientSeed = 0; // Random seed generated by client
|
|
|
|
|
uint32_t serverSeed = 0; // Seed from SMSG_AUTH_CHALLENGE
|
|
|
|
|
|
|
|
|
|
// Characters
|
|
|
|
|
std::vector<Character> characters; // Character list from SMSG_CHAR_ENUM
|
|
|
|
|
|
|
|
|
|
// Movement
|
|
|
|
|
MovementInfo movementInfo; // Current player movement state
|
|
|
|
|
uint32_t movementTime = 0; // Movement timestamp counter
|
2026-02-20 02:19:17 -08:00
|
|
|
std::chrono::steady_clock::time_point movementClockStart_ = std::chrono::steady_clock::now();
|
|
|
|
|
uint32_t lastMovementTimestampMs_ = 0;
|
2026-02-18 23:30:38 -08:00
|
|
|
bool serverMovementAllowed_ = true;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
// Inventory
|
|
|
|
|
Inventory inventory;
|
|
|
|
|
|
|
|
|
|
// Entity tracking
|
|
|
|
|
EntityManager entityManager; // Manages all entities in view
|
|
|
|
|
|
|
|
|
|
// Chat
|
2026-02-04 11:31:08 -08:00
|
|
|
std::deque<MessageChatData> chatHistory; // Recent chat messages
|
2026-02-02 12:24:50 -08:00
|
|
|
size_t maxChatHistory = 100; // Maximum chat messages to keep
|
2026-02-14 14:30:09 -08:00
|
|
|
std::vector<std::string> joinedChannels_; // Active channel memberships
|
|
|
|
|
ChatBubbleCallback chatBubbleCallback_;
|
2026-02-14 15:11:43 -08:00
|
|
|
EmoteAnimCallback emoteAnimCallback_;
|
2026-02-02 12:24:50 -08:00
|
|
|
|
|
|
|
|
// Targeting
|
|
|
|
|
uint64_t targetGuid = 0;
|
2026-02-07 13:44:36 -08:00
|
|
|
uint64_t focusGuid = 0; // Focus target
|
|
|
|
|
uint64_t lastTargetGuid = 0; // Previous target
|
2026-02-02 12:24:50 -08:00
|
|
|
std::vector<uint64_t> tabCycleList;
|
|
|
|
|
int tabCycleIndex = -1;
|
|
|
|
|
bool tabCycleStale = true;
|
|
|
|
|
|
|
|
|
|
// Heartbeat
|
|
|
|
|
uint32_t pingSequence = 0; // Ping sequence number (increments)
|
|
|
|
|
float timeSinceLastPing = 0.0f; // Time since last ping sent (seconds)
|
|
|
|
|
float pingInterval = 30.0f; // Ping interval (30 seconds)
|
2026-02-11 21:14:35 -08:00
|
|
|
float timeSinceLastMoveHeartbeat_ = 0.0f; // Periodic movement heartbeat to keep server position synced
|
|
|
|
|
float moveHeartbeatInterval_ = 0.5f;
|
2026-02-02 12:24:50 -08:00
|
|
|
uint32_t lastLatency = 0; // Last measured latency (milliseconds)
|
|
|
|
|
|
2026-02-07 16:59:20 -08:00
|
|
|
// Player GUID and map
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
uint64_t playerGuid = 0;
|
2026-02-07 16:59:20 -08:00
|
|
|
uint32_t currentMapId_ = 0;
|
2026-02-08 03:39:02 -08:00
|
|
|
bool hasHomeBind_ = false;
|
|
|
|
|
uint32_t homeBindMapId_ = 0;
|
|
|
|
|
glm::vec3 homeBindPos_{0.0f};
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
|
|
|
|
// ---- Phase 1: Name caches ----
|
|
|
|
|
std::unordered_map<uint64_t, std::string> playerNameCache;
|
|
|
|
|
std::unordered_set<uint64_t> pendingNameQueries;
|
|
|
|
|
std::unordered_map<uint32_t, CreatureQueryResponseData> creatureInfoCache;
|
|
|
|
|
std::unordered_set<uint32_t> pendingCreatureQueries;
|
2026-02-08 00:59:40 -08:00
|
|
|
std::unordered_map<uint32_t, GameObjectQueryResponseData> gameObjectInfoCache_;
|
|
|
|
|
std::unordered_set<uint32_t> pendingGameObjectQueries_;
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
Add /roll and friend management commands
Roll Command:
- Add /roll, /random, /rnd commands for random number generation
- Support multiple formats: /roll, /roll 100, /roll 1-100, /roll 10 50
- Broadcasts rolls to party/raid with "[Name] rolls X (min-max)" format
- Cap max roll at 10,000 to prevent abuse
- Use MSG_RANDOM_ROLL (0x1FB) bidirectional opcode
Friend Commands:
- Add /friend add <name>, /addfriend <name> to add friends
- Add /friend remove <name>, /removefriend <name> to remove friends
- Support aliases: /delfriend, /remfriend
- Maintain local friends cache mapping names to GUIDs for lookups
- Display status messages for all friend actions:
- Friend added/removed confirmations
- Friend online/offline notifications
- Error messages (not found, already friends, list full, ignoring)
Social Opcodes:
- Add CMSG_ADD_FRIEND (0x69) and SMSG_FRIEND_STATUS (0x68)
- Add CMSG_DEL_FRIEND (0x6A) for friend removal
- Add CMSG_SET_CONTACT_NOTES (0x6B) for friend notes (future use)
- Add CMSG_ADD_IGNORE (0x6C) and CMSG_DEL_IGNORE (0x6D) (future use)
Implementation:
- Add RandomRollPacket builder and RandomRollParser for roll data
- Add AddFriendPacket and DelFriendPacket builders
- Add FriendStatusParser to handle server friend status updates
- Add friendsCache map to store friend name-to-GUID mappings
- Add handleRandomRoll() and handleFriendStatus() packet handlers
- Comprehensive slash command parsing with multiple formats and aliases
2026-02-07 12:51:30 -08:00
|
|
|
// ---- Friend list cache ----
|
|
|
|
|
std::unordered_map<std::string, uint64_t> friendsCache; // name -> guid
|
2026-02-18 23:30:38 -08:00
|
|
|
uint32_t lastContactListMask_ = 0;
|
|
|
|
|
uint32_t lastContactListCount_ = 0;
|
|
|
|
|
|
|
|
|
|
// ---- World state and faction initialization snapshots ----
|
|
|
|
|
uint32_t worldStateMapId_ = 0;
|
|
|
|
|
uint32_t worldStateZoneId_ = 0;
|
|
|
|
|
std::unordered_map<uint32_t, uint32_t> worldStates_;
|
|
|
|
|
std::vector<FactionStandingInit> initialFactions_;
|
Add /roll and friend management commands
Roll Command:
- Add /roll, /random, /rnd commands for random number generation
- Support multiple formats: /roll, /roll 100, /roll 1-100, /roll 10 50
- Broadcasts rolls to party/raid with "[Name] rolls X (min-max)" format
- Cap max roll at 10,000 to prevent abuse
- Use MSG_RANDOM_ROLL (0x1FB) bidirectional opcode
Friend Commands:
- Add /friend add <name>, /addfriend <name> to add friends
- Add /friend remove <name>, /removefriend <name> to remove friends
- Support aliases: /delfriend, /remfriend
- Maintain local friends cache mapping names to GUIDs for lookups
- Display status messages for all friend actions:
- Friend added/removed confirmations
- Friend online/offline notifications
- Error messages (not found, already friends, list full, ignoring)
Social Opcodes:
- Add CMSG_ADD_FRIEND (0x69) and SMSG_FRIEND_STATUS (0x68)
- Add CMSG_DEL_FRIEND (0x6A) for friend removal
- Add CMSG_SET_CONTACT_NOTES (0x6B) for friend notes (future use)
- Add CMSG_ADD_IGNORE (0x6C) and CMSG_DEL_IGNORE (0x6D) (future use)
Implementation:
- Add RandomRollPacket builder and RandomRollParser for roll data
- Add AddFriendPacket and DelFriendPacket builders
- Add FriendStatusParser to handle server friend status updates
- Add friendsCache map to store friend name-to-GUID mappings
- Add handleRandomRoll() and handleFriendStatus() packet handlers
- Comprehensive slash command parsing with multiple formats and aliases
2026-02-07 12:51:30 -08:00
|
|
|
|
2026-02-07 12:58:11 -08:00
|
|
|
// ---- Ignore list cache ----
|
|
|
|
|
std::unordered_map<std::string, uint64_t> ignoreCache; // name -> guid
|
|
|
|
|
|
|
|
|
|
// ---- Logout state ----
|
|
|
|
|
bool loggingOut_ = false;
|
|
|
|
|
|
2026-02-07 13:03:21 -08:00
|
|
|
// ---- Display state ----
|
|
|
|
|
bool helmVisible_ = true;
|
|
|
|
|
bool cloakVisible_ = true;
|
Implement SMSG_STANDSTATE_UPDATE and SMSG_ITEM_PUSH_RESULT handlers
SMSG_STANDSTATE_UPDATE:
- Parse uint8 stand state from server confirmation packet
- Store in standState_ member (0=stand, 7=dead, 8=kneel, etc.)
- Expose getStandState(), isSitting(), isDead(), isKneeling() accessors
SMSG_ITEM_PUSH_RESULT:
- Parse full WotLK 3.3.5a payload: guid, received, created, showInChat,
bagSlot, itemSlot, itemId, suffixFactor, randomPropertyId, count, totalCount
- Show "Received: <name> x<count>" chat notification when showInChat=1
- Queue item info lookup via queryItemInfo so name resolves asap
2026-03-09 12:58:52 -07:00
|
|
|
uint8_t standState_ = 0; // 0=stand, 1=sit, ..., 7=dead, 8=kneel (server-confirmed)
|
2026-02-07 13:03:21 -08:00
|
|
|
|
|
|
|
|
// ---- Follow state ----
|
|
|
|
|
uint64_t followTargetGuid_ = 0;
|
|
|
|
|
|
2026-02-07 13:17:01 -08:00
|
|
|
// ---- AFK/DND status ----
|
|
|
|
|
bool afkStatus_ = false;
|
|
|
|
|
bool dndStatus_ = false;
|
|
|
|
|
std::string afkMessage_;
|
|
|
|
|
std::string dndMessage_;
|
|
|
|
|
std::string lastWhisperSender_;
|
|
|
|
|
|
2026-02-06 03:11:43 -08:00
|
|
|
// ---- Online item tracking ----
|
|
|
|
|
struct OnlineItemInfo {
|
|
|
|
|
uint32_t entry = 0;
|
|
|
|
|
uint32_t stackCount = 1;
|
|
|
|
|
};
|
|
|
|
|
std::unordered_map<uint64_t, OnlineItemInfo> onlineItems_;
|
|
|
|
|
std::unordered_map<uint32_t, ItemQueryResponseData> itemInfoCache_;
|
|
|
|
|
std::unordered_set<uint32_t> pendingItemQueries_;
|
|
|
|
|
std::array<uint64_t, 23> equipSlotGuids_{};
|
|
|
|
|
std::array<uint64_t, 16> backpackSlotGuids_{};
|
2026-02-13 22:14:34 -08:00
|
|
|
// Container (bag) contents: containerGuid -> array of item GUIDs per slot
|
|
|
|
|
struct ContainerInfo {
|
|
|
|
|
uint32_t numSlots = 0;
|
|
|
|
|
std::array<uint64_t, 36> slotGuids{}; // max 36 slots
|
|
|
|
|
};
|
|
|
|
|
std::unordered_map<uint64_t, ContainerInfo> containerContents_;
|
2026-02-06 18:34:45 -08:00
|
|
|
int invSlotBase_ = -1;
|
|
|
|
|
int packSlotBase_ = -1;
|
|
|
|
|
std::map<uint16_t, uint32_t> lastPlayerFields_;
|
2026-02-06 03:13:42 -08:00
|
|
|
bool onlineEquipDirty_ = false;
|
2026-02-14 16:33:24 -08:00
|
|
|
std::array<uint32_t, 19> lastEquipDisplayIds_{};
|
2026-02-06 03:11:43 -08:00
|
|
|
|
2026-02-13 20:10:19 -08:00
|
|
|
// Visible equipment for other players: detect the update-field layout (base + stride)
|
|
|
|
|
// using the local player's own equipped items, then decode other players by index.
|
2026-02-14 15:43:09 -08:00
|
|
|
// Default to known WotLK 3.3.5a layout: UNIT_END(148) + 0x0088 = 284, stride 2.
|
|
|
|
|
// The heuristic in maybeDetectVisibleItemLayout() can still override if needed.
|
|
|
|
|
int visibleItemEntryBase_ = 284;
|
2026-02-13 20:10:19 -08:00
|
|
|
int visibleItemStride_ = 2;
|
2026-02-14 15:43:09 -08:00
|
|
|
bool visibleItemLayoutVerified_ = false; // true once heuristic confirms/overrides default
|
2026-02-13 20:10:19 -08:00
|
|
|
std::unordered_map<uint64_t, std::array<uint32_t, 19>> otherPlayerVisibleItemEntries_;
|
|
|
|
|
std::unordered_set<uint64_t> otherPlayerVisibleDirty_;
|
2026-02-13 20:19:33 -08:00
|
|
|
std::unordered_map<uint64_t, uint32_t> otherPlayerMoveTimeMs_;
|
2026-02-19 16:45:39 -08:00
|
|
|
std::unordered_map<uint64_t, float> otherPlayerSmoothedIntervalMs_; // EMA of packet intervals
|
2026-02-13 20:10:19 -08:00
|
|
|
|
2026-02-13 20:26:55 -08:00
|
|
|
// Inspect fallback (when visible item fields are missing/unreliable)
|
|
|
|
|
std::unordered_map<uint64_t, std::array<uint32_t, 19>> inspectedPlayerItemEntries_;
|
|
|
|
|
std::unordered_set<uint64_t> pendingAutoInspect_;
|
|
|
|
|
float inspectRateLimit_ = 0.0f;
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 2: Combat ----
|
|
|
|
|
bool autoAttacking = false;
|
2026-02-20 03:38:12 -08:00
|
|
|
bool autoAttackRequested_ = false; // local intent (CMSG_ATTACKSWING sent)
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
uint64_t autoAttackTarget = 0;
|
2026-02-06 18:34:45 -08:00
|
|
|
bool autoAttackOutOfRange_ = false;
|
2026-02-20 17:53:33 -08:00
|
|
|
float autoAttackOutOfRangeTime_ = 0.0f;
|
|
|
|
|
float autoAttackRangeWarnCooldown_ = 0.0f;
|
2026-02-17 15:37:02 -08:00
|
|
|
float autoAttackResendTimer_ = 0.0f; // Re-send CMSG_ATTACKSWING every ~1s while attacking
|
2026-02-20 03:14:48 -08:00
|
|
|
float autoAttackFacingSyncTimer_ = 0.0f; // Periodic facing sync while meleeing
|
2026-02-06 18:34:45 -08:00
|
|
|
std::unordered_set<uint64_t> hostileAttackers_;
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
std::vector<CombatTextEntry> combatText;
|
|
|
|
|
|
|
|
|
|
// ---- Phase 3: Spells ----
|
2026-02-05 21:28:21 -08:00
|
|
|
WorldEntryCallback worldEntryCallback_;
|
2026-02-07 16:59:20 -08:00
|
|
|
UnstuckCallback unstuckCallback_;
|
2026-02-08 03:24:12 -08:00
|
|
|
UnstuckCallback unstuckGyCallback_;
|
2026-03-07 22:03:28 -08:00
|
|
|
UnstuckCallback unstuckHearthCallback_;
|
2026-02-08 03:32:00 -08:00
|
|
|
BindPointCallback bindPointCallback_;
|
2026-02-05 21:55:52 -08:00
|
|
|
CreatureSpawnCallback creatureSpawnCallback_;
|
|
|
|
|
CreatureDespawnCallback creatureDespawnCallback_;
|
2026-02-13 19:40:54 -08:00
|
|
|
PlayerSpawnCallback playerSpawnCallback_;
|
|
|
|
|
PlayerDespawnCallback playerDespawnCallback_;
|
2026-02-13 20:10:19 -08:00
|
|
|
PlayerEquipmentCallback playerEquipmentCallback_;
|
2026-02-06 13:47:03 -08:00
|
|
|
CreatureMoveCallback creatureMoveCallback_;
|
2026-02-08 00:59:40 -08:00
|
|
|
TransportMoveCallback transportMoveCallback_;
|
2026-02-11 00:54:38 -08:00
|
|
|
TransportSpawnCallback transportSpawnCallback_;
|
2026-02-07 19:44:03 -08:00
|
|
|
GameObjectSpawnCallback gameObjectSpawnCallback_;
|
2026-02-12 00:04:53 -08:00
|
|
|
GameObjectMoveCallback gameObjectMoveCallback_;
|
2026-02-07 19:44:03 -08:00
|
|
|
GameObjectDespawnCallback gameObjectDespawnCallback_;
|
2026-02-23 05:39:02 -08:00
|
|
|
GameObjectCustomAnimCallback gameObjectCustomAnimCallback_;
|
2026-02-08 00:59:40 -08:00
|
|
|
|
|
|
|
|
// Transport tracking
|
2026-02-12 00:04:53 -08:00
|
|
|
struct TransportAttachment {
|
|
|
|
|
ObjectType type = ObjectType::OBJECT;
|
|
|
|
|
uint64_t transportGuid = 0;
|
|
|
|
|
glm::vec3 localOffset{0.0f};
|
|
|
|
|
float localOrientation = 0.0f;
|
|
|
|
|
bool hasLocalOrientation = false;
|
|
|
|
|
};
|
|
|
|
|
std::unordered_map<uint64_t, TransportAttachment> transportAttachments_;
|
2026-02-08 00:59:40 -08:00
|
|
|
std::unordered_set<uint64_t> transportGuids_; // GUIDs of known transport GameObjects
|
2026-02-12 00:04:53 -08:00
|
|
|
std::unordered_set<uint64_t> serverUpdatedTransportGuids_;
|
2026-02-08 00:59:40 -08:00
|
|
|
uint64_t playerTransportGuid_ = 0; // Transport the player is riding (0 = none)
|
|
|
|
|
glm::vec3 playerTransportOffset_ = glm::vec3(0.0f); // Player offset on transport
|
2026-02-12 00:45:24 -08:00
|
|
|
uint64_t playerTransportStickyGuid_ = 0; // Last transport player was on (temporary retention)
|
|
|
|
|
float playerTransportStickyTimer_ = 0.0f; // Seconds to keep sticky transport alive after transient clears
|
2026-02-10 21:29:10 -08:00
|
|
|
std::unique_ptr<TransportManager> transportManager_; // Transport movement manager
|
2026-02-17 15:13:54 -08:00
|
|
|
std::unordered_set<uint32_t> knownSpells;
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
std::unordered_map<uint32_t, float> spellCooldowns; // spellId -> remaining seconds
|
|
|
|
|
uint8_t castCount = 0;
|
|
|
|
|
bool casting = false;
|
|
|
|
|
uint32_t currentCastSpellId = 0;
|
|
|
|
|
float castTimeRemaining = 0.0f;
|
2026-02-19 03:31:49 -08:00
|
|
|
uint64_t pendingGameObjectInteractGuid_ = 0;
|
Implement complete talent system with dual spec support
Network Protocol:
- Add SMSG_TALENTS_INFO (0x4C0) packet parsing for talent data
- Add CMSG_LEARN_TALENT (0x251) to request learning talents
- Add MSG_TALENT_WIPE_CONFIRM (0x2AB) opcode for spec switching
- Parse talent spec, unspent points, and learned talent ranks
DBC Parsing:
- Load Talent.dbc: talent grid positions, ranks, prerequisites, spell IDs
- Load TalentTab.dbc: talent tree definitions with correct field indices
- Fix localized string field handling (17 fields per string)
- Load Spell.dbc and SpellIcon.dbc for talent icons and tooltips
- Class mask filtering using bitwise operations (1 << (class - 1))
UI Implementation:
- Complete talent tree UI with tabbed interface for specs
- Display talent icons from spell data with proper tinting/borders
- Enhanced tooltips: spell name, rank, current/next descriptions, prereqs
- Visual states: green (maxed), yellow (partial), white (available), gray (locked)
- Tier unlock system (5 points per tier requirement)
- Rank overlay on icons with shadow text
- Click to learn talents with validation
Dual Spec Support:
- Store unspent points and learned talents per spec (0 and 1)
- Track active spec and display its talents
- Spec switching UI with buttons for Spec 1/Spec 2
- Handle both SMSG_TALENTS_INFO packets from server at login
- Display unspent points for both specs in header
- Independent talent trees for each specialization
2026-02-10 02:00:13 -08:00
|
|
|
|
|
|
|
|
// Talents (dual-spec support)
|
|
|
|
|
uint8_t activeTalentSpec_ = 0; // Currently active spec (0 or 1)
|
|
|
|
|
uint8_t unspentTalentPoints_[2] = {0, 0}; // Unspent points per spec
|
|
|
|
|
std::unordered_map<uint32_t, uint8_t> learnedTalents_[2]; // Learned talents per spec
|
|
|
|
|
std::unordered_map<uint32_t, TalentEntry> talentCache_; // talentId -> entry
|
|
|
|
|
std::unordered_map<uint32_t, TalentTabEntry> talentTabCache_; // tabId -> entry
|
|
|
|
|
bool talentDbcLoaded_ = false;
|
2026-02-26 17:56:11 -08:00
|
|
|
|
|
|
|
|
// ---- Area trigger detection ----
|
|
|
|
|
struct AreaTriggerEntry {
|
|
|
|
|
uint32_t id = 0;
|
|
|
|
|
uint32_t mapId = 0;
|
|
|
|
|
float x = 0, y = 0, z = 0; // canonical WoW coords (converted from DBC)
|
|
|
|
|
float radius = 0;
|
|
|
|
|
float boxLength = 0, boxWidth = 0, boxHeight = 0;
|
|
|
|
|
float boxYaw = 0;
|
|
|
|
|
};
|
|
|
|
|
bool areaTriggerDbcLoaded_ = false;
|
|
|
|
|
std::vector<AreaTriggerEntry> areaTriggers_;
|
|
|
|
|
std::unordered_set<uint32_t> activeAreaTriggers_; // triggers player is currently inside
|
|
|
|
|
float areaTriggerCheckTimer_ = 0.0f;
|
2026-02-27 04:59:12 -08:00
|
|
|
bool areaTriggerSuppressFirst_ = false; // suppress first check after map transfer
|
2026-02-26 17:56:11 -08:00
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
float castTimeTotal = 0.0f;
|
|
|
|
|
std::array<ActionBarSlot, 12> actionBar{};
|
|
|
|
|
std::vector<AuraSlot> playerAuras;
|
|
|
|
|
std::vector<AuraSlot> targetAuras;
|
2026-02-26 10:41:29 -08:00
|
|
|
uint64_t petGuid_ = 0;
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
2026-02-26 17:56:11 -08:00
|
|
|
// ---- Battleground queue state ----
|
|
|
|
|
struct BgQueueSlot {
|
|
|
|
|
uint32_t queueSlot = 0;
|
|
|
|
|
uint32_t bgTypeId = 0;
|
|
|
|
|
uint8_t arenaType = 0;
|
|
|
|
|
uint32_t statusId = 0; // 0=none, 1=wait_queue, 2=wait_join, 3=in_progress
|
|
|
|
|
};
|
|
|
|
|
std::array<BgQueueSlot, 3> bgQueues_{};
|
|
|
|
|
|
|
|
|
|
// Instance difficulty
|
|
|
|
|
uint32_t instanceDifficulty_ = 0;
|
|
|
|
|
bool instanceIsHeroic_ = false;
|
|
|
|
|
|
2026-03-09 13:36:23 -07:00
|
|
|
// Instance / raid lockouts
|
|
|
|
|
std::vector<InstanceLockout> instanceLockouts_;
|
|
|
|
|
|
2026-03-09 13:30:23 -07:00
|
|
|
// LFG / Dungeon Finder state
|
|
|
|
|
LfgState lfgState_ = LfgState::None;
|
|
|
|
|
uint32_t lfgDungeonId_ = 0; // current dungeon entry
|
2026-03-09 13:47:07 -07:00
|
|
|
uint32_t lfgProposalId_ = 0; // pending proposal id (0 = none)
|
2026-03-09 13:30:23 -07:00
|
|
|
int32_t lfgAvgWaitSec_ = -1; // estimated wait, -1=unknown
|
|
|
|
|
uint32_t lfgTimeInQueueMs_= 0; // ms already in queue
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 4: Group ----
|
|
|
|
|
GroupListData partyData;
|
|
|
|
|
bool pendingGroupInvite = false;
|
|
|
|
|
std::string pendingInviterName;
|
|
|
|
|
|
2026-02-13 21:39:48 -08:00
|
|
|
// ---- Guild state ----
|
|
|
|
|
std::string guildName_;
|
|
|
|
|
std::vector<std::string> guildRankNames_;
|
|
|
|
|
GuildRosterData guildRoster_;
|
2026-02-25 14:44:44 -08:00
|
|
|
GuildInfoData guildInfoData_;
|
|
|
|
|
GuildQueryResponseData guildQueryData_;
|
2026-02-13 21:39:48 -08:00
|
|
|
bool hasGuildRoster_ = false;
|
|
|
|
|
bool pendingGuildInvite_ = false;
|
|
|
|
|
std::string pendingGuildInviterName_;
|
|
|
|
|
std::string pendingGuildInviteGuildName_;
|
2026-02-25 14:44:44 -08:00
|
|
|
bool showPetitionDialog_ = false;
|
|
|
|
|
uint32_t petitionCost_ = 0;
|
|
|
|
|
uint64_t petitionNpcGuid_ = 0;
|
2026-02-13 21:39:48 -08:00
|
|
|
|
2026-02-05 14:35:12 -08:00
|
|
|
uint64_t activeCharacterGuid_ = 0;
|
2026-02-08 03:05:38 -08:00
|
|
|
Race playerRace_ = Race::HUMAN;
|
2026-02-05 14:35:12 -08:00
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// ---- Phase 5: Loot ----
|
|
|
|
|
bool lootWindowOpen = false;
|
2026-02-17 16:31:00 -08:00
|
|
|
bool autoLoot_ = false;
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
LootResponseData currentLoot;
|
2026-02-05 14:01:26 -08:00
|
|
|
struct LocalLootState {
|
|
|
|
|
LootResponseData data;
|
|
|
|
|
bool moneyTaken = false;
|
|
|
|
|
};
|
|
|
|
|
std::unordered_map<uint64_t, LocalLootState> localLootState_;
|
2026-02-18 04:13:26 -08:00
|
|
|
struct PendingLootRetry {
|
|
|
|
|
uint64_t guid = 0;
|
|
|
|
|
float timer = 0.0f;
|
|
|
|
|
uint8_t remainingRetries = 0;
|
2026-02-20 19:51:04 -08:00
|
|
|
bool sendLoot = false;
|
2026-02-18 04:13:26 -08:00
|
|
|
};
|
|
|
|
|
std::vector<PendingLootRetry> pendingGameObjectLootRetries_;
|
2026-02-20 19:51:04 -08:00
|
|
|
struct PendingLootOpen {
|
|
|
|
|
uint64_t guid = 0;
|
|
|
|
|
float timer = 0.0f;
|
|
|
|
|
};
|
|
|
|
|
std::vector<PendingLootOpen> pendingGameObjectLootOpens_;
|
2026-02-18 04:11:00 -08:00
|
|
|
uint64_t pendingLootMoneyGuid_ = 0;
|
|
|
|
|
uint32_t pendingLootMoneyAmount_ = 0;
|
|
|
|
|
float pendingLootMoneyNotifyTimer_ = 0.0f;
|
|
|
|
|
std::unordered_map<uint64_t, float> recentLootMoneyAnnounceCooldowns_;
|
2026-02-05 14:01:26 -08:00
|
|
|
uint64_t playerMoneyCopper_ = 0;
|
2026-02-19 17:45:09 -08:00
|
|
|
int32_t playerArmorRating_ = 0;
|
2026-02-13 19:47:49 -08:00
|
|
|
// Some servers/custom clients shift update field indices. We can auto-detect coinage by correlating
|
|
|
|
|
// money-notify deltas with update-field diffs and then overriding UF::PLAYER_FIELD_COINAGE at runtime.
|
|
|
|
|
uint32_t pendingMoneyDelta_ = 0;
|
|
|
|
|
float pendingMoneyDeltaTimer_ = 0.0f;
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
|
|
|
|
// Gossip
|
|
|
|
|
bool gossipWindowOpen = false;
|
|
|
|
|
GossipMessageData currentGossip;
|
|
|
|
|
|
2026-02-19 03:31:49 -08:00
|
|
|
void performGameObjectInteractionNow(uint64_t guid);
|
|
|
|
|
|
2026-02-06 11:59:51 -08:00
|
|
|
// Quest details
|
|
|
|
|
bool questDetailsOpen = false;
|
|
|
|
|
QuestDetailsData currentQuestDetails;
|
|
|
|
|
|
2026-02-06 21:50:15 -08:00
|
|
|
// Quest turn-in
|
|
|
|
|
bool questRequestItemsOpen_ = false;
|
|
|
|
|
QuestRequestItemsData currentQuestRequestItems_;
|
2026-02-19 01:12:14 -08:00
|
|
|
uint32_t pendingTurnInQuestId_ = 0;
|
|
|
|
|
uint64_t pendingTurnInNpcGuid_ = 0;
|
|
|
|
|
bool pendingTurnInRewardRequest_ = false;
|
2026-02-20 17:14:13 -08:00
|
|
|
std::unordered_map<uint32_t, float> pendingQuestAcceptTimeouts_;
|
|
|
|
|
std::unordered_map<uint32_t, uint64_t> pendingQuestAcceptNpcGuids_;
|
2026-02-06 21:50:15 -08:00
|
|
|
bool questOfferRewardOpen_ = false;
|
|
|
|
|
QuestOfferRewardData currentQuestOfferReward_;
|
|
|
|
|
|
2026-02-06 13:47:03 -08:00
|
|
|
// Quest log
|
|
|
|
|
std::vector<QuestLogEntry> questLog_;
|
2026-02-19 00:30:21 -08:00
|
|
|
std::unordered_set<uint32_t> pendingQuestQueryIds_;
|
2026-02-20 17:14:13 -08:00
|
|
|
bool pendingLoginQuestResync_ = false;
|
|
|
|
|
float pendingLoginQuestResyncTimeout_ = 0.0f;
|
2026-02-06 13:47:03 -08:00
|
|
|
|
2026-02-06 20:10:10 -08:00
|
|
|
// Quest giver status per NPC
|
|
|
|
|
std::unordered_map<uint64_t, QuestGiverStatus> npcQuestStatus_;
|
|
|
|
|
|
2026-02-06 14:24:38 -08:00
|
|
|
// Faction hostility lookup (populated from FactionTemplate.dbc)
|
|
|
|
|
std::unordered_map<uint32_t, bool> factionHostileMap_;
|
|
|
|
|
bool isHostileFaction(uint32_t factionTemplateId) const {
|
|
|
|
|
auto it = factionHostileMap_.find(factionTemplateId);
|
|
|
|
|
return it != factionHostileMap_.end() ? it->second : true; // default hostile if unknown
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-07 16:59:20 -08:00
|
|
|
// Taxi / Flight Paths
|
|
|
|
|
std::unordered_map<uint32_t, TaxiNode> taxiNodes_;
|
|
|
|
|
std::vector<TaxiPathEdge> taxiPathEdges_;
|
2026-02-08 21:32:38 -08:00
|
|
|
std::unordered_map<uint32_t, std::vector<TaxiPathNode>> taxiPathNodes_; // pathId -> ordered waypoints
|
2026-02-07 16:59:20 -08:00
|
|
|
bool taxiDbcLoaded_ = false;
|
|
|
|
|
bool taxiWindowOpen_ = false;
|
|
|
|
|
ShowTaxiNodesData currentTaxiData_;
|
|
|
|
|
uint64_t taxiNpcGuid_ = 0;
|
|
|
|
|
bool onTaxiFlight_ = false;
|
2026-02-08 03:05:38 -08:00
|
|
|
bool taxiMountActive_ = false;
|
|
|
|
|
uint32_t taxiMountDisplayId_ = 0;
|
|
|
|
|
bool taxiActivatePending_ = false;
|
|
|
|
|
float taxiActivateTimer_ = 0.0f;
|
|
|
|
|
bool taxiClientActive_ = false;
|
2026-02-08 23:15:26 -08:00
|
|
|
float taxiLandingCooldown_ = 0.0f; // Prevent re-entering taxi right after landing
|
2026-02-11 21:14:35 -08:00
|
|
|
float taxiStartGrace_ = 0.0f; // Ignore transient landing/dismount checks right after takeoff
|
2026-02-08 03:05:38 -08:00
|
|
|
size_t taxiClientIndex_ = 0;
|
|
|
|
|
std::vector<glm::vec3> taxiClientPath_;
|
2026-02-11 18:25:04 -08:00
|
|
|
float taxiClientSpeed_ = 32.0f;
|
2026-02-08 03:05:38 -08:00
|
|
|
float taxiClientSegmentProgress_ = 0.0f;
|
|
|
|
|
bool taxiRecoverPending_ = false;
|
|
|
|
|
uint32_t taxiRecoverMapId_ = 0;
|
|
|
|
|
glm::vec3 taxiRecoverPos_{0.0f};
|
2026-02-07 17:59:40 -08:00
|
|
|
uint32_t knownTaxiMask_[12] = {}; // Track previously known nodes for discovery alerts
|
|
|
|
|
bool taxiMaskInitialized_ = false; // First SMSG_SHOWTAXINODES seeds mask without alerts
|
2026-02-07 19:04:15 -08:00
|
|
|
std::unordered_map<uint32_t, uint32_t> taxiCostMap_; // destNodeId -> total cost in copper
|
|
|
|
|
void buildTaxiCostMap();
|
2026-02-08 03:05:38 -08:00
|
|
|
void applyTaxiMountForCurrentNode();
|
2026-02-20 02:19:17 -08:00
|
|
|
uint32_t nextMovementTimestampMs();
|
2026-02-11 22:27:02 -08:00
|
|
|
void sanitizeMovementForTaxi();
|
2026-02-08 03:05:38 -08:00
|
|
|
void startClientTaxiPath(const std::vector<uint32_t>& pathNodes);
|
|
|
|
|
void updateClientTaxi(float deltaTime);
|
2026-02-07 16:59:20 -08:00
|
|
|
|
2026-02-15 14:00:41 -08:00
|
|
|
// Mail
|
|
|
|
|
bool mailboxOpen_ = false;
|
|
|
|
|
uint64_t mailboxGuid_ = 0;
|
|
|
|
|
std::vector<MailMessage> mailInbox_;
|
|
|
|
|
int selectedMailIndex_ = -1;
|
|
|
|
|
bool showMailCompose_ = false;
|
2026-02-16 18:46:44 -08:00
|
|
|
bool hasNewMail_ = false;
|
2026-02-25 14:11:09 -08:00
|
|
|
std::array<MailAttachSlot, MAIL_MAX_ATTACHMENTS> mailAttachments_{};
|
2026-02-15 14:00:41 -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
|
|
|
|
|
bool bankOpen_ = false;
|
|
|
|
|
uint64_t bankerGuid_ = 0;
|
|
|
|
|
std::array<uint64_t, 28> bankSlotGuids_{};
|
|
|
|
|
std::array<uint64_t, 7> bankBagSlotGuids_{};
|
2026-02-26 11:12:34 -08:00
|
|
|
int effectiveBankSlots_ = 28; // 24 for Classic, 28 for TBC/WotLK
|
|
|
|
|
int effectiveBankBagSlots_ = 7; // 6 for Classic, 7 for TBC/WotLK
|
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
|
|
|
|
|
|
|
|
// 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;
|
2026-02-25 14:44:44 -08:00
|
|
|
// Last search params for re-query (pagination, auto-refresh after bid/buyout)
|
|
|
|
|
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_;
|
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
|
|
|
// Routing: which result vector to populate from next SMSG_AUCTION_LIST_RESULT
|
|
|
|
|
enum class AuctionResultTarget { BROWSE, OWNER, BIDDER };
|
|
|
|
|
AuctionResultTarget pendingAuctionTarget_ = AuctionResultTarget::BROWSE;
|
|
|
|
|
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
// Vendor
|
|
|
|
|
bool vendorWindowOpen = false;
|
|
|
|
|
ListInventoryData currentVendorItems;
|
2026-02-19 05:28:13 -08:00
|
|
|
std::deque<BuybackItem> buybackItems_;
|
|
|
|
|
std::unordered_map<uint64_t, BuybackItem> pendingSellToBuyback_;
|
|
|
|
|
int pendingBuybackSlot_ = -1;
|
2026-02-19 05:48:40 -08:00
|
|
|
uint32_t pendingBuybackWireSlot_ = 0;
|
2026-02-19 05:28:13 -08:00
|
|
|
uint32_t pendingBuyItemId_ = 0;
|
|
|
|
|
uint32_t pendingBuyItemSlot_ = 0;
|
Add gameplay systems: combat, spells, groups, loot, vendors, and UI
Implement ~70 new protocol opcodes across 5 phases while maintaining
full 3.3.5a private server compatibility:
- Phase 1: Server-aware targeting (CMSG_SET_SELECTION), player/creature
name queries, CMSG_SET_ACTIVE_MOVER after login
- Phase 2: Auto-attack, melee/spell damage parsing, health/mana/power
tracking from UPDATE_OBJECT fields, floating combat text
- Phase 3: Spell casting, action bar (12 slots, keys 1-=), cast bar,
cooldown tracking, aura/buff system with cancellation
- Phase 4: Group invite/accept/decline/leave, party frames UI,
/invite chat command
- Phase 5: Loot window, NPC gossip dialog, vendor buy/sell interface
Also: disable debug HUD/panels by default, gate 3D rendering to
IN_GAME state only, fix window resize not updating UI positions.
2026-02-04 10:30:52 -08:00
|
|
|
|
2026-02-08 14:33:39 -08:00
|
|
|
// Trainer
|
|
|
|
|
bool trainerWindowOpen_ = false;
|
|
|
|
|
TrainerListData currentTrainerList_;
|
|
|
|
|
struct SpellNameEntry { std::string name; std::string rank; };
|
|
|
|
|
std::unordered_map<uint32_t, SpellNameEntry> spellNameCache_;
|
|
|
|
|
bool spellNameCacheLoaded_ = false;
|
2026-02-08 14:46:01 -08:00
|
|
|
std::vector<TrainerTab> trainerTabs_;
|
2026-02-08 14:33:39 -08:00
|
|
|
void handleTrainerList(network::Packet& packet);
|
|
|
|
|
void loadSpellNameCache();
|
2026-02-08 14:46:01 -08:00
|
|
|
void categorizeTrainerSpells();
|
2026-02-08 14:33:39 -08:00
|
|
|
|
2026-02-02 12:24:50 -08:00
|
|
|
// Callbacks
|
|
|
|
|
WorldConnectSuccessCallback onSuccess;
|
|
|
|
|
WorldConnectFailureCallback onFailure;
|
2026-02-05 14:13:48 -08:00
|
|
|
CharCreateCallback charCreateCallback_;
|
2026-02-06 03:24:46 -08:00
|
|
|
CharDeleteCallback charDeleteCallback_;
|
2026-02-17 13:59:29 -08:00
|
|
|
CharLoginFailCallback charLoginFailCallback_;
|
2026-02-06 18:34:45 -08:00
|
|
|
uint8_t lastCharDeleteResult_ = 0xFF;
|
2026-02-05 14:18:41 -08:00
|
|
|
bool pendingCharCreateResult_ = false;
|
|
|
|
|
bool pendingCharCreateSuccess_ = false;
|
|
|
|
|
std::string pendingCharCreateMsg_;
|
2026-02-12 02:09:15 -08:00
|
|
|
bool requiresWarden_ = false;
|
|
|
|
|
bool wardenGateSeen_ = false;
|
|
|
|
|
float wardenGateElapsed_ = 0.0f;
|
|
|
|
|
float wardenGateNextStatusLog_ = 2.0f;
|
|
|
|
|
uint32_t wardenPacketsAfterGate_ = 0;
|
|
|
|
|
bool wardenCharEnumBlockedLogged_ = false;
|
|
|
|
|
std::unique_ptr<WardenCrypto> wardenCrypto_;
|
2026-02-14 02:00:15 -08:00
|
|
|
std::unique_ptr<WardenMemory> wardenMemory_;
|
2026-02-12 02:43:20 -08:00
|
|
|
std::unique_ptr<WardenModuleManager> wardenModuleManager_;
|
2026-02-05 12:01:03 -08:00
|
|
|
|
2026-02-13 16:53:28 -08:00
|
|
|
// Warden module download state
|
|
|
|
|
enum class WardenState {
|
|
|
|
|
WAIT_MODULE_USE, // Waiting for first SMSG (MODULE_USE)
|
|
|
|
|
WAIT_MODULE_CACHE, // Sent MODULE_MISSING, receiving module chunks
|
|
|
|
|
WAIT_HASH_REQUEST, // Module received, waiting for HASH_REQUEST
|
|
|
|
|
WAIT_CHECKS, // Hash sent, waiting for check requests
|
|
|
|
|
};
|
|
|
|
|
WardenState wardenState_ = WardenState::WAIT_MODULE_USE;
|
|
|
|
|
std::vector<uint8_t> wardenModuleHash_; // 16 bytes MD5
|
|
|
|
|
std::vector<uint8_t> wardenModuleKey_; // 16 bytes RC4
|
|
|
|
|
uint32_t wardenModuleSize_ = 0;
|
|
|
|
|
std::vector<uint8_t> wardenModuleData_; // Downloaded module chunks
|
2026-02-13 18:59:09 -08:00
|
|
|
std::vector<uint8_t> wardenLoadedModuleImage_; // Parsed module image for key derivation
|
2026-02-14 19:20:32 -08:00
|
|
|
std::shared_ptr<WardenModule> wardenLoadedModule_; // Loaded Warden module
|
2026-02-13 18:59:09 -08:00
|
|
|
|
|
|
|
|
// Pre-computed challenge/response entries from .cr file
|
|
|
|
|
struct WardenCREntry {
|
|
|
|
|
uint8_t seed[16];
|
|
|
|
|
uint8_t reply[20];
|
|
|
|
|
uint8_t clientKey[16]; // Encrypt key (client→server)
|
|
|
|
|
uint8_t serverKey[16]; // Decrypt key (server→client)
|
|
|
|
|
};
|
|
|
|
|
std::vector<WardenCREntry> wardenCREntries_;
|
|
|
|
|
// Module-specific check type opcodes [9]: MEM, PAGE_A, PAGE_B, MPQ, LUA, DRIVER, TIMING, PROC, MODULE
|
|
|
|
|
uint8_t wardenCheckOpcodes_[9] = {};
|
|
|
|
|
bool loadWardenCRFile(const std::string& moduleHashHex);
|
2026-02-13 16:53:28 -08:00
|
|
|
|
2026-02-05 12:07:58 -08:00
|
|
|
// ---- XP tracking ----
|
|
|
|
|
uint32_t playerXp_ = 0;
|
|
|
|
|
uint32_t playerNextLevelXp_ = 0;
|
|
|
|
|
uint32_t serverPlayerLevel_ = 1;
|
|
|
|
|
static uint32_t xpForLevel(uint32_t level);
|
|
|
|
|
|
2026-02-10 19:30:45 -08:00
|
|
|
// ---- Server time tracking (for deterministic celestial/sky systems) ----
|
|
|
|
|
float gameTime_ = 0.0f; // Server game time in seconds
|
|
|
|
|
float timeSpeed_ = 0.0166f; // Time scale (default: 1 game day = 1 real hour)
|
|
|
|
|
void handleLoginSetTimeSpeed(network::Packet& packet);
|
|
|
|
|
|
2026-02-17 17:59:41 -08:00
|
|
|
// ---- Weather state (SMSG_WEATHER) ----
|
|
|
|
|
uint32_t weatherType_ = 0; // 0=clear, 1=rain, 2=snow, 3=storm
|
|
|
|
|
float weatherIntensity_ = 0.0f; // 0.0 to 1.0
|
|
|
|
|
|
2026-02-07 14:21:50 -08:00
|
|
|
// ---- Player skills ----
|
|
|
|
|
std::map<uint32_t, PlayerSkill> playerSkills_;
|
|
|
|
|
std::unordered_map<uint32_t, std::string> skillLineNames_;
|
|
|
|
|
std::unordered_map<uint32_t, uint32_t> skillLineCategories_;
|
2026-02-08 14:46:01 -08:00
|
|
|
std::unordered_map<uint32_t, uint32_t> spellToSkillLine_; // spellID -> skillLineID
|
2026-02-07 14:21:50 -08:00
|
|
|
bool skillLineDbcLoaded_ = false;
|
2026-02-08 14:46:01 -08:00
|
|
|
bool skillLineAbilityLoaded_ = false;
|
2026-02-11 18:25:04 -08:00
|
|
|
static constexpr size_t PLAYER_EXPLORED_ZONES_COUNT = 128;
|
|
|
|
|
std::vector<uint32_t> playerExploredZones_ =
|
|
|
|
|
std::vector<uint32_t>(PLAYER_EXPLORED_ZONES_COUNT, 0u);
|
|
|
|
|
bool hasPlayerExploredZones_ = false;
|
2026-02-07 14:21:50 -08:00
|
|
|
void loadSkillLineDbc();
|
2026-02-08 14:46:01 -08:00
|
|
|
void loadSkillLineAbilityDbc();
|
2026-02-07 14:21:50 -08:00
|
|
|
void extractSkillFields(const std::map<uint16_t, uint32_t>& fields);
|
2026-02-11 18:25:04 -08:00
|
|
|
void extractExploredZoneFields(const std::map<uint16_t, uint32_t>& fields);
|
2026-02-07 14:21:50 -08:00
|
|
|
|
2026-02-07 00:00:06 -08:00
|
|
|
NpcDeathCallback npcDeathCallback_;
|
Add comprehensive NPC voice system with interaction and combat sounds
Implements full NPC voice interaction system supporting 6 different sound categories
for all playable races/genders. System loads ~450+ voice clips from MPQ archives.
Voice Categories:
- Greeting: Play on NPC right-click interaction
- Farewell: Play when closing gossip/dialog windows
- Vendor: Play when opening merchant/vendor windows
- Pissed: Play after clicking NPC 5+ times (spam protection)
- Aggro: Play when NPC enters combat with player
- Flee: Play when NPC is fleeing (ready for low-health triggers)
Features:
- Race/gender detection from NPC display IDs via CreatureDisplayInfoExtra.dbc
- Intelligent click tracking for pissed sounds
- Combat sounds use player character vocal files for humanoid NPCs
- Cooldown system prevents voice spam (2s default, combat sounds bypass)
- Generic fallback voices for unsupported NPC types
- 3D positional audio support
Voice Support:
- All playable races: Human, Dwarf, Gnome, Night Elf, Orc, Tauren, Troll, Undead
- Male and female variants for each race
- StandardNPC sounds for social interactions
- Character vocal sounds for combat
Technical Changes:
- Refactored NpcVoiceManager to support multiple sound categories
- Added callbacks: NpcFarewell, NpcVendor, NpcAggro
- Extended voice loading to parse both StandardNPC and Character vocal paths
- Integrated with GameHandler for gossip, vendor, and combat events
- Added detailed voice detection logging for debugging
Also includes:
- Sound manifest files added to docs/ for reference
- Blacksmith hammer pitch increased to 1.6x (was 1.4x)
- Blacksmith volume reduced 30% to 0.25 (was 0.35)
2026-02-09 16:03:51 -08:00
|
|
|
NpcAggroCallback npcAggroCallback_;
|
2026-02-07 00:00:06 -08:00
|
|
|
NpcRespawnCallback npcRespawnCallback_;
|
2026-02-05 14:01:26 -08:00
|
|
|
MeleeSwingCallback meleeSwingCallback_;
|
2026-02-07 00:00:06 -08:00
|
|
|
NpcSwingCallback npcSwingCallback_;
|
2026-02-09 01:29:44 -08:00
|
|
|
NpcGreetingCallback npcGreetingCallback_;
|
Add comprehensive NPC voice system with interaction and combat sounds
Implements full NPC voice interaction system supporting 6 different sound categories
for all playable races/genders. System loads ~450+ voice clips from MPQ archives.
Voice Categories:
- Greeting: Play on NPC right-click interaction
- Farewell: Play when closing gossip/dialog windows
- Vendor: Play when opening merchant/vendor windows
- Pissed: Play after clicking NPC 5+ times (spam protection)
- Aggro: Play when NPC enters combat with player
- Flee: Play when NPC is fleeing (ready for low-health triggers)
Features:
- Race/gender detection from NPC display IDs via CreatureDisplayInfoExtra.dbc
- Intelligent click tracking for pissed sounds
- Combat sounds use player character vocal files for humanoid NPCs
- Cooldown system prevents voice spam (2s default, combat sounds bypass)
- Generic fallback voices for unsupported NPC types
- 3D positional audio support
Voice Support:
- All playable races: Human, Dwarf, Gnome, Night Elf, Orc, Tauren, Troll, Undead
- Male and female variants for each race
- StandardNPC sounds for social interactions
- Character vocal sounds for combat
Technical Changes:
- Refactored NpcVoiceManager to support multiple sound categories
- Added callbacks: NpcFarewell, NpcVendor, NpcAggro
- Extended voice loading to parse both StandardNPC and Character vocal paths
- Integrated with GameHandler for gossip, vendor, and combat events
- Added detailed voice detection logging for debugging
Also includes:
- Sound manifest files added to docs/ for reference
- Blacksmith hammer pitch increased to 1.6x (was 1.4x)
- Blacksmith volume reduced 30% to 0.25 (was 0.35)
2026-02-09 16:03:51 -08:00
|
|
|
NpcFarewellCallback npcFarewellCallback_;
|
|
|
|
|
NpcVendorCallback npcVendorCallback_;
|
2026-02-19 21:13:13 -08:00
|
|
|
ChargeCallback chargeCallback_;
|
2026-02-17 17:23:42 -08:00
|
|
|
LevelUpCallback levelUpCallback_;
|
2026-02-19 20:36:25 -08:00
|
|
|
OtherPlayerLevelUpCallback otherPlayerLevelUpCallback_;
|
2026-03-09 13:53:42 -07:00
|
|
|
AchievementEarnedCallback achievementEarnedCallback_;
|
2026-02-07 17:59:40 -08:00
|
|
|
MountCallback mountCallback_;
|
2026-02-08 21:32:38 -08:00
|
|
|
TaxiPrecacheCallback taxiPrecacheCallback_;
|
2026-02-08 22:00:33 -08:00
|
|
|
TaxiOrientationCallback taxiOrientationCallback_;
|
|
|
|
|
TaxiFlightStartCallback taxiFlightStartCallback_;
|
2026-02-07 17:59:40 -08:00
|
|
|
uint32_t currentMountDisplayId_ = 0;
|
2026-02-14 16:42:47 -08:00
|
|
|
uint32_t mountAuraSpellId_ = 0; // Spell ID of the aura that caused mounting (for CMSG_CANCEL_AURA fallback)
|
2026-02-07 17:59:40 -08:00
|
|
|
float serverRunSpeed_ = 7.0f;
|
Add missing movement ACK responses to avoid server stalls
Implement generic handlers for force speed changes (walk, run back,
swim, swim back, flight, flight back, turn rate, pitch rate),
movement flag toggles (CAN_FLY, HOVER, feather fall, water walk),
and knockback ACKs. Fix SMSG_TIME_SYNC_REQ to respond with
CMSG_TIME_SYNC_RESP instead of silently dropping.
2026-02-26 03:02:51 -08:00
|
|
|
float serverWalkSpeed_ = 2.5f;
|
|
|
|
|
float serverRunBackSpeed_ = 4.5f;
|
|
|
|
|
float serverSwimSpeed_ = 4.722f;
|
|
|
|
|
float serverSwimBackSpeed_ = 2.5f;
|
|
|
|
|
float serverFlightSpeed_ = 7.0f;
|
|
|
|
|
float serverFlightBackSpeed_ = 4.5f;
|
|
|
|
|
float serverTurnRate_ = 3.14159f;
|
|
|
|
|
float serverPitchRate_ = 3.14159f;
|
2026-02-06 17:27:20 -08:00
|
|
|
bool playerDead_ = false;
|
2026-02-07 23:12:24 -08:00
|
|
|
bool releasedSpirit_ = false;
|
2026-02-07 21:47:14 -08:00
|
|
|
uint64_t pendingSpiritHealerGuid_ = 0;
|
|
|
|
|
bool resurrectPending_ = false;
|
2026-02-07 23:12:24 -08:00
|
|
|
bool resurrectRequestPending_ = false;
|
|
|
|
|
uint64_t resurrectCasterGuid_ = 0;
|
2026-02-07 21:47:14 -08:00
|
|
|
bool repopPending_ = false;
|
|
|
|
|
uint64_t lastRepopRequestMs_ = 0;
|
2026-02-02 12:24:50 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace game
|
|
|
|
|
} // namespace wowee
|