Quantcast

update to wrath version

Ou Junhui [09-03-22 - 08:49]
update to wrath version
Filename
oUF/blizzard.lua
oUF/colors.lua
oUF/elements/additionalpower.lua
oUF/elements/alternativepower.lua
oUF/elements/classpower.lua
oUF/elements/combatindicator.lua
oUF/elements/health.lua
oUF/elements/healthprediction.lua
oUF/elements/leaderindicator.lua
oUF/elements/partyindicator.lua
oUF/elements/phaseindicator.lua
oUF/elements/portrait.lua
oUF/elements/power.lua
oUF/elements/powerprediction.lua
oUF/elements/pvpindicator.lua
oUF/elements/raidroleindicator.lua
oUF/elements/readycheckindicator.lua
oUF/elements/runes.lua
oUF/elements/stagger.lua
oUF/elements/tags.lua
oUF/elements/threatindicator.lua
oUF/elements/totems.lua
oUF/events.lua
oUF/factory.lua
oUF/finalize.lua
oUF/init.lua
oUF/oUF.toc
oUF/oUF.xml
oUF/oUF_Classic.xml
oUF/oUF_TBC.xml
oUF/oUF_Wrath.xml
oUF/ouf.lua
oUF/private.lua
oUF/units.lua
oUF_Simple/core/functions.lua
oUF_Simple/core/style.lua
oUF_Simple/oUF_Simple.toc
oUF_SimpleConfig/oUF_SimpleConfig.toc
oUF_SimpleConfig/player.lua
rButtonAura/rButtonAura.toc
rButtonAura_Zork/rButtonAura_Zork.toc
rChatPlus/rChatPlus.toc
rFilter/rFilter.toc
rFilter_Zork/rFilter_Zork.toc
rSkin/rSkin.toc
rStatusButton/core.lua
diff --git a/oUF/blizzard.lua b/oUF/blizzard.lua
index e90aae8..3c29780 100644
--- a/oUF/blizzard.lua
+++ b/oUF/blizzard.lua
@@ -5,7 +5,7 @@ local oUF = ns.oUF
 local MAX_ARENA_ENEMIES = _G.MAX_ARENA_ENEMIES or 5

 -- sourced from FrameXML/TargetFrame.lua
-local MAX_BOSS_FRAMES = _G.MAX_BOSS_FRAMES or 5
+local MAX_BOSS_FRAMES = 8

 -- sourced from FrameXML/PartyMemberFrame.lua
 local MAX_PARTY_MEMBERS = _G.MAX_PARTY_MEMBERS or 4
@@ -69,10 +69,10 @@ function oUF:DisableBlizzard(unit)

 		-- For the damn vehicle support:
 		PlayerFrame:RegisterEvent('PLAYER_ENTERING_WORLD')
-		--PlayerFrame:RegisterEvent('UNIT_ENTERING_VEHICLE')
-		--PlayerFrame:RegisterEvent('UNIT_ENTERED_VEHICLE')
-		--PlayerFrame:RegisterEvent('UNIT_EXITING_VEHICLE')
-		--PlayerFrame:RegisterEvent('UNIT_EXITED_VEHICLE')
+		PlayerFrame:RegisterEvent('UNIT_ENTERING_VEHICLE')
+		PlayerFrame:RegisterEvent('UNIT_ENTERED_VEHICLE')
+		PlayerFrame:RegisterEvent('UNIT_EXITING_VEHICLE')
+		PlayerFrame:RegisterEvent('UNIT_EXITED_VEHICLE')

 		-- User placed frames don't animate
 		PlayerFrame:SetUserPlaced(true)
@@ -87,7 +87,7 @@ function oUF:DisableBlizzard(unit)
 		handleFrame(TargetofFocusFrame)
 	elseif(unit == 'targettarget') then
 		handleFrame(TargetFrameToT)
---[[elseif(unit:match('boss%d?$')) then
+	elseif(unit:match('boss%d?$')) then
 		local id = unit:match('boss(%d)')
 		if(id) then
 			handleFrame('Boss' .. id .. 'TargetFrame')
@@ -95,7 +95,7 @@ function oUF:DisableBlizzard(unit)
 			for i = 1, MAX_BOSS_FRAMES do
 				handleFrame(string.format('Boss%dTargetFrame', i))
 			end
-		end]]
+		end
 	elseif(unit:match('party%d?$')) then
 		local id = unit:match('party(%d)')
 		if(id) then
@@ -117,7 +117,7 @@ function oUF:DisableBlizzard(unit)

 		-- Blizzard_ArenaUI should not be loaded
 		_G.Arena_LoadUI = function() end
-		SetCVar('showArenaEnemyFrames', '0', 'SHOW_ARENA_ENEMY_FRAMES_TEXT')
+		--SetCVar('showArenaEnemyFrames', '0', 'SHOW_ARENA_ENEMY_FRAMES_TEXT')
 	elseif(unit:match('nameplate%d+$')) then
 		local frame = C_NamePlate.GetNamePlateForUnit(unit)
 		if(frame and frame.UnitFrame) then
@@ -129,4 +129,4 @@ function oUF:DisableBlizzard(unit)
 			handleFrame(frame.UnitFrame, true)
 		end
 	end
-end
\ No newline at end of file
+end
diff --git a/oUF/colors.lua b/oUF/colors.lua
index 9bfe2b9..b36b62a 100644
--- a/oUF/colors.lua
+++ b/oUF/colors.lua
@@ -1,4 +1,4 @@
-local parent, ns = ...
+local _, ns = ...
 local oUF = ns.oUF
 local Private = oUF.Private

@@ -10,6 +10,11 @@ local colors = {
 		1, 1, 0,
 		0, 1, 0
 	},
+	happiness = {
+		[1] = {.69, .31, .31},
+		[2] = {.65, .63, .35},
+		[3] = {.33, .59, .33},
+	},
 	health = {49 / 255, 207 / 255, 37 / 255},
 	disconnected = {0.6, 0.6, 0.6},
 	tapped = {0.6, 0.6, 0.6},
@@ -17,6 +22,7 @@ local colors = {
 		{247 / 255, 65 / 255, 57 / 255}, -- blood
 		{148 / 255, 203 / 255, 247 / 255}, -- frost
 		{173 / 255, 235 / 255, 66 / 255}, -- unholy
+		{247 / 255, 66 / 255, 247 / 255}, -- death
 	},
 	selection = {
 		[ 0] = {255 / 255, 0 / 255, 0 / 255}, -- HOSTILE
@@ -38,19 +44,20 @@ local colors = {
 	debuff = {},
 	reaction = {},
 	power = {},
-	happiness = {
-		[1] = {1, 0, 0}, -- need.... | unhappy
-		[2] = {1, 1, 0}, -- new..... | content
-		[3] = {0, 1, 0}, -- colors.. | happy
+	threat = {
+		[0] = { .69, .69, .69},
+		[1] = { 1, 1, .47 },
+		[2] = { 1, .6, 0 },
+		[3] = { 1, 0, 0 },
 	},
 }

 -- We do this because people edit the vars directly, and changing the default
 -- globals makes SPICE FLOW!
 local function customClassColors()
-	if(CUSTOM_CLASS_COLORS) then
+	if(_G.CUSTOM_CLASS_COLORS) then
 		local function updateColors()
-			for classToken, color in next, CUSTOM_CLASS_COLORS do
+			for classToken, color in next, _G.CUSTOM_CLASS_COLORS do
 				colors.class[classToken] = {color.r, color.g, color.b}
 			end

@@ -60,14 +67,14 @@ local function customClassColors()
 		end

 		updateColors()
-		CUSTOM_CLASS_COLORS:RegisterCallback(updateColors)
+		_G.CUSTOM_CLASS_COLORS:RegisterCallback(updateColors)

 		return true
 	end
 end

 if(not customClassColors()) then
-	for classToken, color in next, RAID_CLASS_COLORS do
+	for classToken, color in next, _G.RAID_CLASS_COLORS do
 		colors.class[classToken] = {color.r, color.g, color.b}
 	end

@@ -81,11 +88,11 @@ if(not customClassColors()) then
 	end)
 end

-for debuffType, color in next, DebuffTypeColor do
+for debuffType, color in next, _G.DebuffTypeColor do
 	colors.debuff[debuffType] = {color.r, color.g, color.b}
 end

-for eclass, color in next, FACTION_BAR_COLORS do
+for eclass, color in next, _G.FACTION_BAR_COLORS do
 	colors.reaction[eclass] = {color.r, color.g, color.b}
 end

@@ -94,8 +101,8 @@ for power, color in next, PowerBarColor do
 		if(type(select(2, next(color))) == 'table') then
 			colors.power[power] = {}

-			for index, color in next, color do
-				colors.power[power][index] = {color.r, color.g, color.b}
+			for index, color_ in next, color do
+				colors.power[power][index] = {color_.r, color_.g, color_.b}
 			end
 		else
 			colors.power[power] = {color.r, color.g, color.b, atlas = color.atlas}
@@ -121,6 +128,16 @@ colors.power[16] = colors.power.ARCANE_CHARGES
 colors.power[17] = colors.power.FURY
 colors.power[18] = colors.power.PAIN

+-- alternate power, sourced from FrameXML/CompactUnitFrame.lua
+colors.power.ALTERNATE = {0.7, 0.7, 0.6}
+colors.power[10] = colors.power.ALTERNATE
+
+if GetThreatStatusColor then
+	for i = 0, 3 do
+		colors.threat[i] = {GetThreatStatusColor(i)}
+	end
+end
+
 local function colorsAndPercent(a, b, ...)
 	if(a <= 0 or b == 0) then
 		return nil, ...
@@ -265,4 +282,4 @@ oUF.colors = colors
 oUF.useHCYColorGradient = false

 frame_metatable.__index.colors = colors
-frame_metatable.__index.ColorGradient = oUF.ColorGradient
\ No newline at end of file
+frame_metatable.__index.ColorGradient = oUF.ColorGradient
diff --git a/oUF/elements/additionalpower.lua b/oUF/elements/additionalpower.lua
index 8fbaa52..04d3e5e 100644
--- a/oUF/elements/additionalpower.lua
+++ b/oUF/elements/additionalpower.lua
@@ -1,7 +1,8 @@
 --[[
 # Element: Additional Power Bar

-Handles the visibility and updating of a status bar that displays the player's additional power, such as Mana for druids.
+Handles the visibility and updating of a status bar that displays the player's additional power, such as Mana for
+Balance druids.

 ## Widget

@@ -17,18 +18,18 @@ A default texture will be applied if the widget is a StatusBar and doesn't have

 ## Options

-.frequentUpdates                  - Indicates whether to use UNIT_POWER_FREQUENT instead UNIT_POWER_UPDATE to update the
-                                    bar (boolean)
-.smoothGradient                   - 9 color values to be used with the .colorSmooth option (table)
+.frequentUpdates - Indicates whether to use UNIT_POWER_FREQUENT instead UNIT_POWER_UPDATE to update the bar (boolean)
+.displayPairs    - Use to override display pairs. (table)
+.smoothGradient  - 9 color values to be used with the .colorSmooth option (table)

 The following options are listed by priority. The first check that returns true decides the color of the bar.

-.colorPower        - Use `self.colors.power[token]` to color the bar based on the player's additional power type
-                     (boolean)
-.colorClass        - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
-                     second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
-.colorSmooth       - Use `self.colors.smooth` to color the bar with a smooth gradient based on the player's current
-                     additional power percentage (boolean)
+.colorPower  - Use `self.colors.power[token]` to color the bar based on the player's additional power type
+               (boolean)
+.colorClass  - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
+               second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
+.colorSmooth - Use `self.colors.smooth` to color the bar with a smooth gradient based on the player's current
+               additional power percentage (boolean)

 ## Sub-Widget Options

@@ -53,21 +54,35 @@ The following options are listed by priority. The first check that returns true
     self.AdditionalPower = AdditionalPower
 --]]

-if(select(2, UnitClass('player')) ~= 'DRUID') then return end
-
 local _, ns = ...
 local oUF = ns.oUF

-local function UpdateColor(self, event, unit, powertype)
-	if(not (unit and unit == 'player') and powertype == 'MANA') then return end
+local _, playerClass = UnitClass('player')
+
+-- ElvUI block
+local unpack = unpack
+local CopyTable = CopyTable
+local UnitIsUnit = UnitIsUnit
+local UnitPower = UnitPower
+local UnitPowerMax = UnitPowerMax
+local UnitHasVehicleUI = UnitHasVehicleUI
+local UnitPowerType = UnitPowerType
+-- end block
+
+-- sourced from FrameXML/AlternatePowerBar.lua
+local POWER_NAME = _G.ADDITIONAL_POWER_BAR_NAME or 'MANA'
+local POWER_INDEX = _G.ADDITIONAL_POWER_BAR_INDEX or 0
+local ALT_MANA_INFO = _G.ALT_MANA_BAR_PAIR_DISPLAY_INFO or {DRUID={[8]=true}, SHAMAN={[11]=true}, PRIEST={[13]=true}}
+
+local function UpdateColor(self, event, unit, powerType)
+	if(not (unit and UnitIsUnit(unit, 'player') and powerType == POWER_NAME)) then return end
 	local element = self.AdditionalPower

 	local r, g, b, t
 	if(element.colorPower) then
-		t = self.colors.power[0]
-	elseif(element.colorClass and UnitIsPlayer(unit)) then
-		local _, class = UnitClass(unit)
-		t = self.colors.class[class]
+		t = self.colors.power[POWER_INDEX]
+	elseif(element.colorClass) then
+		t = self.colors.class[playerClass]
 	elseif(element.colorSmooth) then
 		r, g, b = self:ColorGradient(element.cur or 1, element.max or 1, unpack(element.smoothGradient or self.colors.smooth))
 	end
@@ -86,27 +101,23 @@ local function UpdateColor(self, event, unit, powertype)
 		end
 	end

-	if(element.PostUpdateColor) then
-		element:PostUpdateColor(unit, r, g, b)
-	end
-end
-
-local function ColorPath(self, ...)
-	--[[ Override: AdditionalPower.UpdateColor(self, event, unit, ...)
-	Used to completely override the internal function for updating the widgets' colors.
+	--[[ Callback: AdditionalPower:PostUpdateColor(r, g, b)
+	Called after the element color has been updated.

-	* self  - the parent object
-	* event - the event triggering the update (string)
-	* unit  - the unit accompanying the event (string)
-	* ...   - the arguments accompanying the event
+	* self - the AdditionalPower element
+	* r    - the red component of the used color (number)[0-1]
+	* g    - the green component of the used color (number)[0-1]
+	* b    - the blue component of the used color (number)[0-1]
 	--]]
-	(self.AdditionalPower.UpdateColor or UpdateColor) (self, ...)
+	if(element.PostUpdateColor) then
+		element:PostUpdateColor(r, g, b)
+	end
 end

-local function Update(self, event, unit, powertype)
-	if(not (unit and unit == 'player') and powertype == 'MANA') then return end
-
+local function Update(self, event, unit, powerType)
+	if(not (unit and UnitIsUnit(unit, 'player') and powerType == POWER_NAME)) then return end
 	local element = self.AdditionalPower
+
 	--[[ Callback: AdditionalPower:PreUpdate(unit)
 	Called before the element has been updated.

@@ -117,25 +128,23 @@ local function Update(self, event, unit, powertype)
 		element:PreUpdate(unit)
 	end

-	local cur = UnitPower('player', 0)
-	local max = UnitPowerMax('player', 0)
-
+	local cur, max = UnitPower('player', POWER_INDEX), UnitPowerMax('player', POWER_INDEX)
 	element:SetMinMaxValues(0, max)
+
 	element:SetValue(cur)

 	element.cur = cur
 	element.max = max

-	--[[ Callback: AdditionalPower:PostUpdate(unit, cur, max)
+	--[[ Callback: AdditionalPower:PostUpdate(cur, max)
 	Called after the element has been updated.

 	* self - the AdditionalPower element
-	* unit - the unit for which the update has been triggered (string)
 	* cur  - the current value of the player's additional power (number)
 	* max  - the maximum value of the player's additional power (number)
 	--]]
 	if(element.PostUpdate) then
-		return element:PostUpdate(unit, cur, max)
+		return element:PostUpdate(cur, max, event) -- ElvUI adds event
 	end
 end

@@ -148,9 +157,17 @@ local function Path(self, ...)
 	* unit  - the unit accompanying the event (string)
 	* ...   - the arguments accompanying the event
 	--]]
-	(self.AdditionalPower.Override or Update) (self, ...)
+	(self.AdditionalPower.Override or Update) (self, ...);

-	ColorPath(self, ...)
+	--[[ Override: AdditionalPower.UpdateColor(self, event, unit, ...)
+	Used to completely override the internal function for updating the widgets' colors.
+
+	* self  - the parent object
+	* event - the event triggering the update (string)
+	* unit  - the unit accompanying the event (string)
+	* ...   - the arguments accompanying the event
+	--]]
+	(self.AdditionalPower.UpdateColor or UpdateColor) (self, ...)
 end

 local function ElementEnable(self)
@@ -166,36 +183,57 @@ local function ElementEnable(self)

 	element:Show()

-	Path(self, 'ElementEnable', 'player', 'MANA')
+	element.__isEnabled = true
+
+	Path(self, 'ElementEnable', 'player', POWER_NAME)
 end

 local function ElementDisable(self)
 	local element = self.AdditionalPower

-	if(element.frequentUpdates) then
-		self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
-	else
-		self:RegisterEvent('UNIT_POWER_UPDATE', Path)
-	end
-
 	self:UnregisterEvent('UNIT_MAXPOWER', Path)
+	self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
+	self:UnregisterEvent('UNIT_POWER_UPDATE', Path)

-	self.AdditionalPower:Hide()
+	element:Hide()

-	Path(self, 'ElementDisable', 'player', 'MANA')
+	element.__isEnabled = false
+	Path(self, 'ElementDisable', 'player', POWER_NAME)
 end

-local function Visibility(self)
+local function Visibility(self, event, unit)
+	local element = self.AdditionalPower
 	local shouldEnable

-	if((UnitPowerType('player') ~= 0) and (UnitPowerMax('player', 0) ~= 0)) then
-		shouldEnable = true
+	if (oUF.isClassic or oUF.isTBC) or not UnitHasVehicleUI('player') then
+		local allowed = element.displayPairs[playerClass]
+		if allowed and UnitPowerMax(unit, POWER_INDEX) ~= 0 then
+			shouldEnable = allowed[UnitPowerType(unit)]
+		end
 	end

-	if(shouldEnable) then
+	local isEnabled = element.__isEnabled
+
+	if(shouldEnable and not isEnabled) then
 		ElementEnable(self)
-	else
+
+		--[[ Callback: AdditionalPower:PostVisibility(isVisible)
+		Called after the element's visibility has been changed.
+
+		* self      - the AdditionalPower element
+		* isVisible - the current visibility state of the element (boolean)
+		--]]
+		if(element.PostVisibility) then
+			element:PostVisibility(true)
+		end
+	elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then
 		ElementDisable(self)
+
+		if(element.PostVisibility) then
+			element:PostVisibility(false)
+		end
+	elseif(shouldEnable and isEnabled) then
+		Path(self, event, unit, POWER_NAME)
 	end
 end

@@ -207,22 +245,47 @@ local function VisibilityPath(self, ...)
 	* event - the event triggering the update (string)
 	* unit  - the unit accompanying the event (string)
 	--]]
-	return (self.AdditionalPower.OverrideVisibility or Visibility) (self, ...)
+	(self.AdditionalPower.OverrideVisibility or Visibility) (self, ...)
 end

 local function ForceUpdate(element)
-	return VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
+	VisibilityPath(element.__owner, 'ForceUpdate', element.__owner.unit)
+end
+
+--[[ Power:SetFrequentUpdates(state, isForced)
+Used to toggle frequent updates.
+
+* self  - the Power element
+* state - the desired state (boolean)
+* isForced - forces the event update even if the state wasn't changed (boolean)
+--]]
+local function SetFrequentUpdates(element, state, isForced)
+	if(element.frequentUpdates ~= state or isForced) then
+		element.frequentUpdates = state
+		if(state) then
+			element.__owner:UnregisterEvent('UNIT_POWER_UPDATE', Path)
+			element.__owner:RegisterEvent('UNIT_POWER_FREQUENT', Path)
+		else
+			element.__owner:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
+			element.__owner:RegisterEvent('UNIT_POWER_UPDATE', Path)
+		end
+	end
 end

 local function Enable(self, unit)
 	local element = self.AdditionalPower
-	if(element and unit == 'player') then
+	if(element and UnitIsUnit(unit, 'player')) then
 		element.__owner = self
 		element.ForceUpdate = ForceUpdate
+		element.SetFrequentUpdates = SetFrequentUpdates

 		self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)

-		if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
+		if(not element.displayPairs) then
+			element.displayPairs = CopyTable(ALT_MANA_INFO)
+		end
+
+		if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then
 			element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
 		end

@@ -239,4 +302,4 @@ local function Disable(self)
 	end
 end

-oUF:AddElement('AdditionalPower', VisibilityPath, Enable, Disable)
\ No newline at end of file
+oUF:AddElement('AdditionalPower', VisibilityPath, Enable, Disable)
diff --git a/oUF/elements/alternativepower.lua b/oUF/elements/alternativepower.lua
index 6185b8d..56ce005 100644
--- a/oUF/elements/alternativepower.lua
+++ b/oUF/elements/alternativepower.lua
@@ -59,8 +59,11 @@ local unitSelectionType = Private.unitSelectionType
 -- sourced from FrameXML/UnitPowerBarAlt.lua
 local ALTERNATE_POWER_INDEX = Enum.PowerType.Alternate or 10
 local ALTERNATE_POWER_NAME = 'ALTERNATE'
+local GameTooltip = GameTooltip

 local function updateTooltip(self)
+	if GameTooltip:IsForbidden() then return end
+
 	local name, tooltip = GetUnitPowerBarStringsByID(self.__barID)
 	GameTooltip:SetText(name or '', 1, 1, 1)
 	GameTooltip:AddLine(tooltip or '', nil, nil, nil, true)
@@ -68,13 +71,16 @@ local function updateTooltip(self)
 end

 local function onEnter(self)
-	if(not self:IsVisible()) then return end
+	if GameTooltip:IsForbidden() or not self:IsVisible() then return end

+	GameTooltip:ClearAllPoints()
 	GameTooltip_SetDefaultAnchor(GameTooltip, self)
 	self:UpdateTooltip()
 end

 local function onLeave()
+	if GameTooltip:IsForbidden() then return end
+
 	GameTooltip:Hide()
 end

@@ -141,12 +147,16 @@ local function Update(self, event, unit, powerType)
 		element:PreUpdate()
 	end

-	local cur, max, min
+	local min, max, cur = 0
 	local barInfo = element.__barInfo
 	if(barInfo) then
 		cur = UnitPower(unit, ALTERNATE_POWER_INDEX)
 		max = UnitPowerMax(unit, ALTERNATE_POWER_INDEX)
-		min = barInfo.minPower
+
+		if barInfo.minPower then
+			min = barInfo.minPower
+		end
+
 		element:SetMinMaxValues(min, max)
 		element:SetValue(cur)
 	end
diff --git a/oUF/elements/classpower.lua b/oUF/elements/classpower.lua
index c2cc7aa..74ac39a 100644
--- a/oUF/elements/classpower.lua
+++ b/oUF/elements/classpower.lua
@@ -50,13 +50,20 @@ local oUF = ns.oUF
 local _, PlayerClass = UnitClass('player')

 -- sourced from FrameXML/Constants.lua
+local SPEC_MAGE_ARCANE = _G.SPEC_MAGE_ARCANE or 1
+local SPEC_MONK_WINDWALKER = _G.SPEC_MONK_WINDWALKER or 3
+local SPEC_WARLOCK_DESTRUCTION = _G.SPEC_WARLOCK_DESTRUCTION or 3
 local SPELL_POWER_ENERGY = Enum.PowerType.Energy or 3
 local SPELL_POWER_COMBO_POINTS = Enum.PowerType.ComboPoints or 4
+local SPELL_POWER_SOUL_SHARDS = Enum.PowerType.SoulShards or 7
+local SPELL_POWER_HOLY_POWER = Enum.PowerType.HolyPower or 9
+local SPELL_POWER_CHI = Enum.PowerType.Chi or 12
+local SPELL_POWER_ARCANE_CHARGES = Enum.PowerType.ArcaneCharges or 16

 -- Holds the class specific stuff.
 local ClassPowerID, ClassPowerType
 local ClassPowerEnable, ClassPowerDisable
-local RequirePower, RequireSpell
+local RequireSpec, RequirePower, RequireSpell

 local function UpdateColor(element, powerType)
 	local color = element.__owner.colors.power[powerType]
@@ -71,16 +78,23 @@ local function UpdateColor(element, powerType)
 			bg:SetVertexColor(r * mu, g * mu, b * mu)
 		end
 	end
-end

-local function Update(self, event, unit, powerType)
-	if event == "PLAYER_TARGET_CHANGED" then
-		unit, powerType = "player", "COMBO_POINTS"
-	elseif powerType == "ENERGY" then
-		powerType = "COMBO_POINTS" -- sometimes powerType return ENERGY for the first combo point
+	--[[ Callback: ClassPower:PostUpdateColor(r, g, b)
+	Called after the element color has been updated.
+
+	* self - the ClassPower element
+	* r    - the red component of the used color (number)[0-1]
+	* g    - the green component of the used color (number)[0-1]
+	* b    - the blue component of the used color (number)[0-1]
+	--]]
+	if(element.PostUpdateColor) then
+		element:PostUpdateColor(r, g, b)
 	end
+end

-	if (not (unit and (UnitIsUnit(unit, 'player') and powerType == ClassPowerType))) then
+local function Update(self, event, unit, powerType)
+	if(not (unit and (UnitIsUnit(unit, 'player') and (not powerType or powerType == ClassPowerType)
+		or unit == 'vehicle' and powerType == 'COMBO_POINTS'))) then
 		return
 	end

@@ -95,17 +109,28 @@ local function Update(self, event, unit, powerType)
 		element:PreUpdate()
 	end

-	local cur, max, mod, oldMax
+	local cur, max, mod, oldMax, chargedPoints
 	if(event ~= 'ClassPowerDisable') then
-		local powerID = ClassPowerID
-		--cur = UnitPower(unit, powerID, true)
-		cur = GetComboPoints(unit, "target")	-- has to use GetComboPoints in classic
+		local powerID = unit == 'vehicle' and SPELL_POWER_COMBO_POINTS or ClassPowerID
+		cur = not oUF.isRetail and powerType == 'COMBO_POINTS' and GetComboPoints('player', 'target') or UnitPower(unit, powerID, true)
 		max = UnitPowerMax(unit, powerID)
 		mod = UnitPowerDisplayMod(powerID)

 		-- mod should never be 0, but according to Blizz code it can actually happen
 		cur = mod == 0 and 0 or cur / mod

+		-- BUG: Destruction is supposed to show partial soulshards, but Affliction and Demonology should only show full ones
+		if oUF.isRetail and (ClassPowerType == 'SOUL_SHARDS' and GetSpecialization() ~= SPEC_WARLOCK_DESTRUCTION) then
+			cur = cur - cur % 1
+		end
+
+		if oUF.isRetail and (PlayerClass == 'ROGUE') then
+			chargedPoints = GetUnitChargedPowerPoints(unit)
+
+			-- UNIT_POWER_POINT_CHARGE doesn't provide a power type
+			powerType = powerType or ClassPowerType
+		end
+
 		local numActive = cur + 0.9
 		for i = 1, max do
 			if(i > numActive) then
@@ -137,9 +162,10 @@ local function Update(self, event, unit, powerType)
 	* max           - the maximum amount of power (number)
 	* hasMaxChanged - indicates whether the maximum amount has changed since the last update (boolean)
 	* powerType     - the active power type (string)
+	* chargedTable  - current chargedPoints table
 	--]]
 	if(element.PostUpdate) then
-		return element:PostUpdate(cur, max, oldMax ~= max, powerType)
+		return element:PostUpdate(cur, max, oldMax ~= max, powerType, chargedPoints)  -- ElvUI uses chargedPoints as table
 	end
 end

@@ -159,21 +185,26 @@ local function Visibility(self, event, unit)
 	local element = self.ClassPower
 	local shouldEnable

-	if(ClassPowerID) then
-		-- use 'player' instead of unit because 'SPELLS_CHANGED' is a unitless event
-		if(not RequirePower or RequirePower == UnitPowerType('player')) then
-			if(not RequireSpell or IsPlayerSpell(RequireSpell)) then
-				self:UnregisterEvent('SPELLS_CHANGED', Visibility)
-				shouldEnable = true
-				unit = 'player'
-			else
-				self:RegisterEvent('SPELLS_CHANGED', Visibility, true)
+	if oUF.isRetail and UnitHasVehicleUI('player') then
+		shouldEnable = PlayerVehicleHasComboPoints()
+		unit = 'vehicle'
+	elseif(ClassPowerID) then
+		if(not RequireSpec or oUF.isRetail and (RequireSpec == GetSpecialization())) then
+			-- use 'player' instead of unit because 'SPELLS_CHANGED' is a unitless event
+			if(not RequirePower or RequirePower == UnitPowerType('player')) then
+				if(not RequireSpell or IsPlayerSpell(RequireSpell)) then
+					self:UnregisterEvent('SPELLS_CHANGED', Visibility)
+					shouldEnable = true
+					unit = 'player'
+				else
+					self:RegisterEvent('SPELLS_CHANGED', Visibility, true)
+				end
 			end
 		end
 	end

