Load Spell.dbc TargetAuraState (added to every expansion layout at its
verified column) into the spell cache with getSpellTargetAuraState. The
action bar now dims abilities whose target isn't in the required aura state
(e.g. Execute below 20% health), with a tooltip naming the requirement, and
SMSG_CAST_FAILED result 111 (Target aurastate) now yields 'Target must be
below 20% health.' instead of the opaque protocol label.
Load Achievement.dbc's IconID (added to the WotLK DBC layout, field 42) into
the achievement cache and resolve it through SpellIcon.dbc to the artwork.
The earned list now renders a bordered 32px icon with the name and points
beside it, replacing the gold-star glyph; a star placeholder fills the slot
while an icon streams in or when one is absent. Icon textures are lazily
BLP-loaded and cached in WindowManager with a per-frame upload cap.
WotLK Tooltip (139->187) and TBC Rank (136->144) / Tooltip (154->178)
layout indices assumed the wrong locale-block stride and landed on empty
columns; point them at the verified enUS strings.
Rework the talent description formatter into a real $-token resolver: it
handles $s/$o/$m/$M base points and $d durations with cross-spell
$<spellId> references (e.g. $14201d), plus $l/$g plural/gender forms,
using live spell data via GameHandler. Unresolvable tokens ($h proc chance,
$t period) are stripped cleanly instead of rendering raw, so Enrage now
reads 'a 4% damage bonus for 12 sec' rather than '$14201s1% ... $14201d'.
The talent panel read Spell.dbc's Tooltip column, which the layouts pointed
at an empty locale field, so hovering a talent showed only name and rank. Add
the correct Description column to every expansion's DBC layout (verified
against each Spell.dbc's string blocks) and read it in the talent screen,
substituting $s/$o magnitude tokens with the rank's EffectBasePoints so
descriptions read with concrete numbers. Unlearned talents show their rank-1
effect under 'Effect:'.
Parse per-animation M2 color alpha tracks across vanilla and WotLK layouts so hidden lumberjack bundle meshes remain culled until their authored death sequence.
Keep scripted worker emotes and display swaps coherent across movement and async model loads. Rework food and drink presentation around the seated aura lifecycle, repeat consumption audio, preserve real cast animations on auto-stand, and retain potion swigs.
Add server-driven intoxication movement, camera, and post-process effects plus focused regression coverage for M2 alpha tracks and consumable classification.
PR #101 dropped the trailing security-flags byte from the legacy LOGON_PROOF,
but mangos-family realmd reads the 1.11+ proof as a fixed-size struct that
includes it, so protocol-3 logins against stock vanilla realms would stall.
Also flip the Turtle profile to auth protocol 8 (vmangos-derived servers
require it) so the first login attempt no longer fails and retries; the
vanilla-family fallback chain still tries protocol 3 second.
protocolVersion 3 was rejected during auth against a VMangos classic
server - the working live-tested value is 8, matching tbc/turtle's
existing protocol selection.
The name column moved across expansions (Vanilla 10, TBC 13, WotLK 14), but the
layouts and every caller used field 8. That column holds an integer, which
getString() then treats as a string-block offset, so enchant names came back
garbled mid-string ("Sharpened (+2 Damage)" surfaced as "ockbiter 3"). Resolve
the column from the record width via detectEnchantmentNameField() and use it at
all four call sites.
Item-enhancement consumables cast a spell onto another item, but CMSG_USE_ITEM
only ever wrote a unit or self target, so the server dropped the cast. Using one
now reads the on-use spell's Spell.dbc Targets mask and, when TARGET_FLAG_ITEM is
set, arms a targeting cursor whose next item click sends the use against that
item's GUID.
Fix several gameplay paths where client-side state diverged from server
semantics.
Ability availability now checks the resource pool declared by Spell.dbc
instead of comparing only against the player's currently displayed power
type. This makes action-bar greying work for mana, rage, focus, energy,
runes, and runic power without class-name assumptions, and supports reactive
aura-state abilities such as Overpower.
Improve bandage handling:
- translate the hidden Recently Bandaged aura failure into a clear message
- report bandage interruptions with actionable text
- apply spell-aware failure text across all cast-failure packet paths
- synchronize a stationary movement state before CMSG_USE_ITEM for bandages
so stale server-side movement does not falsely interrupt the channel
Fix quest objective tracking by decoding quest-query objectives with the
correct expansion-specific packet layouts. Classic and Turtle, TBC, and
Wrath now use the proper objective offsets and structures, game-object IDs
are decoded correctly, implausible objective data is rejected, and stale
corrupted tracker entries are removed when valid quest data arrives.
Fix thrown-weapon use:
- keep Throw out of the eight-yard melee range gate
- route Throw through the ranged-weapon animation path
- avoid duplicate melee/special attack animations
- correct thrown and ranged-right inventory type constants used by
action-bar range checks
Build passes. Packet, entity, animation capability, and combat FSM tests
pass.
Data/expansions/tbc/dbc_layouts.json had DurationIndex=40 — but that
column is RangeIndex in TBC 2.4.3. DurationIndex is at column 34.
Per cmangos mangos-tbc src/game/Server/DBCStructure.h:
uint32 CastingTimeIndex; // 22
uint32 DurationIndex; // 34
uint32 rangeIndex; // 40
Visible impact prior to this fix on TBC servers: every spell-duration
lookup read the spell's RangeIndex value (an index into SpellRange.dbc)
instead of its actual DurationIndex (an index into SpellDuration.dbc).
Cast durations and aura durations would have come back as nonsense
values — most likely zero or wildly incorrect for spells whose range
index happens to be a valid duration row.
Found by scanning all dbc_layouts.json files for duplicate field
indices within a single DBC entry — the (DurationIndex, RangeIndex,
40) collision was the only one across all four expansions.
Classic (Duration=40 Range=33) and WotLK (Duration=40 Range=49)
remained intact; only TBC had the alias.
item_tooltip_renderer.cpp:378 queries Faction.dbc Name field to
resolve faction IDs to localized names for the 'Requires X Reputation'
line in item tooltips. None of the four dbc_layouts.json defined a
Name entry under Faction; the code's ternary fallback (20u) only
fired when the entire Faction layout was null. With the layout
present, (*layout)['Name'] returned DBC_FIELD_INVALID (0xFFFFFFFF)
and dbc->getString(r, 0xFFFFFFFF) read out of bounds.
Result: s_factionNames never populated → every item with a reputation
requirement displayed 'Unknown Faction'.
Canonical Name column index per Faction.dbc DBC format strings
(string offset to the English-locale entry):
Vanilla 1.12: 19 (cmangos-classic DBCfmt.h FactionEntryfmt:
"niiiiiiiiiiiiiiiiiissssssssxxxxxxxxxx")
TBC 2.4.3: 23 (cmangos-tbc SQLStorages.cpp FactionEntryfmt:
"iiiiiiiiiiiiiiiiiiiffiissssssssssssssss")
WotLK 3.3.5a: 23 (TrinityCore 3.3.5 DBCfmt.h FactionEntryfmt:
"niiiiiiiiiiiiiiiiiiffiissssssssssssssssxxxxxxxxxxxxxxxxxx")
Note: in 1.12 the row layout omits ReputationFlags[4] that TBC/WotLK
added, so the Name string offset moves from 19 → 23 across the
TBC bump.
Same root-cause pattern as bd5e9aa2 and 50e31ab0 (DBC field referenced
by code but missing from layout JSON → operator[] sentinel beats
the ternary fallback).
entity_spawner.cpp:1832-1835 queries these for shoulder-piece M2
attachment (shoulders have two models — left at attachment point 5
and right at attachment point 6):
const uint32_t leftModelField = idiL ? (*idiL)["LeftModel"] : 1u;
const uint32_t rightModelField = idiL ? (*idiL)["RightModel"] : 2u;
const uint32_t leftTexFieldS = idiL ? (*idiL)["LeftModelTexture"] : 3u;
const uint32_t rightTexFieldS = idiL ? (*idiL)["RightModelTexture"]: 4u;
None of the four dbc_layouts.json files defined RightModel or
RightModelTexture. The ternary returns the layout lookup result when
idiL is non-null — and DBCFieldMap::operator[] on a missing field
returns DBC_FIELD_INVALID (0xFFFFFFFF), NOT the intended fallback.
So shoulder right-side M2 model and texture loaded from field
0xFFFFFFFF (out of bounds, getUInt32 returns 0) and the right
shoulder pad never rendered on any character.
Added the standard pairing values (RightModel=2, RightModelTexture=4)
to all four expansion layouts — these match the canonical
ItemDisplayInfo.dbc field order and the code's intended fallbacks.
Same root cause as bd5e9aa2 (SpellRange.MinRange) — the
'tnL ? (*tnL)["Field"] : N' pattern silently breaks when the field
is missing from the JSON but the DBC is present, because the
sentinel from operator[] beats the fallback N.
application.cpp:438 queries SpellRange.MinRange to populate the
spell-range map used by minimum-distance casting checks. None of the
four dbc_layouts.json files defined MinRange, so the lookup returned
the DBC_FIELD_INVALID sentinel (0xFFFFFFFF); rDbc->getFloat(i, 0xFFFFFFFF)
then read out of bounds and returned 0. Minimum-range checks were
silently dead on every expansion.
Canonical SpellRange.dbc layouts (per spellbook_screen.cpp:71-74):
Classic 1.12: 0=ID, 1=MinRange, 2=MaxRange
TBC / WotLK: 0=ID, 1=MinRangeFriendly, 2=MinRangeHostile,
3=MaxRangeFriendly, 4=MaxRangeHostile
The existing MaxRange values (classic 2, TBC/WotLK 4) follow the
'Hostile' convention; MinRange is wired the same way (1 for Vanilla,
2 for TBC/WotLK).
Visible effect: spells with a non-zero minimum range (hunter ranged
abilities, Pyroblast, etc.) will now correctly trigger 'You are too
close' errors and target-validity checks at the client level.
Per cmangos / vmangos Vanilla 1.12 opcode tables:
SMSG_INSPECT = 0x115 (cmangos Opcodes.h:315, vmangos Opcodes_1_12_1.h:280)
That wire slot was REPURPOSED in TBC to SMSG_INSPECT_RESULTS_UPDATE
(with a different packet body). The Classic opcode table inherited the
post-TBC name, which meant:
- Server sends 0x115 with the Vanilla SMSG_INSPECT body
(PackedGUID + 19 uint32 itemEntries — EQUIPMENT_SLOT_END=19).
- fromWire(0x115) returned LogicalOpcode::SMSG_INSPECT_RESULTS_UPDATE
on Classic.
- social_handler.cpp:128 routed the bytes to handleInspectResults(),
which parses the WotLK-style format and misread the packet.
- The handler at game_handler_packets.cpp:1902 — which has the
correct Classic 1.12 parser and an explicit comment 'only reachable
on Classic servers' — was dead code on Classic.
Fixing the JSON name routes wire 0x115 to the Classic-aware handler.
TBC and WotLK JSONs are untouched (SMSG_INSPECT_RESULTS_UPDATE = 0x115
is correct for those expansions).
Turtle inherits classic via _extends, so it gets the fix automatically.
Not patched in this commit:
- SMSG_SET_REST_START / SMSG_QUEST_FORCE_REMOVE both legitimately
exist at 0x21E across forks (vmangos uses one name, AzerothCore/TC
uses the other). quest_handler.cpp:685-700 already disambiguates
by expansion at runtime, so the existing mapping is defensible.
- SMSG_LEVELUP_INFO_ALT — appears to be a project-invented name with
no upstream wire value. Left alone.
UNIT_NPC_EMOTESTATE is read in entity_controller.cpp:551 for stationary
NPC looping animations (sleeping, talking, working, etc.) and in
animation_callback_handler.cpp:323.
- classic, turtle, tbc: field was missing entirely — fieldIndex() was
returning the 0xFFFF sentinel, so NPC idle emote animations never
played on those expansions.
- wotlk: field was set to 164, which is past UNIT_END (148) — that
index falls inside the PLAYER_ range, so reading it would have
pulled an unrelated player-fields value rather than the unit emote
state.
Authoritative sources:
Vanilla 1.12: 148 (vmangos UpdateFields_1_12_1.h:93,
OBJECT_END + 0x8E)
TBC 2.4.3: 169 (cmangos mangos-tbc UpdateFields.h:118,
OBJECT_END + 0xA3)
WotLK 3.3.5a: 83 (TrinityCore 3.3.5 UpdateFields.h:140,
OBJECT_END + 0x4D — adjacent to UNIT_NPC_FLAGS=82)
Python collision check after patch: no UNIT_* aliasing in any file.
The classic and turtle update_fields.json files had several wrong
indices that aliased fields together and misread the unit record.
Cross-referenced vmangos UpdateFields_1_12_1.h
(github.com/vmangos/core, OBJECT_END=6) and corrected:
- UNIT_FIELD_BYTES_1: 133 -> 138 (was colliding with MOUNTDISPLAYID)
- UNIT_FIELD_STAT0..STAT4: 138..142 -> 150..154 (the old slot held
pet fields PETNUMBER/PET_NAME_TIMESTAMP/
PETEXPERIENCE/PETNEXTLEVELEXP, not stats)
- UNIT_FIELD_RESISTANCES: 154 -> 155 (off by one — STAT4 lives at 154)
- UNIT_FIELD_NATIVEDISPLAYID: added (was missing) -> 132
The verified other indices (DISPLAYID=131, MOUNTDISPLAYID=133,
DYNAMIC_FLAGS=143, NPC_FLAGS=147, BYTES_0=36) all matched vmangos
and were left alone.
Practical impact on Classic/Turtle prior to this fix:
- entity_controller.cpp:548-553 read MOUNTDISPLAYID and BYTES_1 from
the same slot — mount/dismount detection and shapeshift form
detection would race and clobber each other.
- All STAT* readers were reading pet-related fields instead of stats,
so character-sheet stats and stat-derived UI on Classic/Turtle
would be wrong/zero.
- UNIT_FIELD_RESISTANCES readers got STAT4 instead of armor resist.
Python collision check after patch: no UNIT_* collisions in either
file.
Add complete spell visual pipeline resolving the DBC chain
(Spell → SpellVisual → SpellVisualKit → SpellVisualEffectName → M2)
with precast/cast/impact phases, bone-attached positioning, and
automatic dual-hand mirroring.
Ribbon rendering fixes:
- Parse visibility track as uint8 (was read as float, suppressing
all ribbon edges due to ~1.4e-45 failing the >0.5 check)
- Filter garbage emitters with bone=UINT_MAX unconditionally
- Guard against NaN spine positions from corrupt bone data
- Resolve ribbon textures via direct index, not textureLookup table
- Fall back to bone 0 when ribbon bone index is out of range
Particle rendering fixes:
- Reduce spell particle scale from 5x to 1.5x (was oversized)
- Exempt spell effect instances from position-based deduplication
Spell handler integration:
- Trigger precast visuals on SMSG_SPELL_START with server castTimeMs
- Trigger cast/impact visuals on SMSG_SPELL_GO
- Cancel precast visuals on cast interrupt/failure/movement
M2 classifier expansion:
- Add AmbientEmitterType enum for sound system integration
- Add 20+ foliage tokens, 4 spell effect tokens, isSmallFoliage flag
- Add markModelAsSpellEffect() to override disableAnimation
DBC layouts:
- Add SpellVisualID field to Spell.dbc for all expansion configs
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
Revert static JSON layout changes (15-22 back to 14-21) since WotLK
loads the Classic 23-field DBC. Add getItemDisplayInfoTextureFields()
helper that detects field count at runtime and adjusts the texture
base index accordingly (14 for 23-field, 15 for 25-field).
TBC and WotLK have 25-field ItemDisplayInfo.dbc (vs 23 in Classic/Turtle)
with 2 extra fields before the texture region block. The texture fields
start at index 15 (not 14), shifting all 8 regions by +1.
This caused every equipment texture to be composited into the wrong body
region — e.g. LegLower textures landing in FootTexture, belt textures in
LegLowerTexture instead of LegUpperTexture ("everything shifted by 1").
Verified against raw DBC binary data: Classic field[14]=ArmUpper,
TBC/WotLK field[15]=ArmUpper.
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.
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.).
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)
PR #19 (572bb4ef) swapped CharSections.dbc field indices, placing
Texture1-3 at fields 4-6 and VariationIndex/ColorIndex at 8-9. Binary
analysis of the actual DBC files (Classic, TBC, Turtle — all identical
layout, no WotLK-specific override) confirms the correct order is:
Field 4 = VariationIndex
Field 5 = ColorIndex
Field 6 = Texture1 (string)
Field 7 = Texture2 (string)
Field 8 = Texture3 (string)
Field 9 = Flags
With the wrong indices, VariationIndex/ColorIndex reads returned string
offsets (garbage values that never matched), so all CharSections lookups
failed silently — producing white untextured character models at the
login screen and in-world.
Fixes all 4 expansion JSON layouts, hardcoded fallbacks in
character_preview.cpp, application.cpp, and character_create_screen.cpp.
Also handles the single-layer edge case (body skin only, no face/underwear)
by loading the texture directly instead of skipping compositing.
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.
Implement the core WoW frame system that nearly all addons use:
- CreateFrame(type, name, parent, template) — creates a frame table
with metatable methods, optionally registered as a global by name
- frame:RegisterEvent(event) — register frame for event dispatch
- frame:UnregisterEvent(event) — unregister
- frame:SetScript(type, handler) — set OnEvent/OnUpdate/etc handlers
- frame:GetScript(type) — retrieve handlers
- frame:Show()/Hide()/IsShown()/IsVisible() — visibility state
- frame:GetName() — return frame name
Event dispatch now fires both global RegisterEvent handlers AND
frame OnEvent scripts, matching WoW's dual dispatch model.
Updated HelloWorld to use standard WoW addon pattern:
local f = CreateFrame("Frame", "MyFrame")
f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:SetScript("OnEvent", function(self, event, ...) end)
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.
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.
Add PLAYER_FIELD_HONOR_CURRENCY and PLAYER_FIELD_ARENA_CURRENCY to the
update field system for WotLK (indices 1422/1423) and TBC (1505/1506).
Parse values from both CREATE_OBJECT and VALUES update paths, and show
them in the character Stats tab under a PvP Currency section.
Load AttributesEx from Spell.dbc for all expansions (Classic/TBC/WotLK/
Turtle). Check SPELL_ATTR_EX_NOT_INTERRUPTIBLE (bit 4 = 0x10) to classify
each cast as interruptible or not when SMSG_SPELL_START arrives.
Target frame and nameplate cast bars now use:
- Green: spell can be interrupted by Kick/Counterspell/Pummel etc.
- Red: spell is immune to interrupt (boss abilities, instant-cast effects)
Both colors pulse faster at >80% completion to signal the closing window.
Adds GameHandler::isSpellInterruptible() and UnitCastState::interruptible.
Parse SMSG_PLAY_SPELL_VISUAL (casterGuid + visualId) and spawn a
transient M2 spell effect at the caster's world position.
DBC chain: SpellVisual.dbc → SpellVisualKit.dbc → SpellVisualEffectName.dbc
Lookup priority: CastKit.SpecialEffect0, fallback to MissileModel.
Models are lazy-loaded and cached by path; instances auto-expire after 3.5s.
DBC layouts added to all four expansion layout files (Classic/TBC/WotLK/Turtle).
Tracks PLAYER_FIELD_MOD_DAMAGE_DONE_POS (7 schools at field 1171) and
PLAYER_FIELD_MOD_HEALING_DONE_POS (field 1192) from server update fields.
getSpellPower() returns the max damage bonus across magic schools 1-6.
getHealingPower() returns the raw healing bonus.
Both values displayed in the character screen Combat section alongside
the previously added attack power, dodge, parry, crit, and rating fields.
Adds update field tracking for WotLK secondary combat statistics:
- UNIT_FIELD_ATTACK_POWER / RANGED_ATTACK_POWER (fields 123, 126)
- PLAYER_DODGE/PARRY/BLOCK/CRIT_PERCENTAGE (fields 1025-1029)
- PLAYER_RANGED_CRIT_PERCENTAGE, PLAYER_SPELL_CRIT_PERCENTAGE1 (1030, 1032)
- PLAYER_FIELD_COMBAT_RATING_1 (25 slots at 1231, hit/expertise/haste/etc.)
Both CREATE_OBJECT and VALUES update paths now populate these fields.
The Character screen Stats tab shows them when received from the server,
with graceful fallback when not available (Classic/TBC expansions).
Field indices verified against AzerothCore 3.3.5a UpdateFields.h.
Add LFGDungeons.dbc cache (loadLfgDungeonDbc / getLfgDungeonName) and
use it to enrich three LFG chat messages in WotLK:
- handleLfgJoinResult: "Joined the queue for Culling of Stratholme."
- handleLfgProposalUpdate case 1: "Group found for Halls of Lightning!"
- handleLfgProposalUpdate case 2: "A group has been found for ... Accept or decline."
Falls back to generic text when DBC is unavailable or dungeon ID unknown.
Classic WoW stores aura flags in UNIT_FIELD_AURAFLAGS (12 uint32 fields
packed 4 bytes per uint32, one byte per aura slot). Flag bit 0x02 = harmful
(debuff), 0x04 = helpful (buff).
- Add UNIT_FIELD_AURAFLAGS to update_field_table.hpp (Classic wire index 98)
- Add wire index 98 to Classic and Turtle WoW JSON update field tables
- Both Classic aura rebuild paths (CREATE_OBJECT and VALUES) now read the
flag byte for each aura slot to populate AuraSlot.flags, enabling the
buff/debuff bar to correctly separate buffs from debuffs on Classic
Track player titles from SMSG_TITLE_EARNED into knownTitleBits_ set,
read active title from PLAYER_CHOSEN_TITLE update field (WotLK index
1349), expose via getFormattedTitle()/sendSetTitle() on GameHandler.
Add SetTitlePacket builder (CMSG_SET_TITLE: int32 titleBit, -1=clear).
Titles window (H key) lists all earned titles from CharTitles.dbc,
highlights the active one in gold, and lets the player click to equip
or unequip a title with a single server round-trip.
Previously SMSG_TITLE_EARNED only showed the numeric bit index.
Now it lazy-loads CharTitles.dbc and formats the full title string
with the player's name (e.g. "Title earned: Commander Kelsi!").
- Add CharTitles layout to WotLK (TitleBit=36) and TBC (TitleBit=20) layouts
- loadTitleNameCache() maps each titleBit to its English title string
- SMSG_TITLE_EARNED substitutes %s placeholder with local player's name
- Falls back to "Title earned (bit N)!" if DBC is unavailable
The Criteria tab now loads AchievementCriteria.dbc to display each
criterion's description text, parent achievement name, and a
current/required progress counter (e.g. "25/100") instead of the
raw numeric IDs. The search filter now also matches by achievement name.
AchievementCriteria DBC layout added to wotlk/dbc_layouts.json.
Hovering an earned achievement now shows its point value (gold badge),
description text from Achievement.dbc field 21, and the earn date.
loadAchievementNameCache() also populates achievementDescCache_ and
achievementPointsCache_ in a single DBC pass; Points field (39) added
to the WotLK Achievement DBC layout.