Hourglass = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceDB-2.0", "AceConsole-2.0", "CandyBar-2.0") local Gratuity = AceLibrary("Gratuity-2.0") local CandyBar = AceLibrary("CandyBar-2.0") local Dewdrop = AceLibrary("Dewdrop-2.0") local SharedMedia = AceLibrary("SharedMedia-1.0") local anchor = nil local options = { type = "group", args = { anchor = { order = 1, type = "toggle", name = "Show anchor", desc = "Show the bar anchor frame.", get = function() return anchor and anchor:IsShown() end, set = function(v) Hourglass:ToggleAnchor(v) end, }, min = { type = "text", name = "Minimum duration", desc = "Miniumum cooldown duration to display.", usage = "", get = function () return Hourglass.db.profile.min end, set = function (v) Hourglass.db.profile.min = tonumber(v) end, }, max = { type = "text", name = "Maximum duration", desc = "Maximum cooldown duration to display.", usage = "", get = function () return Hourglass.db.profile.max end, set = function (v) Hourglass.db.profile.max = tonumber(v) end, }, growth = { type = "toggle", name = "Grow upwards", desc = "Toggle bars grow upwards/downwards from anchor.", get = function () return Hourglass.db.profile.growth end, set = function (v) Hourglass.db.profile.growth = v Hourglass:SetCandyBarGroupGrowth("Hourglass", Hourglass.db.profile.growth) end, }, texture = { type = "text", name = "Texture", desc = "Set the texture for the timer bars.", get = function () return Hourglass.db.profile.texture end, set = function (v) Hourglass.db.profile.texture = v for key, barId in ipairs(CandyBar.groups["Hourglass"].bars) do Hourglass:SetCandyBarTexture(barId, SharedMedia:Fetch("statusbar", Hourglass.db.profile.texture)) end end, validate = SharedMedia:List("statusbar"), }, announce = { type = "toggle", name = "Announce (SCT/MSBT)", desc = "Announce cooldown expiry as SCT/MSBT Message.", get = function () return Hourglass.db.profile.announce end, set = function (v) Hourglass.db.profile.announce = v end, }, } } local select = select local pairs = pairs local spells = {} local petspells = {} local items = {} local itemSlots = {"Trinket0Slot", "Trinket1Slot"} local groupedCooldowns = { -- [" Trap$"] = "Traps", } local chainedCooldowns = { ["Cold Snap"] = {"Cone of Cold", "Frost Nova", "Frost Ward", "Ice Barrier", "Ice Block", "Summon Water Elemental"}, ["Preparation"] = {"Cold Blood", "Distract", "Evasion", "Feint", "Gouge", "Kick", "Kidney Shot", "Sprint", "Vanish"}, ["Readiness"] = {"Intimidation", "Kill Command", "Scare Beast", "Aimed Shot", "Arcane Shot", "Concussive Shot", "Distracting Shot", "Flare", "Multi-Shot", "Rapid Fire", "Tranquilizing Shot", "Viper Sting", "Volley", "Counterattack", "Deterrence", "Disengage", "Explosive Trap", "Feign Death", "Freezing Trap", "Frost Trap", "Immolation Trap", "Misdirection", "Mongoose Bite", "Raptor Strike", "Snake Trap", "Wyvern Sting"}, } function Hourglass:OnInitialize() local defaults = { min = 2.5, max = 3600, growth = true, texture = "default", x = nil, y = nil, announce = true, } self:RegisterDB("HourglassDB") self:RegisterDefaults("profile", defaults) self:RegisterChatCommand("/hourglass", {type = "execute", func = "ShowOptions"}) Dewdrop:Register("Hourglass", "children", options, "cursorX", true, "cursorY", true) self:CreateAnchor() self:RegisterCandyBarGroup("Hourglass") self:SetCandyBarGroupPoint("Hourglass", "TOP", anchor, "BOTTOM", 0, 0) self:SetCandyBarGroupGrowth("Hourglass", self.db.profile.growth) end function Hourglass:OnEnable() self:RegisterEvent("SPELLS_CHANGED") self:RegisterEvent("PLAYER_ENTERING_WORLD") self:RegisterEvent("SPELL_UPDATE_COOLDOWN") self:RegisterEvent("PET_BAR_UPDATE_COOLDOWN") self:RegisterEvent("ZONE_CHANGED_NEW_AREA") self:RegisterEvent("BAG_UPDATE_COOLDOWN") self:RegisterEvent("UNIT_INVENTORY_CHANGED") end function Hourglass:SPELLS_CHANGED() self:ScanSpells() self:ScanPetSpells() end function Hourglass:PLAYER_ENTERING_WORLD() self:ScanSpells() self:ScanPetSpells() self:ScanItems() end function Hourglass:SPELL_UPDATE_COOLDOWN() for spellName, data in pairs(spells) do local startTime, duration, enable = GetSpellCooldown(data.id, BOOKTYPE_SPELL) if enable == 1 and duration > self.db.profile.min and duration <= self.db.profile.max and data.startTime ~= startTime then data.startTime = startTime self:StartBar(spellName, data, duration) end end end function Hourglass:PET_BAR_UPDATE_COOLDOWN() for spellName, data in pairs(petspells) do local startTime, duration, enable = GetSpellCooldown(data.id, BOOKTYPE_PET) if enable == 1 and duration > self.db.profile.min and duration <= self.db.profile.max and data.startTime ~= startTime then data.startTime = startTime self:StartBar(spellName, data, duration) end end end function Hourglass:UNIT_SPELLCAST_SUCCEEDED(unit, spellName) if unit == "player" and chainedCooldowns[spellName] then for _, chainedSpellName in pairs(chainedCooldowns[spellName]) do self:StopCandyBar(self:GetBarId(chainedSpellName)) self:CancelScheduledEvent(self:GetBarId(chainedSpellName)) end end end function Hourglass:ZONE_CHANGED_NEW_AREA() local zone = GetRealZoneText() if zone == nil or zone == "" then self:ScheduleEvent(self.ZONE_CHANGED_NEW_AREA, 5, self) elseif strfind(zone, "Arena") then for key, barId in ipairs(CandyBar.groups["Hourglass"].bars) do if CandyBar.handlers[barId].time <= 600 then self:StopCandyBar(barId) self:CancelScheduledEvent(barId) end end end end function Hourglass:UNIT_INVENTORY_CHANGED(unit) if unit == "player" then self:ScanItems() end end function Hourglass:BAG_UPDATE_COOLDOWN(container) self:ScanItems() end function Hourglass:ScanSpells() local i = 1 local spellName = GetSpellName(i, BOOKTYPE_SPELL) local previousSpellName while spellName do if spellName ~= previousSpellName then for pattern, replacement in pairs(groupedCooldowns) do if (string.find(spellName, pattern)) then spellName = replacement break end end Gratuity:SetSpell(i, BOOKTYPE_SPELL) if Gratuity:Find("cooldown", 2, 3, true) then spells[spellName] = { id = i, icon = GetSpellTexture(i, BOOKTYPE_SPELL), startTime = 0, } if chainedCooldowns[spellName] then self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED") end end end i = i + 1 previousSpellName = spellName spellName = GetSpellName(i, BOOKTYPE_SPELL) end self:SPELL_UPDATE_COOLDOWN() end function Hourglass:ScanPetSpells() local i = 1 local spellName = GetSpellName(i, BOOKTYPE_PET) local previousSpellName while spellName do if spellName ~= previousSpellName then Gratuity:SetSpell(i, BOOKTYPE_PET) if Gratuity:Find("cooldown", 2, 3, true) then petspells[spellName] = { id = i, icon = GetSpellTexture(i, BOOKTYPE_PET), startTime = 0, } end end i = i + 1 previousSpellName = spellName spellName = GetSpellName(i, BOOKTYPE_PET) end self:PET_BAR_UPDATE_COOLDOWN() end function Hourglass:ScanItems() for _, slotName in pairs(itemSlots) do local slotId = GetInventorySlotInfo(slotName) local startTime, duration, enable = GetInventoryItemCooldown("player", slotId) if enable == 1 and duration > self.db.profile.min and duration <= self.db.profile.max then local name = select(3, GetInventoryItemLink("player", slotId):find("Hitem[^|]+|h%[([^[]+)%]")) if items[slotName] and items[slotName].name ~= name then self:StopCandyBar(self:GetBarId(slotName)) self:CancelScheduledEvent(self:GetBarId(slotName)) items[slotName] = nil end if not items[slotName] then items[slotName] = { name = name, icon = GetInventoryItemTexture("player", slotId) } end if items[slotName].startTime ~= startTime then items[slotName].startTime = startTime; self:StartBar(slotName, items[slotName], duration) end elseif items[slotName] then self:StopCandyBar(self:GetBarId(slotName)) self:CancelScheduledEvent(self:GetBarId(slotName)) items[slotName] = nil end end end function Hourglass:StartBar(name, data, duration) local barId = self:GetBarId(name) local timeLeft = duration - (GetTime() - data.startTime) self:RegisterCandyBar(barId, duration, data.name and data.name or name, data.icon, "Green", "Orange", "Red") self:RegisterCandyBarWithGroup(barId, "Hourglass") self:SetCandyBarTexture(barId, SharedMedia:Fetch("statusbar", self.db.profile.texture)) self:SetCandyBarFade(barId, 1) self:SetCandyBarTimeLeft(barId, timeLeft) self:StartCandyBar(barId, true) if self.db.profile.announce then self:ScheduleEvent("Hourglass"..name, self.Message, timeLeft, self, data.name and data.name or name) end end function Hourglass:Message(name) if (SCT and SCT.DisplayText) then SCT:DisplayMessage( name.." Ready!", { r=1, g=0, b=0 } ) elseif (MikSBT) then MikSBT.DisplayMessage( name.." Ready!", MikSBT.DISPLAYTYPE_NOTIFICATION, false, 255, 0, 0 ) end end function Hourglass:GetBarId(name) return "Hourglass" .. name end function Hourglass:ShowOptions() Dewdrop:Open("Hourglass") end function Hourglass:CreateAnchor() anchor = CreateFrame("Button", "HourglassFrame", UIParent) anchor:Hide() anchor:SetWidth(200) anchor:SetHeight(16) anchor:SetBackdrop({bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", tile = true, tileSize = 16}) anchor:SetBackdropColor(0.3, 0.3, 0.3, 0.7) anchor:SetMovable(true) anchor:RegisterForDrag("LeftButton") anchor:RegisterForClicks("RightButtonUp") anchor:SetScript("OnClick", function (this) self:ShowOptions() end) anchor:SetScript("OnDragStart", function(this) this:StartMoving() end) anchor:SetScript("OnDragStop", function(this) this:StopMovingOrSizing() self.db.profile.x = this:GetLeft() self.db.profile.y = this:GetTop() -- self:SetCandyBarGroupPoint("Hourglass", "TOPLEFT", UIParent, "BOTTOMLEFT", self.db.profile.x, self.db.profile.y) end) anchor:SetFont(GameFontHighlightSmall:GetFont(), 10) anchor:SetText("Hourglass") if not self.db.profile.x then anchor:SetPoint("CENTER", UIParent, "CENTER", 0, -200) else anchor:ClearAllPoints() anchor:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", self.db.profile.x, self.db.profile.y) end end function Hourglass:ToggleAnchor(show) if show then Dewdrop:Close() anchor:Show() else anchor:Hide() end end