-	local isEnabled = element.isEnabled
-	local powerType = ClassPowerType
+	local isEnabled = element.__isEnabled
+	local powerType = unit == 'vehicle' and 'COMBO_POINTS' or ClassPowerType

 	if(shouldEnable) then
 		--[[ Override: ClassPower:UpdateColor(powerType)
@@ -187,8 +218,22 @@ local function Visibility(self, event, unit)

 	if(shouldEnable and not isEnabled) then
 		ClassPowerEnable(self)
+
+		--[[ Callback: ClassPower:PostVisibility(isVisible)
+		Called after the element's visibility has been changed.
+
+		* self      - the ClassPower element
+		* isVisible - the current visibility state of the element (boolean)
+		--]]
+		if(element.PostVisibility) then
+			element:PostVisibility(true)
+		end
 	elseif(not shouldEnable and (isEnabled or isEnabled == nil)) then
 		ClassPowerDisable(self)
+
+		if(element.PostVisibility) then
+			element:PostVisibility(false)
+		end
 	elseif(shouldEnable and isEnabled) then
 		Path(self, event, unit, powerType)
 	end
@@ -212,36 +257,66 @@ end
 do
 	function ClassPowerEnable(self)
 		self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
-		self:RegisterEvent('PLAYER_TARGET_CHANGED', Path, true)
 		self:RegisterEvent('UNIT_MAXPOWER', Path)

-		self.ClassPower.isEnabled = true
+		if not oUF.isRetail then
+			self:RegisterEvent('PLAYER_TARGET_CHANGED', VisibilityPath, true)
+		end
+
+		if oUF.isRetail and (PlayerClass == 'ROGUE') then
+			self:RegisterEvent('UNIT_POWER_POINT_CHARGE', Path)
+		end
+
+		self.ClassPower.__isEnabled = true

-		Path(self, 'ClassPowerEnable', 'player', ClassPowerType)
+		if (oUF.isRetail or oUF.isWrath) and UnitHasVehicleUI('player') then
+			Path(self, 'ClassPowerEnable', 'vehicle', 'COMBO_POINTS')
+		else
+			Path(self, 'ClassPowerEnable', 'player', ClassPowerType)
+		end
 	end

 	function ClassPowerDisable(self)
 		self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
-		self:UnregisterEvent('PLAYER_TARGET_CHANGED', Path)
 		self:UnregisterEvent('UNIT_MAXPOWER', Path)

+		if oUF.isRetail then
+			self:UnregisterEvent('UNIT_POWER_POINT_CHARGE', Path)
+		else
+			self:UnregisterEvent('PLAYER_TARGET_CHANGED', VisibilityPath)
+		end
+
 		local element = self.ClassPower
 		for i = 1, #element do
 			element[i]:Hide()
 		end

-		self.ClassPower.isEnabled = false
+		element.__isEnabled = false
 		Path(self, 'ClassPowerDisable', 'player', ClassPowerType)
 	end

-	if(PlayerClass == 'ROGUE' or PlayerClass == 'DRUID') then
+	if(PlayerClass == 'MONK') then
+		ClassPowerID = SPELL_POWER_CHI
+		ClassPowerType = 'CHI'
+		RequireSpec = SPEC_MONK_WINDWALKER
+	elseif(PlayerClass == 'PALADIN') then
+		ClassPowerID = SPELL_POWER_HOLY_POWER
+		ClassPowerType = 'HOLY_POWER'
+	elseif(PlayerClass == 'WARLOCK') then
+		ClassPowerID = SPELL_POWER_SOUL_SHARDS
+		ClassPowerType = 'SOUL_SHARDS'
+	elseif(PlayerClass == 'ROGUE' or PlayerClass == 'DRUID') then
 		ClassPowerID = SPELL_POWER_COMBO_POINTS
 		ClassPowerType = 'COMBO_POINTS'

 		if(PlayerClass == 'DRUID') then
 			RequirePower = SPELL_POWER_ENERGY
-			RequireSpell = 768 -- Cat Form
+			RequireSpell = oUF.isRetail and 5221 or 768
 		end
+	elseif(PlayerClass == 'MAGE') then
+		ClassPowerID = SPELL_POWER_ARCANE_CHARGES
+		ClassPowerType = 'ARCANE_CHARGES'
+		RequireSpec = SPEC_MAGE_ARCANE
 	end
 end

@@ -252,6 +327,10 @@ local function Enable(self, unit)
 		element.__max = #element
 		element.ForceUpdate = ForceUpdate

+		if(oUF.isRetail or oUF.isWrath) and (RequireSpec or RequireSpell) then
+			self:RegisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath, true)
+		end
+
 		if(RequirePower) then
 			self:RegisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
 		end
@@ -262,7 +341,7 @@ local function Enable(self, unit)
 		for i = 1, #element do
 			local bar = element[i]
 			if(bar:IsObjectType('StatusBar')) then
-				if(not bar:GetStatusBarTexture()) then
+				if(not (bar:GetStatusBarTexture() or bar:GetStatusBarAtlas())) then
 					bar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
 				end

@@ -278,9 +357,13 @@ local function Disable(self)
 	if(self.ClassPower) then
 		ClassPowerDisable(self)

+		if oUF.isRetail or oUF.isWrath then
+			self:UnregisterEvent('PLAYER_TALENT_UPDATE', VisibilityPath)
+		end
+
 		self:UnregisterEvent('UNIT_DISPLAYPOWER', VisibilityPath)
 		self:UnregisterEvent('SPELLS_CHANGED', Visibility)
 	end
 end

-oUF:AddElement('ClassPower', VisibilityPath, Enable, Disable)
\ No newline at end of file
+oUF:AddElement('ClassPower', VisibilityPath, Enable, Disable)
diff --git a/oUF/elements/combatindicator.lua b/oUF/elements/combatindicator.lua
index 4717be0..ac80c0f 100644
--- a/oUF/elements/combatindicator.lua
+++ b/oUF/elements/combatindicator.lua
@@ -25,7 +25,8 @@ A default texture will be applied if the widget is a Texture and doesn't have a
 local _, ns = ...
 local oUF = ns.oUF

-local function Update(self, event)
+local function Update(self, event, unit)
+	if not unit or self.unit ~= unit then return end
 	local element = self.CombatIndicator

 	--[[ Callback: CombatIndicator:PreUpdate()
@@ -37,7 +38,7 @@ local function Update(self, event)
 		element:PreUpdate()
 	end

-	local inCombat = UnitAffectingCombat('player')
+	local inCombat = UnitAffectingCombat(unit)
 	if(inCombat) then
 		element:Show()
 	else
@@ -71,10 +72,12 @@ end

 local function Enable(self, unit)
 	local element = self.CombatIndicator
-	if(element and UnitIsUnit(unit, 'player')) then
+	if element then
 		element.__owner = self
 		element.ForceUpdate = ForceUpdate

+		self:RegisterEvent('UNIT_COMBAT', Path)
+		self:RegisterEvent('UNIT_FLAGS', Path)
 		self:RegisterEvent('PLAYER_REGEN_DISABLED', Path, true)
 		self:RegisterEvent('PLAYER_REGEN_ENABLED', Path, true)

@@ -92,6 +95,8 @@ local function Disable(self)
 	if(element) then
 		element:Hide()

+		self:UnregisterEvent('UNIT_COMBAT', Path)
+		self:UnregisterEvent('UNIT_FLAGS', Path)
 		self:UnregisterEvent('PLAYER_REGEN_DISABLED', Path)
 		self:UnregisterEvent('PLAYER_REGEN_ENABLED', Path)
 	end
diff --git a/oUF/elements/health.lua b/oUF/elements/health.lua
index 8ef1500..c0337f5 100644
--- a/oUF/elements/health.lua
+++ b/oUF/elements/health.lua
@@ -23,8 +23,10 @@ A default texture will be applied if the widget is a StatusBar and doesn't have

 The following options are listed by priority. The first check that returns true decides the color of the bar.

-.colorTapping      - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
 .colorDisconnected - Use `self.colors.disconnected` to color the bar if the unit is offline (boolean)
+.colorTapping      - Use `self.colors.tapping` to color the bar if the unit isn't tapped by the player (boolean)
+.colorThreat       - Use `self.colors.threat[threat]` to color the bar based on the unit's threat status. `threat` is
+                     defined by the first return of [UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation) (boolean)
 .colorClass        - Use `self.colors.class[class]` to color the bar based on unit class. `class` is defined by the
                      second return of [UnitClass](http://wowprogramming.com/docs/api/UnitClass.html) (boolean)
 .colorClassNPC     - Use `self.colors.class[class]` to color the bar if the unit is a NPC (boolean)
@@ -45,37 +47,33 @@ The following options are listed by priority. The first check that returns true

 .multiplier - Used to tint the background based on the main widgets R, G and B values. Defaults to 1 (number)[0-1]

-## Attributes
-
-.disconnected - Indicates whether the unit is disconnected (boolean)
-
 ## Examples

-	-- Position and size
-	local Health = CreateFrame('StatusBar', nil, self)
-	Health:SetHeight(20)
-	Health:SetPoint('TOP')
-	Health:SetPoint('LEFT')
-	Health:SetPoint('RIGHT')
-
-	-- Add a background
-	local Background = Health:CreateTexture(nil, 'BACKGROUND')
-	Background:SetAllPoints(Health)
-	Background:SetTexture(1, 1, 1, .5)
-
-	-- Options
-	Health.colorTapping = true
-	Health.colorDisconnected = true
-	Health.colorClass = true
-	Health.colorReaction = true
-	Health.colorHealth = true
-
-	-- Make the background darker.
-	Background.multiplier = .5
-
-	-- Register it with oUF
-	Health.bg = Background
-	self.Health = Health
+    -- Position and size
+    local Health = CreateFrame('StatusBar', nil, self)
+    Health:SetHeight(20)
+    Health:SetPoint('TOP')
+    Health:SetPoint('LEFT')
+    Health:SetPoint('RIGHT')
+
+    -- Add a background
+    local Background = Health:CreateTexture(nil, 'BACKGROUND')
+    Background:SetAllPoints(Health)
+    Background:SetTexture(1, 1, 1, .5)
+
+    -- Options
+    Health.colorTapping = true
+    Health.colorDisconnected = true
+    Health.colorClass = true
+    Health.colorReaction = true
+    Health.colorHealth = true
+
+    -- Make the background darker.
+    Background.multiplier = .5
+
+    -- Register it with oUF
+    Health.bg = Background
+    self.Health = Health
 --]]

 local _, ns = ...
@@ -83,21 +81,25 @@ local oUF = ns.oUF
 local Private = oUF.Private

 local unitSelectionType = Private.unitSelectionType
+local _, PlayerClass = UnitClass('player')

 local function UpdateColor(self, event, unit)
 	if(not unit or self.unit ~= unit) then return end
 	local element = self.Health

 	local r, g, b, t
-	if(element.colorDisconnected and element.disconnected) then
+	if(element.colorDisconnected and not UnitIsConnected(unit)) then
 		t = self.colors.disconnected
 	elseif(element.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)) then
 		t = self.colors.tapped
-	elseif(element.colorHappiness and unit == "pet" and GetPetHappiness()) then
+	elseif(element.colorHappiness and not oUF.isRetail and PlayerClass == "HUNTER" and UnitIsUnit(unit, "pet") and GetPetHappiness()) then
 		t = self.colors.happiness[GetPetHappiness()]
-	elseif(element.colorClass and UnitIsPlayer(unit)) or
-		(element.colorClassNPC and not UnitIsPlayer(unit)) or
-		(element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
+	elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
+		t =  self.colors.threat[UnitThreatSituation('player', unit)]
+	elseif(element.colorClass and UnitIsPlayer(unit))
+		or (element.colorClassNPC and not UnitIsPlayer(unit))
+		or ((element.colorClassPet or element.colorPetByUnitClass) and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
+		if element.colorPetByUnitClass then unit = unit == 'pet' and 'player' or gsub(unit, 'pet', '') end
 		local _, class = UnitClass(unit)
 		t = self.colors.class[class]
 	elseif(element.colorSelection and unitSelectionType(unit, element.considerSelectionInCombatHostile)) then
@@ -124,6 +126,15 @@ local function UpdateColor(self, event, unit)
 		end
 	end

+	--[[ Callback: Health:PostUpdateColor(unit, r, g, b)
+	Called after the element color has been updated.
+
+	* self - the Health element
+	* unit - the unit for which the update has been triggered (string)
+	* r    - the red component of the used color (number)[0-1]
+	* g    - the green component of the used color (number)[0-1]
+	* b    - the blue component of the used color (number)[0-1]
+	--]]
 	if(element.PostUpdateColor) then
 		element:PostUpdateColor(unit, r, g, b)
 	end
@@ -155,18 +166,16 @@ local function Update(self, event, unit)
 	end

 	local cur, max = UnitHealth(unit), UnitHealthMax(unit)
-	local disconnected = not UnitIsConnected(unit)
 	element:SetMinMaxValues(0, max)

-	if(disconnected) then
-		element:SetValue(max)
-	else
+	if(UnitIsConnected(unit)) then
 		element:SetValue(cur)
+	else
+		element:SetValue(max)
 	end

 	element.cur = cur
 	element.max = max
-	element.disconnected = disconnected

 	--[[ Callback: Health:PostUpdate(unit, cur, max)
 	Called after the element has been updated.
@@ -182,6 +191,8 @@ local function Update(self, event, unit)
 end

 local function Path(self, event, ...)
+	if (self.isForced and event ~= 'ElvUI_UpdateAllElements') then return end -- ElvUI changed
+
 	--[[ Override: Health.Override(self, event, unit)
 	Used to completely override the internal update function.

@@ -198,62 +209,132 @@ local function ForceUpdate(element)
 	Path(element.__owner, 'ForceUpdate', element.__owner.unit)
 end

-local onUpdateElapsed, onUpdateWait = 0, 0.25
-local function onUpdateHealth(self, elapsed)
-	if onUpdateElapsed > onUpdateWait then
-		Path(self.__owner, 'OnUpdate', self.__owner.unit)
+--[[ Health:SetColorDisconnected(state, isForced)
+Used to toggle coloring if the unit is offline.

-		onUpdateElapsed = 0
-	else
-		onUpdateElapsed = onUpdateElapsed + elapsed
+* self     - the Health element
+* state    - the desired state (boolean)
+* isForced - forces the event update even if the state wasn't changed (boolean)
+--]]
+local function SetColorDisconnected(element, state, isForced)
+	if(element.colorDisconnected ~= state or isForced) then
+		element.colorDisconnected = state
+		if(state) then
+			element.__owner:RegisterEvent('UNIT_CONNECTION', ColorPath)
+			element.__owner:RegisterEvent('PARTY_MEMBER_ENABLE', ColorPath)
+			element.__owner:RegisterEvent('PARTY_MEMBER_DISABLE', ColorPath)
+		else
+			element.__owner:UnregisterEvent('UNIT_CONNECTION', ColorPath)
+			element.__owner:UnregisterEvent('PARTY_MEMBER_ENABLE', ColorPath)
+			element.__owner:UnregisterEvent('PARTY_MEMBER_DISABLE', ColorPath)
+		end
 	end
 end

-local function SetHealthUpdateSpeed(self, state)
-	if state < .1 then state = .1 end
-	onUpdateWait = state
+--[[ Health:SetColorSelection(state, isForced)
+Used to toggle coloring by the unit's selection.
+
+* self     - the Health element
+* state    - the desired state (boolean)
+* isForced - forces the event update even if the state wasn't changed (boolean)
+--]]
+local function SetColorSelection(element, state, isForced)
+	if(element.colorSelection ~= state or isForced) then
+		element.colorSelection = state
+		if(state) then
+			element.__owner:RegisterEvent('UNIT_FLAGS', ColorPath)
+		else
+			element.__owner:UnregisterEvent('UNIT_FLAGS', ColorPath)
+		end
+	end
 end

-local function SetHealthUpdateMethod(self, state, force)
-	if self.effectiveHealth ~= state or force then
-		self.effectiveHealth = state
+--[[ Health:SetColorTapping(state, isForced)
+Used to toggle coloring if the unit isn't tapped by the player.

-		if state then
-			self.Health:SetScript('OnUpdate', onUpdateHealth)
-			self:UnregisterEvent('UNIT_HEALTH_FREQUENT', Path)
-			self:UnregisterEvent('UNIT_HEALTH', Path)
-			self:UnregisterEvent('UNIT_MAXHEALTH', Path)
+* self     - the Health element
+* state    - the desired state (boolean)
+* isForced - forces the event update even if the state wasn't changed (boolean)
+--]]
+local function SetColorTapping(element, state, isForced)
+	if(element.colorTapping ~= state or isForced) then
+		element.colorTapping = state
+		if(state) then
+			element.__owner:RegisterEvent('UNIT_FACTION', ColorPath)
 		else
-			self.Health:SetScript('OnUpdate', nil)
-			self:RegisterEvent('UNIT_HEALTH', Path) -- Needed for Pet Battles
-			self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path)
-			self:RegisterEvent('UNIT_MAXHEALTH', Path)
+			element.__owner:UnregisterEvent('UNIT_FACTION', ColorPath)
 		end
 	end
 end

-local function Enable(self, unit)
+--[[ Health:SetColorThreat(state, isForced)
+Used to toggle coloring by the unit's threat status.
+
+* self     - the Health element
+* state    - the desired state (boolean)
+* isForced - forces the event update even if the state wasn't changed (boolean)
+--]]
+local function SetColorThreat(element, state, isForced)
+	if(element.colorThreat ~= state or isForced) then
+		element.colorThreat = state
+		if(state) then
+			element.__owner:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+		else
+			element.__owner:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+		end
+	end
+end
+
+local function SetColorHappiness(element, state, isForced)
+	if(element.colorHappiness ~= state or isForced) then
+		element.colorHappiness = state
+
+		if(state) then
+			element.__owner:RegisterEvent('UNIT_HAPPINESS', ColorPath)
+		else
+			element.__owner:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+		end
+	end
+end
+
+local function Enable(self)
 	local element = self.Health
 	if(element) then
 		element.__owner = self
 		element.ForceUpdate = ForceUpdate
+		element.SetColorHappiness = SetColorHappiness
+		element.SetColorDisconnected = SetColorDisconnected
+		element.SetColorSelection = SetColorSelection
+		element.SetColorTapping = SetColorTapping
+		element.SetColorThreat = SetColorThreat
+
+		oUF:RegisterEvent(self, 'UNIT_MAXHEALTH', Path)

-		self.SetHealthUpdateSpeed = SetHealthUpdateSpeed
-		self.SetHealthUpdateMethod = SetHealthUpdateMethod
-		SetHealthUpdateMethod(self, self.effectiveHealth, true)
+		if oUF.isRetail then
+			oUF:RegisterEvent(self, 'UNIT_HEALTH', Path)
+		else
+			oUF:RegisterEvent(self, 'UNIT_HEALTH_FREQUENT', Path)
+		end

 		if(element.colorDisconnected) then
-			self:RegisterEvent('UNIT_CONNECTION', ColorPath)
-			self:RegisterEvent('PARTY_MEMBER_ENABLE', ColorPath)
-			self:RegisterEvent('PARTY_MEMBER_DISABLE', ColorPath)
+			oUF:RegisterEvent(self, 'UNIT_CONNECTION', ColorPath)
+			oUF:RegisterEvent(self, 'PARTY_MEMBER_ENABLE', ColorPath)
+			oUF:RegisterEvent(self, 'PARTY_MEMBER_DISABLE', ColorPath)
+		end
+
+		if(element.colorSelection) then
+			oUF:RegisterEvent(self, 'UNIT_FLAGS', ColorPath)
 		end

 		if(element.colorTapping) then
-			self:RegisterEvent('UNIT_FACTION', ColorPath)
+			oUF:RegisterEvent(self, 'UNIT_FACTION', ColorPath)
+		end
+
+		if(element.colorThreat) then
+			oUF:RegisterEvent(self, 'UNIT_THREAT_LIST_UPDATE', ColorPath)
 		end
-		self:RegisterEvent('UNIT_HAPPINESS', ColorPath)

-		if(element:IsObjectType('StatusBar') and not element:GetStatusBarTexture()) then
+		if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then
 			element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
 		end

@@ -268,17 +349,20 @@ local function Disable(self)
 	if(element) then
 		element:Hide()

-		element:SetScript('OnUpdate', nil)
-		self:UnregisterEvent('UNIT_HEALTH_FREQUENT', Path)
-		self:UnregisterEvent('UNIT_HEALTH', Path)
-		self:UnregisterEvent('UNIT_MAXHEALTH', Path)
+		if oUF.isRetail then
+			oUF:UnregisterEvent(self, 'UNIT_HEALTH', Path)
+		else
+			oUF:UnregisterEvent(self, 'UNIT_HEALTH_FREQUENT', Path)
+		end

-		self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
-		self:UnregisterEvent('UNIT_FACTION', ColorPath)
-		self:UnregisterEvent('PARTY_MEMBER_ENABLE', ColorPath)
-		self:UnregisterEvent('PARTY_MEMBER_DISABLE', ColorPath)
-		self:UnregisterEvent('UNIT_HAPPINESS', ColorPath)
+		oUF:UnregisterEvent(self, 'UNIT_MAXHEALTH', Path)
+		oUF:UnregisterEvent(self, 'UNIT_CONNECTION', ColorPath)
+		oUF:UnregisterEvent(self, 'UNIT_FACTION', ColorPath)
+		oUF:UnregisterEvent(self, 'UNIT_FLAGS', ColorPath)
+		oUF:UnregisterEvent(self, 'PARTY_MEMBER_ENABLE', ColorPath)
+		oUF:UnregisterEvent(self, 'PARTY_MEMBER_DISABLE', ColorPath)
+		oUF:UnregisterEvent(self, 'UNIT_THREAT_LIST_UPDATE', ColorPath)
 	end
 end

-oUF:AddElement('Health', Path, Enable, Disable)
\ No newline at end of file
+oUF:AddElement('Health', Path, Enable, Disable)
diff --git a/oUF/elements/healthprediction.lua b/oUF/elements/healthprediction.lua
index 56f7f08..80742db 100644
--- a/oUF/elements/healthprediction.lua
+++ b/oUF/elements/healthprediction.lua
@@ -80,25 +80,8 @@ A default texture will be applied to the Texture widgets if they don't have a te

 local _, ns = ...
 local oUF = ns.oUF
-local myGUID = UnitGUID('player')
-local HealComm, ALL_PENDING_HEALS, ALL_OVERTIME_HEALS, HEAL_TICK_INTERVAL

-if not oUF.isRetail then
-	HealComm = LibStub("LibHealComm-4.0")
-
-	ALL_PENDING_HEALS = bit.bor(HealComm.DIRECT_HEALS, HealComm.BOMB_HEALS)
-	ALL_OVERTIME_HEALS = bit.bor(HealComm.CHANNEL_HEALS, HealComm.HOT_HEALS)
-	HEAL_TICK_INTERVAL = 3
-end
-
-local function GetHealAmount(targetGUID, currentTime, casterGUID)
-    local nextTickTime = currentTime + HEAL_TICK_INTERVAL
-
-    local pendingHeal = HealComm:GetHealAmount(targetGUID, ALL_PENDING_HEALS, nil, casterGUID) or 0
-    local overtimeHeal = HealComm:GetHealAmount(targetGUID, ALL_OVERTIME_HEALS, nextTickTime, casterGUID) or 0
-
-    return (pendingHeal + overtimeHeal) * HealComm:GetHealModifier(casterGUID)
-end
+local HealComm = LibStub('LibHealComm-4.0', true)

 local function Update(self, event, unit)
 	if(self.unit ~= unit) then return end
@@ -115,13 +98,12 @@ local function Update(self, event, unit)
 		element:PreUpdate(unit)
 	end

-	local guid = UnitGUID(unit)
-	local currentTime = GetTime()
-	local isSmoothedEvent = event == "UNIT_MAXHEALTH" or event == "UNIT_HEALTH_FREQUENT" or event == "UNIT_HEALTH"
-	local myIncomingHeal = not oUF.isRetail and GetHealAmount(guid, currentTime, myGUID) or UnitGetIncomingHeals(unit, 'player') or 0
-	local allIncomingHeal = not oUF.isRetail and GetHealAmount(guid, currentTime, nil) or UnitGetIncomingHeals(unit) or 0
-	local absorb = oUF.Retail and UnitGetTotalAbsorbs(unit) or 0
-	local healAbsorb = oUF.Retail and UnitGetTotalHealAbsorbs(unit) or 0
+	local GUID = UnitGUID(unit)
+	local myIncomingHeal = UnitGetIncomingHeals(unit, 'player') or 0
+	local allIncomingHeal = UnitGetIncomingHeals(unit) or 0
+	local overTimeHeals = not oUF.isRetail and HealComm and ((HealComm:GetHealAmount(GUID, HealComm.OVERTIME_AND_BOMB_HEALS) or 0) * (HealComm:GetHealModifier(GUID) or 1)) or 0
+	local absorb = oUF.isRetail and UnitGetTotalAbsorbs(unit) or 0
+	local healAbsorb = oUF.isRetail and UnitGetTotalHealAbsorbs(unit) or 0
 	local health, maxHealth = UnitHealth(unit), UnitHealthMax(unit)
 	local otherIncomingHeal = 0
 	local hasOverHealAbsorb = false
@@ -133,7 +115,6 @@ local function Update(self, event, unit)

 		if(health < healAbsorb) then
 			hasOverHealAbsorb = true
-			healAbsorb = health
 		end
 	else
 		allIncomingHeal = allIncomingHeal - healAbsorb
@@ -146,45 +127,25 @@ local function Update(self, event, unit)
 		if(allIncomingHeal < myIncomingHeal) then
 			myIncomingHeal = allIncomingHeal
 		else
-			otherIncomingHeal = allIncomingHeal - myIncomingHeal
+			otherIncomingHeal = allIncomingHeal - myIncomingHeal + overTimeHeals
 		end
 	end

 	local hasOverAbsorb = false
-	if(health + allIncomingHeal + absorb >= maxHealth) then
-		if(absorb > 0) then
-			hasOverAbsorb = true
-		end
-
-		absorb = math.max(0, maxHealth - health - allIncomingHeal)
+	if(health + allIncomingHeal + absorb >= maxHealth) and (absorb > 0) then
+		hasOverAbsorb = true
 	end

 	if(element.myBar) then
-		if element.smoothing then
-            element.myBar:SetMinMaxSmoothedValue(0, maxHealth)
-            element.myBar:SetSmoothedValue(myIncomingHeal)
-        end
-
-		if not element.smoothing or not isSmoothedEvent then
-            element.myBar:SetMinMaxValues(0, maxHealth)
-            element.myBar:SetValue(myIncomingHeal)
-        end
-
-        element.myBar:Show()
+		element.myBar:SetMinMaxValues(0, maxHealth)
+		element.myBar:SetValue(myIncomingHeal)
+		element.myBar:Show()
 	end

 	if(element.otherBar) then
-		if element.smoothing then
-            element.otherBar:SetMinMaxSmoothedValue(0, maxHealth)
-            element.otherBar:SetSmoothedValue(otherIncomingHeal)
-        end
-
-		if not element.smoothing or not isSmoothedEvent then
-            element.otherBar:SetMinMaxValues(0, maxHealth)
-            element.otherBar:SetValue(otherIncomingHeal)
-        end
-
-        element.otherBar:Show()
+		element.otherBar:SetMinMaxValues(0, maxHealth)
+		element.otherBar:SetValue(otherIncomingHeal)
+		element.otherBar:Show()
 	end

 	if(element.absorbBar) then
@@ -228,11 +189,11 @@ local function Update(self, event, unit)
 	* hasOverHealAbsorb - indicates if the amount of heal absorb is higher than the unit's current health (boolean)
 	--]]
 	if(element.PostUpdate) then
-		return element:PostUpdate(unit, myIncomingHeal, otherIncomingHeal, absorb, healAbsorb, hasOverAbsorb, hasOverHealAbsorb)
+		return element:PostUpdate(unit, myIncomingHeal, otherIncomingHeal, absorb, healAbsorb, hasOverAbsorb, hasOverHealAbsorb, health, maxHealth)
 	end
 end

-local function Path(self, event, ...)
+local function Path(self, ...)
 	--[[ Override: HealthPrediction.Override(self, event, unit)
 	Used to completely override the internal update function.

@@ -240,75 +201,68 @@ local function Path(self, event, ...)
 	* event - the event triggering the update (string)
 	* unit  - the unit accompanying the event
 	--]]
-
-    if not oUF.Retail and self:IsVisible() then
-        for i = 1, select('#', ...) do
-            if self.unit and UnitGUID(self.unit) == (UnitGUID(select(i, ...)) or select(i, ...)) then
-                return (self.HealthPrediction.Override or Update) (self, event, self.unit)
-            end
-        end
-	else
-		return (self.HealthPrediction.Override or Update) (self, event, ...)
-    end
+	return (self.HealthPrediction.Override or Update) (self, ...)
 end

 local function ForceUpdate(element)
 	return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
 end

+local function HealComm_Check(self, element, ...)
+	if element and self:IsVisible() then
+		for i = 1, select('#', ...) do
+			if self.unit and UnitGUID(self.unit) == select(i, ...) then
+				Path(self, nil, self.unit)
+			end
+		end
+	end
+end
+
+local function HealComm_Create(self, element)
+	local update = function(event, casterGUID, spellID, healType, _, ...) HealComm_Check(self, element, ...) end
+	local modified = function(event, guid) HealComm_Check(self, element, guid) end
+	return update, modified
+end
+
 local function Enable(self)
 	local element = self.HealthPrediction
 	if(element) then
 		element.__owner = self
 		element.ForceUpdate = ForceUpdate

+		oUF:RegisterEvent(self, 'UNIT_MAXHEALTH', Path)
+		oUF:RegisterEvent(self, 'UNIT_HEAL_PREDICTION', Path)
+
 		if oUF.isRetail then
-			self:RegisterEvent('UNIT_HEALTH', Path)
-			self:RegisterEvent('UNIT_HEAL_PREDICTION', Path)
-			self:RegisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path)
-			self:RegisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path)
+			oUF:RegisterEvent(self, 'UNIT_HEALTH', Path)
+			oUF:RegisterEvent(self, 'UNIT_ABSORB_AMOUNT_CHANGED', Path)
+			oUF:RegisterEvent(self, 'UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path)
 		else
-			self:RegisterEvent('UNIT_HEALTH_FREQUENT', Path)
-
-			local function UpdateHeal(event, casterGUID, spellID, healType, _, ...)
-				Path(self, event, ...)
+			if not self.HealComm_Update then
+				self.HealComm_Update, self.HealComm_Modified = HealComm_Create(self, element)
 			end

-			local function UpdateModifier(event, guid)
-				Path(self, event, guid)
-			end
+			HealComm.RegisterCallback(element, 'HealComm_HealStarted', self.HealComm_Update)
+			HealComm.RegisterCallback(element, 'HealComm_HealUpdated', self.HealComm_Update)
+			HealComm.RegisterCallback(element, 'HealComm_HealDelayed', self.HealComm_Update)
+			HealComm.RegisterCallback(element, 'HealComm_HealStopped', self.HealComm_Update)
+			HealComm.RegisterCallback(element, 'HealComm_ModifierChanged', self.HealComm_Modified)
+			HealComm.RegisterCallback(element, 'HealComm_GUIDDisappeared', self.HealComm_Modified)

-			HealComm.RegisterCallback(self, "HealComm_HealStarted", UpdateHeal)
-			HealComm.RegisterCallback(self, "HealComm_HealUpdated", UpdateHeal)
-			HealComm.RegisterCallback(self, "HealComm_HealDelayed", UpdateHeal)
-			HealComm.RegisterCallback(self, "HealComm_HealStopped", UpdateHeal)
-			HealComm.RegisterCallback(self, "HealComm_ModifierChanged", UpdateModifier)
-			HealComm.RegisterCallback(self, "HealComm_GUIDDisappeared", UpdateModifier)
+			oUF:RegisterEvent(self, 'UNIT_HEALTH_FREQUENT', Path)
 		end

-		self:RegisterEvent('UNIT_MAXHEALTH', Path)
-
-		if(not element.maxOverflow) then
+		if (not element.maxOverflow) then
 			element.maxOverflow = 1.05
 		end

 		if(element.myBar) then
-			if(element.smoothing) then
-                element.myBar.SetSmoothedValue = SmoothStatusBarMixin.SetSmoothedValue
-                element.myBar.SetMinMaxSmoothedValue = SmoothStatusBarMixin.SetMinMaxSmoothedValue
-            end
-
 			if(element.myBar:IsObjectType('StatusBar') and not element.myBar:GetStatusBarTexture()) then
 				element.myBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
 			end
 		end

 		if(element.otherBar) then
-			if(element.smoothing) then
-                element.otherBar.SetSmoothedValue = SmoothStatusBarMixin.SetSmoothedValue
-                element.otherBar.SetMinMaxSmoothedValue = SmoothStatusBarMixin.SetMinMaxSmoothedValue
-            end
-
 			if(element.otherBar:IsObjectType('StatusBar') and not element.otherBar:GetStatusBarTexture()) then
 				element.otherBar:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
 			end
@@ -371,11 +325,23 @@ local function Disable(self)
 			element.overHealAbsorb:Hide()
 		end

-		self:UnregisterEvent('UNIT_HEALTH', Path)
-		self:UnregisterEvent('UNIT_MAXHEALTH', Path)
-		self:UnregisterEvent('UNIT_HEAL_PREDICTION', Path)
-		self:UnregisterEvent('UNIT_ABSORB_AMOUNT_CHANGED', Path)
-		self:UnregisterEvent('UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path)
+		oUF:UnregisterEvent(self, 'UNIT_MAXHEALTH', Path)
+		oUF:UnregisterEvent(self, 'UNIT_HEAL_PREDICTION', Path)
+
+		if oUF.isRetail then
+			oUF:UnregisterEvent(self, 'UNIT_HEALTH', Path)
+			oUF:UnregisterEvent(self, 'UNIT_ABSORB_AMOUNT_CHANGED', Path)
+			oUF:UnregisterEvent(self, 'UNIT_HEAL_ABSORB_AMOUNT_CHANGED', Path)
+		else
+			HealComm.UnregisterCallback(element, 'HealComm_HealStarted')
+			HealComm.UnregisterCallback(element, 'HealComm_HealUpdated')
+			HealComm.UnregisterCallback(element, 'HealComm_HealDelayed')
+			HealComm.UnregisterCallback(element, 'HealComm_HealStopped')
+			HealComm.UnregisterCallback(element, 'HealComm_ModifierChanged')
+			HealComm.UnregisterCallback(element, 'HealComm_GUIDDisappeared')
+
+			oUF:UnregisterEvent(self, 'UNIT_HEALTH_FREQUENT', Path)
+		end
 	end
 end

diff --git a/oUF/elements/leaderindicator.lua b/oUF/elements/leaderindicator.lua
index 70dd083..223ea0e 100644
--- a/oUF/elements/leaderindicator.lua
+++ b/oUF/elements/leaderindicator.lua
@@ -38,7 +38,15 @@ local function Update(self, event)
 		element:PreUpdate()
 	end

-	local isLeader = (UnitInParty(unit) or UnitInRaid(unit)) and UnitIsGroupLeader(unit)
+	-- ElvUI changed block
+	local isLeader
+	if IsInInstance() then
+		isLeader = UnitIsGroupLeader(unit)
+	else
+		isLeader = UnitLeadsAnyGroup(unit)
+	end
+	-- end block
+
 	if(isLeader) then
 		element:Show()
 	else
diff --git a/oUF/elements/partyindicator.lua b/oUF/elements/partyindicator.lua
new file mode 100644
index 0000000..3a2b153
--- /dev/null
+++ b/oUF/elements/partyindicator.lua
@@ -0,0 +1,90 @@
+--[[
+# Element: Party Indicator (by Caedis)
+	Toggles the visibility of an indicator based on if the player was in a group before joining the instance.
+
+## Widget
+	PartyIndicator - Player only widget.
+]]
+
+local _, ns = ...
+local oUF = ns.oUF
+
+local function Update(self, event)
+	local element = self.PartyIndicator
+
+	if(element.PreUpdate) then
+		element:PreUpdate()
+	end
+
+	local forced = not event or event == 'ElvUI_UpdateAllElements'
+	if forced or event == 'GROUP_ROSTER_UPDATE' then
+		if IsInGroup(LE_PARTY_CATEGORY_HOME) and IsInGroup(LE_PARTY_CATEGORY_INSTANCE) then
+			element:Show()
+		else
+			element:Hide()
+		end
+	end
+
+	if forced or event == 'UPDATE_CHAT_COLOR' then
+		local private = ChatTypeInfo.PARTY
+		if private and element.HomeIcon then
+			element.HomeIcon:SetVertexColor(private.r, private.g, private.b, 1)
+		end
+
+		local public = ChatTypeInfo.INSTANCE_CHAT
+		if public and element.InstanceIcon then
+			element.InstanceIcon:SetVertexColor(public.r, public.g, public.b, 1)
+		end
+	end
+
+	if(element.PostUpdate) then
+		return element:PostUpdate()
+	end
+end
+
+local function Path(self, ...)
+	--[[ Override: PartyIndicator.Override(self, event)
+	Used to completely override the internal update function.
+
+	* self  - the parent object
+	* event - the event triggering the update (string)
+	--]]
+	return (self.PartyIndicator.Override or Update) (self, ...)
+end
+
+local function ForceUpdate(element)
+	return Path(element.__owner, 'ForceUpdate')
+end
+
+local function Enable(self)
+	local element = self.PartyIndicator
+	if element then
+		element.__owner = self
+		element.ForceUpdate = ForceUpdate
+
+		self:RegisterEvent('UPDATE_CHAT_COLOR', Path, true)
+		self:RegisterEvent('GROUP_ROSTER_UPDATE', Path, true)
+
+		if(element.HomeIcon and element.HomeIcon:IsObjectType('Texture') and not element.HomeIcon:GetTexture()) then
+			element.HomeIcon:SetTexture([[Interface\FriendsFrame\UI-Toast-FriendOnlineIcon]])
+		end
+
+		if(element.InstanceIcon and element.InstanceIcon:IsObjectType('Texture') and not element.InstanceIcon:GetTexture()) then
+			element.InstanceIcon:SetTexture([[Interface\FriendsFrame\UI-Toast-FriendOnlineIcon]])
+		end
+
+		return true
+	end
+end
+
+local function Disable(self)
+	local element = self.PartyIndicator
+	if(element) then
+		element:Hide()
+
+		self:UnregisterEvent('UPDATE_CHAT_COLOR', Path)
+		self:UnregisterEvent('GROUP_ROSTER_UPDATE', Path)
+	end
+end
+
+oUF:AddElement('PartyIndicator', Path, Enable, Disable)
diff --git a/oUF/elements/phaseindicator.lua b/oUF/elements/phaseindicator.lua
index 24ac51d..18a62d5 100644
--- a/oUF/elements/phaseindicator.lua
+++ b/oUF/elements/phaseindicator.lua
@@ -7,16 +7,27 @@ Toggles the visibility of an indicator based on the unit's phasing relative to t

 PhaseIndicator - Any UI widget.

+## Sub-Widgets
+
+Icon - A `Texture` to represent the phased status.
+
 ## Notes

 A default texture will be applied if the widget is a Texture and doesn't have a texture or a color set.
+OnEnter and OnLeave script handlers will be set to display a Tooltip if the widget is mouse enabled and does not have
+OnEnter and/or OnLeave handlers.

 ## Examples

     -- Position and size
-    local PhaseIndicator = self:CreateTexture(nil, 'OVERLAY')
+    local PhaseIndicator = CreateFrame('Frame', nil, self)
     PhaseIndicator:SetSize(16, 16)
     PhaseIndicator:SetPoint('TOPLEFT', self)
+    PhaseIndicator:EnableMouse(true)
+
+    local Icon = PhaseIndicator:CreateTexture(nil, 'OVERLAY')
+    Icon:SetAllPoints()
+    PhaseIndicator.Icon = Icon

     -- Register it with oUF
     self.PhaseIndicator = PhaseIndicator
@@ -25,6 +36,38 @@ A default texture will be applied if the widget is a Texture and doesn't have a
 local _, ns = ...
 local oUF = ns.oUF

+local GameTooltip = GameTooltip
+
+--[[ Override: PhaseIndicator:UpdateTooltip()
+Used to populate the tooltip when the widget is hovered.
+
+* self - the PhaseIndicator widget
+--]]
+local function UpdateTooltip(element)
+	if GameTooltip:IsForbidden() then return end
+
+	local text = PartyUtil.GetPhasedReasonString(element.reason, element.__owner.unit)
+	if(text) then
+		GameTooltip:SetText(text, nil, nil, nil, nil, true)
+		GameTooltip:Show()
+	end
+end
+
+local function onEnter(element)
+	if GameTooltip:IsForbidden() or not element:IsVisible() then return end
+
+	if(element.reason) then
+		GameTooltip:SetOwner(element, 'ANCHOR_BOTTOMRIGHT')
+		element:UpdateTooltip()
+	end
+end
+
+local function onLeave()
+	if GameTooltip:IsForbidden() then return end
+
+	GameTooltip:Hide()
+end
+
 local function Update(self, event, unit)
 	if(self.unit ~= unit) then return end

@@ -39,21 +82,26 @@ local function Update(self, event, unit)
 		element:PreUpdate()
 	end

-	local isInSamePhase = UnitInPhase(unit)
-	if(not isInSamePhase and UnitIsPlayer(unit) and UnitIsConnected(unit)) then
+	-- BUG: UnitPhaseReason returns wrong data for friendly NPCs in phased scenarios like WM or Chromie Time
+	-- https://github.com/Stanzilla/WoWUIBugs/issues/49
+	local phaseReason = UnitIsPlayer(unit) and UnitIsConnected(unit) and UnitPhaseReason(unit) or nil
+	if(phaseReason) then
 		element:Show()
 	else
 		element:Hide()
 	end

-	--[[ Callback: PhaseIndicator:PostUpdate(isInSamePhase)
+	element.reason = phaseReason
+
+	--[[ Callback: PhaseIndicator:PostUpdate(isInSamePhase, phaseReason)
 	Called after the element has been updated.

 	* self          - the PhaseIndicator element
 	* isInSamePhase - indicates whether the unit is in the same phase as the player (boolean)
+	* phaseReason   - the reason why the unit is in a different phase (number?)
 	--]]
 	if(element.PostUpdate) then
-		return element:PostUpdate(isInSamePhase)
+		return element:PostUpdate(not phaseReason, phaseReason)
 	end
 end

@@ -80,8 +128,21 @@ local function Enable(self)

 		self:RegisterEvent('UNIT_PHASE', Path)

-		if(element:IsObjectType('Texture') and not element:GetTexture()) then
-			element:SetTexture([[Interface\TargetingFrame\UI-PhasingIcon]])
+		local icon = (element.Icon or element)
+		if(icon:IsObjectType('Texture') and not icon:GetTexture()) then
+			icon:SetTexture([[Interface\TargetingFrame\UI-PhasingIcon]])
+		end
+
+		if(element.IsMouseEnabled and element:IsMouseEnabled()) then
+			if(not element:GetScript('OnEnter')) then
+				element:SetScript('OnEnter', onEnter)
+			end
+
+			if(not element:GetScript('OnLeave')) then
+				element:SetScript('OnLeave', onLeave)
+			end
+
+			element.UpdateTooltip = element.UpdateTooltip or UpdateTooltip
 		end

 		return true
@@ -97,4 +158,4 @@ local function Disable(self)
 	end
 end

-oUF:AddElement('PhaseIndicator', Path, Enable, Disable)
\ No newline at end of file
+oUF:AddElement('PhaseIndicator', Path, Enable, Disable)
diff --git a/oUF/elements/portrait.lua b/oUF/elements/portrait.lua
index d68a637..81df9bf 100644
--- a/oUF/elements/portrait.lua
+++ b/oUF/elements/portrait.lua
@@ -12,6 +12,10 @@ Portrait - A `PlayerModel` or a `Texture` used to represent the unit's portrait.
 A question mark model will be used if the widget is a PlayerModel and the client doesn't have the model information for
 the unit.

+## Options
+
+.showClass - Displays the unit's class in the portrait (boolean)
+
 ## Examples

     -- 3D Portrait
@@ -35,6 +39,15 @@ the unit.
 local _, ns = ...
 local oUF = ns.oUF

+-- ElvUI block
+local UnitIsUnit = UnitIsUnit
+local UnitGUID = UnitGUID
+local UnitIsConnected = UnitIsConnected
+local UnitIsVisible = UnitIsVisible
+local UnitClassBase = UnitClassBase
+local SetPortraitTexture = SetPortraitTexture
+-- end block
+
 local function Update(self, event, unit)
 	if(not unit or not UnitIsUnit(self.unit, unit)) then return end

@@ -50,9 +63,14 @@ local function Update(self, event, unit)

 	local guid = UnitGUID(unit)
 	local isAvailable = UnitIsConnected(unit) and UnitIsVisible(unit)
-	if(event ~= 'OnUpdate' or element.guid ~= guid or element.state ~= isAvailable) then
-		if(element:IsObjectType('PlayerModel')) then
-			if(not isAvailable) then
+	local hasStateChanged = event ~= 'OnUpdate' or element.guid ~= guid or element.state ~= isAvailable
+	if hasStateChanged then
+		element.playerModel = element:IsObjectType('PlayerModel')
+		element.state = isAvailable
+		element.guid = guid
+
+		if element.playerModel then
+			if not isAvailable then
 				element:SetCamDistanceScale(0.25)
 				element:SetPortraitZoom(0)
 				element:SetPosition(0, 0, 0.25)
@@ -65,22 +83,25 @@ local function Update(self, event, unit)
 				element:ClearModel()
 				element:SetUnit(unit)
 			end
-		else
-			SetPortraitTexture(element, unit)
+		elseif not element.customTexture then -- ElvUI changed
+			local class = element.showClass and UnitClassBase(unit)
+			if class then
+				element:SetAtlas('classicon-' .. class)
+			else
+				SetPortraitTexture(element, unit)
+			end
 		end
-
-		element.guid = guid
-		element.state = isAvailable
 	end

 	--[[ Callback: Portrait:PostUpdate(unit)
 	Called after the element has been updated.

-	* self - the Portrait element
-	* unit - the unit for which the update has been triggered (string)
+	* self            - the Portrait element
+	* unit            - the unit for which the update has been triggered (string)
+	* hasStateChanged - indicates whether the state has changed since the last update (boolean)
 	--]]
 	if(element.PostUpdate) then
-		return element:PostUpdate(unit)
+		return element:PostUpdate(unit, hasStateChanged)
 	end
 end

diff --git a/oUF/elements/power.lua b/oUF/elements/power.lua
index 873618b..4f2fa81 100644
--- a/oUF/elements/power.lua
+++ b/oUF/elements/power.lua
@@ -22,6 +22,8 @@ A default texture will be applied if the widget is a StatusBar and doesn't have
 .displayAltPower                  - Use this to let the widget display alternative power, if the unit has one.
                                     By default, it does so only for raid and party units. If none, the display will fall
                                     back to the primary power (boolean)
+.useAtlas                         - Use this to let the widget use an atlas for its texture if an atlas is present in
+                                    `self.colors.power` for the appropriate power type (boolean)
 .smoothGradient                   - 9 color values to be used with the .colorSmooth option (table)
 .considerSelectionInCombatHostile - Indicates whether selection should be considered hostile while the unit is in
                                     combat with the player (boolean)
@@ -108,9 +110,9 @@ type and zero for the minimum value.
 --]]
 local function GetDisplayPower(element)
 	local unit = element.__owner.unit
-	local _, min, _, _, _, _, showOnRaid = UnitAlternatePowerInfo(unit)
-	if(showOnRaid) then
-		return ALTERNATE_POWER_INDEX, min
+	local barInfo = GetUnitPowerBarInfo(unit)
+	if(barInfo and barInfo.showOnRaid and (UnitInParty(unit) or UnitInRaid(unit))) then
+		return ALTERNATE_POWER_INDEX, barInfo.minPower
 	end
 end

@@ -120,14 +122,11 @@ local function UpdateColor(self, event, unit)

 	local pType, pToken, altR, altG, altB = UnitPowerType(unit)

-	local r, g, b, t
-	local happiness = GetPetHappiness()
+	local r, g, b, t, atlas
 	if(element.colorDisconnected and not UnitIsConnected(unit)) then
 		t = self.colors.disconnected
 	elseif(element.colorTapping and not UnitPlayerControlled(unit) and UnitIsTapDenied(unit)) then
 		t = self.colors.tapped
-	elseif(element.colorHappiness and unit == "pet" and happiness) then
-		t = self.colors.happiness[happiness]
 	elseif(element.colorThreat and not UnitPlayerControlled(unit) and UnitThreatSituation('player', unit)) then
 		t =  self.colors.threat[UnitThreatSituation('player', unit)]
 	elseif(element.colorPower) then
@@ -149,6 +148,10 @@ local function UpdateColor(self, event, unit)
 		else
 			t = self.colors.power[ALTERNATE_POWER_INDEX]
 		end
+
+		if(element.useAtlas and t and t.atlas) then
+			atlas = t.atlas
+		end
 	elseif(element.colorClass and UnitIsPlayer(unit))
 		or (element.colorClassNPC and not UnitIsPlayer(unit))
 		or (element.colorClassPet and UnitPlayerControlled(unit) and not UnitIsPlayer(unit)) then
@@ -167,7 +170,10 @@ local function UpdateColor(self, event, unit)
 		r, g, b = t[1], t[2], t[3]
 	end

-	if(b) then
+	if(atlas) then
+		element:SetStatusBarAtlas(atlas)
+		element:SetStatusBarColor(1, 1, 1)
+	elseif(b) then
 		element:SetStatusBarColor(r, g, b)

 		local bg = element.bg
@@ -180,12 +186,13 @@ local function UpdateColor(self, event, unit)
 	--[[ Callback: Power:PostUpdateColor(unit, r, g, b)
 	Called after the element color has been updated.

-	* self - the Power element
-	* unit - the unit for which the update has been triggered (string)
-	* r    - the red component of the used color (number)[0-1]
-	* g    - the green component of the used color (number)[0-1]
-	* b    - the blue component of the used color (number)[0-1]
+	local bg = element.bg
+	if(bg and b) then
+		local mu = bg.multiplier or 1
+		bg:SetVertexColor(r * mu, g * mu, b * mu)
+	end
 	--]]
+
 	if(element.PostUpdateColor) then
 		element:PostUpdateColor(unit, r, g, b)
 	end
@@ -217,12 +224,14 @@ local function Update(self, event, unit)
 	end

 	local displayType, min
-	if(element.displayAltPower) then
+	if(oUF.isRetail and element.displayAltPower) then
 		displayType, min = element:GetDisplayPower()
 	end

 	local cur, max = UnitPower(unit, displayType), UnitPowerMax(unit, displayType)
-	element:SetMinMaxValues(min or 0, max)
+	if not min then min = 0 end
+
+	element:SetMinMaxValues(min, max)

 	if(UnitIsConnected(unit)) then
 		element:SetValue(cur)
@@ -249,7 +258,9 @@ local function Update(self, event, unit)
 	end
 end

-local function Path(self, ...)
+local function Path(self, event, ...)
+	if (self.isForced and event ~= 'ElvUI_UpdateAllElements') then return end -- ElvUI changed
+
 	--[[ Override: Power.Override(self, event, unit, ...)
 	Used to completely override the internal update function.

@@ -258,9 +269,9 @@ local function Path(self, ...)
 	* unit  - the unit accompanying the event (string)
 	* ...   - the arguments accompanying the event
 	--]]
-	(self.Power.Override or Update) (self, ...);
+	(self.Power.Override or Update) (self, event, ...);

-	ColorPath(self, ...)
+	ColorPath(self, event, ...)
 end

 local function ForceUpdate(element)
@@ -370,39 +381,39 @@ local function Enable(self)
 		element.SetColorThreat = SetColorThreat
 		element.SetFrequentUpdates = SetFrequentUpdates

+		oUF:RegisterEvent(self, 'UNIT_MAXPOWER', Path)
+
+		if(element.frequentUpdates) then
+			oUF:RegisterEvent(self, 'UNIT_POWER_FREQUENT', Path)
+		else
+			oUF:RegisterEvent(self, 'UNIT_POWER_UPDATE', Path)
+		end
+
 		if(element.colorDisconnected) then
-			self:RegisterEvent('UNIT_CONNECTION', ColorPath)
+			oUF:RegisterEvent(self, 'UNIT_CONNECTION', ColorPath)
 		end

 		if(element.colorSelection) then
-			self:RegisterEvent('UNIT_FLAGS', ColorPath)
+			oUF:RegisterEvent(self, 'UNIT_FLAGS', ColorPath)
 		end

 		if(element.colorTapping) then
-			self:RegisterEvent('UNIT_FACTION', ColorPath)
+			oUF:RegisterEvent(self, 'UNIT_FACTION', ColorPath)
 		end

 		if(element.colorThreat) then
-			self:RegisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
-		end
-
-		if(element.frequentUpdates) then
-			self:RegisterEvent('UNIT_POWER_FREQUENT', Path)
-		else
-			self:RegisterEvent('UNIT_POWER_UPDATE', Path)
+			oUF:RegisterEvent(self, 'UNIT_THREAT_LIST_UPDATE', ColorPath)
 		end

-		self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
-		self:RegisterEvent('UNIT_MAXPOWER', Path)
-		self:RegisterEvent('UNIT_POWER_BAR_HIDE', Path)
-		self:RegisterEvent('UNIT_POWER_BAR_SHOW', Path)
-		self:RegisterEvent('UNIT_HAPPINESS', Path)
+		oUF:RegisterEvent(self, 'UNIT_DISPLAYPOWER', Path)
+		oUF:RegisterEvent(self, 'UNIT_POWER_BAR_HIDE', Path)
+		oUF:RegisterEvent(self, 'UNIT_POWER_BAR_SHOW', Path)

 		if(element:IsObjectType('StatusBar') and not (element:GetStatusBarTexture() or element:GetStatusBarAtlas())) then
 			element:SetStatusBarTexture([[Interface\TargetingFrame\UI-StatusBar]])
 		end

-		if(not element.GetDisplayPower) then
+		if(oUF.isRetail and not element.GetDisplayPower) then
 			element.GetDisplayPower = GetDisplayPower
 		end

@@ -417,18 +428,17 @@ local function Disable(self)
 	if(element) then
 		element:Hide()

-		self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
-		self:UnregisterEvent('UNIT_MAXPOWER', Path)
-		self:UnregisterEvent('UNIT_POWER_BAR_HIDE', Path)
-		self:UnregisterEvent('UNIT_POWER_BAR_SHOW', Path)
-		self:UnregisterEvent('UNIT_POWER_FREQUENT', Path)
-		self:UnregisterEvent('UNIT_POWER_UPDATE', Path)
-		self:UnregisterEvent('UNIT_HAPPINESS', Path)
-		self:UnregisterEvent('UNIT_CONNECTION', ColorPath)
-		self:UnregisterEvent('UNIT_FACTION', ColorPath)
-		self:UnregisterEvent('UNIT_FLAGS', ColorPath)
-		self:UnregisterEvent('UNIT_THREAT_LIST_UPDATE', ColorPath)
+		oUF:UnregisterEvent(self, 'UNIT_DISPLAYPOWER', Path)
+		oUF:UnregisterEvent(self, 'UNIT_MAXPOWER', Path)
+		oUF:UnregisterEvent(self, 'UNIT_POWER_BAR_HIDE', Path)
+		oUF:UnregisterEvent(self, 'UNIT_POWER_BAR_SHOW', Path)
+		oUF:UnregisterEvent(self, 'UNIT_POWER_FREQUENT', Path)
+		oUF:UnregisterEvent(self, 'UNIT_POWER_UPDATE', Path)
+		oUF:UnregisterEvent(self, 'UNIT_CONNECTION', ColorPath)
+		oUF:UnregisterEvent(self, 'UNIT_FACTION', ColorPath)
+		oUF:UnregisterEvent(self, 'UNIT_FLAGS', ColorPath)
+		oUF:UnregisterEvent(self, 'UNIT_THREAT_LIST_UPDATE', ColorPath)
 	end
 end

-oUF:AddElement('Power', Path, Enable, Disable)
\ No newline at end of file
+oUF:AddElement('Power', Path, Enable, Disable)
diff --git a/oUF/elements/powerprediction.lua b/oUF/elements/powerprediction.lua
index be28e42..7dc3f27 100644
--- a/oUF/elements/powerprediction.lua
+++ b/oUF/elements/powerprediction.lua
@@ -44,8 +44,8 @@ local _, ns = ...
 local oUF = ns.oUF

 -- sourced from FrameXML/AlternatePowerBar.lua
-local ADDITIONAL_POWER_BAR_INDEX = ADDITIONAL_POWER_BAR_INDEX or 0
-local ALT_MANA_BAR_PAIR_DISPLAY_INFO = ALT_MANA_BAR_PAIR_DISPLAY_INFO
+local ADDITIONAL_POWER_BAR_INDEX = _G.ADDITIONAL_POWER_BAR_INDEX or 0
+local ALT_MANA_BAR_PAIR_DISPLAY_INFO = _G.ALT_MANA_BAR_PAIR_DISPLAY_INFO

 local _, playerClass = UnitClass('player')

@@ -64,26 +64,31 @@ local function Update(self, event, unit)
 		element:PreUpdate(unit)
 	end

-	local _, _, _, startTime, endTime, _, _, notInterruptible, spellID = UnitCastingInfo(unit)
-	local mainPowerType = UnitPowerType(unit)
-	local hasAltManaBar = oUF.Retail and ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass] and ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass][mainPowerType]
 	local mainCost, altCost = 0, 0
+	local mainType = UnitPowerType(unit)
+	local mainMax = UnitPowerMax(unit, mainType)
+	local isPlayer = UnitIsUnit('player', unit)
+	local altManaInfo = isPlayer and oUF.isRetail and ALT_MANA_BAR_PAIR_DISPLAY_INFO[playerClass]
+	local hasAltManaBar = altManaInfo and altManaInfo[mainType]
+	local _, _, _, startTime, endTime, _, _, _, spellID = UnitCastingInfo(unit)

 	if(event == 'UNIT_SPELLCAST_START' and startTime ~= endTime) then
 		local costTable = GetSpellPowerCost(spellID)
-
-		-- hasRequiredAura is always false if there's only 1 subtable
-		local checkRequiredAura = #costTable > 1
-
-		for _, costInfo in next, costTable do
-			if(not checkRequiredAura or costInfo.hasRequiredAura) then
-				if(costInfo.type == mainPowerType) then
-					mainCost = costInfo.cost
+		if not costTable then
+			element.mainCost = mainCost
+			element.altCost = altCost
+		else
+			local checkRequiredAura = isPlayer and #costTable > 1
+			for _, costInfo in next, costTable do
+				local cost, ctype, cperc = costInfo.cost, costInfo.type, costInfo.costPercent
+				local checkSpec = not checkRequiredAura or costInfo.hasRequiredAura
+				if checkSpec and ctype == mainType then
+					mainCost = ((isPlayer or cost < mainMax) and cost) or (mainMax * cperc) / 100
 					element.mainCost = mainCost

 					break
-				elseif(costInfo.type == ADDITIONAL_POWER_BAR_INDEX) then
-					altCost = costInfo.cost
+				elseif hasAltManaBar and checkSpec and ctype == ADDITIONAL_POWER_BAR_INDEX then
+					altCost = cost
 					element.altCost = altCost

 					break
@@ -91,8 +96,7 @@ local function Update(self, event, unit)
 			end
 		end
 	elseif(spellID) then
-		-- if we try to cast a spell while casting another one we need to avoid
-		-- resetting the element
+		-- if we try to cast a spell while casting another one we need to avoid resetting the element
 		mainCost = element.mainCost or 0
 		altCost = element.altCost or 0
 	else
@@ -101,7 +105,7 @@ local function Update(self, event, unit)
 	end

 	if(element.mainBar) then
-		element.mainBar:SetMinMaxValues(0, UnitPowerMax(unit, mainPowerType))
+		element.mainBar:SetMinMaxValues(0, mainMax)
 		element.mainBar:SetValue(mainCost)
 		element.mainBar:Show()
 	end
@@ -142,17 +146,17 @@ local function ForceUpdate(element)
 	return Path(element.__owner, 'ForceUpdate', element.__owner.unit)
 end

-local function Enable(self, unit)
+local function Enable(self)
 	local element = self.PowerPrediction
-	if(element and UnitIsUnit(unit, 'player')) then
+	if(element) then
 		element.__owner = self
 		element.ForceUpdate = ForceUpdate

-		self:RegisterEvent('UNIT_SPELLCAST_START', Path)
-		self:RegisterEvent('UNIT_SPELLCAST_STOP', Path)
-		self:RegisterEvent('UNIT_SPELLCAST_FAILED', Path)
-		self:RegisterEvent('UNIT_SPELLCAST_SUCCEEDED', Path)
-		self:RegisterEvent('UNIT_DISPLAYPOWER', Path)
+		oUF:RegisterEvent(self, 'UNIT_SPELLCAST_START', Path)
+		oUF:RegisterEvent(self, 'UNIT_SPELLCAST_STOP', Path)
+		oUF:RegisterEvent(self, 'UNIT_SPELLCAST_FAILED', Path)
+		oUF:RegisterEvent(self, 'UNIT_SPELLCAST_SUCCEEDED', Path)
+		oUF:RegisterEvent(self, 'UNIT_DISPLAYPOWER', Path)

 		if(element.mainBar) then
 			if(element.mainBar:IsObjectType('StatusBar')
@@ -183,11 +187,11 @@ local function Disable(self)
 			element.altBar:Hide()
 		end

-		self:UnregisterEvent('UNIT_SPELLCAST_START', Path)
-		self:UnregisterEvent('UNIT_SPELLCAST_STOP', Path)
-		self:UnregisterEvent('UNIT_SPELLCAST_FAILED', Path)
-		self:UnregisterEvent('UNIT_SPELLCAST_SUCCEEDED', Path)
-		self:UnregisterEvent('UNIT_DISPLAYPOWER', Path)
+		oUF:UnregisterEvent(self, 'UNIT_SPELLCAST_START', Path)
+		oUF:UnregisterEvent(self, 'UNIT_SPELLCAST_STOP', Path)
+		oUF:UnregisterEvent(self, 'UNIT_SPELLCAST_FAILED', Path)
+		oUF:UnregisterEvent(self, 'UNIT_SPELLCAST_SUCCEEDED', Path)
+		oUF:UnregisterEvent(self, 'UNIT_DISPLAYPOWER', Path)
 	end
 end

diff --git a/oUF/elements/pvpindicator.lua b/oUF/elements/pvpindicator.lua
index 9cb2c66..5963371 100644
--- a/oUF/elements/pvpindicator.lua
+++ b/oUF/elements/pvpindicator.lua
@@ -53,12 +53,12 @@ local function Update(self, event, unit)

 	local status
 	local factionGroup = UnitFactionGroup(unit) or 'Neutral'
-	local honorRewardInfo = C_PvP.GetHonorRewardInfo(UnitHonorLevel(unit))
+	local honorRewardInfo = oUF.isRetail and C_PvP.GetHonorRewardInfo(UnitHonorLevel(unit))

 	if(UnitIsPVPFreeForAll(unit)) then
 		status = 'FFA'
 	elseif(factionGroup ~= 'Neutral' and UnitIsPVP(unit)) then
-		if(unit == 'player' and UnitIsMercenary(unit)) then
+		if oUF.isRetail and (unit == 'player' and UnitIsMercenary(unit)) then
 			if(factionGroup == 'Horde') then
 				factionGroup = 'Alliance'
 			elseif(factionGroup == 'Alliance') then
@@ -128,7 +128,10 @@ local function Enable(self)
 		element.ForceUpdate = ForceUpdate

 		self:RegisterEvent('UNIT_FACTION', Path)
-		self:RegisterEvent('HONOR_LEVEL_UPDATE', Path, true)
+
+		if oUF.isRetail then
+			self:RegisterEvent('HONOR_LEVEL_UPDATE', Path, true)
+		end

 		return true
 	end
@@ -144,7 +147,10 @@ local function Disable(self)
 		end

 		self:UnregisterEvent('UNIT_FACTION', Path)
-		self:UnregisterEvent('HONOR_LEVEL_UPDATE', Path)
+
+		if oUF.isRetail then
+			self:UnregisterEvent('HONOR_LEVEL_UPDATE', Path)
+		end
 	end
 end

diff --git a/oUF/elements/raidroleindicator.lua b/oUF/elements/raidroleindicator.lua
index ed63d82..26941bc 100644
--- a/oUF/elements/raidroleindicator.lua
+++ b/oUF/elements/raidroleindicator.lua
@@ -42,7 +42,8 @@ local function Update(self, event)
 	end

 	local role, isShown
-	if(UnitInRaid(unit)) then
+	local inVehicle = (oUF.isRetail or oUF.isWrath) and UnitHasVehicleUI(unit)
+	if(UnitInRaid(unit) and not inVehicle) then
 		if(GetPartyAssignment('MAINTANK', unit)) then
 			isShown = true
 			element:SetTexture(MAINTANK_ICON)
diff --git a/oUF/elements/readycheckindicator.lua b/oUF/elements/readycheckindicator.lua
index 1906301..1c710c3 100644
--- a/oUF/elements/readycheckindicator.lua
+++ b/oUF/elements/readycheckindicator.lua
@@ -122,14 +122,14 @@ end

 local function Enable(self, unit)
 	local element = self.ReadyCheckIndicator
-	unit = unit and unit:match('(%a+)%d*')
+	unit = unit and unit:match('(%a+)%d*$')
 	if(element and (unit == 'party' or unit == 'raid')) then
 		element.__owner = self
 		element.ForceUpdate = ForceUpdate

-		element.readyTexture = element.readyTexture or READY_CHECK_READY_TEXTURE
-		element.notReadyTexture = element.notReadyTexture or READY_CHECK_NOT_READY_TEXTURE
-		element.waitingTexture = element.waitingTexture or READY_CHECK_WAITING_TEXTURE
+		element.readyTexture = element.readyTexture or _G.READY_CHECK_READY_TEXTURE
+		element.notReadyTexture = element.notReadyTexture or _G.READY_CHECK_NOT_READY_TEXTURE
+		element.waitingTexture = element.waitingTexture or _G.READY_CHECK_WAITING_TEXTURE

 		local AnimationGroup = element:CreateAnimationGroup()
 		AnimationGroup:HookScript('OnFinished', OnFinished)
diff --git a/oUF/elements/runes.lua b/oUF/elements/runes.lua
index 2c75253..7d41ef0 100644
--- a/oUF/elements/runes.lua
+++ b/oUF/elements/runes.lua
@@ -47,7 +47,16 @@ if(select(2, UnitClass('player')) ~= 'DEATHKNIGHT') then return end
 local _, ns = ...
 local oUF = ns.oUF

-local runemap = {1, 2, 3, 4, 5, 6}
+local sort = sort
+local ipairs = ipairs
+local UnitHasVehicleUI = UnitHasVehicleUI
+local GetSpecialization = GetSpecialization
+local GetRuneCooldown = GetRuneCooldown
+local GetRuneType = GetRuneType
+local UnitIsUnit = UnitIsUnit
+local GetTime = GetTime
+
+local runemap = oUF.isWrath and {1, 2, 5, 6, 3, 4} or {1, 2, 3, 4, 5, 6}
 local hasSortOrder = false

 local function onUpdate(self, elapsed)
@@ -80,27 +89,56 @@ local function descSort(runeAID, runeBID)
 	end
 end

-local function UpdateColor(self, event)
-	local element = self.Runes
+local function UpdateRuneType(rune, runeID, alt)
+	rune.runeType = GetRuneType(runeID) or alt

-	local spec = GetSpecialization() or 0
+	return rune
+end

-	local color
-	if(spec > 0 and spec < 4 and element.colorSpec) then
-		color = self.colors.runes[spec]
-	else
-		color = self.colors.power.RUNES
+local function ColorRune(self, bar, runeType)
+	local color = runeType and self.colors.runes[runeType] or self.colors.power.RUNES
+	local r, g, b = color[1], color[2], color[3]
+	bar:SetStatusBarColor(r, g, b)
+
+	local bg = bar.bg
+	if bg then
+		local mu = bg.multiplier or 1
+		bg:SetVertexColor(r * mu, g * mu, b * mu)
 	end

-	local r, g, b = color[1], color[2], color[3]
+	return color, r, g, b
+end

-	for index = 1, #element do
-		element[index]:SetStatusBarColor(r, g, b)
+local function UpdateColor(self, event, runeID, alt)
+	local element = self.Runes

-		local bg = element[index].bg
-		if(bg) then
-			local mu = bg.multiplier or 1
-			bg:SetVertexColor(r * mu, g * mu, b * mu)
+	local rune, specType
+	if oUF.isWrath then -- runeID, alt
+		if runeID and event == 'RUNE_TYPE_UPDATE' then
+			rune = UpdateRuneType(element[runemap[runeID]], runeID, alt)
+		end
+	else
+		local spec = element.colorSpec and GetSpecialization() or 0
+		if spec > 0 and spec < 4 then
+			specType = spec
+		end
+	end
+
+	local color, r, g, b
+	if rune then
+		color, r, g, b = ColorRune(self, rune, specType or rune.runeType)
+	else
+		for i = 1, #element do
+			local bar = element[i]
+			if oUF.isWrath then
+				if not bar.runeType then
+					bar.runeType = GetRuneType(runemap[i])
+				end
+			else
+				bar.runeType = specType
+			end
+
+			color, r, g, b = ColorRune(self, bar, specType or bar.runeType)
 		end
 	end

@@ -113,7 +151,7 @@ local function UpdateColor(self, event)
 	* b    - the blue component of the used color (number)[0-1]
 	--]]
 	if(element.PostUpdateColor) then
-		element:PostUpdateColor(r, g, b)
+		element:PostUpdateColor(r, g, b, color, rune)
 	end
 end

@@ -131,37 +169,47 @@ end
 local function Update(self, event)
 	local element = self.Runes

-	if(element.sortOrder == 'asc') then
-		table.sort(runemap, ascSort)
-		hasSortOrder = true
-	elseif(element.sortOrder == 'desc') then
-		table.sort(runemap, descSort)
-		hasSortOrder = true
-	elseif(hasSortOrder) then
-		table.sort(runemap)
-		hasSortOrder = false
+	if not oUF.isWrath then
+		if element.sortOrder == 'asc' then
+			sort(runemap, ascSort)
+			hasSortOrder = true
+		elseif element.sortOrder == 'desc' then
+			sort(runemap, descSort)
+			hasSortOrder = true
+		elseif hasSortOrder then
+			sort(runemap)
+			hasSortOrder = false
+		end
 	end

-	local rune, start, duration, runeReady
-	for index, runeID in next, runemap do
-		rune = element[index]
-		if(not rune) then break end
+	local allReady = true
+	local currentTime = GetTime()
+	local hasVehicle = UnitHasVehicleUI('player')
+	for index, runeID in ipairs(runemap) do
+		local rune = element[index]
+		if not rune then break end

-		if(UnitHasVehicleUI('player')) then
+		if hasVehicle then
 			rune:Hide()
+
+			allReady = false
 		else
-			start, duration, runeReady = GetRuneCooldown(runeID)
-			if(runeReady) then
+			local start, duration, runeReady = GetRuneCooldown(runeID)
+			if runeReady then
 				rune:SetMinMaxValues(0, 1)
 				rune:SetValue(1)
 				rune:SetScript('OnUpdate', nil)
-			elseif(start) then
-				rune.duration = GetTime() - start
+			elseif start then
+				rune.duration = currentTime - start
 				rune:SetMinMaxValues(0, duration)
 				rune:SetValue(0)
 				rune:SetScript('OnUpdate', onUpdate)
 			end

+			if not runeReady then
+				allReady = false
+			end
+
 			rune:Show()
 		end
 	end
@@ -173,7 +221,7 @@ local function Update(self, event)
 	* runemap - the ordered list of runes' indices (table)
 	--]]
 	if(element.PostUpdate) then
-		return element:PostUpdate(runemap)
+		return element:PostUpdate(runemap, hasVehicle, allReady)
 	end
 end

@@ -211,7 +259,18 @@ local function Enable(self, unit)
 			end
 		end

-		self:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath)
+		-- ElvUI block
+		if element.IsObjectType and element:IsObjectType("Frame") then
+			element:Show()
+		end
+		-- end block
+
+		if oUF.isRetail then
+			self:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath)
+		else
+			self:RegisterEvent('RUNE_TYPE_UPDATE', ColorPath, true)
+		end
+
 		self:RegisterEvent('RUNE_POWER_UPDATE', Path, true)

 		return true
@@ -225,7 +284,18 @@ local function Disable(self)
 			element[i]:Hide()
 		end

-		self:UnregisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath)
+		-- ElvUI block
+		if element.IsObjectType and element:IsObjectType("Frame") then
+			element:Hide()
+		end
+		-- end block
+
+		if oUF.isRetail then
+			self:UnregisterEvent('PLAYER_SPECIALIZATION_CHANGED', ColorPath)
+		else
+			self:UnregisterEvent('RUNE_TYPE_UPDATE', ColorPath)
+		end
+
 		self:UnregisterEvent('RUNE_POWER_UPDATE', Path)
 	end
 end
diff --git a/oUF/elements/stagger.lua b/oUF/elements/stagger.lua
index 0ae3a61..5f2806e 100644
--- a/oUF/elements/stagger.lua
+++ b/oUF/elements/stagger.lua
@@ -34,20 +34,29 @@ if(select(2, UnitClass('player')) ~= 'MONK') then return end
 local _, ns = ...
 local oUF = ns.oUF

+-- ElvUI block
+local GetSpecialization = GetSpecialization
+local UnitHasVehiclePlayerFrameUI = UnitHasVehiclePlayerFrameUI
+local UnitHealthMax = UnitHealthMax
+local UnitIsUnit = UnitIsUnit
+local UnitStagger = UnitStagger
+-- GLOBALS: MonkStaggerBar
+-- end block
+
 -- sourced from FrameXML/Constants.lua
-local SPEC_MONK_BREWMASTER = SPEC_MONK_BREWMASTER or 1
+local SPEC_MONK_BREWMASTER = _G.SPEC_MONK_BREWMASTER or 1

 -- sourced from FrameXML/MonkStaggerBar.lua
-local BREWMASTER_POWER_BAR_NAME = BREWMASTER_POWER_BAR_NAME or 'STAGGER'
+local BREWMASTER_POWER_BAR_NAME = _G.BREWMASTER_POWER_BAR_NAME or 'STAGGER'

 -- percentages at which bar should change color
-local STAGGER_YELLOW_TRANSITION =  STAGGER_YELLOW_TRANSITION or 0.3
-local STAGGER_RED_TRANSITION = STAGGER_RED_TRANSITION or 0.6
+local STAGGER_YELLOW_TRANSITION =  _G.STAGGER_YELLOW_TRANSITION or 0.3
+local STAGGER_RED_TRANSITION = _G.STAGGER_RED_TRANSITION or 0.6

 -- table indices of bar colors
-local STAGGER_GREEN_INDEX = STAGGER_GREEN_INDEX or 1
-local STAGGER_YELLOW_INDEX = STAGGER_YELLOW_INDEX or 2
-local STAGGER_RED_INDEX = STAGGER_RED_INDEX or 3
+local STAGGER_GREEN_INDEX = _G.STAGGER_GREEN_INDEX or 1
+local STAGGER_YELLOW_INDEX = _G.STAGGER_YELLOW_INDEX or 2
+local STAGGER_RED_INDEX = _G.STAGGER_RED_INDEX or 3

 local function UpdateColor(self, event, unit)
 	if(unit and unit ~= self.unit) then return end
@@ -92,8 +101,18 @@ local function UpdateColor(self, event, unit)
 	end
 end

-local function Update(self, event, unit)
-	if(unit and unit ~= self.unit) then return end
+local staggerID = {
+	[124275] = true, -- [GREEN]  Light Stagger
+	[124274] = true, -- [YELLOW] Moderate Stagger
+	[124273] = true, -- [RED]    Heavy Stagger
+}
+
+local function verifyStagger(frame, event, unit, auraInfo)
+	return staggerID[auraInfo.spellId]
+end
+
+local function Update(self, event, unit, isFullUpdate, updatedAuras)
+	if oUF:ShouldSkipAuraUpdate(self, event, unit, isFullUpdate, updatedAuras, verifyStagger) then return end

 	local element = self.Stagger

@@ -148,21 +167,32 @@ local function Path(self, ...)
 	(self.Stagger.UpdateColor or UpdateColor) (self, ...)
 end

+-- ElvUI changed
 local function Visibility(self, event, unit)
-	if(SPEC_MONK_BREWMASTER ~= GetSpecialization() or UnitHasVehiclePlayerFrameUI('player')) then
-		if(self.Stagger:IsShown()) then
-			self.Stagger:Hide()
-			self:UnregisterEvent('UNIT_AURA', Path)
-		end
-	else
-		if(not self.Stagger:IsShown()) then
-			self.Stagger:Show()
-			self:RegisterEvent('UNIT_AURA', Path)
-		end
+	local element = self.Stagger
+	local isShown = element:IsShown()
+	local useClassbar = (SPEC_MONK_BREWMASTER ~= GetSpecialization()) or UnitHasVehiclePlayerFrameUI('player')
+	local stateChanged = false
+
+	if useClassbar and isShown then
+		element:Hide()
+		self:UnregisterEvent('UNIT_AURA', Path)
+		stateChanged = true
+	elseif not useClassbar and not isShown then
+		element:Show()
+		self:RegisterEvent('UNIT_AURA', Path)
+		stateChanged = true
+	end
+
+	if element.PostVisibility then
+		element.PostVisibility(self, event, unit, not useClassbar, stateChanged)
+	end

+	if not useClassbar then
 		Path(self, event, unit)
 	end
 end
