Commit graph

1035 commits

Author SHA1 Message Date
Paul
5af9f7aa4b chore(renderer): extract AnimationController and remove audio pass-throughs
Extract ~1,500 lines of character animation state from Renderer into a dedicated
AnimationController class, and complete the AudioCoordinator migration by removing
all 10 audio pass-through getters from Renderer.

AnimationController:
- New: include/rendering/animation_controller.hpp (182 lines)
- New: src/rendering/animation_controller.cpp (1,703 lines)
- Moves: locomotion state machine (50+ members), mount animation (40+ members),
  emote system, footstep triggering, surface detection, melee combat animations
- Renderer holds std::unique_ptr<AnimationController> and delegates completely
- AnimationController accesses audio via renderer_->getAudioCoordinator()

Audio caller migration:
- Migrate ~60 external callers from renderer->getXManager() to AudioCoordinator
  directly, grouped by access pattern:
  - UIServices: settings_panel, game_screen, toast_manager, chat_panel,
    combat_ui, window_manager
  - GameServices: game_handler, spell_handler, inventory_handler, quest_handler,
    social_handler, combat_handler
  - Application singleton: application.cpp, auth_screen.cpp, lua_engine.cpp
- Remove 10 pass-through getter definitions from renderer.cpp
- Remove 10 pass-through getter declarations from renderer.hpp
- Remove individual audio manager forward declarations from renderer.hpp
- Redirect 69 internal renderer.cpp audio calls to audioCoordinator_ directly
- game_handler.cpp: withSoundManager template uses services_.audioCoordinator;
  MFP changed from &Renderer::getUiSoundManager to &AudioCoordinator::getUiSoundManager
- GameServices struct: add AudioCoordinator* audioCoordinator member
- settings_panel: applyAudioVolumes(Renderer*) -> applyAudioVolumes(AudioCoordinator*)
2026-04-02 13:06:31 +03:00
Paul
1c0e9dd1df chore(application): extract appearance controller and unify UI flow
- Refactor UI application architecture: extracted appearance controller into ui_services.hpp + implementation updates
- Update UI components and managers to use new service layer:
  - `action_bar_panel`, `auth_screen`, `character_screen`, `chat_panel`, `combat_ui`, `dialog_manager`, `game_screen`, `settings_panel`, `social_panel`, `toast_manager`, `ui_manager`, `window_manager`
- Adjust core application entrypoints:
  - application.cpp
- Update component implementations for new controller flow:
  - action_bar_panel.cpp, `chat_panel.cpp`, `combat_ui.cpp`, `dialog_manager.cpp`, `game_screen.cpp`, `settings_panel.cpp`, `social_panel.cpp`, `toast_manager.cpp`, `window_manager.cpp`

These staged changes implement a major architectural refactor for UI/appearance controller separation
2026-04-01 20:59:17 +03:00
Paul
d43397163e refactor: decouple Application singleton by extracting core subsystems and updating interfaces
- Add `audio::AudioCoordinator` interface and implementation
- Modify `Application` to reduce singleton usage and move controller responsibilities:
  - application.hpp
  - application.cpp
- Update UI and audio headers/sources:
  - game_screen.hpp
  - game_screen.cpp
  - ui_manager.hpp
  - audio_coordinator.hpp
  - audio_coordinator.cpp
- Project config touched:
  - CMakeLists.txt
2026-04-01 20:38:37 +03:00
Paul
afeaa13562 chore(application): extract entity spawner + composer, apply app and UI updates
- add include/core/appearance_composer.hpp + src/core/appearance_composer.cpp
- update include/core/application.hpp + src/core/application.cpp
- update src/ui/game_screen.cpp
- adjust CMakeLists.txt and README.md for new composer module
2026-04-01 13:31:48 +03:00
Paul
0e6aaeb44e fix warnings, remove phases from commentaries 2026-03-31 20:11:28 +03:00
Paul
43aecab1ef Merge commit '32bb0becc8' into chore/game-screen-extract 2026-03-31 19:51:37 +03:00
Paul
c9353853f8 chore(game-ui): extract GameScreen domains
- Extracted `GameScreen` functionality into dedicated UI domains
- Added new panels:
  - `action_bar_panel`
  - `combat_ui`
  - `social_panel`
  - `window_manager`
