Skip to content

v8.4.0 — themes grid + Carbon, DLL capability tooling, cleanup - #1

Open
ShikawaLePaladin wants to merge 24 commits into
masterfrom
feature/themes-and-dll-enhancements
Open

v8.4.0 — themes grid + Carbon, DLL capability tooling, cleanup#1
ShikawaLePaladin wants to merge 24 commits into
masterfrom
feature/themes-and-dll-enhancements

Conversation

@ShikawaLePaladin

Copy link
Copy Markdown
Owner

First release of the ShikawaLePaladin continuation of the fork. Four workstreams,
each committed separately.

🎨 Themes

  • Firstrun "choose profile" step is now a data-driven grid (was a hardcoded 4). It
    surfaces every built-in profile and auto-sizes the window. Adding a theme = 1 list
    entry + 1 profile table.
  • Expose the previously-hidden Adapta and Light profiles in the wizard.
  • New dark high-contrast Carbon theme (derived from Slim), registered in the
    VARIABLES_LOADED loader (required — pfUI_profiles is a SavedVariable) with its own
    new_module_positions.

🔌 DLL capability tooling

  • /pfdll now probes and reports the individual API surfaces each mod exposes
    (SuperWoW 2.x / Nampower / UnitXP_SP3). Quick way to see what a private server permits.
  • New /pfnpspread cycles SuperWoW 2.0's NameplateMotion CVar (overlap / default /
    smart / compact). Gated behind UnitNameplate; inert on older/absent SuperWoW.

🧹 Fixes

  • README Requirements corrected (Nampower = only hard dep; SuperWoW/UnitXP optional).
  • In-game clickable links repointed from the deleted me0wg4ming repo to this fork.
  • Firstrun profile hint points to the real menu path.

⚠️ Needs in-game validation

No Lua runtime available offline — changes were structurally validated (bracket balance,
Lua 5.0 idioms, closure-in-loop) but the Carbon look and the 7-button wizard grid
layout
should be eyeballed in-game. Run /pfdll to confirm which DLLs OctoWoW allows.

🤖 Generated with Claude Code

ShikawaLePaladin and others added 3 commits July 17, 2026 20:04
… fix dead links

Themes:
- Rework the firstrun "choose profile" step into a data-driven button grid.
  It now surfaces all built-in profiles instead of a hardcoded 4. Adding a new
  theme is one list entry + one profile table; the grid auto-sizes the window.
