--[[ |
PowerUp - Paladin Module |
|
These are the general thoughts behind how the Holy Power decay-timer works.. |
|
Observation has shown that a charge expires approximately 10 seconds after you receieve it, unless you are in combat. If you are in |
combat the charge persists (unless you use it of course) and when you exit combat a timer will start. There's one very importat |
aspect to make note off though. If you had a charge before you entered combat, with for example 5 seconds left on its duration, and |
you entered combat and didn't use the charge, the timer will pick up where it paused prior to combat. |
|
Due to latency both between one self and the servers as well as difference when the game considers you out of combat to when you're |
actually out of combat (and Blizzards internal timer starts) it's not possible to make it 100% accurate, ergo it's guesstimating by |
adding the players current latency (which itself is a average value) onto the maximum-value of the bar. While not perfect, it makes |
it accurate enough to the point where you get a reliable indication of when it's going to expire. |
|
It also seems like UNIT_POWER doesn't fire for new charges when you're already at the max amount. The CLEU SPELL_ENERGIZE event does |
fire though. |
]] |
|
-- local PowerUp = _G.PowerUp |
|
if PowerUp.class ~= "PALADIN" then return end |
|
local db, pguid |
local powerType, powerName |
|
-- Setup frames |
function PowerUp:Init() |
db = PowerUpDB |
|
powerType = "HOLY_POWER" |
powerName = SPELL_POWER_HOLY_POWER |
|
for i=1, #self.bars do |
self.bars[i]:SetVertexColor(db.colors.paladin.r, db.colors.paladin.g, db.colors.paladin.b) |
end |
|
-- create overlay if enabled |
if db.showhptimer then |
self.timer = self.timer or CreateFrame("StatusBar", "PowerUpTimer", self) |
|
self.timer:SetAllPoints(self) |
self.timer:SetMinMaxValues(0, 10) |
self.timer:SetValue(0) |
|
self.timer:SetStatusBarTexture(self.bars[1]:GetTexture()) |
self.timer:SetStatusBarColor(db.colors.overlay.r, db.colors.overlay.g, db.colors.overlay.b, db.hptimeralpha) |
|
self.timer.text = self.timer.text or self.timer:CreateFontString(nil, "OVERLAY") |
self.timer.text:SetFontObject(GameFontHighlight) |
self.timer.text:SetPoint("LEFT", self.timer, "RIGHT", 5, 0) |
|
-- we need this to account for pausing and whatnot |
self:RegisterEvent("PLAYER_REGEN_ENABLED") |
self:RegisterEvent("PLAYER_REGEN_DISABLED") |
end |
|
self.last = 0 |
|
self:RegisterEvent("UNIT_POWER") |
self.UNIT_POWER = self.RefreshPowers |
|
-- update powers at login/zoning in case we have some already |
-- if a power disappears during loading screen, it wont update |
-- properly otherwise. |
self:RegisterEvent("PLAYER_ENTERING_WORLD") |
end |
|
-- Throttle? Not really necessary maybe, since it's not running for |
-- excessive amounts of time. |
local function onUpdate(self, elapsed) |
local value = self.timer:GetValue() |
local new = value - elapsed |
|
if value <= 0 then |
self.timer:Hide() |
self:SetScript("OnUpdate", nil) |
else |
self.timer:SetValue(new) |
|
if db.showtimertext then |
self.timer.text:SetFormattedText("%.1f", new) |
else |
self.timer.text:SetText("") |
end |
|
if db.usehpgradient then |
self.timer:SetStatusBarColor(1*(1-(value/10)), 1*(value/10), 0, db.hptimeralpha) |
end |
end |
end |
|
-- All the latency-stuff is there to offset possible fluctuations in lag causing the timer |
-- to not be exactly 10s every time. See note above for a few more details. That also |
-- explains why we're first checking if there was any active prior to combat. |
function PowerUp:StartTimer() |
if InCombatLockdown() then return end |
|
local prior = nil |
local num = UnitPower("player", SPELL_POWER_HOLY_POWER) |
|
for i=1, num do |
if self.bars[i].wasactive then |
prior = i |
end |
end |
|
local _, _, latency = GetNetStats() |
latency = format("%.02f", (latency/1000)) |
|
if not prior then |
self.timer:SetMinMaxValues(0, 10+latency) |
self.timer:SetValue(10+latency) |
else |
self.timer:SetMinMaxValues(0, (10+latency)-self.bars[prior].alreadyElapsed) |
self.timer:SetValue((10+latency) - self.bars[prior].alreadyElapsed) |
end |
self:SetScript("OnUpdate", onUpdate) |
self.timer:Show() |
end |
|
-- Save how much has already elapsed if there are charges available |
function PowerUp:PLAYER_REGEN_DISABLED() |
local num = UnitPower("player", SPELL_POWER_HOLY_POWER) |
if self.timer:IsVisible() and num > 0 then |
local min, max = self.timer:GetMinMaxValues() |
self:SetScript("OnUpdate", nil) |
self.timer:Hide() |
self.bars[num].wasactive = true |
self.bars[num].alreadyElapsed = 10 - self.timer:GetValue() |
self.timer:SetValue(0) |
end |
end |
|
-- If there are any charges, start a timer! |
function PowerUp:PLAYER_REGEN_ENABLED() |
local num = UnitPower("player", SPELL_POWER_HOLY_POWER) |
if num > 0 then |
self:StartTimer() |
end |
end |
|
function PowerUp:PLAYER_ENTERING_WORLD() |
pguid = UnitGUID("player") |
self:RefreshPowers("player", powerType) |
end |
|
-- use CLEU when at max charges |
function PowerUp:COMBAT_LOG_EVENT_UNFILTERED(timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, spellId, spellName, _, _, powerType) |
if sourceGUID == pguid and event == "SPELL_ENERGIZE" and powerType == 9 then |
if InCombatLockdown() then |
self.bars[db.max].wasactive = false |
else |
self:StartTimer() |
end |
end |
end |
|
function PowerUp:RefreshPowers(unit, power) |
if unit ~= "player" or (power and power ~= powerType) then return end |
local num = UnitPower("player", powerName) |
|
for i = 1, db.max do |
if(i <= num) then |
self.bars[i]:SetAlpha(1) |
-- we have more than 1, so check if the prior one was active before we |
-- entered combat and remove the flag if true. |
if num > 1 and db.showhptimer then |
if self.bars[num-1].wasactive then |
self.bars[num-1].wasactive = false |
end |
end |
else |
self.bars[i]:SetAlpha(0) |
-- Check if the charge was active before combat and make a note |
-- that it expired during combat. |
if db.showhptimer and self.bars[i].wasactive then |
self.bars[i].wasactive = false |
end |
end |
end |
|
if db.showhptimer and not InCombatLockdown() then |
if num == 0 then -- hiiiide |
self.timer:SetValue(0) |
self.timer:Hide() |
self:SetScript("OnUpdate", nil) |
elseif num > self.last then |
-- increase, start new timer if applicable |
|
self:StartTimer() |
elseif num < self.last then |
-- decrease |
self:StartTimer() |
end |
elseif not db.showhptimer and self.timer:IsVisible() then |
self.timer:Hide() |
self:SetScript("OnUpdate", nil) |
end |
|
-- if we're at max, UNIT_POWER won't fire until one charge expires, |
-- which means the timer won't update properly. |
if num == db.max then |
self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
else |
self:UnregisterEvent("COMBAT_LOG_EVENT_UNFILTERED") |
end |
|
self.last = num |
|
if db.hidewhenempty and num == 0 then |
self:Hide() |
else |
self:Show() |
end |
end |