78 Commits

Author SHA1 Message Date
Brues c994d00596 Toggle bagslots visibility via SetShown
Replace explicit if/else calling :Hide()/:Show() with :SetShown(not IsShown())
2026-07-31 13:22:17 -05:00
Brues 4be680183a Use GetSize/SetSize for size operations
Replace separate GetWidth/GetHeight and SetWidth/SetHeight calls with GetSize/SetSize for consistency and brevity. Updated modules: addonbuttons (store size via GetSize), chatcopy (use SetSize), easteregg (use SetSize for explosions), farmmode (use GetSize/SetSize when adjusting map size), and game_menu (use GetSize/SetSize when resizing frame).
2026-07-30 14:29:30 -05:00
Brues 2352f1c6ed Use GetSize/SetSize for map frame and buttons
Replace separate GetWidth/GetHeight and SetWidth/SetHeight calls with GetSize and SetSize in modules/map.lua.
2026-07-30 14:11:34 -05:00
Brues 305ff6c86e Collapse frameState.hasTarget into targetGuid
hasTarget was always snapshotted alongside targetGuid (UnitExists("target")
next to UnitGUID("target")), so it was just targetGuid ~= nil. Drop the
field and derive it from targetGuid at both read sites; remove the now-unused
UnitExists perf-cache local.
2026-07-30 13:45:53 -05:00
Brues a8b131898b Event-drive nameplate target state; drop per-tick poll and targetPlateGuid
frameState.hasTarget/targetGuid were polled via UnitExists("target") every
central-loop tick, while targetPlateGuid held the same guid but was already
event-driven -- redundant. Set frameState target fields in PLAYER_TARGET_CHANGED
(seeded on PLAYER_ENTERING_WORLD for a target held across reload), remove the
poll, and collapse targetPlateGuid into frameState.targetGuid (the castbar
frame now reads that). The central loop's only remaining per-tick poll is
GetTime().
2026-07-30 11:59:56 -05:00
Brues 1f9be33772 Use GetStringColorObject for buffbar colors; numeric border check
Store the buffbar color/bordercolor/textcolor as cached read-only ColorMixins
via GetStringColorObject instead of building per-bar {r,g,b,a} tables from
GetStringColor. These color tables are only ever read (SetStatusBarColor /
SetTextColor / the border check), so sharing the cached objects is safe and
drops the intermediate locals and per-bar allocations.

GetStringColorObject's components are numbers, so fix CreateBuffBarFrame's
border check from ~= "0" (string) to ~= 0.
2026-07-30 02:44:56 -05:00
Brues a798e67b7f Use GetStringColor for buffbar color parsing
Route the three buffbar color config splits through GetStringColor (cached)
instead of bare strsplit. GetStringColor returns strings, so this is
behavior-preserving -- including the bordercolor ~= "0" check in
CreateBuffBarFrame -- and just adds the shared color cache and consistency
with the rest of the codebase.
2026-07-30 02:39:56 -05:00
Brues 8b87e30266 Revert GetStringColor to strings; keep object numeric; tidy cmatch
- GetStringColor returns strings again (its lifelong contract). The earlier
  numeric conversion was a return-type change that could break any caller
  doing string comparisons on components (e.g. buffwatch's `~= "0"`); every
  caller was written against strings and color setters coerce, so reverting
  is the safe fix without a codebase-wide audit.
- GetStringColorObject now tonumbers its own inputs, so its ColorMixin stays
  numerically correct (GenerateHexColor/IsEqualTo) independent of the above.
- cmatch: move its a-e / va-ve / ra-re scratch out of module scope into clear
  function-locals (idx*/val*/out*). Strict 1:1 rename, logic unchanged; also
  drops the shared-upvalue reentrancy concern.
2026-07-30 02:39:16 -05:00
Brues f68b14e53b Use SetSize instead of SetWidth/SetHeight
Replaced numerous SetWidth/SetHeight calls with SetSize for consistency and brevity across UI code. Touched api/ui-widgets.lua, api/unitframes.lua and multiple modules (actionbar, addonbuttons, addons, afkcam, autovendor, bags, bgscore, buff, buffwatch, nameplates). Also simplified some sizing math in buff module. No functional behavior intended to change — code modernization only.
2026-07-30 02:27:03 -05:00
Brues 8ab6fab04f Event-drive nameplate mouseover via UPDATE_MOUSEOVER_UNIT
ClassicAPI polyfills UPDATE_MOUSEOVER_UNIT to fire on mouseover loss as well
as gain (src/unit/Mouseover.cpp), so the per-tick UnitGUID("mouseover") poll
in the central loop is no longer needed. Update frameState.mouseoverGuid on
the event and flag just the plates losing/gaining hover (via plateByGuid,
which holds overlays) for an immediate refresh.
2026-07-30 02:01:10 -05:00
Brues 6d1bfe805e Use UnitClassBase for class detection 2026-07-30 01:26:29 -05:00
Brues 838f7f5d25 guard against nil units
UPDATE_MOUSEOVER_UNIT can fire when unit is dropped now so guard against that
2026-07-30 01:20:50 -05:00
Brues fad078fa87 Drop dead GUID-label branch in unit frame OnEnter
No unit frame ever has a GUID label -- CreateUnitFrame is only ever called
with fixed type names (Player/Target/Focus/Party/Raid/...), and .label is only
ever assigned those. The string.find(this.label, "^0x") branch was a leftover
from an older focus implementation; focus now uses the real "focus" unit
token, so OnEnter always resolves the mouseover via the normal unitstr path.
2026-07-30 01:09:53 -05:00
Brues 48d76138ed Iterate active nameplates only; fix global eventcache propagation
- The central OnUpdate looped the entire plate pool (registry) every tick with
  an IsVisible guard. Maintain a visiblePlates set via NAME_PLATE_UNIT_ADDED/
  _REMOVED and iterate that instead, so hidden pool slots aren't touched. The
  IsVisible guard stays as a safety net.
- Fix the global refresh propagation: it set .eventcache on the base frame,
  but OnUpdate reads/clears it on the overlay (nameplate) -- so the propagation
  was a no-op and global refreshes (e.g. target-change alpha/strata) fell
  through to the 0.5s catch-all timer. Set plate.nameplate.eventcache and scope
  to visiblePlates, so those refreshes land on the next tick as intended.

OnConfigChange still iterates the full registry (hidden plates must pick up
config changes before they next show).
2026-07-29 23:43:27 -05:00
Brues fe22dfc456 Detect nameplate mouseover by GUID compare, not Blizzard glow texture
Both mouseover checks relied on original.glow:IsShown() (a fragile proxy for
the hovered plate, on a Blizzard texture pfUI hides/restyles) gated by
UnitExists("mouseover"). Cache the engine mouseover unit's GUID once per
central-loop tick (frameState.mouseoverGuid) and have each plate compare its
cachedGuid against it.

More correct for the data path: the "mouseover" unit token is only chosen
for the plate whose GUID actually matches the engine's mouseover unit, so
overlapping plates can't double-match and paint the wrong unit's data. Also
cheaper -- one UnitGUID("mouseover") per tick plus a per-plate table compare,
versus the old per-plate IsShown gated on a per-tick UnitExists.
2026-07-29 16:57:25 -05:00
Brues 5eaab2784f Resolve target castbar plate via cached GUID, not per-frame lookup
The unthrottled target castbar frame called C_NamePlate.GetNamePlateForUnit
every frame. Stash the target's GUID on PLAYER_TARGET_CHANGED (seeded on
PLAYER_ENTERING_WORLD for a target held across reload) and resolve the plate
through plateByGuid instead -- a table lookup plus a real idle skip when
there's no target. The plate is looked up per frame (not cached) so a plate
spawning/despawning while the unit stays targeted still resolves correctly.
2026-07-29 16:36:29 -05:00
Brues f41d5ac6d0 Make nameplate castbars event-driven; unthrottle target bar
Previously every visible plate polled C_Spell.UnitCastingInfo each throttled
tick just to detect casts. Now cast state is event-driven:

- SPELL_START_OTHER (nampower) stamps a per-GUID castState cache (spellId,
  timing, channel flag from spellType); SPELL_FAILED_OTHER clears it; normal
  completion expires at endTime. GetCastInfo just reads the cache, so all
  call sites (castbar update, non-target detection, casting name-color) stop
  polling.
- plateByGuid routes events to plates in O(1) and bounds the cache to on-screen
  casters; NAME_PLATE_UNIT_ADDED seeds an already-casting unit with one poll.
- The vestigial nameplate.castUpdate flag now fires on cast start to bypass the
  throttle for an immediate bar.

With the poll gone, per-tick work is a cache read + SetValue, so the dedicated
target castbar frame now runs unthrottled (every frame) for the smoothest
sweep, and the non-target nameplates_castbar default rises 50 -> 100 FPS.

Known limits: other-unit cast pushback isn't reported by nampower, and a
mob-cancelled channel with no fail event lingers until endTime.
2026-07-29 16:29:12 -05:00
Brues af8780bb41 Use GetStringColor for newitem glow color
Replace CreateColor/Color:GetRGBA usage with pfUI.api.GetStringColor in modules/newitem.lua
2026-07-29 14:39:25 -05:00
Brues ea37f41db1 Check r[3] instead of table.getn in rgbhex
Replace table.getn(r) >= 3 with r[3] ~= nil in api/api.lua
2026-07-29 14:35:44 -05:00
Brues 6f36da7aa1 Cache and streamline color helpers in api
- GetStringColor: memoize via a metatable __index cache (single lookup on
  hits) and store numeric components so ColorMixin comparisons/arithmetic
  behave, not just setter coercion.
- GetStringColorObject: new accessor returning a cached, shared read-only
  ColorMixin for callers that want an object instead of raw values.
- rgbhex: memoize the markup keyed on the byte values that actually determine
  the output (Round(x*255)), so continuously-varying inputs like health
  gradients collapse onto a bounded set instead of leaking a cache entry per
  shade. Build misses via C_ColorUtil.GenerateTextColorCode on a plain table
  instead of allocating a throwaway ColorMixin. Fix a latent bug where the
  r/g/b/a temporaries were file-scoped, so a malformed input returned the
  previous call's color instead of an empty string.
2026-07-29 14:06:25 -05:00
Brues 149d5dd362 Scope tooltip cursor-follow to when shown; default it to smooth
The cursor-follow OnUpdate polled GetCursorPosition() 10x/second forever,
even with no tooltip visible. Rework it so the follower frame is created
once, hidden, and only shown while a tooltip is up -- an OnUpdate fires only
while its frame is shown, so the poll now runs solely during tooltip display.
Position the follower immediately on show to avoid a one-frame flash.

Also bump the tooltip_cursor throttle default from custom/10 FPS to the
fastest preset (50 FPS) so cursor tracking is smooth out of the box while
the Throttling tooltip knob stays available for low-end machines.
2026-07-29 11:42:18 -05:00
Brues 0156d9dfec Harden strsplit against third-party global clobbering
BigWigs (SpellRequests) redefines the global string:split to return a table,
and another addon clobbers the strsplit global too. pfUI.api.strsplit and the
bare strsplit callers inherited the broken versions depending on load order,
producing 'attempt to compare number with nil' from GetStringColor.

- Make pfUI.api.strsplit fully self-contained (no delegation to global
  strsplit / string.split), so no override can reach it.
- Optimize the hot path: single-char delimiters use plain-text find (no
  pattern compilation, no per-call char-class string); localize string.find
  and string.sub.
- Route the per-frame castbar/nameplate color splits through GetStringColor,
  which caches, instead of re-splitting a constant string every update.
2026-07-29 10:37:29 -05:00
Brues 6b945c2c97 buff min classicapi version to 1.8.2 2026-07-28 19:26:09 -05:00
Brues 452eef3864 Drop custom debuff durations from turtle-wow.lua
C_UnitAuras supplies Turtle-adjusted durations directly to the aura readers,
so the L["debuffs"] database fallback for these four custom debuffs is dead.
2026-07-28 13:29:11 -05:00
Brues 6f7a57f530 Restore UnitDebuff/UnitOwnDebuff as C_UnitAuras adapters
Third-party addons (e.g. pfUI-WeakIcons) still expect libdebuff's legacy
multi-return reader signature. Reimplement UnitDebuff/UnitOwnDebuff as thin
adapters over C_UnitAuras that remap AuraData onto:
  effect, rank, texture, stacks, dtype, duration, timeleft, caster

No GetUnitField slot mapping or ownDebuffs/allAuraCasts bookkeeping involved;
C_UnitAuras already resolves source and expiration. timeleft is gated on
duration > 0 to avoid stale expirationTime on permanent auras.
2026-07-28 10:48:42 -05:00
Brues a55460e543 Add reverse sort direction and priority options to bag sorter
libbagsort:Sort now accepts an opts table:
  - reverse: place the first-ranked item into the last slot of the last
    bag (junk fills from the opposite end)
  - reversePrio: flip the category ranking (e.g. hearthstone sorts last)

Wired to two new checkboxes under Bags & Bank, both defaulting off.
2026-07-27 18:15:07 -05:00
Brues 58aaeef5f0 can't have any fun 2026-07-27 17:17:56 -05:00
Brues 487af0c8f4 Use string.split instead of strsplit
Some users have addons that pollute the global namespace with a version of strsplit that doesn't match Blizzard's spec
Closes #31
2026-07-27 15:47:28 -05:00
Brues 00292ca3b4 Focus/Nameplates now respond solely to UNIT_* events
commit 70b1e66c2d
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sun Jul 26 18:30:18 2026 -0500

    Use SetSize/SetShown and simplify minimap/map

commit 7b6bfe9975
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 11:27:14 2026 -0500

    Include raidpet frames in /pftest test mode

    The unit-frame test toggle (showall) only previews frames that exist and
    are positioned. Raidpet frames are created when raidpet.visible == "1",
    but LayoutPets' collapse mode only positions pets whose raidpet<N> unit
    actually exists, so solo/in test mode they stayed hidden.

    Add a showall branch to LayoutPets that mirror-lays every pet cell and
    shows it (bypassing collapse and the roster gate), still guarded by the
    existing showpets check so nothing happens when raidpet is disabled. Call
    LayoutPets from the /pftest handler so the grid updates immediately on
    toggle-on and restores to the normal layout on toggle-off.

commit 4c65c38647
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 10:34:33 2026 -0500

    Remove unused RangeCache local in UnitInRange

commit 6c96bbbe6c
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 10:34:33 2026 -0500

    Use Clamp() for the two-sided clamps in ui-widgets

    Replace the hand-rolled math.min/math.max and if/elseif clamp idioms in the
    status bar and scroll frame with Clamp(). Equivalent for every value seen
    (min <= max always holds), just clearer.

commit 830e0a0be1
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 10:34:33 2026 -0500

    Drop vanilla GetItemInfo shim for C_Item.GetItemInfo

    The compat/vanilla.lua GetItemInfo override reshaped vanilla's tuple into
    retail order by inserting nil at slot 4 (itemLevel), but truncated at 8
    fields, dropping itemEquipLoc/itemTexture. ClassicAPI's global GetItemInfo
    keeps the vanilla shape (its hook only warms the item cache), so the shim
    stayed necessary but incomplete.

    Remove it and point the three callers at ClassicAPI's C_Item.GetItemInfo,
    which returns the full 18-field retail tuple. Positions 1-8 are identical
    to the old shim output, so bags/roll are unchanged; character.lua's
    itemSlot (equipLoc, field 9) was always nil under the truncating shim and
    now resolves correctly for ShaguScore.

commit c0da63657d
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 10:09:34 2026 -0500

    Various cleanup

    Removes version compatibility checks for TBC/Vanilla, consolidating code to target a single WoW version. Refactors repetitive SetWidth/SetHeight calls to SetSize for cleaner code. Removes duplicate function definitions from unitxp module and simplifies conditional show/hide operations using SetShown.

commit 11a6302c2d
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 09:53:37 2026 -0500

    Delegate pfUI.api.strsplit to ClassicAPI's strsplit

    Replace the Lua pattern-based implementation with a thin wrapper around
    ClassicAPI's C-level strsplit. Keeps the pfUI.api.strsplit entry point for
    backwards compatibility with addons that call it, while dropping the
    redundant reimplementation.

    Behavioral note: the old version used ([^delim]+) which silently collapsed
    empty fields; delegating to real strsplit now preserves them
    ("a,,b" -> "a", "", "b"). All in-repo callers split numeric color tuples,
    version strings, or build name-keyed lookup tables, none of which are
    affected by empty-field preservation.

commit 67c126eac8
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 01:01:02 2026 -0500

    Bump ClassicAPI minimum version to 1.8.0

commit a6cf157518
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 00:49:50 2026 -0500

    read spell rank via C_Spell.GetSpellSubtext

    The rank string comes from the spell subtext ("Rank N"), which ClassicAPI's
    C_Spell.GetSpellSubtext returns directly -- so drop nampower's
    GetSpellRecField(spellId, "rank") here. The existing "Rank " gsub parse is
    unchanged.

commit 4b1ba99b4f
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 00:33:20 2026 -0500

    Move player info overlay onto ClassicAPI (drop Nampower)

    The haste/spell-power overlay read both values through Nampower and disabled
    itself entirely without it. Move both to ClassicAPI so it works on any
    ClassicAPI client:

    - Spell power: GetSpellPower("net") (nampower) -> GetSpellBonusDamage(i)
      (ClassicAPI, same per-school field). Merged the build+scan into one loop;
      the default school seeds the tiebreak so equal schools still favor it.
    - Haste: GetUnitField("player", "modCastSpeed") -> UnitSpellHaste("player"),
      which returns the haste percentage directly (the (1/modCastSpeed-1)*100
      conversion is now baked in, off the same UNIT_MOD_CAST_SPEED field, signed).
    - Dropped the "if not GetUnitField then return" gate -- UpdateInfoText no
      longer touches Nampower, so the overlay runs everywhere.

commit 7df4aa6d50
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Sat Jul 25 00:32:44 2026 -0500

    Hook the real global _G.UnitHealth for feign death

    Inside a RegisterModule body, `function UnitHealth(...)` defines UnitHealth on
    the pfUI environment, not the real global -- so the feign-death real-HP fix
    only reached callers that resolve UnitHealth through pfUI's env, and missed
    _G consumers (Blizzard frames, other addons). Hook _G.UnitHealth explicitly
    (and capture oldUnitHealth from _G) so the un-gate applies everywhere.

commit b0bf2fd869
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Fri Jul 24 21:10:58 2026 -0500

    Refactor nampower module

    Simplify reactive spell storage by using spell IDs instead of texture/name tables. Update to use modern C_Spell APIs (GetSpellTexture, GetSpellName) instead of manual texture paths. Consolidate SetWidth/SetHeight calls to SetSize and use print() instead of DEFAULT_CHAT_FRAME:AddMessage().

commit 0b06961333
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Fri Jul 24 20:54:23 2026 -0500

    Use GetNamePlateForUnit for target lookups; drop dead ScanGuid block

    - Replace the three GetNamePlateForGUID(UnitGUID("target")) round-trips with
      GetNamePlateForUnit("target"), which resolves the token to a GUID internally
      -- no UnitGUID string detour, and it returns nil for no-target/no-plate so
      the UnitExists guards collapse. GetNamePlateForGUID is left for raw-GUID cases.
    - Remove the dead libunitscan.ScanGuid nameplate block (ScanGuid was deleted
      from libunitscan long ago, so the guard was never true) -- it carried the
      last GetUnitField("npcFlags") read.

commit 3e6210086e
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Fri Jul 24 20:54:23 2026 -0500

    Drop Nampower stats system and polling from unit frames

    GetUnitStats now reads health/power straight from UnitHealth/UnitPower
    (the descriptor fields the server broadcasts) -- for a real unit token
    GetUnitField read nothing different, so the whole Nampower-vs-fallback
    apparatus was measuring a distinction that no longer exists. Removed:

    - The stats system: pfUI.uf.stats, pfUIStatsFrame + UpdateStatsDisplay, the
      lastUnitStats change-cache, the /pfuistats slash command, and every counter
      increment (event/heartbeat/earlyReturn/throttledSkip/nampower/fallback).
    - All GetUnitField health reads (GetUnitStats, heal-prediction, health-gradient
      color) -- collapsed to the UnitHealth/UnitHealthMax they already fell back to.
    - The heartbeat-polling backstop and its fallbackThrottle/lastEventUpdate deps.
      Frames now refresh on events only; eventless frames still use their own tick,
      and range/aggro still run in the eventless-actions block.

commit 63001b7b0c
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Fri Jul 24 20:09:42 2026 -0500

    Move nameplates onto ClassicAPI stable nameplate tokens

    ClassicAPI now assigns retail-exact, per-plate-stable "nameplateN" tokens and
    fires vanilla UNIT_* events for them, so the nameplate module can key off the
    token instead of Nampower/SuperWoW GUID primitives:

    - Events: UNIT_AURA_GUID/UNIT_FLAGS_GUID -> UNIT_AURA/UNIT_FLAGS, matched by
      the "nameplateN" token (guarded on the token prefix, since these also fire
      for target/party/raid). Registered unconditionally -- no GetUnitField gate.
    - Health: GetUnitField(guid, "health"/"maxHealth") -> UnitHealth/UnitHealthMax
      on the plate's cached token. Same UNIT_FIELD_HEALTH the server broadcasts
      (real HP on Turtle; the ~= 100 scaled-vs-real guard is unchanged).
    - Combat/target in GetCombatStateColor: GetUnitField("flags") + HasFlag ->
      UnitAffectingCombat(token); GetUnitField("target") + SuperWoW "<guid>target"
      -> the "nameplateNtarget" chain. Dropped the now-dead HasFlag,
      UNIT_FLAG_IN_COMBAT, and guidTargetTokenCache.
    - GetCastInfo now takes the token directly; every caller already holds it, so
      the UnitTokenFromGUID(guid) round-trip is gone (unused module-wide now).

    NAME_PLATE_UNIT_ADDED caches the token as plate.nameplate.unit alongside the
    GUID; REMOVED clears both. GUID is retained only as the stable cache key
    (debuffCache/threatMemory/combatColorCache). Only GetUnitField("npcFlags")
    remains -- it has no token/vanilla equivalent.

commit ce1c49fcbb
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Fri Jul 24 18:20:06 2026 -0500

    Make focus/focustarget event-driven via ClassicAPI unit events

    ClassicAPI now fires UNIT_* (health/mana/aura/...) with arg1 == "focus" and
    arg1 == "focustarget", observed per-unit like target/party/raid. Both frames
    already registered those events (focus/focustarget are in pfValidUnits) and
    their OnEvent already matches arg1 == label, so the 0.2s polling ticks were
    pure workarounds for the missing events. Drop both ticks; the frames now
    refresh on-event like target, with range/glow still on the shared 0.5s state
    pass and PLAYER_FOCUS_CHANGED still driving assign/clear.
2026-07-26 18:32:36 -05:00
Brues cba3604906 Use UnitGUID instead of UnitExists for GUID
Replace the previous extended UnitExists GUID retrieval with UnitGUID and simplify the Nampower health lookup flow. Also minor whitespace/formatting cleanup.
2026-07-24 17:06:12 -05:00
Brues a31d10384b Read unit power from ClassicAPI instead of Nampower's GetUnitField
GetUnitStats parsed the power type out of the bytes0 descriptor field and
read each power slot via GetUnitField(guid, "powerN")/"maxPowerN", manually
dividing rage by 10. ClassicAPI's UnitPower/UnitPowerMax read the same
descriptor slots and apply the engine's own power-divisor table (rage /10,
happiness scaling), so:

  powerType = UnitPowerType(unitstr) or 0
  power = UnitPower(unitstr, powerType)
  maxPower = UnitPowerMax(unitstr, powerType)

is equivalent and drops nine GetUnitField calls plus the bytes0 parsing.
Power now resolves through the hard-dep ClassicAPI even without Nampower;
GetUnitField in this path is left only for health, which has no ClassicAPI
real-HP equivalent.
2026-07-24 17:01:09 -05:00
Brues f06af48bc2 nampower: Use SetSize, UnitClassBase and simplify icon logic
Replace SetWidth/SetHeight with SetSize for pfUI.spellqueue and reactive icons. Use UnitClassBase("player") to obtain the player's class token. Simplify reactive icon visibility by using SetShown and aggregating a single anyVisible flag, then calling SetShown on the parent frame. Minor readability and API modernization changes.
2026-07-24 16:49:35 -05:00
Brues d73c4de695 Modernize power-API usage onto ClassicAPI
- Replace all UnitMana/UnitManaMax calls with UnitPower/UnitPowerMax. The
  no-arg form returns the unit's primary power from the same field vanilla's
  UnitMana read, so these are behavior-preserving. Drops two dead
  UnitMana/UnitManaMax local caches in nameplates.lua.
- Replace magic power-type numbers (0/1/2/3) with Enum.PowerType.Mana/Rage/
  Focus/Energy in the GetUnitStats branches, the power-bar color block, the
  druid mana bar, GetStatusValue's powerdyn, and energytick's mode checks.
2026-07-24 16:37:34 -05:00
Brues dd8c529463 Move druid mana bar into the unit frame, off nampower
The druid secondary mana bar (shown while shapeshifted into a form that
uses energy/rage) lived in nampower.lua and read base mana through
nampower's GetUnitField. Extract it into the unit frame proper and drive
it with ClassicAPI instead:

- Create pfDruidMana_<unit> as f.druidmana in CreateUnitFrame (player and
  target), lay it out in UpdateConfig from the existing C.unitframes.druidmana*
  keys, and update it in a new pfUI.uf:UpdateDruidMana driven by the frame's
  own base-refresh pass (UNIT_MANA / UNIT_DISPLAYPOWER). No separate event
  frames, no nampower dependency.
- Read mana via UnitPower(unit, 0) / UnitPowerMax(unit, 0), the ClassicAPI
  slot getters that return the mana pool regardless of the active power, so
  it works while in Cat/Bear form.
- Add a "Show Druid Mana Bar Text" toggle (druidmanatext) so the current/max
  readout can be hidden while keeping the bar; config default, GUI checkbox,
  and locale stubs.
- Remove the now-dead block from nampower.lua.
2026-07-24 16:23:28 -05:00
Brues 47a7b4c686 Simplify totems frame sizing
Replace separate SetWidth/SetHeight calls with a single SetSize using precomputed 'thickness' and 'length' values. This refactors the totems layout math into clearer variables (thickness = iconsize + spacing*2, length = thickness * count) for horizontal and vertical directions, improving readability and maintainability without changing behavior.
2026-07-24 16:08:36 -05:00
Brues cf3f1e5440 Rework raid self/group frame visibility and rename the solo option
- selfinraid now gates on `not IsInGroup()`, so "show self in raid frames"
  applies only when truly solo (both party and raid suppress it), matching
  the option's actual behavior.
- Hide the redundant group frames when a party is promoted to the raid grid
  (raidforgroup + hide_in_raid), not just in an actual raid. A shared
  hide_group local drives both the party-member and self branches; the
  party-member branch is scoped to cache_raid == 0 so the raidforgroup-mapped
  raid frames (which themselves carry label "party") aren't hidden too.
- Rename "Always Show Self In Raid Frames" to "Show Self In Raid Frames When
  Solo" in gui.lua and all locale files; the four previously-translated
  strings are reset to nil stubs since the meaning changed.
2026-07-24 15:02:38 -05:00
Brues 182127bd67 Refactor totems to use CreateColor API
Replace manual color tables with CreateColor() function calls for better code consistency and API usage. Update tooltip color handling to use WHITE_FONT_COLOR:GetRGB() instead of hardcoded hex color codes. Rename 'slots' variable to 'slotColors' for clarity.
2026-07-24 15:00:16 -05:00
Brues 3d2e6e202b corrected rangecheck vanilla label 2026-07-24 14:14:46 -05:00
Brues 3a062ee2ac Recast Totem will now use the same rank totem 2026-07-24 10:00:22 -05:00
Brues 5ed1d98ecc Raid Pets and Optimized Chat Bubble Styling
commit f19d7402810637fc32460864104cb792ac5af863
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Wed Jul 22 01:05:52 2026 -0500

    remove comment

commit 60f4968f06d19d42bdc6347f98ff4d5a34785e97
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Wed Jul 22 01:05:06 2026 -0500

    Bump ClassicAPI minimum version to 10705

    Update the minimum required ClassicAPI version from 10704 (1.7.4) to 10705 (1.7.5).

commit 088dba4c23f4aa7ce98b9ce9d75bc5892cd40520
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Wed Jul 22 01:04:04 2026 -0500

    Add raid-pet frames: an independent, roster-driven pet grid

    New "raidpet" unitframe type that shows raid members' pets (raidpet1..40)
    in their own movable block (pfRaidPetCluster), off by default. It's a
    flat pool of frames laid out by pfUI.uf.raid:LayoutPets straight from the
    raid roster -- cell N shows raidpet<N> -- so it's fully decoupled from how
    the raid grid arranges its own slots.

    Layout is independent of the raid grid: raidpet carries its own
    width/height plus a Layout section (raidlayout / raidpadding / raidfill),
    and its own Collapse Empty Slots toggle that packs only the pets that
    exist into the leading cells. The raid grid gets the same collapse option
    (sequential slot assignment in AddUnitToGroup instead of by subgroup).
    Collapsed pets re-pack on roster changes and on UNIT_PET so summons and
    dismisses track live without polling.

    Also:
    - unitframes: a "raidpet" branch in UpdateVisibility (hide when the pet is
      out of range or its raid<N> owner is gone), and fix cache_raid so the
      "pfRaid" prefix check doesn't misread pfRaidPet<n> frames (char 7 is
      non-numeric -> nil compare crash).
    - New "Owner Name" text option: on any pet frame (raidpet/partypet/pet) it
      shows the owner's class-colored name so you can tell whose pet it is.
    - unlock: a pfRaidPet drag cluster, a numeric-suffix guard so pfRaid no
      longer matches (and crashes on) pet frames, and RaidPet config mappings.
    - config/gui/translations for all of the above.

commit 52f02c8963fe7ec90f36100ebe069c7807529301
Author: Brues <5278969+brues-code@users.noreply.github.com>
Date:   Mon Jul 20 23:09:06 2026 -0500

    Enumerate chat bubbles via ClassicAPI instead of scanning WorldFrame

    ClassicAPI's C_ChatBubbles.GetAllChatBubbles() walks the engine's own
    bubble list and returns the exact set of live bubble frames, with real
    GetRegions(), so the decoration idiom works unchanged. Replace the
    WorldFrame:GetChildren() sweep and drop the IsBubble heuristic (unnamed
    frame whose first region is the ChatBubble-Background texture) -- the API
    only ever hands back bubbles, so that guess is both redundant and more
    fragile than the engine list. Cheaper too: it iterates only live bubbles
    rather than every world child on each chat event.
2026-07-23 23:08:05 -05:00
Brues fa1dc5637e Bump ClassicAPI min to 1.7.4
Totem functions!
2026-07-20 22:17:49 -05:00
Brues 8506f5ffbf Localize the totem tooltip click hints
Add a Left Click / Right Click hint to the totem icon tooltip via
AddDoubleLine, matching the panel.lua convention. Reuses the existing
"Left Click" / "Right Click" strings and adds "Recast Totem" /
"Target Totem" as new translation keys (stubbed across all locales; they
fall back to English until translated).

Also drop the now-orphaned "Range Check Interval" string from every
locale manifest -- the setting was removed when librange stopped
scanning, but its translation stubs were left behind.
2026-07-20 22:16:05 -05:00
Brues 9c529512d1 Replace libtotem with ClassicAPI's native totem tracker
ClassicAPI now ships GetTotemInfo/GetTotemTimeLeft/GetTotemDuration/
TargetTotem plus a native PLAYER_TOTEM_UPDATE event, backed by a
data-driven tracker (slot from the Spell.dbc summon effect, duration from
SpellDuration.dbc, and object-manager death detection). That's exactly
what libtotem hand-rolled -- and better -- so delete the library outright:
its spellid/icon tables, the CastSpellByName/CastSpell/UseAction hooks,
the SPELL_GO commit path, and the active-totem bookkeeping.

modules/totems.lua becomes a thin consumer of the native API:
- Driven by PLAYER_TOTEM_UPDATE; drop the shaman tick-poller that only
  existed because vanilla had no totem event.
- Fix the GetTotemInfo call sites: the native 1st return is tool presence,
  not "summoned", so key active state on name/start instead.
- Right-click a totem icon to TargetTotem it; tooltip shows remaining time
  via GetTotemTimeLeft.

modules/turtle-wow.lua: drop the Totemic Recall handler that poked
libtotem:Clean() -- the native tracker detects the totems despawning and
clears the slots itself. Also clean up the now-orphaned translation string
and a stale libtotem mention in libdebuff's comment.
2026-07-20 21:51:08 -05:00
Brues 88d0f7bf74 Use table.wipe to reset spell caches
Clear existing spell cache tables with table.wipe instead of creating new tables when LEARNED_SPELL_IN_TAB fires. This preserves existing table references (spellmaxrank, spellindex, spellinfo), avoiding stale references and potential bugs while being slightly more efficient. Change applied in libs/libspell.lua.
2026-07-20 21:35:31 -05:00
Brues a3ff20782d Use table.wipe and table.insert for tables
Replace custom wipe implementation with a call to table.wipe in api/api.lua and update its doc comment to explain behavior (resets Lua 5.0 length via luaL_setn, advises using table.insert). Replace manual table.getn(t)+1 array appends with table.insert in modules/loot.lua (two sites). Makes table operations safer and more idiomatic, avoiding manual metatable handling and getn-based append idioms.
2026-07-20 21:16:12 -05:00
Brues 88c2462fbd CLASS_SORT_ORDER is already defined by !!!ClassicAPI 2026-07-20 21:15:25 -05:00
Brues e28a7e5606 Optimize isempty function using next() 2026-07-20 18:46:09 -05:00
Brues dfa74c5756 Make the bag sort family-aware and locale-independent
Two fixes to libbagsort's planning stage.

Family-aware placement: the sort treated every bag in the list as
interchangeable storage, so with a quiver / soul / profession bag in the
set it would try to swap a general item into a slot that can't hold it.
The client rejects that swap, but the grid was updated as if it
succeeded, desyncing the plan and corrupting the sort from there on. Now
each destination slot is tagged with its bag's family (via ClassicAPI's
GetItemFamily, which reports bag families reliably) and every item is
routed to a cell that accepts it -- matching specialty bag first,
overflowing to general -- so nothing lands where it can't go and family
items consolidate into their bags for free.

Locale-independent categories: SortCategoryPrefix compared the localized
itemType/quality strings from GetItemInfo, which silently miscategorize
everything on a non-enUS client. Switch to the numeric classID/quality
via C_Item.GetItemInfo and ClassicAPI's Enum.ItemClass / Enum.ItemQuality.
2026-07-20 17:46:37 -05:00
Brues 1c0c9dc019 Replace librange's position scan with ClassicAPI's UnitInRange
librange was a per-frame position scanner: it swept party/raid unit
tokens, cached each one's distance via UnitPosition, and answered range
queries from that cache. All of it existed only because 1.12 had no cheap
way to check an arbitrary unit's distance. ClassicAPI's UnitInRange does
exactly that C-side (fixed 40y healing range, position miss reported via
the second return), so the whole library collapses to a direct call.

Wins from dropping the cache:
- No staleness. The scanner's zone-death and roster-reindex bugs simply
  can't exist without a cache to go stale, so this supersedes the
  keep-alive fixes from 756e8840.
- All classes get target-frame range fading. The old target path faked a
  40y check via IsActionInRange on a healing spell found on the action
  bar, so classes without such a spell (GetRangeSlot returned nil) never
  had a working target range check.

The rangecheck == "0" master switch used to be enforced by hiding the
scanner; with no scanner, move that gate into pfUI.api.UnitInRange so
disabling the check still means nothing fades. Threshold is now 40y (the
ClassicAPI constant) rather than the old 45y. Drop the now-dead
rangechecki (Range Check Interval) setting, its GUI row, and migration.
2026-07-20 16:54:27 -05:00
Brues 801935130e Update GetItemLinkByName to use C_Item API
Replace vanilla GetItemInfo and manual link construction with C_Item.GetItemNameByID and C_Item.GetItemInfo
2026-07-20 15:11:50 -05:00
Brues 8cdced5ec0 Simplify modf function
Delegate to ClassicAPI
2026-07-20 15:10:31 -05:00
Brues 756e8840af Keep the rangecheck scanner alive across zones and roster changes
PLAYER_LEAVING_WORLD fires on every loading screen, not just logout, but
librange treated it as terminal: it latched librange_isLoggingOut and
tore OnUpdate off the frame, neither of which was ever restored. So the
first zone (into a BG, dungeon, etc.) permanently killed the distance
scan -- unitdata stopped updating and UnitInSpellRange defaulted every
unit to in-range until /reload, which the next loading screen then undid.
Only PLAYER_LOGOUT is terminal now; PLAYER_LEAVING_WORLD just hides for
the loading screen and PLAYER_ENTERING_WORLD re-shows it.

Also invalidate on RAID_ROSTER_UPDATE / PARTY_MEMBERS_CHANGED: the range
state is cached per unit token, so a roster re-index leaves each unitN
mapped to a different player with stale data. Clear the token cache and
restart the sweep so shifted/joined slots are re-evaluated within one
pass instead of inheriting the previous occupant's range.
2026-07-20 14:12:07 -05:00
Brues b2db091d54 bump min ClassicAPI version 2026-07-20 02:42:34 -05:00
Brues 5fae0bd459 Add priest shadowform auto-paging, sharing the druid-stealth flag
Mirror the druid-stealth page switch for priests: swap to the auto page
(8) while in Shadowform, back to the default page when it drops. Driven
by UPDATE_SHAPESHIFT_FORM (form ID 28), which fully covers shadowform on
its own -- no prowl-style stealth substate to chase.

Fold the new state into the existing prowl machinery instead of
duplicating it: prowl/shadowform are mutually exclusive by class, so one
shared `formpaging` flag and one page constant serve both, and the
OnUpdate switch collapses to a single class-gated block.
2026-07-20 02:40:37 -05:00
Brues 3deddf2b08 Drive questitem off QUEST_ACCEPTED/QUEST_REMOVED instead of rescanning
The item->quest map only changes when a quest enters or leaves the log,
not on progress, yet it was fully rebuilt on every QUEST_LOG_UPDATE burst
(a whole log walk + GetQuestDetails per quest). Maintain it incrementally
from ClassicAPI's QUEST_ACCEPTED / QUEST_REMOVED, keyed on the stable
questID with title/level cached at add time (the old log index shifted on
any add/remove). QUEST_LOG_UPDATE now only drives a one-time login seed
until the detail cache warms, since QUEST_ACCEPTED is suppressed for the
bulk sync; afterward it's a no-op and questing does no rebuilds.
2026-07-19 02:25:23 -05:00
Brues 650bcda001 Allocate newitem glow lazily, only for slots that go new
UpdateSlot previously created the glow texture and OnEnter acknowledge
hook on the first pass over every slot, then toggled visibility. Move
both inside the "is new" branch so a slot only allocates when it actually
holds a new item -- most bag/bank slots never do. Behavior is unchanged:
the glow is still created once per slot and reused, and the hook is
installed exactly when it's first needed.
2026-07-17 16:04:03 -05:00
Brues 931fe6c22d Harden the ClassicAPI-missing path so the disable notice can show
pfUI's TOC depends on the !!!ClassicAPI addon, so a nil CLASSIC_API_VERSION
means the addon loaded but the DLL isn't present -- yet the graceful-disable
branch itself called ClassicAPI APIs (EventUtil.ContinueOnPlayerLogin, and
Mixin/CallbackRegistryMixin for pfUI.events), so it crashed instead of
informing the user.

- Defer the popup with a bare PLAYER_ENTERING_WORLD frame (stock 1.12)
  instead of EventUtil/IsLoggedIn/PLAYER_LOGIN (ClassicAPI-era).
- Read the editbox via getglobal rather than _G.
- Guard pfUI.events creation behind `not pfUI.disabled`.
- Reword the notice: since the addon is present but the DLL isn't (or is
  outdated), tell the user the addon ships bundled with the DLL and to
  delete the !!!ClassicAPI folder and (re)install the latest release.
2026-07-17 15:12:30 -05:00
Brues bd4a40b0f2 Add newitem module: highlight freshly-acquired bag items
New module built on ClassicAPI's C_NewItems + BAG_NEW_ITEMS_UPDATED.
Glows bag slots (bags 0-4) holding items acquired since login, keyed on
item GUID so the flag survives rearranging. Hovering an item
acknowledges it (RemoveNewItem); closing the bags clears the rest via
ClearAll. Glow is UI-ActionButton-Border, sized off the slot width so it
tracks the icon_size config.

To stay decoupled from the bag frames, the bag module now broadcasts a
reusable "bag:closed" event through pfUI.events from its OnHide (carrying
the container so subscribers can tell backpack from bank), guarded so the
initial setup Hide() doesn't fire a phantom close.

Config: appearance.bags.newitem + newitem_color, with GUI toggles.
2026-07-17 14:47:22 -05:00
Brues 31ff2773b3 Defer macrotweak conflicts; use SetSize
Replace the previous RunNextFrame conflict check with per-addon EventUtil.ContinueOnAddOnLoaded calls in modules/macrotweak.lua so macrotweak is disabled as soon as known conflicting addons load. Simplify variable naming and ensure the disabled flag is set correctly. In skins/blizzard/macro.lua replace separate SetHeight/SetWidth calls with a single SetSize(150,22) for MacroEditButton to tidy UI sizing.
2026-07-15 13:45:06 -05:00
Brues 8176b906df Re-anchor tradeskill merge bar to real craft starts
EnterTradeskillMerge sized the merged bar as startMs + single*count, a
zero-latency assumption. Each craft boundary actually costs a server
round-trip, so the real chain runs ~(N-1)*lag longer than the bar
assumed. At the clear the overall fill was clamped to full and looked
done, but the fast per-craft spark tracks real time and came up short by
the accumulated lag -- freezing partway on the final craft.

StartTradeskillCraft now re-pins endTime to each craft's real start
(remaining crafts each still take `single`), so on the last craft
remaining==1 and endTime lands on its true completion. The spark and the
overall progress now reach the right edge together.
2026-07-13 12:34:45 -05:00
Brues 721ecce59d Remove RegisterNewModule call for loothistory 2026-07-13 00:32:21 -05:00
Brues 73b409fb88 Route slash registration through pfUI.api.RegisterSlashCommand
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.
2026-07-13 00:06:20 -05:00
Brues 0665764610 cleanup 2026-07-12 15:22:57 -05:00
Brues 3faf06141f Skin Arena Frame 2026-07-12 14:49:17 -05:00
Brues 0c06401ec4 Simplify GUI toggle logic 2026-07-12 14:14:38 -05:00
Brues c68e48111d Remove libtooltip 2026-07-12 14:01:25 -05:00
Brues 6936fd894b Replace unusable tooltip scan with C_PlayerInfo.CanUseItem
The libtipscan approach scanned each bag/bank item's tooltip for red
text, then had to carve out broken (0-durability) items since those also
color red. C_PlayerInfo.CanUseItem checks item requirements directly
(proficiency, level, class/race, skill/spell/rep) and ignores item
state, so broken-but-equippable gear is never flagged and the durability
exclusion drops out entirely. Bank slots resolve through
C_Container.GetContainerItemID(-1, slot) instead of the inventory-slot
workaround the scanner needed.
2026-07-12 13:48:36 -05:00
Brues b5277ea457 These modules aren't new anymore 2026-07-11 16:04:58 -05:00
Brues 63f0dcbf7a Use GetInventoryItemID instead of parsing link 2026-07-11 13:18:48 -05:00
Brues 0344bff471 cleanup 2026-07-11 12:59:33 -05:00
Brues 1510969105 Unused strings 2026-07-11 12:57:07 -05:00
Brues 6e7361c543 Removed redundant compare.basestats setting
Just disable the module if you don't want stat comparison
2026-07-11 12:43:15 -05:00
Brues 2e20a03cbd Restore Inspect UI frame skin
removed during the tbc purge
2026-07-11 12:36:03 -05:00
Brues 7389c241a4 using GetSpellInfo with just a spell id is dangerous
Handful of addons will polyfill their own GetSpellInfo that only accept (bookSlot, bookType) so it's only safe to use C_Spell.GetSpellInfo with just a spell id
2026-07-11 09:47:46 -05:00
Brues fb5230828c Add Loot History module
A pfUI-native group-loot roll history window built on ClassicAPI's
C_LootHistory backport, adapted from the anniversary Blizzard reference.

- Movable/scrollable window (ESC-closable, Clear button) listing rolled
  items; each row expands to per-player rolls.
- Item icon/name/quality rendered via the !!!ClassicAPI Item mixin
  (Item:CreateFromItemLink + ContinueOnItemLoad), so uncached items load
  asynchronously and repaint their row.
- Winner shown on the collapsed row (name/roll/roll-type) and marked in the
  expanded list with a checkmark left of the name (matches the reference).
- Expansion state keys on the stable rollID; events (FULL_UPDATE /
  ROLL_CHANGED / ROLL_COMPLETE) drive a rebuild while shown, and re-attach
  the scroll child so a growing list scrolls without a /reload.
- Toggle via /loothistory or /lh; optional auto-show on new rolls behind
  loothistory.autoshow (default off).
2026-07-11 00:02:31 -05:00
Brues 7aee348a70 Bump min version to 1.6.4 2026-07-10 20:27:16 -05:00
Brues 2a5f480839 Show addon dependencies in tooltip
Add display of required and optional addon dependencies to the addons tooltip. Introduce AddDependencyLines helper in modules/addons.lua which lists dependencies with color coding: green for loaded, yellow for present but unloaded, and red for missing (uses new T["Missing"]). Store dependency arrays on addon frames (adeps / aoptdeps) using GetAddOnDependencies and C_AddOns.GetAddOnOptionalDependencies. Add translation keys 'Dependencies', 'Optional Dependencies', and 'Missing' to env/translations_enUS.lua.
2026-07-10 20:26:05 -05:00
Brues 23d1ab840c Show sell value in tooltip when merchant hidden
When the MerchantFrame is not shown, display the item's total vendor sell value on the tooltip. Adds a guard to call SetTooltipMoney(frame, sell * count) if sell > 0 so stacked items show their combined sell price.
2026-07-10 13:23:52 -05:00
90 changed files with 2104 additions and 2285 deletions
+83 -57
View File
@@ -64,6 +64,10 @@ end
-- Requires UnitXP_SP3
function pfUI.api.UnitInLineOfSight(unit1, unit2)
if not pfUI.api.HasUnitXP() then return nil end
if not unit2 then
unit2 = unit1
unit1 = "player"
end
local success, inSight = pcall(UnitXP, "inSight", unit1, unit2)
if success then return inSight end
return nil
@@ -74,6 +78,10 @@ end
-- Requires UnitXP_SP3
function pfUI.api.UnitIsBehind(unit1, unit2)
if not pfUI.api.HasUnitXP() then return nil end
if not unit2 then
unit2 = unit1
unit1 = "player"
end
local success, behind = pcall(UnitXP, "behind", unit1, unit2)
if success then return behind end
return nil
@@ -84,16 +92,24 @@ gfind = string.gmatch or string.gfind
mod = math.mod or mod
-- [ strsplit ]
-- Splits a string using a delimiter.
-- Splits a string using a delimiter. Self-contained on purpose: it does NOT
-- delegate to the global strsplit / string.split, because third-party addons
-- clobber those (e.g. BigWigs' SpellRequests redefines string:split to return
-- a table, which would make this return a single table instead of r,g,b,a and
-- break color/version parsing depending on load order). Delimiter chars are
-- treated as a set (any one char splits), and empty fields are preserved
-- ("a,,b" -> "a", "", "b"), matching real strsplit semantics.
-- 'delimiter' [string] characters that will be interpreted as delimiter
-- characters (bytes) in the string.
-- 'subject' [string] String to split.
-- return: [list] a list of strings.
local format, sgsub = string.format, string.gsub
function pfUI.api.strsplit(delimiter, subject)
if not subject then return nil end
local delimiter, fields = delimiter or ":", {}
local pattern = string.format("([^%s]+)", delimiter)
string.gsub(subject, pattern, function(c) fields[table.getn(fields)+1] = c end)
local fields = {}
delimiter = delimiter or ":"
local pattern = format("([^%s]+)", delimiter)
sgsub(subject, pattern, function(c) fields[table.getn(fields)+1] = c end)
return unpack(fields)
end
@@ -102,11 +118,7 @@ end
-- 'tbl' [table] the table that shall be checked
-- return: [boolean] result of the check.
function pfUI.api.isempty(tbl)
if not tbl then return true end
for k, v in pairs(tbl) do
return false
end
return true
return next(tbl or {}) == nil
end
-- [ checkversion ]
@@ -135,7 +147,6 @@ end
-- It takes care of the rangecheck module if existing.
-- unit [string] A unit to query (string, unitID)
-- return: [bool] "1" if in range otherwise "nil"
local RangeCache = {}
function pfUI.api.UnitInRange(unit)
if not UnitExists(unit) or not UnitIsVisible(unit) then
return nil
@@ -143,6 +154,11 @@ function pfUI.api.UnitInRange(unit)
return 1
end
-- master switch: with the 40y check off, a visible unit beyond interact
-- range counts as in range (nothing fades). Invisible units already
-- returned nil above, matching the pre-collapse behavior.
if C.unitframes.rangecheck == "0" then return 1 end
-- UnitXP precise mode: skip librange entirely, use direct distance check
if C.unitframes.rangecheck_mode == "unitxp" and _G.UnitXP then
local threshold = tonumber(C.unitframes.rangecheck_distance) or 40
@@ -215,7 +231,7 @@ end
-- unit [string] the unitstring
-- return: [table] string, r, g, b
function pfUI.api.GetUnitColor(unitstr)
local _, class = UnitClass(unitstr)
local class = UnitClassBase(unitstr)
local classColor = PFUI_CLASS_COLORS[class]
return classColor:GenerateHexColorMarkup(), classColor:GetRGB()
end
@@ -266,11 +282,7 @@ end
-- 'f' [float] the number to breakdown.
-- returns: [int],[float] whole and fractional part.
function pfUI.api.modf(f)
if modf then return modf(f) end
if f > 0 then
return math.floor(f), mod(f,1)
end
return math.ceil(f), mod(f,1)
return math.modf(f)
end
-- [ GetServerEpoch ]
@@ -365,22 +377,20 @@ end
-- 'str' [string] input string that should be matched
-- 'pat' [string] unformatted pattern
-- returns: [strings] matched string in capture order
local a, b, c, d, e
local _, va, vb, vc, vd, ve
local ra, rb, rc, rd, re
function pfUI.api.cmatch(str, pat)
-- read capture indexes
a, b, c, d, e = GetCaptures(pat)
_, _, va, vb, vc, vd, ve = string.find(str, pfUI.api.SanitizePattern(pat))
-- idx* = the logical %N index of each physical capture slot (nil when the
-- pattern has no %N$ markers); val* = the matched values in physical order.
local idx1, idx2, idx3, idx4, idx5 = GetCaptures(pat)
local _, _, val1, val2, val3, val4, val5 = string.find(str, pfUI.api.SanitizePattern(pat))
-- put entries into the proper return values
ra = e == 1 and ve or d == 1 and vd or c == 1 and vc or b == 1 and vb or va
rb = e == 2 and ve or d == 2 and vd or c == 2 and vc or a == 2 and va or vb
rc = e == 3 and ve or d == 3 and vd or a == 3 and va or b == 3 and vb or vc
rd = e == 4 and ve or a == 4 and va or c == 4 and vc or b == 4 and vb or vd
re = a == 5 and va or d == 5 and vd or c == 5 and vc or b == 5 and vb or ve
-- reorder the physical matches into logical (%1..%5) order
local out1 = idx5 == 1 and val5 or idx4 == 1 and val4 or idx3 == 1 and val3 or idx2 == 1 and val2 or val1
local out2 = idx5 == 2 and val5 or idx4 == 2 and val4 or idx3 == 2 and val3 or idx1 == 2 and val1 or val2
local out3 = idx5 == 3 and val5 or idx4 == 3 and val4 or idx1 == 3 and val1 or idx2 == 3 and val2 or val3
local out4 = idx5 == 4 and val5 or idx1 == 4 and val1 or idx3 == 4 and val3 or idx2 == 4 and val2 or val4
local out5 = idx1 == 5 and val1 or idx4 == 5 and val4 or idx3 == 5 and val3 or idx2 == 5 and val2 or val5
return ra, rb, rc, rd, re
return out1, out2, out3, out4, out5
end
-- [ GetItemLinkByName ]
@@ -389,10 +399,10 @@ end
-- returns: [string] entire itemLink for the given item
function pfUI.api.GetItemLinkByName(name)
for itemID = 1, 25818 do
local itemName, hyperLink, itemQuality = GetItemInfo(itemID)
if (itemName and itemName == name) then
local _, _, _, hex = GetItemQualityColor(tonumber(itemQuality))
return hex.. "|H"..hyperLink.."|h["..itemName.."]|h|r"
local itemName = C_Item.GetItemNameByID(itemID)
if itemName and itemName == name then
local _, itemLink = C_Item.GetItemInfo(itemID)
return itemLink
end
end
end
@@ -719,24 +729,15 @@ function pfUI.api.CopyTable(src)
end
-- [ Wipe Table ]
-- Empties a table and returns it
-- Empties a table and returns it.
-- 'src' [table] the table that should be emptied.
-- return: [table] the emptied table.
-- Delegates to ClassicAPI's table.wipe, which also resets the Lua 5.0 getn
-- length (luaL_setn(t,0)) so table.insert on a wiped table resumes at [1].
-- Append to wiped arrays with table.insert -- NOT the t[table.getn(t)+1]=v
-- idiom, which needs an unmanaged length counter and won't work here.
function pfUI.api.wipe(src)
-- notes: table.insert, table.remove will have undefined behavior
-- when used on tables emptied this way because Lua removes nil
-- entries from tables after an indeterminate time.
-- Instead of table.insert(t,v) use t[table.getn(t)+1]=v as table.getn collapses nil entries.
-- There are no issues with hash tables, t[k]=v where k is not a number behaves as expected.
local mt = getmetatable(src) or {}
if mt.__mode == nil or mt.__mode ~= "kv" then
mt.__mode = "kv"
src=setmetatable(src,mt)
end
for k in pairs(src) do
src[k] = nil
end
return src
return table.wipe(src)
end
-- [ Load Movable ]
@@ -994,16 +995,34 @@ end
-- [ GetStringColor ]
-- Queries the pfUI setting strings and extract its color codes
-- returns r,g,b,a
local color_cache = {}
function pfUI.api.GetStringColor(colorstr)
if not color_cache[colorstr] then
local r, g, b, a = pfUI.api.strsplit(",", colorstr)
color_cache[colorstr] = { r, g, b, a }
-- returns r,g,b,a as strings
local color_cache = setmetatable({}, {
__index = function(t, k)
local color = { pfUI.api.strsplit(",", k) }
rawset(t, k, color)
return color
end
})
function pfUI.api.GetStringColor(colorstr)
return unpack(color_cache[colorstr])
end
-- [ GetStringColorObject ]
-- Like GetStringColor, but returns a cached ColorMixin instead of raw values.
-- The object is a shared per-string singleton, so treat it as read-only.
-- returns a ColorMixin
local color_object_cache = setmetatable({}, {
__index = function(t, k)
local r,g,b,a = pfUI.api.GetStringColor(k)
local color = CreateColor(tonumber(r), tonumber(g), tonumber(b), tonumber(a))
rawset(t, k, color)
return color
end
})
function pfUI.api.GetStringColorObject(colorstr)
return color_object_cache[colorstr]
end
-- [ rgbhex ]
-- Returns color format from color info
-- 'r' [table | number] color table or r color component
@@ -1011,12 +1030,13 @@ end
-- 'b' [number] optional b color component
-- 'a' [number] optional alpha component
-- returns color string in the form of '|caarrggbb'
local _r, _g, _b, _a
local rgbhex_cache = {}
function pfUI.api.rgbhex(r, g, b, a)
local _r, _g, _b, _a
if type(r) == "table" then
if r.r then
_r, _g, _b, _a = r.r, r.g, r.b, (r.a or 1)
elseif table.getn(r) >= 3 then
elseif r[3] ~= nil then
_r, _g, _b, _a = r[1], r[2], r[3], (r[4] or 1)
end
elseif tonumber(r) then
@@ -1024,7 +1044,13 @@ function pfUI.api.rgbhex(r, g, b, a)
end
if _r and _g and _b and _a then
return CreateColor(_r, _g, _b, _a):GenerateHexColorMarkup()
local key = ((Round(_r*255)*256 + Round(_g*255))*256 + Round(_b*255))*256 + Round(_a*255)
local hex = rgbhex_cache[key]
if not hex then
hex = "|c" .. C_ColorUtil.GenerateTextColorCode({ r = _r, g = _g, b = _b, a = _a })
rgbhex_cache[key] = hex
end
return hex
end
return ""
+31 -9
View File
@@ -162,6 +162,8 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("appearance", "infight", "intensity", "16")
pfUI:UpdateConfig("appearance", "bags", "unusable", "1")
pfUI:UpdateConfig("appearance", "bags", "unusable_color", ".9,.2,.2,1")
pfUI:UpdateConfig("appearance", "bags", "newitem", "1")
pfUI:UpdateConfig("appearance", "bags", "newitem_color", "1,1,1,1")
pfUI:UpdateConfig("appearance", "bags", "borderlimit", "1")
pfUI:UpdateConfig("appearance", "bags", "borderonlygear", "0")
pfUI:UpdateConfig("appearance", "bags", "fulltext", "1")
@@ -172,6 +174,8 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("appearance", "bags", "bagrowlength", "10")
pfUI:UpdateConfig("appearance", "bags", "bankrowlength", "10")
pfUI:UpdateConfig("appearance", "bags", "autoSortOnOpen", "0")
pfUI:UpdateConfig("appearance", "bags", "sortreverse", "0")
pfUI:UpdateConfig("appearance", "bags", "sortprioreverse", "0")
pfUI:UpdateConfig("appearance", "minimap", "size", "140")
pfUI:UpdateConfig("appearance", "minimap", "arrowscale", "1")
pfUI:UpdateConfig("appearance", "minimap", "zonetext", "off")
@@ -196,6 +200,8 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("loot", nil, "rollannounce", "0")
pfUI:UpdateConfig("loot", nil, "raritytimer", "1")
pfUI:UpdateConfig("loothistory", nil, "autoshow", "0")
pfUI:UpdateConfig("unitframes", nil, "disable", "0")
pfUI:UpdateConfig("unitframes", nil, "pastel", "1")
pfUI:UpdateConfig("unitframes", nil, "custom", "0")
@@ -227,8 +233,8 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("unitframes", nil, "druidmanaoffy", "0")
pfUI:UpdateConfig("unitframes", nil, "druidmanaspace", "-3")
pfUI:UpdateConfig("unitframes", nil, "druidmanatexture", "Interface\\AddOns\\pfUI\\img\\bar")
pfUI:UpdateConfig("unitframes", nil, "druidmanatext", "1")
pfUI:UpdateConfig("unitframes", nil, "rangechecki", "4")
pfUI:UpdateConfig("unitframes", nil, "combowidth", "6")
pfUI:UpdateConfig("unitframes", nil, "comboheight", "6")
pfUI:UpdateConfig("unitframes", nil, "swingtimerwidth", "200")
@@ -379,6 +385,27 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("unitframes", "grouppet", "glowcombat", "0")
pfUI:UpdateConfig("unitframes", "grouppet", "txthpright", "healthperc")
pfUI:UpdateConfig("unitframes", "raidpet", "portrait", "off")
pfUI:UpdateConfig("unitframes", "raidpet", "width", "50")
pfUI:UpdateConfig("unitframes", "raidpet", "height", "14")
pfUI:UpdateConfig("unitframes", "raidpet", "pheight", "0")
pfUI:UpdateConfig("unitframes", "raidpet", "buffs", "off")
pfUI:UpdateConfig("unitframes", "raidpet", "buffsize", "16")
pfUI:UpdateConfig("unitframes", "raidpet", "debuffs", "off")
pfUI:UpdateConfig("unitframes", "raidpet", "debuffsize", "16")
pfUI:UpdateConfig("unitframes", "raidpet", "faderange", "1")
pfUI:UpdateConfig("unitframes", "raidpet", "glowcombat", "0")
pfUI:UpdateConfig("unitframes", "raidpet", "txthpright", "healthperc")
-- off by default; mirrors the raid grid layout when enabled
pfUI:UpdateConfig("unitframes", "raidpet", "visible", "0")
-- collapse: pack only pets that exist (from the roster snapshot) instead
-- of mirroring every raid slot
pfUI:UpdateConfig("unitframes", "raidpet", "collapse", "1")
-- pet block has its own layout, independent of the raid grid
pfUI:UpdateConfig("unitframes", "raidpet", "raidlayout", "8x5")
pfUI:UpdateConfig("unitframes", "raidpet", "raidpadding", "3")
pfUI:UpdateConfig("unitframes", "raidpet", "raidfill", "VERTICAL")
pfUI:UpdateConfig("unitframes", "raid", "portrait", "off")
pfUI:UpdateConfig("unitframes", "raid", "width", "50")
pfUI:UpdateConfig("unitframes", "raid", "height", "26")
@@ -397,6 +424,7 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("unitframes", "raid", "raidlayout", "8x5")
pfUI:UpdateConfig("unitframes", "raid", "raidpadding", "3")
pfUI:UpdateConfig("unitframes", "raid", "raidfill", "VERTICAL")
pfUI:UpdateConfig("unitframes", "raid", "collapse", "0")
pfUI:UpdateConfig("unitframes", "raid", "raidgrouplabel", "0")
pfUI:UpdateConfig("unitframes", "raid", "grouplabelxoff", "0")
pfUI:UpdateConfig("unitframes", "raid", "grouplabelyoff", "8")
@@ -452,7 +480,7 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("unitframes", "ptarget", "txthpright", "none")
pfUI:UpdateConfig("unitframes", "ptarget", "overhealperc", "10")
local ufs = { "player", "target", "focus", "focustarget", "group", "grouptarget", "grouppet", "raid", "ttarget", "pet", "ptarget", "fallback", "tttarget" }
local ufs = { "player", "target", "focus", "focustarget", "group", "grouptarget", "grouppet", "raid", "raidpet", "ttarget", "pet", "ptarget", "fallback", "tttarget" }
for _, unit in pairs(ufs) do
pfUI:UpdateConfig("unitframes", unit, "selfdebuff", "0")
pfUI:UpdateConfig("unitframes", unit, "visible", "1")
@@ -624,6 +652,7 @@ function pfUI:LoadConfig()
pfUI:UpdateConfig("bars", nil, "pagemastershift", "0")
pfUI:UpdateConfig("bars", nil, "pagemasterctrl", "0")
pfUI:UpdateConfig("bars", nil, "druidstealth", "0")
pfUI:UpdateConfig("bars", nil, "priestshadow", "0")
pfUI:UpdateConfig("bars", nil, "showcastable", "1")
pfUI:UpdateConfig("bars", nil, "glowrange", "1")
pfUI:UpdateConfig("bars", nil, "rangecolor", "1,0.1,0.1,1")
@@ -1105,13 +1134,6 @@ function pfUI:MigrateConfig()
end
end
-- migrating rangecheck interval (> 3.2.2)
if checkversion(3, 2, 2) then
if tonumber(pfUI_config.unitframes.rangechecki) <= 1 then
pfUI_config.unitframes.rangechecki = "2"
end
end
-- migrating legacy buff/debuff naming (> 3.5.0)
if checkversion(3, 5, 0) then
local unitframes = { "player", "target", "focus", "group", "grouptarget", "grouppet", "raid", "ttarget", "pet", "ptarget", "fallback" }
+24 -59
View File
@@ -21,8 +21,7 @@ do -- statusbars
local handlers = {
["DisplayValue"] = function(self, val)
val = val > self.max and self.max or val
val = val < self.min and self.min or val
val = Clamp(val, self.min, self.max)
-- remove animation queue
if val == self.val_ then
@@ -38,8 +37,7 @@ do -- statusbars
point = height / (self.max - self.min) * (val - self.min)
-- keep values in limits
point = math.min(height, point)
point = math.max(0, point)
point = Clamp(point, 0, height)
-- set point to zero if value and max is zero
if val == 0 then point = 0 end
@@ -57,8 +55,7 @@ do -- statusbars
point = width / (self.max - self.min) * (val - self.min)
-- keep values in limits
point = math.min(width, point)
point = math.max(0, point)
point = Clamp(point, 0, width)
-- set point to zero if value and max is zero
if val == 0 then point = 0 end
@@ -138,15 +135,8 @@ do -- statusbars
end
do -- dropdown
local _, class = UnitClass("player")
local color = PFUI_CLASS_COLORS[class]
local function ListEntryOnShow()
if this.parent.id == this.id then
this.icon:Show()
else
this.icon:Hide()
end
this.icon:SetShown(this.parent.id == this.id)
end
local function ListEntryOnClick()
@@ -288,8 +278,7 @@ do -- dropdown
frame.icon = frame:CreateTexture(nil, "OVERLAY")
frame.icon:SetPoint("RIGHT", frame, "RIGHT", -2, 0)
frame.icon:SetHeight(16)
frame.icon:SetWidth(16)
frame.icon:SetSize(16, 16)
frame.icon:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
frame.text = frame:CreateFontString(nil, "OVERLAY")
@@ -329,8 +318,7 @@ do -- dropdown
local button = CreateFrame("Button", nil, frame)
button:SetPoint("RIGHT", frame, "RIGHT", -2, 0)
button:SetWidth(16)
button:SetHeight(16)
button:SetSize(16, 16)
button:SetScript("OnClick", ListButtonOnClick)
SkinArrowButton(button, "down")
button.icon:SetVertexColor(1,.9,.1)
@@ -380,8 +368,7 @@ function pfUI.api.CreateTabChild(self, title, bwidth, bheight, bottom, static)
end
-- set dimensions
b:SetHeight(button_height)
b:SetWidth(button_width)
b:SetSize(button_width, button_height)
b:SetID(childcount)
if not self.align or self.align == "LEFT" then
@@ -516,13 +503,7 @@ function pfUI.api.CreateScrollFrame(name, parent)
local max = f:GetVerticalScrollRange()
local new = current - step
if new >= max then
f:SetVerticalScroll(max)
elseif new <= 0 then
f:SetVerticalScroll(0)
else
f:SetVerticalScroll(new)
end
f:SetVerticalScroll(Clamp(new, 0, max))
f:UpdateScrollState()
end
@@ -539,8 +520,7 @@ function pfUI.api.CreateScrollChild(name, parent)
local f = CreateFrame("Frame", name, parent)
-- dummy values required
f:SetWidth(1)
f:SetHeight(1)
f:SetSize(1, 1)
f:SetAllPoints(parent)
parent:SetScrollChild(f)
@@ -607,8 +587,7 @@ end
function pfUI.api.SetHighlight(frame, cr, cg, cb)
if not frame then return end
if not cr or not cg or not cb then
local _, class = UnitClass("player")
cr, cg, cb = GetClassColor(class)
cr, cg, cb = GetClassColor(UnitClassBase('player'))
end
frame.cr, frame.cg, frame.cb = cr, cg, cb, ca
@@ -653,8 +632,7 @@ function pfUI.api.SkinButton(button, cr, cg, cb, icon, disableHighlight)
if not b then b = button end
if not b then return end
if not cr or not cg or not cb then
local _, class = UnitClass("player")
cr, cg, cb = GetClassColor(class)
cr, cg, cb = GetClassColor(UnitClassBase('player'))
end
pfUI.api.CreateBackdrop(b, nil, true)
b:SetNormalTexture("")
@@ -702,8 +680,7 @@ function pfUI.api.SkinCollapseButton(button, all)
b.icon = _G[name] or CreateFrame("Button", name, b)
if all then size = 14 end
b.icon:SetWidth(size)
b.icon:SetHeight(size)
b.icon:SetSize(size, size)
b.icon:SetPoint("LEFT", 2, 2)
CreateBackdrop(b.icon)
b.icon.text = b.icon:CreateFontString(nil, "OVERLAY")
@@ -732,12 +709,10 @@ end
function pfUI.api.SkinRotateButton(button)
pfUI.api.CreateBackdrop(button)
local _, class = UnitClass("player")
local color = PFUI_CLASS_COLORS[class]
local cr, cg, cb = color.r , color.g, color.b
local cr, cg, cb = GetClassColor(UnitClassBase('player'))
button:SetWidth(button:GetWidth() - 18)
button:SetHeight(button:GetHeight() - 18)
local btnW, btnH = button:GetSize()
button:SetSize(btnW - 18, btnH - 18)
button:GetNormalTexture():SetTexCoord(0.3, 0.29, 0.3, 0.65, 0.69, 0.29, 0.69, 0.65)
button:GetPushedTexture():SetTexCoord(0.3, 0.29, 0.3, 0.65, 0.69, 0.29, 0.69, 0.65)
@@ -759,8 +734,7 @@ function pfUI.api.SkinCloseButton(button, parentFrame, offsetX, offsetY)
SkinButton(button, 1, .25, .25)
button:SetWidth(15)
button:SetHeight(15)
button:SetSize(15, 15)
if parentFrame then
button:ClearAllPoints()
@@ -787,8 +761,7 @@ function pfUI.api.SkinArrowButton(button, dir, size)
button:SetDisabledTexture(nil)
if size then
button:SetWidth(size)
button:SetHeight(size)
button:SetSize(size, size)
end
if not button.icon then
@@ -894,8 +867,7 @@ function pfUI.api.SkinCheckbox(frame, size)
frame:SetPushedTexture("")
frame:SetHighlightTexture("")
if size then
frame:SetWidth(size)
frame:SetHeight(size)
frame:SetSize(size, size)
end
CreateBackdrop(frame)
SetAllPointsOffset(frame.backdrop, frame, 4)
@@ -923,8 +895,7 @@ function pfUI.api.SkinDropDown(frame, cr, cg, cb, useSmall)
CreateBackdrop(button)
button.backdrop:ClearAllPoints()
button.backdrop:SetWidth(18)
button.backdrop:SetHeight(18)
button.backdrop:SetSize(18, 18)
button.backdrop:SetPoint("RIGHT", frame.backdrop, "RIGHT", -2, 0)
if not button.icon then
@@ -936,9 +907,7 @@ function pfUI.api.SkinDropDown(frame, cr, cg, cb, useSmall)
end
if not cr or not cg or not cb then
local _, class = UnitClass("player")
local color = PFUI_CLASS_COLORS[class]
cr, cg, cb = color.r , color.g, color.b
cr, cg, cb = GetClassColor(UnitClassBase('player'))
end
SetHighlight(button, cr, cg, cb)
@@ -1108,8 +1077,7 @@ function pfUI.api.CreateQuestionDialog(text, yes, no, editbox, onclose)
-- buttons
question.yes = CreateFrame("Button", "pfQuestionDialogYes", question, "UIPanelButtonTemplate")
pfUI.api.SkinButton(question.yes)
question.yes:SetWidth(100)
question.yes:SetHeight(22)
question.yes:SetSize(100, 22)
question.yes:SetText(yescap)
question.yes:SetScript("OnClick", function()
if yes then yes() end
@@ -1124,8 +1092,7 @@ function pfUI.api.CreateQuestionDialog(text, yes, no, editbox, onclose)
question.no = CreateFrame("Button", "pfQuestionDialogNo", question, "UIPanelButtonTemplate")
pfUI.api.SkinButton(question.no)
question.no:SetWidth(100)
question.no:SetHeight(22)
question.no:SetSize(100, 22)
question.no:SetText(nocap)
question.no:SetScript("OnClick", function()
if no then no() end
@@ -1141,8 +1108,7 @@ function pfUI.api.CreateQuestionDialog(text, yes, no, editbox, onclose)
question.close = CreateFrame("Button", "pfQuestionDialogClose", question)
question.close:SetPoint("TOPRIGHT", -border, -border)
pfUI.api.CreateBackdrop(question.close)
question.close:SetHeight(10)
question.close:SetWidth(10)
question.close:SetSize(10, 10)
question.close.texture = question.close:CreateTexture("pfQuestionDialogCloseTex")
question.close.texture:SetTexture(pfUI.media["img:close"])
question.close.texture:ClearAllPoints()
@@ -1244,9 +1210,8 @@ function pfUI.api.CreateInfoBox(text, time, parent, height)
infobox.duration = time
infobox.lastshow = GetTime()
infobox:SetWidth(infobox.text:GetStringWidth() + 50)
infobox:SetSize(infobox.text:GetStringWidth() + 50, height)
infobox:SetParent(parent)
infobox:SetHeight(height)
infobox:SetFrameStrata("FULLSCREEN_DIALOG")
infobox:Show()
+171 -500
View File
@@ -19,10 +19,10 @@ function pfUI.uf.ClearGuidTracking()
end
-- slash command to toggle unitframe test mode
_G.SLASH_PFTEST1, _G.SLASH_PFTEST2 = "/pftest", "/pfuftest"
_G.SlashCmdList.PFTEST = function()
pfUI.api.RegisterSlashCommand("PFTEST", { "/pftest", "/pfuftest" }, function()
pfUI.uf.showall = not pfUI.uf.showall
end
if pfUI.uf.raid and pfUI.uf.raid.LayoutPets then pfUI.uf.raid:LayoutPets() end
end, true)
-- HoT buff indicators that need name verification because their icons are
-- reused by other spells. Maps icon (lowercased) → expected aura name +
@@ -127,115 +127,16 @@ visibilityscan:SetScript("OnUpdate", function()
end)
-- ============================================================================
-- GetUnitStats - Nampower Integration for Health + Power
-- GetUnitStats - health + power for a unit token.
-- Returns: hp, maxHp, power, maxPower, powerType
-- IMPORTANT: Uses _G.UnitExists directly to avoid conflicts with Nampower's
-- use UnitGUID(unit) for GUID lookup (Nampower 3.0.0+)
-- ============================================================================
-- Cache für Stats-Tracking (nur Änderungen zählen)
pfUI.api.lastUnitStats = pfUI.api.lastUnitStats or {}
function pfUI.api.GetUnitStats(unitstr, trackStats)
local hp, maxHp, power, maxPower, powerType
local usedNampower = false
-- Try GetUnitField first if available (for all units: players, pets, NPCs)
if GetUnitField then
-- Use the standard check first, then get guid separately
local exists = _G.UnitExists(unitstr)
if exists then
-- Get guid via the extended UnitExists for Nampower
local _, guid = _G.UnitExists(unitstr)
if guid then
hp = GetUnitField(guid, "health")
maxHp = GetUnitField(guid, "maxHealth")
-- Get power type from bytes0
local bytes0 = GetUnitField(guid, "bytes0")
if bytes0 then
local temp = math.floor(bytes0 / 16777216)
powerType = temp - math.floor(temp / 256) * 256
else
powerType = UnitPowerType(unitstr) or 0
end
-- Get power values based on type
if powerType == 1 then
-- Rage (Nampower stores rage * 10, maxPower2 stores maxRage * 10)
local rage = GetUnitField(guid, "power2")
local maxRage = GetUnitField(guid, "maxPower2")
power = rage and math.floor(rage / 10) or UnitMana(unitstr)
maxPower = maxRage and math.floor(maxRage / 10) or UnitManaMax(unitstr)
elseif powerType == 3 then
-- Energy
power = GetUnitField(guid, "power4") or UnitMana(unitstr)
if power then power = math.floor(power) end
maxPower = GetUnitField(guid, "maxPower4") or UnitManaMax(unitstr)
elseif powerType == 2 then
-- Focus (Hunter pets use power3)
power = GetUnitField(guid, "power3") or UnitMana(unitstr)
if power then power = math.floor(power) end
maxPower = GetUnitField(guid, "maxPower3") or UnitManaMax(unitstr)
else
-- Mana (default)
power = GetUnitField(guid, "power1") or UnitMana(unitstr)
maxPower = GetUnitField(guid, "maxPower1") or UnitManaMax(unitstr)
end
-- Check if Nampower gave valid health data
if hp and hp > 0 and maxHp and maxHp > 0 then
usedNampower = true
-- Track Nampower success - NUR bei echten Änderungen
if trackStats and pfUI.uf and pfUI.uf.stats and pfUI.uf.stats.enabled then
local lastStats = pfUI.api.lastUnitStats[unitstr]
if not lastStats or lastStats.hp ~= hp or lastStats.maxHp ~= maxHp or
lastStats.power ~= power or lastStats.maxPower ~= maxPower then
pfUI.uf.stats.nampowerUsed = (pfUI.uf.stats.nampowerUsed or 0) + 1
pfUI.api.lastUnitStats[unitstr] = {
hp = hp,
maxHp = maxHp,
power = power,
maxPower = maxPower
}
end
end
return hp, maxHp, power or 0, maxPower or 1, powerType
end
end
end
end
-- Fallback to standard API (for players when Nampower fails)
hp = UnitHealth(unitstr) or 0
maxHp = UnitHealthMax(unitstr) or 1
powerType = UnitPowerType(unitstr) or 0
power = UnitMana(unitstr) or 0
maxPower = UnitManaMax(unitstr) or 1
-- Track Fallback usage - NUR bei echten Änderungen
if trackStats and not usedNampower then
if pfUI.uf and pfUI.uf.stats and pfUI.uf.stats.enabled then
local lastStats = pfUI.api.lastUnitStats[unitstr]
if not lastStats or lastStats.hp ~= hp or lastStats.maxHp ~= maxHp or
lastStats.power ~= power or lastStats.maxPower ~= maxPower then
pfUI.uf.stats.fallbackUsed = (pfUI.uf.stats.fallbackUsed or 0) + 1
pfUI.api.lastUnitStats[unitstr] = {
hp = hp,
maxHp = maxHp,
power = power,
maxPower = maxPower
}
end
end
end
return hp, maxHp, power, maxPower, powerType
function pfUI.api.GetUnitStats(unitstr)
local powerType = UnitPowerType(unitstr) or 0
return UnitHealth(unitstr) or 0,
UnitHealthMax(unitstr) or 1,
UnitPower(unitstr, powerType) or 0,
UnitPowerMax(unitstr, powerType) or 1,
powerType
end
local aggrodata = { }
@@ -294,7 +195,7 @@ function pfUI.uf:UpdateVisibility()
-- cache result of strsub to avoid repeating calls
if not self.cache_raid then
if strsub(self:GetName(),0,6) == "pfRaid" then
self.cache_raid = tonumber(strsub(self:GetName(),7,8))
self.cache_raid = tonumber(strsub(self:GetName(),7,8)) or 0
else
self.cache_raid = 0
end
@@ -305,7 +206,7 @@ function pfUI.uf:UpdateVisibility()
local id = self.cache_raid
-- always show self in raidframes
if not IsInRaid() and IsInGroup() and C.unitframes.selfinraid == "1" and id == 1 then
if not IsInGroup() and C.unitframes.selfinraid == "1" and id == 1 then
self.id = ""
self.label = "player"
@@ -339,6 +240,12 @@ function pfUI.uf:UpdateVisibility()
local unitstr = string.format("%s%s", self.label or "", self.id or "")
local visibility = string.format("[target=%s,exists] show; hide", unitstr)
-- Group frames are redundant when the group is already shown as a raid grid:
-- either an actual raid, or a party promoted to the raid grid via
-- raidforgroup. hide_in_raid gates whether we hide them in that case.
local hide_group = C["unitframes"]["group"]["hide_in_raid"] == "1"
and (IsInRaid() or (C.unitframes.raidforgroup == "1" and IsInGroup()))
if pfUI.unlock and pfUI.unlock:IsShown() then
-- display during unlock mode
visibility = "show"
@@ -347,13 +254,14 @@ function pfUI.uf:UpdateVisibility()
-- frame shall not be visible
visibility = "hide"
self.visible = nil
elseif C["unitframes"]["group"]["hide_in_raid"] == "1" and self.label and strsub(self.label,0,5) == "party" and IsInRaid() then
-- hide group while in raid and option is set
elseif hide_group and self.cache_raid == 0 and self.label and strsub(self.label,0,5) == "party" then
-- hide group while shown as a raid grid and option is set (raid frames
-- carry label "party" under raidforgroup, so exclude them by cache_raid)
visibility = "hide"
self.visible = nil
elseif ( self.fname == "Group0" or self.fname == "PartyPet0" or self.fname == "Party0Target" )
and (not IsInGroup() or (C["unitframes"]["group"]["hide_in_raid"] == "1" and IsInRaid())) then
-- hide self in group if solo or hide in raid is set
and (not IsInGroup() or hide_group) then
-- hide self in group if solo or shown as a raid grid
visibility = "hide"
self.visible = nil
end
@@ -373,6 +281,11 @@ function pfUI.uf:UpdateVisibility()
self:Hide()
return
end
elseif self.label == "raidpet" then
if not UnitIsVisible(unitstr) or not UnitExists("raid" .. self.id) then
self:Hide()
return
end
elseif self.label == "pettarget" then
if not UnitIsVisible(unitstr) or not UnitExists("pet") then
self:Hide()
@@ -407,19 +320,16 @@ function pfUI.uf:UpdateFrameSize()
if self.config.portrait == "left" or self.config.portrait == "right" then
if ptwidth == "-1" and ptheight == "-1" then
-- align portrait size to frame
self.portrait:SetWidth(real_height)
self.portrait:SetHeight(real_height)
self.portrait:SetSize(real_height, real_height)
portrait = real_height + spacing + 2*default_border
else
-- use custom portrait size
self.portrait:SetWidth(ptwidth)
self.portrait:SetHeight(ptheight)
self.portrait:SetSize(ptwidth, ptheight)
portrait = ptwidth + spacing + 2*default_border
end
end
self:SetWidth(width + portrait)
self:SetHeight(real_height)
self:SetSize(width + portrait, real_height)
end
function pfUI.uf:UpdateConfig()
@@ -456,8 +366,7 @@ function pfUI.uf:UpdateConfig()
f.glow:SetScript("OnUpdate", pfUI.uf.glow.UpdateGlowAnimation)
f.glow:Hide()
f.combat:SetWidth(tonumber(f.config.squaresize))
f.combat:SetHeight(tonumber(f.config.squaresize))
f.combat:SetSize(tonumber(f.config.squaresize), tonumber(f.config.squaresize))
f.combat:ClearAllPoints()
f.combat:SetPoint(f.config.squarepos, 0, 0)
f.combat:Hide()
@@ -465,8 +374,7 @@ function pfUI.uf:UpdateConfig()
f.hp:ClearAllPoints()
f.hp:SetPoint("TOP", 0, 0)
f.hp:SetWidth(f.config.width)
f.hp:SetHeight(f.config.height)
f.hp:SetSize(f.config.width, f.config.height)
if tonumber(f.config.height) < 0 then f.hp:Hide() end
pfUI.api.CreateBackdrop(f.hp, default_border)
@@ -489,8 +397,7 @@ function pfUI.uf:UpdateConfig()
f.power:ClearAllPoints()
f.power:SetPoint(f.config.panchor, f.hp, relative_point, f.config.poffx, -2 * default_border - spacing + f.config.poffy * GetPerfectPixel())
f.power:SetWidth((f.config.pwidth ~= "-1" and f.config.pwidth or f.config.width))
f.power:SetHeight(f.config.pheight)
f.power:SetSize((f.config.pwidth ~= "-1" and f.config.pwidth or f.config.width), f.config.pheight)
if tonumber(f.config.pheight) < 0 then f.power:Hide() end
pfUI.api.CreateBackdrop(f.power, default_border)
@@ -518,6 +425,50 @@ function pfUI.uf:UpdateConfig()
fontstyle = C.global.font_unit_style
end
-- Druid secondary mana bar: texture/color/size/position below the power bar,
-- using its own C.unitframes.druidmana* config. Values are read in
-- UpdateDruidMana; here we only lay it out.
if f.druidmana then
local DC = C.unitframes
local dmTexture = DC.druidmanatexture or "Interface\\AddOns\\pfUI\\img\\bar"
f.druidmana:SetStatusBarTexture(pfUI.media[dmTexture] or dmTexture)
f.druidmana:SetFrameLevel(f:GetFrameLevel() + 5)
local manacolor = f.config.defcolor == "0" and f.config.manacolor or C.unitframes.manacolor
f.druidmana:SetStatusBarColor(GetStringColor(manacolor))
local dmHeight = tonumber(DC.druidmanaheight) or 10
local dmWidth = DC.druidmanawidth or "-1"
local dmOffX = tonumber(DC.druidmanaoffx) or 0
local dmOffY = tonumber(DC.druidmanaoffy) or 0
local dmSpace = tonumber(DC.druidmanaspace) or -3
local dmSpacing = -2 * default_border - dmSpace
f.druidmana:SetHeight(dmHeight)
f.druidmana:ClearAllPoints()
local w = dmWidth ~= "-1" and tonumber(dmWidth) or nil
if w then
f.druidmana:SetWidth(w)
f.druidmana:SetPoint("TOP", f.power, "BOTTOM", dmOffX, dmSpacing + dmOffY)
else
f.druidmana:SetPoint("TOPLEFT", f.power, "BOTTOMLEFT", dmOffX, dmSpacing + dmOffY)
f.druidmana:SetPoint("TOPRIGHT", f.power, "BOTTOMRIGHT", dmOffX, dmSpacing + dmOffY)
end
if not f.druidmana._hasbd then
CreateBackdrop(f.druidmana, default_border)
CreateBackdropShadow(f.druidmana)
f.druidmana._hasbd = true
end
local tr, tg, tb = ManaBarColor[Enum.PowerType.Mana].r, ManaBarColor[Enum.PowerType.Mana].g, ManaBarColor[Enum.PowerType.Mana].b
if C.unitframes.pastel == "1" then
tr, tg, tb = (tr + .75) * .5, (tg + .75) * .5, (tb + .75) * .5
end
f.druidmana.text:SetFont(fontname, fontsize, fontstyle)
f.druidmana.text:SetTextColor(tr, tg, tb, 1)
end
f.portrait.tex:SetAllPoints(f.portrait)
f.portrait.tex:SetTexCoord(.1, .9, .1, .9)
f.portrait.model:SetAllPoints(f.portrait)
@@ -574,11 +525,7 @@ function pfUI.uf:UpdateConfig()
end
if f.group then
if f.config.raidgrouplabel == "1" then
f.group:Show()
else
f.group:Hide()
end
f.group:SetShown(f.config.raidgrouplabel == "1")
local xoff = tonumber(f.config.grouplabelxoff) or 0
local yoff = tonumber(f.config.grouplabelyoff) or 8
@@ -647,8 +594,7 @@ function pfUI.uf:UpdateConfig()
f.powerCenterText:SetPoint("TOPLEFT",f.power.bar, "TOPLEFT", f.config.txtpowercenteroffx, 1 + tonumber(f.config.txtpowercenteroffy))
f.powerCenterText:SetPoint("BOTTOMRIGHT",f.power.bar, "BOTTOMRIGHT", f.config.txtpowercenteroffx, f.config.txtpowercenteroffy)
f.incHeal:SetHeight(f.config.height)
f.incHeal:SetWidth(f.config.width)
f.incHeal:SetSize(f.config.width, f.config.height)
f.incHeal.texture:SetTexture(pfUI.media["img:bar"])
local cr, cg, cb, ca = GetStringColor(f.config.healcolor)
cr, cg, cb, ca = tonumber(cr), tonumber(cg), tonumber(cb), tonumber(ca)
@@ -664,53 +610,46 @@ function pfUI.uf:UpdateConfig()
end
f.ressIcon:SetFrameLevel(16)
f.ressIcon:SetWidth(32)
f.ressIcon:SetHeight(32)
f.ressIcon:SetSize(32, 32)
f.ressIcon:SetPoint("CENTER", f, "CENTER", 0, 4)
f.ressIcon.texture:SetTexture(pfUI.media["img:ress"])
f.ressIcon.texture:SetAllPoints(f.ressIcon)
f.ressIcon:Hide()
f.leaderIcon:SetWidth(10)
f.leaderIcon:SetHeight(10)
f.leaderIcon:SetSize(10, 10)
f.leaderIcon:SetPoint("CENTER", f, "TOPLEFT", 0, 0)
f.leaderIcon.texture:SetTexture("Interface\\GROUPFRAME\\UI-Group-LeaderIcon")
f.leaderIcon.texture:SetAllPoints(f.leaderIcon)
f.leaderIcon:Hide()
f.lootIcon:SetWidth(10)
f.lootIcon:SetHeight(10)
f.lootIcon:SetSize(10, 10)
f.lootIcon:SetPoint("CENTER", f, "LEFT", 0, 0)
f.lootIcon.texture:SetTexture("Interface\\GROUPFRAME\\UI-Group-MasterLooter")
f.lootIcon.texture:SetAllPoints(f.lootIcon)
f.lootIcon:Hide()
f.pvpIcon:SetWidth(f.config.pvpiconsize)
f.pvpIcon:SetHeight(f.config.pvpiconsize)
f.pvpIcon:SetSize(f.config.pvpiconsize, f.config.pvpiconsize)
f.pvpIcon:SetPoint(f.config.pvpiconalign, f, f.config.pvpiconalign, f.config.pvpiconoffx, f.config.pvpiconoffy)
f.pvpIcon.texture:SetTexture(pfUI.media["img:pvp"])
f.pvpIcon.texture:SetAllPoints(f.pvpIcon)
f.pvpIcon.texture:SetVertexColor(1,1,1,.5)
f.pvpIcon:Hide()
f.raidIcon:SetWidth(f.config.raidiconsize)
f.raidIcon:SetHeight(f.config.raidiconsize)
f.raidIcon:SetSize(f.config.raidiconsize, f.config.raidiconsize)
f.raidIcon:SetPoint("CENTER", f, f.config.raidiconalign, f.config.raidiconoffx, f.config.raidiconoffy)
local raidIconTex = C.unitframes.blizzard_raidicons == "1" and "Interface\\TargetingFrame\\UI-RaidTargetingIcons" or pfUI.media["img:raidicons"]
f.raidIcon.texture:SetTexture(raidIconTex)
f.raidIcon.texture:SetAllPoints(f.raidIcon)
f.raidIcon:Hide()
f.restIcon:SetWidth(16)
f.restIcon:SetHeight(16)
f.restIcon:SetSize(16, 16)
f.restIcon:SetPoint("TOP", f, "TOPLEFT", 0, -1)
f.restIcon.texture:SetTexture("Interface\\CharacterFrame\\UI-StateIcon", true)
f.restIcon.texture:SetTexCoord(0, .5, 0, .421875)
f.restIcon.texture:SetAllPoints(f.restIcon)
f.restIcon:Hide()
f.happinessIcon:SetWidth(tonumber(C.unitframes.pet.happinesssize))
f.happinessIcon:SetHeight(tonumber(C.unitframes.pet.happinesssize))
f.happinessIcon:SetSize(tonumber(C.unitframes.pet.happinesssize), tonumber(C.unitframes.pet.happinesssize))
f.happinessIcon:SetPoint("CENTER", f, "TOPLEFT", default_border, -default_border)
f.happinessIcon.texture:SetTexture(pfUI.media["img:neutral"])
f.happinessIcon.texture:SetAllPoints(f.happinessIcon)
@@ -778,8 +717,7 @@ function pfUI.uf:UpdateConfig()
invert_v * (i-1-row*perrow)*(multiply*default_border + f.config.buffsize + 1),
invert_h * (row*(multiply*default_border + f.config.buffsize + 1) + (multiply*default_border + 1)))
f.buffs[i]:SetWidth(f.config.buffsize)
f.buffs[i]:SetHeight(f.config.buffsize)
f.buffs[i]:SetSize(f.config.buffsize, f.config.buffsize)
-- Create CD frame if it doesn't exist
if not f.buffs[i].cd then
@@ -808,11 +746,7 @@ function pfUI.uf:UpdateConfig()
-- immediately show/hide existing cooldown text
if f.buffs[i].cd.pfCooldownText then
if cooldown_text == 1 then
f.buffs[i].cd.pfCooldownText:Show()
else
f.buffs[i].cd.pfCooldownText:Hide()
end
f.buffs[i].cd.pfCooldownText:SetShown(cooldown_text == 1)
end
f.buffs[i].id = i
@@ -855,8 +789,7 @@ function pfUI.uf:UpdateConfig()
f.debuffs[i]:SetFrameLevel(12)
f.debuffs[i]:RegisterForClicks("RightButtonUp")
f.debuffs[i]:ClearAllPoints()
f.debuffs[i]:SetWidth(f.config.debuffsize)
f.debuffs[i]:SetHeight(f.config.debuffsize)
f.debuffs[i]:SetSize(f.config.debuffsize, f.config.debuffsize)
f.debuffs[i]:SetNormalTexture(nil)
-- Create CD frame if it doesn't exist
@@ -886,11 +819,7 @@ function pfUI.uf:UpdateConfig()
-- immediately show/hide existing cooldown text
if f.debuffs[i].cd.pfCooldownText then
if cooldown_text == 1 then
f.debuffs[i].cd.pfCooldownText:Show()
else
f.debuffs[i].cd.pfCooldownText:Hide()
end
f.debuffs[i].cd.pfCooldownText:SetShown(cooldown_text == 1)
end
f.debuffs[i].id = i
@@ -1020,8 +949,6 @@ function pfUI.uf.OnEvent()
this.update_full = true
-- UNIT_XXX Events
elseif arg1 and (arg1 == this.label .. this.id or (UnitGUID and arg1 == UnitGUID(this.label .. this.id))) then
this.lastEventUpdate = GetTime()
if event == "UNIT_PORTRAIT_UPDATE" or event == "UNIT_MODEL_CHANGED" then
this.update_portrait = true
elseif event == "UNIT_AURA" then
@@ -1043,154 +970,19 @@ local _GetTime = GetTime
pfUI.uf.now = 0
-- ============================================================================
-- GLOBAL FALLBACK THROTTLE - Limits total fallback updates across ALL frames
-- ============================================================================
pfUI.uf.fallbackThrottle = {
lastUpdate = 0,
interval = 0.1, -- 10 updates per second total (not per frame!)
updatesThisInterval = 0,
maxUpdatesPerInterval = 5 -- Max 5 frames can update per interval
}
-- ============================================================================
-- STATS SYSTEM - Performance tracking for Nampower vs Fallback
-- ============================================================================
pfUI.uf.stats = {
eventUpdates = 0,
heartbeatUpdates = 0,
earlyReturns = 0,
nampowerUsed = 0,
fallbackUsed = 0,
throttledSkips = 0,
startTime = 0,
enabled = true
}
-- Stats Frame (Live Display)
pfUI.uf.statsFrame = CreateFrame("Frame", "pfUIStatsFrame", UIParent)
pfUI.uf.statsFrame:SetWidth(200)
pfUI.uf.statsFrame:SetHeight(220)
pfUI.uf.statsFrame:SetPoint("TOPRIGHT", UIParent, "TOPRIGHT", -10, -200)
pfUI.uf.statsFrame:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 8,
insets = { left = 3, right = 3, top = 3, bottom = 3 }
})
pfUI.uf.statsFrame:SetBackdropColor(0, 0, 0, 0.8)
pfUI.uf.statsFrame:EnableMouse(true)
pfUI.uf.statsFrame:SetMovable(true)
pfUI.uf.statsFrame:SetClampedToScreen(true)
pfUI.uf.statsFrame:RegisterForDrag("LeftButton")
pfUI.uf.statsFrame:SetScript("OnDragStart", function() this:StartMoving() end)
pfUI.uf.statsFrame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
pfUI.uf.statsFrame:Hide()
-- Stats Title
pfUI.uf.statsFrame.title = pfUI.uf.statsFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
pfUI.uf.statsFrame.title:SetPoint("TOP", pfUI.uf.statsFrame, "TOP", 0, -8)
pfUI.uf.statsFrame.title:SetText("Performance")
-- Stats Text (multi-line)
pfUI.uf.statsFrame.text = pfUI.uf.statsFrame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
pfUI.uf.statsFrame.text:SetPoint("TOPLEFT", pfUI.uf.statsFrame, "TOPLEFT", 10, -30)
pfUI.uf.statsFrame.text:SetWidth(180)
pfUI.uf.statsFrame.text:SetHeight(180)
pfUI.uf.statsFrame.text:SetJustifyH("LEFT")
pfUI.uf.statsFrame.text:SetJustifyV("TOP")
pfUI.uf.statsFrame.text:SetText("Initializing...")
-- Update function for stats display
pfUI.uf.UpdateStatsDisplay = function()
local elapsed = GetTime() - pfUI.uf.stats.startTime
if elapsed < 0.1 then return end
local eventRate = pfUI.uf.stats.eventUpdates / elapsed
local heartbeatRate = pfUI.uf.stats.heartbeatUpdates / elapsed
local totalFrameUpdates = eventRate + heartbeatRate
-- Calculate Nampower vs Fallback percentages (ONLY counts actual data changes!)
local totalDataChanges = pfUI.uf.stats.nampowerUsed + pfUI.uf.stats.fallbackUsed
local nampowerPct = totalDataChanges > 0 and math.floor((pfUI.uf.stats.nampowerUsed / totalDataChanges) * 100) or 0
local fallbackPct = totalDataChanges > 0 and math.floor((pfUI.uf.stats.fallbackUsed / totalDataChanges) * 100) or 0
-- Calculate data change rate (how often HP/Mana actually changes)
local dataChangeRate = totalDataChanges / elapsed
local statsText = string.format(
"Time: %.1fs\n" ..
"|cffaaaaaa--- Frame Updates ---|r\n" ..
"Event: %.1f/s (%d)\n" ..
"Heartbeat: %.1f/s (%d)\n" ..
"Total: %.1f/s\n" ..
"\n" ..
"|cffaaaaaa--- Data Changes ---|r\n" ..
"Rate: %.1f/s (%d)\n" ..
"|cff00ff00NP: %d%% (%d)|r\n" ..
"|cffff8800FB: %d%% (%d)|r",
elapsed,
eventRate,
pfUI.uf.stats.eventUpdates,
heartbeatRate,
pfUI.uf.stats.heartbeatUpdates,
totalFrameUpdates,
dataChangeRate,
totalDataChanges,
nampowerPct,
pfUI.uf.stats.nampowerUsed,
fallbackPct,
pfUI.uf.stats.fallbackUsed
)
pfUI.uf.statsFrame.text:SetText(statsText)
end
-- Stats update timer
pfUI.uf.statsUpdateTimer = 0
-- Cache cleanup timer (clean lastUnitStats every 30s to prevent memory leak)
pfUI.uf.cacheCleanupTimer = 0
-- ============================================================================
-- OnUpdate with Heartbeat Polling and Fallback
-- OnUpdate - eventless per-frame work (range check, aggro glow) and draining
-- the event-set update flags. Frames refresh on events only; no polling.
-- ============================================================================
function pfUI.uf.OnUpdate()
local now = _GetTime()
pfUI.uf.now = now
-- Update stats display (throttled to 0.2s)
if pfUI.uf.statsFrame and pfUI.uf.statsFrame:IsShown() then
if (pfUI.uf.statsUpdateTimer or 0) <= now then
pfUI.uf.statsUpdateTimer = now + 0.2
if pfUI.uf.stats.startTime > 0 then
pfUI.uf.UpdateStatsDisplay()
end
end
end
-- Cleanup lastUnitStats cache every 30 seconds to prevent memory leak
if (pfUI.uf.cacheCleanupTimer or 0) <= now then
pfUI.uf.cacheCleanupTimer = now + 30
-- Only keep cache for units that currently exist
if pfUI.api.lastUnitStats then
for unitstr in pairs(pfUI.api.lastUnitStats) do
if not _G.UnitExists(unitstr) then
pfUI.api.lastUnitStats[unitstr] = nil
end
end
end
end
-- update combat feedback (no throttle - needs immediate feedback)
if this.feedbackText then CombatFeedback_OnUpdate(arg1) end
-- Throttle raid/party frames for performance
if this.label == "raid" or this.label == "party" then
if (this.throttleTick or 0) > now then
if pfUI.uf.stats and pfUI.uf.stats.enabled then
pfUI.uf.stats.throttledSkips = pfUI.uf.stats.throttledSkips + 1
end
return
end
this.throttleTick = now + 0.1 -- Default: 10 FPS
@@ -1274,19 +1066,7 @@ function pfUI.uf.OnUpdate()
local unit = this.label .. this.id
local heal = libpredict:UnitGetIncomingHeals(unit)
-- O(1) Nampower lookup via GUID (same pattern as nameplates.lua)
local health, maxHealth
if GetUnitField then
local guid = UnitGUID(unit)
if guid then
health = GetUnitField(guid, "health")
maxHealth = GetUnitField(guid, "maxHealth")
end
end
-- Fallback to standard API
if not health or not maxHealth or maxHealth == 0 then
health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
end
local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
if heal - health - maxHealth ~= this.predictstate then
local overhealperc = tonumber(this.config.overhealperc)
@@ -1343,86 +1123,6 @@ function pfUI.uf.OnUpdate()
-- EVENT-BASED UPDATES (Health, Mana, Auras, etc.)
-- ============================================================================
-- Check if we have pending updates from events
local hasUpdates = this.update_full or this.update_base or
this.update_aura or this.update_portrait or
this.update_pvp or this.update_indicators
-- Track event-triggered updates (not API calls, just frame updates)
if hasUpdates and pfUI.uf.stats and pfUI.uf.stats.enabled then
pfUI.uf.stats.eventUpdates = pfUI.uf.stats.eventUpdates + 1
end
-- Heartbeat Polling: If no events pending, check if we need fallback
if not hasUpdates then
local timeSinceEvent = this.lastEventUpdate and (now - this.lastEventUpdate) or 999
-- If >0.5s since last event and unit exists, try heartbeat
if timeSinceEvent > 0.5 and this.label and _G.UnitExists(this.label .. this.id) then
local needsFallback = false
-- Check if Nampower can provide data
if GetUnitField then
-- Use _G.UnitExists to avoid conflicts with range checking
local unitstr = this.label .. this.id
local exists = _G.UnitExists(unitstr)
if exists then
local _, guid = _G.UnitExists(unitstr)
if guid then
local hp = GetUnitField(guid, "health")
if not hp or hp == 0 then
needsFallback = true
end
else
needsFallback = true
end
else
needsFallback = true
end
else
needsFallback = true
end
if needsFallback then
-- GLOBAL Throttle: Limit fallback updates across ALL frames
local throttle = pfUI.uf.fallbackThrottle
-- Reset counter each interval
if now - throttle.lastUpdate > throttle.interval then
throttle.lastUpdate = now
throttle.updatesThisInterval = 0
end
-- Check if we've exceeded max updates this interval
if throttle.updatesThisInterval >= throttle.maxUpdatesPerInterval then
if pfUI.uf.stats and pfUI.uf.stats.enabled then
pfUI.uf.stats.earlyReturns = pfUI.uf.stats.earlyReturns + 1
end
return
end
throttle.updatesThisInterval = throttle.updatesThisInterval + 1
-- Nampower not available or no data - trigger fallback update
this.update_base = true
if pfUI.uf.stats and pfUI.uf.stats.enabled then
pfUI.uf.stats.heartbeatUpdates = pfUI.uf.stats.heartbeatUpdates + 1
end
else
-- Nampower working fine, no update needed
if pfUI.uf.stats and pfUI.uf.stats.enabled then
pfUI.uf.stats.earlyReturns = pfUI.uf.stats.earlyReturns + 1
end
return
end
else
-- Too soon or unit doesn't exist
if pfUI.uf.stats and pfUI.uf.stats.enabled then
pfUI.uf.stats.earlyReturns = pfUI.uf.stats.earlyReturns + 1
end
return
end
end
-- process indicator update events
if this.update_indicators then
@@ -1480,15 +1180,9 @@ end
function pfUI.uf.OnEnter()
if not this.label then return end
-- Nampower: Set native mouseover unit for macro/addon compatibility
if SetMouseoverUnit then
local unitstr = this.label .. this.id
-- For GUID-based frames (focus), use the GUID directly
if this.label and string.find(this.label, "^0x") then
SetMouseoverUnit(this.label)
elseif UnitExists(unitstr) then
SetMouseoverUnit(unitstr)
end
local unitstr = this.label .. this.id
if UnitExists(unitstr) then
SetMouseoverUnit(unitstr)
end
if this.config.showtooltip == "0" then return end
@@ -1498,10 +1192,7 @@ function pfUI.uf.OnEnter()
end
function pfUI.uf.OnLeave()
-- Nampower: Clear native mouseover unit
if SetMouseoverUnit then
SetMouseoverUnit()
end
SetMouseoverUnit("")
GameTooltip:FadeOut()
end
@@ -1638,6 +1329,19 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
f.power = CreateFrame("Frame",nil, f)
f.power.bar = CreateStatusBar(nil, f.power)
-- Druid secondary mana bar: shows base mana (read via ClassicAPI
-- UnitPower(unit, Enum.PowerType.Mana), which works regardless of the active
-- power) while shapeshifted into a form that uses energy/rage. Player +
-- target only;
-- styled/positioned in UpdateConfig, driven in UpdateDruidMana.
if C.unitframes.druidmanabar == "1" and (f.label == "player" or f.label == "target") then
f.druidmana = CreateFrame("StatusBar", "pfDruidMana_" .. f.label .. f.id, f)
f.druidmana.text = f.druidmana:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
f.druidmana.text:SetPoint("CENTER", f.druidmana, "CENTER", 0, 0)
f.druidmana.text:SetJustifyH("CENTER")
f.druidmana:Hide()
end
f.glow = CreateFrame("Frame", nil, f)
f.combat = CreateFrame("Frame", nil, f.hp.bar)
f.combat.tex = f.combat:CreateTexture(nil, "OVERLAY")
@@ -1813,7 +1517,7 @@ function pfUI.uf:RefreshIndicators(unit)
end
if unit.happinessIcon and unit:GetName() == "pfPet" then -- Happiness Icon
local _, pclass = UnitClass("player")
local pclass = UnitClassBase("player")
if unit.config.happinessicon == "0" or pclass ~= "HUNTER" then
unit.happinessIcon:Hide()
else
@@ -1847,6 +1551,32 @@ function pfUI.uf:RefreshIndicators(unit)
end
end
-- Druid secondary mana bar update. Reads base mana with ClassicAPI
-- UnitPower/UnitPowerMax(unit, Enum.PowerType.Mana), which return the mana
-- slot regardless of the unit's active power -- so it works while shapeshifted,
-- with no nampower/GetUnitField dependency. Shown only while off mana
-- (Cat=energy, Bear=rage); non-player frames only for druid units.
function pfUI.uf:UpdateDruidMana(unit)
local bar = unit.druidmana
local unitstr = unit.label .. unit.id
if not UnitExists(unitstr) then bar:Hide() return end
if unit.label ~= "player" then
local cls = UnitClassBase(unitstr)
if cls ~= "DRUID" then bar:Hide() return end
end
if UnitPowerType(unitstr) == Enum.PowerType.Mana then bar:Hide() return end
local mana, maxmana = UnitPower(unitstr, Enum.PowerType.Mana), UnitPowerMax(unitstr, Enum.PowerType.Mana)
if not maxmana or maxmana == 0 then bar:Hide() return end
bar:SetMinMaxValues(0, maxmana)
bar:SetValue(mana)
if C.unitframes.druidmanatext == "1" then
bar.text:SetText(pfUI.api.Abbreviate(mana) .. "/" .. pfUI.api.Abbreviate(maxmana))
else
bar.text:SetText("")
end
bar:Show()
end
function pfUI.uf:RefreshUnit(unit, component)
-- break early on misconfigured UF's
if not unit.label then return end
@@ -2050,8 +1780,7 @@ function pfUI.uf:RefreshUnit(unit, component)
if size ~= indicator.size or disptype ~= indicator.disp or indipos ~= indicator.ipos then
indicator:ClearAllPoints()
indicator:SetPoint(indipos, 0, 0)
indicator:SetHeight(size)
indicator:SetWidth(size)
indicator:SetSize(size, size)
indicator.size = size
indicator.disp = disptype
indicator.ipos = indipos
@@ -2080,16 +1809,14 @@ function pfUI.uf:RefreshUnit(unit, component)
indicator[debuff].tex:SetVertexColor(dispelColor:GetRGBA())
indicator[debuff].tex:Show()
indicator[debuff]:ClearAllPoints()
indicator[debuff]:SetHeight(size)
indicator[debuff]:SetWidth(size)
indicator[debuff]:SetSize(size, size)
indicator[debuff]:SetBackdrop(nil)
elseif disptype == "3" then
indicator[debuff].tex:SetTexture(dispelColor:GetRGBA())
indicator[debuff].tex:SetVertexColor(1,1,1,1)
indicator[debuff].tex:Show()
indicator[debuff]:ClearAllPoints()
indicator[debuff]:SetHeight(size)
indicator[debuff]:SetWidth(size)
indicator[debuff]:SetSize(size, size)
indicator[debuff]:SetBackdrop(nil)
elseif disptype == "2" then
indicator[debuff].tex:Hide()
@@ -2267,7 +1994,7 @@ function pfUI.uf:RefreshUnit(unit, component)
-- base frame
if component == "all" or component == "base" then
-- Unit HP/MP with Nampower Integration
local hp, hpmax, power, powermax, powerType = pfUI.api.GetUnitStats(unitstr, true)
local hp, hpmax, power, powermax, powerType = pfUI.api.GetUnitStats(unitstr)
-- Store original values for color calculations (before invert_healthbar modifies hp)
local hp_orig, hpmax_orig = hp, hpmax
@@ -2351,13 +2078,13 @@ function pfUI.uf:RefreshUnit(unit, component)
local r, g, b, a = .5, .5, .5, 1
local utype = UnitPowerType(unitstr)
if utype == 0 then
if utype == Enum.PowerType.Mana then
r, g, b, a = GetStringColor(mana)
elseif utype == 1 then
elseif utype == Enum.PowerType.Rage then
r, g, b, a = GetStringColor(rage)
elseif utype == 2 then
elseif utype == Enum.PowerType.Focus then
r, g, b, a = GetStringColor(focus)
elseif utype == 3 then
elseif utype == Enum.PowerType.Energy then
r, g, b, a = GetStringColor(energy)
end
@@ -2393,6 +2120,8 @@ function pfUI.uf:RefreshUnit(unit, component)
end
end
if unit.druidmana then pfUI.uf:UpdateDruidMana(unit) end
pfUI.uf:RefreshUnitState(unit)
end
end
@@ -2483,7 +2212,7 @@ function pfUI.uf:ClickAction(button)
-- drop food on petframe
if label == "pet" and CursorHasItem() then
local _, playerClass = UnitClass("player")
local playerClass = UnitClassBase("player")
if playerClass == "HUNTER" then
DropItemOnUnit("pet")
return
@@ -2536,8 +2265,7 @@ function pfUI.uf:AddIcon(frame, pos, icon, timeleft, stacks, start, duration)
-- update icon configuration
if frame.icon[pos].iconsize ~= iconsize or frame.icon[pos].spacing ~= spacing then
frame.icon[pos]:SetWidth(iconsize)
frame.icon[pos]:SetHeight(iconsize)
frame.icon[pos]:SetSize(iconsize, iconsize)
frame.icon[pos]:SetPoint("TOPLEFT", frame.icon, "TOPLEFT", (pos-1)*(iconsize + spacing), 0)
frame.icon[pos].stacks:SetFont(pfUI.font_unit, math.max(iconsize/3, 10), "OUTLINE")
frame.icon[pos].iconsize = iconsize
@@ -2593,7 +2321,7 @@ function pfUI.uf:HideIcon(frame, pos)
end
function pfUI.uf:SetupDebuffFilter(allclasses)
local _, myclass = UnitClass("player")
local myclass = UnitClassBase("player")
local debuffs = {}
if myclass == "PALADIN" or myclass == "PRIEST" or myclass == "WARLOCK" or allclasses then
@@ -2616,7 +2344,7 @@ function pfUI.uf:SetupDebuffFilter(allclasses)
end
function pfUI.uf:SetupBuffIndicators(config)
local _, myclass = UnitClass("player")
local myclass = UnitClassBase("player")
local indicators = {}
if config.show_buffs == "1" then -- buffs
@@ -2840,7 +2568,7 @@ function pfUI.uf:GetStatusValue(unit, pos)
end
-- Get stats with Nampower Integration
local hp, hpmax, mp, mpmax, powerType = pfUI.api.GetUnitStats(unitstr, true)
local hp, hpmax, mp, mpmax, powerType = pfUI.api.GetUnitStats(unitstr)
local rhp, rhpmax = hp, hpmax
-- Use libhealth for mob health estimation (overrides Nampower/Standard)
@@ -2870,6 +2598,19 @@ function pfUI.uf:GetStatusValue(unit, pos)
else
return ""
end
elseif config == "ownername" then
local owner
if unit.label == "raidpet" then owner = "raid" .. unit.id
elseif unit.label == "partypet" then owner = "party" .. unit.id
elseif unit.label == "pet" then owner = "player" end
if not (owner and UnitExists(owner)) then return "" end
local color = ""
if unit.config["classcolor"] == "1" and UnitIsPlayer(owner) then
local _, r, g, b = GetUnitColor(owner)
if C.unitframes.pastel == "1" then r, g, b = (r+.75)*.5, (g+.75)*.5, (b+.75)*.5 end
color = rgbhex(r, g, b)
end
return color .. pfUI.uf:GetNameString(owner)
-- health
elseif config == "health" then
@@ -2929,7 +2670,7 @@ function pfUI.uf:GetStatusValue(unit, pos)
elseif config == "powermax" then
return unit:GetColor("power") .. pfUI.api.Abbreviate(mpmax)
elseif config == "powerperc" then
local perc = UnitManaMax(unitstr) > 0 and ceil(mp / mpmax * 100) or 0
local perc = UnitPowerMax(unitstr) > 0 and ceil(mp / mpmax * 100) or 0
return unit:GetColor("power") .. perc
elseif config == "powermiss" then
local power = ceil(mp - mpmax)
@@ -2940,7 +2681,7 @@ function pfUI.uf:GetStatusValue(unit, pos)
end
elseif config == "powerdyn" then
-- show percentage when only mana is less than 100%
if mp ~= mpmax and UnitPowerType(unitstr) == 0 then
if mp ~= mpmax and UnitPowerType(unitstr) == Enum.PowerType.Mana then
return unit:GetColor("power") .. pfUI.api.Abbreviate(mp) .. " - " .. ceil(mp / mpmax * 100) .. "%"
else
return unit:GetColor("power") .. pfUI.api.Abbreviate(mp)
@@ -2983,19 +2724,7 @@ function pfUI.uf.GetColor(self, preset)
r, g, b = color.r, color.g, color.b
elseif preset == "health" and config["healthcolor"] == "1" then
-- O(1) Nampower lookup for health gradient color
local hp, hpmax
if GetUnitField then
local guid = UnitGUID(unitstr)
if guid then
hp = GetUnitField(guid, "health")
hpmax = GetUnitField(guid, "maxHealth")
end
end
-- Fallback to standard API
if not hp or not hpmax then
hp, hpmax = UnitHealth(unitstr), UnitHealthMax(unitstr)
end
local hp, hpmax = UnitHealth(unitstr), UnitHealthMax(unitstr)
if hpmax and hpmax > 0 then
r, g, b = GetColorGradient(hp / hpmax)
else
@@ -3017,61 +2746,3 @@ function pfUI.uf.GetColor(self, preset)
return rgbhex(r,g,b)
end
-- ============================================================================
-- Slash Commands for Stats Frame
-- ============================================================================
_G.SLASH_PFUISTATS1 = "/pfuistats"
_G.SLASH_PFUISTATS2 = "/ufstats"
_G.SlashCmdList["PFUISTATS"] = function(msg)
msg = string.lower(msg or "")
if not pfUI.uf.stats then
DEFAULT_CHAT_FRAME:AddMessage("|cffff0000ERROR:|r Stats not initialized!")
return
end
-- Initialize startTime on first use
if pfUI.uf.stats.startTime == 0 then
pfUI.uf.stats.startTime = GetTime()
end
if msg == "reset" then
pfUI.uf.stats.eventUpdates = 0
pfUI.uf.stats.heartbeatUpdates = 0
pfUI.uf.stats.earlyReturns = 0
pfUI.uf.stats.nampowerUsed = 0
pfUI.uf.stats.fallbackUsed = 0
pfUI.uf.stats.throttledSkips = 0
pfUI.uf.stats.startTime = GetTime()
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00pfUI Stats:|r Reset!")
elseif msg == "toggle" then
pfUI.uf.stats.enabled = not pfUI.uf.stats.enabled
local status = pfUI.uf.stats.enabled and "|cff00ff00ON|r" or "|cffff0000OFF|r"
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00pfUI Stats:|r Tracking: " .. status)
elseif msg == "show" then
if pfUI.uf.statsFrame then
pfUI.uf.statsFrame:Show()
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00pfUI Stats:|r Frame shown")
end
elseif msg == "hide" then
if pfUI.uf.statsFrame then
pfUI.uf.statsFrame:Hide()
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00pfUI Stats:|r Frame hidden")
end
else
-- Toggle frame (default action)
if pfUI.uf.statsFrame then
if pfUI.uf.statsFrame:IsShown() then
pfUI.uf.statsFrame:Hide()
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00pfUI Stats:|r Frame hidden")
else
pfUI.uf.statsFrame:Show()
DEFAULT_CHAT_FRAME:AddMessage("|cff00ff00pfUI Stats:|r Frame shown")
end
end
end
end
-9
View File
@@ -29,15 +29,6 @@ UNITFRAME_SECURE_TEMPLATE = nil
--[[ Vanilla API Extensions ]]--
do -- GetItemInfo
local name, link, rarity, minlevel, itype, isubtype, stack
function GetItemInfo(item)
if not item then return end
name, link, rarity, minlevel, itype, isubtype, stack = _G.GetItemInfo(item)
return name, link, rarity, nil, minlevel, itype, isubtype, stack
end
end
do -- RunMacroText
local obj = { ["GetText"] = function(self) return self.text end }
obj = setmetatable(obj, {__index = function(tab,key)
-17
View File
@@ -1,20 +1,3 @@
-- this table is added in later expansions
CLASS_SORT_ORDER = CLASS_SORT_ORDER or {
"WARRIOR",
"DEATHKNIGHT",
"PALADIN",
"MONK",
"PRIEST",
"SHAMAN",
"DRUID",
"ROGUE",
"MAGE",
"WARLOCK",
"HUNTER",
"DEMONHUNTER",
"UNKNOWN",
}
CLASS_ICON_TCOORDS = CLASS_ICON_TCOORDS or {
["WARRIOR"] = {0, 0.25, 0, 0.25},
["MAGE"] = {0.25, 0.49609375, 0, 0.25},
+7 -4
View File
@@ -27,7 +27,6 @@ pfUI_translation["deDE"] = {
["Always Show Item Comparison"] = nil,
["Always Show On Target Units"] = nil,
["Always Show On Units With Missing HP"] = nil,
["Always Show Self In Raid Frames"] = nil,
["Always Use 2D Portraits"] = nil,
["Ammo Counter"] = nil,
["Anchor Bags Above Chat"] = nil,
@@ -124,6 +123,7 @@ pfUI_translation["deDE"] = {
["Click Casting"] = nil,
["Clock"] = nil,
["Close"] = nil,
["Collapse Empty Slots"] = nil,
["Color"] = nil,
["Color Buff Stacks"] = nil,
["Color Debuff Stacks"] = nil,
@@ -138,7 +138,6 @@ pfUI_translation["deDE"] = {
["Combat Timer"] = nil,
["Combopoint Height"] = nil,
["Combopoint Width"] = nil,
["Compare Item Base Stats"] = nil,
["Components"] = nil,
["Config UI Settings"] = nil,
["Configuration"] = nil,
@@ -569,6 +568,7 @@ pfUI_translation["deDE"] = {
["Overwrite If Unit Is Attacking Others"] = nil,
["Overwrite If Unit Is Attacking You"] = nil,
["Overwrite If Unit Is Casting"] = nil,
["Owner Name"] = nil,
["Pageable"] = nil,
["Paging Actionbar"] = nil,
["Panel"] = nil,
@@ -616,12 +616,13 @@ pfUI_translation["deDE"] = {
["Raid Mark X-Offset"] = nil,
["Raid Mark Y-Offset"] = nil,
["Raid Padding"] = nil,
["Raid-Pet"] = nil,
["Random"] = nil,
["Random Roll Announcement Rarity"] = nil,
["Random Rolling"] = nil,
["Range Based Hunter Paging"] = nil,
["Range Check Interval"] = nil,
["Rank"] = nil,
["Recast Totem"] = nil,
["Red Border On Enemy Units"] = nil,
["Red Name Text On Infight Units"] = nil,
["Regional Settings"] = nil,
@@ -703,6 +704,7 @@ pfUI_translation["deDE"] = {
["Show Description"] = nil,
["Show Dispel Indicators"] = nil,
["Show Druid Mana Bar"] = nil,
["Show Druid Mana Bar Text"] = nil,
["Show Duration Inside Buff"] = nil,
["Show Empty Buttons"] = nil,
["Show FPS and Latency Colors"] = nil,
@@ -739,6 +741,7 @@ pfUI_translation["deDE"] = {
["Show Required Questitem Count"] = nil,
["Show Resting"] = nil,
["Show Self In Group Frames"] = nil,
["Show Self In Raid Frames When Solo"] = nil,
["Show Spell Icon"] = nil,
["Show Spell Name"] = nil,
["Show Stacks"] = nil,
@@ -783,6 +786,7 @@ pfUI_translation["deDE"] = {
["Target Castbar"] = nil,
["Target Debuff Bar"] = nil,
["Target Nameplate Zoom Factor"] = nil,
["Target Totem"] = nil,
["Target-Target"] = nil,
["Target-Target-Target"] = nil,
["Text"] = nil,
@@ -877,7 +881,6 @@ pfUI_translation["deDE"] = {
["XP Percentage"] = nil,
["Yellow Border On Neutral Units"] = nil,
["Yes"] = nil,
["You gain (.+) Mana from Totemic Recall"] = nil,
["You got"] = nil,
["Your interface is now set up.\n\nFor advanced configuration, just open the |cff33ffccpf|rUI settings via the escape menu or type \"|cffffffaa/pfui|r\" into the chat.\n\n Have a nice trip!\n\n|cffaaaaaa- Shagu"] = nil,
["Your items have been repaired for"] = nil,
+17 -4
View File
@@ -19,6 +19,7 @@ pfUI_translation["enUS"] = {
["Align Chat Windows"] = nil,
["Aligned Position"] = nil,
["All messages will be forwarded to:"] = nil,
["All players passed"] = nil,
["Alt-Click Action"] = nil,
["Always Allow Drag Via Shift Key"] = nil,
["Always Show"] = nil,
@@ -27,7 +28,6 @@ pfUI_translation["enUS"] = {
["Always Show Item Comparison"] = nil,
["Always Show On Target Units"] = nil,
["Always Show On Units With Missing HP"] = nil,
["Always Show Self In Raid Frames"] = nil,
["Always Use 2D Portraits"] = nil,
["Ammo Counter"] = nil,
["Anchor Bags Above Chat"] = nil,
@@ -119,11 +119,13 @@ pfUI_translation["enUS"] = {
["Chat Bubble Transparency"] = nil,
["Chat Default Brackets"] = nil,
["Class"] = nil,
["Clear"] = nil,
["Clear Rolls"] = nil,
["Click Action"] = nil,
["Click Casting"] = nil,
["Clock"] = nil,
["Close"] = nil,
["Collapse Empty Slots"] = nil,
["Color"] = nil,
["Color Buff Stacks"] = nil,
["Color Debuff Stacks"] = nil,
@@ -138,7 +140,6 @@ pfUI_translation["enUS"] = {
["Combat Timer"] = nil,
["Combopoint Height"] = nil,
["Combopoint Width"] = nil,
["Compare Item Base Stats"] = nil,
["Components"] = nil,
["Config UI Settings"] = nil,
["Configuration"] = nil,
@@ -195,6 +196,7 @@ pfUI_translation["enUS"] = {
["Deficit"] = nil,
["Delete profile"] = nil,
["Delete / Reset"] = nil,
["Dependencies"] = nil,
["Descending"] = nil,
["Description Font"] = nil,
["Description Font Size"] = nil,
@@ -409,6 +411,7 @@ pfUI_translation["enUS"] = {
["Highlight Equipped Items"] = nil,
["Highlight Not Usable Spells"] = nil,
["Highlight Out Of Mana Spells"] = nil,
["Highlight New Items"] = nil,
["Highlight Out Of Range Spells"] = nil,
["Highlight Settings That Require Reload"] = nil,
["Highlight Unusable Items"] = nil,
@@ -477,6 +480,7 @@ pfUI_translation["enUS"] = {
["Look & Feel"] = nil,
["Loot"] = nil,
["Loot & Spam"] = nil,
["Loot History"] = nil,
["Macro Text Color"] = nil,
["Macro Text Size"] = nil,
["Main Actionbar"] = nil,
@@ -499,6 +503,7 @@ pfUI_translation["enUS"] = {
["Menu Font Size"] = nil,
["Messages are no longer forwarded to:"] = nil,
["Middle Mouse Button"] = nil,
["Missing"] = nil,
["Minimap"] = nil,
["Minimap Panel"] = nil,
["Minimap Size (|cffffaaaaExperimental|r)"] = nil,
@@ -525,6 +530,7 @@ pfUI_translation["enUS"] = {
["Network Latency"] = nil,
["Network Up"] = nil,
["New entry:"] = nil,
["New Item Color"] = nil,
["NEW TIMER"] = nil,
["Next"] = nil,
["Next Memory Cleanup"] = nil,
@@ -552,6 +558,7 @@ pfUI_translation["enUS"] = {
["Only Show Own Debuffs (|cffffaaaaExperimental|r)"] = nil,
["Only Show Target Castbar"] = nil,
["On State Change"] = nil,
["Optional Dependencies"] = nil,
["Options"] = nil,
["Orientation"] = nil,
["Other Panel: Minimap"] = nil,
@@ -569,6 +576,7 @@ pfUI_translation["enUS"] = {
["Overwrite If Unit Is Attacking Others"] = nil,
["Overwrite If Unit Is Attacking You"] = nil,
["Overwrite If Unit Is Casting"] = nil,
["Owner Name"] = nil,
["Pageable"] = nil,
["Paging Actionbar"] = nil,
["Panel"] = nil,
@@ -616,12 +624,13 @@ pfUI_translation["enUS"] = {
["Raid Mark X-Offset"] = nil,
["Raid Mark Y-Offset"] = nil,
["Raid Padding"] = nil,
["Raid-Pet"] = nil,
["Random"] = nil,
["Random Roll Announcement Rarity"] = nil,
["Random Rolling"] = nil,
["Range Based Hunter Paging"] = nil,
["Range Check Interval"] = nil,
["Rank"] = nil,
["Recast Totem"] = nil,
["Red Border On Enemy Units"] = nil,
["Red Name Text On Infight Units"] = nil,
["Regional Settings"] = nil,
@@ -645,6 +654,7 @@ pfUI_translation["enUS"] = {
["Resting"] = nil,
["Reveal Unexplored Areas"] = nil,
["Switch to current zone"] = nil,
["Retrieving item information..."] = nil,
["Right"] = nil,
["Right Actionbar"] = nil,
["Right Anchor"] = nil,
@@ -703,6 +713,7 @@ pfUI_translation["enUS"] = {
["Show Description"] = nil,
["Show Dispel Indicators"] = nil,
["Show Druid Mana Bar"] = nil,
["Show Druid Mana Bar Text"] = nil,
["Show Duration Inside Buff"] = nil,
["Show Empty Buttons"] = nil,
["Show FPS and Latency Colors"] = nil,
@@ -739,6 +750,7 @@ pfUI_translation["enUS"] = {
["Show Required Questitem Count"] = nil,
["Show Resting"] = nil,
["Show Self In Group Frames"] = nil,
["Show Self In Raid Frames When Solo"] = nil,
["Show Spell Icon"] = nil,
["Show Spell Name"] = nil,
["Show Stacks"] = nil,
@@ -780,12 +792,14 @@ pfUI_translation["enUS"] = {
["Switch Pages On Alt Key Press"] = nil,
["Switch Pages On Ctrl Key Press"] = nil,
["Switch Pages On Druid Stealth"] = nil,
["Switch Pages On Priest Shadowform"] = nil,
["Switch Pages On Shift Key Press"] = nil,
["Systeminfo"] = nil,
["Target"] = nil,
["Target Castbar"] = nil,
["Target Debuff Bar"] = nil,
["Target Nameplate Zoom Factor"] = nil,
["Target Totem"] = nil,
["Target-Target"] = nil,
["Target-Target-Target"] = nil,
["Text"] = nil,
@@ -883,7 +897,6 @@ pfUI_translation["enUS"] = {
["XP Percentage"] = nil,
["Yellow Border On Neutral Units"] = nil,
["Yes"] = nil,
["You gain (.+) Mana from Totemic Recall"] = nil,
["You got"] = nil,
["Your interface is now set up.\n\nFor advanced configuration, just open the |cff33ffccpf|rUI settings via the escape menu or type \"|cffffffaa/pfui|r\" into the chat.\n\n Have a nice trip!\n\n|cffaaaaaa- Shagu"] = nil,
["Your items have been repaired for"] = nil,
+7 -4
View File
@@ -27,7 +27,6 @@ pfUI_translation["esES"] = {
["Always Show Item Comparison"] = "Mostrar siempre la comparativa entre objetos",
["Always Show On Target Units"] = "Mostrar siempre en el objectivo",
["Always Show On Units With Missing HP"] = "Mostrar siempre en unidades con falta de salud",
["Always Show Self In Raid Frames"] = "Mostrarse siempre a sí mismo en los marcos de banda",
["Always Use 2D Portraits"] = "Usar siempre retratos 2D",
["Ammo Counter"] = "Contador de munición",
["Anchor Bags Above Chat"] = nil,
@@ -124,6 +123,7 @@ pfUI_translation["esES"] = {
["Click Casting"] = "Lanzamiento al hacer click",
["Clock"] = "Reloj",
["Close"] = "Cerrar",
["Collapse Empty Slots"] = nil,
["Color"] = nil,
["Color Buff Stacks"] = "Colorear pilas de beneficios",
["Color Debuff Stacks"] = "Colorear pilas de perjuicios",
@@ -138,7 +138,6 @@ pfUI_translation["esES"] = {
["Combat Timer"] = "Temporizador de combate",
["Combopoint Height"] = nil,
["Combopoint Width"] = nil,
["Compare Item Base Stats"] = "Comparar estadísticas bases de objetos",
["Components"] = "Componentes",
["Config UI Settings"] = nil,
["Configuration"] = "Configuración",
@@ -569,6 +568,7 @@ pfUI_translation["esES"] = {
["Overwrite If Unit Is Attacking Others"] = nil,
["Overwrite If Unit Is Attacking You"] = nil,
["Overwrite If Unit Is Casting"] = nil,
["Owner Name"] = nil,
["Pageable"] = "Paginable",
["Paging Actionbar"] = "Paginando la barra de acción",
["Panel"] = "Panel",
@@ -616,12 +616,13 @@ pfUI_translation["esES"] = {
["Raid Mark X-Offset"] = nil,
["Raid Mark Y-Offset"] = nil,
["Raid Padding"] = "Espaciado del marco de banda",
["Raid-Pet"] = nil,
["Random"] = "Aleatorio",
["Random Roll Announcement Rarity"] = "Anuncio para tirar los dados aleatoriamente",
["Random Rolling"] = "Tirar los dados aleatoriamente",
["Range Based Hunter Paging"] = "Paginado de alcance para cazadores",
["Range Check Interval"] = "Intervalo de comprobación de alcance",
["Rank"] = "Rango",
["Recast Totem"] = nil,
["Red Border On Enemy Units"] = "Borde rojo en unidades enemigas",
["Red Name Text On Infight Units"] = nil,
["Regional Settings"] = nil,
@@ -703,6 +704,7 @@ pfUI_translation["esES"] = {
["Show Description"] = "Mostrar descripción",
["Show Dispel Indicators"] = "Mostrar indicadores para disipar",
["Show Druid Mana Bar"] = nil,
["Show Druid Mana Bar Text"] = nil,
["Show Duration Inside Buff"] = "Mostrar la duración dentro del beneficios",
["Show Empty Buttons"] = "Mostrar botones vacíos",
["Show FPS and Latency Colors"] = "Mostrar FPS y colores de latencia",
@@ -739,6 +741,7 @@ pfUI_translation["esES"] = {
["Show Required Questitem Count"] = "Muestra el número requerido de objetos de misión",
["Show Resting"] = "Mostrar descanso",
["Show Self In Group Frames"] = "Mostrar a sí mismo en marcos de grupo",
["Show Self In Raid Frames When Solo"] = nil,
["Show Spell Icon"] = "Mostrar icono de hechizo",
["Show Spell Name"] = nil,
["Show Stacks"] = "Mostrar pilas",
@@ -783,6 +786,7 @@ pfUI_translation["esES"] = {
["Target Castbar"] = "Barra de lanzamiento del objetivo",
["Target Debuff Bar"] = "Barra de perjuicios del objetivo",
["Target Nameplate Zoom Factor"] = "Factor de zoom de la placa de nombre del objetivo",
["Target Totem"] = nil,
["Target-Target"] = "Objetivo-Objetivo",
["Target-Target-Target"] = "Objetivo-Objetivo-Objetivo",
["Text"] = nil,
@@ -877,7 +881,6 @@ pfUI_translation["esES"] = {
["XP Percentage"] = "Porcentaje de exp.",
["Yellow Border On Neutral Units"] = "Borde amarillo en unidades neutrales",
["Yes"] = "",
["You gain (.+) Mana from Totemic Recall"] = nil,
["You got"] = "Obtienes",
["Your interface is now set up.\n\nFor advanced configuration, just open the |cff33ffccpf|rUI settings via the escape menu or type \"|cffffffaa/pfui|r\" into the chat.\n\n Have a nice trip!\n\n|cffaaaaaa- Shagu"] = "Ahora su interfaz está configurada.\n\nPara la configuración avanzada, abra la configuración |cff33ffccpf|rUI por el menú de escape o escriba \"|cffffffaa/pfui|r\" en el chat.",
["Your items have been repaired for"] = "Tus objetos se han reparado por",
+7 -4
View File
@@ -27,7 +27,6 @@ pfUI_translation["frFR"] = {
["Always Show Item Comparison"] = "Toujours afficher la comparaison d'objet",
["Always Show On Target Units"] = "Toujours montrer sur la cible",
["Always Show On Units With Missing HP"] = "Toujours montrer sur les cibles avec de la vie manquante",
["Always Show Self In Raid Frames"] = "Toujours montrer soi-même dans le cadre de raid",
["Always Use 2D Portraits"] = "Toujours utiliser les portraits 2D",
["Ammo Counter"] = "Compteur de munitions",
["Anchor Bags Above Chat"] = nil,
@@ -124,6 +123,7 @@ pfUI_translation["frFR"] = {
["Click Casting"] = "Clique sur le lancement de sort",
["Clock"] = "Horloge",
["Close"] = "Fermer",
["Collapse Empty Slots"] = nil,
["Color"] = nil,
["Color Buff Stacks"] = "Couleur des l'empilements des Améliorations",
["Color Debuff Stacks"] = "Couleur de l'empilements de Affaiblissements",
@@ -138,7 +138,6 @@ pfUI_translation["frFR"] = {
["Combat Timer"] = "Chronomètre de combat",
["Combopoint Height"] = nil,
["Combopoint Width"] = nil,
["Compare Item Base Stats"] = "Compare les stats de base d'un objet",
["Components"] = "Composants",
["Config UI Settings"] = nil,
["Configuration"] = "Configuration",
@@ -569,6 +568,7 @@ pfUI_translation["frFR"] = {
["Overwrite If Unit Is Attacking Others"] = nil,
["Overwrite If Unit Is Attacking You"] = nil,
["Overwrite If Unit Is Casting"] = nil,
["Owner Name"] = nil,
["Pageable"] = "Pageable",
["Paging Actionbar"] = "Barre d'action de pagination",
["Panel"] = "Panneau",
@@ -616,12 +616,13 @@ pfUI_translation["frFR"] = {
["Raid Mark X-Offset"] = nil,
["Raid Mark Y-Offset"] = nil,
["Raid Padding"] = "Remplissage du Raid",
["Raid-Pet"] = nil,
["Random"] = "Aléatoire",
["Random Roll Announcement Rarity"] = "Rareté des annonces des jets de dés aléatoires",
["Random Rolling"] = "Lancer de dés aléatoires",
["Range Based Hunter Paging"] = "Pagination de distance basée sur le chasseur",
["Range Check Interval"] = "Intervalle de vérification de la distance",
["Rank"] = nil,
["Recast Totem"] = nil,
["Red Border On Enemy Units"] = "Bordure rouge sur les unités ennemies",
["Red Name Text On Infight Units"] = nil,
["Regional Settings"] = nil,
@@ -703,6 +704,7 @@ pfUI_translation["frFR"] = {
["Show Description"] = "Afficher les descriptions",
["Show Dispel Indicators"] = "Afficher les indicateurs de dissipation",
["Show Druid Mana Bar"] = nil,
["Show Druid Mana Bar Text"] = nil,
["Show Duration Inside Buff"] = "Afficher la durée à l'intérieur des améliorations",
["Show Empty Buttons"] = "Afficher les boutons vides",
["Show FPS and Latency Colors"] = nil,
@@ -739,6 +741,7 @@ pfUI_translation["frFR"] = {
["Show Required Questitem Count"] = nil,
["Show Resting"] = "Afficher au repos",
["Show Self In Group Frames"] = "S'afficher dans les cadres de groupe",
["Show Self In Raid Frames When Solo"] = nil,
["Show Spell Icon"] = "Afficher l'icone des sorts",
["Show Spell Name"] = nil,
["Show Stacks"] = "Afficher les empilements",
@@ -783,6 +786,7 @@ pfUI_translation["frFR"] = {
["Target Castbar"] = "Barre d'incantation de la cible",
["Target Debuff Bar"] = "Barre des affaiblissements de la cible",
["Target Nameplate Zoom Factor"] = "Facteur de zoom du Nameplate de la cible",
["Target Totem"] = nil,
["Target-Target"] = "Cible de la cible",
["Target-Target-Target"] = "Cible de la cible de la cible",
["Text"] = nil,
@@ -877,7 +881,6 @@ pfUI_translation["frFR"] = {
["XP Percentage"] = "Pourcentage de la barre d'expérience",
["Yellow Border On Neutral Units"] = "Bordure jaune sur les unités neutres",
["Yes"] = "Oui",
["You gain (.+) Mana from Totemic Recall"] = nil,
["You got"] = "Vous avez",
["Your interface is now set up.\n\nFor advanced configuration, just open the |cff33ffccpf|rUI settings via the escape menu or type \"|cffffffaa/pfui|r\" into the chat.\n\n Have a nice trip!\n\n|cffaaaaaa- Shagu"] = nil,
["Your items have been repaired for"] = "Vos objets ont été réparés pour",
+7 -4
View File
@@ -27,7 +27,6 @@ pfUI_translation["koKR"] = {
["Always Show Item Comparison"] = "항상 착용 장비와 비교 표시",
["Always Show On Target Units"] = nil,
["Always Show On Units With Missing HP"] = nil,
["Always Show Self In Raid Frames"] = nil,
["Always Use 2D Portraits"] = "항상 2D초상화 사용",
["Ammo Counter"] = "탄약 갯수",
["Anchor Bags Above Chat"] = nil,
@@ -124,6 +123,7 @@ pfUI_translation["koKR"] = {
["Click Casting"] = nil,
["Clock"] = "시계",
["Close"] = "닫기",
["Collapse Empty Slots"] = nil,
["Color"] = nil,
["Color Buff Stacks"] = nil,
["Color Debuff Stacks"] = nil,
@@ -138,7 +138,6 @@ pfUI_translation["koKR"] = {
["Combat Timer"] = "전투 타이머",
["Combopoint Height"] = nil,
["Combopoint Width"] = nil,
["Compare Item Base Stats"] = nil,
["Components"] = nil,
["Config UI Settings"] = nil,
["Configuration"] = "구성",
@@ -569,6 +568,7 @@ pfUI_translation["koKR"] = {
["Overwrite If Unit Is Attacking Others"] = nil,
["Overwrite If Unit Is Attacking You"] = nil,
["Overwrite If Unit Is Casting"] = nil,
["Owner Name"] = nil,
["Pageable"] = nil,
["Paging Actionbar"] = nil,
["Panel"] = "패널",
@@ -616,12 +616,13 @@ pfUI_translation["koKR"] = {
["Raid Mark X-Offset"] = nil,
["Raid Mark Y-Offset"] = nil,
["Raid Padding"] = nil,
["Raid-Pet"] = nil,
["Random"] = nil,
["Random Roll Announcement Rarity"] = nil,
["Random Rolling"] = nil,
["Range Based Hunter Paging"] = nil,
["Range Check Interval"] = nil,
["Rank"] = nil,
["Recast Totem"] = nil,
["Red Border On Enemy Units"] = nil,
["Red Name Text On Infight Units"] = nil,
["Regional Settings"] = nil,
@@ -703,6 +704,7 @@ pfUI_translation["koKR"] = {
["Show Description"] = nil,
["Show Dispel Indicators"] = nil,
["Show Druid Mana Bar"] = nil,
["Show Druid Mana Bar Text"] = nil,
["Show Duration Inside Buff"] = nil,
["Show Empty Buttons"] = nil,
["Show FPS and Latency Colors"] = nil,
@@ -739,6 +741,7 @@ pfUI_translation["koKR"] = {
["Show Required Questitem Count"] = nil,
["Show Resting"] = nil,
["Show Self In Group Frames"] = nil,
["Show Self In Raid Frames When Solo"] = nil,
["Show Spell Icon"] = nil,
["Show Spell Name"] = nil,
["Show Stacks"] = nil,
@@ -783,6 +786,7 @@ pfUI_translation["koKR"] = {
["Target Castbar"] = nil,
["Target Debuff Bar"] = nil,
["Target Nameplate Zoom Factor"] = nil,
["Target Totem"] = nil,
["Target-Target"] = "대상-대상",
["Target-Target-Target"] = nil,
["Text"] = nil,
@@ -877,7 +881,6 @@ pfUI_translation["koKR"] = {
["XP Percentage"] = "경험치 퍼센트",
["Yellow Border On Neutral Units"] = nil,
["Yes"] = nil,
["You gain (.+) Mana from Totemic Recall"] = nil,
["You got"] = nil,
["Your interface is now set up.\n\nFor advanced configuration, just open the |cff33ffccpf|rUI settings via the escape menu or type \"|cffffffaa/pfui|r\" into the chat.\n\n Have a nice trip!\n\n|cffaaaaaa- Shagu"] = nil,
["Your items have been repaired for"] = nil,
+7 -4
View File
@@ -27,7 +27,6 @@ pfUI_translation["ruRU"] = {
["Always Show Item Comparison"] = "Всегда показывать сравнение предметов",
["Always Show On Target Units"] = "Всегда показывать над выбранной целью",
["Always Show On Units With Missing HP"] = "Всегда показывать над целями с неполным здоровьем",
["Always Show Self In Raid Frames"] = "Всегда показывать себя в рейде",
["Always Use 2D Portraits"] = "Всегда использовать 2D-портреты",
["Ammo Counter"] = "Счетчик боеприпасов",
["Anchor Bags Above Chat"] = nil,
@@ -124,6 +123,7 @@ pfUI_translation["ruRU"] = {
["Click Casting"] = "Каст по нажатию",
["Clock"] = "Часы",
["Close"] = "Закрыть",
["Collapse Empty Slots"] = nil,
["Color"] = nil,
["Color Buff Stacks"] = "Цвет стаков баффа",
["Color Debuff Stacks"] = "Цвет стаков дебаффа",
@@ -138,7 +138,6 @@ pfUI_translation["ruRU"] = {
["Combat Timer"] = "Таймер боя",
["Combopoint Height"] = nil,
["Combopoint Width"] = nil,
["Compare Item Base Stats"] = "Сравнивать базовые характеристики предмета",
["Components"] = "Компоненты",
["Config UI Settings"] = "Настройка параметров пользовательского интерфейса",
["Configuration"] = "Конфигурация",
@@ -569,6 +568,7 @@ pfUI_translation["ruRU"] = {
["Overwrite If Unit Is Attacking Others"] = nil,
["Overwrite If Unit Is Attacking You"] = nil,
["Overwrite If Unit Is Casting"] = nil,
["Owner Name"] = nil,
["Pageable"] = "Прокрутка страниц",
["Paging Actionbar"] = "Прокрутка панелей",
["Panel"] = "Панель",
@@ -616,12 +616,13 @@ pfUI_translation["ruRU"] = {
["Raid Mark X-Offset"] = nil,
["Raid Mark Y-Offset"] = nil,
["Raid Padding"] = "Отступ рейда",
["Raid-Pet"] = nil,
["Random"] = "Случайно",
["Random Roll Announcement Rarity"] = "Оповещение случайного броска для качества предмета",
["Random Rolling"] = "Случайный бросок костей для",
["Range Based Hunter Paging"] = "[|cffA9D271Охотник|r] Переключение страниц на основе диапазона",
["Range Check Interval"] = "Интервал проверки диапазона",
["Rank"] = "Ранг",
["Recast Totem"] = nil,
["Red Border On Enemy Units"] = "Красные границы вражеских юнитов",
["Red Name Text On Infight Units"] = nil,
["Regional Settings"] = "Региональные настройки",
@@ -703,6 +704,7 @@ pfUI_translation["ruRU"] = {
["Show Description"] = "Показать описание",
["Show Dispel Indicators"] = "Показать индикаторы рассеивания",
["Show Druid Mana Bar"] = nil,
["Show Druid Mana Bar Text"] = nil,
["Show Duration Inside Buff"] = "Показать продолжительность внутри баффа",
["Show Empty Buttons"] = "Показать пустые кнопки",
["Show FPS and Latency Colors"] = "Показать частоту кадров и задержку в цвете",
@@ -739,6 +741,7 @@ pfUI_translation["ruRU"] = {
["Show Required Questitem Count"] = "Показать необходимое количество предметов для задания",
["Show Resting"] = "Показать иконку отдыха",
["Show Self In Group Frames"] = "Показать себя в окне группы",
["Show Self In Raid Frames When Solo"] = nil,
["Show Spell Icon"] = "Показать иконку заклинания",
["Show Spell Name"] = "Показать название заклинания",
["Show Stacks"] = "Показать стаки",
@@ -783,6 +786,7 @@ pfUI_translation["ruRU"] = {
["Target Castbar"] = "Панель применения цели",
["Target Debuff Bar"] = "Панель дебаффов цели",
["Target Nameplate Zoom Factor"] = "Коэффициент увеличения индикатора здоровья цели",
["Target Totem"] = nil,
["Target-Target"] = "Цель цели",
["Target-Target-Target"] = "Цель цели цели",
["Text"] = nil,
@@ -877,7 +881,6 @@ pfUI_translation["ruRU"] = {
["XP Percentage"] = "Процент опыта",
["Yellow Border On Neutral Units"] = "Желтые границы на нейтральных юнитах",
["Yes"] = "Да",
["You gain (.+) Mana from Totemic Recall"] = nil,
["You got"] = "Вы получили",
["Your interface is now set up.\n\nFor advanced configuration, just open the |cff33ffccpf|rUI settings via the escape menu or type \"|cffffffaa/pfui|r\" into the chat.\n\n Have a nice trip!\n\n|cffaaaaaa- Shagu"] = "Теперь ваш интерфейс настроен.\n\nДля расширенной настройки откройте \"Настройки |cff33ffccpf|rUI\" с помощью escape меню или введите \"|cffffffaa/pfui|r\" в чат.\n\nЖелаю хорошего путешествия!\n\n|cffaaaaaa- Shagu",
["Your items have been repaired for"] = "Ваши предметы были отремонтированы за",
+7 -4
View File
@@ -27,7 +27,6 @@ pfUI_translation["zhCN"] = {
["Always Show Item Comparison"] = "始终显示装备比较(或按SHIFT键)",
["Always Show On Target Units"] = "始终在目标单位上显示",
["Always Show On Units With Missing HP"] = "始终在未满血单位上显示",
["Always Show Self In Raid Frames"] = "始终在团队框架中显示自己",
["Always Use 2D Portraits"] = "始终使用2D头像",
["Ammo Counter"] = "弹药数量",
["Anchor Bags Above Chat"] = "将背包锚定在聊天框上方",
@@ -124,6 +123,7 @@ pfUI_translation["zhCN"] = {
["Click Casting"] = "点击施法",
["Clock"] = "时间",
["Close"] = "关闭",
["Collapse Empty Slots"] = nil,
["Color"] = "颜色",
["Color Buff Stacks"] = "Buff堆叠颜色",
["Color Debuff Stacks"] = "Debuff堆叠颜色",
@@ -138,7 +138,6 @@ pfUI_translation["zhCN"] = {
["Combat Timer"] = "战斗计时器",
["Combopoint Height"] = "连击点高度",
["Combopoint Width"] = "连击点宽度",
["Compare Item Base Stats"] = "基于属性的装备对比",
["Components"] = "组件",
["Config UI Settings"] = "界面设置",
["Configuration"] = "配置",
@@ -569,6 +568,7 @@ pfUI_translation["zhCN"] = {
["Overwrite If Unit Is Attacking Others"] = "如果单位正在攻击其它单位则变色",
["Overwrite If Unit Is Attacking You"] = "如果单位正在攻击你则变色",
["Overwrite If Unit Is Casting"] = "如果单位正在施法则变色",
["Owner Name"] = nil,
["Pageable"] = "可分页",
["Paging Actionbar"] = "分页动作条",
["Panel"] = "面板",
@@ -616,12 +616,13 @@ pfUI_translation["zhCN"] = {
["Raid Mark X-Offset"] = nil,
["Raid Mark Y-Offset"] = nil,
["Raid Padding"] = "团队填充",
["Raid-Pet"] = nil,
["Random"] = "给随机玩家",
["Random Roll Announcement Rarity"] = "随机Roll点稀有度",
["Random Rolling"] = "随机Roll点 物品:",
["Range Based Hunter Paging"] = "启用基于范围的自动分页[|cff7fff7f猎人|r]",
["Range Check Interval"] = "范围检查间隔",
["Rank"] = "军衔",
["Recast Totem"] = nil,
["Red Border On Enemy Units"] = "显示敌方单位红色边框",
["Red Name Text On Infight Units"] = "进战斗的单位显示红色姓名",
["Regional Settings"] = "区域设置",
@@ -703,6 +704,7 @@ pfUI_translation["zhCN"] = {
["Show Description"] = "显示描述",
["Show Dispel Indicators"] = "显示驱散指示器",
["Show Druid Mana Bar"] = "显示德鲁伊法力条",
["Show Druid Mana Bar Text"] = nil,
["Show Duration Inside Buff"] = "显示持续时间在Buff里面",
["Show Empty Buttons"] = "显示空按钮",
["Show FPS and Latency Colors"] = "显示帧数以及延迟颜色",
@@ -740,6 +742,7 @@ pfUI_translation["zhCN"] = {
["Show Required Questitem Count"] = "显示所需的任务物品计数",
["Show Resting"] = "显示休息图标",
["Show Self In Group Frames"] = "在队伍框架中显示自己",
["Show Self In Raid Frames When Solo"] = nil,
["Show Spell Icon"] = "显示技能图标",
["Show Spell Name"] = "显示技能名称",
["Show Stacks"] = "显示堆叠",
@@ -784,6 +787,7 @@ pfUI_translation["zhCN"] = {
["Target Castbar"] = "目标施法条",
["Target Debuff Bar"] = "目标Debuffs条",
["Target Nameplate Zoom Factor"] = "目标姓名板缩放系数",
["Target Totem"] = nil,
["Target-Target"] = "目标的目标",
["Target-Target-Target"] = "目标的目标的目标",
["Text"] = "文本",
@@ -878,7 +882,6 @@ pfUI_translation["zhCN"] = {
["XP Percentage"] = "经验百分比",
["Yellow Border On Neutral Units"] = "显示中立单位黄色边框",
["Yes"] = "",
["You gain (.+) Mana from Totemic Recall"] = "你从图腾召回获得了(.+)点法力值",
["You got"] = "你已得到",
["Your interface is now set up.\n\nFor advanced configuration, just open the |cff33ffccpf|rUI settings via the escape menu or type \"|cffffffaa/pfui|r\" into the chat.\n\n Have a nice trip!\n\n|cffaaaaaa- Shagu"] = "你的界面现在已经完成设置.高级设置请点击游戏菜单或者输入命令/pfui进行设置.祝您游戏愉快",
["Your items have been repaired for"] = "你的物品已经修好了",
+7 -4
View File
@@ -27,7 +27,6 @@ pfUI_translation["zhTW"] = {
["Always Show Item Comparison"] = "始終顯示裝備比較",
["Always Show On Target Units"] = nil,
["Always Show On Units With Missing HP"] = nil,
["Always Show Self In Raid Frames"] = nil,
["Always Use 2D Portraits"] = "始終使用2D頭像",
["Ammo Counter"] = "彈藥數量",
["Anchor Bags Above Chat"] = nil,
@@ -124,6 +123,7 @@ pfUI_translation["zhTW"] = {
["Click Casting"] = nil,
["Clock"] = "時間",
["Close"] = "關閉",
["Collapse Empty Slots"] = nil,
["Color"] = nil,
["Color Buff Stacks"] = nil,
["Color Debuff Stacks"] = nil,
@@ -138,7 +138,6 @@ pfUI_translation["zhTW"] = {
["Combat Timer"] = "戰鬥計時器",
["Combopoint Height"] = nil,
["Combopoint Width"] = nil,
["Compare Item Base Stats"] = "基於屬性的裝備對比",
["Components"] = "組件",
["Config UI Settings"] = nil,
["Configuration"] = "配置",
@@ -569,6 +568,7 @@ pfUI_translation["zhTW"] = {
["Overwrite If Unit Is Attacking Others"] = "如果单位正在攻擊其它单位則覆蓋",
["Overwrite If Unit Is Attacking You"] = "如果单位正在攻擊你則覆蓋",
["Overwrite If Unit Is Casting"] = "如果单位正在施法則覆蓋",
["Owner Name"] = nil,
["Pageable"] = nil,
["Paging Actionbar"] = nil,
["Panel"] = "面板",
@@ -616,12 +616,13 @@ pfUI_translation["zhTW"] = {
["Raid Mark X-Offset"] = nil,
["Raid Mark Y-Offset"] = nil,
["Raid Padding"] = nil,
["Raid-Pet"] = nil,
["Random"] = "給隨機玩家",
["Random Roll Announcement Rarity"] = "隨機Roll點公示稀有度",
["Random Rolling"] = "隨機Roll點 物品:",
["Range Based Hunter Paging"] = nil,
["Range Check Interval"] = "範圍檢查間隔",
["Rank"] = nil,
["Recast Totem"] = nil,
["Red Border On Enemy Units"] = nil,
["Red Name Text On Infight Units"] = nil,
["Regional Settings"] = nil,
@@ -703,6 +704,7 @@ pfUI_translation["zhTW"] = {
["Show Description"] = nil,
["Show Dispel Indicators"] = nil,
["Show Druid Mana Bar"] = nil,
["Show Druid Mana Bar Text"] = nil,
["Show Duration Inside Buff"] = "顯示持續時間在Buff裏面",
["Show Empty Buttons"] = nil,
["Show FPS and Latency Colors"] = nil,
@@ -739,6 +741,7 @@ pfUI_translation["zhTW"] = {
["Show Required Questitem Count"] = nil,
["Show Resting"] = nil,
["Show Self In Group Frames"] = nil,
["Show Self In Raid Frames When Solo"] = nil,
["Show Spell Icon"] = nil,
["Show Spell Name"] = nil,
["Show Stacks"] = nil,
@@ -783,6 +786,7 @@ pfUI_translation["zhTW"] = {
["Target Castbar"] = nil,
["Target Debuff Bar"] = nil,
["Target Nameplate Zoom Factor"] = nil,
["Target Totem"] = nil,
["Target-Target"] = "目標的目標",
["Target-Target-Target"] = nil,
["Text"] = nil,
@@ -877,7 +881,6 @@ pfUI_translation["zhTW"] = {
["XP Percentage"] = "經驗百分比",
["Yellow Border On Neutral Units"] = nil,
["Yes"] = nil,
["You gain (.+) Mana from Totemic Recall"] = nil,
["You got"] = nil,
["Your interface is now set up.\n\nFor advanced configuration, just open the |cff33ffccpf|rUI settings via the escape menu or type \"|cffffffaa/pfui|r\" into the chat.\n\n Have a nice trip!\n\n|cffaaaaaa- Shagu"] = "您的UI已經設置完畢.使用遊戲菜單或在聊天窗口輸入\"|cffffffaa/pfui|r\"開啟高級設置.祝您遊戲愉快!\n\n|cffaaaaaa- Shagu",
["Your items have been repaired for"] = "你的物品已經修好了",
-2
View File
@@ -4,9 +4,7 @@
<Include file="..\libs\libdebuff.lua"/>
<Include file="..\libs\librange.lua"/>
<Include file="..\libs\libunitscan.lua"/>
<Include file="..\libs\libtooltip.lua"/>
<Include file="..\libs\libhealth.lua"/>
<Include file="..\libs\libtotem.lua"/>
<Include file="..\libs\libthrottle.lua"/>
<Include file="..\libs\libpredict.lua"/>
<Include file="..\libs\libbagsort.lua"/>
+2
View File
@@ -78,4 +78,6 @@
<Include file="..\modules\unitxp.lua"/>
<Include file="..\modules\bgscore.lua"/>
<Include file="..\modules\equipmentmanager.lua"/>
<Include file="..\modules\loothistory.lua"/>
<Include file="..\modules\newitem.lua"/>
</Ui>
+1
View File
@@ -1,5 +1,6 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/">
<Include file="..\skins\blizzard\character.lua"/>
<Include file="..\skins\blizzard\inspect.lua"/>
<Include file="..\skins\blizzard\spellbook.lua"/>
<Include file="..\skins\blizzard\friends.lua"/>
<Include file="..\skins\blizzard\talents.lua"/>
+123 -63
View File
@@ -11,26 +11,27 @@ pfUI.api.libbagsort = libbagsort
libbagsort.itemGrid = {}
libbagsort.bagList = nil
local HEARTHSTONE_ITEM_ID = 6948
local ItemClass = Enum.ItemClass
local ItemQuality = Enum.ItemQuality
-- Lower prefix = sorted earlier in the bag.
local function SortCategoryPrefix(itemId, itemType, itemSubType, quality)
if itemId == HEARTHSTONE_ITEM_ID then return "00" end
if quality == 0 then return "13" end -- Poor (gray) always last
if itemType == "Weapon" or itemType == "Armor" then
if quality and quality >= 4 then return "01" end -- Epic+ gear
if quality == 3 then return "02" end -- Rare gear
if quality == 2 then return "03" end -- Uncommon gear
return "04" -- Common/poor gear
local function SortCategoryPrefix(itemId, classID, quality)
if itemId == HEARTHSTONE_ITEM_ID then return "00" end
if quality == ItemQuality.Poor then return "13" end -- gray always last
if classID == ItemClass.Weapon or classID == ItemClass.Armor then
if quality and quality >= ItemQuality.Epic then return "01" end -- Epic+ gear
if quality == ItemQuality.Rare then return "02" end -- Rare gear
if quality == ItemQuality.Uncommon then return "03" end -- Uncommon gear
return "04" -- Common/poor gear
end
if itemType == "Consumable" then return "05" end
if itemType == "Reagent" then return "06" end
if itemType == "Trade Goods" then return "07" end
if itemType == "Quest" then return "08" end
if classID == ItemClass.Consumable then return "05" end
if classID == ItemClass.Reagent then return "06" end
if classID == ItemClass.Tradegoods then return "07" end
if classID == ItemClass.Questitem then return "08" end
-- Non-gear items without a specific type, sorted by quality
if quality and quality >= 4 then return "09" end
if quality == 3 then return "10" end
if quality == 2 then return "11" end
if quality and quality >= ItemQuality.Epic then return "09" end
if quality == ItemQuality.Rare then return "10" end
if quality == ItemQuality.Uncommon then return "11" end
return "12"
end
@@ -41,18 +42,31 @@ local function SortCountSuffix(count)
return string.sub(s, -6)
end
local function SortKey(itemId, name, itype, subtype, quality, count)
return SortCategoryPrefix(itemId, itype, subtype, quality)
.. (itype or "") .. "|" .. (subtype or "") .. "|" .. (name or "zzz") .. "|" .. SortCountSuffix(count)
local function SortKey(itemId, name, classID, subClassID, quality, count)
-- Zero-pad the class/subclass so the secondary grouping sorts numerically
-- (as a string, "10" would otherwise precede "2").
return SortCategoryPrefix(itemId, classID, quality)
.. string.format("%02d|%02d|", classID or 99, subClassID or 99)
.. (name or "zzz") .. "|" .. SortCountSuffix(count)
end
local function ClearSortData()
libbagsort.itemGrid = {}
libbagsort.bagList = nil
libbagsort.opts = nil
libbagsort:UnregisterEvent("BAG_UPDATE_DELAYED")
libbagsort:SetScript("OnEvent", nil)
end
local function ReverseArray(t)
local i, j = 1, table.getn(t)
while i < j do
t[i], t[j] = t[j], t[i]
i = i + 1
j = j - 1
end
end
-- Two-pointer consolidation: sorts stacks largest-first, then merges from
-- both ends toward the middle. n is set explicitly so table.getn / table.sort
-- work correctly in Lua 5.0.
@@ -112,36 +126,61 @@ local function BuildConsolidateOps(bagList)
return ops
end
-- Bag family bitmask (1 << (familyID-1)); 0 = general-purpose (holds
-- anything). Backpack (0) and bank (-1) are always general. A specialty
-- bag's family comes from the equipped bag item -- ClassicAPI derives it
-- from the container subclass when the raw field is empty (Turtle leaves
-- bags' m_bagFamily at 0), so quivers/soul/profession bags report properly.
local function BagFamily(bag)
if bag == 0 or bag == -1 then return 0 end
local id = GetInventoryItemID("player", ContainerIDToInventoryID(bag))
return id and C_Item.GetItemFamily(id) or 0
end
local function BuildSortGrid()
local bagList = libbagsort.bagList
libbagsort.itemGrid = {}
local normalItems = {}
local poorItems = {}
local bagCount = 0
local bagSlots = {}
-- Destination cells, split by the family they can accept. A specialty
-- bag's slots only take items of its own family; general slots take
-- anything. Cells are collected in forward order (bag order, slot 1..n).
local generalCells = {} -- { {bag=,slot=}, ... }
local specialtyCells = {} -- family -> { {bag=,slot=}, ... }
for _, bag in ipairs(bagList) do
bagCount = bagCount + 1
local fam = BagFamily(bag)
local numSlots = GetContainerNumSlots(bag)
bagSlots[bagCount] = numSlots
if numSlots > 0 then
libbagsort.itemGrid[bag] = {}
for slot = 1, numSlots do
if fam == 0 then
tinsert(generalCells, {bag=bag, slot=slot})
else
specialtyCells[fam] = specialtyCells[fam] or {}
tinsert(specialtyCells[fam], {bag=bag, slot=slot})
end
local itemId = C_Container.GetContainerItemID(bag, slot)
if itemId then
-- pfUI's compat layer shims GetItemInfo to the modern 10-field
-- signature (inserts nil for itemLevel between quality and
-- minlevel) — so itype/subtype sit at positions 6/7, not 5/6.
local name, _, quality, _, _, itype, subtype = GetItemInfo(itemId)
-- C_Item.GetItemInfo is the full 18-field tuple; classID/subClassID
-- sit at positions 12/13. We categorize on those numeric class IDs
-- rather than the localized itemType/itemSubType strings. (pfUI's
-- shimmed global GetItemInfo is only 10 fields and lacks them.)
local name, _, quality, _, _, _, _, _, _, _, _, classID, subClassID = C_Item.GetItemInfo(itemId)
local _, count = GetContainerItemInfo(bag, slot)
local item = {
key = SortKey(itemId, name, itype, subtype, quality, count),
key = SortKey(itemId, name, classID, subClassID, quality, count),
-- vanilla items carry at most one family bit, so equality
-- against a bag family suffices (no bit.band needed).
family = C_Item.GetItemFamily(itemId) or 0,
srcBag = bag,
srcSlot = slot,
curBag = bag,
curSlot = slot,
}
if quality == 0 then
if quality == ItemQuality.Poor then
tinsert(poorItems, item)
else
tinsert(normalItems, item)
@@ -152,46 +191,61 @@ local function BuildSortGrid()
end
end
table.sort(normalItems, function(a, b) return a.key < b.key end)
-- Sort poor items descending so they read in ascending order when placed
-- back-to-front (last poor item lands on the last slot).
table.sort(poorItems, function(a, b) return a.key > b.key end)
local opts = libbagsort.opts or {}
local reverse = opts.reverse
local reversePrio = opts.reversePrio
-- Forward pass: assign normal items from slot 1 of bag 1 onward
local bagIdx, destSlot = 1, 1
while bagIdx <= bagCount and bagSlots[bagIdx] == 0 do
bagIdx = bagIdx + 1
if reverse then
ReverseArray(generalCells)
for _, cells in pairs(specialtyCells) do
ReverseArray(cells)
end
end
if reversePrio then
table.sort(normalItems, function(a, b) return a.key > b.key end)
else
table.sort(normalItems, function(a, b) return a.key < b.key end)
end
if reverse then
table.sort(poorItems, function(a, b) return a.key < b.key end)
else
table.sort(poorItems, function(a, b) return a.key > b.key end)
end
-- Forward pass: route each normal item into the next free cell that
-- accepts it -- a matching specialty bag first, overflowing to general.
local genIdx = 1
local specIdx = {} -- family -> next free index into specialtyCells[family]
for _, item in ipairs(normalItems) do
while bagIdx <= bagCount do
if destSlot <= bagSlots[bagIdx] then break end
bagIdx = bagIdx + 1
destSlot = 1
local cell
local fam = item.family
if fam ~= 0 and specialtyCells[fam] then
local i = specIdx[fam] or 1
if i <= table.getn(specialtyCells[fam]) then
cell = specialtyCells[fam][i]
specIdx[fam] = i + 1
end
end
if bagIdx > bagCount then break end
local grid = libbagsort.itemGrid[item.srcBag][item.srcSlot]
grid.destBag = bagList[bagIdx]
grid.destSlot = destSlot
destSlot = destSlot + 1
if not cell and genIdx <= table.getn(generalCells) then
cell = generalCells[genIdx]
genIdx = genIdx + 1
end
if not cell then break end
item.destBag = cell.bag
item.destSlot = cell.slot
end
-- Reverse pass: assign poor items from the last slot of the last bag backward
local rBagIdx = bagCount
local rDestSlot = 0
while rBagIdx >= 1 do
if bagSlots[rBagIdx] > 0 then rDestSlot = bagSlots[rBagIdx]; break end
rBagIdx = rBagIdx - 1
end
-- Reverse pass: poor items are general; fill remaining general cells from
-- the back, stopping before the ones the forward pass already claimed.
local genBack = table.getn(generalCells)
for _, item in ipairs(poorItems) do
while rBagIdx >= 1 and rDestSlot < 1 do
rBagIdx = rBagIdx - 1
rDestSlot = rBagIdx >= 1 and bagSlots[rBagIdx] or 0
end
if rBagIdx < 1 then break end
local grid = libbagsort.itemGrid[item.srcBag][item.srcSlot]
grid.destBag = bagList[rBagIdx]
grid.destSlot = rDestSlot
rDestSlot = rDestSlot - 1
if genBack < genIdx then break end
local cell = generalCells[genBack]
genBack = genBack - 1
item.destBag = cell.bag
item.destSlot = cell.slot
end
end
@@ -248,9 +302,15 @@ end
-- BAG_UPDATE_DELAYED cycle), then place items by category/name/quality.
-- e.g. `libbagsort:Sort({0, 1, 2, 3, 4})` for the main bags;
-- `{-1, 5, 6, 7, 8, 9, 10}` for the bank.
function libbagsort:Sort(bagList)
--
-- opts (optional): { reverse = bool, reversePrio = bool }
-- reverse - place the first-ranked item into the last slot of the last
-- bag (junk fills from the opposite end).
-- reversePrio - flip the category ranking (e.g. hearthstone sorts last).
function libbagsort:Sort(bagList, opts)
ClearSortData()
self.bagList = bagList
self.opts = opts
-- Phase 1: fire every consolidation op in a single batch.
local ops = BuildConsolidateOps(bagList)
+59 -9
View File
@@ -11,12 +11,14 @@ setfenv(1, pfUI:GetEnvironment())
-- This eliminates ~400 lines of error-prone shift logic while maintaining full
-- multi-caster tracking support.
--
-- The public per-aura readers (UnitDebuff, UnitOwnDebuff) were retired in favor
-- of ClassicAPI's C_UnitAuras (which now provides sourceUnit/sourceGUID and
-- non-player expirationTime). What remains in libdebuff is the cast-event
-- bookkeeping consumed by GetBestAuraCast (libpredict HoT tracking) and the
-- libdebuff_*_hooks broadcast surface (subscribers in actionbar / swingtimer
-- / libtotem react to SPELL_GO and SPELL_FAILED).
-- The internal debuff plumbing now runs on ClassicAPI's C_UnitAuras (which
-- provides sourceUnit/sourceGUID and non-player expirationTime). The public
-- per-aura readers (UnitDebuff, UnitOwnDebuff) survive only as thin adapters
-- over C_UnitAuras for third-party addons (e.g. pfUI-WeakIcons) that still
-- expect the legacy multi-return signature. The rest of libdebuff is the
-- cast-event bookkeeping consumed by GetBestAuraCast (libpredict HoT tracking)
-- and the libdebuff_*_hooks broadcast surface (subscribers in actionbar /
-- swingtimer react to SPELL_GO and SPELL_FAILED).
-- return instantly when another libdebuff is already active
if pfUI.api.libdebuff then return end
@@ -27,8 +29,7 @@ if GetLocale() == "ruRU" then
end
local libdebuff = CreateFrame("Frame", "pfdebuffsScanner", UIParent)
local _, class = UnitClass("player")
local lastspell
local class = UnitClassBase("player")
-- Nampower Support
local hasNampower = false
@@ -762,6 +763,55 @@ function libdebuff:GetBestAuraCast(guid, spellName)
return nil
end
-- ============================================================================
-- API: UnitDebuff / UnitOwnDebuff (C_UnitAuras adapters)
-- ============================================================================
-- Thin readers kept for third-party addons (e.g. pfUI-WeakIcons) that still
-- expect libdebuff's legacy multi-return signature:
-- effect, rank, texture, stacks, dtype, duration, timeleft, caster
-- ClassicAPI's C_UnitAuras already resolves source and expiration, so these
-- just remap its AuraData onto that tuple -- no cast-tracking tables
-- (ownDebuffs/allAuraCasts) or GetUnitField slot mapping involved.
local function AuraToLegacy(aura)
if not aura then return nil end
local duration = aura.duration or 0
local timeleft = -1
-- Only report a timer for genuinely timed auras. ClassicAPI can leave a
-- stale expirationTime on permanent (duration 0) auras, so gate on duration.
if duration > 0 and aura.expirationTime and aura.expirationTime > 0 then
timeleft = aura.expirationTime - GetTime()
if timeleft < 0 then timeleft = 0 end
end
-- Aura spellId is the specific cast rank, so its subtext is the active rank.
local rank
local subtext = aura.spellId and C_Spell.GetSpellSubtext(aura.spellId)
if subtext and subtext ~= "" then
rank = tonumber((string.gsub(subtext, "Rank ", "")))
end
local dtype = aura.dispelName
if dtype == "" then dtype = nil end
local caster = aura.isFromPlayerOrPlayerPet and "player" or "other"
return aura.name, rank, aura.icon, aura.applications or 0, dtype, duration, timeleft, caster
end
-- id is a 1-based harmful-aura index, matching C_UnitAuras / Blizzard's
-- compacted debuff slots.
function libdebuff:UnitDebuff(unit, id)
return AuraToLegacy(C_UnitAuras.GetAuraDataByIndex(unit, id, "HARMFUL"))
end
-- Player-cast harmful auras only, via the PLAYER filter -- no manual
-- caster-GUID bookkeeping needed.
function libdebuff:UnitOwnDebuff(unit, id)
return AuraToLegacy(C_UnitAuras.GetAuraDataByIndex(unit, id, "HARMFUL|PLAYER"))
end
-- ============================================================================
-- NAMPOWER EVENT HANDLING
-- ============================================================================
@@ -1125,7 +1175,7 @@ if hasNampower then
-- Rank aus spellId ermitteln
local rankNum = 0
local rankString = GetSpellRecField(spellId, "rank")
local rankString = C_Spell.GetSpellSubtext(spellId)
if rankString and rankString ~= "" then
rankNum = tonumber((string.gsub(rankString, "Rank ", ""))) or 0
end
+6 -7
View File
@@ -291,7 +291,7 @@ pfUI.libdebuff_spell_start_other_hooks["libpredict"] = function(spellId, casterG
local targetName = resolveNameFromGuid(targetGuid)
if not targetName then return end
local rankStr = GetSpellRecField and GetSpellRecField(spellId, "rank") or ""
local rankStr = C_Spell.GetSpellSubtext(spellId) or ""
local spellKey = spellName .. (rankStr or "")
local amount = foreignCache[casterName] and foreignCache[casterName][spellKey]
@@ -355,11 +355,9 @@ pfUI.libdebuff_spell_go_hooks["libpredict"] = function(spellId, a1, a2, a3, a4,
elseif hotType == "Renew" then duration = renewDuration or 15
end
local rank = 0
if GetSpellRecField then
local rankStr = GetSpellRecField(spellId, "rank")
if rankStr and rankStr ~= "" then
rank = tonumber((string.gsub(rankStr, "Rank ", ""))) or 0
end
local rankSub = C_Spell.GetSpellSubtext(spellId)
if rankSub and rankSub ~= "" then
rank = tonumber((string.gsub(rankSub, "Rank ", ""))) or 0
end
local playerName = UnitName("player")
libpredict:Hot(playerName, targetName, hotType, duration, nil, "SPELL_GO_SELF", rank)
@@ -1020,7 +1018,8 @@ hooksecurefunc("UseAction", function(slot, target, selfcast)
local kind, id = GetActionInfo(slot)
local effect, rank
if kind == "spell" then
effect, rank = GetSpellInfo(id)
local spellInfo = C_Spell.GetSpellInfo(id)
effect, rank = spellInfo.name, spellInfo.rank
elseif kind == "macro" then
effect, rank = GetMacroSpell(id)
end
+14 -164
View File
@@ -2,178 +2,28 @@
setfenv(1, pfUI:GetEnvironment())
--[[ librange ]]--
-- A pfUI library that detects and caches distance to units.
-- A thin wrapper over ClassicAPI's UnitInRange: a fixed 40y healing-range
-- check computed C-side from unit positions, valid for any unit. There is
-- no cache or scan loop -- the check is cheap enough to run per query,
-- which also sidesteps the staleness a cached scan hit on zone changes and
-- roster re-indexing.
--
-- librange:UnitInSpellRange(unit)
-- Returns `1` if the unit is within range, `nil` otherwise.
--
-- Requires SuperWoW's UnitPosition for the friendly scan path. Target
-- range still works via IsActionInRange (vanilla-native) for any class
-- with a known 40y healing spell on the action bar.
if pfUI.api.librange then return end
local _, class = UnitClass("player")
local librange = CreateFrame("Frame", "pfRangecheck", UIParent)
-- 40y spells per class. Only consulted to find an action-bar slot for the
-- IsActionInRange target-range path; the party/raid scan uses UnitPosition.
local spells = {
["PALADIN"] = {
"Interface\\Icons\\Spell_Holy_FlashHeal",
"Interface\\Icons\\Spell_Holy_HolyBolt",
},
["PRIEST"] = {
"Interface\\Icons\\Spell_Holy_FlashHeal",
"Interface\\Icons\\Spell_Holy_LesserHeal",
"Interface\\Icons\\Spell_Holy_Heal",
"Interface\\Icons\\Spell_Holy_GreaterHeal",
"Interface\\Icons\\Spell_Holy_Renew",
},
["DRUID"] = {
"Interface\\Icons\\Spell_Nature_HealingTouch",
"Interface\\Icons\\Spell_Nature_ResistNature",
"Interface\\Icons\\Spell_Nature_Rejuvenation",
},
["SHAMAN"] = {
"Interface\\Icons\\Spell_Nature_MagicImmunity",
"Interface\\Icons\\Spell_Nature_HealingWaveLesser",
"Interface\\Icons\\Spell_Nature_HealingWaveGreater",
},
}
-- friendly units the scan loop iterates
local units = {}
table.insert(units, "pet")
for i=1,4 do table.insert(units, "party" .. i) end
for i=1,4 do table.insert(units, "partypet" .. i) end
for i=1,40 do table.insert(units, "raid" .. i) end
for i=1,40 do table.insert(units, "raidpet" .. i) end
local numunits = table.getn(units)
local unitcache = {}
local unitdata = {}
local librange_isLoggingOut = false
librange.id = 1
librange:Hide()
librange:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
librange:RegisterEvent("PLAYER_ENTERING_WORLD")
librange:RegisterEvent("PLAYER_LOGOUT")
librange:RegisterEvent("PLAYER_LEAVING_WORLD")
librange:SetScript("OnEvent", function()
if event == "PLAYER_LOGOUT" or event == "PLAYER_LEAVING_WORLD" then
librange_isLoggingOut = true
this:SetScript("OnUpdate", nil)
this:Hide()
return
end
if pfUI_config.unitframes.rangecheck == "0" then
this:Hide()
return
end
this.interval = tonumber(C.unitframes.rangechecki)/numunits
if event == "ACTIONBAR_SLOT_CHANGED" or event == "PLAYER_ENTERING_WORLD" then
librange.slot = this:GetRangeSlot()
if UnitPosition then this:Show() end
end
end)
librange:SetScript("OnUpdate", function()
if librange_isLoggingOut then return end
if (this.tick or 1) > GetTime() then return end
this.tick = GetTime() + this.interval
while not this:NeedRangeScan(units[this.id]) and this.id <= numunits do
this.id = this.id + 1
end
if this.id <= numunits then
local unit = units[this.id]
if not UnitIsUnit("target", unit) then
local x1, y1, z1 = UnitPosition("player")
local x2, y2, z2 = UnitPosition(unit)
if x1 and x2 then
local distance = ((x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2)^.5
unitdata[unit] = distance < 45 and 1 or 0
end
end
this.id = this.id + 1
else
this.id = 1
end
end)
function librange:NeedRangeScan(unit)
if not UnitExists(unit) then return nil end
if not UnitIsVisible(unit) then return nil end
if CheckInteractDistance(unit, 4) then return nil end
return true
end
function librange:GetRealUnit(unit)
if unitdata[unit] then return unit end
if unitcache[unit] and UnitIsUnit(unitcache[unit], unit) then
return unitcache[unit]
end
for id, realunit in pairs(units) do
if UnitIsUnit(realunit, unit) then
unitcache[unit] = realunit
return realunit
end
end
return unit
end
function librange:GetRangeSlot()
if not spells[class] then return nil end
for i=1,120 do
-- Resolve the slot to a spellID for both spell and macro actions; the old
-- `not GetActionText` macro-filter missed macros that cast a 40y heal but
-- displayed a non-spell icon. C_Spell.GetSpellTexture(spellID) gives the
-- spell's *intrinsic* icon, which is what we match against.
local kind, id = GetActionInfo(i)
local spellID
if kind == "spell" then
spellID = id
elseif kind == "macro" then
local _, _, sid = GetMacroSpell(id)
spellID = sid
end
if spellID then
local texture = C_Spell.GetSpellTexture(spellID)
if texture then
for _, check in pairs(spells[class]) do
if check == texture then return i end
end
end
end
end
return nil
end
local librange = {}
function librange:UnitInSpellRange(unit)
if UnitIsUnit("target", unit) then
if not librange.slot then return nil end
return IsActionInRange(librange.slot) == 1 and 1 or nil
end
local unit = librange:GetRealUnit(unit)
if unitdata[unit] and unitdata[unit] == 1 then
return 1
elseif not unitdata[unit] then
return 1
else
return nil
end
-- _G-qualified: bare `UnitInRange` resolves to pfUI.api.UnitInRange inside
-- the pfUI environment (which calls us), so this must reach ClassicAPI's
-- global directly or it recurses.
local inRange, checked = _G.UnitInRange(unit)
-- position miss (e.g. a unit outside the client's sync range): we can't
-- tell, so default to in-range -- matches the old cache's nil behavior.
if not checked then return 1 end
return inRange and 1 or nil
end
-- add librange to pfUI API
+3 -1
View File
@@ -118,7 +118,9 @@ end
local resetcache = CreateFrame("Frame")
resetcache:RegisterEvent("LEARNED_SPELL_IN_TAB")
resetcache:SetScript("OnEvent", function()
spellmaxrank, spellindex, spellinfo = {}, {}, {}
table.wipe(spellmaxrank)
table.wipe(spellindex)
table.wipe(spellinfo)
end)
-- add libspell to pfUI API
+2 -2
View File
@@ -35,7 +35,7 @@ libthrottle.defaults = {
nameplates_target = "custom",
nameplates_castbar = "custom",
nameplates_mass = "custom",
tooltip_cursor = "custom",
tooltip_cursor = "fastest",
chat_tab = "custom",
swingtimer = "custom",
}
@@ -160,7 +160,7 @@ libthrottle:SetScript("OnEvent", function()
-- Set defaults for custom fields if missing
if not _G.pfUI_throttle.nameplates_target_custom then _G.pfUI_throttle.nameplates_target_custom = "50" end
if not _G.pfUI_throttle.nameplates_custom then _G.pfUI_throttle.nameplates_custom = "10" end
if not _G.pfUI_throttle.nameplates_castbar_custom then _G.pfUI_throttle.nameplates_castbar_custom = "50" end
if not _G.pfUI_throttle.nameplates_castbar_custom then _G.pfUI_throttle.nameplates_castbar_custom = "100" end
if not _G.pfUI_throttle.nameplates_mass_custom then _G.pfUI_throttle.nameplates_mass_custom = "7" end
if not _G.pfUI_throttle.tooltip_cursor_custom then _G.pfUI_throttle.tooltip_cursor_custom = "10" end
if not _G.pfUI_throttle.chat_tab_custom then _G.pfUI_throttle.chat_tab_custom = "10" end
-59
View File
@@ -1,59 +0,0 @@
-- load pfUI environment
setfenv(1, pfUI:GetEnvironment())
--[[ libtooltip ]]--
-- A pfUI library that provides additional GameTooltip information.
--
-- libtooltip:GetItemID()
-- returns the itemID of the current GameTooltip
-- `nil` when no item is displayed
--
-- libtooltip:GetItemLink()
-- returns the itemLink of the current GameTooltip
-- `nil` when no item is displayed
--
-- libtooltip:GetItemCount()
-- returns the item count (bags) of the current GameTooltip
-- `nil` when no item is displayed
-- return instantly when another libtooltip is already active
if pfUI.api.libtooltip then return end
local libtooltip = CreateFrame("Frame" , "pfLibTooltip", GameTooltip)
libtooltip:SetScript("OnShow", function()
if this:GetParent():HasItem() then
libtooltip.itemName, libtooltip.itemLink, libtooltip.itemID = this:GetParent():GetItem()
end
end)
libtooltip:SetScript("OnHide", function()
this.itemID = nil
this.itemLink = nil
this.itemCount = nil
this.itemName = nil
end)
-- core functions
libtooltip.GetItemID = function(self)
if not libtooltip.itemLink then return end
if not libtooltip.itemID then
libtooltip.itemID = C_Item.GetItemInfoInstant(libtooltip.itemLink)
end
return libtooltip.itemID
end
libtooltip.GetItemLink = function(self)
return libtooltip.itemLink
end
libtooltip.GetItemCount = function(self)
return libtooltip.itemCount
end
pfUI.api.libtooltip = libtooltip
hooksecurefunc(GameTooltip, "SetBagItem", function(self, container, slot)
_, libtooltip.itemCount = GetContainerItemInfo(container, slot)
end)
-274
View File
@@ -1,274 +0,0 @@
-- load pfUI environment
setfenv(1, pfUI:GetEnvironment())
--[[ libtotem ]]--
-- A pfUI library that tries to emulate the TotemAPI that was introduced in Patch 2.4.
-- It detects and saves all current totems of the player and returns information based
-- on the totem slot ID. The function GetTotemInfo is supposed to work as it would
-- on later expansions.
--
-- GetTotemInfo(id)
-- Returns totem informations on the givent totem slot
-- active, name, start, duration, icon
-- return instantly when another libtotem is already active
if pfUI.api.libtotem then return end
MAX_TOTEMS = MAX_TOTEMS or 4
FIRE_TOTEM_SLOT = FIRE_TOTEM_SLOT or 1
EARTH_TOTEM_SLOT = EARTH_TOTEM_SLOT or 2
WATER_TOTEM_SLOT = WATER_TOTEM_SLOT or 3
AIR_TOTEM_SLOT = AIR_TOTEM_SLOT or 4
local _, class = UnitClass("player")
local libtotem
local active = { [1] = {}, [2] = {}, [3] = {}, [4] = {} }
-- SpellID -> { slot, duration } mapping
-- rank-specific durations are handled via spellId directly
local spellids = {
-- FIRE (slot 1)
[1535] = { slot = FIRE_TOTEM_SLOT, duration = 5 }, -- Fire Nova Totem R1
[8498] = { slot = FIRE_TOTEM_SLOT, duration = 5 }, -- Fire Nova Totem R2
[8499] = { slot = FIRE_TOTEM_SLOT, duration = 5 }, -- Fire Nova Totem R3
[11314] = { slot = FIRE_TOTEM_SLOT, duration = 5 }, -- Fire Nova Totem R4
[11315] = { slot = FIRE_TOTEM_SLOT, duration = 5 }, -- Fire Nova Totem R5
[8227] = { slot = FIRE_TOTEM_SLOT, duration = 120 }, -- Flametongue Totem R1
[8249] = { slot = FIRE_TOTEM_SLOT, duration = 120 }, -- Flametongue Totem R2
[10526] = { slot = FIRE_TOTEM_SLOT, duration = 120 }, -- Flametongue Totem R3
[16387] = { slot = FIRE_TOTEM_SLOT, duration = 120 }, -- Flametongue Totem R4
[8184] = { slot = FIRE_TOTEM_SLOT, duration = 120 }, -- Frost Resistance Totem R1
[10478] = { slot = FIRE_TOTEM_SLOT, duration = 120 }, -- Frost Resistance Totem R2
[10479] = { slot = FIRE_TOTEM_SLOT, duration = 120 }, -- Frost Resistance Totem R3
[8190] = { slot = FIRE_TOTEM_SLOT, duration = 20 }, -- Magma Totem R1
[10585] = { slot = FIRE_TOTEM_SLOT, duration = 20 }, -- Magma Totem R2
[10586] = { slot = FIRE_TOTEM_SLOT, duration = 20 }, -- Magma Totem R3
[10587] = { slot = FIRE_TOTEM_SLOT, duration = 20 }, -- Magma Totem R4
[3599] = { slot = FIRE_TOTEM_SLOT, duration = 30 }, -- Searing Totem R1
[6363] = { slot = FIRE_TOTEM_SLOT, duration = 35 }, -- Searing Totem R2
[6364] = { slot = FIRE_TOTEM_SLOT, duration = 40 }, -- Searing Totem R3
[6365] = { slot = FIRE_TOTEM_SLOT, duration = 45 }, -- Searing Totem R4
[10437] = { slot = FIRE_TOTEM_SLOT, duration = 50 }, -- Searing Totem R5
[10438] = { slot = FIRE_TOTEM_SLOT, duration = 55 }, -- Searing Totem R6
-- EARTH (slot 2)
[2484] = { slot = EARTH_TOTEM_SLOT, duration = 45 }, -- Earthbind Totem
[5730] = { slot = EARTH_TOTEM_SLOT, duration = 15 }, -- Stoneclaw Totem R1
[6390] = { slot = EARTH_TOTEM_SLOT, duration = 15 }, -- Stoneclaw Totem R2
[6391] = { slot = EARTH_TOTEM_SLOT, duration = 15 }, -- Stoneclaw Totem R3
[6392] = { slot = EARTH_TOTEM_SLOT, duration = 15 }, -- Stoneclaw Totem R4
[10427] = { slot = EARTH_TOTEM_SLOT, duration = 15 }, -- Stoneclaw Totem R5
[10428] = { slot = EARTH_TOTEM_SLOT, duration = 15 }, -- Stoneclaw Totem R6
[8071] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Stoneskin Totem R1
[8154] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Stoneskin Totem R2
[8155] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Stoneskin Totem R3
[10406] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Stoneskin Totem R4
[10407] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Stoneskin Totem R5
[10408] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Stoneskin Totem R6
[8075] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Strength of Earth Totem R1
[8160] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Strength of Earth Totem R2
[8161] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Strength of Earth Totem R3
[10442] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Strength of Earth Totem R4
[25361] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Strength of Earth Totem R5
[8143] = { slot = EARTH_TOTEM_SLOT, duration = 120 }, -- Tremor Totem
-- WATER (slot 3)
[8170] = { slot = WATER_TOTEM_SLOT, duration = 120 }, -- Disease Cleansing Totem
[8185] = { slot = WATER_TOTEM_SLOT, duration = 120 }, -- Fire Resistance Totem R1
[10537] = { slot = WATER_TOTEM_SLOT, duration = 120 }, -- Fire Resistance Totem R2
[10538] = { slot = WATER_TOTEM_SLOT, duration = 120 }, -- Fire Resistance Totem R3
[5394] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Healing Stream Totem R1
[6375] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Healing Stream Totem R2
[6377] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Healing Stream Totem R3
[10462] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Healing Stream Totem R4
[10463] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Healing Stream Totem R5
[5675] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Mana Spring Totem R1
[10495] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Mana Spring Totem R2
[10496] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Mana Spring Totem R3
[10497] = { slot = WATER_TOTEM_SLOT, duration = 60 }, -- Mana Spring Totem R4
[16190] = { slot = WATER_TOTEM_SLOT, duration = 12 }, -- Mana Tide Totem
[8166] = { slot = WATER_TOTEM_SLOT, duration = 120 }, -- Poison Cleansing Totem
-- AIR (slot 4)
[8835] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Grace of Air Totem R1
[10627] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Grace of Air Totem R2
[8177] = { slot = AIR_TOTEM_SLOT, duration = 45 }, -- Grounding Totem
[10595] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Nature Resistance Totem R1
[10600] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Nature Resistance Totem R2
[10601] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Nature Resistance Totem R3
[25359] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Tranquil Air Totem
[8512] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Windfury Totem R1
[10613] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Windfury Totem R2
[10614] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Windfury Totem R3
[15107] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Windwall Totem R1
[15421] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Windwall Totem R2
[15422] = { slot = AIR_TOTEM_SLOT, duration = 120 }, -- Windwall Totem R3
}
-- icon-based fallback table (used by CastSpell/UseAction hooks that don't have spellId)
local totems = {
[FIRE_TOTEM_SLOT] = {
["Spell_Fire_SealOfFire"] = {[-1] = 5},
["Spell_Nature_GuardianWard"] = {[-1] = 120},
["Spell_FrostResistanceTotem_01"] = {[-1] = 120},
["Spell_Fire_SelfDestruct"] = {[-1] = 20},
["Spell_Fire_SearingTotem"] = {[-1] = 55,[1] = 30,[2] = 35,[3] = 40,[4] = 45,[5] = 50,[6] = 55},
},
[EARTH_TOTEM_SLOT] = {
["Spell_Nature_StrengthOfEarthTotem02"] = {[-1] = 45},
["Spell_Nature_StoneClawTotem"] = {[-1] = 15},
["Spell_Nature_StoneSkinTotem"] = {[-1] = 120},
["Spell_Nature_EarthBindTotem"] = {[-1] = 120},
["Spell_Nature_TremorTotem"] = {[-1] = 120},
},
[WATER_TOTEM_SLOT] = {
["Spell_Nature_DiseaseCleansingTotem"] = {[-1] = 120},
["Spell_FireResistanceTotem_01"] = {[-1] = 120},
["INV_Spear_04"] = {[-1] = 60},
["Spell_Nature_ManaRegenTotem"] = {[-1] = 60},
["Spell_Frost_SummonWaterElemental"] = {[-1] = 12},
["Spell_Nature_PoisonCleansingTotem"] = {[-1] = 120},
},
[AIR_TOTEM_SLOT] = {
["Spell_Nature_InvisibilityTotem"] = {[-1] = 120},
["Spell_Nature_GroundingTotem"] = {[-1] = 45},
["Spell_Nature_NatureResistanceTotem"] = {[-1] = 120},
["Spell_Nature_Brilliance"] = {[-1] = 120},
["Spell_Nature_Windfury"] = {[-1] = 120},
["Spell_Nature_EarthBind"] = {[-1] = 120},
},
}
GetTotemInfo = function(id)
if not active[id] or not active[id].name then return end
if active[id].start + active[id].duration - GetTime() < 0 then
libtotem:Clean(id)
return nil
end
return 1, active[id].name, active[id].start, active[id].duration, active[id].icon
end
if class ~= "SHAMAN" then return end
libtotem = CreateFrame("Frame")
libtotem:RegisterEvent("PLAYER_DEAD")
libtotem:SetScript("OnEvent", function()
if event == "PLAYER_DEAD" then
for i = 1, 4 do libtotem:Clean(i) end
end
end)
libtotem.totems = totems
libtotem.Clean = function(self, slot)
active[slot].name = nil
active[slot].start = nil
active[slot].duration = nil
active[slot].icon = nil
end
-- Direct SpellID commit (Nampower SPELL_GO_SELF, most accurate)
libtotem.CommitBySpellId = function(spellId, icon)
local data = spellids[spellId]
if not data then return false end
local slot = data.slot
active[slot].name = active[slot].pending_name or active[slot].name
active[slot].duration = data.duration
active[slot].icon = icon or active[slot].pending_icon
active[slot].start = GetTime()
active[slot].pending_name = nil
active[slot].pending_icon = nil
return true
end
-- Fallback: icon-based lookup (for CastSpell/UseAction without spellId)
libtotem.CheckAddQueue = function(self, name, rank, icon, spellId)
-- if we have a spellId, just store the name/icon as pending for SPELL_GO
if spellId and spellids[spellId] then
local slot = spellids[spellId].slot
active[slot].pending_name = name
active[slot].pending_icon = icon
return true
end
-- icon-based fallback
for slot = 1, 4 do
for texture, data in pairs(totems[slot]) do
if string.find(icon, texture, 1) then
if rank then
_, _, rank = string.find(rank, "%s(%d+)")
end
local duration
if rank and tonumber(rank) and data[tonumber(rank)] then
duration = data[tonumber(rank)]
else
duration = data[-1]
end
active[slot].pending_name = name
active[slot].pending_icon = icon
active[slot].pending_duration = duration
return true
end
end
end
return nil
end
-- assign library to global space
pfUI.api.libtotem = libtotem
-- SPELL_GO_SELF from libdebuff: commit directly by SpellID, no queue needed
pfUI.libdebuff_spell_go_hooks = pfUI.libdebuff_spell_go_hooks or {}
pfUI.libdebuff_spell_go_hooks["libtotem"] = function(spellId)
if not spellId then return end
local data = spellids[spellId]
if not data then return end
local slot = data.slot
-- use pending name/icon if available (set by CastSpellByName hook), else GetSpellInfo
local name = active[slot].pending_name
local icon = active[slot].pending_icon
if not name and GetSpellInfo then
name = GetSpellInfo(spellId)
end
active[slot].name = name
active[slot].duration = data.duration
active[slot].icon = icon
active[slot].start = GetTime()
active[slot].pending_name = nil
active[slot].pending_icon = nil
active[slot].pending_duration = nil
end
-- Hook CastSpellByName to store pending name/icon per slot
hooksecurefunc("CastSpellByName", function(effect, target)
local name, rank, icon, _, _, _, spellId = libspell.GetSpellInfo(effect)
if not name then return end
libtotem:CheckAddQueue(name, rank, icon, spellId)
end)
-- Hook CastSpell to store pending name/icon per slot
hooksecurefunc("CastSpell", function(id, bookType)
if not id or not bookType then return end
if bookType ~= BOOKTYPE_SPELL and bookType ~= BOOKTYPE_PET then return end
local name, rank, icon, _, _, _, spellId = libspell.GetSpellInfo(id, bookType)
if not name then return end
libtotem:CheckAddQueue(name, rank, icon, spellId)
end)
-- Hook UseAction. GetActionInfo + GetMacroSpell give us the spellID
-- directly for both spell-action and macro-action slots, so the
-- tooltip-scan fallback (and the "no spellId available" caveat) goes away.
hooksecurefunc("UseAction", function(slot, target, selfcast)
if not IsCurrentAction(slot) then return end
local kind, id = GetActionInfo(slot)
local name, rank, spellID
if kind == "spell" then
spellID = id
name, rank = GetSpellInfo(id)
elseif kind == "macro" then
name, rank, spellID = GetMacroSpell(id)
end
if not name then return end
libtotem:CheckAddQueue(name, rank, GetActionTexture(slot), spellID)
end)
+22 -20
View File
@@ -89,7 +89,7 @@ libunitscan:SetScript("OnEvent", function()
-- update own character details
local name = UnitName("player")
local _, class = UnitClass("player")
local class = UnitClassBase("player")
local level = UnitLevel("player")
local guild = GetGuildInfo("player")
AddData("players", name, class, level, nil, guild)
@@ -128,7 +128,7 @@ libunitscan:SetScript("OnEvent", function()
local name, class, level, unit, _, guild
for i = 1, GetNumPartyMembers() do
unit = "party" .. i
_, class = UnitClass(unit)
class = UnitClassBase(unit)
name = UnitName(unit)
level = UnitLevel(unit)
guild = GetGuildInfo(unit)
@@ -149,24 +149,26 @@ libunitscan:SetScript("OnEvent", function()
or event == "NAME_PLATE_UNIT_ADDED" and arg1
or "mouseover"
local name, class, level, elite, guild, _
if UnitIsPlayer(scan) then
_, class = UnitClass(scan)
level = UnitLevel(scan)
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
level = level > 0 and level or nil
name = UnitName(scan)
guild = GetGuildInfo(scan)
AddData("players", name, class, level, nil, guild)
RememberByUnit(scan, name, class)
else
_, class = UnitClass(scan)
elite = UnitClassification(scan)
level = UnitLevel(scan)
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
level = level > 0 and level or nil
name = UnitName(scan)
guild = UnitSubName(scan)
AddData("mobs", name, class, level, elite, guild)
if UnitExists(scan) then
if UnitIsPlayer(scan) then
class = UnitClassBase(scan)
level = UnitLevel(scan)
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
level = level > 0 and level or nil
name = UnitName(scan)
guild = GetGuildInfo(scan)
AddData("players", name, class, level, nil, guild)
RememberByUnit(scan, name, class)
else
class = UnitClassBase(scan)
elite = UnitClassification(scan)
level = UnitLevel(scan)
-- UnitLevel returns -1 for unknown levels, don't overwrite known values
level = level > 0 and level or nil
name = UnitName(scan)
guild = UnitSubName(scan)
AddData("mobs", name, class, level, elite, guild)
end
end
end
end)
+36 -28
View File
@@ -1,5 +1,5 @@
pfUI:RegisterModule("actionbar", function ()
local _, class = UnitClass("player")
local class = UnitClassBase("player")
local _, cr, cg, cb = GetUnitColor('player')
local er, eg, eb, ea = GetStringColor(pfUI_config.appearance.border.color)
@@ -168,8 +168,7 @@ pfUI:RegisterModule("actionbar", function ()
["zoomfade"] = function()
if this.active == 0 then
-- init animation
this:SetWidth(this.parent:GetWidth())
this:SetHeight(this.parent:GetHeight())
this:SetSize(this.parent:GetSize())
this:SetScale(this.parent:GetScale())
this.tex:SetTexture(this.parent.icon:GetTexture())
this.tex:SetVertexColor(this.parent.icon:GetVertexColor())
@@ -191,8 +190,7 @@ pfUI:RegisterModule("actionbar", function ()
["shrinkreturn"] = function()
if this.active == 0 then
-- init animation
this:SetWidth(this.parent:GetWidth())
this:SetHeight(this.parent:GetHeight())
this:SetSize(this.parent:GetSize())
this:SetScale(this.parent:GetScale())
this.tex:SetTexture(this.parent.icon:GetTexture())
this.tex:SetVertexColor(this.parent.icon:GetVertexColor())
@@ -218,8 +216,7 @@ pfUI:RegisterModule("actionbar", function ()
["elasticzoom"] = function()
if this.active == 0 then
-- init animation
this:SetWidth(this.parent:GetWidth())
this:SetHeight(this.parent:GetHeight())
this:SetSize(this.parent:GetSize())
this:SetScale(this.parent:GetScale())
this.tex:SetTexture(this.parent.icon:GetTexture())
this.tex:SetVertexColor(this.parent.icon:GetVertexColor())
@@ -245,8 +242,7 @@ pfUI:RegisterModule("actionbar", function ()
["wobblezoom"] = function()
if this.active == 0 then
-- init animation
this:SetWidth(this.parent:GetWidth())
this:SetHeight(this.parent:GetHeight())
this:SetSize(this.parent:GetSize())
this:SetScale(this.parent:GetScale())
this.tex:SetTexture(this.parent.icon:GetTexture())
this.tex:SetVertexColor(this.parent.icon:GetVertexColor())
@@ -853,16 +849,20 @@ pfUI:RegisterModule("actionbar", function ()
end
end
local cat, stealth
local inCatForm = nil
local prowlActive = nil
-- Cat Form ID per vanilla 1.12 SpellShapeshiftForm.dbc.
-- Form IDs per vanilla 1.12 SpellShapeshiftForm.dbc.
local CAT_FORM = 1
local SHADOWFORM = 28
local function HasCatForm()
return GetShapeshiftFormID() == CAT_FORM and true or nil
end
local function InShadowform()
return GetShapeshiftFormID() == SHADOWFORM and true or nil
end
local function FullScan()
if class ~= "DRUID" then return nil end
inCatForm = HasCatForm()
@@ -872,7 +872,7 @@ pfUI:RegisterModule("actionbar", function ()
-- pagemaster / meta page switch
do
local prowl, shift, ctrl, alt, default = 8, 6, 5, 3, 1
local formpage, shift, ctrl, alt, default = 8, 6, 5, 3, 1
-- set temporary pagemaster bindings keybinds
if C.bars.pagemaster == "1" then
@@ -890,8 +890,10 @@ pfUI:RegisterModule("actionbar", function ()
end)
end
-- setup page switch frame
local prowling = nil
-- setup page switch frame. `formpaging` is the shared "auto-page is
-- active" flag; druid prowl and priest shadowform each drive it, and
-- no character is ever both, so one flag covers both features.
local formpaging = nil
local pageswitch = CreateFrame("Frame", "pfActionBarPageSwitch", UIParent)
pageswitch:RegisterEvent("PLAYER_ENTERING_WORLD")
pageswitch:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
@@ -905,10 +907,17 @@ pfUI:RegisterModule("actionbar", function ()
return
end
if class == "PRIEST" then
if event == "UPDATE_SHAPESHIFT_FORM" or event == "PLAYER_ENTERING_WORLD" then
formpaging = InShadowform()
end
return
end
if class ~= "DRUID" then return end
if event == "PLAYER_ENTERING_WORLD" then
prowling = FullScan()
formpaging = FullScan()
return
end
@@ -917,7 +926,7 @@ pfUI:RegisterModule("actionbar", function ()
inCatForm = HasCatForm()
if not inCatForm then
prowlActive = nil
prowling = nil
formpaging = nil
end
return
end
@@ -927,10 +936,10 @@ pfUI:RegisterModule("actionbar", function ()
if inCatForm then
if IsStealthed() then
prowlActive = true
prowling = true
formpaging = true
else
prowlActive = nil
prowling = nil
formpaging = nil
end
end
end)
@@ -946,7 +955,7 @@ pfUI:RegisterModule("actionbar", function ()
if PROWL_IDS[spellId] then
inCatForm = true
prowlActive = true
prowling = true
formpaging = true
end
end
pageswitch:SetScript("OnUpdate", function()
@@ -964,11 +973,12 @@ pfUI:RegisterModule("actionbar", function ()
SwitchBar(default)
end
-- switch actionbar page if druid stealth is detected
if C.bars.druidstealth == "1" then
if prowling and _G.CURRENT_ACTIONBAR_PAGE == 1 then
SwitchBar(prowl)
elseif not prowling and _G.CURRENT_ACTIONBAR_PAGE == 8 then
-- switch actionbar page while druid stealth / priest shadowform is active
if (class == "DRUID" and C.bars.druidstealth == "1")
or (class == "PRIEST" and C.bars.priestshadow == "1") then
if formpaging and _G.CURRENT_ACTIONBAR_PAGE == 1 then
SwitchBar(formpage)
elseif not formpaging and _G.CURRENT_ACTIONBAR_PAGE == 8 then
SwitchBar(default)
end
end
@@ -1162,8 +1172,7 @@ pfUI:RegisterModule("actionbar", function ()
-- general appearance
f.showempty = showempty == "1" and true or nil
f:SetHeight(size)
f:SetWidth(size)
f:SetSize(size, size)
CreateBackdrop(f, border)
return f
@@ -1335,8 +1344,7 @@ pfUI:RegisterModule("actionbar", function ()
-- adjust actionbar size
BarLayoutSize(bars[i], buttons, formfactor, size, border, spacing, uneven, fillmode)
bars[i]:SetWidth(bars[i]._size[1])
bars[i]:SetHeight(bars[i]._size[2])
bars[i]:SetSize(bars[i]._size[1], bars[i]._size[2])
bars[i]:ClearAllPoints()
if i == 1 then -- main
bars[i]:SetPoint("BOTTOM", 0, 2*border)
+11 -20
View File
@@ -37,15 +37,10 @@ pfUI:RegisterModule("addonbuttons", function ()
pfUI.addonbuttons.minimapbutton = CreateFrame("Button", "pfMinimapButton", pfUI.minimap or UIParent)
pfUI.addonbuttons.minimapbutton:SetFrameLevel(24)
pfUI.addonbuttons.minimapbutton:SetWidth(12)
pfUI.addonbuttons.minimapbutton:SetHeight(12)
pfUI.addonbuttons.minimapbutton:SetSize(12, 12)
pfUI.addonbuttons.minimapbutton:SetScript("OnClick", function()
if pfUI.addonbuttons:IsShown() then
pfUI.addonbuttons:Hide()
else
pfUI.addonbuttons:Show()
end
pfUI.addonbuttons:SetShown(not pfUI.addonbuttons:IsShown())
end)
pfUI.addonbuttons.buttons = {}
@@ -163,27 +158,25 @@ pfUI:RegisterModule("addonbuttons", function ()
pfUI.addonbuttons:SetScale(pfUI.minimap:GetScale())
pfUI.addonbuttons.minimapbutton:ClearAllPoints()
local mbtnWidth, mbtnHeight = pfUI.minimap:GetSize()
local dynamicSize = ceil((GetNumButtons() > 0 and GetNumButtons() or 1) / tonumber(C.abuttons.rowsize)) * GetStringSize() + tonumber(C.abuttons.spacing)
if C.abuttons.position == "bottom" then
pfUI.addonbuttons:SetWidth(pfUI.minimap:GetWidth())
pfUI.addonbuttons:SetHeight(ceil((GetNumButtons() > 0 and GetNumButtons() or 1) / tonumber(C.abuttons.rowsize)) * GetStringSize() + tonumber(C.abuttons.spacing))
pfUI.addonbuttons:SetSize(mbtnWidth, dynamicSize)
pfUI.addonbuttons:SetPoint("TOP", pfUI.minimap, "BOTTOM", 0 , -default_border * 3)
SkinArrowButton(pfUI.addonbuttons.minimapbutton, "down")
pfUI.addonbuttons.minimapbutton:SetPoint("BOTTOM", pfUI.minimap, "BOTTOM", 0, 4)
elseif C.abuttons.position == "left" then
pfUI.addonbuttons:SetWidth(ceil((GetNumButtons() > 0 and GetNumButtons() or 1) / tonumber(C.abuttons.rowsize)) * GetStringSize() + tonumber(C.abuttons.spacing))
pfUI.addonbuttons:SetHeight(pfUI.minimap:GetHeight())
pfUI.addonbuttons:SetSize(dynamicSize, mbtnHeight)
pfUI.addonbuttons:SetPoint("TOPRIGHT", pfUI.minimap, "TOPLEFT", -default_border * 3, 0)
SkinArrowButton(pfUI.addonbuttons.minimapbutton, "left")
pfUI.addonbuttons.minimapbutton:SetPoint("LEFT", pfUI.minimap, "LEFT", 4, 0)
elseif C.abuttons.position == "top" then
pfUI.addonbuttons:SetWidth(pfUI.minimap:GetWidth())
pfUI.addonbuttons:SetHeight(ceil((GetNumButtons() > 0 and GetNumButtons() or 1) / tonumber(C.abuttons.rowsize)) * GetStringSize() + tonumber(C.abuttons.spacing))
pfUI.addonbuttons:SetSize(mbtnWidth, dynamicSize)
pfUI.addonbuttons:SetPoint("BOTTOM", pfUI.minimap, "TOP", 0 , default_border * 3)
SkinArrowButton(pfUI.addonbuttons.minimapbutton, "up")
pfUI.addonbuttons.minimapbutton:SetPoint("TOP", pfUI.minimap, "TOP", 0, -4)
elseif C.abuttons.position == "right" then
pfUI.addonbuttons:SetWidth(ceil((GetNumButtons() > 0 and GetNumButtons() or 1) / tonumber(C.abuttons.rowsize)) * GetStringSize() + tonumber(C.abuttons.spacing))
pfUI.addonbuttons:SetHeight(pfUI.minimap:GetHeight())
pfUI.addonbuttons:SetSize(dynamicSize, mbtnHeight)
pfUI.addonbuttons:SetPoint("TOPLEFT", pfUI.minimap, "TOPRIGHT", default_border * 3, 0)
SkinArrowButton(pfUI.addonbuttons.minimapbutton, "right")
pfUI.addonbuttons.minimapbutton:SetPoint("RIGHT", pfUI.minimap, "RIGHT", -4, 0)
@@ -231,7 +224,7 @@ pfUI:RegisterModule("addonbuttons", function ()
frame.backup.is_clamped_to_screen = frame:IsClampedToScreen()
frame.backup.is_movable = frame:IsMovable()
frame.backup.point = {frame:GetPoint()}
frame.backup.size = {frame:GetHeight(), frame:GetWidth()}
frame.backup.size = {frame:GetSize()}
frame.backup.scale = frame:GetScale()
if frame:HasScript("OnDragStart") then
frame.backup.on_drag_start = frame:GetScript("OnDragStart")
@@ -256,8 +249,7 @@ pfUI:RegisterModule("addonbuttons", function ()
frame:SetClampedToScreen(frame.backup.is_clamped_to_screen)
frame:SetMovable(frame.backup.is_movable)
frame:SetScale(frame.backup.scale)
frame:SetHeight(frame.backup.size[1])
frame:SetWidth(frame.backup.size[2])
frame:SetSize(frame.backup.size[2], frame.backup.size[1])
frame:ClearAllPoints()
frame:SetPoint(frame.backup.point[1], frame.backup.point[2], frame.backup.point[3], frame.backup.point[4], frame.backup.point[5])
if frame.backup.on_drag_start ~= nil then
@@ -440,6 +432,5 @@ pfUI:RegisterModule("addonbuttons", function ()
pfUI.addonbuttons:UpdateConfig()
_G.SLASH_PFABP1, _G.SLASH_PFABP2 = "/abp", "/pfabp"
_G.SlashCmdList.PFABP = ManualAddOrRemove
pfUI.api.RegisterSlashCommand("PFABP", { "/abp", "/pfabp" }, ManualAddOrRemove, true)
end)
+26 -14
View File
@@ -18,8 +18,7 @@ pfUI:RegisterModule("addons", function ()
-- addon window
pfUI.addons = CreateFrame("Frame", "pfAddons", UIParent)
pfUI.addons:SetFrameStrata("DIALOG")
pfUI.addons:SetHeight(490)
pfUI.addons:SetWidth(380)
pfUI.addons:SetSize(380, 490)
pfUI.addons:SetPoint("CENTER", 0,0)
pfUI.addons:EnableMouseWheel(1)
pfUI.addons:SetMovable(true)
@@ -51,8 +50,7 @@ pfUI:RegisterModule("addons", function ()
pfUI.addons.close = CreateFrame("Button", "pfBagClose", pfUI.addons)
pfUI.addons.close:SetPoint("TOPRIGHT", -border*2,-border*2 )
CreateBackdrop(pfUI.addons.close)
pfUI.addons.close:SetHeight(15)
pfUI.addons.close:SetWidth(15)
pfUI.addons.close:SetSize(15, 15)
pfUI.addons.close.texture = pfUI.addons.close:CreateTexture("pfBagClose")
pfUI.addons.close.texture:SetTexture(pfUI.media["img:close"])
pfUI.addons.close.texture:ClearAllPoints()
@@ -125,8 +123,7 @@ pfUI:RegisterModule("addons", function ()
end)
pfUI.addons.profile:SetPoint("TOP", pfUI.addons, "TOP", 0, -30)
pfUI.addons.profile:SetHeight(30)
pfUI.addons.profile:SetWidth(370)
pfUI.addons.profile:SetSize(370, 30)
CreateBackdrop(pfUI.addons.profile, nil, true)
-- addon profile: title
@@ -139,8 +136,7 @@ pfUI:RegisterModule("addons", function ()
-- addon profile: delete
pfUI.addons.profile.del = CreateFrame("Button", nil, pfUI.addons.profile, "UIPanelButtonTemplate")
SkinButton(pfUI.addons.profile.del)
pfUI.addons.profile.del:SetWidth(16)
pfUI.addons.profile.del:SetHeight(16)
pfUI.addons.profile.del:SetSize(16, 16)
pfUI.addons.profile.del:SetPoint("RIGHT", -10, 0)
pfUI.addons.profile.del:GetFontString():SetPoint("CENTER", 1, 0)
pfUI.addons.profile.del:SetText("-")
@@ -157,8 +153,7 @@ pfUI:RegisterModule("addons", function ()
-- addon profile: create
pfUI.addons.profile.add = CreateFrame("Button", nil, pfUI.addons.profile, "UIPanelButtonTemplate")
SkinButton(pfUI.addons.profile.add)
pfUI.addons.profile.add:SetWidth(16)
pfUI.addons.profile.add:SetHeight(16)
pfUI.addons.profile.add:SetSize(16, 16)
pfUI.addons.profile.add:SetPoint("RIGHT", pfUI.addons.profile.del, "LEFT", -4, 0)
pfUI.addons.profile.add:GetFontString():SetPoint("CENTER", 1, 0)
pfUI.addons.profile.add:SetText("+")
@@ -201,8 +196,7 @@ pfUI:RegisterModule("addons", function ()
-- addon list: scroll frame
pfUI.addons.scroll = CreateScrollFrame("pfAddonListScroll", pfUI.addons)
pfUI.addons.scroll:SetWidth(360)
pfUI.addons.scroll:SetHeight(410)
pfUI.addons.scroll:SetSize(360, 410)
pfUI.addons.scroll:SetPoint("BOTTOM", 0, 10)
pfUI.addons.scroll.backdrop = CreateFrame("Frame", nil, pfUI.addons.scroll)
@@ -217,6 +211,21 @@ pfUI:RegisterModule("addons", function ()
pfUI.addons.list:RegisterEvent("PLAYER_ENTERING_WORLD")
pfUI.addons.list:SetHeight(GetNumAddOns() * 25 + 26)
local function AddDependencyLines(header, deps)
if not deps or table.getn(deps) == 0 then return end
GameTooltip:AddLine(" ")
GameTooltip:AddLine(header .. ":", .2, 1, .8)
for _, dep in ipairs(deps) do
if IsAddOnLoaded(dep) then
GameTooltip:AddLine(" " .. dep, .5, 1, .5)
elseif C_AddOns.DoesAddOnExist(dep) then
GameTooltip:AddLine(" " .. dep, 1, .82, 0)
else
GameTooltip:AddLine(" " .. dep .. " (" .. T["Missing"] .. ")", 1, .4, .4)
end
end
end
local function AddonOnEnter()
this:SetBackdropBorderColor(1,1,1,.08)
@@ -231,6 +240,8 @@ pfUI:RegisterModule("addons", function ()
end
GameTooltip:AddLine(this.anote, .75,.75,.75,1)
AddDependencyLines(T["Dependencies"], this.adeps)
AddDependencyLines(T["Optional Dependencies"], this.aoptdeps)
GameTooltip:SetWidth(180)
GameTooltip:Show()
end
@@ -272,9 +283,10 @@ pfUI:RegisterModule("addons", function ()
frame.anote = anote
frame.aauthor = aauthor
frame.aversion = aversion
frame.adeps = { GetAddOnDependencies(i) } -- required (.toc Dependencies)
frame.aoptdeps = { C_AddOns.GetAddOnOptionalDependencies(i) } -- optional (.toc OptionalDeps)
frame:SetWidth(340)
frame:SetHeight(25)
frame:SetSize(340, 25)
frame:SetPoint("TOPLEFT", 5, i * -25 + 20)
frame:SetBackdrop(pfUI.backdrop_hover)
+1 -2
View File
@@ -48,8 +48,7 @@ pfUI:RegisterModule("afkcam", function ()
local chat = CreateFrame("ScrollingMessageFrame", "pfAFKCamChat", overlay)
chat:EnableMouse(false)
chat:EnableMouseWheel(true)
chat:SetHeight(150)
chat:SetWidth(500)
chat:SetSize(500, 150)
chat:SetPoint("BOTTOMLEFT",overlay,"BOTTOMLEFT", 10, 10)
chat:SetTimeVisible(1800.0)
chat:SetMaxLines(500)
+1 -2
View File
@@ -56,8 +56,7 @@ pfUI:RegisterModule("autovendor", function ()
-- Setup Autosell button
autovendor.button = CreateFrame("Button", "pfMerchantAutoVendorButton", MerchantFrame)
autovendor.button:SetWidth(36)
autovendor.button:SetHeight(36)
autovendor.button:SetSize(36, 36)
autovendor.button.icon = autovendor.button:CreateTexture("ARTWORK")
autovendor.button.icon:SetTexture("Interface\\Icons\\Spell_Shadow_SacrificialShield")
autovendor.button:SetScript("OnEnter", function()
+31 -37
View File
@@ -8,6 +8,13 @@ pfUI:RegisterModule("bags", function ()
local scanner = libtipscan:GetScanner("input_search")
local function BagSortOpts()
return {
reverse = C.appearance.bags.sortreverse == "1",
reversePrio = C.appearance.bags.sortprioreverse == "1",
}
end
-- function to detect openable items in inventory
local openable = { bag = nil, slot = nil, icon = nil }
local function GetNextOpenable()
@@ -319,8 +326,7 @@ pfUI:RegisterModule("bags", function ()
default_border + x*(frame.button_size+default_border*3),
-default_border*2 - y*(frame.button_size+default_border*3) - topspace)
pfUI.bags[bag].slots[slot].frame:SetHeight(frame.button_size)
pfUI.bags[bag].slots[slot].frame:SetWidth(frame.button_size)
pfUI.bags[bag].slots[slot].frame:SetSize(frame.button_size, frame.button_size)
if x >= rowlength - 1 then
y = y + 1
@@ -337,12 +343,13 @@ pfUI:RegisterModule("bags", function ()
local chat = pfUI.chat and ( object == "bank" and pfUI.chat.left or pfUI.chat.right) or nil
frame:SetScript("OnShow", function()
frame.opened = true
if C.appearance.bags.hidechat == "1" and chat and chat:IsVisible() then
frame.chatWasOpen = true
chat:Hide()
end
if C.appearance.bags.autoSortOnOpen == "1" then
libbagsort:Sort({0, 1, 2, 3, 4})
libbagsort:Sort({0, 1, 2, 3, 4}, BagSortOpts())
end
pfUI.bag:CreateBags(object)
PlaySound("INTERFACESOUND_BACKPACKOPEN")
@@ -355,6 +362,10 @@ pfUI:RegisterModule("bags", function ()
end
pfUI.bag:CreateBags(object)
PlaySound("INTERFACESOUND_BACKPACKCLOSE")
if frame.opened then
frame.opened = nil
pfUI.events:TriggerEvent("bag:closed", object)
end
end)
end
@@ -443,7 +454,7 @@ pfUI:RegisterModule("bags", function ()
end
end
local _, _, q, _, _, _, itype = GetItemInfo(itemID)
local _, _, q, _, _, _, itype = C_Item.GetItemInfo(itemID)
-- running advanced item color scan
if C.appearance.bags.borderonlygear == "0" and texture and quality and quality < 1 then
@@ -533,8 +544,7 @@ pfUI:RegisterModule("bags", function ()
local width = (frame.button_size/5*4 + default_border*2) * (max-min+1+extra)
local height = default_border + (frame.button_size/5*4 + default_border)
frame.bagslots:SetWidth(width)
frame.bagslots:SetHeight(height)
frame.bagslots:SetSize(width, height)
for slot=min, max do
if not frame.bagslots.slots[slot] then
frame.bagslots.slots[slot] = {}
@@ -594,8 +604,7 @@ pfUI:RegisterModule("bags", function ()
frame.bagslots.slots[slot].frame:ClearAllPoints()
frame.bagslots.slots[slot].frame:SetPoint("TOPLEFT", frame.bagslots, "TOPLEFT", left, top)
frame.bagslots.slots[slot].frame:SetHeight(frame.button_size/5*4)
frame.bagslots.slots[slot].frame:SetWidth(frame.button_size/5*4)
frame.bagslots.slots[slot].frame:SetSize(frame.button_size/5*4, frame.button_size/5*4)
CreateBackdrop(frame.bagslots.slots[slot].frame, default_border)
frame.bagslots.slots[slot].frame:Show()
@@ -614,8 +623,7 @@ pfUI:RegisterModule("bags", function ()
end
frame.bagslots.buy:SetPoint("RIGHT", frame.bagslots, "RIGHT", -default_border, 0)
CreateBackdrop(frame.bagslots.buy, default_border)
frame.bagslots.buy:SetHeight(frame.button_size/5*4)
frame.bagslots.buy:SetWidth(frame.button_size/5*4)
frame.bagslots.buy:SetSize(frame.button_size/5*4, frame.button_size/5*4)
frame.bagslots.buy:SetText("+")
frame.bagslots.buy:SetTextColor(.5,.5,1,1)
frame.bagslots.buy:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
@@ -707,8 +715,7 @@ pfUI:RegisterModule("bags", function ()
frame.close = CreateFrame("Button", "pfBagClose", frame)
frame.close:SetPoint("TOPRIGHT", -default_border*1,-default_border )
CreateBackdrop(frame.close, default_border)
frame.close:SetHeight(12)
frame.close:SetWidth(12)
frame.close:SetSize(12, 12)
frame.close.texture = frame.close:CreateTexture("pfBagClose")
frame.close.texture:SetTexture(pfUI.media["img:close"])
frame.close.texture:ClearAllPoints()
@@ -733,8 +740,7 @@ pfUI:RegisterModule("bags", function ()
frame.bags = CreateFrame("Button", "pfBagSlotShow", frame)
frame.bags:SetPoint("TOPRIGHT", frame.close, "TOPLEFT", -default_border*3, 0)
CreateBackdrop(frame.bags, default_border)
frame.bags:SetHeight(12)
frame.bags:SetWidth(12)
frame.bags:SetSize(12, 12)
frame.bags:SetTextColor(1,1,.25,1)
frame.bags:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
frame.bags.texture = frame.bags:CreateTexture("pfBagArrowUp")
@@ -761,11 +767,7 @@ pfUI:RegisterModule("bags", function ()
end)
frame.bags:SetScript("OnClick", function()
if pfUI.bag.right.bagslots:IsShown() then
pfUI.bag.right.bagslots:Hide()
else
pfUI.bag.right.bagslots:Show()
end
pfUI.bag.right.bagslots:SetShown(not pfUI.bag.right.bagslots:IsShown())
end)
end
@@ -774,8 +776,7 @@ pfUI:RegisterModule("bags", function ()
frame.open = CreateFrame("Button", "pfBagSlotOpen", frame)
frame.open:SetPoint("TOPRIGHT", frame.bags, "TOPLEFT", -default_border*3, 0)
CreateBackdrop(frame.open, default_border)
frame.open:SetHeight(12)
frame.open:SetWidth(12)
frame.open:SetSize(12, 12)
frame.open:SetTextColor(1,1,.25,1)
frame.open:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
frame.open.texture = frame.open:CreateTexture("pfBagOpenContainer")
@@ -833,8 +834,7 @@ pfUI:RegisterModule("bags", function ()
frame.disenchant = CreateFrame("Button", "pfBagSlotDisenchant", frame)
frame.disenchant:SetPoint("TOPRIGHT", frame.open, "TOPLEFT", -default_border*3, 0)
CreateBackdrop(frame.disenchant, default_border)
frame.disenchant:SetHeight(12)
frame.disenchant:SetWidth(12)
frame.disenchant:SetSize(12, 12)
frame.disenchant:SetTextColor(1,1,.25,1)
frame.disenchant:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
frame.disenchant.texture = frame.disenchant:CreateTexture("pfBagDisenchant")
@@ -876,8 +876,7 @@ pfUI:RegisterModule("bags", function ()
frame.picklock = CreateFrame("Button", "pfBagSlotPicklock", frame)
frame.picklock:SetPoint("TOPRIGHT", frame.disenchant, "TOPLEFT", -default_border*3, 0)
CreateBackdrop(frame.picklock, default_border)
frame.picklock:SetHeight(12)
frame.picklock:SetWidth(12)
frame.picklock:SetSize(12, 12)
frame.picklock:SetTextColor(1,1,.25,1)
frame.picklock:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
frame.picklock.texture = frame.picklock:CreateTexture("pfBagPicklock")
@@ -919,8 +918,7 @@ pfUI:RegisterModule("bags", function ()
frame.keys = CreateFrame("Button", "pfBagSlotShow", frame)
frame.keys:SetPoint("TOPRIGHT", frame.picklock, "TOPLEFT", -default_border*3, 0)
CreateBackdrop(frame.keys, default_border)
frame.keys:SetHeight(12)
frame.keys:SetWidth(12)
frame.keys:SetSize(12, 12)
frame.keys:SetTextColor(1,1,.25,1)
frame.keys:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
frame.keys.texture = frame.keys:CreateTexture("pfBagArrowUp")
@@ -962,8 +960,7 @@ pfUI:RegisterModule("bags", function ()
frame.sort = CreateFrame("Button", "pfBagSort", frame)
frame.sort:SetPoint("TOPRIGHT", frame.keys, "TOPLEFT", -default_border*3, 0)
CreateBackdrop(frame.sort, default_border)
frame.sort:SetHeight(12)
frame.sort:SetWidth(12)
frame.sort:SetSize(12, 12)
frame.sort.texture = frame.sort:CreateTexture("pfBagSortIcon")
frame.sort.texture:SetTexture(pfUI.media["img:sort"])
frame.sort.texture:ClearAllPoints()
@@ -988,7 +985,7 @@ pfUI:RegisterModule("bags", function ()
end)
frame.sort:SetScript("OnClick", function()
libbagsort:Sort({0, 1, 2, 3, 4})
libbagsort:Sort({0, 1, 2, 3, 4}, BagSortOpts())
end)
end
@@ -996,8 +993,7 @@ pfUI:RegisterModule("bags", function ()
if not frame.gold and (C.appearance.bags.movable == "1" or not pfUI.panel) then
frame.gold = CreateFrame("Frame", "pfBagGoldString", frame)
frame.gold:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -4, 1)
frame.gold:SetWidth(200)
frame.gold:SetHeight(18)
frame.gold:SetSize(200, 18)
frame.gold:RegisterEvent("PLAYER_ENTERING_WORLD")
frame.gold:RegisterEvent("PLAYER_MONEY")
frame.gold:SetScript("OnEvent", function()
@@ -1133,8 +1129,7 @@ pfUI:RegisterModule("bags", function ()
frame.close = CreateFrame("Button", "pfBagClose", frame)
frame.close:SetPoint("TOPRIGHT", -default_border*1,-default_border )
CreateBackdrop(frame.close, default_border)
frame.close:SetHeight(12)
frame.close:SetWidth(12)
frame.close:SetSize(12, 12)
frame.close.texture = frame.close:CreateTexture("pfBagClose")
frame.close.texture:SetTexture(pfUI.media["img:close"])
frame.close.texture:ClearAllPoints()
@@ -1159,8 +1154,7 @@ pfUI:RegisterModule("bags", function ()
frame.bags = CreateFrame("Button", "pfBagSlotShow", frame)
frame.bags:SetPoint("TOPRIGHT", frame.close, "TOPLEFT", -default_border*3, 0)
CreateBackdrop(frame.bags, default_border)
frame.bags:SetHeight(12)
frame.bags:SetWidth(12)
frame.bags:SetSize(12, 12)
frame.bags:SetTextColor(1,1,.25,1)
frame.bags:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
frame.bags.texture = frame.bags:CreateTexture("pfBagArrowUp")
@@ -1226,7 +1220,7 @@ pfUI:RegisterModule("bags", function ()
end)
frame.sort:SetScript("OnClick", function()
libbagsort:Sort({-1, 5, 6, 7, 8, 9, 10})
libbagsort:Sort({-1, 5, 6, 7, 8, 9, 10}, BagSortOpts())
end)
end
end
+2 -4
View File
@@ -2,14 +2,12 @@ pfUI:RegisterModule("bgscore", function ()
local bgframe = WorldStateAlwaysUpFrame
if not bgframe then
bgframe = CreateFrame("Frame", "WorldStateAlwaysUpFrame", UIParent)
bgframe:SetWidth(200)
bgframe:SetHeight(25)
bgframe:SetSize(200, 25)
bgframe:SetPoint("TOP", UIParent, "TOP", 0, -100)
end
local mover = CreateFrame("Frame", "pfUIBGScoreMover", UIParent)
mover:SetWidth(220)
mover:SetHeight(30)
mover:SetSize(220, 30)
mover:SetPoint("TOP", UIParent, "TOP", 0, -100)
mover:SetFrameStrata("DIALOG")
mover:SetMovable(true)
+2 -9
View File
@@ -17,12 +17,6 @@ pfUI:RegisterModule("bubbles", function ()
RunNextFrame(function() pfUI.bubbles:ScanBubbles() end)
end)
function pfUI.bubbles:IsBubble(f)
if f:GetName() then return end
if not f:GetRegions() then return end
return f:GetRegions().GetTexture and f:GetRegions():GetTexture() == "Interface\\Tooltips\\ChatBubble-Background"
end
function pfUI.bubbles:ProcessBubble(f)
f.text:Hide()
f.text:SetFont(pfUI.font_default, tonumber(C.global.font_size) * UIParent:GetScale(), "OUTLINE")
@@ -34,9 +28,8 @@ pfUI:RegisterModule("bubbles", function ()
end
function pfUI.bubbles:ScanBubbles()
local childs = { WorldFrame:GetChildren() }
for _, f in pairs(childs) do
if not f.frame and pfUI.bubbles:IsBubble(f) then
for _, f in ipairs(C_ChatBubbles.GetAllChatBubbles()) do
if not f.frame then
local textures = {f:GetRegions()}
for _, object in pairs(textures) do
if object:GetObjectType() == "Texture" then
+21 -16
View File
@@ -277,28 +277,27 @@ pfUI:RegisterModule("buff", function ()
-- config loading
function pfUI.buff:UpdateConfigBuffButton(buff)
local fontsize = C.buffs.fontsize == "-1" and C.global.font_size or C.buffs.fontsize
local buffSize, buffSpacing = tonumber(C.buffs.size), tonumber(C.buffs.spacing)
local rowcount, relFrame, offsetX, offsetY
if buff.btype == "HELPFUL" then
if buff.weapon == 1 and C.buffs.separateweapons == "1" then
rowcount = floor((buff.gid-1) / tonumber(C.buffs.wepbuffrowsize))
relFrame = pfUI.buff.wepbuffs
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.wepbuffrowsize))*(tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing))
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing))
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.wepbuffrowsize))*(buffSize+2*buffSpacing)
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+buffSize+2*buffSpacing)
else
rowcount = floor((buff.gid-1) / tonumber(C.buffs.buffrowsize))
relFrame = pfUI.buff.buffs
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.buffrowsize))*(tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing))
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing))
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.buffrowsize))*(buffSize+2*buffSpacing)
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+buffSize+2*buffSpacing)
end
else
rowcount = floor((buff.gid-1) / tonumber(C.buffs.debuffrowsize))
relFrame = pfUI.buff.debuffs
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.debuffrowsize))*(tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing))
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing))
offsetX = -(buff.gid-1-rowcount*tonumber(C.buffs.debuffrowsize))*(buffSize+2*buffSpacing)
offsetY = -(rowcount) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+buffSize+2*buffSpacing)
end
buff:SetWidth(tonumber(C.buffs.size))
buff:SetHeight(tonumber(C.buffs.size))
buff:SetSize(buffSize, buffSize)
buff:ClearAllPoints()
buff:SetPoint("TOPRIGHT", relFrame, "TOPRIGHT",offsetX, offsetY)
@@ -318,20 +317,26 @@ pfUI:RegisterModule("buff", function ()
function pfUI.buff:UpdateConfig()
local fontsize = C.buffs.fontsize == "-1" and C.global.font_size or C.buffs.fontsize
pfUI.buff.buffs:SetWidth(tonumber(C.buffs.buffrowsize) * (tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing)))
pfUI.buff.buffs:SetHeight(ceil(32/tonumber(C.buffs.buffrowsize)) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing)))
pfUI.buff.buffs:SetPoint("TOPRIGHT", pfUI.minimap or UIParent, "TOPLEFT", -4*tonumber(C.buffs.spacing), 0)
local spacing = tonumber(C.buffs.spacing)
local cell = tonumber(C.buffs.size) + 2 * spacing
local rowextra = C.buffs.textinside == "1" and 0 or (fontsize * 1.5)
local function SizeBuffFrame(frame, rowsize, count)
rowsize = tonumber(rowsize)
frame:SetSize(rowsize * cell, ceil(count / rowsize) * (rowextra + cell))
end
SizeBuffFrame(pfUI.buff.buffs, C.buffs.buffrowsize, 32)
pfUI.buff.buffs:SetPoint("TOPRIGHT", pfUI.minimap or UIParent, "TOPLEFT", -4 * spacing, 0)
UpdateMovable(pfUI.buff.buffs)
pfUI.buff.debuffs:SetWidth(tonumber(C.buffs.debuffrowsize) * (tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing)))
pfUI.buff.debuffs:SetHeight(ceil(16/tonumber(C.buffs.debuffrowsize)) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing)))
SizeBuffFrame(pfUI.buff.debuffs, C.buffs.debuffrowsize, 16)
pfUI.buff.debuffs:SetPoint("TOPRIGHT", pfUI.buff.buffs, "BOTTOMRIGHT", 0, 0)
UpdateMovable(pfUI.buff.debuffs)
if C.buffs.separateweapons == "1" then
pfUI.buff.wepbuffs:ClearAllPoints()
pfUI.buff.wepbuffs:SetWidth(tonumber(C.buffs.wepbuffrowsize) * (tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing)))
pfUI.buff.wepbuffs:SetHeight(ceil(2/tonumber(C.buffs.wepbuffrowsize)) * ((C.buffs.textinside == "1" and 0 or (fontsize*1.5))+tonumber(C.buffs.size)+2*tonumber(C.buffs.spacing)))
SizeBuffFrame(pfUI.buff.wepbuffs, C.buffs.wepbuffrowsize, 2)
pfUI.buff.wepbuffs:SetPoint("TOPRIGHT", pfUI.buff.debuffs, "BOTTOMRIGHT", 0, 0)
pfUI.buff.wepbuffs:Show()
UpdateMovable(pfUI.buff.wepbuffs)
+13 -25
View File
@@ -162,8 +162,7 @@ pfUI:RegisterModule("buffwatch", function ()
local color = parent.color
local bordercolor = parent.bordercolor
local textcolor = parent.textcolor
local width = parent:GetWidth()
local height = parent:GetHeight()
local width, height = parent:GetSize()
local framename = "pf" .. parent.unit .. ( parent.type == "HARMFUL" and "Debuff" or "Buff" ) .. "Bar" .. bar
local font = parent.config.use_unitfonts == "1" and pfUI.font_unit or pfUI.font_default
@@ -172,8 +171,7 @@ pfUI:RegisterModule("buffwatch", function ()
frame:EnableMouse(1)
frame:Hide()
frame:SetPoint("BOTTOM", 0, (bar-1)*(height+2*border+1))
frame:SetWidth(width)
frame:SetHeight(height)
frame:SetSize(width, height)
frame.bar = CreateFrame("StatusBar", "pfBuffBar" .. bar, frame)
frame.bar:SetPoint("TOPLEFT", frame, "TOPLEFT", height+1, 0)
@@ -202,8 +200,7 @@ pfUI:RegisterModule("buffwatch", function ()
frame.time:SetJustifyH("RIGHT")
frame.icon = frame:CreateTexture(nil, "OVERLAY")
frame.icon:SetWidth(height)
frame.icon:SetHeight(height)
frame.icon:SetSize(height, height)
frame.icon:SetPoint("LEFT", frame, "LEFT", 0, 0)
frame.icon:SetTexCoord(.07,.93,.07,.93)
@@ -225,7 +222,7 @@ pfUI:RegisterModule("buffwatch", function ()
CreateBackdrop(frame)
CreateBackdropShadow(frame)
if bordercolor.r ~= "0" and bordercolor.g ~= "0" and bordercolor.b ~= "0" and bordercolor.a ~= "0" then
if bordercolor.r ~= 0 and bordercolor.g ~= 0 and bordercolor.b ~= 0 and bordercolor.a ~= 0 then
frame.backdrop:SetBackdropBorderColor(bordercolor.r,bordercolor.g,bordercolor.b,1)
end
@@ -422,18 +419,15 @@ pfUI:RegisterModule("buffwatch", function ()
if pfUI.uf.player and C.buffbar.pbuff.enable == "1" then
pfUI.uf.player.buffbar = CreateBuffBarFrame("Player", "HELPFUL")
local config = C.buffbar.pbuff
local r, g, b, a = strsplit(",", config.color)
local br, bg, bb, ba = strsplit(",", config.bordercolor)
local tr, tg, tb, ta = strsplit(",", config.textcolor)
pfUI.uf.player.buffbar:SetWidth(config.width == "-1" and pfUI.uf.player:GetWidth() or config.width)
pfUI.uf.player.buffbar:SetHeight(config.height)
pfUI.uf.player.buffbar.threshold = tonumber(config.threshold)
pfUI.uf.player.buffbar.config = config
pfUI.uf.player.buffbar.buffcmp = config.sort == "asc" and asc or desc
pfUI.uf.player.buffbar.color = { r = r, g = g, b = b, a = a }
pfUI.uf.player.buffbar.bordercolor = { r = br, g = bg, b = bb, a = ba }
pfUI.uf.player.buffbar.textcolor = { r = tr, g = tg, b = tb, a = ta }
pfUI.uf.player.buffbar.color = GetStringColorObject(config.color)
pfUI.uf.player.buffbar.bordercolor = GetStringColorObject(config.bordercolor)
pfUI.uf.player.buffbar.textcolor = GetStringColorObject(config.textcolor)
pfUI.uf.player.buffbar.anchors = {
pfUI.uf.player,
pfUI.uf.player and pfUI.uf.player.debuffs,
@@ -448,9 +442,6 @@ pfUI:RegisterModule("buffwatch", function ()
-- create player debuffbars
if pfUI.uf.player and C.buffbar.pdebuff.enable == "1" then
local config = C.buffbar.pdebuff
local r, g, b, a = strsplit(",", config.color)
local br, bg, bb, ba = strsplit(",", config.bordercolor)
local tr, tg, tb, ta = strsplit(",", config.textcolor)
pfUI.uf.player.debuffbar = CreateBuffBarFrame("Player", "HARMFUL")
pfUI.uf.player.debuffbar:SetWidth(config.width == "-1" and pfUI.uf.player:GetWidth() or config.width)
@@ -458,9 +449,9 @@ pfUI:RegisterModule("buffwatch", function ()
pfUI.uf.player.debuffbar.threshold = tonumber(config.threshold)
pfUI.uf.player.debuffbar.config = config
pfUI.uf.player.debuffbar.buffcmp = config.sort == "asc" and asc or desc
pfUI.uf.player.debuffbar.color = { r = r, g = g, b = b, a = a }
pfUI.uf.player.debuffbar.bordercolor = { r = br, g = bg, b = bb, a = ba }
pfUI.uf.player.debuffbar.textcolor = { r = tr, g = tg, b = tb, a = ta }
pfUI.uf.player.debuffbar.color = GetStringColorObject(config.color)
pfUI.uf.player.debuffbar.bordercolor = GetStringColorObject(config.bordercolor)
pfUI.uf.player.debuffbar.textcolor = GetStringColorObject(config.textcolor)
pfUI.uf.player.debuffbar.anchors = {
pfUI.uf.player,
pfUI.uf.player and pfUI.uf.player.buffbar and pfUI.uf.player.buffbar.bars,
@@ -476,18 +467,15 @@ pfUI:RegisterModule("buffwatch", function ()
-- create target debuffbars
if pfUI.uf.target and C.buffbar.tdebuff.enable == "1" then
local config = C.buffbar.tdebuff
local r, g, b, a = strsplit(",", config.color)
local br, bg, bb, ba = strsplit(",", config.bordercolor)
local tr, tg, tb, ta = strsplit(",", config.textcolor)
pfUI.uf.target.debuffbar = CreateBuffBarFrame("Target", "HARMFUL")
pfUI.uf.target.debuffbar:SetWidth(config.width == "-1" and pfUI.uf.target:GetWidth() or config.width)
pfUI.uf.target.debuffbar:SetHeight(config.height)
pfUI.uf.target.debuffbar.config = config
pfUI.uf.target.debuffbar.buffcmp = config.sort == "asc" and asc or desc
pfUI.uf.target.debuffbar.color = { r = r, g = g, b = b, a = a }
pfUI.uf.target.debuffbar.bordercolor = { r = br, g = bg, b = bb, a = ba }
pfUI.uf.target.debuffbar.textcolor = { r = tr, g = tg, b = tb, a = ta }
pfUI.uf.target.debuffbar.color = GetStringColorObject(config.color)
pfUI.uf.target.debuffbar.bordercolor = GetStringColorObject(config.bordercolor)
pfUI.uf.target.debuffbar.textcolor = GetStringColorObject(config.textcolor)
pfUI.uf.target.debuffbar.threshold = tonumber(config.threshold)
pfUI.uf.target.debuffbar.anchors = {
pfUI.uf.target,
+10 -7
View File
@@ -69,6 +69,11 @@ pfUI:RegisterModule("castbar", function ()
-- spark to the left edge of the bar.
local function StartTradeskillCraft(cb)
cb.currentCraftStart = GetTime() * 1000
local remaining = cb.tradeskillTotal - (cb.tradeskillCompleted or 0)
cb.endTime = cb.currentCraftStart + cb.tradeskillSingleMs * remaining
local duration = (cb.endTime - cb.startTime) / 1000
cb.bar:SetMinMaxValues(0, duration)
cb.lastMax = duration
UpdateTradeskillLabel(cb)
end
@@ -85,11 +90,11 @@ pfUI:RegisterModule("castbar", function ()
cb:SetAlpha(1)
cb.fadeout = nil
cb.bar:SetStatusBarColor(strsplit(",", C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"]))
cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"]))
local rank = ""
if spellID and GetSpellRecField then
rank = GetSpellRecField(spellID, "rank") or ""
if spellID then
rank = C_Spell.GetSpellSubtext(spellID) or ""
end
local spellname = (cb.showname and name) and (name .. " ") or ""
local rankstr = (cb.showrank and rank ~= "") and string.format("|cffaaffcc[%s]|r", rank) or ""
@@ -98,8 +103,7 @@ pfUI:RegisterModule("castbar", function ()
if tex and cb.showicon then
local size = cb:GetHeight()
cb.icon:Show()
cb.icon:SetHeight(size)
cb.icon:SetWidth(size)
cb.icon:SetSize(size, size)
cb.icon.texture:SetTexture(tex)
cb.bar:SetPoint("TOPLEFT", cb.icon, "TOPRIGHT", cb.spacing, 0)
else
@@ -164,8 +168,7 @@ pfUI:RegisterModule("castbar", function ()
-- icon
cb.icon = CreateFrame("Frame", nil, cb)
cb.icon:SetPoint("TOPLEFT", 0, 0)
cb.icon:SetHeight(16)
cb.icon:SetWidth(16)
cb.icon:SetSize(16, 16)
cb.icon.texture = cb.icon:CreateTexture(nil, "OVERLAY")
cb.icon.texture:SetAllPoints()
+1 -1
View File
@@ -429,7 +429,7 @@ pfUI:RegisterModule("chat", function ()
_G["ChatFrame" .. i .. "TabFlash"].Show = function() return end
end
local _, class = UnitClass("player")
local class = UnitClassBase("player")
local classColor = PFUI_CLASS_COLORS[class]
_G["ChatFrame" .. i .. "TabText"]:SetTextColor((classColor.r + .3) * .5, (classColor.g + .3) * .5, (classColor.b + .3) * .5, 1)
_G["ChatFrame" .. i .. "TabText"]:SetFont(panelfont,panelfont_size, "OUTLINE")
+1 -2
View File
@@ -96,8 +96,7 @@ pfUI:RegisterModule("chatcopy", function ()
scroll:Hide()
local editbox = CreateFrame("EditBox", "pfChatCopyBox" .. i, scroll)
editbox:SetHeight(frame:GetHeight())
editbox:SetWidth(frame:GetWidth())
editbox:SetSize(frame:GetSize())
editbox:SetAllPoints(scroll)
editbox:SetTextColor(1,1,1,1)
editbox:SetFontObject(ChatFontNormal)
+1 -1
View File
@@ -5,7 +5,7 @@ pfUI:RegisterModule("combopoints", function ()
ComboFrame:Hide()
ComboFrame:UnregisterAllEvents()
local _, class = UnitClass("player")
local class = UnitClassBase("player")
local combo_width = C["unitframes"]["combowidth"]
local combo_height = C["unitframes"]["comboheight"]
pfUI.combopoints = {}
+2 -4
View File
@@ -123,8 +123,7 @@ pfUI:RegisterModule("easteregg", function ()
local f = GetExplosion()
f:ClearAllPoints()
f:SetPoint("CENTER", fireworks, "TOPLEFT", x, y)
f:SetWidth(25)
f:SetHeight(25)
f:SetSize(25, 25)
f.tex:SetTexture(1,1,1,.5)
f:SetAlpha(1)
f:Show()
@@ -134,8 +133,7 @@ pfUI:RegisterModule("easteregg", function ()
local f = GetExplosion()
f:ClearAllPoints()
f:SetPoint("CENTER", fireworks, "TOPLEFT", x+(math.random(0,100)-50), y+(math.random(0,100)-50))
f:SetWidth(2)
f:SetHeight(2)
f:SetSize(2, 2)
f.tex:SetTexture(math.random(),math.random(),math.random(),1)
f:SetAlpha(1)
f:Show()
+7 -7
View File
@@ -2,7 +2,7 @@ local function getAdjustedTickTimer()
local adjustedEnergyTick = 2
-- Check rogue talents and compute energy tick timing reduction for Combat spec (1.18.0 Blade Rush Talent)
if UnitClass("player") == "Rogue" then
if UnitClassBase("player") == "ROGUE" then
local _, _, _, _, currRank = GetTalentInfo(2, 16)
local bladeRushRank = currRank or 0
@@ -32,10 +32,10 @@ pfUI:RegisterModule("energytick", function()
energytick:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS")
energytick:SetScript("OnEvent", function()
if UnitPowerType("player") == 0 and C.unitframes.player.manatick == "1" then
if UnitPowerType("player") == Enum.PowerType.Mana and C.unitframes.player.manatick == "1" then
this.mode = "MANA"
this:Show()
elseif UnitPowerType("player") == 3 and C.unitframes.player.energy == "1" then
elseif UnitPowerType("player") == Enum.PowerType.Energy and C.unitframes.player.energy == "1" then
this.mode = "ENERGY"
this:Show()
else
@@ -51,11 +51,11 @@ pfUI:RegisterModule("energytick", function()
end
if event == "PLAYER_ENTERING_WORLD" then
this.lastMana = UnitMana("player")
this.lastMana = UnitPower("player")
end
if (event == "UNIT_MANA" or event == "UNIT_ENERGY") and arg1 == "player" then
this.currentMana = UnitMana("player")
this.currentMana = UnitPower("player")
local diff = 0
if this.lastMana then
diff = this.currentMana - this.lastMana
@@ -64,7 +64,7 @@ pfUI:RegisterModule("energytick", function()
if this.mode == "MANA" and diff < 0 then
this.target = 5
elseif this.mode == "MANA" and diff > 0 then
if UnitMana("player") >= UnitManaMax("player") then
if UnitPower("player") >= UnitPowerMax("player") then
this.start = nil
this.spark:SetAlpha(0)
this:Hide()
@@ -105,7 +105,7 @@ pfUI:RegisterModule("energytick", function()
if this.current > this.max then
-- Don't restart tick timer if mana is full
if this.mode == "MANA" and UnitMana("player") >= UnitManaMax("player") then
if this.mode == "MANA" and UnitPower("player") >= UnitPowerMax("player") then
this.start = nil
this.spark:SetAlpha(0)
return
+3 -5
View File
@@ -88,7 +88,7 @@ pfUI:RegisterModule("eqcompare", function ()
local prevMerchant = ShoppingTooltip1.SetMerchantCompareItem
local function SetMerchantCompareItem(self, index, compareItem)
if C.tooltip.compare.basestats == "1" and compareItem == 1 then
if compareItem == 1 then
ShowCompareItem(nil, GetMerchantItemLink(index), 1)
return false
end
@@ -97,7 +97,7 @@ pfUI:RegisterModule("eqcompare", function ()
local prevAuction = ShoppingTooltip1.SetAuctionCompareItem
local function SetAuctionCompareItem(self, type, index, compareItem)
if C.tooltip.compare.basestats == "1" and compareItem == 1 then
if compareItem == 1 then
ShowCompareItem(nil, GetAuctionItemLink(type, index), 1)
return false
end
@@ -132,9 +132,7 @@ pfUI:RegisterModule("eqcompare", function ()
local function makeHook(getter)
return function(tooltip, arg1, arg2, arg3)
if C.tooltip.compare.basestats == "1" then
ShowCompareItem(tooltip, getter(arg1, arg2, arg3))
end
ShowCompareItem(tooltip, getter(arg1, arg2, arg3))
end
end
+4 -4
View File
@@ -25,8 +25,7 @@ pfUI:RegisterModule("farmmode", function ()
Minimap_ZoomOut()
end
_G.SLASH_PFFARMMAP1, _G.SLASH_PFFARMMAP2 = "/farm", "/farmmode"
_G.SlashCmdList.PFFARMMAP = ToggleFarmMode
pfUI.api.RegisterSlashCommand("PFFARMMAP", { "/farm", "/farmmode" }, ToggleFarmMode, true)
pfUI.farmmap = CreateFrame("Minimap", "pfFarmMap", UIParent)
pfUI.farmmap:Hide()
@@ -42,8 +41,9 @@ pfUI:RegisterModule("farmmode", function ()
pfUI.farmmap:RegisterForDrag("LeftButton")
pfUI.farmmap:SetScript("OnMouseWheel", function()
if IsControlKeyDown() then
this:SetWidth(this:GetWidth() + (arg1 > 0 and 10 or -10))
this:SetHeight(this:GetHeight() + (arg1 > 0 and 10 or -10))
local adjust = (arg1 > 0 and 10 or -10)
local width, height = this:GetSize()
this:SetSize(width + adjust, height + adjust)
Minimap_ZoomIn()
Minimap_ZoomOut()
elseif IsShiftKeyDown() then
+2 -2
View File
@@ -1,6 +1,6 @@
pfUI:RegisterModule("feigndeath", function ()
local oldUnitHealth = UnitHealth
function UnitHealth(unit)
local oldUnitHealth = _G.UnitHealth
_G.UnitHealth = function(unit)
if UnitIsFeignDeath(unit) then
local hp = GetUnitField(unit, "health")
if hp and hp > 0 then return hp end
+11 -12
View File
@@ -2,20 +2,22 @@ pfUI:RegisterModule("focus", function ()
-- do not go further on disabled UFs
if C.unitframes.disable == "1" then return end
pfUI.uf.focus = pfUI.uf:CreateUnitFrame("Focus", nil, C.unitframes.focus, .2)
pfUI.uf.focus = pfUI.uf:CreateUnitFrame("Focus", nil, C.unitframes.focus)
pfUI.uf.focus:UpdateFrameSize()
pfUI.uf.focus:SetPoint("BOTTOMLEFT", UIParent, "BOTTOM", 220, 220)
UpdateMovable(pfUI.uf.focus)
pfUI.uf.focus:Hide()
pfUI.uf.focustarget = pfUI.uf:CreateUnitFrame("FocusTarget", nil, C.unitframes.focustarget, .2)
pfUI.uf.focustarget = pfUI.uf:CreateUnitFrame("FocusTarget", nil, C.unitframes.focustarget)
pfUI.uf.focustarget:UpdateFrameSize()
pfUI.uf.focustarget:SetPoint("BOTTOMLEFT", pfUI.uf.focus, "TOP", 0, 10)
UpdateMovable(pfUI.uf.focustarget)
pfUI.uf.focustarget:Hide()
-- PLAYER_FOCUS_CHANGED drives immediate refresh on focus assign / clear.
-- The frame's 0.2s tick keeps health/power/aura data fresh between events.
-- Between events, ClassicAPI fires UNIT_* (health/mana/aura/...) with
-- arg1 == "focus" and arg1 == "focustarget", so both frames update
-- event-driven like target and need no polling tick.
local refresher = CreateFrame("Frame")
refresher:RegisterEvent("PLAYER_FOCUS_CHANGED")
refresher:SetScript("OnEvent", function()
@@ -30,8 +32,7 @@ end)
-- /focusname is pfUI-specific because the engine has no name→GUID
-- lookup for off-screen units — we resolve via a short target-swap.
SLASH_PFFOCUSNAME1, SLASH_PFFOCUSNAME2 = '/focusname', '/pffocusname'
function SlashCmdList.PFFOCUSNAME(msg)
pfUI.api.RegisterSlashCommand("PFFOCUSNAME", { '/focusname', '/pffocusname' }, function(msg)
if msg == "" then return end
local prevGUID = UnitGUID("target")
@@ -61,10 +62,9 @@ function SlashCmdList.PFFOCUSNAME(msg)
else
ClearTarget()
end
end
end, true)
SLASH_PFCASTFOCUS1, SLASH_PFCASTFOCUS2 = '/castfocus', '/pfcastfocus'
function SlashCmdList.PFCASTFOCUS(msg)
pfUI.api.RegisterSlashCommand("PFCASTFOCUS", { '/castfocus', '/pfcastfocus' }, function(msg)
local focusGUID = UnitGUID("focus")
if not focusGUID or focusGUID == "0x0000000000000000" then
UIErrorsFrame:AddMessage(SPELL_FAILED_BAD_TARGETS, 1, 0, 0)
@@ -105,10 +105,9 @@ function SlashCmdList.PFCASTFOCUS(msg)
else
TargetLastTarget()
end
end
end, true)
SLASH_PFSWAPFOCUS1, SLASH_PFSWAPFOCUS2 = '/swapfocus', '/pfswapfocus'
function SlashCmdList.PFSWAPFOCUS(msg)
pfUI.api.RegisterSlashCommand("PFSWAPFOCUS", { '/swapfocus', '/pfswapfocus' }, function(msg)
local targetGUID = UnitGUID("target")
local oldFocusGUID = UnitGUID("focus")
@@ -118,4 +117,4 @@ function SlashCmdList.PFSWAPFOCUS(msg)
TargetUnit(oldFocusGUID)
end
end
end
end, true)
+20 -20
View File
@@ -961,7 +961,7 @@ pfUI:RegisterModule("gui", function ()
"16:" .. T["Very Slow"],
},
["uf_rangecheck_mode"] = {
"vanilla:" .. T["Vanilla (Spellbook)"],
"vanilla:" .. T["ClassicAPI (UnitInRange)"],
"unitxp:" .. T["UnitXP (Precise)"],
},
["uf_raidlayout"] = {
@@ -1068,6 +1068,7 @@ pfUI:RegisterModule("gui", function ()
"unitrev:" .. T["Unit String (Reverse)"],
"name:" .. T["Name"],
"nameshort:" .. T["Name (Short)"],
"ownername:" .. T["Owner Name"],
"level:" .. T["Level"],
"class:" .. T["Class"],
"namehealth:" .. T["Name | Health Missing"],
@@ -2119,10 +2120,9 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(nil, T["Enable 40y-Range Check"], C.unitframes, "rangecheck", "checkbox", nil, nil, nil, nil)
CreateConfig(nil, T["Range Check Mode"], C.unitframes, "rangecheck_mode", "dropdown", pfUI.gui.dropdowns.uf_rangecheck_mode, nil, nil, nil)
CreateConfig(nil, T["UnitXP Range Threshold (yards)"], C.unitframes, "rangecheck_distance", nil, nil, nil, nil, nil)
CreateConfig(nil, T["Range Check Interval"], C.unitframes, "rangechecki", "dropdown", pfUI.gui.dropdowns.uf_rangecheckinterval, nil, nil, nil)
CreateConfig(nil, T["Use Raid Frames To Display Group Members"], C.unitframes, "raidforgroup", "checkbox")
CreateConfig(nil, T["Always Show Self In Raid Frames"], C.unitframes, "selfinraid", "checkbox")
CreateConfig(nil, T["Show Self In Raid Frames When Solo"], C.unitframes, "selfinraid", "checkbox")
CreateConfig(nil, T["Show Self In Group Frames"], C.unitframes, "selfingroup", "checkbox")
CreateConfig(nil, T["Use Raid Frames To Display Group Members"], C.unitframes, "raidforgroup", "checkbox")
CreateConfig(nil, T["Hide Group Frames While In Raid"], C.unitframes.group, "hide_in_raid", "checkbox")
CreateConfig(nil, T["Max Amount Of Raid Frames"], C.unitframes, "maxraid", "dropdown", pfUI.gui.dropdowns.maxraid)
@@ -2143,6 +2143,7 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(nil, T["Druid Settings"], nil, nil, "header")
CreateConfig(nil, T["Show Druid Mana Bar"], C.unitframes, "druidmanabar", "checkbox", nil, nil, nil, nil)
CreateConfig(nil, T["Show Druid Mana Bar Text"], C.unitframes, "druidmanatext", "checkbox", nil, nil, nil, nil)
CreateConfig(nil, T["Druid Mana Bar Height"], C.unitframes, "druidmanaheight", nil, nil, nil, nil, nil)
CreateConfig(nil, T["Druid Mana Bar Width (-1 = auto)"], C.unitframes, "druidmanawidth", nil, nil, nil, nil, nil)
CreateConfig(nil, T["Druid Mana Bar X-Offset"], C.unitframes, "druidmanaoffx", nil, nil, nil, nil, nil)
@@ -2185,6 +2186,7 @@ pfUI:RegisterModule("gui", function ()
[10] = { "grouptarget", T["Group-Target"]},
[11] = { "grouppet", T["Group-Pet"] },
[12] = { "raid", T["Raid"] },
[13] = { "raidpet", T["Raid-Pet"] },
}
CreateGUIEntry(T["Unit Frames"], T["Click Casting"], function()
@@ -2234,6 +2236,7 @@ pfUI:RegisterModule("gui", function ()
U.ptarget = U["pettarget"]
U.grouptarget = U["group"]
U.grouppet = U["group"]
U.raidpet = U["raid"]
-- build config entries
CreateConfig(U[c], T["Display Frame"] .. ": " .. t, C.unitframes[c], "visible", "checkbox")
@@ -2278,6 +2281,13 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(U["raid"], T["Raid Padding"], C.unitframes[c], "raidpadding")
CreateConfig(U["raid"], T["Raid Layout"], C.unitframes[c], "raidlayout", "dropdown", pfUI.gui.dropdowns.uf_raidlayout)
CreateConfig(U["raid"], T["Raid Fill Direction"], C.unitframes[c], "raidfill", "dropdown", pfUI.gui.dropdowns.orientation)
CreateConfig(U["raid"], T["Collapse Empty Slots"], C.unitframes[c], "collapse", "checkbox")
elseif c == "raidpet" then
CreateConfig(U[c], T["Layout"], nil, nil, "header")
CreateConfig(U["raid"], T["Raid Padding"], C.unitframes[c], "raidpadding")
CreateConfig(U["raid"], T["Raid Layout"], C.unitframes[c], "raidlayout", "dropdown", pfUI.gui.dropdowns.uf_raidlayout)
CreateConfig(U["raid"], T["Raid Fill Direction"], C.unitframes[c], "raidfill", "dropdown", pfUI.gui.dropdowns.orientation)
CreateConfig(U["raid"], T["Collapse Empty Slots"], C.unitframes[c], "collapse", "checkbox")
end
CreateConfig(U[c], T["Healthbar"], nil, nil, "header")
@@ -2413,6 +2423,8 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(nil, T["Enable Item Quality Color For Equipment Only"], C.appearance.bags, "borderonlygear", "checkbox")
CreateConfig(nil, T["Highlight Unusable Items"], C.appearance.bags, "unusable", "checkbox")
CreateConfig(nil, T["Unusable Item Color"], C.appearance.bags, "unusable_color", "color")
CreateConfig(nil, T["Highlight New Items"], C.appearance.bags, "newitem", "checkbox")
CreateConfig(nil, T["New Item Color"], C.appearance.bags, "newitem_color", "color")
CreateConfig(nil, T["Enable Movable Bags"], C.appearance.bags, "movable", "checkbox")
CreateConfig(nil, T["Anchor Bags Above Chat"], C.appearance.bags, "abovechat", "checkbox")
CreateConfig(nil, T["Hide Chat When Bags Are Opened"], C.appearance.bags, "hidechat", "checkbox")
@@ -2423,6 +2435,8 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(nil, T["Auto Sell Grey Items"], C.global, "autosell", "checkbox")
CreateConfig(nil, T["Auto Repair Items"], C.global, "autorepair", "checkbox")
CreateConfig(nil, T["Auto Sort When Opening Bags"], C.appearance.bags, "autoSortOnOpen", "checkbox")
CreateConfig(nil, T["Reverse Sort Direction (Last Bag First)"], C.appearance.bags, "sortreverse", "checkbox")
CreateConfig(nil, T["Reverse Sort Priority (Hearthstone Last)"], C.appearance.bags, "sortprioreverse", "checkbox")
end)
CreateGUIEntry(T["Loot"], nil, function()
@@ -2573,6 +2587,7 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(U["bars"], T["Switch Pages On Shift Key Press"], C.bars, "pagemastershift", "checkbox")
CreateConfig(U["bars"], T["Switch Pages On Ctrl Key Press"], C.bars, "pagemasterctrl", "checkbox")
CreateConfig(U["bars"], T["Switch Pages On Druid Stealth"], C.bars, "druidstealth", "checkbox")
CreateConfig(U["bars"], T["Switch Pages On Priest Shadowform"], C.bars, "priestshadow", "checkbox")
CreateConfig(nil, T["Range Based Hunter Paging"], C.bars, "hunterbar", "checkbox", nil, nil, nil, nil)
end)
@@ -2759,22 +2774,7 @@ pfUI:RegisterModule("gui", function ()
CreateConfig(nil, T["Show Movement Speed"], C.tooltip, "movespeed", "checkbox")
CreateConfig(nil, T["Custom Transparency"], C.tooltip, "alpha")
CreateConfig(nil, T["Status Bar Texture"], C.tooltip.statusbar, "texture", "dropdown", pfUI.gui.dropdowns.uf_bartexture)
CreateConfig(nil, T["Compare Item Base Stats"], C.tooltip.compare, "basestats", "checkbox")
local showAlways = CreateConfig(nil, T["Always Show Item Comparison"], C.tooltip.compare, "showalways", "checkbox")
local function gate()
local on = C.tooltip.compare.basestats == "1"
if on then
showAlways.input:Enable()
showAlways.caption:SetTextColor(1, 1, 1)
else
showAlways.input:Disable()
showAlways.caption:SetTextColor(0.5, 0.5, 0.5)
end
end
gate()
pfUI.events:RegisterCallback("config:changed", function(_, cat, key)
if cat == C.tooltip.compare and key == "basestats" then gate() end
end, "eqcompare-showalways-gate")
CreateConfig(nil, T["Always Show Item Comparison"], C.tooltip.compare, "showalways", "checkbox")
CreateConfig(nil, T["Always Show Extended Vendor Values"], C.tooltip.vendor, "showalways", "checkbox")
CreateConfig(U["questitem"], T["Show Related Quest On Questitems"], C.tooltip.questitem, "showquest", "checkbox")
CreateConfig(U["questitem"], T["Show Required Questitem Count"], C.tooltip.questitem, "showcount", "checkbox")
+1 -1
View File
@@ -1,5 +1,5 @@
pfUI:RegisterModule("hunterbar", function ()
local _,class = UnitClass("player")
local class = UnitClassBase("player")
if class ~= "HUNTER" or C.bars.hunterbar == "0" then return end
-- Wing Clip (any rank) and Arcane Shot (any rank) spell IDs.
+1 -3
View File
@@ -2,14 +2,12 @@
-- Announces Innervate casts via raid/party/battleground chat
-- Registers AURA_CAST events directly - zero polling, pure event-driven
pfUI:RegisterNewModule("innervatecall", "Innervate Callout", "DRUID")
pfUI:RegisterModule("innervatecall", function ()
-- Requires Nampower for AURA_CAST events
if not GetNampowerVersion then return end
-- Only load for druids
local _, playerClass = UnitClass("player")
if playerClass ~= "DRUID" then return end
if UnitClassBase("player") ~= "DRUID" then return end
local INNERVATE_SPELLID = 29166
+2 -2
View File
@@ -236,7 +236,7 @@ pfUI:RegisterModule("loot", function ()
if (candidate) then
index_to_name[i] = candidate
name_to_index[candidate] = i
randoms[table.getn(randoms)+1]=i
table.insert(randoms, i)
if candidate == pfUI.loot.me then
pfUI.loot.my_index = i
end
@@ -693,7 +693,7 @@ pfUI:RegisterModule("loot", function ()
else -- not an eligible candidate for that item
pfUI.loot.rollers[who] = {roll=tonumber(roll),value="disabled"}
end
pfUI.loot.rollers_sorted[table.getn(pfUI.loot.rollers_sorted)+1]={who=who,roll=tonumber(roll),value=pfUI.loot.rollers[who].value}
table.insert(pfUI.loot.rollers_sorted, {who=who,roll=tonumber(roll),value=pfUI.loot.rollers[who].value})
end
end
table.sort(pfUI.loot.rollers_sorted,function(a,b)
+388
View File
@@ -0,0 +1,388 @@
pfUI:RegisterModule("loothistory", function ()
local rawborder, border = GetBorderSize()
-- Layout
local ITEM_H, PLAYER_H = 24, 18
local ITEM_W, PLAYER_W = 350, 330
-- rollType constants returned by C_LootHistory.GetPlayerInfo (0/1/2; vanilla
-- has no disenchant roll).
local ROLL_PASS, ROLL_NEED, ROLL_GREED = 0, 1, 2
local ROLL_TEX = {
[ROLL_NEED] = "Interface\\Buttons\\UI-GroupLoot-Dice-Up",
[ROLL_GREED] = "Interface\\Buttons\\UI-GroupLoot-Coin-Up",
[ROLL_PASS] = "Interface\\Buttons\\UI-GroupLoot-Pass-Up",
}
local WINMARK = "Interface\\Buttons\\UI-CheckBox-Check"
local QUESTIONMARK = "Interface\\Icons\\INV_Misc_QuestionMark"
local function ClassColor(class)
local c = class and RAID_CLASS_COLORS[class]
if c then return c.r, c.g, c.b end
return 1, 1, 1
end
-- Paint an item row's icon/name/quality from a loaded Item mixin.
local function RenderItemVisual(f, item)
local r, g, b = 1, 1, 1
local qc = item:GetItemQualityColor()
if qc then r, g, b = qc.r, qc.g, qc.b end
f.icon:SetTexture(item:GetItemIcon())
f.iconbg:SetBackdropBorderColor(r, g, b, 1)
f.name:SetText(item:GetItemName() or UNKNOWN)
f.name:SetTextColor(r, g, b)
end
local function ShowRetrieving(f)
f.icon:SetTexture(QUESTIONMARK)
f.iconbg:SetBackdropBorderColor(1, .3, .3, 1)
f.name:SetText(T["Retrieving item information..."])
f.name:SetTextColor(1, .3, .3)
end
-- expansion state keyed on the stable rollID (survives ring-index shifts)
local expanded = {}
-- ==========================================================================
-- Window
-- ==========================================================================
pfUI.loothistory = CreateFrame("Frame", "pfLootHistory", UIParent)
pfUI.loothistory:SetFrameStrata("DIALOG")
pfUI.loothistory:SetSize(380, 490)
pfUI.loothistory:SetPoint("CENTER", 0, 0)
pfUI.loothistory:SetMovable(true)
pfUI.loothistory:EnableMouse(true)
pfUI.loothistory:RegisterForDrag("LeftButton")
pfUI.loothistory:SetScript("OnDragStart", function() this:StartMoving() end)
pfUI.loothistory:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
pfUI.loothistory:Hide()
CreateBackdrop(pfUI.loothistory, nil, true, .75)
CreateBackdropShadow(pfUI.loothistory)
tinsert(UISpecialFrames, "pfLootHistory")
pfUI.loothistory.caption = pfUI.loothistory:CreateFontString("Status", "LOW", "GameFontNormal")
pfUI.loothistory.caption:SetFont(pfUI.font_default, C.global.font_size + 4, "OUTLINE")
pfUI.loothistory.caption:SetTextColor(.2, 1, .8, 1)
pfUI.loothistory.caption:SetPoint("TOP", 0, -10)
pfUI.loothistory.caption:SetText(T["Loot History"])
-- close button
pfUI.loothistory.close = CreateFrame("Button", nil, pfUI.loothistory)
pfUI.loothistory.close:SetPoint("TOPRIGHT", -border*2, -border*2)
CreateBackdrop(pfUI.loothistory.close)
pfUI.loothistory.close:SetSize(15, 15)
pfUI.loothistory.close.texture = pfUI.loothistory.close:CreateTexture("pfLootHistoryClose")
pfUI.loothistory.close.texture:SetTexture(pfUI.media["img:close"])
pfUI.loothistory.close.texture:SetPoint("TOPLEFT", pfUI.loothistory.close, "TOPLEFT", 4, -4)
pfUI.loothistory.close.texture:SetPoint("BOTTOMRIGHT", pfUI.loothistory.close, "BOTTOMRIGHT", -4, 4)
pfUI.loothistory.close.texture:SetVertexColor(1, .25, .25, 1)
pfUI.loothistory.close:SetScript("OnEnter", function()
CreateBackdrop(pfUI.loothistory.close)
pfUI.loothistory.close.backdrop:SetBackdropBorderColor(1, .25, .25, 1)
end)
pfUI.loothistory.close:SetScript("OnLeave", function() CreateBackdrop(pfUI.loothistory.close) end)
pfUI.loothistory.close:SetScript("OnClick", function() pfUI.loothistory:Hide() end)
-- clear button
pfUI.loothistory.clear = CreateFrame("Button", nil, pfUI.loothistory, "UIPanelButtonTemplate")
SkinButton(pfUI.loothistory.clear)
pfUI.loothistory.clear:SetSize(60, 16)
pfUI.loothistory.clear:SetPoint("TOPLEFT", 10, -8)
pfUI.loothistory.clear:SetText(T["Clear"])
pfUI.loothistory.clear:SetScript("OnClick", function() C_LootHistory.Clear() end)
-- scroll frame
pfUI.loothistory.scroll = CreateScrollFrame("pfLootHistoryScroll", pfUI.loothistory)
pfUI.loothistory.scroll:SetSize(360, 440)
pfUI.loothistory.scroll:SetPoint("BOTTOM", 0, 10)
pfUI.loothistory.scroll.backdrop = CreateFrame("Frame", nil, pfUI.loothistory.scroll)
pfUI.loothistory.scroll.backdrop:SetFrameLevel(1)
pfUI.loothistory.scroll.backdrop:SetPoint("TOPLEFT", pfUI.loothistory.scroll, "TOPLEFT", -5, 5)
pfUI.loothistory.scroll.backdrop:SetPoint("BOTTOMRIGHT", pfUI.loothistory.scroll, "BOTTOMRIGHT", 5, -5)
CreateBackdrop(pfUI.loothistory.scroll.backdrop, nil, true)
local list = CreateScrollChild("pfLootHistoryList", pfUI.loothistory.scroll)
pfUI.loothistory.list = list
-- ==========================================================================
-- Frame pools
-- ==========================================================================
local itemFrames = {}
local usedPlayers, freePlayers = {}, {}
local FullUpdate -- forward declaration (toggle handlers call it)
local function CreateItemFrame()
local f = CreateFrame("Button", nil, list)
f:SetSize(ITEM_W, ITEM_H)
f:SetBackdrop(pfUI.backdrop_hover)
f:SetBackdropBorderColor(1, 1, 1, .04)
f:EnableMouse(1)
-- expand / collapse toggle
f.toggle = CreateFrame("Button", nil, f)
f.toggle:SetSize(14, 14)
f.toggle:SetPoint("LEFT", 4, 0)
f.toggle:SetScript("OnClick", function()
local id = f.rollID
if id then expanded[id] = not expanded[id]; FullUpdate() end
end)
-- icon + quality-colored border
f.iconbg = CreateFrame("Frame", nil, f)
f.iconbg:SetSize(ITEM_H - 8, ITEM_H - 8)
f.iconbg:SetPoint("LEFT", f.toggle, "RIGHT", 4, 0)
CreateBackdrop(f.iconbg, nil, true)
f.icon = f.iconbg:CreateTexture(nil, "ARTWORK")
f.icon:SetPoint("TOPLEFT", f.iconbg, "TOPLEFT", 2, -2)
f.icon:SetPoint("BOTTOMRIGHT", f.iconbg, "BOTTOMRIGHT", -2, 2)
f.icon:SetTexCoord(.08, .92, .08, .92)
-- winner block (right side, shown for decided rolls)
f.winicon = f:CreateTexture(nil, "OVERLAY")
f.winicon:SetSize(14, 14)
f.winicon:SetPoint("RIGHT", f, "RIGHT", -6, 0)
f.winroll = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.winroll:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.winroll:SetPoint("RIGHT", f.winicon, "LEFT", -2, 0)
f.winroll:SetTextColor(1, 1, 1, 1)
f.winname = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.winname:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.winname:SetPoint("RIGHT", f.winroll, "LEFT", -4, 0)
f.winname:SetJustifyH("RIGHT")
-- item name (leaves room on the right for the winner block)
f.name = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.name:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.name:SetPoint("LEFT", f.iconbg, "RIGHT", 5, 0)
f.name:SetPoint("RIGHT", f, "RIGHT", -100, 0)
f.name:SetJustifyH("LEFT")
f:SetScript("OnEnter", function()
this:SetBackdropBorderColor(1, 1, 1, .08)
if this.itemLink then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:SetHyperlink(this.itemLink)
GameTooltip:Show()
end
end)
f:SetScript("OnLeave", function()
this:SetBackdropBorderColor(1, 1, 1, .04)
GameTooltip:Hide()
end)
f:SetScript("OnClick", function()
local id = this.rollID
if id then expanded[id] = not expanded[id]; FullUpdate() end
end)
return f
end
local function CreatePlayerFrame()
local f = CreateFrame("Frame", nil, list)
f:SetSize(PLAYER_W, PLAYER_H)
-- name is indented to leave room for the winner checkmark on its left
f.name = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.name:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.name:SetPoint("LEFT", 20, 0)
f.name:SetJustifyH("LEFT")
f.rollicon = f:CreateTexture(nil, "OVERLAY")
f.rollicon:SetSize(16, 16)
f.rollicon:SetPoint("RIGHT", -4, 0)
f.rolltext = f:CreateFontString("Status", "OVERLAY", "GameFontNormal")
f.rolltext:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
f.rolltext:SetPoint("RIGHT", f.rollicon, "LEFT", -3, 0)
f.rolltext:SetTextColor(1, 1, 1, 1)
-- winner checkmark, just left of the player name (matches reference)
f.winmark = f:CreateTexture(nil, "OVERLAY")
f.winmark:SetSize(16, 16)
f.winmark:SetTexture(WINMARK)
f.winmark:SetPoint("RIGHT", f.name, "LEFT", -1, 0)
return f
end
local function RecycleAllPlayers()
for i = 1, table.getn(usedPlayers) do
local pf = usedPlayers[i]
pf:Hide()
table.insert(freePlayers, pf)
end
usedPlayers = {}
end
local function GetPlayerFrame()
local pf = table.remove(freePlayers) or CreatePlayerFrame()
table.insert(usedPlayers, pf)
return pf
end
local function SetToggleTexture(toggle, isExpanded)
if isExpanded then
toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up")
toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-Down")
else
toggle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up")
toggle:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-Down")
end
end
-- ==========================================================================
-- Rendering
-- ==========================================================================
local function UpdateItemFrame(f, i)
local rollID, itemLink, numPlayers, isDone, winnerIdx = C_LootHistory.GetItem(i)
f.rollID = rollID
f.itemIdx = i
f.itemLink = itemLink
f.numPlayers = numPlayers or 0
f.isDone = isDone
local isExpanded = rollID and expanded[rollID]
SetToggleTexture(f.toggle, isExpanded)
-- Item icon/name/quality via the ClassicAPI Item mixin. When the item
-- isn't cached yet, show a placeholder and re-paint this row from the
-- ContinueOnItemLoad callback (guarded on rollID: rows are pooled, so the
-- callback must no-op if the row has since been reused for another roll).
local item = itemLink and Item:CreateFromItemLink(itemLink)
if item and not item:IsItemEmpty() then
if item:IsItemDataCached() then
RenderItemVisual(f, item)
else
ShowRetrieving(f)
local pending = rollID
item:ContinueOnItemLoad(function()
if f.rollID == pending then RenderItemVisual(f, item) end
end)
end
else
ShowRetrieving(f)
end
-- winner summary only on a decided, collapsed row
if isDone and not isExpanded then
if winnerIdx then
local wname, wclass, wrollType, wroll = C_LootHistory.GetPlayerInfo(i, winnerIdx)
f.winicon:SetTexture(ROLL_TEX[wrollType] or ROLL_TEX[ROLL_NEED])
f.winicon:Show()
if wroll and wroll > 0 then f.winroll:SetText(wroll) else f.winroll:SetText("") end
f.winroll:Show()
f.winname:SetText(wname or UNKNOWN)
f.winname:SetTextColor(ClassColor(wclass))
f.winname:Show()
else
-- nobody won: everyone passed
f.winicon:SetTexture(ROLL_TEX[ROLL_PASS])
f.winicon:Show()
f.winroll:SetText("")
f.winroll:Show()
f.winname:SetText(T["All players passed"])
f.winname:SetTextColor(1, .4, .4)
f.winname:Show()
end
else
f.winicon:Hide()
f.winroll:Hide()
f.winname:Hide()
end
end
local function RenderPlayerFrame(pf, name, class, rollType, roll, isWinner)
pf.name:SetText(name or UNKNOWN)
pf.name:SetTextColor(ClassColor(class))
pf.rollicon:SetTexture(ROLL_TEX[rollType] or ROLL_TEX[ROLL_PASS])
if roll and roll > 0 then pf.rolltext:SetText(roll) else pf.rolltext:SetText("") end
if isWinner then pf.winmark:Show() else pf.winmark:Hide() end
end
-- A player row is worth showing while the roll is undecided (see everyone),
-- or afterwards only if they actually rolled or it's you (hide the passers'
-- noise on a decided roll) — mirrors Blizzard's ShouldDisplayPlayer.
local function ShouldDisplayPlayer(isDone, roll, isMe)
return isMe or (roll and roll > 0) or not isDone
end
function FullUpdate()
if not pfUI.loothistory:IsShown() then return end
RecycleAllPlayers()
local num = C_LootHistory.GetNumItems()
local y = -2
for i = 1, num do
local f = itemFrames[i] or CreateItemFrame()
itemFrames[i] = f
UpdateItemFrame(f, i)
f:ClearAllPoints()
f:SetPoint("TOPLEFT", list, "TOPLEFT", 4, y)
f:Show()
y = y - ITEM_H - 2
if f.rollID and expanded[f.rollID] then
for p = 1, f.numPlayers do
local name, class, rollType, roll, isWinner, isMe = C_LootHistory.GetPlayerInfo(i, p)
if ShouldDisplayPlayer(f.isDone, roll, isMe) then
local pf = GetPlayerFrame()
RenderPlayerFrame(pf, name, class, rollType, roll, isWinner)
pf:ClearAllPoints()
pf:SetPoint("TOPLEFT", list, "TOPLEFT", 22, y)
pf:Show()
y = y - PLAYER_H
end
end
y = y - 2
end
end
for i = num + 1, table.getn(itemFrames) do
itemFrames[i]:Hide()
end
-- Resize the scroll child and re-attach it: SetHeight alone on a
-- SetAllPoints'd child doesn't make the ScrollFrame recompute its scroll
-- range, so a dynamically-grown list wouldn't scroll until a /reload.
list:SetHeight(math.max(1, -y + 2))
pfUI.loothistory.scroll:SetScrollChild(list)
pfUI.loothistory.scroll:UpdateScrollState()
end
pfUI.loothistory:SetScript("OnShow", function() FullUpdate() end)
-- ==========================================================================
-- Events
-- ==========================================================================
local events = CreateFrame("Frame")
events:RegisterEvent("LOOT_HISTORY_FULL_UPDATE")
events:RegisterEvent("LOOT_HISTORY_ROLL_CHANGED")
events:RegisterEvent("LOOT_HISTORY_ROLL_COMPLETE")
events:SetScript("OnEvent", function()
-- auto-show on a new roll opening / completing, if enabled
if C.loothistory.autoshow == "1"
and (event == "LOOT_HISTORY_FULL_UPDATE" or event == "LOOT_HISTORY_ROLL_COMPLETE")
and not pfUI.loothistory:IsShown() then
pfUI.loothistory:Show() -- OnShow runs FullUpdate
return
end
FullUpdate() -- no-op while hidden
end)
-- ==========================================================================
-- Slash command
-- ==========================================================================
local function Toggle()
pfUI.loothistory:SetShown(not pfUI.loothistory:IsShown())
end
pfUI.api.RegisterSlashCommand("PFLOOTHISTORY", { "/loothistory", "/pfloothistory" }, Toggle, true)
end)
+6 -10
View File
@@ -2,15 +2,14 @@ pfUI:RegisterModule("macrotweak", function ()
local conflictAddons = { "Supermacro", "SuperCleveRoidMacros", "UltimaMacros" }
local disabled = false
local function CheckConflicts()
for _, name in pairs(conflictAddons) do
if IsAddOnLoaded(name) then
for _, addon in pairs(conflictAddons) do
local name = addon
EventUtil.ContinueOnAddOnLoaded(name, function()
if not disabled then
DEFAULT_CHAT_FRAME:AddMessage("|cff33ffccpfUI|r: " .. name .. " found, macrotweak disabled.")
disabled = true
return true
end
end
return false
disabled = true
end)
end
-- do not write macro calls into chat input history
@@ -64,7 +63,4 @@ pfUI:RegisterModule("macrotweak", function ()
UseInventoryItem(slot)
end
end)
-- Check conflicts after one tick so all addons have finished loading
RunNextFrame(CheckConflicts)
end)
+5 -11
View File
@@ -25,11 +25,7 @@ pfUI:RegisterModule("map", function ()
pfUI.map = { UpdateConfig = UpdateTooltipScale }
function _G.ToggleWorldMap()
if WorldMapFrame:IsShown() then
WorldMapFrame:Hide()
else
WorldMapFrame:Show()
end
WorldMapFrame:SetShown(not WorldMapFrame:IsShown())
end
C.position["WorldMapFrame"] = C.position["WorldMapFrame"] or { alpha = 1.0, scale = 0.7 }
@@ -107,8 +103,8 @@ pfUI:RegisterModule("map", function ()
WorldMapFrame:ClearAllPoints()
WorldMapFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
WorldMapFrame:SetWidth(WorldMapButton:GetWidth() + 15)
WorldMapFrame:SetHeight(WorldMapButton:GetHeight() + 55)
local wmWidth, wmHeight = WorldMapButton:GetSize()
WorldMapFrame:SetSize(wmWidth + 15, wmHeight + 55)
LoadMovable(WorldMapFrame)
-- skin
@@ -130,8 +126,7 @@ pfUI:RegisterModule("map", function ()
btn:SetHighlightTexture("")
btn.text = _G["pfUI_map_autozoneswitchText"]
CreateBackdrop(btn, nil, true)
btn:SetWidth(14)
btn:SetHeight(14)
btn:SetSize(14, 14)
btn:SetPoint("RIGHT", WorldMapContinentDropDown, "LEFT", -8, 2)
btn.text:ClearAllPoints()
btn.text:SetPoint("RIGHT", btn, "LEFT", -4, 1)
@@ -169,8 +164,7 @@ pfUI:RegisterModule("map", function ()
WorldMapButton.coords.text:SetJustifyH("RIGHT")
WorldMapButton.coords:SetScript("OnUpdate", function()
local width = WorldMapButton:GetWidth()
local height = WorldMapButton:GetHeight()
local width, height = WorldMapButton:GetSize()
local mx, my = WorldMapButton:GetCenter()
local scale = WorldMapButton:GetEffectiveScale()
local x, y = GetCursorPosition()
+1 -1
View File
@@ -85,7 +85,7 @@ pfUI:RegisterModule("mapcolors", function ()
end
local function ColorizeName(frame)
local _, class = UnitClass(frame.unit)
local class = UnitClassBase(frame.unit)
local color = PFUI_CLASS_COLORS[class]
frame.name = frame.name or UnitName(frame.unit)
frame.name = '|c'..color.colorStr..frame.name..'|r'
-1
View File
@@ -1,4 +1,3 @@
pfUI:RegisterNewModule("marktracking", "Mark Tracker")
pfUI:RegisterModule("marktracking", function ()
-- Requires mark1-mark8 unit tokens (Turtle WoW / Nampower)
if not UnitExists("mark1") and not UnitExists("mark8") then
+9 -26
View File
@@ -33,11 +33,9 @@ pfUI:RegisterModule("minimap", function ()
pfUI.minimap.UpdateConfig = function(self)
size = tonumber(C.appearance.minimap.size) or 140
pfUI.minimap:SetWidth(size)
pfUI.minimap:SetHeight(size)
pfUI.minimap:SetSize(size, size)
Minimap:SetWidth(size)
Minimap:SetHeight(size)
Minimap:SetSize(size, size)
-- vanilla+tbc: do the best to detect the minimap arrow
local arrowscale = tonumber(C.appearance.minimap.arrowscale)
@@ -158,8 +156,7 @@ pfUI:RegisterModule("minimap", function ()
pfUI.minimapCoordinates:SetPoint("BOTTOMLEFT", 3, 3)
end
pfUI.minimapCoordinates:SetHeight(C.global.font_size)
pfUI.minimapCoordinates:SetWidth(Minimap:GetWidth())
pfUI.minimapCoordinates:SetSize(Minimap:GetWidth(), C.global.font_size)
pfUI.minimapCoordinates.text = pfUI.minimapCoordinates:CreateFontString("MinimapCoordinatesText", "LOW", "GameFontNormal")
pfUI.minimapCoordinates.text:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
pfUI.minimapCoordinates.text:SetTextColor(1,1,1,1)
@@ -171,19 +168,14 @@ pfUI:RegisterModule("minimap", function ()
pfUI.minimapCoordinates.text:SetJustifyH("LEFT")
end
if C.appearance.minimap.coordstext ~= "on" then
pfUI.minimapCoordinates:Hide()
else
pfUI.minimapCoordinates:Show()
end
pfUI.minimapCoordinates:SetShown(C.appearance.minimap.coordstext == "on")
-- Create zone text frame in top center of minimap
pfUI.minimapZone = CreateFrame("Frame", "pfMinimapZone", pfUI.minimap)
pfUI.minimapZone:RegisterEvent("MINIMAP_ZONE_CHANGED")
pfUI.minimapZone:RegisterEvent("PLAYER_ENTERING_WORLD")
pfUI.minimapZone:SetPoint("TOP", 0, -3)
pfUI.minimapZone:SetHeight(C.global.font_size + 2)
pfUI.minimapZone:SetWidth(Minimap:GetWidth())
pfUI.minimapZone:SetSize(Minimap:GetWidth(), C.global.font_size + 2)
pfUI.minimapZone.text = pfUI.minimapZone:CreateFontString("minimapZoneText", "LOW", "GameFontNormal")
pfUI.minimapZone.text:SetFont(pfUI.font_default, C.global.font_size + 2, "OUTLINE")
pfUI.minimapZone.text:SetAllPoints(pfUI.minimapZone)
@@ -205,17 +197,13 @@ pfUI:RegisterModule("minimap", function ()
elseif pvp == "contested" then
pfUI.minimapZone.text:SetTextColor(1.0, 0.7, 0)
else
pfUI.minimapZone.text:SetTextColor(1, 1, 1, 1)
pfUI.minimapZone.text:SetTextColor(WHITE_FONT_COLOR:GetRGBA())
end
pfUI.minimapZone.text:SetText(GetMinimapZoneText())
end
end)
if C.appearance.minimap.zonetext ~= "on" then
pfUI.minimapZone:Hide()
else
pfUI.minimapZone:Show()
end
pfUI.minimapZone:SetShown(C.appearance.minimap.zonetext == "on")
-- Minimap hover event
-- Update and toggle showing of coordinates and zone text on mouse enter/leave
@@ -241,8 +229,7 @@ pfUI:RegisterModule("minimap", function ()
pfUI.minimap.pvpicon:RegisterEvent("UPDATE_FACTION")
pfUI.minimap.pvpicon:RegisterEvent("UNIT_FACTION")
pfUI.minimap.pvpicon:SetFrameStrata("HIGH")
pfUI.minimap.pvpicon:SetWidth(16)
pfUI.minimap.pvpicon:SetHeight(16)
pfUI.minimap.pvpicon:SetSize(16, 16)
pfUI.minimap.pvpicon:SetAlpha(.5)
pfUI.minimap.pvpicon:SetParent(pfUI.minimap)
pfUI.minimap.pvpicon:SetPoint("BOTTOMRIGHT", pfUI.minimap, "BOTTOMRIGHT", -5, 5)
@@ -251,11 +238,7 @@ pfUI:RegisterModule("minimap", function ()
pfUI.minimap.pvpicon.texture:SetAllPoints(pfUI.minimap.pvpicon)
pfUI.minimap.pvpicon:SetScript("OnEvent", function()
if C.unitframes.player.showPVPMinimap == "1" and UnitIsPVP("player") then
pfUI.minimap.pvpicon:Show()
else
pfUI.minimap.pvpicon:Hide()
end
pfUI.minimap.pvpicon:SetShown(C.unitframes.player.showPVPMinimap == "1" and UnitIsPVP("player"))
end)
end)
+2 -3
View File
@@ -1,6 +1,5 @@
pfUI:RegisterModule("mouseover", function ()
_G.SLASH_PFCAST1, _G.SLASH_PFCAST2 = "/pfcast", "/pfmouse"
function SlashCmdList.PFCAST(msg)
pfUI.api.RegisterSlashCommand("PFCAST", { "/pfcast", "/pfmouse" }, function(msg)
local func = pfUI.api.TryMemoizedFuncLoadstringForSpellCasts(msg)
local unit = "mouseover"
@@ -30,5 +29,5 @@ pfUI:RegisterModule("mouseover", function ()
if restore_target then TargetUnit(unit) end
func()
if restore_target then TargetLastTarget() end
end
end, true)
end)
+188 -161
View File
@@ -4,7 +4,6 @@ pfUI:RegisterModule("nameplates", function ()
-- Local function references for performance
local GetTime = GetTime
local UnitExists = UnitExists
local UnitName = UnitName
local UnitClass = UnitClass
local UnitLevel = UnitLevel
@@ -15,8 +14,6 @@ pfUI:RegisterModule("nameplates", function ()
local UnitCanAssist = UnitCanAssist
local UnitHealth = UnitHealth
local UnitHealthMax = UnitHealthMax
local UnitMana = UnitMana
local UnitManaMax = UnitManaMax
local pairs = pairs
local tonumber = tonumber
local strlower = strlower
@@ -60,16 +57,26 @@ pfUI:RegisterModule("nameplates", function ()
local inFriendlyZone = false
local platecount = 0
local registry = {}
-- Subset of registry that currently has a unit assigned (between
-- NAME_PLATE_UNIT_ADDED and _REMOVED). The central loop iterates this instead
-- of the full pool so hidden pool slots aren't touched every tick.
local visiblePlates = {}
local raidGuidCache = {} -- guid -> name (rebuilt on RAID_ROSTER_UPDATE/PARTY_MEMBERS_CHANGED)
-- Resolve a plate GUID to its cast/channel info via C_Spell. Returns a
-- compact struct (spellName / icon / startTime / endTime / duration /
-- isChannel) or nil when the unit isn't casting / the GUID can't map to a
-- live token.
local function GetCastInfo(guid)
if not guid then return nil end
local unit = UnitTokenFromGUID(guid)
-- Per-GUID cast state, populated by nampower's SPELL_START_OTHER events and
-- cleared on SPELL_FAILED_OTHER / plate removal / expiry. This replaces the
-- old per-tick C_Spell poll on every visible plate: cast detection is now
-- event driven, and GetCastInfo just reads this cache.
local castState = {}
-- guid -> nameplate, maintained on NAME_PLATE_UNIT_ADDED/_REMOVED so a cast
-- event can find its plate in O(1) and only cache casts we actually show.
local plateByGuid = {}
-- One-shot C_Spell poll. Only used to seed a plate that spawns while its
-- unit is already mid-cast (its SPELL_START_OTHER fired before the plate
-- existed). Never called per frame.
local function PollCastInfo(unit)
if not unit then return nil end
local name, _, texture, startMs, endMs, _, _, _, spellID = C_Spell.UnitCastingInfo(unit)
local isChannel
@@ -88,14 +95,27 @@ pfUI:RegisterModule("nameplates", function ()
isChannel = isChannel,
}
end
-- Read a unit's current cast from the event-driven cache (keyed by GUID).
-- Returns the cached struct while the cast is still active, else nil (and
-- prunes the expired entry). Same struct shape and callers as before, minus
-- the per-tick poll.
local function GetCastInfo(unit)
if not unit then return nil end
local guid = UnitGUID(unit)
if not guid then return nil end
local info = castState[guid]
if info and info.endTime > GetTime() then return info end
if info then castState[guid] = nil end
return nil
end
local guidTargetTokenCache = {} -- guid -> "<guid>target" interned string
local debuffCache = {} -- guid -> { [spellID] = { start, duration } }
-- Reusable per-plate debuff display buffer (avoid GC churn from per-call table creation)
local debuffDisplayBuf = {} -- [i] = { effect, texture, stacks, dtype, duration, timeleft }
for i = 1, 16 do debuffDisplayBuf[i] = {} end
local threatMemory = {} -- guid -> true if mob had player targeted
local debuffSeen = {} -- reusable table for debuff tracking (avoid GC churn)
-- local debuffSeen = {} -- reusable table for debuff tracking (avoid GC churn)
-- PERF: visiblePlateCount maintained event-driven (NAME_PLATE_UNIT_ADDED/_REMOVED)
local visiblePlateCount = 0
@@ -159,20 +179,13 @@ pfUI:RegisterModule("nameplates", function ()
-- ============================================================================
local frameState = {
now = 0,
hasTarget = false,
targetGuid = nil,
hasMouseover = false,
mouseoverGuid = nil,
}
-- cache default border color
local er, eg, eb, ea = GetStringColor(pfUI_config.appearance.border.color)
-- Vanilla Lua 5.0 bitwise check: math.mod(math.floor(value / flag), 2) ~= 0
local function HasFlag(flags, flag)
return math.mod(math.floor(flags / flag), 2) ~= 0
end
local UNIT_FLAG_IN_COMBAT = 524288 -- 0x00080000
local NULL_GUID = "0x0000000000000000"
local function RebuildRaidGuidCache()
@@ -191,10 +204,11 @@ pfUI:RegisterModule("nameplates", function ()
local combatColorCache = {} -- guid -> { color, expires }
local function GetCombatStateColor(guid)
local function GetCombatStateColor(guid, token)
-- PERF: Quick exit if player not in combat
if not UnitAffectingCombat("player") then return false end
if UnitCanAssist("player", guid) then return false end
if not token then return false end
if UnitCanAssist("player", token) then return false end
-- PERF: 0.2s throttle per guid - color changes are not time-critical
local now = frameState.now
@@ -203,24 +217,17 @@ pfUI:RegisterModule("nameplates", function ()
return cached.color
end
local flags = GetUnitField and GetUnitField(guid, "flags")
if not flags then return false end
if not HasFlag(flags, UNIT_FLAG_IN_COMBAT) then return false end
if not UnitAffectingCombat(token) then return false end
local mobTargetGuid = GetUnitField and GetUnitField(guid, "target")
-- The mob's current target via the nameplate token chain (ClassicAPI):
-- "nameplateNtarget" resolves to whatever this plate's unit is targeting,
-- so no GetUnitField("target") or SuperWoW "<guid>target" token needed.
local target = token .. "target"
local mobTargetGuid = UnitGUID(target)
local hasTarget = mobTargetGuid and mobTargetGuid ~= NULL_GUID
-- PERF: cache the SuperWoW-style "<guid>target" unit token. The concat
-- intern-hits Lua's string pool every call; caching once per guid
-- saves the hash+lookup. Cleared in NAME_PLATE_UNIT_REMOVED.
local target = guidTargetTokenCache[guid]
if not target then
target = guid .. "target"
guidTargetTokenCache[guid] = target
end
local color = false
local castInfo = GetCastInfo(guid)
local castInfo = GetCastInfo(token)
local isCasting = castInfo and castInfo.endTime and now < castInfo.endTime
local targetingPlayer = hasTarget and UnitIsUnit(target, "player")
@@ -442,8 +449,7 @@ pfUI:RegisterModule("nameplates", function ()
nameplate.debuffs[i]:SetPoint(aligna, nameplate.debuffs[i-limit], alignb, 0, space)
end
nameplate.debuffs[i]:SetWidth(tonumber(C.nameplates.debuffsize))
nameplate.debuffs[i]:SetHeight(tonumber(C.nameplates.debuffsize))
nameplate.debuffs[i]:SetSize(debuffsize, debuffsize)
-- Update cooldown display settings
if nameplate.debuffs[i].cd then
@@ -468,10 +474,11 @@ nameplates:RegisterEvent("PARTY_MEMBERS_CHANGED")
nameplates:RegisterEvent("NAME_PLATE_CREATED")
nameplates:RegisterEvent("NAME_PLATE_UNIT_ADDED")
nameplates:RegisterEvent("NAME_PLATE_UNIT_REMOVED")
if GetUnitField then
nameplates:RegisterEvent("UNIT_FLAGS_GUID")
nameplates:RegisterEvent("UNIT_AURA_GUID")
end
nameplates:RegisterEvent("UNIT_AURA")
nameplates:RegisterEvent("UNIT_FLAGS")
nameplates:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
nameplates:RegisterEvent("SPELL_START_OTHER")
nameplates:RegisterEvent("SPELL_FAILED_OTHER")
nameplates:SetScript("OnEvent", function()
-- Stop event handling during logout to prevent crash 132
@@ -489,6 +496,7 @@ end
CacheConfig()
this:SetGameVariables()
RebuildRaidGuidCache()
frameState.targetGuid = UnitGUID("target")
end
-- Handle friendly zone nameplate disable feature
@@ -544,10 +552,21 @@ end
end
elseif event == "NAME_PLATE_UNIT_ADDED" then
-- arg1 = "nameplateN" unit token; resolve to GUID for cache keys
-- arg1 = "nameplateN" unit token. Cache the GUID for cache keys and the
-- token itself for token-based UnitX reads (stable per plate lifetime).
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
if plate and plate.nameplate then
plate.nameplate.cachedGuid = UnitGUID(arg1)
visiblePlates[plate] = plate
local guid = UnitGUID(arg1)
plate.nameplate.cachedGuid = guid
plate.nameplate.unit = arg1
if guid then
plateByGuid[guid] = plate.nameplate
-- Seed: the unit may already be mid-cast (its SPELL_START_OTHER fired
-- before this plate existed). One poll here catches that; ongoing
-- casts arrive via the event.
castState[guid] = PollCastInfo(arg1)
end
nameplates.OnShow(plate)
end
visiblePlateCount = visiblePlateCount + 1
@@ -556,57 +575,104 @@ end
visiblePlateCount = visiblePlateCount > 0 and visiblePlateCount - 1 or 0
-- arg1 = "nameplateN" unit token; UnitGUID still resolves inside the
-- handler (the slot is freed after dispatch returns)
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
if plate then visiblePlates[plate] = nil end
local guid = UnitGUID(arg1)
if guid then
if debuffCache[guid] then debuffCache[guid] = nil end
if threatMemory[guid] then threatMemory[guid] = nil end
if guidTargetTokenCache[guid] then guidTargetTokenCache[guid] = nil end
if combatColorCache[guid] then combatColorCache[guid] = nil end
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
if castState[guid] then castState[guid] = nil end
if plateByGuid[guid] then plateByGuid[guid] = nil end
if plate and plate.nameplate and plate.nameplate.cachedGuid == guid then
plate.nameplate.cachedGuid = nil
plate.nameplate.unit = nil
end
end
elseif event == "UNIT_FLAGS_GUID" then
-- Nampower: fires instantly when any unit's flags change (e.g. stun, combat enter/leave)
-- arg1 = guid — directly flag that nameplate for immediate update, bypassing throttle
local plate = C_NamePlate.GetNamePlateForGUID(arg1)
if plate and plate.nameplate then
plate.nameplate.eventcache = true
elseif event == "UNIT_FLAGS" then
if arg1 and strfind(arg1, "^nameplate") then
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
if plate and plate.nameplate then
plate.nameplate.eventcache = true
end
end
elseif event == "UNIT_AURA_GUID" then
-- Nampower: fires when a unit's aura set changes (add/remove/modify).
-- arg1 = guid. Flag the matching plate so OnUpdate triggers a fresh
-- C_UnitAuras read on the next tick instead of waiting on the 0.5s
-- throttle — covers expirations, dispels, refreshes, and stack changes
-- in one event.
local plate = C_NamePlate.GetNamePlateForGUID(arg1)
if plate and plate.nameplate then
plate.nameplate.auraUpdate = true
elseif event == "UPDATE_MOUSEOVER_UNIT" then
local new = UnitGUID("mouseover")
local old = frameState.mouseoverGuid
if new ~= old then
frameState.mouseoverGuid = new
local po = old and plateByGuid[old]
if po then po.eventcache = true end
local pn = new and plateByGuid[new]
if pn then pn.eventcache = true end
end
elseif event == "SPELL_START_OTHER" then
-- nampower: arg2=spellId, arg3=casterGuid, arg6=castTime(ms),
-- arg7=channel duration(ms, 0 if not a channel), arg8=spellType
-- (1 = channel). Cache the cast only for a unit we have a plate for, so
-- the table stays bounded to on-screen casters.
local casterGuid = arg3
local plate = casterGuid and plateByGuid[casterGuid]
if plate then
local isChannel = arg8 == 1
local durationMs = isChannel and arg7 or arg6
if durationMs and durationMs > 0 then
local spellId = arg2
local now = GetTime()
castState[casterGuid] = {
spellName = C_Spell.GetSpellName(spellId),
spellID = spellId,
icon = C_Spell.GetSpellTexture(spellId),
startTime = now,
endTime = now + durationMs / 1000,
duration = durationMs / 1000,
isChannel = isChannel,
}
plate.castUpdate = true -- bypass the throttle so the bar shows now
end
end
elseif event == "SPELL_FAILED_OTHER" then
-- nampower: arg1=casterGuid, arg2=spellId. Clear on interrupt/failure.
local casterGuid = arg1
if casterGuid and castState[casterGuid] then
castState[casterGuid] = nil
local plate = plateByGuid[casterGuid]
if plate then plate.castUpdate = true end
end
elseif event == "UNIT_AURA" then
-- ClassicAPI: fires with arg1 == "nameplateN" when a unit's aura set
-- changes (add/remove/modify). Flag the matching plate so OnUpdate does a
-- fresh C_UnitAuras read next tick instead of waiting on the 0.5s
-- throttle -- covers expirations, dispels, refreshes, and stack changes
-- in one event. Guard on the token prefix (UNIT_AURA also fires for
-- target/party/raid).
if arg1 and strfind(arg1, "^nameplate") then
local plate = C_NamePlate.GetNamePlateForUnit(arg1)
if plate and plate.nameplate then
plate.nameplate.auraUpdate = true
end
end
elseif event == "PLAYER_TARGET_CHANGED" then
-- Flag target plate for update via GUID registry
local targetGuid = UnitGUID("target")
if targetGuid then
local plate = C_NamePlate.GetNamePlateForGUID(targetGuid)
if plate and plate.nameplate then
plate.nameplate.targetUpdate = true
end
frameState.targetGuid = UnitGUID('target')
-- Flag the target's plate for update
local plate = C_NamePlate.GetNamePlateForUnit("target")
if plate and plate.nameplate then
plate.nameplate.targetUpdate = true
end
-- Also propagate to all plates for alpha/strata updates
this.eventcache = true
elseif event == "PLAYER_COMBO_POINTS" or event == "UNIT_COMBO_POINTS" then
-- Only flag the target plate for combo point update
local targetGuid = UnitGUID("target")
if targetGuid then
local plate = C_NamePlate.GetNamePlateForGUID(targetGuid)
if plate and plate.nameplate then
plate.nameplate.comboUpdate = true
end
-- Only flag the target's plate for combo point update
local plate = C_NamePlate.GetNamePlateForUnit("target")
if plate and plate.nameplate then
plate.nameplate.comboUpdate = true
end
else
this.eventcache = true
@@ -622,21 +688,15 @@ end
-- PERF: Cache GetTime() once per frame
frameState.now = now
frameState.hasTarget, frameState.targetGuid = UnitExists("target")
frameState.hasMouseover = UnitExists("mouseover")
-- propagate events to all nameplates
if this.eventcache then
this.eventcache = nil
for plate in pairs(registry) do
plate.eventcache = true
for plate in pairs(visiblePlates) do
plate.nameplate.eventcache = true
end
end
-- visiblePlateCount is maintained event-driven via NAME_PLATE_UNIT_ADDED/_REMOVED.
-- Central OnUpdate for all visible plates
for plate in pairs(registry) do
for plate in pairs(visiblePlates) do
if plate:IsVisible() then
nameplates.OnUpdate(plate, frameState)
end
@@ -669,7 +729,7 @@ end
nameplates.OnCreate = function(frame)
local parent = frame or this
platecount = platecount + 1
platename = "pfNamePlate" .. platecount
local platename = "pfNamePlate" .. platecount
-- create pfUI nameplate overlay
local nameplate = CreateFrame("Button", platename, parent)
@@ -734,8 +794,7 @@ end
nameplate.totem = CreateFrame("Frame", nil, nameplate)
nameplate.totem:SetPoint("CENTER", nameplate, "CENTER", 0, 0)
nameplate.totem:SetHeight(32)
nameplate.totem:SetWidth(32)
nameplate.totem:SetSize(32, 32)
nameplate.totem.icon = nameplate.totem:CreateTexture(nil, "OVERLAY")
nameplate.totem.icon:SetTexCoord(.078, .92, .079, .937)
nameplate.totem.icon:SetAllPoints()
@@ -823,11 +882,11 @@ end
local plate_width = C.nameplates.width + 50
local plate_height = C.nameplates.heighthealth + font_size + 5
local plate_height_cast = C.nameplates.heighthealth + font_size + 5 + C.nameplates.heightcast + 5
-- local plate_height_cast = C.nameplates.heighthealth + font_size + 5 + C.nameplates.heightcast + 5
local combo_size = 5
local width = tonumber(C.nameplates.width)
local debuffsize = tonumber(C.nameplates.debuffsize)
-- local width = tonumber(C.nameplates.width)
-- local debuffsize = tonumber(C.nameplates.debuffsize)
local healthoffset = tonumber(C.nameplates.health.offset)
local orientation = C.nameplates.verticalhealth == "1" and "VERTICAL" or "HORIZONTAL"
@@ -840,8 +899,7 @@ end
RebuildOfftanks()
nameplate:SetWidth(plate_width)
nameplate:SetHeight(plate_height)
nameplate:SetSize(plate_width, plate_height)
nameplate:SetPoint("TOP", parent, "TOP", 0, 0)
nameplate.name:SetFont(font, font_size, font_style)
@@ -870,23 +928,20 @@ end
nameplate.guild:SetFont(font, font_size, font_style)
nameplate.glow:SetWidth(C.nameplates.width + 60)
nameplate.glow:SetHeight(C.nameplates.heighthealth + 30)
nameplate.glow:SetSize(C.nameplates.width + 60, C.nameplates.heighthealth + 30)
nameplate.glow:SetVertexColor(glowr, glowg, glowb, glowa)
nameplate.raidicon:ClearAllPoints()
nameplate.raidicon:SetPoint("BOTTOM", nameplate.health, "TOP", C.nameplates.raidiconoffx, C.nameplates.raidiconoffy)
nameplate.level:SetFont(font, font_size, font_style)
nameplate.raidicon:SetWidth(C.nameplates.raidiconsize)
nameplate.raidicon:SetHeight(C.nameplates.raidiconsize)
nameplate.raidicon:SetSize(C.nameplates.raidiconsize, C.nameplates.raidiconsize)
for i=1,16 do
UpdateDebuffConfig(nameplate, i)
end
for i=1,5 do
nameplate.combopoints[i]:SetWidth(combo_size)
nameplate.combopoints[i]:SetHeight(combo_size)
nameplate.combopoints[i]:SetSize(combo_size, combo_size)
nameplate.combopoints[i]:SetPoint("TOPRIGHT", nameplate.health, "BOTTOMRIGHT", -(i-1)*(combo_size+default_border*3), -default_border*3)
CreateBackdrop(nameplate.combopoints[i], default_border)
end
@@ -944,7 +999,7 @@ end
end
local target = plate.istarget
local mouseover = UnitExists("mouseover") and plate.original.glow:IsShown() or nil
local mouseover = plate.cachedGuid and plate.cachedGuid == frameState.mouseoverGuid or nil
local unitstr = target and "target" or mouseover and "mouseover" or plate.cachedGuid or nil
-- resolve player vs npc from plate's own unit so libunitscan can't return
@@ -988,16 +1043,14 @@ end
-- always make sure to keep plate visible
plate:Show()
if target and cfg.targetglow then
plate.glow:Show() else plate.glow:Hide()
end
plate.glow:SetShown(target and cfg.targetglow)
-- target indicator
if cfg.outcombatstate then
local guid = plate.cachedGuid or ""
-- determine color based on combat state
local color = GetCombatStateColor(guid)
local color = GetCombatStateColor(guid, plate.unit)
if not color then color = combatstate.NONE end
-- set border color
@@ -1072,7 +1125,7 @@ end
if guild and C.nameplates.showguildname == "1" then
plate.guild:SetText(guild)
if guild == GetGuildInfo("player") then
if UnitIsInMyGuild(plate.unit) then
plate.guild:SetTextColor(0, 0.9, 0, 1)
else
plate.guild:SetTextColor(0.8, 0.8, 0.8, 1)
@@ -1091,15 +1144,15 @@ end
if cfg.showhp then
local rhp, rhpmax, estimated
local guid = plate.cachedGuid
if guid and GetUnitField then
local npHp = GetUnitField(guid, "health")
local npMaxHp = GetUnitField(guid, "maxHealth")
local unit = plate.unit
if unit then
local npHp = UnitHealth(unit)
local npMaxHp = UnitHealthMax(unit)
if npHp and npHp > 0 and npMaxHp and npMaxHp > 0 and npMaxHp ~= 100 then
rhp, rhpmax = npHp, npMaxHp
end
end
-- Fallback to existing methods
if not rhp then
if hpmax > 100 or (round(hpmax/100*hp) ~= hp) then
@@ -1150,7 +1203,7 @@ end
if cfg.barcombatstate then
local guid = plate.cachedGuid or ""
local color = GetCombatStateColor(guid)
local color = GetCombatStateColor(guid, plate.unit)
if color then
r, g, b, a = color.r, color.g, color.b, color.a
@@ -1270,19 +1323,7 @@ end
end
nameplates.OnShow = function(frame)
local frame = frame or this
local nameplate = frame.nameplate
-- cachedGuid is set by NAME_PLATE_UNIT_ADDED before this fires
local guid = nameplate.cachedGuid
if guid and pfUI.api.libunitscan and pfUI.api.libunitscan.ScanGuid then
-- notify libunitscan so it can cache unit data without mouseover
local name = nameplate.original.name:GetText()
local npcFlags = GetUnitField(guid, "npcFlags") or 0
pfUI.api.libunitscan.ScanGuid(guid, name, npcFlags == 0)
end
nameplates:OnDataChanged(nameplate)
nameplates:OnDataChanged((frame or this).nameplate)
end
nameplates.OnUpdate = function(frame, state)
@@ -1296,13 +1337,13 @@ end
-- and immediately correct on de-target (unlike istarget which updates one tick later)
local targetGuid = state and state.targetGuid
local target = (targetGuid and nameplate.cachedGuid and targetGuid == nameplate.cachedGuid) or
(state and state.hasTarget and frame:GetAlpha() >= 0.99) or nil
(state and state.targetGuid and frame:GetAlpha() >= 0.99) or nil
-- Target plate castbar runs on its own dedicated frame (nameplates.castbarFrame).
-- For non-target plates with castbar active, use castbar throttle to ensure
-- smooth animation without overloading the central loop.
local isCastingNonTarget = not target and nameplate.castbar and nameplate.castbar:IsShown()
if not isCastingNonTarget and not target and cfg.showcastbar and nameplate.cachedGuid then
local castInfo = GetCastInfo(nameplate.cachedGuid)
local castInfo = GetCastInfo(nameplate.unit)
if castInfo and castInfo.endTime > now then
isCastingNonTarget = true
end
@@ -1346,7 +1387,7 @@ end
local update
local original = nameplate.original
local name = original.name:GetText()
local mouseover = state and state.hasMouseover and original.glow:IsShown() or nil
local mouseover = nameplate.cachedGuid and nameplate.cachedGuid == frameState.mouseoverGuid or nil
-- trigger queued event update
if hasEventUpdate then
@@ -1374,8 +1415,7 @@ end
if C.nameplates["overlap"] == "1" then
if frame:GetWidth() > 1 then
frame:SetWidth(1)
frame:SetHeight(1)
frame:SetSize(1, 1)
end
else
if not nameplate.dwidth then
@@ -1383,8 +1423,9 @@ end
end
if floor(frame:GetWidth()) ~= nameplate.dwidth then
frame:SetWidth(nameplate:GetWidth() * UIParent:GetScale())
frame:SetHeight(nameplate:GetHeight() * UIParent:GetScale())
local nameW, nameH = nameplate:GetSize()
local uiScale = UIParent:GetScale()
frame:SetSize(nameW * uiScale, nameH * uiScale)
end
end
@@ -1410,7 +1451,7 @@ end
-- Set non-target plate alpha
local configAlpha = cfg.notargalpha or 0.5
local desiredAlpha = (target or not state.hasTarget) and 1 or configAlpha
local desiredAlpha = (target or not state.targetGuid) and 1 or configAlpha
if nameplate.cachedAlpha ~= desiredAlpha then
nameplate:SetAlpha(desiredAlpha)
@@ -1441,13 +1482,7 @@ end
-- trigger update when name color changed (includes combat state check)
local r, g, b = original.name:GetTextColor()
local inCombatWithPlayer = false
if cfg.namefightcolor then
local guid = nameplate.cachedGuid
if guid then
inCombatWithPlayer = UnitAffectingCombat(guid) and UnitAffectingCombat("player")
end
end
local inCombatWithPlayer = cfg.namefightcolor and UnitAffectingCombat(nameplate.unit) and UnitAffectingCombat("player")
if r + g + b ~= nameplate.cache.namecolor or (cfg.namefightcolor and nameplate.cache.inCombat ~= inCombatWithPlayer) then
nameplate.cache.namecolor = r + g + b
@@ -1495,7 +1530,7 @@ end
nameplate.health.targetHeight = hc
end
local w, h = nameplate.health:GetWidth(), nameplate.health:GetHeight()
local w, h = nameplate.health:GetSize()
local wc, hc = nameplate.health.targetWidth, nameplate.health.targetHeight
if wc and hc then
@@ -1507,15 +1542,14 @@ end
nameplate.health.zoomTransition = true
else
if nameplate.health.zoomTransition then
nameplate.health:SetWidth(wc)
nameplate.health:SetHeight(hc)
nameplate.health:SetSize(wc, hc)
nameplate.health.zoomTransition = nil
end
nameplate.health.zoomed = true
end
end
elseif nameplate.health.zoomed or nameplate.health.zoomTransition then
local w, h = nameplate.health:GetWidth(), nameplate.health:GetHeight()
local w, h = nameplate.health:GetSize()
local wc = cfg.width
local hc = cfg.heighthealth
@@ -1524,8 +1558,7 @@ end
elseif h > hc + 0.5 then
nameplate.health:SetHeight(h*0.95)
else
nameplate.health:SetWidth(wc)
nameplate.health:SetHeight(hc)
nameplate.health:SetSize(wc, hc)
nameplate.health.zoomTransition = nil
nameplate.health.zoomed = nil
nameplate.health.targetWidth = nil
@@ -1591,7 +1624,7 @@ end
-- Shared castbar update logic (used by both dedicated frame and central loop)
nameplates.UpdateCastbar = function(nameplate, now)
if not nameplate or not nameplate.castbar then return end
local castInfo = GetCastInfo(nameplate.cachedGuid)
local castInfo = GetCastInfo(nameplate.unit)
if not castInfo or castInfo.endTime < now then
nameplate.castbar.isShown = nil
nameplate.castbar.lastEndTime = nil
@@ -1607,7 +1640,7 @@ end
-- Relative 0..duration range to avoid float precision loss with large
-- absolute timestamps.
nameplate.castbar:SetMinMaxValues(0, duration)
nameplate.castbar:SetStatusBarColor(strsplit(",", C.appearance.castbar[(isChannel and "channelcolor" or "castbarcolor")]))
nameplate.castbar:SetStatusBarColor(GetStringColor(C.appearance.castbar[(isChannel and "channelcolor" or "castbarcolor")]))
if castInfo.icon then
nameplate.castbar.icon.tex:SetTexture(castInfo.icon)
nameplate.castbar.icon.tex:SetTexCoord(.1,.9,.1,.9)
@@ -1627,23 +1660,17 @@ end
if not nameplate.castbar.isShown then nameplate.castbar.isShown = true; nameplate.castbar:Show() end
end
-- Dedicated frame that updates ONLY the target plate castbar.
-- Uses nameplates_castbar throttle from libthrottle.
-- Dedicated frame that updates ONLY the target plate castbar. Unthrottled:
-- now that casts are event-driven, this just reads the cache + SetValue, so
-- it animates the fill every frame for the smoothest sweep on the bar the
-- player watches most. (Non-target plates stay throttled via the central
-- loop's nameplates_castbar gate.)
nameplates.castbarFrame = CreateFrame("Frame", nil, UIParent)
nameplates.castbarFrame:SetScript("OnUpdate", function()
if not cfg.showcastbar then return end
local now = GetTime()
local throttle = pfUI.throttle:Get("nameplates_castbar")
if (this.tick or 0) > now then return end
this.tick = now + throttle
local targetGuid = UnitExists("target") and UnitGUID("target")
if not targetGuid then return end
local frame = C_NamePlate.GetNamePlateForGUID(targetGuid)
if not frame or not frame.nameplate then return end
nameplates.UpdateCastbar(frame.nameplate, now)
if not cfg.showcastbar or not frameState.targetGuid then return end
local nameplate = plateByGuid[frameState.targetGuid]
if not nameplate then return end
nameplates.UpdateCastbar(nameplate, GetTime())
end)
-- set nameplate game settings
+19 -220
View File
@@ -15,8 +15,7 @@ pfUI:RegisterModule("nampower", function ()
pfUI.spellqueue = CreateFrame("Frame", "pfSpellQueue", UIParent)
pfUI.spellqueue:SetFrameStrata("HIGH")
pfUI.spellqueue:SetWidth(size)
pfUI.spellqueue:SetHeight(size)
pfUI.spellqueue:SetSize(size, size)
pfUI.spellqueue:Hide()
-- Position near player castbar if available
@@ -53,8 +52,7 @@ pfUI:RegisterModule("nampower", function ()
return
end
local eventCode = arg1
local spellId = arg2
local eventCode, spellId = arg1, arg2
if eventCode == NORMAL_QUEUED or eventCode == NON_GCD_QUEUED or eventCode == ON_SWING_QUEUED then
local texture = C_Spell.GetSpellTexture(spellId)
@@ -74,21 +72,21 @@ pfUI:RegisterModule("nampower", function ()
-- Shows when reactive abilities like Overpower, Revenge, Execute are usable
if C.unitframes.reactive_indicator == "1" then
local size = tonumber(C.unitframes.reactive_size) or 28
local _, class = UnitClass("player")
local class = UnitClassBase("player")
-- Reactive spells by class
local reactiveSpells = {
WARRIOR = {
{ name = "Overpower", texture = "Interface\\Icons\\Ability_MeleeDamage" },
{ name = "Revenge", texture = "Interface\\Icons\\Ability_Warrior_Revenge" },
{ name = "Execute", texture = "Interface\\Icons\\INV_Sword_48" },
7384, -- Overpower
6572, -- Revenge
5283, -- Execute
},
ROGUE = {
{ name = "Riposte", texture = "Interface\\Icons\\Ability_Warrior_Challange" },
76, -- Riposte
},
HUNTER = {
{ name = "Mongoose Bite", texture = "Interface\\Icons\\Ability_Hunter_SwiftStrike" },
{ name = "Counterattack", texture = "Interface\\Icons\\Ability_Warrior_Challange" },
1495, -- Mongoose Bite
19306, -- Counterattack
},
}
@@ -97,21 +95,19 @@ pfUI:RegisterModule("nampower", function ()
pfUI.reactive = CreateFrame("Frame", "pfReactiveIndicator", UIParent)
pfUI.reactive:SetFrameStrata("HIGH")
local spellCount = table.getn(spells)
pfUI.reactive:SetWidth(size * spellCount + 4 * (spellCount - 1))
pfUI.reactive:SetHeight(size)
pfUI.reactive:SetSize(size * spellCount + 4 * (spellCount - 1), size)
pfUI.reactive:SetPoint("CENTER", UIParent, "CENTER", 0, -200)
pfUI.reactive:Hide()
pfUI.reactive.icons = {}
for i, spell in ipairs(spells) do
local icon = CreateFrame("Frame", nil, pfUI.reactive)
icon:SetWidth(size)
icon:SetHeight(size)
icon:SetSize(size, size)
icon:SetPoint("LEFT", pfUI.reactive, "LEFT", (i-1) * (size + 4), 0)
icon.texture = icon:CreateTexture(nil, "ARTWORK")
icon.texture:SetAllPoints(icon)
icon.texture:SetTexture(spell.texture)
icon.texture:SetTexture(C_Spell.GetSpellTexture(spell))
icon.texture:SetTexCoord(.08, .92, .08, .92)
icon.glow = icon:CreateTexture(nil, "OVERLAY")
@@ -122,7 +118,7 @@ pfUI:RegisterModule("nampower", function ()
CreateBackdrop(icon)
icon:Hide()
icon.spellName = spell.name
icon.spellName = C_Spell.GetSpellName(spell)
pfUI.reactive.icons[i] = icon
end
@@ -132,27 +128,17 @@ pfUI:RegisterModule("nampower", function ()
local anyVisible = false
for _, icon in ipairs(this.icons) do
local usable = C_Spell.IsSpellUsable(icon.spellName)
if usable then
icon:Show()
anyVisible = true
else
icon:Hide()
end
end
if anyVisible then
this:Show()
else
this:Hide()
icon:SetShown(usable)
anyVisible = anyVisible or usable
end
this:SetShown(anyVisible)
end)
end
end
-- /disenchantall slash command (DisenchantAll is Nampower-provided)
if DisenchantAll then
_G.SLASH_PFDISENCHANTALL1 = "/disenchantall"
_G.SLASH_PFDISENCHANTALL2 = "/dea"
SlashCmdList["PFDISENCHANTALL"] = function(msg)
pfUI.api.RegisterSlashCommand("PFDISENCHANTALL", { "/disenchantall", "/dea" }, function(msg)
-- DisenchantAll(itemIdOrName | quality, [includeSoulbound]).
-- Quality is a string keyword ("greens", "blues", "purples", or pipe-
-- combined). Numbers are interpreted as item IDs, not quality levels.
@@ -160,195 +146,8 @@ pfUI:RegisterModule("nampower", function ()
local arg = (msg and msg ~= "") and msg or "greens"
local target = tonumber(arg) or arg
DisenchantAll(target)
DEFAULT_CHAT_FRAME:AddMessage("|cff33ffccpfUI|r: DisenchantAll(" .. tostring(target) .. ")")
end
print("|cff33ffccpfUI|r: DisenchantAll(" .. tostring(target) .. ")")
end, true)
end
-- Druid Secondary Mana Bar
-- Shows base mana when druid is in shapeshift form (Bear/Cat uses Rage/Energy)
-- Uses Nampower's GetUnitField to get base mana values
-- Fully self-contained: uses its own config settings from C.unitframes.druidmana*
if GetUnitField and pfUI.uf and pfUI_config.unitframes.druidmanabar == "1" then
local rawborder, default_border = GetBorderSize("unitframes")
local DC = C.unitframes -- druid mana config lives here as druidmana* keys
-- Shared helper: create a druid mana bar on a unit frame
local function CreateDruidManaBar(parent, unit)
if not parent then return nil end
local parentConfig = parent.config
-- Read own config values
local dmHeight = tonumber(DC.druidmanaheight) or 10
local dmWidth = DC.druidmanawidth or "-1"
local dmOffX = tonumber(DC.druidmanaoffx) or 0
local dmOffY = tonumber(DC.druidmanaoffy) or 0
local dmSpace = tonumber(DC.druidmanaspace) or -3
local dmTexture = DC.druidmanatexture or "Interface\\AddOns\\pfUI\\img\\bar"
local bar = CreateFrame("StatusBar", "pfDruidMana_" .. unit, parent)
bar:SetFrameStrata(parent:GetFrameStrata())
bar:SetFrameLevel(parent:GetFrameLevel() + 5)
bar:SetStatusBarTexture(pfUI.media[dmTexture] or dmTexture)
-- Bar color: use same manacolor logic as the normal power bar
local manacolor = parentConfig.defcolor == "0" and parentConfig.manacolor or C.unitframes.manacolor
local r, g, b, a = pfUI.api.strsplit(",", manacolor)
bar:SetStatusBarColor(tonumber(r) or .25, tonumber(g) or .25, tonumber(b) or 1, tonumber(a) or 1)
-- Size: own width/height, fallback to parent power bar width if -1
local width = dmWidth ~= "-1" and tonumber(dmWidth) or nil
if width then
bar:SetWidth(width)
end
bar:SetHeight(dmHeight)
-- Position below the power bar with own spacing + offsets
local spacing = -2 * default_border - dmSpace
if width then
-- Fixed width: use single point with offset
bar:SetPoint("TOP", parent.power, "BOTTOM", dmOffX, spacing + dmOffY)
else
-- Auto width: anchor to both sides of power bar
bar:SetPoint("TOPLEFT", parent.power, "BOTTOMLEFT", dmOffX, spacing + dmOffY)
bar:SetPoint("TOPRIGHT", parent.power, "BOTTOMRIGHT", dmOffX, spacing + dmOffY)
end
bar:Hide()
CreateBackdrop(bar)
CreateBackdropShadow(bar)
-- Font settings (same logic as power bar)
local fontname = pfUI.font_unit
local fontsize = tonumber(pfUI_config.global.font_unit_size)
local fontstyle = pfUI_config.global.font_unit_style
if parentConfig.customfont == "1" then
fontname = pfUI.media[parentConfig.customfont_name]
fontsize = tonumber(parentConfig.customfont_size)
fontstyle = parentConfig.customfont_style
end
-- Text color (always mana-colored)
local tr, tg, tb = ManaBarColor[0].r, ManaBarColor[0].g, ManaBarColor[0].b
if C.unitframes.pastel == "1" then
tr, tg, tb = (tr + .75) * .5, (tg + .75) * .5, (tb + .75) * .5
end
-- Single center text showing current/max
bar.text = bar:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
bar.text:SetFontObject(GameFontWhite)
bar.text:SetFont(fontname, fontsize, fontstyle)
bar.text:SetPoint("CENTER", bar, "CENTER", 0, 0)
bar.text:SetJustifyH("CENTER")
bar.text:SetTextColor(tr, tg, tb, 1)
return bar
end
-- Shared helper: update druid mana bar values and text
local function UpdateDruidManaBar(bar, unit)
if not UnitExists(unit) then
bar:Hide()
return
end
-- For non-player units, only show if the target is a Druid
if unit ~= "player" then
local _, unitClass = UnitClass(unit)
if unitClass ~= "DRUID" then
bar:Hide()
return
end
end
local powerType = UnitPowerType(unit)
-- Only show when NOT using mana (i.e., in Bear/Cat form)
if powerType == 0 then
bar:Hide()
return
end
-- Get base mana using Nampower's GetUnitField
local baseMana, baseMaxMana
local guid = UnitGUID(unit)
if guid then
baseMana = GetUnitField(guid, "power1")
baseMaxMana = GetUnitField(guid, "maxPower1")
end
-- Round down power values (Nampower can return decimals)
if baseMana then baseMana = math.floor(baseMana) end
if baseMaxMana then baseMaxMana = math.floor(baseMaxMana) end
if type(baseMana) ~= "number" or type(baseMaxMana) ~= "number" or baseMaxMana == 0 then
bar:Hide()
return
end
-- Update bar
bar:SetMinMaxValues(0, baseMaxMana)
bar:SetValue(baseMana)
-- Always show current/max
bar.text:SetText(string.format("%s/%s", Abbreviate(baseMana), Abbreviate(baseMaxMana)))
bar:Show()
end
-- ===== Player Druid Mana Bar =====
local _, playerClass = UnitClass("player")
if pfUI.uf.player and playerClass == "DRUID" then
local playerMana = CreateDruidManaBar(pfUI.uf.player, "player")
if playerMana then
playerMana:RegisterEvent("UNIT_MANA")
playerMana:RegisterEvent("UNIT_MAXMANA")
playerMana:RegisterEvent("UNIT_DISPLAYPOWER")
playerMana:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
playerMana:RegisterEvent("PLAYER_LOGOUT")
playerMana:SetScript("OnEvent", function()
if event == "PLAYER_LOGOUT" then
this:UnregisterAllEvents()
this:SetScript("OnEvent", nil)
return
end
if arg1 == nil or arg1 == "player" then
UpdateDruidManaBar(playerMana, "player")
end
end)
-- Initial update
UpdateDruidManaBar(playerMana, "player")
end
end
-- ===== Target Druid Mana Bar =====
if pfUI.uf.target then
local targetMana = CreateDruidManaBar(pfUI.uf.target, "target")
if targetMana then
targetMana:RegisterEvent("UNIT_MANA")
targetMana:RegisterEvent("UNIT_MAXMANA")
targetMana:RegisterEvent("UNIT_DISPLAYPOWER")
targetMana:RegisterEvent("PLAYER_TARGET_CHANGED")
targetMana:RegisterEvent("PLAYER_LOGOUT")
targetMana:SetScript("OnEvent", function()
if event == "PLAYER_LOGOUT" then
this:UnregisterAllEvents()
this:SetScript("OnEvent", nil)
return
end
if event == "PLAYER_TARGET_CHANGED" or arg1 == nil or arg1 == "target" then
UpdateDruidManaBar(targetMana, "target")
end
end)
-- Initial update
UpdateDruidManaBar(targetMana, "target")
end
end
end
end)
+68
View File
@@ -0,0 +1,68 @@
pfUI:RegisterModule("newitem", function ()
if not pfUI.bag then return end
if C.appearance.bags.newitem ~= "1" then return end
pfUI.newitem = {}
local r, g, b, a = pfUI.api.GetStringColor(C.appearance.bags.newitem_color)
function pfUI.newitem:UpdateSlot(bag, slot)
if bag < 0 or bag > 4 then return end
if not pfUI.bags[bag] then return end
if not pfUI.bags[bag].slots[slot] then return end
local frame = pfUI.bags[bag].slots[slot].frame
if frame.hasItem and C_NewItems.IsNewItem(bag, slot) then
if not frame.newitem then
local glow = frame:CreateTexture(nil, "OVERLAY")
glow:SetTexture("Interface\\Buttons\\UI-ActionButton-Border")
glow:SetBlendMode("ADD")
glow:SetVertexColor(r, g, b, a)
glow:SetPoint("CENTER", frame, "CENTER")
glow:Hide()
glow.RefreshSize = function(g)
local w = g:GetParent():GetWidth()
if w > 0 then g:SetSize(w * 1.8, w * 1.8) end
end
frame.newitem = glow
frame:HookScript("OnEnter", function()
C_NewItems.RemoveNewItem(bag, slot)
end)
end
frame.newitem:RefreshSize()
frame.newitem:Show()
elseif frame.newitem and frame.newitem:IsShown() then
frame.newitem:Hide()
end
end
-- The new-item set can change without any slot's contents changing (an item
-- acknowledged, pruned when it leaves the bags, or ClearAll) -- re-evaluate
-- every decorated slot when that happens.
function pfUI.newitem:RefreshAll()
for bag in pairs(pfUI.bags) do
local slots = pfUI.bags[bag] and pfUI.bags[bag].slots
if slots then
for slot in pairs(slots) do
pfUI.newitem:UpdateSlot(bag, slot)
end
end
end
end
-- per-slot: pfUI re-runs UpdateSlot whenever a slot's contents change.
hooksecurefunc(pfUI.bag, "UpdateSlot", function(self, bag, slot)
pfUI.newitem:UpdateSlot(bag, slot)
end)
EventRegistry:RegisterFrameEventAndCallback("BAG_NEW_ITEMS_UPDATED", function()
pfUI.newitem:RefreshAll()
end)
pfUI.events:RegisterCallback("bag:closed", function(_, object)
if object then return end
C_NewItems.ClearAll()
end, "newitem")
end)
+11 -14
View File
@@ -34,7 +34,7 @@ pfUI:RegisterModule("player", function ()
playerFrame.infoTopCenterText:SetHeight(14)
end
local _, myclass = UnitClass("player")
local myclass = UnitClassBase("player")
playerFrame.myclass = myclass
playerFrame.isSpellCaster = myclass ~= "WARRIOR" and myclass ~= "ROGUE" and myclass ~= "HUNTER"
@@ -47,7 +47,7 @@ pfUI:RegisterModule("player", function ()
return string.format("%02X%02X%02X", r * 255, g * 255, b * 255)
end
-- SP school colors indexed by GetSpellPower("net") return order
-- SP school colors indexed by GetSpellBonusDamage's 1-based school order
-- (1=phys, 2=holy, 3=fire, 4=nature, 5=frost, 6=shadow, 7=arcane)
local spColors = { "FFFFFF", "FFFF80", "FF8000", "4DFF4D", "80FFFF", "9482C9", "FFFFFF" }
@@ -60,16 +60,14 @@ pfUI:RegisterModule("player", function ()
-- Compute and cache the haste/SP text; called from OnUpdate, throttled to 0.25s
local function UpdateInfoText()
if not GetUnitField then return end -- do nothing for older nampower
local cfg = playerFrame.config
if not cfg then
return
end
-- display_haste: "0"=hidden, "1"=show modCastSpeed (gear haste). Talent-
-- side cast-time reductions show up in the actual cast bar via
-- C_Spell.UnitCastingInfo; double-folding them into this overlay was
-- mixing two different concepts into one number.
-- display_haste: "0"=hidden, "1"=show cast-speed haste (UnitSpellHaste,
-- from UNIT_MOD_CAST_SPEED). Talent/spell-specific cast-time reductions
-- show up in the actual cast bar via C_Spell.UnitCastingInfo; folding them
-- in here too was mixing two different concepts into one number.
local showHaste = cfg.display_haste == "1"
local showSP = cfg.display_spellpower == "1"
@@ -79,21 +77,20 @@ pfUI:RegisterModule("player", function ()
return
end
local haste = GetUnitField("player", "modCastSpeed")
local haste = UnitSpellHaste("player")
local text = ""
if showHaste and isSpellCaster and haste then
local hasteHex = cfgColorToHex(cfg.display_haste_color) or "FFFFFF"
text = string.format("|cff%s%.1f%%|r", hasteHex, (1 / haste - 1) * 100)
text = string.format("|cff%s%.1f%%|r", hasteHex, haste)
end
if showSP and isSpellCaster then
local schools = { GetSpellPower("net") }
local defSchool = spDefaultSchool[myclass] or 2
local maxSP = schools[defSchool] or 0
local maxSP = GetSpellBonusDamage(defSchool) or 0
local maxColor = spColors[defSchool]
for i = 2, 7 do -- skip physical (1)
local v = schools[i] or 0
for i = 2, 7 do -- skip physical (1); default school seeds the tiebreak
local v = GetSpellBonusDamage(i) or 0
if v > maxSP then
maxSP = v
maxColor = spColors[i]
+57 -36
View File
@@ -1,8 +1,43 @@
pfUI:RegisterModule("questitem", function ()
-- [itemID] = { index = questLogIndex, count = requiredCount }. Rebuilt
-- on QUEST_LOG_UPDATE from ClassicAPI's per-quest cached requirements.
local requiredItems = {}
local function AddQuest(questID)
local details = C_QuestLog.GetQuestDetails(questID)
if not details then return false end
if details.requirements then
for _, req in ipairs(details.requirements) do
if req.kind == "item" and req.id and req.id > 0 then
requiredItems[req.id] = {
questID = questID,
title = details.title,
level = details.level,
count = req.count,
}
end
end
end
return true
end
local function RemoveQuest(questID)
for itemID, entry in pairs(requiredItems) do
if entry.questID == questID then requiredItems[itemID] = nil end
end
end
local function Seed()
for k in pairs(requiredItems) do requiredItems[k] = nil end
local complete = true
local i = 1
while true do
local questID = C_QuestLog.GetQuestIDForLogIndex(i)
if questID == nil then break end
if questID > 0 and not AddQuest(questID) then complete = false end
i = i + 1
end
return complete
end
local function AddTooltip(frame, itemID)
if not itemID then return end
if C.tooltip.questitem.showquest ~= "1" then return end
@@ -19,7 +54,7 @@ pfUI:RegisterModule("questitem", function ()
if not entry and not replace then return end
local quest, level = UNKNOWN, 255
if entry then quest, level = GetQuestLogTitle(entry.index) end
if entry then quest, level = entry.title, entry.level end
if not quest then return end
local color = GetDifficultyColor(level)
@@ -42,48 +77,37 @@ pfUI:RegisterModule("questitem", function ()
pfUI.questitem = CreateFrame("Frame", "pfQuestItemScanner", UIParent)
pfUI.questitem:RegisterEvent("PLAYER_ENTERING_WORLD")
pfUI.questitem:RegisterEvent("QUEST_LOG_UPDATE")
pfUI.questitem:RegisterEvent("QUEST_ACCEPTED")
pfUI.questitem:RegisterEvent("QUEST_REMOVED")
pfUI.questitem:SetScript("OnEvent", function()
-- debounce rebuilds — QUEST_LOG_UPDATE fires in bursts
this.run = GetTime() + .5
if C.tooltip.questitem.showquest ~= "1" then return end
if event == "QUEST_ACCEPTED" then -- arg1 = logIndex, arg2 = questID
if not AddQuest(arg2) then -- cache cold (rare) -> reseed
this.seeding = true
this.run = GetTime() + .5
end
elseif event == "QUEST_REMOVED" then -- arg1 = questID
RemoveQuest(arg1)
elseif event == "PLAYER_ENTERING_WORLD" then
this.seeding = true -- seed pre-existing quests
this.run = GetTime() + .5
elseif event == "QUEST_LOG_UPDATE" and this.seeding then
this.run = GetTime() + .5 -- keep retrying while cache warms
end
end)
pfUI.questitem:SetScript("OnUpdate", function()
if C.tooltip.questitem.showquest ~= "1" then return end
if not this.run or GetTime() < this.run then return end
for k in pairs(requiredItems) do requiredItems[k] = nil end
-- GetQuestIDForLogIndex returns nil past the end, 0 for headers, else
-- the questID. GetQuestDetails reads the engine's static-info cache —
-- nil if not yet populated; we'll catch it on the next refresh.
local i = 1
while true do
local questID = C_QuestLog.GetQuestIDForLogIndex(i)
if questID == nil then break end
if questID > 0 then
local details = C_QuestLog.GetQuestDetails(questID)
if details and details.requirements then
for _, req in ipairs(details.requirements) do
if req.kind == "item" and req.id and req.id > 0 then
requiredItems[req.id] = { index = i, count = req.count }
end
end
end
end
i = i + 1
end
this.run = nil
if Seed() then this.seeding = nil end
end)
-- reload quest entries on config change
pfUI.questitem.UpdateConfig = function()
if C.tooltip.questitem.showquest ~= "1" then return end
pfUI.questitem.seeding = true
pfUI.questitem.run = GetTime() + .5
end
-- regular tooltip: catch every Show via a child frame's OnShow, then ask
-- the tooltip directly for the item it's displaying. Replaces a libtooltip
-- indirection that did the same query with extra caching layers.
pfUI.questitem.tooltip = CreateFrame("Frame", "pfQuestItems", GameTooltip)
pfUI.questitem.tooltip:SetScript("OnShow", function()
if GameTooltip:HasItem() then
@@ -92,9 +116,6 @@ pfUI:RegisterModule("questitem", function ()
end
end)
-- itemref tooltip (chat link clicks): hooksecurefunc runs after SetItemRef
-- populates ItemRefTooltip, so we just read the item back out of the tooltip
-- instead of re-parsing the "item:NNN" out of the link string.
hooksecurefunc("SetItemRef", function()
if IsModifierKeyDown() then return end
if ItemRefTooltip:HasItem() then
+116 -8
View File
@@ -13,11 +13,32 @@ pfUI:RegisterModule("raid", function ()
local rawborder, default_border = GetBorderSize("chat")
local cluster = CreateFrame("Frame", "pfRaidCluster", UIParent)
cluster:SetFrameLevel(20)
cluster:SetWidth(120)
cluster:SetHeight(10)
cluster:SetSize(120, 10)
cluster:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", default_border*2, C.chat.left.height + default_border*5)
UpdateMovable(cluster)
-- Separate, independently-movable block that mirrors the raid grid layout
-- for pet frames (raidpet1..40). Defaults to the right of the raid grid.
local petcluster = CreateFrame("Frame", "pfRaidPetCluster", UIParent)
petcluster:SetFrameLevel(20)
petcluster:SetSize(120, 10)
petcluster:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", default_border*2 + 300, C.chat.left.height + default_border*5)
UpdateMovable(petcluster)
-- flat pool of pet frames, laid out by LayoutPets (mirror or collapsed)
pfUI.uf.raid.pets = {}
-- 1-based grid slot -> (row, col) for the current fill direction, matching
-- the raid grid's own fill loops.
local function SlotToCoord(slot, fill, x, y)
slot = slot - 1
if fill == "VERTICAL" then
return floor(slot / y) + 1, mod(slot, y) + 1
else
return mod(slot, x) + 1, floor(slot / x) + 1
end
end
pfUI.uf.raid.tanksfirst = {
["PF_TANK_TOGGLE"] = { T["Toggle as Tank"], "toggleTank" }
}
@@ -28,6 +49,8 @@ pfUI:RegisterModule("raid", function ()
function pfUI.uf.raid:UpdateConfig()
local rawborder, default_border = GetBorderSize("unitframes")
maxraid = tonumber(C.unitframes.maxraid)
local showpets = C.unitframes.raidpet.visible == "1"
self.showpets = showpets
for i=1,maxraid do
pfUI.uf.raid[i] = pfUI.uf.raid[i] or pfUI.uf:CreateUnitFrame("Raid", i, C.unitframes.raid)
@@ -36,6 +59,18 @@ pfUI:RegisterModule("raid", function ()
pfUI.uf.raid[i]:UpdateConfig()
pfUI.uf.raid[i]:UpdateFrameSize()
if showpets then
self.pets[i] = self.pets[i] or pfUI.uf:CreateUnitFrame("RaidPet", i, C.unitframes.raidpet, 0.5)
self.pets[i]:SetParent(petcluster)
self.pets[i]:SetFrameLevel(5)
self.pets[i]:UpdateConfig()
self.pets[i]:UpdateFrameSize()
elseif self.pets[i] then
self.pets[i]:UpdateConfig()
self.pets[i]:Hide()
RemoveMovable(self.pets[i])
end
end
local i = 1
@@ -47,6 +82,17 @@ pfUI:RegisterModule("raid", function ()
local _, _, x, y = string.find(layout,"(.+)x(.+)")
x, y = tonumber(x), tonumber(y)
if showpets then
local petcfg = C.unitframes.raidpet
local _, _, px, py = string.find(petcfg.raidlayout, "(.+)x(.+)")
self.petgrid = {
fill = petcfg.raidfill, x = tonumber(px), y = tonumber(py),
pad = tonumber(petcfg.raidpadding) * GetPerfectPixel(),
w = self.pets[1]:GetWidth()+2*default_border,
h = self.pets[1]:GetHeight()+2*default_border,
}
end
if fill == "VERTICAL" then
for r=1, x do for g=1, y do
if pfUI.uf.raid[i] then
@@ -66,6 +112,50 @@ pfUI:RegisterModule("raid", function ()
i = i + 1
end end
end
self:LayoutPets()
self:Show()
end
function pfUI.uf.raid:LayoutPets()
if not self.showpets or not self.petgrid then return end
local grid = self.petgrid
local function place(pet, cell, id)
pet.id = id
local r, g = SlotToCoord(cell, grid.fill, grid.x, grid.y)
pet:ClearAllPoints()
pet:SetPoint("BOTTOMLEFT", petcluster, "BOTTOMLEFT", (r-1)*(grid.pad+grid.w), (g-1)*(grid.pad+grid.h))
UpdateMovable(pet, true)
pet:UpdateVisibility()
end
if pfUI.uf.showall then
for id = 1, maxraid do
if self.pets[id] then place(self.pets[id], id, id) end
end
return
end
if C.unitframes.raidpet.collapse == "1" then
-- Pack the pets that exist into the leading cells, no gaps.
local k = 0
for id = 1, maxraid do
if UnitExists("raidpet"..id) and self.pets[k+1] then
k = k + 1
place(self.pets[k], k, id)
end
end
for j = k+1, maxraid do
if self.pets[j] then self.pets[j].id = 0 self.pets[j]:Hide() end
end
else
-- Mirror: cell N always shows raidpet<N> at a fixed position.
for id = 1, maxraid do
if self.pets[id] then place(self.pets[id], id, id) end
end
end
end
pfUI.uf.raid:UpdateConfig()
@@ -76,13 +166,22 @@ pfUI:RegisterModule("raid", function ()
frame:UpdateVisibility()
end
-- add units to the beginning of their groups
-- add units to their groups; collapse packs everyone into the leading slots
function pfUI.uf.raid:AddUnitToGroup(index, group)
for subindex = 1, 5 do
local ids = subindex + 5*(group-1)
if pfUI.uf.raid[ids] and pfUI.uf.raid[ids].id == 0 and pfUI.uf.raid[ids].config.visible == "1" then
SetRaidIndex(pfUI.uf.raid[ids], index)
return
if C.unitframes.raid.collapse == "1" then
for ids = 1, maxraid do
if pfUI.uf.raid[ids] and pfUI.uf.raid[ids].id == 0 and pfUI.uf.raid[ids].config.visible == "1" then
SetRaidIndex(pfUI.uf.raid[ids], index)
return
end
end
else
for subindex = 1, 5 do
local ids = subindex + 5*(group-1)
if pfUI.uf.raid[ids] and pfUI.uf.raid[ids].id == 0 and pfUI.uf.raid[ids].config.visible == "1" then
SetRaidIndex(pfUI.uf.raid[ids], index)
return
end
end
end
end
@@ -92,7 +191,14 @@ pfUI:RegisterModule("raid", function ()
pfUI.uf.raid:RegisterEvent("PARTY_MEMBERS_CHANGED")
pfUI.uf.raid:RegisterEvent("PARTY_LEADER_CHANGED")
pfUI.uf.raid:RegisterEvent("VARIABLES_LOADED")
pfUI.uf.raid:RegisterEvent("UNIT_PET")
pfUI.uf.raid:SetScript("OnEvent", function()
if event == "UNIT_PET" then
if this.showpets and C.unitframes.raidpet.collapse == "1" then
this:LayoutPets()
end
return
end
this:Show()
-- Debounce: delay update by 0.5s to batch rapid roster changes (mass swaps)
this.pendingUpdate = GetTime() + 0.5
@@ -127,6 +233,8 @@ pfUI:RegisterModule("raid", function ()
end
end
this:LayoutPets()
-- Smart GUID-based updates: only refresh frames where unit changed
if pfUI.uf.guidTracker then
local tracker = pfUI.uf.guidTracker
+1 -1
View File
@@ -42,7 +42,7 @@ pfUI:RegisterModule("roll", function ()
end
local _, _, itemLink = string.find(hyperlink, "(item:%d+:%d+:%d+:%d+)")
local itemName = GetItemInfo(itemLink)
local itemName = C_Item.GetItemInfo(itemLink)
-- delete obsolete tables
if pfUI.roll.cache[itemName] and pfUI.roll.cache[itemName]["TIMESTAMP"] < GetTime() - 60 then
+2
View File
@@ -23,6 +23,8 @@ pfUI:RegisterModule("sellvalue", function ()
frame:AddDoubleLine(T["Buy"] .. ":", CreateGoldString(buy), 1, 1, 1)
end
end
elseif not MerchantFrame:IsShown() and sell > 0 then
SetTooltipMoney(frame, sell * count)
end
frame:Show()
end
+2 -3
View File
@@ -389,9 +389,8 @@ pfUI:RegisterModule("share", function ()
end)
end
_G.SLASH_PFEXPORT1, _G.SLASH_PFEXPORT2, _G.SLASH_PFEXPORT3 = "/export", "/import", "/share"
function SlashCmdList.PFEXPORT(msg, editbox)
pfUI.api.RegisterSlashCommand("PFEXPORT", { "/export", "/import", "/share" }, function(msg, editbox)
f:Show()
end
end, true)
end
end)
+4 -7
View File
@@ -2,8 +2,7 @@
-- https://github.com/balakethelock/SuperWoW
-- DLL Status Check Command (always available)
SLASH_PFDLLSTATUS1 = "/pfdll"
SlashCmdList["PFDLLSTATUS"] = function()
pfUI.api.RegisterSlashCommand("PFDLLSTATUS", { "/pfdll" }, function()
local chat = DEFAULT_CHAT_FRAME
chat:AddMessage("|cff33ffccpfUI|r: DLL Status Check")
@@ -43,7 +42,7 @@ SlashCmdList["PFDLLSTATUS"] = function()
else
chat:AddMessage(" |cffff0000Target frame|r: NOT found")
end
end
end, true)
pfUI:RegisterModule("superwow", function ()
if SetAutoloot and SpellInfo and not SUPERWOW_VERSION then
@@ -173,12 +172,10 @@ pfUI:RegisterModule("superwow", function ()
end
-- Add slash command for clickthrough toggle
_G.SLASH_PFCLICKTHROUGH1 = "/clickthrough"
_G.SLASH_PFCLICKTHROUGH2 = "/ct"
SlashCmdList["PFCLICKTHROUGH"] = function()
pfUI.api.RegisterSlashCommand("PFCLICKTHROUGH", { "/clickthrough", "/ct" }, function()
local enabled = pfUI.api.ToggleClickthrough()
DEFAULT_CHAT_FRAME:AddMessage("|cff33ffccpfUI|r: Clickthrough mode " .. (enabled and "|cff00ff00enabled|r" or "|cffff0000disabled|r"))
end
end, true)
end
end)
+3 -4
View File
@@ -1,4 +1,3 @@
pfUI:RegisterNewModule("swingtimer", "Swing Timer")
pfUI:RegisterModule("swingtimer", function ()
local rawborder, border = GetBorderSize()
@@ -83,7 +82,7 @@ pfUI:RegisterModule("swingtimer", function ()
local ohR, ohG, ohB, ohA = ParseColor(C.unitframes.swingtimerohcolor, 0.3, 0.8, 0.3, 1)
local raR, raG, raB, raA = ParseColor(C.unitframes.swingtimerrangedcolor, 0.3, 0.6, 1.0, 1)
local rwR, rwG, rwB, rwA = ParseColor(C.unitframes.swingtimerrangedwarncolor, 0.9, 0.0, 0.0, 1)
local isHunter = UnitClass("player") == "Hunter"
local isHunter = UnitClassBase("player") == "HUNTER"
local mhDefaultR, mhDefaultG, mhDefaultB = mhR, mhG, mhB
@@ -430,7 +429,7 @@ pfUI:RegisterModule("swingtimer", function ()
local kind, id = GetActionInfo(slot)
local name
if kind == "spell" then
name = GetSpellInfo(id)
name = C_Spell.GetSpellName(id)
elseif kind == "macro" then
name = GetMacroSpell(id)
end
@@ -909,7 +908,7 @@ pfUI:RegisterModule("swingtimer", function ()
S.autoAttackActive = false
elseif event == "PLAYER_ENTERING_WORLD" then
local _, class = UnitClass("player")
local class = UnitClassBase("player")
S.isWarrior = (class == "WARRIOR")
S.isDruid = (class == "DRUID")
UpdateWeaponSpeeds()
+50 -32
View File
@@ -3,8 +3,7 @@ pfUI:RegisterModule("tooltip", function ()
pfUI.tooltip = CreateFrame('Frame', "pfTooltip", GameTooltip)
pfUI.tooltip.anchorframe = CreateFrame('Frame', "pfTooltipAnchor", UIParent)
pfUI.tooltip.anchorframe:SetWidth(128)
pfUI.tooltip.anchorframe:SetHeight(72)
pfUI.tooltip.anchorframe:SetSize(128, 72)
pfUI.tooltip.anchorframe:SetPoint("TOP", UIParent, "TOP", 0, -50)
pfUI.tooltip.anchorframe:Hide()
UpdateMovable(pfUI.tooltip.anchorframe)
@@ -24,36 +23,54 @@ pfUI:RegisterModule("tooltip", function ()
end
if C.tooltip.position == "cursor" then
-- Cursor mode makes the tooltip follow the mouse. The client has no
-- mouse-move event, so following means polling GetCursorPosition() via an
-- invisible follower frame that the tooltip anchors to. The follower is
-- only shown while a tooltip is visible -- an OnUpdate fires only while its
-- frame is shown, so the poll stops the moment the tooltip hides instead
-- of running forever.
local follower, Reposition
if C.tooltip.cursoralign ~= "native" then
local size = tonumber(C.tooltip.cursoroffset) * 2
follower = CreateFrame("Frame", nil, UIParent)
follower:SetSize(size, size)
follower:Hide()
Reposition = function()
local scale = UIParent:GetScale()
local x, y = GetCursorPosition()
follower:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x/scale, y/scale)
if C.tooltip.cursoralign == "top" then
follower:SetWidth(GameTooltip:GetWidth())
end
end
follower:SetScript("OnUpdate", function()
-- throttle - cursor following doesn't need to be every frame
if (this.tick or 0) > GetTime() then return end
this.tick = GetTime() + (pfUI.throttle and pfUI.throttle:Get("tooltip_cursor") or 0.1)
Reposition()
end)
-- stop polling as soon as the tooltip is gone
pfUI.tooltip:SetScript("OnHide", function() follower:Hide() end)
end
function _G.GameTooltip_SetDefaultAnchor(tooltip, parent)
tooltip:SetOwner(parent, "ANCHOR_CURSOR")
if C.tooltip.cursoralign ~= "native" then
-- create mouse follow frame
if not tooltip.cursor then
tooltip.cursor = CreateFrame("Frame", nil, UIParent)
tooltip.cursor:SetWidth(tonumber(C.tooltip.cursoroffset) * 2)
tooltip.cursor:SetHeight(tonumber(C.tooltip.cursoroffset) * 2)
tooltip.cursor:SetScript("OnUpdate", function()
-- throttle - cursor following doesn't need to be every frame
if (this.tick or 0) > GetTime() then return end
this.tick = GetTime() + (pfUI.throttle and pfUI.throttle:Get("tooltip_cursor") or 0.1)
if not follower then return end
local scale = UIParent:GetScale()
local x, y = GetCursorPosition()
this:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x/scale, y/scale)
if C.tooltip.cursoralign == "top" then
tooltip.cursor:SetWidth(tooltip:GetWidth())
end
end)
end
-- position the follower right away so the tooltip doesn't flash at a
-- stale spot before the first OnUpdate tick
follower:Show()
Reposition()
-- adjust tooltip to mouse frame
if C.tooltip.cursoralign == "top" then
tooltip:SetPoint("BOTTOMLEFT", tooltip.cursor, "TOPLEFT", 0, 0)
elseif C.tooltip.cursoralign == "left" then
tooltip:SetPoint("BOTTOMRIGHT", tooltip.cursor, "LEFT", 0, 0)
elseif C.tooltip.cursoralign == "right" then
tooltip:SetPoint("BOTTOMLEFT", tooltip.cursor, "RIGHT", 0, 0)
end
if C.tooltip.cursoralign == "top" then
tooltip:SetPoint("BOTTOMLEFT", follower, "TOPLEFT", 0, 0)
elseif C.tooltip.cursoralign == "left" then
tooltip:SetPoint("BOTTOMRIGHT", follower, "LEFT", 0, 0)
elseif C.tooltip.cursoralign == "right" then
tooltip:SetPoint("BOTTOMLEFT", follower, "RIGHT", 0, 0)
end
end
end
@@ -172,8 +189,9 @@ pfUI:RegisterModule("tooltip", function ()
local unit = pfUI.tooltip:GetUnit()
if unit == "none" then
-- process item tooltips
if C.tooltip.itemid == "1" and libtooltip:GetItemID() then
GameTooltip:AddLine(T["ItemID"] .. ": " .. libtooltip:GetItemID(), .25,.5,1)
if C.tooltip.itemid == "1" and GameTooltip:HasItem() then
local _, _, itemID = GameTooltip:GetItem()
GameTooltip:AddLine(T["ItemID"] .. ": " .. itemID, .25,.5,1)
GameTooltip:Show()
end
@@ -183,7 +201,7 @@ pfUI:RegisterModule("tooltip", function ()
local pvpname = UnitPVPName(unit)
local name = UnitName(unit)
local validTarget, target = pcall(UnitName, unit .. 'target')
local _, class = UnitClass(unit)
local class = UnitClassBase(unit)
local guild, rankstr, rankid = GetGuildInfo(unit)
local reaction = UnitReaction(unit, "player")
local pvptitle = gsub(gsub(pvpname or name, name, "", 1), "^%s*(.-)%s*$", "%1")
@@ -218,7 +236,7 @@ pfUI:RegisterModule("tooltip", function ()
end
if validTarget and target then
local _, targetClass = UnitClass(unit .. "target")
local targetClass = UnitClassBase(unit .. "target")
local targetReaction = UnitReaction("player",unit .. "target")
if UnitIsPlayer(unit .. "target") and targetClass then
local color = PFUI_CLASS_COLORS[targetClass]
+32 -45
View File
@@ -1,64 +1,53 @@
pfUI:RegisterModule("totems", function ()
local _, class = UnitClass("player")
local slots = {
[FIRE_TOTEM_SLOT] = { r = .5, g = .2, b = .1 },
[EARTH_TOTEM_SLOT] = { r = .2, g = .4, b = .1 },
[WATER_TOTEM_SLOT] = { r = .1, g = .4, b = .6 },
[AIR_TOTEM_SLOT] = { r = .4, g = .1, b = .7 },
local slotColors = {
[FIRE_TOTEM_SLOT] = CreateColor(.5, .2, .1),
[EARTH_TOTEM_SLOT] = CreateColor(.2, .4, .1),
[WATER_TOTEM_SLOT] = CreateColor(.1, .4, .6),
[AIR_TOTEM_SLOT] = CreateColor(.4, .1, .7),
}
local totems = CreateFrame("Frame", "pfTotems", UIParent)
totems:RegisterEvent("PLAYER_TOTEM_UPDATE")
totems:RegisterEvent("PLAYER_ENTERING_WORLD")
totems:SetScript("OnEvent", function(self)
totems:RefreshList()
totems:SetScript("OnEvent", function()
this:RefreshList()
end)
if class == "SHAMAN" then
-- there's no totem event in vanilla using ticks instead
local eventemu = CreateFrame("Frame")
eventemu:SetScript("OnUpdate", function()
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + .5 end
totems:RefreshList()
end)
end
totems.OnEnter = function(self)
if not this.id then return end
local active, name, start, duration, icon = GetTotemInfo(this.id)
if not name or not active then return end -- Prüfen ob name gültig ist
local color = slots[this.id]
local id = this:GetID()
local spellID = select(7, GetTotemInfo(id))
if not spellID or spellID == 0 then return end
GameTooltip:SetOwner(this, "ANCHOR_LEFT")
GameTooltip:SetText(name, color.r+.2, color.g+.2, color.b+.2)
GameTooltip:SetSpellByID(spellID)
GameTooltip:AddDoubleLine(T["Left Click"], T["Recast Totem"], nil, nil, nil, WHITE_FONT_COLOR:GetRGB())
GameTooltip:AddDoubleLine(T["Right Click"], T["Target Totem"], nil, nil, nil, WHITE_FONT_COLOR:GetRGB())
GameTooltip:Show()
end
totems.OnLeave = function(self)
GameTooltip:Hide()
end
totems.OnLeave = GameTooltip_Hide
totems.OnClick = function(self)
if this.id and arg1 and arg1 == "LeftButton" then
-- Try to recast totem on left click
local active, name, start, duration, icon = GetTotemInfo(this.id)
if name then CastSpellByName(name) end
local id = this:GetID()
if arg1 == "LeftButton" then
local spellID = select(7, GetTotemInfo(id))
if spellID and spellID > 0 then CastSpell(FindSpellBookSlotByID(spellID)) end
elseif arg1 == "RightButton" then
TargetTotem(id)
end
end
totems.RefreshList = function(self)
local count = 0
for i = 1, MAX_TOTEMS do
local active, name, start, duration, icon = GetTotemInfo(i)
local _, _, start, duration, icon = GetTotemInfo(i)
if active and icon and icon ~= "" then
if start and start > 0 and icon and icon ~= "" then
count = count + 1
local color = slots[i]
self.bar[count]:Show()
self.bar[count]:SetBackdropBorderColor(color.r, color.g, color.b)
self.bar[count]:SetBackdropBorderColor(slotColors[i]:GetRGB())
self.bar[count].icon:SetTexture(icon)
self.bar[count].id = i
self.bar[count]:SetID(i)
CooldownFrame_SetTimer(self.bar[count].cd, start, duration, 1)
end
@@ -77,14 +66,14 @@ end
self:Show()
end
local count = count and count > 0 and count or MAX_TOTEMS
count = count and count > 0 and count or MAX_TOTEMS
local thickness = self.iconsize + self.spacing*2
local length = thickness * count
if pfUI_config.totems.direction == "HORIZONTAL" then
self:SetHeight(self.iconsize + self.spacing*2)
self:SetWidth(self.spacing*2 + self.iconsize + (count-1)*(self.iconsize + self.spacing*2))
self:SetSize(length, thickness)
else
self:SetWidth(self.iconsize + self.spacing*2)
self:SetHeight(self.spacing*2 + self.iconsize + (count-1)*(self.iconsize + self.spacing*2))
self:SetSize(thickness, length)
end
end
@@ -114,8 +103,7 @@ end
end
end
self.bar[i]:SetHeight(self.iconsize)
self.bar[i]:SetWidth(self.iconsize)
self.bar[i]:SetSize(self.iconsize, self.iconsize)
CreateBackdrop(self.bar[i], nil, true)
self.bar[i].icon = self.bar[i].icon or self.bar[i]:CreateTexture(nil, "ARTWORK")
@@ -123,8 +111,7 @@ end
SetAllPointsOffset(self.bar[i].icon, self.bar[i], 2,-2)
self.bar[i].cdbg = self.bar[i].cdbg or CreateFrame("Frame", nil, self.bar[i])
self.bar[i].cdbg:SetHeight(self.iconsize - 3)
self.bar[i].cdbg:SetWidth(self.iconsize - 3)
self.bar[i].cdbg:SetSize(self.iconsize - 3, self.iconsize - 3)
self.bar[i].cdbg:SetPoint("CENTER", self.bar[i], "CENTER", 0, 0)
self.bar[i].cd = self.bar[i].cd or CreateFrame(COOLDOWN_FRAME_TYPE, "pfTotemsBar"..i.."Cooldown", self.bar[i].cdbg, "CooldownFrameTemplate")
self.bar[i].cd.pfCooldownStyleAnimation = 1
+1 -1
View File
@@ -128,7 +128,7 @@ pfUI:RegisterModule("tracking", function ()
end)
function pfUI.tracking:RefreshSpells()
local _, playerClass = UnitClass("player")
local playerClass = UnitClassBase("player")
local isCatForm = pfUI.tracking:PlayerIsDruidInCatForm(playerClass)
-- Build set of valid SpellIDs for this class
+39 -39
View File
@@ -80,24 +80,6 @@ pfUI:RegisterModule("turtle-wow", function ()
end)
end
-- custom debuff durations
L["debuffs"]["Hand of Reckoning"] = {[0]=3.0}
L["debuffs"]['Insect Swarm'] = {[0]=18.0}
L["debuffs"]['Moonfire'] = {[1]=9.0,[2]=18.0,[3]=18.0,[4]=18.0,[5]=18.0,[6]=18.0,[7]=18.0,[8]=18.0,[9]=18.0,[10]=18.0,[0]=18.0}
L["debuffs"]['Deep Wound'] = {[0]=6.0}
-- turtle wow totemic recall clear totem indicators
local _, class = UnitClass("player")
if libtotem and class == "SHAMAN" then
local trecall = CreateFrame("Frame", "pfTotemsRecall", UIParent)
trecall:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF")
trecall:SetScript("OnEvent", function()
if arg1 and string.find(arg1, T["You gain (.+) Mana from Totemic Recall"]) then
for i = 1, 4 do libtotem:Clean(i) end
end
end)
end
local delay = CreateFrame("Frame")
delay:SetScript("OnUpdate", function()
this:Hide()
@@ -299,36 +281,54 @@ pfUI:RegisterModule("turtle-wow", function ()
-- break if theres nothing left to do
if initialized then return end
-- adjust ui positions
local _, border = GetBorderSize()
-- adjust the inspect frame's Talents tab
SkinTab(InspectFrameTab3)
InspectFrameTab3:ClearAllPoints()
InspectFrameTab3:SetPoint("LEFT", InspectFrameTab2, "RIGHT", GetBorderSize()*2 + 1, 0)
TWTalentFrameTab1:SetPoint("TOPLEFT", TWTalentFrameScrollFrame, "TOPLEFT", 2, TWTalentFrameTab1:GetHeight() + 4)
InspectFrameTab3:SetPoint("LEFT", InspectFrameTab2, "RIGHT", border*2 + 1, 0)
-- reload text position
InspectFrameTab3:Hide()
InspectFrameTab3:Show()
-- skin inspect window elements
StripTextures(InspectTalentsFrame)
StripTextures(TWTalentFrameScrollFrame)
SkinScrollbar(TWTalentFrameScrollFrameScrollBar)
for i = 1, 3 do
SkinTab(_G["TWTalentFrameTab"..i])
end
-- the talent tree frame is created lazily; skin it once it exists
if TWTalentFrame then
StripTextures(InspectTalentsFrame)
StripTextures(TWTalentFrame)
StripTextures(TWTalentFrameScrollFrame)
SkinScrollbar(TWTalentFrameScrollFrameScrollBar)
-- skin each talent button
for i = 1, (MAX_NUM_TALENTS or 100) do
local talent = _G["TWTalentFrameTalent" .. i]
if talent then
StripTextures(talent)
SkinButton(talent, nil, nil, nil, _G["TWTalentFrameTalent" .. i .. "IconTexture"])
_G["TWTalentFrameTalent" .. i .. "Rank"]:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
-- skin + position the talent-tree tabs
for i = 1, 3 do
local tab = _G["TWTalentFrameTab"..i]
if tab then
SkinTab(tab)
tab:ClearAllPoints()
local lastTab = _G["TWTalentFrameTab"..(i-1)]
if lastTab then
tab:SetPoint("LEFT", lastTab, "RIGHT", border*2 + 1, 0)
else
tab:SetPoint("TOPLEFT", TWTalentFrameScrollFrame, "TOPLEFT", 2, tab:GetHeight() + 4)
end
end
end
end
-- only run once
initialized = true
-- skin each talent button
for i = 1, (MAX_NUM_TALENTS or 100) do
local talent = _G["TWTalentFrameTalent"..i]
if talent then
StripTextures(talent)
SkinButton(talent, nil, nil, nil, _G["TWTalentFrameTalent"..i.."IconTexture"])
local rank = _G["TWTalentFrameTalent"..i.."Rank"]
if rank then
rank:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
end
end
end
-- only run once the talent frame has actually been skinned
initialized = true
end
end)
end)
end
+2 -23
View File
@@ -331,29 +331,8 @@ pfUI:RegisterModule("unitxp", function ()
return success and found
end
pfUI.api.UnitInLineOfSight = function(unit1, unit2)
if not unit2 then
unit2 = unit1
unit1 = "player"
end
local success, inSight = pcall(UnitXP, "inSight", unit1, unit2)
if success then return inSight end
return nil
end
pfUI.api.UnitIsBehind = function(unit1, unit2)
if not unit2 then
unit2 = unit1
unit1 = "player"
end
local success, behind = pcall(UnitXP, "behind", unit1, unit2)
if success then return behind end
return nil
end
-- Debug command to test UnitXP indicators
_G.SLASH_PFUNITXP1 = "/pfunitxp"
SlashCmdList["PFUNITXP"] = function()
pfUI.api.RegisterSlashCommand("PFUNITXP", { "/pfunitxp" }, function()
local chat = DEFAULT_CHAT_FRAME
chat:AddMessage("|cff33ffccpfUI|r: UnitXP Indicator Debug")
@@ -387,5 +366,5 @@ pfUI:RegisterModule("unitxp", function ()
else
chat:AddMessage(" Target frame: |cffff0000NOT found|r")
end
end
end, true)
end)
+6 -2
View File
@@ -6,6 +6,7 @@ pfUI:RegisterModule("unlock", function ()
-- Name Shift Ctrl
{ "pfCombo", 5 },
{ "pfRaid", 40, 5 },
{ "pfRaidPet", 40, 5 },
{ "pfGroup", 4 },
{ "pfLootRollFrame", 4 },
}
@@ -35,6 +36,8 @@ pfUI:RegisterModule("unlock", function ()
-- groupframes
["Raid%d"] = { T["Group Frames"], T["Raid"] },
["Raid%d%d"] = { T["Group Frames"], T["Raid"] },
["RaidPet%d"] = { T["Group Frames"], T["Raid-Pet"] },
["RaidPet%d%d"] = { T["Group Frames"], T["Raid-Pet"] },
["Group%d"] = { T["Group Frames"], T["Group"] },
["Party%dTarget"] = { T["Group Frames"], T["Group-Target"] },
["PartyPet%d"] = { T["Group Frames"], T["Group-Pet"] },
@@ -98,7 +101,8 @@ pfUI:RegisterModule("unlock", function ()
-- search and add clustered frames
for id, cluster in pairs(clusters) do
local len = strlen(cluster[1])
if strsub(frame:GetName(),0,len) == cluster[1] then
local fid = tonumber(strsub(frame:GetName(),len+1,len+2))
if fid and strsub(frame:GetName(),0,len) == cluster[1] then
if IsShiftKeyDown() and cluster[2] then
for i = 1, cluster[2] do
if _G[cluster[1] .. i] ~= frame then
@@ -106,7 +110,7 @@ pfUI:RegisterModule("unlock", function ()
end
end
elseif IsControlKeyDown() and cluster[3] then
local id = tonumber(strsub(frame:GetName(),len+1,len+2))
local id = fid
local b = 1
for i = cluster[3]+1, cluster[2], cluster[3] do
+8 -23
View File
@@ -4,8 +4,6 @@ pfUI:RegisterModule("unusable", function ()
pfUI.unusable = {}
local scanner = libtipscan:GetScanner("unusable")
local durability = string.gsub(DURABILITY_TEMPLATE, "%%[^%s]+", "(.+)")
local r, g, b, a = strsplit(",", C.appearance.bags.unusable_color)
function pfUI.unusable:UpdateSlot(bag, slot)
@@ -13,31 +11,18 @@ pfUI:RegisterModule("unusable", function ()
if not pfUI.bags[bag] then return end
if not pfUI.bags[bag].slots[slot] then return end
-- add button shortcuts
local frame = pfUI.bags[bag].slots[slot].frame
local name = frame:GetName()
-- return on empty buttons
local frame = pfUI.bags[bag].slots[slot].frame
if not frame.hasItem then return end
-- set the proper tooltip method
if bag == BANK_CONTAINER then
scanner:SetInventoryItem("player", 39+slot)
else
scanner:SetBagItem(bag, slot)
-- C_PlayerInfo.CanUseItem is the "is this red in the tooltip" gate:
-- proficiency, required level, class/race, skill/spell/rep. It checks
-- *requirements* only, so a broken (0-durability) item still reads as
-- usable -- no durability-line exclusion needed like the old scanner.
local itemID = C_Container.GetContainerItemID(bag, slot)
if itemID and not C_PlayerInfo.CanUseItem(itemID) then
_G.SetItemButtonTextureVertexColor(frame, r, g, b, a)
end
-- check for red color in tooltip
local red = scanner:Color(RED_FONT_COLOR)
if not red then return end
-- check for broken items
local left = scanner:Line(red)
local _, _, broken = string.find(left, durability, 1)
if broken then return end
-- update button vertex color
_G.SetItemButtonTextureVertexColor(frame, r, g, b, a)
end
-- update on regular pfUI button updates
+1 -2
View File
@@ -3,8 +3,7 @@ pfUI:RegisterModule("whisperproxy", function ()
local proxy = CreateFrame("Button", "pfWhisperProxy", pfUI.chat.left.panelTop)
proxy:SetPoint("TOPRIGHT", pfUI.chat.left, "TOPRIGHT", -22, -5)
proxy:SetWidth(12)
proxy:SetHeight(12)
proxy:SetSize(12, 12)
proxy.tex = proxy:CreateTexture(nil, "OVERLAY")
proxy.tex:SetAllPoints()
proxy.tex:SetTexture(pfUI.media["img:proxy"])
+2 -10
View File
@@ -183,11 +183,7 @@ end
local self = self or this
if self.text_mouse == "1" then
if MouseIsOver(self) then
self.bar.text:Show()
else
self.bar.text:Hide()
end
self.bar.text:SetShown(MouseIsOver(self))
end
if self.always then return end
@@ -352,11 +348,7 @@ end
b.bar.text:SetJustifyH("CENTER")
b.bar.text:SetFont(pfUI.font_default, C.global.font_size, "OUTLINE")
if b.text == "1" then
b.bar.text:Show()
else
b.bar.text:Hide()
end
b.bar.text:SetShown(b.text == "1")
b.restedbar = b.restedbar or CreateFrame("StatusBar", nil, b)
b.restedbar:SetStatusBarTexture(pfUI.media[C.panel.xp.texture])
+25 -14
View File
@@ -5,11 +5,7 @@ end
SLASH_PFUI1 = '/pfui'
function SlashCmdList.PFUI(msg, editbox)
if pfUI.gui:IsShown() then
pfUI.gui:Hide()
else
pfUI.gui:Show()
end
pfUI.gui:SetShown(not pfUI.gui:IsShown())
end
SLASH_GM1, SLASH_GM2 = '/gm', '/support'
@@ -27,7 +23,7 @@ do
-- ClassicAPI dependency check.
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
-- API surface that ClassicAPI polyfills, so presence is required.
local PFUI_CLASSIC_API_MIN = 10600 -- (X*10000 + Y*100 + Z)
local PFUI_CLASSIC_API_MIN = 10802 -- (X*10000 + Y*100 + Z)
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
@@ -40,9 +36,16 @@ do
if not CLASSIC_API_VERSION or CLASSIC_API_VERSION < PFUI_CLASSIC_API_MIN then
local minVersion = FormatVersion(PFUI_CLASSIC_API_MIN)
pfUI.disabled = true
EventUtil.ContinueOnPlayerLogin(function()
local detail
if not CLASSIC_API_VERSION then
detail = "The ClassicAPI DLL isn't loaded. The |cff33ffcc!!!ClassicAPI|r addon ships bundled with it -- delete your |cff33ffcc!!!ClassicAPI|r folder and install the latest release from:"
else
detail = "ClassicAPI " .. minVersion .. " or newer is required. Delete your |cff33ffcc!!!ClassicAPI|r folder and reinstall the latest release from:"
end
local function ShowRequiredPopup()
StaticPopupDialogs["PFUI_CLASSICAPI_REQUIRED"] = {
text = "This fork of |cff33ffccpf|cffffffffUI|r requires ClassicAPI\n " .. minVersion .. " or newer.\n\nAll |cff33ffccpf|cffffffffUI|r modules have been disabled.\nInstall ClassicAPI from:",
text = "|cff33ffccpf|cffffffffUI|r has been disabled.\n\n" .. detail,
button1 = OKAY,
hasEditBox = 1,
editBoxWidth = 280,
@@ -51,7 +54,7 @@ do
hideOnEscape = 1,
preferredIndex = 3,
OnShow = function()
local editBox = _G[this:GetName().."EditBox"]
local editBox = getglobal(this:GetName().."EditBox")
if editBox then
editBox:SetText(PFUI_CLASSIC_API_LATEST_URL)
editBox:HighlightText()
@@ -61,9 +64,15 @@ do
}
StaticPopup_Show("PFUI_CLASSICAPI_REQUIRED")
DEFAULT_CHAT_FRAME:AddMessage(
"This fork of |cff33ffccpf|cffffffffUI|r requires ClassicAPI " .. minVersion .. "+. Get it at " .. PFUI_CLASSIC_API_LATEST_URL,
"|cff33ffccpf|cffffffffUI|r disabled: " .. detail .. " " .. PFUI_CLASSIC_API_LATEST_URL,
1, 0.3, 0.3
)
end
local loginFrame = CreateFrame("Frame")
loginFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
loginFrame:SetScript("OnEvent", function()
loginFrame:UnregisterEvent("PLAYER_ENTERING_WORLD")
ShowRequiredPopup()
end)
elseif CLASSIC_API_VERSION < PFUI_CLASSIC_API_LATEST then
EventUtil.ContinueOnPlayerLogin(function()
@@ -101,9 +110,11 @@ pfUI.movables = {}
pfUI.version = {}
pfUI.env = {}
pfUI.events = Mixin({}, CallbackRegistryMixin)
pfUI.events:OnLoad()
pfUI.events:SetUndefinedEventsAllowed(true)
if not pfUI.disabled then
pfUI.events = Mixin({}, CallbackRegistryMixin)
pfUI.events:OnLoad()
pfUI.events:SetUndefinedEventsAllowed(true)
end
-- check if macro addons are loaded (disables macrotweak/macroscan)
function pfUI:MacroAddonsLoaded()
@@ -298,7 +309,7 @@ function pfUI:CheckNewModules()
pfUI_init.seen_modules = pfUI_init.seen_modules or {}
local pending = 0
local _, playerClass = UnitClass("player")
local playerClass = UnitClassBase("player")
for _, entry in pairs(pfUI.new_modules) do
if not pfUI_init.seen_modules[entry.name] and pfUI_init["finalize"] then
if not entry.class or entry.class == playerClass then
+4 -9
View File
@@ -2,15 +2,10 @@ pfUI:RegisterSkin("Auctionhouse", function ()
local rawborder, border = GetBorderSize()
local bpad = rawborder > 1 and border - GetPerfectPixel() or GetPerfectPixel()
HookAddonOrVariable("Blizzard_AuctionUI", function()
-- Compatibility
if BrowseResetButton then -- tbc
SkinButton(BrowseResetButton)
else -- vanilla
SkinArrowButton(BidPrevPageButton, "left", 18)
SkinArrowButton(BidNextPageButton, "right", 18)
SkinArrowButton(AuctionsPrevPageButton, "left", 18)
SkinArrowButton(AuctionsNextPageButton, "right", 18)
end
SkinArrowButton(BidPrevPageButton, "left", 18)
SkinArrowButton(BidNextPageButton, "right", 18)
SkinArrowButton(AuctionsPrevPageButton, "left", 18)
SkinArrowButton(AuctionsNextPageButton, "right", 18)
hooksecurefunc("AuctionFrame_OnShow", function()
AuctionFrame:ClearAllPoints()
+1 -2
View File
@@ -52,8 +52,7 @@ pfUI:RegisterSkin("Battlefield", function ()
end)
BattlefieldFrame.textbox = CreateFrame("Frame", "BattlefieldFrameTextBox", BattlefieldFrame)
BattlefieldFrame.textbox:SetWidth(320)
BattlefieldFrame.textbox:SetHeight(110)
BattlefieldFrame.textbox:SetSize(320, 110)
CreateBackdrop(BattlefieldFrame.textbox)
BattlefieldFrame.textbox:SetPoint("BOTTOM", BattlefieldFrame.backdrop, "BOTTOM", 0, 36)
BattlefieldFrameZoneDescription:ClearAllPoints()
+1 -2
View File
@@ -6,8 +6,7 @@ pfUI:RegisterSkin("Battlefield Minimap", function ()
CreateBackdrop(BattlefieldMinimap, nil, nil, 0)
CreateBackdropShadow(BattlefieldMinimap)
BattlefieldMinimap:SetWidth(220)
BattlefieldMinimap:SetHeight(146)
BattlefieldMinimap:SetSize(220, 146)
SkinCloseButton(BattlefieldMinimapCloseButton, BattlefieldMinimap, 0, 0)
+24 -10
View File
@@ -4,7 +4,25 @@ pfUI:RegisterSkin("Character", function ()
-- Honor Tab
StripTextures(HonorFrame)
StripTextures(ArenaFrame)
if ArenaFrame then
StripTextures(ArenaFrame)
for _, frame in pairs({'Arena', 'Honor'}) do
for i = 1, 2 do
local tab = _G[frame.."FrameTab"..i]
local lastTab = _G[frame.."FrameTab"..(i-1)]
if lastTab and lastTab:IsShown() then
tab:ClearAllPoints()
tab:SetPoint("LEFT", lastTab, "RIGHT", border*2 + 1, 0)
end
SkinTab(tab)
end
end
for i = 1, 3 do
local team = _G["ArenaFrameTeam"..i]
StripTextures(team)
CreateBackdrop(team)
end
end
HonorFrameProgressBar:SetStatusBarTexture(pfUI.media["img:bar"])
CreateBackdrop(HonorFrameProgressBar)
@@ -113,7 +131,7 @@ pfUI:RegisterSkin("Character", function ()
if ShaguScore and itemID then
local itemLevel = C_Item.GetCurrentItemLevel({ equipmentSlotIndex = slotId })
local _, _, quality, _, _, _, _, _, itemSlot, _ = GetItemInfo(itemID)
local _, _, quality, _, _, _, _, _, itemSlot, _ = C_Item.GetItemInfo(itemID)
local score = ShaguScore:Calculate(itemSlot, quality, itemLevel)
if score and score > 0 and quality and quality > 0 then
local r,g,b = GetItemQualityColor(quality)
@@ -159,8 +177,7 @@ pfUI:RegisterSkin("Character", function ()
for i,c in pairs(magicResTextureCords) do
local magicResFrame = _G["MagicResFrame"..i]
magicResFrame:SetWidth(26)
magicResFrame:SetHeight(26)
magicResFrame:SetSize(26, 26)
CreateBackdrop(magicResFrame)
SetAllPointsOffset(magicResFrame.backdrop, magicResFrame, 2)
local icon = GetNoNameObject(magicResFrame, "Texture", "BACKGROUND", "ResistanceIcons")
@@ -218,8 +235,7 @@ pfUI:RegisterSkin("Character", function ()
for i,c in pairs(magicResTextureCords) do
local magicResFrame = _G["PetMagicResFrame"..i]
magicResFrame:SetWidth(26)
magicResFrame:SetHeight(26)
magicResFrame:SetSize(26, 26)
CreateBackdrop(magicResFrame)
SetAllPointsOffset(magicResFrame.backdrop, magicResFrame, 2)
local icon = GetNoNameObject(magicResFrame, "Texture", "BACKGROUND", "ResistanceIcons")
@@ -239,8 +255,7 @@ pfUI:RegisterSkin("Character", function ()
local war = _G["ReputationBar"..i.."AtWarCheck"]
StripTextures(war)
war:SetWidth(13)
war:SetHeight(13)
war:SetSize(13, 13)
war:ClearAllPoints()
war:SetPoint("LEFT", bar.backdrop, "RIGHT", 6, 0)
war.icon = war:CreateTexture(nil, "OVERLAY")
@@ -338,8 +353,7 @@ pfUI:RegisterSkin("Character", function ()
SkillDetailStatusBar:SetParent(SkillDetailScrollFrame)
StripTextures(SkillDetailStatusBarUnlearnButton)
SkillDetailStatusBarUnlearnButton:SetWidth(20)
SkillDetailStatusBarUnlearnButton:SetHeight(20)
SkillDetailStatusBarUnlearnButton:SetSize(20, 20)
SkillDetailStatusBarUnlearnButton:SetHitRectInsets(0,0,0,0)
SkillDetailStatusBarUnlearnButton:ClearAllPoints()
SkillDetailStatusBarUnlearnButton:SetPoint("LEFT", SkillDetailStatusBar, "RIGHT", 6, 0)
+2 -2
View File
@@ -3,8 +3,8 @@ pfUI:RegisterSkin("Game Menu", function ()
CreateBackdrop(GameMenuFrame, nil, true, .75)
CreateBackdropShadow(GameMenuFrame)
GameMenuFrame:SetWidth(GameMenuFrame:GetWidth() - 30)
GameMenuFrame:SetHeight(GameMenuFrame:GetHeight() + 6)
local menuWidth, menuHeight = GameMenuFrame:GetSize()
GameMenuFrame:SetSize(menuWidth - 30, menuHeight + 6)
local title = GetNoNameObject(GameMenuFrame, "FontString", "ARTWORK", MAIN_MENU)
title:SetTextColor(1,1,1,1)
+193
View File
@@ -0,0 +1,193 @@
local slots = {
"HeadSlot",
"NeckSlot",
"ShoulderSlot",
"BackSlot",
"ChestSlot",
"ShirtSlot",
"TabardSlot",
"WristSlot",
"HandsSlot",
"WaistSlot",
"LegsSlot",
"FeetSlot",
"Finger0Slot",
"Finger1Slot",
"Trinket0Slot",
"Trinket1Slot",
"MainHandSlot",
"SecondaryHandSlot",
"RangedSlot",
}
pfUI:RegisterSkin("Inspect", function ()
local rawborder, border = GetBorderSize()
local bpad = rawborder > 1 and border - GetPerfectPixel() or GetPerfectPixel()
HookAddonOrVariable("Blizzard_InspectUI", function()
local cache = {}
CreateBackdrop(InspectFrame, nil, nil, .75)
CreateBackdropShadow(InspectFrame)
InspectFrame.backdrop:SetPoint("TOPLEFT", 10, -10)
InspectFrame.backdrop:SetPoint("BOTTOMRIGHT", -30, 72)
InspectFrame:SetHitRectInsets(10,30,10,72)
EnableMovable("InspectFrame", "Blizzard_InspectUI", INSPECTFRAME_SUBFRAMES)
SkinCloseButton(InspectFrameCloseButton, InspectFrame.backdrop, -6, -6)
InspectFrame:DisableDrawLayer("ARTWORK")
InspectNameText:ClearAllPoints()
InspectNameText:SetPoint("TOP", InspectFrame.backdrop, "TOP", 0, -10)
-- Turtle WoW has up to 4 inspect tabs: Character, Honor, Arena, Talents
for i = 1, 4 do
local tab = _G["InspectFrameTab"..i]
if tab then
local lastTab = _G["InspectFrameTab"..(i-1)]
tab:ClearAllPoints()
if lastTab then
tab:SetPoint("LEFT", lastTab, "RIGHT", border*2 + 1, 0)
else
tab:SetPoint("TOPLEFT", InspectFrame.backdrop, "BOTTOMLEFT", bpad, -(border + (border == 1 and 1 or 2)))
end
SkinTab(tab)
end
end
do -- Character Tab
StripTextures(InspectPaperDollFrame)
EnableClickRotate(InspectModelFrame)
local rotL = InspectModelRotateLeftButton or InspectModelFrameRotateLeftButton
if rotL then rotL:Hide() end
local rotR = InspectModelRotateRightButton or InspectModelFrameRotateRightButton
if rotR then rotR:Hide() end
for _, slot in pairs(slots) do
local frame = _G["Inspect"..slot]
StripTextures(frame)
CreateBackdrop(frame)
SetAllPointsOffset(frame.backdrop, frame, 0)
HandleIcon(frame.backdrop, _G["Inspect"..slot.."IconTexture"])
local funce = frame:GetScript("OnEnter")
frame:SetScript("OnEnter", function()
local bid = this:GetID()
if not GetInventoryItemLink(InspectFrame.unit, this:GetID()) and this.hasItem then
GameTooltip:SetOwner(this, "ANCHOR_TOPRIGHT")
GameTooltip:SetHyperlink("item:"..cache[bid]["id"])
GameTooltip:Show()
else
funce()
end
end)
end
local function ColorSlot(slot, id, itemID, vslot)
local item = Item:CreateFromItemID(itemID)
if item:IsItemEmpty() then return end
item:ContinueOnItemLoad(function()
if not InspectFrame.unit then return end
if GetInventoryItemID(InspectFrame.unit, id) ~= itemID then return end
local quality = item:GetItemQuality()
if not quality then return end
local r, g, b = GetItemQualityColor(quality)
slot.backdrop:SetBackdropBorderColor(r, g, b)
if ShaguScore then
if not slot.scoreText then
slot.scoreText = slot:CreateFontString(nil, "OVERLAY", "GameFontNormal")
slot.scoreText:SetFont(pfUI.font_default, 12, "OUTLINE")
slot.scoreText:SetPoint("TOPRIGHT", 0, 0)
end
local itemLevel = ShaguScore.Database[itemID] or 0
local score = ShaguScore:Calculate(vslot, quality, itemLevel)
if score and score > 0 then
slot.scoreText:SetText(score)
slot.scoreText:SetTextColor(r, g, b)
else
slot.scoreText:SetText("")
end
end
end)
end
local function UpdateSlots()
if not InspectFrame.unit then return end
local guild, title = GetGuildInfo(InspectFrame.unit)
if guild then
InspectGuildText:SetPoint("TOP", InspectLevelText, "BOTTOM", 0, -1)
InspectGuildText:SetText(format(TEXT(GUILD_TITLE_TEMPLATE), title, guild))
InspectGuildText:Show()
else
InspectGuildText:SetText("")
InspectGuildText:Hide()
end
for _, vslot in pairs(slots) do
local id = GetInventorySlotInfo(vslot)
local itemID = GetInventoryItemID(InspectFrame.unit, id)
local slot = _G["Inspect" .. vslot]
if itemID then
ColorSlot(slot, id, itemID, vslot)
elseif not slot.hasItem then
-- genuinely empty slot: reset to a plain backdrop
CreateBackdrop(slot)
SetAllPointsOffset(slot.backdrop, slot, 0)
if slot.scoreText then
slot.scoreText:SetText("")
end
end
end
end
hooksecurefunc("InspectPaperDollItemSlotButton_Update", function(button)
local bid = button:GetID()
local itemID = GetInventoryItemID(InspectFrame.unit, bid)
if itemID then
cache[bid] = cache[bid] or {}
cache[bid]["id"] = itemID
cache[bid]["tex"] = GetInventoryItemTexture(InspectFrame.unit, button:GetID())
cache[bid]["count"] = GetInventoryItemCount(InspectFrame.unit, button:GetID())
cache[bid]["name"] = UnitName(InspectFrame.unit)
elseif cache[bid] and UnitName(InspectFrame.unit) == cache[bid].name then
-- restore cache information
SetItemButtonTexture(button, cache[bid]["tex"])
SetItemButtonCount(button, cache[bid]["count"])
button.hasItem = 1
end
UpdateSlots()
end)
end
do -- Honor Tab
StripTextures(InspectHonorFrame)
if InspectArenaFrame then
StripTextures(InspectArenaFrame)
for i = 1, 3 do
local team = _G["InspectArenaFrameTeam"..i]
StripTextures(team)
CreateBackdrop(team)
end
end
CreateBackdrop(InspectHonorFrameProgressBar)
InspectHonorFrameProgressBar:SetStatusBarTexture(pfUI.media["img:bar"])
InspectHonorFrameProgressBar:SetHeight(24)
end
-- NOTE: Turtle WoW's Talent tab (InspectTalentsFrame / TWTalentFrame) is
-- skinned in modules/turtle-wow.lua, which activates once this skin is
-- registered (it gates on pfUI.skin["Inspect"]).
end)
end)
+2 -4
View File
@@ -167,12 +167,10 @@ pfUI:RegisterSkin("Turtle LFT", function ()
local sep = LFTGroupReadyFrame:CreateTexture(nil, "ARTWORK")
sep:SetTexture("Interface\\FrameXML\\LFT\\images\\ui-lfg-separator")
sep:SetPoint("TOPLEFT", LFTGroupReadyFrame, "TOPLEFT", 10, -125)
sep:SetWidth(288)
sep:SetHeight(16)
sep:SetSize(288, 16)
-- Restore role icon (updated dynamically by LFT_GroupReadyShow)
LFTGroupReadyFrameRoleTexture:SetWidth(56)
LFTGroupReadyFrameRoleTexture:SetHeight(56)
LFTGroupReadyFrameRoleTexture:SetSize(56, 56)
LFTGroupReadyFrameRoleTexture:ClearAllPoints()
LFTGroupReadyFrameRoleTexture:SetPoint("LEFT", LFTGroupReadyFrame, "LEFT", 20, -20)
LFTGroupReadyFrameRoleTexture:Show()
+1 -2
View File
@@ -45,8 +45,7 @@ pfUI:RegisterSkin("Macro", function ()
MacroNewButton:ClearAllPoints()
MacroNewButton:SetPoint("RIGHT", MacroExitButton, "LEFT", -2*bpad, 0)
MacroEditButton:SetHeight(22)
MacroEditButton:SetWidth(150)
MacroEditButton:SetSize(150, 22)
MacroEditButton:ClearAllPoints()
MacroEditButton:SetPoint("BOTTOMLEFT", MacroFrameSelectedMacroButton, "BOTTOMRIGHT", 6, -2)
+1 -1
View File
@@ -105,7 +105,7 @@ pfUI:RegisterSkin("Options - New", function ()
local er, eg, eb = pfUI.api.GetStringColor(pfUI_config.appearance.border.color)
btn:SetBackdropColor(br, bg, bb, 0.75)
btn:SetBackdropBorderColor(er, eg, eb, 1)
local _, class = UnitClass("player")
local class = UnitClassBase("player")
local color = PFUI_CLASS_COLORS[class]
SetHighlight(btn, color.r, color.g, color.b)
btn:SetFont(pfUI.font_default, pfUI_config.global.font_size, "OUTLINE")
+6 -24
View File
@@ -6,31 +6,15 @@ pfUI:RegisterSkin("Quest Log", function ()
_G.MAX_WATCHABLE_QUESTS = 20 -- TODO
do -- quest log frame
-- Compatibility
local QUEST_COUNT
if QuestLogCount then -- tbc
QUEST_COUNT = QuestLogCount
StripTextures(QUEST_COUNT)
QUEST_COUNT:ClearAllPoints()
hooksecurefunc("QuestLogUpdateQuestCount", function(numQuests)
QUEST_COUNT:ClearAllPoints()
QUEST_COUNT:SetPoint("BOTTOMRIGHT", QuestLogFrame, "TOPRIGHT", 0, -50)
end)
else -- vanilla
QUEST_COUNT = QuestLogQuestCount
QUEST_COUNT:ClearAllPoints()
QUEST_COUNT:SetPoint("TOPRIGHT", -10, -30)
end
QuestLogQuestCount:ClearAllPoints()
QuestLogQuestCount:SetPoint("TOPRIGHT", -10, -30)
hooksecurefunc("QuestLog_OnShow", function()
QuestLogFrame:ClearAllPoints()
QuestLogFrame:SetPoint("TOPLEFT", 10, -104)
end)
QuestLogFrame:SetWidth(676)
QuestLogFrame:SetHeight(440)
QuestLogFrame:SetSize(676, 440)
QuestLogFrame:DisableDrawLayer("BACKGROUND")
StripTextures(QuestLogFrame, true)
@@ -64,10 +48,9 @@ pfUI:RegisterSkin("Quest Log", function ()
QuestLogFrameLevelsCheckButtonText:SetText(T["Quest Levels"])
CreateBackdrop(QuestLogTrack)
QuestLogTrack:SetHeight(8)
QuestLogTrack:SetWidth(8)
QuestLogTrack:SetSize(8, 8)
QuestLogTrack:ClearAllPoints()
QuestLogTrack:SetPoint("RIGHT", QUEST_COUNT, "LEFT", -5, 0)
QuestLogTrack:SetPoint("RIGHT", QuestLogQuestCount, "LEFT", -5, 0)
StripTextures(QuestLogTrack)
QuestLogTrackTracking:SetTexture(.8,.8,.8,1)
@@ -228,8 +211,7 @@ pfUI:RegisterSkin("Quest Log", function ()
SetAllPointsOffset(item.backdrop, item, 4)
SetHighlight(item)
icon:SetWidth(ysize)
icon:SetHeight(ysize)
icon:SetSize(ysize, ysize)
icon:ClearAllPoints()
icon:SetPoint("LEFT", 6, 0)
icon:SetTexCoord(.08, .92, .08, .92)
+3 -12
View File
@@ -1,13 +1,5 @@
pfUI:RegisterSkin("Readycheck", function ()
HookAddonOrVariable("Blizzard_RaidUI", function()
-- Compatibility
local update_func
if ReadyCheckFrame_OnUpdate then -- tbc
update_func = "ReadyCheckFrame_OnUpdate"
else -- vanilla
update_func = "ReadyCheck_OnUpdate"
end
StripTextures(ReadyCheckFrame, true)
CreateBackdrop(ReadyCheckFrame, nil, nil, .75)
CreateBackdropShadow(ReadyCheckFrame)
@@ -25,8 +17,7 @@ pfUI:RegisterSkin("Readycheck", function ()
local frame = CreateFrame("Button", nil, ReadyCheckFrame)
frame:SetPoint("TOP", ReadyCheckFrameText, "BOTTOM", 0, -6)
frame:SetWidth(220)
frame:SetHeight(10)
frame:SetSize(220, 10)
frame.bar = CreateFrame("StatusBar", "ReadyCheckFrameStatusBar", ReadyCheckFrame)
frame.bar:SetStatusBarTexture(pfUI.media["img:bar"])
@@ -35,7 +26,7 @@ pfUI:RegisterSkin("Readycheck", function ()
frame.bar.text = frame.bar:CreateFontString("Status", "DIALOG", "GameFontNormal")
frame.bar.text:SetFontObject(GameFontWhite)
frame.bar.text:SetFont(pfUI.font_default, 12, "OUTLINE")
frame.bar.text:SetPoint("CENTER", 0, 0)
frame.bar.text:SetPoint("CENTER")
local max
hooksecurefunc("ShowReadyCheck", function()
@@ -43,7 +34,7 @@ pfUI:RegisterSkin("Readycheck", function ()
frame.bar:SetMinMaxValues(0, max)
end)
hooksecurefunc(update_func, function()
hooksecurefunc("ReadyCheck_OnUpdate", function()
if not ReadyCheckFrame.timer then return end
local perc = ReadyCheckFrame.timer/max
+1 -8
View File
@@ -4,14 +4,7 @@ pfUI:RegisterSkin("Talents", function ()
HookAddonOrVariable("Blizzard_TalentUI", function()
-- Compatibility
local TALENT_FRAME, TALENT_FRAME_NAME
if PlayerTalentFrame then -- tbc
TALENT_FRAME = _G.PlayerTalentFrame
else -- vanilla
TALENT_FRAME = _G.TalentFrame
end
TALENT_FRAME_NAME = TALENT_FRAME:GetName()
local TALENT_FRAME, TALENT_FRAME_NAME = _G.TalentFrame, _G.TalentFrame:GetName()
StripTextures(TALENT_FRAME)
CreateBackdrop(TALENT_FRAME, nil, nil, .75)