Commit Graph

3856 Commits

Author SHA1 Message Date
Brues 439d5a397a eqcompare: numeric InventoryType lookup, drop bagtypes/itemtypes locales
Both sub-tables carried per-locale strings only so pfUI's own code could
match against localized text. ClassicAPI's numeric item APIs replace
both:

- GetBagFamily now reads classID/subClassID from C_Item.GetItemInfoInstant
  and switches on the numbers (class 1 = Container, class 11 = Quiver).
- eqcompare pulls the itemID from GameTooltip:GetItem(), fetches the
  numeric invType via C_Item.GetItemInventoryTypeByID, and looks up the
  destination slot(s) in a numeric slotTable keyed by Enum.InventoryType.
  Pair-slot invtypes (finger / trinket / one-hand weapon) list both
  destinations directly, so the "_other" string-concat hack is gone.

Removes the setglobal INVTYPE_* injection, the tooltip text scan, and
the itemtypes + bagtypes locale sub-tables across all 7 files.
2026-07-01 15:43:03 -05:00
Brues 5524ad3b91 locales: strip 4 dead sub-tables (hunterpaging, interrupts, spells, icons)
Audited every consumer of pfUI_locale[*][key] across the codebase. Four
sub-tables have no non-locale-file readers left:

  - hunterpaging  — old auto-page trigger removed
  - interrupts    — replaced by Nampower SPELL_INTERRUPTED events
  - spells        — replaced by ClassicAPI Spell.dbc lookups
  - icons         — replaced by ClassicAPI C_Spell.GetSpellName / icon path

Removed the entries from all 7 locale files. ~18k dead lines gone,
~70% shrink per file.
2026-07-01 12:13:25 -05:00
Brues 0f59a3a9b5 replace poll-until-cancel OnUpdate frames with C_Timer / RunNextFrame
Seven ad-hoc OnUpdate handlers were only spinning long enough to reach
a known deadline or a next-frame defer, then unhooking themselves.
Convert them to their proper primitives:

- autovendor: 0.3s wait after junk sell → C_Timer.After(0.3, ...)
- innervatecall: cooldown-expiry ready ping → C_Timer.After(cd, ...)
- focus: re-arm UI_ERROR_MESSAGE next tick → RunNextFrame
- macrotweak: conflict scan after addons load → RunNextFrame
- ui-widgets (CreateQuestionDialog): font-measure resize → RunNextFrame
- libdebuff: post-PEW Nampower init → RunNextFrame
- bubbles: WorldFrame scan after chat event → RunNextFrame

Net -18 lines and no more throwaway frames sitting on the OnUpdate list.
2026-07-01 10:43:46 -05:00
Brues ffdf376ac4 add pfUI.events callback registry, replace addoncompat OnUpdate poll
Introduce a central pfUI.events registry (ClassicAPI's
CallbackRegistryMixin, undefined events allowed) initialized in pfUI.lua
before any module body runs, so publishers/subscribers don't depend on
module load order.

firstrun sets `pfUI.firstrun.completed` and fires `firstrun:complete` at
the point NextStep detects no pending steps. PLAYER_ENTERING_WORLD re-
enters this path on every zone, so the flag is a one-shot guard.

