--[[ Element: Cast Bar THIS FILE HEAVILY MODIFIED FOR USE WITH SUPERVILLAIN UI ]] local parent, ns = ... local oUF = ns.oUF local SuperVillain = SVUI[1] local updateSafeZone = function(self) local sz = self.SafeZone local width = self:GetWidth() local _, _, _, ms = GetNetStats() -- Guard against GetNetStats returning latencies of 0. if(ms ~= 0) then -- MADNESS! local safeZonePercent = (width / self.max) * (ms / 1e5) if(safeZonePercent > 1) then safeZonePercent = 1 end sz:SetWidth(width * safeZonePercent) sz:Show() else sz:Hide() end end local UNIT_SPELLCAST_SENT = function (self, event, unit, spell, rank, target) local castbar = self.Castbar castbar.curTarget = (target and target ~= "") and target or nil end local UNIT_SPELLCAST_START = function(self, event, unit, spell) if(self.unit ~= unit) or not unit then return end local castbar = self.Castbar local name, _, text, texture, startTime, endTime, tradeskill, castid, interrupt = UnitCastingInfo(unit) if(not name) then castbar:Hide() return end endTime = endTime / 1e3 startTime = startTime / 1e3 local repeatCount = GetTradeskillRepeatCount() or 1 local start = GetTime() - startTime if(tradeskill) then if(castbar.previous ~= name) then castbar.recipecount = 1 castbar.maxrecipe = GetTradeskillRepeatCount() castbar.duration = start else castbar.recipecount = castbar.recipecount or 1 castbar.maxrecipe = castbar.maxrecipe or repeatCount castbar.duration = castbar.duration or start end else castbar.recipecount = nil castbar.maxrecipe = 1 castbar.duration = start end castbar.previous = name castbar.tradeskill = tradeskill castbar.castid = castid local max = (endTime - startTime) * castbar.maxrecipe castbar.max = max castbar.delay = 0 castbar.casting = true castbar.interrupt = interrupt castbar:SetMinMaxValues(0, max) castbar:SetValue(0) if(castbar.Text) then castbar.Text:SetText(text) end if(castbar.Icon) then castbar.Icon:SetTexture(texture) end if(castbar.Time) then castbar.Time:SetText() end local shield = castbar.Shield if(shield and interrupt) then shield:Show() elseif(shield) then shield:Hide() end local sf = castbar.SafeZone if(sf) then sf:ClearAllPoints() sf:SetPoint'RIGHT' sf:SetPoint'TOP' sf:SetPoint'BOTTOM' updateSafeZone(castbar) end if(castbar.PostCastStart) then castbar:PostCastStart(unit, name, castid) end --castbar:Show() SuperVillain:SecureFadeIn(castbar, 0.5, 0.5, 1) end local UNIT_SPELLCAST_FAILED = function(self, event, unit, spellname, _, castid) if (self.unit ~= unit) or not unit then return end local castbar = self.Castbar if (castbar.castid ~= castid) then return end castbar.previous = nil castbar.casting = nil castbar.tradeskill = nil castbar.recipecount = nil castbar.maxrecipe = nil castbar.interrupt = nil castbar:SetValue(0) castbar:Hide() if(castbar.PostCastFailed) then return castbar:PostCastFailed(unit, spellname, castid) end end local UNIT_SPELLCAST_INTERRUPTED = function(self, event, unit, spellname, _, castid) if(self.unit ~= unit) or not unit then return end local castbar = self.Castbar if (castbar.castid ~= castid) then return end castbar.previous = nil castbar.casting = nil castbar.tradeskill = nil castbar.recipecount = nil castbar.maxrecipe = nil castbar.channeling = nil castbar:SetValue(0) castbar:Hide() if(castbar.PostCastInterrupted) then return castbar:PostCastInterrupted(unit, spellname, castid) end end local UNIT_SPELLCAST_INTERRUPTIBLE = function(self, event, unit) if(self.unit ~= unit) or not unit then return end local shield = self.Castbar.Shield if(shield) then shield:Hide() end local castbar = self.Castbar if(castbar.PostCastInterruptible) then return castbar:PostCastInterruptible(unit) end end local UNIT_SPELLCAST_NOT_INTERRUPTIBLE = function(self, event, unit) if(self.unit ~= unit) or not unit then return end local shield = self.Castbar.Shield if(shield) then shield:Show() end local castbar = self.Castbar if(castbar.PostCastNotInterruptible) then return castbar:PostCastNotInterruptible(unit) end end local UNIT_SPELLCAST_DELAYED = function(self, event, unit, spellname, _, castid) if(self.unit ~= unit) or not unit then return end local castbar = self.Castbar local name, _, text, texture, startTime, endTime = UnitCastingInfo(unit) if(not startTime or not castbar:IsShown()) then return end local duration = GetTime() - (startTime / 1000) if(duration < 0) then duration = 0 end castbar.previous = name castbar.delay = castbar.delay + castbar.duration - duration castbar.duration = duration castbar:SetValue(duration) if(castbar.PostCastDelayed) then return castbar:PostCastDelayed(unit, name, castid) end end local UNIT_SPELLCAST_STOP = function(self, event, unit, spellname, _, castid) if (self.unit ~= unit) or not unit then return end local castbar = self.Castbar if (castbar.castid ~= castid) then return end if(castbar.tradeskill and castbar.recipecount and castbar.recipecount >= 0) then castbar.recipecount = castbar.recipecount + 1 else castbar.previous = nil castbar.casting = nil castbar.interrupt = nil castbar.tradeskill = nil castbar.recipecount = nil castbar.maxrecipe = nil castbar:SetValue(0) end SuperVillain:SecureFadeOut(castbar, 4, 1, 0, true) if(castbar.PostCastStop) then return castbar:PostCastStop(unit, spellname, castid) end end local UNIT_SPELLCAST_CHANNEL_START = function(self, event, unit, spellname) if (self.unit ~= unit) or not unit then return end local castbar = self.Castbar local name, _, text, texture, startTime, endTime, isTrade, interrupt = UnitChannelInfo(unit) if (not name) then return end endTime = endTime / 1e3 startTime = startTime / 1e3 local max = (endTime - startTime) local duration = endTime - GetTime() castbar.previous = name castbar.duration = duration castbar.max = max castbar.delay = 0 castbar.startTime = startTime castbar.endTime = endTime castbar.extraTickRatio = 0 castbar.channeling = true castbar.interrupt = interrupt -- We have to do this, as it's possible for spell casts to never have _STOP -- executed or be fully completed by the OnUpdate handler before CHANNEL_START -- is called. castbar.casting = nil castbar.tradeskill = nil castbar.recipecount = nil castbar.maxrecipe = nil castbar.castid = nil castbar:SetMinMaxValues(0, max) castbar:SetValue(duration) if(castbar.Text) then castbar.Text:SetText(name) end if(castbar.Icon) then castbar.Icon:SetTexture(texture) end if(castbar.Time) then castbar.Time:SetText() end local shield = castbar.Shield if(shield and interrupt) then shield:Show() elseif(shield) then shield:Hide() end local sf = castbar.SafeZone if(sf) then sf:ClearAllPoints() sf:SetPoint'LEFT' sf:SetPoint'TOP' sf:SetPoint'BOTTOM' updateSafeZone(castbar) end if(castbar.PostChannelStart) then castbar:PostChannelStart(unit, name) end --castbar:Show() SuperVillain:SecureFadeIn(castbar, 0.2, 0, 1) end local UNIT_SPELLCAST_CHANNEL_UPDATE = function(self, event, unit, spellname) if(self.unit ~= unit) or not unit then return end local castbar = self.Castbar local name, _, text, texture, startTime, endTime, oldStart = UnitChannelInfo(unit) if(not name or not castbar:IsShown()) then return end castbar.previous = name local duration = (endTime / 1000) - GetTime() local startDelay = castbar.startTime - startTime / 1000 castbar.startTime = startTime / 1000 castbar.endTime = endTime / 1000 castbar.delay = castbar.delay + startDelay castbar.duration = duration castbar.max = (endTime - startTime) / 1000 castbar:SetMinMaxValues(0, castbar.max) castbar:SetValue(duration) if(castbar.PostChannelUpdate) then return castbar:PostChannelUpdate(unit, name) end end local UNIT_SPELLCAST_CHANNEL_STOP = function(self, event, unit, spellname) if(self.unit ~= unit) or not unit then return end local castbar = self.Castbar if(castbar:IsShown()) then castbar.channeling = nil castbar.interrupt = nil castbar:SetValue(castbar.max) castbar:Hide() if(castbar.PostChannelStop) then return castbar:PostChannelStop(unit, spellname) end end end local UpdateCastingTimeInfo = function(self, duration) if(self.Time) then if(self.delay ~= 0) then if(self.CustomDelayText) then self:CustomDelayText(duration) else self.Time:SetFormattedText("%.1f|cffff0000-%.1f|r", duration, self.delay) end elseif(self.recipecount and self.recipecount > 0) then self.Time:SetText(self.recipecount .. "/" .. self.maxrecipe) else if(self.CustomTimeText) then self:CustomTimeText(duration) else self.Time:SetFormattedText("%.1f", duration) end end end if(self.Spark) then self.Spark:SetPoint("CENTER", self, "LEFT", (duration / self.max) * self:GetWidth(), 0) end end local onUpdate = function(self, elapsed) self.lastUpdate = (self.lastUpdate or 0) + elapsed if not (self.casting or self.channeling) then self.unitName = nil self.previous = nil self.casting = nil self.tradeskill = nil self.recipecount = nil self.maxrecipe = nil self.castid = nil self.channeling = nil self:SetValue(1) self:Hide() return end if(self.casting) then local duration = self.duration + self.lastUpdate if(duration >= self.max) then self.previous = nil self.casting = nil self.tradeskill = nil self.recipecount = nil self.maxrecipe = nil self:Hide() if(self.PostCastStop) then self:PostCastStop(self.__owner.unit) end return end UpdateCastingTimeInfo(self, duration) self.duration = duration self:SetValue(duration) elseif(self.channeling) then local duration = self.duration - self.lastUpdate if(duration <= 0) then self.channeling = nil self:Hide() if(self.PostChannelStop) then self:PostChannelStop(self.__owner.unit) end return end UpdateCastingTimeInfo(self, duration) self.duration = duration self:SetValue(duration) end self.lastUpdate = 0 end local Update = function(self, ...) UNIT_SPELLCAST_START(self, ...) return UNIT_SPELLCAST_CHANNEL_START(self, ...) end local ForceUpdate = function(element) return Update(element.__owner, 'ForceUpdate', element.__owner.unit) end local Enable = function(object, unit) local castbar = object.Castbar if(castbar) then castbar.__owner = object castbar.ForceUpdate = ForceUpdate if(not (unit and unit:match'%wtarget$')) then object:RegisterEvent("UNIT_SPELLCAST_SENT", UNIT_SPELLCAST_SENT) object:RegisterEvent("UNIT_SPELLCAST_START", UNIT_SPELLCAST_START) object:RegisterEvent("UNIT_SPELLCAST_FAILED", UNIT_SPELLCAST_FAILED) object:RegisterEvent("UNIT_SPELLCAST_STOP", UNIT_SPELLCAST_STOP) object:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED", UNIT_SPELLCAST_INTERRUPTED) object:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE", UNIT_SPELLCAST_INTERRUPTIBLE) object:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", UNIT_SPELLCAST_NOT_INTERRUPTIBLE) object:RegisterEvent("UNIT_SPELLCAST_DELAYED", UNIT_SPELLCAST_DELAYED) object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START", UNIT_SPELLCAST_CHANNEL_START) object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", UNIT_SPELLCAST_CHANNEL_UPDATE) object:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP", UNIT_SPELLCAST_CHANNEL_STOP) --object:RegisterEvent("UPDATE_TRADESKILL_RECAST", UPDATE_TRADESKILL_RECAST) end castbar:SetScript("OnUpdate", castbar.OnUpdate or onUpdate) if(object.unit == "player") then CastingBarFrame:UnregisterAllEvents() CastingBarFrame.Show = CastingBarFrame.Hide CastingBarFrame:Hide() elseif(object.unit == 'pet') then PetCastingBarFrame:UnregisterAllEvents() PetCastingBarFrame.Show = PetCastingBarFrame.Hide PetCastingBarFrame:Hide() end if(castbar:IsObjectType'StatusBar' and not castbar:GetStatusBarTexture()) then castbar:SetStatusBarTexture[[Interface\TargetingFrame\UI-StatusBar]] end local spark = castbar.Spark if(spark and spark:IsObjectType'Texture' and not spark:GetTexture()) then spark:SetTexture[[Interface\CastingBar\UI-CastingBar-Spark]] end local shield = castbar.Shield if(shield and shield:IsObjectType'Texture' and not shield:GetTexture()) then shield:SetTexture[[Interface\CastingBar\UI-CastingBar-Small-Shield]] end local sz = castbar.SafeZone if(sz and sz:IsObjectType'Texture' and not sz:GetTexture()) then sz:SetTexture(1, 0, 0) end castbar:Hide() return true end end local Disable = function(object, unit) local castbar = object.Castbar if(castbar) then object:UnregisterEvent("UNIT_SPELLCAST_SENT", UNIT_SPELLCAST_SENT) object:UnregisterEvent("UNIT_SPELLCAST_START", UNIT_SPELLCAST_START) object:UnregisterEvent("UNIT_SPELLCAST_FAILED", UNIT_SPELLCAST_FAILED) object:UnregisterEvent("UNIT_SPELLCAST_STOP", UNIT_SPELLCAST_STOP) object:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTED", UNIT_SPELLCAST_INTERRUPTED) object:UnregisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE", UNIT_SPELLCAST_INTERRUPTIBLE) object:UnregisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE", UNIT_SPELLCAST_NOT_INTERRUPTIBLE) object:UnregisterEvent("UNIT_SPELLCAST_DELAYED", UNIT_SPELLCAST_DELAYED) object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_START", UNIT_SPELLCAST_CHANNEL_START) object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE", UNIT_SPELLCAST_CHANNEL_UPDATE) object:UnregisterEvent("UNIT_SPELLCAST_CHANNEL_STOP", UNIT_SPELLCAST_CHANNEL_STOP) --object:UnregisterEvent("UPDATE_TRADESKILL_RECAST", UPDATE_TRADESKILL_RECAST) castbar:SetScript("OnUpdate", nil) end end oUF:AddElement('Castbar', Update, Enable, Disable)