mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 01:23:51 +00: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.
This commit is contained in:
parent
6bf3fa4ed4
commit
c49bb58e47
14 changed files with 3039 additions and 84 deletions
|
|
@ -3,11 +3,16 @@
|
|||
#include "game/world_packets.hpp"
|
||||
#include "game/character.hpp"
|
||||
#include "game/inventory.hpp"
|
||||
#include "game/spell_defines.hpp"
|
||||
#include "game/group_defines.hpp"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace wowee {
|
||||
namespace network { class WorldSocket; class Packet; }
|
||||
|
|
@ -165,6 +170,77 @@ public:
|
|||
bool hasTarget() const { return targetGuid != 0; }
|
||||
void tabTarget(float playerX, float playerY, float playerZ);
|
||||
|
||||
// ---- Phase 1: Name queries ----
|
||||
void queryPlayerName(uint64_t guid);
|
||||
void queryCreatureInfo(uint32_t entry, uint64_t guid);
|
||||
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; }
|
||||
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);
|
||||
const std::vector<uint32_t>& getKnownSpells() const { return knownSpells; }
|
||||
bool isCasting() const { return casting; }
|
||||
uint32_t getCurrentCastSpellId() const { return currentCastSpellId; }
|
||||
float getCastProgress() const { return castTimeTotal > 0 ? (castTimeTotal - castTimeRemaining) / castTimeTotal : 0.0f; }
|
||||
float getCastTimeRemaining() const { return castTimeRemaining; }
|
||||
|
||||
// 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);
|
||||
|
||||
// Auras
|
||||
const std::vector<AuraSlot>& getPlayerAuras() const { return playerAuras; }
|
||||
const std::vector<AuraSlot>& getTargetAuras() const { return targetAuras; }
|
||||
|
||||
// Cooldowns
|
||||
float getSpellCooldown(uint32_t spellId) const;
|
||||
|
||||
// Player GUID
|
||||
uint64_t getPlayerGuid() const { return playerGuid; }
|
||||
void setPlayerGuid(uint64_t guid) { playerGuid = guid; }
|
||||
|
||||
// ---- 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; }
|
||||
|
||||
// ---- Phase 5: Loot ----
|
||||
void lootTarget(uint64_t guid);
|
||||
void lootItem(uint8_t slotIndex);
|
||||
void closeLoot();
|
||||
bool isLootWindowOpen() const { return lootWindowOpen; }
|
||||
const LootResponseData& getCurrentLoot() const { return currentLoot; }
|
||||
|
||||
// NPC Gossip
|
||||
void interactWithNpc(uint64_t guid);
|
||||
void selectGossipOption(uint32_t optionId);
|
||||
void closeGossip();
|
||||
bool isGossipWindowOpen() const { return gossipWindowOpen; }
|
||||
const GossipMessageData& getCurrentGossip() const { return currentGossip; }
|
||||
|
||||
// Vendor
|
||||
void openVendor(uint64_t npcGuid);
|
||||
void buyItem(uint64_t vendorGuid, uint32_t itemId, uint32_t slot, uint8_t count);
|
||||
void sellItem(uint64_t vendorGuid, uint64_t itemGuid, uint8_t count);
|
||||
bool isVendorWindowOpen() const { return vendorWindowOpen; }
|
||||
const ListInventoryData& getVendorItems() const { return currentVendorItems; }
|
||||
|
||||
/**
|
||||
* Set callbacks
|
||||
*/
|
||||
|
|
@ -234,6 +310,45 @@ private:
|
|||
*/
|
||||
void handleMessageChat(network::Packet& packet);
|
||||
|
||||
// ---- Phase 1 handlers ----
|
||||
void handleNameQueryResponse(network::Packet& packet);
|
||||
void handleCreatureQueryResponse(network::Packet& packet);
|
||||
|
||||
// ---- 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);
|
||||
void handleAuraUpdate(network::Packet& packet, bool isAll);
|
||||
void handleLearnedSpell(network::Packet& packet);
|
||||
void handleRemovedSpell(network::Packet& packet);
|
||||
|
||||
// ---- 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);
|
||||
|
||||
// ---- Phase 5 handlers ----
|
||||
void handleLootResponse(network::Packet& packet);
|
||||
void handleLootReleaseResponse(network::Packet& packet);
|
||||
void handleLootRemoved(network::Packet& packet);
|
||||
void handleGossipMessage(network::Packet& packet);
|
||||
void handleGossipComplete(network::Packet& packet);
|
||||
void handleListInventory(network::Packet& packet);
|
||||
|
||||
void addCombatText(CombatTextEntry::Type type, int32_t amount, uint32_t spellId, bool isPlayerSource);
|
||||
|
||||
/**
|
||||
* Send CMSG_PING to server (heartbeat)
|
||||
*/
|
||||
|
|
@ -301,6 +416,49 @@ private:
|
|||
float pingInterval = 30.0f; // Ping interval (30 seconds)
|
||||
uint32_t lastLatency = 0; // Last measured latency (milliseconds)
|
||||
|
||||
// Player GUID
|
||||
uint64_t playerGuid = 0;
|
||||
|
||||
// ---- 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;
|
||||
|
||||
// ---- Phase 2: Combat ----
|
||||
bool autoAttacking = false;
|
||||
uint64_t autoAttackTarget = 0;
|
||||
std::vector<CombatTextEntry> combatText;
|
||||
|
||||
// ---- Phase 3: Spells ----
|
||||
std::vector<uint32_t> knownSpells;
|
||||
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;
|
||||
float castTimeTotal = 0.0f;
|
||||
std::array<ActionBarSlot, 12> actionBar{};
|
||||
std::vector<AuraSlot> playerAuras;
|
||||
std::vector<AuraSlot> targetAuras;
|
||||
|
||||
// ---- Phase 4: Group ----
|
||||
GroupListData partyData;
|
||||
bool pendingGroupInvite = false;
|
||||
std::string pendingInviterName;
|
||||
|
||||
// ---- Phase 5: Loot ----
|
||||
bool lootWindowOpen = false;
|
||||
LootResponseData currentLoot;
|
||||
|
||||
// Gossip
|
||||
bool gossipWindowOpen = false;
|
||||
GossipMessageData currentGossip;
|
||||
|
||||
// Vendor
|
||||
bool vendorWindowOpen = false;
|
||||
ListInventoryData currentVendorItems;
|
||||
|
||||
// Callbacks
|
||||
WorldConnectSuccessCallback onSuccess;
|
||||
WorldConnectFailureCallback onFailure;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue