# Time To Die

• 15 posts
#1 Sep 15, 2011 at 07:24 UTC - 0 likes

Ive been wracking my brain all night trying to figure this out, theres a function in a few addons (namely MageManaBar and TimeToDie) that both do around the same calculations for giving an estimate for when a mob will die , i tried hooking it to Unit_Health to no avail (still new to lua) i even tried to essentially copy mage mana bars functionality just to make combine as much as i can into Weak Auras.

My ultimate goal in all of this is to have an animation go off when time to oom is >= time to mob death to signify a final burn for arcane mages. But one step at a time for this, just attempting a simple text output of the time to die at the moment. Here is as far as i got, the problem was it was occasioanlly putting in the time but updating so often it defaulted to NIL and i couldn't reliably read it. i did try a few other things but lost the code :(. this was all in a custom text (%c)

function()
local unit = Unitname("target")
local health = UnitHealth("target")
local timetodie = 0

if oldhealth ~= health then
oldhealth = health

local text

if health == UnitHealthMax("target") then
health0, time0, mhealth, mtime = nil
text = "INF"
return text
end

local time = GetTime()

if not health0 then
health0, time0 = health, time
mhealth, mtime = health, time
return
end

mhealth = (mhealth + health) * .5
mtime = (mtime + time) * .5

if mhealth >= health0 then
health0, time0, mhealth, mtime = nil
text= "healing"
else
timetodie = health * (time0 - mtime) / (mhealth - health0)
if  (timetodie <= 60) then
text = format("%0.2d",timetodie)
elseif (timetodie>60) then
text = format("%d:%0.2d",timetodie / 60, timetodie % 60)
end
end

return text
elseif unit == nil then
return "nil"
end
end


Any help would be much appreciated, just found this addon this week and it has already gone beyond what i thought one addon could add!

Last edited Sep 15, 2011 by Hx2600
#2 Sep 15, 2011 at 19:25 UTC - 0 likes

I think ive figured out how to make it work with a trigger for status Health on target with a modified lua code from up top as the %c .. could use a little cleanup on the math as its rounding up, and smoothing out the estimated time but for its a good first draft. I think the biggest issue i might have is finding a way for an animation to trigger when one function is > than the other..

TTD Text (text is %c, this is whats in the editor) as it is now:

function()
local health = UnitHealth("target")
local time = GetTime()
local text
local oldhealth
if oldhealth ~= health then
oldhealth = health
if health == UnitHealthMax("target") then -- THiS BLOCK IS GOOD
health0, time0, mhealth, mtime = nil
text = " - - "
return text
end

if not health0 then -- GOOD
health0, time0 = health, time
mhealth, mtime = health, time
return
end

mhealth = (mhealth + health) * .5
mtime = (mtime + time) * .5

if mhealth >= health0 then
text = " - - "
health0, time0, mhealth, mtime =nil
else
time = health * (time0 - mtime) / (mhealth - health0)
if (time <= 60) then
text = format("%0.2d",time)
elseif (time > 60) then
text = format("%d:%0.2d",time / 60, time % 60)
end
return text
end
end
end


in case anyone wants to fiddle with it:

