diff --git a/assets/Border.tga b/assets/Border.tga
new file mode 100644
index 0000000..c6c8f4f
Binary files /dev/null and b/assets/Border.tga differ
diff --git a/assets/Comfortaa-Bold.ttf b/assets/Comfortaa-Bold.ttf
new file mode 100644
index 0000000..3068e16
Binary files /dev/null and b/assets/Comfortaa-Bold.ttf differ
diff --git a/assets/PTSans-Bold.ttf b/assets/PTSans-Bold.ttf
new file mode 100644
index 0000000..d0265b2
Binary files /dev/null and b/assets/PTSans-Bold.ttf differ
diff --git a/assets/PTSans-License.txt b/assets/PTSans-License.txt
new file mode 100644
index 0000000..759ea1b
--- /dev/null
+++ b/assets/PTSans-License.txt
@@ -0,0 +1,93 @@
+Copyright (c) 2010, ParaType Ltd. (http://www.paratype.com/public),
+with Reserved Font Names "PT Sans", "PT Serif" and "ParaType".
+
+This Font Software is licensed under the Open Font License, Version 1.1
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/assets/TargetOfTarget.blp b/assets/TargetOfTarget.blp
new file mode 100644
index 0000000..9f4c2c0
Binary files /dev/null and b/assets/TargetOfTarget.blp differ
diff --git a/assets/TargetOfTargetSquare.tga b/assets/TargetOfTargetSquare.tga
new file mode 100644
index 0000000..c978699
Binary files /dev/null and b/assets/TargetOfTargetSquare.tga differ
diff --git a/assets/UI-CastingBar-Border-Small.blp b/assets/UI-CastingBar-Border-Small.blp
new file mode 100644
index 0000000..3a593c7
Binary files /dev/null and b/assets/UI-CastingBar-Border-Small.blp differ
diff --git a/assets/UI-CastingBar-Flash-Small.blp b/assets/UI-CastingBar-Flash-Small.blp
new file mode 100644
index 0000000..6cea8fa
Binary files /dev/null and b/assets/UI-CastingBar-Flash-Small.blp differ
diff --git a/assets/UI-CastingBar-Small-Shield.blp b/assets/UI-CastingBar-Small-Shield.blp
new file mode 100644
index 0000000..1cba08f
Binary files /dev/null and b/assets/UI-CastingBar-Small-Shield.blp differ
diff --git a/assets/UI-Classes-Circles.blp b/assets/UI-Classes-Circles.blp
new file mode 100644
index 0000000..b08b0a6
Binary files /dev/null and b/assets/UI-Classes-Circles.blp differ
diff --git a/assets/UI-PARTYFRAME-FLASH.blp b/assets/UI-PARTYFRAME-FLASH.blp
new file mode 100644
index 0000000..50b3d57
Binary files /dev/null and b/assets/UI-PARTYFRAME-FLASH.blp differ
diff --git a/assets/UI-PartyFrame.blp b/assets/UI-PartyFrame.blp
new file mode 100644
index 0000000..110bf6c
Binary files /dev/null and b/assets/UI-PartyFrame.blp differ
diff --git a/assets/UI-Player-Status.blp b/assets/UI-Player-Status.blp
new file mode 100644
index 0000000..3580307
Binary files /dev/null and b/assets/UI-Player-Status.blp differ
diff --git a/assets/UI-TargetingEliteFrame.blp b/assets/UI-TargetingEliteFrame.blp
new file mode 100644
index 0000000..e67c06e
Binary files /dev/null and b/assets/UI-TargetingEliteFrame.blp differ
diff --git a/assets/UI-TargetingFrame.blp b/assets/UI-TargetingFrame.blp
new file mode 100644
index 0000000..61d99ab
Binary files /dev/null and b/assets/UI-TargetingFrame.blp differ
diff --git a/assets/beige.tga b/assets/beige.tga
new file mode 100644
index 0000000..5ce5372
Binary files /dev/null and b/assets/beige.tga differ
diff --git a/assets/default.tga b/assets/default.tga
new file mode 100644
index 0000000..b2e19a8
Binary files /dev/null and b/assets/default.tga differ
diff --git a/assets/dualwield01.tga b/assets/dualwield01.tga
new file mode 100644
index 0000000..d956ed3
Binary files /dev/null and b/assets/dualwield01.tga differ
diff --git a/assets/fontAtari.ttf b/assets/fontAtari.ttf
new file mode 100644
index 0000000..a111c5d
Binary files /dev/null and b/assets/fontAtari.ttf differ
diff --git a/assets/normal.ttf b/assets/normal.ttf
new file mode 100644
index 0000000..1ca255c
Binary files /dev/null and b/assets/normal.ttf differ
diff --git a/assets/units_trinket_border.blp b/assets/units_trinket_border.blp
new file mode 100644
index 0000000..095d107
Binary files /dev/null and b/assets/units_trinket_border.blp differ
diff --git a/core/anchor.lua b/core/anchor.lua
new file mode 100644
index 0000000..af04b35
--- /dev/null
+++ b/core/anchor.lua
@@ -0,0 +1,274 @@
+local addon = select(2,...);
+local event_ = addon:package()
+
+-- /* lua lib */
+local unpack = unpack
+local pairs = pairs
+local wipe = wipe
+local print = print
+local table = addon.table
+
+-- /* WoW APIs */
+local GetEffectiveScale = GetEffectiveScale
+local StaticPopup_Show = StaticPopup_Show
+local InCombatLockdown = InCombatLockdown
+local UIErrorsFrame = UIErrorsFrame
+local UIParent = UIParent
+local CreateFrame = CreateFrame
+
+-- /* consts */
+local CANCEL = CANCEL
+local LOCK = LOCK
+local OKAY = OKAY
+local RESET = RESET
+local ERR_NOT_IN_COMBAT = ERR_NOT_IN_COMBAT
+local istoggle = false
+local secure = true
+
+-- /* create screen shade */
+local shadeFrame = CreateFrame('Frame')
+local shadeTexture = shadeFrame:CreateTexture(nil, 'BACKGROUND', nil, -8)
+shadeFrame:SetFrameStrata('BACKGROUND')
+shadeFrame:SetWidth(GetScreenWidth() * UIParent:GetEffectiveScale())
+shadeFrame:SetHeight(GetScreenHeight() * UIParent:GetEffectiveScale())
+shadeTexture:SetAllPoints(shadeFrame)
+shadeFrame:SetPoint('CENTER', 0, 0)
+
+-- /* create screen crosshair */
+local crosshairFrameNS = CreateFrame('Frame')
+local crosshairTextureNS = crosshairFrameNS:CreateTexture(nil, 'TOOLTIP')
+crosshairFrameNS:SetFrameStrata('TOOLTIP')
+crosshairFrameNS:SetWidth(1)
+crosshairFrameNS:SetHeight(GetScreenHeight() * UIParent:GetEffectiveScale())
+crosshairTextureNS:SetAllPoints(crosshairFrameNS)
+crosshairTextureNS:SetTexture(0, 0, 0, 1)
+
+local crosshairFrameEW = CreateFrame('Frame')
+local crosshairTextureEW = crosshairFrameEW:CreateTexture(nil, 'TOOLTIP')
+crosshairFrameEW:SetFrameStrata('TOOLTIP')
+crosshairFrameEW:SetWidth(GetScreenWidth() * UIParent:GetEffectiveScale())
+crosshairFrameEW:SetHeight(1)
+crosshairTextureEW:SetAllPoints(crosshairFrameEW)
+crosshairTextureEW:SetTexture(0, 0, 0, 1)
+
+-- /* setup screen align */
+local function clear()
+ shadeFrame:Hide()
+ crosshairFrameNS:Hide()
+ crosshairFrameEW:Hide()
+end
+
+local function shade(r, g, b, a)
+ shadeTexture:SetTexture(r, g, b, a)
+ shadeFrame:Show()
+end
+
+local function follow()
+ local mouseX, mouseY = GetCursorPosition()
+ crosshairFrameNS:SetPoint('TOPLEFT', mouseX, 0)
+ crosshairFrameEW:SetPoint('BOTTOMLEFT', 0, mouseY)
+end
+
+local function crosshair(arg)
+ local mouseX, mouseY = GetCursorPosition()
+ crosshairFrameNS:SetPoint('TOPLEFT', mouseX, 0)
+ crosshairFrameEW:SetPoint('BOTTOMLEFT', 0, mouseY)
+ crosshairFrameNS:Show()
+ crosshairFrameEW:Show()
+ if (arg == 'follow') then
+ crosshairFrameNS:SetScript('OnUpdate', follow)
+ else
+ crosshairFrameNS:SetScript('OnUpdate', nil)
+ end
+end
+
+-- /* create mover elements */
+local anchorlist, backup, f = {}, {}
+local function create_anchor(self, text, value, anchor, width, height)
+ local key = 'elements_anchor'
+ if not _appdata[key] then _appdata[key] = {} end
+
+ -- setup frame
+ local mover = CreateFrame('Frame', nil, UIParent)
+ mover:SetWidth(width or self:GetWidth())
+ mover:SetHeight(height or self:GetHeight())
+ mover:SetBackdrop(addon.backdrop)
+ mover:SetBackdropColor(0.67058823529, 0.80392156862, 0.93725490196, .65)
+ mover:SetBackdropBorderColor(0, 1, .62, .5)
+
+ -- setup name
+ mover.text = mover:CreateFontString(nil, 'OVERLAY', 'pUiFont')
+ mover.text:SetPoint('CENTER', 0, 2)
+ mover.text:SetTextColor(1, .8, 0)
+ mover.text:SetText(text)
+
+ tinsert(anchorlist, mover)
+
+ if not _appdata[key][value] then
+ mover:SetPoint(unpack(anchor))
+ else
+ mover:SetPoint(unpack(_appdata[key][value]))
+ end
+ mover:EnableMouse(true)
+ mover:SetMovable(true)
+ mover:SetClampedToScreen(true)
+ mover:SetFrameStrata('HIGH')
+ mover:RegisterForDrag('LeftButton')
+ mover:SetScript('OnDragStart', function() mover:StartMoving() end)
+ mover:SetScript('OnDragStop', function()
+ mover:StopMovingOrSizing()
+ local orig, _, tar, x, y = mover:GetPoint()
+ _appdata[key][value] = {orig, 'UIParent', tar, x, y}
+ end)
+ mover:Hide()
+
+ self:ClearAllPoints()
+ self:SetPoint('CENTER', mover, 'CENTER')
+
+ return mover
+end
+
+-- /* create mover options */
+local function unlock_elements()
+ for i = 1, #anchorlist do
+ local mover = anchorlist[i]
+ if (not mover:IsShown()) then
+ mover:Show()
+ end
+ end
+ table.copy(_appdata['elements_anchor'], backup)
+ f:Show()
+end
+
+local function lock_elements()
+ for i = 1, #anchorlist do
+ local mover = anchorlist[i]
+ mover:Hide()
+ end
+
+ f:Hide()
+ istoggle = false
+ clear()
+end
+
+-- /* setup mover settings */
+StaticPopupDialogs['PRETTY_MOVER_RESET'] = {
+ text = 'Are you sure to reset all frames position?',
+ button1 = OKAY,
+ button2 = CANCEL,
+ OnAccept = function()
+ wipe(_appdata['elements_anchor'])
+ ReloadUI()
+ end,
+ timeout = 0,
+ whileDead = 1,
+ hideOnEscape = true,
+ preferredIndex = 5,
+}
+
+StaticPopupDialogs['PRETTY_MOVER_CANCEL'] = {
+ text = 'Are you sure to reverse your positioning?',
+ button1 = OKAY,
+ button2 = CANCEL,
+ OnAccept = function()
+ table.copy(backup, _appdata['elements_anchor'])
+ ReloadUI()
+ end,
+ timeout = 0,
+ whileDead = 1,
+ hideOnEscape = true,
+ preferredIndex = 5,
+}
+
+-- /* create mover console */
+local function createconsole()
+ if f then return end
+
+ f = CreateFrame('Frame', nil, UIParent)
+ f:SetPoint('TOP', 0, -150)
+ f:SetSize(296, 65)
+ f:SetBackdrop(addon.backdrop)
+ f:SetBackdropColor(0, 0, 0, .7)
+ f:SetBackdropBorderColor(1, .71, 0, .4)
+ addon.console_anchor(f)
+
+ f.text = f:CreateFontString(nil, 'OVERLAY', 'pUiFont')
+ f.text:SetPoint('TOP', 0, -10)
+ f.text:SetText('Console')
+
+ -- setup buttons
+ local bu, text = {}, {LOCK, CANCEL, 'Grid', RESET}
+ for i = 1, 4 do
+ bu[i] = CreateFrame('Button', nil, f)
+ bu[i]:SetSize(70, 28)
+
+ if i==1 then
+ bu[i]:SetPoint('BOTTOMLEFT', 5, 5)
+ else
+ bu[i]:SetPoint('LEFT', bu[i-1], 'RIGHT', 2, 0)
+ end
+
+ bu.text = bu[i]:CreateFontString(nil, 'OVERLAY')
+ bu.text:SetFontObject('pUiFont')
+ bu.text:SetPoint('TOP', 0, -10)
+ bu.text:SetText(text[i])
+ end
+
+ -- create lock button
+ bu[1]:SetScript('OnClick', lock_elements)
+
+ -- create cancel button
+ bu[2]:SetScript('OnClick', function()
+ StaticPopup_Show('PRETTY_MOVER_CANCEL')
+ end)
+
+ -- create grids button
+ bu[3]:SetScript('OnClick', function()
+ if not istoggle then
+ istoggle = true
+ shade(1, 1, 1, .85)
+ crosshairTextureNS:SetTexture(0, 0, 0, 1)
+ crosshairTextureEW:SetTexture(0, 0, 0, 1)
+ crosshair('follow')
+ else
+ istoggle = false
+ clear()
+ end
+ end)
+
+ -- create reset button
+ bu[4]:SetScript('OnClick', function()
+ StaticPopup_Show('PRETTY_MOVER_RESET')
+ end)
+end
+
+-- /* create secure toggle function */
+function event_:PLAYER_REGEN_DISABLED()
+ addon:toggle_anchors(true)
+end
+
+function addon:toggle_anchors(forcelock)
+ if secure and not forcelock then
+ if self:taint() then
+ return UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT)
+ end
+ event_:RegisterEvent('PLAYER_REGEN_DISABLED')
+ createconsole()
+ unlock_elements()
+ elseif not secure then
+ if f and f:IsShown() then
+ lock_elements()
+ end
+ event_:UnregisterEvent('PLAYER_REGEN_DISABLED')
+ end
+
+ secure = not secure
+ return secure
+end
+
+SlashCmdList['PRETTY_MOVER'] = function(...)
+ addon:toggle_anchors()
+end
+SLASH_PRETTY_MOVER1 = '/mover'
+
+addon.c_anchor = create_anchor
\ No newline at end of file
diff --git a/core/config.lua b/core/config.lua
new file mode 100644
index 0000000..cde8a06
--- /dev/null
+++ b/core/config.lua
@@ -0,0 +1,155 @@
+local addon = select(2,...);
+local path = [[Interface\AddOns\pw_unitframes\assets\]]
+
+--[[
+/**
+ * general config
+ * default settings of pretty light UF
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local config = {
+
+ -- general settings:
+ global = {
+ classportraits = true, -- enable portraits by class
+ prettyportraits = true, -- display custom portraits
+ combaticon = true, -- display combat state
+ framecolors = {.22, .22, .22, 1}, -- main colors theme of frames
+ castbar_scale = 1.2, -- castbar scale
+ castbar_offset = 2, -- castbar offset by x-axis
+ FFA = true, -- show FFA status icon for all frames
+ },
+
+ -- buffs & debuffs:
+ auras = {
+ -- size:
+ aura_size = 26, -- aura size
+ minscale = .5, -- minimum scale we want to show cooldown counts at, anything below this will be hidden
+ minduration = 3, -- minimum duration to show cooldown text
+ icon_size = 20, -- normal size for an icon (don't change this)
+ font_size = 14, -- base font size
+ threshold = 6.5, -- last seconds
+ duration_color = {1, .7, 0}, -- text color of duration > threshold
+ threshold_color = {1, 0, 0}, -- text color of duration < threshold
+ buffs_scale = 1.16, -- buffs scale
+ debuffs_scale = 1.16, -- debuffs scale
+ -- position:
+ start_x = 7, -- auras start position by x-axis (buffs)
+ start_y = 26, -- auras start position by y-axis (buffs)
+ offset_x = 1.3, -- spacing between auras by x-axis
+ offset_y = 3, -- spacing between auras by y-axis
+ numrow = 4, -- how many auras to show in one row
+ numrowtot = 3, -- how many auras to show in one (first) row on target if target has target of target (whut?)
+ debuffs_vertical = true, -- vertical growth (from bottom to top)
+ debuffs_offset_y = 5, -- vertical growth offset between debuffs
+ e_debuffs_offset_y = 30, -- vertical growth offset between debuffs on enemy frame
+ -- maximum number of buffs/debuffs:
+ target_maxbuffs = 12, -- max buffs show, recommended to set value between 8-16
+ target_maxdebuffs = 12, -- default: 16, recommended to set value between 8-16
+ -- misc:
+ dispelable = true, -- glowing dispelable buffs
+ },
+
+ -- player frame:
+ player = {
+ scale = 1.08, -- player scale
+ elite = true, -- make yourself an elite
+ level = false, -- show player level
+ leadericon = false, -- show player leader icon
+ name = true, -- show player name
+ petname = false, -- show pet name
+ runescale = 1, -- deathknight rune orbs scale
+ },
+
+ -- target frame:
+ target = {
+ scale = 1.08, -- target scale
+ level = false, -- show target level
+ leadericon = false, -- show target leader icon
+ pvpicon = true, -- show target pvp icon
+ name = true, -- show target name
+ threatscale = 1, -- threat aggro scale
+ threatplayer = true, -- show threat on player frame
+ },
+
+ -- focus frame:
+ focus = {
+ scale = 1, -- focus scale
+ fullsize = 1, -- cvar fullsize 0 or 1
+ level = false, -- show focus level
+ leadericon = false, -- leader icon
+ name = true, -- show focus name
+ threatscale = 1, -- threat aggro scale
+ fk = true, -- enable hotkey macro mode
+ modbutton = 'shift', -- shift, alt, ctrl
+ mousebutton = '1', -- 1 = left, 2 = right, 3 = middle, 4 and 5 = thumb buttons if there are any
+ },
+
+ -- arena frame:
+ arena = {
+ enable = true, -- show arena enemys frames
+ scale = 1.6, -- arena scale
+ name = true, -- show arena enemys name
+ trinkets = true, -- show arena trinkets
+ trinket_announce = true, -- enable trinket announce
+ announce_chat = 'PARTY', -- trinket announce chat type
+ -- text announce:
+ text_trinket = 'Use Trinket!', -- Enemyname (Class): Use Trinket!
+ text_wotf = 'Use WotF!',
+ textstring_size = 8, -- text font size of health and mana bars
+ textcast_size = 7, -- text font size of castbar spell name
+ },
+
+ -- party frames:
+ party = {
+ enable = true, -- show party member frames
+ scale = 1.26, -- party members scale
+ castbar_scale = 1.07, -- castbar scale
+ showbuffs = true, -- show party buffs
+ maxbuffs = 4, -- how many buffs to show
+ },
+
+ -- target of targets:
+ targettarget = {
+ scale = 1.16, -- scale for target of target and focus target
+ squarestyle = false, -- enable square style for target of targets
+ partytargets = true, -- show party targets
+ arenatargets = true, -- show arena targets
+ partytarget_scale = 0.9, -- party target scale
+ arenatarget_scale = 0.6, -- arena target scale
+ },
+
+ -- default and backup for restore:
+ position = {
+ ['runebar'] = {'TOP', PlayerFrameManaBar, 'BOTTOM', 12, -10},
+ },
+
+ media = {
+ -- assets:
+ statusbar = path..'beige.tga', -- main statusbar texture theme
+ targetFrame = path..'UI-TargetingFrame', -- player, target, focus texture
+ targetElite = path..'UI-TargetingEliteFrame', -- elite texture
+ targetTargetNormal = path..'TargetOfTarget', -- target of target normal
+ targetTargetSquare = path..'TargetOfTargetSquare.tga', -- target of target square style
+ partyFrame = path..'UI-PartyFrame', -- party frame texture
+ border = path..'Border.tga', -- main auras border texture
+ trinket_border = path..'units_trinket_border', -- trinket border
+ dualweild = path..'dualwield01.tga', -- combat icon
+ portraits = path..'UI-Classes-Circles', -- my custom portraits ^__^
+ castborder = path..'UI-CastingBar-Border-Small', -- main castbar border texture
+ castflash = path..'UI-CastingBar-Flash-Small', -- main castbar flash texture
+ castshield = path..'UI-CastingBar-Small-Shield', -- castbar non-interrupt texture
+ -- font:
+ font = path..'normal.ttf', -- main font theme
+ font_style = '', -- OUTLINE
+ font_size = 14, -- font size
+ font_offset = 1, -- font shadow offset
+ },
+}
+
+addon.config = config
\ No newline at end of file
diff --git a/core/core.lua b/core/core.lua
new file mode 100644
index 0000000..9f8d9f6
--- /dev/null
+++ b/core/core.lua
@@ -0,0 +1,81 @@
+--[[
+/**
+ * compatibility core functions
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local select = select
+local addon = select(2,...);
+
+local UnitAffectingCombat = UnitAffectingCombat
+local InCombatLockdown = InCombatLockdown
+
+-- /* init SavedVariables */
+local addon_config = {}
+_appdata = addon_config
+
+-- /* implicit compatibility */
+local texcoord = {.08, .92, .08, .92}
+local backdrop = {bgFile = [[Interface\Buttons\WHITE8x8]],
+edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], edgeSize = 14,
+insets = {left = 2.6, right = 2.6, top = 2.6, bottom = 2.6}}
+local noop = function() return end
+local eject = function(obj)
+ if obj.UnregisterAllEvents then
+ obj:UnregisterAllEvents()
+ end
+ obj.Show = noop
+ obj:Hide()
+end
+
+-- /* for avoid taint */
+local function taintable()
+ return (InCombatLockdown() or (UnitAffectingCombat('player') or UnitAffectingCombat('pet')))
+end
+
+-- /* checks if the texture we are trying to set it */
+local function check_texture(arg1, arg2)
+ if arg1:GetTexture() ~= arg2 then arg1:SetTexture(arg2) end
+end
+
+-- /* create movable frame */
+local function console_anchor(parent, saved, shifthk)
+ local frame = parent or self
+ frame:SetMovable(true)
+ frame:SetUserPlaced(true)
+ frame:SetClampedToScreen(true)
+ frame:EnableMouse(true)
+ frame:RegisterForDrag('LeftButton')
+ frame:SetScript('OnDragStart', function()
+ if shifthk and not IsShiftKeyDown() then return end
+ frame:StartMoving()
+ end)
+ frame:SetScript('OnDragStop', function()
+ frame:StopMovingOrSizing()
+ if saved then
+ local orig, _, tar, x, y = frame:GetPoint()
+ _appdata['elements_anchor'][frame:GetName()] = {orig, 'UIParent', tar, x, y}
+ end
+ end)
+end
+
+-- /* create main font */
+local pUiFont = CreateFont('pUiFont')
+pUiFont:SetFont([[Interface\AddOns\pw_unitframes\assets\PTSans-Bold.ttf]], 14)
+pUiFont:SetShadowColor(0, 0, 0, 1)
+pUiFont:SetShadowOffset(1,-1)
+local pUiFont_Auras = CreateFont('pUiFont_Auras')
+pUiFont_Auras:SetFont(pUiFont:GetFont(), 10, 'OUTLINE')
+
+-- /* callback */
+addon.texcoord = texcoord
+addon.noop = noop
+addon.taint = taintable
+addon.eject = eject
+addon.backdrop = backdrop
+addon.check_texture = check_texture
+addon.console_anchor = console_anchor
\ No newline at end of file
diff --git a/core/core.xml b/core/core.xml
new file mode 100644
index 0000000..030d948
--- /dev/null
+++ b/core/core.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/event.lua b/core/event.lua
new file mode 100644
index 0000000..030ea84
--- /dev/null
+++ b/core/event.lua
@@ -0,0 +1,75 @@
+local addon = select(2,...)
+
+local next = next
+local pcall = pcall
+local rawset = rawset
+
+--[[
+/**
+ * event handler
+ * usage: E = addon:package()
+ * function E:ADDON_LOADED()
+ * respond to ADDON_LOADED event
+ * end
+ *
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x, Eve(semlib)
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local frame, callbacks, _, prototype = CreateFrame('Frame'), {}, ...;
+
+local function RegisterEvent(module, event, func)
+ if func then
+ rawset(module, event, func)
+ end
+ if (not callbacks[event]) then
+ callbacks[event] = {}
+ end
+ callbacks[event][module] = true
+ if strmatch(event, '^[%u_]+$') then
+ pcall(function() return frame:RegisterEvent(event) end)
+ end
+ return module
+end
+
+local function UnregisterEvent(module, event)
+ if callbacks[event] then callbacks[event][module] = nil
+ if (not next(callbacks[event]) and strmatch(event,'^[%u_]+$')) then -- don't unregister unless the event table is empty
+ frame:UnregisterEvent(event)
+ end
+ end
+ return module
+end
+
+local function FireEvent(_, event, ...)
+ if callbacks[event] then
+ for module in pairs(callbacks[event]) do
+ module[event](module, ...)
+ end
+ end
+end
+
+local event_module = {
+ __newindex = RegisterEvent, -- function E:ADDON_LOADED() end
+ __call = FireEvent, -- E('CallBack', ...) -- Fire a callback across ALL modules
+ __index = {
+ RegisterEvent = RegisterEvent, -- E:RegisterEvent('ADDON_LOADED', func)
+ UnregisterEvent = UnregisterEvent, -- E:UnregisterEvent('ADDON_LOADED')
+ FireEvent = FireEvent, -- E:FireEvent('CallBack', ...)
+ },
+}
+
+prototype.package = setmetatable({}, {
+ __call = function(callback_event)
+ local module = setmetatable({}, event_module)
+ callback_event[#callback_event+1] = module
+ return module
+ end,
+})
+
+frame:SetScript('OnEvent', FireEvent)
+
+-- setmetatable({}, {__index = function(self, event) self[event] = {} return self[event] end})
\ No newline at end of file
diff --git a/core/preinit.lua b/core/preinit.lua
new file mode 100644
index 0000000..a86d939
--- /dev/null
+++ b/core/preinit.lua
@@ -0,0 +1,13 @@
+local addonName, addon = ...;
+
+--[[
+/**
+ * preinit addon
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+_G[addonName] = addon
\ No newline at end of file
diff --git a/core/table.lua b/core/table.lua
new file mode 100644
index 0000000..2787dd7
--- /dev/null
+++ b/core/table.lua
@@ -0,0 +1,45 @@
+local addon = select(2,...);
+
+local select = select
+local pairs = pairs
+local next = next
+local type = type
+
+--[[
+/**
+ * table utils
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local function table_assign(src, pool)
+ src = src or {}
+ pool = pool or {}
+ for k,v in pairs(src) do
+ if type(v) == 'table' then
+ if pool[k] == nil then
+ pool[k] = {}
+ end
+ else
+ if pool[k] == nil then
+ pool[k] = src[k]
+ end
+ end
+ end
+end
+
+local function table_copy(src, pool)
+ pool = pool or {}
+ for k,v in pairs(src) do
+ pool[k] = v
+ end
+ return pool
+end
+
+addon.table = setmetatable({
+ assign_over = table_assign,
+ copy = table_copy,
+},{__index = table})
\ No newline at end of file
diff --git a/modules/arena.lua b/modules/arena.lua
new file mode 100644
index 0000000..8d4d7da
--- /dev/null
+++ b/modules/arena.lua
@@ -0,0 +1,130 @@
+local addon = select(2,...);
+local config = addon.config;
+local uconfig, src = config.arena, config.media;
+if not uconfig.enable then return end;
+
+--[[
+/**
+ * unit: arena
+ * contains style and functions of arena frame
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local _G = _G
+local unpack = unpack
+
+-- /* WoW APIs */
+local hooksecurefunc = hooksecurefunc
+
+-- /* consts */
+local MAX_ARENA_ENEMIES = MAX_ARENA_ENEMIES or 5
+local texcoord = addon.texcoord
+local noop = addon.noop
+
+-- /* create arena style */
+local function frame_style_arena()
+ local castbar;
+ for i = 1, MAX_ARENA_ENEMIES do
+ local frame = _G['ArenaEnemyFrame'..i];
+ ArenaEnemyFrames:SetScale(uconfig.scale*1.3)
+
+ -- main style setup:
+ frame.texture = _G[frame:GetName()..'Texture']
+ frame.texture:ClearAllPoints();
+ frame.texture:SetSize(120, 52);
+ frame.texture:SetPoint('TOPLEFT', frame, 'TOPLEFT', 0, 5);
+ frame.texture:SetTexture(src.targetFrame);
+ frame.texture:SetVertexColor(unpack(config.global.framecolors))
+ frame.texture:SetTexCoord(0.09375, 1.0, 0, 0.78125)
+
+ frame.pet = _G[frame:GetName()..'PetFrame']
+ frame.pet:SetScale(.74)
+ frame.pet:ClearAllPoints();
+ frame.pet:SetPoint('TOPLEFT', frame, 'TOPLEFT', 2, -38)
+
+ frame.pettexture = _G[frame.pet:GetName()..'Texture']
+ frame.pettexture:SetVertexColor(unpack(config.global.framecolors))
+
+ frame.bg = _G[frame:GetName()..'Background']
+ frame.bg:SetSize(62, 20)
+ frame.bg:SetPoint('TOPLEFT', 3, -8)
+
+ frame.healthbar:SetSize(62, 14);
+ frame.healthbar:SetPoint('TOPLEFT', frame, 'TOPLEFT', 3, -8);
+ frame.manabar:SetSize(62, 6);
+ frame.manabar:SetPoint('TOPLEFT', frame.healthbar, 'TOPLEFT', 0, -14);
+
+ frame.name:ClearAllPoints();
+ frame.name:SetPoint('BOTTOM', frame.healthbar, 'TOP', 0, 4);
+ frame.name:SetFont(src.font, src.font_size -6)
+ frame.name:SetShadowColor(0, 0, 0, 1)
+ frame.name:SetShadowOffset(.6, -.6)
+ if not uconfig.name then frame.name:SetAlpha(0) end
+
+ frame.flash = _G[frame:GetName()..'Flash']
+ frame.flash:Hide()
+
+ frame.healthbar.TextString:ClearAllPoints()
+ frame.healthbar.TextString:SetPoint('CENTER', frame.healthbar)
+ frame.healthbar.TextString.SetPoint = noop
+ frame.healthbar.TextString:SetFont(src.font, uconfig.textstring_size)
+ frame.healthbar.TextString:SetShadowColor(0, 0, 0, 1)
+ frame.healthbar.TextString:SetShadowOffset(.6, -.6)
+
+ frame.manabar.TextString:ClearAllPoints()
+ frame.manabar.TextString:SetPoint('CENTER', frame.manabar)
+ frame.manabar.TextString.SetPoint = noop
+ frame.manabar.TextString:SetFont(src.font, uconfig.textstring_size)
+ frame.manabar.TextString:SetShadowColor(0, 0, 0, 1)
+ frame.manabar.TextString:SetShadowOffset(.6, -.6)
+
+ frame.classPortrait:SetSize(34, 34);
+ frame.classPortrait:ClearAllPoints();
+ frame.classPortrait:SetPoint('RIGHT', frame, 'RIGHT', -4, -2);
+
+ -- castbar setup:
+ castbar = _G[frame:GetName()..'CastingBar']
+ castbar:SetSize(74, 6)
+ castbar.border = castbar:CreateTexture(nil,'OVERLAY')
+ castbar.border:SetSize(98, 28)
+ castbar.border:SetPoint('CENTER', castbar)
+ castbar.border:SetTexture(src.castborder)
+
+ castbar.flash = _G[castbar:GetName()..'Flash']
+ castbar.flash:SetSize(98, 28)
+ castbar.flash:ClearAllPoints()
+ castbar.flash:SetPoint('CENTER', castbar)
+ castbar.flash:SetTexture(src.castflash)
+
+ castbar.spark = _G[castbar:GetName()..'Spark']
+ castbar.spark:SetSize(14, 14)
+
+ castbar.icon = _G[castbar:GetName()..'Icon']
+ castbar.icon:SetSize(10, 10)
+ castbar.icon:SetTexCoord(unpack(texcoord))
+
+ castbar.icon.border = castbar:CreateTexture(nil,'OVERLAY')
+ castbar.icon.border:SetPoint('TOPRIGHT', castbar.icon, 2, 2)
+ castbar.icon.border:SetPoint('BOTTOMLEFT', castbar.icon, -2, -2)
+ castbar.icon.border:SetTexture(src.border)
+
+ castbar.text = _G[castbar:GetName()..'Text']
+ castbar.text:ClearAllPoints()
+ castbar.text:SetPoint('CENTER', castbar, 0, 1)
+ castbar.text:SetFont(src.font, uconfig.textcast_size)
+ castbar.text:SetShadowColor(0, 0, 0, 1)
+ castbar.text:SetShadowOffset(.6, -.6)
+
+ castbar.timer = castbar:CreateFontString(nil,'OVERLAY')
+ castbar.timer:SetPoint('RIGHT', castbar, 'RIGHT', -2, 0)
+ castbar.timer:SetFont(src.font, uconfig.textcast_size -1)
+ castbar.timer:SetShadowColor(0, 0, 0, 1)
+ castbar.timer:SetShadowOffset(.6, -.6)
+ castbar.update = 0.1
+ end
+end
+hooksecurefunc('Arena_LoadUI',frame_style_arena);
\ No newline at end of file
diff --git a/modules/elements/auras.lua b/modules/elements/auras.lua
new file mode 100644
index 0000000..9703091
--- /dev/null
+++ b/modules/elements/auras.lua
@@ -0,0 +1,467 @@
+local addon = select(2,...);
+local config = addon.config.auras;
+local src = addon.config.media;
+
+--[[
+/**
+ * element: auras
+ * contains style and functions of buffs and debuffs
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+-- /* lua lib */
+local _G = _G
+local select = select
+local unpack = unpack
+local strfind = string.find
+
+-- /* WoW APIs */
+local UnitCanAttack = UnitCanAttack
+local UnitIsFriend = UnitIsFriend
+local UnitIsEnemy = UnitIsEnemy
+local GetName = GetName
+local UnitBuff = UnitBuff
+local UnitDebuff = UnitDebuff
+local hooksecurefunc = hooksecurefunc
+
+-- /* locals */
+local __TargetFrame_UpdateAuras
+local __TargetFrame_UpdateAurasDispel
+local __UpdateAuraPositions
+local __UpdateBuffAnchor
+local __UpdateDebuffAnchor
+local __UpdateTargetAuraPositions
+local __RefreshDebuffs
+
+-- /* consts */
+local BUFFS_SCALE = config.buffs_scale
+local DEBUFFS_SCALE = config.debuffs_scale
+local MAX_TARGET_BUFFS = 32
+local MAX_TARGET_DEBUFFS = 16
+local AURA_START_X = config.start_x
+local AURA_START_Y = config.start_y
+local AURA_OFFSET_X = config.offset_x
+local AURA_OFFSET_Y = config.offset_y
+local LARGE_AURA_SIZE = config.aura_size
+local SMALL_AURA_SIZE = config.aura_size
+local AURA_ROW_WIDTH = 25 * config.numrow
+local NUM_TOT_AURA_ROWS = config.numrowtot
+local DEBUFFS_VERTICAL = config.debuffs_vertical
+local DEBUFFS_OFFSET_Y = config.debuffs_offset_y
+local E_DEBUFFS_OFFSET_Y = config.e_debuffs_offset_y
+local partybuffs = addon.config.party
+local MAX_PARTY_BUFFS = partybuffs.maxbuffs
+local MAX_PARTY_DEBUFFS = 4
+local texcoord = addon.texcoord
+local maxshows
+
+TargetFrame.maxBuffs = config.target_maxbuffs
+TargetFrame.maxDebuffs = config.target_maxdebuffs
+TargetFrame_UpdateAuras(TargetFrame)
+
+-- /* create anchor frame */
+local t_buffs = CreateFrame('Frame', 'TargetBuffs', UIParent)
+local t_debuffs = CreateFrame('Frame', 'TargetDebuffs', UIParent)
+t_buffs:SetSize(146, 28)
+t_debuffs:SetSize(146, 28)
+
+-- /* create dispelable buffs border */
+function __TargetFrame_UpdateAurasDispel(self)
+ for i=1, MAX_TARGET_BUFFS do
+ _, _, ic, _, debuffType = UnitBuff(self.unit, i)
+ if(ic and (not self.maxBuffs or i<=self.maxBuffs)) then
+ fic = _G[self:GetName()..'Buff'..i..'Icon']
+ fs = _G[self:GetName()..'Buff'..i..'Stealable']
+ fs:SetPoint('TOPRIGHT', fic, 3.4, 3.4)
+ fs:SetPoint('BOTTOMLEFT', fic, -3.4, -3.4)
+ fs:SetBlendMode('ADD')
+ fs:SetDrawLayer('OVERLAY', 7)
+ if(UnitIsEnemy(PlayerFrame.unit, self.unit) and debuffType == 'Magic') then fs:Show() else fs:Hide() end
+ end
+ end
+end
+
+-- /* create style buffs & debuffs */
+function __TargetFrame_UpdateAuras(self)
+ if maxshows then return end
+ local frame, frameName
+ local frameIcon, frameCount, frameCooldown
+ local name, rank, icon, count, debuffType
+ local color
+ local frameBorder
+ local selfName = _G[self:GetName()]
+ if selfName:IsShown() then
+ for i = 1, MAX_TARGET_BUFFS do
+ frame = _G[self:GetName()..'Buff'..i]
+ if (not frame) then break end
+ if (not frame.styled) then
+ frame:SetScale(BUFFS_SCALE)
+ frame.styled = true
+ -- icons:
+ frameIcon = _G[self:GetName()..'Buff'..i..'Icon']
+ if frameIcon then
+ frameIcon:SetPoint('TOPLEFT', frame, 'TOPLEFT', 2, -2)
+ frameIcon:SetPoint('BOTTOMRIGHT', frame, 'BOTTOMRIGHT', -2, 2)
+ frameIcon:SetTexCoord(unpack(texcoord))
+ end
+ -- border:
+ local bo = frame:CreateTexture(nil, 'OVERLAY')
+ if bo then
+ bo:SetTexture(src.border)
+ bo:SetPoint('TOPRIGHT', frameIcon, 3.4, 3.4)
+ bo:SetPoint('BOTTOMLEFT', frameIcon, -3.4, -3.4)
+ end
+ -- count:
+ frameCount = _G[self:GetName()..'Buff'..i..'Count']
+ if frameCount then
+ frameCount:SetJustifyH('CENTER')
+ frameCount:SetFontObject('pUiFont_Auras')
+ frameCount:SetDrawLayer('OVERLAY', 7)
+ end
+ -- cooldown:
+ frameCooldown = _G[self:GetName()..'Buff'..i..'Cooldown']
+ if frameCooldown then
+ frameCooldown:ClearAllPoints()
+ frameCooldown:SetPoint('TOPLEFT', frame, 1.5, -1.5)
+ frameCooldown:SetPoint('BOTTOMRIGHT', frame, -1.5, 1.5)
+ frameCooldown:SetFrameLevel(frame:GetFrameLevel())
+ end
+ if i == MAX_TARGET_BUFFS then
+ maxshows = true
+ end
+ end
+ end
+ for i = 1, MAX_TARGET_DEBUFFS do
+ frame = _G[self:GetName()..'Debuff'..i]
+ if (not frame) then break end
+ if (not frame.styled) then
+ frame:SetScale(DEBUFFS_SCALE)
+ frame.styled = true
+ -- icons:
+ frameIcon = _G[self:GetName()..'Debuff'..i..'Icon']
+ if frameIcon then
+ frameIcon:SetPoint('TOPLEFT', frame, 'TOPLEFT', 2, -2)
+ frameIcon:SetPoint('BOTTOMRIGHT', frame, 'BOTTOMRIGHT', -2, 2)
+ frameIcon:SetTexCoord(unpack(texcoord))
+ end
+ -- border:
+ local bo = frame:CreateTexture(nil, 'OVERLAY', nil, 7)
+ if bo then
+ bo:SetTexture(src.border)
+ bo:SetPoint('TOPRIGHT', frameIcon, 3.4, 3.4)
+ bo:SetPoint('BOTTOMLEFT', frameIcon, -3.4, -3.4)
+ end
+ -- color:
+ local debuffName = UnitDebuff(self.unit, i)
+ _,_,_,_, debuffType = UnitDebuff(self.unit, i)
+ if debuffName then
+ color = DebuffTypeColor[debuffType] or DebuffTypeColor.none
+ frameBorder = _G[self:GetName()..'Debuff'..i..'Border']
+ frameBorder:Hide()
+ if color then
+ bo:SetVertexColor(color.r, color.g, color.b)
+ end
+ else
+ bo:SetVertexColor(1, 1, 1, 1)
+ end
+ -- count:
+ frameCount = _G[self:GetName()..'Debuff'..i..'Count']
+ if frameCount then
+ frameCount:SetJustifyH('CENTER')
+ frameCount:SetFontObject('pUiFont_Auras')
+ frameCount:SetDrawLayer('OVERLAY', 7)
+ end
+ -- cooldown:
+ frameCooldown = _G[self:GetName()..'Debuff'..i..'Cooldown']
+ if frameCooldown then
+ frameCooldown:ClearAllPoints()
+ frameCooldown:SetPoint('TOPLEFT', frame, 1.5, -1.5)
+ frameCooldown:SetPoint('BOTTOMRIGHT', frame, -1.5, 1.5)
+ end
+ if i == MAX_TARGET_DEBUFFS then
+ maxshows = true
+ end
+ end
+ end
+ end
+end
+
+-- /* style auras position */
+function __UpdateAuraPositions(self, auraName, numAuras, numOppositeAuras, largeAuraList, updateFunc, maxRowWidth, offsetX, mirrorAurasVertically)
+ local size
+ local offsetY = AURA_OFFSET_Y
+ local offsetX = AURA_OFFSET_X
+ local rowWidth = 0
+ local firstBuffOnRow = 1
+ for i=1, numAuras do
+ if ( largeAuraList[i] ) then
+ size = LARGE_AURA_SIZE
+ offsetY = AURA_OFFSET_Y + AURA_OFFSET_Y
+ else
+ size = SMALL_AURA_SIZE
+ end
+ if ( i == 1 ) then
+ rowWidth = size
+ self.auraRows = self.auraRows + 1
+ else
+ rowWidth = rowWidth + size + offsetX
+ end
+ if ( rowWidth > maxRowWidth ) then
+ updateFunc(self, auraName, i, numOppositeAuras, firstBuffOnRow, size, offsetX, offsetY, mirrorAurasVertically)
+ rowWidth = size
+ self.auraRows = self.auraRows + 1
+ firstBuffOnRow = i
+ offsetY = AURA_OFFSET_Y
+ if ( self.auraRows > NUM_TOT_AURA_ROWS ) then
+ maxRowWidth = AURA_ROW_WIDTH;
+ end
+ else
+ updateFunc(self, auraName, i, numOppositeAuras, i - 1, size, offsetX, offsetY, mirrorAurasVertically)
+ end
+ end
+end
+
+function __UpdateBuffAnchor(self, buffName, index, numDebuffs, anchorIndex, size, offsetX, offsetY, mirrorVertically)
+ local point, relativePoint
+ local startY, auraOffsetY
+ if ( mirrorVertically ) then
+ point = 'BOTTOM'
+ relativePoint = 'TOP'
+ startY = -8
+ offsetY = -offsetY
+ auraOffsetY = -AURA_OFFSET_Y
+ else
+ point = 'TOP'
+ relativePoint = 'BOTTOM'
+ startY = AURA_START_Y
+ auraOffsetY = AURA_OFFSET_Y -- debuffs
+ end
+
+ local buff = _G[buffName..index]
+ if ( index == 1 ) then
+ -- if ( UnitIsFriend('player', self.unit) or numDebuffs == 0 ) then
+ -- unit is friendly or there are no debuffs...buffs start on top
+ if (self.unit == 'target') then
+ buff:ClearAllPoints()
+ buff:SetPoint(point..'LEFT', t_buffs, relativePoint..'LEFT', AURA_START_X, startY)
+ else
+ buff:SetPoint(point..'LEFT', self, relativePoint..'LEFT', AURA_START_X, startY)
+ end
+ -- else
+ -- unit is not friendly and we have debuffs...buffs start on bottom
+ -- buff:SetPoint(point..'LEFT', self.debuffs, relativePoint..'LEFT', 0, -offsetY)
+ -- end
+ self.buffs:SetPoint(point..'LEFT', buff, point..'LEFT', 0, 0)
+ self.buffs:SetPoint(relativePoint..'LEFT', buff, relativePoint..'LEFT', 0, -auraOffsetY)
+ self.spellbarAnchor = buff
+ elseif ( anchorIndex ~= (index-1) ) then
+ -- anchor index is not the previous index...must be a new row
+ buff:SetPoint(point..'LEFT', _G[buffName..anchorIndex], relativePoint..'LEFT', 0, -offsetY)
+ self.buffs:SetPoint(relativePoint..'LEFT', buff, relativePoint..'LEFT', 0, -auraOffsetY)
+ self.spellbarAnchor = buff
+ else
+ -- anchor index is the previous index
+ buff:SetPoint(point..'LEFT', _G[buffName..anchorIndex], point..'RIGHT', offsetX, 0)
+ end
+end
+
+function __UpdateDebuffAnchor(self, debuffName, index, numBuffs, anchorIndex, size, offsetX, offsetY, mirrorVertically)
+ local buff = _G[debuffName..index];
+ local isFriend = UnitIsFriend('player', self.unit);
+
+ -- For mirroring vertically
+ local point, relativePoint;
+ local startY, auraOffsetY;
+ mirrorVertically = DEBUFFS_VERTICAL
+ if ( mirrorVertically ) then
+ point = 'TOP'
+ relativePoint = 'TOP'
+ startY = AURA_START_Y
+ offsetY = -offsetY * DEBUFFS_OFFSET_Y
+ auraOffsetY = AURA_OFFSET_Y
+ else
+ point = 'TOP';
+ relativePoint = 'BOTTOM';
+ startY = AURA_START_Y;
+ auraOffsetY = AURA_OFFSET_Y;
+ end
+
+ if ( index == 1 ) then
+ -- if ( isFriend and numBuffs > 0 ) then
+ -- unit is friendly and there are buffs...debuffs start on bottom
+ if (self.unit == 'target') then
+ buff:SetPoint(point..'LEFT', t_debuffs, relativePoint..'LEFT', AURA_START_X, startY);
+ else
+ buff:SetPoint(point..'LEFT', self, relativePoint..'LEFT', AURA_START_X, startY);
+ end
+ -- else
+ -- unit is not friendly or there are no buffs...debuffs start on top
+ -- if (self.unit == 'target') then
+ -- buff:SetPoint(point..'LEFT', t_debuffs, relativePoint..'LEFT', AURA_START_X, startY);
+ -- else
+ -- buff:SetPoint(point..'LEFT', self, relativePoint..'LEFT', AURA_START_X, startY);
+ -- end
+ -- end
+ self.debuffs:SetPoint(point..'LEFT', buff, point..'LEFT', 0, 0);
+ self.debuffs:SetPoint(relativePoint..'LEFT', buff, relativePoint..'LEFT', 0, -auraOffsetY);
+ if ( ( isFriend ) or ( not isFriend and numBuffs == 0) ) then
+ self.spellbarAnchor = buff;
+ end
+ elseif ( anchorIndex ~= (index-1) ) then
+ -- anchor index is not the previous index...must be a new row
+ buff:SetPoint(point..'LEFT', _G[debuffName..anchorIndex], relativePoint..'LEFT', 0, E_DEBUFFS_OFFSET_Y);
+ self.debuffs:SetPoint(relativePoint..'LEFT', buff, relativePoint..'LEFT', 0, -auraOffsetY);
+ if ( ( isFriend ) or ( not isFriend and numBuffs == 0) ) then
+ self.spellbarAnchor = buff;
+ end
+ else
+ -- anchor index is the previous index
+ buff:SetPoint(point..'LEFT', _G[debuffName..(index-1)], point..'RIGHT', offsetX, 0);
+ end
+end
+
+function __UpdateTargetAuraPositions(self, auraName, numAuras, numOppositeAuras, largeAuraList, updateFunc, maxRowWidth, offsetX)
+ local AURA_OFFSET_Y = 3;
+ local LARGE_AURA_SIZE = 30;
+ local SMALL_AURA_SIZE = 21;
+ local size;
+ local offsetY = AURA_OFFSET_Y;
+ local rowWidth = 0;
+ local firstBuffOnRow = 1;
+ for i=1, numAuras do
+ if ( largeAuraList[i] ) then
+ size = LARGE_AURA_SIZE;
+ offsetY = AURA_OFFSET_Y + AURA_OFFSET_Y;
+ else
+ size = SMALL_AURA_SIZE;
+ end
+ if ( i == 1 ) then
+ rowWidth = size;
+ self.auraRows = self.auraRows + 1;
+ else
+ rowWidth = rowWidth + size + offsetX;
+ end
+ if ( rowWidth > AURA_ROW_WIDTH ) then
+ updateFunc(self, auraName, i, numOppositeAuras, firstBuffOnRow, size, offsetX, offsetY);
+ rowWidth = size;
+ self.auraRows = self.auraRows + 1;
+ firstBuffOnRow = i;
+ offsetY = AURA_OFFSET_Y;
+ else
+ updateFunc(self, auraName, i, numOppositeAuras, i - 1, size, offsetX, offsetY);
+ end
+ end;
+end;
+
+-- /* create auras for party */
+local function CreatePartyAuras()
+ local i;
+ for i = 1,4,1 do
+ local party = 'PartyMemberFrame'..i;
+ local buffs;
+ local debuffs;
+ local icn, bo, oldborder;
+ if (not party) then break end
+ -- buffs:
+ for j = 1, MAX_PARTY_BUFFS, 1 do
+ buffs = CreateFrame('Button', party..'Buff'..j, getglobal(party), 'PartyBuffFrameTemplate');
+ buffs:SetID(j);
+ buffs:SetScale(1.8)
+ buffs:ClearAllPoints();
+ if j == 1 then
+ buffs:SetPoint('TOPLEFT', party, 'TOPLEFT', 24, -20);
+ else
+ buffs:SetPoint('LEFT', party..'Buff'..j-1, 'RIGHT', -1, 0);
+ end;
+ if (not buffs.styled) then
+ -- icon:
+ icn = _G[buffs:GetName()..'Icon']
+ if icn then
+ icn:SetPoint('TOPLEFT', buffs, 'TOPLEFT', 2, -2)
+ icn:SetPoint('BOTTOMRIGHT', buffs, 'BOTTOMRIGHT', -2, 2)
+ icn:SetTexCoord(unpack(texcoord))
+ end
+ -- border:
+ bo = buffs:CreateTexture(nil, 'OVERLAY', nil, 7)
+ if bo then
+ bo:SetTexture(src.border)
+ bo:SetPoint('TOPRIGHT', icn, 1.6, 1.6)
+ bo:SetPoint('BOTTOMLEFT', icn, -1.6, -1.6)
+ end
+ buffs.styled = true
+ end
+ -- if j == MAX_PARTY_BUFFS then
+ -- maxshows = true
+ -- end
+ end
+
+ -- debuffs first row:
+ for k = 1, MAX_PARTY_DEBUFFS, 1 do
+ debuffs = getglobal(party..'Debuff'..k);
+ debuffs:SetScale(1.7)
+ debuffs:ClearAllPoints();
+ if (k == 1) then
+ debuffs:SetPoint('TOPLEFT', party, 'TOPLEFT', 70, -8)
+ else
+ debuffs:SetPoint('LEFT', _G[party..'Debuff'..(k-1)], 'RIGHT', -1, 0)
+ end
+ if (not debuffs.styled) then
+ -- icon:
+ icn = _G[debuffs:GetName()..'Icon']
+ if icn then
+ icn:SetPoint('TOPLEFT', debuffs, 'TOPLEFT', 2, -2)
+ icn:SetPoint('BOTTOMRIGHT', debuffs, 'BOTTOMRIGHT', -2, 2)
+ icn:SetTexCoord(unpack(texcoord))
+ end
+ -- border:
+ bo = debuffs:CreateTexture(nil, 'OVERLAY', nil, 7)
+ if bo then
+ bo:SetTexture(src.border)
+ bo:SetPoint('TOPRIGHT', icn, 1.6, 1.6)
+ bo:SetPoint('BOTTOMLEFT', icn, -1.6, -1.6)
+ end
+ -- color:
+ oldborder = _G[debuffs:GetName()..'Border']
+ oldborder:Hide()
+ bo:SetVertexColor(1, 0, 0)
+ debuffs.styled = true
+ end
+ -- if (k == 4) then maxshows = true end
+ end
+ end
+end
+
+-- /* hide buffinfo tooltip */
+__PartyMemberBuffTooltip_Update = PartyMemberBuffTooltip_Update;
+PartyMemberBuffTooltip_Update = function(self)
+ if (not partybuffs.showbuffs) then
+ __PartyMemberBuffTooltip_Update(self)
+ end
+ return;
+end
+
+-- /* hook func is safe to call */
+function __RefreshDebuffs(self, unit, numDebuffs, suffix, checkCVar)
+ local name = self:GetName();
+ numDebuffs = numDebuffs or 4;
+ if strfind(name, '^PartyMemberFrame%d$') then
+ if partybuffs.showbuffs then
+ RefreshBuffs(self, unit, MAX_PARTY_BUFFS);
+ end
+ end
+end
+
+-- /* setup module */
+CreatePartyAuras()
+hooksecurefunc('RefreshDebuffs',__RefreshDebuffs)
+hooksecurefunc('TargetFrame_UpdateAuras',__TargetFrame_UpdateAuras)
+if config.dispelable then
+ hooksecurefunc('TargetFrame_UpdateAuras',__TargetFrame_UpdateAurasDispel)
+end
+hooksecurefunc('TargetFrame_UpdateAuraPositions',__UpdateAuraPositions)
+hooksecurefunc('TargetFrame_UpdateBuffAnchor',__UpdateBuffAnchor)
+hooksecurefunc('TargetFrame_UpdateDebuffAnchor',__UpdateDebuffAnchor)
\ No newline at end of file
diff --git a/modules/elements/castbar.lua b/modules/elements/castbar.lua
new file mode 100644
index 0000000..6244eeb
--- /dev/null
+++ b/modules/elements/castbar.lua
@@ -0,0 +1,86 @@
+local addon = select(2,...);
+local config = addon.config;
+local own, src = config.global, config.media
+
+--[[
+/**
+ * element: castbar
+ * contains castbars for player, target, focus
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+-- /* lua lib */
+local _G = _G
+local unpack = unpack
+local pairs = pairs
+local setmetatable = setmetatable
+
+-- /* WoW APIs */
+local CreateFrame = CreateFrame
+local hooksecurefunc = hooksecurefunc
+
+-- /* consts */
+local noop = addon.noop
+local texcoord = addon.texcoord
+
+-- /* config */
+local config_dimension = setmetatable({
+ CastingBarFrame = {siz = {w=30, h=30},},
+ TargetFrameSpellBar = {siz = {w=22, h=22},},
+ FocusFrameSpellBar = {siz = {w=22, h=22},},
+},{
+ __index = function(t,k)
+ local _,_,v = k:GetName()
+ t[k] = v
+ return v
+ end,
+})
+
+-- /* create castbars style */
+local function stylecastbar()
+ for _,frame in pairs({CastingBarFrame,TargetFrameSpellBar,FocusFrameSpellBar}) do
+ frame:SetScale(own.castbar_scale)
+
+ frame.border = _G[frame:GetName()..'Border']
+ frame.border:SetTexture(src.castborder)
+ frame.border:SetVertexColor(unpack(own.framecolors))
+
+ frame.flash = _G[frame:GetName()..'Flash']
+ frame.flash:SetTexture(src.castflash)
+
+ frame.shield = _G[frame:GetName()..'BorderShield']
+ frame.shield:SetTexture(src.castshield)
+
+ frame.text = _G[frame:GetName()..'Text']
+ frame.text:SetFontObject('pUiFont')
+
+ frame.timer = frame:CreateFontString(nil,'OVERLAY','pUiFont')
+ frame.timer:SetPoint('RIGHT', frame, 'RIGHT', -2, 1)
+ frame.update = 0.1
+ end
+
+ for _,frame in pairs({CastingBarFrameIcon,TargetFrameSpellBarIcon,FocusFrameSpellBarIcon}) do
+ local data = config_dimension[frame:GetParent():GetName()]
+ frame:Show()
+ frame:SetSize(data.siz.w, data.siz.h)
+ frame:SetTexCoord(unpack(texcoord))
+
+ frame.border = frame:GetParent():CreateTexture(nil,'OVERLAY')
+ frame.border:SetPoint('TOPRIGHT', frame, 3, 3)
+ frame.border:SetPoint('BOTTOMLEFT', frame, -3, -3)
+ frame.border:SetTexture(src.border)
+ end
+
+ -- set some elements to top bar, its special for player:
+ CastingBarFrameBorder:SetPoint('TOP', 0, 26)
+ CastingBarFrameFlash:SetPoint('TOP', 0, 26)
+ CastingBarFrameIcon:ClearAllPoints()
+ CastingBarFrameIcon:SetPoint('CENTER', CastingBarFrame, 'TOP', 0, 24)
+ CastingBarFrameText:ClearAllPoints()
+ CastingBarFrameText:SetPoint('CENTER', 0, 1)
+end
+stylecastbar()
\ No newline at end of file
diff --git a/modules/elements/colour.lua b/modules/elements/colour.lua
new file mode 100644
index 0000000..65fe6df
--- /dev/null
+++ b/modules/elements/colour.lua
@@ -0,0 +1,115 @@
+local addon = select(2,...);
+local framecolors = addon.config.global.framecolors;
+local texture = addon.config.media.statusbar;
+
+--[[
+/**
+ * element: colour
+ * contains class colors
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+-- /* lua lib */
+local unpack = unpack
+local select = select
+local pairs = pairs
+local next = next
+
+-- /* WoW APIs */
+local UnitIsConnected = UnitIsConnected
+local UnitClass = UnitClass
+local UnitIsPlayer = UnitIsPlayer
+local UnitReaction = UnitReaction
+local UnitIsTapped = UnitIsTapped
+local UnitIsTappedByAllThreatList = UnitIsTappedByAllThreatList
+local UnitPlayerControlled = UnitPlayerControlled
+local UnitIsTappedByPlayer = UnitIsTappedByPlayer
+local FACTION_BAR_COLORS = FACTION_BAR_COLORS
+local RAID_CLASS_COLORS = RAID_CLASS_COLORS
+local CUSTOM_CLASS_COLORS = CUSTOM_CLASS_COLORS
+local hooksecurefunc = hooksecurefunc
+
+-- /* get textures */
+local nextframes = {
+ PlayerFrameTexture,TargetFrameTextureFrameTexture,TargetFrameToTTextureFrameTexture,
+ FocusFrameTextureFrameTexture,FocusFrameToTTextureFrameTexture,
+ PlayerFrameAlternateManaBarBorder,PetFrameTexture,
+ Boss1TargetFrameTextureFrameTexture,Boss2TargetFrameTextureFrameTexture,
+ Boss3TargetFrameTextureFrameTexture,Boss4TargetFrameTextureFrameTexture,
+ Boss5TargetFrameTextureFrameTexture,
+}
+
+local nextcastbars = {
+ CastingBarFrame,FocusFrameSpellBar,TargetFrameSpellBar,PetCastingBarFrame,
+ ArenaEnemyFrame1CastingBar,ArenaEnemyFrame2CastingBar,ArenaEnemyFrame3CastingBar,
+ ArenaEnemyFrame4CastingBar,ArenaEnemyFrame5CastingBar,PartyCastingBar1,
+ PartyCastingBar2,PartyCastingBar3,PartyCastingBar4
+}
+
+local colors = setmetatable({},{__index = function(self, key)
+ local tbl = RAID_CLASS_COLORS[key];
+ tbl = {tbl.r*1.28, tbl.g*1.28, tbl.b*1.28}
+ self[key] = tbl
+ return tbl
+end})
+
+-- /* set statusbar color for other bars */
+local setbarcolor = PlayerFrameHealthBar.SetStatusBarColor
+local function otherbarscolour_hook(self)
+ local class = select(2, UnitClass(self.unit))
+ if class and UnitIsPlayer(self.unit) then
+ setbarcolor(self, unpack(colors[class]))
+ end
+end
+
+-- /* set statusbar color for UnitIsPlayer */
+local function set_statuscolour(healthbar, unit)
+ if UnitIsPlayer(unit) and unit == healthbar.unit and UnitClass(unit) then
+ if (not UnitIsConnected(unit)) then
+ healthbar:SetStatusBarColor(.6, .6, .6, .5)
+ return
+ end
+ -- local _, class = UnitClass(unit)
+ local class = select(2,UnitClass(unit))
+ local color = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class];
+ if class then
+ healthbar:SetStatusBarColor(color.r*1.18, color.g*1.18, color.b*1.18)
+ end
+ elseif UnitExists(unit) and not UnitIsPlayer(unit) and unit == healthbar.unit then
+ local reaction = FACTION_BAR_COLORS[UnitReaction(unit,'player')]
+ if reaction then
+ healthbar:SetStatusBarColor(reaction.r*1.42, reaction.g*1.42, reaction.b*1.42)
+ else
+ healthbar:SetStatusBarColor(0, .6, .1)
+ end
+ if (not UnitPlayerControlled(unit) and UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not UnitIsTappedByAllThreatList(unit)) then
+ healthbar:SetStatusBarColor(.5, .5, .5) -- gray if npc is tapped by other player
+ end
+ end
+end
+
+local function setuphook(self)
+ hooksecurefunc(self,'SetStatusBarColor',otherbarscolour_hook)
+ self:SetStatusBarTexture(texture)
+end
+
+for _,frame in pairs(nextcastbars) do setuphook(frame) end
+for _,frame in next, nextframes do frame:SetVertexColor(unpack(framecolors)) end
+
+-- /* setup statusbar texture */
+hooksecurefunc(getmetatable(PlayerFrameHealthBar).__index, 'Show', function(sb)
+ if sb:GetParent().healthbar then
+ if (not sb.style) then
+ sb:SetStatusBarTexture(texture)
+ sb:GetStatusBarTexture():SetHorizTile(true)
+ sb.style = true
+ end
+ end
+end)
+hooksecurefunc('UnitFrameHealthBar_Update',set_statuscolour)
+hooksecurefunc('HealthBar_OnValueChanged',function(self) set_statuscolour(self,self.unit) end)
+hooksecurefunc('CastingBarFrame_OnLoad',setuphook)
\ No newline at end of file
diff --git a/modules/elements/cooldown.lua b/modules/elements/cooldown.lua
new file mode 100644
index 0000000..a6dffa9
--- /dev/null
+++ b/modules/elements/cooldown.lua
@@ -0,0 +1,98 @@
+local addon = select(2,...);
+local config = addon.config.auras;
+
+-- /* lua lib */
+local getmetatable = getmetatable
+local unpack = unpack
+local format = string.format
+local floor = math.floor
+local min, max = math.min, math.max
+
+-- /* WoW APIs */
+local UIParent = UIParent
+local CreateFrame = CreateFrame
+local hooksecurefunc = hooksecurefunc
+
+--[[
+/**
+ * element: cooldowns
+ * contains duration and cooldown time of auras
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x. credit: nightcracker
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local day, hour, minute = 86400, 3600, 60
+local function formattime(s)
+ if s >= day then
+ return format('%dd',floor(s/day + .5)),s%day
+ elseif s >= hour then
+ return format('%dh',floor(s/hour + .5)),s%hour
+ elseif s >= minute then
+ return format('%dm',floor(s/minute + .5)),s%minute
+ elseif s <= config.threshold then
+ return format('%.1f',s), s - format('%.1f',s)
+ end
+ return floor(s + .5), s - floor(s)
+end
+
+local function update(self, elapsed)
+ if (not self:GetParent().unit) then return end -- for auras
+ if (not self.text:IsShown()) then return end
+ if self.nextupdate > 0 then
+ self.nextupdate = self.nextupdate - elapsed
+ elseif (self:GetEffectiveScale()/UIParent:GetEffectiveScale()) < config.minscale then
+ self.text:SetText''
+ self.nextupdate = 1
+ else
+ self.nextupdate = 1
+ local remaining = self.duration - (GetTime() - self.start)
+ if remaining > 0 then
+ local ftime, nextupdate = formattime(remaining)
+ self.text:SetText(ftime)
+ self.nextupdate = nextupdate
+ if remaining > config.threshold then
+ self.text:SetTextColor(unpack(config.duration_color))
+ else
+ self.text:SetTextColor(unpack(config.threshold_color))
+ end
+ else
+ self.text:SetText''
+ self.text:Hide()
+ end
+ end
+end
+
+local function createtext(self)
+ local scale = min(self:GetParent():GetWidth()/config.icon_size, 1)
+ if scale < config.minscale then
+ self.noOCC = true
+ else
+ local text = self:GetParent():CreateFontString(nil, 'OVERLAY', 'pUiFont_Auras')
+ text:SetPoint('TOP', 0, 4)
+ self:SetScript('OnUpdate', update)
+ self:SetAlpha(1)
+ self.text = text
+ return text
+ end
+end
+
+local function startcd(self, start, duration)
+ if start > 0 and duration > config.minduration then
+ self.start = start
+ self.duration = duration
+ self.nextupdate = 0
+ local height = self:GetHeight()
+ self.height = height
+
+ local text = self.text or createtext(self)
+ if text then
+ text:Show()
+ end
+ end
+end
+
+local cooldownIndex = getmetatable(ActionButton1Cooldown).__index
+hooksecurefunc(cooldownIndex, 'SetCooldown', startcd)
\ No newline at end of file
diff --git a/modules/elements/minmax.lua b/modules/elements/minmax.lua
new file mode 100644
index 0000000..4679797
--- /dev/null
+++ b/modules/elements/minmax.lua
@@ -0,0 +1,78 @@
+local addon = select(2,...);
+
+-- /* lua lib */
+local abs = math.abs
+local select = select
+local tonumber = tonumber
+local min = math.min
+local max = math.max
+local ceil = math.ceil
+local strfind = string.find
+local strsub = string.sub
+local format = format
+local tostring = tostring
+local rawset = rawset
+local setmetatable = setmetatable
+
+local hooksecurefunc = hooksecurefunc
+
+--[[
+/**
+ * element: minmax
+ * contains string format and math functions
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local frameNames = setmetatable({}, {__index = function(t,k)
+ local v = k:GetName() rawset(t,k,v) return v end
+})
+
+hooksecurefunc('TextStatusBar_UpdateTextString', function(statusBar)
+ local str, val
+ local textString = statusBar.TextString;
+ local value = statusBar:GetValue();
+ local _, valueMax = statusBar:GetMinMaxValues()
+ if (textString) then
+ if (value and value > 0) then
+ if value >= 1e9 then
+ -- 1,000,000,000+ like 8b
+ str,val = '%.0fb', value/1e9
+ elseif value >= 1e6 then
+ -- 1,000,000+ like 14m
+ str,val = '%.0fm', value/1e6
+ elseif value >= 1e3 then
+ -- 1,000+ like 2k
+ str,val = '%.0fk', value/1e3
+ else
+ -- don't shorten numbers under 1,000
+ str,val = '%d', value
+ end
+ if strfind(frameNames[statusBar],'Health') and value < valueMax then
+ textString:SetFormattedText(str..' — %i%%', val, ceil(value/valueMax*100));
+ else
+ textString:SetFormattedText(str, val)
+ end
+ end
+ end
+end)
+
+-- /* cast time */
+hooksecurefunc('CastingBarFrame_OnUpdate', function(self, elapsed)
+ if not self.timer then return end
+ if self.update and self.update < elapsed then
+ if self.casting then
+ self.timer:SetFormattedText('%.1f',max(self.maxValue - self.value,0))
+ elseif self.channeling then
+ self.timer:SetFormattedText('%.1f',max(self.value,0))
+ else
+ self.timer:SetText('')
+ end
+ self.update = 0.1
+ else
+ self.update = self.update - elapsed
+ end
+end)
\ No newline at end of file
diff --git a/modules/elements/portraits.lua b/modules/elements/portraits.lua
new file mode 100644
index 0000000..4236d72
--- /dev/null
+++ b/modules/elements/portraits.lua
@@ -0,0 +1,50 @@
+local addon = select(2,...);
+local config = addon.config;
+local own, src, tot = config.global, config.media, config.targettarget;
+
+-- /* lua lib */
+local unpack = unpack
+local select = select
+
+-- /* WoW APIs */
+local UnitClass = UnitClass
+local UnitIsPlayer = UnitIsPlayer
+local hooksecurefunc = hooksecurefunc
+local CLASS_ICON_TCOORDS = CLASS_ICON_TCOORDS
+
+local squareicn = [[Interface\Glues\CharacterCreate\UI-CharacterCreate-Classes]]
+
+--[[
+/**
+ * element: portraits
+ * contains unit class portrait textures
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+hooksecurefunc('UnitFramePortrait_Update',function(self)
+ if self.portrait and own.classportraits then
+ if UnitIsPlayer(self.unit) then
+ local class = CLASS_ICON_TCOORDS[select(2, UnitClass(self.unit))]
+ if class then
+ -- checking targetoftargets and set square icons if config is squarestyle:
+ if (tot.squarestyle and self.unit == 'targettarget' and self.unit == 'focus-target') then
+ self.portrait:SetTexture(squareicn)
+ else
+ if own.prettyportraits then self.portrait:SetTexture(src.portraits)
+ else self.portrait:SetTexture('Interface\\TargetingFrame\\UI-Classes-Circles') end
+ end
+ self.portrait:SetTexCoord(unpack(class))
+ end
+ else
+ if (tot.squarestyle and self.unit == 'targettarget' and self.unit == 'focus-target') then
+ self.portrait:SetTexCoord(.08,.92,.08,.92)
+ else
+ self.portrait:SetTexCoord(0, 1, 0, 1)
+ end
+ end
+ end
+end);
\ No newline at end of file
diff --git a/modules/elements/trinkets.lua b/modules/elements/trinkets.lua
new file mode 100644
index 0000000..8300f7f
--- /dev/null
+++ b/modules/elements/trinkets.lua
@@ -0,0 +1,127 @@
+local addon = select(2,...);
+local event_ = addon:package();
+local config = addon.config;
+local uconfig, src = config.arena, config.media;
+if not uconfig.enable or not uconfig.trinkets then return end;
+
+--[[
+/**
+ * element: trinkets
+ * contains arena enemies cooldown trinket
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local unpack = unpack
+local select = select
+local format = string.format
+local wipe = wipe
+
+local GetTime = GetTime
+local GetSpellInfo = GetSpellInfo
+local IsInInstance = IsInInstance
+local UnitName = UnitName
+local UnitClass = UnitClass
+local UnitExists = UnitExists
+local UnitFactionGroup = UnitFactionGroup
+local UnitIsPlayer = UnitIsPlayer
+local UnitGUID = UnitGUID
+
+local MAX_ARENA_ENEMIES = MAX_ARENA_ENEMIES or 5
+local PVP_TRINKET_FACTION = {
+ ['Alliance'] = 'Interface\\Icons\\inv_jewelry_trinketpvp_01',
+ ['Horde'] = 'Interface\\Icons\\inv_jewelry_trinketpvp_02',
+}
+
+local trinket_spells = {
+ [GetSpellInfo(59752)] = 120,
+ [GetSpellInfo(42292)] = 120,
+ [GetSpellInfo(7744)] = 45,
+}
+
+local trinket_cooldown = {}
+function event_:PLAYER_LEAVING_WORLD()
+ wipe(trinket_cooldown)
+end
+
+local function ArenaTrinkets_OnEvent(self, event, unit, spell)
+ local msgtype
+ local instanceType = select(2, IsInInstance())
+ if instanceType ~= 'arena' then
+ self:Hide()
+ return;
+ else
+ self:Show()
+ end
+
+ if (unit == self.unit) then
+ local cooldown = trinket_spells[spell]
+ if cooldown then
+ local curTime = GetTime()
+ trinket_cooldown[UnitGUID(self.unit)] = curTime + cooldown
+ self.cooldown:Show()
+ self.cooldown:SetCooldown(curTime, cooldown)
+ if uconfig.trinket_announce then
+ msgtype = trinket_spells[spell] == 120 and uconfig.text_trinket or uconfig.text_wotf
+ SendChatMessage(UnitName(self.unit)..' ('..UnitClass(self.unit)..'): '..msgtype,uconfig.announce_chat)
+ end
+ end
+ end
+end
+
+local function ArenaTrinkets_OnShow(self, event, ...)
+ if (UnitExists(self.unit)) then
+ local faction = PVP_TRINKET_FACTION[select(2,UnitFactionGroup(self.unit))]
+ if faction then
+ self.icon:SetTexture(faction)
+ end
+
+ local curTime = GetTime()
+ local expiration = trinket_cooldown[UnitGUID(self.unit)]
+ if (expiration and expiration > curTime) then
+ self.cooldown:Show()
+ self.cooldown:SetCooldown(curTime, expiration)
+ else
+ self.cooldown:Hide()
+ end
+ end
+end
+
+local function styletrinkets()
+ for i = 1, MAX_ARENA_ENEMIES do
+ local parent = _G['ArenaEnemyFrame'..i]
+ local trinket = CreateFrame('Frame', '$parentTrinketFrame', parent)
+ trinket:SetFrameLevel(parent:GetFrameLevel()+2)
+ trinket:SetSize(14, 14)
+ trinket:SetPoint('LEFT', parent, 'CENTER', 10, -17)
+
+ local unit = 'arena'..i
+ trinket.unit = unit
+
+ local faction = PVP_TRINKET_FACTION[select(2,UnitFactionGroup(unit))]
+ trinket.icon = trinket:CreateTexture('$parentTexture', 'BORDER')
+ trinket.icon:SetAllPoints(trinket)
+ trinket.icon:SetTexture(faction)
+
+ trinket.border = trinket:CreateTexture('$parentBorder', 'OVERLAY', nil, 7)
+ trinket.border:SetPoint('CENTER', trinket)
+ trinket.border:SetSize(20, 20)
+ trinket.border:SetTexture(src.trinket_border)
+ trinket.border:SetVertexColor(unpack(config.global.framecolors))
+
+ trinket.cooldown = CreateFrame('Cooldown', '$parentCooldown', trinket, 'CooldownFrameTemplate')
+ trinket.cooldown:SetFrameLevel(trinket:GetFrameLevel())
+ trinket.cooldown:SetAllPoints(trinket)
+ trinket.cooldown:SetDrawEdge(true)
+
+ trinket:RegisterEvent('UNIT_SPELLCAST_SUCCEEDED')
+ trinket:SetScript('OnShow', ArenaTrinkets_OnShow)
+ trinket:SetScript('OnEvent', ArenaTrinkets_OnEvent)
+ end
+end
+
+if not IsAddOnLoaded('Blizzard_ArenaUI') then LoadAddOn('Blizzard_ArenaUI') end
+styletrinkets()
\ No newline at end of file
diff --git a/modules/focus.lua b/modules/focus.lua
new file mode 100644
index 0000000..8538e25
--- /dev/null
+++ b/modules/focus.lua
@@ -0,0 +1,53 @@
+local addon = select(2,...);
+local config = addon.config.focus;
+local mouse, mode = config.mousebutton, config.modbutton;
+
+--[[
+/**
+ * unit: focus
+ * contains style and functions of focus frame
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local _G = _G
+local pairs = pairs
+local type = type
+
+-- /* WoW APIs */
+local UIParent = UIParent
+local CreateFrame = CreateFrame
+local hooksecurefunc = hooksecurefunc
+
+-- /* focus selection frames */
+local nextframes = {
+ TargetFrame,PlayerFrame,PetFrame,PartyMemberFrame1,PartyMemberFrame2,
+ PartyMemberFrame3,PartyMemberFrame4,ArenaEnemyFrame1,ArenaEnemyFrame2,
+ ArenaEnemyFrame3,ArenaEnemyFrame4,ArenaEnemyFrame5,
+}
+
+-- /* create attribute type for hotkey */
+local function setfocushk(frame)
+ frame:SetAttribute(mode..'-type'..mouse, 'focus')
+end
+
+-- /* setup hooks */
+local function setup_hook(type, name, parent, template)
+ if (template == 'SecureUnitButtonTemplate') and config.fk then
+ setfocushk(_G[name])
+ end
+end
+
+hooksecurefunc('CreateFrame', setup_hook)
+
+-- /* create focus key frame */
+local focuser = CreateFrame('CheckButton', 'Focuser', UIParent, 'SecureActionButtonTemplate')
+focuser:SetAttribute('type1', 'macro')
+focuser:SetAttribute('macrotext', '/focus mouseover')
+SetOverrideBindingClick(Focuser, true, mode..'-BUTTON'..mouse, 'Focuser')
+
+-- /* set the keybindings */
+for _,frame in pairs(nextframes) do setfocushk(frame) end
\ No newline at end of file
diff --git a/modules/init.lua b/modules/init.lua
new file mode 100644
index 0000000..8c612cc
--- /dev/null
+++ b/modules/init.lua
@@ -0,0 +1,42 @@
+local addonName, addon = ...;
+local event_ = addon:package();
+
+local table = addon.table
+local unpack = unpack
+local select = select
+local pairs = pairs
+local print = print
+local collectgarbage = collectgarbage
+
+--[[
+/**
+ * initialize addon
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local default_config = {
+ signin = false,
+ elements_anchor = {},
+}
+
+function event_:ADDON_LOADED()
+ self:UnregisterEvent(event)
+ if (addonName ~= 'pw_unitframes') then
+ return print('[debug]: initialization |cfff12c60error|r, report to s0high')
+ end
+
+ -- create save data table:
+ _appdata['signin'] = true
+ table.assign_over(default_config, _appdata)
+ SetCVar('fullSizeFocusFrame', addon.config.focus.fullsize);
+
+ addon:setup_anchor()
+
+ collectgarbage('collect')
+
+ self.ADDON_LOADED = nil
+end
\ No newline at end of file
diff --git a/modules/main.lua b/modules/main.lua
new file mode 100644
index 0000000..3f78b8c
--- /dev/null
+++ b/modules/main.lua
@@ -0,0 +1,157 @@
+local addon = select(2,...);
+local config, c_anchor = addon.config, addon.c_anchor;
+local src, position = config.media, config.position;
+
+--[[
+/**
+ * create units style
+ * contains anchor and functions for all units
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+-- /* lua lib */
+local unpack = unpack
+local pairs = pairs
+local setmetatable = setmetatable
+local ipairs = ipairs
+
+-- /* WoW APIs */
+local UnitClass = UnitClass
+local UnitAffectingCombat = UnitAffectingCombat
+local UIParent = UIParent
+local CreateFrame = CreateFrame
+local hooksecurefunc = hooksecurefunc
+
+-- /* consts */
+local noop = addon.noop
+local sqr = config.targettarget.squarestyle
+local xofs,yofs = config.auras.start_x,config.auras.start_y
+
+-- /* anchor table */
+local config_anchor = setmetatable({
+ PlayerFrame = {pos={a='CENTER', p=UIParent, a2='CENTER', x=-290, y=-100},siz={w=140, h=40}},
+ TargetFrame = {pos={a='CENTER', p=UIParent, a2='CENTER', x=290, y=-100},siz={w=140, h=40}},
+ PetFrame = {pos={a='TOPLEFT', p=PlayerFrame, a2='TOPLEFT', x=98, y=-84},siz={w=120, h=36}},
+ PartyMemberFrame1 = {pos={a='LEFT', p=UIParent, a2='LEFT', x=120, y=125},siz={w=150, h=144}},
+ ArenaEnemyFrame1 = {pos={a='RIGHT', p=UIParent, a2='RIGHT', x=-120, y=125},siz={w=150, h=144}},
+ PartyTargetFrame1 = {pos={a='TOPLEFT', p=PartyMemberFrame1, a2='TOPLEFT', x=-62, y=0},siz={w=50, h=70}},
+ ArenaTargetFrame1 = {pos={a='TOPRIGHT', p=ArenaEnemyFrame1, a2='TOPRIGHT',x=62, y=0},siz={w=50, h=70}},
+ TargetFrameToT = {pos={a='TOPLEFT', p=TargetFrame, a2='BOTTOMRIGHT', x=sqr and -20 or -116, y=sqr and 87 or 20},siz={w=90, h=40}},
+ FocusFrameToT = {pos={a='TOPLEFT', p=FocusFrame, a2='BOTTOMRIGHT', x=sqr and -20 or -116, y=sqr and 87 or 20},siz={w=90, h=40}},
+ CastingBarFrame = {pos={a='CENTER', p=UIParent, a2='CENTER', x=0, y=-160},siz={w=220, h=24}},
+ TargetFrameSpellBar = {pos={a='CENTER', p=TargetFrame, a2='TOPRIGHT', x=-142, y=50},siz={w=184, h=22}},
+ FocusFrameSpellBar = {pos={a='CENTER', p=FocusFrame, a2='TOPLEFT', x=100, y=15},siz={w=184, h=22}},
+ PartyCastingBar1 = {pos={a='TOPLEFT', p=PartyMemberFrame1, a2='TOPRIGHT', x=-2, y=-18},siz={w =174, h=42}},
+ TargetBuffs = {pos={a='TOPLEFT', p=TargetFrame, a2='BOTTOMLEFT', x=xofs, y=yofs},siz={w=124, h=30}},
+ TargetDebuffs = {pos={a='LEFT', p=TargetFrame, a2='LEFT', x=xofs, y=yofs +6},siz={w=124, h=30}},
+},{
+ __index = function(t,k)
+ local _,_,v = k:GetName()
+ t[k] = v
+ return v
+ end,
+})
+
+-- /* string table */
+local strings = {
+ own = {
+ PlayerFrameHealthBarText,
+ PlayerFrameManaBarText,
+ TargetFrameTextureFrameHealthBarText,
+ TargetFrameTextureFrameManaBarText,
+ FocusFrameTextureFrameHealthBarText,
+ FocusFrameTextureFrameManaBarText,
+ PetFrameHealthBarText,
+ PetFrameManaBarText
+ },
+ party = {
+ PartyMemberFrame1HealthBarText,
+ PartyMemberFrame1ManaBarText,
+ PartyMemberFrame2HealthBarText,
+ PartyMemberFrame2ManaBarText,
+ PartyMemberFrame3HealthBarText,
+ PartyMemberFrame3ManaBarText,
+ PartyMemberFrame4HealthBarText,
+ PartyMemberFrame4ManaBarText
+ },
+}
+
+local nextframes = {
+ PlayerFrame,TargetFrame,PartyMemberFrame1,ArenaEnemyFrame1,PartyTargetFrame1,TargetFrameToT,FocusFrameToT,
+ CastingBarFrame,TargetFrameSpellBar,FocusFrameSpellBar,PartyCastingBar1,TargetBuffs,TargetDebuffs,
+ ArenaTargetFrame1,PetFrame
+}
+
+-- /* make frames cleaner */
+for _,objname in ipairs({
+ 'PlayerAttackBackground','PlayerAttackGlow',
+ 'PlayerFrameFlash','PlayerRestGlow',
+ 'PlayerStatusGlow','PlayerStatusTexture',
+ 'TargetFrameNameBackground','FocusFrameNameBackground',
+}) do
+ local obj = _G[objname]
+ if obj then
+ obj:Hide()
+ obj.Show = noop
+ end
+end
+
+-- /* setup anchor */
+function addon:setup_anchor()
+ if addon:taint() then return end
+ PlayerFrame:SetScale(config.player.scale)
+ TargetFrame:SetScale(config.target.scale)
+ FocusFrame:SetScale(config.focus.scale)
+
+ -- create anchor:
+ for _,frame in pairs(nextframes) do
+ local data = config_anchor[frame:GetName()]
+ local position = {data.pos.a, data.pos.p, data.pos.a2, data.pos.x, data.pos.y}
+ frame:ClearAllPoints()
+ frame.anchor = c_anchor(frame, frame:GetName(), frame:GetName(), position, data.siz.w, data.siz.h)
+ frame.SetPoint = noop
+ end
+end
+
+-- /* create combat indicator */
+local function style_combat(parent, xoffset, unit)
+ local cicon = CreateFrame('Frame', nil, parent)
+ cicon:SetPoint('RIGHT', xoffset, 5)
+ cicon:SetSize(28, 28)
+
+ -- create dualwield texture:
+ cicon.t = cicon:CreateTexture(nil, 'BORDER')
+ cicon.t:SetAllPoints()
+ cicon.t:SetTexture(src.dualweild)
+ cicon:SetScript('OnUpdate', function(self)
+ if UnitAffectingCombat(unit) then
+ self:SetAlpha(1)
+ else
+ self:SetAlpha(0)
+ end
+ end);
+end
+
+if config.global.combaticon then
+ style_combat(TargetFrame, -6, 'target')
+ style_combat(FocusFrame, -6, 'focus')
+end
+
+-- /* create string style */
+local function style_string()
+ for _,text in pairs(strings.own) do
+ text:SetFont(src.font, src.font_size)
+ text:SetShadowColor(0, 0, 0, 1)
+ text:SetShadowOffset(src.font_offset*1.2, -src.font_offset*1.2)
+ end
+ for _,text in pairs(strings.party) do
+ text:SetFont(src.font, src.font_size -2)
+ text:SetShadowColor(0, 0, 0, 1)
+ text:SetShadowOffset(src.font_offset, -src.font_offset)
+ end
+end
+style_string()
\ No newline at end of file
diff --git a/modules/modules.xml b/modules/modules.xml
new file mode 100644
index 0000000..7587c3a
--- /dev/null
+++ b/modules/modules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/party.lua b/modules/party.lua
new file mode 100644
index 0000000..9c8d466
--- /dev/null
+++ b/modules/party.lua
@@ -0,0 +1,189 @@
+local addon = select(2,...);
+local config = addon.config;
+local uconfig, src = config.party, config.media;
+if not uconfig.enable then return end
+
+--[[
+/**
+ * unit: party members
+ * contains style and functions of party members frame
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+-- /* lua lib */
+local _G = _G
+local unpack = unpack
+local select = select
+
+-- /* WoW APIs */
+local UnitChannelInfo = UnitChannelInfo
+local UnitCastingInfo = UnitCastingInfo
+local MAX_PARTY_MEMBERS = MAX_PARTY_MEMBERS or 4
+
+-- /* consts */
+local __PartyMemberFrame_UpdatePvPStatus
+local texcoord = addon.texcoord
+local noop = addon.noop
+
+-- /* castbar position */
+local function PartyCastingBar_OnShow()
+ for i = 1, MAX_PARTY_MEMBERS do
+ local partycastbar = _G['PartyCastingBar'..i]
+ partycastbar:SetSize(125, 10)
+ if i == 1 then
+ partycastbar:SetPoint('TOPLEFT', PartyMemberFrame1, 'TOPRIGHT', -2, -18)
+ else
+ partycastbar:SetPoint('TOP', _G['PartyCastingBar'..i-1], 'BOTTOM', 0, -66)
+ end
+ end
+end
+
+-- /* handling events */
+local function PartyCastingBar_OnEvent(self, event, ...)
+ local arg1 = ...
+ if (event == 'CVAR_UPDATE') then
+ if (self.casting or self.channeling) then
+ self:Show()
+ else
+ self:Hide()
+ end
+ return
+ elseif (event == 'PARTY_MEMBERS_CHANGED' or event == 'PARTY_MEMBER_ENABLE'
+ or event == 'PARTY_MEMBER_DISABLE' or event == 'PARTY_LEADER_CHANGED') then
+ local nameChannel = UnitChannelInfo(self.unit)
+ local nameSpell = UnitCastingInfo(self.unit)
+ if (nameChannel) then
+ event = 'UNIT_SPELLCAST_CHANNEL_START'
+ arg1 = self.unit
+ elseif (nameSpell) then
+ event = 'UNIT_SPELLCAST_START'
+ arg1 = self.unit
+ else
+ self.casting = nil
+ self.channeling = nil
+ self:SetMinMaxValues(0,0)
+ self:SetValue(0)
+ self:Hide()
+ return
+ end
+ PartyCastingBar_OnShow(self)
+ end
+ CastingBarFrame_OnEvent(self, event, arg1, select(2,...))
+end
+
+local function SetPartySpellbarAspect(self)
+ local spellbar = self:GetName();
+
+ local castborder = _G[spellbar..'Border'];
+ if (castborder) then
+ castborder:SetTexture(src.castborder);
+ castborder:SetWidth(165);
+ castborder:SetHeight(49);
+ castborder:ClearAllPoints();
+ castborder:SetPoint('TOP', self, 'TOP', 0, 20);
+ end
+
+ local castflash = _G[spellbar..'Flash'];
+ if (castflash) then
+ castflash:SetTexture(src.castflash);
+ castflash:SetWidth(165);
+ castflash:SetHeight(49);
+ castflash:ClearAllPoints();
+ castflash:SetPoint('TOP', self, 'TOP', 0, 20);
+ end
+
+ local casticon = _G[spellbar..'Icon'];
+ if (casticon) then
+ casticon:SetSize(22, 22)
+ casticon:ClearAllPoints()
+ casticon:SetPoint('LEFT', spellbar, 'RIGHT', 5, 0)
+ casticon:SetTexCoord(unpack(texcoord))
+ casticon:Show();
+
+ casticon.border = casticon:GetParent():CreateTexture(nil,'OVERLAY')
+ casticon.border:SetPoint('TOPRIGHT', casticon, 3, 3)
+ casticon.border:SetPoint('BOTTOMLEFT', casticon, -3, -3)
+ casticon.border:SetTexture(src.border)
+ end
+end
+
+-- /* create party style */
+local function frame_style_party()
+ if not addon:taint() then
+ local castbar
+ for i = 1, MAX_PARTY_MEMBERS do
+ local frame = _G['PartyMemberFrame'..i]
+ local parent = frame or UIParent
+
+ -- main style setup:
+ frame:SetScale(uconfig.scale)
+
+ frame.texture = _G[frame:GetName()..'Texture']
+ frame.texture:SetTexture(src.partyFrame)
+ frame.texture:SetVertexColor(unpack(config.global.framecolors))
+
+ frame.pettexture = _G[frame:GetName()..'PetFrameTexture']
+ frame.pettexture:SetVertexColor(unpack(config.global.framecolors))
+
+ frame.healthbar = _G[frame:GetName()..'HealthBar']
+ frame.healthbar:SetHeight(12)
+ frame.healthbar:SetPoint('TOPLEFT', 46, -13)
+
+ frame.manabar = _G[frame:GetName()..'ManaBar']
+ frame.manabar:SetPoint('TOPLEFT', 46, -25)
+
+ frame.name = _G[frame:GetName()..'Name']
+ frame.name:SetFont(src.font, src.font_size -1)
+ frame.name:SetShadowColor(0, 0, 0, 1)
+ frame.name:SetShadowOffset(1, -1)
+
+ frame.flash = _G[frame:GetName()..'Flash']
+ frame.flash:SetAlpha(0)
+
+ frame.healthbar.text = _G[frame.healthbar:GetName()..'Text']
+ frame.healthbar.text:ClearAllPoints()
+ frame.healthbar.text:SetPoint('CENTER', frame, 'CENTER', 18, 9)
+
+ frame.manabar.text = _G[frame.manabar:GetName()..'Text']
+ frame.manabar.text:ClearAllPoints()
+ frame.manabar.text:SetPoint('CENTER', frame, 'CENTER', 18, -1)
+
+ -- castbar setup:
+ castbar = CreateFrame('STATUSBAR', 'PartyCastingBar'..i, parent, 'CastingBarFrameTemplate')
+ castbar.partyID = i
+ castbar:SetScale(uconfig.castbar_scale)
+
+ castbar:SetScript('OnShow', PartyCastingBar_OnShow)
+ castbar:SetScript('OnEvent', PartyCastingBar_OnEvent)
+
+ castbar:RegisterEvent('PARTY_MEMBERS_CHANGED')
+ castbar:RegisterEvent('PARTY_MEMBER_ENABLE')
+ castbar:RegisterEvent('PARTY_MEMBER_DISABLE')
+ castbar:RegisterEvent('PARTY_LEADER_CHANGED')
+ castbar:RegisterEvent('CVAR_UPDATE')
+
+ CastingBarFrame_OnLoad(castbar, 'party'..i, false, false)
+
+ -- style castbar:
+ SetPartySpellbarAspect(castbar);
+
+ local previous = _G['PartyMemberFrame'..(i-1)..'PetFrame']
+ if previous then frame:SetPoint('TOPLEFT', previous, 'BOTTOMLEFT', -23, -30) end
+ end
+ end
+end
+
+-- /* FFA for partymembers */
+function __PartyMemberFrame_UpdatePvPStatus(self)
+ local id = self:GetID()
+ local pvpicon = _G['PartyMemberFrame'..id..'PVPIcon']
+ pvpicon:SetTexture('Interface\\TargetingFrame\\UI-PVP-FFA')
+end
+
+-- /* setup module */
+if config.global.FFA then hooksecurefunc('PartyMemberFrame_UpdatePvPStatus',__PartyMemberFrame_UpdatePvPStatus) end
+frame_style_party()
\ No newline at end of file
diff --git a/modules/partytarget.lua b/modules/partytarget.lua
new file mode 100644
index 0000000..354865c
--- /dev/null
+++ b/modules/partytarget.lua
@@ -0,0 +1,276 @@
+local addon = select(2,...);
+local config = addon.config;
+local uconfig, src = config.targettarget, config.media;
+local e_party, e_arena = config.party.enable, config.arena.enable;
+
+--[[
+/**
+ * unit: party target
+ * contains style and functions of party target and arena target frames
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+-- /* lua lib */
+local _G = _G
+local unpack = unpack
+local select = select
+local floor = math.floor
+local max = math.max
+
+-- /* WoW APIs */
+local UnitClass = UnitClass
+local UnitIsConnected = UnitIsConnected
+local UnitPlayerControlled = UnitPlayerControlled
+local UnitIsTapped = UnitIsTapped
+local UnitIsTappedByPlayer = UnitIsTappedByPlayer
+local UnitIsTappedByAllThreatList = UnitIsTappedByAllThreatList
+local UnitReaction = UnitReaction
+local UnitIsGhost = UnitIsGhost
+local UnitIsDead = UnitIsDead
+local UnitName = UnitName
+local UnitHealth = UnitHealth
+local UnitHealthMax = UnitHealthMax
+local UnitPowerType = UnitPowerType
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local PowerBarColor = PowerBarColor
+local UnitIsPlayer = UnitIsPlayer
+local UnitInRange = UnitInRange
+local UnitIsUnit = UnitIsUnit
+local UnitExists = UnitExists
+local UIParent = UIParent
+local hooksecurefunc = hooksecurefunc
+
+-- /* consts */
+local FACTION_BAR_COLORS = FACTION_BAR_COLORS
+local CUSTOM_CLASS_COLORS = CUSTOM_CLASS_COLORS
+local RAID_CLASS_COLORS = RAID_CLASS_COLORS
+local CLASS_ICON_TCOORDS = CLASS_ICON_TCOORDS
+local MAX_PARTY_MEMBERS = MAX_PARTY_MEMBERS or 4
+local MAX_ARENA_ENEMIES = MAX_ARENA_ENEMIES or 5
+
+-- /* locals */
+local __PartyTarget_OnUpdate
+
+-- /* define style */
+local styleconfig = {
+ square = {
+ siz = {w=70, h=75, x=-62, y=8},
+ tex = {w=64, h=64, x=0, y=-2, t=src.targetTargetSquare, c={0,1,0,1}},
+ hpb = {w=30, h=10, x=0, y=-10},
+ hpt = { x=0, y=-3, j='CENTER', s=12},
+ mpb = {w=30, h=10, x=0, y=0},
+ nam = {w=55, h=10, x=0, y=46, j='CENTER', s=13},
+ por = {w=32, h=32, x=0, y=9, t={.08,.92,.08,.92}},
+ },
+}
+local data = styleconfig.square
+local squareicn = [[Interface\Glues\CharacterCreate\UI-CharacterCreate-Classes]]
+
+-- /* update name */
+local function PartyTarget_UpdateName(self, unit)
+ local getname = UnitName(unit)
+ self.name:SetText(getname)
+ self.name:SetFontObject('pUiFont')
+end
+
+-- /* update healthbar */
+local function PartyTarget_UpdateHealth(self, unit)
+ if (UnitIsGhost(unit)) then
+ self.healthbar:SetValue(0)
+ self.healthbar.text:SetText('|cffeed200Ghost|r')
+ return
+ end
+ if (UnitIsDead(unit)) then
+ self.healthbar:SetValue(0)
+ self.healthbar.text:SetText('|cffeed200Dead|r')
+ return
+ end
+
+ local hp = UnitHealth(unit)
+ local perc = floor(hp/max((UnitHealthMax(unit) or 1),1)*100)
+ self.healthbar:SetValue(perc)
+
+ if UnitIsPlayer(unit) and unit == self.unit and UnitClass(unit) then
+ if (not UnitIsConnected(unit)) then
+ self.healthbar:SetStatusBarColor(.6, .6, .6, .5)
+ return
+ end
+ local class = select(2,UnitClass(unit))
+ local color = CUSTOM_CLASS_COLORS and CUSTOM_CLASS_COLORS[class] or RAID_CLASS_COLORS[class];
+ if class then
+ self.healthbar:SetStatusBarColor(color.r*1.18, color.g*1.18, color.b*1.18)
+ end
+ elseif UnitExists(unit) and not UnitIsPlayer(unit) and unit == self.unit then
+ local reaction = FACTION_BAR_COLORS[UnitReaction(unit, 'player')]
+ if reaction then
+ self.healthbar:SetStatusBarColor(reaction.r*1.42, reaction.g*1.42, reaction.b*1.42)
+ else
+ self.healthbar:SetStatusBarColor(0, .6, .1)
+ end
+ if (not UnitPlayerControlled(unit) and UnitIsTapped(unit) and not UnitIsTappedByPlayer(unit) and not UnitIsTappedByAllThreatList(unit)) then
+ self.healthbar:SetStatusBarColor(.5, .5, .5) -- gray if npc is tapped by other player
+ end
+ end
+end
+
+-- /* update manabar */
+local function PartyTarget_UpdatePower(self, unit)
+ local powerType = UnitPowerType(unit)
+ local color = PowerBarColor[powerType] or PowerBarColor['MANA']
+ self.manabar:SetStatusBarColor(color.r, color.g, color.b)
+ self.manabar:SetValue(floor(UnitPower(unit,powerType)/UnitPowerMax(unit,powerType) * 100))
+end
+
+-- /* update fade */
+local function PartyTarget_UpdateAlpha(self, unit)
+ if (not UnitIsPlayer(unit)) then
+ self:SetAlpha(1)
+ elseif (UnitInRange(unit)) then
+ self:SetAlpha(1)
+ else
+ self:SetAlpha(0.7)
+ end
+end
+
+-- /* update portraits */
+local function PartyTarget_UpdatePortrait(self, unit)
+ if UnitIsPlayer(self.unit) and config.global.classportraits then
+ local class = CLASS_ICON_TCOORDS[select(2, UnitClass(self.unit))]
+ self.portrait:SetTexture(squareicn)
+ self.portrait:SetTexCoord(unpack(class))
+ else
+ self.portrait:SetTexCoord(.08,.92,.08,.92)
+ end
+end
+
+-- /* update party target frame */
+function __PartyTarget_OnUpdate(self)
+ local unit = 'party'..self:GetID()..'target'
+ local frame = _G['PartyTargetFrame'..self:GetID()]
+ if UnitExists(unit) then
+ SetPortraitTexture(frame.portrait, unit)
+ PartyTarget_UpdateName(frame, unit)
+ PartyTarget_UpdateHealth(frame, unit)
+ PartyTarget_UpdatePower(frame, unit)
+ PartyTarget_UpdateAlpha(frame, unit)
+ PartyTarget_UpdatePortrait(frame, unit)
+ else
+ frame:SetAlpha(0)
+ end
+end
+
+-- /* update arena target frame */
+local function ArenaTarget_OnUpdate(self)
+ local unit = 'arena'..self:GetID()..'target'
+ local frame = _G['ArenaTargetFrame'..self:GetID()]
+ if UnitExists(unit) then
+ SetPortraitTexture(frame.portrait, unit)
+ PartyTarget_UpdateName(frame, unit)
+ PartyTarget_UpdateHealth(frame, unit)
+ PartyTarget_UpdatePower(frame, unit)
+ PartyTarget_UpdateAlpha(frame, unit)
+ PartyTarget_UpdatePortrait(frame, unit)
+ else
+ frame:SetAlpha(0)
+ end
+end
+
+-- /* create group target frame */
+local function c_target(i, ptype, utype, ftype)
+ local parent = _G[ptype..i] or UIParent
+ local frame = CreateFrame('Button', ftype..i, parent, 'SecureUnitButtonTemplate')
+ frame.unit = utype..i..'target'
+ frame:SetID(i)
+ frame:SetFrameStrata('LOW')
+ frame:SetSize(data.siz.w, data.siz.h)
+ frame:SetAttribute('unit', utype..i..'target')
+ frame:SetAttribute('type1', 'target')
+
+ frame.texture = CreateFrame('Frame', nil, frame)
+ frame.texture:SetSize(128, 64)
+ frame.texture:SetPoint('CENTER', data.tex.x, data.tex.y)
+ frame.texture:SetFrameLevel(8)
+ frame.texture.border = frame.texture:CreateTexture(nil, 'BORDER')
+ frame.texture.border:SetSize(data.tex.w, data.tex.h)
+ frame.texture.border:SetPoint('CENTER')
+ frame.texture.border:SetTexture(data.tex.t)
+ frame.texture.border:SetVertexColor(unpack(config.global.framecolors))
+
+ frame.portrait = frame:CreateTexture(nil, 'BACKGROUND')
+ frame.portrait:SetSize(data.por.w, data.por.h)
+ frame.portrait:SetPoint('CENTER', frame.texture.border, data.por.x, data.por.y)
+ frame.portrait:SetTexture('Interface\\TargetingFrame\\TargetDead')
+ frame.portrait:SetTexCoord(unpack(data.por.t))
+
+ frame.healthbar = CreateFrame('STATUSBAR', nil, frame, 'TextStatusBar')
+ frame.healthbar:SetStatusBarTexture(src.statusbar)
+ frame.healthbar:SetSize(data.hpb.w, data.hpb.h)
+ frame.healthbar:SetPoint('CENTER', frame.texture.border, data.hpb.x, data.hpb.y)
+ frame.healthbar:SetFrameLevel(1)
+ frame.healthbar:SetMinMaxValues(0, 100)
+
+ frame.healthbar.text = frame.texture:CreateFontString(nil, 'ARTWORK')
+ frame.healthbar.text:SetPoint('CENTER', frame.healthbar, 'CENTER')
+ frame.healthbar.text:SetFont(src.font, src.font_size -1)
+ frame.healthbar.text:SetTextColor(1, 1, 1)
+
+ frame.manabar = CreateFrame('STATUSBAR', nil, frame, 'TextStatusBar')
+ frame.manabar:SetStatusBarTexture(src.statusbar)
+ frame.manabar:SetSize(data.mpb.w, data.mpb.h)
+ frame.manabar:SetPoint('TOPLEFT', frame.healthbar, 'BOTTOMLEFT', data.mpb.x, data.mpb.y)
+ frame.manabar:SetFrameLevel(1)
+ frame.manabar:SetMinMaxValues(0, 100)
+
+ frame.name = frame:CreateFontString(nil, 'ARTWORK')
+ frame.name:SetSize(data.nam.w, data.nam.h)
+ frame.name:SetPoint('TOP', frame.healthbar, data.nam.x, data.nam.y)
+ frame.name:SetFont(src.font, src.font_size -1)
+ frame.name:SetShadowColor(0, 0, 0, 1)
+ frame.name:SetShadowOffset(1, -1)
+ frame.name:SetTextColor(1, 0.82, 0)
+ frame.name:SetJustifyH(data.nam.j)
+
+ frame:SetAlpha(0)
+
+ hooksecurefunc('Arena_LoadUI', function()
+ frame:RegisterEvent('ARENA_OPPONENT_UPDATE')
+ frame:SetScript('OnUpdate', ArenaTarget_OnUpdate)
+ end);
+
+ return frame
+end
+
+-- /* setup arena target */
+if uconfig.arenatargets and e_arena then
+ if not IsAddOnLoaded('Blizzard_ArenaUI') then LoadAddOn('Blizzard_ArenaUI') end
+ for i=1, MAX_ARENA_ENEMIES do
+ c_target(i, 'ArenaEnemyFrame', 'arena', 'ArenaTargetFrame')
+ local arenatarget = _G['ArenaTargetFrame'..i]
+ arenatarget:SetScale(uconfig.arenatarget_scale)
+ if i==1 then
+ arenatarget:SetPoint('TOPRIGHT', ArenaEnemyFrame1, 'TOPRIGHT', -data.siz.x, data.siz.y);
+ else
+ arenatarget:SetPoint('TOP', _G['ArenaTargetFrame'..i-1], 'BOTTOM', 0, -10);
+ end;
+ end
+end
+
+-- /* setup party target */
+if uconfig.partytargets and e_party then
+ for i=1, MAX_PARTY_MEMBERS do
+ c_target(i, 'PartyMemberFrame', 'party', 'PartyTargetFrame')
+ local partytarget = _G['PartyTargetFrame'..i]
+ partytarget:SetScale(uconfig.partytarget_scale)
+ if i==1 then
+ partytarget:SetPoint('TOPLEFT', PartyMemberFrame1, 'TOPLEFT', data.siz.x, data.siz.y);
+ else
+ partytarget:SetPoint('TOP', _G['PartyTargetFrame'..i-1], 'BOTTOM', 0, -16);
+ end;
+ end
+ hooksecurefunc('PartyMemberFrame_OnUpdate',__PartyTarget_OnUpdate)
+end
\ No newline at end of file
diff --git a/modules/player.lua b/modules/player.lua
new file mode 100644
index 0000000..999811f
--- /dev/null
+++ b/modules/player.lua
@@ -0,0 +1,88 @@
+local addon = select(2,...);
+local config = addon.config;
+local uconfig, src = config.player, config.media;
+
+--[[
+/**
+ * unit: player
+ * contains style and functions of player frame
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local __PlayerFrame_ToPlayerArt
+local __PlayerFrame_UpdatePvPStatus
+
+-- /* create player style */
+function __PlayerFrame_ToPlayerArt(self)
+ if uconfig.elite then PlayerFrameTexture:SetTexture(src.targetElite)
+ else PlayerFrameTexture:SetTexture(src.targetFrame) end
+
+ -- style combat icon:
+ PlayerAttackIcon:ClearAllPoints()
+ PlayerAttackIcon:SetPoint('TOPLEFT', PlayerRestIcon, -30, 20)
+ PlayerAttackIcon:SetSize(28, 28)
+ PlayerAttackIcon:SetTexture(src.dualweild)
+ PlayerAttackIcon:SetTexCoord(0, 1, 0, 1);
+
+ -- style rune orbs:
+ -- RuneFrame:ClearAllPoints()
+ -- RuneFrame.Anchor = addon.create_anchor(RuneFrame,'Runes',RuneFrame:GetName(),config.position.runebar,140,40)
+ -- RuneFrame:SetParent(PlayerFrame)
+ -- RuneFrame:SetScale(uconfig.runescale*.95)
+
+ PlayerFrameVehicleTexture:Hide()
+ PlayerFrameGroupIndicator:Hide()
+
+ -- style resources:
+ self.healthbar:SetWidth(119);
+ self.healthbar:SetHeight(27);
+ self.healthbar:SetPoint('TOPLEFT', 106, -24);
+ self.manabar:SetWidth(119);
+ self.manabar:SetPoint('TOPLEFT', 106, -52);
+
+ -- reanchor portrait:
+ self.portrait:ClearAllPoints()
+ self.portrait:SetPoint('TOPLEFT', 44, -12)
+
+ -- style string format:
+ self.healthbar.TextString:SetPoint('CENTER', PlayerFrame, 'CENTER', 50, 12)
+ self.manabar.TextString:SetPoint('CENTER', PlayerFrame, 'CENTER', 48, -7)
+
+ self.name:SetPoint('CENTER', 50, 37)
+ self.name:SetFont(src.font, src.font_size+1)
+ self.name:SetShadowColor(0, 0, 0, 1)
+ self.name:SetShadowOffset(1, -1)
+
+ -- style frame background:
+ PlayerFrameBackground:ClearAllPoints()
+ PlayerFrameBackground:SetPoint('TOPLEFT', 106, -24)
+
+ -- style pet frame:
+ PetName:SetFont(src.font, src.font_size -2)
+ PetName:SetShadowColor(0, 0, 0, 1)
+ PetName:SetShadowOffset(1, -1)
+
+ PlayerFrameAlternateManaBar:ClearAllPoints()
+ PlayerFrameAlternateManaBar:SetPoint('BOTTOMLEFT', self, 'BOTTOMLEFT', 128, 23)
+
+ -- tweak player elements with config:
+ if (not uconfig.name) then PlayerName:SetAlpha(0) end
+ if (not uconfig.leadericon) then PlayerLeaderIcon:SetAlpha(0) end
+ if (not uconfig.level) then PlayerLevelText:SetAlpha(0) end
+ if (not uconfig.petname) then PetName:SetAlpha(0) end
+end
+
+-- /* FFA for player */
+function __PlayerFrame_UpdatePvPStatus()
+ PlayerPVPIcon:SetTexture('Interface\\TargetingFrame\\UI-PVP-FFA')
+end
+
+-- /* register module */
+hooksecurefunc('PlayerFrame_ToPlayerArt',__PlayerFrame_ToPlayerArt)
+if config.global.FFA then
+ hooksecurefunc('PlayerFrame_UpdatePvPStatus',__PlayerFrame_UpdatePvPStatus)
+end
\ No newline at end of file
diff --git a/modules/target.lua b/modules/target.lua
new file mode 100644
index 0000000..d879fbd
--- /dev/null
+++ b/modules/target.lua
@@ -0,0 +1,91 @@
+local addon = select(2,...);
+local config = addon.config;
+local uconfig, src = config.target, config.media;
+
+--[[
+/**
+ * unit: target
+ * contains style and functions of target frame
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+local __TargetFrame_CheckClassification
+local __TargetFrame_CheckFaction
+
+-- /* create target style */
+function __TargetFrame_CheckClassification(self, forceNormalTexture)
+ local classification = UnitClassification(self.unit);
+ local threat = self.threatIndicator;
+ if forceNormalTexture then
+ self.borderTexture:SetTexture(src.targetFrame);
+ elseif classification == 'worldboss' or classification == 'elite' then
+ self.borderTexture:SetTexture(src.targetElite);
+ elseif classification == 'rareelite' then
+ self.borderTexture:SetTexture(src.targetElite);
+ elseif classification == 'rare' then
+ self.borderTexture:SetTexture(src.targetElite);
+ else
+ self.borderTexture:SetTexture(src.targetFrame);
+ forceNormalTexture = true;
+ end
+
+ addon.check_texture(threat,'Interface\\TargetingFrame\\UI-TargetingFrame-Flash')
+ if (forceNormalTexture) then
+ self.haveElite = nil;
+ if (threat) then
+ if (classification == 'minus') then
+ addon.check_texture(threat,'Interface\\TargetingFrame\\UI-TargetingFrame-Minus-Flash')
+ threat:SetTexCoord(0, 1, 0, 1);
+ else
+ threat:SetTexture('Interface\\TargetingFrame\\UI-FocusFrame-Large-Flash');
+ threat:SetTexCoord(0.0, 0.945, 0.0, 0.73125);
+ end
+ end
+ else
+ self.haveElite = true;
+ if (threat) then
+ threat:SetTexCoord(0, 0.9453125, 0.181640625, 0.400390625);
+ threat:SetWidth(242);
+ threat:SetHeight(112);
+ end
+ end
+
+ self.healthbar:SetSize(119, 27);
+ self.healthbar:SetPoint('TOPLEFT', 7, -24);
+ self.healthbar.TextString:SetPoint('CENTER', self.healthbar, 'CENTER', 0, 0);
+ self.manabar:SetPoint('TOPLEFT', 6, -52);
+
+ self.name:SetPoint('LEFT', 15, 38)
+ self.name:SetFont(src.font, src.font_size+1)
+ self.name:SetShadowColor(0, 0, 0, 1)
+ self.name:SetShadowOffset(1, -1)
+
+ self.deadText:SetPoint('CENTER', self.healthbar, 'CENTER', 0, 0);
+ self.deadText:SetFontObject('pUiFont')
+ self.deadText:SetTextColor(1, 1, 1)
+
+ TargetFrameBackground:SetPoint('TOPRIGHT', -107, -24)
+ TargetFrameNumericalThreat:SetScale(uconfig.threatscale)
+ if uconfig.threatplayer then
+ TargetFrameNumericalThreat:SetPoint('BOTTOM', PlayerFrame, 'TOP', 75, -22)
+ end
+
+ if not uconfig.name then self.name:SetAlpha(0) end
+ if not uconfig.leadericon then self.leaderIcon:SetAlpha(0) end
+ if not uconfig.pvpicon then self.pvpIcon:SetAlpha(0) end
+ if not uconfig.level then self.levelText:SetAlpha(0) end
+end
+
+-- /* FFA for target */
+function __TargetFrame_CheckFaction(self)
+ self.pvpIcon:SetTexture('Interface\\TargetingFrame\\UI-PVP-FFA')
+end
+
+hooksecurefunc('TargetFrame_CheckClassification',__TargetFrame_CheckClassification)
+if config.global.FFA then
+ hooksecurefunc('TargetFrame_CheckFaction',__TargetFrame_CheckFaction)
+end
\ No newline at end of file
diff --git a/modules/targettarget.lua b/modules/targettarget.lua
new file mode 100644
index 0000000..af154a5
--- /dev/null
+++ b/modules/targettarget.lua
@@ -0,0 +1,91 @@
+local addon = select(2,...);
+local config = addon.config;
+local uconfig, src = config.targettarget, config.media;
+
+local unpack = unpack
+local select = select
+
+--[[
+/**
+ * unit: target of target/focus
+ * contains style and functions of target of target frames
+ * https://github.com/s0h2x/
+ * (c) 2022, s0h2x
+ *
+ * This file is provided as is (no warranties).
+ */
+]]
+
+-- /* define style */
+local styleconfig = {
+ square = {
+ siz = {w=70, h=75, x=-20, y=87},
+ tex = {w=64, h=64, x=0, y=-2, t=src.targetTargetSquare, c={0,1,0,1}},
+ hpb = {w=30, h=10, x=0, y=-10},
+ hpt = { x=0, y=-3, j='CENTER', s=12},
+ mpb = {w=30, h=10, x=0, y=0},
+ nam = {w=65, h=10, x=0, y=46, j='CENTER', s=13},
+ por = {w=32, h=32, x=0, y=9, t={.08,.92,.08,.92}},
+ },
+ normal = {
+ siz = {w=85, h=20, x=-98, y=10},
+ tex = {w=128,h=64, x=16, y=-10, t=src.targetTargetNormal, c={0,1,0,1}},
+ hpb = {w=43, h=6, x=2, y=14},
+ hpt = { x=-4, y=-3, j='CENTER', s=12},
+ mpb = {w=37, h=7, x=-1, y=0},
+ nam = {w=65, h=10, x=11, y=-18, j='LEFT', s=13},
+ por = {w=40, h=40, x=-40, y=10, t={0,1,0,1}},
+ },
+}
+
+local function get_data_style()
+ if uconfig.squarestyle then
+ return styleconfig.square
+ end
+ return styleconfig.normal
+end
+
+-- /* create ToT & ToF style */
+local function frame_style_tot(self)
+ local data = get_data_style()
+ local texture = _G[self:GetName()..'TextureFrameTexture']
+ self:SetScale(uconfig.scale)
+ self:ClearAllPoints()
+ self:SetSize(data.siz.w, data.siz.h)
+
+ texture:SetTexture(data.tex.t)
+ texture:SetSize(data.tex.w, data.tex.h)
+ texture:ClearAllPoints()
+ texture:SetPoint('CENTER', data.tex.x, data.tex.y)
+ texture:SetTexCoord(unpack(data.tex.c))
+
+ self.portrait:ClearAllPoints()
+ self.portrait:SetSize(data.por.w, data.por.h)
+ self.portrait:SetPoint('CENTER', texture, data.por.x, data.por.y)
+ self.portrait:SetTexCoord(unpack(data.por.t))
+
+ self.healthbar:ClearAllPoints()
+ self.healthbar:SetSize(data.hpb.w, data.hpb.h)
+ self.healthbar:SetPoint('CENTER', texture, data.hpb.x, data.hpb.y)
+
+ self.manabar:ClearAllPoints()
+ self.manabar:SetSize(data.mpb.w, data.mpb.h)
+ self.manabar:SetPoint('TOPLEFT', self.healthbar, 'BOTTOMLEFT', data.mpb.x, data.mpb.y)
+
+ self.deadText:ClearAllPoints()
+ self.deadText:SetPoint('CENTER', self:GetName()..'HealthBar', 'CENTER', 1, 0)
+
+ self.name:ClearAllPoints()
+ self.name:SetSize(data.nam.w, data.nam.h)
+ self.name:SetPoint('TOP', self:GetName()..'HealthBar', data.nam.x, data.nam.y)
+ self.name:SetFont(src.font, src.font_size-1)
+ self.name:SetShadowColor(0, 0, 0, 1)
+ self.name:SetShadowOffset(1, -1)
+ self.name:SetJustifyH(data.nam.j)
+
+ self.background:ClearAllPoints()
+ self.background:SetAllPoints(self.healthbar)
+end
+
+-- /* setup module */
+for _,frame in pairs({TargetFrameToT, FocusFrameToT}) do frame_style_tot(frame) end
\ No newline at end of file
diff --git a/pw_unitframes.toc b/pw_unitframes.toc
new file mode 100644
index 0000000..ef97d12
--- /dev/null
+++ b/pw_unitframes.toc
@@ -0,0 +1,8 @@
+## Interface: 30300
+## Title: |cff00ffff*|r |cffabcdefpw_unitframes|r
+## Notes: Lightweight unitframes
+## Version: 1.2c
+## SavedVariables: _appdata
+## Author: s0h2x
+
+pw_unitframes.xml
\ No newline at end of file
diff --git a/pw_unitframes.xml b/pw_unitframes.xml
new file mode 100644
index 0000000..cd91949
--- /dev/null
+++ b/pw_unitframes.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file