diff --git a/libs/libcast.lua b/libs/libcast.lua new file mode 100644 index 00000000..8741bb01 --- /dev/null +++ b/libs/libcast.lua @@ -0,0 +1,301 @@ +-- load pfUI environment +setfenv(1, pfUI:GetEnvironment()) + +--[[ libcast ]]-- +-- A pfUI library that detects and saves all ongoing castbars of players, NPCs and enemies. +-- This also includes spells that usually don't have a castbar like Multi-Shot and Aimed Shot. +-- +-- libcast:GetCastInfo(unit) +-- Returns all ongoing casts of a unit (name) +-- cast, start, casttime, icon, delay, channel +-- +-- libcast:RegisterEventFunc(func, frame) +-- Triggers the given function `func` with `frame` as arg1, +-- whenever a new cast-event was detected +-- +-- libcast:TriggerEvents() +-- Triggers all registered event functions. +-- +-- libcast:AddAction(mob, spell, channel) +-- Adds a spell to the database by using pfUI's spell database +-- to obtain durations and icons +-- +-- libcast:RemoveAction(mob, spell) +-- Removes the castbar of a given mob, if `spell` is an interrupt. +-- spell can be set to "INTERRUPT" to force remove an action. +-- + +local libcast = CreateFrame("Frame", "pfEnemyCast") + +function libcast:GetCastInfo(unit) + local db = self.db[unit] + + -- clean legacy values + if db and db.start + db.delay + db.casttime / 1000 > GetTime() then + return db.cast, db.start, db.casttime, db.icon, db.delay, db.channel + elseif db then + self.db[unit] = nil + end + + return nil, 0, 0, "", 0, nil +end + +function libcast:RegisterEventFunc(func, frame) + table.insert(self.frames, { func, frame }) +end + +function libcast:TriggerEvents() + for id, ft in pairs(self.frames) do ft[1](ft[2]) end +end + +function libcast:AddAction(mob, spell, channel) + if L["spells"][spell] ~= nil then + local casttime = L["spells"][spell].t + local icon = L["spells"][spell].icon + self.db[mob] = {cast = spell, start = GetTime(), casttime = casttime, icon = icon, delay = 0, channel = channel} + self:TriggerEvents() + end +end + +function libcast:RemoveAction(mob, spell) + if self.db[mob] and ( L["interrupts"][spell] ~= nil or spell == "INTERRUPT" ) then + self.db[mob] = nil + self:TriggerEvents() + end +end + +-- Combatlog parser strings +libcast.SPELL_CAST = SanitizePattern(SPELLCASTOTHERSTART) +libcast.SPELL_PERFORM = SanitizePattern(SPELLPERFORMOTHERSTART) +libcast.SPELL_GAINS = SanitizePattern(AURAADDEDOTHERHELPFUL) +libcast.SPELL_AFFLICTED = SanitizePattern(AURAADDEDOTHERHARMFUL) +libcast.SPELL_HIT = SanitizePattern(SPELLLOGSELFOTHER) +libcast.SPELL_CRIT = SanitizePattern(SPELLLOGCRITSELFOTHER) +libcast.OTHER_SPELL_HIT = SanitizePattern(SPELLLOGOTHEROTHER) +libcast.OTHER_SPELL_CRIT = SanitizePattern(SPELLLOGCRITOTHEROTHER) +libcast.SPELL_INTERRUPT = SanitizePattern(SPELLINTERRUPTSELFOTHER) +libcast.OTHER_SPELL_INTERRUPT = SanitizePattern(SPELLINTERRUPTOTHEROTHER) + +-- main data +libcast.db = {} +libcast.frames = {} + +-- environmental casts +libcast:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF") +libcast:RegisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_PARTY_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_PARTY_BUFF") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS") +libcast:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE") +libcast:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF") + +-- player spells +libcast:RegisterEvent("SPELLCAST_START") +libcast:RegisterEvent("SPELLCAST_STOP") +libcast:RegisterEvent("SPELLCAST_FAILED") +libcast:RegisterEvent("SPELLCAST_INTERRUPTED") +libcast:RegisterEvent("SPELLCAST_DELAYED") +libcast:RegisterEvent("SPELLCAST_CHANNEL_START") +libcast:RegisterEvent("SPELLCAST_CHANNEL_STOP") +libcast:RegisterEvent("SPELLCAST_CHANNEL_UPDATE") +libcast:RegisterEvent("PLAYER_TARGET_CHANGED") + +libcast:SetScript("OnEvent", function() + local player = UnitName("player") + + -- Fill database with player casts + if event == "PLAYER_TARGET_CHANGED" then + this:TriggerEvents() + elseif event == "SPELLCAST_START" then + this.db[player] = {cast = arg1, start = GetTime(), casttime = arg2, icon = nil, channel = nil, delay = 0} + this:TriggerEvents() + elseif event == "SPELLCAST_STOP" or event == "SPELLCAST_FAILED" or event == "SPELLCAST_INTERRUPTED" then + if this.db[player] and not this.db[player].channel then + this.db[player] = nil + this:TriggerEvents() + end + elseif ( event == "SPELLCAST_DELAYED" ) then + if this.db[player] then + this.db[player].delay = this.db[player].delay + arg1/1000 + this:TriggerEvents() + end + elseif ( event == "SPELLCAST_CHANNEL_START" ) then + this.db[player] = {cast = arg2, start = GetTime(), casttime = arg1, icon = nil, channel = true, delay = 0} + this:TriggerEvents() + elseif event == "SPELLCAST_CHANNEL_STOP" then + if this.db[player] and this.db[player].channel then + this.db[player] = nil + this:TriggerEvents() + end + elseif ( event == "SPELLCAST_CHANNEL_UPDATE" ) then + this.db[player].delay = this.db[player].delay + this.db[player].casttime / 1000 - this.db[player].delay + this.db[player].start - GetTime() - arg1 / 1000 + + -- Fill database with environmental casts + elseif arg1 then + -- (.+) begins to cast (.+). + for mob, spell in string.gfind(arg1, libcast.SPELL_CAST) do + libcast:AddAction(mob, spell) + return + end + + -- (.+) begins to perform (.+). + for mob, spell in string.gfind(arg1, libcast.SPELL_PERFORM) do + libcast:AddAction(mob, spell) + return + end + + -- (.+) gains (.+). + for mob, spell in string.gfind(arg1, libcast.SPELL_GAINS) do + libcast:RemoveAction(mob, spell) + return + end + + -- (.+) is afflicted by (.+). + for mob, spell in string.gfind(arg1, libcast.SPELL_AFFLICTED) do + libcast:RemoveAction(mob, spell) + return + end + + -- Your (.+) hits (.+) for (%d+). + for spell, mob in string.gfind(arg1, libcast.SPELL_HIT) do + libcast:RemoveAction(mob, spell) + return + end + + -- Your (.+) crits (.+) for (%d+). + for spell, mob in string.gfind(arg1, libcast.SPELL_CRIT) do + libcast:RemoveAction(mob, spell) + return + end + + -- (.+)'s (.+) %a hits (.+) for (%d+). + for _, spell, mob in string.gfind(arg1, libcast.OTHER_SPELL_HIT) do + libcast:RemoveAction(mob, spell) + return + end + + -- (.+)'s (.+) %a crits (.+) for (%d+). + for _, spell, mob in string.gfind(arg1, libcast.OTHER_SPELL_CRIT) do + libcast:RemoveAction(mob, spell) + return + end + + -- You interrupt (.+)'s (.+)."; + for mob, spell in string.gfind(arg1, libcast.SPELL_INTERRUPT) do + libcast:RemoveAction(mob, "INTERRUPT") + return + end + + -- (.+) interrupts (.+)'s (.+). + for _, mob, spell in string.gfind(arg1, libcast.OTHER_SPELL_INTERRUPT) do + libcast:RemoveAction(mob, "INTERRUPT") + return + end + end +end) + +--[[ Custom Casts + Enable Castbars for spells that don't have a castbar by default + (e.g Multi-Shot and Aimed Shot) +]]-- +local aimedshot = L["customcast"]["AIMEDSHOT"] +local multishot = L["customcast"]["MULTISHOT"] + +libcast.customcast = {} +libcast.customcast[strlower(aimedshot)] = function(begin) + if begin then + local duration = 3000 + + for i=1,32 do + if UnitBuff("player", i) == "Interface\\Icons\\Racial_Troll_Berserk" then + local berserk = 0.3 + if((UnitHealth("player")/UnitHealthMax("player")) >= 0.40) then + berserk = (1.30 - (UnitHealth("player") / UnitHealthMax("player"))) / 3 + end + duration = duration / (1 + berserk) + elseif UnitBuff("player", i) == "Interface\\Icons\\Ability_Hunter_RunningShot" then + duration = duration / 1.4 + elseif UnitBuff("player", i) == "Interface\\Icons\\Ability_Warrior_InnerRage" then + duration = duration / 1.3 + elseif UnitBuff("player", i) == "Interface\\Icons\\Inv_Trinket_Naxxramas04" then + duration = duration / 1.2 + elseif UnitDebuff("player", i) == "Interface\\Icons\\Spell_Shadow_CurseOfTounges" then + duration = duration / 0.5 + end + end + + local _,_, lag = GetNetStats() + local start = GetTime() + lag/1000 + + libcast.db[UnitName("player")] = {cast = aimedshot, start = start, casttime = duration, icon = icon, delay = 0, channel = nil} + libcast:TriggerEvents() + else + libcast.db[UnitName("player")] = nil + libcast:TriggerEvents() + end +end + +libcast.customcast[strlower(multishot)] = function(begin) + if begin then + local duration = 500 + local _,_, lag = GetNetStats() + local start = GetTime() + lag/1000 + + libcast.db[UnitName("player")] = {cast = multishot, start = start, casttime = duration, icon = icon, delay = 0, channel = nil} + libcast:TriggerEvents() + else + libcast.db[UnitName("player")] = nil + libcast:TriggerEvents() + end +end + +local function CastCustom(spell) + if not libcast:GetCastInfo(UnitName("player")) then + for custom, func in pairs(libcast.customcast) do + if strfind(strlower(spell), custom) or strlower(spell) == custom then + func(true) + end + end + end +end + +hooksecurefunc("CastSpell", function(id, bookType) + if GetSpellCooldown(id, bookType) ~= 0 then + local spellName = GetSpellName(id, bookType) + CastCustom(spellName) + end +end, true) + +hooksecurefunc("CastSpellByName", function(spellName, target) + for i=1,120 do + -- detect if any cast is ongoing + if IsCurrentAction(i) then + CastCustom(spellName) + return + end + end +end, true) + +local scanner = CreateFrame("GameTooltip", "pfSpellScanner", nil, "GameTooltipTemplate") +scanner:SetOwner(WorldFrame, "ANCHOR_NONE") +hooksecurefunc("UseAction", function(slot, target, button) + if GetActionText(slot) or not IsCurrentAction(slot) then return end + scanner:ClearLines() + scanner:SetAction(slot) + local spellName = pfSpellScannerTextLeft1:GetText() + CastCustom(spellName) +end, true) + +-- add libcast to pfUI API +pfUI.api.libcast = libcast diff --git a/modules/castbar.lua b/modules/castbar.lua index dfa3e820..7bc6cd5a 100644 --- a/modules/castbar.lua +++ b/modules/castbar.lua @@ -1,5 +1,4 @@ pfUI:RegisterModule("castbar", function () - local font = C.castbar.use_unitfonts == "1" and pfUI.font_unit or pfUI.font_default local font_size = C.castbar.use_unitfonts == "1" and C.global.font_unit_size or C.global.font_size @@ -8,6 +7,114 @@ pfUI:RegisterModule("castbar", function () default_border = C.appearance.border.unitframes end + local function CreateCastbar(name, parent, unitstr, unitname) + local cb = CreateFrame("Frame", name, parent or UIParent) + + CreateBackdrop(cb, default_border) + UpdateMovable(cb) + + cb:SetHeight(C.global.font_size * 1.5) + cb:SetFrameStrata("MEDIUM") + cb:Hide() + + cb.unitstr = unitstr + cb.unitname = unitname + + cb.delay = 0 + + -- statusbar + cb.bar = CreateFrame("StatusBar", nil, cb) + cb.bar:SetStatusBarTexture("Interface\\AddOns\\pfUI\\img\\bar") + cb.bar:ClearAllPoints() + cb.bar:SetAllPoints(cb) + cb.bar:SetMinMaxValues(0, 100) + cb.bar:SetValue(20) + local r,g,b,a = strsplit(",", C.appearance.castbar.castbarcolor) + cb.bar:SetStatusBarColor(r,g,b,a) + + -- text left + cb.bar.left = cb.bar:CreateFontString("Status", "DIALOG", "GameFontNormal") + cb.bar.left:ClearAllPoints() + cb.bar.left:SetPoint("TOPLEFT", cb.bar, "TOPLEFT", 3, 0) + cb.bar.left:SetPoint("BOTTOMRIGHT", cb.bar, "BOTTOMRIGHT", -3, 0) + cb.bar.left:SetNonSpaceWrap(false) + cb.bar.left:SetFontObject(GameFontWhite) + cb.bar.left:SetTextColor(1,1,1,1) + cb.bar.left:SetFont(font, font_size, "OUTLINE") + cb.bar.left:SetText("left") + cb.bar.left:SetJustifyH("left") + + -- text right + cb.bar.right = cb.bar:CreateFontString("Status", "DIALOG", "GameFontNormal") + cb.bar.right:ClearAllPoints() + cb.bar.right:SetPoint("TOPLEFT", cb.bar, "TOPLEFT", 3, 0) + cb.bar.right:SetPoint("BOTTOMRIGHT", cb.bar, "BOTTOMRIGHT", -3, 0) + cb.bar.right:SetNonSpaceWrap(false) + cb.bar.right:SetFontObject(GameFontWhite) + cb.bar.right:SetTextColor(1,1,1,1) + cb.bar.right:SetFont(font, font_size, "OUTLINE") + cb.bar.right:SetText("right") + cb.bar.right:SetJustifyH("right") + + cb:SetScript("OnUpdate", function() + if this.fadeout and this:GetAlpha() > 0 then + this:SetAlpha(this:GetAlpha()-0.05) + if this:GetAlpha() == 0 then + this:Hide() + this.fadeout = nil + end + return + end + + local name = this.unitstr and UnitName(this.unitstr) or this.unitname + local spellname, start, duration, icon, delay, channel = libcast:GetCastInfo(name) + if spellname then + local max = duration / 1000 + local cur = channel and duration / 1000 - delay + start - GetTime() or + GetTime() - start - delay + cur = cur > max and max or cur + cur = cur < 0 and 0 or cur + + this.bar:SetValue(cur) + + if delay > 0 then + delay = "|cffffaaaa" .. (channel and "-" or "+") .. round(delay,1) .. " |r " + this.bar.right:SetText(delay .. string.format("%.1f",cur) .. " / " .. round(max,1)) + else + this.bar.right:SetText(string.format("%.1f",cur) .. " / " .. round(max,1)) + end + + this.fadeout = nil + else + this.bar:SetMinMaxValues(1,100) + this.bar:SetValue(100) + this.fadeout = 1 + end + end) + + function cb.OnEvent(self) + local name = self.unitstr and UnitName(self.unitstr) or self.unitname + + local spellname, start, casttime, icon, delay, channel = libcast:GetCastInfo(name) + if spellname then + self.bar:SetStatusBarColor(strsplit(",", C.appearance.castbar[(channel and "channelcolor" or "castbarcolor")])) + self.bar:SetMinMaxValues(0, casttime / 1000) + self.bar.left:SetText(spellname) + + self:SetAlpha(1) + self:Show() + self.fadeout = nil + else + self.bar:SetMinMaxValues(1,100) + self.bar:SetValue(100) + self.fadeout = 1 + end + end + + libcast:RegisterEventFunc(cb.OnEvent, cb) + return cb + end + pfUI.castbar = CreateFrame("Frame", "pfCastBar", UIParent) -- hide blizzard @@ -17,10 +124,7 @@ pfUI:RegisterModule("castbar", function () end -- [[ pfPlayerCastbar ]] -- - pfUI.castbar.player = CreateFrame("Frame", "pfPlayerCastbar", UIParent) - pfUI.castbar.player:SetFrameStrata("MEDIUM") - CreateBackdrop(pfUI.castbar.player, default_border) - pfUI.castbar.player:SetHeight(C.global.font_size * 1.5) + pfUI.castbar.player = CreateCastbar("pfPlayerCastbar", UIParent, "player") if pfUI.uf.player then local pspace = tonumber(C.unitframes.player.pspace) @@ -31,307 +135,8 @@ pfUI:RegisterModule("castbar", function () pfUI.castbar.player:SetWidth(200) end - UpdateMovable(pfUI.castbar.player) - pfUI.castbar.player:Hide() - pfUI.castbar.player.delay = 0 - - -- statusbar - pfUI.castbar.player.bar = CreateFrame("StatusBar", nil, pfUI.castbar.player) - pfUI.castbar.player.bar:SetStatusBarTexture("Interface\\AddOns\\pfUI\\img\\bar") - pfUI.castbar.player.bar:ClearAllPoints() - pfUI.castbar.player.bar:SetAllPoints(pfUI.castbar.player) - pfUI.castbar.player.bar:SetMinMaxValues(0, 100) - pfUI.castbar.player.bar:SetValue(20) - local r,g,b,a = strsplit(",", C.appearance.castbar.castbarcolor) - pfUI.castbar.player.bar:SetStatusBarColor(r,g,b,a) - - -- text left - pfUI.castbar.player.bar.left = pfUI.castbar.player.bar:CreateFontString("Status", "DIALOG", "GameFontNormal") - pfUI.castbar.player.bar.left:ClearAllPoints() - pfUI.castbar.player.bar.left:SetPoint("TOPLEFT", pfUI.castbar.player.bar, "TOPLEFT", 3, 0) - pfUI.castbar.player.bar.left:SetPoint("BOTTOMRIGHT", pfUI.castbar.player.bar, "BOTTOMRIGHT", -3, 0) - pfUI.castbar.player.bar.left:SetNonSpaceWrap(false) - pfUI.castbar.player.bar.left:SetFontObject(GameFontWhite) - pfUI.castbar.player.bar.left:SetTextColor(1,1,1,1) - pfUI.castbar.player.bar.left:SetFont(font, font_size, "OUTLINE") - pfUI.castbar.player.bar.left:SetText("left") - pfUI.castbar.player.bar.left:SetJustifyH("left") - - -- text right - pfUI.castbar.player.bar.right = pfUI.castbar.player.bar:CreateFontString("Status", "DIALOG", "GameFontNormal") - pfUI.castbar.player.bar.right:ClearAllPoints() - pfUI.castbar.player.bar.right:SetPoint("TOPLEFT", pfUI.castbar.player.bar, "TOPLEFT", 3, 0) - pfUI.castbar.player.bar.right:SetPoint("BOTTOMRIGHT", pfUI.castbar.player.bar, "BOTTOMRIGHT", -3, 0) - pfUI.castbar.player.bar.right:SetNonSpaceWrap(false) - pfUI.castbar.player.bar.right:SetFontObject(GameFontWhite) - pfUI.castbar.player.bar.right:SetTextColor(1,1,1,1) - pfUI.castbar.player.bar.right:SetFont(font, font_size, "OUTLINE") - pfUI.castbar.player.bar.right:SetText("right") - pfUI.castbar.player.bar.right:SetJustifyH("right") - - -- events - pfUI.castbar.player:RegisterEvent("SPELLCAST_START") - pfUI.castbar.player:RegisterEvent("SPELLCAST_STOP") - pfUI.castbar.player:RegisterEvent("SPELLCAST_DELAYED") - pfUI.castbar.player:RegisterEvent("SPELLCAST_CHANNEL_START") - pfUI.castbar.player:RegisterEvent("SPELLCAST_CHANNEL_STOP") - pfUI.castbar.player:RegisterEvent("SPELLCAST_CHANNEL_UPDATE") - pfUI.castbar.player:RegisterEvent("SPELLCAST_FAILED") - pfUI.castbar.player:RegisterEvent("SPELLCAST_INTERRUPTED") - - local scanner = CreateFrame("GameTooltip", "pfSpellScanner", nil, "GameTooltipTemplate") - scanner:SetOwner(WorldFrame, "ANCHOR_NONE") - - local delayByLag = CreateFrame("Frame", "pfDelayCast", nil) - delayByLag.currentCast = nil - delayByLag.startTime = nil - - function delayByLag:SetCast(cast) - for custom in pairs(pfUI.castbar.player.customcast) do - if strfind(strlower(cast), strlower(custom)) then - delayByLag.currentCast = custom - delayByLag.startTime = GetTime() - end - end - end - - delayByLag:SetScript("OnUpdate", function() - if this.currentCast and this.startTime then - local _,_, lag = GetNetStats() - if this.startTime + lag/1000 < GetTime() then - pfUI.castbar.player.customcast[this.currentCast](true) - this.currentCast = nil - this.startTime = nil - end - end - end) - - local aimedshot = L["customcast"]["AIMEDSHOT"] - local multishot = L["customcast"]["MULTISHOT"] - - pfUI.castbar.player.customcast = {} - pfUI.castbar.player.customcast[aimedshot] = function(begin) - if begin then - local duration = 3000 - - for i=1,32 do - if UnitBuff("player", i) == "Interface\\Icons\\Racial_Troll_Berserk" then - local berserk = 0.3 - if((UnitHealth("player")/UnitHealthMax("player")) >= 0.40) then - berserk = (1.30 - (UnitHealth("player") / UnitHealthMax("player"))) / 3 - end - duration = duration / (1 + berserk) - elseif UnitBuff("player", i) == "Interface\\Icons\\Ability_Hunter_RunningShot" then - duration = duration / 1.4 - elseif UnitBuff("player", i) == "Interface\\Icons\\Ability_Warrior_InnerRage" then - duration = duration / 1.3 - elseif UnitBuff("player", i) == "Interface\\Icons\\Inv_Trinket_Naxxramas04" then - duration = duration / 1.2 - elseif UnitDebuff("player", i) == "Interface\\Icons\\Spell_Shadow_CurseOfTounges" then - duration = duration / 0.5 - end - end - - if not pfUI.castbar.player.casting then - pfUI.castbar.player:SpellcastStart(aimedshot, duration) - end - else - pfUI.castbar.player:SpellcastStop() - end - end - - pfUI.castbar.player.customcast[multishot] = function(begin) - if begin then - local duration = 500 - if not pfUI.castbar.player.casting then - pfUI.castbar.player:SpellcastStart(multishot, duration) - end - else - pfUI.castbar.player:SpellcastStop() - end - end - - hooksecurefunc("CastSpell", function(id, bookType) - if GetSpellCooldown(id, bookType) ~= 0 then - local spellName = GetSpellName(id, bookType) - delayByLag:SetCast(spellName, true) - end - end, true) - - hooksecurefunc("CastSpellByName", function(spellName, target) - for i=1,120 do - -- detect if any cast is ongoing - if IsCurrentAction(i) then - delayByLag:SetCast(spellName) - return - end - end - end, true) - - hooksecurefunc("UseAction", function(slot, target, button) - if GetActionText(slot) or not IsCurrentAction(slot) then return end - scanner:ClearLines() - scanner:SetAction(slot) - local spellName = pfSpellScannerTextLeft1:GetText() - delayByLag:SetCast(spellName) - end, true) - - function pfUI.castbar.player:SpellcastStart(spell, duration) - pfUI.castbar.player.delay = 0 - pfUI.castbar.player.spell = spell - pfUI.castbar.player.bar.left:SetText(spell) - local r,g,b,a = strsplit(",", C.appearance.castbar.castbarcolor) - pfUI.castbar.player.bar:SetStatusBarColor(r,g,b,a) - pfUI.castbar.player.startTime = GetTime() - pfUI.castbar.player.maxValue = duration / 1000 - pfUI.castbar.player.endTime = nil - pfUI.castbar.player.bar:SetMinMaxValues(0, pfUI.castbar.player.maxValue) - pfUI.castbar.player.bar:SetValue(pfUI.castbar.player.startTime) - pfUI.castbar.player.holdTime = 0 - pfUI.castbar.player.casting = 1 - pfUI.castbar.player.channeling = nil - pfUI.castbar.player.mode = "casting" - pfUI.castbar.player.fadeout = nil - pfUI.castbar.player:SetAlpha(1) - pfUI.castbar.player:Show() - end - - function pfUI.castbar.player:SpellcastStop() - delayByLag.currentCast = nil - delayByLag.startTime = nil - - if pfUI.castbar.player.casting then - pfUI.castbar.player.fadeout = 1 - pfUI.castbar.player.casting = nil - pfUI.castbar.player.bar:SetMinMaxValues(1,pfUI.castbar.player.bar:GetValue()) - end - end - - function pfUI.castbar.player:SpellcastChannelStart(duration, spell) - pfUI.castbar.player.delay = 0 - pfUI.castbar.player.spell = spell - pfUI.castbar.player.bar.left:SetText(spell) - local r,g,b,a = strsplit(",", C.appearance.castbar.channelcolor) - pfUI.castbar.player.bar:SetStatusBarColor(r,g,b,a) - pfUI.castbar.player.maxValue = nil - pfUI.castbar.player.startTime = GetTime() - pfUI.castbar.player.endTime = pfUI.castbar.player.startTime + (arg1 / 1000) - pfUI.castbar.player.duration = duration / 1000 - pfUI.castbar.player.bar:SetMinMaxValues(pfUI.castbar.player.startTime, pfUI.castbar.player.endTime) - pfUI.castbar.player.bar:SetValue(pfUI.castbar.player.endTime) - pfUI.castbar.player.holdTime = 0 - pfUI.castbar.player.casting = nil - pfUI.castbar.player.channeling = 1 - pfUI.castbar.player.fadeout = nil - pfUI.castbar.player:SetAlpha(1) - pfUI.castbar.player:Show() - end - - function pfUI.castbar.player:SpellcastChannelStop() - delayByLag.currentCast = nil - delayByLag.startTime = nil - - if pfUI.castbar.player.channeling then - pfUI.castbar.player.fadeout = 1 - pfUI.castbar.player.channeling = nil - - if GetTime() + 0.3 < pfUI.castbar.player.endTime then - pfUI.castbar.player.bar:SetStatusBarColor(1,.5,.5,1) - pfUI.castbar.player.bar:SetMinMaxValues(1,100) - pfUI.castbar.player.bar:SetValue(100) - end - end - end - - pfUI.castbar.player:SetScript("OnEvent", function () - if ( event == "SPELLCAST_START" ) then - pfUI.castbar.player:SpellcastStart(arg1, arg2) - elseif event == "SPELLCAST_STOP" or event == "SPELLCAST_FAILED" or event == "SPELLCAST_INTERRUPTED" then - pfUI.castbar.player:SpellcastStop() - elseif ( event == "SPELLCAST_DELAYED" ) then - if( pfUI.castbar.player:IsShown() ) then - pfUI.castbar.player.delay = pfUI.castbar.player.delay + arg1/1000 - end - elseif ( event == "SPELLCAST_CHANNEL_START" ) then - pfUI.castbar.player:SpellcastChannelStart(arg1, arg2) - elseif event == "SPELLCAST_CHANNEL_STOP" then - pfUI.castbar.player:SpellcastChannelStop() - elseif ( event == "SPELLCAST_CHANNEL_UPDATE" ) then - if ( pfUI.castbar.player:IsShown() ) then - pfUI.castbar.player.delay = pfUI.castbar.player.delay + arg1/1000 - local origDuration = pfUI.castbar.player.endTime - pfUI.castbar.player.startTime - pfUI.castbar.player.endTime = GetTime() + (arg1 / 1000) - pfUI.castbar.player.startTime = pfUI.castbar.player.endTime - origDuration - pfUI.castbar.player.bar:SetMinMaxValues(pfUI.castbar.player.startTime, pfUI.castbar.player.endTime) - end - end - end) - - pfUI.castbar.player:SetScript("OnUpdate", function () - if C.castbar.player.hide_pfui == "1" then pfUI.castbar.player:Hide() return end - - -- cast - if pfUI.castbar.player.casting then - local cur = GetTime() - pfUI.castbar.player.startTime - pfUI.castbar.player.delay - local max = pfUI.castbar.player.maxValue - local delay = pfUI.castbar.player.delay - - pfUI.castbar.player.bar:SetValue(cur) - - if cur > max then cur = max end - - if delay > 0 then - delay = "|cffffaaaa+" .. round(delay,1) .. " |r " - pfUI.castbar.player.bar.right:SetText(delay .. string.format("%.1f",cur) .. " / " .. round(max,1)) - else - pfUI.castbar.player.bar.right:SetText(string.format("%.1f",cur) .. " / " .. round(max,1)) - end - - return - - -- channel - elseif pfUI.castbar.player.channeling then - local time = GetTime() - local barValue = pfUI.castbar.player.startTime + (pfUI.castbar.player.endTime - time) - - pfUI.castbar.player.bar:SetValue( barValue ) - - local cur = pfUI.castbar.player.endTime - GetTime() - local max = pfUI.castbar.player.endTime - pfUI.castbar.player.startTime - local delay = pfUI.castbar.player.delay - if cur > max then cur = max end - if ( time > pfUI.castbar.player.endTime ) then - time = pfUI.castbar.player.endTime - end - if ( time >= pfUI.castbar.player.endTime ) then - pfUI.castbar.player.channeling = nil - pfUI.castbar.player.fadeout = 1 - return - end - if delay > 0 then - delay = "|cffffaaaa-" .. round(delay,1) .. " |r " - pfUI.castbar.player.bar.right:SetText(delay .. round(cur,1)) - else - pfUI.castbar.player.bar.right:SetText(round(cur,1)) - end - - return - - -- fadeout - elseif pfUI.castbar.player.fadeout and pfUI.castbar.player:GetAlpha() > 0 then - pfUI.castbar.player:SetAlpha(pfUI.castbar.player:GetAlpha()-0.025) - if pfUI.castbar.player:GetAlpha() == 0 then - pfUI.castbar.player:Hide() - pfUI.castbar.player.fadeout = nil - end - end - end) - -- [[ pfTargetCastbar ]] -- - pfUI.castbar.target = CreateFrame("Frame", "pfTargetCastbar", UIParent) - pfUI.castbar.target:SetFrameStrata("MEDIUM") - CreateBackdrop(pfUI.castbar.target, default_border) - pfUI.castbar.target:SetHeight(C.global.font_size * 1.5) + pfUI.castbar.target = CreateCastbar("pfTargetCastbar", UIParent, "target") if pfUI.uf.target then local pspace = tonumber(C.unitframes.target.pspace) @@ -341,199 +146,4 @@ pfUI:RegisterModule("castbar", function () pfUI.castbar.target:SetPoint("CENTER", 0, -225) pfUI.castbar.target:SetWidth(200) end - - UpdateMovable(pfUI.castbar.target) - pfUI.castbar.target:Hide() - - - -- statusbar - pfUI.castbar.target.bar = CreateFrame("StatusBar", nil, pfUI.castbar.target) - pfUI.castbar.target.bar:SetStatusBarTexture("Interface\\AddOns\\pfUI\\img\\bar") - pfUI.castbar.target.bar:ClearAllPoints() - pfUI.castbar.target.bar:SetAllPoints(pfUI.castbar.target) - pfUI.castbar.target.bar:SetMinMaxValues(0, 100) - pfUI.castbar.target.bar:SetValue(20) - local r,g,b,a = strsplit(",", C.appearance.castbar.castbarcolor) - pfUI.castbar.target.bar:SetStatusBarColor(r,g,b,a) - - -- text left - pfUI.castbar.target.bar.left = pfUI.castbar.target.bar:CreateFontString("Status", "DIALOG", "GameFontNormal") - pfUI.castbar.target.bar.left:ClearAllPoints() - pfUI.castbar.target.bar.left:SetPoint("TOPLEFT", pfUI.castbar.target.bar, "TOPLEFT", 3, 0) - pfUI.castbar.target.bar.left:SetPoint("BOTTOMRIGHT", pfUI.castbar.target.bar, "BOTTOMRIGHT", -3, 0) - pfUI.castbar.target.bar.left:SetNonSpaceWrap(false) - pfUI.castbar.target.bar.left:SetFontObject(GameFontWhite) - pfUI.castbar.target.bar.left:SetTextColor(1,1,1,1) - pfUI.castbar.target.bar.left:SetFont(font, font_size, "OUTLINE") - pfUI.castbar.target.bar.left:SetText("left") - pfUI.castbar.target.bar.left:SetJustifyH("left") - - -- text right - pfUI.castbar.target.bar.right = pfUI.castbar.target.bar:CreateFontString("Status", "DIALOG", "GameFontNormal") - pfUI.castbar.target.bar.right:ClearAllPoints() - pfUI.castbar.target.bar.right:SetPoint("TOPLEFT", pfUI.castbar.target.bar, "TOPLEFT", 3, 0) - pfUI.castbar.target.bar.right:SetPoint("BOTTOMRIGHT", pfUI.castbar.target.bar, "BOTTOMRIGHT", -3, 0) - pfUI.castbar.target.bar.right:SetNonSpaceWrap(false) - pfUI.castbar.target.bar.right:SetFontObject(GameFontWhite) - pfUI.castbar.target.bar.right:SetTextColor(1,1,1,1) - pfUI.castbar.target.bar.right:SetFont(font, font_size, "OUTLINE") - pfUI.castbar.target.bar.right:SetText("right") - pfUI.castbar.target.bar.right:SetJustifyH("right") - - pfUI.castbar.target.bar:SetScript("OnUpdate", function() - if pfUI.castbar.target.drag and pfUI.castbar.target.drag:IsShown() then this:Show() return end - if UnitExists("target") and pfUI.castbar.target.casterDB[UnitName("target")] then - local spellname = pfUI.castbar.target.casterDB[UnitName("target")].cast or 0 - local starttime = pfUI.castbar.target.casterDB[UnitName("target")].starttime or 0 - local casttime = pfUI.castbar.target.casterDB[UnitName("target")].casttime or 0 - - if starttime + casttime > GetTime() then - if pfUI.castbar.target.bar then - pfUI.castbar.target.bar:SetMinMaxValues(0, casttime) - pfUI.castbar.target.bar:SetValue(GetTime() - starttime) - pfUI.castbar.target.bar.left:SetText(spellname) - pfUI.castbar.target.bar.right:SetText(round(GetTime() - starttime,1) .. " / " .. casttime) - end - else - pfUI.castbar.target.casterDB[UnitName("target")] = nil - pfUI.castbar.target:Hide() - end - else - pfUI.castbar.target:Hide() - end - end) - - pfUI.castbar.target.SPELL_CAST = SanitizePattern(SPELLCASTOTHERSTART) - pfUI.castbar.target.SPELL_PERFORM = SanitizePattern(SPELLPERFORMOTHERSTART) - pfUI.castbar.target.SPELL_GAINS = SanitizePattern(AURAADDEDOTHERHELPFUL) - pfUI.castbar.target.SPELL_AFFLICTED = SanitizePattern(AURAADDEDOTHERHARMFUL) - pfUI.castbar.target.SPELL_HIT = SanitizePattern(SPELLLOGSELFOTHER) - pfUI.castbar.target.SPELL_CRIT = SanitizePattern(SPELLLOGCRITSELFOTHER) - pfUI.castbar.target.OTHER_SPELL_HIT = SanitizePattern(SPELLLOGOTHEROTHER) - pfUI.castbar.target.OTHER_SPELL_CRIT = SanitizePattern(SPELLLOGCRITOTHEROTHER) - pfUI.castbar.target.SPELL_INTERRUPT = SanitizePattern(SPELLINTERRUPTSELFOTHER) - pfUI.castbar.target.OTHER_SPELL_INTERRUPT = SanitizePattern(SPELLINTERRUPTOTHEROTHER) - - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_BUFF") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PARTY_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PARTY_BUFF") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_BUFFS") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_DAMAGE") - pfUI.castbar.target:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_CREATURE_BUFF") - pfUI.castbar.target:RegisterEvent("PLAYER_TARGET_CHANGED") - - pfUI.castbar.target.casterDB = {} - - pfUI.castbar.target:SetScript("OnEvent", function() - if event == "PLAYER_TARGET_CHANGED" then - if UnitExists("target") and pfUI.castbar.target.casterDB[UnitName("target")] then - local starttime = pfUI.castbar.target.casterDB[UnitName("target")].starttime or 0 - local casttime = pfUI.castbar.target.casterDB[UnitName("target")].casttime or 0 - if starttime + casttime > GetTime() then - if C.castbar.target.hide_pfui == "1" then - pfUI.castbar.target:Hide() - else - pfUI.castbar.target:Show() - end - elseif pfUI.castbar.target.drag and not pfUI.castbar.target.drag:IsShown() then - pfUI.castbar.target.casterDB[UnitName("target")] = nil - pfUI.castbar.target:Hide() - end - end - elseif arg1 then - -- (.+) begins to cast (.+). - for mob, spell in string.gfind(arg1, pfUI.castbar.target.SPELL_CAST) do - pfUI.castbar.target:Action(mob, spell) - return - end - -- (.+) begins to perform (.+). - for mob, spell in string.gfind(arg1, pfUI.castbar.target.SPELL_PERFORM) do - pfUI.castbar.target:Action(mob, spell) - return - end - - -- (.+) gains (.+). - for mob, spell in string.gfind(arg1, pfUI.castbar.target.SPELL_GAINS) do - pfUI.castbar.target:StopAction(mob, spell) - return - end - - -- (.+) is afflicted by (.+). - for mob, spell in string.gfind(arg1, pfUI.castbar.target.SPELL_AFFLICTED) do - pfUI.castbar.target:StopAction(mob, spell) - return - end - - -- Your (.+) hits (.+) for (%d+). - for spell, mob in string.gfind(arg1, pfUI.castbar.target.SPELL_HIT) do - pfUI.castbar.target:StopAction(mob, spell) - return - end - - -- Your (.+) crits (.+) for (%d+). - for spell, mob in string.gfind(arg1, pfUI.castbar.target.SPELL_CRIT) do - pfUI.castbar.target:StopAction(mob, spell) - return - end - - -- (.+)'s (.+) %a hits (.+) for (%d+). - for _, spell, mob in string.gfind(arg1, pfUI.castbar.target.OTHER_SPELL_HIT) do - pfUI.castbar.target:StopAction(mob, spell) - return - end - - -- (.+)'s (.+) %a crits (.+) for (%d+). - for _, spell, mob in string.gfind(arg1, pfUI.castbar.target.OTHER_SPELL_CRIT) do - pfUI.castbar.target:StopAction(mob, spell) - return - end - - -- You interrupt (.+)'s (.+)."; - for mob, spell in string.gfind(arg1, pfUI.castbar.target.SPELL_INTERRUPT) do - pfUI.castbar.target:StopAction(mob, "INTERRUPT") - return - end - - -- (.+) interrupts (.+)'s (.+). - for _, mob, spell in string.gfind(arg1, pfUI.castbar.target.OTHER_SPELL_INTERRUPT) do - pfUI.castbar.target:StopAction(mob, "INTERRUPT") - return - end - end - end) - - function pfUI.castbar.target:Action(mob, spell) - if L["spells"][spell] ~= nil then - local casttime = L["spells"][spell].t / 1000 - local icon = L["spells"][spell].icon - pfUI.castbar.target.casterDB[mob] = {cast = spell, starttime = GetTime(), casttime = casttime, icon = icon} - if UnitExists("target") and pfUI.castbar.target.casterDB[UnitName("target")] then - if C.castbar.target.hide_pfui == "1" then - pfUI.castbar.target:Hide() - else - pfUI.castbar.target:Show() - end - elseif pfUI.castbar.target.drag and not pfUI.castbar.target.drag:IsShown() then - pfUI.castbar.target:Hide() - end - end - end - - function pfUI.castbar.target:StopAction(mob, spell) - if pfUI.castbar.target.casterDB[mob] and ( L["interrupts"][spell] ~= nil or spell == "INTERRUPT" ) then - pfUI.castbar.target.casterDB[mob] = nil - end - end end) diff --git a/modules/nameplates.lua b/modules/nameplates.lua index 470f6ab3..22867c08 100644 --- a/modules/nameplates.lua +++ b/modules/nameplates.lua @@ -496,16 +496,17 @@ pfUI:RegisterModule("nameplates", function () end -- show castbar - if healthbar.castbar and pfUI.castbar and C.nameplates["showcastbar"] == "1" and pfUI.castbar.target.casterDB[unitname] ~= nil and pfUI.castbar.target.casterDB[unitname]["cast"] ~= nil then - if pfUI.castbar.target.casterDB[unitname]["starttime"] + pfUI.castbar.target.casterDB[unitname]["casttime"] <= GetTime() then - pfUI.castbar.target.casterDB[unitname] = nil + if healthbar.castbar and pfUI.castbar and C.nameplates["showcastbar"] == "1" then + local spellname, start, casttime, icon = libcast:GetCastInfo(unitname) + casttime = casttime / 1000 + if not spellname then healthbar.castbar:Hide() else - healthbar.castbar:SetMinMaxValues(0, pfUI.castbar.target.casterDB[unitname]["casttime"]) - healthbar.castbar:SetValue(GetTime() - pfUI.castbar.target.casterDB[unitname]["starttime"]) - healthbar.castbar.text:SetText(round( pfUI.castbar.target.casterDB[unitname]["starttime"] + pfUI.castbar.target.casterDB[unitname]["casttime"] - GetTime(),1)) + healthbar.castbar:SetMinMaxValues(0, casttime) + healthbar.castbar:SetValue(GetTime() - start) + healthbar.castbar.text:SetText(round(start + casttime - GetTime(),1)) if C.nameplates.spellname == "1" and healthbar.castbar.spell then - healthbar.castbar.spell:SetText(pfUI.castbar.target.casterDB[unitname]["cast"]) + healthbar.castbar.spell:SetText(spellname) else healthbar.castbar.spell:SetText("") end @@ -514,8 +515,8 @@ pfUI:RegisterModule("nameplates", function () this.debuffs[1]:SetPoint("TOPLEFT", healthbar.castbar, "BOTTOMLEFT", 0, -3) end - if pfUI.castbar.target.casterDB[unitname]["icon"] then - healthbar.castbar.icon:SetTexture("Interface\\Icons\\" .. pfUI.castbar.target.casterDB[unitname]["icon"]) + if icon then + healthbar.castbar.icon:SetTexture("Interface\\Icons\\" .. icon) healthbar.castbar.icon:SetTexCoord(.1,.9,.1,.9) end end diff --git a/pfUI.toc b/pfUI.toc index f1db8015..340233bf 100644 --- a/pfUI.toc +++ b/pfUI.toc @@ -39,6 +39,9 @@ api\config.lua api\ui-widgets.lua api\unitframes.lua +# libs +libs\libcast.lua + # modules modules\firstrun.lua modules\gui.lua