- Expose the previously-hidden Adapta and Light profiles in the wizard.
- Add a new dark high-contrast "Carbon" theme (derived from Slim's layout),
  registered in both the initial assignment and the VARIABLES_LOADED loader
  (required, since pfUI_profiles is a SavedVariable) with new_module_positions.

Cleanup / fixes:
- README: correct the Requirements section — Nampower is the only hard
  dependency; SuperWoW and UnitXP_SP3 are optional/feature-detected. Add an
  OctoWoW note and mention /pfdll.
- Repoint in-game clickable URLs (config website buttons, libdebuff nampower
  install links) from the deleted me0wg4ming repo to ShikawaLePaladin/pfUI.
- Fix firstrun profile hint to the real menu path (Settings > General > Profile).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d control

- /pfdll now probes and reports the specific API surfaces each DLL exposes
  (SuperWoW 2.x: UnitNameplate/CursorPosition/GetSpeed/CanLootUnit/..., Nampower:
  GetSpellRec/GetUnitField/GetSpellIdCooldown/GetSpellModifiers/..., plus UnitXP_SP3
  presence). This turns "is SuperWoW/UnitXP allowed on this server?" into a one
  command in-game answer - useful on private servers like OctoWoW.
- Add /pfnpspread (alias /pfnameplatespread) to cycle SuperWoW 2.0's NameplateMotion
  CVar (overlap / default / smart / compact spread). Gated behind UnitNameplate as a
  SuperWoW-2.0 proxy; SetCVar persists across sessions. Fully absent otherwise.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Bump pfUI.toc / pfUI-tbc.toc to 8.4.0 and version badge to the fork.
- Add 8.4.0 changelog entry (themes grid + Carbon, /pfdll probing, /pfnpspread,
  requirements/link fixes) in the existing README style.
- Update Author line to credit the ShikawaLePaladin continuation while keeping
  Shagu (original) and me0wg4ming (fork) attribution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: decd07718c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread modules/superwow.lua
Comment on lines +295 to +296
SLASH_PFNAMEPLATESPREAD1 = "/pfnpspread"
SLASH_PFNAMEPLATESPREAD2 = "/pfnameplatespread"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Register the nameplate spread slash aliases globally

When SuperWoW 2.0 is present, this module body runs under pfUI:GetEnvironment() via pfUI:LoadModule, so bare SLASH_* assignments are stored on the pfUI environment table rather than _G. WoW's slash command discovery reads the global SLASH_PFNAMEPLATESPREAD* names, so /pfnpspread and /pfnameplatespread will not be recognized even though SlashCmdList gets a handler; assign these through _G or use the existing RegisterSlashCommand helper.

Useful? React with 👍 / 👎.

ShikawaLePaladin and others added 21 commits July 17, 2026 20:25
Adds a self-contained Trinket Bar module showing the two equipped trinkets with a
live cooldown swipe, click-to-use, and hover tooltip. Off by default; toggled via
Unit Frames > General > Trinket Bar Settings. Movable through the standard pfUI
unlock system.

Follows the totems.lua conventions (COOLDOWN_FRAME_TYPE + CooldownFrame_SetTimer,
so pfUI's cooldown text/styling applies automatically; PLAYER_LOGOUT shutdown to
avoid crash 132). Uses only stock 1.12 inventory API, so it works with or without
DLLs; cooldown stays ms-accurate through Nampower when present.

- new module: modules/trinketbar.lua (+ init/modules.xml include)
- config defaults: trinketbar="0", trinketbar_size="32" (api/config.lua)
- GUI options under the DLL/Nampower settings block (modules/gui.lua)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a small coin icon on the nameplate of lootable corpses. Off by default,
toggled under Nameplates. The check runs in the existing central OnUpdate but is
throttled to ~0.4s per plate (loot state only changes on death) and wrapped in
pcall so an unexpected CanLootUnit signature can never break the shared nameplate
loop. cfg.lootable is force-disabled when CanLootUnit is absent, so this is fully
inert without SuperWoW 2.0.

Investigation note: the planned "refactor nameplate discovery to UnitNameplate()"
was dropped as unnecessary — plate->unit association already uses SuperWoW's
frame:GetName(1) throughout, so a risky rewrite of the WorldFrame scan would add
risk for no real gain. Added a genuinely-new feature instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Root cause: the registered events (UNIT_INVENTORY_CHANGED, BAG_UPDATE_COOLDOWN,
ACTIONBAR_UPDATE_COOLDOWN) don't fire when a trinket's on-use cooldown starts from
being clicked directly on this custom bar - none of them cover "equipped item used
outside a bag/action button". Confirmed in-game: cooldown swipe never appeared
after using a trinket.

Fix: poll GetInventoryItemCooldown on a throttled (0.2s) OnUpdate, same approach
the default Blizzard character pane trinket slots use.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…not a GUID

Confirmed in-game: CanLootUnit(rawGuid) silently returned false, while
CanLootUnit("target") returned 1 (truthy) on an actually-lootable corpse.
CanLootUnit(), called with no argument, errors ("Usage: CanlootUnit(\"unit\")"),
confirming it strictly requires a bound unit token.

Fix: track mouseoverGuid alongside the existing targetGuid in frameState, and
only query CanLootUnit with "target"/"mouseover" when the plate's cached GUID
matches one of those - never with the raw GUID. This limits the indicator to
plates that are currently targeted or moused-over (SuperWoW 2.0 doesn't seem to
expose a way to query loot state for arbitrary units), but it now actually works
instead of being silently dead code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Compared against every other module that creates a Cooldown frame (bags.lua,
totems.lua, actionbar.lua) - all of them set pfCooldownType and
pfCooldownStyleAnimation. Without those, pfUI's central cooldown.lua hook treats
the frame as "foreign" and (by default settings) does nothing to it, so neither
the forced swipe nor pfUI's styled countdown text ever apply - matches the user's
report of no visible timer on the icon (only the plain tooltip cooldown text).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t it)

Confirmed in-game: even limited to the targeted/moused-over plate (the only case
the fixed unit-token version could support), the indicator still never showed.
SuperWoW 2.0's CanLootUnit doesn't provide what this feature needs reliably on
this client. Rather than ship a checkbox that silently does nothing, pulling it
entirely - clean removal, no dead config/GUI/texture left behind.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds manual /roll-based SR/MS/OS/Transmog loot distribution as used by guilds
running loot council instead of Blizzard's native Need/Greed/Pass. This is a
distinct system from the native group-loot popup already handled above in this
file - not a duplicate, just grouped in the same module.

Ported into pfUI conventions rather than copied as-is: CreateBackdrop/SkinButton
styling instead of raw backdrop code, UpdateMovable instead of a hand-rolled drag
script, config-driven duration/autoclose (C.loot.council.*) instead of hardcoded
values, and PLAYER_LOGOUT event cleanup to avoid crash 132.

