Thread Tools Display Modes
03-04-24, 10:24 PM   #1
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
Timer with 2 variables

Lua Code:
  1. local addonName, addon = ...
  2. local Backdrop = {
  3.     bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
  4. }
  5.  
  6. local frame_x = 100    
  7. local frame_y = -250    
  8. local f = CreateFrame("Button", "ZAMTimer777", UIParent, "BackdropTemplate")
  9. f:SetWidth(255)                                          
  10. f:SetHeight(30)
  11. f:SetBackdrop(Backdrop)
  12. f.text = f:CreateFontString(nil,"OVERLAY","GameTooltipText")
  13. f.text:SetTextHeight(15)
  14. f.text:SetPoint("CENTER")
  15. f:SetClampedToScreen(true)
  16. f:SetPoint("CENTER",UIParent,"CENTER",frame_x,frame_y)
  17. f:EnableMouse(true)
  18. f:SetMovable(true)
  19. f:RegisterForDrag("LeftButton")
  20. f:RegisterForClicks("AnyUp")
  21. f:Show()
  22. f:RegisterEvent("PLAYER_ENTERING_WORLD")
  23. f:SetScript("OnDragStart",function(this)
  24.     this:StartMoving()
  25. end)
  26. f:SetScript("OnDragStop",function(this)  
  27.     this:StopMovingOrSizing()
  28.     frame_x,frame_y = this:GetRIGHT()
  29.     frame_x = frame_x - GetScreenWidth() / 2
  30.     frame_y = frame_y - GetScreenHeight() / 2
  31.     this:ClearAllPoints()
  32.     this:SetPoint("CENTER",UIParent,"CENTER",frame_x,frame_y)
  33. end)
  34. -- first %s is replaced by the color. The second is replaced by the time. |r resets the color back to default
  35. local Localizations = {
  36.     enUS = {
  37.         Waiting = "|c1C7BCEFFEvent:\nbefore the start: %s%s|r",
  38.         Running = "|cFF35BE21Event:\n%s%s until completion|r",
  39.     },
  40. }
  41.  
  42. local locale = GetLocale()
  43. local L = Localizations[locale] or Localizations.enUS -- Default to enUS if locale doesn't exist in the table
  44.  
  45. ------------------------------------------------------------------------------------------------------
  46. -- These might be converted to Saved Variables so each character can determine
  47. -- wether or not to play a sound, the alert times and colors and sound to play.
  48. -- If so then most of the code below will have to move into an event handler for
  49. -- the PLAYER_LOGIN or PLAYER_ENTERING_WORLD event.
  50. local useColor = true
  51. local useSound = true
  52. local alert1 = 600 -- Alarm 1 set to 10 minutes before event
  53. local alert1Color = "|cffffff00" -- Yellow
  54. local alert2 = 300 -- Alarm 2 set to 5 minutes before event
  55. local alert2Color = "|cffff0000" -- Red
  56. local soundKit = 32585 -- Alarm sound
  57. ------------------------------------------------------------------------------------------------------
  58.  
  59. local function printTime(timetotrun, inevent)
  60.     local hideSeconds = timetotrun >= 120
  61.     local msg = L.Waiting
  62.     local msgColor = "|cffffffff"
  63.     if inevent then
  64.         msg = L.Running
  65.     else
  66.         if useColor and timetotrun <= alert2 then
  67.             msgColor = alert2Color
  68.         elseif timetotrun <= alert1 then
  69.             if useSound and not ZAMTimer777.Alerted then
  70.                 ZAMTimer777.Alerted = true
  71.                 PlaySound(soundKit, "Master")
  72.             end
  73.             if useColor then
  74.                 msgColor = alert1Color
  75.             end
  76.         end
  77.     end
  78.     f.text:SetText(format(msg, msgColor, SecondsToTime(timetotrun, hideSeconds)))
  79. end
  80.  
  81. regionEventStartTime = {
  82.     [1] = { -- eu
  83.         starttime = 1709615040,
  84.         eventDuration = 240,
  85.         eventIntervalInSeconds = 3600,
  86.         enable = true,
  87.         datablock = {}
  88.     },
  89. }
  90.  
  91. local inEvent, timeToRun
  92. local eventTime = regionEventStartTime[1].eventDuration -- Time the event runs in seconds(15 mins)
  93. local waitTime = regionEventStartTime[1].eventIntervalInSeconds -- Time between events in seconds (90 mins)
  94. local startTime = regionEventStartTime[1].starttime -- Start time from the table
  95. local serverTime = GetServerTime()
  96. local timeToEvent = (startTime - serverTime) % waitTime -- Remaining time before next event starts
  97.  
  98. if timeToEvent > (waitTime - eventTime) then -- Is there between 1:15 and 1:30 to go? If so, we're in the event
  99.     inEvent = true
  100.     timeToRun = eventTime - (waitTime - timeToEvent)
  101. else                    -- Otherwise, set the ticker timer to time to next event
  102.     inEvent = false
  103.     timeToRun = timeToEvent
  104. end
  105. local ticker = C_Timer.NewTicker(1, function()
  106.     if timeToRun > 0 then
  107.         timeToRun = timeToRun - 1
  108.         printTime(timeToRun, inEvent)
  109.         return
  110.     end
  111.     ZAMTimer777.Alerted = false
  112.     if inEvent then -- The event just finished
  113.         inEvent = false
  114.         timeToRun = waitTime - eventTime -- Reset ticker timer to 90 minutes wait time minus 15 mins event time
  115.     else  -- Waiting for the next event just expired
  116.         inEvent = true
  117.         timeToRun = eventTime -- And the event is running
  118.     end
  119.     printTime(timeToRun, inEvent)
  120. end)
  121. printTime(timeToRun, inEvent)

1) Data. There is an event A and an event B.
2) Event A data is entered into the code (Start at 1709615040, interval 3600 and event time 240)
3) Event B (Start at 1709629200, interval 21600 (6 hours) and event time 7200 (2 hours))

Task:
1) The timer should fire every hour (this is in the code and it works).
2) The timer should increase the interval between events when event B occurs, for the duration of event B (by 2 hours).

For example:
08:04 - event A has started - the timer shows 1 hour until the next event.
09:04 - event A has started - the timer shows 1 hour until the next event.
10:04 - event A has started - the timer shows 3 hours until the next event. Since at 11:00 there will be event B.
11:04 - event A has not started - the timer shows 2 hours until the next event. Since at 11:00 there was event B.
12:04 - event A has not started - the timer shows 1 hour until the next event. Since at 11:00 there was event B.
13:04 - event A has started - the timer shows 1 hour until the next event.

Last edited by Hubb777 : 03-04-24 at 10:36 PM.
  Reply With Quote
03-05-24, 11:50 PM   #2
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
The following option is possible:
So that event A counts every hour.
When event B occurred, event A was extended for the duration of event B.
  Reply With Quote
03-06-24, 11:55 AM   #3
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
Sounds like you would want to replace the ticker with an OnUdate script with a countdown that does essentially the same thing but with an added second countdown adjusting the resets etc. of the first when it runs into/outof range. And the added initial check when the code starts to see which settings to use on login.

A second table for adjustment times might be something like (not really required if the adjustment start times etc. are the same (offset (+/- xxx seconds from event start), interval/duration) in every region).
Lua Code:
  1. regionEventAdjustTime = { -- when the "adjustment" event occures
  2.     [1] = {
  3.         starttime = 1709615040, -- when the "adjustment" time starts
  4.         eventDuration = 21600, -- How long "adjustment" lasts [6 hours]
  5.         addIntervalInSeconds = 3600, -- Add seconds to event interval when in range, subtract when not
  6.         addSomethingElse = 2700, -- Add something else when in adjust period like the event duration?
  7.     },
  8. }
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.
  Reply With Quote
03-07-24, 12:17 AM   #4
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
Originally Posted by Fizzlemizz View Post
Sounds like you would want to replace the ticker with an OnUdate script with a countdown that does essentially the same thing but with an added second countdown adjusting the resets etc. of the first when it runs into/outof range. And the added initial check when the code starts to see which settings to use on login.

A second table for adjustment times might be something like (not really required if the adjustment start times etc. are the same (offset (+/- xxx seconds from event start), interval/duration) in every region).
Lua Code:
  1. regionEventAdjustTime = { -- when the "adjustment" event occures
  2.     [1] = {
  3.         starttime = 1709615040, -- when the "adjustment" time starts
  4.         eventDuration = 21600, -- How long "adjustment" lasts [6 hours]
  5.         addIntervalInSeconds = 3600, -- Add seconds to event interval when in range, subtract when not
  6.         addSomethingElse = 2700, -- Add something else when in adjust period like the event duration?
  7.     },
  8. }
As I understand it, in order for this to work, I also need to make changes to this code?
Lua Code:
  1. local inEvent, timeToRun
  2. local eventTime = regionEventStartTime[1].eventDuration -- Time the event runs in seconds(15 mins)
  3. local waitTime = regionEventStartTime[1].eventIntervalInSeconds -- Time between events in seconds (90 mins)
  4. local startTime = regionEventStartTime[1].starttime -- Start time from the table
  5. local serverTime = GetServerTime()
  6. local timeToEvent = (startTime - serverTime) % waitTime -- Remaining time before next event starts
  7.  
  8. if timeToEvent > (waitTime - eventTime) then -- Is there between 1:15 and 1:30 to go? If so, we're in the event
  9.     inEvent = true
  10.     timeToRun = eventTime - (waitTime - timeToEvent)
  11. else                    -- Otherwise, set the ticker timer to time to next event
  12.     inEvent = false
  13.     timeToRun = timeToEvent
  14. end

Did I do the right thing?
Lua Code:
  1. local inEvent, timeToRun
  2. local eventTime = regionEventStartTime[1].eventDuration -- Time the event runs in seconds(15 mins)
  3. local waitTime = regionEventStartTime[1].eventIntervalInSeconds -- Time between events in seconds (60 mins)
  4. local startTime = regionEventStartTime[1].starttime -- Start time from the table
  5.  
  6. local eventTime = regionEventAdjustTime[1].eventDuration -- Time the event runs in seconds(6 hours)
  7. local waitTime = regionEventAdjustTime[1].addIntervalInSeconds -- Time between events in seconds (90 mins)
  8. local startTime = regionEventAdjustTime[1].starttime -- Start time from the table
  9.  
  10. local serverTime = GetServerTime()
  11. local timeToEvent = (startTime - serverTime) % waitTime -- Remaining time before next event starts
  12.  
  13. if timeToEvent > (waitTime - eventTime) then -- Is there between 1:15 and 1:30 to go? If so, we're in the event
  14.     inEvent = true
  15.     timeToRun = eventTime - (waitTime - timeToEvent)
  16. else                    -- Otherwise, set the ticker timer to time to next event
  17.     inEvent = false
  18.     timeToRun = timeToEvent
  19. end

Last edited by Hubb777 : 03-07-24 at 12:29 AM.
  Reply With Quote
03-08-24, 10:32 PM   #5
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
The first time I missed a line.

Lua Code:
  1. local startTime = regionEventAdjustTime[1].addSomethingElse


Lua Code:
  1. local inEvent, timeToRun
  2. local eventTime = regionEventStartTime[1].eventDuration -- Time the event runs in seconds(15 mins)
  3. local waitTime = regionEventStartTime[1].eventIntervalInSeconds -- Time between events in seconds (60 mins)
  4. local startTime = regionEventStartTime[1].starttime -- Start time from the table
  5.  
  6. local eventTime = regionEventAdjustTime[1].eventDuration -- Time the event runs in seconds(6 hours)
  7. local waitTime = regionEventAdjustTime[1].addIntervalInSeconds -- Time between events in seconds (90 mins)
  8. local startTime = regionEventAdjustTime[1].starttime -- Start time from the table
  9. local startTime = regionEventAdjustTime[1].addSomethingElse
  10.  
  11. local serverTime = GetServerTime()
  12. local timeToEvent = (startTime - serverTime) % waitTime -- Remaining time before next event starts
  13.  
  14. if timeToEvent > (waitTime - eventTime) then -- Is there between 1:15 and 1:30 to go? If so, we're in the event
  15.     inEvent = true
  16.     timeToRun = eventTime - (waitTime - timeToEvent)
  17. else                    -- Otherwise, set the ticker timer to time to next event
  18.     inEvent = false
  19.     timeToRun = timeToEvent
  20. end
But it still didn't work, I'm missing something.
  Reply With Quote
03-10-24, 08:46 AM   #6
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
There's some information missing from your OP
2) Event A data is entered into the code (Start at 1709615040, interval 3600 and event time 240)
3) Event B (Start at 1709629200, interval 21600 (6 hours) and event time 7200 (2 hours))
A guess at what you want:

Event B Starts at 1709629200, lasts for 6 hours. During that 6 hours, the time between the events is 2 hours (instead of 1).

and what's missing:

Does event B occur once a day? If not what is the interval between repeats? 6 hours Event B followed by 6 hours Event A then repeat? Or something different (6 Hours B, 3 hours A, 6 Hours B...).

Is the actual event time (the one this process is tracking) still the same duration during Event A and B (240 or whatever) and just the interval between is varied (1/2 hours)?

The 3.93333333 hours between your start times would cause some strange timings to the actual event going into/out of these A/B sessions (like suddenly adding 2 hours to the start time just minutes before the countdown display said it was supposed to start etc.).

Maybe figuring out ALL the actual mechanics (6 hours session B, 4.9333333 hours session A maybe?) before starting would help decide if the addon itself is "sensible" (no offence intended).
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 03-10-24 at 08:52 AM.
  Reply With Quote
03-10-24, 09:43 PM   #7
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
Originally Posted by Fizzlemizz View Post
There's some information missing from your OP


A guess at what you want:

Event B Starts at 1709629200, lasts for 6 hours. During that 6 hours, the time between the events is 2 hours (instead of 1).

and what's missing:

Does event B occur once a day? If not what is the interval between repeats? 6 hours Event B followed by 6 hours Event A then repeat? Or something different (6 Hours B, 3 hours A, 6 Hours B...).

Is the actual event time (the one this process is tracking) still the same duration during Event A and B (240 or whatever) and just the interval between is varied (1/2 hours)?

The 3.93333333 hours between your start times would cause some strange timings to the actual event going into/out of these A/B sessions (like suddenly adding 2 hours to the start time just minutes before the countdown display said it was supposed to start etc.).

Maybe figuring out ALL the actual mechanics (6 hours session B, 4.9333333 hours session A maybe?) before starting would help decide if the addon itself is "sensible" (no offence intended).

I'll try to explain:
There are 2 events (event A and event B)
2) Event А (Start at 1709615040, interval 3600 (1 hours) and event time 240 (4 minutes))
3) Event B (Start at 1709629200, interval 21600 (6 hours) and event time 7200 (2 hours))

If event B occurs, event A does not start.
Event B occurs every 6 hours and lasts 2 hours.
Event B occurs every 6 hours (there can be several B events per day).

It is necessary that the event timer A correctly counts down the time until the next event. Taking into account that while event B is happening, event A cannot happen.

Last edited by Hubb777 : 03-10-24 at 09:47 PM.
  Reply With Quote
03-11-24, 12:53 PM   #8
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
1 possible method based on information given and no idea how the interaction between the start times might play into calculating session A/B start times day-to-day etc. etc.

The test times, if you want to un-comment them, should give a rough idea of what's going on as the test cycles over 12 minutes instead of 12 hours.

The * should designate it's running special (session B ) times.

Lua Code:
  1. local addonName, addon = ...
  2. local L, MyRegion
  3. local TotalTime = 43200 -- Overall time 12 hours (6 special, 6 Standard just guessing! 6 Special + ??? standard)
  4. local EventDuration = 240 -- Actual tracked event run time 4 minutes???
  5. local RegionTimes = {
  6.     [1] = {
  7.         standard = { -- session A 6 hours
  8.             starttime = 1709615040,
  9.             eventinterval = 3600, -- runs every 1 hour
  10.             enable = true,
  11.             datablock = {}
  12.         },
  13.         special = { -- session B 6 hours
  14.             starttime = 1709629200,
  15.             eventinterval = 7200, -- but runs every 2 hours
  16.             sessionduration = 21600, -- calculates 6 hours window where eventinterval is increased to 2 hours)
  17.         },
  18.     },
  19. }
  20.  
  21. --[[ TEST TIMES ONLY: over 12 minutes instead of 12 hours ]]--
  22. -- NOT EXACLTLY ACCURATE!!!!!
  23. --[[
  24. TotalTime = 720 -- 12 mins (6 special, 6 standard)
  25. EventDuration = 20 -- event lasts 20 seconds instead of 4 minutes
  26.  
  27. RegionTimes[1].standard.eventinterval = 60 -- i minute instead of 1 hoiur
  28.  
  29. -- Special timming starts 4 intervals - 1 event time after standard start time (probably not completely accurate but just testing)
  30. RegionTimes[1].special.starttime = RegionTimes[1].standard.starttime + ((RegionTimes[1].standard.eventinterval * 4) - EventDuration) -- + 4 mins - 1 event
  31. RegionTimes[1].special.eventinterval = 120 -- Every 2 mins
  32. RegionTimes[1].special.sessionduration = 360 -- Special time lasts 6 minutes (50% of TotalTime ?)
  33. ]]--
  34. --[[ END TEST TIMES ]]--
  35.  
  36. local Localizations = {
  37.     enUS = {
  38.         Waiting = "|c1C7BCEFFEvent:%s\nbefore the start: %s%s|r",
  39.         Running = "|cFF35BE21Event:%s\n%s%s until completion|r",
  40.     },
  41. }
  42.  
  43. ------------------------------------------------------------------------------------------------------
  44. -- These might be converted to Saved Variables so each character can determine
  45. -- wether or not to play a sound, the alert times and colors and sound to play.
  46. -- If so then most of the code below will have to move into an event handler for
  47. -- the PLAYER_LOGIN or PLAYER_ENTERING_WORLD event.
  48. local defaults = {
  49.     useColor = true,
  50.     useSound = true,
  51.     alert1 = 600, -- Alarm 1 set to 10 minutes before event
  52.     alert1Color = "|cffffff00", -- Yellow
  53.     alert2 = 300, -- Alarm 2 set to 5 minutes before event
  54.     alert2Color = "|cffff0000", -- Red
  55.     soundKit = 32585, -- Alarm sound
  56. }
  57.  
  58. ------------------------------------------------------------------------------------------------------
  59. local function CalcTime(starttime, servertime, duration, interval)
  60.     local timeToEvent = (starttime - servertime) % interval
  61.     local inEvent, timeToRun
  62.     if timeToEvent > (interval - duration) then -- Is there between 1:15 and 1:30 to go? If so, we're in the event
  63.         inEvent = true
  64.         timeToRun = duration - (interval - timeToEvent)
  65.     else                    -- Otherwise, set the timer to time to next event
  66.         inEvent = false
  67.         timeToRun = timeToEvent
  68.     end
  69.     return inEvent, timeToRun
  70. end
  71.  
  72. local function printTime(self)
  73.     local serverTime = GetServerTime()
  74.     -- Check to see if we're in the special event time
  75.     local isSpecial = ""
  76.     local inEvent = CalcTime(MyRegion.special.starttime, serverTime, MyRegion.special.sessionduration, TotalTime) -- Are we in the 6 hour window?
  77.     if inEvent then -- if so then calulate 2 hour intervals
  78.         isSpecial = "|cffffff00*|r"
  79.         inEvent, timeToRun = CalcTime(MyRegion.special.starttime, serverTime, EventDuration, MyRegion.special.eventinterval)
  80.     else --  calulate 1 hour intervals (return to normal programming)
  81.         inEvent, timeToRun = CalcTime(MyRegion.standard.starttime, serverTime, EventDuration, MyRegion.standard.eventinterval)
  82.     end
  83.     local hideSeconds = timeToRun >= 120
  84.     local msg = L.Waiting
  85.     local msgColor = "|cffffffff"
  86.     if inEvent then
  87.         msg = L.Running
  88.     else
  89.         if defaults.useColor and timeToRun <= defaults.alert2 then
  90.             msgColor = defaults.alert2Color
  91.         elseif timeToRun <= defaults.alert1 then
  92.             if defaults.useSound and not self.Alerted then
  93.                 self.Alerted = true
  94.                 PlaySound(defaults.soundKit, "Master")
  95.             end
  96.             if defaults.useColor then
  97.                 msgColor = defaults.alert1Color
  98.             end
  99.         end
  100.     end
  101.     self.Text:SetText(format(msg, isSpecial, msgColor, SecondsToTime(timeToRun, hideSeconds)))
  102. end
  103.  
  104. ------------------------------------------------------------------------------------------------------
  105. local Backdrop = {
  106.     bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
  107. }
  108.  
  109. local frame_x = 100    
  110. local frame_y = -250    
  111. local f = CreateFrame("Button", "ZAMTimer777", UIParent, "BackdropTemplate")
  112. f:SetWidth(255)                                          
  113. f:SetHeight(30)
  114. f:SetPoint("CENTER")
  115. f:SetBackdrop(Backdrop)
  116. f:SetClampedToScreen(true)
  117. f:EnableMouse(true)
  118. f:SetMovable(true)
  119. f:SetUserPlaced(true)
  120. f:RegisterForDrag("LeftButton")
  121. f:RegisterForClicks("AnyUp")
  122. f.Text = f:CreateFontString(nil, "OVERLAY", "GameTooltipText")
  123. f.Text:SetPoint("CENTER")
  124. f.Elapsed = 0 -- Set starting timeout (0 second)
  125. f:SetScript("OnDragStart",function(self)
  126.     self:StartMoving()
  127. end)
  128. f:SetScript("OnDragStop",function(self)  
  129.     self:StopMovingOrSizing()
  130. end)
  131. f:RegisterEvent("PLAYER_LOGIN")
  132. f:SetScript("OnEvent", function(self)
  133.     local locale = GetLocale()
  134.     L = Localizations[locale] or Localizations.enUS -- Default to enUS if locale doesn't exist in the table
  135.     MyRegion = RegionTimes[GetCurrentRegion()] or RegionTimes[1] -- Default to region 1 (US) if it doesn't exist in the table
  136.     self:SetScript("OnUpdate", function(self, elapsed)
  137.     self.Elapsed = self.Elapsed - elapsed
  138.     if self.Elapsed > 0 then -- Only check once per second
  139.         return
  140.     end
  141.     self.Elapsed = 1 -- reset the timeout (we've counted down 1 second)
  142.     printTime(self)
  143.     end)
  144. end)

You're essentially asking 2 questions. 1. how do I create a frame to track the process of x event and 2. how does Blizzard calculate the timings of x event.

This shows how 1 might work but as to 2, I have no idea so if this is not right (highly likely) then I'll leave it so maybe someone with more of an idea of what's going or might be able to figure it out.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 03-11-24 at 07:14 PM.
  Reply With Quote
03-12-24, 12:27 AM   #9
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
This timer works like the previous one (counting once per hour).

The start of event A and B is almost identical (event A starts five minutes at the beginning of the hour (for example, 09:05 or 10:05), and event B always starts at the beginning of the hour).

You can ignore the start time of event A, and tie it to the time of event B (a difference of 5 minutes is not critical)

We have an interval of 6 hours (it is after this time that event B begins).
What if you specify the following data in the counter:
event start - 1710223200
event interval 1 - 60 minutes
event interval 2 - 60 minutes
event interval 3 - 60 minutes
event interval 4 - 60 minutes
Skip event 1 - 120 minutes
Repeat all events.
This is possible in the counter based on “true” and “false”.
The timer will take data from 5 lines, each time outputting data based on how many hours have passed since the start of the 6 hour cycle.
Or won't that work either?

Last edited by Hubb777 : 03-12-24 at 04:16 AM.
  Reply With Quote
03-12-24, 08:19 AM   #10
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
I managed to find an addon that makes the required timer. But how can I apply this code to my code?
Lua Code:
  1. local _, L = ...
  2. local LMB, RMB = CreateAtlasMarkup("NPE_LeftClick", 18, 18), CreateAtlasMarkup("NPE_RightClick", 18,18)
  3.  
  4. local DefaultConfig = {
  5.     collapsed = false,
  6.     pinned = true,
  7.     events = {
  8.         [1] = { name = "Storm's Fury",
  9.             texture = "ElementalStorm-Boss-Water",
  10.             eventRegionOffset = {
  11.                 [1] = 1670338860 + 3600,
  12.                 [2] = 1670698860,
  13.             eventDuration = 7200,
  14.             eventInterval = 18000,
  15.             enable = true,
  16.             sound = false,
  17.             voice_before = true,
  18.             voice_active = true,
  19.             anim = true,
  20.             questID = 74378,
  21.             findEventOnMap = false,
  22.             coor = {2025, 59.84, 82.29},
  23.             datablock = {}
  24.         },
  25.         [2] = { name = "Trial of Elements",
  26.             texture = "VignetteLootElite",
  27.             eventRegionOffset = {
  28.                 [1] = 1670342460,
  29.                 [2] = 1670698860,
  30.             eventDuration = 600,
  31.             eventInterval = 3600,
  32.             enable = true,
  33.             sound = false,
  34.             voice_before = true,
  35.             voice_active = true,
  36.             anim = true,
  37.             questID = 71995,
  38.             findEventOnMap = false,
  39.             coor = {},
  40.             datablock = {
  41.                 [0] = {name = "Trial of the Elements", enable = false, coor = {2085, 25.80, 25.84},},
  42.                 [1] = {name = "Trial of the Elements", enable = false, coor = {2085, 25.80, 25.84},},
  43.                 [2] = {name = "Trial of the Elements", enable = true, coor = {2085, 25.80, 25.84},},
  44.             },
  45.         },
  46.     },
  47. }
  48.  
  49. EventsTrackerMixin = {}
  50. local eventFrame = {}
  51.  
  52. function EventsTrackerMixin:FindEventOnMaps(eventName, maps)
  53.     for _, mapID in next, maps do
  54.         local areaPoiIDs = C_AreaPoiInfo.GetAreaPOIForMap(mapID);
  55.         for _, ids in pairs(areaPoiIDs) do
  56.             --areaPoiID,position,name,description,textureIndex,widgetSetID,atlasName,uiTextureKit,shouldGlow,factionID,isPrimaryMapForPOI,isAlwaysOnFlightmap,addPaddingAboveWidgets, highlightWorldQuestsOnHover, highlightVignettesOnHover
  57.             local poiInfo = C_AreaPoiInfo.GetAreaPOIInfo(mapID, ids);
  58.             if eventName == "all" then --and poiInfo.isPrimaryMapForPOI then
  59.                 for k, v in pairs(poiInfo) do
  60.                     print(k,v);
  61.                 end
  62.                 print("--------------------------------------");
  63.             end
  64.            
  65.             if ((poiInfo.atlasName == "dreamsurge_hub-icon" and eventName == "Dreamsurge") or poiInfo.name == eventName) and poiInfo.isPrimaryMapForPOI then
  66.                 local elementType = poiInfo.atlasName and strmatch(poiInfo.atlasName, "ElementalStorm%-Lesser%-(.+)") or "";
  67.                 local x, y = poiInfo.position:GetXY();
  68.                
  69.                 return mapID, x*100, y*100, poiInfo.areaPoiID, poiInfo.atlasName, elementType
  70.             end
  71.         end
  72.     end
  73. end
  74.  
  75. local function SetTextureForEventFrame(frame, texture)
  76.     if tonumber(texture) then
  77.         frame.icon:SetTexture(texture)
  78.         frame.icon:SetTexCoord(.08, .92, 0.08, 0.92)
  79.     else
  80.         local info = C_Texture.GetAtlasInfo(texture)
  81.         if info then
  82.             frame.icon:SetAtlas(texture)
  83.         else
  84.             frame.icon:SetTexture(texture)
  85.         end
  86.     end
  87. end
  88.  
  89. function EventsTrackerMixin:CreateEvent(v, index)
  90.     local serverResetTime = GetServerTime() - (604800 - C_DateAndTime.GetSecondsUntilWeeklyReset())
  91.     local eFrame = CreateFrame("Button", nil, EventsTrackerHeader, "EventsTrackerButton")
  92.     local region = GetCurrentRegion()
  93.     -- ptr
  94.     if not region or region > 5 then
  95.         region = 1
  96.     end
  97.    
  98.     eFrame.init = false
  99.     eFrame.notification = false
  100.     eFrame.timeTmp = nil
  101.     eFrame.index = index
  102.    
  103.     eFrame.cfg = v
  104.     eFrame.cfg.tooltipTitle = v.name
  105.     eFrame.cfg.tooltipText = v.tooltipText or ""
  106.     eFrame.cfg.eventNewRegionOffset = v.eventRegionOffset[region] > 1600000000 and v.eventRegionOffset[region] or (serverResetTime + v.eventRegionOffset[region])
  107.    
  108.     SetTextureForEventFrame(eFrame, v.texture)
  109.            
  110.     if tonumber(v.questID) then
  111.         eFrame.icon:SetDesaturated(C_QuestLog.IsQuestFlaggedCompleted(v.questID))
  112.     end
  113.            
  114.     eFrame:SetScript("OnUpdate", function(self, elapsed)
  115.         self.elapsed = (self.elapsed or 1) + elapsed
  116.         if self.elapsed < 1 then return end
  117.         self.elapsed = 0
  118.         if not self:IsShown() then return end
  119.  
  120.         local timeFromFirstStart = GetServerTime() - self.cfg.eventNewRegionOffset
  121.         local timeToNextEvent = (self.cfg.eventInterval - timeFromFirstStart % self.cfg.eventInterval) + (self.timeTmp and self.timeTmp or 0)
  122.         local timeActiveEvent = self.timeTmp and timeToNextEvent or self.cfg.eventDuration - (self.cfg.eventInterval - timeToNextEvent)
  123.         local isEventActive = (self.cfg.eventInterval + (self.timeTmp and self.timeTmp or 0)) - timeToNextEvent <= self.cfg.eventDuration
  124.         local showedTime = isEventActive and timeActiveEvent or timeToNextEvent
  125.            
  126.         if not self.init or (self.isEventActive and not isEventActive) then
  127.             if (self.isEventActive and not isEventActive) then self.isEventActive = false end
  128.             self.timer:SetTextColor(.9, .9, .9)
  129.             self.timeTmp = nil
  130.                        
  131.             -- hladam dalsi event v databloku ak je neaky disabled preskocim ho a pripocitam cas
  132.             if next(self.cfg.datablock) then
  133.                 local index = math.floor(((timeFromFirstStart + (not isEventActive and self.cfg.eventInterval or 0)) / self.cfg.eventInterval) % (#self.cfg.datablock + 1))
  134.                                                
  135.                 -- ak su nasledujuce eventy v databloku vypnute najdem prvy aktivny a upravim cas
  136.                 for i = 0, #self.cfg.datablock do
  137.                     if not self.cfg.datablock[index].enable then
  138.                         self.timeTmp = (self.timeTmp or 0) + self.cfg.eventInterval
  139.                     else
  140.                         break
  141.                     end
  142.                     index = index == #self.cfg.datablock and 0 or (index + 1)
  143.                 end
  144.                
  145.                 self.cfg.tooltipTitle = self.cfg.datablock[index].name
  146.                 self.cfg.coor = self.cfg.datablock[index].coor
  147.            
  148.             elseif self.cfg.findEventOnMap then
  149.                 self.cfg.tooltipTitle = self.cfg.name
  150.                 SetTextureForEventFrame(self, self.cfg.texture)
  151.                 self.icon:SetDesaturated(true)
  152.                 wipe(self.cfg.coor)
  153.                
  154.             end
  155.         end
  156.        
  157.         if showedTime < 3600 then
  158.             self.timer:SetText(date("%M:%S", showedTime))
  159.         else
  160.             self.timer:SetText(date("%H", showedTime)-1 .. date("h%M", showedTime))
  161.         end
  162.        
  163.         if not self.isEventActive and isEventActive then
  164.             if self.timeTmp then
  165.                 if self.timeTmp > 0 then
  166.                     self.timeTmp = self.timeTmp - self.cfg.eventInterval
  167.                 end
  168.            
  169.             elseif self.cfg.eventDuration > 0 then
  170.                 if self.cfg.findEventOnMap then
  171.                     local mapID, x, y, areaPoiID, atlasName, elementType = EventsTrackerMixin:FindEventOnMaps(self.cfg.name, {2022, 2023, 2024, 2025})
  172.                     if mapID then
  173.                         local mapName = C_Map.GetMapInfo(mapID).name
  174.                         self.cfg.tooltipTitle = self.cfg.name .. " in " ..mapName
  175.                         self.cfg.coor = {mapID, x, y}
  176.                         if atlasName then
  177.                             self.icon:SetAtlas(atlasName)
  178.                         end
  179.                         self.icon:SetDesaturated(false)
  180.                     else
  181.                         self.cfg.tooltipTitle = self.cfg.name
  182.                         SetTextureForEventFrame(self, self.cfg.texture)
  183.                         self.icon:SetDesaturated(true)
  184.                         wipe(self.cfg.coor)
  185.                         return
  186.                     end
  187.                 end
  188.                
  189.                 self.timer:SetTextColor(0, 1, 0)
  190.                 if self.cfg.anim and not self.icon.Anim:IsPlaying() then
  191.                     self.icon.Anim:Play()
  192.                 end
  193.                 if self.voice_active and self.init then
  194.                     C_VoiceChat.SpeakText(0, self.cfg.name.." is active.", 1, 0, 100)
  195.                 end
  196.             end
  197.             self.isEventActive = true
  198.            
  199.         elseif not isEventActive then
  200.             if showedTime < 300 and not self.timeTmp then
  201.                 if not self.notification then
  202.                     if self.cfg.sound and self.init then
  203.                         PlaySound(32585, "Master")
  204.                     end
  205.                     if self.cfg.voice_before and self.init then
  206.                         C_VoiceChat.SpeakText(0, self.cfg.name.." event will start in a moment.", 1, 0, 100)
  207.                     end
  208.                     if self.cfg.anim and not self.icon.Anim:IsPlaying() then
  209.                         self.icon.Anim:Play()
  210.                     end
  211.                     self.timer:SetTextColor(1, 1, 0)
  212.                     self.notification = true
  213.                 end
  214.             elseif self.notification then
  215.                 self.notification = false
  216.             end
  217.         end
  218.    
  219.         self.init = true       
  220.     end)
  221.  
  222.     return eFrame
  223. end
  224.  
  225. function EventsTrackerMixin:ReloadAllEvents()
  226.     local firstEventFrame, previousEventFrame, showedEventCount
  227.     local rowCounter = 0
  228.    
  229.     for i, v in ipairs(L.cfg.events) do
  230.         if v.enable and not L.cfg.collapsed then
  231.             if not eventFrame[i] then
  232.                 eventFrame[i] = EventsTrackerMixin:CreateEvent(v, i)
  233.                 eventFrame[i].init = false
  234.                 eventFrame[i].notification = false
  235.                 eventFrame[i].isEventActive = nil
  236.             end
  237.            
  238.             eventFrame[i]:ClearAllPoints()
  239.             showedEventCount = (showedEventCount or 0) + 1
  240.             if not previousEventFrame then
  241.                 eventFrame[i]:SetPoint("TOPLEFT", EventsTrackerHeader, "BOTTOMLEFT", 5, -2)
  242.                 firstEventFrame = eventFrame[i]
  243.                 rowCounter = 1
  244.             elseif showedEventCount == 8 or showedEventCount == 15 then
  245.                 eventFrame[i]:SetPoint("TOP", firstEventFrame, "BOTTOM", 0, -12)
  246.                 firstEventFrame = eventFrame[i]
  247.                 rowCounter = rowCounter + 1
  248.             else
  249.                 eventFrame[i]:SetPoint("LEFT", previousEventFrame, "RIGHT", 6, 0)
  250.             end
  251.            
  252.             eventFrame[i].enable = true
  253.             eventFrame[i]:Show()
  254.             previousEventFrame = eventFrame[i]
  255.            
  256.         elseif eventFrame[i] then
  257.             eventFrame[i]:Hide()
  258.             eventFrame[i]:SetScript("OnUpdate", nil)
  259.             eventFrame[i] = nil
  260.         end
  261.     end
  262.    
  263.     if showedEventCount and showedEventCount > 0 then
  264.         EventsTrackerHeader.MinimizeButton:SetButtonState("NORMAL", false)
  265.     else
  266.         L.cfg.collapsed = true
  267.         EventsTrackerHeader.MinimizeButton:SetButtonState("PUSHED", true)
  268.     end
  269.    
  270.     if EventsTrackerHeader.pinned then
  271.         EventsTrackerHeader:EnableMouse(false)
  272.         EventsTrackerHeader:ClearAllPoints()
  273.         EventsTrackerHeader:SetPoint("BOTTOM", ObjectiveTrackerBlocksFrame, "TOP", -10, rowCounter * 38)
  274.         EventsTrackerHeader:SetParent(ObjectiveTrackerBlocksFrame)
  275.     else
  276.         EventsTrackerHeader:EnableMouse(true)
  277.         EventsTrackerHeader:SetParent(UIParent)
  278.     end
  279. end
  280.  
  281. function EventsTrackerMixin:GetLinkToEvent(index)
  282.     return L.cfg.events[index]
  283. end
  284.  
  285. function EventsTrackerMixin:CreateEventsTracker()
  286.     if not _G["EventsTable"] then _G["EventsTable"] = DefaultConfig end
  287.     L.cfg = _G["EventsTable"]
  288.    
  289.     for key, value in pairs(DefaultConfig) do
  290.         if L.cfg[key] == nil then
  291.             L.cfg[key] = value
  292.         end
  293.     end
  294.    
  295.     for key, value in pairs(DefaultConfig.events) do
  296.         if L.cfg.events[key] == nil or L.cfg.events[key].name ~= DefaultConfig.events[key].name then
  297.             L.cfg.events[key] = value
  298.         else
  299.             L.cfg.events[key].texture = DefaultConfig.events[key].texture
  300.             L.cfg.events[key].eventRegionOffset = DefaultConfig.events[key].eventRegionOffset
  301.             L.cfg.events[key].eventDuration = DefaultConfig.events[key].eventDuration
  302.             L.cfg.events[key].eventInterval = DefaultConfig.events[key].eventInterval
  303.             L.cfg.events[key].questID = DefaultConfig.events[key].questID
  304.             L.cfg.events[key].findEventOnMap = DefaultConfig.events[key].findEventOnMap
  305.             L.cfg.events[key].coor = DefaultConfig.events[key].coor
  306.             L.cfg.events[key].datablock = nil;
  307.             L.cfg.events[key].datablock = DefaultConfig.events[key].datablock
  308.             L.cfg.events[key].regionEventStartTime = nil
  309.         end
  310.     end
  311.    
  312.     EventsTrackerHeader.pinned = L.cfg.pinned
  313.     if L.cfg.pinned then
  314.         EventsTrackerHeader.PinnedButton:SetButtonState("PUSHED", true)
  315.     else
  316.         EventsTrackerHeader.PinnedButton:SetButtonState("NORMAL", false)
  317.     end
  318.     self:ReloadAllEvents()
  319.    
  320.     EventsTrackerHeader.MinimizeButton:SetScript("OnClick", function(self, button)
  321.         if button ==  "LeftButton" then
  322.             if not L.cfg.collapsed then
  323.                 L.cfg.collapsed = true
  324.                 EventsTrackerMixin:ReloadAllEvents()
  325.             else
  326.                 L.cfg.collapsed = false
  327.                 EventsTrackerMixin:ReloadAllEvents()
  328.             end
  329.            
  330.         elseif button == "RightButton"then
  331.             local menuFrame = CreateFrame("Frame", "EventsMenuFrame", UIParent, "UIDropDownMenuTemplate")
  332.             local menu = {}
  333.             local eventListMenu = {}
  334.            
  335.             for i, v in ipairs(L.cfg.events) do
  336.                 tinsert(eventListMenu,
  337.                     { text = v.name,
  338.                         checked = function() return v.enable; end,
  339.                         keepShownOnClick = 1,
  340.                         tooltipOnButton = 1,
  341.                         tooltipTitle = v.name,
  342.                         tooltipText = "Enable or diasable this event.",
  343.                         func = function() v.enable = not v.enable; EventsTrackerMixin:ReloadAllEvents(); end;
  344.                     }
  345.                 )
  346.             end
  347.        
  348.             tinsert(menu, { text = "Enable events", hasArrow = true, notCheckable = 1, menuList = eventListMenu})
  349.             EasyMenu(menu, menuFrame, "cursor", 0 , 0, "MENU");    
  350.         end
  351.     end)
  352.    
  353.     EventsTrackerHeader.PinnedButton:SetScript("OnClick", function(self, button)
  354.         if button ==  "LeftButton" then
  355.             if L.cfg.pinned then
  356.                 L.cfg.pinned = false
  357.                 EventsTrackerHeader.pinned = false
  358.                 EventsTrackerHeader.PinnedButton:SetButtonState("NORMAL", false)
  359.                 local point, relativeTo, relativePoint, xOfs, yOfs = EventsTrackerHeader:GetPoint(1)
  360.                 EventsTrackerHeader:SetPoint(point, relativeTo, relativePoint, xOfs, yOfs+20)
  361.             else
  362.                 L.cfg.pinned = true
  363.                 EventsTrackerHeader.pinned = true
  364.                 EventsTrackerHeader.PinnedButton:SetButtonState("PUSHED", true)
  365.             end
  366.             EventsTrackerMixin:ReloadAllEvents()
  367.         end
  368.     end)
  369. end
  370.  
  371. function EventsTrackerMixin:OnEvent(event, ...)
  372.     local arg1 = ...
  373.     if ( event == "ADDON_LOADED" ) then
  374.         if arg1 == _ then
  375.             self:CreateEventsTracker()
  376.             if IsAddOnLoaded(_) then
  377.                 self:UnregisterEvent('ADDON_LOADED')
  378.             end
  379.         end
  380.    
  381.     elseif ( event == "SCENARIO_UPDATE" ) then
  382.         --print(event, arg1)
  383.         if arg1 == false then
  384.             local bestMap = C_Map.GetBestMapForUnit("player")
  385.             if bestMap == 2085 then
  386.                 if IsAddOnLoaded("Nameplates") then
  387.                     textPanelMixin:ShowText("Nemas aktivne scenarko", 10)
  388.                 else
  389.                     print("You dont have active scenario, fly out and back from cave")
  390.                 end
  391.                 --https://github.com/Gethe/wow-ui-source/blob/live/Interface/SharedXML/SoundKitConstants.lua
  392.                 PlaySound(SOUNDKIT.UI_RAID_BOSS_WHISPER_WARNING, "Master")
  393.             end
  394.         end
  395.     elseif ( event == "PLAYER_ENTERING_WORLD" or ( event == "UNIT_QUEST_LOG_CHANGED" and arg1 == "player")) or event == "QUEST_TURNED_IN" then
  396.         for i, v in ipairs(L.cfg.events) do
  397.             if v.enable and v.questID and eventFrame[i] and not v.findEventOnMap then
  398.                 eventFrame[i].icon:SetDesaturated(C_QuestLog.IsQuestFlaggedCompleted(v.questID))
  399.             end
  400.         end
  401.    
  402.     end
  403. end
  404.  
  405. function EventsTrackerMixin:OnLoad()
  406.     for _, event in pairs({
  407.         "ADDON_LOADED",
  408.         "PLAYER_ENTERING_WORLD",
  409.         "UNIT_QUEST_LOG_CHANGED",
  410.         "QUEST_TURNED_IN",
  411.         "SCENARIO_UPDATE",
  412.         --  QUESTLINE_UPDATE, QUEST_POI_UPDATE, PVP_RATED_STATS_UPDATE AREA_POIS_UPDATED
  413.     }) do self:RegisterEvent(event) end
  414. end

Event A - Trial of Elements (interval 1 hour, duration 4 minutes, if event B occurs, event A does not occur)
Event B - Storm's Fury (interval 6 hours, duration 2 hours)

Last edited by Hubb777 : 03-12-24 at 08:22 AM.
  Reply With Quote
03-12-24, 12:06 PM   #11
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
Originally Posted by Hubb777 View Post
I managed to find an addon that makes the required timer.
No you didn't, because the code expects each "event" to run 24/7/365 lasting "duration" seconds repeating every interval seconds without "interuption" (same as your original request on this topic) and now you are asking for something different.

Originally Posted by Hubb777 View Post
Event A - Trial of Elements (interval 1 hour, duration 4 minutes, if event B occurs, event A does not occur)
Event B - Storm's Fury (interval 6 hours, duration 2 hours)
You seem to be confusing yourself by continually calling very different processes "event" and then not considering how those processes might interact.

Possibly:
  • I want to track an event.
  • The event last 4 minutes.
  • There are 2 seperate sessions (A and B) in which the event runs.
  • Both sessions last 6 hours (2 of each session every 24 hours)
  • Session A - The event first runs when the session starts and again every 1 hour (4 minutes event time, 56 minutes wait time repeated over 6 hours).
  • Session B - The event first runs when the session starts and again every 2 hours (4 minutes event time, 1 hour 56 minutes wait time repeated over 6 hours).
  • Each game region has different Session A start times eg.:
Lua Code:
  1. local RegionStartTimes = {
  2.     [1] = 1670338860, -- US
  3.     [2] = "region 2 start time eg. 1670348660",
  4.     [3] = "region 3 start time eg. 1670327460",
  5. --  ...
  6. }
  • Session B start times are caclulated 6 hours after Session A starts.

Maybe that's not it, but knowing what you want and then clearly breaking it down in your own mind before looking for code or translating and asking for help is more likely to get you where you want.

Maybe just, "I want to track game event "xxxxxx" with a waiting/running countdown timer. Does anyone know how the event works and how I might create the countdown for it?". (admittedly less likely to get you what you want because anyone here seriously interested in such a thing would most likely have created an addon for it already)

Good luck.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 03-12-24 at 01:00 PM.
  Reply With Quote
03-12-24, 09:59 PM   #12
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
See:
1. There is event A and event B - they run 24//7/365
2. Event A has an interval of 1 hour and a duration of 4 minutes (Start at 1709615040, interval 3600 and event time 240).
3. Event B interval 6 hours, duration 2 hours. (Start at 1709629200, interval 21600 (6 hours) and event time 7200 (2 hours))
4. If event B occurs, event A does not occur.
5. There is no need to take into account the time of different regions.
Below I have outlined the rotation for 24 hours
00:05 - Event А
01:05 - Event А
02:05 - Event А
03:05 - Event А
04:00 - Event B
05:00 - Event B
06:05 - Event А
07:05 - Event А
08:05 - Event А
09:05 - Event А
10:00 - Event B
11:00 - Event B
12:05 - Event А
13:05 - Event А
14:05 - Event А
15:05 - Event А
16:00 - Event B
17:00 - Event B
18:05 - Event А
19:05 - Event А
20:05 - Event А
21:05 - Event А
22:00 - Event B
23:00 - Event B

Last edited by Hubb777 : 03-12-24 at 10:43 PM.
  Reply With Quote
03-12-24, 11:15 PM   #13
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
In addon Events tracker, this function is implemented. When event B is in progress, event A has not started and its start time is increased (see picture)



The code below shows the entire code of addon Events tracker (the code shows the time of different regions, Europe, America, etc. but I only need 1 region - Europe)
Where - Trial of Elements is event A
Where - Storm's fury is event B
The timer only needs to display event A


As I understand it, this is done through the datablock function
Lua Code:
  1. datablock = {
  2.                 [0] = {name = "Trial of the Elements", enable = false, coor = {2085, 27.91, 25.86},},
  3.                 [1] = {name = "Trial of the Elements", enable = false, coor = {2085, 27.91, 25.86},},
  4.                 [2] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},},
  5.                 [3] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},},
  6.                 [4] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},},
  7.             },



Lua Code:
  1. local _, L = ...
  2. local LMB, RMB = CreateAtlasMarkup("NPE_LeftClick", 18, 18), CreateAtlasMarkup("NPE_RightClick", 18,18);
  3. --EVENTS_TRACKER_MODULE = ObjectiveTracker_GetModuleInfoTable("EVENTS_TRACKER_MODULE");
  4. --EVENTS_TRACKER_MODULE.updateReasonModule = OBJECTIVE_TRACKER_UPDATE_MODULE_EVENTS;
  5. --EVENTS_TRACKER_MODULE:SetHeader(ObjectiveTrackerFrame.BlocksFrame.ProfessionHeader, PROFESSIONS_TRACKER_HEADER_PROFESSION);
  6.  
  7. EventsTrackerMixin = {}
  8. local eventFrame = {}
  9. local selfName
  10.  
  11. ---------------------------------------------
  12. -- Default config
  13. local DefaultConfig = {
  14.     collapsed = false,
  15.     iconSize = 26,
  16.     iconSpace = 8,
  17.     iconsInRow = 8,
  18.     fontSize = 10,
  19.     speakVolume = 70,
  20.     timeBefore = 300,
  21.     extendedTooltip = true,
  22.     events = {
  23.         [1] = { name = "Community feast",
  24.             texture = "MajorFactions_MapIcons_Tuskarr64",
  25.             eventRegionOffset = {
  26.                 [1] = 52,   -- us
  27.                 [2] = 52,   -- kr
  28.                 [3] = 52,   -- eu
  29.                 [4] = 52,   -- tw
  30.                 [5] = 52,}, -- ch              
  31.             eventDuration = 900,
  32.             eventInterval = 5400,
  33.             enable = true,
  34.             sound = false,
  35.             voice_before = false,
  36.             voice_active = false,
  37.             anim = true,
  38.             questIDs = {70893},
  39.             findEventOnMap = {},
  40.             coor = {2024, 13.4, 48.4},
  41.             datablock = {},
  42.         },
  43.         [2] = { name = "Researchers under fire",
  44.             texture = "MajorFactions_MapIcons_Niffen64",
  45.             eventRegionOffset = {
  46.                 [1] = 1800,
  47.                 [2] = 1800,
  48.                 [3] = 1800,
  49.                 [4] = 1800,
  50.                 [5] = 1800,},
  51.             eventDuration = 1500,
  52.             eventInterval = 3600,
  53.             enable = true,
  54.             sound = false,
  55.             voice_before = false,
  56.             voice_active = false,
  57.             anim = true,
  58.             questIDs = {75627, 75628, 75629, 75630}, -- Epic 75630, Rare 75629, Uncommon, 75628, Common 75627
  59.             findEventOnMap = {},
  60.             coor = {2133, 47.6, 56.7},
  61.             datablock = {},
  62.         },
  63.         [3] = { name = "Dragonbane Keep",
  64.             texture = "MajorFactions_MapIcons_Expedition64",
  65.             eventRegionOffset = {
  66.                 [1] = 100,
  67.                 [2] = 100,
  68.                 [3] = 100,
  69.                 [4] = 100
  70.                 [5] = 100,},
  71.             eventDuration = 3600,
  72.             eventInterval = 7200,
  73.             enable = true,
  74.             sound = false,
  75.             voice_before = false,
  76.             voice_active = false,
  77.             anim = true,
  78.             questIDs = {70866},
  79.             findEventOnMap = {},
  80.             coor = {2022, 30.48, 78.20},
  81.             datablock = {},
  82.         },
  83.         [4] = { name = "Time rift",
  84.             texture = "interface/targetingframe/unitframeicons.blp", --ChromieTime-32x32
  85.             eventRegionOffset = {
  86.                 [1] = 20,
  87.                 [2] = 20,
  88.                 [3] = 20,
  89.                 [4] = 20,  
  90.                 [5] = 20,},
  91.             eventDuration = 900,
  92.             eventInterval = 3600,
  93.             enable = true,
  94.             sound = false,
  95.             voice_before = false,
  96.             voice_active = false,
  97.             anim = true,
  98.             questIDs = {77836},
  99.             findEventOnMap = {},
  100.             coor = {2025, 51, 57},
  101.             datablock = {},
  102.         },
  103.         [5] = { name = "Rares spawn",
  104.             texture = "VignetteKillElite",
  105.             eventRegionOffset = {
  106.                 [1] = 0,
  107.                 [2] = 0,
  108.                 [3] = 14400,
  109.                 [4] = 0,
  110.                 [5] = 0,},
  111.             eventDuration = 60,
  112.             eventInterval = 1800,
  113.             enable = true,
  114.             sound = false,
  115.             voice_before = false,
  116.             voice_active = false,
  117.             anim = true,
  118.             questIDs = {},
  119.             findEventOnMap = {},
  120.             coor = {},
  121.             datablock = {
  122.                 [0] = {name = "Amethyzar the Glittering", enable = true, coor = {2022, 63.6, 55.0},},
  123.                 [1] = {name = "Eldoren the Reborn", enable = true, coor = {2025, 47.8, 51.2},},
  124.                 [2] = {name = "Pheran", enable = true, coor = {2025, 60.6, 61.6},},
  125.                 [3] = {name = "Skag the Thrower", enable = true, coor = {2024, 26.8, 49.6},},
  126.                 [4] = {name = "Mikrin of the Raging Winds", enable = true, coor = {2023, 63.0, 80.0},},
  127.                 [5] = {name = "Rokmur", enable = true, coor = {2025, 50.0, 51.6},},
  128.                 [6] = {name = "Smogswog the Firebreather", enable = true, coor = {2022, 69.6, 64.6},},
  129.                 [7] = {name = "Matriarch Remalla", enable = true, coor = {2025, 52.8, 59.0},},
  130.                 [8] = {name = "O'nank Shorescour", enable = true, coor = {2022, 79.19, 52.92},},
  131.                 [9] = {name = "Researcher Sneakwing", enable = true, coor = {2023, 37.0, 53.8},},
  132.                 [10] = {name = "Treasure-Mad Trambladd", enable = true, coor = {2025, 35.0, 70.0},},
  133.                 [11] = {name = "Harkyn Grymstone", enable = true, coor = {2022, 42.2, 39.6},},
  134.                 [12] = {name = "Fulgurb", enable = true, coor = {2023, 75.2, 46.8},},
  135.                 [13] = {name = "Sandana the Tempest", enable = true, coor = {2025, 37.6, 78.0},},
  136.                 [14] = {name = "Gorjo the Crab Shackler", enable = true, coor = {2022, 78.6, 49.8},},
  137.                 [15] = {name = "Steamgill", enable = true, coor = {2023, 53.6, 72.8},},
  138.                 [16] = {name = "Tempestrian", enable = true, coor = {2025, 50.0, 79.0},},
  139.                 [17] = {name = "Massive Magmashell", enable = true, coor = {2022, 21.8, 76.6},},
  140.                 [18] = {name = "Grumbletrunk", enable = true, coor = {2024, 19.6, 43.2},},
  141.                 [19] = {name = "Oshigol", enable = true, coor = {2023, 61.6, 30.0},},
  142.                 [20] = {name = "Broodweaver Araznae", enable = true, coor = {2025, 61.51, 73.74},},
  143.                 [21] = {name = "Azra's Prized Peony", enable = true, coor = {2022, 54.6, 71.6},},
  144.                 [22] = {name = "Malsegan", enable = true, coor = {2023, 72.0, 46.6},},
  145.                 [23] = {name = "Phleep", enable = true, coor = {2025, 58.6, 85.6},},
  146.                 [24] = {name = "Magmaton", enable = true, coor = {2022, 40.0, 64.0},},
  147.                 [25] = {name = "Gruffy", enable = true, coor = {2024, 32.6, 29.2},},
  148.                 [26] = {name = "Ronsak the Decimator", enable = true, coor = {2023, 43.6, 55.4},},
  149.                 [27] = {name = "Riverwalker Tamopo", enable = true, coor = {2025, 39.8, 70.0},},
  150.             },
  151.         },
  152.         [6] = { name = "Dreamsurge",
  153.             texture = "dreamsurge_hub-icon",
  154.             eventRegionOffset = {
  155.                 [1] = 19,
  156.                 [2] = 19,
  157.                 [3] = 19,
  158.                 [4] = 19,  
  159.                 [5] = 19,},
  160.             eventDuration = 1800,
  161.             eventInterval = 1800,
  162.             enable = true,
  163.             sound = false,
  164.             voice_before = false,
  165.             voice_active = false,
  166.             anim = true,
  167.             questIDs = {77251},
  168.             findEventOnMap = {2022, 2023, 2024, 2025},
  169.             coor = {},
  170.             datablock = {},
  171.         },
  172.         [7] = { name = "Storm's Fury",
  173.             texture = "ElementalStorm-Boss-Water",
  174.             eventRegionOffset = {
  175.                 [1] = 1670338860 + 3600,
  176.                 [2] = 1670698860,
  177.                 [3] = 1674763260,
  178.                 [4] = 1670698860,
  179.                 [5] = 1670677260,},
  180.             eventDuration = 7200,
  181.             eventInterval = 18000,
  182.             enable = true,
  183.             sound = false,
  184.             voice_before = false,
  185.             voice_active = false,
  186.             anim = true,
  187.             questIDs = {74378}, --73162
  188.             findEventOnMap = {},
  189.             coor = {2025, 59.84, 82.29},
  190.             datablock = {},
  191.         },
  192.         [8] = { name = "Trial of Elements",         -- ENCOUNTER_LOOT_RECEIVED: encounterID, itemID, itemLink, quantity, playerName, classFileName
  193.             texture = "VignetteLootElite",          -- AREA_POIS_UPDATE
  194.             eventRegionOffset = {
  195.                 [1] = 1670342460,
  196.                 [2] = 1670698860,
  197.                 [3] = 1674763260,
  198.                 [4] = 1670698860,
  199.                 [5] = 1670677260,},
  200.             eventDuration = 600,
  201.             eventInterval = 3600,
  202.             enable = true,
  203.             sound = false,
  204.             voice_before = false,
  205.             voice_active = false,
  206.             anim = true,
  207.             questIDs = {71995}, --71033 Flood
  208.             findEventOnMap = {},
  209.             coor = {},
  210.             datablock = {
  211.                 [0] = {name = "Trial of the Elements", enable = false, coor = {2085, 27.91, 25.86},},
  212.                 [1] = {name = "Trial of the Elements", enable = false, coor = {2085, 27.91, 25.86},},
  213.                 [2] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},},
  214.                 [3] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},},
  215.                 [4] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},},
  216.             },
  217.         },
  218.         [9] = { name = "Elemental Storm",
  219.             texture = "ElementalStorm-Lesser-Earth",
  220.             eventRegionOffset = {
  221.                 [1] = 60,
  222.                 [2] = 60,
  223.                 [3] = 60,
  224.                 [4] = 60,  
  225.                 [5] = 60,},
  226.             eventDuration = 7200,
  227.             eventInterval = 10800,
  228.             enable = true,
  229.             sound = false,
  230.             voice_before = false,
  231.             voice_active = false,
  232.             anim = true,
  233.             questIDs = {70752, 70753, 70754, 70723, 72686}, -- Water 70752, Air 70753, Fire 70754, Earth 70723, Surge 72686
  234.             findEventOnMap = {2022, 2023, 2024, 2025},
  235.             coor = {},
  236.             datablock = {},
  237.         },
  238.         [10] = {    name = "Superbloom",
  239.             texture = "MajorFactions_MapIcons_Dream64",
  240.             eventRegionOffset = {
  241.                 [1] = 11,
  242.                 [2] = 11,
  243.                 [3] = 11,
  244.                 [4] = 11,  
  245.                 [5] = 11,},
  246.             eventDuration = 1040,
  247.             eventInterval = 3600,
  248.             enable = true,
  249.             sound = false,
  250.             voice_before = false,
  251.             voice_active = false,
  252.             anim = true,
  253.             questIDs = {78319},
  254.             findEventOnMap = {},
  255.             coor = {2200, 51.39, 59.71},
  256.             datablock = {},
  257.         },
  258.         [11] = {    name = "The Big Dig",
  259.             texture = "interface/archeology/arch-icon-marker.blp",
  260.             eventRegionOffset = {
  261.                 [1] = 1836,
  262.                 [2] = 1836,
  263.                 [3] = 1836,
  264.                 [4] = 1836,
  265.                 [5] = 1836,},
  266.             eventDuration = 552,
  267.             eventInterval = 3600,
  268.             enable = true,
  269.             sound = false,
  270.             voice_before = false,
  271.             voice_active = false,
  272.             anim = true,
  273.             questIDs = {79226},
  274.             findEventOnMap = {},
  275.             coor = {2024, 26.96, 46.46},
  276.             datablock = {},
  277.         },
  278.         [12] = {    name = "Hearthstone",
  279.             texture = "WarlockPortal-Yellow-32x32",
  280.             eventRegionOffset = {
  281.                 [1] = 48,
  282.                 [2] = 48,
  283.                 [3] = 48,
  284.                 [4] = 48,  
  285.                 [5] = 48,},
  286.             eventDuration = 300,
  287.             eventInterval = 3600,
  288.             enable = true,
  289.             sound = false,
  290.             voice_before = false,
  291.             voice_active = false,
  292.             anim = true,
  293.             questIDs = {},
  294.             findEventOnMap = {},
  295.             coor = {},
  296.             datablock = {
  297.                 [0] = {name = "Hearthstone in Valdraken", enable = true, coor = {2112, 62.38, 67.40},},
  298.                 [1] = {name = "Hearthstone in Stormwind", enable = true, coor = {84, 33.8, 19.6},}, --UnitFactionGroup("player") == 'Alliance' and {84, 33.8, 19.6} or {1, 52.8, 15.8},},
  299.                 [2] = {name = "Hearthstone in Durotar", enable = true, coor = {1, 52.8, 15.8},},
  300.             },
  301.         },
  302.     },
  303. }
  304.  
  305. ---------------------------------------------
  306. -- Setup functions
  307. SetupEventsTrackerMixin = {};
  308. function SetupEventsTrackerMixin:OnShow()
  309.     self.IconSizeSlider:SetEnabled(true);
  310.     self.IconSizeSlider:SetupSlider(L.cfg.iconSize);
  311.     self.IconSpaceSlider:SetEnabled(true);
  312.     self.IconSpaceSlider:SetupSlider(L.cfg.iconSpace);
  313.     self.IconsInRowSlider:SetEnabled(true);
  314.     self.IconsInRowSlider:SetupSlider(L.cfg.iconsInRow);
  315.     self.FontSizeSlider:SetEnabled(true);
  316.     self.FontSizeSlider:SetupSlider(L.cfg.fontSize);
  317.     self.SpeakVolumeSlider:SetEnabled(true);
  318.     self.SpeakVolumeSlider:SetupSlider(L.cfg.speakVolume);
  319.     self.TimeBeforeSlider:SetEnabled(true);
  320.     self.TimeBeforeSlider:SetupSlider(L.cfg.timeBefore);
  321.     self.ExtendedTooltipCheckButton:SetControlChecked(L.cfg.extendedTooltip);
  322.    
  323.     local function onExtendedTooltipChecked(isChecked, isUserInput)
  324.         L.cfg.extendedTooltip = isChecked
  325.     end
  326.     self.ExtendedTooltipCheckButton:SetCallback(onExtendedTooltipChecked);
  327.    
  328.     self.animIn:Play();
  329. end
  330.  
  331. IconSizeSliderMixin = {};
  332. function IconSizeSliderMixin:SetupSlider(value)
  333.     self.Slider:Init(value, 12, 40, 40 - 12, self.formatters);
  334. end
  335. function IconSizeSliderMixin:SetEnabled(enabled)
  336.     self.Slider:SetEnabled_(enabled);
  337. end
  338. function IconSizeSliderMixin:OnSliderValueChanged(value)
  339.     L.cfg.iconSize = value;
  340.     EventsTrackerMixin:ReloadAllEvents();
  341. end
  342.  
  343. IconSpaceSliderMixin = {};
  344. function IconSpaceSliderMixin:SetupSlider(value)
  345.     self.Slider:Init(value, 0, 16, 16, self.formatters);
  346. end
  347. function IconSpaceSliderMixin:SetEnabled(enabled)
  348.     self.Slider:SetEnabled_(enabled);
  349. end
  350. function IconSpaceSliderMixin:OnSliderValueChanged(value)
  351.     L.cfg.iconSpace = value;
  352.     EventsTrackerMixin:ReloadAllEvents();
  353. end
  354.  
  355. IconsInRowSliderMixin = {};
  356. function IconsInRowSliderMixin:SetupSlider(value)
  357.     self.Slider:Init(value, 1, 40, 40 - 1, self.formatters);
  358. end
  359. function IconsInRowSliderMixin:SetEnabled(enabled)
  360.     self.Slider:SetEnabled_(enabled);
  361. end
  362. function IconsInRowSliderMixin:OnSliderValueChanged(value)
  363.     L.cfg.iconsInRow = value;
  364.     EventsTrackerMixin:ReloadAllEvents();
  365. end
  366.  
  367. FontSizeSliderMixin = {};
  368. function FontSizeSliderMixin:SetupSlider(value)
  369.     self.Slider:Init(value, 7, 20, 20 - 7, self.formatters);
  370. end
  371. function FontSizeSliderMixin:SetEnabled(enabled)
  372.     self.Slider:SetEnabled_(enabled);
  373. end
  374. function FontSizeSliderMixin:OnSliderValueChanged(value)
  375.     L.cfg.fontSize = value;
  376.     EventsTrackerMixin:ReloadAllEvents();
  377. end
  378.  
  379. SpeakVolumeSliderMixin = {};
  380. function SpeakVolumeSliderMixin:SetupSlider(value)
  381.     self.Slider:Init(value, 1, 100, 99, self.formatters);
  382. end
  383. function SpeakVolumeSliderMixin:SetEnabled(enabled)
  384.     self.Slider:SetEnabled_(enabled);
  385. end
  386. function SpeakVolumeSliderMixin:OnSliderValueChanged(value)
  387.     L.cfg.speakVolume = value;
  388. end
  389.  
  390. TimeBeforeSliderMixin = {};
  391. function TimeBeforeSliderMixin:SetupSlider(value)
  392.     self.Slider:Init(value, 60, 600, 600-60, self.formatters);
  393. end
  394. function TimeBeforeSliderMixin:SetEnabled(enabled)
  395.     self.Slider:SetEnabled_(enabled);
  396. end
  397. function TimeBeforeSliderMixin:OnSliderValueChanged(value)
  398.     L.cfg.timeBefore = value;
  399. end
  400.  
  401. ---------------------------------------------
  402. -- Pomocne funkcie
  403. EventsTrackerMixin.FUNC_QUEUE_TABLE = {}
  404. function EventsTrackerMixin:CallFunctionOutOfCombat(funcName, ...)
  405.     if type(funcName) == 'function' then
  406.         if InCombatLockdown() then
  407.             table_insert(self.FUNC_QUEUE_TABLE,{funcName,{...}})
  408.         else
  409.             funcName(...)
  410.         end
  411.     end
  412. end
  413.  
  414. -- 2022 The Walking Shore, 2023 Ohn'Ahran plains, 2024 The Azure Span, 2025 Taldraszus, 2112 Valdrakken
  415. --/dump EventsTrackerMixin:FindEventOnMaps("all", {84})
  416. function EventsTrackerMixin:FindEventOnMaps(eventName, maps)
  417.     for _, mapID in next, maps do
  418.         local areaPoiIDs = C_AreaPoiInfo.GetAreaPOIForMap(mapID);
  419.         for _, ids in pairs(areaPoiIDs) do
  420.             --areaPoiID,position,name,description,textureIndex,widgetSetID,atlasName,uiTextureKit,shouldGlow,factionID,isPrimaryMapForPOI,isAlwaysOnFlightmap,addPaddingAboveWidgets,highlightWorldQuestsOnHover,highlightVignettesOnHover
  421.             local poiInfo = C_AreaPoiInfo.GetAreaPOIInfo(mapID, ids);
  422.             if eventName == "all" then
  423.                 print("--------------------------------------");
  424.                 print(C_Map.GetMapInfo(mapID).name .. "("..mapID..") - "..poiInfo.name)
  425.                 print(poiInfo.atlasName, poiInfo.isPrimaryMapForPOI)
  426.                                
  427.             elseif ((poiInfo.atlasName == "dreamsurge_hub-icon" and eventName == "Dreamsurge") or poiInfo.name == eventName) and poiInfo.isPrimaryMapForPOI then
  428.                 local elementType = poiInfo.atlasName and strmatch(poiInfo.atlasName, "ElementalStorm%-Lesser%-(.+)") or "";
  429.                 local x, y = poiInfo.position:GetXY();
  430.                
  431.                 return mapID, x*100, y*100, poiInfo.areaPoiID, poiInfo.atlasName, elementType
  432.             end
  433.         end
  434.     end
  435. end
  436.  
  437. local function SetTextureForEventFrame(frame, texture)
  438.     if tonumber(texture) then
  439.         frame.icon:SetTexture(texture);
  440.         frame.icon:SetTexCoord(.08, .92, 0.08, 0.92);
  441.     else
  442.         local info = C_Texture.GetAtlasInfo(texture);
  443.         if info then
  444.             frame.icon:SetAtlas(texture);
  445.         else
  446.             frame.icon:SetTexture(texture);
  447.         end
  448.     end
  449. end
  450.  
  451. local function isQuestCompleted(questIDTable)
  452.     local completed = 0;
  453.     if questIDTable and (type(questIDTable) == "table") then
  454.         for _, questID in pairs(questIDTable) do
  455.             if (C_QuestLog.IsOnQuest(questID)) then
  456.                 isCompleted = C_QuestLog.IsComplete(questID);
  457.             else
  458.                 isCompleted = C_QuestLog.IsQuestFlaggedCompleted(questID);
  459.             end
  460.            
  461.             if isCompleted then
  462.                 completed = completed + 1;
  463.             end
  464.         end
  465.     end
  466.     return (completed > 0)
  467. end
  468.  
  469. local function InstanceCheck()
  470.     if IsInInstance() then
  471.         if EventsTrackerHeader:IsShown() then
  472.             EventsTrackerMixin:ReloadAllEvents(true)
  473.             EventsTrackerHeader:Hide()
  474.         end
  475.     elseif not EventsTrackerHeader:IsShown() then
  476.         EventsTrackerMixin:ReloadAllEvents(false)
  477.         EventsTrackerHeader:Show()
  478.     end
  479. end
  480.  
  481. local function SetupReset()
  482.     for key, value in pairs(DefaultConfig.events) do
  483.         L.cfg.events[key].enable = value.enable;
  484.         L.cfg.events[key].sound = value.sound;
  485.         L.cfg.events[key].voice_before = value.voice_before;
  486.         L.cfg.events[key].voice_active = value.voice_active;
  487.         L.cfg.events[key].anim = value.anim;
  488.     end
  489.    
  490.     L.cfg.collapsed = DefaultConfig.collapsed;
  491.     L.cfg.iconSize = DefaultConfig.iconSize;
  492.     L.cfg.iconSpace = DefaultConfig.iconSpace;
  493.     L.cfg.iconsInRow = DefaultConfig.iconsInRow;
  494.     L.cfg.fontSize = DefaultConfig.fontSize;
  495.     L.cfg.speakVolume = DefaultConfig.speakVolume;
  496.     L.cfg.timeBefore = DefaultConfig.timeBefore;
  497.     L.cfg.savedposition = {"CENTER", nil, "CENTER", 0, 0};
  498.    
  499.     EventsTrackerHeader:ClearAllPoints();
  500.     EventsTrackerHeader:SetPoint(unpack(L.cfg.savedposition));
  501.     EventsTrackerMixin:ReloadAllEvents();
  502. end
  503.  
  504. function EventsTrackerMixin:GetLinkToEvent(index)
  505.     return L.cfg.events[index];
  506. end
  507.  
  508. function EventsTrackerMixin:GetLinkToFullEvent(index)
  509.     return DefaultConfig.events[index];
  510. end
  511.  
  512. function EventsTrackerMixin:GetTimeBefore()
  513.     return L.cfg.timeBefore;
  514. end
  515.  
  516. function EventsTrackerMixin:GetCollapsed()
  517.     return L.cfg.collapsed;
  518. end
  519.  
  520. function EventsTrackerMixin:SetCollapsed(value)
  521.     L.cfg.collapsed = value;
  522. end
  523.  
  524. function EventsTrackerMixin:SavePosition(point, relativeTo, relativePoint, xOfs, yOfs)
  525.     L.cfg.savedposition = {point, relativeTo, relativePoint, xOfs, yOfs};
  526. end
  527.  
  528. local function UpdateAllQuestCompleted()
  529.     for i, v in ipairs(L.cfg.events) do
  530.         if next(DefaultConfig.events[i].questIDs) then
  531.             local isComplete = isQuestCompleted(DefaultConfig.events[i].questIDs);
  532.             if v.enable and eventFrame[i] then
  533.                 eventFrame[i].icon:SetDesaturated(isComplete);
  534.             end
  535.             L.cfg.events[i].isComplete = isComplete;
  536.             _G["EventsTrackerDB"][selfName].events[i].isComplete = isComplete;
  537.         end
  538.     end
  539. end
  540.  
  541. function EventsTrackerMixin:GetToolTipComplete(index)
  542.     if not next(DefaultConfig.events[index].questIDs) then
  543.         return "", ""
  544.     end
  545.    
  546.     local completeOnCurrentChar;
  547.     local completeOnAccout = "";
  548.            
  549.     if _G["EventsTrackerDB"][selfName].events[index].isComplete then
  550.         completeOnCurrentChar = "|cFF00FF00Complete on this character|r"
  551.     else
  552.         completeOnCurrentChar = "|cFFFF0000Not complete on this character|r";
  553.     end
  554.    
  555.     if L.cfg.extendedTooltip then
  556.         for name in pairs(_G["EventsTrackerDB"]) do
  557.             if name ~= selfName and _G["EventsTrackerDB"][name].enable then
  558.                 if not _G["EventsTrackerDB"][name].events[index] or  _G["EventsTrackerDB"][name].events[index].isComplete == nil or not _G["EventsTrackerDB"][name].events[index].isComplete then
  559.                     local classColorStr = _G["EventsTrackerDB"][name].class and RAID_CLASS_COLORS[_G["EventsTrackerDB"][name].class].colorStr or "FFFFFFFF"
  560.                     completeOnAccout = completeOnAccout .. "|c"..classColorStr .. name .. "|r\n"
  561.                 end
  562.             end
  563.         end
  564.     end
  565.     return completeOnCurrentChar, completeOnAccout
  566. end
  567.  
  568. function EventsTrackerMixin:WeeklyUpdate(reset)
  569.     local weeklyResetTime = C_DateAndTime.GetSecondsUntilWeeklyReset()
  570.     if reset or (_G["EventsTrackerSetup"].savedResetTime and _G["EventsTrackerSetup"].savedResetTime < weeklyResetTime) then
  571.         print("|cFFFF0000Events tracker weekly reset.|r")
  572.         for name in pairs(_G["EventsTrackerDB"]) do
  573.             for i in pairs(_G["EventsTrackerDB"][name].events) do
  574.                 if i > #DefaultConfig.events then
  575.                     _G["EventsTrackerDB"][name].events[i] = nil
  576.                 elseif next(DefaultConfig.events[i].questIDs) then
  577.                     _G["EventsTrackerDB"][name].events[i].isComplete = false;
  578.                 end
  579.             end
  580.         end
  581.     end
  582.     _G["EventsTrackerSetup"].savedResetTime = weeklyResetTime;
  583. end
  584.  
  585. local function FindNextEventInDataBlock(self, index)
  586.     for i = 0, #DefaultConfig.events[self.index].datablock do
  587.         if not DefaultConfig.events[self.index].datablock[index].enable then
  588.             self.timeTmp = (self.timeTmp or 0) + DefaultConfig.events[self.index].eventInterval;
  589.         else
  590.             return index
  591.         end
  592.         index = index == #DefaultConfig.events[self.index].datablock and 0 or (index + 1);
  593.     end
  594.     return index
  595. end
  596.                
  597. local function CreateEventFrame(v, index)
  598.     local eFrame = CreateFrame("Button", nil, EventsTrackerHeader, "EventsTrackerButton");
  599.     local serverResetTime = GetServerTime() - (604800 - C_DateAndTime.GetSecondsUntilWeeklyReset());
  600.     local region = GetCurrentRegion();
  601.     -- ptr
  602.     if not region or region > 5 then
  603.         region = 1;
  604.     end
  605.    
  606.     eFrame.index = index;
  607.     eFrame.initComplete = false;
  608.     eFrame.notification = false;
  609.     eFrame.isEventActive = nil;
  610.     eFrame.timeTmp = nil;
  611.        
  612.     eFrame.enable = v.enable;
  613.     eFrame.sound = v.sound;
  614.     eFrame.voice_before = v.voice_before;
  615.     eFrame.voice_active = v.voice_active;
  616.     eFrame.anim = v.anim;
  617.    
  618.     eFrame.tooltipTitle = DefaultConfig.events[index].name;
  619.     eFrame.coor = DefaultConfig.events[index].coor;
  620.     eFrame.eventNewRegionOffset = DefaultConfig.events[index].eventRegionOffset[region] > 1600000000 and DefaultConfig.events[index].eventRegionOffset[region] or (serverResetTime + DefaultConfig.events[index].eventRegionOffset[region]);
  621.    
  622.     SetTextureForEventFrame(eFrame, DefaultConfig.events[index].texture);
  623.     eFrame.icon:SetDesaturated(v.isComplete);
  624.    
  625.     eFrame:SetScript("OnUpdate", function(self, elapsed)
  626.         self.elapsed = (self.elapsed or 1) + elapsed;
  627.         if self.elapsed < 1 then return end
  628.         self.elapsed = 0;
  629.         if not self:IsShown() then return end
  630.  
  631.         local timeFromFirstStart = GetServerTime() - self.eventNewRegionOffset;
  632.         local timeToNextEvent = (DefaultConfig.events[self.index].eventInterval - timeFromFirstStart % DefaultConfig.events[self.index].eventInterval) + (self.timeTmp and self.timeTmp or 0);
  633.         local timeActiveEvent = self.timeTmp and timeToNextEvent or DefaultConfig.events[self.index].eventDuration - (DefaultConfig.events[self.index].eventInterval - timeToNextEvent);
  634.         local isEventActive = (DefaultConfig.events[self.index].eventInterval + (self.timeTmp and self.timeTmp or 0)) - timeToNextEvent <= DefaultConfig.events[self.index].eventDuration;
  635.         local showedTime = isEventActive and timeActiveEvent or timeToNextEvent;
  636.            
  637.         if not self.initComplete or (self.isEventActive and not isEventActive) then
  638.             if (self.isEventActive and not isEventActive) then self.isEventActive = false end
  639.             self.timer:SetTextColor(.9, .9, .9);
  640.             self.timeTmp = nil;
  641.                        
  642.             -- hladam dalsi event v databloku ak je neaky disabled preskocim ho a pripocitam cas
  643.             if next(DefaultConfig.events[self.index].datablock) then --not isEventActive and
  644.                 local index = math.floor(((timeFromFirstStart + (not self.isEventActive and DefaultConfig.events[self.index].eventInterval or 0)) / DefaultConfig.events[self.index].eventInterval) % (#DefaultConfig.events[self.index].datablock + 1));
  645.                                
  646.                 -- ak su nasledujuce eventy v databloku vypnute najdem prvy aktivny a upravim cas
  647.                 index = FindNextEventInDataBlock(self, index)
  648.                
  649.                 local tmp = self.timeTmp
  650.                 local nextIndex = index + 1
  651.                 nextIndex = nextIndex > #DefaultConfig.events[self.index].datablock and 0 or nextIndex;
  652.                 nextIndex = FindNextEventInDataBlock(self, nextIndex)
  653.                 self.timeTmp = tmp
  654.                                
  655.                 if DefaultConfig.events[self.index].datablock[index].name ~= DefaultConfig.events[self.index].datablock[nextIndex].name then
  656.                     self.tooltipTitle = DefaultConfig.events[self.index].datablock[index].name .. "\n|cFF808080" .. DefaultConfig.events[self.index].datablock[nextIndex].name .."|r";
  657.                 else
  658.                     self.tooltipTitle = DefaultConfig.events[self.index].datablock[index].name
  659.                 end
  660.                
  661.                 self.coor = DefaultConfig.events[self.index].datablock[index].coor;
  662.                
  663.             elseif next(DefaultConfig.events[self.index].findEventOnMap) then
  664.                 -- po ukonceni eventu (elemental storm) zmen na zakladnu iconu a popis
  665.                 self.tooltipTitle = DefaultConfig.events[self.index].name;
  666.                 SetTextureForEventFrame(self, DefaultConfig.events[self.index].texture);
  667.                 self.icon:SetDesaturated(true);
  668.                 wipe(self.coor);
  669.                
  670.             end
  671.         end
  672.        
  673.         if showedTime < 3600 then
  674.             self.timer:SetText(date("%M:%S", showedTime));
  675.         else
  676.             self.timer:SetText(date("%H", showedTime)-1 .. date("h%M", showedTime));
  677.         end
  678.        
  679.         if not self.isEventActive and isEventActive then
  680.             if self.timeTmp and self.timeTmp > 0 then
  681.                 self.timeTmp = self.timeTmp - DefaultConfig.events[self.index].eventInterval;
  682.                            
  683.             elseif DefaultConfig.events[self.index].eventDuration > 0 then
  684.                 if next(DefaultConfig.events[self.index].findEventOnMap) then
  685.                     local mapID, x, y, areaPoiID, atlasName, elementType = EventsTrackerMixin:FindEventOnMaps(DefaultConfig.events[self.index].name, DefaultConfig.events[self.index].findEventOnMap);
  686.                     if mapID then
  687.                         local mapName = C_Map.GetMapInfo(mapID).name;
  688.                         self.tooltipTitle = DefaultConfig.events[self.index].name .. " in " ..mapName;
  689.                         self.coor = {mapID, x, y};
  690.                         if atlasName then
  691.                             self.icon:SetAtlas(atlasName);
  692.                         end
  693.                         self.icon:SetDesaturated(false);
  694.                     else
  695.                         self.tooltipTitle = DefaultConfig.events[self.index].name;
  696.                         SetTextureForEventFrame(self, DefaultConfig.events[self.index].texture);
  697.                         self.icon:SetDesaturated(true);
  698.                         wipe(self.coor);
  699.                         return;
  700.                     end
  701.                 end
  702.                
  703.                 self.timer:SetTextColor(0, 1, 0);
  704.                 if self.anim and not self.icon.Anim:IsPlaying() then
  705.                     self.icon.Anim:Play();
  706.                 end
  707.                 if self.voice_active and self.initComplete then
  708.                     C_VoiceChat.SpeakText(0, DefaultConfig.events[self.index].name.." is active.", 1, 0, L.cfg.speakVolume);
  709.                 end
  710.             end
  711.             self.isEventActive = true;
  712.            
  713.         elseif not isEventActive then
  714.             if showedTime < L.cfg.timeBefore and not self.timeTmp then
  715.                 if not self.notification then
  716.                     if self.sound and self.initComplete then
  717.                         PlaySound(32585, "Master");
  718.                     end
  719.                     if self.voice_before and self.initComplete then
  720.                         C_VoiceChat.SpeakText(0, DefaultConfig.events[self.index].name.." event will start in a moment.", 1, 0, L.cfg.speakVolume);
  721.                     end
  722.                     if self.anim and not self.icon.Anim:IsPlaying() then
  723.                         self.icon.Anim:Play();
  724.                     end
  725.                     self.timer:SetTextColor(1, 1, 0);
  726.                     self.notification = true;
  727.                 end
  728.             elseif self.notification then
  729.                 self.notification = false;
  730.             end
  731.         end
  732.    
  733.         self.initComplete = true    ;
  734.     end)
  735.  
  736.     return eFrame;
  737. end
  738.  
  739. function EventsTrackerMixin:ReloadAllEvents(hideAll)
  740.     local firstEventFrame, lastEventFrame;
  741.     local iconsInRow = 0;
  742.    
  743.     for i, v in ipairs(L.cfg.events) do
  744.         if not hideAll and v.enable and not L.cfg.collapsed then
  745.             if not eventFrame[i] then
  746.                 eventFrame[i] = CreateEventFrame(v, i);
  747.             end
  748.             eventFrame[i]:SetSize(L.cfg.iconSize, L.cfg.iconSize)
  749.             eventFrame[i].icon:SetSize(L.cfg.iconSize + 6, L.cfg.iconSize + 6)
  750.             eventFrame[i]:ClearAllPoints();
  751.             eventFrame[i].timer:SetFont("Fonts\\FRIZQT__.TTF", L.cfg.fontSize, "OUTLINE")
  752.            
  753.             iconsInRow = (iconsInRow or 0) + 1;
  754.             if not lastEventFrame then
  755.                 eventFrame[i]:SetPoint("TOPLEFT", EventsTrackerHeader, "TOPRIGHT", 4, -5);
  756.                 firstEventFrame = eventFrame[i];
  757.             elseif iconsInRow > L.cfg.iconsInRow then
  758.                 eventFrame[i]:SetPoint("TOP", firstEventFrame, "BOTTOM", 0, -12);
  759.                 firstEventFrame = eventFrame[i];
  760.                 iconsInRow = 1;
  761.             else
  762.                 eventFrame[i]:SetPoint("LEFT", lastEventFrame, "RIGHT", L.cfg.iconSpace, 0);
  763.             end
  764.            
  765.             eventFrame[i].enable = true;
  766.             eventFrame[i]:Show();
  767.             lastEventFrame = eventFrame[i];
  768.            
  769.         elseif eventFrame[i] then
  770.             eventFrame[i]:Hide();
  771.             eventFrame[i]:SetScript("OnUpdate", nil);
  772.             eventFrame[i] = nil;
  773.         end
  774.     end
  775.    
  776.     EventsTrackerHeader.CollapsedButton:SetButtonState(L.cfg.collapsed and "PUSHED" or "NORMAL", L.cfg.collapsed and true or false);
  777. end
  778.  
  779. function EventsTrackerMixin:OnEvent(event, ...)
  780.     local arg1 = ...
  781.     if ( event == "ADDON_LOADED" ) then
  782.         if arg1 == _ then
  783.             selfName = UnitName("player") .. " - " .. GetRealmName();
  784.            
  785.             if _G["EventsTrackerDB"] == nil then _G["EventsTrackerDB"] = {}; end
  786.             if _G["EventsTrackerDB"][selfName] == nil then
  787.                 _G["EventsTrackerDB"][selfName] = {};
  788.                 _G["EventsTrackerDB"][selfName].class = select(2, UnitClass("player"));
  789.                 _G["EventsTrackerDB"][selfName].enable = true;
  790.                 _G["EventsTrackerDB"][selfName].events = {};
  791.             end
  792.            
  793.             -- prekopiruj nove eventy
  794.             for i, v in pairs(DefaultConfig.events) do
  795.                 if _G["EventsTrackerDB"][selfName].events[i] == nil then
  796.                     _G["EventsTrackerDB"][selfName].events[i] = {};
  797.                     _G["EventsTrackerDB"][selfName].events[i].enable = v.enable;
  798.                     _G["EventsTrackerDB"][selfName].events[i].sound = v.sound;
  799.                     _G["EventsTrackerDB"][selfName].events[i].voice_before = v.voice_before;
  800.                     _G["EventsTrackerDB"][selfName].events[i].voice_active = v.voice_active;
  801.                     _G["EventsTrackerDB"][selfName].events[i].anim = v.anim;
  802.                 end
  803.             end
  804.             -- zmaz zvysne eventy pod char save
  805.             if #DefaultConfig.events <  #_G["EventsTrackerDB"][selfName].events then
  806.                 for i = #DefaultConfig.events+1, #_G["EventsTrackerDB"][selfName].events do
  807.                     _G["EventsTrackerDB"][selfName].events[i] = nil
  808.                 end
  809.             end
  810.             -- pridaj nove hodnoty
  811.             for key, value in pairs(DefaultConfig) do
  812.                 if _G["EventsTrackerDB"][selfName][key] == nil and type(value) ~= "table" then
  813.                     _G["EventsTrackerDB"][selfName][key] = value;
  814.                 end
  815.             end
  816.            
  817.             L.cfg = _G["EventsTrackerDB"][selfName];
  818.            
  819.             -- ak nebol nastaveny savedposition pre ETH nastav ho z predchadzajucej pozicie uzivatela
  820.             if not L.cfg.savedposition or (type(L.cfg.savedposition) ~= "table") then
  821.                 local point, relativeTo, relativePoint, xOfs, yOfs = EventsTrackerHeader:GetPoint(1)
  822.                 if point then
  823.                     L.cfg.savedposition = {point, relativeTo, relativePoint, xOfs, yOfs};
  824.                 else
  825.                     L.cfg.savedposition = {"CENTER", nil, "CENTER", 0, 0}
  826.                 end
  827.             end
  828.            
  829.             if _G["EventsTrackerSetup"] == nil then _G["EventsTrackerSetup"] = {}; end
  830.                        
  831.             EventsTrackerHeader.SetupButton:SetScript("OnClick", function(self, button)
  832.                 if button == "LeftButton" then
  833.                     if SetupEventsTrackerFrame:IsShown() then
  834.                         SetupEventsTrackerFrame:Hide()
  835.                         EventsTrackerHeader.SetupButton:SetButtonState("NORMAL", false);
  836.                     else
  837.                         SetupEventsTrackerFrame:Show()
  838.                         EventsTrackerHeader.SetupButton:SetButtonState("PUSHED", true);
  839.                     end
  840.                                
  841.                 elseif button == "RightButton"then
  842.                     local menuFrame = CreateFrame("Frame", "EventsMenuFrame", UIParent, "UIDropDownMenuTemplate");
  843.                     local menu = {};
  844.                     local eventListMenu = {};
  845.                     local copySetupMenu = {};
  846.                     local charactersEnableMenu = {};
  847.                     local selfName = UnitName("player") .. " - " .. GetRealmName();
  848.                    
  849.                     -- vytvor Events list menu
  850.                     for i, v in ipairs(L.cfg.events) do
  851.                         tinsert(eventListMenu,
  852.                             { text = DefaultConfig.events[i].name,
  853.                                 checked = function() return v.enable; end,
  854.                                 keepShownOnClick = 1,
  855.                                 tooltipOnButton = 1,
  856.                                 tooltipTitle = v.name,
  857.                                 tooltipText = "Enable or diasable this event.",
  858.                                 func = function() v.enable = not v.enable; EventsTrackerMixin:ReloadAllEvents(); end
  859.                             }
  860.                         )
  861.                     end
  862.                    
  863.                     -- vytvor Reset menu
  864.                     tinsert(copySetupMenu,
  865.                         { text = "Reset to default",
  866.                             notCheckable = 1,
  867.                             tooltipOnButton = 1,
  868.                             tooltipTitle = "Reset",
  869.                             tooltipText = "Reset setup for active character to default.",
  870.                             colorCode = "|cFFFF0000",
  871.                             func = function()
  872.                                 SetupReset()
  873.                                 CloseDropDownMenus();
  874.                                 if SetupEventsTrackerFrame:IsShown() then
  875.                                     SetupEventsTrackerFrame:Hide()
  876.                                 end
  877.                             end
  878.                         })
  879.                    
  880.                     -- vytvor Copy to all
  881.                     tinsert(copySetupMenu,
  882.                         { text = "Copy to all",
  883.                             notCheckable = 1,
  884.                             tooltipOnButton = 1,
  885.                             tooltipTitle = "Copy",
  886.                             tooltipText = "Copy this active setup to all your characters.",
  887.                             colorCode = "|cFFFF0000",
  888.                             func = function()
  889.                                 for name in pairs(_G["EventsTrackerDB"]) do
  890.                                     if name ~= selfName then
  891.                                         for key, value in pairs(L.cfg) do
  892.                                             if ( key == "events" ) then
  893.                                                 for i, event in pairs(value) do
  894.                                                     for x, y in pairs(event) do
  895.                                                         if x ~= "isComplete" then
  896.                                                             if _G["EventsTrackerDB"][name].events[i] == nil then
  897.                                                                 _G["EventsTrackerDB"][name].events[i] = {}
  898.                                                             end
  899.                                                             _G["EventsTrackerDB"][name].events[i][x] = y;
  900.                                                         end
  901.                                                     end
  902.                                                 end
  903.                                                
  904.                                             elseif key ~= "class" then
  905.                                                 _G["EventsTrackerDB"][name][key] = value;
  906.                                             end
  907.                                         end
  908.                                     end
  909.                                 end
  910.                                 CloseDropDownMenus();
  911.                             end
  912.                         })
  913.                    
  914.                     -- pridaj separator
  915.                     tinsert(copySetupMenu,
  916.                         {   text = "", hasArrow = false;    dist = 0; isTitle = true; isUninteractable = true; notCheckable = true; iconOnly = true;
  917.                             icon = "Interface\\Common\\UI-TooltipDivider-Transparent"; tCoordLeft = 0; tCoordRight = 1; tCoordTop = 0; tCoordBottom = 1; tSizeX = 0; tSizeY = 8;    tFitDropDownSizeX = true;
  918.                             iconInfo = {    tCoordLeft = 0, tCoordRight = 1,    tCoordTop = 0, tCoordBottom = 1, tSizeX = 0, tSizeY = 8, tFitDropDownSizeX = true},
  919.                         })
  920.                                            
  921.                     -- vytvor copy form selected char
  922.                     for name in pairs(_G["EventsTrackerDB"]) do
  923.                         local classColorStr = _G["EventsTrackerDB"][name].class and RAID_CLASS_COLORS[_G["EventsTrackerDB"][name].class].colorStr or "FFFFFFFF"
  924.                         if name ~= selfName then
  925.                             tinsert(copySetupMenu,
  926.                                 { text = name,
  927.                                     notCheckable = 1,
  928.                                     tooltipOnButton = 1,
  929.                                     tooltipTitle = name,
  930.                                     tooltipText = "Copy setup from this character",
  931.                                     colorCode = "|c" .. classColorStr,
  932.                                     func = function()
  933.                                         for key, value in pairs(_G["EventsTrackerDB"][name]) do
  934.                                             if ( key == "events" ) then
  935.                                                 for i, event in pairs(value) do
  936.                                                     for x, y in pairs(event) do
  937.                                                         if x ~= "isComplete" then
  938.                                                             _G["EventsTrackerDB"][selfName].events[i][x] = y;
  939.                                                             L.cfg.events[i][x] = y;
  940.                                                         end
  941.                                                     end
  942.                                                 end
  943.                                                
  944.                                             elseif key ~= "class" then
  945.                                                 _G["EventsTrackerDB"][selfName][key] = value;
  946.                                                 L.cfg[key] = value;
  947.                                             end
  948.                                         end
  949.                                                                                
  950.                                         if SetupEventsTrackerFrame:IsShown() then
  951.                                             SetupEventsTrackerFrame:Hide()
  952.                                         end
  953.                                         EventsTrackerMixin:ReloadAllEvents();
  954.                                         CloseDropDownMenus();
  955.                                     end
  956.                                 }
  957.                             )
  958.                         end
  959.                     end
  960.                    
  961.                     -- vytvor character enable
  962.                     for name in pairs(_G["EventsTrackerDB"]) do
  963.                         local classColorStr = _G["EventsTrackerDB"][name].class and RAID_CLASS_COLORS[_G["EventsTrackerDB"][name].class].colorStr or "FFFFFFFF"
  964.                         tinsert(charactersEnableMenu,
  965.                             { text = name,
  966.                                 checked = function() return _G["EventsTrackerDB"][name].enable; end,
  967.                                 keepShownOnClick = 1,
  968.                                 tooltipOnButton = 1,
  969.                                 tooltipTitle = name,
  970.                                 tooltipText = "Enable this character for toolTip information.",
  971.                                 colorCode = "|c" .. classColorStr,
  972.                                 func = function() _G["EventsTrackerDB"][name].enable = not _G["EventsTrackerDB"][name].enable; end
  973.                             }
  974.                         )
  975.                     end
  976.                    
  977.                     tinsert(menu, { text = "Enable events", hasArrow = true, notCheckable = 1, menuList = eventListMenu});
  978.                     tinsert(menu, { text = "Characters in toolTip", hasArrow = true, notCheckable = 1, menuList = charactersEnableMenu});
  979.                     if copySetupMenu and #copySetupMenu > 0 then
  980.                         tinsert(menu, { text = "Copy setup", hasArrow = true, notCheckable = 1, menuList = copySetupMenu});
  981.                     end
  982.                     EasyMenu(menu, menuFrame, "cursor", 0 , 0, "MENU");
  983.                 end        
  984.             end)
  985.                        
  986.             function EventsTrackerAlertFrame_SetUp(self, str, sound)
  987.                 if str ~= nil then
  988.                     self.Text:SetText(str);
  989.                 end
  990.                 --https://github.com/Gethe/wow-ui-source/blob/live/Interface/SharedXML/SoundKitConstants.lua
  991.                 if sound then
  992.                     PlaySound(sound);
  993.                 end
  994.             end
  995.  
  996.             EventsTrackerAlertSystem = AlertFrame:AddQueuedAlertFrameSubSystem("EventsTrackerWarningTemplate", EventsTrackerAlertFrame_SetUp, 6, math.huge);
  997.  
  998.             SLASH_ETRACKER1 = "/etracker"
  999.             SlashCmdList["ETRACKER"] = function(msg)
  1000.                 if ( msg == "reset" ) then
  1001.                     SetupReset()
  1002.                 end
  1003.             end
  1004.            
  1005.             if IsAddOnLoaded(_) then
  1006.                 self:UnregisterEvent('ADDON_LOADED');
  1007.             end
  1008.         end
  1009.            
  1010.     elseif ( event == "SCENARIO_UPDATE" ) then
  1011.         if arg1 == false then
  1012.             local bestMap = C_Map.GetBestMapForUnit("player");
  1013.             if bestMap == 2085 then
  1014.                 EventsTrackerAlertSystem:AddAlert("You dont have active scenario, fly out and back to cave.", SOUNDKIT.UI_RAID_BOSS_WHISPER_WARNING);
  1015.             end
  1016.         elseif arg1 == nil then
  1017.             UpdateAllQuestCompleted()
  1018.         end
  1019.    
  1020.     elseif ( event == "ZONE_CHANGED_NEW_AREA" ) then
  1021.         EventsTrackerMixin:CallFunctionOutOfCombat(InstanceCheck())
  1022.        
  1023.     elseif ( event == "PLAYER_ENTERING_WORLD" or ( event == "UNIT_QUEST_LOG_CHANGED" and arg1 == "player")) or event == "QUEST_TURNED_IN" or event == "ENCOUNTER_LOOT_RECEIVED" then
  1024.         if event == "PLAYER_ENTERING_WORLD" then
  1025.             self:CallFunctionOutOfCombat(InstanceCheck())
  1026.             self:ReloadAllEvents();
  1027.             EventsTrackerHeader:ClearAllPoints();
  1028.             EventsTrackerHeader:SetPoint(unpack(L.cfg.savedposition));
  1029.         end
  1030.         UpdateAllQuestCompleted()
  1031.            
  1032.     elseif ( event == "PLAYER_REGEN_ENABLED" ) then
  1033.         for _, function_tbl in ipairs(self.FUNC_QUEUE_TABLE) do
  1034.             if type(function_tbl[1]) == 'function' then
  1035.                 function_tbl[1](unpack(function_tbl[2]))
  1036.             end
  1037.         end
  1038.         wipe(self.FUNC_QUEUE_TABLE)
  1039.        
  1040.     elseif ( event == "COVENANT_CHOSEN" or event == "COVENANT_CALLINGS_UPDATED" ) then
  1041.         self:WeeklyUpdate()
  1042.        
  1043.     end
  1044. end
  1045.  
  1046. function EventsTrackerMixin:OnLoad()
  1047.     for _, event in pairs({
  1048.         "ADDON_LOADED",
  1049.         "PLAYER_ENTERING_WORLD",
  1050.         "ZONE_CHANGED_NEW_AREA",
  1051.         "UNIT_QUEST_LOG_CHANGED",   -- QUEST_WATCH_UPDATE. QUEST_LOG_UPDATE, UI_INFO_MESSAGE 303,"Objective complete"
  1052.         "QUEST_TURNED_IN",
  1053.         "SCENARIO_UPDATE",
  1054.         "PLAYER_REGEN_ENABLED",     -- pre spustenie funkcii outOfCombat
  1055.         "COVENANT_CHOSEN",          -- COVENANT_CALLINGS_UPDATED, GUILDBANK_UPDATE_WITHDRAWMONEY, TREASURE_PICKER_CACHE_FLUSH pre weekly update ak je player online pocas weekly resetu
  1056.         "COVENANT_CALLINGS_UPDATED",
  1057.         "ENCOUNTER_LOOT_RECEIVED"-- pre Trial of the element
  1058.     }) do self:RegisterEvent(event) end
  1059. end

Last edited by Hubb777 : 03-12-24 at 11:23 PM.
  Reply With Quote
03-13-24, 10:24 AM   #14
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
Originally Posted by Hubb777 View Post
See:
1. There is event A and event B - they run 24//7/365
2. Event A has an interval of 1 hour and a duration of 4 minutes (Start at 1709615040, interval 3600 and event time 240).
3. Event B interval 6 hours, duration 2 hours. (Start at 1709629200, interval 21600 (6 hours) and event time 7200 (2 hours))
4. If event B occurs, event A does not occur.
5. There is no need to take into account the time of different regions.
Below I have outlined the rotation for 24 hours
00:05 - Event А
01:05 - Event А
02:05 - Event А
03:05 - Event А
04:00 - Event B
05:00 - Event B
06:05 - Event А
07:05 - Event А
08:05 - Event А
09:05 - Event А
10:00 - Event B
11:00 - Event B
12:05 - Event А
13:05 - Event А
14:05 - Event А
15:05 - Event А
16:00 - Event B
17:00 - Event B
18:05 - Event А
19:05 - Event А
20:05 - Event А
21:05 - Event А
22:00 - Event B
23:00 - Event B
Given you can't see the inconsistency between what you described and what you listed there's little chance of getting a result. It can't all be just translation because you are not addressing each step (process) as being seperate and different.
  • Describing Event A intervals 1 hours, listing 1 hour intervals
  • Describing Event B intervals 6 hours, listing 1 hour intervals.
  • Describing Event A duration 4 minutes, listing 1 hour intervals
  • Describing Event B duration 2 hours, listing 1 hour intervals

In the code listed, the datablock is just a list of what looks like map pin locations, nothing to do with time.

Suspiciously cropped picture is suspicious, and not saying what you think it is...

Maybe it's because of the difference between the way the addon works and the way the event you want track works is why it's not included in the addon.

Just to finish up, another guess at what you are looking for (more actual processes being tracked with their own names and times). Still guessing you want to track the running/waiting periods of the same actual event.
1 Event, runs for 4 minutes.
1 Session, totaling 6 hours, repeating
2 Sub-Sessions (A and B)
Sub-Session A: Event lasts 4 minutes and interval between Events is 1 hour (4 minutes + 56 minutes repeating 4 times). Sub-Session A runs for 4 hours total
Sub-Session B: Event lasts 4 minutes and interval between Events is 2 hours (4 minutes + 1 hour 56 minutes no repeats). Sub-Session B runs for 2 hours total

Code:
Session Start (6 hours):
00:05 - Sub-Session А -- Event for 4 minutes
01:05 - Sub-Session А -- Event for 4 minutes
02:05 - Sub-Session А -- Event for 4 minutes
03:05 - Sub-Session А -- Event for 4 minutes

04:00 - Sub-Session B -- Event for 4 minutes
05:00 - Sub-Session B -- extended wait time
Session End:

Repeat (6 hours):
06:05 - Sub-Session А -- Event for 4 minutes
07:05 - Sub-Session А -- Event for 4 minutes
08:05 - Sub-Session А -- Event for 4 minutes
09:05 - Sub-Session А -- Event for 4 minutes

10:00 - Sub-Session B -- Event for 4 minutes
11:00 - Sub-Session B -- extended wait time

Repeat (6 hours):
12:05 - Sub-Session А -- Event for 4 minutes
13:05 - Sub-Session А -- Event for 4 minutes
14:05 - Sub-Session А -- Event for 4 minutes
15:05 - Sub-Session А -- Event for 4 minutes

16:00 - Sub-Session B -- Event for 4 minutes
17:00 - Sub-Session B -- extended wait time

Repeat (6 hours):
18:05 - Sub-Session А -- Event for 4 minutes
19:05 - Sub-Session А -- Event for 4 minutes
20:05 - Sub-Session А -- Event for 4 minutes
21:05 - Sub-Session А -- Event for 4 minutes

22:00 - Sub-Session B -- Event for 4 minutes
23:00 - Sub-Session B -- extended wait time
The addon you posted could work with the 6 hour session repeating. It doesn't "understand" sub-sessions or their variable nature (or differing running times of the actual event if the above is not correct in assuming it's only ever 4 minutes long).

I've spent too much time on this and I'm sure you're sick of hearing from me. I will leave it to you and others to try and find a workable solution for whatever it is you are wanting to do.
Have Fun!
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 03-13-24 at 01:09 PM.
  Reply With Quote
03-13-24, 10:54 PM   #15
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
I apologize for causing you any inconvenience. And took up your time.

I'll try to explain again. In details
for convenience, I gave an example of a start at 00:00, and not at 00:05 as in the example above. Sorry again.

Session Start (6 hours):
(line 0) Time 06:00 - Sub-Session B -- + 60 min = 07:00 (120 minutes until next event)
(line 1) Time 07:00 - Sub-Session B - + 60 min = 08:00 (60 minutes until next event)
(line 2) Time 08:00 - Sub-Session А -- Event for 4 minutes. 08:00 + 4 min = 08:04 (56 minutes until next event)
(line 3) Time 09:00 - Sub-Session А -- Event for 4 minutes. 09:00 + 4 min = 09:04 (56 minutes until next event)
(line 4) Time 10:00 - Sub-Session А -- Event for 4 minutes. 10:00 + 4 min = 10:04 (176 minutes until next event)
Session End:
Repeat (6 hours):
(line 0) Time 11:00 - Sub-Session B -- + 60 min = 12:00 (120 minutes until next event)
(line 1) Time 12:00 - Sub-Session B - + 60 min = 13:00 (60 minutes until next event)
(line 2) Time 13:00 - Sub-Session А -- Event for 4 minutes. 13:00 + 4 min = 13:04 (56 minutes until next event)
(line 3) Time 14:00 - Sub-Session А -- Event for 4 minutes. 14:00 + 4 min = 14:04 (56 minutes until next event)
(line 4) Time 15:00 - Sub-Session А -- Event for 4 minutes. 15:00 + 4 min = 15:04 (176 minutes until next event)


It seems like we just can't understand each other. I'll try to explain everything. (line 0 and 1 will be both "false") (line 2,3 and 4 will be like "true")
If we fail to understand each other, I will have to abandon this idea =(

Last edited by Hubb777 : 03-13-24 at 11:30 PM.
  Reply With Quote
03-14-24, 10:39 AM   #16
Xrystal
nUI Maintainer
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2006
Posts: 5,934
Some questions:

1. What EXACTLY are you trying to monitor, an event that the game runs outside of your control ( what is it ) , or an event you have created yourself which you have total control over ( maybe you can make some adjustments to it to make the addon writing easier and expand on it as your addon writing skills improve) ?

2. What are you HOPING to achieve with this addon ?

3. What is working as expected ?

4. What isn't working as expected ? What were you wanting it to do ? What is it doing instead ?

5. Have you made sure you have something like bugrabber and bugsack active picking up any errors ? If you have errors the addon will stop at that point, so you would need to fix those errors before seeing how the code runs when it isn't bugging out.

If you weren't aware, unfortunately programming can involve a lot of testing, fixing, testing, fixing time. Some less of them, some more of them. It all depends on the complexity of the project.
__________________


Characters:
Gwynedda - 70 - Demon Warlock
Galaviel - 65 - Resto Druid
Gamaliel - 61 - Disc Priest
Gwynytha - 60 - Survival Hunter
Lienae - 60 - Resto Shaman
Plus several others below level 60

Info Panel IDs : http://www.wowinterface.com/forums/s...818#post136818
  Reply With Quote
03-14-24, 01:14 PM   #17
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
I wasn't going to but...
Your numbers still dont add up
Code:
Session Start (6 hours):
(line 0) Time 06:00 - Sub-Session B -- + 60 min = 07:00 (120 minutes until next event)
(line 1) Time 07:00 - Sub-Session B - + 60 min = 08:00 (60 minutes until next event)
(line 2) Time 08:00 - Sub-Session А -- Event for 4 minutes. 08:00 + 4 min = 08:04 (56 minutes until next event)
(line 3) Time 09:00 - Sub-Session А -- Event for 4 minutes. 09:00 + 4 min = 09:04 (56 minutes until next event)
(line 4) Time 10:00 - Sub-Session А -- Event for 4 minutes. 10:00 + 4 min = 10:04 (176 minutes until next event)
Session End:
60+60+4+56+4+56+4+176 = 420 (7 hours).

But again using some guesswork (116 is instead of 176) the explanation seems to look like this (I'm starting to feel like ChatGPT, just keep saying something even if you don't understand the request ):
  • 6 hour repeating session
  • 4 minute event runs 3 times begining at startTime, then 60 minutes apart for a total duration of 2 hours and 4 minutes (Sub-session A)(4 + 56 + 4 + 56 + 4).
  • Followed by 3 hours 56 minutes waiting (Sub-session B)

2:04 + 3:56 (Sub-session A + Sub-session B) make up each 6 hour session. Then repeat.

(I've included some test times to run over 6 minutes instead of 6 hours. To use, remove the --[[ directly above the replacement times and remove the ]]-- directly below them. Put them back or delete the test times to use the 6 hour rotation.

The * shows you are in the 3:56 waiting period.

If this is it then you will have to find a startTime where the first of the 4 minute events starts on a day in your region and replace 1709615040 with that time.

Lua Code:
  1. local addonName, addon = ...
  2. local L, MyRegion
  3. local RegionTimes = {
  4.     [1] = {
  5.         startTime = 1709615040,
  6.         totalDuration = 21600, -- complete session time 6 hours repeating
  7.         A = { -- sub-session -- event runs 3 times
  8.             duration = 7440, -- 2 hours 4 minutes
  9.             interval = 3600, -- runs every 1 hour (56 minutes wait time)
  10.             eventtime = 240, -- 4 minutes run time
  11.         },
  12.         B = { -- sub-session -- just waiting.
  13.             duration = 14160, -- 3 hours 56 minutes
  14.         },
  15.     },
  16. }
  17.  
  18. --[[ TEST TIMES ONLY: over 6 minutes instead of 6 hours ]]--
  19.  
  20. --[[
  21. RegionTimes[1].totalDuration = 360 -- 6 minutes
  22. RegionTimes[1].A.duration = 124 -- 2 minutes 4 seconds
  23. RegionTimes[1].A.interval = 60 -- 1 minute
  24. RegionTimes[1].A.eventtime = 4 -- 4 seconds
  25.  
  26. RegionTimes[1].B.duration = 236 -- 3 minute 56 seconds
  27. ]]--
  28.  
  29. --[[ END TEST TIMES ]]--
  30.  
  31. local Localizations = {
  32.     enUS = {
  33.         Waiting = "|c1C7BCEFFEvent:%s\nbefore the start: %s%s|r",
  34.         Running = "|cFF35BE21Event:%s\n%s%s until completion|r",
  35.     },
  36. }
  37.  
  38. ------------------------------------------------------------------------------------------------------
  39. -- These might be converted to Saved Variables so each character can determine
  40. -- wether or not to play a sound, the alert times and colors and sound to play.
  41. -- If so then most of the code below will have to move into an event handler for
  42. -- the PLAYER_LOGIN or PLAYER_ENTERING_WORLD event.
  43. local defaults = {
  44.     useColor = true,
  45.     useSound = true,
  46.     alert1 = 600, -- Alarm 1 set to 10 minutes before event
  47.     alert1Color = "|cffffff00", -- Yellow
  48.     alert2 = 300, -- Alarm 2 set to 5 minutes before event
  49.     alert2Color = "|cffff0000", -- Red
  50.     soundKit = 32585, -- Alarm sound
  51. }
  52.  
  53. ------------------------------------------------------------------------------------------------------
  54. local function CalcTime(starttime, servertime, duration, interval)
  55.     local timeToEvent = (starttime - servertime) % interval
  56.     local inEvent, timeToRun
  57.     if timeToEvent > (interval - duration) then -- Is there between 1:15 and 1:30 to go? If so, we're in the event
  58.         inEvent = true
  59.         timeToRun = duration - (interval - timeToEvent)
  60.     else                    -- Otherwise, set the timer to time to next event
  61.         inEvent = false
  62.         timeToRun = timeToEvent
  63.     end
  64.     return inEvent, timeToRun
  65. end
  66.  
  67. local function printTime(self)
  68.     local serverTime = GetServerTime()
  69.     -- Calculate remaining time in current cycle
  70.     local remainingTime = (MyRegion.startTime - serverTime) % MyRegion.totalDuration
  71.     local longWait = ""
  72.     local inEvent
  73.     if remainingTime > RegionTimes[1].B.duration then -- in Session A time
  74.     inEvent, remainingTime = CalcTime(MyRegion.startTime, serverTime, MyRegion.A.eventtime, MyRegion.A.interval)
  75.     else -- in Session B time
  76.     longWait = "|cffffff00*|r"
  77.     end
  78.     local hideSeconds = remainingTime >= 120
  79.     local msg = L.Waiting
  80.     local msgColor = "|cffffffff"
  81.     if inEvent then
  82.         msg = L.Running
  83.     else
  84.         if defaults.useColor and remainingTime <= defaults.alert2 then
  85.             msgColor = defaults.alert2Color
  86.         elseif remainingTime <= defaults.alert1 then
  87.             if defaults.useSound and not self.Alerted then
  88.                 self.Alerted = true
  89.                 PlaySound(defaults.soundKit, "Master")
  90.             end
  91.             if defaults.useColor then
  92.                 msgColor = defaults.alert1Color
  93.             end
  94.         end
  95.     end
  96.     self.Text:SetText(format(msg, longWait, msgColor, SecondsToTime(remainingTime, false)))
  97. end
  98.  
  99. ------------------------------------------------------------------------------------------------------
  100. local Backdrop = {
  101.     bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
  102. }
  103.  
  104. local frame_x = 100    
  105. local frame_y = -250    
  106. local f = CreateFrame("Button", "ZAMTimer777", UIParent, "BackdropTemplate")
  107. f:SetWidth(255)                                          
  108. f:SetHeight(30)
  109. f:SetPoint("CENTER")
  110. f:SetBackdrop(Backdrop)
  111. f:SetClampedToScreen(true)
  112. f:EnableMouse(true)
  113. f:SetMovable(true)
  114. f:SetUserPlaced(true)
  115. f:RegisterForDrag("LeftButton")
  116. f:RegisterForClicks("AnyUp")
  117. f.Text = f:CreateFontString(nil, "OVERLAY", "GameTooltipText")
  118. f.Text:SetPoint("CENTER")
  119. f.Elapsed = 0 -- Set starting timeout (0 second)
  120. f:SetScript("OnDragStart",function(self)
  121.     self:StartMoving()
  122. end)
  123. f:SetScript("OnDragStop",function(self)  
  124.     self:StopMovingOrSizing()
  125. end)
  126. f:RegisterEvent("PLAYER_LOGIN")
  127. f:SetScript("OnEvent", function(self)
  128.     local locale = GetLocale()
  129.     L = Localizations[locale] or Localizations.enUS -- Default to enUS if locale doesn't exist in the table
  130.     MyRegion = RegionTimes[GetCurrentRegion()] or RegionTimes[1] -- Default to region 1 (US) if it doesn't exist in the table
  131.     self:SetScript("OnUpdate", function(self, elapsed)
  132.     self.Elapsed = self.Elapsed - elapsed
  133.     if self.Elapsed > 0 then -- Only check once per second
  134.         return
  135.     end
  136.     self.Elapsed = 1 -- reset the timeout (we've counted down 1 second)
  137.     printTime(self)
  138.     end)
  139. end)
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 03-14-24 at 04:33 PM.
  Reply With Quote
03-14-24, 10:01 PM   #18
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
Hello. Thank you very much for your help. Today I will test this code. I wrote to the creator of addon Events tracker, below is the text of his response. Perhaps his answer will help us understand each other. Once again sorry for the inconvenience.



Hm Trial of the Element (event A) is only one event where i don't calculate from weekly restart.

This event i calculate from Storm Fury (event B)




[8] = { name = "Trial of the Elements",

texture = "VignetteLootElite",

eventRegionOffset = { [1] = 1670342460, [2] = 1670698860, [3] = 1674763260, [4] = 1670698860, [5] = 1670677260,},

eventDuration = 600,

eventInterval = 3600,

enable = true,

sound = false,

voice_before = false,

voice_active = false,

anim = true,

questIDs = {71995},

findEventOnMap = {},

coor = {},

datablock = {

[0] = {name = "Trial of the Elements", enable = false, coor = {2085, 27.91, 25.86},},

[1] = {name = "Trial of the Elements", enable = false, coor = {2085, 27.91, 25.86},},

[2] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},},

[3] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},},

[4] = {name = "Trial of the Elements", enable = true, coor = {2085, 27.91, 25.86},}, }, },



In datablock 2x event is disabled, because in this time is Storm Fury active.
Find new active hour :


local index = math.floor(((timeFromFirstStart + (not isEventActive and DefaultConfig.events[self.index].eventInterval or 0)) / DefaultConfig.events[self.index].eventInterval) % (#DefaultConfig.events[self.index].datablock + 1));



By this function i find correct time (if next event is FALSE + evetTime)

index = FindNextEventInDataBlock(self, index)



local function FindNextEventInDataBlock(self, index)

for i = 0, #DefaultConfig.events[self.index].datablock do

if not DefaultConfig.events[self.index].datablock[index].enable then

self.timeTmp = (self.timeTmp or 0) + DefaultConfig.events[self.index].eventInterval;

else return index

end

index = index == #DefaultConfig.events[self.index].datablock and 0 or (index + 1);

end

return index

end

Last edited by Hubb777 : 03-14-24 at 10:03 PM.
  Reply With Quote
03-14-24, 11:02 PM   #19
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
If Trial of the Element is what you are wanting to track, then why not use the addon and remove the entries for all the other events (or disable them) instead of trying to re-invent the wheel?
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.
  Reply With Quote
03-15-24, 11:01 PM   #20
Hubb777
A Flamescale Wyrmkin
 
Hubb777's Avatar
AddOn Author - Click to view addons
Join Date: Jan 2024
Posts: 111
Originally Posted by Fizzlemizz View Post
If Trial of the Element is what you are wanting to track, then why not use the addon and remove the entries for all the other events (or disable them) instead of trying to re-invent the wheel?
Hi, your code works. Thank you very much. I finished testing it, there were difficulties with the duration, but I managed to set the correct values.


“Reinventing the wheel” - in some ways you are right. But the Events tracker addon is quite technically complicated for me to understand. And if the author abandons it, then I will be left without the functionality I need.

I'll tell you a little story. I've been using the ChatBar addon for a long time. But with the release of the Shadowlands update. The author of the addon stopped playing Warcraft and stopped updating the addon. And the addon broke. I have been supporting the addon for more than 2 years, updating it, fixing it. This was within my power because this addon is very simple. With the release of Dragonflight, the author returned and began updating the addon again.

The addon was simple and I was able to fix it, if it had been folded like an Events tracker, I would have abandoned these attempts and ChatBar, like hundreds of other addons, would have remained in history.

Therefore, I have to “reinvent the wheel” so as not to lose the functionality that I need.
  Reply With Quote

WoWInterface » AddOns, Compilations, Macros » AddOn Help/Support » Timer with 2 variables


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off