diff --git a/MaxDps.toc b/MaxDps.toc
index 71a3416..f7d1991 100644
--- a/MaxDps.toc
+++ b/MaxDps.toc
@@ -1,6 +1,6 @@
## Title: MaxDps
## Notes: Rotation helper framework.
-## Version: 7.1.3
+## Version: 7.1.4
## Author: Kaminaris
## Interface: 70100
## SavedVariables: MaxDpsOptions
@@ -20,4 +20,5 @@ Libs\AceConfig-3.0\AceConfig-3.0.xml
core.lua
buttons.lua
-helper.lua
\ No newline at end of file
+helper.lua
+timetodie.lua
\ No newline at end of file
diff --git a/helper.lua b/helper.lua
index 5e4522b..a90ad8d 100644
--- a/helper.lua
+++ b/helper.lua
@@ -114,6 +114,12 @@ function MaxDps:EndCast(target)
return timeShift, spell, gcd;
end
+function MaxDps:SameSpell(spell1, spell2)
+ local spellName1 = GetSpellInfo(spell1);
+ local spellName2 = GetSpellInfo(spell2);
+ return spellName1 == spellName2;
+end
+
function MaxDps:TargetPercentHealth()
local health = UnitHealth('target');
if health <= 0 then
@@ -193,38 +199,6 @@ function MaxDps:Cooldown(spell, timeShift)
end;
end
-function MaxDps:TimeToDie(health)
- local unit = UnitGUID('target');
- if unit ~= TDDps_TargetGuid then
- return INF;
- end
-
- health = health or UnitHealth('target');
-
- if health == UnitHealthMax('target') then
- TD_Hp0, TD_T0, TD_Hpm, TD_Tm = nil, nil, nil, nil;
- return INF;
- end
-
- local time = GetTime();
-
- if not TD_Hp0 then
- TD_Hp0, TD_T0 = health, time;
- TD_Hpm, TD_Tm = health, time;
- --print('phial3');
- return INF;
- end
-
- TD_Hpm = (TD_Hpm + health) * .5;
- TD_Tm = (TD_Tm + time) * .5;
-
- if TD_Hpm >= TD_Hp0 then
- TD_Hp0, TD_T0, TD_Hpm, TD_Tm = nil, nil, nil, nil;
- else
- return health * (TD_T0 - TD_Tm) / (TD_Hpm - TD_Hp0);
- end
-end
-
function MaxDps:Mana(minus, timeShift)
local _, casting = GetManaRegen();
local mana = UnitPower('player', 0) - minus + (casting * timeShift);
@@ -239,3 +213,23 @@ function MaxDps:Bloodlust(timeShift)
return false;
end
+
+function MaxDps:FormatTime(left)
+ 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
diff --git a/timetodie.lua b/timetodie.lua
new file mode 100644
index 0000000..dd4880c
--- /dev/null
+++ b/timetodie.lua
@@ -0,0 +1,124 @@
+local INF = 2147483647;
+
+function MaxDps:InitTTD(maxSamples, interval)
+ self.ttd = {};
+ self.ttd.Windows = maxSamples or 8; -- Max number of samples
+
+ -- Code variables
+ self.ttd.GUID = nil; -- Remember GUID of mob you are tracking
+ self.ttd.MaxValue = 0; -- Remember max HP for relative shift
+ self.ttd.Last = GetTime(); -- Remember last update
+ self.ttd.Start = nil; -- First data collection time for relative shift
+ self.ttd.Index = 0; -- Current ring buffer index
+ self.ttd.Times = {}; -- Ring buffer data - data_x
+ self.ttd.Values = {}; -- Ring buffer data - data_y
+ self.ttd.Samples = 0; -- Number of collected (active) samples
+ self.ttd.Estimate = nil; -- Estimated end time (not relative)
+ self.ttd.TimeToDie = INF; -- Estimated end time relative
+
+ self.ttd.Timer = self:ScheduleRepeatingTimer('TimeToDie', interval or 1.5);
+end
+
+function MaxDps:DisableTTD()
+ if self.ttd.Timer then
+ self:CancelTimer(self.ttd.Timer);
+ end
+end
+
+function MaxDps:TimeToDie(target)
+ target = target or 'target';
+
+ -- Query current time (throttle updating over time)
+ local now = GetTime();
+
+ -- Current data
+ local data = UnitHealth(target);
+
+ -- Reset data?
+ if data == UnitHealthMax(target) or not self.ttd.GUID or self.ttd.GUID ~= UnitGUID(target) then
+ self.ttd.GUID = nil
+ self.ttd.Start = nil
+ self.ttd.Estimate = nil
+ end
+
+ -- No start time?
+ if not self.ttd.Start or not self.ttd.GUID then
+ self.ttd.Start = now;
+ self.ttd.Index = 0;
+ self.ttd.Samples = 0;
+ self.ttd.MaxValue = UnitHealthMax(target) / 2;
+ self.ttd.GUID = UnitGUID(target);
+ end
+
+ -- Remember current time
+ self.ttd.Last = now;
+
+ -- Save new data (Use relative values to prevent 'overflow')
+ self.ttd.Values[self.ttd.Index] = data - self.ttd.MaxValue;
+ self.ttd.Times[self.ttd.Index] = now - self.ttd.Start;
+
+ -- Next index
+ self.ttd.Index = self.ttd.Index + 1;
+
+ -- Update number of active samples
+ if self.ttd.Index > self.ttd.Samples then
+ self.ttd.Samples = self.ttd.Index;
+ end
+
+ -- Using table as ring buffer
+ if self.ttd.Index >= self.ttd.Windows then
+ self.ttd.Index = 0;
+ end
+
+ -- Min number of samples
+ if self.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, self.ttd.Samples - 1 do
+ -- Calc mean value
+ x_M = x_M + self.ttd.Times[index] / self.ttd.Samples;
+ y_M = y_M + self.ttd.Values[index] / self.ttd.Samples;
+
+ -- Calc sum of squares
+ SS_xx = SS_xx + self.ttd.Times[index] * self.ttd.Times[index];
+ SS_xy = SS_xy + self.ttd.Times[index] * self.ttd.Values[index];
+ end
+
+ -- Few last additions to mean value / sum of squares
+ SS_xx = SS_xx - self.ttd.Samples * x_M * x_M;
+ SS_xy = SS_xy - self.ttd.Samples * x_M * y_M;
+
+ -- Calc a_0, a_1 of linear interpolation (data_y = a_1 * data_x + a_0)
+ local a_1 = SS_xy / SS_xx;
+ local a_0 = (y_M - a_1 * x_M) + self.ttd.MaxValue;
+
+ -- Find zero-point (Switch back to absolute values)
+ local 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
+ self.ttd.Estimate = x + self.ttd.Start;
+ -- Fallback
+ else
+ self.ttd.Estimate = nil;
+ end
+
+ -- Not enough data
+ else
+ self.ttd.Estimate = nil;
+ end
+
+ -- No/False information
+ if not self.ttd.Estimate then
+ self.ttd.TimeToDie = INF;
+ -- Already over
+ elseif now > self.ttd.Estimate then
+ self.ttd.TimeToDie = 0;
+ else
+ self.ttd.TimeToDie = self.ttd.Estimate - now;
+ end
+
+ return self.ttd.TimeToDie;
+end
\ No newline at end of file