Fixed a real bug from the original addon while porting: it used its own
English-only class-name-keyed color table (broke on non-English clients since
GetRaidRosterInfo's class name is localized). Now uses the real fileName-keyed
RAID_CLASS_COLORS via GetRaidRosterInfo's 6th return value.

Off by default - opt in under Loot > Loot Council Settings. New /pflootcouncil
slash command toggles the window.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes "attempt to call method 'GetHeight' (a nil value)" at addonbuttons.lua:149.
The scanner only checked that _G[button_name] was non-nil, not that it was still
a valid frame object - a global can exist under that name without exposing
frame methods (e.g. another addon reused the name, or the owning addon's frame
got torn down/replaced). Pre-existing bug, unrelated to this session's other
changes; surfaced by the user's specific addon mix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Investigated docking it like DPSMate (pfUI.thirdparty.meters system) but
OctoMeter has a fundamentally different architecture: multiple simultaneous
windows with magnet-snapping and its own flat-texture theme system, vs
DPSMate's single fixed-name scroll list. Reparenting/SetAllPoints into
pfUI.chat.right would fight OctoMeter's own window management.

Instead: push pfUI's current border/background colors into OctoMeter's own
Database settings (borderColor/bgColor) and call Window:ApplyThemeToAll(), so
it visually blends with the active pfUI theme while staying fully independent
(movable, resizable, multi-window, snapping all still OctoMeter's own).
OctoMeter already ships its own minimap button, picked up automatically by
pfUI's existing addon-button organizer, so no extra toggle button was added.

On by default (matches other skin-only thirdparty integrations), toggle under
Thirdparty > Integrations > "OctoMeter (Skin)".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…p nil-guard

addonbuttons.lua: the existing GetHeight guard (previous commit) only covered
one call site. Same class of bug hit two more in the wild (confirmed via user's
in-game errors): ProcessButtons' IsVisible() call and RestoreButton's SetParent
call on a stale top-frame name. Added a shared IsValidGlobalFrame() helper
(checks GetObjectType, not just non-nil) and applied it at every _G[button_name]
site, including UpdatePanel's cleanup pass so stale entries get pruned instead
of silently re-erroring every update.

roll.lua (loot council):
- Fixed "attempt to concatenate a nil value" on the SR/MS/OS/TM button tooltip
  by nil-guarding both operands.
- Restored the item-icon retry logic dropped during the LootBlare port: a
  freshly-seen item isn't always cached client-side yet, so GetItemInfo can
  return nil name/icon on the first call. Now retries every ~0.5s (up to ~10s)
  until it resolves, same reason the original addon had its own CheckItem
  polling loop that I'd simplified away.

Not pushed - holding per instruction until told to push.
…lookup

Root cause of "attempt to index field '?'" on click: the button OnClick/OnEnter
closures captured the loop variable `cap` directly instead of storing it on the
button frame - this codebase's own established pattern (see totems.lua's
this.id) avoids exactly that, for good reason: it broke in practice here,
confirmed by the user's repeated in-game errors. Fixed by storing b.cap and
reading this.cap inside the handlers instead of the captured loop variable.

Also simplified the item-icon lookup: use ExtractItemLink's already-clean
"item:id:..." string directly instead of re-extracting a fixed number of
':'-separated fields (fragile on item links with a different field count -
enchants/gems/unique IDs/extra server fields). Removed the arbitrary 20-retry
give-up cap on the icon-resolution poll; it's already naturally bounded by
council.isRolling (the roll duration timer).

Not pushed - holding per instruction.
…ItemInfo

In-game evidence: GameTooltip:SetHyperlink() rendered the full item tooltip
(stats, quality, etc.) proving the item was already client-cached, yet
GetItemInfo() on the exact same link string kept returning nil across many
retries. GetHyperlink/SetHyperlink is far more tolerant of link format than
GetItemInfo - if this server's item links carry extra fields beyond stock
vanilla's, GetItemInfo may choke on them.

Now extracts just the bare numeric item ID via "item:(%d+)" and passes that
number to GetItemInfo instead of the full link string - the simplest form it
accepts, nothing extra left to trip over. council.itemLink (the full link,
used for the icon's tooltip/dressup/chat-insert) is untouched.

Not pushed - holding per instruction.
Two attempted fixes (full link, then bare item ID) haven't resolved the icon
issue, and I can't reproduce this OctoWoW-specific behavior locally. Rather
than guess a third time, print exactly what GetItemInfo receives and returns
so the next test gives real data. To remove once understood.

Not pushed - holding per instruction.
… position

In-game debug data confirmed the real bug: GetItemInfo's name (1st return)
resolves correctly, but the icon consistently came back nil at the position
stock vanilla's documented signature would put it (9th/10th) - even though the
item was fully client-cached (its tooltip rendered completely via
SetHyperlink). This server's GetItemInfo return layout doesn't match what I
assumed, and the original LootBlare addon I ported from had the exact same
fixed-position assumption (also likely wrong/untested for icons).

New ResolveItemIcon(itemId) helper: try the dedicated GetItemIcon() API first
(feature-detected), then fall back to scanning ALL of GetItemInfo's return
values for whatever actually looks like a texture path (a string starting with
"Interface\") instead of trusting one fixed index. Works regardless of which
position this server's GetItemInfo puts the icon at. Removed the temporary
debug prints now that the root cause is understood.

Not pushed - holding per instruction.
Previous fix (GetItemIcon + string-path scan) still didn't resolve the icon.
Rather than guess a 4th time, dump every return value with its type/index -
possible the icon comes back as a numeric fileID rather than a string path,
which the current scan would silently skip.

Not pushed - holding per instruction.
Confirmed via debug: this server's GetItemInfo only returns 3 values (name,
link, quality) - no icon at all, unlike stock vanilla's 11. Nampower exposes
richer item data via GetItemStats(id, true) (already used elsewhere in this
file for itemLevel) - dump its full field set to check for an icon-shaped key
before giving up on a GetItemInfo-based approach entirely.

Not pushed - holding per instruction.
…otBlare step)

Root cause finally identified: on this server, GetItemInfo() only returns full
item data (icon included) once the client has already fully resolved that item
via a tooltip query - called cold, it returns just a lightweight 3-field result
(name/link/quality), which is exactly what debug logging showed every time.

The original LootBlare addon (which the user confirmed works correctly for
icons) primes this: it calls SetHyperlink() on a hidden tooltip and polls until
the tooltip text resolves, before ever calling GetItemInfo. I'd dropped that
step while porting - my code called GetItemInfo directly on a cold item.

Restored via pfUI's own libtipscan scanner (SetHyperlink on
libtipscan:GetScanner("lootcouncil")) right when a roll starts, before the
first GetItemInfo attempt. Cleaned up the now-answered GetItemStats field-dump
debug spam; left one compact confirmation print for this next test.

Not pushed - holding per instruction.
…setup

Side-by-side in-game test was conclusive: the original LootBlare addon
resolved the icon correctly on the exact same item, at the exact same moment,
while my libtipscan-based priming still failed. The one concrete difference:
LootBlare's discover tooltip uses SetOwner(UIParent, "ANCHOR_PRESERVE"), while
libtipscan's shared scanner uses SetOwner(WorldFrame, "ANCHOR_NONE").

Replaced the libtipscan-based priming with a dedicated hidden GameTooltip
(pfLootCouncilItemProbe) using the exact same owner/anchor LootBlare uses.
Also re-prime on every retry tick (not just once at roll start), matching
LootBlare's ShowFrame loop which re-touches the tooltip continuously rather
than a single one-shot call.

Not pushed - holding per instruction.
…bare ID

Investigated AtlasLoot per suggestion: it doesn't dynamically resolve icons at
all (own bundled static database of classic loot icons, not usable here), and
it only hooks the real GameTooltip/ItemRefTooltip/TmogTooltip - not any
custom-created tooltip, so it isn't quietly assisting either LootBlare's or
this addon's own probe tooltip. Not the explanation, but re-reading LootBlare's
code against my own more carefully surfaced a real untested gap: LootBlare's
SetItemInfo calls GetItemInfo(itemLinkArg) with the FULL link string, while my
code had switched to a bare numeric ID early on (before the priming fix
existed) and never tried full-link + priming together.

ResolveItemIcon now takes itemLinkOrId generically (GetItemIcon/GetItemInfo get
whatever was passed; GetItemStats specifically extracts a numeric ID from it,
since Nampower's API wants a plain ID there).

Not pushed - holding per instruction.
unitframes.lua already reads and acts on C.unitframes[unit].selfdebuff at
several points (lines ~207, 2182, 2236, 2256, 2495) - filtering the debuff
icons shown on a unit frame down to only the player's own casts (exactly what
a Warlock wants for tracking their own DoTs on target without noise from other
casters). The logic was fully working but had no GUI checkbox - only the
separate buffbar.tdebuff module's own copy of this feature was exposed
(Unit Frames > General > "Show Only Own Debuffs").

Added the checkbox to the per-unit Debuffs section (inside the
unitframeSettings loop), so it now applies to target/focus/party/raid/etc.
Config default ("0") was already set for every relevant unit via the existing
ufs loop in api/config.lua - no default changes needed.

Not pushed - holding per instruction.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant