You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

312 lines
12 KiB

--========================================================--
-- Scorpio UnitFrame Power API --
-- --
-- Author : kurapica125@outlook.com --
-- Create Date : 2021/03/06 --
--========================================================--
--========================================================--
Scorpio "Scorpio.Secure.UnitFrame.PowerAPI""1.0.0"
--========================================================--
namespace "Scorpio.Secure.UnitFrame"
import "System.Reactive"
import "System.Toolset"
------------------------------------------------------------
-- Unit Power API --
------------------------------------------------------------
local _PlayerClass = select(2, UnitClass("player"))
local _ClassPowerType, _ClassPowerToken, _PrevClassPowerType
local _ClassPowerRefresh = Subject()
local _ClassPowerSubject = Subject()
local _ClassPowerMaxSubject = Subject()
local SPEC_DEMONHUNTER_VENGENCE = 2
local SOULFRAGMENT = 203981
local SOULFRAGMENTNAME
local STAGGER = 100 -- DIFF to other class type
local FindAuraByName = _G.AuraUtil.FindAuraByName
local PowerType = _G.Enum.PowerType
__Async__()
OnEnable = OnEnable + function ()
-- Use the custom unit event to provide the API
if _PlayerClass == "WARRIOR" then
elseif _PlayerClass == "DEATHKNIGHT" then
_ClassPowerToken = "RUNES"
_ClassPowerType = PowerType.Runes
while true do
local spec = GetSpecialization()
Continue(RefreshClassPower)
NextEvent("PLAYER_SPECIALIZATION_CHANGED")
end
elseif _PlayerClass == "PALADIN" and Scorpio.IsRetail then
_ClassPowerToken = "HOLY_POWER"
local level = UnitLevel("player")
while level < PALADINPOWERBAR_SHOW_LEVEL do
level = NextEvent("PLAYER_LEVEL_UP")
end
_ClassPowerType = PowerType.HolyPower
elseif _PlayerClass == "MONK" then
_ClassPowerToken = "CHI"
while true do
local spec = GetSpecialization()
_ClassPowerType = spec == SPEC_MONK_WINDWALKER and PowerType.Chi or spec == SPEC_MONK_BREWMASTER and STAGGER or nil
Continue(RefreshClassPower)
NextEvent("PLAYER_SPECIALIZATION_CHANGED")
end
elseif _PlayerClass == "PRIEST" and Scorpio.IsRetail then
_ClassPowerToken = "MANA"
while true do
_ClassPowerType = GetSpecialization() == SPEC_PRIEST_SHADOW and PowerType.Mana or nil
Continue(RefreshClassPower)
NextEvent("PLAYER_SPECIALIZATION_CHANGED")
end
elseif _PlayerClass == "SHAMAN" and Scorpio.IsRetail then
_ClassPowerToken = "MANA"
while true do
_ClassPowerType = GetSpecialization() ~= SPEC_SHAMAN_RESTORATION and PowerType.Mana or nil
Continue(RefreshClassPower)
NextEvent("PLAYER_SPECIALIZATION_CHANGED")
end
elseif _PlayerClass == "DRUID" then
_ClassPowerToken = "COMBO_POINTS"
while true do
_ClassPowerType = GetShapeshiftFormID() == CAT_FORM and PowerType.ComboPoints or nil
Continue(RefreshClassPower)
NextEvent("UPDATE_SHAPESHIFT_FORM")
end
elseif _PlayerClass == "ROGUE" then
_ClassPowerToken = "COMBO_POINTS"
_ClassPowerType = PowerType.ComboPoints
elseif _PlayerClass == "MAGE" and Scorpio.IsRetail then
_ClassPowerToken = "ARCANE_CHARGES"
while true do
_ClassPowerType = GetSpecialization() == SPEC_MAGE_ARCANE and PowerType.ArcaneCharges or nil
Continue(RefreshClassPower)
NextEvent("PLAYER_SPECIALIZATION_CHANGED")
end
elseif _PlayerClass == "WARLOCK" and Scorpio.IsRetail then
_ClassPowerToken = "SOUL_SHARDS"
_ClassPowerType = PowerType.SoulShards
elseif _PlayerClass == "HUNTER" then
elseif _PlayerClass == "DEMONHUNTER" then
SOULFRAGMENTNAME = GetSpellInfo(SOULFRAGMENT)
_ClassPowerToken = "DEMONHUNTER"
while true do
_ClassPowerType = GetSpecialization() == SPEC_DEMONHUNTER_VENGENCE and SOULFRAGMENT or nil
Continue(RefreshClassPower)
NextEvent("PLAYER_SPECIALIZATION_CHANGED")
end
end
return RefreshClassPower()
end
function RefreshClassPower()
if _ClassPowerType then
if _PrevClassPowerType ~= _ClassPowerType then
if _PrevClassPowerType then
_ClassPowerSubject:Unsubscribe()
_ClassPowerMaxSubject:Unsubscribe()
end
_PrevClassPowerType = _ClassPowerType
-- Binding the real event source
_ClassPowerSubject:Resubscribe()
_ClassPowerMaxSubject:Resubscribe()
if _ClassPowerType == SOULFRAGMENT then
-- Use aura to track, keep using Next() for throttling
Wow.FromEvent("UNIT_AURA"):MatchUnit("player"):Subscribe(_ClassPowerSubject)
elseif _ClassPowerType == STAGGER then
Wow.FromEvent("UNIT_HEALTH"):MatchUnit("player"):Subscribe(_ClassPowerSubject)
Wow.FromEvent("UNIT_MAXHEALTH"):MatchUnit("player"):Subscribe(_ClassPowerMaxSubject)
elseif _ClassPowerType == PowerType.Runes then
Wow.FromEvent("RUNE_POWER_UPDATE"):Map("=>'player'"):Subscribe(_ClassPowerSubject)
else
Wow.FromEvent("UNIT_POWER_FREQUENT"):MatchUnit("player"):Subscribe(_ClassPowerSubject)
Wow.FromEvent("UNIT_MAXPOWER"):MatchUnit("player"):Subscribe(_ClassPowerMaxSubject)
end
end
else
_PrevClassPowerType = false
_ClassPowerSubject:Unsubscribe()
_ClassPowerMaxSubject:Unsubscribe()
end
-- Publish the changes
_ClassPowerRefresh:OnNext("any") -- For all, but other unit's indicator will be disabled and hide
_ClassPowerSubject:OnNext("player") -- For player only
_ClassPowerMaxSubject:OnNext("player")
end
__Static__() __AutoCache__()
function Wow.ClassPower()
if _PlayerClass == "DEATHKNIGHT" then
-- A simple total rune as basic features
return Wow.FromUnitEvent(_ClassPowerSubject):Next():Map(function(unit) local count = 0 for i = 1, 6 do local _, _, ready = GetRuneCooldown(i) if ready then count = count + 1 end end return count end)
elseif _PlayerClass == "DEMONHUNTER" then
return Wow.FromUnitEvent(_ClassPowerSubject):Next():Map(function(unit) return _ClassPowerType and min((select(3, FindAuraByName(SOULFRAGMENTNAME, "player", "PLAYER|HELPFUL"))) or 0, 5) or 0 end)
elseif _PlayerClass == "MONK" then
return Wow.FromUnitEvent(_ClassPowerSubject):Next():Map(function(unit) return (_ClassPowerType == STAGGER and UnitStagger(unit) or _ClassPowerType and UnitPower(unit, _ClassPowerType)) or 0 end)
else
return Wow.FromUnitEvent(_ClassPowerSubject):Next():Map(function(unit) return _ClassPowerType and UnitPower(unit, _ClassPowerType) or 0 end)
end
end
__Static__() __AutoCache__()
function Wow.ClassPowerMax()
local minMax = { min = 0 }
if _PlayerClass == "DEATHKNIGHT" then
minMax.max = 6
return Wow.FromUnitEvent(_ClassPowerMaxSubject):Map(function(unit)
return minMax
end)
elseif _PlayerClass == "DEMONHUNTER" then
minMax.max = 5
-- Only track max 5 soul fragment
return Wow.FromUnitEvent(_ClassPowerMaxSubject):Map(function(unit)
return minMax
end)
elseif _PlayerClass == "MONK" then
return Wow.FromUnitEvent(_ClassPowerMaxSubject):Map(function(unit)
minMax.max = _ClassPowerType == STAGGER and UnitHealthMax(unit) or _ClassPowerType and UnitPowerMax(unit, _ClassPowerType) or 100
return minMax
end)
else
return Wow.FromUnitEvent(_ClassPowerMaxSubject):Map(function(unit)
minMax.max = _ClassPowerType and UnitPowerMax(unit, _ClassPowerType) or 100
return minMax
end)
end
end
__Static__() __AutoCache__()
function Wow.ClassPowerColor()
if _PlayerClass == "MONK" then
local STAGGER_YELLOW_TRANSITION = _G.STAGGER_YELLOW_TRANSITION
local STAGGER_RED_TRANSITION = _G.STAGGER_RED_TRANSITION
return Wow.FromUnitEvent(_ClassPowerSubject):Map(function(unit)
if _ClassPowerType and UnitIsUnit(unit, "player") then
if _ClassPowerType == STAGGER then
local curr = UnitStagger(unit)
local maxs = UnitHealthMax(unit)
if curr and maxs then
local pct = curr / max
if (pct >= STAGGER_RED_TRANSITION) then
return Color.RED
elseif (pct >= STAGGER_YELLOW_TRANSITION) then
return Color.YELLOW
else
return Color.GREEN
end
end
else
return Color[_ClassPowerToken]
end
end
return Color.DISABLED
end)
else
return Wow.FromUnitEvent(_ClassPowerRefresh):Map(function(unit)
return UnitIsUnit(unit, "player") and _ClassPowerType and Color[_ClassPowerToken] or Color.DISABLED
end)
end
end
__Static__() __AutoCache__()
function Wow.ClassPowerUsable()
return Wow.FromUnitEvent(_ClassPowerRefresh):Map(function(unit) return UnitIsUnit(unit, "player") and _ClassPowerType and true or false end)
end
__Static__() __AutoCache__()
function Wow.UnitPower(frequent)
return Wow.FromUnitEvent(frequent and "UNIT_POWER_FREQUENT" or "UNIT_POWER_UPDATE", "UNIT_MAXPOWER", "UNIT_DISPLAYPOWER", "UNIT_POWER_BAR_SHOW", "UNIT_POWER_BAR_HIDE")
:Next():Map(function(unit) return UnitPower(unit, (UnitPowerType(unit))) end)
end
__Static__() __AutoCache__()
function Wow.UnitPowerMax()
local minMax = { min = 0 }
return Wow.FromUnitEvent("UNIT_MAXPOWER", "UNIT_DISPLAYPOWER", "UNIT_POWER_BAR_SHOW", "UNIT_POWER_BAR_HIDE")
:Map(function(unit) minMax.max = UnitPowerMax(unit, (UnitPowerType(unit))) return minMax end)
end
__Static__() __AutoCache__()
function Wow.UnitPowerColor()
local scolor = Color(1, 1, 1)
return Wow.FromUnitEvent("UNIT_CONNECTION", "UNIT_DISPLAYPOWER", "UNIT_POWER_BAR_SHOW", "UNIT_POWER_BAR_HIDE")
:Map(function(unit)
if not UnitIsConnected(unit) then
scolor.r = 0.5
scolor.g = 0.5
scolor.b = 0.5
else
local ptype, ptoken, r, g, b = UnitPowerType(unit)
local color = ptoken and Color[ptoken]
if color then return color end
if r then
scolor.r = r
scolor.g = g
scolor.b = b
else
return Color.MANA
end
end
return scolor
end)
end
__Static__() __AutoCache__()
function Wow.UnitMana()
local MANA = _G.Enum.PowerType.Mana
return Wow.FromUnitEvent("UNIT_POWER_UPDATE", "UNIT_MAXPOWER", "UNIT_DISPLAYPOWER", "UNIT_POWER_BAR_SHOW", "UNIT_POWER_BAR_HIDE")
:Map(function(unit) return UnitPower(unit, MANA) end)
end
__Static__() __AutoCache__()
function Wow.UnitManaMax()
local MANA = _G.Enum.PowerType.Mana
local minMax = { min = 0 }
return Wow.FromUnitEvent("UNIT_MAXPOWER", "UNIT_DISPLAYPOWER", "UNIT_POWER_BAR_SHOW", "UNIT_POWER_BAR_HIDE")
:Map(function(unit) minMax.max = UnitPowerMax(unit, MANA) return minMax end)
end
__Static__() __AutoCache__()
function Wow.UnitManaVisible()
local MANA = _G.Enum.PowerType.Mana
return Wow.FromUnitEvent("UNIT_MAXPOWER", "UNIT_DISPLAYPOWER", "UNIT_POWER_BAR_SHOW", "UNIT_POWER_BAR_HIDE")
:Map(function(unit) return UnitPowerType(unit) ~= MANA and (UnitPowerMax(unit, MANA) or 0) > 0 end)
end