Commit Graph

4051 Commits

Author SHA1 Message Date
Brues 0fc08e77c0 Create .pkgmeta 2026-09-02 10:26:28 -05:00
Brues 7f3795b45b Add .luarc.json for Lua 5.1 language server diagnostics 2026-09-02 10:23:48 -05:00
Brues 8eee766652 chat: apply Blizzard per-window transparency to docked backdrops
The native chat background transparency slider drives FCF_SetWindowAlpha,
which only touches the ChatFrame*Background textures pfUI hides on docked
frames, so the visible pfUI backdrop never responded to it.

Mirror the selected window's stored alpha (GetChatWindowInfo) onto the pfUI
backdrop and refresh it from RefreshChat, FCF_SetWindowAlpha and
FCF_SelectDockFrame so the native slider drives it live and persists across
/reload. Default the SetupPositions window alpha to 0.8 to keep the historical
look, and migrate existing installs whose windows still carry the old hard-0
alpha so their chat background is not suddenly transparent.

Fixes #48
2026-09-02 01:05:47 -05:00
Brues 2b5288a688 nameplates: don't run GetUnitInfo for minions 2026-08-31 16:43:38 -05:00
Brues daba4e202e Default saved variables with 'or {}' instead of overwriting
Seed the SavedVariables globals only when absent (X = X or {}) rather
than unconditionally assigning {}. Behaviorally identical under the
current load order -- a returning character's data is restored over these
between file load and ADDON_LOADED -- but expresses intent as a default
and won't clobber data if that timing ever changed.
v9.0.21
2026-08-31 12:04:00 -05:00
Brues 98c7751416 Utilize CAPI Tracking functions
commit 8ea5c81789
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Mon Aug 24 23:40:01 2026 -0500

    bump CAPI min to 1.12.4