dieFhaGivLUeiLrPk1PuvSkLQ4viuzwkvUfs1UuvLFHqvdtvCmqyzQs8mOOPHOUgsP2guPVbsgNQKohuH1bveZdHc3dkTpLIyHif6HqfvtuPQSrKI(OQQYivQQojurzLaEjcfntek1nvvv1ovks)uPWtrYubrxvPkTxL8xKcgSCyiwmcL8yeYKrWLvzZiYNHcJgvNgOzdQBdPDJs)gfgoivlhQ65QQmDfxhfTDLI67QQQmELsNhPK5dvK2p9cIfKlk0ffHffHfKlkcG)GomcTG82olkOr0IIiM)ggOqEBNffjMSenGmyF)raZmdMbriWg)qGhUH12ll4S)dbE4V)oi4X4MVFeWmZGzqecSnGONH1(3nqcIEV)iGzMbZGieyBUTJaMzgmdIqGngWe4hc8WfWmZajzmGjWpe4HBItXA8dbE42WpwbmZmZmJbmb(HapCdRXpe4HlGzMzMzGKm(HapCdlwBVSGZ(pe4H))iBF)DqWJXnF)yd)yn60ni3piLrJe7nW5etdNrz)BJn2NaMzMzMzMz8dbE4p7Sbe9E2zO8dbE47m0be9mSgliSaMzMzMzMzZTDmS2xJUr3(kGzMzMzMzg(ByIN1MB7iGzMzMzhlbbmZmZmtaZmZmZajzSmgJFiWd)Xg(XA0PB)BJn2NaMzMzMzMz8dbE4p7Sbe9EmSg)qGh(oBarpbmZmZmZmZq5hc8W3zOdi6zyn(Hap8D2aIEcyMzMzMzMH)gM4zfWmZmZSJLGaMzMzMjGzMzMzO8dbE4gw7nk)qGhUrCg)qGh(hBp2F0waZmZmZqhq0ZWAVrhq0ZioBarVp2ES)OTaMzMzMjGzMzMzGKmu(HapCBtWA8dbE4p2WpwbmZmZmZmZMB7yyTVgDJU9vaZmZmZmZm(Hap8ND2aIEp7mu(Hap8Dg6aIEgwwqybmZmZm7G)DcyMzMzMzMnGONH14hc8WT9yVhq07XOBOdi69XiE7nk)qGhUr34hc8WF(iGzMzMzMzgij79aIEgXaRH7ZhB4hRaMzMzMzMzMz2CBhdRrIbEuK59xO983le(UBarVpMzMzMzMjGzMzMzMz2b)7ajzVhq0Z2ed3Np2WpwbmZmZmZmZmZS52ogwJed8OiZ7VqJaobAp)9cHV7gq0ZiEd3ND2aIEg0mCF(iGzMzMzMz2XsqaZmZmZmZm83WepRn32raZmZmZowccyMzhlbbowcciGaciGaciGaciGalkMSdEqmW4WVGCrXKfCwudcEmUznlkIy(ByGc5TD2l0jGm3I628XolQbpigyC4xqUOgAb9Br9BqgM)wumzbNf1GGhJBwum)D0atwWzrJlkM)oAa6hEIo2HFiWdFrSwumzVnFSZIcH5WynlQ)dKWWx0ekYq9cUKF5fYqbbzOEEfZfj6KFDrTDdsK(DZIM0PneycfzmFftiG4btiG6vYls0jtErH)WaKblK0c63IAUTZIIFGyWNfnXfhy(6R4(afoGGmeKH6bIfj6KXXIcKWIcsq0Zgg2(aVffT2GePF3SOjDYq9Gju4IluKXbMpyIJNxwKOtM2Rzr9BrbXFK)dZf1MxBkeKFEwZAb

Last edited Sep 15, 2011 by Hx2600
#3 Sep 22, 2011 at 18:00 UTC - 0 likes

So after some debugging, here is some code:

Time To OOM:

-- Custom text function
function()
-- Setup trigger (once)
if not WA_TTOOM_Windows then
-- User variables
WA_TTOOM_Windows = 8             -- Max number of samples
WA_TTOOM_Steps = 1.5             -- Time between samples

-- Code variables
WA_TTOOM_MaxValue = 0            -- Remember max HP for relative shift
WA_TTOOM_Last = GetTime()        -- Remember last update
WA_TTOOM_Start = nil             -- First data collection time for relative shift
WA_TTOOM_Index = 0               -- Current ring buffer index
WA_TTOOM_Times = {}              -- Ring buffer data - data_x
WA_TTOOM_Values = {}             -- Ring buffer data - data_y
WA_TTOOM_Samples = 0             -- Number of collected (active) samples
WA_TTOOM_Estimate = nil          -- Estimated end time (not relative)
end

-- Query current time (throttle updating over time)
local now = GetTime()
if now - WA_TTOOM_Last >= WA_TTOOM_Steps then
-- Current data
local data = UnitPower("player")

-- Reset data?
if data == UnitPowerMax("player") then
WA_TTOOM_Start = nil
WA_TTOOM_Estimate = nil
end

-- No start time?
if not WA_TTOOM_Start then
WA_TTOOM_Start = now
WA_TTOOM_Index = 0
WA_TTOOM_Samples = 0
WA_TTOOM_MaxValue = UnitPowerMax("player") / 2
end

-- Remember current time
WA_TTOOM_Last = now

-- Save new data (Use relative values to prevent "overflow")
WA_TTOOM_Values[WA_TTOOM_Index] = data - WA_TTOOM_MaxValue
WA_TTOOM_Times[WA_TTOOM_Index] = now - WA_TTOOM_Start

-- Next index
WA_TTOOM_Index = WA_TTOOM_Index + 1

-- Update number of active samples
if WA_TTOOM_Index > WA_TTOOM_Samples then
WA_TTOOM_Samples = WA_TTOOM_Index
end

-- Using table as ring buffer
if WA_TTOOM_Index >= WA_TTOOM_Windows then
WA_TTOOM_Index = 0
end

-- Min number of samples
if WA_TTOOM_Samples >= 2 then
-- Estimation variables
local SS_xy, SS_xx, x_M, y_M = 0, 0, 0, 0

-- Calc pre-solution values
for index = 0, WA_TTOOM_Samples-1 do
-- Calc mean value
x_M = x_M + WA_TTOOM_Times[index] / WA_TTOOM_Samples
y_M = y_M + WA_TTOOM_Values[index] / WA_TTOOM_Samples

-- Calc sum of squares
SS_xx = SS_xx + WA_TTOOM_Times[index] * WA_TTOOM_Times[index]
SS_xy = SS_xy + WA_TTOOM_Times[index] * WA_TTOOM_Values[index]
end

-- Few last additions to mean value / sum of squares
SS_xx = SS_xx - WA_TTOOM_Samples * x_M * x_M
SS_xy = SS_xy - WA_TTOOM_Samples * x_M * y_M

-- Results
local a_0, a_1, x = 0, 0, 0

-- Calc a_0, a_1 of linear interpolation (data_y = a_1 * data_x + a_0)
a_1 = SS_xy / SS_xx
a_0 = y_M - a_1 * x_M

-- Find zero-point (Switch back to absolute values)
a_0 = a_0 + WA_TTOOM_MaxValue
x = - (a_0 / a_1)

-- Valid/Usable solution
if a_1 and a_1 < 1 and a_0 and a_0 > 0 and x and x > 0 then
WA_TTOOM_Estimate = x + WA_TTOOM_Start
-- Fallback
else
WA_TTOOM_Estimate = nil
end

-- Not enough data
else
WA_TTOOM_Estimate = nil
end
end

-- No/False information
if not WA_TTOOM_Estimate then
return "<No Information>"

elseif now > WA_TTOOM_Estimate then
return "<Estimated to be OOM>"

-- Seconds only
elseif WA_TTOOM_Estimate - now <= 60 then
return string.format("%0.2d", WA_TTOOM_Estimate - now)

-- More than seconds
else
return string.format("%d:%0.2d", (WA_TTOOM_Estimate - now) / 60, (WA_TTOOM_Estimate - now) % 60)
end
end


Time To Die:

-- Custom text function
function()
-- Setup trigger (once)
if not WA_TTD_Windows then
-- User variables
WA_TTD_Windows = 8             -- Max number of samples
WA_TTD_Steps = 1.5             -- Time between samples

-- Code variables
WA_TTD_GUID = nil              -- Remember GUID of mob you are tracking
WA_TTD_MaxValue = 0            -- Remember max HP for relative shift
WA_TTD_Last = GetTime()        -- Remember last update
WA_TTD_Start = nil             -- First data collection time for relative shift
WA_TTD_Index = 0               -- Current ring buffer index
WA_TTD_Times = {}              -- Ring buffer data - data_x
WA_TTD_Values = {}             -- Ring buffer data - data_y
WA_TTD_Samples = 0             -- Number of collected (active) samples
WA_TTD_Estimate = nil          -- Estimated end time (not relative)
end

-- Query current time (throttle updating over time)
local now = GetTime()
if now - WA_TTD_Last >= WA_TTD_Steps then
-- Current data
local data = UnitHealth("target")

-- Reset data?
if data == UnitHealthMax("target") or not WA_TTD_GUID or WA_TTD_GUID ~= UnitGUID("target") then
WA_TTD_GUID = nil
WA_TTD_Start = nil
WA_TTD_Estimate = nil
end

-- No start time?
if not WA_TTD_Start or not WA_TTD_GUID then
WA_TTD_Start = now
WA_TTD_Index = 0
WA_TTD_Samples = 0
WA_TTD_MaxValue = UnitHealthMax("target") / 2
WA_TTD_GUID = UnitGUID("target")
end

-- Remember current time
WA_TTD_Last = now

-- Save new data (Use relative values to prevent "overflow")
WA_TTD_Values[WA_TTD_Index] = data - WA_TTD_MaxValue
WA_TTD_Times[WA_TTD_Index] = now - WA_TTD_Start

-- Next index
WA_TTD_Index = WA_TTD_Index + 1

-- Update number of active samples
if WA_TTD_Index > WA_TTD_Samples then
WA_TTD_Samples = WA_TTD_Index
end

-- Using table as ring buffer
if WA_TTD_Index >= WA_TTD_Windows then
WA_TTD_Index = 0
end

-- Min number of samples
if WA_TTD_Samples >= 2 then
-- Estimation variables
local SS_xy, SS_xx, x_M, y_M = 0, 0, 0, 0

-- Calc pre-solution values
for index = 0, WA_TTD_Samples-1 do
-- Calc mean value
x_M = x_M + WA_TTD_Times[index] / WA_TTD_Samples
y_M = y_M + WA_TTD_Values[index] / WA_TTD_Samples

-- Calc sum of squares
SS_xx = SS_xx + WA_TTD_Times[index] * WA_TTD_Times[index]
SS_xy = SS_xy + WA_TTD_Times[index] * WA_TTD_Values[index]
end

-- Few last additions to mean value / sum of squares
SS_xx = SS_xx - WA_TTD_Samples * x_M * x_M
SS_xy = SS_xy - WA_TTD_Samples * x_M * y_M

-- Results
local a_0, a_1, x = 0, 0, 0

-- Calc a_0, a_1 of linear interpolation (data_y = a_1 * data_x + a_0)
a_1 = SS_xy / SS_xx
a_0 = y_M - a_1 * x_M

-- Find zero-point (Switch back to absolute values)
a_0 = a_0 + WA_TTD_MaxValue
x = - (a_0 / a_1)

-- Valid/Usable solution
if a_1 and a_1 < 1 and a_0 and a_0 > 0 and x and x > 0 then
WA_TTD_Estimate = x + WA_TTD_Start
-- Fallback
else
WA_TTD_Estimate = nil
end

-- Not enough data
else
WA_TTD_Estimate = nil
end
end

-- No/False information
if not WA_TTD_Estimate then
return "<No Information>"

elseif now > WA_TTD_Estimate then

-- Seconds only
elseif WA_TTD_Estimate - now <= 60 then
return string.format("%0.2d", WA_TTD_Estimate - now)

-- More than seconds
else
return string.format("%d:%0.2d", (WA_TTD_Estimate - now) / 60, (WA_TTD_Estimate - now) % 60)
end
end


Both codes are are to be used as custom texts and contain two settings:

• WA_TTD/TTOOM_Windows - Which is the maximum number of samples collected to estimate the time of death/oom. Higher numbers mean more accuracy (as more data is collected) but also mean slower processing time. I'd recommend values between 5-40 samples. (Higher number=More accuracy )
• WA_TTD/TTOOM_Steps - The minimum delay between data collection. This can be used to "stretch" (higher numbers) the time the samples cover, but reduce short time accuracy as data is collected less often. Recommend values between 0.5-5 seconds. (Lower values=More accuracy)
Last edited Nov 07, 2011 by CommanderSirow
#4 Oct 31, 2011 at 13:19 UTC - 0 likes

There were a couple extra ")" in there...

the line that is: return "<Estimated to be OOM>") and return "<Estimated to be dead>")