- Updated `game_screen` + CMakeLists.txt integration
- Added new headers and sources under ui and ui
2026-03-31 19:49:52 +03:00
Paul
af9874484a chore(game-ui): extract GameScreen domains into DialogManager + SettingsPanel
- Add `DialogManager` + `SettingsPanel` UI modules
- Refactor `GameScreen` to delegate dialogs and settings to new domains
- Update CMakeLists.txt to include new sources
- Include header/source files:
  - dialog_manager.hpp
  - settings_panel.hpp
  - dialog_manager.cpp
  - settings_panel.cpp
  - game_screen.cpp
- Keep `GameScreen` surface behavior while decoupling feature responsibilities
2026-03-31 10:07:58 +03:00
Paul
9764286cae chore(game-screen): extract toast manager from game screen
- refactor: move toast UI logic into new `ToastManager` component
- add toast_manager.hpp + toast_manager.cpp
- update game_screen.hpp + game_screen.cpp to use `ToastManager`
- adjust app initialization in application.cpp
- keep root CMake target in CMakeLists.txt updated
2026-03-31 09:18:17 +03:00
Paul
0f1cd5fe9a chore(game-ui): extract chat panel into dedicated UI module
- moved chat panel logic out of `game_screen` into `chat_panel`
- added chat_panel.hpp and chat_panel.cpp
- updated game_screen.hpp and game_screen.cpp to integrate new `ChatPanel` component
- updated build config in CMakeLists.txt to include new UI module sources
2026-03-31 08:53:14 +03:00
Kelsi
cb17c69c40 docs: add why-comments to spellbook icon caching and DBC fallback
- Explain icon load deferral strategy: returning null without caching
  allows retry next frame when budget resets, rather than permanently
  blacklisting icons that were deferred due to rate-limiting
- Explain DBC field fallback logic: hard-coded WotLK indices are a
  safety net when dbc_layouts.json is missing; fieldCount >= 200
  distinguishes WotLK (234 fields) from Classic (148)
2026-03-30 17:32:07 -07:00
Kelsi
92369c1cec docs: add why-comments to rendering, packets, and UI code
- charge_effect: explain inversesqrt guard (prevents NaN on stationary
  character) and dust accumulator rate (30 particles/sec * 16ms)
- swim_effects: explain why insect pipeline disables depth test
  (screen-space sprites must render above water geometry)
- packet_parsers_classic: explain spline waypoint cap (DoS prevention)
  and packed GUID compression format (non-zero bytes only, mask byte)
- talent_screen: explain class ID to bitmask conversion (1-indexed
  WoW class IDs → power-of-2 mask for TalentTab.classMask matching)
- auth_screen: explain login music volume reduction (80% so UI sounds
  remain audible over background track)
2026-03-30 17:23:07 -07:00
Kelsi
4215950dcd refactor: extract class/race restriction helpers, add DBC fallback comment
- inventory_screen: extract renderClassRestriction() and
  renderRaceRestriction() from two identical 40-line blocks in quest
  info and item info tooltips. Both used identical bitmask logic,
  strncat formatting, and player-class/race validation (-49 lines net)
- world_map: add why-comment on AreaTable.dbc fallback field indices —
  explains that incorrect indices silently return wrong data and why
  the WotLK stock layout (ID=0, Parent=2, ExploreFlag=3) is chosen
  as the safest default
2026-03-30 15:45:48 -07:00
Kelsi
169595433a debug: add GO interaction diagnostics at every decision point
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
Adds [GO-DIAG] WARNING-level logs at:
- Right-click dispatch (raypick hit / re-interact with target)
- interactWithGameObject entry + all BLOCKED paths
- SMSG_SPELL_GO (wasInTimedCast, lastGoGuid, pendingGoGuid state)
- SMSG_LOOT_RESPONSE (items, gold, guid)
- Raypick candidate GO positions (entity pos + hit center + radius)

