Dibs-v0.1.4-classic
What's new
Changelog
[v0.1.4] — custom & tank EP weights, weapon skill, all-slot enchants & planner filters
Added
- Weights tab — EP weight templates. A new tab (beside Planner / Wishlist) edits EP stat weights
as templates. The per-spec defaults (HawsJon) are immutable; Save As copies the current
values into a named template, Delete removes a saved one, Reset discards unsaved edits. A
dropdown lists the defaults + your saved templates (account-wide,
DibsDB.weights[classID]), and the selected template is active and drives all EP scoring — including its spec (picking a Beast-Mastery template scores you as BM). It threads through the EP column, hover breakdown, set-bonus EP, and loadout totals vians.Items:ScoringClassSpec/WeightSource; custom templates register into LibItemDB as adibsweight source, and Dibs never touches the lib's global default, so other addons sharing LibItemDB are unaffected. New modulens.Weights(pureWeights.Sanitize, unit-tested inTests/weights_spec.lua); the UI uses new sharedLibAceGUIWidgetshelpers —CreateDropdownBox(MINOR 7) andShowDialog(MINOR 8, the naming prompt). - Planner filters + sort. The gear list gains a filter row: a Source dropdown, a Sort by
dropdown, and a Search box (matches any field — name, source — as you type). The Source dropdown
is tiered — instead of one giant flat list of every zone, the slot's sources are grouped into
Raids / Dungeons / World & other hover-flyout submenus (categorised by
ns.Items:SourceCategory, data-driven offGetInstances), each A–Z. The Sort by dropdown re-orders the list by a chosen stat instead of EP and swaps the score column to show that stat's value — so you can rank a slot by Agility, Stamina, etc.; it's a sort, not a filter (items without the stat sink to the bottom, they aren't hidden). It's tiered too — the ~30 scorable stats are grouped into Primary / Melee & Ranged / Spell / Defense / Weapon Skill / Other submenus (purens.Items.StatCategory, unit-tested), each A–Z. Built on shared LibAceGUIWidgets widgets —CreateSearchBox+ pureSearchMatch(ported from TOGProfessionMaster),CreateDropdownBox, and the new cascading-submenu support inOpenMenu/ToggleMenu(lib MINOR 10). - Tank scoring. The Weights tab now surfaces tank templates — Protection (warrior / paladin) and
Feral Tank / Guardian (druid) — alongside the DPS/healer specs, scored with LibItemDB's dedicated
tankweight scale (defense / dodge / parry / block / block value). They only appear for tank-capable classes (the tank scale lists no specs for others). Picking one scores your whole build as that tank spec (EP column, hover breakdown, set-bonus EP, totals). The template model now carries a weight source per template (nil = HawsJon,tank, ordibsfor a saved custom), threaded throughns.Weights→ns.Items:WeightSource. - Weapon skill now scores. Weapon-skill gear (Edgemaster's Handguards, +skill weapons and rings) was
reading as zero because LibItemDB models +skill (fewer misses/dodges, better glancing) only when you
tell it your weapon. Dibs now passes the equipped main-hand's type + white DPS in
opts.attack(new pureItems.WeaponTypeToken, unit-tested), so +skill is valued for the weapon you actually swing, everywhere EP is computed. LibItemDB models it (not a flat weight), so it never double-counts. Because it's modeled rather than linearly weighted, theWEAPON_SKILL_*rows are omitted from the Weights editor (a number there does nothing) — weapon skill still scores and stays sortable in the Planner's Sort dropdown. A weapon candidate is scored for its OWN type, not the equipped weapon's (equipping Maladath means wielding a sword, so its+swordsis valued for swords) —attackOptsis item-aware, and weapon-slot rows re-score per-item since the bulk ranking can only carry one type. A+skillring/glove still uses the equipped type. (The magnitude of weapon-skill EP is LibItemDB's — itsscoreWeaponSkillshould scale by the per-hand DPS weight HawsJon tuned, hunter melee0.75vs warrior5.31vs ranged2.6, so a hunter's melee weapon skill is reduced-not-zero; Dibs only supplies the type + DPS.) - Free wins from LibItemDB v0.4.2 — no Dibs code needed: spell penetration, ranged/quiver
haste, feral attack power (Atiesh, Blessed Qiraji War Hammer, …), and life-steal / haste
procs (e.g. Corrupted Ashbringer) now fold into EP automatically through
GetStats/GetItemScore; the newweaponskillbreakdown row renders in the hover EP breakdown; and now-hidden items (Ashbringer, Shard of the Defiler) drop out of the rankings. - Every enchantable slot now has enchants — including head, shoulder & legs. Dibs' enchant adapter
(Data/Enchants.lua) now reads ProfessionDB's unified, slot-indexed enchant
catalog (
EnchantsForSlot/GetEnchant), which merges craftable enchants (enchanting recipes) with item-applied ones — reputation arcanums, ZG inscriptions, armor kits, shield spikes, Wolfshead, Mithril Spurs. That closes the gap where head/shoulder/legs (and other kit slots) showed nothing, because those aren't enchanting recipes at all. Dibs now maps each paperdoll slot to PDB's slot token(s) (resolving weapon 1H/2H/shield handedness) and passes the catalog entries through; entries are keyed by enchant id, so a worn item's applied enchant — arcanums included — now resolves deterministically from its link id viaGetEnchantinstead of relying on the tooltip scan (still kept as the fallback). The picker shows the enchant's flavor name (e.g. Arcanum of Rapidity, resolved from the catalog'sitemId) with its stat text. Requires a ProfessionDB that shipsEnchantsForSlot; feature-detected, so an older ProfessionDB just degrades to the craftable enchants as before. The old recipe-name→slot classifier and Enchanting-only index are retired;ns.Enchants.ParseStatTextstays (the worn-tooltip fallback), still covered byTests/enchants_spec.lua. - Shift-click to link, and a BiS explainer. Shift-clicking an item in the Planner list now links
it into chat (and Ctrl-click dresses it up) — standard
HandleModifiedItemClickhandling, so a plain click still slots the item. And the window's info "i" tooltip now explains, on the Planner tab, why you see several BiS badges: it's the best item per 20+ man raid (your MC BiS, your AQ40 BiS, …), not a claim they're all equal — so newcomers aren't confused by "so many BiS items". - Enchant picker grouped by role. A slot with many enchants (helms, chests) now groups them into
Physical / Caster / Tank / Resistance / Other submenus, each best-EP first, with the role that fits
your weights surfaced first (a short list stays flat). Pure
ns.Items.EnchantRole(unit-tested). The submenu ▶ arrows only show on hover now (a shared LibAceGUIWidgets menu change), and the Sort dropdown's stat list is likewise tiered (see Planner filters);Mana Per 5 Sec.groups under Spell so there's no lonely one-item "Other". - Enchant EP — ranked and folded into totals. The per-slot enchant picker now scores every enchant
under your active weight scale and lists them best-EP first, showing each enchant's EP, so the top
enchant for the slot is obvious. The chosen enchant's EP is also added into the loadout's Total EP
(and the equipped baseline picks up your worn enchants), so Total EP and its
+Ndelta reflect enchants the same way the stat summary already does. Newns.Items:ScoreStats(pure coreItems.SumStatEP, unit-tested inTests/scorestats_spec.lua) scores an arbitrary stat table via LibItemDB's weight scale;Loadout:TotalEP/EPDeltafold in the enchant contribution through the sameslotBonusesresolution used for stats (assigned enchant wins, else the worn one).
Changed
- Item sources now come from LibItemDB's merged
GetSourcesinstead of the boss-drop-only instance forward-map (GetInstanceItems). So the Source column and the raid BiS badge see every origin the new CMaNGOS location data carries — quest, vendor, PvP, reputation, and raid quest/vendor items the AtlasLoot boss graph missed — not just boss loot. "Other" shrinks hard: Striker's Diadem now reads Temple of Ahn'Qiraj, PvP gear reads PvP, reputation gear reads its faction.ns.Items:InstanceOfnow returns any source label;ns.Items:IsRaidSourceresolves a raid by a boss-dropinstanceKeyor, for keyless quest/vendor locations, by mapping the place name back to its key (LibItemDB normalizes those location names to the AtlasLoot SourceNames spelling, so the map fromGetInstancesresolves them directly). Resolution is a pureItems.ResolveSource(unit-tested,Tests/source_spec.lua) that prefers the raid identity, so a raid quest item labels and badges as its raid, consistently with that raid's boss drops. Backward-compatible —GetSourcesexists on the current released LibItemDB (it returns boss drops there), so it degrades gracefully; the full richness lights up on the LibItemDB build that ships the location pipeline.
Fixed
- Worn-enchant defense parsed to the wrong stat key. The
ParseStatTextfallback (used to read a worn item's enchant off its tooltip when the id isn't in the catalog) mapped "Defense" toITEM_MOD_DEFENSE_SKILL_RATING, which isn't a LibItemDB key — so a worn defense enchant didn't aggregate or score. Now maps to LibItemDB's actualDEFENSEkey (plusBLOCK_VALUE); covered byTests/enchants_spec.lua. - Dropdown menus were see-through over the gear list — a real draw-order bug in the shared widget
library, not backdrop alpha (an earlier pass wrongly "fixed" it by setting the fill colour). The menu
re-parented to its anchor and rendered at the anchor's frame level inside the window's
FULLSCREEN_DIALOGstrata; the RowList's cells sit at a higher effective level in that same window, so their text drew straight through the menu's opaque backdrop. Fixed in LibAceGUIWidgets by rendering every menu at theTOOLTIPstrata (above the window entirely — strata beats level), so no window content can overdraw it. The fill is now solid black (backdrop0,0,0,1plus a belt-and-suspenders solid-black background texture). This corrects the Source/Sort/enchant dropdowns and every other menu in the suite at once. (Ships in LibAceGUIWidgets MINOR 10; the Sort dropdown showing category submenus is the tell that MINOR 10 is the loaded lib.)
[v0.1.3] — smarter scoring: set bonuses, proc weapons & best-in-raid
Added
- Compare-to-equipped stat deltas in the Planner. The summary now shows a red/green
delta beside any stat a loadout changes versus your currently-equipped gear — Total EP,
primaries, and the derived stats (Attack Power / Crit / Hit / Armor / resistances). Swap a
helm and you see e.g.
Agility +3(green) andRanged Hit -1.0%(red). "Current Gear" shows none until you actually swap a piece. Swapping a weapon projects Melee/Ranged DPS too — the DB weapon's DPS change plus the attack-power change (~14 AP = 1 DPS) — so the DPS lines move with the build instead of staying on your worn weapon. - Set bonuses track the loadout. The Set bonuses area now reflects the built loadout's piece counts — every tier shown green (met) or grey (not) by the loadout — and updates as you swap set pieces in and out. Previously it stayed fixed on your worn gear's active bonuses, because it trusted the game tooltip's own (worn-based) rendering; tier thresholds are now rebuilt from LibItemDB's set data so the display is loadout-driven.
- On-use trinkets get an EP. LibItemDB now folds an uptime-averaged EP for on-use effects
into its scoring, so a trinket like Earthstrike (+280 AP on use) ranks properly instead of
reading
0— Dibs gets that for free through the EP ranking. Best-in-raid badges: for each 20+ man raid (MC, BWL, Onyxia, AQ40, AQ20, Zul'Gurub, Naxxramas), the highest-EP item you can actually get there carries a gold BiS badge — your MC BiS, your AQ40 BiS, one per raid — computed after eligibility on the loadout-adjusted EP via pureItems.BestBySource(unit-tested). 5/10-man dungeons, world bosses, and theOtherbucket are not badged (Items:IsRaidSourcematches LibItemDB's locale-independent instance keys against a fixed Classic raid set). This is EP-driven, not WoWSims' curated lists — those are progression-tier and sparse (a hunter only has a pre-raid + MC set), so they can't answer "best from AQ40/Naxx" and their pick isn't even the top-EP item of its tier; on frozen Classic Era, where every drop list is permanent, the best item per raid is the honest answer. An item whose special effect isn't fully captured in the EP still gets a~marker (ns.Items:HasUnscoredProc). Via newns.Itemsreads (GetUseEffect,HasUnscoredProc). (The "upgrades only" filter stays a plain EP comparison — those badges are informational and don't exempt a low-EP item from being hidden.) - EP score breakdown on hover. Hovering an item in the Planner's gear list now appends an EP
breakdown to its tooltip: each weighted stat as
value x weight = EP, then the set-bonus / on-use / proc buckets, then the total — so a score is explainable rather than a black box (e.g. why Thunderfury's or Earthstrike's EP lands where it does). LibItemDB owns the math and exposes an itemizedGetItemScoreBreakdownthat decomposes exactly whatGetItemScoresums, so the breakdown can never drift from the score; Dibs renders it via a new feature-detectedns.Items:GetScoreBreakdown(Data/ItemSources.lua) in the row-hover tooltip (GUI/Planner.lua). Stat rows label via WoW's own localized stat globals; the bucket labels + header are new locale keys (planner_ep_breakdown/_set/_use/_proc). The block simply doesn't appear on a LibItemDB build without the breakdown API. - Flat-chance procs scale to your weapon cadence. Dibs now passes the loadout's swings/sec
(
opts.attack.hitsPerSec, derived fromUnitAttackSpeed) into every LibItemDB score path — the EP column (GetSlotRanking),GetEP, and the breakdown — so flat-chance proc EP reflects your actual weapon speed instead of the lib's per-class default. PPM procs are weapon-speed-normalized and ignore it (the famous ones were already right). The cadence math is a pure, nil-safe, unit-tested helper (ns.Items.SwingsPerSec, covered byTests/attack_spec.lua); the value reflects worn weapons — an approximation when planning a weapon swap, and absent-safe so nothing regresses without it. - Set bonuses show their EP. Each tier in the Planner's Set bonuses panel now shows how much EP
that bonus is worth for your class & spec — e.g.
(4) Set: … — 23 EP— so a set bonus can be weighed against raw stats. LibItemDB scores each tier's granted stats with the same weights as item EP (LibItemDB'sGetSetBonusEP, consumed through feature-detectedns.Items:GetSetBonusEP), so the numbers can't drift from the item scores; the suffix simply doesn't appear on a LibItemDB build without the API. - Equipped-aware set-bonus EP (marginal value). The Planner now ranks a set piece by its stats
PLUS the set stage that equipping it actually unlocks given the rest of your loadout — the real
marginal upgrade value — instead of LibItemDB's context-free per-piece amortization (which put a
phantom "Set bonus" fraction on a lone piece). This flows through the EP column, the hover
breakdown (whose set-bonus row now reflects your current set count, and whose total still equals
the column), and the loadout Total EP (which adds the real active set bonuses once per set, not
a per-piece fraction). Dibs asks LibItemDB for pure-stats EP (
setBonus=false) and computes the marginal itself fromGetSetBonusEP+ the loadout's piece counts (newLoadout:SetCounts, pureItems.SetEPTotal/Items.SetEPMarginal, unit-tested inTests/setep_spec.lua); the lib's amortized proxy stays the fallback on an older LibItemDB. - Offline unit-test harness (dev-only). A new
Tests/folder brings the shared WoWAPITesting harness in as a submodule (Tests/wowapi) so pure logic can be unit-tested with no game client. Ships a pilot spec,Tests/enchants_spec.lua, that loadsData/Enchants.luathrough the harness and coversns.Enchants.ParseStatText(11 cases:Stat +N/+N Stat, theAll StatsandAll Resistancesfan-outs, compound effects, mp5, Armor→RESISTANCE0_NAME, Spell Power/Damage, a single elemental resist, unparseable procs, and nil/blank). Run it with zero dependencies —lua Tests/wowapi/run.luafrom the addon root (the harness's bundled runner) — or withbustedon CI (.github/workflows/tests.yml). Supporting files: a thin.bustedshim that defers to the harness's shared config,Tests/.luarc.jsonfor the spec's busted/requireglobals, and.gitmodules. None of it ships —Tests,.busted, and.gitmodulesare in the.pkgmetaignore list.
Changed
- Class-obtainability filtering. Items are gated by LibItemDB's authoritative
ClassUsable, which corrects Blizzard's mis-flagged tier/dungeon sets, AQ40 2.5, Naxx T3, and Atiesh (the raw item data reports them as usable by every class). Wired intons.Items:CanUse, so it covers every listing path — the EP picker, the instance-list fallback, and wishlist eligibility — filtered by the profile's class (alt-safe). A hunter no longer sees rogue T3 (Bonescythe), etc. Requires LibItemDB with its class-restriction data loaded.
[v0.1.2] — accurate stats, deterministic enchants, per-character wishlists
Added
- Per-character wishlists with an all-alts view. Each character keeps its own list
(
DibsDB.chars[key]), and a Character selector in the Wishlist tab lets you view and plan any of your alts' lists from one place. Your existing flat list migrates into the logged-in character automatically. - Tag dibs to a scheduled event. When ClassicCalendar is present, the Wishlist tab
gains an Event box that filters to a scheduled raid and auto-tags new dibs to it, a
per-row "tag to event" action, and an Event column.
Data\Events.lua(ns.Events) reads the calendar'sCalendarHelperDB; fully optional — no calendar, no event UI. - Magic resistances in the summary. Per-school character totals (Fire/Nature/Frost/
Shadow/Arcane, and any school a future flavour exposes) read from
UnitResistance, shown when non-zero — data-driven and version-agnostic.
Changed
- Hit % now matches the character sheet. Melee and Ranged Hit read the game's own
GetHitModifier()total (gear + talents + head/leg enchants) plus the planned gear/enchant delta, with a worn ranged-weapon scope's hit read off that slot's enchant. Fixes the 9%-vs-11% gap (the missing 2% was the Zandalar head/leg hit enchants). - Deterministic worn enchants via ProfessionDB. With LibProfessionDB's new
enchantId/enchantSlot/statsfields, a worn item's applied enchant resolves straight from its link id to structured stats — retiring the recipe-name grep and the effect-string parser for enriched recipes (both kept only as fallbacks). The tooltip scan remains for enchants no data source carries (head/leg, scopes). - LibAceGUIWidgets and ProfessionDB are required dependencies. Both are restored to
## Dependenciesand the.pkgmetaCurseForge relations (libaceguiwidgets/libprofessiondb) now that LibAceGUIWidgets' CF project is approved — so CurseForge auto-installs the full stack. ProfessionDB backs the enchant data (enchantId/enchantSlot/stats).
[v0.1.1] — packaging fix
Changed
- LibAceGUIWidgets is an optional dependency for now. Its CurseForge project
(id
1599206) is still awaiting moderator approval, so it isn't publicly accessible — and CurseForge rejects a release whose project relations point at an unapproved project (errorCode 1018), which failed the v0.1.0 CurseForge upload (the GitHub release succeeded). Removed it from the.pkgmetaCurseForge relations and moved it to## OptionalDepsinDibs.tocso the addon packages and uploads. The library is still required for the UI — install it alongside Dibs — and it will be restored as a dependency once its CF project is approved. No code changes.
[v0.1.0] — initial development
First release. New capabilities, folded in as they land — this is initial build-out, so entries describe new things, not iteration.
Added
- Loadable Classic Era addon +
/dibs.Dibs.luabootstrap registers theDibsDBSavedVariable (defaults-merge), resolves its version viaC_AddOns.GetAddOnMetadata(legacy fallback), and adds the/dibsslash command. Full pre-implementation design underdocs/; BigWigs packager.pkgmeta, GitHub release workflow, MITLICENSE, markdownlint/luarc config. - FastGuildInvite-style layout + family branding. Bootstrap +
Constants.luaat root, feature/comms logic underModules\, UI underGUI\(AceGUI-3.0 via the shared LibAceGUIWidgets), shipped data underData\, localization underLocale\. Brand orangeffFF8000, shared with FGI / TOGProfessionMaster. - External shared dependencies. Ace3, AceCommQueue-1.0, VersionCheck-1.0,
LibGuildRoster, LibLocaleOverride, LibAceGUIWidgets, LibItemDB (ItemDB), DeltaSync —
declared in
Dibs.toc+.pkgmeta(not vendored), matching the DeltaSync consumer ecosystem. Only LibDataBroker-1.1 + LibDBIcon-1.0 are vendored (Libs\). - Localization system.
ns.L.<code>tables (FGI model, not AceLocale) registered with LibLocaleOverride;ns.GetLocale()returns the merged table (key-as-fallback), and the UI reuses LLO's AceGUI helpers. English (enUS) for dev; every user-facing string routes through the accessor. - Data-sync + version-check scaffold.
Modules\Comms.luawires the shared comms stack — an AceComm/AceCommQueue send instance, an isolated DeltaSync host (NewHost), a LibGuildRoster identity/trust gate, and a per-type sync-handler registry.Modules\Version.luawires VersionCheck-1.0 for an out-of-date reminder. The wishlist diff/merge + P2P catch-up are registry seams pending the sync-scope decisions (docs/06). - Main window.
/dibsopens a branded LibAceGUIWidgetsClearFramewith a tab strip (Planner / Wishlist), a bottom status bar (Close button + info "i" tooltip, lifted above the resize strips), and localized tab fonts. Size/position, the open tab, and the Wishlist scroll persist across sessions; a minimum size keeps it from shrinking below the Planner's contents. - Minimap button. A LibDataBroker launcher shown via vendored LibDBIcon-1.0; position +
hidden state persist in
DibsDB.minimap. - Item data layer (
Data\ItemSources.lua). A thinns.Itemsadapter over LibItemDB (metadata, drop sources, EP/BiS, item sets) so no module touches the lib directly. Also owns Dibs-side logic: an item→instance reverse index for the Source column, a talent-tree → spec resolver, and the full equipment-eligibility gate. - Wishlist tab. A sortable
RowListof your called-dibs items by source instance; add by shift-click/paste + Enter, remove via the row action; backed byDibsDB.wishlist. - Paperdoll Planner — a SixtyUpgrades-style loadout builder. A character-sheet slot
grid where each slot shows the item slotted in your active loadout (falling back to
equipped). Click a slot to list every gear option that fits it — a whole-DB, EP-ranked
list (community-standard HawsJon weights via LibItemDB, scored for your real spec)
with click-sortable Source / EP / iLvl columns, item tooltips on hover, an "Upgrades
only" filter, and a Main-Hand "Hide two-handed" toggle. Left-click a row to slot the
item; the coin icon adds it to your wishlist; right-click a slot to clear it.
- Only shows what the character can use. One
ns.Items:CanUse(id [, profile])gates every row by faction, class (armor + shield + weapon proficiency + "Classes:" tag) and race ("Races:" tag), read from the client's own tooltip data and applied at render so it self-heals as item data streams in.profileis parameterized for the future "plan for an alt" feature. - Loadout templates. Save / load named loadouts (account-wide, tagged by class) from a
top bar — Save As, Load, Delete, Reset to equipped.
Modules\Loadout.lua(ns.Loadout) owns loadouts + aggregation;DibsDB.loadoutspersists them. - Live summary (centre panel, replacing the 3D model): total EP, average + total item level, and a full character-total stat block — primary stats plus derived Attack Power / Ranged AP / Crit / Armor / melee + ranged Hit and melee + ranged DPS computed to match the character sheet exactly for your current gear (game value + gear delta + per-class conversion ripple) — and active set bonuses with their real effect text. Scrollable; the loadout picker is the shared library dropdown (checkbox rows, click-outside to close); controls carry tooltips.
- Enchants, SixtyUpgrades-style. A per-slot enchant picker (dropdown box, populated
from LibProfessionDB's Enchanting catalog, handedness-aware for weapons/off-hands)
lets you assign an enchant to a planned piece; its stats — parsed from the recipe's
effect text via a shared free-text→stat parser — fold straight into the loadout totals.
Your currently-worn enchants are read live off each equipped item's tooltip (the
applied enchant's green line, wherever it renders, incl. an engineering scope's ranged-
hit), so the current-gear totals reflect them without any applied-enchant-id map (which no
data source ships). Hovering a paperdoll slot uses the worn item link (the same one the
character sheet uses), so its applied enchant shows in the tooltip too.
Modules\Loadout.luastores enchant assignments per loadout (copied by Save As, dropped by Reset) and layers them instatsOf;Data\Enchants.lua(ns.Enchants) is the catalog adapter + parser. ProfessionDB is an optional dependency — absent, planned enchants simply aren't offered and worn enchants still scan. - Tooltip-authoritative equip effects. A few item "Equip:" values render differently from the offline DB's stored number (classic mp5 rounds the DB value down — e.g. Scythe of the Unseen Path shows 3 mana/5s where the DB has 2); the item's live tooltip now overrides the DB for those, so the summary matches the game.
- Only shows what the character can use. One
EP stat weights are HawsJon / Pawn / Vger (CC BY-NC-ND), credited in-app per the weights' licence.
This mod has no additional files