just remove the ) off each one..

#5 Nov 06, 2011 at 18:48 UTC - 0 likes

@CommanderSirow: Go

I really like the look of this but Im struggling to find how to set it up. I tried to look at custom text but theres more boxes/choices and Im not sure which I should be selecting. Can you please tell me which options?

#6 Nov 07, 2011 at 10:17 UTC - 0 likes

Enter %c into the text-box, than a custom code box should appear. Copy/Paste code into it (Maybe change the 2 variables after "- - User variables" in the code), but that's really all that's to it.

Oh and ofc you should add a trigger (and maybe a load-conditions) to the display, eg. use a condition trigger, not mounted, something that activates the display whenever needed.

Last edited Nov 07, 2011 by CommanderSirow
#7 Nov 08, 2011 at 21:54 UTC - 0 likes

@CommanderSirow: Go

Thanks but Im still having trouble with this. I have created 2 Text Auras, one called Time to Die, and another called Time to OOM. I put %c in the display text box. And then pasted the relevant code into the Custom function box, leaving Update custom text on Every Frame selected. I set load in combat. I have not set triggers because I simply dont know which ones to select. I couldnt see anything I thought was related to it. I know its annoying to get newbie questions like this but would be grateful for some final pointers.

edit, I changed Time to Die trigger to health, target. and that gets the number but. Is there a way to get it converted into minutes/sounds? a number reading 500+ isnt really that useful unless you are good at maths on the fly. It also doesnt match my Time to Die addon text, not sure which is better, but both use huge numbers of seconds rather than minutes/seconds. Have done a similar thing for mana, using Power -> Type mana

