mirror of
https://github.com/brues-code/pfUI.git
synced 2026-10-20 19:30:49 +00:00
Modernize cast bars, unit-frame clicks, and mark tracking with ClassicAPI (#32)
* Migrate player castbar to ClassicAPI UNIT_SPELLCAST_* events
Drive the player cast path off ClassicAPI's synthesized, player-only
UNIT_SPELLCAST_* events instead of the vanilla SPELLCAST_* plus nampower
SPELL_{START,GO,DELAYED}_SELF mix. START/CHANNEL_START poll UnitCastingInfo/
UnitChannelInfo and stamp; STOP/CHANNEL_STOP/FAILED/INTERRUPTED clear;
SUCCEEDED drives tradeskill craft counting; DELAYED/CHANNEL_UPDATE re-poll.
Since UNIT_SPELLCAST_START fires for chained same-spell recasts, the nampower
SELF deps and their RunNextFrame co-hook-ordering workarounds are gone.
Remote target/focus bars keep SPELL_*_OTHER (the new events are player-only).
Fix the cast-start flash: StampBar now primes the fill on the stamp frame,
and ClearBar no longer snaps the bar to full (that snap lingered in the fade
tail and flashed when the next cast stamped).
Add a red flash on a cancelled cast: new appearance.castbar.failcolor,
flashed by ClearBar only when a cast was actually in progress.
Handle pushback Quartz-style: DELAYED/CHANNEL_UPDATE re-poll just the times
and accumulate the endMs shift into this.delay for the +/- indicator (cast
+X, channel -X), rather than a full restamp.
* Route target/focus castbars through remote UNIT_SPELLCAST_*
ClassicAPI now fires UNIT_SPELLCAST_* for remote tokens (target/focus/...)
via PollRemote, so drop the nampower SPELL_*_OTHER path and drive all three
bars off one event model. The gate is now token-based (arg1 == this.unitstr,
plus the arg1=="player" + UnitIsUnit case for target=self); the RunNextFrame
defer is gone since the remote poll fires after UnitCastingInfo is readable.
Cast detection is now nampower-free across every bar.
Use the event's rank payload (arg5): thread it through RefreshBar into
StampBar, which now only calls C_Spell.GetSpellSubtext as a fallback on the
retarget re-poll (PLAYER_TARGET/FOCUS_CHANGED) where no event is in hand.
* Drive nameplate castbars off UNIT_SPELLCAST_*
ClassicAPI now fires UNIT_SPELLCAST_* for nameplate tokens, so populate the
per-GUID castState cache from UNIT_SPELLCAST_{START,CHANNEL_START} (poll
PollCastInfo for the timing the payload omits) and clear it on
{STOP,CHANNEL_STOP} -- the remote poll fires STOP for natural end, interrupt,
and cancel alike. Replaces the nampower SPELL_{START,FAILED}_OTHER path; the
^nameplate arg1 gate ignores the target/focus/party fires of the same events,
and the NAME_PLATE_UNIT_ADDED seed still catches a plate spawning mid-cast.
Nameplate cast detection is now nampower-free.
* We no longer use these features from SuperWoW/Nampower
* Use secure unit attributes; remove mouseover scripts
Switch unitframes to attribute-driven clicks and remove mouseover tooltip handlers. Adds SetAttribute("unit") in UpdateVisibility and sets frame attributes (unit and type1='target') when creating frames. Removes OnEnter/OnLeave functions and their SetScript registrations and eliminates direct TargetUnit calls in ClickAction
* Use SetShown and simplify component default
Replace explicit Show/Hide conditionals in api/unitframes.lua with SetShown(...) for ressIcon, leaderIcon, lootIcon, pvpIcon, and restIcon to reduce branching and improve readability. Also remove the local shadowing of the parameter 'component' by using assignment (component = component or ""). No intended behavior changes.
* Drive unit-frame clicks via secure attributes
Replace the Lua OnClick dispatch (OnClick/ClickAction/RightClickAction) with
secure frame attributes: default type1=target / type2=menu, and EnableClickCast
now writes type/spell/macrotext/menu/target/focus attributes per button+modifier
instead of caching a clickactions table read at click time. Drops the now-dead
clickactions table and buttons list.
Also set a "unit" attribute on each frame (at creation and re-synced in
UpdateVisibility to the live token, so a party shown on the raid grid reports
partyN, not raidN) so the hovered unit resolves from the frame.
Match the target/focus/menu click keywords exactly rather than by prefix, so a
spell whose name starts with "focus"/"target"/"menu" (e.g. Focus Magic) casts
instead of being swallowed as the keyword action.
* Simplify marktracking colors and refresh per mark
Replace the hand-rolled ParseColor plus its default-color table with
GetStringColor -- the raidmarkercolor_* config keys already carry those same
defaults, so the fallback was dead code.
Restructure the refresh off observed mark tokens: UNIT_HEALTH/UNIT_MAXHEALTH
now arrive as arg1 == "markN", so refresh just that one row (UpdateRow) instead
of rescanning all eight on every nearby unit's health tick. A visibility flip
(into range / death / hp crossing 0) re-packs the rows, so UpdateRow hands off
to a full UpdateDisplay; RAID_TARGET_UPDATE / PLAYER_ENTERING_WORLD stay full
refreshes, with the 1s poll as the range-change backstop.
* not true anymore
* Poll marktracking fallback via C_Timer instead of OnUpdate
The 1s range-change safety net ran a per-frame OnUpdate that no-oped ~59 of
every 60 frames. Replace it with C_Timer.NewTicker(FALLBACK_INTERVAL,
UpdateDisplay) -- one wakeup per second off the shared timer driver -- and drop
the elapsed accumulator. The scanner frame is now purely event-driven.
* SuperWoW is now optional
* Update README feature list
Add 'Mouseover Unit Frames' and 'Click-casting' to the main features list. Update the SuperWoW entry to reflect that it tracks party/raid units on the minimap (replacing the prior SetMouseoverUnit note).
* Replace fixed-interval OnUpdate polls with C_Timer/RunNextFrame
Swap hand-rolled per-frame throttles for the modern timer primitives:
- turtle-wow: one-shot next-frame defer (self-hiding OnUpdate frame) -> RunNextFrame
- panel: clock, combat, and fps widgets -> NewTicker(1); guild roster -> NewTicker(60)
- minimap: coordinates text -> NewTicker(0.1)
- addonbuttons: one-shot init -> RunNextFrame; 5s button rescan -> NewTicker(5),
guarded by IsShown() to preserve the old "paused while hidden" behavior
Ticker callbacks reference frames via upvalue since 'this' is unbound outside
OnUpdate. Genuine per-frame work (bar fills, fades, drag) and polls already
coordinated through pfUI.throttle are left as-is.
* update pfQuest link
* Use SetShown/SetSize in panel module
Replace manual Show/Hide toggles with SetShown(not ... ) and replace SetWidth/SetHeight with SetSize in modules/panel.lua. Changes simplify toggle logic (timer, WorldMap, chat hide buttons) and unify sizing calls for timer, frames, textures, and microbutton. No behavior changes intended; purely refactor for conciseness and consistency.
* Bump ClassicAPI min version to 1.9.0
* Drive reagent counter from events instead of a polling OnUpdate
The pfReagentCounter frame ran an OnUpdate that (1) progressively rescanned
all 120 action slots one-per-100ms on any slot change and (2) recounted
reagent inventory on a 1s throttle. Replace both with direct event handling:
- ACTIONBAR_SLOT_CHANGED updates just the changed slot (arg1), full-scanning
only when arg1 is 0/nil, instead of restarting a ~12s rescan on every edit
- BAG_UPDATE_DELAYED recounts tracked reagents directly (it is already
Blizzard's coalesced bag event, so the extra 1s throttle was redundant)
- PLAYER_ENTERING_WORLD seeds the full reagent map once
UpdateSlot now seeds a new reagent's real count via GetItemCount so a freshly
placed reagent spell shows the correct number immediately. The updatecache ->
BarsUpdate render path and the IsReagentAction/GetReagentCount accessors are
unchanged.
This commit is contained in:
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
[](https://octowow.st/)
|
[](https://octowow.st/)
|
||||||
[](https://github.com/brues-code/ClassicAPI)
|
[](https://github.com/brues-code/ClassicAPI)
|
||||||
[](https://github.com/balakethelock/SuperWoW)
|
|
||||||
[](https://github.com/brues-code/nampower)
|
[](https://github.com/brues-code/nampower)
|
||||||
|
[](https://github.com/balakethelock/SuperWoW)
|
||||||
[](https://codeberg.org/konaka/UnitXP_SP3)
|
[](https://codeberg.org/konaka/UnitXP_SP3)
|
||||||
|
|
||||||
**A pfUI fork specifically optimized for ClassicAPI on [Octo WoW](https://octowow.st/) which requires Nampower and SuperWoW with optional UnitXP_SP3 DLL integration.**
|
**A pfUI fork specifically optimized for ClassicAPI on [Octo WoW](https://octowow.st/) which requires Nampower and SuperWoW with optional UnitXP_SP3 DLL integration.**
|
||||||
@@ -36,21 +36,20 @@ Provides:
|
|||||||
- Faster, safer profile sharing - Engine-side serialize/compress/base64 via C_EncodingUtil
|
- Faster, safer profile sharing - Engine-side serialize/compress/base64 via C_EncodingUtil
|
||||||
- C_Timer - After / NewTicker replacing hand-rolled OnUpdate throttles
|
- C_Timer - After / NewTicker replacing hand-rolled OnUpdate throttles
|
||||||
- Feign death, shapeshift and quest-item detection via real API calls
|
- Feign death, shapeshift and quest-item detection via real API calls
|
||||||
|
- Mouseover Unit Frames
|
||||||
|
- Click-casting
|
||||||
- Plenty other functions
|
- Plenty other functions
|
||||||
|
|
||||||
### [SuperWoW](https://github.com/balakethelock/SuperWoW)
|
|
||||||
|
|
||||||
Provides:
|
|
||||||
- UnitPosition for distance calculations
|
|
||||||
- SetMouseoverUnit for improved targeting
|
|
||||||
|
|
||||||
### [Nampower](https://github.com/brues-code/nampower)
|
### [Nampower](https://github.com/brues-code/nampower)
|
||||||
|
|
||||||
Provides:
|
Provides:
|
||||||
- Spell queue indicator
|
- Spell queue indicator
|
||||||
- GCD indicator
|
- GCD indicator
|
||||||
- Reactive spell detection
|
|
||||||
- Enhanced cast information
|
### [SuperWoW](https://github.com/balakethelock/SuperWoW)
|
||||||
|
|
||||||
|
Provides:
|
||||||
|
- Tracks party/raid units on the minimap
|
||||||
|
|
||||||
### [UnitXP_SP3](https://codeberg.org/konaka/UnitXP_SP3)
|
### [UnitXP_SP3](https://codeberg.org/konaka/UnitXP_SP3)
|
||||||
|
|
||||||
@@ -91,7 +90,7 @@ pfUI supports and contains language specific code for the following gameclients.
|
|||||||
* Russian (ruRU)
|
* Russian (ruRU)
|
||||||
|
|
||||||
## Recommended Addons
|
## Recommended Addons
|
||||||
* [pfQuest](https://shagu.org/pfQuest) A simple database and quest helper
|
* [pfQuest](https://github.com/brues-code/pfQuest) A simple database and quest helper
|
||||||
* [SuperCleveRoidMacros](https://github.com/brues-code/SuperCleveRoidMacros) Supports modern macro formats
|
* [SuperCleveRoidMacros](https://github.com/brues-code/SuperCleveRoidMacros) Supports modern macro formats
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ function pfUI:LoadConfig()
|
|||||||
pfUI:UpdateConfig("appearance", "cd", "dynamicsize", "1")
|
pfUI:UpdateConfig("appearance", "cd", "dynamicsize", "1")
|
||||||
pfUI:UpdateConfig("appearance", "castbar", "castbarcolor", ".7,.7,.9,.8")
|
pfUI:UpdateConfig("appearance", "castbar", "castbarcolor", ".7,.7,.9,.8")
|
||||||
pfUI:UpdateConfig("appearance", "castbar", "channelcolor", ".9,.9,.7,.8")
|
pfUI:UpdateConfig("appearance", "castbar", "channelcolor", ".9,.9,.7,.8")
|
||||||
|
pfUI:UpdateConfig("appearance", "castbar", "failcolor", "1,.2,.2,.8")
|
||||||
pfUI:UpdateConfig("appearance", "castbar", "texture", "Interface\\AddOns\\pfUI\\img\\bar")
|
pfUI:UpdateConfig("appearance", "castbar", "texture", "Interface\\AddOns\\pfUI\\img\\bar")
|
||||||
pfUI:UpdateConfig("appearance", "infight", "screen", "0")
|
pfUI:UpdateConfig("appearance", "infight", "screen", "0")
|
||||||
pfUI:UpdateConfig("appearance", "infight", "aggro", "0")
|
pfUI:UpdateConfig("appearance", "infight", "aggro", "0")
|
||||||
|
|||||||
+31
-157
@@ -238,6 +238,7 @@ function pfUI.uf:UpdateVisibility()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local unitstr = string.format("%s%s", self.label or "", self.id or "")
|
local unitstr = string.format("%s%s", self.label or "", self.id or "")
|
||||||
|
self:SetAttribute("unit", unitstr ~= "" and unitstr or nil)
|
||||||
local visibility = string.format("[target=%s,exists] show; hide", unitstr)
|
local visibility = string.format("[target=%s,exists] show; hide", unitstr)
|
||||||
|
|
||||||
-- Group frames are redundant when the group is already shown as a raid grid:
|
-- Group frames are redundant when the group is already shown as a raid grid:
|
||||||
@@ -1110,11 +1111,7 @@ function pfUI.uf.OnUpdate()
|
|||||||
|
|
||||||
-- update ressurections
|
-- update ressurections
|
||||||
local ress = libpredict:UnitHasIncomingResurrection(unit)
|
local ress = libpredict:UnitHasIncomingResurrection(unit)
|
||||||
if ress and UnitIsDeadOrGhost(unit) then
|
this.ressIcon:SetShown(ress and UnitIsDeadOrGhost(unit))
|
||||||
this.ressIcon:Show()
|
|
||||||
else
|
|
||||||
this.ressIcon:Hide()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1177,52 +1174,6 @@ function pfUI.uf.OnUpdate()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function pfUI.uf.OnEnter()
|
|
||||||
if not this.label then return end
|
|
||||||
|
|
||||||
local unitstr = this.label .. this.id
|
|
||||||
if UnitExists(unitstr) then
|
|
||||||
SetMouseoverUnit(unitstr)
|
|
||||||
end
|
|
||||||
|
|
||||||
if this.config.showtooltip == "0" then return end
|
|
||||||
GameTooltip_SetDefaultAnchor(GameTooltip, this)
|
|
||||||
GameTooltip:SetUnit(this.label .. this.id)
|
|
||||||
GameTooltip:Show()
|
|
||||||
end
|
|
||||||
|
|
||||||
function pfUI.uf.OnLeave()
|
|
||||||
SetMouseoverUnit("")
|
|
||||||
|
|
||||||
GameTooltip:FadeOut()
|
|
||||||
end
|
|
||||||
|
|
||||||
function pfUI.uf.OnClick()
|
|
||||||
if not this.label and this.unitname then
|
|
||||||
TargetByName(this.unitname, true)
|
|
||||||
else
|
|
||||||
pfUI.uf:ClickAction(arg1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function pfUI.uf:RightClickAction(unit)
|
|
||||||
if unit == "player" then
|
|
||||||
ToggleDropDownMenu(1, nil, PlayerFrameDropDown, "cursor")
|
|
||||||
elseif unit == "target" then
|
|
||||||
ToggleDropDownMenu(1, nil, TargetFrameDropDown, "cursor")
|
|
||||||
elseif unit == "pet" then
|
|
||||||
ToggleDropDownMenu(1, nil, PetFrameDropDown, "cursor")
|
|
||||||
elseif unit == "party" or strfind(unit, "party%d") then
|
|
||||||
ToggleDropDownMenu(1, nil, getglobal("PartyMemberFrame" .. this.id .. "DropDown"), "cursor")
|
|
||||||
elseif unit == "raid" or strfind(unit, "raid%d") then
|
|
||||||
local name = this.lastUnit
|
|
||||||
local unitstr = this.label .. this.id
|
|
||||||
FriendsDropDown.displayMode = "MENU"
|
|
||||||
FriendsDropDown.initialize = function() UnitPopup_ShowMenu(_G[UIDROPDOWNMENU_OPEN_MENU], "PARTY", unitstr, name, id) end
|
|
||||||
ToggleDropDownMenu(1, nil, FriendsDropDown, "cursor")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function pfUI.uf:EnableEvents()
|
function pfUI.uf:EnableEvents()
|
||||||
local f = self
|
local f = self
|
||||||
|
|
||||||
@@ -1261,13 +1212,12 @@ end
|
|||||||
function pfUI.uf:EnableScripts()
|
function pfUI.uf:EnableScripts()
|
||||||
local f = self
|
local f = self
|
||||||
|
|
||||||
f:SetScript("OnClick", pfUI.uf.OnClick)
|
f:SetAttribute("type1", "target")
|
||||||
|
f:SetAttribute("type2", "menu")
|
||||||
|
|
||||||
f:SetScript("OnShow", pfUI.uf.OnShow)
|
f:SetScript("OnShow", pfUI.uf.OnShow)
|
||||||
f:SetScript("OnEvent", pfUI.uf.OnEvent)
|
f:SetScript("OnEvent", pfUI.uf.OnEvent)
|
||||||
f:SetScript("OnUpdate", pfUI.uf.OnUpdate)
|
f:SetScript("OnUpdate", pfUI.uf.OnUpdate)
|
||||||
f:SetScript("OnEnter", pfUI.uf.OnEnter)
|
|
||||||
f:SetScript("OnLeave", pfUI.uf.OnLeave)
|
|
||||||
f:EnableClickCast()
|
f:EnableClickCast()
|
||||||
|
|
||||||
-- add frame to visibility refresh handler
|
-- add frame to visibility refresh handler
|
||||||
@@ -1423,6 +1373,10 @@ function pfUI.uf:CreateUnitFrame(unit, id, config, tick)
|
|||||||
f:Hide()
|
f:Hide()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if f.label ~= "" then
|
||||||
|
f:SetAttribute("unit", f.label .. f.id)
|
||||||
|
end
|
||||||
|
|
||||||
-- register frame for clique
|
-- register frame for clique
|
||||||
_G.ClickCastFrames = ClickCastFrames or {}
|
_G.ClickCastFrames = ClickCastFrames or {}
|
||||||
ClickCastFrames[f] = true
|
ClickCastFrames[f] = true
|
||||||
@@ -1477,11 +1431,7 @@ function pfUI.uf:RefreshIndicators(unit)
|
|||||||
local unitstr = unit.label .. unit.id
|
local unitstr = unit.label .. unit.id
|
||||||
|
|
||||||
if unit.leaderIcon then -- Leader Icon
|
if unit.leaderIcon then -- Leader Icon
|
||||||
if unit.config.leadericon == "1" and UnitIsPartyLeader(unitstr) and IsInGroup() then
|
unit.leaderIcon:SetShown(unit.config.leadericon == "1" and UnitIsPartyLeader(unitstr) and IsInGroup())
|
||||||
unit.leaderIcon:Show()
|
|
||||||
else
|
|
||||||
unit.leaderIcon:Hide()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if unit.lootIcon then -- Loot Icon
|
if unit.lootIcon then -- Loot Icon
|
||||||
@@ -1491,29 +1441,16 @@ function pfUI.uf:RefreshIndicators(unit)
|
|||||||
-- no third return value here.. but leaving this as a hint
|
-- no third return value here.. but leaving this as a hint
|
||||||
local method, group, raid = GetLootMethod()
|
local method, group, raid = GetLootMethod()
|
||||||
local name = group and UnitName(group == 0 and "player" or "party"..group) or raid and UnitName("raid"..raid) or nil
|
local name = group and UnitName(group == 0 and "player" or "party"..group) or raid and UnitName("raid"..raid) or nil
|
||||||
|
unit.lootIcon:SetShown(name and name == UnitName(unitstr))
|
||||||
if name and name == UnitName(unitstr) then
|
|
||||||
unit.lootIcon:Show()
|
|
||||||
else
|
|
||||||
unit.lootIcon:Hide()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if unit.pvpIcon then -- PvP Icon
|
if unit.pvpIcon then -- PvP Icon
|
||||||
if unit.config.showPVP == "1" and UnitIsPVP(unitstr) then
|
unit.pvpIcon:SetShown(unit.config.showPVP == "1" and UnitIsPVP(unitstr))
|
||||||
unit.pvpIcon:Show()
|
|
||||||
else
|
|
||||||
unit.pvpIcon:Hide()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if unit.restIcon and unit:GetName() == "pfPlayer" then -- Rest Icon
|
if unit.restIcon and unit:GetName() == "pfPlayer" then -- Rest Icon
|
||||||
if C.unitframes.player.showRest == "1" and UnitIsUnit(unitstr, "player") and IsResting() then
|
unit.restIcon:SetShown(C.unitframes.player.showRest == "1" and UnitIsUnit(unitstr, "player") and IsResting())
|
||||||
unit.restIcon:Show()
|
|
||||||
else
|
|
||||||
unit.restIcon:Hide()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if unit.happinessIcon and unit:GetName() == "pfPet" then -- Happiness Icon
|
if unit.happinessIcon and unit:GetName() == "pfPet" then -- Happiness Icon
|
||||||
@@ -1583,7 +1520,7 @@ function pfUI.uf:RefreshUnit(unit, component)
|
|||||||
if not unit.hp then return end
|
if not unit.hp then return end
|
||||||
if not unit.power then return end
|
if not unit.power then return end
|
||||||
if not unit.id then unit.id = "" end
|
if not unit.id then unit.id = "" end
|
||||||
local component = component or ""
|
component = component or ""
|
||||||
|
|
||||||
-- don't update scanner activity
|
-- don't update scanner activity
|
||||||
if unit.label == "target" or unit.label == "targettarget" or unit.label == "targettargettarget" then
|
if unit.label == "target" or unit.label == "targettarget" or unit.label == "targettargettarget" then
|
||||||
@@ -2126,14 +2063,6 @@ function pfUI.uf:RefreshUnit(unit, component)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local buttons = {
|
|
||||||
[1] = "LeftButton",
|
|
||||||
[2] = "RightButton",
|
|
||||||
[3] = "MiddleButton",
|
|
||||||
[4] = "Button4",
|
|
||||||
[5] = "Button5",
|
|
||||||
}
|
|
||||||
|
|
||||||
local modifiers = {
|
local modifiers = {
|
||||||
[""] = "",
|
[""] = "",
|
||||||
["alt"] = "_alt",
|
["alt"] = "_alt",
|
||||||
@@ -2143,86 +2072,31 @@ local modifiers = {
|
|||||||
|
|
||||||
function pfUI.uf:EnableClickCast()
|
function pfUI.uf:EnableClickCast()
|
||||||
if self.config.clickcast ~= "1" then return end
|
if self.config.clickcast ~= "1" then return end
|
||||||
for bid, button in pairs(buttons) do
|
for bid = 1, 5 do -- LeftButton, RightButton, MiddleButton, Button4, Button5
|
||||||
for modifier, mconf in pairs(modifiers) do
|
for modifier, mconf in pairs(modifiers) do
|
||||||
local bconf = bid == 1 and "" or bid
|
local bconf = bid == 1 and "" or bid
|
||||||
if pfUI_config.unitframes["clickcast"..bconf..mconf] ~= "" then
|
local action = pfUI_config.unitframes["clickcast"..bconf..mconf]
|
||||||
-- fill clickaction table
|
if action and action ~= "" then
|
||||||
self.clickactions = self.clickactions or {}
|
local prefix = modifier ~= "" and (modifier .. "-") or ""
|
||||||
self.clickactions[modifier..button] = pfUI_config.unitframes["clickcast"..bconf..mconf]
|
local low = string.lower(action)
|
||||||
|
if low == "menu" then
|
||||||
|
self:SetAttribute(prefix .. "type" .. bid, "menu")
|
||||||
|
elseif low == "target" then
|
||||||
|
self:SetAttribute(prefix .. "type" .. bid, "target")
|
||||||
|
elseif low == "focus" then
|
||||||
|
self:SetAttribute(prefix .. "type" .. bid, "focus")
|
||||||
|
elseif string.find(action, "^/") then
|
||||||
|
self:SetAttribute(prefix .. "type" .. bid, "macro")
|
||||||
|
self:SetAttribute(prefix .. "macrotext" .. bid, action)
|
||||||
|
else
|
||||||
|
self:SetAttribute(prefix .. "type" .. bid, "spell")
|
||||||
|
self:SetAttribute(prefix .. "spell" .. bid, action)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function pfUI.uf:ClickAction(button)
|
|
||||||
local label = this.label or ""
|
|
||||||
local id = this.id or ""
|
|
||||||
local unitstr = label .. id
|
|
||||||
local showmenu = button == "RightButton" and true or nil
|
|
||||||
if SpellIsTargeting() and button == "RightButton" then
|
|
||||||
SpellStopTargeting()
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if SpellIsTargeting() and button == "LeftButton" then
|
|
||||||
SpellTargetUnit(unitstr)
|
|
||||||
elseif CursorHasItem() then
|
|
||||||
DropItemOnUnit(unitstr)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- run click casting if enabled
|
|
||||||
local modstring = ""
|
|
||||||
modstring = IsAltKeyDown() and modstring.."alt" or modstring
|
|
||||||
modstring = IsControlKeyDown() and modstring.."ctrl" or modstring
|
|
||||||
modstring = IsShiftKeyDown() and modstring.."shift" or modstring
|
|
||||||
modstring = modstring..button
|
|
||||||
if this.clickactions and this.clickactions[modstring] then
|
|
||||||
local action_lower = string.lower(this.clickactions[modstring])
|
|
||||||
if string.find(action_lower, "^menu") then
|
|
||||||
-- show menu
|
|
||||||
showmenu = true
|
|
||||||
elseif string.find(action_lower, "^target") then
|
|
||||||
-- target unit
|
|
||||||
showmenu = nil
|
|
||||||
else
|
|
||||||
-- run click cast action
|
|
||||||
local is_macro = string.find(this.clickactions[modstring], "^%/(.+)")
|
|
||||||
|
|
||||||
local tswitch = UnitIsUnit(unitstr, "target")
|
|
||||||
TargetUnit(unitstr)
|
|
||||||
|
|
||||||
if is_macro then
|
|
||||||
RunMacroText(this.clickactions[modstring])
|
|
||||||
else
|
|
||||||
CastSpellByName(this.clickactions[modstring])
|
|
||||||
end
|
|
||||||
|
|
||||||
if not tswitch then TargetLastTarget() end
|
|
||||||
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- dropdown menus
|
|
||||||
if showmenu then
|
|
||||||
pfUI.uf:RightClickAction(label)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- drop food on petframe
|
|
||||||
if label == "pet" and CursorHasItem() then
|
|
||||||
local playerClass = UnitClassBase("player")
|
|
||||||
if playerClass == "HUNTER" then
|
|
||||||
DropItemOnUnit("pet")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- default click
|
|
||||||
TargetUnit(unitstr)
|
|
||||||
end
|
|
||||||
|
|
||||||
function pfUI.uf:AddIcon(frame, pos, icon, timeleft, stacks, start, duration)
|
function pfUI.uf:AddIcon(frame, pos, icon, timeleft, stacks, start, duration)
|
||||||
local showtime = frame.config.indicator_time == "1" and true or nil
|
local showtime = frame.config.indicator_time == "1" and true or nil
|
||||||
local showstacks = frame.config.indicator_stacks == "1" and true or nil
|
local showstacks = frame.config.indicator_stacks == "1" and true or nil
|
||||||
|
|||||||
+24
-40
@@ -1561,60 +1561,44 @@ pfUI:RegisterModule("actionbar", function ()
|
|||||||
if reagent_slots[slot] ~= newID then
|
if reagent_slots[slot] ~= newID then
|
||||||
reagent_slots[slot] = newID
|
reagent_slots[slot] = newID
|
||||||
if newID then
|
if newID then
|
||||||
reagent_counts[newID] = reagent_counts[newID] or 0
|
reagent_counts[newID] = reagent_counts[newID] or C_Item.GetItemCount(newID)
|
||||||
end
|
end
|
||||||
updatecache[slot] = true
|
updatecache[slot] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Recount every tracked reagent and flag its buttons for a refresh.
|
||||||
|
local RecountReagents = function()
|
||||||
|
for itemID in pairs(reagent_counts) do
|
||||||
|
reagent_counts[itemID] = C_Item.GetItemCount(itemID)
|
||||||
|
end
|
||||||
|
for slot in pairs(reagent_slots) do
|
||||||
|
updatecache[slot] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local reagentcounter = CreateFrame("Frame", "pfReagentCounter", UIParent)
|
local reagentcounter = CreateFrame("Frame", "pfReagentCounter", UIParent)
|
||||||
reagentcounter:RegisterEvent("PLAYER_ENTERING_WORLD")
|
reagentcounter:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
reagentcounter:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
|
reagentcounter:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
|
||||||
reagentcounter:RegisterEvent("BAG_UPDATE_DELAYED")
|
reagentcounter:RegisterEvent("BAG_UPDATE_DELAYED")
|
||||||
reagentcounter:SetScript("OnEvent", function()
|
reagentcounter:SetScript("OnEvent", function()
|
||||||
if event == "BAG_UPDATE_DELAYED" then
|
if event == "ACTIONBAR_SLOT_CHANGED" then
|
||||||
this.event = true
|
-- arg1 is the changed slot; 0 (or nil) means "all slots"
|
||||||
|
if arg1 and arg1 > 0 then
|
||||||
|
UpdateSlot(arg1)
|
||||||
|
else
|
||||||
|
for slot = 1, 120 do UpdateSlot(slot) end
|
||||||
|
end
|
||||||
|
elseif event == "BAG_UPDATE_DELAYED" then
|
||||||
|
-- inventory changed: refresh the counts we already track
|
||||||
|
RecountReagents()
|
||||||
else
|
else
|
||||||
this.scan = 1
|
-- PLAYER_ENTERING_WORLD: seed the full reagent map (UpdateSlot seeds
|
||||||
|
-- each new reagent's count; a BAG_UPDATE_DELAYED follows during login)
|
||||||
|
for slot = 1, 120 do UpdateSlot(slot) end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Reagent counter update with throttle for performance optimization
|
|
||||||
reagentcounter:SetScript("OnUpdate", function()
|
|
||||||
-- Throttle entire function to 10 FPS for smooth scanning
|
|
||||||
if (this.tick_update or 0) > GetTime() then return end
|
|
||||||
this.tick_update = GetTime() + 0.1
|
|
||||||
|
|
||||||
-- scan one action slot per update
|
|
||||||
if this.scan and this.scan <= 120 then
|
|
||||||
UpdateSlot(this.scan)
|
|
||||||
this.scan = this.scan + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- trigger reagent count updates after action scans
|
|
||||||
if this.scan and this.scan >= 120 then
|
|
||||||
this.event = true
|
|
||||||
this.scan = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- queue events to fire only once per second
|
|
||||||
if not this.event then return end
|
|
||||||
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 1 end
|
|
||||||
|
|
||||||
-- scan for all reagent item counts
|
|
||||||
for itemID in pairs(reagent_counts) do
|
|
||||||
reagent_counts[itemID] = C_Item.GetItemCount(itemID)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- update all actionbar buttons
|
|
||||||
for slot in pairs(reagent_slots) do
|
|
||||||
updatecache[slot] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- remove event trigger
|
|
||||||
this.event = nil
|
|
||||||
end)
|
|
||||||
|
|
||||||
function IsReagentAction(slot)
|
function IsReagentAction(slot)
|
||||||
return reagent_slots[slot] and true or nil
|
return reagent_slots[slot] and true or nil
|
||||||
end
|
end
|
||||||
|
|||||||
+16
-13
@@ -397,22 +397,25 @@ pfUI:RegisterModule("addonbuttons", function ()
|
|||||||
pfUI.addonbuttons:ProcessButtons()
|
pfUI.addonbuttons:ProcessButtons()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
pfUI.addonbuttons:SetScript("OnUpdate", function()
|
-- Initial setup on the next frame, once other addons' minimap buttons exist
|
||||||
|
RunNextFrame(function()
|
||||||
-- check if the panel should be shown by default
|
-- check if the panel should be shown by default
|
||||||
if not this.initialized then
|
if C.abuttons.showdefault == "1" and GetNumButtons() > 0 then
|
||||||
if C.abuttons.showdefault == "1" and GetNumButtons() > 0 then
|
pfUI.addonbuttons:Show()
|
||||||
pfUI.addonbuttons:Show()
|
else
|
||||||
else
|
pfUI.addonbuttons:Hide()
|
||||||
pfUI.addonbuttons:Hide()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- update all buttons
|
|
||||||
pfUI.addonbuttons:ProcessButtons()
|
|
||||||
this.initialized = true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- throttle updates to once per 5 seconds
|
-- update all buttons and apply workarounds
|
||||||
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 5 end
|
pfUI.addonbuttons:ProcessButtons()
|
||||||
|
for k, v in pairs(pfUI.addonbuttons.overrides) do
|
||||||
|
_G[k] = v
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- Rescan minimap buttons every 5 seconds while the panel is shown
|
||||||
|
C_Timer.NewTicker(5, function()
|
||||||
|
if not pfUI.addonbuttons:IsShown() then return end
|
||||||
|
|
||||||
-- reload/rescan minimap buttons
|
-- reload/rescan minimap buttons
|
||||||
pfUI.addonbuttons:ProcessButtons()
|
pfUI.addonbuttons:ProcessButtons()
|
||||||
|
|||||||
+112
-137
@@ -16,9 +16,13 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Clear cast state on the bar. Shows the bar full for one frame, then
|
-- Clear cast state on the bar and start the fade-out. On a normal end the bar
|
||||||
-- OnUpdate fades it out.
|
-- is left at its current fill (a completed cast is already ~full; nothing
|
||||||
local function ClearBar(cb)
|
-- snaps to full, which used to flash for a frame when the next cast stamped
|
||||||
|
-- the bar). When `failed` is set for a cast that was actually in progress, the
|
||||||
|
-- bar flashes full red before fading — the cancelled-cast indicator.
|
||||||
|
local function ClearBar(cb, failed)
|
||||||
|
local wasActive = cb.endTime ~= nil
|
||||||
cb.startTime, cb.endTime, cb.isChannel = nil, nil, nil
|
cb.startTime, cb.endTime, cb.isChannel = nil, nil, nil
|
||||||
cb.activeName, cb.spellID = nil, nil
|
cb.activeName, cb.spellID = nil, nil
|
||||||
cb.isTradeskill = nil
|
cb.isTradeskill = nil
|
||||||
@@ -26,8 +30,11 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
cb.tradeskillSingleMs, cb.currentCraftStart = nil, nil
|
cb.tradeskillSingleMs, cb.currentCraftStart = nil, nil
|
||||||
cb.lastMax = nil
|
cb.lastMax = nil
|
||||||
cb.delay = 0
|
cb.delay = 0
|
||||||
cb.bar:SetMinMaxValues(1, 100)
|
if failed and wasActive then
|
||||||
cb.bar:SetValue(100)
|
cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar.failcolor))
|
||||||
|
cb.bar:SetMinMaxValues(0, 1)
|
||||||
|
cb.bar:SetValue(1)
|
||||||
|
end
|
||||||
if cb.bar.spark then cb.bar.spark:Hide() end
|
if cb.bar.spark then cb.bar.spark:Hide() end
|
||||||
cb.fadeout = 1
|
cb.fadeout = 1
|
||||||
end
|
end
|
||||||
@@ -65,8 +72,8 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Mark the start of craft 2..N within an active merge (called from the
|
-- Mark the start of craft 2..N within an active merge (called from the
|
||||||
-- SPELLCAST_START / SPELL_START_SELF handlers). Resets the per-craft
|
-- UNIT_SPELLCAST_START handler). Resets the per-craft spark to the left
|
||||||
-- spark to the left edge of the bar.
|
-- edge of the bar.
|
||||||
local function StartTradeskillCraft(cb)
|
local function StartTradeskillCraft(cb)
|
||||||
cb.currentCraftStart = GetTime() * 1000
|
cb.currentCraftStart = GetTime() * 1000
|
||||||
local remaining = cb.tradeskillTotal - (cb.tradeskillCompleted or 0)
|
local remaining = cb.tradeskillTotal - (cb.tradeskillCompleted or 0)
|
||||||
@@ -79,7 +86,7 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
|
|
||||||
-- Stamp the bar with cast data and render text/icon/lag once. OnUpdate
|
-- Stamp the bar with cast data and render text/icon/lag once. OnUpdate
|
||||||
-- then animates the fill from this state without touching C_Spell.
|
-- then animates the fill from this state without touching C_Spell.
|
||||||
local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill)
|
local function StampBar(cb, name, tex, startMs, endMs, spellID, isChannel, delayMs, isTradeskill, rank)
|
||||||
cb.startTime = startMs
|
cb.startTime = startMs
|
||||||
cb.endTime = endMs
|
cb.endTime = endMs
|
||||||
cb.isChannel = isChannel
|
cb.isChannel = isChannel
|
||||||
@@ -92,10 +99,13 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
|
|
||||||
cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"]))
|
cb.bar:SetStatusBarColor(GetStringColor(C.appearance.castbar[isChannel and "channelcolor" or "castbarcolor"]))
|
||||||
|
|
||||||
local rank = ""
|
-- Rank: prefer the value the UNIT_SPELLCAST_* event delivered (arg5, passed
|
||||||
if spellID then
|
-- through by RefreshBar). Only the retarget re-poll has no event in hand, so
|
||||||
|
-- it falls back to a lookup.
|
||||||
|
if not rank and spellID then
|
||||||
rank = C_Spell.GetSpellSubtext(spellID) or ""
|
rank = C_Spell.GetSpellSubtext(spellID) or ""
|
||||||
end
|
end
|
||||||
|
rank = rank or ""
|
||||||
local spellname = (cb.showname and name) and (name .. " ") or ""
|
local spellname = (cb.showname and name) and (name .. " ") or ""
|
||||||
local rankstr = (cb.showrank and rank ~= "") and string.format("|cffaaffcc[%s]|r", rank) or ""
|
local rankstr = (cb.showrank and rank ~= "") and string.format("|cffaaffcc[%s]|r", rank) or ""
|
||||||
cb.bar.left:SetText(spellname .. rankstr)
|
cb.bar.left:SetText(spellname .. rankstr)
|
||||||
@@ -122,11 +132,21 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
|
|
||||||
cb.bar:SetMinMaxValues(0, duration)
|
cb.bar:SetMinMaxValues(0, duration)
|
||||||
cb.lastMax = duration
|
cb.lastMax = duration
|
||||||
|
|
||||||
|
-- Prime the fill on this frame. StampBar otherwise leaves the previous
|
||||||
|
-- value in place (ClearBar, run on the prior cast's STOP, leaves it full),
|
||||||
|
-- so the bar would flash full for the frame between here and the next
|
||||||
|
-- OnUpdate tick. Reset the throttle too so the timer text updates promptly.
|
||||||
|
local nowSec = GetTime()
|
||||||
|
local cur = isChannel and (endMs / 1000 - nowSec) or (nowSec - startMs / 1000)
|
||||||
|
if cur < 0 then cur = 0 elseif cur > duration then cur = duration end
|
||||||
|
cb.bar:SetValue(cur)
|
||||||
|
cb.tick = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
-- One-shot poll: read C_Spell for the bar's unit, stamp or clear. Called
|
-- One-shot poll: read C_Spell for the bar's unit, stamp or clear. Called
|
||||||
-- from event handlers (cast start, target/focus change), never per-frame.
|
-- from event handlers (cast start, target/focus change), never per-frame.
|
||||||
local function RefreshBar(cb)
|
local function RefreshBar(cb, rank)
|
||||||
local query = cb.unitstr ~= "" and cb.unitstr or cb.unitname
|
local query = cb.unitstr ~= "" and cb.unitstr or cb.unitname
|
||||||
if not query or (cb.unitstr ~= "" and not UnitExists(cb.unitstr)) then
|
if not query or (cb.unitstr ~= "" and not UnitExists(cb.unitstr)) then
|
||||||
ClearBar(cb)
|
ClearBar(cb)
|
||||||
@@ -149,7 +169,7 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if name and startMs and endMs then
|
if name and startMs and endMs then
|
||||||
StampBar(cb, name, tex, startMs, endMs, spellID, isChan, delayMs, isTradeskill)
|
StampBar(cb, name, tex, startMs, endMs, spellID, isChan, delayMs, isTradeskill, rank)
|
||||||
else
|
else
|
||||||
ClearBar(cb)
|
ClearBar(cb)
|
||||||
end
|
end
|
||||||
@@ -294,35 +314,27 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Cast lifecycle events. Player bars react to vanilla SPELLCAST_*; non-
|
-- Cast lifecycle, entirely on ClassicAPI's UNIT_SPELLCAST_* events. They
|
||||||
-- player bars also react to Nampower SPELL_*_OTHER (gated by the
|
-- fire per unit token: arg1=="player" for the player's own casts, and the
|
||||||
-- NP_EnableSpell{Start,Go}Events CVars, enabled by libdebuff) plus the
|
-- remote token(s) ("target", "focus", ...) for other units -- so one set of
|
||||||
-- retarget event. Player events also feed non-player bars for the
|
-- events drives every bar with no Nampower dependency. The handler routes an
|
||||||
-- target=self case.
|
-- event to this bar when arg1 matches its unit, or -- since the player's own
|
||||||
cb:RegisterEvent("SPELLCAST_START")
|
-- casts only ever fire arg1=="player" -- when the bar's unit resolves to the
|
||||||
cb:RegisterEvent("SPELLCAST_STOP")
|
-- player (target=self). PLAYER_TARGET/FOCUS_CHANGED re-polls so a unit
|
||||||
cb:RegisterEvent("SPELLCAST_FAILED")
|
-- already mid-cast when it becomes the target/focus still shows.
|
||||||
cb:RegisterEvent("SPELLCAST_INTERRUPTED")
|
cb:RegisterEvent("UNIT_SPELLCAST_START")
|
||||||
cb:RegisterEvent("SPELLCAST_CHANNEL_START")
|
cb:RegisterEvent("UNIT_SPELLCAST_STOP")
|
||||||
cb:RegisterEvent("SPELLCAST_CHANNEL_STOP")
|
cb:RegisterEvent("UNIT_SPELLCAST_FAILED")
|
||||||
cb:RegisterEvent("SPELLCAST_CHANNEL_UPDATE")
|
cb:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
|
||||||
cb:RegisterEvent("SPELL_DELAYED_SELF")
|
cb:RegisterEvent("UNIT_SPELLCAST_DELAYED")
|
||||||
-- Chained same-spell recasts never run the client cast path (the 1.12
|
cb:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
|
||||||
-- engine short-circuits at spellID == current-cast), so vanilla
|
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
|
||||||
-- SPELLCAST_START never fires for them. nampower's SPELL_START_SELF
|
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
|
||||||
-- (server-driven) is the only signal that shows them.
|
cb:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE")
|
||||||
cb:RegisterEvent("SPELL_START_SELF")
|
if unitstr == "target" then
|
||||||
if unitstr == "player" then
|
cb:RegisterEvent("PLAYER_TARGET_CHANGED")
|
||||||
cb:RegisterEvent("SPELL_GO_SELF")
|
elseif unitstr == "focus" then
|
||||||
end
|
cb:RegisterEvent("PLAYER_FOCUS_CHANGED")
|
||||||
if unitstr ~= "player" and unitstr ~= "" then
|
|
||||||
cb:RegisterEvent("SPELL_START_OTHER")
|
|
||||||
cb:RegisterEvent("SPELL_FAILED_OTHER")
|
|
||||||
if unitstr == "target" then
|
|
||||||
cb:RegisterEvent("PLAYER_TARGET_CHANGED")
|
|
||||||
elseif unitstr == "focus" then
|
|
||||||
cb:RegisterEvent("PLAYER_FOCUS_CHANGED")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
cb:SetScript("OnEvent", function()
|
cb:SetScript("OnEvent", function()
|
||||||
@@ -333,83 +345,33 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if event == "SPELL_START_OTHER" then
|
-- UNIT_SPELLCAST_* fire per unit token (arg1). Handle an event when it's
|
||||||
-- arg3=casterGuid. Defer one frame so ClassicAPI's UnitChannelInfo
|
-- for this bar's unit, or -- since the player's own casts only ever fire
|
||||||
-- can see the engine's +0x228 broadcast for remote-unit channels
|
-- arg1=="player" -- when this bar's unit currently resolves to the player
|
||||||
-- (the cohook+packet handler runs in the same frame; the broadcast
|
-- (target=self / focus=self).
|
||||||
-- propagates after).
|
-- Args: arg1=unit, arg2=castGUID, arg3=spellID, arg4=name, arg5=rank.
|
||||||
if arg3 == UnitGUID(unit) then
|
if arg1 ~= unit and not (arg1 == "player" and UnitIsUnit(unit, "player")) then
|
||||||
local target = this
|
|
||||||
RunNextFrame(function() RefreshBar(target) end)
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if event == "SPELL_FAILED_OTHER" then
|
if event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then
|
||||||
if arg1 == UnitGUID(unit) then ClearBar(this) end
|
-- START also fires per craft in a same-spell chain, so an active merge
|
||||||
return
|
-- just resyncs the current craft's spark/label instead of restamping.
|
||||||
end
|
|
||||||
|
|
||||||
-- Vanilla SPELLCAST_* + SPELL_DELAYED_SELF fire only for the local
|
|
||||||
-- player. Non-player bars handle them only when their unit currently
|
|
||||||
-- resolves to the player (target=self / focus=self).
|
|
||||||
if not UnitIsUnit(unit, 'player') then return end
|
|
||||||
|
|
||||||
if event == "SPELLCAST_START" or event == "SPELLCAST_CHANNEL_START" then
|
|
||||||
if this.tradeskillTotal then
|
if this.tradeskillTotal then
|
||||||
-- Mid-chain craft N+1 of N. Keep the merged bar; resync the spark
|
|
||||||
-- to the new craft's start and refresh the "(N)" count label.
|
|
||||||
StartTradeskillCraft(this)
|
StartTradeskillCraft(this)
|
||||||
else
|
else
|
||||||
RefreshBar(this)
|
RefreshBar(this, arg5)
|
||||||
if this.isTradeskill and (this.pendingTradeskillCount or 0) > 1
|
if this.isTradeskill and (this.pendingTradeskillCount or 0) > 1
|
||||||
and C.castbar.player.mergetradeskill == "1" then
|
and C.castbar.player.mergetradeskill == "1" then
|
||||||
EnterTradeskillMerge(this, this.startTime, this.endTime, this.pendingTradeskillCount)
|
EnterTradeskillMerge(this, this.startTime, this.endTime, this.pendingTradeskillCount)
|
||||||
end
|
end
|
||||||
this.pendingTradeskillCount = nil
|
this.pendingTradeskillCount = nil
|
||||||
end
|
end
|
||||||
elseif event == "SPELL_START_SELF" then
|
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
|
||||||
-- Catches chained same-spell recasts (no SPELLCAST_START fires) —
|
-- Per-craft completion during a tradeskill merge (arg3 = spellID):
|
||||||
-- including tradeskill chaining where craft 2..N reuse one spell.
|
-- count and clear when the chain is done. A no-op for normal casts,
|
||||||
-- Defer one frame so ClassicAPI's SMSG_SPELL_START co-hook has
|
-- which are cleared by UNIT_SPELLCAST_STOP.
|
||||||
-- stamped g_cast before we poll, regardless of co-hook order.
|
if this.tradeskillTotal and arg3 == this.tradeskillSpellID then
|
||||||
if this.tradeskillTotal then
|
|
||||||
StartTradeskillCraft(this)
|
|
||||||
else
|
|
||||||
local target = this
|
|
||||||
RunNextFrame(function()
|
|
||||||
-- Re-check: SPELL_START_SELF (nampower co-hook) fires before vanilla
|
|
||||||
-- SPELLCAST_START on the same packet, so SPELLCAST_START may have
|
|
||||||
-- entered merge in this same frame. Don't restamp over it.
|
|
||||||
if target.tradeskillTotal then
|
|
||||||
StartTradeskillCraft(target)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
RefreshBar(target)
|
|
||||||
if target.unitstr == "player" and target.isTradeskill
|
|
||||||
and (target.pendingTradeskillCount or 0) > 1
|
|
||||||
and C.castbar.player.mergetradeskill == "1" then
|
|
||||||
EnterTradeskillMerge(target, target.startTime, target.endTime, target.pendingTradeskillCount)
|
|
||||||
end
|
|
||||||
target.pendingTradeskillCount = nil
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
elseif event == "SPELLCAST_CHANNEL_STOP" then
|
|
||||||
-- A channel's stop can arrive after a following cast already claimed
|
|
||||||
-- the bar (channel->cast transition); only clear if a channel is
|
|
||||||
-- actually being shown, so it doesn't wipe an active cast bar.
|
|
||||||
if this.isChannel then ClearBar(this) end
|
|
||||||
elseif event == "SPELLCAST_STOP" then
|
|
||||||
-- During a tradeskill chain, SPELL_GO_SELF already counted this craft
|
|
||||||
-- and either cleared the bar (chain done) or kept it running. Only a
|
|
||||||
-- non-merge cast clears here.
|
|
||||||
if not this.tradeskillTotal then ClearBar(this) end
|
|
||||||
elseif event == "SPELLCAST_FAILED" or event == "SPELLCAST_INTERRUPTED" then
|
|
||||||
ClearBar(this)
|
|
||||||
elseif event == "SPELL_GO_SELF" then
|
|
||||||
-- arg2 = spellId. In a tradeskill merge, count each successful craft
|
|
||||||
-- and clear when the chain is done.
|
|
||||||
if this.tradeskillTotal and arg2 == this.tradeskillSpellID then
|
|
||||||
this.tradeskillCompleted = (this.tradeskillCompleted or 0) + 1
|
this.tradeskillCompleted = (this.tradeskillCompleted or 0) + 1
|
||||||
if this.tradeskillCompleted >= this.tradeskillTotal then
|
if this.tradeskillCompleted >= this.tradeskillTotal then
|
||||||
ClearBar(this)
|
ClearBar(this)
|
||||||
@@ -417,33 +379,46 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
UpdateTradeskillLabel(this)
|
UpdateTradeskillLabel(this)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif event == "SPELL_DELAYED_SELF" then
|
elseif event == "UNIT_SPELLCAST_CHANNEL_STOP" then
|
||||||
-- Cast pushback. nampower's event carries the delay (arg2); apply it
|
-- A channel's stop can arrive after a following cast already claimed
|
||||||
-- locally rather than re-polling, so the bar doesn't depend on
|
-- the bar (channel->cast transition); only clear if a channel is
|
||||||
-- ClassicAPI's SMSG_SPELL_DELAYED co-hook having bumped g_cast before
|
-- actually being shown, so it doesn't wipe an active cast bar.
|
||||||
-- this fires (co-hook order vs nampower is not guaranteed).
|
if this.isChannel then ClearBar(this) end
|
||||||
if not this.endTime or not arg2 then return end
|
elseif event == "UNIT_SPELLCAST_STOP" then
|
||||||
local delayMs = tonumber(arg2) or 0
|
-- STOP fires between crafts in a merge too (each craft is a new cast);
|
||||||
if delayMs > 0 then
|
-- UNIT_SPELLCAST_SUCCEEDED owns the count, so only a non-merge cast
|
||||||
this.delay = (this.delay or 0) + delayMs / 1000
|
-- clears here.
|
||||||
this.endTime = this.endTime + delayMs
|
if not this.tradeskillTotal then ClearBar(this) end
|
||||||
local newDuration = (this.endTime - this.startTime) / 1000
|
elseif event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" then
|
||||||
this.bar:SetMinMaxValues(0, newDuration)
|
ClearBar(this, true)
|
||||||
this.lastMax = newDuration
|
elseif event == "UNIT_SPELLCAST_DELAYED" or event == "UNIT_SPELLCAST_CHANNEL_UPDATE" then
|
||||||
end
|
-- Pushback: a cast delayed later or a channel shortened. Following
|
||||||
elseif event == "SPELLCAST_CHANNEL_UPDATE" then
|
-- Quartz, re-poll just the times and accumulate the shift into a running
|
||||||
-- Channel pushback. ClassicAPI doesn't track channel delay in
|
-- this.delay for the +/- indicator, rather than a full restamp (which
|
||||||
-- g_channel, so we adjust endTime + delay locally and resize the
|
-- would reset that total and re-render icon/text). ClassicAPI moves
|
||||||
-- bar so OnUpdate animates against the new total.
|
-- endMs (SpellDelayed_h bumps g_cast.endMs; the MSG_CHANNEL_UPDATE
|
||||||
if not this.endTime or not arg1 then return end
|
-- co-hook rewrites g_channel.endMs) while startMs stays put, so we diff
|
||||||
local newEndMs = GetTime() * 1000 + arg1
|
-- endMs. delay is a positive magnitude; OnUpdate signs it "+" for casts
|
||||||
local diff = this.endTime - newEndMs
|
-- and "-" for channels. Skipped during a tradeskill merge.
|
||||||
if diff > 50 then
|
if this.endTime and not this.tradeskillTotal then
|
||||||
this.delay = (this.delay or 0) + diff / 1000
|
local query = this.unitstr ~= "" and this.unitstr or this.unitname
|
||||||
this.endTime = newEndMs
|
local startMs, endMs
|
||||||
local newDuration = (this.endTime - this.startTime) / 1000
|
if this.isChannel then
|
||||||
this.bar:SetMinMaxValues(0, newDuration)
|
local _, _, _, s, e = C_Spell.UnitChannelInfo(query)
|
||||||
this.lastMax = newDuration
|
startMs, endMs = s, e
|
||||||
|
else
|
||||||
|
local _, _, _, s, e = C_Spell.UnitCastingInfo(query)
|
||||||
|
startMs, endMs = s, e
|
||||||
|
end
|
||||||
|
if startMs and endMs then
|
||||||
|
local shift = this.isChannel and (this.endTime - endMs) or (endMs - this.endTime)
|
||||||
|
this.delay = (this.delay or 0) + shift / 1000
|
||||||
|
this.startTime = startMs
|
||||||
|
this.endTime = endMs
|
||||||
|
local newDuration = (endMs - startMs) / 1000
|
||||||
|
this.bar:SetMinMaxValues(0, newDuration)
|
||||||
|
this.lastMax = newDuration
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -489,10 +464,10 @@ pfUI:RegisterModule("castbar", function ()
|
|||||||
UpdateMovable(pfUI.castbar.player)
|
UpdateMovable(pfUI.castbar.player)
|
||||||
|
|
||||||
-- Tradeskill merge: hook DoTradeSkill so the player castbar knows the
|
-- Tradeskill merge: hook DoTradeSkill so the player castbar knows the
|
||||||
-- requested count before the first SPELLCAST_START fires. Always-on hook
|
-- requested count before the first UNIT_SPELLCAST_START fires. Always-on
|
||||||
-- (the config knob is read at event time so toggling takes effect on the
|
-- hook (the config knob is read at event time so toggling takes effect on
|
||||||
-- next craft without a /reload). DoTradeSkill is synchronous; the server
|
-- the next craft without a /reload). DoTradeSkill is synchronous; the
|
||||||
-- roundtrip to SPELLCAST_START gives us plenty of time after this hook.
|
-- server roundtrip to UNIT_SPELLCAST_START gives us plenty of time.
|
||||||
hooksecurefunc("DoTradeSkill", function(index, num)
|
hooksecurefunc("DoTradeSkill", function(index, num)
|
||||||
if pfUI.castbar.player then
|
if pfUI.castbar.player then
|
||||||
pfUI.castbar.player.pendingTradeskillCount = tonumber(num) or 1
|
pfUI.castbar.player.pendingTradeskillCount = tonumber(num) or 1
|
||||||
|
|||||||
+54
-59
@@ -1,57 +1,32 @@
|
|||||||
pfUI:RegisterModule("marktracking", function ()
|
pfUI:RegisterModule("marktracking", function ()
|
||||||
-- Requires mark1-mark8 unit tokens (Turtle WoW / Nampower)
|
|
||||||
if not UnitExists("mark1") and not UnitExists("mark8") then
|
if not UnitExists("mark1") and not UnitExists("mark8") then
|
||||||
if not pcall(function() UnitExists("mark1") end) then return end
|
if not pcall(function() UnitExists("mark1") end) then return end
|
||||||
end
|
end
|
||||||
|
|
||||||
local rawborder, border = GetBorderSize()
|
local rawborder, border = GetBorderSize()
|
||||||
|
|
||||||
-- Parse color strings "r,g,b,a" into components
|
|
||||||
local function ParseColor(str, dr, dg, db, da)
|
|
||||||
if not str or str == "" then return dr, dg, db, da end
|
|
||||||
local _, _, r, g, b, a = string.find(str, "([%d%.]+),([%d%.]+),([%d%.]+),([%d%.]+)")
|
|
||||||
if r then
|
|
||||||
return tonumber(r) or dr, tonumber(g) or dg, tonumber(b) or db, tonumber(a) or da
|
|
||||||
end
|
|
||||||
return dr, dg, db, da
|
|
||||||
end
|
|
||||||
|
|
||||||
local markerOrder = { 8, 7, 6, 5, 4, 3, 2, 1 } -- skull, cross, square, moon, triangle, diamond, circle, star
|
local markerOrder = { 8, 7, 6, 5, 4, 3, 2, 1 } -- skull, cross, square, moon, triangle, diamond, circle, star
|
||||||
local markerTokens = {}
|
local markerTokens = {}
|
||||||
for i = 1, 8 do markerTokens[i] = "mark" .. i end
|
|
||||||
|
|
||||||
-- Default colors per marker
|
|
||||||
local defaultColors = {
|
|
||||||
[1] = { 1.0, 0.9, 0.0, 1 }, -- star: yellow
|
|
||||||
[2] = { 1.0, 0.5, 0.0, 1 }, -- circle: orange
|
|
||||||
[3] = { 0.8, 0.0, 0.8, 1 }, -- diamond: purple
|
|
||||||
[4] = { 0.0, 0.8, 0.0, 1 }, -- triangle: green
|
|
||||||
[5] = { 0.7, 0.7, 0.7, 1 }, -- moon: silver
|
|
||||||
[6] = { 0.0, 0.4, 0.9, 1 }, -- square: blue
|
|
||||||
[7] = { 0.9, 0.0, 0.0, 1 }, -- cross: red
|
|
||||||
[8] = { 1.0, 1.0, 1.0, 1 }, -- skull: white
|
|
||||||
}
|
|
||||||
|
|
||||||
local markerConfigKeys = {
|
local markerConfigKeys = {
|
||||||
[1] = "raidmarkercolor_star",
|
"raidmarkercolor_star",
|
||||||
[2] = "raidmarkercolor_circle",
|
"raidmarkercolor_circle",
|
||||||
[3] = "raidmarkercolor_diamond",
|
"raidmarkercolor_diamond",
|
||||||
[4] = "raidmarkercolor_triangle",
|
"raidmarkercolor_triangle",
|
||||||
[5] = "raidmarkercolor_moon",
|
"raidmarkercolor_moon",
|
||||||
[6] = "raidmarkercolor_square",
|
"raidmarkercolor_square",
|
||||||
[7] = "raidmarkercolor_cross",
|
"raidmarkercolor_cross",
|
||||||
[8] = "raidmarkercolor_skull",
|
"raidmarkercolor_skull",
|
||||||
}
|
}
|
||||||
|
|
||||||
local markerColors = {}
|
local markerColors = {}
|
||||||
for i = 1, 8 do
|
for i, markKey in ipairs(markerConfigKeys) do
|
||||||
local d = defaultColors[i]
|
markerTokens[i] = "mark" .. i
|
||||||
local r, g, b, a = ParseColor(C.unitframes[markerConfigKeys[i]], d[1], d[2], d[3], d[4])
|
local r, g, b, a = GetStringColor(C.unitframes[markKey])
|
||||||
markerColors[i] = { r, g, b, a }
|
markerColors[i] = { tonumber(r), tonumber(g), tonumber(b), tonumber(a) }
|
||||||
end
|
end
|
||||||
|
|
||||||
local FALLBACK_INTERVAL = 1.0 -- safety net for units that come into range after marker was set
|
local FALLBACK_INTERVAL = 1.0 -- safety net for units that come into range after marker was set
|
||||||
local elapsed = 0
|
|
||||||
local isUnlocked = false
|
local isUnlocked = false
|
||||||
local ROW_HEIGHT = tonumber(C.unitframes.raidmarkerheight) or 14
|
local ROW_HEIGHT = tonumber(C.unitframes.raidmarkerheight) or 14
|
||||||
local BAR_WIDTH = tonumber(C.unitframes.raidmarkerwidth) or 80
|
local BAR_WIDTH = tonumber(C.unitframes.raidmarkerwidth) or 80
|
||||||
@@ -125,19 +100,16 @@ pfUI.marktracking = CreateFrame("Frame", "pfMarkTracking", UIParent)
|
|||||||
local i = markerOrder[idx]
|
local i = markerOrder[idx]
|
||||||
|
|
||||||
local row = CreateFrame("Button", nil, pfUI.marktracking)
|
local row = CreateFrame("Button", nil, pfUI.marktracking)
|
||||||
row:SetWidth(TOTAL_ROW_WIDTH)
|
row:SetSize(TOTAL_ROW_WIDTH, ROW_HEIGHT)
|
||||||
row:SetHeight(ROW_HEIGHT)
|
|
||||||
row:Hide()
|
row:Hide()
|
||||||
|
|
||||||
row:RegisterForClicks("LeftButtonUp")
|
row:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||||||
row:SetScript("OnClick", function()
|
row:SetAttribute("type1", "target")
|
||||||
TargetUnit(markerTokens[this.markerIndex])
|
row:SetAttribute("type2", "menu")
|
||||||
end)
|
|
||||||
|
|
||||||
-- raid icon
|
-- raid icon
|
||||||
row.icon = row:CreateTexture(nil, "ARTWORK")
|
row.icon = row:CreateTexture(nil, "ARTWORK")
|
||||||
row.icon:SetWidth(ROW_HEIGHT)
|
row.icon:SetSize(ROW_HEIGHT, ROW_HEIGHT)
|
||||||
row.icon:SetHeight(ROW_HEIGHT)
|
|
||||||
row.icon:SetPoint("LEFT", row, "LEFT", 1, 0)
|
row.icon:SetPoint("LEFT", row, "LEFT", 1, 0)
|
||||||
local markTex = C.unitframes.blizzard_raidicons == "1" and "Interface\\TargetingFrame\\UI-RaidTargetingIcons" or pfUI.media["img:raidicons"]
|
local markTex = C.unitframes.blizzard_raidicons == "1" and "Interface\\TargetingFrame\\UI-RaidTargetingIcons" or pfUI.media["img:raidicons"]
|
||||||
row.icon:SetTexture(markTex)
|
row.icon:SetTexture(markTex)
|
||||||
@@ -145,8 +117,7 @@ pfUI.marktracking = CreateFrame("Frame", "pfMarkTracking", UIParent)
|
|||||||
|
|
||||||
-- portrait (right side)
|
-- portrait (right side)
|
||||||
row.portrait = row:CreateTexture(nil, "ARTWORK")
|
row.portrait = row:CreateTexture(nil, "ARTWORK")
|
||||||
row.portrait:SetWidth(PORTRAIT_SIZE)
|
row.portrait:SetSize(PORTRAIT_SIZE, PORTRAIT_SIZE)
|
||||||
row.portrait:SetHeight(PORTRAIT_SIZE)
|
|
||||||
row.portrait:SetPoint("RIGHT", row, "RIGHT", -1, 0)
|
row.portrait:SetPoint("RIGHT", row, "RIGHT", -1, 0)
|
||||||
row.portrait:SetTexCoord(.1, .9, .1, .9)
|
row.portrait:SetTexCoord(.1, .9, .1, .9)
|
||||||
if not rm_showportrait then row.portrait:Hide() end
|
if not rm_showportrait then row.portrait:Hide() end
|
||||||
@@ -204,8 +175,8 @@ pfUI.marktracking = CreateFrame("Frame", "pfMarkTracking", UIParent)
|
|||||||
local token = markerTokens[i]
|
local token = markerTokens[i]
|
||||||
|
|
||||||
if UnitExists(token) and not UnitIsDead(token) then
|
if UnitExists(token) and not UnitIsDead(token) then
|
||||||
local hp = UnitHealth(token)
|
local hp, maxhp = UnitHealth(token), UnitHealthMax(token)
|
||||||
local maxhp = UnitHealthMax(token)
|
row:SetAttribute('unit', token)
|
||||||
|
|
||||||
if hp and maxhp and maxhp > 0 and hp > 0 then
|
if hp and maxhp and maxhp > 0 and hp > 0 then
|
||||||
local pct = hp / maxhp
|
local pct = hp / maxhp
|
||||||
@@ -267,6 +238,27 @@ pfUI.marktracking = CreateFrame("Frame", "pfMarkTracking", UIParent)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Fast per-row refresh for a single mark's UNIT_HEALTH/UNIT_MAXHEALTH: moves
|
||||||
|
-- just the bar + hp text. If the mark's visibility flips (comes into range,
|
||||||
|
-- dies, hp crosses 0) the visible rows re-pack, so hand off to UpdateDisplay.
|
||||||
|
local function UpdateRow(i)
|
||||||
|
if isUnlocked then return end
|
||||||
|
local row = pfUI.marktracking.rows[i]
|
||||||
|
if not row then return end
|
||||||
|
local token = markerTokens[i]
|
||||||
|
local hp, maxhp = UnitHealth(token), UnitHealthMax(token)
|
||||||
|
local shouldShow = UnitExists(token) and not UnitIsDead(token)
|
||||||
|
and hp and maxhp and maxhp > 0 and hp > 0 and true or false
|
||||||
|
if shouldShow ~= (row:IsShown() and true or false) then
|
||||||
|
UpdateDisplay()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not shouldShow then return end
|
||||||
|
local pct = hp / maxhp
|
||||||
|
row.health:SetValue(pct)
|
||||||
|
if rm_showpct then row.hptext:SetText(math.ceil(pct * 100) .. "%") end
|
||||||
|
end
|
||||||
|
|
||||||
-- Unlock mode: show fixed 1-row placeholder so positioning works correctly
|
-- Unlock mode: show fixed 1-row placeholder so positioning works correctly
|
||||||
if pfUI.unlock then
|
if pfUI.unlock then
|
||||||
local origShow = pfUI.unlock:GetScript("OnShow")
|
local origShow = pfUI.unlock:GetScript("OnShow")
|
||||||
@@ -292,24 +284,27 @@ pfUI.marktracking = CreateFrame("Frame", "pfMarkTracking", UIParent)
|
|||||||
-- Event-driven scanner frame
|
-- Event-driven scanner frame
|
||||||
local scanner = CreateFrame("Frame")
|
local scanner = CreateFrame("Frame")
|
||||||
|
|
||||||
-- RAID_TARGET_UPDATE: fires when a raid marker is set/cleared
|
-- RAID_TARGET_UPDATE: a raid marker was set/cleared -> full refresh
|
||||||
-- PLAYER_ENTERING_WORLD: fires on login, reload, and zone transitions
|
-- PLAYER_ENTERING_WORLD: login/reload/zone -> full refresh
|
||||||
-- UNIT_HEALTH/UNIT_MAXHEALTH: fires on HP changes for real-time bar updates
|
-- UNIT_HEALTH/UNIT_MAXHEALTH: ClassicAPI fires these per token; with the mark
|
||||||
|
-- tokens observed they arrive as arg1 == "markN", so we refresh just that
|
||||||
|
-- one row (UpdateRow) instead of rescanning all eight.
|
||||||
scanner:RegisterEvent("RAID_TARGET_UPDATE")
|
scanner:RegisterEvent("RAID_TARGET_UPDATE")
|
||||||
scanner:RegisterEvent("PLAYER_ENTERING_WORLD")
|
scanner:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||||
scanner:RegisterEvent("UNIT_HEALTH")
|
scanner:RegisterEvent("UNIT_HEALTH")
|
||||||
scanner:RegisterEvent("UNIT_MAXHEALTH")
|
scanner:RegisterEvent("UNIT_MAXHEALTH")
|
||||||
|
|
||||||
scanner:SetScript("OnEvent", function()
|
scanner:SetScript("OnEvent", function()
|
||||||
|
if event == "UNIT_HEALTH" or event == "UNIT_MAXHEALTH" then
|
||||||
|
-- arg1 is the token; "markN" -> N, nil for any non-mark token.
|
||||||
|
local i = arg1 and tonumber(string.match(arg1, "^mark(%d)"))
|
||||||
|
if i then UpdateRow(i) end
|
||||||
|
return
|
||||||
|
end
|
||||||
UpdateDisplay()
|
UpdateDisplay()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Fallback poll at 1s: catches units that come into range AFTER a marker was set
|
-- Fallback poll: catches units that come into range AFTER a marker was set
|
||||||
-- (no event fires for that case, so we need this safety net)
|
-- (no event fires for that case, so we need this safety net)
|
||||||
scanner:SetScript("OnUpdate", function()
|
C_Timer.NewTicker(FALLBACK_INTERVAL, UpdateDisplay)
|
||||||
elapsed = elapsed + arg1
|
|
||||||
if elapsed < FALLBACK_INTERVAL then return end
|
|
||||||
elapsed = 0
|
|
||||||
UpdateDisplay()
|
|
||||||
end)
|
|
||||||
end)
|
end)
|
||||||
+7
-9
@@ -131,18 +131,16 @@ pfUI:RegisterModule("minimap", function ()
|
|||||||
|
|
||||||
-- Create coordinates text frame with location configurable
|
-- Create coordinates text frame with location configurable
|
||||||
pfUI.minimapCoordinates = CreateFrame("Frame", "pfMinimapCoord", pfUI.minimap)
|
pfUI.minimapCoordinates = CreateFrame("Frame", "pfMinimapCoord", pfUI.minimap)
|
||||||
pfUI.minimapCoordinates:SetScript("OnUpdate", function()
|
-- Update coords every 0.1 seconds
|
||||||
-- Throttle to update coords every 0.1 seconds
|
C_Timer.NewTicker(0.1, function()
|
||||||
if ( this.tick or 0) > GetTime() then return end
|
|
||||||
this.tick = GetTime() + .1
|
|
||||||
|
|
||||||
if C.appearance.minimap.coordstext == "off" then return end
|
if C.appearance.minimap.coordstext == "off" then return end
|
||||||
|
|
||||||
this.posX, this.posY = GetPlayerMapPosition("player")
|
local coord = pfUI.minimapCoordinates
|
||||||
if this.posX ~= 0 and this.posY ~= 0 then
|
coord.posX, coord.posY = GetPlayerMapPosition("player")
|
||||||
this.text:SetText(string.format("%.1f, %.1f", round(this.posX * 100, 1), round(this.posY * 100, 1)))
|
if coord.posX ~= 0 and coord.posY ~= 0 then
|
||||||
|
coord.text:SetText(string.format("%.1f, %.1f", round(coord.posX * 100, 1), round(coord.posY * 100, 1)))
|
||||||
else
|
else
|
||||||
this.text:SetText("|cffffaaaaN/A")
|
coord.text:SetText("|cffffaaaaN/A")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|||||||
+37
-41
@@ -64,18 +64,19 @@ pfUI:RegisterModule("nameplates", function ()
|
|||||||
|
|
||||||
local raidGuidCache = {} -- guid -> name (rebuilt on RAID_ROSTER_UPDATE/PARTY_MEMBERS_CHANGED)
|
local raidGuidCache = {} -- guid -> name (rebuilt on RAID_ROSTER_UPDATE/PARTY_MEMBERS_CHANGED)
|
||||||
|
|
||||||
-- Per-GUID cast state, populated by nampower's SPELL_START_OTHER events and
|
-- Per-GUID cast state, populated from ClassicAPI's UNIT_SPELLCAST_* events
|
||||||
-- cleared on SPELL_FAILED_OTHER / plate removal / expiry. This replaces the
|
-- (which now fire for nameplate tokens) and cleared on STOP / plate removal /
|
||||||
-- old per-tick C_Spell poll on every visible plate: cast detection is now
|
-- expiry. This replaces the old per-tick C_Spell poll on every visible plate:
|
||||||
-- event driven, and GetCastInfo just reads this cache.
|
-- cast detection is event driven, and GetCastInfo just reads this cache.
|
||||||
local castState = {}
|
local castState = {}
|
||||||
-- guid -> nameplate, maintained on NAME_PLATE_UNIT_ADDED/_REMOVED so a cast
|
-- 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.
|
-- event can find its plate in O(1) and only cache casts we actually show.
|
||||||
local plateByGuid = {}
|
local plateByGuid = {}
|
||||||
|
|
||||||
-- One-shot C_Spell poll. Only used to seed a plate that spawns while its
|
-- One-shot C_Spell poll. Builds the cast struct for a UNIT_SPELLCAST_* event
|
||||||
-- unit is already mid-cast (its SPELL_START_OTHER fired before the plate
|
-- (the payload carries no timing) and seeds a plate that spawns while its unit
|
||||||
-- existed). Never called per frame.
|
-- is already mid-cast (its START fired before the plate existed). Picks cast
|
||||||
|
-- vs channel itself. Never called per frame.
|
||||||
local function PollCastInfo(unit)
|
local function PollCastInfo(unit)
|
||||||
if not unit then return nil end
|
if not unit then return nil end
|
||||||
local name, _, texture, startMs, endMs, _, _, _, spellID = C_Spell.UnitCastingInfo(unit)
|
local name, _, texture, startMs, endMs, _, _, _, spellID = C_Spell.UnitCastingInfo(unit)
|
||||||
@@ -477,8 +478,10 @@ nameplates:RegisterEvent("NAME_PLATE_UNIT_REMOVED")
|
|||||||
nameplates:RegisterEvent("UNIT_AURA")
|
nameplates:RegisterEvent("UNIT_AURA")
|
||||||
nameplates:RegisterEvent("UNIT_FLAGS")
|
nameplates:RegisterEvent("UNIT_FLAGS")
|
||||||
nameplates:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
|
nameplates:RegisterEvent("UPDATE_MOUSEOVER_UNIT")
|
||||||
nameplates:RegisterEvent("SPELL_START_OTHER")
|
nameplates:RegisterEvent("UNIT_SPELLCAST_START")
|
||||||
nameplates:RegisterEvent("SPELL_FAILED_OTHER")
|
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START")
|
||||||
|
nameplates:RegisterEvent("UNIT_SPELLCAST_STOP")
|
||||||
|
nameplates:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP")
|
||||||
|
|
||||||
nameplates:SetScript("OnEvent", function()
|
nameplates:SetScript("OnEvent", function()
|
||||||
-- Stop event handling during logout to prevent crash 132
|
-- Stop event handling during logout to prevent crash 132
|
||||||
@@ -562,9 +565,9 @@ nameplates:RegisterEvent("SPELL_FAILED_OTHER")
|
|||||||
plate.nameplate.unit = arg1
|
plate.nameplate.unit = arg1
|
||||||
if guid then
|
if guid then
|
||||||
plateByGuid[guid] = plate.nameplate
|
plateByGuid[guid] = plate.nameplate
|
||||||
-- Seed: the unit may already be mid-cast (its SPELL_START_OTHER fired
|
-- Seed: the unit may already be mid-cast (its UNIT_SPELLCAST_START
|
||||||
-- before this plate existed). One poll here catches that; ongoing
|
-- fired before this plate existed). One poll here catches that;
|
||||||
-- casts arrive via the event.
|
-- ongoing casts arrive via the event.
|
||||||
castState[guid] = PollCastInfo(arg1)
|
castState[guid] = PollCastInfo(arg1)
|
||||||
end
|
end
|
||||||
nameplates.OnShow(plate)
|
nameplates.OnShow(plate)
|
||||||
@@ -609,39 +612,32 @@ nameplates:RegisterEvent("SPELL_FAILED_OTHER")
|
|||||||
if pn then pn.eventcache = true end
|
if pn then pn.eventcache = true end
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == "SPELL_START_OTHER" then
|
elseif event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_CHANNEL_START" then
|
||||||
-- nampower: arg2=spellId, arg3=casterGuid, arg6=castTime(ms),
|
-- ClassicAPI fires UNIT_SPELLCAST_* per unit token, including the caster's
|
||||||
-- arg7=channel duration(ms, 0 if not a channel), arg8=spellType
|
-- "nameplateN". The payload has no timing, so poll it (PollCastInfo picks
|
||||||
-- (1 = channel). Cache the cast only for a unit we have a plate for, so
|
-- cast vs channel) and cache -- only for a unit we have a plate for, so
|
||||||
-- the table stays bounded to on-screen casters.
|
-- the table stays bounded to on-screen casters.
|
||||||
local casterGuid = arg3
|
if arg1 and strfind(arg1, "^nameplate") then
|
||||||
local plate = casterGuid and plateByGuid[casterGuid]
|
local guid = UnitGUID(arg1)
|
||||||
if plate then
|
local plate = guid and plateByGuid[guid]
|
||||||
local isChannel = arg8 == 1
|
if plate then
|
||||||
local durationMs = isChannel and arg7 or arg6
|
castState[guid] = PollCastInfo(arg1)
|
||||||
if durationMs and durationMs > 0 then
|
if castState[guid] then
|
||||||
local spellId = arg2
|
plate.castUpdate = true -- bypass the throttle so the bar shows now
|
||||||
local now = GetTime()
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == "SPELL_FAILED_OTHER" then
|
elseif event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_CHANNEL_STOP" then
|
||||||
-- nampower: arg1=casterGuid, arg2=spellId. Clear on interrupt/failure.
|
-- Cast/channel ended (natural, interrupted, or cancelled -- the poll fires
|
||||||
local casterGuid = arg1
|
-- STOP for all three). Clear the cached cast and refresh its plate.
|
||||||
if casterGuid and castState[casterGuid] then
|
if arg1 and strfind(arg1, "^nameplate") then
|
||||||
castState[casterGuid] = nil
|
local guid = UnitGUID(arg1)
|
||||||
local plate = plateByGuid[casterGuid]
|
if guid and castState[guid] then
|
||||||
if plate then plate.castUpdate = true end
|
castState[guid] = nil
|
||||||
|
local plate = plateByGuid[guid]
|
||||||
|
if plate then plate.castUpdate = true end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif event == "UNIT_AURA" then
|
elseif event == "UNIT_AURA" then
|
||||||
|
|||||||
+17
-36
@@ -37,18 +37,12 @@ pfUI:RegisterModule("panel", function()
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
if arg1 == "LeftButton" then
|
if arg1 == "LeftButton" then
|
||||||
if widget.timerFrame:IsShown() then
|
widget.timerFrame:SetShown(not widget.timerFrame:IsShown())
|
||||||
widget.timerFrame:Hide()
|
|
||||||
else
|
|
||||||
widget.timerFrame:Show()
|
|
||||||
end
|
|
||||||
elseif arg1 == "RightButton" then
|
elseif arg1 == "RightButton" then
|
||||||
widget.timerFrame.Snapshot = GetTime()
|
widget.timerFrame.Snapshot = GetTime()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
widget:SetScript("OnUpdate",function()
|
C_Timer.NewTicker(1, function()
|
||||||
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 1 end
|
|
||||||
|
|
||||||
local secondsenabled = C.panel.seconds == "1"
|
local secondsenabled = C.panel.seconds == "1"
|
||||||
local fmt
|
local fmt
|
||||||
if C.global.twentyfour == "0" then
|
if C.global.twentyfour == "0" then
|
||||||
@@ -62,8 +56,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
|
|
||||||
widget.timerFrame = CreateFrame("Frame", "pfUITimer", UIParent)
|
widget.timerFrame = CreateFrame("Frame", "pfUITimer", UIParent)
|
||||||
widget.timerFrame:Hide()
|
widget.timerFrame:Hide()
|
||||||
widget.timerFrame:SetWidth(120)
|
widget.timerFrame:SetSize(120, 35)
|
||||||
widget.timerFrame:SetHeight(35)
|
|
||||||
widget.timerFrame:SetPoint("TOP", 0, -100)
|
widget.timerFrame:SetPoint("TOP", 0, -100)
|
||||||
UpdateMovable(widget.timerFrame)
|
UpdateMovable(widget.timerFrame)
|
||||||
|
|
||||||
@@ -103,11 +96,9 @@ pfUI:RegisterModule("panel", function()
|
|||||||
pfUI.panel:OutputPanel("combat", T["Combat"] .. ": " .. NOT_APPLICABLE)
|
pfUI.panel:OutputPanel("combat", T["Combat"] .. ": " .. NOT_APPLICABLE)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
widget.combat:SetScript("OnUpdate", function()
|
C_Timer.NewTicker(1, function()
|
||||||
if not this.tick then this.tick = GetTime() end
|
if widget.combat.combat then
|
||||||
if GetTime() <= this.tick + 1 then return else this.tick = GetTime() end
|
pfUI.panel:OutputPanel("combat", "|cffffaaaa" .. SecondsToTime(ceil(GetTime() - widget.combat.combat)))
|
||||||
if this.combat then
|
|
||||||
pfUI.panel:OutputPanel("combat", "|cffffaaaa" .. SecondsToTime(ceil(GetTime() - this.combat)))
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
@@ -153,9 +144,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
pfUI.addons:Show()
|
pfUI.addons:Show()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
widget:SetScript("OnUpdate",function()
|
C_Timer.NewTicker(1, function()
|
||||||
if ( this.tick or 1) > GetTime() then return else this.tick = GetTime() + 1 end
|
|
||||||
|
|
||||||
fps = floor(GetFramerate())
|
fps = floor(GetFramerate())
|
||||||
_, _, lag = GetNetStats()
|
_, _, lag = GetNetStats()
|
||||||
|
|
||||||
@@ -346,7 +335,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
widget:RegisterEvent("PLAYER_GUILD_UPDATE")
|
widget:RegisterEvent("PLAYER_GUILD_UPDATE")
|
||||||
widget.Tooltip = function()
|
widget.Tooltip = function()
|
||||||
-- skip without guild
|
-- skip without guild
|
||||||
if not GetGuildInfo("player") then return end
|
if not IsInGuild() then return end
|
||||||
|
|
||||||
local raidparty = {}
|
local raidparty = {}
|
||||||
for i=1,4 do -- detect people in group
|
for i=1,4 do -- detect people in group
|
||||||
@@ -398,7 +387,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
end
|
end
|
||||||
widget.Click = function() ToggleFriendsFrame(3) end
|
widget.Click = function() ToggleFriendsFrame(3) end
|
||||||
widget:SetScript("OnEvent", function()
|
widget:SetScript("OnEvent", function()
|
||||||
if GetGuildInfo("player") then
|
if IsInGuild() then
|
||||||
local count = 0
|
local count = 0
|
||||||
for i = 1, GetNumGuildMembers() do
|
for i = 1, GetNumGuildMembers() do
|
||||||
local _, _, _, _, _, _, _, _, online = GetGuildRosterInfo(i)
|
local _, _, _, _, _, _, _, _, online = GetGuildRosterInfo(i)
|
||||||
@@ -411,9 +400,8 @@ pfUI:RegisterModule("panel", function()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
widget:SetScript("OnUpdate",function()
|
C_Timer.NewTicker(60, function()
|
||||||
if ( this.tick or 60) > GetTime() then return else this.tick = GetTime() + 60 end
|
if IsInGuild() then GuildRoster() end
|
||||||
if GetGuildInfo("player") then GuildRoster() end
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -492,11 +480,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
GameTooltip:Show()
|
GameTooltip:Show()
|
||||||
end
|
end
|
||||||
widget.Click = function()
|
widget.Click = function()
|
||||||
if WorldMapFrame:IsShown() then
|
WorldMapFrame:SetShown(not WorldMapFrame:IsShown())
|
||||||
WorldMapFrame:Hide()
|
|
||||||
else
|
|
||||||
WorldMapFrame:Show()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
widget:SetScript("OnEvent", function()
|
widget:SetScript("OnEvent", function()
|
||||||
pfUI.panel:OutputPanel("zone", GetMinimapZoneText(), widget.Tooltip, widget.Click)
|
pfUI.panel:OutputPanel("zone", GetMinimapZoneText(), widget.Tooltip, widget.Click)
|
||||||
@@ -645,8 +629,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
local frame = CreateFrame("Button", nil, parent)
|
local frame = CreateFrame("Button", nil, parent)
|
||||||
frame:SetFrameLevel(0)
|
frame:SetFrameLevel(0)
|
||||||
frame:ClearAllPoints()
|
frame:ClearAllPoints()
|
||||||
frame:SetWidth(width)
|
frame:SetSize(width, parent:GetHeight())
|
||||||
frame:SetHeight(parent:GetHeight())
|
|
||||||
frame:SetPoint(location, 0, 0)
|
frame:SetPoint(location, 0, 0)
|
||||||
frame.text = frame:CreateFontString("Status", "LOW", "GameFontNormal")
|
frame.text = frame:CreateFontString("Status", "LOW", "GameFontNormal")
|
||||||
frame.text:ClearAllPoints()
|
frame.text:ClearAllPoints()
|
||||||
@@ -687,8 +670,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
local imgstring = "img:" .. leftright
|
local imgstring = "img:" .. leftright
|
||||||
parent.texture:SetTexture(pfUI.media[imgstring])
|
parent.texture:SetTexture(pfUI.media[imgstring])
|
||||||
parent.texture:SetPoint("CENTER", 0, 0)
|
parent.texture:SetPoint("CENTER", 0, 0)
|
||||||
parent.texture:SetWidth(8)
|
parent.texture:SetSize(8, 8)
|
||||||
parent.texture:SetHeight(8)
|
|
||||||
parent.texture:SetVertexColor(.25,.25,.25,1)
|
parent.texture:SetVertexColor(.25,.25,.25,1)
|
||||||
return parent.texture
|
return parent.texture
|
||||||
end
|
end
|
||||||
@@ -710,7 +692,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
UpdateMovable(pfUI.panel.left)
|
UpdateMovable(pfUI.panel.left)
|
||||||
|
|
||||||
pfUI.panel.left.hide:SetScript("OnClick", function()
|
pfUI.panel.left.hide:SetScript("OnClick", function()
|
||||||
if pfUI.chat.left:IsShown() then pfUI.chat.left:Hide() else pfUI.chat.left:Show() end
|
pfUI.chat.left:SetShown(not pfUI.chat.left:IsShown())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if not pfUI.chat then pfUI.panel.left.hide:Hide() end
|
if not pfUI.chat then pfUI.panel.left.hide:Hide() end
|
||||||
@@ -747,7 +729,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
UpdateMovable(pfUI.panel.right)
|
UpdateMovable(pfUI.panel.right)
|
||||||
|
|
||||||
pfUI.panel.right.hide:SetScript("OnClick", function()
|
pfUI.panel.right.hide:SetScript("OnClick", function()
|
||||||
if pfUI.chat.right:IsShown() then pfUI.chat.right:Hide() else pfUI.chat.right:Show() end
|
pfUI.chat.right:SetShown(not pfUI.chat.right:IsShown())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if not pfUI.chat then pfUI.panel.right.hide:Hide() end
|
if not pfUI.chat then pfUI.panel.right.hide:Hide() end
|
||||||
@@ -796,8 +778,7 @@ pfUI:RegisterModule("panel", function()
|
|||||||
pfUI.panel.microbutton = CreateFrame("Frame", "pfPanelMicroButton", UIParent)
|
pfUI.panel.microbutton = CreateFrame("Frame", "pfPanelMicroButton", UIParent)
|
||||||
pfUI.panel.microbutton:SetPoint("TOP", pfUI.panel.minimap, "BOTTOM", 0, -2*default_border)
|
pfUI.panel.microbutton:SetPoint("TOP", pfUI.panel.minimap, "BOTTOM", 0, -2*default_border)
|
||||||
UpdateMovable(pfUI.panel.microbutton)
|
UpdateMovable(pfUI.panel.microbutton)
|
||||||
pfUI.panel.microbutton:SetHeight(23)
|
pfUI.panel.microbutton:SetSize(145, 23)
|
||||||
pfUI.panel.microbutton:SetWidth(145)
|
|
||||||
pfUI.panel.microbutton:SetFrameStrata("MEDIUM")
|
pfUI.panel.microbutton:SetFrameStrata("MEDIUM")
|
||||||
|
|
||||||
for i=1,table.getn(MICRO_BUTTONS) do
|
for i=1,table.getn(MICRO_BUTTONS) do
|
||||||
|
|||||||
@@ -80,10 +80,7 @@ pfUI:RegisterModule("turtle-wow", function ()
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
local delay = CreateFrame("Frame")
|
RunNextFrame(function()
|
||||||
delay:SetScript("OnUpdate", function()
|
|
||||||
this:Hide()
|
|
||||||
|
|
||||||
-- correct positions of new game menu layout
|
-- correct positions of new game menu layout
|
||||||
if GameMenuButtonShop and (GameMenuButtonPFUI or GameMenuButtonPFUIAddOns) then
|
if GameMenuButtonShop and (GameMenuButtonPFUI or GameMenuButtonPFUIAddOns) then
|
||||||
-- calculate new offset for the shop button
|
-- calculate new offset for the shop button
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ do
|
|||||||
-- ClassicAPI dependency check.
|
-- ClassicAPI dependency check.
|
||||||
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
|
-- pfUI relies pervasively on the modern C_* / SuperWoW / nameplate / focus
|
||||||
-- API surface that ClassicAPI polyfills, so presence is required.
|
-- API surface that ClassicAPI polyfills, so presence is required.
|
||||||
local PFUI_CLASSIC_API_MIN = 10802 -- (X*10000 + Y*100 + Z)
|
local PFUI_CLASSIC_API_MIN = 10900 -- (X*10000 + Y*100 + Z)
|
||||||
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
local PFUI_CLASSIC_API_LATEST = PFUI_CLASSIC_API_MIN
|
||||||
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
local PFUI_CLASSIC_API_WEBSITE = "https://github.com/brues-code/ClassicAPI"
|
||||||
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
local PFUI_CLASSIC_API_LATEST_URL = PFUI_CLASSIC_API_WEBSITE .. "/releases/latest"
|
||||||
|
|||||||
Reference in New Issue
Block a user