+-- end block

 local function VisibilityPath(self, ...)
 	--[[ Override: Stagger.OverrideVisibility(self, event, unit)
diff --git a/oUF/elements/tags.lua b/oUF/elements/tags.lua
index 1d51f06..d15836e 100644
--- a/oUF/elements/tags.lua
+++ b/oUF/elements/tags.lua
@@ -12,15 +12,15 @@ A FontString to hold a tag string. Unlike other elements, this widget must not h
 ## Notes

 A `Tag` is a Lua string consisting of a function name surrounded by square brackets. The tag will be replaced by the
-output of the function and displayed as text on the font string widget with that the tag has been registered. Literals
-can be pre- or appended by separating them with a `>` before or `<` after the function name. The literals will be only
+output of the function and displayed as text on the font string widget with that the tag has been registered.
+Literals can be pre or appended by separating them with a `>` before or `<` after the function name. The literals will be only
 displayed when the function returns a non-nil value. I.e. `"[perhp<%]"` will display the current health as a percentage
 of the maximum health followed by the % sign.

-A `Tag String` is a Lua string consisting of one or multiple tags with optional literals between them. Each tag will be
-updated individually and the output will follow the tags order. Literals will be displayed in the output string
-regardless of whether the surrounding tag functions return a value. I.e. `"[curhp]/[maxhp]"` will resolve to something
-like `2453/5000`.
+A `Tag String` is a Lua string consisting of one or multiple tags with optional literals between them.
+Each tag will be updated individually and the output will follow the tags order. Literals will be displayed in the
+output string regardless of whether the surrounding tag functions return a value. I.e. `"[curhp]/[maxhp]"` will resolve
+to something like `2453/5000`.

 A `Tag Function` is used to replace a single tag in a tag string by its output. A tag function receives only two
 arguments - the unit and the realUnit of the unit frame used to register the tag (see Options for further details). The
@@ -37,9 +37,9 @@ in the `oUF.Tags.SharedEvents` table as follows: `oUF.Tags.SharedEvents.EVENT_NA
 .overrideUnit    - if specified on the font string widget, the frame's realUnit will be passed as the second argument to
                    every tag function whose name is contained in the relevant tag string. Otherwise the second argument
                    is always nil (boolean)
-.frequentUpdates - defines how often the correspondig tag function(s) should be called. This will override the events for
-                   the tag(s), if any. If the value is a number, it is taken as a time interval in seconds. If the value
-                   is a boolean, the time interval is set to 0.5 seconds (number or boolean)
+.frequentUpdates - defines how often the corresponding tag function(s) should be called. This will override the events
+                   for the tag(s), if any. If the value is a number, it is taken as a time interval in seconds. If the
+                   value is a boolean, the time interval is set to 0.5 seconds (number or boolean)

 ## Attributes

@@ -69,10 +69,20 @@ local _, ns = ...
 local oUF = ns.oUF
 local Private = oUF.Private

-local nierror = Private.nierror
 local unitExists = Private.unitExists
 local xpcall = Private.xpcall

+-- ElvUI block
+local _G = _G
+local CreateFrame = CreateFrame
+local hooksecurefunc = hooksecurefunc
+local setfenv, getfenv, gsub = setfenv, getfenv, gsub
+local rawget, rawset, select = rawget, rawset, select
+local format, tinsert, tremove = format, tinsert, tremove
+local next, type, pcall, unpack = next, type, pcall, unpack
+local error, assert, loadstring = error, assert, loadstring
+-- end block
+
 local _PATTERN = '%[..-%]+'

 local _ENV = {
@@ -84,7 +94,14 @@ local _ENV = {
 				r, g, b = unpack(r)
 			end
 		end
-		return string.format('|cff%02x%02x%02x', r * 255, g * 255, b * 255)
+
+		-- ElvUI block
+		if not r or type(r) == 'string' then --wtf?
+			return '|cffFFFFFF'
+		end
+		-- end block
+
+		return format('|cff%02x%02x%02x', r * 255, g * 255, b * 255)
 	end,
 }
 _ENV.ColorGradient = function(...)
@@ -110,6 +127,17 @@ local tagStrings = {
 		end
 	end]],

+	['arenaspec'] = [[function(u)
+		local id = u:match('arena(%d)$')
+		if(id) then
+			local specID = GetArenaOpponentSpec(tonumber(id))
+			if(specID and specID > 0) then
+				local _, specName = GetSpecializationInfoByID(specID)
+				return specName
+			end
+		end
+	end]],
+
 	['chi'] = [[function()
 		if(GetSpecialization() == SPEC_MONK_WINDWALKER) then
 			local num = UnitPower('player', Enum.PowerType.Chi)
@@ -169,7 +197,7 @@ local tagStrings = {

 	['difficulty'] = [[function(u)
 		if UnitCanAttack('player', u) then
-			local l = UnitEffectiveLevel(u)
+			local l = (UnitEffectiveLevel or UnitLevel)(u)
 			return Hex(GetCreatureDifficultyColor((l > 0) and l or 999))
 		end
 	end]],
@@ -210,7 +238,10 @@ local tagStrings = {
 	end]],

 	['level'] = [[function(u)
-		local l = UnitLevel(u)
+		local l = (UnitEffectiveLevel or UnitLevel)(u)
+		if C_PetBattles and (UnitIsWildBattlePet(u) or UnitIsBattlePetCompanion(u)) then
+			l = UnitBattlePetLevel(u)
+		end

 		if(l > 0) then
 			return l
@@ -284,7 +315,7 @@ local tagStrings = {
 					return Hex(altR, altG, altB)
 				end
 			else
-				return Hex(_COLORS.power[pType])
+				return Hex(_COLORS.power[pType] or _COLORS.power.MANA)
 			end
 		end

@@ -483,21 +514,20 @@ local vars = setmetatable({}, {

 _ENV._VARS = vars

+-- ElvUI switches to UNIT_POWER_FREQUENT for regen powers
 local tagEvents = {
 	['affix']               = 'UNIT_CLASSIFICATION_CHANGED',
-	['arcanecharges']       = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE',
-	['chi']                 = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE',
+	['arenaspec']           = 'ARENA_PREP_OPPONENT_SPECIALIZATIONS',
 	['classification']      = 'UNIT_CLASSIFICATION_CHANGED',
-	['cpoints']             = 'UNIT_POWER_FREQUENT PLAYER_TARGET_CHANGED',
+	['cpoints']             = 'UNIT_POWER_UPDATE PLAYER_TARGET_CHANGED',
 	['curhp']               = 'UNIT_HEALTH UNIT_MAXHEALTH',
-	['curmana']             = 'UNIT_POWER_UPDATE UNIT_MAXPOWER',
-	['curpp']               = 'UNIT_POWER_UPDATE UNIT_MAXPOWER',
+	['curmana']             = 'UNIT_POWER_FREQUENT UNIT_MAXPOWER',
+	['curpp']               = 'UNIT_POWER_FREQUENT UNIT_MAXPOWER',
 	['dead']                = 'UNIT_HEALTH',
 	['deficit:name']        = 'UNIT_HEALTH UNIT_MAXHEALTH UNIT_NAME_UPDATE',
 	['difficulty']          = 'UNIT_FACTION',
 	['faction']             = 'NEUTRAL_FACTION_SELECT_RESULT',
 	['group']               = 'GROUP_ROSTER_UPDATE',
-	['holypower']           = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE',
 	['leader']              = 'PARTY_LEADER_CHANGED',
 	['leaderlong']          = 'PARTY_LEADER_CHANGED',
 	['level']               = 'UNIT_LEVEL PLAYER_LEVEL_UP',
@@ -505,11 +535,11 @@ local tagEvents = {
 	['maxmana']             = 'UNIT_POWER_UPDATE UNIT_MAXPOWER',
 	['maxpp']               = 'UNIT_MAXPOWER',
 	['missinghp']           = 'UNIT_HEALTH UNIT_MAXHEALTH',
-	['missingpp']           = 'UNIT_MAXPOWER UNIT_POWER_UPDATE',
+	['missingpp']           = 'UNIT_MAXPOWER UNIT_POWER_FREQUENT',
 	['name']                = 'UNIT_NAME_UPDATE',
 	['offline']             = 'UNIT_HEALTH UNIT_CONNECTION',
 	['perhp']               = 'UNIT_HEALTH UNIT_MAXHEALTH',
-	['perpp']               = 'UNIT_MAXPOWER UNIT_POWER_UPDATE',
+	['perpp']               = 'UNIT_MAXPOWER UNIT_POWER_FREQUENT',
 	['plus']                = 'UNIT_CLASSIFICATION_CHANGED',
 	['powercolor']          = 'UNIT_DISPLAYPOWER',
 	['pvp']                 = 'UNIT_FACTION',
@@ -520,18 +550,35 @@ local tagEvents = {
 	['smartlevel']          = 'UNIT_LEVEL PLAYER_LEVEL_UP UNIT_CLASSIFICATION_CHANGED',
 	['soulshards']          = 'UNIT_POWER_UPDATE',
 	['status']              = 'UNIT_HEALTH PLAYER_UPDATE_RESTING UNIT_CONNECTION',
+	['threat']              = 'UNIT_THREAT_SITUATION_UPDATE',
+	['threatcolor']         = 'UNIT_THREAT_SITUATION_UPDATE',
 }

 local unitlessEvents = {
+	ARENA_PREP_OPPONENT_SPECIALIZATIONS = true,
 	GROUP_ROSTER_UPDATE = true,
 	NEUTRAL_FACTION_SELECT_RESULT = true,
 	PARTY_LEADER_CHANGED = true,
 	PLAYER_LEVEL_UP = true,
 	PLAYER_TARGET_CHANGED = true,
 	PLAYER_UPDATE_RESTING = true,
+	RAID_TARGET_UPDATE = true,
 	RUNE_POWER_UPDATE = true,
 }

+if oUF.isRetail then
+	tagEvents['arcanecharges']       = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE'
+	tagEvents['chi']                 = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE'
+	tagEvents['holypower']           = 'UNIT_POWER_UPDATE PLAYER_TALENT_UPDATE'
+	unitlessEvents.PLAYER_TALENT_UPDATE = true
+elseif oUF.isWrath then
+	unitlessEvents.PLAYER_TALENT_UPDATE = true
+end
+
+for tag, events in pairs(tagEvents) do -- ElvUI: UNIT_HEALTH is bugged on TBC, use same method to convert as E.AddTag
+	tagEvents[tag] = (oUF.isRetail and gsub(events, 'UNIT_HEALTH_FREQUENT', 'UNIT_HEALTH')) or gsub(events, 'UNIT_HEALTH([^%s_]?)', 'UNIT_HEALTH_FREQUENT%1')
+end
+
 local events = {}
 local eventFrame = CreateFrame('Frame')
 eventFrame:SetScript('OnEvent', function(self, event, unit)
@@ -585,124 +632,78 @@ local function Update(self)
 	end
 end

+-- ElvUI block
+local onUpdateDelay = {}
+local function escapeSequence(a) return format('|%s', a) end
+local function makeDeadTagFunc(bracket)
+	return function()
+		return format('|cFFffffff%s|r', bracket)
+	end
+end
+
+local function makeTagFunc(tag, prefix, suffix)
+	return function(unit, realUnit, customArgs)
+		local str = tag(unit, realUnit, customArgs)
+		if str then
+			return format('%s%s%s', prefix or '', str, suffix or '')
+		end
+	end
+end
+-- end block
+
 local tagPool = {}
 local funcPool = {}
 local tmp = {}

+local function getTagName(tag)
+	local tagStart = tag:match('>+()') or 2
+	local tagEnd = (tag:match('.-()<') or -1) - 1

--- full tag syntax: '[prefix$>tag-name<$suffix(a,r,g,s)]'
--- for a small test case see https://github.com/oUF-wow/oUF/pull/602
-local function getBracketData(tag)
-	local prefixEnd, prefixOffset = tag:match('()$>'), 1
-	if(not prefixEnd) then
-		prefixEnd = 1
-	else
-		prefixEnd = prefixEnd - 1
-		prefixOffset = 3
-	end
-
-	local suffixEnd = (tag:match('()%(', prefixOffset + 1) or -1) - 1
-	local suffixStart, suffixOffset = tag:match('<$()', prefixEnd), 1
-	if(not suffixStart) then
-		suffixStart = suffixEnd + 1
-	else
-		suffixOffset = 3
-	end
-
-	return tag:sub(prefixEnd + prefixOffset, suffixStart - suffixOffset),
-		prefixEnd,
-		suffixStart,
-		suffixEnd,
-		tag:match('%((.-)%)', suffixOffset + 1)
+	return tag:sub(tagStart, tagEnd), tagStart, tagEnd
 end

 local function getTagFunc(tagstr)
 	local func = tagPool[tagstr]
-	if(not func) then
-		local format, numTags = tagstr:gsub('%%', '%%%%'):gsub(_PATTERN, '%%s')
+	if not func then
+		local frmt, numTags = tagstr:gsub('%%', '%%%%'):gsub(_PATTERN, '%%s')
 		local args = {}
-		local idx = 1
-
-		local format_ = {}
-		for i = 1, numTags do
-			format_[i] = '%s'
-		end

+		-- ElvUI changed
 		for bracket in tagstr:gmatch(_PATTERN) do
 			local tagFunc = funcPool[bracket] or tags[bracket:sub(2, -2)]
-			if(not tagFunc) then
-				local tagName, prefixEnd, suffixStart, suffixEnd, customArgs = getBracketData(bracket)
-				local tag = tags[tagName]
-				if(tag) then
-					if(prefixEnd ~= 1 or suffixStart - suffixEnd ~= 1) then
-						local prefix = prefixEnd ~= 1 and bracket:sub(2, prefixEnd) or ''
-						local suffix = suffixStart - suffixEnd ~= 1 and bracket:sub(suffixStart, suffixEnd) or ''
-
-						tagFunc = function(unit, realUnit)
-							local str
-							if(customArgs) then
-								str = tag(unit, realUnit, string.split(',', customArgs))
-							else
-								str = tag(unit, realUnit)
-							end
-
-							if(str and str ~= '') then
-								return prefix .. str .. suffix
-							end
-						end
-					else
-						tagFunc = function(unit, realUnit)
-							local str
-							if(customArgs) then
-								str = tag(unit, realUnit, string.split(',', customArgs))
-							else
-								str = tag(unit, realUnit)
-							end
-
-							if(str and str ~= '') then
-								return str
-							end
-						end
-					end
+			if not tagFunc then
+				local tagName, tagStart, tagEnd = getTagName(bracket)

+				local tag = tags[tagName]
+				if tag then
+					tagStart, tagEnd = tagStart - 2, tagEnd + 2
+					tagFunc = makeTagFunc(tag, tagStart ~= 0 and bracket:sub(2, tagStart), tagEnd ~= 0 and bracket:sub(tagEnd, -2))
 					funcPool[bracket] = tagFunc
 				end
 			end

-			if(tagFunc) then
-				table.insert(args, tagFunc)
-
-				idx = idx + 1
-			else
-				nierror(string.format('Attempted to use invalid tag %s.', bracket))
-
-				format_[idx] = bracket
-				format = format:format(unpack(format_, 1, numTags))
-				format_[idx] = '%s'
-
-				numTags = numTags - 1
-			end
+			tinsert(args, tagFunc or makeDeadTagFunc(bracket))
 		end

 		func = function(self)
 			local parent = self.parent
 			local unit = parent.unit
-			local realUnit
-			if(self.overrideUnit) then
-				realUnit = parent.realUnit
-			end
+			local realUnit = self.overrideUnit and parent.realUnit
+			local customArgs = parent.__customargs[self]

-			_ENV._COLORS = parent.colors
 			_ENV._FRAME = parent
-			for i, f in next, args do
-				tmp[i] = f(unit, realUnit) or ''
+			_ENV._COLORS = parent.colors
+
+			for i, fnc in next, args do
+				tmp[i] = fnc(unit, realUnit, customArgs) or ''
 			end

 			-- We do 1, numTags because tmp can hold several unneeded variables.
-			return self:SetFormattedText(format, unpack(tmp, 1, numTags))
+			self:SetFormattedText(frmt, unpack(tmp, 1, numTags))
 		end

 		tagPool[tagstr] = func
+		-- end block
 	end

 	return func
@@ -713,13 +714,13 @@ local function registerEvent(fontstr, event)

 	local isOK = xpcall(eventFrame.RegisterEvent, eventFrame, event)
 	if(isOK) then
-		table.insert(events[event], fontstr)
+		tinsert(events[event], fontstr)
 	end
 end

 local function registerEvents(fontstr, tagstr)
 	for tag in tagstr:gmatch(_PATTERN) do
-		tag = getBracketData(tag)
+		tag = getTagName(tag)
 		local tagevents = tagEvents[tag]
 		if(tagevents) then
 			for event in tagevents:gmatch('%S+') do
@@ -739,7 +740,7 @@ local function unregisterEvents(fontstr)
 					eventFrame:UnregisterEvent(event)
 				end

-				table.remove(data, index)
+				tremove(data, index)
 			else
 				index = index + 1
 			end
@@ -749,6 +750,30 @@ local function unregisterEvents(fontstr)
 	end
 end

+-- this bullshit is to fix texture strings not adjusting to its inherited alpha
+-- it is a blizzard issue with how texture strings are rendered
+local alphaFix = CreateFrame('Frame')
+alphaFix.fontStrings = {}
+alphaFix:SetScript('OnUpdate', function()
+	local strs = alphaFix.fontStrings
+	if next(strs) then
+		for fs in next, strs do
+			strs[fs] = nil
+
+			local a = fs:GetAlpha()
+			fs:SetAlpha(0)
+			fs:SetAlpha(a)
+		end
+	else
+		alphaFix:Hide()
+	end
+end)
+
+local function fixAlpha(self)
+	alphaFix.fontStrings[self] = true
+	alphaFix:Show()
+end
+
 local taggedFS = {}

 --[[ Tags: frame:Tag(fs, tagstr, ...)
@@ -764,26 +789,75 @@ local function Tag(self, fs, tagstr, ...)

 	if(not self.__tags) then
 		self.__tags = {}
-		table.insert(self.__elements, Update)
+		self.__mousetags = {} -- ElvUI
+		self.__customargs = {} -- ElvUI
+
+		tinsert(self.__elements, Update)
 	elseif(self.__tags[fs]) then
 		-- We don't need to remove it from the __tags table as Untag handles
 		-- that for us.
 		self:Untag(fs)
 	end

+	-- ElvUI
+	if not fs.__HookedAlphaFix then
+		hooksecurefunc(fs, 'SetText', fixAlpha)
+		hooksecurefunc(fs, 'SetFormattedText', fixAlpha)
+		fs.__HookedAlphaFix = true
+	end
+
+	tagstr = tagstr:gsub('||([TCRAtcra])', escapeSequence)
+
+	local customArgs = tagstr:match('{(.-)}%]')
+	if customArgs then
+		self.__customargs[fs] = customArgs
+		tagstr = tagstr:gsub('{.-}%]', ']')
+	else
+		self.__customargs[fs] = nil
+	end
+
+	if not self.isNamePlate then
+		if tagstr:find('%[mouseover%]') then
+			self.__mousetags[fs] = true
+			fs:SetAlpha(0)
+
+			tagstr = tagstr:gsub('%[mouseover%]', '')
+		else
+			for fontString in next, self.__mousetags do
+				if fontString == fs then
+					self.__mousetags[fontString] = nil
+					fs:SetAlpha(1)
+				end
+			end
+		end
+	end
+
+	local containsOnUpdate
+	for tag in tagstr:gmatch(_PATTERN) do
+		tag = getTagName(tag)
+		if not tagEvents[tag] then
+			containsOnUpdate = onUpdateDelay[tag] or 0.15;
+		end
+	end
+	-- end block
+
 	fs.parent = self
 	fs.UpdateTag = getTagFunc(tagstr)

-	if(self.__eventless or fs.frequentUpdates) then
+	if(self.__eventless or fs.frequentUpdates) or containsOnUpdate then -- ElvUI changed
 		local timer
 		if(type(fs.frequentUpdates) == 'number') then
 			timer = fs.frequentUpdates
+		-- ElvUI added check
+		elseif containsOnUpdate then
+			timer = containsOnUpdate
+		-- end block
 		else
 			timer = .5
 		end

 		if(not eventlessUnits[timer]) then eventlessUnits[timer] = {} end
-		table.insert(eventlessUnits[timer], fs)
+		tinsert(eventlessUnits[timer], fs)

 		createOnUpdate(timer)
 	else
@@ -819,7 +893,7 @@ local function Untag(self, fs)
 		local fontstr = timers[index]
 		while fontstr do
 			if(fs == fontstr) then
-				table.remove(timers, index)
+				tremove(timers, index)
 			else
 				index = index + 1
 			end
@@ -836,24 +910,24 @@ end

 local function strip(tag)
 	-- remove prefix, custom args, and suffix
-	return tag:gsub('%[.-$>', '['):gsub('%(.-%)%]', ']'):gsub('<$.-%]', ']')
+	return tag:gsub("%[[^%[%]]*>", "["):gsub("<[^%[%]]*%]", "]") -- ElvUI uses old tag format
 end

 oUF.Tags = {
 	Methods = tags,
 	Events = tagEvents,
 	SharedEvents = unitlessEvents,
+	OnUpdateThrottle = onUpdateDelay, -- ElvUI
 	Vars = vars,
 	RefreshMethods = function(self, tag)
 		if(not tag) then return end

-		-- If a tag's name contains magic chars, there's a chance that
-		-- string.match will fail to find the match.
+		-- If a tag's name contains magic chars, there's a chance that string.match will fail to find the match.
 		tag = '%[' .. tag:gsub('[%^%$%(%)%%%.%*%+%-%?]', '%%%1') .. '%]'

-		for func in next, funcPool do
-			if(strip(func):match(tag)) then
-				funcPool[func] = nil
+		for bracket in next, funcPool do
+			if(strip(bracket):match(tag)) then
+				funcPool[bracket] = nil
 			end
 		end

@@ -876,9 +950,9 @@ oUF.Tags = {
 	RefreshEvents = function(self, tag)
 		if(not tag) then return end

-		-- If a tag's name contains magic chars, there's a chance that
-		-- string.match will fail to find the match.
+		-- If a tag's name contains magic chars, there's a chance that string.match will fail to find the match.
 		tag = '%[' .. tag:gsub('[%^%$%(%)%%%.%*%+%-%?]', '%%%1') .. '%]'
+
 		for tagstr in next, tagPool do
 			if(strip(tagstr):match(tag)) then
 				for fs, ts in next, taggedFS do
@@ -894,4 +968,4 @@ oUF.Tags = {

 oUF:RegisterMetaFunction('Tag', Tag)
 oUF:RegisterMetaFunction('Untag', Untag)
-oUF:RegisterMetaFunction('UpdateTags', Update)
\ No newline at end of file
+oUF:RegisterMetaFunction('UpdateTags', Update)
diff --git a/oUF/elements/threatindicator.lua b/oUF/elements/threatindicator.lua
index 6eb6fd3..1cb1ece 100644
--- a/oUF/elements/threatindicator.lua
+++ b/oUF/elements/threatindicator.lua
@@ -15,7 +15,7 @@ A default texture will be applied if the widget is a Texture and doesn't have a
 ## Options

 .feedbackUnit - The unit whose threat situation is being requested. If defined, it'll be passed as the first argument to
-                [GetThreatStatusColor](http://wowprogramming.com/docs/api/UnitThreatSituation.html).
+                [UnitThreatSituation](https://wow.gamepedia.com/API_UnitThreatSituation).

 ## Examples

@@ -34,20 +34,6 @@ local Private = oUF.Private

 local unitExists = Private.unitExists

-if not GetThreatStatusColor then
-	function GetThreatStatusColor(status)
-		if status == 3 then
-			return 1, 0, 0
-		elseif status == 2 then
-			return 1, .6, 0
-		elseif status == 1 then
-			return 1, 1, .47
-		else
-			return .69, .69, .69
-		end
-	end
-end
-
 local function Update(self, event, unit)
 	if(unit ~= self.unit) then return end

@@ -75,7 +61,7 @@ local function Update(self, event, unit)

 	local r, g, b
 	if(status and status > 0) then
-		r, g, b = GetThreatStatusColor(status)
+		r, g, b = unpack(self.colors.threat[status])

 		if(element.SetVertexColor) then
 			element:SetVertexColor(r, g, b)
diff --git a/oUF/elements/totems.lua b/oUF/elements/totems.lua
index 6694473..c48f585 100644
--- a/oUF/elements/totems.lua
+++ b/oUF/elements/totems.lua
@@ -48,21 +48,46 @@ OnEnter and OnLeave script handlers will be set to display a Tooltip if the `Tot
 local _, ns = ...
 local oUF = ns.oUF

+local GameTooltip = GameTooltip
+local GetTotemInfo = GetTotemInfo
+local GetTime = GetTime
+
 local function UpdateTooltip(self)
+	if GameTooltip:IsForbidden() then return end
+
 	GameTooltip:SetTotem(self:GetID())
 end

 local function OnEnter(self)
-	if(not self:IsVisible()) then return end
+	if GameTooltip:IsForbidden() or not self:IsVisible() then return end

 	GameTooltip:SetOwner(self, 'ANCHOR_BOTTOMRIGHT')
 	self:UpdateTooltip()
 end

 local function OnLeave()
+	if GameTooltip:IsForbidden() then return end
+
 	GameTooltip:Hide()
 end

+local function TotemOnUpdate(self, elapsed)
+	self.elapsed = (self.elapsed or 0) + elapsed
+
+	if (self.elapsed >= .01) then
+		self.elapsed = 0
+
+		local _, _, startTime, expiration = GetTotemInfo(self:GetID())
+		local currentTime = GetTime() - startTime
+
+		if currentTime <= 0 or expiration <= 0 then
+			self:SetValue(0)
+		else
+			self:SetValue(1 - (currentTime / expiration))
+		end
+	end
+end
+
 local function UpdateTotem(self, event, slot)
 	local element = self.Totems
 	if(slot > #element) then return end
@@ -77,15 +102,20 @@ local function UpdateTotem(self, event, slot)

 	local totem = element[slot]
 	local haveTotem, name, start, duration, icon = GetTotemInfo(slot)
-	if(haveTotem and duration > 0) then
-		if(totem.Icon) then
+
+	if haveTotem and duration > 0 then
+		if totem.Icon then
 			totem.Icon:SetTexture(icon)
 		end

-		if(totem.Cooldown) then
+		if totem.Cooldown then
 			totem.Cooldown:SetCooldown(start, duration)
 		end

+		if totem:IsObjectType('StatusBar') then
+			totem:SetValue(0)
+		end
+
 		totem:Show()
 	else
 		totem:Hide()
@@ -119,13 +149,19 @@ local function Path(self, ...)
 end

 local function Update(self, event)
-	for i = 1, #self.Totems do
+	local element = self.Totems
+
+	for i = 1, #element do
 		Path(self, event, i)
 	end
+
+	if(element.PostUpdateColor) then
+		element:PostUpdateColor()
+	end
 end

 local function ForceUpdate(element)
-	return Update(element.__owner, 'ForceUpdate')
+	Update(element.__owner, 'ForceUpdate')
 end

 local function Enable(self)
@@ -139,7 +175,11 @@ local function Enable(self)

 			totem:SetID(i)

-			if(totem:IsMouseEnabled()) then
+			if totem:IsObjectType('StatusBar') then
+				totem:SetScript('OnUpdate', TotemOnUpdate)
+			end
+
+			if totem:IsMouseEnabled() then
 				totem:SetScript('OnEnter', OnEnter)
 				totem:SetScript('OnLeave', OnLeave)

@@ -154,6 +194,7 @@ local function Enable(self)
 			end
 		end

+		element:Show()
 		self:RegisterEvent('PLAYER_TOTEM_UPDATE', Path, true)

 		return true
@@ -167,6 +208,7 @@ local function Disable(self)
 			element[i]:Hide()
 		end

+		element:Hide()
 		self:UnregisterEvent('PLAYER_TOTEM_UPDATE', Path)
 	end
 end
diff --git a/oUF/events.lua b/oUF/events.lua
index 98db72a..a5aece9 100644
--- a/oUF/events.lua
+++ b/oUF/events.lua
@@ -1,10 +1,11 @@
-local parent, ns = ...
+local _, ns = ...
 local oUF = ns.oUF
 local Private = oUF.Private

 local argcheck = Private.argcheck
-local error = Private.error
+local validateEvent = Private.validateEvent
 local validateUnit = Private.validateUnit
+local isUnitEvent = Private.isUnitEvent
 local frame_metatable = Private.frame_metatable

 -- Original event methods
@@ -16,6 +17,12 @@ local isEventRegistered = frame_metatable.__index.IsEventRegistered
 -- to update unit frames correctly, some events need to be registered for
 -- a specific combination of primary and secondary units
 local secondaryUnits = {
+	UNIT_ENTERED_VEHICLE = {
+		pet = 'player',
+	},
+	UNIT_EXITED_VEHICLE = {
+		pet = 'player',
+	},
 	UNIT_PET = {
 		pet = 'player',
 	},
@@ -98,8 +105,8 @@ function frame_metatable.__index:RegisterEvent(event, func, unitless)
 	argcheck(func, 3, 'function')

 	local curev = self[event]
-	local kind = type(curev)
 	if(curev) then
+		local kind = type(curev)
 		if(kind == 'function' and curev ~= func) then
 			self[event] = setmetatable({curev, func}, event_metatable)
 		elseif(kind == 'table') then
@@ -113,11 +120,12 @@ function frame_metatable.__index:RegisterEvent(event, func, unitless)
 		if(unitless or self.__eventless) then
 			-- re-register the event in case we have mixed registration
 			registerEvent(self, event)
+
 			if(self.unitEvents) then
 				self.unitEvents[event] = nil
 			end
 		end
-	else
+	elseif(validateEvent(event)) then
 		self[event] = func

 		if(not self:GetScript('OnEvent')) then
@@ -129,6 +137,7 @@ function frame_metatable.__index:RegisterEvent(event, func, unitless)
 		else
 			self.unitEvents = self.unitEvents or {}
 			self.unitEvents[event] = true
+
 			-- UpdateUnits will take care of unit event registration for header
 			-- units in case we don't have a valid unit yet
 			local unit1, unit2 = self.unit
@@ -137,6 +146,10 @@ function frame_metatable.__index:RegisterEvent(event, func, unitless)
 					unit2 = secondaryUnits[event][unit1]
 				end

+				-- be helpful and throw a custom error when attempting to register
+				-- an event that is unitless
+				assert(isUnitEvent(event, unit1), string.format('Event "%s" is not an unit event', event))
+
 				registerUnitEvent(self, event, unit1, unit2 or '')
 			end
 		end
@@ -178,4 +191,4 @@ function frame_metatable.__index:UnregisterEvent(event, func)

 		unregisterEvent(self, event)
 	end
-end
\ No newline at end of file
+end
diff --git a/oUF/factory.lua b/oUF/factory.lua
index f862eba..2e2cf41 100644
--- a/oUF/factory.lua
+++ b/oUF/factory.lua
@@ -1,48 +1,71 @@
-local parent, ns = ...
+local _, ns = ...
 local oUF = ns.oUF
 local Private = oUF.Private

 local argcheck = Private.argcheck

-local _QUEUE = {}
-local _FACTORY = CreateFrame'Frame'
-_FACTORY:SetScript('OnEvent', function(self, event, ...)
+local queue = {}
+local factory = CreateFrame('Frame')
+factory:SetScript('OnEvent', function(self, event, ...)
 	return self[event](self, event, ...)
 end)

-_FACTORY:RegisterEvent'PLAYER_LOGIN'
-_FACTORY.active = true
+factory:RegisterEvent('PLAYER_LOGIN')
+factory.active = true

-function _FACTORY:PLAYER_LOGIN()
+function factory:PLAYER_LOGIN()
 	if(not self.active) then return end

-	for _, func in next, _QUEUE do
+	for _, func in next, queue do
 		func(oUF)
 	end

 	-- Avoid creating dupes.
-	wipe(_QUEUE)
+	table.wipe(queue)
 end

+--[[ Factory: oUF:Factory(func)
+Used to call a function directly if the current character is logged in and the factory is active. Else the function is
+queued up to be executed at a later time (upon PLAYER_LOGIN by default).
+
+* self - the global oUF object
+* func - function to be executed or delayed (function)
+--]]
 function oUF:Factory(func)
 	argcheck(func, 2, 'function')

 	-- Call the function directly if we're active and logged in.
-	if(IsLoggedIn() and _FACTORY.active) then
+	if(IsLoggedIn() and factory.active) then
 		return func(self)
 	else
-		table.insert(_QUEUE, func)
+		table.insert(queue, func)
 	end
 end

+--[[ Factory: oUF:EnableFactory()
+Used to enable the factory.
+
+* self - the global oUF object
+--]]
 function oUF:EnableFactory()
-	_FACTORY.active = true
+	factory.active = true
 end

+--[[ Factory: oUF:DisableFactory()
+Used to disable the factory.
+
+* self - the global oUF object
+--]]
 function oUF:DisableFactory()
-	_FACTORY.active = nil
+	factory.active = nil
 end

+--[[ Factory: oUF:RunFactoryQueue()
+Used to try to execute queued up functions. The current player must be logged in and the factory must be active for
+this to succeed.
+
+* self - the global oUF object
+--]]
 function oUF:RunFactoryQueue()
-	_FACTORY:PLAYER_LOGIN()
-end
\ No newline at end of file
+	factory:PLAYER_LOGIN()
+end
diff --git a/oUF/finalize.lua b/oUF/finalize.lua
index dec0bc1..55119b8 100644
--- a/oUF/finalize.lua
+++ b/oUF/finalize.lua
@@ -1,4 +1,4 @@
-local parent, ns = ...
+local _, ns = ...

 -- It's named Private for a reason!
-ns.oUF.Private = nil
\ No newline at end of file
+ns.oUF.Private = nil
diff --git a/oUF/init.lua b/oUF/init.lua
index dabbd5d..1a8e978 100644
--- a/oUF/init.lua
+++ b/oUF/init.lua
@@ -1,3 +1,10 @@
-local parent, ns = ...
+local _, ns = ...
 ns.oUF = {}
-ns.oUF.Private = {}
\ No newline at end of file
+ns.oUF.Private = {}
+
+local _, _, _, toc = GetBuildInfo()
+
+ns.oUF.isRetail = WOW_PROJECT_ID == WOW_PROJECT_MAINLINE
+ns.oUF.isClassic = WOW_PROJECT_ID == WOW_PROJECT_CLASSIC
+ns.oUF.isTBC = toc >= 20500 and toc < 30000 -- TODO: Wrath
+ns.oUF.isWrath = toc >= 30400 and toc < 40000 -- TODO: Wrath
diff --git a/oUF/oUF.toc b/oUF/oUF.toc
index 822f8b7..5e6d839 100644
--- a/oUF/oUF.toc
+++ b/oUF/oUF.toc
@@ -1,5 +1,5 @@
-## Interface: 20504
-## Title: oUF |cff1a9fc0BCC|r
+## Interface: 30400
+## Title: oUF |cff1a9fc0WLK|r
 ## Author: Haste, lightspark, p3lim, Rainrider
 ## Version: @project-version@
 ## Notes: Unit frame framework. Does nothing by itself.
@@ -15,38 +15,4 @@ libs\CallbackHandler-1.0\CallbackHandler-1.0.lua
 libs\LibHealComm-4.0\ChatThrottleLib.lua
 libs\LibHealComm-4.0\LibHealComm-4.0.lua

-init.lua
-private.lua
-ouf.lua
-events.lua
-combatevents.lua
-factory.lua
-blizzard.lua
-units.lua
-colors.lua
-elements\assistantindicator.lua
-elements\auras.lua
-elements\castbar.lua
-elements\classpower.lua
-elements\combatindicator.lua
-elements\grouproleindicator.lua
-elements\health.lua
-elements\healthprediction.lua
-elements\leaderindicator.lua
-elements\phaseindicator.lua
-elements\portrait.lua
-elements\power.lua
-elements\powerprediction.lua
-elements\pvpindicator.lua
-elements\questindicator.lua
-elements\raidroleindicator.lua
-elements\raidtargetindicator.lua
-elements\range.lua
-elements\readycheckindicator.lua
-elements\restingindicator.lua
-elements\resurrectindicator.lua
-elements\stagger.lua
-elements\tags.lua
-elements\threatindicator.lua
-elements\totems.lua
-finalize.lua
\ No newline at end of file
+oUF_Wrath.xml
\ No newline at end of file
diff --git a/oUF/oUF.xml b/oUF/oUF.xml
index 043ccc6..4e37a8c 100644
--- a/oUF/oUF.xml
+++ b/oUF/oUF.xml
@@ -9,33 +9,81 @@
 	<Script file="units.lua"/>
 	<Script file="colors.lua"/>

-	<Script file='Plugins\RaidDebuffs.lua' />
-
 	<Script file="elements\additionalpower.lua"/>
+	<Script file="elements\alternativepower.lua"/>
 	<Script file="elements\assistantindicator.lua"/>
 	<Script file="elements\auras.lua"/>
 	<Script file="elements\castbar.lua"/>
 	<Script file="elements\classpower.lua"/>
 	<Script file="elements\combatindicator.lua"/>
-	<Script file="elements\healprediction.lua"/>
+	<Script file="elements\grouproleindicator.lua"/>
 	<Script file="elements\health.lua"/>
+	<Script file="elements\healthprediction.lua"/>
 	<Script file="elements\leaderindicator.lua"/>
 	<Script file="elements\masterlooterindicator.lua"/>
+	<Script file="elements\partyindicator.lua"/>
 	<Script file="elements\phaseindicator.lua"/>
 	<Script file="elements\portrait.lua"/>
 	<Script file="elements\power.lua"/>
+	<Script file="elements\powerprediction.lua"/>
+	<Script file="elements\pvpclassificationindicator.lua"/>
+	<Script file="elements\pvpindicator.lua"/>
+	<Script file="elements\questindicator.lua"/>
 	<Script file="elements\raidroleindicator.lua"/>
 	<Script file="elements\raidtargetindicator.lua"/>
 	<Script file="elements\range.lua"/>
 	<Script file="elements\readycheckindicator.lua"/>
 	<Script file="elements\restingindicator.lua"/>
 	<Script file="elements\resurrectindicator.lua"/>
+	<Script file="elements\runes.lua"/>
+	<Script file="elements\stagger.lua"/>
+	<Script file="elements\summonindicator.lua"/>
 	<Script file="elements\tags.lua"/>
 	<Script file="elements\threatindicator.lua"/>
-
-	<Script file='Plugins\FloatingCombatFeedback.lua' />
-	<Script file='Plugins\Swing.lua' />
-	<Script file='Plugins\EnergyManaRegen.lua' />
+	<Script file="elements\totems.lua"/>

 	<Script file="finalize.lua"/>
-</Ui>
\ No newline at end of file
+
+	<!--
+		Sub-object as a child of the parent unit frame:
+	<Button name="oUF_HeaderTargetTemplate" inherits="SecureUnitButtonTemplate" virtual="true">
+		<Frames>
+			<Button name="$parentTarget" inherits="SecureUnitButtonTemplate">
+				<Attributes>
+					<Attribute name="unitsuffix" type="string" value="target"/>
+					<Attribute name="useparent-unit" type="boolean" value="true"/>
+				</Attributes>
+			</Button>
+		</Frames>
+	</Button>
+
+		Separate unit template example:
+	<Button name="oUF_HeaderSeparateSubOjectsTemplate" inherits="SecureUnitButtonTemplate" virtual="true">
+		<Attributes>
+			<Attribute name="oUF-onlyProcessChildren" type="boolean" value="true"/>
+		</Attributes>
+
+		<Frames>
+			<Button name="$parentUnit" inherits="SecureUnitButtonTemplate">
+				<Attributes>
+					<Attribute name="useparent-unit" type="boolean" value="true"/>
+				</Attributes>
+			</Button>
+
+			<Button name="$parentPet" inherits="SecureUnitButtonTemplate">
+				<Attributes>
+					<Attribute name="unitsuffix" type="string" value="pet"/>
+					<Attribute name="useparent-unit" type="boolean" value="true"/>
+				</Attributes>
+			</Button>
+
+			<Button name="$parentTarget" inherits="SecureUnitButtonTemplate">
+				<Attributes>
+					<Attribute name="unitsuffix" type="string" value="target"/>
+					<Attribute name="useparent-unit" type="boolean" value="true"/>
+				</Attributes>
+			</Button>
+		</Frames>
+	</Button>
+	-->
+</Ui>
diff --git a/oUF/oUF_Classic.xml b/oUF/oUF_Classic.xml
new file mode 100644
index 0000000..5ea9f98
--- /dev/null
+++ b/oUF/oUF_Classic.xml
@@ -0,0 +1,39 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/">
+	<Script file="init.lua"/>
+	<Script file="private.lua"/>
+	<Script file="ouf.lua"/>
+	<Script file="events.lua"/>
+	<Script file="combatevents.lua"/>
+	<Script file="factory.lua"/>
+	<Script file="blizzard.lua"/>
+	<Script file="units.lua"/>
+	<Script file="colors.lua"/>
+
+	<Script file="elements\additionalpower.lua"/>
+	<Script file="elements\assistantindicator.lua"/>
+	<Script file="elements\auras.lua"/>
+	<Script file="elements\castbar.lua"/>
+	<Script file="elements\classpower.lua"/>
+	<Script file="elements\combatindicator.lua"/>
+	<Script file="elements\grouproleindicator.lua"/>
+	<Script file="elements\health.lua"/>
+	<Script file="elements\healthprediction.lua"/>
+	<Script file="elements\leaderindicator.lua"/>
+	<Script file="elements\masterlooterindicator.lua"/>
+	<Script file="elements\portrait.lua"/>
+	<Script file="elements\power.lua"/>
+	<Script file="elements\powerprediction.lua"/>
+	<Script file="elements\pvpindicator.lua"/>
+	<Script file="elements\questindicator.lua"/>
+	<Script file="elements\raidroleindicator.lua"/>
+	<Script file="elements\raidtargetindicator.lua"/>
+	<Script file="elements\range.lua"/>
+	<Script file="elements\readycheckindicator.lua"/>
+	<Script file="elements\restingindicator.lua"/>
+	<Script file="elements\resurrectindicator.lua"/>
+	<Script file="elements\tags.lua"/>
+	<Script file="elements\threatindicator.lua"/>
+	<Script file="elements\totems.lua"/>
+
+	<Script file="finalize.lua"/>
+</Ui>
diff --git a/oUF/oUF_TBC.xml b/oUF/oUF_TBC.xml
new file mode 100644
index 0000000..5ea9f98
--- /dev/null
+++ b/oUF/oUF_TBC.xml
@@ -0,0 +1,39 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/">
+	<Script file="init.lua"/>
+	<Script file="private.lua"/>
+	<Script file="ouf.lua"/>
+	<Script file="events.lua"/>
+	<Script file="combatevents.lua"/>
+	<Script file="factory.lua"/>
+	<Script file="blizzard.lua"/>
+	<Script file="units.lua"/>
+	<Script file="colors.lua"/>
+
+	<Script file="elements\additionalpower.lua"/>
+	<Script file="elements\assistantindicator.lua"/>
+	<Script file="elements\auras.lua"/>
+	<Script file="elements\castbar.lua"/>
+	<Script file="elements\classpower.lua"/>
+	<Script file="elements\combatindicator.lua"/>
+	<Script file="elements\grouproleindicator.lua"/>
+	<Script file="elements\health.lua"/>
+	<Script file="elements\healthprediction.lua"/>
+	<Script file="elements\leaderindicator.lua"/>
+	<Script file="elements\masterlooterindicator.lua"/>
+	<Script file="elements\portrait.lua"/>
+	<Script file="elements\power.lua"/>
+	<Script file="elements\powerprediction.lua"/>
+	<Script file="elements\pvpindicator.lua"/>
+	<Script file="elements\questindicator.lua"/>
+	<Script file="elements\raidroleindicator.lua"/>
+	<Script file="elements\raidtargetindicator.lua"/>
+	<Script file="elements\range.lua"/>
+	<Script file="elements\readycheckindicator.lua"/>
+	<Script file="elements\restingindicator.lua"/>
+	<Script file="elements\resurrectindicator.lua"/>
+	<Script file="elements\tags.lua"/>
+	<Script file="elements\threatindicator.lua"/>
+	<Script file="elements\totems.lua"/>
+
+	<Script file="finalize.lua"/>
+</Ui>
diff --git a/oUF/oUF_Wrath.xml b/oUF/oUF_Wrath.xml
new file mode 100644
index 0000000..c547186
--- /dev/null
+++ b/oUF/oUF_Wrath.xml
@@ -0,0 +1,40 @@
+<Ui xmlns="http://www.blizzard.com/wow/ui/">
+	<Script file="init.lua"/>
+	<Script file="private.lua"/>
+	<Script file="ouf.lua"/>
+	<Script file="events.lua"/>
+	<Script file="combatevents.lua"/>
+	<Script file="factory.lua"/>
+	<Script file="blizzard.lua"/>
+	<Script file="units.lua"/>
+	<Script file="colors.lua"/>
+
+	<Script file="elements\additionalpower.lua"/>
+	<Script file="elements\assistantindicator.lua"/>
+	<Script file="elements\auras.lua"/>
+	<Script file="elements\castbar.lua"/>
+	<Script file="elements\classpower.lua"/>
+	<Script file="elements\combatindicator.lua"/>
+	<Script file="elements\grouproleindicator.lua"/>
+	<Script file="elements\health.lua"/>
+	<Script file="elements\healthprediction.lua"/>
+	<Script file="elements\leaderindicator.lua"/>
+	<Script file="elements\masterlooterindicator.lua"/>
+	<Script file="elements\portrait.lua"/>
+	<Script file="elements\power.lua"/>
+	<Script file="elements\powerprediction.lua"/>
+	<Script file="elements\pvpindicator.lua"/>
+	<Script file="elements\questindicator.lua"/>
+	<Script file="elements\raidroleindicator.lua"/>
+	<Script file="elements\raidtargetindicator.lua"/>
+	<Script file="elements\range.lua"/>
+	<Script file="elements\readycheckindicator.lua"/>
+	<Script file="elements\restingindicator.lua"/>
+	<Script file="elements\resurrectindicator.lua"/>
+	<Script file="elements\runes.lua"/>
+	<Script file="elements\tags.lua"/>
+	<Script file="elements\threatindicator.lua"/>
+	<Script file="elements\totems.lua"/>
+
+	<Script file="finalize.lua"/>
+</Ui>
diff --git a/oUF/ouf.lua b/oUF/ouf.lua
index 9342a92..aba9cba 100644
--- a/oUF/ouf.lua
+++ b/oUF/ouf.lua
@@ -10,7 +10,7 @@ local Private = oUF.Private

 local argcheck = Private.argcheck
 local error = Private.error
-local print = Private.print
+local print = Private.print --luacheck: no unused
 local unitExists = Private.unitExists

 local styles, style = {}
@@ -19,31 +19,27 @@ local callback, objects, headers = {}, {}, {}
 local elements = {}
 local activeElements = {}

+-- ElvUI
+local _G = _G
+local assert, setmetatable = assert, setmetatable
+local unpack, tinsert, tremove = unpack, tinsert, tremove
+local next, time, wipe, type = next, time, wipe, type
+local select, pairs, ipairs = select, pairs, ipairs
+local strupper, strsplit = strupper, strsplit
+
+local GetNamePlateForUnit = C_NamePlate.GetNamePlateForUnit
+local CreateFrame = CreateFrame
+local IsLoggedIn = IsLoggedIn
+local UnitGUID = UnitGUID
+local SetCVar = SetCVar
+-- end
+
 local PetBattleFrameHider = CreateFrame('Frame', (global or parent) .. '_PetBattleFrameHider', UIParent, 'SecureHandlerStateTemplate')
 PetBattleFrameHider:SetAllPoints()
 PetBattleFrameHider:SetFrameStrata('LOW')
 RegisterStateDriver(PetBattleFrameHider, 'visibility', '[petbattle] hide; show')

--- updating of "invalid" units.
-local function enableTargetUpdate(object)
-	object.onUpdateFrequency = object.onUpdateFrequency or .5
-	object.__eventless = true
-
-	local total = 0
-	object:SetScript('OnUpdate', function(self, elapsed)
-		if(not self.unit) then
-			return
-		elseif(total > self.onUpdateFrequency) then
-			self:UpdateAllElements('OnUpdate')
-			total = 0
-		end
-
-		total = total + elapsed
-	end)
-end
-Private.enableTargetUpdate = enableTargetUpdate
-
-local function updateActiveUnit(self, event, unit)
+local function updateActiveUnit(self, event)
 	-- Calculate units to work with
 	local realUnit, modUnit = SecureButton_GetUnit(self), SecureButton_GetModifiedUnit(self)

@@ -54,16 +50,26 @@ local function updateActiveUnit(self, event, unit)
 		realUnit = 'target'
 	end

+	if(modUnit == 'pet' and realUnit ~= 'pet') then
+		modUnit = 'vehicle'
+	end
+
 	if(not unitExists(modUnit)) then return end

 	-- Change the active unit and run a full update.
 	if(Private.UpdateUnits(self, modUnit, realUnit)) then
-		self:UpdateAllElements('RefreshUnit')
+		self:UpdateAllElements(event or 'RefreshUnit')

 		return true
 	end
 end

+local function evalUnitAndUpdate(self, event)
+	if(not updateActiveUnit(self, event)) then
+		return self:UpdateAllElements(event)
+	end
+end
+
 local function iterateChildren(...)
 	for i = 1, select('#', ...) do
 		local obj = select(i, ...)
@@ -110,7 +116,7 @@ for k, v in next, {
 			activeElements[self][name] = true

 			if(element.update) then
-				table.insert(self.__elements, element.update)
+				tinsert(self.__elements, element.update)
 			end
 		end
 	end,
@@ -128,10 +134,12 @@ for k, v in next, {
 		if(not enabled) then return end

 		local update = elements[name].update
-		for k, func in next, self.__elements do
-			if(func == update) then
-				table.remove(self.__elements, k)
-				break
+		if(update) then
+			for k, func in next, self.__elements do
+				if(func == update) then
+					tremove(self.__elements, k)
+					break
+				end
 			end
 		end

@@ -222,9 +230,7 @@ for k, v in next, {
 end

 local function onShow(self)
-	if(not updateActiveUnit(self, 'OnShow')) then
-		return self:UpdateAllElements('OnShow')
-	end
+	evalUnitAndUpdate(self, 'OnShow')
 end

 local function updatePet(self, event, unit)
@@ -239,9 +245,8 @@ local function updatePet(self, event, unit)
 	end

 	if(self.unit ~= petUnit) then return end
-	if(not updateActiveUnit(self, event)) then
-		return self:UpdateAllElements(event)
-	end
+
+	evalUnitAndUpdate(self, event)
 end

 local function updateRaid(self, event)
@@ -253,6 +258,18 @@ local function updateRaid(self, event)
 	end
 end

+-- boss6-8 exsist in some encounters, but unit event registration seems to be
+-- completely broken for them, so instead we use OnUpdate to update them.
+local eventlessUnits = {
+	['boss6'] = true,
+	['boss7'] = true,
+	['boss8'] = true,
+}
+
+local function isEventlessUnit(unit)
+	return unit:match('%w+target') or eventlessUnits[unit]
+end
+
 local function initObject(unit, style, styleFunc, header, ...)
 	local num = select('#', ...)
 	for i = 1, num do
@@ -260,25 +277,34 @@ local function initObject(unit, style, styleFunc, header, ...)
 		local objectUnit = object:GetAttribute('oUF-guessUnit') or unit
 		local suffix = object:GetAttribute('unitsuffix')

+		-- Handle the case where someone has modified the unitsuffix attribute in
+		-- oUF-initialConfigFunction.
+		if(suffix and not objectUnit:match(suffix)) then
+			objectUnit = objectUnit .. suffix
+		end
+
 		object.__elements = {}
 		object.style = style
 		object = setmetatable(object, frame_metatable)

 		-- Expose the frame through oUF.objects.
-		table.insert(objects, object)
+		tinsert(objects, object)

 		-- We have to force update the frames when PEW fires.
-		object:RegisterEvent('PLAYER_ENTERING_WORLD', object.UpdateAllElements, true)
-
-		-- Handle the case where someone has modified the unitsuffix attribute in
-		-- oUF-initialConfigFunction.
-		if(suffix and not objectUnit:match(suffix)) then
-			objectUnit = objectUnit .. suffix
-		end
+		-- It's also important to evaluate units before running an update
+		-- because sometimes events that are required for unit updates end up
+		-- not firing because of loading screens. For instance, there's a slight
+		-- delay between UNIT_EXITING_VEHICLE and UNIT_EXITED_VEHICLE during
+		-- which a user can go through a loading screen after which the player
+		-- frame will be stuck with the 'vehicle' unit.
+		object:RegisterEvent('PLAYER_ENTERING_WORLD', evalUnitAndUpdate, true)
+
+		if(not isEventlessUnit(objectUnit)) then
+			object:RegisterEvent('UNIT_ENTERED_VEHICLE', evalUnitAndUpdate)
+			object:RegisterEvent('UNIT_EXITED_VEHICLE', evalUnitAndUpdate)

-		if(not (suffix == 'target' or objectUnit and objectUnit:match('target'))) then
 			-- We don't need to register UNIT_PET for the player unit. We register it
-			-- mainly because UNIT_EXITED_VEHICLE and UNIT_ENTERED_VEHICLE doesn't always
+			-- mainly because UNIT_EXITED_VEHICLE and UNIT_ENTERED_VEHICLE don't always
 			-- have pet information when they fire for party and raid units.
 			if(objectUnit ~= 'player') then
 				object:RegisterEvent('UNIT_PET', updatePet)
@@ -290,10 +316,11 @@ local function initObject(unit, style, styleFunc, header, ...)
 			object:SetAttribute('*type1', 'target')
 			object:SetAttribute('*type2', 'togglemenu')

-			-- Other boss and target units are handled by :HandleUnit().
-			if(suffix == 'target') then
-				enableTargetUpdate(object)
+			if(isEventlessUnit(objectUnit)) then
+				oUF:HandleEventlessUnit(object)
 			else
+				-- No need to enable this for eventless units.
+				object:SetAttribute('toggleForVehicle', true)
 				oUF:HandleUnit(object)
 			end
 		else
@@ -310,10 +337,12 @@ local function initObject(unit, style, styleFunc, header, ...)
 			end

 			if(suffix == 'target') then
-				enableTargetUpdate(object)
+				oUF:HandleEventlessUnit(object)
 			end
 		end

+		activeElements[object] = {} -- ElvUI: styleFunc on headers break before this is set when they try to enable elements before it's set.
+
 		Private.UpdateUnits(object, objectUnit)

 		styleFunc(object, objectUnit, not header)
@@ -326,7 +355,6 @@ local function initObject(unit, style, styleFunc, header, ...)
 			object:SetScript('OnShow', onShow)
 		end

-		activeElements[object] = {}
 		for element in next, elements do
 			object:EnableElement(element, objectUnit)
 		end
@@ -337,8 +365,8 @@ local function initObject(unit, style, styleFunc, header, ...)

 		-- Make Clique kinda happy
 		if(not object.isNamePlate) then
-			_G.ClickCastFrames = ClickCastFrames or {}
-			ClickCastFrames[object] = true
+			_G.ClickCastFrames = _G.ClickCastFrames or {}
+			_G.ClickCastFrames[object] = true
 		end
 	end
 end
@@ -367,7 +395,7 @@ Used to add a function to a table to be executed upon unit frame/header initiali
 * func - function to be added
 --]]
 function oUF:RegisterInitCallback(func)
-	table.insert(callback, func)
+	tinsert(callback, func)
 end

 --[[ oUF:RegisterMetaFunction(name, func)
@@ -510,7 +538,7 @@ local function generateName(unit, ...)
 	elseif(party) then
 		append = 'Party'
 	elseif(unit) then
-		append = unit:gsub('^%l', string.upper)
+		append = unit:gsub('^%l', strupper)
 	end

 	if(append) then
@@ -535,7 +563,7 @@ local function generateName(unit, ...)
 end

 do
-	local function styleProxy(self, frame, ...)
+	local function styleProxy(self, frame)
 		return walkObject(_G[frame])
 	end

@@ -628,7 +656,7 @@ do
 		local name = overrideName or generateName(nil, ...)
 		local header = CreateFrame('Frame', name, PetBattleFrameHider, template)

-		header:SetAttribute('template', 'SecureUnitButtonTemplate, SecureHandlerStateTemplate, SecureHandlerEnterLeaveTemplate, SecureHandlerShowHideTemplate, SecureHandlerMouseUpDownTemplate')
+		header:SetAttribute('template', 'SecureUnitButtonTemplate, SecureHandlerStateTemplate, SecureHandlerEnterLeaveTemplate')
 		for i = 1, select('#', ...), 2 do
 			local att, val = select(i, ...)
 			if(not att) then break end
@@ -640,14 +668,43 @@ do
 		header.visibility = visibility

 		-- Expose the header through oUF.headers.
-		table.insert(headers, header)
+		tinsert(headers, header)

 		-- We set it here so layouts can't directly override it.
 		header:SetAttribute('initialConfigFunction', initialConfigFunction)
+		header:SetAttribute('_initialAttributeNames', '_onenter,_onleave,refreshUnitChange,_onstate-vehicleui')
+		header:SetAttribute('_initialAttribute-_onenter', [[
+			local snippet = self:GetAttribute('clickcast_onenter')
+			if(snippet) then
+				self:Run(snippet)
+			end
+		]])
+		header:SetAttribute('_initialAttribute-_onleave', [[
+			local snippet = self:GetAttribute('clickcast_onleave')
+			if(snippet) then
+				self:Run(snippet)
+			end
+		]])
+		header:SetAttribute('_initialAttribute-refreshUnitChange', [[
+			local unit = self:GetAttribute('unit')
+			if(unit) then
+				RegisterStateDriver(self, 'vehicleui', '[@' .. unit .. ',unithasvehicleui]vehicle; novehicle')
+			else
+				UnregisterStateDriver(self, 'vehicleui')
+			end
+		]])
+		header:SetAttribute('_initialAttribute-_onstate-vehicleui', [[
+			local unit = self:GetAttribute('unit')
+			if(newstate == 'vehicle' and unit and UnitPlayerOrPetInRaid(unit) and not UnitTargetsVehicleInRaidUI(unit)) then
+				self:SetAttribute('toggleForVehicle', false)
+			else
+				self:SetAttribute('toggleForVehicle', true)
+			end
+		]])
 		header:SetAttribute('oUF-headerType', isPetHeader and 'pet' or 'group')

-		if(Clique) then
-			SecureHandlerSetFrameRef(header, 'clickcast_header', Clique.header)
+		if(_G.Clique) then
+			SecureHandlerSetFrameRef(header, 'clickcast_header', _G.Clique.header)
 		end

 		if(header:GetAttribute('showParty')) then
@@ -655,12 +712,12 @@ do
 		end

 		if(visibility) then
-			local type, list = string.split(' ', visibility, 2)
+			local type, list = strsplit(' ', visibility, 2)
 			if(list and type == 'custom') then
 				RegisterAttributeDriver(header, 'state-visibility', list)
 				header.visibility = list
 			else
-				local condition = getCondition(string.split(',', visibility))
+				local condition = getCondition(strsplit(',', visibility))
 				RegisterAttributeDriver(header, 'state-visibility', condition)
 				header.visibility = condition
 			end
@@ -682,17 +739,17 @@ oUF implements some of its own attributes. These can be supplied by the layout,

 * oUF-enableArenaPrep - can be used to toggle arena prep support. Defaults to true (boolean)
 --]]
-function oUF:Spawn(unit, overrideName, noHandle)
+function oUF:Spawn(unit, overrideName, overrideTemplate) -- ElvUI adds overrideTemplate
 	argcheck(unit, 2, 'string')
 	if(not style) then return error('Unable to create frame. No styles have been registered.') end

 	unit = unit:lower()

 	local name = overrideName or generateName(unit)
-	local object = CreateFrame('Button', name, PetBattleFrameHider, 'SecureUnitButtonTemplate')
+	local object = CreateFrame('Button', name, PetBattleFrameHider, overrideTemplate or 'SecureUnitButtonTemplate')
 	Private.UpdateUnits(object, unit)

-	if not noHandle then self:DisableBlizzard(unit) end
+	self:DisableBlizzard(unit)
 	walkObject(object, unit)

 	object:SetAttribute('unit', unit)
@@ -715,7 +772,7 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars)
 	argcheck(nameplateCallback, 3, 'function', 'nil')
 	argcheck(nameplateCVars, 4, 'table', 'nil')
 	if(not style) then return error('Unable to create frame. No styles have been registered.') end
-	if(oUF_NamePlateDriver) then return error('oUF nameplate driver has already been initialized.') end
+	if(_G.oUF_NamePlateDriver) then return error('oUF nameplate driver has already been initialized.') end

 	local style = style
 	local prefix = namePrefix or generateName()
@@ -734,6 +791,7 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars)
 	eventHandler:RegisterEvent('NAME_PLATE_UNIT_ADDED')
 	eventHandler:RegisterEvent('NAME_PLATE_UNIT_REMOVED')
 	eventHandler:RegisterEvent('PLAYER_TARGET_CHANGED')
+	eventHandler:RegisterEvent('UNIT_FACTION')

 	if(IsLoggedIn()) then
 		if(nameplateCVars) then
@@ -753,7 +811,7 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars)
 				end
 			end
 		elseif(event == 'PLAYER_TARGET_CHANGED') then
-			local nameplate = C_NamePlate.GetNamePlateForUnit('target')
+			local nameplate = GetNamePlateForUnit('target')
 			if(nameplateCallback) then
 				nameplateCallback(nameplate and nameplate.unitFrame, event, 'target')
 			end
@@ -763,8 +821,15 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars)
 			if(nameplate) then
 				nameplate.unitFrame:UpdateAllElements(event)
 			end
+		elseif(event == 'UNIT_FACTION' and unit) then
+			local nameplate = GetNamePlateForUnit(unit)
+			if(not nameplate) then return end
+
+			if(nameplateCallback) then
+				nameplateCallback(nameplate.unitFrame, event, unit)
+			end
 		elseif(event == 'NAME_PLATE_UNIT_ADDED' and unit) then
-			local nameplate = C_NamePlate.GetNamePlateForUnit(unit)
+			local nameplate = GetNamePlateForUnit(unit)
 			if(not nameplate) then return end

 			if(not nameplate.unitFrame) then
@@ -791,7 +856,7 @@ function oUF:SpawnNamePlates(namePrefix, nameplateCallback, nameplateCVars)
 			-- ForceUpdate calls layout devs have to do themselves
 			nameplate.unitFrame:UpdateAllElements(event)
 		elseif(event == 'NAME_PLATE_UNIT_REMOVED' and unit) then
-			local nameplate = C_NamePlate.GetNamePlateForUnit(unit)
+			local nameplate = GetNamePlateForUnit(unit)
 			if(not nameplate) then return end

 			nameplate.unitFrame:SetAttribute('unit', nil)
@@ -808,15 +873,15 @@ Used to register an element with oUF.

 * self    - the global oUF object
 * name    - unique name of the element (string)
-* update  - used to update the element (function?)
-* enable  - used to enable the element for a given unit frame and unit (function?)
-* disable - used to disable the element for a given unit frame (function?)
+* update  - used to update the element (function)
+* enable  - used to enable the element for a given unit frame and unit (function)
+* disable - used to disable the element for a given unit frame (function)
 --]]
 function oUF:AddElement(name, update, enable, disable)
 	argcheck(name, 2, 'string')
 	argcheck(update, 3, 'function', 'nil')