both texts say No information a lot during combat

aanndddd the OP wanted to make auras that played off each other i.e. popped up if Mana would run out before boss death. Is this supposed to do that, if so, how? I havent find a way to link to auras together yet like Powauras does

Last edited Nov 08, 2011 by knowntobe
#8 Nov 09, 2011 at 10:46 UTC - 0 likes
Quote:

Is there a way to get it converted into minutes/sounds? a number reading 500+ isnt really that useful unless you are good at maths on the fly.

Totally understandable! :)

Replace:

    -- Seconds only
elseif WA_TTD_Estimate - now <= 60 then
return string.format("%0.2d", WA_TTD_Estimate - now)

-- More than seconds
else
return string.format("%d:%0.2d", (WA_TTD_Estimate - now) / 60, (WA_TTD_Estimate - now) % 60)
end


with:

    -- Convert time to readable format
else
local left    = WA_TTD_Estimate - now;

local seconds = left >= 0        and math.floor((left % 60)    / 1   ) or 0;
local minutes = left >= 60       and math.floor((left % 3600)  / 60  ) or 0;
local hours   = left >= 3600     and math.floor((left % 86400) / 3600) or 0;
local days    = left >= 86400    and math.floor((left % 31536000) / 86400) or 0;
local years   = left >= 31536000 and math.floor( left / 31536000) or 0;