commit 39a46563a1
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Mon Aug 24 23:35:49 2026 -0500

    tracking: use native ClassicAPI tracking API

    Replace the hardcoded knownTrackingSpells class table and the
    icon-substring spellbook scan with ClassicAPI's native tracking
    functions:

    - RefreshSpells now enumerates GetNumTrackingTypes() / GetTrackingInfo(),
      which the DLL derives from the spellbook by tracking-aura effect. This
      drops the per-class spell/icon table and picks up server-custom
      trackers (e.g. Turtle's Find Trees) automatically.
    - Selecting a tracker in the menu uses SetTracking(index) instead of
      CastSpell(slot, BOOKTYPE_SPELL).
    - Keep the Druid Cat Form gate on Track Humanoids (5225) and the
      existing invalidSpells filter. Falls back to no entries if the tracking
      API is absent.

    Active icon (GetTrackingTexture), cancel (CancelTrackingBuff), and the
    hover tooltip (GameTooltip:SetTrackingSpell) were already native and are
    unchanged.

Fixes #42
2026-08-30 17:19:17 -05:00
Brues 8796fab6d8 libpredict: predict incoming heals for built-in click casting (#44)
Built-in click casting drives the cast through secure frame attributes,
bypassing the CastSpell/CastSpellByName/UseAction hooks that populate
spell_queue -- so the heal-prediction lookup in the SPELL_START_SELF
handler missed and no incoming heal showed.

Populate spell_queue from the cast's own rank-specific spellId (via
C_Spell.GetSpellName/GetSpellSubtext) right before the cache lookup, so
prediction works regardless of how the cast was initiated. Deriving the
rank from the actual spellId also fixes stale-rank lookups when a prior
keybind cast left a different rank of the same spell queued.
2026-08-24 21:37:41 -05:00
brues-code 7ca0e40d8b CAPI needs 1.12.1 for UnitAura changes 2026-08-24 12:05:18 -05:00
brues-code 2f93b246a1 Accidentally bumped ClassicAPI to the wrong version 2026-08-24 11:48:54 -05:00
Brues c647698f8f bump CAPI min 2026-08-24 11:07:38 -05:00
Brues 48026008b6 buffwatch: use official dispel-type colours for debuff bars
The debuff-bar auto colour read the vanilla DebuffTypeColor global,
diverging from unitframes/buff which use C_UnitAuras.GetAuraDispelTypeColor
(the BC GlobalColor.dbc palette ClassicAPI ships). Switch buffwatch to the
same accessor so all aura displays share one palette; nil/unknown types
fall back to DEBUFF_TYPE_NONE instead of the old ad-hoc (1, .2, .2).
2026-08-24 11:07:38 -05:00
Brues c1d96bae58 buff/buffwatch: positional aura reads in hot refresh loops
buff.lua RefreshBuffButton runs 50x per PLAYER_AURAS_CHANGED and
buffwatch.lua GetBuffData runs 32x per RefreshBuffBarFrame; both now use
the zero-allocation positional C_UnitAuras.UnitAura instead of the
table-allocating GetAuraDataByIndex.

buffwatch also threads the aura's dispelType out of GetBuffData onto the
frame.buffs row, so the debuff-bar colour reads it from the row instead
of re-fetching the aura with GetDebuffDataByIndex on every name change.

Cold single-lookups (hover/click tooltips) keep the readable table API.
2026-08-24 11:07:38 -05:00
Brues 1d44c5ec6f unitframes: scan debuff slots once for dispel indicators
The dispellable-indicator block re-scanned all 16 harmful slots for
every dispellable type (O(types x 16) UnitDebuff calls per refresh).
Scan the 16 slots once into a reusable set, then have the per-type loop
check the set. Zero-allocation (the set is cleared and reused within the
single RefreshUnit call).
2026-08-24 11:07:38 -05:00
Brues 8f88dfd852 Use positional C_UnitAuras accessors in hot aura scans
Swap the per-frame aura-refresh loops from table-allocating
GetAuraDataByIndex/GetBuffDataByIndex/GetDebuffDataByIndex/GetUnitAuras
to the zero-allocation positional C_UnitAuras.UnitAura/UnitBuff/UnitDebuff.

unitframes: buff/debuff icon loops, the dispellable-indicator 16-slot
scan, the two GetUnitAuras indicator passes, and the custom-debuff scan.
nameplates: the per-plate debuff scan now writes positional results
straight into the reusable display buffer, dropping the per-aura tables
and the result array.

Filters change from HARMFUL|PLAYER/HARMFUL to PLAYER/nil since UnitBuff/
UnitDebuff lock the range and still honor the PLAYER predicate. Cold
single-lookups (hover/click, tooltip, totem icon, libdebuff) keep the
readable table API.
2026-08-24 11:07:37 -05:00
Brues a57214aeb0 Bump ClassicAPI minimum version 2026-08-24 11:07:37 -05:00
Brues 9bde843e33 utlize inline icons and CreateGoldString in repair module 2026-08-24 11:07:37 -05:00
Brues ad13e6ace3 Utilize SetFormattedText
This change updates several text setters to use `SetFormattedText` instead of passing `string.format(...)` into `SetText`. It also switches a few regex captures from `string.find` to `string.match` for cleaner capture handling, and replaces explicit width/height setters with `SetSize` in the first-run dialog for consistency.
2026-08-24 11:07:37 -05:00
Brues 82c74c2db5 Skip declaring pfSellData on turtle client
This giant table is just going to be immediately replaced so there's no point in declaring it.
2026-08-21 14:59:19 -05:00
roby-brok a3cfd711fe nameplates: read friendly name colours from the class table
The class-colour write sourced r, g, b from the health bar rather than
from PFUI_CLASS_COLORS[class], which the condition tested for but never
read. So "class colours on friendly names" only produced a class colour
when friendclassc - a bar option - happened to be on as well; otherwise
the name took the generic friendly colour. In every case it also
inherited the tapped-grey and barcombatstate overrides meant for the bar,
neither of which belongs on the name.

The name now reads the class table directly.

The discarded "and PFUI_CLASS_COLORS[class]" term was dead weight: the
table carries an __index metamethod returning a grey ColorMixin for any
missing key, so it was always truthy and merely allocated a throwaway
table per evaluation. "and class" is the real guard. One behaviour change
falls out - a friendly player of an unrecognised class now takes that
grey fallback rather than the bar colour, which is what the option means.

(cherry picked from commit f880dc3528db2ba0d0936b00a4dff8deec48e6d2)
(cherry picked from commit 111d70004d4fb172f168aa48a4cb6177a7f0d393)
v9.0.20
2026-08-21 13:31:07 -05:00
roby-brok a7ad1f073f nameplates: give the name colour a single owner
cache.namecolor was written by two writers holding unrelated quantities:
the computed health-bar colour in OnDataChanged, which class-colours
friendly player names when friendclassnamec is on, and Blizzard's own
name FontString in the OnUpdate sync. Sharing one key let either suppress
the other, so the option silently lost - names came out white with
namefightcolor off, or the plain reaction colour with it on.

It also forced a full data pass every throttled tick, because the sync
writer sets update = true whenever it writes and the two kept flipping
the key. That defeats the half-second tick gate entirely.

Compounded by nameplate.cache surviving pool reuse: OnShow re-runs the
data pass but never clears the table, which is built once at plate
creation, so a recycled plate could inherit the previous unit's name
colour.

Ownership is now explicit through cache.ownname, each writer keeps its
own key, and both are invalidated when ownership flips.

(cherry picked from commit 0a4b3a7d6ae523cf70584adbb694a8740024b7cd)
(cherry picked from commit 0df9bb9fa907349182fb03217cab6aa1777aa7d9)
2026-08-21 13:31:07 -05:00
roby-brok fe5b3b135b nameplates: use true difficulty colours for level text
The level string was brightened by +0.3 on all three channels before
display, in the levelFromDB path and again in the OnUpdate colour sync.
A flat offset desaturates toward white and costs the high tiers most,
because their green/blue channels start near zero: verydifficult
1.00/0.50/0.25 becomes 1.00/0.80/0.55 and reads as yellow, impossible
1.00/0.10/0.10 becomes 1.00/0.40/0.40 and reads as orange. Orange and
yellow ended up 0.2 apart on a single channel, so a mob 3-4 levels above
the player showed yellow and a skull-range mob showed orange.

Both offsets dropped. Ownership of the colour is now explicit through
cache.levelfromdb so the two writers no longer race: the sync block
stands down on ?? plates, and the DB path clears cache.levelcolor so the
sync re-asserts cleanly once the level resolves. That also fixes a stale
cache - nameplate.cache is built once at plate creation and survives pool
reuse, so a recycled plate could keep the previous unit's colour.

Deleting the sync block instead would be wrong: it is the only thing that
colours the level on non-?? plates, and plate.level is created with no
colour at all.

Reported by Iden via Discord.

(cherry picked from commit eaa9beac51953d2a959c67d5ff5bc50273a919c3)
(cherry picked from commit 3fdb3b23136b260d111509e24e6d7b0d0b9b1b33)
2026-08-21 13:31:07 -05:00
Brues 9c29f0c7d4 Add handlesHookScript capability flag
Introduce pfUI.handlesHookScript boolean in pfUI.lua to signal that this fork's actionbar buttons correctly support the modern HookScript widget method. This prevents ClassicAPI's AddOnCompat shim from shadowing HookScript during actionbar load. The flag documents behavior (not identity): forks that maintain HookScript-correct actionbar code should keep the flag; forks that do not should clear it to opt into the safe compatibility fallback.
2026-08-21 13:26:09 -05:00
Brues 685ecb4a3e Removed !!!ClassicAPI from toc dependencies
Addon is now baked into the DLL and !!!ClassicAPI will always load before pfUI so this only served to confuse users
2026-08-18 10:35:31 -05:00
Brues 8cdaf1fc00 Prefer GetCoinTextureString in CreateGoldString
If the global GetCoinTextureString exists, use it to format money (wrapped in white color codes) for CreateGoldString. Keeps the existing numeric fallback formatting for environments without GetCoinTextureString.
2026-08-18 04:38:09 -05:00
Brues bb39c9d94e Add localized race info to pfUI environment
Initialize pfUI.env.L["race"] by iterating C_CreatureInfo.GetRaceInfo and C_CreatureInfo.GetFactionInfo. Builds a table keyed by clientFileString containing raceName, raceID and faction (groupTag).
2026-08-18 04:34:34 -05:00
Brues 18059ffbb7 Class-color aura caster name in tooltips 2026-08-18 04:29:33 -05:00
Brues d75e280238 Show party pets in raidpet frames under raidforgroup
When "Use Raid Frames To Display Group Members" is on and in a party,
raid pet frames tried to show raidpet1..40 (nonexistent in a party)
instead of the player pet and partypet1..4.

Remap raidpet grid slots to pet / partypet<N> in UpdateVisibility,
keyed on a stable pfRaidPet<N> slot, mirroring the raid player frames.
LayoutPets now mirror-places the party pet slots, and the raid updater
runs LayoutPets when in a party (not just a raid).

Also exclude raid pet frames (label "partypet", cache_raidpet set) from
the hide_in_raid group-hiding clause so they are not hidden.
2026-08-13 18:03:56 -05:00
Brues 9eb34b8f0a Revert "40-y rangecheck on by default"
This reverts commit af6893c10c.
2026-08-13 17:43:13 -05:00
Brues f8dde49f09 Add IsPlayerGuid API wrapper
Expose the built-in IsPlayerGuid helper through pfUI.api so callers can check whether a GUID or unit token matches the local player. This keeps the pfUI API surface consistent with the underlying WoW API while making the check available through the addon namespace.
2026-08-13 17:32:47 -05:00
Brues 74fbbb6154 Use PFUI_CLASS_COLORS in loothistory v9.0.19 2026-08-12 14:33:05 -05:00
Brues af6893c10c 40-y rangecheck on by default 2026-08-12 14:25:37 -05:00
Brues be6b2ea036 Support binding a click to a named macro
Accept "macro:<name>" in a click-cast action to run a saved macro by
name via the secure `macro` attribute (leading space after the colon is
trimmed). ClassicAPI dispatches it through RunMacro, so a conditional
addon still evaluates the macro body.
2026-08-12 00:33:49 -05:00
roby-brok afdb6c3862 unitframes: stop UnitHasAggro rescanning and reallocating on every call
Two costs on the hot path. It concatenated '<u>target' and '<u>targettarget'
per call per unit, though pfValidUnits never changes after load -- now built
once into a static triple list. And only positive results were cached, so the
common case (nothing has aggro) rescanned the entire unit table on every call;
negative results now cache for 0.3s, short enough that aggro still appears
promptly.
2026-08-11 02:06:28 -05:00
Brues b230a45b92 Show spell and unit IDs on tooltips
Add "Show Spell IDs" and "Show Unit IDs" options alongside the existing
item-ID line. Spell IDs come from GameTooltip:GetSpell() on spell
tooltips and from the aura's spellId on unit-aura tooltips; unit IDs
come from C_CreatureInfo.GetCreatureID on the mouseover unit's GUID
(skipped for players and guarded when the GUID carries no entry).
2026-08-11 00:38:28 -05:00
Brues ef1fa47539 Dock GreedMeter into the chat panel
Register GreedMeter's primary window on the meter dock's damage slot,
mirroring the ShaguDPS integration. GreedMeter builds its windows lazily
and supports several, so frames are resolved at call time.

A second GreedMeter window docks into the panel's other half: pfUI's
dock decides fill-vs-split by whether the threat slot is filled, so hook
GreedMeter's window add/remove to reconcile that slot and re-run the
resize. Only the first two windows fit the panel; any beyond that float.
2026-08-10 23:52:52 -05:00
Brues ab0ad7dcf9 Group tooltip settings into sections 2026-08-10 15:07:01 -05:00
Brues c82813df5b Use GetRGB() for NORMAL_FONT_COLOR 2026-08-10 15:05:48 -05:00
Brues 6e1f8095a2 Allow whitespace-only macro names
strtrim collapsed a name like " " to "" and the empty guard then
rejected the save, but a whitespace-only name is valid in vanilla and a
common way to make a name-less macro. Save the raw text and only reject
a truly empty box.
2026-08-10 09:53:34 -05:00
Brues 9cabdf2974 Revert the pixel-perfect scale change
GetPerfectPixel switched to UIParent:GetEffectiveScale(), which reports
the true unclamped scale (e.g. 1.42 on the larger pixelperfect presets,
since the module calls UIParent:SetScale past the uiScale cvar's 1.0
cap). At that scale 768/screenheight/scale drops below half a pixel and
the border edgeSize rounds to zero, so button borders disappeared.

The uiScale cvar's <=1.0 cap was load-bearing, not a bug: it keeps the
1px borders from vanishing. Restore the cvar-based measurement and move
pixelperfect back to its original load position.
2026-08-10 01:27:27 -05:00
Brues b6931359b0 Use the real UKNOWNBEING global in libpredict guards
The 1.12 client defines Blizzard's own misspelling, UKNOWNBEING
("Unknown Being"); UNKNOWNBEING does not exist and resolves to nil, so
both guards never matched. Point them at the real global.
2026-08-10 01:13:47 -05:00
roby-brok e017dbf515 Fix guards, cache keys and comparisons that never match (#40)
* chat: detect whispers before the timestamp is prepended

Whisper detection tests for the whisper colour code at position 1, but the
timestamp is prepended first, so with timestamps enabled the code is no longer
at position 1 and every whisper failed the test -- losing both the recolour and
the correct chat-history entry.

(cherry picked from commit 4b69d597631c422d9360a94ff129323288a28cc2)

* macrotweak + libpredict: inverted install guard, misspelled globals

macrotweak: _AddHistoryLine is the backup slot this block creates, so it is nil
until line 18 runs. Guarding on its truthiness meant the chat-history filter
never installed at all -- macro calls kept landing in chat input history.

libpredict: UKNOWNBEING / UNKOWNBEING are misspelled, so both resolve to nil and
the guards never matched the real UNKNOWNBEING. Neutral if the global is absent
on this client, correct if present.

Not needed: his libpredict already fixed the always-true
'event == "A" or "B"' condition (libs/libpredict.lua:828).

(cherry picked from commit 4068110dc4134823f1c09f60ca5f8959302cd14f)

* mapreveal: look the explore cache up by the key it is actually stored under

explorecaches is keyed by the plain area name (line ~160), but the hover frame
carried only a decorated 'mapFileName (area)' display string, so every lookup
missed and the hover highlight never fired. Store the plain name alongside it
and key off that; the tooltip keeps the decorated string.

(cherry picked from commit 5e6fe969a03a88c68e28614548b9d44db562ab9a)

* socialmod: don't clobber the friend-online match with the offline one

The offline match was assigned unconditionally over the online match, so a
friend coming online never had lastseen recorded.

(cherry picked from commit ad927806c46042163f84bde4db1082726bedf28b)

* swingtimer: off-hand weapons are inventory type 22, not 21

The off-hand slot accepts one-hand (13) and off-hand (22) weapons. Type 21 is
INVTYPE_WEAPONMAINHAND and can never be equipped there, so the off-hand swing
timer never recognised a real off-hand weapon.

The other two swingtimer fixes are not needed here: his hunter check already
uses UnitClassBase (locale-independent, better than our UnitClass second
return), and his generic on-next-swing detection covers Raptor Strike without
our hardcoded spell-id list.

(cherry picked from commit 9ab7f5f7224d12361ca6cd5a49181cbb4bebd387)

* superwow: compare the version numerically, not by exact string

SUPERWOW_VERSION == "1.5" silently disables the GUID-to-name combat text hook
on any release past 1.5. Currently 1.5 here, so this is forward-compat only.

Not needed: the clickthrough slash commands already go through
RegisterSlashCommand, which writes _G properly.

(cherry picked from commit 82a37752a5782479849ce7e1304c24733c2ff97a)

* api: measure a real pixel against UIParent, not the uiScale cvar

The uiScale cvar caps at 1.0 while both the pixelperfect module and the
firstrun slider push UIParent past it via SetScale, and it is ignored entirely
while useUiScale is off, so borders came out the wrong thickness on the
Huge/Large presets. Ask the frame for its effective scale instead, and guard an
unparseable gxResolution.

Also cache GetItemLinkByName and count its failures: the scan walked every id
on each call with no memory, so an unresolvable name hitched on every tooltip
hover. Raise the ceiling from 25818 to 61000 as well -- Octo/Turtle custom
items live well past the vanilla range and never resolved.

(cherry picked from commit dac2d3416aef85a4c4b71c0239d93d309e76e30b)

* init: load pixelperfect first so GetPerfectPixel caches the right scale

pixelperfect sets the UI scale that GetPerfectPixel measures against, and that
value is cached on first use. Loading it 56th baked in the previous scale.

(cherry picked from commit dd89a210330583f890a51a82b29e968f3ad36b34)

* modules: route two global overrides through _G so they leave the sandbox

pfUI.env has __index but no __newindex, so a bare global assignment inside a
RegisterModule closure is written into the sandbox table and never reaches _G.
unitxp's BattlefieldFrame_Show override therefore never fired the BG queue-pop
notification, and RaidFrame.lua never saw GROUP_REPLACE_PARTY.

The slash-command half of this fix is not needed here: RegisterSlashCommand
already writes through _G.

(cherry picked from commit 617c8320aca2465af62cf0ff5be7dceaed29a3b2)

* bags: remove the duplicate search OnHide handler

Two byte-identical frame.search OnHide handlers were installed back to back;
the second overwrote the first, so the first was dead code.

(cherry picked from commit e77650448b92e5d7f18ae58632e4531cb2813ea6)

* buffwatch: invalidate the filter cache when a skill is listed

fcache is built once per config table and never cleared, so ctrl/shift-clicking
a skill onto the whitelist or blacklist had no effect until the next reload.

* roll: actually capture the everyone-passed subject

strfind(LOOT_ROLL_ALL_PASSED, LOOT_ROLL_PASSED) has no captures, so `everyone`
was always nil, never reached the blacklist, and "Everyone has passed on: X"
was recorded as a real player passing.

Builds a sample from LOOT_ROLL_ALL_PASSED and runs the same LOOT_ROLL_PASSED
match the scanner uses, so the subject is captured the way it will actually
appear.
2026-08-10 01:13:32 -05:00
roby-brok 69d778d6d6 Fix two dangling skin includes and four error paths (#39)
* skins: drop includes for two files that were never committed

init/skins.xml referenced custom_merchant.lua and arena_score.lua, neither of
which is tracked in git. Every install -- release zips included, since the
release workflow packages the repo -- throws two 'Error loading' lines at
login and ships without those two skins.

(cherry picked from commit b338b4a16d0def4ae89fde5c6026e58a796b8c00)

* map: don't re-anchor the world map to the frame GetPoint returned

Ctrl+scroll rescales the map and repositions it to keep the top-left fixed, but
it re-anchored using the relative frame GetPoint handed back. Once anything else
is anchored to WorldMapFrame that throws

  WorldMapFrame:SetPoint(): <unnamed> is dependent on this

and the error aborts the rest of the zoom handler, so SetScale never runs.

Anchor to the parent instead. That is what the rest of pfUI's movable system
already assumes -- LoadMovable uses the 3-arg form and SaveMovable stores only
xpos/ypos with no relative frame.

(cherry picked from commit bf055d87fc0a04ac912c13fa874a4331f47bdfa8)

* firstrun: return after bailing on a disabled chat module

All three chat setup steps printed 'Chat module is disabled' and then carried on
into the nil pfUI.chat they had just tested for.

(cherry picked from commit 1af427e3b38bb7c13f645ae7a48b8ade3e7455a9)

* unitxp: stop the free-frame distance poller on logout

The PLAYER_LOGOUT handler stops the indicators to avoid the UnitXP crash on
exit, but in free-frame distance mode the polling runs on a separate scanner
frame that was never exposed, so the handler could not reach it and its
OnUpdate kept calling into UnitXP during teardown.

Exposes the frame as pfUI.uf.target.distanceScanner and stops it alongside the
others.

* roll: bail out on an item the client has not cached

C_Item.GetItemInfo returns nil for an item that is not cached yet, and the next
line assigns pfUI.roll.cache[itemName], which throws "table index is nil" on a
nil key. Easy to hit on a fresh login when someone rolls on an item you have
never seen.

* cooldown: return after hiding on a nil parent

Without the return it falls straight through to parent:GetName() on the nil it
just tested for.
2026-08-10 01:00:47 -05:00
Brues 75a25cf614 Show a mouseover unit's buffs on the tooltip
Add a "Show Unit Buffs" option that draws a row of buff icons above the
tooltip for mouseover units. Icons come from a ClassicAPI object pool
and are re-anchored left-to-right on each refresh; a single throttled
ticker counts down the remaining time on the visible icons.
2026-08-09 23:12:20 -05:00
Brues 9daf6165fd Show a note-only menu for offline friends
The friend right-click menu only opens for online players, so notes
could not be edited on offline friends. The full menu is useless
offline anyway (Whisper/Invite/Target need an online player), so open
a menu of our own with just the note editor for offline friends.
2026-08-09 22:47:28 -05:00
Brues 06768c985a Merge classicapi-next: friend list and spell fields on ClassicAPI
Squashed from the classicapi-next branch:
- Read spell fields through ClassicAPI instead of nampower (libdebuff, swingtimer)
- Read friend and who-list class tokens from C_FriendList (socialmod, libunitscan)
- Count online friends with C_FriendList.GetNumOnlineFriends
- Add a friend notes module (modules/friendnotes.lua)
- Bump ClassicAPI minimum version to 10906
2026-08-09 19:14:40 -05:00
Brues 881a17e508 Build the class name lookup from FillLocalizedClassList
Replace the hardcoded per-locale ["class"] reverse-lookup tables (localized
class name -> token) with a runtime build in GetEnvironment:

  L["class"] = tInvert(FillLocalizedClassList({}))

The client's own class list supplies the localized names for whatever locale is
running, so the tables were pure duplication -- and this also covers locales the
hardcoded tables never listed. Consumers (libunitscan, panel, socialmod) are
unchanged. Drop ["class"] from every locale file.
2026-08-09 19:03:29 -05:00
Brues 4e461d766e Read debuff durations from C_UnitAuras instead of a static table
Rewrite libdebuff's duration lookups on ClassicAPI's C_UnitAuras, whose
expirationTime carries the real, talent-modified remaining time:

- GetDuration reads the live duration of a matching aura on the player
  (C_UnitAuras.GetAuraDataBySpellName) instead of L["debuffs"][effect][rank].
- GetBestAuraCast reads the active aura's expirationTime directly rather than
  scanning the ownDebuffs/allAuraCasts cast tables -- a unit only ever holds one
  instance of a given spell, so that is inherently the effective one.
- GetMaxRank deleted (it only fed the old GetDuration); AddPending's
  known-debuff guard removed.

The public tracking tables (pfUI.libdebuff_*) are untouched. Drop the now-unused
L["debuffs"] and L["dyndebuffs"] tables from every locale.
2026-08-09 19:02:35 -05:00
Brues 2dfaa65168 Gate combopoint updates and fold player class-color branches
- combopoints: only ever show on the target's plate, so re-issue Show/Hide
  only when the target's combo count changes, and skip non-target plates once
  cleared (they start hidden) -- instead of hiding all five every tick on every
  plate. plate.cpShown tracks the shown count and stays in sync with the frames.
- player class color: merge the identical ENEMY_PLAYER / FRIENDLY_PLAYER
  branches into one condition.
2026-08-09 13:01:29 -05:00
Brues 97ef039d3a Fetch the totem buff icon via GetBuffDataByIndex
Use C_UnitAuras.GetBuffDataByIndex(guid, 1) instead of GetUnitAuras(guid)[1]:
a passive totem's provided buff is its single helpful aura, so the buff-
filtered single-slot fetch is both more precise and cheaper than building the
full aura list to take the first entry.
2026-08-09 03:39:11 -05:00
Brues 25ef02705c Remove dead totems and critters locale tables
Nameplate totem/critter detection now uses UnitCreatureTypeID instead of
name-matching, so the L["totems"] and L["critters"] tables have no remaining
readers. Drop them from every locale file.
2026-08-09 03:17:00 -05:00