-	argcheck(enable, 4, 'function', 'nil')
-	argcheck(disable, 5, 'function', 'nil')
+	argcheck(enable, 4, 'function')
+	argcheck(disable, 5, 'function')

 	if(elements[name]) then return error('Element [%s] is already registered.', name) end
 	elements[name] = {
@@ -844,4 +909,250 @@ if(global) then
 	else
 		_G[global] = oUF
 	end
-end
\ No newline at end of file
+end
+
+do -- ShouldSkipAuraUpdate by Blizzard (implemented and heavily modified by Simpy)
+	local SpellGetVisibilityInfo = SpellGetVisibilityInfo
+	local SpellIsPriorityAura = SpellIsPriorityAura
+	local UnitAffectingCombat = UnitAffectingCombat
+
+	local hasValidPlayer = false
+	local cachedVisibility = {}
+	local cachedPriority = {}
+
+	local eventFrame = CreateFrame('Frame')
+	eventFrame:RegisterEvent('PLAYER_REGEN_ENABLED')
+	eventFrame:RegisterEvent('PLAYER_REGEN_DISABLED')
+	eventFrame:RegisterEvent('PLAYER_ENTERING_WORLD')
+	eventFrame:RegisterEvent('PLAYER_LEAVING_WORLD')
+
+	if oUF.isRetail then
+		eventFrame:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED')
+	end
+
+	eventFrame:SetScript('OnEvent', function(_, event)
+		if event == 'PLAYER_ENTERING_WORLD' then
+			hasValidPlayer = true
+		elseif event == 'PLAYER_LEAVING_WORLD' then
+			hasValidPlayer = false
+		elseif event == 'PLAYER_SPECIALIZATION_CHANGED' then
+			wipe(cachedVisibility)
+		elseif event == 'PLAYER_REGEN_ENABLED' or event == 'PLAYER_REGEN_DISABLED' then
+			wipe(cachedVisibility)
+			wipe(cachedPriority)
+		end
+	end)
+
+	local function VisibilityInfo(spellId)
+		return SpellGetVisibilityInfo(spellId, UnitAffectingCombat('player') and 'RAID_INCOMBAT' or 'RAID_OUTOFCOMBAT')
+	end
+
+	local function CachedVisibility(spellId)
+		if cachedVisibility[spellId] == nil then
+			if not hasValidPlayer then -- Don't cache the info if the player is not valid since we didn't get a valid result
+				return VisibilityInfo(spellId)
+			else
+				cachedVisibility[spellId] = {VisibilityInfo(spellId)}
+			end
+		end
+
+		return unpack(cachedVisibility[spellId])
+	end
+
+	local function AllowAura(spellId)
+		local hasCustom, alwaysShowMine, showForMySpec = CachedVisibility(spellId)
+		return (not hasCustom) or alwaysShowMine or showForMySpec
+	end
+
+	local AlwaysAllow = { -- spells could get stuck but it's very rare, this table is for that
+		[335904] = true -- Doom Winds: Unable to gain effects of Doom Winds
+	}
+
+	local function AuraIsPriority(spellId)
+		if AlwaysAllow[spellId] then
+			return true
+		end
+
+		if cachedPriority[spellId] == nil then
+			cachedPriority[spellId] = SpellIsPriorityAura(spellId)
+		end
+
+		return cachedPriority[spellId]
+	end
+
+	local function CouldDisplayAura(frame, event, unit, auraInfo)
+		if auraInfo.isNameplateOnly then
+			return frame.isNamePlate
+		elseif auraInfo.isBossAura or AuraIsPriority(auraInfo.spellId) then
+			return true
+		elseif auraInfo.isHarmful or auraInfo.isHelpful then
+			return AllowAura(auraInfo.spellId)
+		end
+
+		return false
+	end
+
+	local function ShouldSkipAura(frame, event, unit, fullUpdate, updatedAuras, relevantFunc, ...)
+		if fullUpdate or fullUpdate == nil then
+			return false
+		elseif updatedAuras and relevantFunc then
+			for _, auraInfo in ipairs(updatedAuras) do
+				if relevantFunc(frame, event, unit, auraInfo, ...) then
+					return false
+				end
+			end
+
+			return true
+		end
+	end
+
+	function oUF:ShouldSkipAuraUpdate(frame, event, unit, fullUpdate, updatedAuras, relevantFunc)
+		return (not unit or frame.unit ~= unit) or ShouldSkipAura(frame, event, unit, fullUpdate, updatedAuras, relevantFunc or CouldDisplayAura)
+	end
+end
+
+do -- Event Pooler by Simpy
+	local pooler = CreateFrame('Frame')
+	pooler.events = {}
+	pooler.times = {}
+
+	pooler.delay = 0.1 -- update check rate
+	pooler.instant = 1 -- seconds since last event
+
+	pooler.run = function(funcs, frame, event, ...)
+		for _, func in pairs(funcs) do
+			func(frame, event, ...)
+		end
+	end
+
+	pooler.execute = function(event, pool, instant, arg1, ...)
+		for frame, info in pairs(pool) do
+			local funcs = info.functions
+			if instant and funcs then
+				if event == 'UNIT_AURA' and oUF.isRetail then
+					local fullUpdate, updatedAuras = ...
+					if not oUF:ShouldSkipAuraUpdate(frame, event, arg1, fullUpdate, updatedAuras) then
+						pooler.run(funcs, frame, event, arg1, fullUpdate, updatedAuras)
+					end
+				else
+					pooler.run(funcs, frame, event, arg1, ...)
+				end
+			else
+				local data = funcs and info.data[event]
+				if data then
+					if event == 'UNIT_AURA' and oUF.isRetail then
+						local allowUnit = false
+						for _, args in ipairs(data) do
+							local unit, fullUpdate, updatedAuras = unpack(args)
+							if not oUF:ShouldSkipAuraUpdate(frame, event, unit, fullUpdate, updatedAuras) then
+								allowUnit = unit
+								break
+							end
+						end
+
+						if allowUnit then
+							pooler.run(funcs, frame, event, allowUnit)
+						end
+					else
+						local count = #data
+						local args = count and data[count]
+						if args then
+							-- if count > 1 then print(frame:GetDebugName(), event, count, unpack(args)) end
+							pooler.run(funcs, frame, event, unpack(args))
+						end
+
+					end
+
+					wipe(data)
+				end
+			end
+		end
+	end
+
+	pooler.update = function()
+		for event, pool in pairs(pooler.events) do
+			pooler.execute(event, pool)
+		end
+	end
+
+	pooler.tracker = function(frame, event, arg1, ...)
+		-- print('tracker', frame, event, arg1, ...)
+
+		local pool = pooler.events[event]
+		if pool then
+			local now = time()
+			local last = pooler.times[event]
+			if last and (last + pooler.instant) < now then
+				pooler.execute(event, pool, true, arg1, ...)
+				-- print('instant', frame:GetDebugName(), event, arg1)
+			elseif arg1 ~= nil then -- require arg1, no unitless
+				local pooled = pool[frame]
+				if pooled then
+					if not pooled.data[event] then
+						pooled.data[event] = {}
+					end
+
+					tinsert(pooled.data[event], {arg1, ...})
+				end
+			end
+
+			pooler.times[event] = now
+		end
+	end
+
+	pooler.onUpdate = function(self, elapsed)
+		if self.elapsed and self.elapsed > pooler.delay then
+			pooler.update()
+
+			self.elapsed = 0
+		else
+			self.elapsed = (self.elapsed or 0) + elapsed
+		end
+	end
+
+	pooler:SetScript('OnUpdate', pooler.onUpdate)
+
+	function oUF:RegisterEvent(frame, event, func)
+		-- print('RegisterEvent', frame, event, func)
+
+		if not pooler.events[event] then
+			pooler.events[event] = {}
+			pooler.events[event][frame] = {functions={},data={}}
+		elseif not pooler.events[event][frame] then
+			pooler.events[event][frame] = {functions={},data={}}
+		end
+
+		frame:RegisterEvent(event, pooler.tracker)
+		tinsert(pooler.events[event][frame].functions, func)
+	end
+
+	function oUF:UnregisterEvent(frame, event, func)
+		-- print('UnregisterEvent', frame, event, func)
+
+		local pool = pooler.events[event]
+		if pool then
+			local pooled = pool[frame]
+			if pooled then
+				for i, funct in ipairs(pooled.functions) do
+					if funct == func then
+						tremove(pooled.functions, i)
+					end
+				end
+
+				if not next(pooled.functions) then
+					pooled.functions = nil
+					pooled.data = nil -- clear data
+				end
+
+				if not next(pooled) then
+					pool[frame] = nil
+				end
+			end
+
+			if not next(pool) then
+				pooler.events[event] = nil
+				frame:UnregisterEvent(event, pooler.tracker)
+			end
+		end
+	end
+end
diff --git a/oUF/private.lua b/oUF/private.lua
index 9d31559..cc61027 100644
--- a/oUF/private.lua
+++ b/oUF/private.lua
@@ -1,4 +1,4 @@
-local parent, ns = ...
+local _, ns = ...
 local Private = ns.oUF.Private

 function Private.argcheck(value, num, ...)
@@ -8,7 +8,7 @@ function Private.argcheck(value, num, ...)
 		if(type(value) == select(i, ...)) then return end
 	end

-	local types = strjoin(', ', ...)
+	local types = string.join(', ', ...)
 	local name = debugstack(2,2,0):match(": in function [`<](.-)['>]")
 	error(string.format("Bad argument #%d to '%s' (%s expected, got %s)", num, name, types, type(value)), 3)
 end
@@ -77,4 +77,13 @@ function Private.validateEvent(event)
 	end

 	return isOK
-end
\ No newline at end of file
+end
+
+function Private.isUnitEvent(event, unit)
+	local isOK = pcall(validator.RegisterUnitEvent, validator, event, unit)
+	if(isOK) then
+		validator:UnregisterEvent(event)
+	end
+
+	return isOK
+end
diff --git a/oUF/units.lua b/oUF/units.lua
index 517090f..7ea00d7 100644
--- a/oUF/units.lua
+++ b/oUF/units.lua
@@ -1,21 +1,246 @@
-local parent, ns = ...
+local _, ns = ...
 local oUF = ns.oUF
 local Private = oUF.Private

-local enableTargetUpdate = Private.enableTargetUpdate
+local unitExists = Private.unitExists
+
+local function updateArenaPreparationElements(self, event, elementName, specID)
+	local element = self[elementName]
+	if(element and self:IsElementEnabled(elementName)) then
+		if(element.OverrideArenaPreparation) then
+			--[[ Override: Health.OverrideArenaPreparation(self, event, specID)
+			Used to completely override the internal update function for arena preparation.
+
+			* self   - the parent object
+			* event  - the event triggering the update (string)
+			* specID - the specialization ID for the opponent (number)
+			--]]
+			--[[ Override: Power.OverrideArenaPreparation(self, event, specID)
+			Used to completely override the internal update function for arena preparation.
+
+			* self   - the parent object
+			* event  - the event triggering the update (string)
+			* specID - the specialization ID for the opponent (number)
+			--]]
+			element.OverrideArenaPreparation(self, event, specID)
+			return
+		end
+
+		element:SetMinMaxValues(0, 1)
+		element:SetValue(1)
+		if(element.UpdateColorArenaPreparation) then
+			--[[ Override: Health:UpdateColor(specID)
+			Used to completely override the internal function for updating the widget's colors
+			during arena preparation.
+
+			* self   - the Health element
+			* specID - the specialization ID for the opponent (number)
+			--]]
+			--[[ Override: Power:UpdateColor(specID)
+			Used to completely override the internal function for updating the widget's colors
+			during arena preparation.
+
+			* self   - the Power element
+			* specID - the specialization ID for the opponent (number)
+			--]]
+			element:UpdateColorArenaPreparation(specID)
+		else
+			-- this section just replicates the color options available to the Health and Power elements
+			local r, g, b, t, _
+			-- if(element.colorPower and elementName == 'Power') then
+				-- FIXME: no idea if we can get power type here without the unit
+			if(element.colorClass) then
+				local _, _, _, _, _, class = GetSpecializationInfoByID(specID)
+				t = self.colors.class[class]
+			elseif(element.colorReaction) then
+				t = self.colors.reaction[2]
+			elseif(element.colorSmooth) then
+				_, _, _, _, _, _, r, g, b = unpack(element.smoothGradient or self.colors.smooth)
+			elseif(element.colorHealth and elementName == 'Health') then
+				t = self.colors.health
+			end
+
+			if(t) then
+				r, g, b = t[1], t[2], t[3]
+			end
+
+			if(r or g or b) then
+				element:SetStatusBarColor(r, g, b)
+
+				local bg = element.bg
+				if(bg) then
+					local mu = bg.multiplier or 1
+					bg:SetVertexColor(r * mu, g * mu, b * mu)
+				end
+			end
+		end
+
+		if(element.PostUpdateArenaPreparation) then
+			--[[ Callback: Health:PostUpdateArenaPreparation(event, specID)
+			Called after the element has been updated during arena preparation.
+
+			* self   - the Health element
+			* event  - the event triggering the update (string)
+			* specID - the specialization ID for the opponent (number)
+			--]]
+			--[[ Callback: Power:PostUpdateArenaPreparation(event, specID)
+			Called after the element has been updated during arena preparation.
+
+			* self   - the Power element
+			* event  - the event triggering the update (string)
+			* specID - the specialization ID for the opponent (number)
+			--]]
+			element:PostUpdateArenaPreparation(event, specID)
+		end
+	end
+end
+
+local function updateArenaPreparation(self, event)
+	if(not self:GetAttribute('oUF-enableArenaPrep')) then
+		return
+	end
+
+	if(event == 'ARENA_OPPONENT_UPDATE' and not self:IsEnabled()) then
+		self:Enable()
+		self:UpdateAllElements('ArenaPreparation')
+		self:UnregisterEvent(event, updateArenaPreparation)
+
+		-- show elements that don't handle their own visibility
+		if(self:IsElementEnabled('Auras')) then
+			if(self.Auras) then self.Auras:Show() end
+			if(self.Buffs) then self.Buffs:Show() end
+			if(self.Debuffs) then self.Debuffs:Show() end
+		end
+
+		if(self.Portrait and self:IsElementEnabled('Portrait')) then
+			self.Portrait:Show()
+		end
+	elseif(event == 'PLAYER_ENTERING_WORLD' and not UnitExists(self.unit)) then
+		-- semi-recursive call for when the player zones into an arena
+		if oUF.isRetail then
+			updateArenaPreparation(self, 'ARENA_PREP_OPPONENT_SPECIALIZATIONS')
+		end
+	elseif(event == 'ARENA_PREP_OPPONENT_SPECIALIZATIONS') then
+		if(InCombatLockdown()) then
+			-- prevent calling protected functions if entering arena while in combat
+			self:RegisterEvent('PLAYER_REGEN_ENABLED', updateArenaPreparation, true)
+			return
+		end
+
+		if(self.PreUpdate) then
+			self:PreUpdate(event)
+		end
+
+		local id = tonumber(self.id)
+		if(not self:IsEnabled() and GetNumArenaOpponentSpecs() < id) then
+			-- hide the object if the opponent leaves
+			self:Hide()
+		end
+
+		local specID = GetArenaOpponentSpec(id)
+		if(specID) then
+			if(self:IsEnabled()) then
+				-- disable the unit watch so we can forcefully show the object ourselves
+				self:Disable()
+				self:RegisterEvent('ARENA_OPPONENT_UPDATE', updateArenaPreparation)
+			end
+
+			-- update Health and Power (if available) with "fake" data
+			updateArenaPreparationElements(self, event, 'Health', specID)
+			updateArenaPreparationElements(self, event, 'Power', specID)
+
+			-- hide all other (relevant) elements (they have no effect during arena prep)
+			if(self.Auras) then self.Auras:Hide() end
+			if(self.Buffs) then self.Buffs:Hide() end
+			if(self.Debuffs) then self.Debuffs:Hide() end
+			if(self.Castbar) then self.Castbar:Hide() end
+			if(self.CombatIndicator) then self.CombatIndicator:Hide() end
+			if(self.PartyIndicator) then self.PartyIndicator:Hide() end
+			if(self.GroupRoleIndicator) then self.GroupRoleIndicator:Hide() end
+			if(self.Portrait) then self.Portrait:Hide() end
+			if(self.PvPIndicator) then self.PvPIndicator:Hide() end
+			if(self.RaidTargetIndicator) then self.RaidTargetIndicator:Hide() end
+
+			self:Show()
+			self:UpdateTags()
+		end
+
+		if(self.PostUpdate) then
+			self:PostUpdate(event)
+		end
+	elseif(event == 'PLAYER_REGEN_ENABLED') then
+		self:UnregisterEvent(event, updateArenaPreparation)
+		updateArenaPreparation(self, 'ARENA_PREP_OPPONENT_SPECIALIZATIONS')
+	end
+end

 -- Handles unit specific actions.
 function oUF:HandleUnit(object, unit)
-	local unit = object.unit or unit
+	unit = object.unit or unit
 	if(unit == 'target') then
 		object:RegisterEvent('PLAYER_TARGET_CHANGED', object.UpdateAllElements, true)
 	elseif(unit == 'mouseover') then
 		object:RegisterEvent('UPDATE_MOUSEOVER_UNIT', object.UpdateAllElements, true)
 	elseif(unit == 'focus') then
 		object:RegisterEvent('PLAYER_FOCUS_CHANGED', object.UpdateAllElements, true)
+	elseif(unit:match('boss%d?$')) then
+		object:RegisterEvent('INSTANCE_ENCOUNTER_ENGAGE_UNIT', object.UpdateAllElements, true)
+		object:RegisterEvent('UNIT_TARGETABLE_CHANGED', object.UpdateAllElements)
 	elseif(unit:match('arena%d?$')) then
 		object:RegisterEvent('ARENA_OPPONENT_UPDATE', object.UpdateAllElements, true)
-	elseif(unit and unit:match('%w+target')) then
-		enableTargetUpdate(object)
+		if oUF.isRetail then
+			object:RegisterEvent('ARENA_PREP_OPPONENT_SPECIALIZATIONS', updateArenaPreparation, true)
+		end
+		object:SetAttribute('oUF-enableArenaPrep', true)
+		-- the event handler only fires for visible frames, so we have to hook it for arena prep
+		object:HookScript('OnEvent', updateArenaPreparation)
 	end
-end
\ No newline at end of file
+end
+
+local eventlessObjects = {}
+local onUpdates = {}
+
+local function createOnUpdate(timer)
+	if(not onUpdates[timer]) then
+		local frame = CreateFrame('Frame')
+		local objects = eventlessObjects[timer]
+
+		frame:SetScript('OnUpdate', function(self, elapsed)
+			self.elapsed = (self.elapsed or 0) + elapsed
+			if(self.elapsed > timer) then
+				for _, object in next, objects do
+					if(object.unit and unitExists(object.unit)) then
+						object:UpdateAllElements('OnUpdate')
+					end
+				end
+
+				self.elapsed = 0
+			end
+		end)
+
+		onUpdates[timer] = frame
+	end
+end
+
+function oUF:HandleEventlessUnit(object)
+	object.__eventless = true
+
+	local timer = object.onUpdateFrequency or 0.5
+
+	-- Remove it, in case it's registered with another timer previously
+	for t, objects in next, eventlessObjects do
+		if(t ~= timer) then
+			for i, obj in next, objects do
+				if(obj == object) then
+					table.remove(objects, i)
+					break
+				end
+			end
+		end
+	end
+
+	if(not eventlessObjects[timer]) then eventlessObjects[timer] = {} end
+	table.insert(eventlessObjects[timer], object)
+
+	createOnUpdate(timer)
+end
diff --git a/oUF_Simple/core/functions.lua b/oUF_Simple/core/functions.lua
index 7fd4540..c6ffb56 100644
--- a/oUF_Simple/core/functions.lua
+++ b/oUF_Simple/core/functions.lua
@@ -693,4 +693,66 @@ local function CreateEneryTicker(self)

 	return s
 end
-L.F.CreateEneryTicker = CreateEneryTicker
\ No newline at end of file
+L.F.CreateEneryTicker = CreateEneryTicker
+
+local function RunesPostUpdate(self, runemap)
+	local bar = self
+	local runemap = runemap
+
+	for i, runeId in next, runemap do
+		local isReady = select(3, GetRuneCooldown(runeId))
+
+		if isReady then
+			bar[i]:SetAlpha(1)
+		else
+			bar[i]:SetAlpha(0.5)
+		end
+	end
+end
+
+--CreateRunesBar
+local function CreateRunesBar(self)
+  if not self.cfg.runebar or not self.cfg.runebar.enabled then return end
+  if(select(2, UnitClass('player')) ~= 'DEATHKNIGHT') then return end
+
+  local s = CreateFrame("Frame", self:GetName().."RuneBar", self)
+  local w, h = unpack(self.cfg.runebar.size)
+  -- Runes
+	-- s:SetFrameLevel(self.Health:GetFrameLevel() + 1)
+  s:SetSize(w, h)
+  SetPoint(s,self,self.cfg.runebar.point)
+
+	-- s:SetHeight(6)
+	-- s:SetPoint("TOPLEFT", self.Health, 0, 10)
+	-- s:SetPoint("TOPRIGHT", self.Health, 0, 10)
+
+  --backdrop
+  CreateBackdrop(s)
+
+  for i = 1, 6 do
+		s[i] = CreateFrame("StatusBar", self:GetName().."Rune"..i, s)
+		s[i]:SetHeight(s:GetHeight())
+		s[i]:SetStatusBarTexture(L.C.textures.statusbar)
+		s[i]:SetStatusBarColor(self.Power:GetStatusBarColor())
+
+		s[i].bg = s[i]:CreateTexture(nil, "BACKGROUND")
+		s[i].bg:SetAllPoints(s[i])
+		s[i].bg:SetTexture(L.C.textures.statusbar)
+		s[i].bg:SetAlpha(0.4)
+    --attributes
+    s[i].bg.multiplier = L.C.colors.bgMultiplier
+
+		if i == 1 then
+			s[i]:SetWidth(w/6)
+			s[i]:SetPoint("LEFT", s, "LEFT", 0, 0)
+		else
+			s[i]:SetWidth(w/6 - 2)
+			s[i]:SetPoint("LEFT", s[i-1], "RIGHT", 2, 0)
+		end
+	end
+
+  s.PostUpdate = RunesPostUpdate
+	s.colorSpec = true
+  return s
+end
+L.F.CreateRunesBar = CreateRunesBar
\ No newline at end of file
diff --git a/oUF_Simple/core/style.lua b/oUF_Simple/core/style.lua
index 7483279..4231dc8 100644
--- a/oUF_Simple/core/style.lua
+++ b/oUF_Simple/core/style.lua
@@ -37,6 +37,7 @@ local function CreateStyle(self)
   L.F.ToggleSmooth(self, L.C.smooth)
   self.Castbar = L.F.CreateCastBar(self)
   self.rClassBar = L.F.CreateClassBar(self)
+  self.Runes = L.F.CreateRunesBar(self)
   -- self.AlternativePower = L.F.CreateAltPowerBar(self)
   -- self.AdditionalPower = L.F.CreateAdditionalPowerBar(self)
   self.Swing = L.F.CreateSwing(self)
diff --git a/oUF_Simple/oUF_Simple.toc b/oUF_Simple/oUF_Simple.toc
index d9cfe55..e363171 100644
--- a/oUF_Simple/oUF_Simple.toc
+++ b/oUF_Simple/oUF_Simple.toc
@@ -1,5 +1,5 @@
-## Interface: 20504
-## Title: oUF_Simple |cff1a9fc0BCC|r
+## Interface: 30400
+## Title: oUF_Simple |cff1a9fc0WLK|r
 ## Author: zork
 ## Notes: Simple oUF layout
 ## Dependencies: oUF, rLib, oUF_SimpleConfig
diff --git a/oUF_SimpleConfig/oUF_SimpleConfig.toc b/oUF_SimpleConfig/oUF_SimpleConfig.toc
index ae05426..a31a237 100644
--- a/oUF_SimpleConfig/oUF_SimpleConfig.toc
+++ b/oUF_SimpleConfig/oUF_SimpleConfig.toc
@@ -1,6 +1,6 @@
-## Interface: 20504
+## Interface: 30400
 ## Author: zork
-## Title: oUF_SimpleConfig |cff1a9fc0BCC|r
+## Title: oUF_SimpleConfig |cff1a9fc0WLK|r
 ## Notes: oUF_Simple config
 ## RequiredDeps: rLib

diff --git a/oUF_SimpleConfig/player.lua b/oUF_SimpleConfig/player.lua
index 18b9412..ffe0f47 100644
--- a/oUF_SimpleConfig/player.lua
+++ b/oUF_SimpleConfig/player.lua
@@ -64,8 +64,7 @@ L.C.player = {
       enabled = true,
       point = {"RIGHT",-2,0},
       size = 8,
-      --tag = "[perpp]",
-      tag = "[curmana]",
+      tag = "[curpp]",
       font = L.C.fonts.expressway,
     },
   },
