Commit graph

1054 commits

Author SHA1 Message Date
Kelsi
1dd3823013 perf: use second GPU queue for parallel texture/buffer uploads
Request 2 queues from the graphics family when available (NVIDIA
exposes 16, AMD 2+). Upload batches now submit to queue[1] while
rendering uses queue[0], enabling parallel GPU transfers without
queue-family ownership transfer barriers (same family).

Falls back to single-queue path on GPUs with only 1 queue in the
graphics family. Transfer command pool is separate to avoid contention.
2026-03-24 14:09:16 -07:00
Kelsi
891b9e5822 fix: show friendly map names on loading screen (Outland not Expansion01)
Add mapDisplayName() with friendly names for continents: "Eastern
Kingdoms", "Kalimdor", "Outland", "Northrend". The loading screen
previously showed WDT directory names like "Expansion01" when
Map.dbc's localized name field was empty or matched the internal name.
2026-03-24 13:20:06 -07:00
Kelsi
9a6a430768 fix: track render pass subpass mode to prevent ImGui secondary violation
When parallel recording is active, the scene pass uses
VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS. Post-processing paths
(FSR/FXAA) end the scene pass and begin a new INLINE render pass for
the swapchain output. ImGui rendering must use the correct mode —
secondary buffers for SECONDARY passes, direct calls for INLINE.

Previously the check used a static condition based on enabled features
(!fsr && !fsr2 && !fxaa && parallel), which could mismatch if a
feature was enabled but initialization failed. Replace with
endFrameInlineMode_ flag that tracks the actual current render pass
mode at runtime, eliminating the validation error
VUID-vkCmdDrawIndexed-commandBuffer-recording that caused intermittent
NVIDIA driver crashes.
2026-03-24 13:05:27 -07:00
Kelsi
a152023e5e fix: add VkSampler cache to prevent sampler exhaustion crash
Validation layers revealed 9965 VkSamplers allocated against a device
limit of 4000 — every VkTexture created its own sampler even when
configurations were identical. This exhausted NVIDIA's sampler pool
and caused intermittent SIGSEGV in vkCmdBeginRenderPass.

Add a thread-safe sampler cache in VkContext that deduplicates samplers
by FNV-1a hash of all 14 VkSamplerCreateInfo fields. All texture,
render target, renderer, water, and loading screen sampler creation
now goes through getOrCreateSampler(). Textures set ownsSampler_=false
so shared samplers aren't double-freed.

Also auto-disable anisotropy in the cache when the physical device
doesn't support the samplerAnisotropy feature, fixing the validation
error VUID-VkSamplerCreateInfo-anisotropyEnable-01070.
2026-03-24 11:44:54 -07:00
Kelsi Rae Davis
0a32c0fa27
Merge pull request #21 from ldmonster/chore/add-classification-to-render
refactor(rendering): extract M2 classification into pure functions
2026-03-24 10:18:24 -07:00
Kelsi
d2a396df11 feat: log GPU vendor/name at init, add PLAY_SOUND diagnostics
Log GPU name and vendor ID during VkContext initialization for easier
debugging of GPU-specific issues (FSR3, driver compat, etc.). Add
isAmdGpu()/isNvidiaGpu() accessors.

Temporarily log SMSG_PLAY_SOUND and SMSG_PLAY_OBJECT_SOUND at WARN
level (sound ID, name, file path) to diagnose unidentified ambient
NPC sounds reported by the user.
2026-03-24 09:56:54 -07:00
Paul
cbfe7d5f44 refactor(rendering): extract M2 classification into pure functions 2026-03-24 19:55:24 +03:00
Kelsi
c8c01f8ac0 perf: add Vulkan pipeline cache persistence for faster startup
Create a VkPipelineCache at device init, loaded from disk if available.
All 65 pipeline creation calls across 19 renderer files now use the
shared cache. On shutdown, the cache is serialized to disk so subsequent
launches skip redundant shader compilation.

Cache path: ~/.local/share/wowee/pipeline_cache.bin (Linux),
~/Library/Caches/wowee/ (macOS), %APPDATA%\wowee\ (Windows).
Stale/corrupt caches are handled gracefully (fallback to empty cache).
2026-03-24 09:47:03 -07:00
Kelsi
c18720f0f0 feat: server-synced bag sort, fix world map continent bounds, update docs
Inventory sort: clicking "Sort Bags" now generates CMSG_SWAP_ITEM packets
to move items server-side (one swap per frame to avoid race conditions).
Client-side sort runs immediately for visual preview; server swaps follow.
New Inventory::computeSortSwaps() computes minimal swap sequence using
selection-sort permutation on quality→itemId→stackCount comparator.

World map: fix continent bounds derivation that used intersection (max/min)
instead of union (min/max) of child zone bounds, causing continent views
to display zoomed-in/clipped.

Update README.md and docs/status.md with current features, release info,
and known gaps (v1.8.2-preview, 664 opcode handlers, NPC voices, bag
independence, CharSections auto-detect, quest GO server limitation).
2026-03-24 09:24:09 -07:00
Kelsi
8a617e842b fix: direct CMSG_LOOT for chest GOs and increase M2 descriptor pools
Chest-type game objects (quest pickups, treasure chests) now send
CMSG_LOOT directly with the GO GUID instead of CMSG_GAMEOBJ_USE +
delayed CMSG_LOOT. The server's loot handler activates the GO and
sends SMSG_LOOT_RESPONSE in one step. The old approach failed because
CMSG_GAMEOBJ_USE opened+despawned the GO before CMSG_LOOT arrived.

Double M2 bone and material descriptor pool sizes (8192 → 16384) to
handle the increased NPC count from the spline parsing fix — patrolling
NPCs that were previously invisible now spawn correctly, exhausting
the old pool limits.
2026-03-23 17:41:42 -07:00
Kelsi
503f9ed650 fix: auto-detect CharSections.dbc layout and add Blood Elf/Draenei NPC voices
CharSections.dbc has different field layouts between stock WotLK (textures
at field 4-6) and Classic/TBC/Turtle/HD-textured WotLK (VariationIndex at
field 4). Add detectCharSectionsFields() that probes field-4 values at
runtime to determine the correct layout, so both stock and modded clients
work without JSON changes.

Also add BLOODELF_MALE/FEMALE and DRAENEI_MALE/FEMALE voice types to the
NPC voice system — previously all Blood Elf and Draenei NPCs fell through
to GENERIC (random dwarf/gnome/night elf/orc mix).
2026-03-23 11:00:49 -07:00
Kelsi
11ecc475c8 feat: resolve spell \$d duration to real seconds from SpellDuration.dbc
Spell descriptions now substitute \$d with actual duration values:
  Before: "X damage over X sec"
  After:  "30 damage over 18 sec"

Implementation:
- DurationIndex field (40) added to all expansion Spell.dbc layouts
- SpellDuration.dbc loaded during cache build: maps index → base ms
- cleanSpellDescription substitutes \$d with resolved seconds/minutes
- getSpellDuration() accessor on GameHandler

Combined with \$s1/\$s2/\$s3 from the previous commit, most common
spell description templates are now fully resolved with real values.
2026-03-23 01:00:18 -07:00
Kelsi
a5aa1faf7a feat: resolve spell \$s1/\$s2/\$s3 to real DBC damage/heal values
Spell descriptions now substitute \$s1/\$s2/\$s3 template variables
with actual effect base points from Spell.dbc (field 80/81/82).
For example: "causes \$s1 Fire Damage" → "causes 562 Fire Damage".

Implementation:
- Added EffectBasePoints0/1/2 to all 4 expansion DBC layouts
- SpellNameEntry now stores effectBasePoints[3]
- loadSpellNameCache reads base points during DBC iteration
- cleanSpellDescription substitutes \$s1→abs(base)+1 when available
- getSpellEffectBasePoints() accessor on GameHandler

Values are DBC base points (before spell power scaling). Still uses
"X" placeholder for unresolved variables (\$d, \$o1, etc.).
2026-03-23 00:51:19 -07:00
Kelsi
587c0ef60d feat: track shapeshift form and fire UPDATE_SHAPESHIFT_FORM events
Add UNIT_FIELD_BYTES_1 to all expansion update field tables (Classic=133,
TBC/WotLK=137). Byte 3 of this field contains the shapeshift form ID
(Bear=1, Cat=3, Travel=4, Moonkin=31, Tree=36, Battle Stance=17, etc.).

Track form changes in the VALUES update handler and fire
UPDATE_SHAPESHIFT_FORM + UPDATE_SHAPESHIFT_FORMS events when the
form changes. This enables stance bar addons and druid form tracking.

New Lua functions:
- GetShapeshiftForm() — returns current form ID (0 = no form)
- GetNumShapeshiftForms() — returns form count by class (Warrior=3,
  Druid=6, DK=3, Rogue=1, Priest=1, Paladin=3)
2026-03-22 22:12:17 -07:00
Kelsi
b9a1b0244b feat: add GetEnchantInfo for enchantment name resolution
GetEnchantInfo(enchantId) looks up the enchantment name from
SpellItemEnchantment.dbc (field 14). Returns the display name
like "Crusader", "+22 Intellect", or "Mongoose" for a given
enchant ID.

Used by equipment comparison addons and tooltip addons to display
enchantment names on equipped gear. The enchant ID comes from the
item's ITEM_FIELD_ENCHANTMENT update field.

Also adds getEnchantName() to GameHandler for C++ access.
2026-03-22 21:53:58 -07:00
Kelsi
3b4909a140 fix: populate item subclass names for TBC expansion
The TBC item query parser left subclassName empty, so TBC items showed
no weapon/armor type in tooltips or the character sheet (e.g., "Sword",
"Plate", "Shield" were all blank). The Classic and WotLK parsers
correctly map subClass IDs to names.

Fix: call getItemSubclassName() in the TBC parser, same as WotLK.
Expose getItemSubclassName() in the header (was static, now shared
across parser files).
2026-03-22 20:30:08 -07:00
Kelsi
e4da47b0d7 feat: add UI_ERROR_MESSAGE events and quest removal notifications
Fire UI_ERROR_MESSAGE from addUIError() so Lua addons can react to
error messages like "Not enough mana" or "Target is too far away".
Previously only the C++ overlay callback was notified. Also add
addUIInfoMessage() helper for informational system messages.

Fire QUEST_REMOVED and QUEST_LOG_UPDATE when quests are removed from
the quest log — both via server-driven removal (SMSG_QUEST_UPDATE_FAILED
etc.) and player-initiated abandon (CMSG_QUESTLOG_REMOVE_QUEST). Quest
tracking addons like Questie register for these events to update their
map markers and objective displays.
2026-03-22 16:53:35 -07:00
Kelsi
5086520354 feat: add spell book tab API for SpellBookFrame addon compatibility
Implement GetNumSpellTabs, GetSpellTabInfo, GetSpellBookItemInfo, and
GetSpellBookItemName — the core functions SpellBookFrame.lua needs to
organize known spells into class skill line tabs.

Tabs are built lazily from knownSpells grouped by SkillLineAbility.dbc
mappings (category 7 = class). A "General" tab collects spells not in
any class skill line. Tabs auto-rebuild when the spell count changes.

Also adds SpellBookTab struct and getSpellBookTabs() to GameHandler.
2026-03-22 15:40:40 -07:00
Kelsi
f29ebbdd71 feat: add quest watch/tracking and selection Lua API for WatchFrame
Implement the quest tracking functions needed by WatchFrame.lua:
- SelectQuestLogEntry/GetQuestLogSelection — quest log selection state
- GetNumQuestWatches — count of tracked quests
- GetQuestIndexForWatch(watchIdx) — map Nth watched quest to log index
- AddQuestWatch/RemoveQuestWatch — toggle quest tracking by log index
- IsQuestWatched — check if a quest log entry is tracked
- GetQuestLink — generate colored quest link string

Backed by existing trackedQuestIds_ set and questLog_ vector.
Adds selectedQuestLogIndex_ state to GameHandler for quest selection.
2026-03-22 15:36:25 -07:00
Kelsi
ce4f93dfcb feat: add UnitCastingInfo/UnitChannelInfo Lua API and fix SMSG_CAST_FAILED events
Expose cast/channel state to Lua addons via UnitCastingInfo(unit) and
UnitChannelInfo(unit), matching the WoW API signature (name, text, texture,
startTime, endTime, isTradeSkill, castID, notInterruptible). Works for
player, target, focus, and pet units using existing UnitCastState tracking.

Also fix handleCastFailed (SMSG_CAST_FAILED, Classic/TBC path) to fire
UNIT_SPELLCAST_FAILED and UNIT_SPELLCAST_STOP events — previously only
the WotLK SMSG_CAST_RESULT path fired these, leaving Classic/TBC addons
unaware of cast failures.