if years > 0 then
return string.format("%d [Y] %d [D] %d:%d:%d [H]", years, days, hours, minutes, seconds);
elseif days > 0 then
return string.format("%d [D] %d:%d:%d [H]", days, hours, minutes, seconds);
elseif hours > 0 then
return string.format("%d:%d:%d [H]", hours, minutes, seconds);
elseif minutes > 0 then
return string.format("%d:%d [M]", minutes, seconds);
else
return string.format("%d [S]", seconds);
end
end

Quote:

It also doesnt match my Time to Die addon text, not sure which is better, but both use huge numbers of seconds rather than minutes/seconds. Have done a similar thing for mana, using Power -> Type mana

TTD and TTOOM basically use the same base code, that is, they

• Collect a predefined number of samples (Current time and current health/mana pair) [*1]
• Use this data to LINEARLY (by linear least squares) approximate the health/mana-over-time curve [*2]
• Find the (first) zero-point of the approximated curve, which should mark the point to OOM/Death [*3]
• Translate this zero-point back to a useable time format

[*1] Most (simple coded) TTOOM/TTD addons just use two values here, one "initial" health/mana value and one that updates over time. The disadvantage is, results can get quite inaccurate the longer the fight takes, this is mainly duo to [*2]. The most robust solution would be to collect an endless amount of samples and weight (give them importance) according of the time since their recording. For simplicity and memory usage, the above code uses a finite number of samples and does not use weights (this is a bit countered by "old" samples being thrown away).

[*2] The easiest assumption basically every TTD/TTOOM addon makes (my code included) about the health/mana-over-time graph, is that it is linear (in time), eg. that the amount of mana you burst out is constant. This should be true in the long run but is violated at times for example:

• A mage is using evocation: Mana goes up instead of down, linearity is violated
• Raid is using heroism: Boss health drops stronger over time, linearity is violated

Whenever this assumptions is violated, all TTD/TTOOM addons will have wrong/inaccurate values. The problem with the simple ones, is that they will be off-value/wrong the whole time (although the error might be small) while using weighted linear least squares will calculate the "best" (in a certain sense) solution given the data and assumptions (linearity) about the problem.

[*3] Again, this assumptions (zero-point == TTD/TTOOM) is only true, as long as the linearity assumption isn't violated and (, for my code code) there are enough samples to represent the curve correctly.

Empirically I only tested the OOM code, which was pretty accurate when bursting out mana and also with little pauses in between (after the data-approximation had recovered from the non-linearity), this SHOULD also hold true for the health code. ;)

Quote:

both texts say No information a lot during combat

Could you elaborate this? Does this happen at the start of combat or even some time during combat? There will generally be a data wipe from the TTD-code when you change targets to prevent transferring data from one target to another. (There is no multi-target support to prevent code-complexity explosion)

NOTE: I could prevent data from wiping, when changing target to a friendly unit, but adding (PROPER) multi-target support would be really a pita (pain in the ass :P).

Quote:

aanndddd the OP wanted to make auras that played off each other i.e. popped up if Mana would run out before boss death. Is this supposed to do that, if so, how? I havent find a way to link to auras together yet like Powauras does

Simplest solution, assuming both TTD and TTOOM displays are running (you can make them invisible, but they have to be active):

• Type: Custom, Status (Every frame)
• Custom show code:
function()
if WA_TTD_Estimate and WA_TTOOM_Estimate and WA_TTDOOM_Estimate < WA_TTD_Estimate then
return true;
else
return false;
end
end

• Custom hide code:
function()
if not WA_TTD_Estimate or not WA_TTOOM_Estimate or WA_TTDOOM_Estimate >= WA_TTD_Estimate then
return true;
else
return false;
end
end

Last edited Nov 11, 2011 by CommanderSirow
#9 Nov 09, 2011 at 11:51 UTC - 0 likes

If one wants to have a unified trigger:

• Type: Custom, Status (Every frame)
• Custom show code:
-- Custom text function
function()
-- Setup trigger (once)
if not WA_TTMAIN_Windows then
-- User variables
WA_TTMAIN_Windows = 50          -- Max number of samples
WA_TTMAIN_Steps = 1.0          -- Time between samples