These logs will pinpoint exactly where the interaction fails:
- No GO-DIAG lines = GOs not in entity manager / not visible
- Raypick GO pos=(0,0,0) = GO position not set from update block
- BLOCKED = guard condition preventing interaction
- SPELL_GO wasInTimedCast=false = timer race (already fixed)
2026-03-29 23:09:28 -07:00
Kelsi
f23a7c06d9 fix: nameplate click hitbox used name text width, not health bar width
The click region for targeting via nameplates was bounded by the name
text (nameX to nameX+textSize.x). Short names like "Wolf" produced a
~30px clickable strip, while the health bar below was 80px wide. Clicks
on the bar outside the name text bounds were ignored. Now uses the wider
of name text or health bar for the horizontal hit area.
2026-03-29 21:54:57 -07:00
Kelsi
5583573beb fix: eliminate last std::rand() calls — music shuffle and UI weather
zone_manager.cpp used std::rand() for music track selection with modulo
bias and global state. game_screen.cpp used std::rand() for rain/snow
particle positions. Both now use local std::mt19937 seeded from
random_device. Also removes the global srand(time(nullptr)) call since
no code depends on the C rand() seed anymore.

No std::rand() or srand() calls remain in the codebase.
2026-03-29 21:01:51 -07:00
Kelsi
f02be1ffac fix: tolower/toupper UB on signed char at 10 remaining call sites
Final sweep across mpq_manager, application, auth_screen, wmo_renderer,
character_renderer, and terrain_manager. All now use the unsigned char
cast pattern. No remaining bare ::tolower/::toupper or std::tolower(c)
calls on signed char in the codebase.
2026-03-29 20:27:16 -07:00
Kelsi
27b2322444 fix: chat mention highlight only covered first line of wrapped messages
The golden tint rect was drawn before rendering with a hardcoded single-
line height. Multi-line wrapped messages only had the first line
highlighted. Now drawn after EndGroup() using GetItemRectMin/Max so the
rect covers all wrapped lines.

Also fixes std::tolower(char) UB at two call sites — negative char
values (extended ASCII) are undefined behavior without unsigned cast.
2026-03-29 19:43:38 -07:00
Kelsi
e629898bfb fix: nameplate health bar division by zero when maxHealth is 0
Freshly spawned entities have maxHealth=0 before fields populate.
0/0 produces NaN which propagates through all geometry calculations
for that nameplate frame. Guard with a maxHealth>0 check.
2026-03-29 19:08:51 -07:00
Kelsi
0795430390 cleanup: remove dead pos=0 reassignment and demote chat logs to DEBUG
Quest log had a redundant pos=0 right after initialization. Chat handler
logged every incoming/outgoing message at WARNING level, flooding the
log and obscuring genuine warnings.
2026-03-29 18:11:49 -07:00
Kelsi
309fd11a7b fix: cast bar invisible due to stale ImGui saved window position
The cast bar window used ImGuiCond_FirstUseEver for positioning, so
ImGui's .ini state restored a stale off-screen position from a prior
session. Switch to ImGuiCond_Always and add NoSavedSettings flag so
the bar always renders centered near the bottom of the screen.

Also demotes remaining diagnostic logs to LOG_DEBUG.
2026-03-29 17:20:02 -07:00
Kelsi
11571c582b fix: hearthstone from action bar, far teleport loading screen
Action bar hearthstone: the slot was type SPELL (spell 8690) not ITEM.
castSpell sends CMSG_CAST_SPELL which the server rejects for item-use
spells. Now detects item-use spells via getItemIdForSpell() and routes
through useItemById() instead, sending CMSG_USE_ITEM correctly.