Adds isChannel field to UnitCastState and getCastTimeTotal() accessor.
2026-03-22 15:05:29 -07:00
Paul
027640189a make start on ubuntu intel video cards 2026-03-22 21:47:12 +03:00
Kelsi
2da0883544 feat: fire BARBER_SHOP_OPEN and BARBER_SHOP_CLOSE events
Fire BARBER_SHOP_OPEN when the barber shop UI is enabled
(SMSG_ENABLE_BARBER_SHOP). Fire BARBER_SHOP_CLOSE when the barber
shop completes or is dismissed. Used by UI customization addons.
2026-03-21 07:54:30 -07:00
Kelsi
19b8d31da2 feat: display Lua addon errors as in-game UI errors
Previously Lua addon errors only logged to the log file. Now they
display as red UI error text to the player (same as spell errors and
game warnings), helping addon developers debug issues in real-time.

Add LuaErrorCallback to LuaEngine, fire it from event handler and
frame OnEvent pcall error paths. Wire the callback to GameHandler's
addUIError in application.cpp.
2026-03-21 06:00:06 -07:00
Kelsi
91794f421e feat: add spell power cost to SpellDataResolver; fix IsUsableSpell mana check
Extend SpellDataInfo with manaCost and powerType fields, extracted from
Spell.dbc ManaCost and PowerType columns. This enables IsUsableSpell()
to properly check if the player has enough mana/rage/energy to cast.

Previously IsUsableSpell always returned notEnoughMana=false since cost
data wasn't available. Now it compares the spell's DBC mana cost against
the player's current power, returning accurate usability and mana state.

This fixes action bar addons showing abilities as usable when the player
lacks sufficient power, and enables OmniCC-style cooldown text to
properly dim insufficient-power abilities.
2026-03-21 04:20:58 -07:00
Kelsi
c7e16646fc feat: resolve spell cast time and range from DBC for GetSpellInfo
Add SpellDataResolver that lazily loads Spell.dbc, SpellCastTimes.dbc,
and SpellRange.dbc to provide cast time and range data. GetSpellInfo()
now returns real castTime (ms), minRange, and maxRange instead of
hardcoded 0 values.

This enables spell tooltip addons, cast bar addons (Quartz), and range
check addons to display accurate spell information. The DBC chain is:
  Spell.dbc[CastingTimeIndex] → SpellCastTimes.dbc[Base ms]
  Spell.dbc[RangeIndex] → SpellRange.dbc[MinRange, MaxRange]

Follows the same lazy-loading pattern as SpellIconPathResolver and
ItemIconPathResolver.
2026-03-21 04:16:12 -07:00
Kelsi
cfb9e09e1d feat: cache player class/race from name queries for UnitClass/UnitRace
Add playerClassRaceCache_ that stores classId and raceId from
SMSG_NAME_QUERY_RESPONSE. This enables UnitClass and UnitRace to return
correct data for players who were previously seen but are now out of
UPDATE_OBJECT range.

Fallback chain for UnitClass/UnitRace is now:
1. Entity update fields (UNIT_FIELD_BYTES_0) — for nearby entities
2. Name query cache — for previously queried players
3. getPlayerClass/Race() — for the local player

This improves class-colored names in chat, unit frames, and nameplates
for players who move out of view range.
2026-03-21 04:11:48 -07:00
Kelsi
8229a963d1 feat: add player name tab-completion in chat input
When typing commands like /w, /whisper, /invite, /trade, /duel, /follow,
/inspect, etc., pressing Tab now cycles through matching player names.

Name sources (in priority order):
1. Last whisper sender (most likely target for /r follow-ups)
2. Party/raid members
3. Friends list
4. Nearby visible players

Tab cycles through all matches; single match auto-appends a space.
Complements the existing slash-command tab-completion.
2026-03-21 03:49:02 -07:00
Kelsi
7105672f06 feat: resolve item icon paths from ItemDisplayInfo.dbc for Lua API
Add ItemIconPathResolver that lazily loads ItemDisplayInfo.dbc to map
displayInfoId → icon texture path. This fixes three Lua API functions
that previously returned nil for item icons:

- GetItemInfo() field 10 (texture) now returns the icon path
- GetActionTexture() for item-type action bar slots now returns icons
- GetLootSlotInfo() field 1 (texture) now returns proper item icons
  instead of incorrectly using the spell icon resolver

Follows the same lazy-loading pattern as SpellIconPathResolver. The DBC
is loaded once on first query and cached for all subsequent lookups.
2026-03-21 02:53:07 -07:00
Kelsi
e21f808714 feat: support SavedVariablesPerCharacter for per-character addon data
Implement the SavedVariablesPerCharacter TOC directive that many addons
use to store different settings per character (Bartender, Dominos,
MoveAnything, WeakAuras, etc.). Without this, all characters share the
same addon data file.

Per-character files are stored as <AddonName>.<CharacterName>.lua.saved
alongside the existing account-wide <AddonName>.lua.saved files. The
character name is resolved from the player GUID at world entry time.

Changes:
- TocFile::getSavedVariablesPerCharacter() parses the TOC directive
- AddonManager loads/saves per-character vars alongside account-wide vars
- Character name set from game handler before addon loading
2026-03-21 02:46:21 -07:00
Kelsi
32a51aa93d feat: add mouseover unit ID support and fire UPDATE_MOUSEOVER_UNIT/PLAYER_FOCUS_CHANGED events
Add "mouseover" as a valid unit ID in resolveUnitGuid so Lua API functions
like UnitName("mouseover"), UnitHealth("mouseover") etc. work for addons.
Fire UPDATE_MOUSEOVER_UNIT event when the mouseover target changes, and
PLAYER_FOCUS_CHANGED event when focus is set or cleared.
2026-03-21 01:26:37 -07:00
Kelsi
4b3e377add feat: resolve random property/suffix names for item display
Load ItemRandomProperties.dbc and ItemRandomSuffix.dbc lazily to resolve
suffix names like "of the Eagle", "of the Monkey" etc. Add
getRandomPropertyName(id) callback on GameHandler wired through Application.
Append suffix to item names in SMSG_ITEM_PUSH_RESULT loot notifications
so items display as "Leggings of the Eagle" instead of just "Leggings".
2026-03-20 19:18:30 -07:00
Kelsi
180990b9f1 feat: play minimap ping sound when party members ping the map
Add playMinimapPing() to UiSoundManager with MapPing.wav (falls back to
target select sound). Play the ping sound in MSG_MINIMAP_PING handler
when the sender is not the local player. Provides audio feedback for
party member map pings, matching WoW behavior.
2026-03-20 18:21:34 -07:00
Kelsi
71837ade19 feat: show zone name on loading screen during world transitions
Add setZoneName() to LoadingScreen and display the map name from Map.dbc
as large gold text with drop shadow above the progress bar. Shown in both
render() and renderOverlay() paths. Zone name is resolved from gameHandler's
getMapName(mapId) during world load. Improves feedback during zone transitions.
2026-03-20 18:12:23 -07:00
Kelsi
14007c81df feat: add /cancelqueuedspell command to clear spell queue
Add cancelQueuedSpell() method that clears queuedSpellId_ and
queuedSpellTarget_. Wire /cancelqueuedspell and /stopspellqueue
slash commands. Useful for combat macros that need to prevent
queued spells from firing after a current cast.
2026-03-20 17:24:16 -07:00
Kelsi
21ead2aa4b feat: add /reload command to re-initialize addon system
Add AddonManager::reload() which saves all SavedVariables, shuts down the
Lua VM, re-initializes it, rescans .toc files, and reloads all addons.
Wire /reload, /reloadui, /rl slash commands that call reload() and fire
VARIABLES_LOADED + PLAYER_LOGIN + PLAYER_ENTERING_WORLD lifecycle events.
Essential for addon development and troubleshooting.
2026-03-20 16:17:04 -07:00
Kelsi
23ebfc7e85 feat: add LFG role check confirmation popup with CMSG_LFG_SET_ROLES
When the dungeon finder initiates a role check (SMSG_LFG_ROLE_CHECK_UPDATE
state=2), show a centered popup with Tank/Healer/DPS checkboxes and
Accept/Leave Queue buttons. Accept sends CMSG_LFG_SET_ROLES with the
selected role mask. Previously only showed passive "Role check in progress"
text with no way to respond.
2026-03-20 16:10:29 -07:00
Kelsi
df7feed648 feat: add distinct STORM weather type with wind-driven particles
Add Weather::Type::STORM enum value and wire it from SMSG_WEATHER type 3.
Storm particles are faster (70 units/s vs rain's 50), wind-angled at 15+
units lateral velocity with gusty turbulence, darker blue-grey tint, and
shorter lifetime. Previously storms rendered identically to rain.
2026-03-20 15:56:58 -07:00
Kelsi
5eaf738b66 feat: show quest POI markers on the world map overlay
Add QuestPoi struct and setQuestPois() to WorldMap, render quest objective
markers as cyan circles with golden outlines and quest title labels. Wire
gossipPois_ (from SMSG_QUEST_POI_QUERY_RESPONSE) through GameScreen to the
world map so quest objectives are visible alongside party dots and taxi nodes.
2026-03-20 15:00:29 -07:00
Kelsi
ae627193f8 feat: fire combat, spell, and cooldown events for Lua addon system
Add PLAYER_REGEN_DISABLED/ENABLED (combat enter/leave) via per-frame
edge detection, LEARNED_SPELL_IN_TAB/SPELLS_CHANGED on spell learn/remove,
SPELL_UPDATE_COOLDOWN/ACTIONBAR_UPDATE_COOLDOWN on cooldown finish, and
PLAYER_XP_UPDATE on XP field changes. Total addon events now at 34.
2026-03-20 14:27:46 -07:00
Kelsi
22b0cc8a3c feat: add GetSpellInfo, GetSpellTexture, GetItemInfo and more Lua API functions
Add spell icon path resolution via SpellIcon.dbc + Spell.dbc lazy loading,
wired through GameHandler callback. Fix UnitBuff/UnitDebuff to return icon
texture paths instead of nil. Add GetLocale, GetBuildInfo, GetCurrentMapAreaID.
2026-03-20 13:58:54 -07:00
Kelsi
ee3f60a1bb feat: add GetNumAddOns and GetAddOnInfo for addon introspection
- GetNumAddOns() — returns count of loaded addons
- GetAddOnInfo(indexOrName) — returns name, title, notes, loadable

Addon info is stored in the Lua registry from the .toc directives
and populated before addon files execute. Useful for addon managers
and compatibility checks between addons.

Total WoW API: 33 functions.
2026-03-20 13:07:45 -07:00
Kelsi
062cfd1e4a feat: add SavedVariables persistence for Lua addons
Addons can now persist data across sessions using the standard WoW
SavedVariables pattern:

1. Declare in .toc: ## SavedVariables: MyAddonDB
2. Use the global in Lua: MyAddonDB = MyAddonDB or {default = true}
3. Data is automatically saved on logout and restored on next login

Implementation:
- TocFile::getSavedVariables() parses comma-separated variable names
- LuaEngine::loadSavedVariables() executes saved .lua file to restore globals
- LuaEngine::saveSavedVariables() serializes Lua tables/values to valid Lua
- Serializer handles tables (nested), strings, numbers, booleans, nil
- Save triggered on PLAYER_LEAVING_WORLD and AddonManager::shutdown()
- Files stored as <AddonDir>/<AddonName>.lua.saved

Updated HelloWorld addon to track login count across sessions.
2026-03-20 12:22:50 -07:00
Kelsi
1f8660f329 feat: add OnUpdate frame script for per-frame addon callbacks
Frames can now set an OnUpdate script that fires every frame with
the elapsed time as an argument. This enables addon timers, polling,
and animations.

  local f = CreateFrame("Frame")
  f:SetScript("OnUpdate", function(self, elapsed)
      -- called every frame with deltaTime
  end)

OnUpdate only fires for visible frames (frame:Hide() pauses it).
Tracked in __WoweeOnUpdateFrames table, dispatched via
LuaEngine::dispatchOnUpdate() called from the Application main loop.
2026-03-20 12:07:22 -07:00
Kelsi
269d9e2d40 feat: fire PLAYER_TARGET_CHANGED and PLAYER_LEVEL_UP addon events
Add a generic AddonEventCallback to GameHandler for firing named events
with string arguments directly from game logic. Wire it to the addon
system in Application.

New events fired:
- PLAYER_TARGET_CHANGED — when target is set or cleared
- PLAYER_LEVEL_UP(newLevel) — on level up

The generic callback pattern makes it easy to add more events from
game_handler.cpp without touching Application/AddonManager code.
Total addon events: 16 (2 world + 12 chat + 2 gameplay).
2026-03-20 11:51:46 -07:00
Kelsi
c1820fd07d feat: add WoW utility functions and SlashCmdList for addon slash commands
Utility functions:
- strsplit(delim, str), strtrim(str), wipe(table)
- date(format), time() — safe replacements for removed os.date/os.time
- format (alias for string.format), tinsert/tremove (table aliases)

SlashCmdList system:
- Addons can register custom slash commands via the standard WoW pattern:
  SLASH_MYADDON1 = "/myaddon"
  SlashCmdList["MYADDON"] = function(args) ... end
- Chat input checks SlashCmdList before built-in commands
- dispatchSlashCommand() iterates SLASH_<NAME>1..9 globals to match

Total WoW API surface: 23 functions + SlashCmdList + 14 events.
2026-03-20 11:40:58 -07:00
Kelsi
0a0ddbfd9f feat: fire CHAT_MSG_* events to Lua addons for all chat types
Wire chat messages to the addon event system via AddonChatCallback.
Every chat message now fires the corresponding WoW event:

- CHAT_MSG_SAY, CHAT_MSG_YELL, CHAT_MSG_WHISPER
- CHAT_MSG_PARTY, CHAT_MSG_GUILD, CHAT_MSG_OFFICER
- CHAT_MSG_RAID, CHAT_MSG_RAID_WARNING, CHAT_MSG_BATTLEGROUND
- CHAT_MSG_SYSTEM, CHAT_MSG_CHANNEL, CHAT_MSG_EMOTE

Event handlers receive (eventName, message, senderName) arguments.
Addons can now filter, react to, or log chat messages in real-time.
2026-03-20 11:29:53 -07:00
Kelsi
510f03fa32 feat: add WoW event system for Lua addons
Implement the WoW-compatible event system that lets addons react to
gameplay events in real-time:

- RegisterEvent(eventName, handler) — register a Lua function for an event
- UnregisterEvent(eventName, handler) — remove a handler
- fireEvent() dispatches events to all registered handlers with args

Currently fired events:
- PLAYER_ENTERING_WORLD — after addons load and world entry completes
- PLAYER_LEAVING_WORLD — before logout/disconnect

Events are stored in a __WoweeEvents Lua table, dispatched via
LuaEngine::fireEvent() which is called from AddonManager::fireEvent().
Error handling logs Lua errors without crashing.

Updated HelloWorld addon to use RegisterEvent for world entry/exit.
2026-03-20 11:23:38 -07:00
Kelsi
290e9bfbd8 feat: add Lua 5.1 addon system with .toc loader and /run command
Foundation for WoW-compatible addon support:

- Vendor Lua 5.1.5 source as a static library (extern/lua-5.1.5)
- TocParser: parses .toc files (## directives + file lists)
- LuaEngine: Lua 5.1 VM with sandboxed stdlib (no io/os/debug),
  WoW-compatible print() that outputs to chat, GetTime() stub
- AddonManager: scans Data/interface/AddOns/ for .toc files,
  loads .lua files on world entry, skips LoadOnDemand addons
- /run <code> slash command for inline Lua execution
- HelloWorld test addon that prints to chat on load

Integration: AddonManager initialized after asset manager, addons
loaded once on first world entry, reset on logout. XML frame
parsing is deferred to a future step.
2026-03-20 11:12:07 -07:00
Kelsi
503115292b fix: save character config when quest tracking changes
setQuestTracked() modified trackedQuestIds_ but didn't call
saveCharacterConfig(), so tracked quests were only persisted if
another action (like editing a macro or rearranging the action bar)
happened to trigger a save before logout. Now saves immediately
when quests are tracked or untracked.
2026-03-20 09:48:27 -07:00
Kelsi
6bd950e817 feat: support /use macros for action bar icon and indicators
Macros with /use ItemName (e.g. /use Healthstone, /use Engineering
trinket) had no icon, cooldown, or tooltip on the action bar because
only /cast and /castsequence were recognized. Now the spell resolution
also handles /use by looking up the item name in the item info cache
and finding its on-use spell ID. Added getItemInfoCache() accessor.
2026-03-20 09:08:49 -07:00