-- Main-Code variables
WA_TTMAIN_Last = 0             -- Remember last update

-- TTOOM variables
WA_TTOOM_Samples = 0           -- Number of collected (active) samples
WA_TTOOM_Index = 0             -- Current ring buffer index
WA_TTOOM_Start = nil           -- First data collection time for relative shift
WA_TTOOM_MaxValue = 0          -- Remember max HP for relative shift
WA_TTOOM_Times = {}            -- Ring buffer data - data_x
WA_TTOOM_Values = {}           -- Ring buffer data - data_y
WA_TTOOM_Estimate = nil        -- Estimated end time (not relative)

-- TTD variables
WA_TTD_Samples = 0             -- Number of collected (active) samples
WA_TTD_Index = 0               -- Current ring buffer index
WA_TTD_Start = nil             -- First data collection time for relative shift
WA_TTD_MaxValue = 0            -- Remember max HP for relative shift
WA_TTD_Times = {}              -- Ring buffer data - data_x
WA_TTD_Values = {}             -- Ring buffer data - data_y
WA_TTD_Estimate = nil          -- Estimated end time (not relative)
WA_TTD_GUID = nil              -- Remember GUID of mob you are tracking

-- Common functions
WA_TTMAIN_NextIndex = function(index, samples)
-- Next index
local newIndex   = index + 1
local newSamples = samples

-- Update number of active samples
if newIndex > samples then
newSamples = newIndex
end

-- Using table as ring buffer
if newIndex >= WA_TTMAIN_Windows then
newIndex = 0
end

-- Return data
return newIndex, newSamples
end
WA_TTMAIN_CalcEstimate = function(times, values, samples, maxValue, startTime)
-- Min number of samples
if samples >= 2 then
-- Estimation variables
local SS_xy, SS_xx, x_M, y_M = 0, 0, 0, 0

-- Calc pre-solution values
for index = 0, samples-1 do
-- Calc mean value
x_M = x_M + times[index]  / samples
y_M = y_M + values[index] / samples

-- Calc sum of squares
SS_xx = SS_xx + times[index] * times[index]
SS_xy = SS_xy + times[index] * values[index]
end

-- Few last additions to mean value / sum of squares
SS_xx = SS_xx - samples * x_M * x_M
SS_xy = SS_xy - samples * x_M * y_M

-- Results
local a_0, a_1, x = 0, 0, 0

-- Calc a_0, a_1 of linear interpolation (data_y = a_1 * data_x + a_0)
a_1 = SS_xy / SS_xx
a_0 = y_M - a_1 * x_M

-- Find zero-point (Switch back to absolute values)
a_0 = a_0 + maxValue
x = - (a_0 / a_1)

-- Valid/Usable solution
if a_1 and a_1 < 1 and a_0 and a_0 > 0 and x and x > 0 then
return x + startTime
-- Fallback
else
return -1
end

-- Not enough data
else
return nil
end
end
WA_TTMAIN_GetString = function(estimate)
-- No estimate available
if not estimate then
return "<No Estimate>"

-- Convert time to readable format
elseif estimate < 0 then
return "<Not decreasing>"
else
-- Time left
local left    = estimate - GetTime();

-- Decode to format
local seconds = left >= 0        and math.floor((left % 60)    / 1   ) or 0;
local minutes = left >= 60       and math.floor((left % 3600)  / 60  ) or 0;
local hours   = left >= 3600     and math.floor((left % 86400) / 3600) or 0;
local days    = left >= 86400    and math.floor((left % 31536000) / 86400) or 0;
local years   = left >= 31536000 and math.floor( left / 31536000) or 0;

-- Format time
if     years   > 0 then
return string.format("%d [Y] %d [D] %d:%d:%d [H]", years, days, hours, minutes, seconds);
elseif days    > 0 then
return string.format("%d [D] %d:%d:%d [H]", days, hours, minutes, seconds);
elseif hours   > 0 then
return string.format("%d:%d:%d [H]", hours, minutes, seconds);
elseif minutes > 0 then
return string.format("%d:%d [M]", minutes, seconds);
else
return string.format("%d [S]", seconds);
end
end
end
end

-- Query current time (throttle updating over time)
local now = GetTime()
if now - WA_TTMAIN_Last >= WA_TTMAIN_Steps then
-- Remember current time
WA_TTMAIN_Last = now

-- Current data
local dataTTOOM = UnitPower("player", SPELL_POWER_MANA)
local dataTTD   = UnitHealth("target")

