Commit Graph
2658 Commits
Author SHA1 Message Date
Brues 1a6314aa60 XP/rep bars: auto-hide rides a timer, drop the OnUpdate 2026-11-03 01:07:02 -06:00
Brues 70bfc1c443 One-shot event handlers: use EventUtil.RegisterOnceFrameEventAndCallback instead of self-unregistering frames 2026-11-03 01:07:02 -06:00
Brues d143e91f81 Mirror timers: bars fill from duration objects, drop the OnUpdate
A breath, fatigue or feign death bar fills from a duration object that
spans the bar at the timer's rate, and a text binding writes the m:ss
countdown. MirrorTimer_Show and MIRROR_TIMER_PAUSE resync it from
GetMirrorTimerProgress; a paused bar holds its value.
2026-11-03 01:07:02 -06:00
Brues 14ae659f2a Swing timer: bars fill from duration objects, drop the OnUpdate
Each bar fills itself from a duration object of the swing, a text
binding counts it down, and the marker with its glows rides the fill's
edge. One C_Timer per bar ends the swing, runs the melee grace and
switches a hunter's reload to the deadzone. Colors update on the events
that change them, ACTIONBAR_UPDATE_STATE standing in for the per-tick
IsCurrentAction reconcile; a bar waiting past its grace hides on
STOP_AUTOATTACK or leaving combat. The three bar builders become one.

The Swing Timer throttle setting only paced the OnUpdate, so it goes.
2026-11-03 01:07:02 -06:00
Brues 9187155ea6 Cast bar: the tradeskill spark rides a timer-driven fill, drop the OnUpdate
The per-craft spark of a merged tradeskill chain sits on the edge of an
invisible status bar that fills from cb.craft (ClassicAPI v1.19.1), so
nothing moves it by hand each frame.
2026-11-03 01:07:02 -06:00
Brues 465e87d7d2 Energy tick: the spark rides a timer-driven fill, drop the OnUpdate
The tick frame is a status bar whose invisible fill sweeps each period
from a duration object, with the spark anchored to the fill's edge
(ClassicAPI v1.19.1). A timer at each period's end rolls the sweep over
by whole periods, paused while hidden and caught up as it shows. The
five-second rule ends on its own timer, and the spark's alpha and the
rule bar update on the events that change them. Full mana now hides the
frame on every event, not just on a power update.
2026-11-03 01:07:02 -06:00
Brues 1abeafcec2 Action bars: range and usable state from ClassicAPI events, drop the range ticker
Shown buttons on bars 1-10 enable C_ActionBar.EnableActionRangeCheck for
their slot and take ACTION_RANGE_CHECK_UPDATE; hiding a bar or paging
releases the old slot. ACTION_USABLE_CHANGED refreshes only the changed
slots; ACTIONBAR_UPDATE_USABLE is left to the stance buttons. Requires
ClassicAPI v1.19.1.
2026-11-03 01:07:02 -06:00
Brues cde16e7fbe Action bars: route events to narrow passes, drop the OnUpdate
The pfActionBar frame ran an OnUpdate every frame and fully rebuilt all 140
buttons on events that only touch one part of them.

- Events go where the stock 1.12 bars send them: page and bonus-bar changes
  to the main bar's pager only, UPDATE_BINDINGS to the keybind text only,
  combat, auto repeat and tradeskill events to the active-border pass, and
  aura/form changes to the stance buttons that exist. Full rebuilds are left
  for entering the world, slot changes and the drag grid.
- Keybind text is read once per binding change from a fixed per-button
  command, no longer formatted and gsub'd on every slot update.
- Updates flush on the next frame through RunNextFrame instead of a 40 Hz
  OnUpdate; range is polled on a C_Timer ticker only while glowrange is on.
- Passes check visibility once per bar and walk only its shown buttons; a bar
  refreshes its buttons from OnShow, replacing the polled stale catch-up.
  Range no longer checks the buttons of disabled bars.