@@ -121,6 +120,11 @@ L.C.player = {
       color = {0,0,0,1}
     },
   },
+  runebar = {
+    enabled = true,
+    size = {265,5},
+    point = {"BOTTOM","TOP",0,4}, --if no relativeTo is given the frame base will be the relativeTo reference
+  },
   --altpowerbar
   altpowerbar = {
     enabled = false,
diff --git a/rButtonAura/rButtonAura.toc b/rButtonAura/rButtonAura.toc
index 797ef03..03bfb54 100644
--- a/rButtonAura/rButtonAura.toc
+++ b/rButtonAura/rButtonAura.toc
@@ -1,5 +1,5 @@
-## Interface: 20504
-## Title: rButtonAura |cff1a9fc0BCC|r
+## Interface: 30400
+## Title: rButtonAura |cff1a9fc0WLK|r
 ## Author: zork
 ## Notes: Highlights action buttons when a matching unit aura is present
 ## RequiredDeps: rLib
diff --git a/rButtonAura_Zork/rButtonAura_Zork.toc b/rButtonAura_Zork/rButtonAura_Zork.toc
index 012c1d0..02042a9 100644
--- a/rButtonAura_Zork/rButtonAura_Zork.toc
+++ b/rButtonAura_Zork/rButtonAura_Zork.toc
@@ -1,5 +1,5 @@
-## Interface: 20504
-## Title: rButtonAura_Zork |cff1a9fc0BCC|r
+## Interface: 30400
+## Title: rButtonAura_Zork |cff1a9fc0WLK|r
 ## Author: zork
 ## Notes: Zork's config for rButtonAura
 ## RequiredDeps: rButtonAura
diff --git a/rChatPlus/rChatPlus.toc b/rChatPlus/rChatPlus.toc
index 3565ce5..3781142 100644
--- a/rChatPlus/rChatPlus.toc
+++ b/rChatPlus/rChatPlus.toc
@@ -1,6 +1,6 @@
-## Interface: 20504
+## Interface: 30400
 ## Author: rawoil
-## Title: rChat|cffff7d0aPlus|r |cff1a9fc0BCC|r
+## Title: rChat|cffff7d0aPlus|r |cff1a9fc0WLK|r
 ## Notes: Chat enhancements advanced
 ## RequiredDeps: rLib, oUF_SimpleConfig

diff --git a/rFilter/rFilter.toc b/rFilter/rFilter.toc
index 909dd1a..b1cef74 100644
--- a/rFilter/rFilter.toc
+++ b/rFilter/rFilter.toc
@@ -1,5 +1,5 @@
-## Interface: 20504
-## Title: rFilter |cff1a9fc0BCC|r
+## Interface: 30400
+## Title: rFilter |cff1a9fc0WLK|r
 ## Author: zork
 ## Notes: Buff, debuff, raidbuff and cooldown filter. Eats puppies!
 ## Dependencies: rLib
diff --git a/rFilter_Zork/rFilter_Zork.toc b/rFilter_Zork/rFilter_Zork.toc
index 13aa5ff..2c92bb9 100644
--- a/rFilter_Zork/rFilter_Zork.toc
+++ b/rFilter_Zork/rFilter_Zork.toc
@@ -1,6 +1,6 @@
-## Interface: 20504
+## Interface: 30400
 ## Author: zork
-## Title: rFilter_Zork |cff1a9fc0BCC|r
+## Title: rFilter_Zork |cff1a9fc0WLK|r
 ## Notes: Layout and optional theme for rFilter
 ## RequiredDeps: rLib, rFilter
 ## OptionalDeps: rButtonTemplate, rButtonTemplate_Zork
diff --git a/rSkin/rSkin.toc b/rSkin/rSkin.toc
index 35d2219..4c7c9f4 100644
--- a/rSkin/rSkin.toc
+++ b/rSkin/rSkin.toc
@@ -1,6 +1,6 @@
-## Interface: 20504
+## Interface: 30400
 ## Author: rawoil
-## Title: rSkin |cff1a9fc0BCC|r
+## Title: rSkin |cff1a9fc0WLK|r
 ## Notes: Reskin other addons to fit zorkui's L&F
 ## RequiredDeps: rLib, rButtonTemplate_Zork, oUF_SimpleConfig
 ## OptionalDeps: DBM-Core, WeakAuras, ls_Toasts, Details, BigWigs_Plugins, ThreatClassic2, Dominos, MerInspect
diff --git a/rStatusButton/core.lua b/rStatusButton/core.lua
index af8065e..db95976 100644
--- a/rStatusButton/core.lua
+++ b/rStatusButton/core.lua
@@ -49,7 +49,7 @@ local function OnEnter(self)
   GameTooltip:SetOwner(self, "ANCHOR_TOP")
   GameTooltip:AddLine(self:GetName(), 1, 0.5, 0, 1, 1, 1)
   --experience
-  if UnitLevel("player") < MAX_PLAYER_LEVEL then -- classic-disable --and not IsXPUserDisabled() then
+  if UnitLevel("player") < 70 then -- MAX_PLAYER_LEVEL then -- classic-disable --and not IsXPUserDisabled() then
     local cur, max = UnitXP("player"), UnitXPMax("player")
     local lvl = UnitLevel("player")
     local rested = GetXPExhaustion() or 0