-- Reset data?
if dataTTOOM == UnitPowerMax("player", SPELL_POWER_MANA) then
WA_TTOOM_Start    = nil
WA_TTOOM_Estimate = nil
end
-- Reset data?
if dataTTD == UnitHealthMax("target") or not WA_TTD_GUID or WA_TTD_GUID ~= UnitGUID("target") then
WA_TTD_GUID       = nil
WA_TTD_Start      = nil
WA_TTD_Estimate   = nil
end

-- No start time?
if not WA_TTOOM_Start then
WA_TTOOM_Start    = now
WA_TTOOM_Index    = 0
WA_TTOOM_Samples  = 0
WA_TTOOM_MaxValue = UnitPowerMax("player", SPELL_POWER_MANA) / 2
end
-- No start time?
if not WA_TTD_Start or not WA_TTD_GUID then
WA_TTD_Start      = now
WA_TTD_Index      = 0
WA_TTD_Samples    = 0
WA_TTD_MaxValue   = UnitHealthMax("target") / 2
WA_TTD_GUID       = UnitGUID("target")
end

-- Save new data (Use relative values to prevent "overflow")
WA_TTOOM_Values[WA_TTOOM_Index] = dataTTOOM - WA_TTOOM_MaxValue
WA_TTOOM_Times[WA_TTOOM_Index]  = now       - WA_TTOOM_Start
-- Save new data (Use relative values to prevent "overflow")
WA_TTD_Values[WA_TTD_Index]     = dataTTD   - WA_TTD_MaxValue
WA_TTD_Times[WA_TTD_Index]      = now       - WA_TTD_Start

-- Next index
WA_TTOOM_Index, WA_TTOOM_Samples = WA_TTMAIN_NextIndex(WA_TTOOM_Index, WA_TTOOM_Samples)
WA_TTD_Index,   WA_TTD_Samples   = WA_TTMAIN_NextIndex(WA_TTD_Index,   WA_TTD_Samples)

-- Calc estimate
WA_TTOOM_Estimate = WA_TTMAIN_CalcEstimate(WA_TTOOM_Times, WA_TTOOM_Values, WA_TTOOM_Samples, WA_TTOOM_MaxValue, WA_TTOOM_Start)
WA_TTD_Estimate   = WA_TTMAIN_CalcEstimate(WA_TTD_Times,   WA_TTD_Values,   WA_TTD_Samples,   WA_TTD_MaxValue,   WA_TTD_Start)
end

-- Always show
-- return true;

-- OOM before kill
if WA_TTOOM_Estimate and WA_TTD_Estimate and (WA_TTD_Estimate > WA_TTOOM_Estimate or WA_TTD_Estimate < 0) then
return true
else
return false
end
end

• Custom hide code:
function()
-- Never hide
-- return false

-- If if no data or kill before oom
if not (WA_TTOOM_Estimate and WA_TTD_Estimate and (WA_TTD_Estimate > WA_TTOOM_Estimate or WA_TTD_Estimate < 0)) then
return true;
else
return false;
end
end

• (Optional) Custom Text code:
function()
if WA_TTMAIN_GetString then
-- Display both as aboslute values
--return string.format("OOM: %s | Death: %s", WA_TTMAIN_GetString(WA_TTOOM_Estimate), WA_TTMAIN_GetString(WA_TTD_Estimate));

-- Display TTD relative to TTOM
return string.format("OOM: %s (%s)", WA_TTMAIN_GetString(WA_TTOOM_Estimate), WA_TTMAIN_GetString(WA_TTD_Estimate and WA_TTOOM_Estimate and (WA_TTD_Estimate - WA_TTOOM_Estimate)));
end
end


(Negative relative death time means not oom before death, positive time means oom before death)

Last edited Nov 13, 2011 by CommanderSirow
#10 Nov 10, 2011 at 10:33 UTC - 0 likes

@CommanderSirow: Go

Great couple of posts! I will be trying this out tonight With regards to the No Information message, this was during a 5 minute DPS test on a single Heroic training dummy. It happens fairly often, normally in the middle of a cast. I will try to narrow it down a bit more when I test the above code.

#11 Nov 11, 2011 at 08:47 UTC - 0 likes

@CommanderSirow: Go I tried this but got the following error

42x <string>:"return -- Custom text function...":130: bad argument #2 to 'format' (number expected, got no value)
<string>:"return -- Custom text function...":130: in function <[string "return -- Custom text function..."]:2>
WeakAuras-1.4.4b\RegionTypes\text.lua:89: in function UpdateCustomText'
nil
Locals:
now = 58668.156
left = 25124.244013111
seconds = 44
minutes = 58
hours = 6
days = 0
years = 0


as for the rest, its making feel rather stupid, because I just dont know where Im supposed to put any of it. Remember Im a newbie to Weak Auras, and Im struggling to find where any of this actually goes.

Last edited Nov 11, 2011 by knowntobe
#12 Nov 11, 2011 at 09:30 UTC - 0 likes
Quote:

I tried this but got the following error

Whoops, the missing argument for string.format where fixed. :D (Hope I did not add any more error :>). Updated the above code(s). ;)

Quote:

as for the rest, its making feel rather stupid, because I just dont know where Im supposed to put any of it. Remember Im a newbie to Weak Auras, and Im struggling to find where any of this actually goes.

I guess you mainly like to know, where you should add the (Optional) Custom Text code and the Custom hide code ?

To get the dialog box for custom hide, in the trigger tab section, switch "Hide" from Timed to custom.

To get the custom text code dialog box, enter "%c" ([C]ustom code) into the text box (on the display tab). ;)

PS: (Important) One more thing, after you update the code enter

/script WA_TTMAIN_Windows=nil
`

into chat! (In order to reset internal code functions)

Last edited Nov 11, 2011 by CommanderSirow
#13 Nov 11, 2011 at 09:43 UTC - 0 likes
Quote from knowntobe: Go

With regards to the No Information message, this was during a 5 minute DPS test on a single Heroic training dummy. It happens fairly often, normally in the middle of a cast. I will try to narrow it down a bit more when I test the above code.

Sorry to ask this again, (regarding the old setup with 2 triggers)(wth the new 1-display setup this is a bit more difficult to debug :P) does this happen with the TTOOM or the TTD display?

Last edited Nov 11, 2011 by CommanderSirow
#14 Nov 13, 2011 at 18:22 UTC - 0 likes

@CommanderSirow: Go Im going to give up with this because I cant follow your steps as I dont have what you say I should have. If I try to muddle through it, it breaks. You either have a special version I dont (mines latest from curse) or are assuming I will "get" the stuff you didnt mention. Rather than keep on sounding like a moron, its best for both if us to just admit that all aparts of this addon arent for everyone.
Overall it is more complicated and less "obvious" than powa auras i.e having to make 2 auras that powa auras can do with 1 is a little "annoying" due to extra time needed. And obviously this side of things (Custom code) is hard work also.
I do like Weak auras for the stuff powa auras doesnt have, and will keep using it, but will give up on custom code.
Will delete the time to oom, and Time to Die, and just use other addons for that.

With regards to the no information, theres no set pattern to it. It can say "no information" in the middle of a cast, or when Im running a few yards, or in between casts. Its not constant and I cant reproduce it in any set way. I just cast spells.
Happens with both TTD and TTOOM

#15 Nov 13, 2011 at 22:55 UTC - 0 likes

I updated the above code to eliminate all syntax error. It should work proper now.

As for the 2-display stuff. I was only suggesting, if you were interested in debugging (any remaining "no info") issue, it would be easier for me to do this with using the 2 display version and than expand the fix onto the 1-display version (its really the same code as the one display code, but separated for target health and player mana), that was all. ;)

Quote:

With regards to the no information, theres no set pattern to it. It can say "no information" in the middle of a cast, or when Im running a few yards, or in between casts. Its not constant and I cant reproduce it in any set way. I just cast spells. Happens with both TTD and TTOOM

Ah ok, what happens is (at least for mana calculation) is probably, that you gained more mana than you are loosing (at least in regards to to the "sample-window), thus it displays "no info", as you will/would not go oom if you continued this way.

I updated the above code to increase the sample amount, less likely to have short term movement impact oom/death time, and it will display "Value increasing instead of no-info if gaining more mana/hp than loosing.

PS: Sad to hear if you really plan to abandon WeakAuras due to this *sadface*

WA really was designed to be both easy to use, but also flexible while still maintaining computational efficiency (the last part isn't completely true for PowerAuras in some parts, at least the last time I looked through the code). The flexibility part can sometimes lead to some/great complexity, as one can utilize the full power of lua + wow-api.

This code will probably though never make its way into WeakAuras as a predefined trigger because of its OnUpdate nature. Basically it means, the trigger needs to be evaluated at every frame (eg. 60 times per second for an average computer), which is something that is tried to be avoided in WA (for performance/efficiency reasons)

The best/most user friendly solution (while still being somewhat conform to WA design philosophies) is to include a list of cool custom triggers (Like this one and others) in the WeakAurasTutorials addon as some predefined examples.

Pro: Don't drop design philosophies, Make some of the more advanced and cpu-intensive triggers available to non-lua coder users.

Con: Not directly obvious for new users to explicitly find them (There should definitely a note on the main-page to redirect new users)

Last edited Nov 13, 2011 by CommanderSirow
• 15 posts