- Cooldowns skip CooldownFrame_SetTimer when start/duration/enable are
  unchanged; the active border only touches widgets when its state changes,
  and the "statechange" animation now follows every state change.
- PET_BAR_UPDATE only shows or hides the pet bar instead of re-running its
  whole layout; unlock mode is hooked instead of polled.
- Stance and pet buttons no longer inherit the previous button's oom tint.

pfUI.bars.update is replaced by pfUI.bars.QueueSlot(slot).
2026-11-03 01:07:02 -06:00
Brues a376afb2d7 UI scale: size borders from the scale the game applies, mirror its options
GetPerfectPixel divided by the uiScale option, or by 1 while useUiScale was
off, though the game's automatic scale is never under 0.9, so default
borders came out about a tenth of a pixel thin. The game scales UIParent
only after add-ons and saved variables load, so the pixel now comes from
GetPhysicalScreenSize and the scale the game is about to apply, worked out
from the same options and rules as OnDisplaySizeChanged. UI_SCALE_CHANGED
offers a reload once when the pixel size changes.

The preset dropdown and the pixelperfect module go: its presets were pixel
perfect only at 1080p and its restore path never ran. The settings show the
game's own Use UI-Scale and UI-Scale options, plus a Pixel Perfect UI-Scale
checkbox (one UI unit per screen pixel, kept through window resizes) that
overrides them. The pixel perfect border and HiDPI options go too; border
sizes now count real pixels. CVAR settings rows write their option through
their own config instead of this:GetParent(), which a dropdown's menu
button is not. The first-run slider stops at 0.64, below which the game
drops uiScale for its automatic scale.
2026-11-03 01:07:02 -06:00
Brues c8cc7bde79 Frame sizes: measure anchor-sized regions with the unscaled getters
GetWidth/GetHeight return an anchor-sized region's size times its effective
scale, so at any UI scale but 1 they disagreed with the sizes and offsets
built from them. The craft spark, raid-marker name shortening, unit frame
indicators, dropdown widening and the cooldown font's first size now read
GetUnscaledWidth/GetUnscaledHeight. The combat log and the settings rows
drop their GetRight()-GetLeft() workarounds for the same bug.
2026-11-03 01:07:02 -06:00
Brues d7e732981b Timer bars: buffwatch, loot roll, infobox and five-second rule drain from duration objects
Each bar hands its fill to StatusBar:SetTimerDuration instead of a per-frame
SetValue. Buffwatch's time text moves to a duration text binding holding the
cooldown formatter, now exposed as GetTimeFormatter (replacing
GetColoredTimeString, whose only caller this was). The five-second rule's
overlay style becomes a color-filled StatusBar too, so both styles share one
path; energytick's OnUpdate keeps only the tick spark.
2026-11-03 01:07:02 -06:00
Brues 2909679d62 Cast bars: fill and count down from duration objects, drop the OnUpdate sweeps
Player/target/focus bars and nameplate castbars hand their fill to
StatusBar:SetTimerDuration and their timer text to a duration text binding.
Pushback re-reads UnitCastingDuration/UnitChannelDuration; a C_Timer clears a
bar whose STOP never arrives. The nameplate castbar throttle is obsolete and
goes with its settings page.
2026-11-03 01:07:02 -06:00
Brues 2a6bddd756 DPSMate dock: find DPSMate by its globals and its first window by settings
The hook gated on an addon folder named exactly DPSMate and a first
window named DPSMate, so repacks under other folder names and renamed
windows never docked (#77). It now waits on login, checks DPSMate's
globals, resolves the first window from DPSMateSettings on every call,
and re-docks after DPSMate rebuilds its frames.
2026-11-02 23:14:27 -06:00
Brues 893524174c Equipment manager: close the slot flyout with the character frame
PopoutsActive checked IsShown, which stays true on the paperdoll and the
sidecar when only CharacterFrame hides. Check IsVisible instead.
2026-11-02 20:08:32 -06:00
Brues 001e09c1b7 Pick cooldown timers per feature with one dropdown
Each feature's settings page now picks its own timers - None, Numbers,
Sweep, or Numbers And Sweep - in place of the "Show Numbers On", "Show
Sweep On" and "Reverse Sweep On" lists on Settings -> Cooldown. Unit
frames get theirs per frame again ("Buff And Debuff Timers" and
"Indicator Timers"), so party and pet can drop their numbers while the
target keeps them. The other dropdowns sit on Action Bars, Bags & Bank,
Buff/Debuff Icons, Totem Icons, Tooltip and Nameplates.

Settings -> Cooldown keeps the shared font, size, threshold, tenths and
colors, plus the timers of Spellbook And Character, Loss Of Control and
Other Addons, which have no page of their own.

CreateCooldown(parent, kind, config, key, name) reads its mode from
config[key]. The kind says only what it times: "spell" hides numbers on
the global cooldown, "aura" drains its sweep, "timer" fills it. The
reverse option is gone; the direction follows the kind.

The migration carries every old setting into its timers: the
C.cooldown kind tables, appearance.cd's foreign and Blizzard toggles,
the buff frame's sweep, the nameplate debuff options, and each unit
frame's timer text, sweep and "Show Time Left" from before the kinds,
so frames that had their own settings keep them. Reverse options are
dropped.
2026-11-02 16:07:41 -06:00
Brues 494f176f18 Nameplates: stay in the world stratum, raise the target by level
The overlay inherits the engine plate's world stratum, below every UI
stratum. Moving it to BACKGROUND/LOW put it level-for-level against the
chat panels, so plates drew over the chat. The target now rises above
the other plates by raising its engine frame and re-parenting the
overlay, which carries the subtree's levels along. Debuff icons take
their level from the health bar so ones grown on a raised plate stay
above it.
2026-11-02 01:36:06 -06:00
Brues 23d25c4791 Focus target: follow its token, not its GUID
The focus target frame filtered its unit events on the unit's GUID, which
only arrive while nampower fires its raw-GUID events (NP_EnableUnitEventsGuid
on, NP_EnableUnitEventsGuidFiltering off) and SuperWoW watches every unit.
Without them the bars froze until the focus switched targets (#76).

ClassicAPI fires the focus target's unit events as "focustarget" and the
focus's UNIT_TARGET as "focus" whatever nampower does, so the frame follows
those tokens. The swap check keeps its own GUID cache, since eventunit is
no longer a GUID for that frame.
2026-11-02 01:06:17 -06:00
Brues ebb4b056c3 Nameplates: drive every plate from unit events, drop the per-tick loop
The module polled: a central OnUpdate at 100 Hz over every visible plate,
a full OnDataChanged refresh of each plate every 0.5 s, and per-tick reads
of the engine's name/level regions, frame size, mouse state and
SpellIsTargeting. ClassicAPI feeds every unit event to the nameplateN
tokens, so none of that is needed.

Each bound plate now registers its unit events on its own frame against
its token (UNIT_HEALTH/MAXHEALTH, UNIT_AURA_DELTA, UNIT_FLAGS,
UNIT_DYNAMIC_FLAGS, UNIT_FACTION, UNIT_LEVEL, UNIT_CLASSIFICATION_CHANGED,
UNIT_NAME_UPDATE, UNIT_TARGET, the casts) and each handler updates only
what that event can change; the module-level events (target, combat,
level-up, roster, guild, spell targeting) fan out to the plates they
concern. Health comes from UnitHealth on the token instead of the
engine bar's OnValueChanged hook; name, level and difficulty colour from
UnitName/UnitLevel/GetDifficultyColor instead of the blanked engine
regions (UnitLevel's -1 is exactly the engine's skull case, so "??B"
survives). The engine resets the plate's size at every bind, so the
engine frame's size and click routing are re-applied from its OnShow
instead of being checked every tick; the overlay steps aside for
ground-target spells on CURRENT_SPELL_CAST_CHANGED.

The only OnUpdate left is a driver frame, shown while a castbar sweeps or
the target zoom animates and hidden when both sets are empty; the zoom
is time-based now rather than per-tick multiplication. The
nameplates/nameplates_target/nameplates_mass throttle categories no
longer mean anything and are gone from libthrottle and the GUI;
nameplates_castbar stays as the sweep rate of non-target castbars.

Mouseover tracking is gone (the token already names the unit), and
libhealth's "known" return now decides whether absolute health is shown,
so a unit whose health is only known as a percentage no longer prints
"57 | 57%".
2026-11-01 21:40:50 -06:00
Brues 8b239a5532 Castbars: hide idle bars instead of fading them to alpha 0
An idle bar stayed shown at alpha 0, so its OnUpdate ran every frame. The fade-out now ends in Hide, a cast shows the bar, and unlock mode keeps it shown for dragging.
2026-11-01 20:44:24 -06:00
Brues 698dedcb7a Chat: cut the per-line work of the AddMessage hook
- Save the chat history from the frames when leaving the world, through
  GetMessageInfo, instead of on every line. Lines written back from the
  history carry a mark, so they are saved as they are. History is no longer
  recorded while it is off, keeps 30 lines instead of 29, and whispers are
  dimmed in the whisper colour (gsub's match count was taken as red).
- Skip the CLINK and URL passes on lines that cannot hold them.
- Colour player links in one gsub with a callback instead of a gsub per name.
- Read a chat line that several frames show only once, by its line ID.
- Build the timestamp once per second.
- Lay the tabs out on hover only when their bar comes back, not 10 times a
  second.
- Drop ChatFrame_OnUpdate: it only blinks the flash of the bottom button
  pfUI hides. The lines fade in the engine's update.
2026-11-01 19:59:53 -06:00
AbyssandBrues e609809fff Raid unitframes: add option to reverse group order (#75)
* Add raidreverse default to unitframes config

Defaults to off, so existing layouts are unchanged.

* Raid frames: add option to reverse group order

Read the new raidreverse setting and mirror the column index when placing raid frames, so group 1 sits on the far right and the following groups grow to the left.

* Add "Reverse Group Order" checkbox to raid settings

Placed under "Raid Fill Direction" in the raid frame options.
/pfui > Settings > Unit Frames > Raid > Layout

* Raid frames: rename reverse option to "Grow Right To Left"

The option mirrors columns in both fill directions, so name it for what
it does. Mirror across the columns maxraid can fill instead of the whole
layout, so smaller raids stay next to the anchor. Lay the raid grid out
through SlotToCoord like the pet grid, move the default next to the other
raid layout keys, and add the label to the locale tables.

---------

Co-authored-by: Brues <5278969+brues-code@users.noreply.github.com>
2026-11-01 18:02:31 -06:00
Brues 3651341697 Scroll every chat copy box to the newest line when it opens
The caret at the end scrolled only the box with the focus, and each
visible chat frame's box takes the focus as it opens, so only the last
one shown reached the bottom. Even that one stopped short: 1.12's
OnCursorChanged has no input context, so ScrollCursorIntoView lets the
last line clip.

Each box now measures its scroll box and scrolls it to the end on the
next frame, after the edit box has laid the new text out.
2026-11-01 17:22:06 -06:00
Antoine ChedinandBrues 77be27094a Add Offsets to unit frame buff/debuff (#74)
* Add anchor offset for unitframe buff or defuff

* Fix default values

* Stack a shared-corner aura block past the other block's Y offset, read the offsets without a table per icon

---------

Co-authored-by: Brues <5278969+brues-code@users.noreply.github.com>
2026-11-01 16:39:48 -06:00
Brues 5476a28982 Skin menu dividers: CreateMenuDivider draws a 1px border-colored line; use it in the radar menu 2026-10-31 21:04:11 -05:00
Brues 987c244591 Load only the client's locale strings; abbreviate numbers through ClassicAPI's numeric formatter; build the module environment once instead of on every load 2026-10-31 20:01:05 -05:00
Brues 14a26b8301 Replace saved-handler wrappers with HookScript; use intrinsic pre/postcall bindings for barbershop and SetHighlight 2026-10-31 19:47:41 -05:00
Brues b2e89b461c Hook OnClick/OnEnter/OnLeave instead of wrapping saved handlers; drop dead TBC bank-slot OnUpdate 2026-10-31 19:40:51 -05:00
Brues 907d282a68 Centralize cooldown setup and settings
Every pfUI cooldown is now made by CreateCooldown(parent, kind) in the
new api/cooldown.lua, which replaces the cooldown module. A kind names
what the cooldown times: actionbar, bags, blizzard (spellbook and
character), unitframe, indicator, nameplate, buff, tooltip, totem or
lossofcontrol. The pfCooldownType, pfCooldownStyleText,
pfCooldownStyleAnimation and pfCooldownSize fields are gone. The new
file owns everything the cooldowns share:
- the numbers' font and size
- the formatter
- each kind's numbers, sweep and sweep direction
- the GCD threshold for spell kinds
- the CooldownFrame_SetTimer hook for other addons' Cooldown frames
UpdateCooldowns applies changed settings to every cooldown at once.
GetAuraTimer moves here from the unit frames.

All settings live in one C.cooldown table, on one page: Settings ->
Cooldown. It has the shared font, size, threshold, tenths and colors,
then "Show Numbers On", "Show Sweep On" and "Reverse Sweep On" lists
with a checkbox per kind. The per-module options are removed:
- each unit frame's timer text, animation and reverse, and the
  indicators' "Show Time Left"
- the nameplate debuff timer options
- the Blizzard and foreign font sizes and toggles
- Action Bars' cooldown text size
- the reverse options of bars, bags, buffs and totems
The old appearance.cd settings are not migrated.

The player buff frame and the tooltip aura icons now show the native
countdown too, which replaces their own text and OnUpdate ticking. The
buff frame keeps its inside or below-the-icon placement. Weapon
enchants report only their time left, so they start through
SetCooldownTimeLeft: numbers, no sweep. A slim poll remains for their
charges and renewals, since no event reports those. Buff indicators
now take the aura's real duration, which gives them a correct sweep.
The spellbook and character slots now hide GCD numbers like the other
spell cooldowns.
2026-10-31 19:17:14 -05:00
Brues 93ab07a662 Show cooldown text through ClassicAPI's native countdown
The cooldown module no longer builds its own text frame with a 10 Hz
OnUpdate per cooldown. The CooldownFrame_SetTimer hook now configures
each Cooldown frame's own countdown instead: SetHideCountdownNumbers
for the per-frame text toggles and omnicc's noCooldownCount,
SetMinimumCountdownDuration for the GCD threshold, and
GetCountdownFontString for the pfUI font and size. The engine ticks
the numbers, gated by the countdownForCooldowns cvar. The cvar gets a
checkbox in the Cooldown settings, and pfUI.SetupCVars turns it on.

The text comes from one shared C_StringUtil numeric rule formatter,
given to each frame with SetCountdownFormatter. Its breakpoints keep
pfUI's format: the number in its unit's cooldown color, a unit (m/h/d)
once the unit below passes 99, and tenths in the low color when
milliseconds are on. Values now round up. GetColoredTimeString formats
through the same formatter, so the buff, buffwatch and tooltip timers
match. A config:changed callback rebuilds the breakpoints, and every
frame picks them up on its next update.

The paper-doll slots swap their indicator Models for Cooldown frames,
as the spellbook and bags already do. They and the spellbook take the
BLIZZARD tag when they are created, replacing the per-update hooks in
the skin module. Models get no numbers. Hide Foreign Cooldown
Animations clears the draw flags instead of setting alpha to 0, so the
numbers stay visible. The buff module's sweep hides its numbers
because buff.timer carries the text.
2026-10-31 18:45:17 -05:00
Brues 84da90c7d4 Run the raid and questitem delay timers on C_Timer
Both modules waited out their delays in an OnUpdate script. Each now
keeps one C_Timer.NewTimer handle and cancels it whenever a new request
comes in, so the update runs 0.5 s after the last one.

Raid: the roster pass becomes pfUI.uf.raid:UpdateRoster, and
pfUI.uf.raid:QueueUpdate schedules it. Roster events queue it with a
0.5 s delay; a config change or a tank toggle queues it for the next
frame. The frame no longer shows and hides itself to run the pass, and
the extra 1 s throttle is gone because the debounce already merges
bursts.

Questitem: without the OnUpdate script the scanner frame only handled
events, so it moves onto pfUI.events with one callback per event, and
pfUI.questitem becomes a plain table. The showquest check now lives in
QueueSeed.
2026-10-31 17:25:44 -05:00
Brues d2cefe69cf Add a DBM-style range radar for party and raid members
/radar toggles it and /radar <yards> sets the range; the right-click
menu and the mouse wheel step through 5-40 yd. The map turns with
GetPlayerFacing so ahead is up, and ClassicAPI.UnitPosition places
class-colored dots (the mirrored name, since SuperWoW takes the global
with x, y, z order).

The range ring is two stacked TempPortraitAlphaMask discs: a ring-color
disc under a slightly smaller background-color one. It turns red when a
member is inside the range, and a list under the radar shows the five
nearest with their raid markers inline. Raid markers come from the
markN tokens, so marked mobs show too and a marked member shows the
marker instead of a dot.

Units behind terrain (UnitInLineOfSight, traced 4x a second) are
dimmed. Units on another floor, over 5 yd up or down and steeper than
45 degrees so hills don't count, get an arrow above or below them.
Hovering a blip shows its name, distance and both states; clicking a
blip or a list row targets it.
2026-10-31 17:17:35 -05:00
Brues 2b7febf617 Replace pfUI's clamp/isempty/modf with ClassicAPI's Clamp/TableIsEmpty
The world map's shift/ctrl wheel alpha and scale use Clamp, and the
fresh-install profile check uses TableIsEmpty (pfUI_init and pfUI_config
are always tables by then). modf only wrapped math.modf and had no callers.
2026-10-31 15:47:52 -05:00
Brues 3b64bfa98b Show the target LoS indicator through ClassicAPI's UnitInLineOfSight
The indicator moves from the unitxp module to the target frame, so it no
longer needs UnitXP_SP3. Its checkbox and the shared font size move to a
Target Indicators header; unitxp_font_size becomes indicator_font_size.
The unused pfUI.api.UnitInLineOfSight wrapper, which shadowed the
ClassicAPI global inside the pfUI environment, is removed.
2026-10-31 15:41:15 -05:00
Brues 217b00e9a4 Use ClassicAPI.strsplit for pfUI's strsplit 2026-10-31 15:33:13 -05:00
Brues b6a41e70ec Switch action bar pages and shift-drag on MODIFIER_STATE_CHANGED 2026-10-31 15:16:28 -05:00
Brues e43ddd31fd Read nameplate units directly instead of scanning by name 2026-10-31 15:08:39 -05:00
Brues f81ea09d1c Choose 3D, 2D or round/square class icon portraits 2026-10-31 14:43:43 -05:00
Brues 78d4e0a56e Run the Turtle WoW setup with RunNextFrame and hook the map once
The one-shot OnUpdate frame becomes RunNextFrame. Its call into the map loader ran with the delay frame as this, so the loader's hooked flag sat on a different frame than on PLAYER_ENTERING_WORLD and the map hooks went on twice: shift and ctrl mouse wheel changed alpha and scale by two steps. The flag is now a local of the module.
2026-10-31 14:28:01 -05:00
Brues caf7112651 Scan chat bubbles once per frame with DirtiableMixin
Each chat message queued its own scan for the next frame, so a busy frame scanned the same bubbles several times. MarkDirty runs one scan for all of that frame's messages.
2026-10-31 14:28:01 -05:00
Brues e5a78c8d54 Animate unit frame bars with ClassicAPI's SmoothStatusBarMixin
Health and power bars take SmoothStatusBarMixin instead of pfUI's own OnUpdate animation, so the animation no longer runs faster at higher frame rates. The speed dropdown becomes an on/off checkbox, since the mixin's rate is fixed. A new range keeps the bar's filled share, so it doesn't jump before the animation moves on.
2026-10-31 14:20:20 -05:00
Brues 43f90751d6 Clear AFK when a holiday scene is clicked 2026-10-31 13:45:35 -05:00
Brues f90279e003 Drive the haste and spell power text from events
Replace the 0.25s ticker with UNIT_SPELL_HASTE for haste and
PLAYER_DAMAGE_DONE_MODS for spell power, which fires on the
MOD_DAMAGE_DONE fields GetSpellBonusDamage reads.
2026-10-31 13:27:48 -05:00
Brues 17fe9f0dd9 Drive the mounted trigger from PLAYER_MOUNT_DISPLAY_CHANGED
IsMounted reads the mount display field, which this event watches. The trigger listened to UNIT_AURA_DELTA, which can fire before that field updates and only worked because the switch waits half a second. UNIT_AURA_DELTA still drives the stealth and dining triggers.
2026-10-31 13:20:03 -05:00
Brues 54e66fea11 Drive range, offline, aggro and combat state from events
Every unit frame re-checked its range fade, offline state, combat and
aggro glow and indicator icons on a 0.2-0.5s tick, and infight polled
aggro every 0.3s. Each now comes from an event.

Aggro: the 270-token scan and its cache are gone. UNIT_TARGET fires for
every unit in view (SuperWoW registers them all), so a table of which
hostile unit attacks which friendly one, by GUID, follows every attacker,
including ones no token reaches. A unit that comes into view mid-fight
is noted when a token first reaches it (target, focus, mouseover, a
nameplate, a member's target). A read drops attackers that left view,
where nothing fires, and a loading screen resets the table. Changes go
out as "aggro:changed" with the old and the new victim, so only the
frames showing those redraw; infight listens too.

Combat square and glow follow UNIT_FLAGS. Range fade follows ClassicAPI's
UNIT_IN_RANGE_UPDATE, registered only by frames that fade, by GUID for a
chained unit; with the 40y check off, frames fade by sight through
UNIT_DISTANCE_CHECK_UPDATE, which also swaps a portrait's question mark
for the model. A UnitXP threshold has no event and keeps its poll.
UNIT_CONNECTION refreshes a member who goes offline or comes back; the
PARTY_MEMBER_ENABLE/DISABLE branches were never registered.

A full refresh now draws the indicator icons and combat state, so a new
unit brings its own. UNIT_FACTION redraws the PvP icon and reaction
colour; its "pvp" refresh step drew nothing. Unlock mode and /pftest
re-apply the fade on entry and exit.

What stays on the tick: the pet frames and the UnitXP range check.
2026-10-31 13:10:46 -05:00
Brues 480889cb05 Drive power from UNIT_POWER_UPDATE and UNIT_MAXPOWER
1.12's UNIT_MANA, UNIT_RAGE and the rest fire for every power a unit
has, not only the one it shows, so a druid in cat or bear form redrew
every frame showing them, health colours and texts included, on each
mana tick. ClassicAPI's generic power events name the power in arg2.

Unit frames register them on their own token and redraw only for the
power their bar shows, or for mana under a druid mana bar. They fire
for tokens only, so the GUID-followed target-of-X frames keep the
per-type events; those now share one list with UNIT_AURA, so a frame
swaps auras and power on the same check.

energytick counts gains on the power it tracks alone, so a cat druid's
mana regen is no longer read as energy. It forgets the power while
hidden, so a bear's mana ticks are not measured against rage, and
re-baselines on a shift, so leaving cat form is not a fake mana gain.

The equipment manager's dining trigger wakes on mana changes only.
2026-10-31 11:55:54 -05:00
Brues b6f58b0e04 Drive auras from UNIT_AURA_DELTA
UNIT_AURA says nothing about what changed and stays silent when a buff
is refreshed or its duration packet lands, so a recast HoT kept its old
timer until something else rebuilt the row. UNIT_AURA_DELTA reports
added, updated and removed aura instances, refreshes included.

Unit frames register it on their own token. An add, a removal or a full
update rebuilds the auras as before; an update-only delta re-reads the
slot behind each shown icon for its stacks and timer and redraws the
buff indicators, without a relayout or a dispel scan. Frames that
follow a GUID (the target-of-X chain) stay on UNIT_AURA, since the
delta only fires for tokens. A finished aura layout announces itself
as "unitframe:auras".

buffwatch drops its 0.4s rescan: bars rebuild on the delta, on login
and on a target change, and a timer wakes the frame when the next aura
crosses the bar threshold. Bars re-anchor when the player or target
frame lays out its aura rows, and a whitelist or blacklist click
applies at once.

Nameplates, the loss of control alert and the equipment manager's
mount/stealth/dining check listen to the delta as well.
2026-10-31 11:32:47 -05:00
Brues cc5c562516 Rebuild the unit tooltip when its unit retargets
pfUI's unit lines -- target, guild, colours, speed, unit id, the buff
row -- were added once from OnShow, so the target line went stale while
hovering, and any SetUnit on a shown tooltip wiped them. They now go on
from OnTooltipSetUnit, every time a unit is set.

While a unit tooltip is up it listens for UNIT_TARGET on the unit's
GUID and re-sets the unit a frame later, through the token the tooltip
was built from: "mouseover" stops naming the unit once the cursor
leaves, so a fading tooltip is left to fade. Item and spell ids stay on
OnShow.
2026-10-31 06:36:42 -05:00
Brues a9542bd467 Follow target-of-target frames with UNIT_TARGET
A frame whose unit is another unit's target (targettarget,
targettargettarget, pettarget, focustarget, partyNtarget) has no token
that unit events name, so it polled: bars every 0.2s, a full aura and
portrait rescan every second, and a GUID compare to notice swaps.

Such a frame now registers its unit events by the unit's GUID, which
every unit event also fires with, and UNIT_TARGET by the GUID of every
link of its chain. A link retargeting re-points the frame at once and
queues one full refresh; the ticks are gone. The 0.2s visibility timer
stays for them, since nothing reports a unit going out of sight.

Nameplates register UNIT_TARGET on their own token, so a mob turning to
someone else recolours its combat state immediately instead of after
the colour cache and data tick run out.

Drop pfScanActive and the namebuf delay: both guarded against the old
target-swapping range scan, which no longer exists. focus.lua's
instantRefresh was never read.
2026-10-31 06:27:21 -05:00
Brues 113ff257cf CHAT_MSG_BN_WHISPER and RAID_INSTANCE_WELCOME are not valid events 2026-10-31 03:12:33 -05:00
Brues 07e315cd86 Toggle the item comparison live with shift
The comparison read IsShiftKeyDown() only when the tooltip was set, so
pressing or releasing shift while hovering did nothing until the next
hover. Each hooked tooltip now remembers the item it shows, dropped on
OnTooltipCleared and OnHide, and MODIFIER_STATE_CHANGED shows or hides
its comparison right away, as on retail.

Merchant and auction comparisons show regardless of shift and never
store a link, so shift leaves them up.
2026-10-31 03:05:56 -05:00