addoncompat drops its 0.1s OnUpdate poll and either RunQueues immediately
(returning user, all steps already done) or subscribes to the event.
2026-07-01 10:20:34 -05:00
Brues 9bdde06150 unitframes: clear stale aura swirl on target swap
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.
2026-06-28 12:41:31 -05:00
Brues 8bf6672114 buffs: cancel by spellID instead of GetPlayerBuff slot index
`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.
v9.0.5
2026-06-28 04:28:59 -05:00
Brues 29b948e6fa character cleanup 2026-06-28 00:14:40 -05:00
Brues 5f61f94a24 Texture ArenaFrame v9.0.4 2026-06-27 23:31:02 -05:00
Brues 65678da3d2 tooltip: optional movement-speed line via GetUnitSpeed
New tooltip.movespeed config knob (default off, checkbox in the GUI's
tooltip page). When on, the unit tooltip gains a "Speed: N%" line where
N is the unit's run speed normalized to vanilla's 7.0 yd/s base — 100
unmounted, 160 on a 60% mount, 200 on epic, less under snares.

Uses runSpeed (return 2 of GetUnitSpeed), not currentSpeed, so the
number reflects what the unit *would* be running at — visible even
while they're standing still. runSpeed is 0 for out-of-range units, so
the line is skipped in that case.
2026-06-27 19:28:40 -05:00
Brues 9b7aca8541 show CLASSIC_API_VERSION in /pfdll 2026-06-27 19:20:06 -05:00
Brues 60525eec3a Clean up throttle 2026-06-27 19:19:51 -05:00
Brues c3829c2bd2 player: drop talent-side modCastingTime fudge from haste display
The player frame's "Effective Haste" mode was hardcoded talent-position
scrapes: GetTalentInfo(1, 16) for the Mage "Accelerated Arcana"
(flat 5%) and GetTalentInfo(1, 14) for the Warlock "Rapid Deterioration"
(3% per rank), folded into the displayed haste % via
`(1 / (modCastSpeed * modCastingTime) - 1) * 100`.

That's two problems in one:
- Hardcoded talent indices and effect percentages — brittle to any
  Turtle tree reshuffle or retune.
- Conceptually muddled: it folds gear-haste and talent-cast-reduction
  into one number that's hard to read as anything specific. The actual
  effective cast time is already shown on the cast bar via
  C_Spell.UnitCastingInfo (engine helper accounts for SpellMod op 10).

Drop modCastingTime, the LEARNED_SPELL_IN_TAB watcher frame that
maintained it, the per-class talent scrape, and the hasteMode == "2"
display branch. Collapse the now-binary "display_haste" config from a
3-option dropdown to a checkbox. Users on legacy "2" will see the
checkbox unchecked once and can re-enable with a single click.
2026-06-27 19:13:49 -05:00
Brues 28de6fd835 finish UnitInRaid("player") → IsInRaid() sweep
Four more sites: GetUnbuffedRoster + SendChatMessageWide in api.lua,
the loot menu's inRaid local, and the raid module's early-return
guard. Same intent, named helper.
2026-06-27 18:57:21 -05:00
Brues fc75e091a4 finish IsInRaid sweep across remaining "raid count > 0" sites
Three more `if GetNumRaidMembers() > 0 then` raid-vs-party branches
switched to `if IsInRaid()`. Same intent, named helper. Repo is now
clean of the legacy idiom (verified with a final grep).

Loops that actually need the count (`for i = 1, GetNumRaidMembers() do
GetRaidRosterInfo(i)`) keep the call — only the boolean form changes.
2026-06-27 18:56:50 -05:00
Brues ef478b0552 thirdparty-vanilla: collapse solo check to not IsInGroup()
The HealComm self-message guard was `not UnitInRaid("player") and
GetNumPartyMembers() < 1` — the long form of "in no group at all."
2026-06-27 18:55:49 -05:00
Brues 760d8992b6 switch group-membership checks to IsInGroup / IsInRaid
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.
2026-06-27 18:54:04 -05:00
Brues 62a99ac410 mouseover/libpredict: drop legacy spell-target plumbing
With Nampower as a hard dep, /pfcast for spell names always takes the
early CastSpellByName(msg, unit) path. The fallback branch that did the
SpellTargetUnit dance (resolve a friendly unit token, disable AutoSelf
Cast, call SpellTargetUnit) hasn't been reachable in a while, and it
dragged a pile of supporting infrastructure with it.

modules/mouseover.lua:
- Drop the st_units token list, GetUnitString helper, and the
  UnitTokenFromGUID rewrite of GetUnitString — all only used by the
  dead fallback.
- Drop the NoSelfCast helper (only the dead fallback called it).
- Drop the pfMouseOver frame; its only purpose was to hold a .unit
  field the dead fallback wrote and libpredict's hook read.
- The macro path collapses to: if not the current target, swap target,
  run the loadstring'd func, restore the previous target.
- 99 lines → 34.

libs/libpredict.lua:
- Drop the dead `local mouseover = pfUI.uf.mouseover.unit` plumbing in
  the CastSpellByName hook — pfUI.uf.mouseover is gone and the field
  was permanently nil anyway. The three `target or mouseover or default`
  fallback chains collapse to `target or default`.

Modern mouseover/click-to-cast detection in libpredict goes through
pfUI.libpredict_pending_cast (populated by libdebuff from Nampower's
SPELL_CAST_EVENT) — that path is GUID-based, server-authoritative, and
untouched.
2026-06-27 18:41:11 -05:00
Brues deeec89955 predict + libdebuff + swingtimer: drop hardcoded spell data
Replace per-locale name tables and per-rank ID lists with single
canonical-rank lookups through C_Spell. Spell.dbc bits hoisted to
named constants at module top.

libpredict:
- Four 7-locale tables (PRAYER_OF_HEALING / REJUVENATION / RENEW /
  REGROWTH) collapsed to one C_Spell.GetSpellName(rank1id) call each.
- 25-entry SPELL_IDS (all ranks of Rejuv + Renew) for SPELL_GO_SELF
  HoT detection replaced by name comparison against REJUVENATION /
  RENEW. No per-rank ID maintenance.

libdebuff:
- GetSpellRecField(id, "name") → C_Spell.GetSpellName(id) at all call
  sites; the presence-guard pattern is gone (ClassicAPI is a hard
  dep, per memory).
- GetSpellRecField(id, "rank") → C_Spell.GetSpellSubtext(id).

swingtimer:
- Hoist FLAG_AUTOATTACK / ATTR_KEEP_SWINGS / ATTR_ON_NEXT_SWING to
  module-top constants via tonumber("0xNN", 16) so the SPELL_GO_SELF
  hot path stops re-parsing them on every call. Lua 5.0 has no hex
  number literals; strtoul-backed tonumber handles the "0x" prefix.
v9.0.3
2026-06-27 18:22:03 -05:00
Brues cca9771ef0 swingtimer: derive spell categories from Spell.dbc attributes
Drop four hardcoded spell-ID tables (swingDelaySpells, hsSpellIDs,
cleaveSpellIDs, maulSpellIDs) and the broad interruptFlags > 0 reset
heuristic in favor of server-parity checks against Spell.dbc bits via
nampower's GetSpellRecField:

- "Resets the swing on cast complete" gated on InterruptFlags's
  SPELL_INTERRUPT_FLAG_AUTOATTACK (0x08) and AttributesEx2's lack of
  SPELL_ATTR_EX2_NOT_RESET_AUTO_ACTIONS (0x20000) — mirrors the server's
  Spell::IsMeleeAttackResetSpell. Reset OH alongside MH to match.

- "Slam-style delay" derived from absent 0x08 + a cast time existing
  (implicit since SPELL_START_SELF only fires for cast-time spells).
  Freezes the swing timer at SPELL_START and adds cast duration on
  SPELL_GO instead of resetting.

- HS / Cleave / Maul classification via IsOnSwingSpell (ATTR_ON_NEXT_
  SWING bit 0x04) + name comparison against rank-1 canonical names,
  centralized into ClassifyOnSwingSpell + SetQueuedKind helpers.

Switch the lone GetSpellRec table-allocator call to GetSpellRecField for
consistency (single-field hash lookup, no shared-table reuse caveat).
2026-06-27 17:52:31 -05:00
Brues 371872bb90 swingtimer: route wand Shoot to ranged bar without resetting MH
Wand Shoot (spellID 5019) wasn't recognized as ranged anywhere, so it
fell through every branch of the SPELL_GO_SELF dispatch and hit the
catch-all interruptFlags > 0 reset, wiping the mainhand swing on every
shot. Casters melee-weaving between MH swings and wand fires lost their
swing visualization.

Replace the hardcoded RANGED_SPELLIDS / WAND_SHOOT_SPELLIDS tables with
C_Spell.IsRangedAutoAttackSpell (Spell.dbc AUTO_REPEAT bit) — catches
both Auto Shot and Shoot today, plus any future auto-repeat ranged
spell. ResetRanged now takes a replaceMH flag: true for Auto Shot /
Throw (Hunter ranged replaces melee), false for wand (independent
timers, both tick concurrently).

Closes #5.
2026-06-27 17:14:48 -05:00
Brues 591045a606 config: stamp sentinel version on dev builds to stop migration re-fire
Dev / git-cloned installs carry "@project-version@" in the toc, which
pfUI normalizes to pfUI.version.string = "dev". MigrateConfig was
writing that literal back into pfUI_config.version; on the next /reload
checkversion() parsed "dev" through tonumber() → nil → 0, evaluated
curversion as 0/0/0, and re-fired every version-gated migration block.
The >3.6.1 buff migration unconditionally rewrites buffs.{buffs,debuffs,
weapons} from the legacy global.hide{,w}buff knobs, so user toggles for
those checkboxes were getting wiped on every reload.

Stamp "999.999.999" on dev builds so subsequent comparisons turn false.
Affected users will need to re-toggle the buffs/debuffs/weapon-buffs
checkboxes once after this update.

Refs #7.
2026-06-27 16:46:56 -05:00
Brues f657a9e7e8 drop MobHealth3 / MobHealthFrame fallbacks
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.
2026-06-27 16:08:39 -05:00
Brues 0cbd9ecf98 Revert "nameplates: drop redundant name check from plate-reassignment gate"
This reverts commit 6ca482fcaa.
2026-06-27 16:01:24 -05:00
Brues 6ca482fcaa nameplates: drop redundant name check from plate-reassignment gate
GUID is the unique identity; the name check was leftover from the
name-only era and became dead weight once cachedGuid (NAME_PLATE_UNIT_
ADDED) was added alongside it.
2026-06-27 15:59:16 -05:00
Brues 8902d43f40 nameplates: wipe full plate.cache on reassignment
The plate-reuse reset only cleared name/guid/player/cdCache, leaving
hp/hpmax/rgb/namecolor/levelcolor/target/mouseover/inCombat behind. The
PERF gates downstream ("only update X when X changed") then skipped bar
fill / color / text updates when the new occupant happened to share a
cached value with the previous one — most easily reproduced on
plate-pool reuse in starting zones (mobs churn fast, percentage values
collide). Nuke the whole cache via table.wipe.

Refs #8.
2026-06-27 15:48:53 -05:00
brues-code 8f006c0643 Update issue templates 2026-06-27 15:07:04 -05:00
Brues de7dacf788 xpbar: route rep tracking through ClassicAPI faction APIs
Drop CHAT_MSG_COMBAT_FACTION_CHANGE + SanitizePattern(FACTION_STANDING_
INCREASED) string parsing in favor of FACTION_STANDING_CHANGED, which
ships (factionID, newStanding, repGained) directly — locale-independent,
no chat-string scrape. Track factionID instead of faction name.

Collapse the two for i=1, 99 GetFactionInfo loops (tooltip + bar fill)
into a single GetRepDisplay helper: GetFactionInfoByID for the remembered
faction, C_Reputation.GetWatchedFactionData for the watched one.

Watched-faction-changed detection now compares factionIDs.
v9.0.2
2026-06-27 01:09:15 -05:00
Brues e0bcbbf2dc castbar: Quartz-style tradeskill merge with per-craft spark
Hook DoTradeSkill to capture the requested count, then on the first
SPELLCAST_START of an isTradeskill cast stretch endTime to span all
crafts so the player bar fills continuously across the chain. Mid-chain
SPELLCAST_START / SPELL_START_SELF events refresh the "(N)" remaining
label and reset a per-craft spark that crosses the bar once per craft.
SPELL_GO_SELF counts completions; SPELLCAST_STOP no-ops while merged.

Gated by a new C.castbar.player.mergetradeskill knob (default on).
2026-06-26 18:43:31 -05:00
Brues 65bbea6fa9 bump min again 2026-06-25 23:46:34 -05:00
Brues 822c873132 castbar: event-driven rewrite on ClassicAPI C_Spell + nampower events
Drive the cast bar from cast lifecycle events instead of polling C_Spell
every frame. OnUpdate now only animates a stamped start/end and fades out;
all state transitions come from events:

- player: vanilla SPELLCAST_START / _STOP / _FAILED / _INTERRUPTED /
  _CHANNEL_START / _CHANNEL_STOP, plus nampower SPELL_START_SELF (the only
  signal for a chained same-spell recast, which never runs the client cast
  path) and SPELL_DELAYED_SELF for pushback (applied from its delayMs arg).
- non-player (target/focus): nampower SPELL_START_OTHER / SPELL_FAILED_OTHER
  + PLAYER_TARGET_CHANGED / PLAYER_FOCUS_CHANGED.

Data comes from ClassicAPI's C_Spell.UnitCastingInfo / UnitChannelInfo
(player exact; other units from the SMSG_SPELL_START cache). SPELL_START_*
re-polls are deferred one frame so ClassicAPI's packet co-hook has stamped
before the read. SPELLCAST_CHANNEL_STOP only clears when a channel is shown,
so a lagged channel-stop doesn't wipe a following cast's bar.

Remove the now-unused CASTBAR_EVENT_* constants from compat/vanilla.lua.
2026-06-25 22:38:53 -05:00
Brues 96fd486187 bump min 2026-06-25 01:49:17 -05:00
Brues b79132b9f4 casts: route everything through C_Spell, drop libcast + libdebuff_casts
ClassicAPI's recent C_Spell additions cover remote-unit casts natively
(SMSG_SPELL_START co-hook caching per caster GUID), so the two parallel
cast trackers pfUI was running — libcast.lua and the libdebuff_casts
table inside libdebuff.lua — can both retire.

Migrations:
- modules/castbar.lua: focus/player cast-info gathering reads
  C_Spell.UnitCastingInfo / UnitChannelInfo directly. Fallback ladder
  (libdebuff_casts → pfGetCastInfo → pfGetChannelInfo) collapses into a
  single call. Pushback handlers stop writing back into a non-existent
  cache; the local this.endTime is the source of truth.
- modules/nameplates.lua: GetCastInfo(guid) now resolves to a unit token
  via UnitTokenFromGUID and queries C_Spell, returning the same compact
  struct shape downstream code expected. UpdateCastbar collapses from a
  three-branch hierarchy (dead IterDebuffs / libdebuff_casts / libcast)
  to one C_Spell read.
- modules/afkcam.lua: pfGetCastInfo+pfGetChannelInfo round-trip becomes
  a single C_Spell.UnitCastingInfo("player") or UnitChannelInfo fallback.
- libs/libpredict.lua: HealComm timing uses C_Spell on the sender's unit
  token after a small group-roster walk to resolve the sender's name.

Deletions:
- libs/libcast.lua entirely (-571 lines) plus its init/libs.xml entry.
- libdebuff_casts / libdebuff_item_icons tables and their write sites
  in libs/libdebuff.lua (the SPELL_START_*, SPELL_GO_*, SPELL_FAILED_*
  event handlers stop maintaining them but keep firing the
  libdebuff_*_hooks broadcast surface for actionbar / swingtimer /
  libtotem). SPELLCAST_CHANNEL_STOP now reads the active channel from
  C_Spell.ChannelInfo.
- modules/superwow.lua's supercast block — UNIT_CASTEVENT writes into
  libcast.db are redundant now that C_Spell co-hooks the same packet.
- The cast-bar item-icon override that swapped in a potion/trinket
  icon for item-triggered casts. Spell icon stays; the item-icon
  metadata path (libdebuff_item_icons) went with libdebuff_casts.

Steady Shot synthetic cast bar — Turtle WoW-specific:
- castbar.lua gains a pfUI.synthetic_casts[unit] fallback that fires
  only when C_Spell returns nil, so abilities the engine treats as
  instant but which have a meaningful wait window can still render a
  cast bar.
- modules/turtle-wow.lua replaces the old libcast.customcast block with
  a Nampower SPELL_QUEUE_EVENT subscriber. ON_SWING_QUEUED matching
  the localized "Steady Shot" name writes a 1.4s synthetic entry;
  ON_SWING_QUEUE_POPPED clears it; castbar's endMs guard self-expires
  the entry as a safety net. Note: haste scaling (libcast.ApplyShotHaste)
  is gone — bar may finish slightly early under +ranged haste buffs.

Net: 152 insertions, 972 deletions.
2026-06-25 01:18:22 -05:00
Brues d62a1222df feigndeath: use UnitIsFeignDeath + GetUnitField, drop tooltip cache
ClassicAPI's UnitIsFeignDeath reads UNIT_FIELD_FLAGS bit 29 directly —
the authoritative server flag, no detection guesswork needed. Combined
with Nampower's GetUnitField("health"), we read live HP off the
descriptor instead of caching the moment-of-death healthbar value via
libtipscan.

Drops the name-keyed cache, the UNIT_HEALTH / PLAYER_TARGET_CHANGED
event handlers, and the tooltip scanner. Also fixes the staleness bug
where a feigning hunter taking further damage kept showing the cached
snapshot from when feign first triggered — live read updates with
every UnitHealth call now.
2026-06-24 22:49:43 -05:00
Brues be6ae25315 libdebuff/nameplates: drop dead per-aura readers and debuff cache
With every external caller of libdebuff:UnitDebuff / :UnitOwnDebuff
now on C_UnitAuras, the two public per-aura readers and the
nameplate-side cache they were feeding have no consumers.

- libs/libdebuff.lua: removes libdebuff:UnitDebuff (~120 lines),
  libdebuff:UnitOwnDebuff (~75 lines), the _ownDebuffSortFunc helper,
  and the local cache table. The slotOwnership / ownDebuffs /
  allAuraCasts / pendingCasts bookkeeping stays — GetBestAuraCast
  (libpredict) and GetEnhancedDebuffs (CleveRoids) still read it, and
  the event handlers maintain it. GetSlotCaster / GetDebuffSlotMap
  stay too; the DEBUFF_ADDED_OTHER handler and the debug printer use
  them. File goes 2010 → 1870 lines.
- modules/nameplates.lua: deletes PlateCacheDebuffs (was already
  rewritten on C_UnitAuras and unused once the display loop bypassed
  the cache), PlateUnitDebuff, the cachedVerify scaffolding, and the
  nameplate.UnitDebuff / nameplate.CacheDebuffs registrations.
- api/config.lua + modules/gui.lua: drops the now-defunct
  "guessdebuffs" knob — its only effect was gating the dead cache.
2026-06-24 22:41:36 -05:00
Brues d6951b386e unitframes/buffwatch/libpredict: route aura reads through C_UnitAuras
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".
2026-06-24 22:41:13 -05:00
Brues fd21b24a74 utilize C_UnitAuras for nameplate auras 2026-06-24 19:14:36 -05:00
Brues 90ac4f9de0 auto generate changelogs 2026-06-22 19:50:44 -05:00
Brues 63f9b26d91 classicapi: default LATEST to MIN so source builds never soft-nudge
Replaces the 99999999 sentinel with `LATEST = MIN`. The elseif
`< LATEST` then reduces to `< MIN` on source builds, which the
preceding `if` branch always catches first — so the soft-nudge never
fires for unpinned installs. No explicit guard needed.

A source/cloned install previously showed "ClassicAPI v9999.99.99 is
available" because the sentinel leaked into FormatVersion before the
release workflow could patch it. With this layout, source installs are
silent and only properly-pinned release zips trigger the nudge.

Workflow sed broadens to "= .*" so it overwrites the line regardless
of whether the RHS is a digit string or a Lua identifier.
v9.0.1
2026-06-22 19:47:57 -05:00
Brues ef94f90876 release: match indented PFUI_CLASSIC_API_LATEST in pin step
Wrapping the version-check block in a do…end indented every constant
by two spaces, so the sed pattern's ^local anchor stopped matching and
the followup grep returned exit 1, killing the step under bash -e.

Captures the leading whitespace into \1 so the indent is preserved
through the substitution, and matches the two-space alignment between
LATEST and = so we don't accidentally hit LATEST_URL on the line below.
v9.0.0
2026-06-22 15:46:27 -05:00
Brues 79003c0c9a minor coloring 2026-06-22 15:41:50 -05:00
Brues 614163ef45 classicapi: hardcode website URL, link to /releases/latest
The earlier change pulled the ClassicAPI URL via
GetAddOnMetadata("!!!ClassicAPI", "X-Website"), but that's only
readable when ClassicAPI is loaded — and the popup that needs the URL
is exactly the case where the dep is absent or out of date. Hardcode
PFUI_CLASSIC_API_WEBSITE as a constant in pfUI.lua instead.

Also points the editbox and chat messages at /releases/latest rather
than /releases/tag/<MIN>. GitHub redirects to the actual latest
release, so users land on something current instead of the version
floor (which may be an ancient tag).
2026-06-22 15:29:09 -05:00
Brues 2d861546a3 fixed nampower link 2026-06-22 15:11:33 -05:00
Brues ff98dde670 classicapi: two-tier version check + drop hardcoded github URLs
Splits the ClassicAPI version check into a hard floor (MIN, manual)
and a soft target (LATEST, pinned by the release workflow). Below MIN
pfUI disables itself entirely as before; between MIN and LATEST it
runs normally but fires a delayed chat nudge after PLAYER_LOGIN with
the available update. PLAYER_LOGIN handlers swap to
EventUtil.ContinueOnPlayerLogin so we don't have to spin a frame for
each branch.

URLs centralize on toc X-Website fields. pfUI.lua factors out
ClassicAPIReleaseUrl(version) sourcing from !!!ClassicAPI's metadata;
modules/gui.lua and libs/libdebuff.lua replace hardcoded
me0wg4ming/pfUI links with GetAddOnMetadata(pfUI.name, "X-Website")
lookups.

release.yml gains a pre-package step that queries ClassicAPI's latest
release tag, packs it (X*10000 + Y*100 + Z), and seds only the LATEST
line in pfUI.lua so the published zip ships with the correct soft
target.
2026-06-22 15:06:04 -05:00
Brues 28ce916cc3 bump min ClassicAPI version to 1.4.3 2026-06-22 14:36:02 -05:00
Brues 0f67ae195a nampower: pass slash arg to DisenchantAll, default to "greens"
Bare DisenchantAll() errored — the DLL requires an arg. Forward the
slash message through and default to "greens" when empty. Per
nampower's player_scripts.cpp, quality is a STRING keyword ("greens",
"blues", "purples", pipe-combined); numbers are interpreted as item
IDs, not quality levels. tonumber() lets users pass numeric item IDs
unquoted.
2026-06-22 14:31:20 -05:00
Brues 66c8e5a0b1 slash: write SLASH_* keys to _G inside module bodies
pfUI module bodies run under pfUI.env (setfenv in LoadModule), which
proxies reads to _G via __index but has no __newindex. Bare
"SLASH_FOO = ..." assignments therefore land on pfUI.env, not on _G,
and WoW's slash dispatcher reads _G.SLASH_* directly — so the slash
command never registered. SlashCmdList[KEY] assignments happened to
work because the table is read first (falls through), then the key
write hits the real global table.

/pfunitxp, /clickthrough, /ct, /disenchantall, /dea — all silently
broken until now. Fixed by prefixing SLASH_* writes with _G.
2026-06-22 14:27:20 -05:00
Brues 2b140da5d4 Update CHANGELOG.md 2026-06-22 14:10:17 -05:00
Brues 1c60901f2a release: bootstrap CHANGELOG.md for first tagged release
Packager auto-generates the GitHub release body from git log since the
last tag. The first release has no prior tag, so it walks all history
and overshoots GitHub's 125k-char body limit. Ship a curated
CHANGELOG.md with the highlights and point packager at it via
.pkgmeta's manual-changelog directive. Subsequent releases diff
tag-to-tag and stay small — either delete both files after this
release lands to restore auto-gen, or keep maintaining CHANGELOG.md
manually.
2026-06-22 13:58:43 -05:00
Brues ee17a39445 updatenotify: isolate fork from upstream pfUI traffic + handle dev builds
Switches the addon-message prefix to "pfUI-brues" so we don't share an
inbound queue with upstream pfUI installs at all — they don't register
a listener for this prefix, so our broadcasts get dropped at the engine
level instead of needing branch-string filtering on their end. The
"main" branch tag stays as a tiebreaker for any future fork variant
sharing this prefix.

Source/dev installs leave the toc Version as "@project-version@" until
release tooling substitutes it. pfUI.lua now stamps those as "dev" with
major/minor/fix=0 instead of silently falling back to 1.2.0, and
updatenotify short-circuits on pfUI.version.string == "dev" before
broadcasting so dev installs don't ship a stale low version to everyone
in guild/raid. Single source of truth — the dev marker lives in pfUI.lua.

URLs centralize via the toc's X-Website. updatenotify and firstrun read
it via GetAddOnMetadata + string.format("%s"), and all eight translation
files swap their hardcoded shagu.org references for the same %s slot.

Drive-bys: groupsize math uses ClassicAPI's IsInRaid/IsInGroup; toc
Author typo "modfied" → "modified".
2026-06-22 13:51:00 -05:00
Brues 95e936e9a1 add git release workflow 2026-06-22 13:05:26 -05:00