Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ files["DragonLoot/"] = {

read_globals = {
-- WoW API - General
"UnitName", "UnitClass", "IsInInstance",
"UnitName", "UnitClass", "IsInInstance", "GetInstanceInfo",
"GetCursorPosition", "GetItemInfoInstant", "GetItemQualityColor",
"C_Item", "C_Container", "C_AddOns", "IsAddOnLoaded", "LoadAddOn",
"CreateColor", "PlaySoundFile",
Expand All @@ -58,6 +58,11 @@ files["DragonLoot/"] = {
"IsModifiedClick", "GameTooltip_ShowCompareItem",
"GetCVarBool",

-- WoW API - UIDropDownMenu (legacy)
"UIDropDownMenu_Initialize", "UIDropDownMenu_CreateInfo",
"UIDropDownMenu_AddButton", "UIDropDownMenu_SetWidth",
"UIDropDownMenu_SetText",

-- WoW API - Loot
"GetNumLootItems", "GetLootSlotInfo", "GetLootSlotLink", "GetLootSlotType",
"LootSlot", "CloseLoot", "IsFishingLoot", "C_Loot",
Expand All @@ -72,6 +77,9 @@ files["DragonLoot/"] = {
-- WoW API - Loot History
"C_LootHistory",

-- WoW API - Encounter Journal
"EJ_GetEncounterInfo",

-- WoW Frames - Loot
"LootFrame",
"GroupLootFrame1", "GroupLootFrame2", "GroupLootFrame3", "GroupLootFrame4",
Expand Down Expand Up @@ -116,6 +124,7 @@ files["DragonLoot/Locales/*.lua"] = {
files["spec/"] = {
globals = {
"UISpecialFrames",
"C_LootHistory",
},
}

Expand Down
54 changes: 30 additions & 24 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ The repository is structured as a multi-addon project separating core logic, con

- **`DragonLoot/`** (Core Addon)
- `Core/`: Core bootstrap (`Init.lua`), addon lifecycle (`Lifecycle.lua`), AceDB database configurations, slash commands, and the minimap icon.
- `Display/`: Custom loot frames (`LootFrame.lua`), roll frames (`RollFrame.lua`), history window (`HistoryFrame.lua`), and associated UI/layout animations.
- `Listeners/`: Event listeners handling version-specific API differences (e.g., `LootListener_Retail.lua` vs. `LootListener_Classic.lua`). Uses packager directives (`#@retail@` / `#@non-retail@`) to load correct listeners.
- `Display/`: Custom loot frames (`LootFrame.lua`), roll frames (`RollFrame.lua`), history window (`HistoryFrame.lua`) with encounter/search filtering, and associated UI/layout animations.
- `Listeners/`: Event listeners handling version-specific API differences (e.g., `LootListener_Retail.lua` vs. `LootListener_Classic.lua`, `EncounterListener_Classic.lua`). Uses packager directives (`#@retail@` / `#@non-retail@`) to load correct listeners.
- `Locales/`: Localized strings for translation support.
- `Libs/`: Embedded external libraries (Ace3, LibSharedMedia-3.0, LibAnimate, etc.).
- **`DragonLoot_Options/`** (Load-on-Demand Configuration)
- A separate companion addon loaded on-demand when the user opens the options interface.
- Contains individual tabs for configuring appearance, animations, roll frame, and history settings, and embeds the custom `DragonWidgets` library.
- Contains individual tabs for configuring appearance, animations, roll frame, and history settings including the filter bar toggle, and embeds the custom `DragonWidgets` library.
- **`spec/`** (Testing Suite)
- Contains the busted unit test suite (`Config_spec.lua`, `Lifecycle_spec.lua`, `MasterLoot_spec.lua`) and a comprehensive WoW API mock harness (`wow_mock.lua`).
- Contains 71 busted tests, including `HistoryFilter_spec.lua` and `EncounterListener_Classic_spec.lua`, and a comprehensive WoW API mock harness (`wow_mock.lua`).

## Config Schema Reference

Current profile schema version: 5.

### Appearance (`db.profile.appearance`)

| Key | Type | Default |
Expand Down Expand Up @@ -66,29 +68,33 @@ The repository is structured as a multi-addon project separating core logic, con

### History (`db.profile.history`)

| Key | Type | Default |
| ---------------- | ------- | ------- |
| enabled | boolean | true |
| maxEntries | number | 50 |
| autoShow | boolean | false |
| lock | boolean | false |
| trackDirectLoot | boolean | true |
| minQuality | number | 2 |
| rowHeightPadding | number | 6 |
| Key | Type | Default |
| ------------------ | ---------- | ------- |
| enabled | boolean | true |
| maxEntries | number | 100 |
| autoShow | boolean | false |
| lock | boolean | false |
| trackDirectLoot | boolean | true |
| minQuality | number | 2 |
| rowHeightPadding | number | 6 |
| filter.encounterID | number/nil | nil |
| filter.search | string | "" |
| filter.barVisible | boolean | true |

## Version-Specific API Differences

| Aspect | Retail | Classic (TBC/MoP) |
| --------------------------- | ----------------------------- | ----------------------- |
| GetLootSlotInfo returns | 10 | 6 |
| GetLootRollItemInfo returns | 13 (incl canTransmog) | 12 |
| C_LootHistory | Encounter-based | Roll-item indexed |
| CANCEL_ALL_LOOT_ROLLS | Yes | No |
| LOOT_READY event | Yes (fires after LOOT_OPENED) | No |
| C_Loot.GetLootRollDuration | Yes | No |
| Loot listener | LootListener_Retail | LootListener_Classic |
| Roll listener | RollListener_Retail | RollListener_Classic |
| History listener | HistoryListener_Retail | HistoryListener_Classic |
| Aspect | Retail | Classic (TBC/MoP) |
| --------------------------- | ----------------------------- | ------------------------------------------- |
| GetLootSlotInfo returns | 10 | 6 |
| GetLootRollItemInfo returns | 13 (incl canTransmog) | 12 |
| C_LootHistory | Encounter-based | Roll-item indexed |
| CANCEL_ALL_LOOT_ROLLS | Yes | No |
| LOOT_READY event | Yes (fires after LOOT_OPENED) | No |
| C_Loot.GetLootRollDuration | Yes | No |
| Loot listener | LootListener_Retail | LootListener_Classic |
| Roll listener | RollListener_Retail | RollListener_Classic |
| Encounter listener | N/A | EncounterListener_Classic (`#@non-retail@`) |
| History listener | HistoryListener_Retail | HistoryListener_Classic |

## DragonToast Integration

Expand Down
29 changes: 20 additions & 9 deletions DragonLoot/Core/Config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ local defaults = {
contentPadding = 6,
rowHeightPadding = 6,
showRollDetails = true,
-- filter.encounterID is intentionally absent from this literal (nil in a table
-- constructor is a no-op). The field is part of the documented shape and gets
-- populated at runtime when the user selects an encounter in the history UI.
filter = {
-- encounterID = nil,
search = "",
barVisible = true,
},
},

appearance = {
Expand Down Expand Up @@ -140,7 +148,7 @@ local defaults = {
-- Profile Migration
-------------------------------------------------------------------------------

local CURRENT_SCHEMA = 4
local CURRENT_SCHEMA = 5

local function DeepCopyValue(value)
if type(value) ~= "table" then
Expand Down Expand Up @@ -184,18 +192,15 @@ local function FillMissingDefaults(profile)
-- Validate existing values: reset if type doesn't match or is invalid
elseif type(currentValue) ~= type(defaultValue) then
profile[section][key] = DeepCopyValue(defaultValue)
-- Handle nested tables (like color values {r,g,b})
-- Handle nested tables (like color values {r,g,b} or history.filter):
-- merge missing/wrong-type keys from defaults without discarding valid
-- existing scalars or extra user fields (e.g. filter.encounterID).
elseif type(defaultValue) == "table" then
local isValid = true
for k, v in pairs(defaultValue) do
if type(currentValue[k]) ~= type(v) then
isValid = false
break
if currentValue[k] == nil or type(currentValue[k]) ~= type(v) then
currentValue[k] = DeepCopyValue(v)
end
end
if not isValid then
profile[section][key] = DeepCopyValue(defaultValue)
end
end
end
end
Expand Down Expand Up @@ -246,6 +251,12 @@ local function MigrateProfile(db)
-- handling when InitializeDB passes the updated defaults table to AceDB:New. The schema
-- bump is recorded by the unconditional assignment to profile.schemaVersion below.

-- v4 -> v5: introduce db.profile.history.filter for the loot history encounter/search
-- filter UI (issue #89). No transformation of existing data is required - FillMissingDefaults
-- (run above when version < CURRENT_SCHEMA) seeds the new filter sub-table from defaults.
-- Existing db.char.history.entries are deliberately left untouched; pre-feature entries
-- without encounterID surface in the "Unknown encounter" bucket at filter time.

profile.schemaVersion = CURRENT_SCHEMA
end

Expand Down
1 change: 1 addition & 0 deletions DragonLoot/Core/Init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ local MODULES = {
{ name = "LootFrame" },
{ name = "RollManager" },
{ name = "HistoryFrame" },
{ name = "EncounterListener_Classic", passAddon = true },
{ name = "HistoryListener", passAddon = true },
{ name = "LootHistoryChat", passAddon = true },
{ name = "Listeners", passAddon = true },
Expand Down
Loading
Loading