Far same-map teleport: hearthstone on the same continent (e.g., Westfall
→ Stormwind on Azeroth) skipped the loading screen, so the player fell
through unloaded terrain. Now triggers a full world reload with loading
screen for teleports > 500 units, with the warmup ground check ensuring
WMO floors are loaded before spawning.
2026-03-28 14:55:58 -07:00
Kelsi
21fb2aa11c fix: backpack window jumps position when selling items (missing ##id in title) 2026-03-28 14:42:21 -07:00
Kelsi
b9ac3de498 tweak: camera defaults stiffness=30, pivot height=1.6 2026-03-28 11:45:21 -07:00
Kelsi
416e091498 feat: add Camera Stiffness and Pivot Height settings for motion comfort
Camera Stiffness (default 20, range 5-100): controls how tightly the
camera follows the player. Higher values = less sway/lag. Users who
experience motion sickness can increase this to reduce floaty camera.

Camera Pivot Height (default 1.8, range 0-3): height of the camera
orbit point above the player's feet. Lower values reduce the
"detached/floating" feel that can cause nausea. Setting to 0 puts the
pivot at foot level (ground-locked camera).

Both settings saved to settings file and applied via sliders in the
Gameplay tab of the Settings window.
2026-03-28 11:39:37 -07:00
Kelsi
2af3594ce8 perf: eliminate per-frame heap allocs in M2 renderer; UI polish and report
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
M2 renderer: move 3 per-frame local containers to member variables:
- particleGroups_ (unordered_map): reuse bucket structure across frames
- ribbonDraws_ (vector): reuse draw call buffer
- shadowTexSetCache_ (unordered_map): reuse descriptor cache
Eliminates ~3 heap allocations per frame in particle/ribbon/shadow passes.

UI polish:
- Nameplate hover tooltip showing level, class (players), guild name
- Bag window titles show slot counts: "Backpack (12/16)"

Player report: CMSG_COMPLAIN packet builder and reportPlayer() method.
"Report Player" option in target frame right-click menu for other players.
Server response handler (SMSG_COMPLAIN_RESULT) was already implemented.
2026-03-27 18:21:47 -07:00
Kelsi
cccd52b32f fix: equipment visibility (remove layout verification gate), follow uses run speed
Equipment: removed the visibleItemLayoutVerified_ gate from
updateOtherPlayerVisibleItems(). The default WotLK field layout (base=284,
stride=2) is correct and should be used immediately. The verification
heuristic was silently blocking ALL other-player equipment rendering by
queuing for auto-inspect (which doesn't return items in WotLK anyway).

Follow: auto-follow now uses run speed (autoRunning) instead of walk speed.
Also uses squared distance for the distance checks.

Commands: /quit, /exit aliases for /logout; /difficulty normal/heroic/25/25heroic
sends CMSG_CHANGEPLAYER_DIFFICULTY.
2026-03-27 18:05:42 -07:00
Kelsi
b366773f29 fix: inspect (packed GUID), follow (client-side auto-walk); add loot/raid commands
Inspect: CMSG_INSPECT was writing full uint64 GUID instead of packed GUID.
Server silently rejected the malformed packet. Fixed both InspectPacket and
QueryInspectAchievementsPacket to use writePackedGuid().

Follow: was a no-op (only stored GUID). Added client-side auto-follow system:
camera controller walks toward followed entity, faces target, cancels on
WASD/mouse input, stops within 3 units, cancels at 40+ units distance.

Party commands:
- /lootmethod (ffa/roundrobin/master/group/nbg) sends CMSG_LOOT_METHOD
- /lootthreshold (0-5 or quality name) sets minimum loot quality
- /raidconvert converts party to raid (leader only)

Equipment diagnostic logging still active for debugging naked players.
2026-03-27 17:54:56 -07:00
Kelsi
16fc3ebfdf feat: target frame right-click context menu; add equipment diagnostic logging
Target frame: add Follow, Clear Target, and Set Raid Mark submenu to the
right-click context menu (Inspect, Trade, Duel were already present).

Equipment diagnostics: add LOG_INFO traces to updateOtherPlayerVisibleItems()
and emitOtherPlayerEquipment() to debug why other players appear naked.
Logs the visible item entry IDs received from the server and the resolved
displayIds from itemInfoCache. Check the log for "emitOtherPlayerEquipment"
to see if entries arrive as zeros (server not sending fields) or if
displayIds are zero (item templates not cached yet).
2026-03-27 17:41:37 -07:00
Kelsi
50a3eb7f07 fix: mail money uint64, other-player cape textures, zone toast dedup, TCP_NODELAY
Mail: change money/COD fields from uint32 to uint64 in CMSG_SEND_MAIL and
SMSG_MAIL_LIST_RESULT for WotLK 3.3.5a. Classic keeps uint32 on the wire.
Fixes money truncation and packet misalignment causing mail failures.

Other-player capes: add cape texture loading to setOnlinePlayerEquipment().
The cape geoset was enabled but no texture was loaded, leaving capes blank.
Now mirrors the local-player path: looks up ItemDisplayInfo.dbc, finds cape
texture candidates, applies via setGroupTextureOverride/setTextureSlotOverride.

Zone toasts: suppress duplicate zone toast when the zone text overlay is
already showing the same zone name. Fixes double "Entering: Stormwind City".

Network: enable TCP_NODELAY on both auth and world sockets after connect(),
disabling Nagle's algorithm to eliminate up to 200ms buffering delay on
small packets (movement, spell casts, chat).

Rendering: track material and bone descriptor sets in M2 renderer to skip
redundant vkCmdBindDescriptorSets calls between batches sharing same textures.
2026-03-27 17:20:31 -07:00
Kelsi
6b1c728377 perf: eliminate double map lookups, dynamic_cast in render loops, div by 255
- Replace count()+operator[] double lookups with find() or try_emplace()
  in gameObjectInstances_, playerTextureSlotsByModelId_, onlinePlayerAppearance_
- Add Entity::isUnit() helper; replace 5 dynamic_cast<Unit*> in per-frame
  UI rendering (nameplates, combat text, pet frame) with isUnit()+static_cast
- Add constexpr kInv255 reciprocal for per-pixel normal map generation loops
  in character_renderer and wmo_renderer
2026-03-27 17:04:13 -07:00
Kelsi
d26eed1e7c perf: constexpr reciprocals, cache redundant lookups, consolidate texture maps
- Hoist DBC field index lookups before loops in game_handler (7 DBC iteration loops)
- Cache getSkybox()/getPosition() calls instead of redundant per-frame queries
- Merge textureHasAlphaByPtr_ + textureColorKeyBlackByPtr_ into single map
- Add constexpr for DEG_TO_RAD, reciprocal constants, physics delta
- Add reserve() for WMO/M2 collision grid queries and portal BFS
- Frustum plane normalize: inversesqrt instead of length+divide
- M2 particle emission: inversesqrt for direction normalization
- Parse creature display IDs from query response
- UI: show spell names/IDs as fallback instead of "Unknown"
2026-03-27 16:47:30 -07:00
Kelsi
b0466e9029 perf: eliminate ~70 unnecessary sqrt ops per frame, optimize caches and threading
Squared distance optimizations across 30 files:
- Convert glm::length() comparisons to glm::dot() (no sqrt)
- Use glm::inversesqrt() for check-then-normalize patterns (1 rsqrt vs 2 sqrt)
- Defer sqrt to after early-out checks in collision/movement code
- Hottest paths: camera_controller (21), weather particles, WMO collision,
  transport movement, creature interpolation, nameplate culling

Container and algorithm improvements:
- std::map<string> → std::unordered_map for asset/DBC/MPQ/warden caches
- std::mutex → std::shared_mutex for asset_manager and mpq_manager caches
- std::sort → std::partial_sort in lighting_manager (top-2 of N volumes)
- Double-lookup find()+operator[] → insert_or_assign in game_handler
- Add reserve() for per-frame vectors: weather, swim_effects, WMO/M2 collision

Threading and synchronization:
- Replace 1ms busy-wait polling with condition_variable in character_renderer
- Move timestamp capture before mutex in logger
- Use memory_order_acquire/release for normal map completion signaling

API additions:
- DBC getStringView()/getStringViewByOffset() for zero-copy string access
- Parse creature display IDs from SMSG_CREATURE_QUERY_SINGLE_RESPONSE
2026-03-27 16:33:16 -07:00
Kelsi
fb3bfe42c9 refactor: add kCastGreen/kQueueGreen constants, remove dead code
Add kCastGreen (interruptible cast bar, 5 uses) and kQueueGreen
(queue status / talent met, 7 uses across game_screen + talent_screen).

Remove commented-out renderQuestMarkers call (replaced by 3D billboards).
2026-03-27 15:01:12 -07:00
Kelsi
5b91ef398e fix: return UINT32_MAX from findMemType on failure, add [[nodiscard]]
The findMemType/findMemoryType helper in auth_screen, loading_screen,
and vk_context returned 0 on failure — a valid memory type index.
Changed to return UINT32_MAX and log an error, so vkAllocateMemory
receives an invalid index and fails cleanly rather than silently
using the wrong memory type.

Add [[nodiscard]] to VkBuffer::uploadToGPU/createMapped and
VkContext::initialize/recreateSwapchain so callers that ignore
failure are flagged at compile time. Suppress with (void) cast at
3 call sites where failure is non-actionable (resize best-effort).
2026-03-27 14:53:29 -07:00
Kelsi
7028dd64c1 refactor: promote remaining static const arrays to constexpr across UI
game_screen: fsrScales, fsrScaleFactors, kTotemInfo, kRaidMarks,
kTimerInfo, kNPMarks, kCellMarks, kPartyMarks, kMMMarks, kCatOrder
keybinding_manager: actionMap

All static const arrays in UI files are now constexpr where possible.
2026-03-27 14:47:58 -07:00
Kelsi
d2430faa51 refactor: promote 7 more static const arrays to constexpr
inventory_screen: groups, tiers, leftSlots, rightSlots, weaponSlots
character_create_screen: kAllRaces, kAllClasses
2026-03-27 14:46:31 -07:00
Kelsi
e474dca2be refactor: add 9 button/bar color constants, batch constexpr promotions
New ui_colors.hpp constants: kBtnGreen, kBtnGreenHover, kBtnRed,
kBtnRedHover, kBtnDkGreen/Hover, kBtnDkRed/Hover, kMidHealthYellow
— replacing 21 inline literals across accept/decline button and
health bar patterns.

Deduplicate kMon/kMonths month arrays (2 copies → 1 kMonthAbbrev).

Promote 22 remaining static const char*/int arrays to constexpr
(kQualHex, resLabels, kRepRankNames, kTotemNames, kReactLabels,
kChatHelp, kMacroHelp, kHelpLines, kMarkWords, componentDirs,
keyLabels, kRollLabels, gossipIcons, kMarkNames, kDiffLabels,
kStatLabels, kCatHeaders, kSlotNames, kResolutions, displayToInternal).
2026-03-27 14:44:52 -07:00
Kelsi
4981d162c5 refactor: deduplicate item-set DBC key arrays, widen totem timer buffer
- Move itemKeys/spellKeys/thrKeys to shared kItemSetItemKeys/
  kItemSetSpellKeys/kItemSetThresholdKeys in ui_colors.hpp, removing
  5 identical local definitions across game_screen and inventory_screen
- Widen totem timer snprintf buffer from 8 to 16 bytes (defensive)
- Promote kStatTooltips to constexpr
2026-03-27 14:40:44 -07:00
Kelsi
92d8262f96 refactor: move kClassMasks, kRaceMasks, kSocketTypes to shared ui_colors.hpp
Deduplicate class/race bitmask arrays (3 copies each → 1 shared) and
socket type definitions (3 copies → 1 shared). Eliminates ~80 lines of
repeated struct definitions across game_screen.cpp and inventory_screen.cpp.
2026-03-27 14:35:16 -07:00
Kelsi
cd29c6d50b refactor: deduplicate class name functions in talent_screen and game_screen
Replace local getClassName()/classNameStr() with shared
game::getClassName() from character.hpp, removing 2 duplicate
name-lookup implementations (static arrays + wrapper functions).
2026-03-27 14:30:45 -07:00
Kelsi
f5a3ebc774 refactor: deduplicate arrays in inventory_screen, add kDarkYellow constant
- Move kSocketTypes to file-scope constexpr, removing 2 identical local
  definitions across tooltip render functions
- Move kResistNames to file-scope constexpr, removing 3 identical local
  definitions (Holy..Arcane resistance labels)
- Move kRepRankNames to file-scope constexpr, removing 2 identical local
  definitions (Hated..Exalted reputation rank labels)
- Add kDarkYellow color constant, replacing 3 inline literals
2026-03-27 14:25:54 -07:00
Kelsi
6783ead4ba fix: guard hexDecode std::stoul; extract duration formatting helpers
- Wrap std::stoul in auth_screen hexDecode() with try-catch to prevent
  crash on malformed saved password hex data
- Add fmtDurationCompact() helper replacing 3 identical duration format
  blocks (hours/minutes/seconds for aura icon overlays)
- Add renderAuraRemaining() helper replacing 5 identical "Remaining: Xm Ys"
  tooltip blocks across player/target/focus/raid aura tooltips
2026-03-27 14:17:28 -07:00
Kelsi
0ae7360255 refactor: deduplicate kRaidMarkNames, promote 4 more arrays to constexpr
- Move kRaidMarkNames to file-scope constexpr, removing 3 duplicate
  local definitions across target/raid/party frame menus
- Promote kReactColors, kEnchantSlotColors, kRollColors from static
  const to static constexpr
2026-03-27 14:13:16 -07:00
Kelsi
f1ecf8be53 refactor: deduplicate kDispelNames, use constexpr arrays, remove std::to_string in IDs
- Move kDispelNames to file-scope constexpr, removing 2 duplicate local
  definitions in raid/party frame rendering
- Promote kTotemColors and kReactDimColors from static const to constexpr
- Replace std::to_string + string concat for ImGui widget IDs with
  snprintf into stack buffers (avoids heap allocations in render loops)
2026-03-27 14:11:05 -07:00
Kelsi
22d0b9cd4c refactor: deduplicate class color functions, add 9 color constants
Move classColor/classColorU32 to shared getClassColor()/getClassColorU32()
in ui_colors.hpp, eliminating duplicate 10-case switch in character_screen
and game_screen.

New ui_colors.hpp constants: kInactiveGray, kVeryLightGray, kSymbolGold,
kLowHealthRed, kDangerRed, kEnergyYellow, kHappinessGreen, kRunicRed,
kSoulShardPurple — replacing 36 inline literals across 4 files.
2026-03-27 14:07:36 -07:00
Kelsi
54006fad83 refactor: add 9 color constants, replace 36 more inline literals
New constants in ui_colors.hpp:
- Power types: kEnergyYellow, kHappinessGreen, kRunicRed, kSoulShardPurple
- UI elements: kInactiveGray, kVeryLightGray, kSymbolGold, kLowHealthRed, kDangerRed

Replacements across game_screen(30), inventory_screen(5), character_screen(1).
2026-03-27 14:05:32 -07:00
Kelsi
762daebc75 refactor: replace 23 more inline color literals across 3 UI files
game_screen: kWhite(3), kSilver(4)
inventory_screen: kWarmGold(8), kFriendlyGreen(2), kSocketGreen(4), kActiveGreen(2)
talent_screen: kHealthGreen(1), kWhite(3), kRed(1)
2026-03-27 14:00:15 -07:00
Kelsi
c38fa6d9ec refactor: replace 31 more inline color literals with named constants in game_screen
Replace inline ImVec4 literals with shared constants from ui_colors.hpp:
kHealthGreen(5), kOrange(5), kWarmGold(5), kFriendlyGreen(3),
kActiveGreen(3), kLightGreen(4), kSocketGreen(2), new constants
kSocketGreen/kActiveGreen/kLightGreen/kHealthGreen/kWarmGold/kOrange/kFriendlyGreen
added to ui_colors.hpp.
2026-03-27 13:57:29 -07:00
Kelsi
e3c999d844 refactor: add 4 color constants, replace 31 more inline literals
Add kDarkRed, kSoftRed, kHostileRed, kMediumGray to ui_colors.hpp and
replace 31 inline ImVec4 literals across game_screen, character_screen,
inventory_screen, and performance_hud. Also replace local color aliases
in performance_hud with shared constants.
2026-03-27 10:20:45 -07:00