mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-04 08:23:50 +00:00
Merge pull request #33 from ldmonster/chore/game-screen-extract
[chore] refactor(ui): GameScreen — extract 7 UI sub-panels
This commit is contained in:
commit
9eb8ca2988
24 changed files with 20568 additions and 19417 deletions
|
|
@ -616,6 +616,14 @@ set(WOWEE_SOURCES
|
|||
src/ui/character_create_screen.cpp
|
||||
src/ui/character_screen.cpp
|
||||
src/ui/game_screen.cpp
|
||||
src/ui/chat_panel.cpp
|
||||
src/ui/toast_manager.cpp
|
||||
src/ui/dialog_manager.cpp
|
||||
src/ui/settings_panel.cpp
|
||||
src/ui/combat_ui.cpp
|
||||
src/ui/social_panel.cpp
|
||||
src/ui/action_bar_panel.cpp
|
||||
src/ui/window_manager.cpp
|
||||
src/ui/inventory_screen.cpp
|
||||
src/ui/quest_log_screen.cpp
|
||||
src/ui/spellbook_screen.cpp
|
||||
|
|
|
|||
|
|
@ -143,28 +143,25 @@ private:
|
|||
void applyUpdateObjectBlock(const UpdateBlock& block, bool& newItemCreated);
|
||||
void finalizeUpdateObjectBatch(bool newItemCreated);
|
||||
|
||||
// --- Phase 1: Extracted helper methods ---
|
||||
bool extractPlayerAppearance(const std::map<uint16_t, uint32_t>& fields,
|
||||
uint8_t& outRace, uint8_t& outGender,
|
||||
uint32_t& outAppearanceBytes, uint8_t& outFacial) const;
|
||||
void maybeDetectCoinageIndex(const std::map<uint16_t, uint32_t>& oldFields,
|
||||
const std::map<uint16_t, uint32_t>& newFields);
|
||||
|
||||
// --- Phase 2: Update type handlers ---
|
||||
void handleCreateObject(const UpdateBlock& block, bool& newItemCreated);
|
||||
void handleValuesUpdate(const UpdateBlock& block);
|
||||
void handleMovementUpdate(const UpdateBlock& block);
|
||||
|
||||
// --- Phase 3: Concern-specific helpers ---
|
||||
// 3i: Update transport-relative child attachment (non-player entities).
|
||||
// Update transport-relative child attachment (non-player entities).
|
||||
// Consolidates identical logic from CREATE/VALUES/MOVEMENT handlers.
|
||||
void updateNonPlayerTransportAttachment(const UpdateBlock& block,
|
||||
const std::shared_ptr<Entity>& entity,
|
||||
ObjectType entityType);
|
||||
// 3f: Rebuild playerAuras_ from UNIT_FIELD_AURAS (Classic/vanilla only).
|
||||
// Rebuild playerAuras_ from UNIT_FIELD_AURAS (Classic/vanilla only).
|
||||
// Consolidates identical logic from CREATE and VALUES handlers.
|
||||
void syncClassicAurasFromFields(const std::shared_ptr<Entity>& entity);
|
||||
// 3h: Detect mount/dismount from UNIT_FIELD_MOUNTDISPLAYID changes (self-player only).
|
||||
// Detect mount/dismount from UNIT_FIELD_MOUNTDISPLAYID changes (self-player only).
|
||||
// Consolidates identical logic from CREATE and VALUES handlers.
|
||||
void detectPlayerMountChange(uint32_t newMountDisplayId,
|
||||
const std::map<uint16_t, uint32_t>& blockFields);
|
||||
|
|
@ -172,7 +169,6 @@ private:
|
|||
// Shared player-death handler: caches corpse position, sets death state.
|
||||
void markPlayerDead(const char* source);
|
||||
|
||||
// --- Phase 4: Field index cache structs ---
|
||||
// Cached field indices resolved once per handler call to avoid repeated lookups.
|
||||
struct UnitFieldIndices {
|
||||
uint16_t health, maxHealth, powerBase, maxPowerBase;
|
||||
|
|
@ -202,43 +198,42 @@ private:
|
|||
uint32_t oldDisplayId = 0;
|
||||
};
|
||||
|
||||
// --- Phase 3: Extracted concern-specific helpers (continued) ---
|
||||
// 3a: Entity factory — creates the correct Entity subclass for the given block.
|
||||
// Entity factory — creates the correct Entity subclass for the given block.
|
||||
std::shared_ptr<Entity> createEntityFromBlock(const UpdateBlock& block);
|
||||
// 3b: Track player-on-transport state from movement blocks.
|
||||
// Track player-on-transport state from movement blocks.
|
||||
void applyPlayerTransportState(const UpdateBlock& block,
|
||||
const std::shared_ptr<Entity>& entity,
|
||||
const glm::vec3& canonicalPos, float oCanonical,
|
||||
bool updateMovementInfoPos);
|
||||
// 3c: Apply unit fields during CREATE — returns true if entity is initially dead.
|
||||
// Apply unit fields during CREATE — returns true if entity is initially dead.
|
||||
bool applyUnitFieldsOnCreate(const UpdateBlock& block,
|
||||
std::shared_ptr<Unit>& unit,
|
||||
const UnitFieldIndices& ufi);
|
||||
// 3c: Apply unit fields during VALUES — returns change tracking result.
|
||||
// Apply unit fields during VALUES — returns change tracking result.
|
||||
UnitFieldUpdateResult applyUnitFieldsOnUpdate(const UpdateBlock& block,
|
||||
const std::shared_ptr<Entity>& entity,
|
||||
std::shared_ptr<Unit>& unit,
|
||||
const UnitFieldIndices& ufi);
|
||||
// 3d: Apply player stat fields (XP, inventory, skills, etc.). isCreate=true for CREATE path.
|
||||
// Apply player stat fields (XP, inventory, skills, etc.). isCreate=true for CREATE path.
|
||||
bool applyPlayerStatFields(const std::map<uint16_t, uint32_t>& fields,
|
||||
const PlayerFieldIndices& pfi, bool isCreate);
|
||||
// 3e: Dispatch spawn callbacks (creature/player) — deduplicates CREATE and VALUES paths.
|
||||
// Dispatch spawn callbacks (creature/player) — deduplicates CREATE and VALUES paths.
|
||||
void dispatchEntitySpawn(uint64_t guid, ObjectType objectType,
|
||||
const std::shared_ptr<Entity>& entity,
|
||||
const std::shared_ptr<Unit>& unit, bool isDead);
|
||||
// 3g: Track item/container on CREATE.
|
||||
// Track item/container on CREATE.
|
||||
void trackItemOnCreate(const UpdateBlock& block, bool& newItemCreated);
|
||||
// 3g: Update item fields on VALUES update.
|
||||
// Update item fields on VALUES update.
|
||||
void updateItemOnValuesUpdate(const UpdateBlock& block,
|
||||
const std::shared_ptr<Entity>& entity);
|
||||
|
||||
// --- Phase 5: Strategy pattern — object-type handler interface ---
|
||||
// Allows extending object-type handling without modifying handler dispatch.
|
||||
struct IObjectTypeHandler {
|
||||
virtual ~IObjectTypeHandler() = default;
|
||||
virtual void onCreate(const UpdateBlock&, std::shared_ptr<Entity>&, bool&) {}
|
||||
virtual void onValuesUpdate(const UpdateBlock&, std::shared_ptr<Entity>&) {}
|
||||
virtual void onMovementUpdate(const UpdateBlock&, std::shared_ptr<Entity>&) {}
|
||||
virtual void onCreate(const UpdateBlock& /*block*/, std::shared_ptr<Entity>& /*entity*/,
|
||||
bool& /*newItemCreated*/) {}
|
||||
virtual void onValuesUpdate(const UpdateBlock& /*block*/, std::shared_ptr<Entity>& /*entity*/) {}
|
||||
virtual void onMovementUpdate(const UpdateBlock& /*block*/, std::shared_ptr<Entity>& /*entity*/) {}
|
||||
};
|
||||
struct UnitTypeHandler;
|
||||
struct PlayerTypeHandler;
|
||||
|
|
@ -249,7 +244,6 @@ private:
|
|||
void initTypeHandlers();
|
||||
IObjectTypeHandler* getTypeHandler(ObjectType type) const;
|
||||
|
||||
// --- Phase 5: Type-specific handler implementations (trampolined from handlers) ---
|
||||
void onCreateUnit(const UpdateBlock& block, std::shared_ptr<Entity>& entity);
|
||||
void onCreatePlayer(const UpdateBlock& block, std::shared_ptr<Entity>& entity);
|
||||
void onCreateGameObject(const UpdateBlock& block, std::shared_ptr<Entity>& entity);
|
||||
|
|
@ -264,7 +258,6 @@ private:
|
|||
void onValuesUpdateItem(const UpdateBlock& block, std::shared_ptr<Entity>& entity);
|
||||
void onValuesUpdateGameObject(const UpdateBlock& block, std::shared_ptr<Entity>& entity);
|
||||
|
||||
// --- Phase 6: Deferred event bus ---
|
||||
// Collects addon events during block processing, flushes at the end.
|
||||
struct PendingEvents {
|
||||
std::vector<std::pair<std::string, std::vector<std::string>>> events;
|
||||
|
|
|
|||
|
|
@ -627,7 +627,6 @@ public:
|
|||
void resetWardenState(); // clear all warden module/crypto state for connect/disconnect
|
||||
void clearUnitCaches(); // clear per-unit cast states and aura caches
|
||||
|
||||
// ---- Phase 1: Name queries (delegated to EntityController) ----
|
||||
void queryPlayerName(uint64_t guid);
|
||||
void queryCreatureInfo(uint32_t entry, uint64_t guid);
|
||||
void queryGameObjectInfo(uint32_t entry, uint64_t guid);
|
||||
|
|
@ -661,7 +660,6 @@ public:
|
|||
return entityController_->getCreatureFamily(entry);
|
||||
}
|
||||
|
||||
// ---- Phase 2: Combat (delegated to CombatHandler) ----
|
||||
void startAutoAttack(uint64_t targetGuid);
|
||||
void stopAutoAttack();
|
||||
bool isAutoAttacking() const;
|
||||
|
|
@ -696,7 +694,6 @@ public:
|
|||
const std::vector<ThreatEntry>* getThreatList(uint64_t unitGuid) const;
|
||||
const std::vector<ThreatEntry>* getTargetThreatList() const;
|
||||
|
||||
// ---- Phase 3: Spells ----
|
||||
void castSpell(uint32_t spellId, uint64_t targetGuid = 0);
|
||||
void cancelCast();
|
||||
void cancelAura(uint32_t spellId);
|
||||
|
|
@ -1239,7 +1236,7 @@ public:
|
|||
void acceptResurrect();
|
||||
void declineResurrect();
|
||||
|
||||
// ---- Phase 4: Group ----
|
||||
// ---- Group ----
|
||||
void inviteToGroup(const std::string& playerName);
|
||||
void acceptGroupInvite();
|
||||
void declineGroupInvite();
|
||||
|
|
@ -1396,7 +1393,7 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// ---- Phase 5: Loot ----
|
||||
// ---- Loot ----
|
||||
void lootTarget(uint64_t guid);
|
||||
void lootItem(uint8_t slotIndex);
|
||||
void closeLoot();
|
||||
|
|
@ -2177,7 +2174,6 @@ private:
|
|||
*/
|
||||
void handlePong(network::Packet& packet);
|
||||
|
||||
// ---- Phase 1 handlers (entity queries delegated to EntityController) ----
|
||||
void handleItemQueryResponse(network::Packet& packet);
|
||||
void queryItemInfo(uint32_t entry, uint64_t guid);
|
||||
void rebuildOnlineInventory();
|
||||
|
|
@ -2190,7 +2186,6 @@ private:
|
|||
void extractContainerFields(uint64_t containerGuid, const std::map<uint16_t, uint32_t>& fields);
|
||||
uint64_t resolveOnlineItemGuid(uint32_t itemId) const;
|
||||
|
||||
// ---- Phase 2 handlers (dead — dispatched via CombatHandler) ----
|
||||
// handleAttackStart, handleAttackStop, handleAttackerStateUpdate,
|
||||
// handleSpellDamageLog, handleSpellHealLog removed
|
||||
|
||||
|
|
@ -2198,12 +2193,6 @@ private:
|
|||
void handleUpdateAuraDuration(uint8_t slot, uint32_t durationMs);
|
||||
// handleSetForcedReactions — dispatched via CombatHandler
|
||||
|
||||
// ---- Phase 3 handlers ----
|
||||
|
||||
// ---- Talent handlers ----
|
||||
|
||||
// ---- Phase 4 handlers ----
|
||||
|
||||
// ---- Guild handlers ----
|
||||
void handlePetSpells(network::Packet& packet);
|
||||
|
||||
|
|
@ -2217,7 +2206,6 @@ private:
|
|||
|
||||
// ---- Other player movement (MSG_MOVE_* from server) ----
|
||||
|
||||
// ---- Phase 5 handlers ----
|
||||
void clearPendingQuestAccept(uint32_t questId);
|
||||
void triggerQuestAcceptResync(uint32_t questId, uint64_t npcGuid, const char* reason);
|
||||
bool hasQuestInLog(uint32_t questId) const;
|
||||
|
|
@ -2411,7 +2399,6 @@ private:
|
|||
uint32_t homeBindZoneId_ = 0;
|
||||
glm::vec3 homeBindPos_{0.0f};
|
||||
|
||||
// ---- Phase 1: Name caches (moved to EntityController) ----
|
||||
|
||||
// ---- Friend/contact list cache ----
|
||||
std::unordered_map<std::string, uint64_t> friendsCache; // name -> guid
|
||||
|
|
@ -2510,11 +2497,10 @@ private:
|
|||
std::unordered_set<uint64_t> pendingAutoInspect_;
|
||||
float inspectRateLimit_ = 0.0f;
|
||||
|
||||
// ---- Phase 2: Combat (state moved to CombatHandler) ----
|
||||
// ---- Combat ----
|
||||
bool wasCombat_ = false; // Previous frame combat state for PLAYER_REGEN edge detection
|
||||
std::deque<std::string> areaTriggerMsgs_;
|
||||
|
||||
// ---- Phase 3: Spells ----
|
||||
WorldEntryCallback worldEntryCallback_;
|
||||
KnockBackCallback knockBackCallback_;
|
||||
CameraShakeCallback cameraShakeCallback_;
|
||||
|
|
@ -2674,7 +2660,7 @@ private:
|
|||
void loadFactionNameCache() const;
|
||||
std::string getFactionName(uint32_t factionId) const;
|
||||
|
||||
// ---- Phase 4: Group ----
|
||||
// ---- Group ----
|
||||
GroupListData partyData;
|
||||
bool pendingGroupInvite = false;
|
||||
std::string pendingInviterName;
|
||||
|
|
@ -2745,7 +2731,7 @@ private:
|
|||
// Barber shop
|
||||
bool barberShopOpen_ = false;
|
||||
|
||||
// ---- Phase 5: Loot ----
|
||||
// ---- Loot ----
|
||||
bool lootWindowOpen = false;
|
||||
bool autoLoot_ = false;
|
||||
bool autoSellGrey_ = false;
|
||||
|
|
|
|||
|
|
@ -1460,7 +1460,7 @@ public:
|
|||
};
|
||||
|
||||
// ============================================================
|
||||
// Phase 1: Foundation — Targeting, Name Queries
|
||||
// Foundation — Targeting, Name Queries
|
||||
// ============================================================
|
||||
|
||||
/** CMSG_SET_SELECTION packet builder */
|
||||
|
|
@ -1663,7 +1663,7 @@ public:
|
|||
};
|
||||
|
||||
// ============================================================
|
||||
// Phase 2: Combat Core
|
||||
// Combat Core
|
||||
// ============================================================
|
||||
|
||||
/** SMSG_MONSTER_MOVE data */
|
||||
|
|
@ -1805,7 +1805,7 @@ public:
|
|||
};
|
||||
|
||||
// ============================================================
|
||||
// Phase 3: Spells, Action Bar, Auras
|
||||
// Spells, Action Bar, Auras
|
||||
// ============================================================
|
||||
|
||||
/** SMSG_INITIAL_SPELLS data */
|
||||
|
|
@ -1930,7 +1930,7 @@ public:
|
|||
};
|
||||
|
||||
// ============================================================
|
||||
// Phase 4: Group/Party System
|
||||
// Group/Party System
|
||||
// ============================================================
|
||||
|
||||
/** CMSG_GROUP_INVITE packet builder */
|
||||
|
|
@ -1998,7 +1998,7 @@ public:
|
|||
};
|
||||
|
||||
// ============================================================
|
||||
// Phase 5: Loot System
|
||||
// Loot System
|
||||
// ============================================================
|
||||
|
||||
/** Loot item entry */
|
||||
|
|
@ -2100,7 +2100,7 @@ public:
|
|||
};
|
||||
|
||||
// ============================================================
|
||||
// Phase 5: NPC Gossip
|
||||
// NPC Gossip
|
||||
// ============================================================
|
||||
|
||||
/** Gossip menu option */
|
||||
|
|
@ -2278,7 +2278,7 @@ public:
|
|||
};
|
||||
|
||||
// ============================================================
|
||||
// Phase 5: Vendor
|
||||
// Vendor
|
||||
// ============================================================
|
||||
|
||||
/** Vendor item entry */
|
||||
|
|
|
|||
78
include/ui/action_bar_panel.hpp
Normal file
78
include/ui/action_bar_panel.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// ============================================================
|
||||
// ActionBarPanel — extracted from GameScreen
|
||||
// Owns all action bar rendering: main bar, stance bar, bag bar,
|
||||
// XP bar, reputation bar, macro resolution.
|
||||
// ============================================================
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace wowee {
|
||||
namespace game { class GameHandler; }
|
||||
namespace pipeline { class AssetManager; }
|
||||
namespace ui {
|
||||
|
||||
class ChatPanel;
|
||||
class SettingsPanel;
|
||||
class InventoryScreen;
|
||||
class SpellbookScreen;
|
||||
class QuestLogScreen;
|
||||
|
||||
class ActionBarPanel {
|
||||
public:
|
||||
// Callback type for resolving spell icons (spellId, assetMgr) → VkDescriptorSet
|
||||
using SpellIconFn = std::function<VkDescriptorSet(uint32_t, pipeline::AssetManager*)>;
|
||||
|
||||
// ---- Action bar render methods ----
|
||||
void renderActionBar(game::GameHandler& gameHandler,
|
||||
SettingsPanel& settingsPanel,
|
||||
ChatPanel& chatPanel,
|
||||
InventoryScreen& inventoryScreen,
|
||||
SpellbookScreen& spellbookScreen,
|
||||
QuestLogScreen& questLogScreen,
|
||||
SpellIconFn getSpellIcon);
|
||||
void renderStanceBar(game::GameHandler& gameHandler,
|
||||
SettingsPanel& settingsPanel,
|
||||
SpellbookScreen& spellbookScreen,
|
||||
SpellIconFn getSpellIcon);
|
||||
void renderBagBar(game::GameHandler& gameHandler,
|
||||
SettingsPanel& settingsPanel,
|
||||
InventoryScreen& inventoryScreen);
|
||||
void renderXpBar(game::GameHandler& gameHandler,
|
||||
SettingsPanel& settingsPanel);
|
||||
void renderRepBar(game::GameHandler& gameHandler,
|
||||
SettingsPanel& settingsPanel);
|
||||
|
||||
// ---- State owned by this panel ----
|
||||
|
||||
// Action bar error-flash: spellId → wall-clock time (seconds) when the flash ends
|
||||
std::unordered_map<uint32_t, float> actionFlashEndTimes_;
|
||||
static constexpr float kActionFlashDuration = 0.5f;
|
||||
|
||||
// Action bar drag state (-1 = not dragging)
|
||||
int actionBarDragSlot_ = -1;
|
||||
VkDescriptorSet actionBarDragIcon_ = VK_NULL_HANDLE;
|
||||
|
||||
// Bag bar state
|
||||
VkDescriptorSet backpackIconTexture_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSet emptyBagSlotTexture_ = VK_NULL_HANDLE;
|
||||
int bagBarPickedSlot_ = -1;
|
||||
int bagBarDragSource_ = -1;
|
||||
|
||||
// Macro editor popup state
|
||||
uint32_t macroEditorId_ = 0;
|
||||
bool macroEditorOpen_ = false;
|
||||
char macroEditorBuf_[256] = {};
|
||||
|
||||
// Macro cooldown cache: maps macro ID → resolved primary spell ID
|
||||
std::unordered_map<uint32_t, uint32_t> macroPrimarySpellCache_;
|
||||
size_t macroCacheSpellCount_ = 0;
|
||||
|
||||
private:
|
||||
uint32_t resolveMacroPrimarySpellId(uint32_t macroId, game::GameHandler& gameHandler);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace wowee
|
||||
194
include/ui/chat_panel.hpp
Normal file
194
include/ui/chat_panel.hpp
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
#pragma once
|
||||
|
||||
#include "game/game_handler.hpp"
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <imgui.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace wowee {
|
||||
namespace pipeline { class AssetManager; }
|
||||
namespace rendering { class Renderer; }
|
||||
namespace ui {
|
||||
|
||||
class InventoryScreen;
|
||||
class SpellbookScreen;
|
||||
class QuestLogScreen;
|
||||
|
||||
/**
|
||||
* Self-contained chat UI panel extracted from GameScreen.
|
||||
*
|
||||
* Owns all chat state: input buffer, sent-history, tab filtering,
|
||||
* slash-command parsing, chat bubbles, and chat-related settings.
|
||||
*/
|
||||
class ChatPanel {
|
||||
public:
|
||||
ChatPanel();
|
||||
|
||||
// ---- Main entry points (called by GameScreen) ----
|
||||
|
||||
/**
|
||||
* Render the chat window (tabs, history, input, etc.)
|
||||
*/
|
||||
void render(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
SpellbookScreen& spellbookScreen,
|
||||
QuestLogScreen& questLogScreen);
|
||||
|
||||
/**
|
||||
* Render 3D-projected chat bubbles above entities.
|
||||
*/
|
||||
void renderBubbles(game::GameHandler& gameHandler);
|
||||
|
||||
/**
|
||||
* Register one-shot callbacks on GameHandler (call once per session).
|
||||
* Sets up the chat-bubble callback.
|
||||
*/
|
||||
void setupCallbacks(game::GameHandler& gameHandler);
|
||||
|
||||
// ---- Input helpers (called by GameScreen keybind handling) ----
|
||||
|
||||
bool isChatInputActive() const { return chatInputActive_; }
|
||||
|
||||
/** Insert a spell / item link into the chat input buffer (shift-click). */
|
||||
void insertChatLink(const std::string& link);
|
||||
|
||||
/** Activate the input field with a leading '/' (slash key). */
|
||||
void activateSlashInput();
|
||||
|
||||
/** Activate (focus) the input field (Enter key). */
|
||||
void activateInput();
|
||||
|
||||
/** Request that the chat input be focused next frame. */
|
||||
void requestRefocus() { refocusChatInput_ = true; }
|
||||
|
||||
/** Set up a whisper to the given player name and focus input. */
|
||||
void setWhisperTarget(const std::string& name);
|
||||
|
||||
/** Execute a macro body (one line per 'click'). */
|
||||
void executeMacroText(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
SpellbookScreen& spellbookScreen,
|
||||
QuestLogScreen& questLogScreen,
|
||||
const std::string& macroText);
|
||||
|
||||
// ---- Slash-command side-effects ----
|
||||
// GameScreen reads these each frame, then clears them.
|
||||
|
||||
struct SlashCommands {
|
||||
bool showInspect = false;
|
||||
bool toggleThreat = false;
|
||||
bool showBgScore = false;
|
||||
bool showGmTicket = false;
|
||||
bool showWho = false;
|
||||
bool toggleCombatLog = false;
|
||||
bool takeScreenshot = false;
|
||||
};
|
||||
|
||||
/** Return accumulated slash-command flags and reset them. */
|
||||
SlashCommands consumeSlashCommands();
|
||||
|
||||
// ---- Chat settings (read/written by GameScreen save/load & settings tab) ----
|
||||
|
||||
bool chatShowTimestamps = false;
|
||||
int chatFontSize = 1; // 0=small, 1=medium, 2=large
|
||||
bool chatAutoJoinGeneral = true;
|
||||
bool chatAutoJoinTrade = true;
|
||||
bool chatAutoJoinLocalDefense = true;
|
||||
bool chatAutoJoinLFG = true;
|
||||
bool chatAutoJoinLocal = true;
|
||||
int activeChatTab = 0;
|
||||
|
||||
/** Spell icon lookup callback — set by GameScreen each frame before render(). */
|
||||
std::function<VkDescriptorSet(uint32_t, pipeline::AssetManager*)> getSpellIcon;
|
||||
|
||||
/** Render the "Chat" tab inside the Settings window. */
|
||||
void renderSettingsTab(std::function<void()> saveSettingsFn);
|
||||
|
||||
/** Reset all chat settings to defaults. */
|
||||
void restoreDefaults();
|
||||
|
||||
/** Replace $g/$G and $n/$N gender/name placeholders in quest/chat text. */
|
||||
std::string replaceGenderPlaceholders(const std::string& text, game::GameHandler& gameHandler);
|
||||
|
||||
private:
|
||||
// ---- Chat input state ----
|
||||
char chatInputBuffer_[512] = "";
|
||||
char whisperTargetBuffer_[256] = "";
|
||||
bool chatInputActive_ = false;
|
||||
int selectedChatType_ = 0; // 0=SAY .. 10=CHANNEL
|
||||
int lastChatType_ = 0;
|
||||
int selectedChannelIdx_ = 0;
|
||||
bool chatInputMoveCursorToEnd_ = false;
|
||||
bool refocusChatInput_ = false;
|
||||
|
||||
// Sent-message history (Up/Down arrow recall)
|
||||
std::vector<std::string> chatSentHistory_;
|
||||
int chatHistoryIdx_ = -1;
|
||||
|
||||
// Macro stop flag
|
||||
bool macroStopped_ = false;
|
||||
|
||||
// Tab-completion state
|
||||
std::string chatTabPrefix_;
|
||||
std::vector<std::string> chatTabMatches_;
|
||||
int chatTabMatchIdx_ = -1;
|
||||
|
||||
// Mention notification
|
||||
size_t chatMentionSeenCount_ = 0;
|
||||
|
||||
// ---- Chat tabs ----
|
||||
struct ChatTab {
|
||||
std::string name;
|
||||
uint64_t typeMask;
|
||||
};
|
||||
std::vector<ChatTab> chatTabs_;
|
||||
std::vector<int> chatTabUnread_;
|
||||
size_t chatTabSeenCount_ = 0;
|
||||
|
||||
void initChatTabs();
|
||||
bool shouldShowMessage(const game::MessageChatData& msg, int tabIndex) const;
|
||||
|
||||
// ---- Chat window visual state ----
|
||||
bool chatScrolledUp_ = false;
|
||||
bool chatForceScrollToBottom_ = false;
|
||||
bool chatWindowLocked_ = true;
|
||||
ImVec2 chatWindowPos_ = ImVec2(0.0f, 0.0f);
|
||||
bool chatWindowPosInit_ = false;
|
||||
|
||||
// ---- Chat bubbles ----
|
||||
struct ChatBubble {
|
||||
uint64_t senderGuid = 0;
|
||||
std::string message;
|
||||
float timeRemaining = 0.0f;
|
||||
float totalDuration = 0.0f;
|
||||
bool isYell = false;
|
||||
};
|
||||
std::vector<ChatBubble> chatBubbles_;
|
||||
bool chatBubbleCallbackSet_ = false;
|
||||
|
||||
// ---- Whisper toast state (populated in render, rendered by GameScreen/ToastManager) ----
|
||||
// Whisper scanning lives here because it's tightly coupled to chat history iteration.
|
||||
size_t whisperSeenCount_ = 0;
|
||||
|
||||
// ---- Helpers ----
|
||||
void sendChatMessage(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
SpellbookScreen& spellbookScreen,
|
||||
QuestLogScreen& questLogScreen);
|
||||
const char* getChatTypeName(game::ChatType type) const;
|
||||
ImVec4 getChatTypeColor(game::ChatType type) const;
|
||||
|
||||
// Cached game handler for input callback (set each frame in render)
|
||||
game::GameHandler* cachedGameHandler_ = nullptr;
|
||||
|
||||
// Join channel input buffer
|
||||
char joinChannelBuffer_[128] = "";
|
||||
|
||||
// Slash command flags (accumulated, consumed by GameScreen)
|
||||
SlashCommands slashCmds_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace wowee
|
||||
76
include/ui/combat_ui.hpp
Normal file
76
include/ui/combat_ui.hpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace wowee {
|
||||
namespace game { class GameHandler; }
|
||||
namespace pipeline { class AssetManager; }
|
||||
namespace ui {
|
||||
|
||||
class SettingsPanel;
|
||||
class SpellbookScreen;
|
||||
|
||||
/**
|
||||
* Combat UI overlay manager (extracted from GameScreen)
|
||||
*
|
||||
* Owns all combat-related rendering:
|
||||
* cast bar, cooldown tracker, raid warning overlay, floating combat text,
|
||||
* DPS/HPS meter, buff bar, battleground score HUD, combat log,
|
||||
* threat window, BG scoreboard.
|
||||
*/
|
||||
class CombatUI {
|
||||
public:
|
||||
CombatUI() = default;
|
||||
|
||||
// ---- Callback type for spell icon lookup (stays in GameScreen) ----
|
||||
using SpellIconFn = std::function<VkDescriptorSet(uint32_t spellId, pipeline::AssetManager*)>;
|
||||
|
||||
// ---- Toggle booleans (written by slash commands / escape handler / settings) ----
|
||||
bool showCombatLog_ = false;
|
||||
bool showThreatWindow_ = false;
|
||||
bool showBgScoreboard_ = false;
|
||||
|
||||
// ---- Raid Warning / Boss Emote big-text overlay ----
|
||||
struct RaidWarnEntry {
|
||||
std::string text;
|
||||
float age = 0.0f;
|
||||
bool isBossEmote = false;
|
||||
static constexpr float LIFETIME = 5.0f;
|
||||
};
|
||||
std::vector<RaidWarnEntry> raidWarnEntries_;
|
||||
bool raidWarnCallbackSet_ = false;
|
||||
size_t raidWarnChatSeenCount_ = 0;
|
||||
|
||||
// ---- DPS meter state ----
|
||||
float dpsCombatAge_ = 0.0f;
|
||||
bool dpsWasInCombat_ = false;
|
||||
float dpsEncounterDamage_ = 0.0f;
|
||||
float dpsEncounterHeal_ = 0.0f;
|
||||
size_t dpsLogSeenCount_ = 0;
|
||||
|
||||
// ---- Public render methods ----
|
||||
void renderCastBar(game::GameHandler& gameHandler, SpellIconFn getSpellIcon);
|
||||
void renderCooldownTracker(game::GameHandler& gameHandler,
|
||||
const SettingsPanel& settings,
|
||||
SpellIconFn getSpellIcon);
|
||||
void renderRaidWarningOverlay(game::GameHandler& gameHandler);
|
||||
void renderCombatText(game::GameHandler& gameHandler);
|
||||
void renderDPSMeter(game::GameHandler& gameHandler,
|
||||
const SettingsPanel& settings);
|
||||
void renderBuffBar(game::GameHandler& gameHandler,
|
||||
SpellbookScreen& spellbookScreen,
|
||||
SpellIconFn getSpellIcon);
|
||||
void renderBattlegroundScore(game::GameHandler& gameHandler);
|
||||
void renderCombatLog(game::GameHandler& gameHandler,
|
||||
SpellbookScreen& spellbookScreen);
|
||||
void renderThreatWindow(game::GameHandler& gameHandler);
|
||||
void renderBgScoreboard(game::GameHandler& gameHandler);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace wowee
|
||||
71
include/ui/dialog_manager.hpp
Normal file
71
include/ui/dialog_manager.hpp
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace wowee {
|
||||
namespace game { class GameHandler; }
|
||||
namespace ui {
|
||||
|
||||
class ChatPanel;
|
||||
class InventoryScreen;
|
||||
|
||||
/**
|
||||
* Dialog / popup overlay manager
|
||||
*
|
||||
* Owns all yes/no popup rendering:
|
||||
* group invite, duel request, duel countdown, loot roll, trade request,
|
||||
* trade window, summon request, shared quest, item text, guild invite,
|
||||
* ready check, BG invite, BF manager invite, LFG proposal, LFG role check,
|
||||
* resurrect, talent wipe confirm, pet unlearn confirm.
|
||||
*/
|
||||
class DialogManager {
|
||||
public:
|
||||
DialogManager() = default;
|
||||
|
||||
/// Render "early" dialogs (group invite through LFG role check)
|
||||
/// called in render() before guild roster / social frame
|
||||
void renderDialogs(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
|
||||
/// Render "late" dialogs (resurrect, talent wipe, pet unlearn)
|
||||
/// called in render() after reclaim corpse button
|
||||
void renderLateDialogs(game::GameHandler& gameHandler);
|
||||
|
||||
private:
|
||||
// Common ImGui window flags for popup dialogs
|
||||
static constexpr ImGuiWindowFlags kDialogFlags =
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize;
|
||||
|
||||
// ---- LFG role state ----
|
||||
uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps)
|
||||
|
||||
// ---- Individual dialog renderers ----
|
||||
void renderGroupInvitePopup(game::GameHandler& gameHandler);
|
||||
void renderDuelRequestPopup(game::GameHandler& gameHandler);
|
||||
void renderDuelCountdown(game::GameHandler& gameHandler);
|
||||
void renderItemTextWindow(game::GameHandler& gameHandler);
|
||||
void renderSharedQuestPopup(game::GameHandler& gameHandler);
|
||||
void renderSummonRequestPopup(game::GameHandler& gameHandler);
|
||||
void renderTradeRequestPopup(game::GameHandler& gameHandler);
|
||||
void renderTradeWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
void renderLootRollPopup(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
void renderGuildInvitePopup(game::GameHandler& gameHandler);
|
||||
void renderReadyCheckPopup(game::GameHandler& gameHandler);
|
||||
void renderBgInvitePopup(game::GameHandler& gameHandler);
|
||||
void renderBfMgrInvitePopup(game::GameHandler& gameHandler);
|
||||
void renderLfgProposalPopup(game::GameHandler& gameHandler);
|
||||
void renderLfgRoleCheckPopup(game::GameHandler& gameHandler);
|
||||
void renderResurrectDialog(game::GameHandler& gameHandler);
|
||||
void renderTalentWipeConfirmDialog(game::GameHandler& gameHandler);
|
||||
void renderPetUnlearnConfirmDialog(game::GameHandler& gameHandler);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace wowee
|
||||
|
|
@ -9,6 +9,14 @@
|
|||
#include "ui/spellbook_screen.hpp"
|
||||
#include "ui/talent_screen.hpp"
|
||||
#include "ui/keybinding_manager.hpp"
|
||||
#include "ui/chat_panel.hpp"
|
||||
#include "ui/toast_manager.hpp"
|
||||
#include "ui/dialog_manager.hpp"
|
||||
#include "ui/settings_panel.hpp"
|
||||
#include "ui/combat_ui.hpp"
|
||||
#include "ui/social_panel.hpp"
|
||||
#include "ui/action_bar_panel.hpp"
|
||||
#include "ui/window_manager.hpp"
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <imgui.h>
|
||||
#include <string>
|
||||
|
|
@ -37,82 +45,46 @@ public:
|
|||
/**
|
||||
* Check if chat input is active
|
||||
*/
|
||||
bool isChatInputActive() const { return chatInputActive; }
|
||||
bool isChatInputActive() const { return chatPanel_.isChatInputActive(); }
|
||||
|
||||
void saveSettings();
|
||||
void loadSettings();
|
||||
void applyAudioVolumes(rendering::Renderer* renderer);
|
||||
|
||||
private:
|
||||
// Chat state
|
||||
char chatInputBuffer[512] = "";
|
||||
char whisperTargetBuffer[256] = "";
|
||||
bool chatInputActive = false;
|
||||
int selectedChatType = 0; // 0=SAY, 1=YELL, 2=PARTY, 3=GUILD, 4=WHISPER, ..., 10=CHANNEL
|
||||
int lastChatType = 0; // Track chat type changes
|
||||
int selectedChannelIdx = 0; // Index into joinedChannels_ when selectedChatType==10
|
||||
bool chatInputMoveCursorToEnd = false;
|
||||
// Chat panel (extracted from GameScreen — owns all chat state and rendering)
|
||||
ChatPanel chatPanel_;
|
||||
|
||||
// Chat sent-message history (Up/Down arrow recall)
|
||||
std::vector<std::string> chatSentHistory_;
|
||||
int chatHistoryIdx_ = -1; // -1 = not browsing history
|
||||
// Toast manager (extracted from GameScreen — owns all toast/notification state and rendering)
|
||||
ToastManager toastManager_;
|
||||
|
||||
// Set to true by /stopmacro; checked in executeMacroText to halt remaining commands.
|
||||
bool macroStopped_ = false;
|
||||
// Dialog manager (extracted from GameScreen — owns all popup/dialog rendering)
|
||||
DialogManager dialogManager_;
|
||||
|
||||
// Action bar error-flash: spellId → wall-clock time (seconds) when the flash ends.
|
||||
// Populated by the SpellCastFailedCallback; queried during action bar button rendering.
|
||||
std::unordered_map<uint32_t, float> actionFlashEndTimes_;
|
||||
// Settings panel (extracted from GameScreen — owns all settings UI and config state)
|
||||
SettingsPanel settingsPanel_;
|
||||
|
||||
// Cached game handler for input callbacks (set each frame in render)
|
||||
game::GameHandler* cachedGameHandler_ = nullptr;
|
||||
// Combat UI (extracted from GameScreen — owns all combat overlay rendering)
|
||||
CombatUI combatUI_;
|
||||
|
||||
// Tab-completion state for slash commands and player names
|
||||
std::string chatTabPrefix_; // prefix captured on first Tab press
|
||||
std::vector<std::string> chatTabMatches_; // matching command list
|
||||
int chatTabMatchIdx_ = -1; // active match index (-1 = inactive)
|
||||
// Social panel (extracted from GameScreen — owns all social/group UI rendering)
|
||||
SocialPanel socialPanel_;
|
||||
|
||||
// Mention notification: plays a sound when the player's name appears in chat
|
||||
size_t chatMentionSeenCount_ = 0; // how many messages have been scanned for mentions
|
||||
// Action bar panel (extracted from GameScreen — owns action/stance/bag/xp/rep bars)
|
||||
ActionBarPanel actionBarPanel_;
|
||||
|
||||
// Chat tabs
|
||||
int activeChatTab_ = 0;
|
||||
struct ChatTab {
|
||||
std::string name;
|
||||
uint64_t typeMask; // bitmask of ChatType values to show (64-bit: types go up to 84)
|
||||
};
|
||||
std::vector<ChatTab> chatTabs_;
|
||||
std::vector<int> chatTabUnread_; // unread message count per tab (0 = none)
|
||||
size_t chatTabSeenCount_ = 0; // how many history messages have been processed
|
||||
void initChatTabs();
|
||||
bool shouldShowMessage(const game::MessageChatData& msg, int tabIndex) const;
|
||||
// Window manager (extracted from GameScreen — owns NPC windows, popups, overlays)
|
||||
WindowManager windowManager_;
|
||||
|
||||
// UI state
|
||||
bool showEntityWindow = false;
|
||||
bool showChatWindow = true;
|
||||
bool showMinimap_ = true; // M key toggles minimap
|
||||
bool showNameplates_ = true; // V key toggles enemy/NPC nameplates
|
||||
bool showFriendlyNameplates_ = true; // Shift+V toggles friendly player nameplates
|
||||
float nameplateScale_ = 1.0f; // Scale multiplier for nameplate bar dimensions
|
||||
uint64_t nameplateCtxGuid_ = 0; // GUID of nameplate right-clicked (0 = none)
|
||||
ImVec2 nameplateCtxPos_{}; // Screen position of nameplate right-click
|
||||
uint32_t lastPlayerHp_ = 0; // Previous frame HP for damage flash detection
|
||||
float damageFlashAlpha_ = 0.0f; // Screen edge flash intensity (fades to 0)
|
||||
bool damageFlashEnabled_ = true;
|
||||
bool lowHealthVignetteEnabled_ = true; // Persistent pulsing red vignette below 20% HP
|
||||
float levelUpFlashAlpha_ = 0.0f; // Golden level-up burst effect (fades to 0)
|
||||
uint32_t levelUpDisplayLevel_ = 0; // Level shown in level-up text
|
||||
|
||||
// Raid Warning / Boss Emote big-text overlay (center-screen, fades after 5s)
|
||||
struct RaidWarnEntry {
|
||||
std::string text;
|
||||
float age = 0.0f;
|
||||
bool isBossEmote = false; // true = amber, false (raid warning) = red+yellow
|
||||
static constexpr float LIFETIME = 5.0f;
|
||||
};
|
||||
std::vector<RaidWarnEntry> raidWarnEntries_;
|
||||
bool raidWarnCallbackSet_ = false;
|
||||
size_t raidWarnChatSeenCount_ = 0; // index into chat history for unread scan
|
||||
|
||||
// UIErrorsFrame: WoW-style center-bottom error messages (spell fails, out of range, etc.)
|
||||
struct UIErrorEntry { std::string text; float age = 0.0f; };
|
||||
|
|
@ -120,161 +92,15 @@ private:
|
|||
bool uiErrorCallbackSet_ = false;
|
||||
static constexpr float kUIErrorLifetime = 2.5f;
|
||||
bool castFailedCallbackSet_ = false;
|
||||
static constexpr float kActionFlashDuration = 0.5f; // seconds for error-red overlay to fade
|
||||
|
||||
// Reputation change toast: brief colored slide-in below minimap
|
||||
struct RepToastEntry { std::string factionName; int32_t delta = 0; int32_t standing = 0; float age = 0.0f; };
|
||||
std::vector<RepToastEntry> repToasts_;
|
||||
bool repChangeCallbackSet_ = false;
|
||||
static constexpr float kRepToastLifetime = 3.5f;
|
||||
|
||||
// Quest completion toast: slide-in when a quest is turned in
|
||||
struct QuestCompleteToastEntry { uint32_t questId = 0; std::string title; float age = 0.0f; };
|
||||
std::vector<QuestCompleteToastEntry> questCompleteToasts_;
|
||||
bool questCompleteCallbackSet_ = false;
|
||||
static constexpr float kQuestCompleteToastLifetime = 4.0f;
|
||||
|
||||
// Zone entry toast: brief banner when entering a new zone
|
||||
struct ZoneToastEntry { std::string zoneName; float age = 0.0f; };
|
||||
std::vector<ZoneToastEntry> zoneToasts_;
|
||||
|
||||
struct AreaTriggerToast { std::string text; float age = 0.0f; };
|
||||
std::vector<AreaTriggerToast> areaTriggerToasts_;
|
||||
void renderAreaTriggerToasts(float deltaTime, game::GameHandler& gameHandler);
|
||||
std::string lastKnownZone_;
|
||||
static constexpr float kZoneToastLifetime = 3.0f;
|
||||
|
||||
// Death screen: elapsed time since the death dialog first appeared
|
||||
float deathElapsed_ = 0.0f;
|
||||
bool deathTimerRunning_ = false;
|
||||
// WoW forces release after ~6 minutes; show countdown until then
|
||||
static constexpr float kForcedReleaseSec = 360.0f;
|
||||
void renderZoneToasts(float deltaTime);
|
||||
bool showPlayerInfo = false;
|
||||
bool showSocialFrame_ = false; // O key toggles social/friends list
|
||||
bool showGuildRoster_ = false;
|
||||
bool showRaidFrames_ = true; // F key toggles raid/party frames
|
||||
bool showWorldMap_ = false; // W key toggles world map
|
||||
std::string selectedGuildMember_;
|
||||
bool showGuildNoteEdit_ = false;
|
||||
bool editingOfficerNote_ = false;
|
||||
char guildNoteEditBuffer_[256] = {0};
|
||||
int guildRosterTab_ = 0; // 0=Roster, 1=Guild Info
|
||||
char guildMotdEditBuffer_[256] = {0};
|
||||
bool showMotdEdit_ = false;
|
||||
char petitionNameBuffer_[64] = {0};
|
||||
char addRankNameBuffer_[64] = {0};
|
||||
bool showAddRankModal_ = false;
|
||||
bool refocusChatInput = false;
|
||||
bool vendorBagsOpened_ = false; // Track if bags were auto-opened for current vendor session
|
||||
bool chatScrolledUp_ = false; // true when user has scrolled above the latest messages
|
||||
bool chatForceScrollToBottom_ = false; // set to true to jump to bottom next frame
|
||||
bool chatWindowLocked = true;
|
||||
ImVec2 chatWindowPos_ = ImVec2(0.0f, 0.0f);
|
||||
bool chatWindowPosInit_ = false;
|
||||
ImVec2 questTrackerPos_ = ImVec2(-1.0f, -1.0f); // <0 = use default
|
||||
ImVec2 questTrackerSize_ = ImVec2(220.0f, 200.0f); // saved size
|
||||
float questTrackerRightOffset_ = -1.0f; // pixels from right edge; <0 = use default
|
||||
bool questTrackerPosInit_ = false;
|
||||
bool showEscapeMenu = false;
|
||||
bool showEscapeSettingsNotice = false;
|
||||
bool showSettingsWindow = false;
|
||||
bool settingsInit = false;
|
||||
bool pendingFullscreen = false;
|
||||
bool pendingVsync = false;
|
||||
int pendingResIndex = 0;
|
||||
bool pendingShadows = true;
|
||||
float pendingShadowDistance = 300.0f;
|
||||
bool pendingWaterRefraction = true;
|
||||
int pendingBrightness = 50; // 0-100, maps to 0.0-2.0 (50 = 1.0 default)
|
||||
int pendingMasterVolume = 100;
|
||||
int pendingMusicVolume = 30;
|
||||
int pendingAmbientVolume = 100;
|
||||
int pendingUiVolume = 100;
|
||||
int pendingCombatVolume = 100;
|
||||
int pendingSpellVolume = 100;
|
||||
int pendingMovementVolume = 100;
|
||||
int pendingFootstepVolume = 100;
|
||||
int pendingNpcVoiceVolume = 100;
|
||||
int pendingMountVolume = 100;
|
||||
int pendingActivityVolume = 100;
|
||||
float pendingMouseSensitivity = 0.2f;
|
||||
bool pendingInvertMouse = false;
|
||||
bool pendingExtendedZoom = false;
|
||||
float pendingCameraStiffness = 30.0f; // Camera smooth speed (higher = tighter, less sway)
|
||||
float pendingPivotHeight = 1.6f; // Camera pivot height above feet (lower = less detached feel)
|
||||
float pendingFov = 70.0f; // degrees, default matches WoW's ~70° horizontal FOV
|
||||
int pendingUiOpacity = 65;
|
||||
bool pendingMinimapRotate = false;
|
||||
bool pendingMinimapSquare = false;
|
||||
bool pendingMinimapNpcDots = false;
|
||||
bool pendingShowLatencyMeter = true;
|
||||
bool pendingSeparateBags = true;
|
||||
bool pendingShowKeyring = true;
|
||||
bool pendingAutoLoot = false;
|
||||
bool pendingAutoSellGrey = false;
|
||||
bool pendingAutoRepair = false;
|
||||
|
||||
// Keybinding customization
|
||||
int pendingRebindAction = -1; // -1 = not rebinding, otherwise action index
|
||||
bool awaitingKeyPress = false;
|
||||
// Macro editor popup state
|
||||
uint32_t macroEditorId_ = 0; // macro index being edited
|
||||
bool macroEditorOpen_ = false; // deferred OpenPopup flag
|
||||
char macroEditorBuf_[256] = {}; // edit buffer
|
||||
bool pendingUseOriginalSoundtrack = true;
|
||||
bool pendingShowActionBar2 = true; // Show second action bar above main bar
|
||||
float pendingActionBarScale = 1.0f; // Multiplier for action bar slot size (0.5–1.5)
|
||||
float pendingActionBar2OffsetX = 0.0f; // Horizontal offset from default center position
|
||||
float pendingActionBar2OffsetY = 0.0f; // Vertical offset from default (above bar 1)
|
||||
bool pendingShowRightBar = false; // Right-edge vertical action bar (bar 3, slots 24-35)
|
||||
bool pendingShowLeftBar = false; // Left-edge vertical action bar (bar 4, slots 36-47)
|
||||
float pendingRightBarOffsetY = 0.0f; // Vertical offset from screen center
|
||||
float pendingLeftBarOffsetY = 0.0f; // Vertical offset from screen center
|
||||
int pendingGroundClutterDensity = 100;
|
||||
int pendingAntiAliasing = 0; // 0=Off, 1=2x, 2=4x, 3=8x
|
||||
bool pendingFXAA = false; // FXAA post-process (combinable with MSAA)
|
||||
bool pendingNormalMapping = true; // on by default
|
||||
float pendingNormalMapStrength = 0.8f; // 0.0-2.0
|
||||
bool pendingPOM = true; // on by default
|
||||
int pendingPOMQuality = 1; // 0=Low(16), 1=Medium(32), 2=High(64)
|
||||
bool pendingFSR = false;
|
||||
int pendingUpscalingMode = 0; // 0=Off, 1=FSR1, 2=FSR3
|
||||
int pendingFSRQuality = 3; // 0=UltraQuality, 1=Quality, 2=Balanced, 3=Native(100%)
|
||||
float pendingFSRSharpness = 1.6f;
|
||||
float pendingFSR2JitterSign = 0.38f;
|
||||
float pendingFSR2MotionVecScaleX = 1.0f;
|
||||
float pendingFSR2MotionVecScaleY = 1.0f;
|
||||
bool pendingAMDFramegen = false;
|
||||
bool fsrSettingsApplied_ = false;
|
||||
|
||||
// Graphics quality presets
|
||||
enum class GraphicsPreset : int {
|
||||
CUSTOM = 0,
|
||||
LOW = 1,
|
||||
MEDIUM = 2,
|
||||
HIGH = 3,
|
||||
ULTRA = 4
|
||||
};
|
||||
GraphicsPreset currentGraphicsPreset = GraphicsPreset::CUSTOM;
|
||||
GraphicsPreset pendingGraphicsPreset = GraphicsPreset::CUSTOM;
|
||||
|
||||
// UI element transparency (0.0 = fully transparent, 1.0 = fully opaque)
|
||||
float uiOpacity_ = 0.65f;
|
||||
bool minimapRotate_ = false;
|
||||
bool minimapSquare_ = false;
|
||||
bool minimapNpcDots_ = false;
|
||||
bool showLatencyMeter_ = true; // Show server latency indicator
|
||||
bool minimapSettingsApplied_ = false;
|
||||
bool volumeSettingsApplied_ = false; // True once saved volume settings applied to audio managers
|
||||
bool msaaSettingsApplied_ = false; // True once saved MSAA setting applied to renderer
|
||||
bool fxaaSettingsApplied_ = false; // True once saved FXAA setting applied to renderer
|
||||
bool waterRefractionApplied_ = false;
|
||||
bool normalMapSettingsApplied_ = false; // True once saved normal map/POM settings applied
|
||||
|
||||
// Mute state: mute bypasses master volume without touching slider values
|
||||
bool soundMuted_ = false;
|
||||
float preMuteVolume_ = 1.0f; // AudioEngine master volume before muting
|
||||
|
||||
/**
|
||||
* Render player info window
|
||||
|
|
@ -286,27 +112,6 @@ private:
|
|||
*/
|
||||
void renderEntityList(game::GameHandler& gameHandler);
|
||||
|
||||
/**
|
||||
* Render chat window
|
||||
*/
|
||||
void renderChatWindow(game::GameHandler& gameHandler);
|
||||
|
||||
/**
|
||||
* Send chat message
|
||||
*/
|
||||
void sendChatMessage(game::GameHandler& gameHandler);
|
||||
void executeMacroText(game::GameHandler& gameHandler, const std::string& macroText);
|
||||
|
||||
/**
|
||||
* Get chat type name
|
||||
*/
|
||||
const char* getChatTypeName(game::ChatType type) const;
|
||||
|
||||
/**
|
||||
* Get chat type color
|
||||
*/
|
||||
ImVec4 getChatTypeColor(game::ChatType type) const;
|
||||
|
||||
/**
|
||||
* Render player unit frame (top-left)
|
||||
*/
|
||||
|
|
@ -339,80 +144,13 @@ private:
|
|||
*/
|
||||
void updateCharacterTextures(game::Inventory& inventory);
|
||||
|
||||
// ---- New UI renders ----
|
||||
void renderActionBar(game::GameHandler& gameHandler);
|
||||
void renderStanceBar(game::GameHandler& gameHandler);
|
||||
void renderBagBar(game::GameHandler& gameHandler);
|
||||
void renderXpBar(game::GameHandler& gameHandler);
|
||||
void renderRepBar(game::GameHandler& gameHandler);
|
||||
void renderCastBar(game::GameHandler& gameHandler);
|
||||
|
||||
void renderMirrorTimers(game::GameHandler& gameHandler);
|
||||
void renderCooldownTracker(game::GameHandler& gameHandler);
|
||||
void renderCombatText(game::GameHandler& gameHandler);
|
||||
void renderRaidWarningOverlay(game::GameHandler& gameHandler);
|
||||
void renderPartyFrames(game::GameHandler& gameHandler);
|
||||
void renderBossFrames(game::GameHandler& gameHandler);
|
||||
void renderUIErrors(game::GameHandler& gameHandler, float deltaTime);
|
||||
void renderRepToasts(float deltaTime);
|
||||
void renderQuestCompleteToasts(float deltaTime);
|
||||
void renderGroupInvitePopup(game::GameHandler& gameHandler);
|
||||
void renderDuelRequestPopup(game::GameHandler& gameHandler);
|
||||
void renderDuelCountdown(game::GameHandler& gameHandler);
|
||||
void renderLootRollPopup(game::GameHandler& gameHandler);
|
||||
void renderTradeRequestPopup(game::GameHandler& gameHandler);
|
||||
void renderTradeWindow(game::GameHandler& gameHandler);
|
||||
void renderSummonRequestPopup(game::GameHandler& gameHandler);
|
||||
void renderSharedQuestPopup(game::GameHandler& gameHandler);
|
||||
void renderItemTextWindow(game::GameHandler& gameHandler);
|
||||
void renderBuffBar(game::GameHandler& gameHandler);
|
||||
void renderSocialFrame(game::GameHandler& gameHandler);
|
||||
void renderLootWindow(game::GameHandler& gameHandler);
|
||||
void renderGossipWindow(game::GameHandler& gameHandler);
|
||||
void renderQuestDetailsWindow(game::GameHandler& gameHandler);
|
||||
void renderQuestRequestItemsWindow(game::GameHandler& gameHandler);
|
||||
void renderQuestOfferRewardWindow(game::GameHandler& gameHandler);
|
||||
void renderVendorWindow(game::GameHandler& gameHandler);
|
||||
void renderTrainerWindow(game::GameHandler& gameHandler);
|
||||
void renderBarberShopWindow(game::GameHandler& gameHandler);
|
||||
void renderStableWindow(game::GameHandler& gameHandler);
|
||||
void renderTaxiWindow(game::GameHandler& gameHandler);
|
||||
void renderLogoutCountdown(game::GameHandler& gameHandler);
|
||||
void renderDeathScreen(game::GameHandler& gameHandler);
|
||||
void renderReclaimCorpseButton(game::GameHandler& gameHandler);
|
||||
void renderResurrectDialog(game::GameHandler& gameHandler);
|
||||
void renderTalentWipeConfirmDialog(game::GameHandler& gameHandler);
|
||||
void renderPetUnlearnConfirmDialog(game::GameHandler& gameHandler);
|
||||
void renderEscapeMenu();
|
||||
void renderSettingsWindow();
|
||||
void renderSettingsAudioTab();
|
||||
void renderSettingsChatTab();
|
||||
void renderSettingsAboutTab();
|
||||
void renderSettingsInterfaceTab();
|
||||
void renderSettingsGameplayTab();
|
||||
void renderSettingsControlsTab();
|
||||
void applyGraphicsPreset(GraphicsPreset preset);
|
||||
void updateGraphicsPresetFromCurrentSettings();
|
||||
void renderQuestMarkers(game::GameHandler& gameHandler);
|
||||
void renderMinimapMarkers(game::GameHandler& gameHandler);
|
||||
void renderQuestObjectiveTracker(game::GameHandler& gameHandler);
|
||||
void renderGuildRoster(game::GameHandler& gameHandler);
|
||||
void renderGuildInvitePopup(game::GameHandler& gameHandler);
|
||||
void renderReadyCheckPopup(game::GameHandler& gameHandler);
|
||||
void renderBgInvitePopup(game::GameHandler& gameHandler);
|
||||
void renderBfMgrInvitePopup(game::GameHandler& gameHandler);
|
||||
void renderLfgProposalPopup(game::GameHandler& gameHandler);
|
||||
void renderLfgRoleCheckPopup(game::GameHandler& gameHandler);
|
||||
void renderChatBubbles(game::GameHandler& gameHandler);
|
||||
void renderMailWindow(game::GameHandler& gameHandler);
|
||||
void renderMailComposeWindow(game::GameHandler& gameHandler);
|
||||
void renderBankWindow(game::GameHandler& gameHandler);
|
||||
void renderGuildBankWindow(game::GameHandler& gameHandler);
|
||||
void renderAuctionHouseWindow(game::GameHandler& gameHandler);
|
||||
void renderDungeonFinderWindow(game::GameHandler& gameHandler);
|
||||
void renderInstanceLockouts(game::GameHandler& gameHandler);
|
||||
void renderNameplates(game::GameHandler& gameHandler);
|
||||
void renderBattlegroundScore(game::GameHandler& gameHandler);
|
||||
void renderDPSMeter(game::GameHandler& gameHandler);
|
||||
void renderDurabilityWarning(game::GameHandler& gameHandler);
|
||||
void takeScreenshot(game::GameHandler& gameHandler);
|
||||
|
||||
|
|
@ -437,298 +175,29 @@ private:
|
|||
bool spellIconDbLoaded_ = false;
|
||||
VkDescriptorSet getSpellIcon(uint32_t spellId, pipeline::AssetManager* am);
|
||||
|
||||
// ItemExtendedCost.dbc cache: extendedCostId -> cost details
|
||||
struct ExtendedCostEntry {
|
||||
uint32_t honorPoints = 0;
|
||||
uint32_t arenaPoints = 0;
|
||||
uint32_t itemId[5] = {};
|
||||
uint32_t itemCount[5] = {};
|
||||
};
|
||||
std::unordered_map<uint32_t, ExtendedCostEntry> extendedCostCache_;
|
||||
bool extendedCostDbLoaded_ = false;
|
||||
void loadExtendedCostDBC();
|
||||
std::string formatExtendedCost(uint32_t extendedCostId, game::GameHandler& gameHandler);
|
||||
|
||||
// Macro cooldown cache: maps macro ID → resolved primary spell ID (0 = no spell found)
|
||||
std::unordered_map<uint32_t, uint32_t> macroPrimarySpellCache_;
|
||||
size_t macroCacheSpellCount_ = 0; // invalidates cache when spell list changes
|
||||
uint32_t resolveMacroPrimarySpellId(uint32_t macroId, game::GameHandler& gameHandler);
|
||||
|
||||
// Death Knight rune bar: client-predicted fill (0.0=depleted, 1.0=ready) for smooth animation
|
||||
float runeClientFill_[6] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
|
||||
|
||||
// Action bar drag state (-1 = not dragging)
|
||||
int actionBarDragSlot_ = -1;
|
||||
VkDescriptorSet actionBarDragIcon_ = VK_NULL_HANDLE;
|
||||
|
||||
// Bag bar state
|
||||
VkDescriptorSet backpackIconTexture_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSet emptyBagSlotTexture_ = VK_NULL_HANDLE;
|
||||
int bagBarPickedSlot_ = -1; // Visual drag in progress (-1 = none)
|
||||
int bagBarDragSource_ = -1; // Mouse pressed on this slot, waiting for drag or click (-1 = none)
|
||||
|
||||
// Who Results window
|
||||
bool showWhoWindow_ = false;
|
||||
void renderWhoWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// Combat Log window
|
||||
bool showCombatLog_ = false;
|
||||
void renderCombatLog(game::GameHandler& gameHandler);
|
||||
|
||||
// Instance Lockouts window
|
||||
bool showInstanceLockouts_ = false;
|
||||
|
||||
// Dungeon Finder state
|
||||
bool showDungeonFinder_ = false;
|
||||
|
||||
// Achievements window
|
||||
bool showAchievementWindow_ = false;
|
||||
char achievementSearchBuf_[128] = {};
|
||||
void renderAchievementWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// Skills / Professions window (K key)
|
||||
bool showSkillsWindow_ = false;
|
||||
void renderSkillsWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// Titles window
|
||||
bool showTitlesWindow_ = false;
|
||||
void renderTitlesWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// Equipment Set Manager window
|
||||
bool showEquipSetWindow_ = false;
|
||||
void renderEquipSetWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// GM Ticket window
|
||||
bool showGmTicketWindow_ = false;
|
||||
bool gmTicketWindowWasOpen_ = false; ///< Previous frame state; used to fire one-shot query
|
||||
char gmTicketBuf_[2048] = {};
|
||||
void renderGmTicketWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// Pet rename modal (triggered from pet frame context menu)
|
||||
bool petRenameOpen_ = false;
|
||||
char petRenameBuf_[16] = {};
|
||||
|
||||
// Inspect window
|
||||
bool showInspectWindow_ = false;
|
||||
void renderInspectWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// Readable text window (books / scrolls / notes)
|
||||
bool showBookWindow_ = false;
|
||||
int bookCurrentPage_ = 0;
|
||||
void renderBookWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// Threat window
|
||||
bool showThreatWindow_ = false;
|
||||
void renderThreatWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// BG scoreboard window
|
||||
bool showBgScoreboard_ = false;
|
||||
void renderBgScoreboard(game::GameHandler& gameHandler);
|
||||
uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps)
|
||||
uint32_t lfgSelectedDungeon_ = 861; // default: random dungeon (entry 861 = Random Dungeon WotLK)
|
||||
|
||||
// Chat settings
|
||||
bool chatShowTimestamps_ = false;
|
||||
int chatFontSize_ = 1; // 0=small, 1=medium, 2=large
|
||||
bool chatAutoJoinGeneral_ = true;
|
||||
bool chatAutoJoinTrade_ = true;
|
||||
bool chatAutoJoinLocalDefense_ = true;
|
||||
bool chatAutoJoinLFG_ = true;
|
||||
bool chatAutoJoinLocal_ = true;
|
||||
|
||||
// Join channel input buffer
|
||||
char joinChannelBuffer_[128] = "";
|
||||
|
||||
static std::string getSettingsPath();
|
||||
|
||||
// Gender placeholder replacement
|
||||
std::string replaceGenderPlaceholders(const std::string& text, game::GameHandler& gameHandler);
|
||||
|
||||
// Chat bubbles
|
||||
struct ChatBubble {
|
||||
uint64_t senderGuid = 0;
|
||||
std::string message;
|
||||
float timeRemaining = 0.0f;
|
||||
float totalDuration = 0.0f;
|
||||
bool isYell = false;
|
||||
};
|
||||
std::vector<ChatBubble> chatBubbles_;
|
||||
bool chatBubbleCallbackSet_ = false;
|
||||
bool levelUpCallbackSet_ = false;
|
||||
bool achievementCallbackSet_ = false;
|
||||
|
||||
// Mail compose state
|
||||
char mailRecipientBuffer_[256] = "";
|
||||
char mailSubjectBuffer_[256] = "";
|
||||
char mailBodyBuffer_[2048] = "";
|
||||
int mailComposeMoney_[3] = {0, 0, 0}; // gold, silver, copper
|
||||
|
||||
// Vendor search filter
|
||||
char vendorSearchFilter_[128] = "";
|
||||
|
||||
// Vendor purchase confirmation for expensive items
|
||||
bool vendorConfirmOpen_ = false;
|
||||
uint64_t vendorConfirmGuid_ = 0;
|
||||
uint32_t vendorConfirmItemId_ = 0;
|
||||
uint32_t vendorConfirmSlot_ = 0;
|
||||
uint32_t vendorConfirmQty_ = 1;
|
||||
uint32_t vendorConfirmPrice_ = 0;
|
||||
std::string vendorConfirmItemName_;
|
||||
|
||||
// Barber shop UI state
|
||||
int barberHairStyle_ = 0;
|
||||
int barberHairColor_ = 0;
|
||||
int barberFacialHair_ = 0;
|
||||
int barberOrigHairStyle_ = 0;
|
||||
int barberOrigHairColor_ = 0;
|
||||
int barberOrigFacialHair_ = 0;
|
||||
bool barberInitialized_ = false;
|
||||
|
||||
// Trainer search filter
|
||||
char trainerSearchFilter_[128] = "";
|
||||
|
||||
// Auction house UI state
|
||||
char auctionSearchName_[256] = "";
|
||||
int auctionLevelMin_ = 0;
|
||||
int auctionLevelMax_ = 0;
|
||||
int auctionQuality_ = 0;
|
||||
int auctionSellDuration_ = 2; // 0=12h, 1=24h, 2=48h
|
||||
int auctionSellBid_[3] = {0, 0, 0}; // gold, silver, copper
|
||||
int auctionSellBuyout_[3] = {0, 0, 0}; // gold, silver, copper
|
||||
int auctionSelectedItem_ = -1;
|
||||
int auctionSellSlotIndex_ = -1; // Selected backpack slot for selling
|
||||
uint32_t auctionBrowseOffset_ = 0; // Pagination offset for browse results
|
||||
int auctionItemClass_ = -1; // Item class filter (-1 = All)
|
||||
int auctionItemSubClass_ = -1; // Item subclass filter (-1 = All)
|
||||
bool auctionUsableOnly_ = false; // Filter to items usable by current class/level
|
||||
|
||||
// Guild bank money input
|
||||
int guildBankMoneyInput_[3] = {0, 0, 0}; // gold, silver, copper
|
||||
|
||||
// Left-click targeting: distinguish click from camera drag
|
||||
glm::vec2 leftClickPressPos_ = glm::vec2(0.0f);
|
||||
bool leftClickWasPress_ = false;
|
||||
|
||||
// Level-up ding animation
|
||||
static constexpr float DING_DURATION = 4.0f;
|
||||
float dingTimer_ = 0.0f;
|
||||
uint32_t dingLevel_ = 0;
|
||||
uint32_t dingHpDelta_ = 0;
|
||||
uint32_t dingManaDelta_ = 0;
|
||||
uint32_t dingStats_[5] = {}; // str/agi/sta/int/spi deltas
|
||||
void renderDingEffect();
|
||||
|
||||
// Achievement toast banner
|
||||
static constexpr float ACHIEVEMENT_TOAST_DURATION = 5.0f;
|
||||
float achievementToastTimer_ = 0.0f;
|
||||
uint32_t achievementToastId_ = 0;
|
||||
std::string achievementToastName_;
|
||||
void renderAchievementToast();
|
||||
|
||||
// Area discovery toast ("Discovered! <AreaName> +XP XP")
|
||||
static constexpr float DISCOVERY_TOAST_DURATION = 4.0f;
|
||||
float discoveryToastTimer_ = 0.0f;
|
||||
std::string discoveryToastName_;
|
||||
uint32_t discoveryToastXP_ = 0;
|
||||
bool areaDiscoveryCallbackSet_ = false;
|
||||
void renderDiscoveryToast();
|
||||
|
||||
// Whisper toast — brief overlay at screen top when a whisper arrives while chat is not focused
|
||||
struct WhisperToastEntry {
|
||||
std::string sender;
|
||||
std::string preview; // first ~60 chars of message
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float WHISPER_TOAST_DURATION = 5.0f;
|
||||
std::vector<WhisperToastEntry> whisperToasts_;
|
||||
size_t whisperSeenCount_ = 0; // how many chat entries have been scanned for whispers
|
||||
void renderWhisperToasts();
|
||||
|
||||
// Quest objective progress toast ("Quest: <ObjectiveName> X/Y")
|
||||
struct QuestProgressToastEntry {
|
||||
std::string questTitle;
|
||||
std::string objectiveName;
|
||||
uint32_t current = 0;
|
||||
uint32_t required = 0;
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float QUEST_TOAST_DURATION = 4.0f;
|
||||
std::vector<QuestProgressToastEntry> questToasts_;
|
||||
bool questProgressCallbackSet_ = false;
|
||||
void renderQuestProgressToasts();
|
||||
|
||||
// Nearby player level-up toast ("<Name> is now level X!")
|
||||
struct PlayerLevelUpToastEntry {
|
||||
uint64_t guid = 0;
|
||||
std::string playerName; // resolved lazily at render time
|
||||
uint32_t newLevel = 0;
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float PLAYER_LEVELUP_TOAST_DURATION = 4.0f;
|
||||
std::vector<PlayerLevelUpToastEntry> playerLevelUpToasts_;
|
||||
bool otherPlayerLevelUpCallbackSet_ = false;
|
||||
void renderPlayerLevelUpToasts(game::GameHandler& gameHandler);
|
||||
|
||||
// PvP honor credit toast ("+N Honor" shown when an honorable kill is credited)
|
||||
struct PvpHonorToastEntry {
|
||||
uint32_t honor = 0;
|
||||
uint32_t victimRank = 0; // 0 = unranked / not available
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float PVP_HONOR_TOAST_DURATION = 3.5f;
|
||||
std::vector<PvpHonorToastEntry> pvpHonorToasts_;
|
||||
bool pvpHonorCallbackSet_ = false;
|
||||
void renderPvpHonorToasts();
|
||||
|
||||
// Item loot toast — quality-coloured popup when an item is received
|
||||
struct ItemLootToastEntry {
|
||||
uint32_t itemId = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t quality = 1; // 0=grey,1=white,2=green,3=blue,4=purple,5=orange
|
||||
std::string name;
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float ITEM_LOOT_TOAST_DURATION = 3.0f;
|
||||
std::vector<ItemLootToastEntry> itemLootToasts_;
|
||||
bool itemLootCallbackSet_ = false;
|
||||
void renderItemLootToasts();
|
||||
|
||||
// Resurrection flash: brief "You have been resurrected!" overlay on ghost→alive transition
|
||||
float resurrectFlashTimer_ = 0.0f;
|
||||
static constexpr float kResurrectFlashDuration = 3.0f;
|
||||
bool ghostStateCallbackSet_ = false;
|
||||
bool appearanceCallbackSet_ = false;
|
||||
bool ghostOpacityStateKnown_ = false;
|
||||
bool ghostOpacityLastState_ = false;
|
||||
uint32_t ghostOpacityLastInstanceId_ = 0;
|
||||
void renderResurrectFlash();
|
||||
|
||||
// Zone discovery text ("Entering: <ZoneName>")
|
||||
static constexpr float ZONE_TEXT_DURATION = 5.0f;
|
||||
float zoneTextTimer_ = 0.0f;
|
||||
std::string zoneTextName_;
|
||||
std::string lastKnownZoneName_;
|
||||
uint32_t lastKnownWorldStateZoneId_ = 0;
|
||||
void renderZoneText(game::GameHandler& gameHandler);
|
||||
|
||||
void renderWeatherOverlay(game::GameHandler& gameHandler);
|
||||
|
||||
// Cooldown tracker
|
||||
bool showCooldownTracker_ = false;
|
||||
|
||||
// DPS / HPS meter
|
||||
bool showDPSMeter_ = false;
|
||||
float dpsCombatAge_ = 0.0f; // seconds in current combat (for accurate early-combat DPS)
|
||||
bool dpsWasInCombat_ = false;
|
||||
float dpsEncounterDamage_ = 0.0f; // total player damage this combat
|
||||
float dpsEncounterHeal_ = 0.0f; // total player healing this combat
|
||||
size_t dpsLogSeenCount_ = 0; // log entries already scanned
|
||||
|
||||
public:
|
||||
void triggerDing(uint32_t newLevel, uint32_t hpDelta = 0, uint32_t manaDelta = 0,
|
||||
uint32_t str = 0, uint32_t agi = 0, uint32_t sta = 0,
|
||||
uint32_t intel = 0, uint32_t spi = 0);
|
||||
void triggerAchievementToast(uint32_t achievementId, std::string name = {});
|
||||
void openDungeonFinder() { showDungeonFinder_ = true; }
|
||||
void openDungeonFinder() { socialPanel_.showDungeonFinder_ = true; }
|
||||
ToastManager& toastManager() { return toastManager_; }
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
|||
169
include/ui/settings_panel.hpp
Normal file
169
include/ui/settings_panel.hpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
|
||||
namespace wowee {
|
||||
namespace rendering { class Renderer; }
|
||||
namespace ui {
|
||||
|
||||
class InventoryScreen;
|
||||
class ChatPanel;
|
||||
|
||||
/**
|
||||
* Settings panel (extracted from GameScreen)
|
||||
*
|
||||
* Owns all settings UI rendering, settings state variables, and
|
||||
* graphics preset logic. Save/load remains in GameScreen since
|
||||
* it serialises cross-cutting state (chat, quest tracker, etc.).
|
||||
*/
|
||||
class SettingsPanel {
|
||||
public:
|
||||
// ---- Settings UI visibility flags (written by EscapeMenu / Escape key) ----
|
||||
bool showEscapeSettingsNotice = false;
|
||||
bool showSettingsWindow = false;
|
||||
bool settingsInit = false;
|
||||
|
||||
// ---- Pending video / graphics settings ----
|
||||
bool pendingFullscreen = false;
|
||||
bool pendingVsync = false;
|
||||
int pendingResIndex = 0;
|
||||
bool pendingShadows = true;
|
||||
float pendingShadowDistance = 300.0f;
|
||||
bool pendingWaterRefraction = true;
|
||||
int pendingBrightness = 50; // 0-100, maps to 0.0-2.0 (50 = 1.0 default)
|
||||
|
||||
// ---- Pending audio settings ----
|
||||
int pendingMasterVolume = 100;
|
||||
int pendingMusicVolume = 30;
|
||||
int pendingAmbientVolume = 100;
|
||||
int pendingUiVolume = 100;
|
||||
int pendingCombatVolume = 100;
|
||||
int pendingSpellVolume = 100;
|
||||
int pendingMovementVolume = 100;
|
||||
int pendingFootstepVolume = 100;
|
||||
int pendingNpcVoiceVolume = 100;
|
||||
int pendingMountVolume = 100;
|
||||
int pendingActivityVolume = 100;
|
||||
|
||||
// ---- Pending camera / controls ----
|
||||
float pendingMouseSensitivity = 0.2f;
|
||||
bool pendingInvertMouse = false;
|
||||
bool pendingExtendedZoom = false;
|
||||
float pendingCameraStiffness = 30.0f; // Camera smooth speed (higher = tighter, less sway)
|
||||
float pendingPivotHeight = 1.6f; // Camera pivot height above feet (lower = less detached feel)
|
||||
float pendingFov = 70.0f; // degrees, default matches WoW's ~70° horizontal FOV
|
||||
|
||||
// ---- Pending UI / interface ----
|
||||
int pendingUiOpacity = 65;
|
||||
bool pendingMinimapRotate = false;
|
||||
bool pendingMinimapSquare = false;
|
||||
bool pendingMinimapNpcDots = false;
|
||||
bool pendingShowLatencyMeter = true;
|
||||
bool pendingSeparateBags = true;
|
||||
bool pendingShowKeyring = true;
|
||||
|
||||
// ---- Pending gameplay ----
|
||||
bool pendingAutoLoot = false;
|
||||
bool pendingAutoSellGrey = false;
|
||||
bool pendingAutoRepair = false;
|
||||
|
||||
// ---- Pending soundtrack ----
|
||||
bool pendingUseOriginalSoundtrack = true;
|
||||
|
||||
// ---- Pending action bar layout ----
|
||||
bool pendingShowActionBar2 = true; // Show second action bar above main bar
|
||||
float pendingActionBarScale = 1.0f; // Multiplier for action bar slot size (0.5–1.5)
|
||||
float pendingActionBar2OffsetX = 0.0f; // Horizontal offset from default center position
|
||||
float pendingActionBar2OffsetY = 0.0f; // Vertical offset from default (above bar 1)
|
||||
bool pendingShowRightBar = false; // Right-edge vertical action bar (bar 3, slots 24-35)
|
||||
bool pendingShowLeftBar = false; // Left-edge vertical action bar (bar 4, slots 36-47)
|
||||
float pendingRightBarOffsetY = 0.0f; // Vertical offset from screen center
|
||||
float pendingLeftBarOffsetY = 0.0f; // Vertical offset from screen center
|
||||
|
||||
// ---- Pending graphics quality ----
|
||||
int pendingGroundClutterDensity = 100;
|
||||
int pendingAntiAliasing = 0; // 0=Off, 1=2x, 2=4x, 3=8x
|
||||
bool pendingFXAA = false; // FXAA post-process (combinable with MSAA)
|
||||
bool pendingNormalMapping = true; // on by default
|
||||
float pendingNormalMapStrength = 0.8f; // 0.0-2.0
|
||||
bool pendingPOM = true; // on by default
|
||||
int pendingPOMQuality = 1; // 0=Low(16), 1=Medium(32), 2=High(64)
|
||||
bool pendingFSR = false;
|
||||
int pendingUpscalingMode = 0; // 0=Off, 1=FSR1, 2=FSR3
|
||||
int pendingFSRQuality = 3; // 0=UltraQuality, 1=Quality, 2=Balanced, 3=Native(100%)
|
||||
float pendingFSRSharpness = 1.6f;
|
||||
float pendingFSR2JitterSign = 0.38f;
|
||||
float pendingFSR2MotionVecScaleX = 1.0f;
|
||||
float pendingFSR2MotionVecScaleY = 1.0f;
|
||||
bool pendingAMDFramegen = false;
|
||||
|
||||
// ---- Graphics quality presets ----
|
||||
enum class GraphicsPreset : int {
|
||||
CUSTOM = 0,
|
||||
LOW = 1,
|
||||
MEDIUM = 2,
|
||||
HIGH = 3,
|
||||
ULTRA = 4
|
||||
};
|
||||
GraphicsPreset currentGraphicsPreset = GraphicsPreset::CUSTOM;
|
||||
GraphicsPreset pendingGraphicsPreset = GraphicsPreset::CUSTOM;
|
||||
|
||||
// ---- Applied-once flags (used by GameScreen::render() one-time-apply blocks) ----
|
||||
bool fsrSettingsApplied_ = false;
|
||||
float uiOpacity_ = 0.65f; // UI element transparency (0.0 = fully transparent, 1.0 = fully opaque)
|
||||
bool minimapRotate_ = false;
|
||||
bool minimapSquare_ = false;
|
||||
bool minimapNpcDots_ = false;
|
||||
bool showLatencyMeter_ = true; // Show server latency indicator
|
||||
bool minimapSettingsApplied_ = false;
|
||||
bool volumeSettingsApplied_ = false; // True once saved volume settings applied to audio managers
|
||||
bool msaaSettingsApplied_ = false; // True once saved MSAA setting applied to renderer
|
||||
bool fxaaSettingsApplied_ = false; // True once saved FXAA setting applied to renderer
|
||||
bool waterRefractionApplied_ = false;
|
||||
bool normalMapSettingsApplied_ = false; // True once saved normal map/POM settings applied
|
||||
|
||||
// ---- Mute state: mute bypasses master volume without touching slider values ----
|
||||
bool soundMuted_ = false;
|
||||
float preMuteVolume_ = 1.0f; // AudioEngine master volume before muting
|
||||
|
||||
// ---- Config toggles (read by GameScreen rendering, edited by Interface tab) ----
|
||||
float nameplateScale_ = 1.0f; // Scale multiplier for nameplate bar dimensions
|
||||
bool showFriendlyNameplates_ = true; // Shift+V toggles friendly player nameplates
|
||||
bool showDPSMeter_ = false;
|
||||
bool showCooldownTracker_ = false;
|
||||
bool damageFlashEnabled_ = true;
|
||||
bool lowHealthVignetteEnabled_ = true; // Persistent pulsing red vignette below 20% HP
|
||||
|
||||
// ---- Public methods ----
|
||||
|
||||
/// Render the settings window (call from GameScreen::render)
|
||||
void renderSettingsWindow(InventoryScreen& inventoryScreen, ChatPanel& chatPanel,
|
||||
std::function<void()> saveCallback);
|
||||
|
||||
/// Apply audio volume levels to all renderer sound managers
|
||||
void applyAudioVolumes(rendering::Renderer* renderer);
|
||||
|
||||
/// Return the platform-specific settings file path
|
||||
static std::string getSettingsPath();
|
||||
|
||||
private:
|
||||
// Keybinding customization (private — only used in Controls tab)
|
||||
int pendingRebindAction_ = -1; // -1 = not rebinding, otherwise action index
|
||||
bool awaitingKeyPress_ = false;
|
||||
|
||||
// Settings tab rendering
|
||||
void renderSettingsInterfaceTab(std::function<void()> saveCallback);
|
||||
void renderSettingsGameplayTab(InventoryScreen& inventoryScreen,
|
||||
std::function<void()> saveCallback);
|
||||
void renderSettingsControlsTab(std::function<void()> saveCallback);
|
||||
void renderSettingsAudioTab(std::function<void()> saveCallback);
|
||||
void renderSettingsAboutTab();
|
||||
void applyGraphicsPreset(GraphicsPreset preset);
|
||||
void updateGraphicsPresetFromCurrentSettings();
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace wowee
|
||||
77
include/ui/social_panel.hpp
Normal file
77
include/ui/social_panel.hpp
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace wowee {
|
||||
namespace game { class GameHandler; }
|
||||
namespace pipeline { class AssetManager; }
|
||||
namespace ui {
|
||||
|
||||
class ChatPanel;
|
||||
class SpellbookScreen;
|
||||
class InventoryScreen;
|
||||
|
||||
/**
|
||||
* Social panel manager (extracted from GameScreen)
|
||||
*
|
||||
* Owns all social/group-related rendering:
|
||||
* party frames, boss frames, guild roster, social/friends frame,
|
||||
* dungeon finder, who window, inspect window.
|
||||
*/
|
||||
class SocialPanel {
|
||||
public:
|
||||
SocialPanel() = default;
|
||||
|
||||
// ---- Callback type for spell icon lookup (stays in GameScreen) ----
|
||||
using SpellIconFn = std::function<VkDescriptorSet(uint32_t spellId, pipeline::AssetManager*)>;
|
||||
|
||||
// ---- Toggle booleans (written by slash commands / escape handler / keybinds / UI buttons) ----
|
||||
bool showSocialFrame_ = false; // O key toggles social/friends list
|
||||
bool showGuildRoster_ = false;
|
||||
bool showRaidFrames_ = true; // F key toggles raid/party frames
|
||||
bool showWhoWindow_ = false;
|
||||
bool showDungeonFinder_ = false;
|
||||
bool showInspectWindow_ = false;
|
||||
|
||||
// ---- Guild roster state ----
|
||||
std::string selectedGuildMember_;
|
||||
bool showGuildNoteEdit_ = false;
|
||||
bool editingOfficerNote_ = false;
|
||||
char guildNoteEditBuffer_[256] = {0};
|
||||
int guildRosterTab_ = 0; // 0=Roster, 1=Guild Info
|
||||
char guildMotdEditBuffer_[256] = {0};
|
||||
bool showMotdEdit_ = false;
|
||||
char petitionNameBuffer_[64] = {0};
|
||||
char addRankNameBuffer_[64] = {0};
|
||||
bool showAddRankModal_ = false;
|
||||
|
||||
// ---- LFG state ----
|
||||
uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps)
|
||||
uint32_t lfgSelectedDungeon_ = 861; // default: random dungeon (entry 861)
|
||||
|
||||
// ---- Public render methods ----
|
||||
void renderPartyFrames(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel,
|
||||
SpellIconFn getSpellIcon);
|
||||
void renderBossFrames(game::GameHandler& gameHandler,
|
||||
SpellbookScreen& spellbookScreen,
|
||||
SpellIconFn getSpellIcon);
|
||||
void renderGuildRoster(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel);
|
||||
void renderSocialFrame(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel);
|
||||
void renderDungeonFinderWindow(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel);
|
||||
void renderWhoWindow(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel);
|
||||
void renderInspectWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace wowee
|
||||
190
include/ui/toast_manager.hpp
Normal file
190
include/ui/toast_manager.hpp
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <imgui.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace wowee {
|
||||
namespace game { class GameHandler; }
|
||||
namespace ui {
|
||||
|
||||
/**
|
||||
* Toast / notification overlay manager
|
||||
*
|
||||
* Owns all toast state, callbacks, and rendering:
|
||||
* level-up ding, achievement, area discovery, whisper, quest progress,
|
||||
* player level-up, PvP honor, item loot, reputation, quest complete,
|
||||
* zone entry, area trigger, resurrect flash, and zone text.
|
||||
*/
|
||||
class ToastManager {
|
||||
public:
|
||||
ToastManager() = default;
|
||||
|
||||
/// Register toast-related callbacks on GameHandler (idempotent — safe every frame)
|
||||
void setupCallbacks(game::GameHandler& gameHandler);
|
||||
|
||||
/// Render "early" toasts (rep, quest-complete, zone, area-trigger) — called before action bars
|
||||
void renderEarlyToasts(float deltaTime, game::GameHandler& gameHandler);
|
||||
|
||||
/// Render "late" toasts (ding, achievement, discovery, whisper, quest progress,
|
||||
/// player level-up, PvP honor, item loot, resurrect flash, zone text) — called after escape menu
|
||||
void renderLateToasts(game::GameHandler& gameHandler);
|
||||
|
||||
/// Fire level-up ding animation + sound
|
||||
void triggerDing(uint32_t newLevel, uint32_t hpDelta = 0, uint32_t manaDelta = 0,
|
||||
uint32_t str = 0, uint32_t agi = 0, uint32_t sta = 0,
|
||||
uint32_t intel = 0, uint32_t spi = 0);
|
||||
|
||||
/// Fire achievement earned toast + sound
|
||||
void triggerAchievementToast(uint32_t achievementId, std::string name = {});
|
||||
|
||||
// --- public state consumed by GameScreen for the golden burst overlay ---
|
||||
float levelUpFlashAlpha = 0.0f;
|
||||
uint32_t levelUpDisplayLevel = 0;
|
||||
|
||||
private:
|
||||
// ---- Ding effect (own level-up) ----
|
||||
static constexpr float DING_DURATION = 4.0f;
|
||||
float dingTimer_ = 0.0f;
|
||||
uint32_t dingLevel_ = 0;
|
||||
uint32_t dingHpDelta_ = 0;
|
||||
uint32_t dingManaDelta_ = 0;
|
||||
uint32_t dingStats_[5] = {};
|
||||
void renderDingEffect();
|
||||
|
||||
// ---- Achievement toast ----
|
||||
static constexpr float ACHIEVEMENT_TOAST_DURATION = 5.0f;
|
||||
float achievementToastTimer_ = 0.0f;
|
||||
uint32_t achievementToastId_ = 0;
|
||||
std::string achievementToastName_;
|
||||
bool achievementCallbackSet_ = false;
|
||||
void renderAchievementToast();
|
||||
|
||||
// ---- Area discovery toast ----
|
||||
static constexpr float DISCOVERY_TOAST_DURATION = 4.0f;
|
||||
float discoveryToastTimer_ = 0.0f;
|
||||
std::string discoveryToastName_;
|
||||
uint32_t discoveryToastXP_ = 0;
|
||||
bool areaDiscoveryCallbackSet_ = false;
|
||||
void renderDiscoveryToast();
|
||||
|
||||
// ---- Whisper toast ----
|
||||
struct WhisperToastEntry {
|
||||
std::string sender;
|
||||
std::string preview;
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float WHISPER_TOAST_DURATION = 5.0f;
|
||||
std::vector<WhisperToastEntry> whisperToasts_;
|
||||
size_t whisperSeenCount_ = 0;
|
||||
void renderWhisperToasts();
|
||||
|
||||
// ---- Quest objective progress toast ----
|
||||
struct QuestProgressToastEntry {
|
||||
std::string questTitle;
|
||||
std::string objectiveName;
|
||||
uint32_t current = 0;
|
||||
uint32_t required = 0;
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float QUEST_TOAST_DURATION = 4.0f;
|
||||
std::vector<QuestProgressToastEntry> questToasts_;
|
||||
bool questProgressCallbackSet_ = false;
|
||||
void renderQuestProgressToasts();
|
||||
|
||||
// ---- Nearby player level-up toast ----
|
||||
struct PlayerLevelUpToastEntry {
|
||||
uint64_t guid = 0;
|
||||
std::string playerName;
|
||||
uint32_t newLevel = 0;
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float PLAYER_LEVELUP_TOAST_DURATION = 4.0f;
|
||||
std::vector<PlayerLevelUpToastEntry> playerLevelUpToasts_;
|
||||
bool otherPlayerLevelUpCallbackSet_ = false;
|
||||
void renderPlayerLevelUpToasts(game::GameHandler& gameHandler);
|
||||
|
||||
// ---- PvP honor toast ----
|
||||
struct PvpHonorToastEntry {
|
||||
uint32_t honor = 0;
|
||||
uint32_t victimRank = 0;
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float PVP_HONOR_TOAST_DURATION = 3.5f;
|
||||
std::vector<PvpHonorToastEntry> pvpHonorToasts_;
|
||||
bool pvpHonorCallbackSet_ = false;
|
||||
void renderPvpHonorToasts();
|
||||
|
||||
// ---- Item loot toast ----
|
||||
struct ItemLootToastEntry {
|
||||
uint32_t itemId = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t quality = 1;
|
||||
std::string name;
|
||||
float age = 0.0f;
|
||||
};
|
||||
static constexpr float ITEM_LOOT_TOAST_DURATION = 3.0f;
|
||||
std::vector<ItemLootToastEntry> itemLootToasts_;
|
||||
bool itemLootCallbackSet_ = false;
|
||||
void renderItemLootToasts();
|
||||
|
||||
// ---- Reputation change toast ----
|
||||
struct RepToastEntry {
|
||||
std::string factionName;
|
||||
int32_t delta = 0;
|
||||
int32_t standing = 0;
|
||||
float age = 0.0f;
|
||||
};
|
||||
std::vector<RepToastEntry> repToasts_;
|
||||
bool repChangeCallbackSet_ = false;
|
||||
static constexpr float kRepToastLifetime = 3.5f;
|
||||
void renderRepToasts(float deltaTime);
|
||||
|
||||
// ---- Quest completion toast ----
|
||||
struct QuestCompleteToastEntry {
|
||||
uint32_t questId = 0;
|
||||
std::string title;
|
||||
float age = 0.0f;
|
||||
};
|
||||
std::vector<QuestCompleteToastEntry> questCompleteToasts_;
|
||||
bool questCompleteCallbackSet_ = false;
|
||||
static constexpr float kQuestCompleteToastLifetime = 4.0f;
|
||||
void renderQuestCompleteToasts(float deltaTime);
|
||||
|
||||
// ---- Zone entry toast ----
|
||||
struct ZoneToastEntry {
|
||||
std::string zoneName;
|
||||
float age = 0.0f;
|
||||
};
|
||||
std::vector<ZoneToastEntry> zoneToasts_;
|
||||
std::string lastKnownZone_;
|
||||
static constexpr float kZoneToastLifetime = 3.0f;
|
||||
void renderZoneToasts(float deltaTime);
|
||||
|
||||
// ---- Area trigger message toast ----
|
||||
struct AreaTriggerToast {
|
||||
std::string text;
|
||||
float age = 0.0f;
|
||||
};
|
||||
std::vector<AreaTriggerToast> areaTriggerToasts_;
|
||||
void renderAreaTriggerToasts(float deltaTime, game::GameHandler& gameHandler);
|
||||
|
||||
// ---- Resurrection flash ----
|
||||
float resurrectFlashTimer_ = 0.0f;
|
||||
static constexpr float kResurrectFlashDuration = 3.0f;
|
||||
bool ghostStateCallbackSet_ = false;
|
||||
void renderResurrectFlash();
|
||||
|
||||
// ---- Zone discovery text ("Entering: <ZoneName>") ----
|
||||
static constexpr float ZONE_TEXT_DURATION = 5.0f;
|
||||
float zoneTextTimer_ = 0.0f;
|
||||
std::string zoneTextName_;
|
||||
std::string lastKnownZoneName_;
|
||||
uint32_t lastKnownWorldStateZoneId_ = 0;
|
||||
void renderZoneText(game::GameHandler& gameHandler);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace wowee
|
||||
182
include/ui/window_manager.hpp
Normal file
182
include/ui/window_manager.hpp
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// ============================================================
|
||||
// WindowManager — extracted from GameScreen
|
||||
// Owns all NPC interaction windows, popup dialogs, and misc
|
||||
// overlay UI: loot, gossip, quest, vendor, trainer, mail, bank,
|
||||
// auction house, barber, stable, taxi, escape menu, death screen,
|
||||
// instance lockouts, achievements, GM ticket, books, titles,
|
||||
// equipment sets, skills.
|
||||
// ============================================================
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace wowee {
|
||||
namespace game { class GameHandler; }
|
||||
namespace pipeline { class AssetManager; }
|
||||
namespace ui {
|
||||
|
||||
class ChatPanel;
|
||||
class SettingsPanel;
|
||||
class InventoryScreen;
|
||||
class SpellbookScreen;
|
||||
|
||||
class WindowManager {
|
||||
public:
|
||||
// Callback type for resolving spell icons (spellId, assetMgr) → VkDescriptorSet
|
||||
using SpellIconFn = std::function<VkDescriptorSet(uint32_t, pipeline::AssetManager*)>;
|
||||
|
||||
// ---- NPC interaction windows ----
|
||||
void renderLootWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
void renderGossipWindow(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel);
|
||||
void renderQuestDetailsWindow(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel,
|
||||
InventoryScreen& inventoryScreen);
|
||||
void renderQuestRequestItemsWindow(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel,
|
||||
InventoryScreen& inventoryScreen);
|
||||
void renderQuestOfferRewardWindow(game::GameHandler& gameHandler,
|
||||
ChatPanel& chatPanel,
|
||||
InventoryScreen& inventoryScreen);
|
||||
void renderVendorWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
void renderTrainerWindow(game::GameHandler& gameHandler,
|
||||
SpellIconFn getSpellIcon);
|
||||
void renderBarberShopWindow(game::GameHandler& gameHandler);
|
||||
void renderStableWindow(game::GameHandler& gameHandler);
|
||||
void renderTaxiWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// ---- Mail and banking ----
|
||||
void renderMailWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
void renderMailComposeWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen);
|
||||
void renderBankWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
void renderGuildBankWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
void renderAuctionHouseWindow(game::GameHandler& gameHandler,
|
||||
InventoryScreen& inventoryScreen,
|
||||
ChatPanel& chatPanel);
|
||||
|
||||
// ---- Popup / overlay windows ----
|
||||
void renderEscapeMenu(SettingsPanel& settingsPanel);
|
||||
void renderLogoutCountdown(game::GameHandler& gameHandler);
|
||||
void renderDeathScreen(game::GameHandler& gameHandler);
|
||||
void renderReclaimCorpseButton(game::GameHandler& gameHandler);
|
||||
void renderInstanceLockouts(game::GameHandler& gameHandler);
|
||||
void renderAchievementWindow(game::GameHandler& gameHandler);
|
||||
void renderGmTicketWindow(game::GameHandler& gameHandler);
|
||||
void renderBookWindow(game::GameHandler& gameHandler);
|
||||
void renderTitlesWindow(game::GameHandler& gameHandler);
|
||||
void renderEquipSetWindow(game::GameHandler& gameHandler);
|
||||
void renderSkillsWindow(game::GameHandler& gameHandler);
|
||||
|
||||
// ---- State owned by this manager ----
|
||||
|
||||
// Instance lockouts
|
||||
bool showInstanceLockouts_ = false;
|
||||
|
||||
// Achievements
|
||||
bool showAchievementWindow_ = false;
|
||||
char achievementSearchBuf_[128] = {};
|
||||
|
||||
// Skills / Professions
|
||||
bool showSkillsWindow_ = false;
|
||||
|
||||
// Titles
|
||||
bool showTitlesWindow_ = false;
|
||||
|
||||
// Equipment Sets
|
||||
bool showEquipSetWindow_ = false;
|
||||
|
||||
// GM Ticket
|
||||
bool showGmTicketWindow_ = false;
|
||||
bool gmTicketWindowWasOpen_ = false;
|
||||
char gmTicketBuf_[2048] = {};
|
||||
|
||||
// Book / scroll reader
|
||||
bool showBookWindow_ = false;
|
||||
int bookCurrentPage_ = 0;
|
||||
|
||||
// Death screen
|
||||
float deathElapsed_ = 0.0f;
|
||||
bool deathTimerRunning_ = false;
|
||||
static constexpr float kForcedReleaseSec = 360.0f;
|
||||
|
||||
// Escape menu
|
||||
bool showEscapeMenu = false;
|
||||
|
||||
// Mail compose
|
||||
char mailRecipientBuffer_[256] = "";
|
||||
char mailSubjectBuffer_[256] = "";
|
||||
char mailBodyBuffer_[2048] = "";
|
||||
int mailComposeMoney_[3] = {0, 0, 0};
|
||||
|
||||
// Vendor
|
||||
char vendorSearchFilter_[128] = "";
|
||||
bool vendorConfirmOpen_ = false;
|
||||
uint64_t vendorConfirmGuid_ = 0;
|
||||
uint32_t vendorConfirmItemId_ = 0;
|
||||
uint32_t vendorConfirmSlot_ = 0;
|
||||
uint32_t vendorConfirmQty_ = 1;
|
||||
uint32_t vendorConfirmPrice_ = 0;
|
||||
std::string vendorConfirmItemName_;
|
||||
bool vendorBagsOpened_ = false;
|
||||
|
||||
// Barber shop
|
||||
int barberHairStyle_ = 0;
|
||||
int barberHairColor_ = 0;
|
||||
int barberFacialHair_ = 0;
|
||||
int barberOrigHairStyle_ = 0;
|
||||
int barberOrigHairColor_ = 0;
|
||||
int barberOrigFacialHair_ = 0;
|
||||
bool barberInitialized_ = false;
|
||||
|
||||
// Trainer
|
||||
char trainerSearchFilter_[128] = "";
|
||||
|
||||
// Auction house
|
||||
char auctionSearchName_[256] = "";
|
||||
int auctionLevelMin_ = 0;
|
||||
int auctionLevelMax_ = 0;
|
||||
int auctionQuality_ = 0;
|
||||
int auctionSellDuration_ = 2;
|
||||
int auctionSellBid_[3] = {0, 0, 0};
|
||||
int auctionSellBuyout_[3] = {0, 0, 0};
|
||||
int auctionSelectedItem_ = -1;
|
||||
int auctionSellSlotIndex_ = -1;
|
||||
uint32_t auctionBrowseOffset_ = 0;
|
||||
int auctionItemClass_ = -1;
|
||||
int auctionItemSubClass_ = -1;
|
||||
bool auctionUsableOnly_ = false;
|
||||
|
||||
// Guild bank money input
|
||||
int guildBankMoneyInput_[3] = {0, 0, 0};
|
||||
|
||||
// ItemExtendedCost.dbc cache
|
||||
struct ExtendedCostEntry {
|
||||
uint32_t honorPoints = 0;
|
||||
uint32_t arenaPoints = 0;
|
||||
uint32_t itemId[5] = {};
|
||||
uint32_t itemCount[5] = {};
|
||||
};
|
||||
std::unordered_map<uint32_t, ExtendedCostEntry> extendedCostCache_;
|
||||
bool extendedCostDbLoaded_ = false;
|
||||
|
||||
private:
|
||||
void loadExtendedCostDBC();
|
||||
std::string formatExtendedCost(uint32_t extendedCostId, game::GameHandler& gameHandler);
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace wowee
|
||||
|
|
@ -2935,7 +2935,7 @@ void Application::setupUICallbacks() {
|
|||
// Level-up callback — play sound, cheer emote, and trigger UI ding overlay + 3D effect
|
||||
gameHandler->setLevelUpCallback([this](uint32_t newLevel) {
|
||||
if (uiManager) {
|
||||
uiManager->getGameScreen().triggerDing(newLevel);
|
||||
uiManager->getGameScreen().toastManager().triggerDing(newLevel);
|
||||
}
|
||||
if (renderer) {
|
||||
renderer->triggerLevelUpEffect(renderer->getCharacterPosition());
|
||||
|
|
@ -2945,7 +2945,7 @@ void Application::setupUICallbacks() {
|
|||
// Achievement earned callback — show toast banner
|
||||
gameHandler->setAchievementEarnedCallback([this](uint32_t achievementId, const std::string& name) {
|
||||
if (uiManager) {
|
||||
uiManager->getGameScreen().triggerAchievementToast(achievementId, name);
|
||||
uiManager->getGameScreen().toastManager().triggerAchievementToast(achievementId, name);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1266,14 +1266,14 @@ struct EntityController::GameObjectTypeHandler : EntityController::IObjectTypeHa
|
|||
struct EntityController::ItemTypeHandler : EntityController::IObjectTypeHandler {
|
||||
EntityController& ctl_;
|
||||
explicit ItemTypeHandler(EntityController& c) : ctl_(c) {}
|
||||
void onCreate(const UpdateBlock& block, std::shared_ptr<Entity>&, bool& newItemCreated) override { ctl_.onCreateItem(block, newItemCreated); }
|
||||
void onCreate(const UpdateBlock& block, std::shared_ptr<Entity>& /*entity*/, bool& newItemCreated) override { ctl_.onCreateItem(block, newItemCreated); }
|
||||
void onValuesUpdate(const UpdateBlock& block, std::shared_ptr<Entity>& entity) override { ctl_.onValuesUpdateItem(block, entity); }
|
||||
};
|
||||
|
||||
struct EntityController::CorpseTypeHandler : EntityController::IObjectTypeHandler {
|
||||
EntityController& ctl_;
|
||||
explicit CorpseTypeHandler(EntityController& c) : ctl_(c) {}
|
||||
void onCreate(const UpdateBlock& block, std::shared_ptr<Entity>&, bool&) override { ctl_.onCreateCorpse(block); }
|
||||
void onCreate(const UpdateBlock& block, std::shared_ptr<Entity>& /*entity*/, bool&) override { ctl_.onCreateCorpse(block); }
|
||||
};
|
||||
|
||||
// ============================================================
|
||||
|
|
|
|||
1751
src/ui/action_bar_panel.cpp
Normal file
1751
src/ui/action_bar_panel.cpp
Normal file
File diff suppressed because it is too large
Load diff
4898
src/ui/chat_panel.cpp
Normal file
4898
src/ui/chat_panel.cpp
Normal file
File diff suppressed because it is too large
Load diff
1890
src/ui/combat_ui.cpp
Normal file
1890
src/ui/combat_ui.cpp
Normal file
File diff suppressed because it is too large
Load diff
1115
src/ui/dialog_manager.cpp
Normal file
1115
src/ui/dialog_manager.cpp
Normal file
File diff suppressed because it is too large
Load diff
19216
src/ui/game_screen.cpp
19216
src/ui/game_screen.cpp
File diff suppressed because it is too large
Load diff
1258
src/ui/settings_panel.cpp
Normal file
1258
src/ui/settings_panel.cpp
Normal file
File diff suppressed because it is too large
Load diff
2626
src/ui/social_panel.cpp
Normal file
2626
src/ui/social_panel.cpp
Normal file
File diff suppressed because it is too large
Load diff
1250
src/ui/toast_manager.cpp
Normal file
1250
src/ui/toast_manager.cpp
Normal file
File diff suppressed because it is too large
Load diff
4264
src/ui/window_manager.cpp
Normal file
4264
src/ui/window_manager.cpp
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue