The RegisterSlashCommand helper in api/api.lua was effectively unused
(only macrotweak called it); every other command hand-rolled the
SLASH_*/SlashCmdList pair. Convert the existing manual registrations to
the helper with force=true, preserving the current always-bind behavior
while centralizing the pattern behind one code path (and its _G. and
conflict-check handling).
Left as-is: pfUI.lua's /rl, /pfui, /gm (registered before api.lua
defines the helper) and the vendored libs' debug commands.
Buff and debuff slots only called CooldownFrame_SetTimer on the
`expirationTime > 0` (or `duration > 0` for buffs) paths. When the new
target's aura at the same slot index had neither — permanent / passive
auras like Retribution Aura — neither branch fired and the slot kept
displaying the previous target's swirl/timer.
Add an explicit 0/0/0 clear on every path that doesn't set a real
timer, so the button always starts from a known state.
Fixes#13.
`GetPlayerBuff(PLAYER_BUFF_START_ID + this.id, filter)` assumes the
visual index pfUI shows matches the engine's slot order. When that
mismapping happens — most easily reproduced by stacking buffs that
share a slot family — right-clicking one buff cancels another.
`C_Spell.CancelSpellByID(spellID)` ships CMSG_CANCEL_AURA keyed to the
spell, not a slot, so it's immune to whatever order the slot table is
in. Cache `spellId` on the button at refresh time in buff.lua; in the
unitframes/buffwatch handlers fetch the aura fresh via
`C_UnitAuras.GetAuraDataByIndex` at click time.
Fixes#10.
ClassicAPI ships modern IsInGroup() / IsInRaid() backports — drop the
GetNumPartyMembers() > 0 and GetNumRaidMembers() > 0 idioms (and the
GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0 conflation) for the
named-intent variants. UnitInRaid("player") → IsInRaid() at the same
sites.
libhealth ships with pfUI and Nampower's GetUnitField (hard-dep) covers
the real-HP read; the MobHealth integration was a chained last-resort
fallback that could never actually win, and on the nameplate path it
also mixed percentage and real-value scales into the bar's SetMinMaxValues
since it overwrote hp/hpmax without hpmin.
ClassicAPI's recent C_UnitAuras additions (sourceUnit / sourceGUID /
non-player expirationTime / the PLAYER filter token) finally cover
everything libdebuff:UnitDebuff and :UnitOwnDebuff were doing — caster
attribution, accurate timing for non-player units, and the own-debuffs
filter. Migrating the remaining callers off the libdebuff readers.
- api/unitframes.lua: collapses the debuff render path's three-branch
if/else into a single C_UnitAuras.GetAuraDataByIndex with a HARMFUL
or HARMFUL|PLAYER filter selected by the selfdebuff config; tooltip
slot-finders match by sourceGUID instead of libdebuff's caster flag;
custom-debuff indicator scan unifies the same way.
- modules/buffwatch.lua: GetBuffData drops the libdebuff fallback;
tooltip slot-finder mirrors the unitframes pattern.
- libs/libpredict.lua: drops the orphaned UnitHasBuff slot-loop (no
callers left).
- api/api.lua: pfUI.api.UnitHasBuff tightens from a HELPFUL iteration
to a single GetAuraDataBySpellName lookup.
Each site that builds a cooldown ring from expirationTime carries the
talent-extension guard — when expirationTime exceeds the dbc base
duration (e.g. Shadow Affinity → SW:P), clamp start to now and use the
remaining time as the effective duration so CooldownFrame_SetTimer
doesn't get a future start it treats as "not yet begun".
f.power.bar inherits f.power's frame level at creation. Bumping
f.power's level later doesn't propagate to existing children, so
CreateBackdrop's parent.fl - 1 backdrop ends up rendering above
the bar — a black bar appears where the power fill should be.
Set the bar's frame level explicitly to parent.fl + 1 after
CreateBackdrop to restore the bar-over-backdrop order.
* focus: migrate to FocusUnit / "focus" token / PLAYER_FOCUS_CHANGED
ClassicAPI now polyfills modern WoW's focus system: FocusUnit / ClearFocus
+ "focus" / "focustarget" unit tokens accepted by every UnitX function +
PLAYER_FOCUS_CHANGED event. Drop pfUI's GUID-juggling pseudo-frame.
- env/tables.lua: add "focus" and "focustarget" to pfValidUnits — the
focus frames now follow the standard event-driven CreateUnitFrame path
with f.label = "focus"
- modules/focus.lua: rewrite. Slash commands use FocusUnit / ClearFocus
directly; no more manual frame.label/unitname/id manipulation. /focus
<name> still does a target-swap to resolve names → units, then
FocusUnit("target") captures the GUID before the target is restored.
PLAYER_FOCUS_CHANGED triggers immediate frame refresh on assign/clear.
- api/unitframes.lua: delete the pseudo-focus block (per-tick "scan all
units for matching name" loop) and the "focus"/"focustarget" special-
case in the visibility branch — "focus" is now a real token.
- modules/castbar.lua: bind the focus castbar to unitstr = "focus" once;
drop the OnUpdate that synced pfUI.castbar.focus from
pfUI.uf.focus.label/unitname. UnitGUID("focus") resolves at read time.
- Drop C_Minimap.SetFocusByGUID / SetFocusByName / ClearFocus calls —
C_Minimap subscribes to PLAYER_FOCUS_CHANGED on its own.
Net -183 lines. Focus stops being a pfUI-special pseudo-frame and
becomes "just another unit token" — same treatment as target/player.
* add nameplate to valid units
---------
Co-authored-by: Brues <5278969+brues-code@users.noreply.github.com>
Both indicator scan loops (preset HoT indicators + custom name-based
indicators) now iterate the populated aura array from
C_UnitAuras.GetUnitAuras instead of brute-forcing UnitBuff(1..32). The
Rejuvenation/Renew/Regrowth disambiguation that previously required
scanner:SetUnitBuff + Line(1) tooltip scans now reads aura.name natively.
HoT-icon → name+predict mappings lifted into a HOT_INDICATORS table at
file scope so future additions are one-line edits.
The custom-debuff loop still defers to libdebuff for caster correlation
when available; C_UnitAuras provides the texture/name backstop. Also
unifies the non-selfdebuff debuff display branches through one
GetDebuffDataByIndex call.
Local `scanner` declaration removed (no remaining tooltip-scan uses in
this file).
BuffOnClick/DebuffOnClick switch to lazy bid lookup before CancelPlayerBuff
(matching the pattern in buff.lua/buffwatch.lua). DebuffOnEnter unifies its
player and non-player branches through GameTooltip:SetUnitAura — the only
divergent path is the selfdebuff caster-correlation lookup that still
needs libdebuff.
Mirror the buff-side cleanup: drop the legacy DebuffOnUpdate poller from
player debuff frames, swap the player branch to GetDebuffDataByIndex with
the same future-start cap, and switch the dispel-indicator scan to
AuraData. libdebuff still owns non-player timers. Deletes the now-orphaned
BuffOnUpdate/DebuffOnUpdate/maxdurations.
* fixed offhand timer incorrectly showing for 2H weapon users
* fixed sw_texture resolving pfUI.media key correctly instead of passing raw file path
* added proper offhand weapon detection via GetEquippedItem + GetItemStatsField (Nampower), with vanilla API fallback
* added UNIT_DIED event to reset timer when target dies
* added ACTIONBAR_SLOT_CHANGED event to keep HS/Cleave slot cache up to date
* added immediate offhand bar hide when OH weapon is unequipped mid-combat
* added player GUID caching for UNIT_DIED comparison
* added GUI options: texture, font size, show/hide timer text, MH/OH labels, offhand bar, HS/Cleave queue color
* added HS/Cleave queue color coding for Warriors (green = Cleave, yellow = Heroic Strike)
* added unit frame text options: attack speed, min/max damage, unit string, HP/mana display variants, pet name
* removed unreliable dual-wield heuristic guard (mhAge < 0.1)
Co-authored-by: Zedris