diff --git a/BetterCharacterStats.lua b/BetterCharacterStats.lua index fb0adee..8368261 100644 --- a/BetterCharacterStats.lua +++ b/BetterCharacterStats.lua @@ -1,1016 +1,1280 @@ -BCS = BCS or {} -BCSConfig = BCSConfig or {} - -local L, IndexLeft, IndexRight -L = BCS.L - -BCS.PLAYERSTAT_DROPDOWN_OPTIONS = { - "PLAYERSTAT_BASE_STATS", - "PLAYERSTAT_MELEE_COMBAT", - "PLAYERSTAT_RANGED_COMBAT", - "PLAYERSTAT_SPELL_COMBAT", - "PLAYERSTAT_SPELL_SCHOOLS", - "PLAYERSTAT_DEFENSES", -} - -BCS.MELEEHIT = { - ["ROGUE"] = { - 5, -- pvp - 8, -- yellow cap - 24.6, -- white cap - }, -} - -BCS.SPELLHIT = { - -- soon(tm) -} - -BCS.PaperDollFrame = PaperDollFrame - -BCS.Debug = false -BCS.DebugStack = {} - -function BCS:DebugTrace(start, limit) - BCS.Debug = nil - local length = getn(BCS.DebugStack) - if not start then start = 1 end - if start > length then start = length end - if not limit then limit = start + 30 end - - BCS:Print("length: " .. length) - BCS:Print("start: " .. start) - BCS:Print("limit: " .. limit) - - for i = start, length, 1 do - BCS:Print("[" .. i .. "] Event: " .. BCS.DebugStack[i].E) - BCS:Print(format( - "[%d] `- Arguments: %s, %s, %s, %s, %s", - i, - BCS.DebugStack[i].arg1, - BCS.DebugStack[i].arg2, - BCS.DebugStack[i].arg3, - BCS.DebugStack[i].arg4, - BCS.DebugStack[i].arg5 - )) - if i >= limit then i = length end - end - -end - -function BCS:Print(message) - ChatFrame2:AddMessage("[BCS] " .. message, 0.63, 0.86, 1.0) -end - -function BCS:OnLoad() - CharacterAttributesFrame:Hide() - PaperDollFrame:UnregisterEvent('UNIT_DAMAGE') - PaperDollFrame:UnregisterEvent('PLAYER_DAMAGE_DONE_MODS') - PaperDollFrame:UnregisterEvent('UNIT_ATTACK_SPEED') - PaperDollFrame:UnregisterEvent('UNIT_RANGEDDAMAGE') - PaperDollFrame:UnregisterEvent('UNIT_ATTACK') - PaperDollFrame:UnregisterEvent('UNIT_STATS') - PaperDollFrame:UnregisterEvent('UNIT_ATTACK_POWER') - PaperDollFrame:UnregisterEvent('UNIT_RANGED_ATTACK_POWER') - - self.Frame = BCSFrame - self.needUpdate = nil - - self.Frame:RegisterEvent("ADDON_LOADED") - self.Frame:RegisterEvent("UNIT_INVENTORY_CHANGED") -- fires when equipment changes - self.Frame:RegisterEvent("CHARACTER_POINTS_CHANGED") -- fires when learning talent - self.Frame:RegisterEvent("PLAYER_AURAS_CHANGED") -- buffs/warrior stances - - local _, classFileName = UnitClass("Player") - self.playerClass = strupper(classFileName) -end - -function BCS:OnEvent() - --[[if BCS.Debug then - local t = { - E = event, - arg1 = arg1 or "nil", - arg2 = arg2 or "nil", - arg3 = arg3 or "nil", - arg4 = arg4 or "nil", - arg5 = arg5 or "nil", - } - tinsert(BCS.DebugStack, t) - end]] - - if - event == "PLAYER_AURAS_CHANGED" or - event == "CHARACTER_POINTS_CHANGED" - then - if BCS.PaperDollFrame:IsVisible() then - BCS:UpdateStats() - else - BCS.needUpdate = true - end - elseif event == "UNIT_INVENTORY_CHANGED" and arg1 == "player" then - if BCS.PaperDollFrame:IsVisible() then - BCS:UpdateStats() - else - BCS.needUpdate = true - end - elseif event == "ADDON_LOADED" and arg1 == "BetterCharacterStats" then - IndexLeft = BCSConfig["DropdownLeft"] or BCS.PLAYERSTAT_DROPDOWN_OPTIONS[1] - IndexRight = BCSConfig["DropdownRight"] or BCS.PLAYERSTAT_DROPDOWN_OPTIONS[2] - - UIDropDownMenu_SetSelectedValue(PlayerStatFrameLeftDropDown, IndexLeft) - UIDropDownMenu_SetSelectedValue(PlayerStatFrameRightDropDown, IndexRight) - end -end - -function BCS:OnShow() - if BCS.needUpdate then - BCS.needUpdate = nil - BCS:UpdateStats() - end -end - --- debugging / profiling ---local avgV = {} ---local avg = 0 -function BCS:UpdateStats() - --[[if BCS.Debug then - local e = event or "nil" - BCS:Print("Update due to " .. e) - end - local beginTime = debugprofilestop()]] - - BCS:UpdatePaperdollStats("PlayerStatFrameLeft", IndexLeft) - BCS:UpdatePaperdollStats("PlayerStatFrameRight", IndexRight) - - --[[local timeUsed = debugprofilestop()-beginTime - table.insert(avgV, timeUsed) - avg = 0 - - for i,v in ipairs(avgV) do - avg = avg + v - end - avg = avg / getn(avgV) - - BCS:Print(format("Average: %d (%d results), Exact: %d", avg, getn(avgV), timeUsed))]] -end - -function BCS:SetStat(statFrame, statIndex) - local label = getglobal(statFrame:GetName().."Label") - local text = getglobal(statFrame:GetName().."StatText") - local stat - local effectiveStat - local posBuff - local negBuff - local statIndexTable = { - "STRENGTH", - "AGILITY", - "STAMINA", - "INTELLECT", - "SPIRIT", - } - - statFrame:SetScript("OnEnter", function() - PaperDollStatTooltip("player", statIndexTable[statIndex]) - end) - - statFrame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) - - label:SetText(TEXT(getglobal("SPELL_STAT"..(statIndex-1).."_NAME"))..":") - stat, effectiveStat, posBuff, negBuff = UnitStat("player", statIndex) - - -- Set the tooltip text - local tooltipText = HIGHLIGHT_FONT_COLOR_CODE..getglobal("SPELL_STAT"..(statIndex-1).."_NAME").." " - - if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then - text:SetText(effectiveStat) - statFrame.tooltip = tooltipText..effectiveStat..FONT_COLOR_CODE_CLOSE - else - tooltipText = tooltipText..effectiveStat - if ( posBuff > 0 or negBuff < 0 ) then - tooltipText = tooltipText.." ("..(stat - posBuff - negBuff)..FONT_COLOR_CODE_CLOSE - end - if ( posBuff > 0 ) then - tooltipText = tooltipText..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE - end - if ( negBuff < 0 ) then - tooltipText = tooltipText..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE - end - if ( posBuff > 0 or negBuff < 0 ) then - tooltipText = tooltipText..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE - end - statFrame.tooltip = tooltipText - - -- If there are any negative buffs then show the main number in red even if there are - -- positive buffs. Otherwise show in green. - if ( negBuff < 0 ) then - text:SetText(RED_FONT_COLOR_CODE..effectiveStat..FONT_COLOR_CODE_CLOSE) - else - text:SetText(GREEN_FONT_COLOR_CODE..effectiveStat..FONT_COLOR_CODE_CLOSE) - end - end -end - -function BCS:SetArmor(statFrame) - - local base, effectiveArmor, armor, posBuff, negBuff = UnitArmor("player") - local totalBufs = posBuff + negBuff - local frame = statFrame - local label = getglobal(frame:GetName() .. "Label") - local text = getglobal(frame:GetName() .. "StatText") - - PaperDollFormatStat(ARMOR, base, posBuff, negBuff, frame, text) - label:SetText(TEXT(ARMOR_COLON)) - - local playerLevel = UnitLevel("player") - local armorReduction = effectiveArmor/((85 * playerLevel) + 400) - armorReduction = 100 * (armorReduction/(armorReduction + 1)) - - frame.tooltipSubtext = format(ARMOR_TOOLTIP, playerLevel, armorReduction) - - frame:SetScript("OnEnter", function() - GameTooltip:SetOwner(this, "ANCHOR_RIGHT") - GameTooltip:SetText(this.tooltip) - GameTooltip:AddLine(this.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) - GameTooltip:Show() - end) - frame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) - -end - -function BCS:SetDamage(statFrame) - local label = getglobal(statFrame:GetName() .. "Label") - label:SetText(TEXT(DAMAGE_COLON)) - local damageText = getglobal(statFrame:GetName() .. "StatText") - local damageFrame = statFrame - - damageFrame:SetScript("OnEnter", CharacterDamageFrame_OnEnter) - damageFrame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) - - local speed, offhandSpeed = UnitAttackSpeed("player") - - local minDamage - local maxDamage - local minOffHandDamage - local maxOffHandDamage - local physicalBonusPos - local physicalBonusNeg - local percent - minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent = UnitDamage("player") - local displayMin = max(floor(minDamage),1) - local displayMax = max(ceil(maxDamage),1) - - minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg - maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg - - local baseDamage = (minDamage + maxDamage) * 0.5 - local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent - local totalBonus = (fullDamage - baseDamage) - local damagePerSecond = (max(fullDamage,1) / speed) - local damageTooltip = max(floor(minDamage),1).." - "..max(ceil(maxDamage),1) - - local colorPos = "|cff20ff20" - local colorNeg = "|cffff2020" - if ( totalBonus == 0 ) then - if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then - damageText:SetText(displayMin.." - "..displayMax) - else - damageText:SetText(displayMin.."-"..displayMax) - end - else - - local color - if ( totalBonus > 0 ) then - color = colorPos - else - color = colorNeg - end - if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then - damageText:SetText(color..displayMin.." - "..displayMax.."|r") - else - damageText:SetText(color..displayMin.."-"..displayMax.."|r") - end - if ( physicalBonusPos > 0 ) then - damageTooltip = damageTooltip..colorPos.." +"..physicalBonusPos.."|r" - end - if ( physicalBonusNeg < 0 ) then - damageTooltip = damageTooltip..colorNeg.." "..physicalBonusNeg.."|r" - end - if ( percent > 1 ) then - damageTooltip = damageTooltip..colorPos.." x"..floor(percent*100+0.5).."%|r" - elseif ( percent < 1 ) then - damageTooltip = damageTooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r" - end - - end - damageFrame.damage = damageTooltip - damageFrame.attackSpeed = speed - damageFrame.dps = damagePerSecond - - -- If there's an offhand speed then add the offhand info to the tooltip - if ( offhandSpeed ) then - minOffHandDamage = (minOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg - maxOffHandDamage = (maxOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg - - local offhandBaseDamage = (minOffHandDamage + maxOffHandDamage) * 0.5 - local offhandFullDamage = (offhandBaseDamage + physicalBonusPos + physicalBonusNeg) * percent - local offhandDamagePerSecond = (max(offhandFullDamage,1) / offhandSpeed) - local offhandDamageTooltip = max(floor(minOffHandDamage),1).." - "..max(ceil(maxOffHandDamage),1) - if ( physicalBonusPos > 0 ) then - offhandDamageTooltip = offhandDamageTooltip..colorPos.." +"..physicalBonusPos.."|r" - end - if ( physicalBonusNeg < 0 ) then - offhandDamageTooltip = offhandDamageTooltip..colorNeg.." "..physicalBonusNeg.."|r" - end - if ( percent > 1 ) then - offhandDamageTooltip = offhandDamageTooltip..colorPos.." x"..floor(percent*100+0.5).."%|r" - elseif ( percent < 1 ) then - offhandDamageTooltip = offhandDamageTooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r" - end - damageFrame.offhandDamage = offhandDamageTooltip - damageFrame.offhandAttackSpeed = offhandSpeed - damageFrame.offhandDps = offhandDamagePerSecond - else - damageFrame.offhandAttackSpeed = nil - end - -end - -function BCS:SetAttackSpeed(statFrame) - local speed, offhandSpeed = UnitAttackSpeed("player") - speed = format("%.2f", speed) - if ( offhandSpeed ) then - offhandSpeed = format("%.2f", offhandSpeed) - end - local text - if ( offhandSpeed ) then - text = speed.." / "..offhandSpeed - else - text = speed - end - - local label = getglobal(statFrame:GetName() .. "Label") - local value = getglobal(statFrame:GetName() .. "StatText") - - label:SetText(TEXT(SPEED)..":") - value:SetText(text) - - --[[statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ATTACK_SPEED).." "..text..FONT_COLOR_CODE_CLOSE; - statFrame.tooltip2 = format(CR_HASTE_RATING_TOOLTIP, GetCombatRating(CR_HASTE_MELEE), GetCombatRatingBonus(CR_HASTE_MELEE));]] - - statFrame:Show() -end - -function BCS:SetAttackPower(statFrame) - local base, posBuff, negBuff = UnitAttackPower("player") - - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(TEXT(ATTACK_POWER_COLON)) - - PaperDollFormatStat(MELEE_ATTACK_POWER, base, posBuff, negBuff, frame, text) - frame.tooltipSubtext = format(MELEE_ATTACK_POWER_TOOLTIP, max((base+posBuff+negBuff), 0)/ATTACK_POWER_MAGIC_NUMBER) -end - -function BCS:SetSpellPower(statFrame, school) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - local colorPos = "|cff20ff20" - local colorNeg = "|cffff2020" - - if school then - label:SetText(L["SPELL_SCHOOL_"..strupper(school)]) - local base = BCS:GetSpellPower() - local fromSchool = BCS:GetSpellPower(school) - local output = base + fromSchool - - if fromSchool > 0 then - output = colorPos .. output .. "|r" - end - - text:SetText(output) - else - local power, secondaryPower, secondaryName = BCS:GetSpellPower() - - label:SetText(L.SPELL_POWER_COLON) - text:SetText(power+secondaryPower) - - if secondaryPower > 0 then - frame.tooltip = format(L.SPELL_POWER_SECONDARY_TOOLTIP, (power+secondaryPower), power, secondaryPower, secondaryName) - - frame:SetScript("OnEnter", function() - GameTooltip:SetOwner(this, "ANCHOR_RIGHT") - GameTooltip:SetText(this.tooltip) - GameTooltip:Show() - end) - frame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) - end - - end -end - -function BCS:SetRating(statFrame, ratingType) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(L.MELEE_HIT_RATING_COLON) - - local colorPos = "|cff20ff20" - local colorNeg = "|cffff2020" - - if ratingType == "MELEE" then - local rating = BCS:GetHitRating() - if BCS.MELEEHIT[BCS.playerClass] then - if rating < BCS.MELEEHIT[BCS.playerClass][1] then - rating = colorNeg .. rating .. "%|r" - elseif rating >= BCS.MELEEHIT[BCS.playerClass][2] then - rating = colorPos .. rating .. "%|r" - else - rating = rating .. "%" - end - else - rating = rating .. "%" - end - text:SetText(rating) - - frame.tooltip = L.MELEE_HIT_TOOLTIP - if L[BCS.playerClass .. "_MELEE_HIT_TOOLTIP"] then - frame.tooltipSubtext = L[BCS.playerClass .. "_MELEE_HIT_TOOLTIP"] - end - elseif ratingType == "RANGED" then - local rating = BCS:GetRangedHitRating() - if BCS.MELEEHIT[BCS.playerClass] then - if rating < BCS.MELEEHIT[BCS.playerClass][1] then - rating = colorNeg .. rating .. "%|r" - elseif rating >= BCS.MELEEHIT[BCS.playerClass][2] then - rating = colorPos .. rating .. "%|r" - else - rating = rating .. "%" - end - else - rating = rating .. "%" - end - text:SetText(rating) - - frame.tooltip = L.MELEE_HIT_TOOLTIP - if L[BCS.playerClass .. "_MELEE_HIT_TOOLTIP"] then - frame.tooltipSubtext = L[BCS.playerClass .. "_MELEE_HIT_TOOLTIP"] - end - elseif ratingType == "SPELL" then - local spell_hit, spell_hit_fire, spell_hit_frost, spell_hit_arcane, spell_hit_shadow = BCS:GetSpellHitRating() - --[[if BCS.SPELLHIT[BCS.playerClass] then - if spell_hit < BCS.SPELLHIT[BCS.playerClass][1] then - spell_hit = colorNeg .. spell_hit .. "%|r" - elseif spell_hit >= BCS.SPELLHIT[BCS.playerClass][2] then - spell_hit = colorPos .. spell_hit .. "%|r" - else - spell_hit = spell_hit .. "%" - end - else - spell_hit = spell_hit .. "%" - end]] - - if spell_hit_fire > 0 or spell_hit_frost > 0 or spell_hit_arcane > 0 or spell_hit_shadow > 0 then - -- got spell hit from talents - local spell_hit_other, spell_hit_other_type - - spell_hit_other = 0 - spell_hit_other_type = "" - - if spell_hit_fire > spell_hit_other then - spell_hit_other = spell_hit_fire - spell_hit_other_type = L.SPELL_SCHOOL_FIRE - end - if spell_hit_frost > spell_hit_other then - spell_hit_other = spell_hit_frost - spell_hit_other_type = L.SPELL_SCHOOL_FROST - end - if spell_hit_arcane > spell_hit_other then - spell_hit_other = spell_hit_arcane - spell_hit_other_type = L.SPELL_SCHOOL_ARCANE - end - if spell_hit_shadow > spell_hit_other then - spell_hit_other = spell_hit_shadow - spell_hit_other_type = L.SPELL_SCHOOL_SHADOW - end - - frame.tooltip = format(L.SPELL_HIT_SECONDARY_TOOLTIP, spell_hit+spell_hit_other, spell_hit, spell_hit_other, spell_hit_other_type) - text:SetText(spell_hit+spell_hit_other.."%") - else - frame.tooltip = L.SPELL_HIT_TOOLTIP - text:SetText(spell_hit.."%") - end - - -- class specific tooltip - if L[BCS.playerClass .. "_SPELL_HIT_TOOLTIP"] then - frame.tooltipSubtext = L[BCS.playerClass .. "_SPELL_HIT_TOOLTIP"] - end - end - - if frame.tooltip then - frame:SetScript("OnEnter", function() - GameTooltip:SetOwner(this, "ANCHOR_RIGHT") - GameTooltip:SetText(this.tooltip) - GameTooltip:AddLine(this.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) - GameTooltip:Show() - end) - frame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) - end - -end - -function BCS:SetMeleeCritChance(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(L.MELEE_CRIT_COLON) - text:SetText(format("%.2f%%", BCS:GetCritChance())) -end - -function BCS:SetSpellCritChance(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(L.SPELL_CRIT_COLON) - text:SetText(format("%.2f%%", BCS:GetSpellCritChance())) -end - -function BCS:SetRangedCritChance(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(L.RANGED_CRIT_COLON) - text:SetText(format("%.2f%%", BCS:GetRangedCritChance())) -end - -function BCS:SetHealing(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - local power,_,_,dmg = BCS:GetSpellPower() - local heal = BCS:GetHealingPower() - - power = power-dmg - - label:SetText(L.HEAL_POWER_COLON) - text:SetText(power+heal) - - frame.tooltip = format(L.SPELL_HEALING_POWER_TOOLTIP, (power+heal), power, heal) - - frame:SetScript("OnEnter", function() - GameTooltip:SetOwner(this, "ANCHOR_RIGHT") - GameTooltip:SetText(this.tooltip) - GameTooltip:Show() - end) - frame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) -end - -function BCS:SetManaRegen(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - local base, casting, mp5 = BCS:GetManaRegen() - local mp2 = mp5*0.4 - local totalRegen = base + mp2 - local totalRegenWhileCasting = (casting/100)*base + mp2 - - label:SetText(L.MANA_REGEN_COLON) - text:SetText(format("%d |cffBF40BF(%d)|r", totalRegen, totalRegenWhileCasting)) - - frame.tooltip = format(L.SPELL_MANA_REGEN_TOOLTIP, totalRegen, totalRegenWhileCasting, base, casting, mp5, mp2) - - frame:SetScript("OnEnter", function() - GameTooltip:SetOwner(this, "ANCHOR_RIGHT") - GameTooltip:SetText(this.tooltip) - GameTooltip:Show() - end) - frame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) -end - -function BCS:SetDodge(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(L.DODGE_COLON) - text:SetText(format("%.2f%%", GetDodgeChance())) -end - -function BCS:SetParry(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(L.PARRY_COLON) - text:SetText(format("%.2f%%", GetParryChance())) -end - -function BCS:SetBlock(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(L.BLOCK_COLON) - text:SetText(format("%.2f%%", GetBlockChance())) -end - -function BCS:SetDefense(statFrame) - local base, modifier = UnitDefense("player") - - local frame = statFrame - local label = getglobal(statFrame:GetName() .. "Label") - local text = getglobal(statFrame:GetName() .. "StatText") - - label:SetText(TEXT(DEFENSE_COLON)) - - local posBuff = 0 - local negBuff = 0 - if ( modifier > 0 ) then - posBuff = modifier - elseif ( modifier < 0 ) then - negBuff = modifier - end - PaperDollFormatStat(DEFENSE_COLON, base, posBuff, negBuff, frame, text) -end - -function BCS:SetRangedDamage(statFrame) - local label = getglobal(statFrame:GetName() .. "Label") - local damageText = getglobal(statFrame:GetName() .. "StatText") - local damageFrame = statFrame - - label:SetText(TEXT(DAMAGE_COLON)) - - damageFrame:SetScript("OnEnter", CharacterRangedDamageFrame_OnEnter) - damageFrame:SetScript("OnLeave", function() - GameTooltip:Hide() - end) - - -- If no ranged attack then set to n/a - if ( PaperDollFrame.noRanged ) then - damageText:SetText(NOT_APPLICABLE) - damageFrame.damage = nil - return - end - - local rangedAttackSpeed, minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent = UnitRangedDamage("player") - local displayMin = max(floor(minDamage),1) - local displayMax = max(ceil(maxDamage),1) - - minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg - maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg - - local baseDamage = (minDamage + maxDamage) * 0.5 - local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent - local totalBonus = (fullDamage - baseDamage) - local damagePerSecond = (max(fullDamage,1) / rangedAttackSpeed) - local tooltip = max(floor(minDamage),1).." - "..max(ceil(maxDamage),1) - - if ( totalBonus == 0 ) then - if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then - damageText:SetText(displayMin.." - "..displayMax) - else - damageText:SetText(displayMin.."-"..displayMax) - end - else - local colorPos = "|cff20ff20" - local colorNeg = "|cffff2020" - local color - if ( totalBonus > 0 ) then - color = colorPos - else - color = colorNeg - end - if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then - damageText:SetText(color..displayMin.." - "..displayMax.."|r") - else - damageText:SetText(color..displayMin.."-"..displayMax.."|r") - end - if ( physicalBonusPos > 0 ) then - tooltip = tooltip..colorPos.." +"..physicalBonusPos.."|r" - end - if ( physicalBonusNeg < 0 ) then - tooltip = tooltip..colorNeg.." "..physicalBonusNeg.."|r" - end - if ( percent > 1 ) then - tooltip = tooltip..colorPos.." x"..floor(percent*100+0.5).."%|r" - elseif ( percent < 1 ) then - tooltip = tooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r" - end - damageFrame.tooltip = tooltip.." "..format(TEXT(DPS_TEMPLATE), damagePerSecond) - end - damageFrame.attackSpeed = rangedAttackSpeed - damageFrame.damage = tooltip - damageFrame.dps = damagePerSecond -end - -function BCS:SetRangedAttackSpeed(startFrame) - local label = getglobal(startFrame:GetName() .. "Label") - local damageText = getglobal(startFrame:GetName() .. "StatText") - local damageFrame = startFrame - - label:SetText(TEXT(SPEED)..":") - - -- If no ranged attack then set to n/a - if ( PaperDollFrame.noRanged ) then - damageText:SetText(NOT_APPLICABLE) - damageFrame.damage = nil - return - end - - local rangedAttackSpeed, minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent = UnitRangedDamage("player") - local displayMin = max(floor(minDamage),1) - local displayMax = max(ceil(maxDamage),1) - - minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg - maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg - - local baseDamage = (minDamage + maxDamage) * 0.5 - local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent - local totalBonus = (fullDamage - baseDamage) - local damagePerSecond = (max(fullDamage,1) / rangedAttackSpeed) - local tooltip = max(floor(minDamage),1).." - "..max(ceil(maxDamage),1) - - if ( totalBonus == 0 ) then - if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then - damageText:SetText(displayMin.." - "..displayMax) - else - damageText:SetText(displayMin.."-"..displayMax) - end - else - local colorPos = "|cff20ff20" - local colorNeg = "|cffff2020" - local color - if ( totalBonus > 0 ) then - color = colorPos - else - color = colorNeg - end - if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then - damageText:SetText(color..displayMin.." - "..displayMax.."|r") - else - damageText:SetText(color..displayMin.."-"..displayMax.."|r") - end - if ( physicalBonusPos > 0 ) then - tooltip = tooltip..colorPos.." +"..physicalBonusPos.."|r" - end - if ( physicalBonusNeg < 0 ) then - tooltip = tooltip..colorNeg.." "..physicalBonusNeg.."|r" - end - if ( percent > 1 ) then - tooltip = tooltip..colorPos.." x"..floor(percent*100+0.5).."%|r" - elseif ( percent < 1 ) then - tooltip = tooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r" - end - damageFrame.tooltip = tooltip.." "..format(TEXT(DPS_TEMPLATE), damagePerSecond) - end - - damageText:SetText(format("%.2f", rangedAttackSpeed)) - - damageFrame.attackSpeed = rangedAttackSpeed - damageFrame.damage = tooltip - damageFrame.dps = damagePerSecond -end - -function BCS:SetRangedAttackPower(statFrame) - local frame = statFrame - local text = getglobal(statFrame:GetName() .. "StatText") - local label = getglobal(statFrame:GetName() .. "Label") - - label:SetText(TEXT(ATTACK_POWER_COLON)) - - -- If no ranged attack then set to n/a - if ( PaperDollFrame.noRanged ) then - text:SetText(NOT_APPLICABLE) - frame.tooltip = nil - return - end - if ( HasWandEquipped() ) then - text:SetText("--") - frame.tooltip = nil - return - end - - local base, posBuff, negBuff = UnitRangedAttackPower("player") - PaperDollFormatStat(RANGED_ATTACK_POWER, base, posBuff, negBuff, frame, text) - frame.tooltipSubtext = format(RANGED_ATTACK_POWER_TOOLTIP, base/ATTACK_POWER_MAGIC_NUMBER) -end - -function BCS:UpdatePaperdollStats(prefix, index) - local stat1 = getglobal(prefix..1) - local stat2 = getglobal(prefix..2) - local stat3 = getglobal(prefix..3) - local stat4 = getglobal(prefix..4) - local stat5 = getglobal(prefix..5) - local stat6 = getglobal(prefix..6) - - stat1:SetScript("OnEnter", nil) - stat2:SetScript("OnEnter", nil) - stat3:SetScript("OnEnter", nil) - stat4:SetScript("OnEnter", nil) - stat4:SetScript("OnEnter", nil) - stat5:SetScript("OnEnter", nil) - stat6:SetScript("OnEnter", nil) - - stat1.tooltip = nil - stat2.tooltip = nil - stat3.tooltip = nil - stat4.tooltip = nil - stat4.tooltip = nil - stat5.tooltip = nil - stat6.tooltip = nil - - stat4:Show() - stat5:Show() - stat6:Show() - - if ( index == "PLAYERSTAT_BASE_STATS" ) then - BCS:SetStat(stat1, 1) - BCS:SetStat(stat2, 2) - BCS:SetStat(stat3, 3) - BCS:SetStat(stat4, 4) - BCS:SetStat(stat5, 5) - BCS:SetArmor(stat6) - elseif ( index == "PLAYERSTAT_MELEE_COMBAT" ) then - BCS:SetDamage(stat1) - BCS:SetAttackSpeed(stat2) - BCS:SetAttackPower(stat3) - BCS:SetRating(stat4, "MELEE") - BCS:SetMeleeCritChance(stat5) - stat6:Hide() - elseif ( index == "PLAYERSTAT_RANGED_COMBAT" ) then - BCS:SetRangedDamage(stat1) - BCS:SetRangedAttackSpeed(stat2) - BCS:SetRangedAttackPower(stat3) - BCS:SetRating(stat4, "RANGED") - BCS:SetRangedCritChance(stat5) - stat6:Hide() - elseif ( index == "PLAYERSTAT_SPELL_COMBAT" ) then - BCS:SetSpellPower(stat1) - BCS:SetRating(stat2, "SPELL") - BCS:SetSpellCritChance(stat3) - BCS:SetHealing(stat4) - BCS:SetManaRegen(stat5) - stat6:Hide() - elseif ( index == "PLAYERSTAT_SPELL_SCHOOLS" ) then - BCS:SetSpellPower(stat1, "Arcane") - BCS:SetSpellPower(stat2, "Fire") - BCS:SetSpellPower(stat3, "Frost") - BCS:SetSpellPower(stat4, "Holy") - BCS:SetSpellPower(stat5, "Nature") - BCS:SetSpellPower(stat6, "Shadow") - elseif ( index == "PLAYERSTAT_DEFENSES" ) then - BCS:SetArmor(stat1) - BCS:SetDefense(stat2) - BCS:SetDodge(stat3) - BCS:SetParry(stat4) - BCS:SetBlock(stat5) - stat6:Hide() - end -end - -local function PlayerStatFrameLeftDropDown_OnClick() - UIDropDownMenu_SetSelectedValue(getglobal(this.owner), this.value) - IndexLeft = this.value - BCSConfig["DropdownLeft"] = IndexLeft - BCS:UpdatePaperdollStats("PlayerStatFrameLeft", this.value) -end - -local function PlayerStatFrameRightDropDown_OnClick() - UIDropDownMenu_SetSelectedValue(getglobal(this.owner), this.value) - IndexRight = this.value - BCSConfig["DropdownRight"] = IndexRight - BCS:UpdatePaperdollStats("PlayerStatFrameRight", this.value) -end - -local function PlayerStatFrameLeftDropDown_Initialize() - local info = {} - local checked = nil - for i=1, getn(BCS.PLAYERSTAT_DROPDOWN_OPTIONS) do - info.text = BCS.L[BCS.PLAYERSTAT_DROPDOWN_OPTIONS[i]] - info.func = PlayerStatFrameLeftDropDown_OnClick - info.value = BCS.PLAYERSTAT_DROPDOWN_OPTIONS[i] - info.checked = checked - info.owner = UIDROPDOWNMENU_OPEN_MENU - UIDropDownMenu_AddButton(info) - end -end - -local function PlayerStatFrameRightDropDown_Initialize() - local info = {} - local checked = nil - for i=1, getn(BCS.PLAYERSTAT_DROPDOWN_OPTIONS) do - info.text = BCS.L[BCS.PLAYERSTAT_DROPDOWN_OPTIONS[i]] - info.func = PlayerStatFrameRightDropDown_OnClick - info.value = BCS.PLAYERSTAT_DROPDOWN_OPTIONS[i] - info.checked = checked - info.owner = UIDROPDOWNMENU_OPEN_MENU - UIDropDownMenu_AddButton(info) - end -end - -function PlayerStatFrameLeftDropDown_OnLoad() - RaiseFrameLevel(this) - RaiseFrameLevel(getglobal(this:GetName() .. "Button")) - UIDropDownMenu_Initialize(this, PlayerStatFrameLeftDropDown_Initialize) - UIDropDownMenu_SetWidth(99, this) - UIDropDownMenu_JustifyText("LEFT") -end - -function PlayerStatFrameRightDropDown_OnLoad() - RaiseFrameLevel(this) - RaiseFrameLevel(getglobal(this:GetName() .. "Button")) - UIDropDownMenu_Initialize(this, PlayerStatFrameRightDropDown_Initialize) - UIDropDownMenu_SetWidth(99, this) - UIDropDownMenu_JustifyText("LEFT") -end - ---pfUI.api.strsplit -function hcstrsplit(delimiter, subject) - if not subject then return nil end - local delimiter, fields = delimiter or ":", {} - local pattern = string.format("([^%s]+)", delimiter) - string.gsub(subject, pattern, function(c) fields[table.getn(fields)+1] = c end) - return unpack(fields) -end - ---Update announcing code taken from pfUI -local major, minor, fix = hcstrsplit(".", tostring(GetAddOnMetadata("BetterCharacterStats", "Version"))) - -local alreadyshown = false -local localversion = tonumber(major*10000 + minor*100 + fix) -local remoteversion = tonumber(bcsupdateavailable) or 0 -local loginchannels = { "BATTLEGROUND", "RAID", "GUILD", "PARTY" } -local groupchannels = { "BATTLEGROUND", "RAID", "PARTY" } - -bcsupdater = CreateFrame("Frame") -bcsupdater:RegisterEvent("CHAT_MSG_ADDON") -bcsupdater:RegisterEvent("PLAYER_ENTERING_WORLD") -bcsupdater:RegisterEvent("PARTY_MEMBERS_CHANGED") -bcsupdater:SetScript("OnEvent", function() - if event == "CHAT_MSG_ADDON" and arg1 == "bcs" then - local v, remoteversion = hcstrsplit(":", arg2) - local remoteversion = tonumber(remoteversion) - if v == "VERSION" and remoteversion then - if remoteversion > localversion then - bcsupdateavailable = remoteversion - if not alreadyshown then - DEFAULT_CHAT_FRAME:AddMessage("|cffffffffBetterCharacterStats|r New version available! https://github.com/Lexiebean/BetterCharacterStats") - alreadyshown = true - end - end - end - --This is a little check that I can use to see if people are actually using the addon. - if v == "PING?" then - for _, chan in pairs(loginchannels) do - SendAddonMessage("bcs", "PONG!:"..GetAddOnMetadata("BetterCharacterStats", "Version"), chan) - end - end - if v == "PONG!" then - --print(arg1 .." "..arg2.." "..arg3.." "..arg4) - end - end - - if event == "PARTY_MEMBERS_CHANGED" then - local groupsize = GetNumRaidMembers() > 0 and GetNumRaidMembers() or GetNumPartyMembers() > 0 and GetNumPartyMembers() or 0 - if ( this.group or 0 ) < groupsize then - for _, chan in pairs(groupchannels) do - SendAddonMessage("bcs", "VERSION:" .. localversion, chan) - end - end - this.group = groupsize - end - - if event == "PLAYER_ENTERING_WORLD" then - if not alreadyshown and localversion < remoteversion then - DEFAULT_CHAT_FRAME:AddMessage("|cffffffffBetterCharacterStats|r New version available! https://github.com/Lexiebean/BetterCharacterStats") - bcsupdateavailable = localversion - alreadyshown = true - end - - for _, chan in pairs(loginchannels) do - SendAddonMessage("bcs", "VERSION:" .. localversion, chan) - end - end - end) \ No newline at end of file +BCS = BCS or {} +BCSConfig = BCSConfig or {} + +local L, IndexLeft, IndexRight +L = BCS.L + +-- Tree of Life aura bonus from other players, your own is calculated in GetHealingPower() +local aura = .0 + +BCS.PLAYERSTAT_DROPDOWN_OPTIONS = { + "PLAYERSTAT_BASE_STATS", + "PLAYERSTAT_MELEE_COMBAT", + "PLAYERSTAT_RANGED_COMBAT", + "PLAYERSTAT_SPELL_COMBAT", + "PLAYERSTAT_SPELL_SCHOOLS", + "PLAYERSTAT_DEFENSES", +} + +BCS.PaperDollFrame = PaperDollFrame + +BCS.Debug = false +BCS.DebugStack = {} + +function BCS:DebugTrace(start, limit) + BCS.Debug = nil + local length = getn(BCS.DebugStack) + if not start then + start = 1 + end + if start > length then + start = length + end + if not limit then + limit = start + 30 + end + + BCS:Print("length: " .. length) + BCS:Print("start: " .. start) + BCS:Print("limit: " .. limit) + + for i = start, length, 1 do + BCS:Print("[" .. i .. "] Event: " .. BCS.DebugStack[i].E) + BCS:Print(format( + "[%d] `- Arguments: %s, %s, %s, %s, %s", + i, + BCS.DebugStack[i].arg1, + BCS.DebugStack[i].arg2, + BCS.DebugStack[i].arg3, + BCS.DebugStack[i].arg4, + BCS.DebugStack[i].arg5 + )) + if i >= limit then + i = length + end + end + +end + +function BCS:Print(message) + ChatFrame2:AddMessage("[BCS] " .. message, 0.63, 0.86, 1.0) +end + +function BCS:OnLoad() + CharacterAttributesFrame:Hide() + PaperDollFrame:UnregisterEvent('UNIT_DAMAGE') + PaperDollFrame:UnregisterEvent('PLAYER_DAMAGE_DONE_MODS') + PaperDollFrame:UnregisterEvent('UNIT_ATTACK_SPEED') + PaperDollFrame:UnregisterEvent('UNIT_RANGEDDAMAGE') + PaperDollFrame:UnregisterEvent('UNIT_ATTACK') + PaperDollFrame:UnregisterEvent('UNIT_STATS') + PaperDollFrame:UnregisterEvent('UNIT_ATTACK_POWER') + PaperDollFrame:UnregisterEvent('UNIT_RANGED_ATTACK_POWER') + + self.Frame = BCSFrame + self.needUpdate = nil + + self.Frame:RegisterEvent("ADDON_LOADED") + self.Frame:RegisterEvent("UNIT_INVENTORY_CHANGED") -- fires when equipment changes + self.Frame:RegisterEvent("CHARACTER_POINTS_CHANGED") -- fires when learning talent + self.Frame:RegisterEvent("PLAYER_AURAS_CHANGED") -- buffs/warrior stances + self.Frame:RegisterEvent("CHAT_MSG_SKILL") --gaining weapon skill + self.Frame:RegisterEvent("CHAT_MSG_ADDON") --needed to recieve aura bonuses from other people +end + +local function PostHookFunction(original,hook) + return function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) + original(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) + hook(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) + end +end + +-- there is less space for player character model with this addon, zoom out and move it up slightly +local z, x, y = -0.2, 0, 0.1 +function BCS_PaperDollFrame_OnEvent(event, unit) + if ( event == "PLAYER_ENTERING_WORLD" ) then + CharacterModelFrame:SetPosition(0, 0, 0) + CharacterModelFrame:SetUnit("player") + CharacterModelFrame:SetPosition(z, x, y) + return + end + if ( unit and unit == "player" ) then + if ( event == "UNIT_MODEL_CHANGED" ) then + CharacterModelFrame:SetPosition(0, 0, 0) + CharacterModelFrame:SetUnit("player") + CharacterModelFrame:SetPosition(z, x, y) + return + end + end +end + +function BCS_PaperDollFrame_OnShow() + CharacterModelFrame:SetPosition(0, 0, 0) + CharacterModelFrame:SetUnit("player") + CharacterModelFrame:SetPosition(z, x, y) +end + +PaperDollFrame_OnShow = PostHookFunction(PaperDollFrame_OnShow, BCS_PaperDollFrame_OnShow) +PaperDollFrame_OnEvent = PostHookFunction(PaperDollFrame_OnEvent, BCS_PaperDollFrame_OnEvent) + +local function strsplit(delimiter, subject) + if not subject then + return nil + end + local delimiter, fields = delimiter or ":", {} + local pattern = string.format("([^%s]+)", delimiter) + string.gsub(subject, pattern, function(c) + fields[table.getn(fields) + 1] = c + end) + return unpack(fields) +end + +-- Scan stuff depending on event, but make sure to scan everything when addon is loaded +function BCS:OnEvent() + --[[if BCS.Debug then + local t = { + E = event, + arg1 = arg1 or "nil", + arg2 = arg2 or "nil", + arg3 = arg3 or "nil", + arg4 = arg4 or "nil", + arg5 = arg5 or "nil", + } + tinsert(BCS.DebugStack, t) + end]] + if event == "CHAT_MSG_ADDON" and arg1 == "bcs" then + BCS.needScanAuras = true + local type, player, amount = strsplit(",", arg2) + if type and player and amount then + if player ~= UnitName("player") then + amount = tonumber(amount) + if type =="TREE" then + --BCS:Print("got tree response amount="..amount) + if amount >= aura then + aura = amount + if BCS.PaperDollFrame:IsVisible() then + BCS:UpdateStats() + else + BCS.needUpdate = true + end + end + end + end + end + elseif event == "PLAYER_AURAS_CHANGED" then + BCS.needScanAuras = true + if not BCS:GetPlayerAura("Tree of Life Aura") then + aura = 0 + end + if BCS.PaperDollFrame:IsVisible() then + BCS:UpdateStats() + else + BCS.needUpdate = true + end + elseif event == "CHARACTER_POINTS_CHANGED" then + BCS.needScanTalents = true + if BCS.PaperDollFrame:IsVisible() then + BCS:UpdateStats() + else + BCS.needUpdate = true + end + elseif event == "CHAT_MSG_SKILL" then + BCS.needScanSkills = true + if BCS.PaperDollFrame:IsVisible() then + BCS:UpdateStats() + else + BCS.needUpdate = true + end + elseif event == "UNIT_INVENTORY_CHANGED" and arg1 == "player" then + BCS.needScanGear = true + BCS.needScanSkills = true + if BCS.PaperDollFrame:IsVisible() then + BCS:UpdateStats() + else + BCS.needUpdate = true + end + elseif event == "ADDON_LOADED" and arg1 == "BetterCharacterStats" then + BCSFrame:UnregisterEvent("ADDON_LOADED") + + local _, race = UnitRace("player") + if race == "Gnome" then + y = 0 + elseif race == "Dwarf" then + y = 0.05 + elseif race == "Troll" then + y = 0.15 + end + + BCS.needScanGear = true + BCS.needScanTalents = true + BCS.needScanAuras = true + BCS.needScanSkills = true + + IndexLeft = BCSConfig["DropdownLeft"] or BCS.PLAYERSTAT_DROPDOWN_OPTIONS[1] + IndexRight = BCSConfig["DropdownRight"] or BCS.PLAYERSTAT_DROPDOWN_OPTIONS[2] + + UIDropDownMenu_SetSelectedValue(PlayerStatFrameLeftDropDown, IndexLeft) + UIDropDownMenu_SetSelectedValue(PlayerStatFrameRightDropDown, IndexRight) + end +end + +--sending messages +local sender = CreateFrame("Frame", "BCSsender") +sender:RegisterEvent("PLAYER_AURAS_CHANGED") +sender:RegisterEvent("CHAT_MSG_ADDON") +sender:SetScript("OnEvent", function() + if not (UnitInParty("player") or UnitInRaid("player")) then + return + end + if event then + local player = UnitName("player") + if event == "PLAYER_AURAS_CHANGED" then + if BCS:GetPlayerAura("Tree of Life Aura") then + SendAddonMessage("bcs", "TREE"..","..player, "PARTY") + --BCS:Print("sent tree request") + end + end + if event == "CHAT_MSG_ADDON" and arg1 == "bcs" then + local type, name, amount = strsplit(",", arg2) + if name ~= player then + local _, treebonus = BCS:GetHealingPower() + if not amount and type == "TREE" and treebonus then + SendAddonMessage("bcs", "TREE"..","..player..","..treebonus, "PARTY") + --BCS:Print("sent tree response, amount="..treebonus) + end + end + end + end +end) + +function BCS:OnShow() + if BCS.needUpdate then + BCS.needUpdate = nil + BCS:UpdateStats() + end +end + +-- debugging / profiling +--local avgV = {} +--local avg = 0 +function BCS:UpdateStats() + --[[if BCS.Debug then + local e = event or "nil" + BCS:Print("Update due to " .. e) + end + local beginTime = debugprofilestop()]] + + BCS:UpdatePaperdollStats("PlayerStatFrameLeft", IndexLeft) + BCS:UpdatePaperdollStats("PlayerStatFrameRight", IndexRight) + BCS.needScanGear = false + BCS.needScanTalents = false + BCS.needScanAuras = false + BCS.needScanSkills = false + --[[local timeUsed = debugprofilestop()-beginTime + table.insert(avgV, timeUsed) + avg = 0 + + for i,v in ipairs(avgV) do + avg = avg + v + end + avg = avg / getn(avgV) + + BCS:Print(format("Average: %d (%d results), Exact: %d", avg, getn(avgV), timeUsed))]] +end + +local function BCS_AddTooltip(statFrame, tooltipExtra) + statFrame:SetScript("OnEnter", function() + GameTooltip:SetOwner(this, "ANCHOR_RIGHT") + GameTooltip:SetText(this.tooltip) + GameTooltip:AddLine(this.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) + if tooltipExtra then + GameTooltip:AddLine(tooltipExtra) + end + GameTooltip:Show() + end) + statFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + end) +end + +local function BCS_AddDamageTooltip(damageText, statFrame, speed, offhandSpeed, ranged) + local rangedAttackSpeed, minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent + local minOffHandDamage, maxOffHandDamage + + if ranged then + rangedAttackSpeed, minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent = UnitRangedDamage("player") + speed = rangedAttackSpeed + else + minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent = UnitDamage("player") + end + + local displayMin = max(floor(minDamage), 1) + local displayMax = max(ceil(maxDamage), 1) + + minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg + maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg + + local baseDamage = (minDamage + maxDamage) * 0.5 + local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent + local totalBonus = (fullDamage - baseDamage) + local damagePerSecond = (max(fullDamage, 1) / speed) + local damageTooltip = max(floor(minDamage), 1) .. " - " .. max(ceil(maxDamage), 1) + local green = "|cff20ff20" + local red = "|cffff2020" + + if (totalBonus == 0) then + if ((displayMin < 100) and (displayMax < 100)) then + damageText:SetText(displayMin .. " - " .. displayMax) + else + damageText:SetText(displayMin .. "-" .. displayMax) + end + else + local color + if (totalBonus > 0) then + color = green + else + color = red + end + if ((displayMin < 100) and (displayMax < 100)) then + damageText:SetText(color .. displayMin .. " - " .. displayMax .. "|r") + else + damageText:SetText(color .. displayMin .. "-" .. displayMax .. "|r") + end + if (physicalBonusPos > 0) then + damageTooltip = damageTooltip .. green .. " +" .. physicalBonusPos .. "|r" + end + if (physicalBonusNeg < 0) then + damageTooltip = damageTooltip .. red .. " " .. physicalBonusNeg .. "|r" + end + if (percent > 1) then + damageTooltip = damageTooltip .. green .. " x" .. floor(percent * 100 + 0.5) .. "%|r" + elseif (percent < 1) then + damageTooltip = damageTooltip .. red .. " x" .. floor(percent * 100 + 0.5) .. "%|r" + end + end + statFrame.damage = damageTooltip + statFrame.attackSpeed = speed + statFrame.dps = damagePerSecond + + -- If there's an offhand speed then add the offhand info to the tooltip + if (offhandSpeed) then + minOffHandDamage = (minOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg + maxOffHandDamage = (maxOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg + + local offhandBaseDamage = (minOffHandDamage + maxOffHandDamage) * 0.5 + local offhandFullDamage = (offhandBaseDamage + physicalBonusPos + physicalBonusNeg) * percent + local offhandDamagePerSecond = (max(offhandFullDamage, 1) / offhandSpeed) + local offhandDamageTooltip = max(floor(minOffHandDamage), 1) .. " - " .. max(ceil(maxOffHandDamage), 1) + if (physicalBonusPos > 0) then + offhandDamageTooltip = offhandDamageTooltip .. green .. " +" .. physicalBonusPos .. "|r" + end + if (physicalBonusNeg < 0) then + offhandDamageTooltip = offhandDamageTooltip .. red .. " " .. physicalBonusNeg .. "|r" + end + if (percent > 1) then + offhandDamageTooltip = offhandDamageTooltip .. green .. " x" .. floor(percent * 100 + 0.5) .. "%|r" + elseif (percent < 1) then + offhandDamageTooltip = offhandDamageTooltip .. red .. " x" .. floor(percent * 100 + 0.5) .. "%|r" + end + statFrame.offhandDamage = offhandDamageTooltip + statFrame.offhandAttackSpeed = offhandSpeed + statFrame.offhandDps = offhandDamagePerSecond + else + statFrame.offhandAttackSpeed = nil + end + + if ranged then + statFrame:SetScript("OnEnter", CharacterRangedDamageFrame_OnEnter) + else + statFrame:SetScript("OnEnter", CharacterDamageFrame_OnEnter) + end + + statFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + end) +end + +function BCS:SetStat(statFrame, statIndex) + local label = getglobal(statFrame:GetName() .. "Label") + local text = getglobal(statFrame:GetName() .. "StatText") + local statIndexTable = { + "STRENGTH", + "AGILITY", + "STAMINA", + "INTELLECT", + "SPIRIT", + } + + statFrame:SetScript("OnEnter", function() + PaperDollStatTooltip("player", statIndexTable[statIndex]) + end) + + statFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + + label:SetText(TEXT(getglobal("SPELL_STAT" .. (statIndex - 1) .. "_NAME")) .. ":") + local stat, effectiveStat, posBuff, negBuff = UnitStat("player", statIndex) + + -- Set the tooltip text + local tooltipText = HIGHLIGHT_FONT_COLOR_CODE .. getglobal("SPELL_STAT" .. (statIndex - 1) .. "_NAME") .. " " + + if ((posBuff == 0) and (negBuff == 0)) then + text:SetText(effectiveStat) + statFrame.tooltip = tooltipText .. effectiveStat .. FONT_COLOR_CODE_CLOSE + else + tooltipText = tooltipText .. effectiveStat + if (posBuff > 0 or negBuff < 0) then + tooltipText = tooltipText .. " (" .. (stat - posBuff - negBuff) .. FONT_COLOR_CODE_CLOSE + end + if (posBuff > 0) then + tooltipText = tooltipText .. FONT_COLOR_CODE_CLOSE .. GREEN_FONT_COLOR_CODE .. "+" .. posBuff .. FONT_COLOR_CODE_CLOSE + end + if (negBuff < 0) then + tooltipText = tooltipText .. RED_FONT_COLOR_CODE .. " " .. negBuff .. FONT_COLOR_CODE_CLOSE + end + if (posBuff > 0 or negBuff < 0) then + tooltipText = tooltipText .. HIGHLIGHT_FONT_COLOR_CODE .. ")" .. FONT_COLOR_CODE_CLOSE + end + statFrame.tooltip = tooltipText + + -- If there are any negative buffs then show the main number in red even if there are + -- positive buffs. Otherwise show in green. + if (negBuff < 0) then + text:SetText(RED_FONT_COLOR_CODE .. effectiveStat .. FONT_COLOR_CODE_CLOSE) + else + text:SetText(GREEN_FONT_COLOR_CODE .. effectiveStat .. FONT_COLOR_CODE_CLOSE) + end + end +end + +function BCS:SetArmor(statFrame) + local base, effectiveArmor, armor, posBuff, negBuff = UnitArmor("player") + local label = getglobal(statFrame:GetName() .. "Label") + local text = getglobal(statFrame:GetName() .. "StatText") + + PaperDollFormatStat(ARMOR, base, posBuff, negBuff, statFrame, text) + label:SetText(TEXT(ARMOR_COLON)) + + local playerLevel = UnitLevel("player") + local armorReduction = effectiveArmor / ((85 * playerLevel) + 400) + armorReduction = 100 * (armorReduction / (armorReduction + 1)) + + statFrame.tooltipSubtext = format(ARMOR_TOOLTIP, playerLevel, armorReduction) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetDamage(statFrame) + local damageText = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + local speed, offhandSpeed = UnitAttackSpeed("player") + + BCS_AddDamageTooltip(damageText, statFrame, speed, offhandSpeed) + + label:SetText(TEXT(DAMAGE_COLON)) +end + +function BCS:SetAttackSpeed(statFrame) + local damageText = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + local speed, offhandSpeed = UnitAttackSpeed("player") + + speed = format("%.2f", speed) + if (offhandSpeed) then + offhandSpeed = format("%.2f", offhandSpeed) + end + local text + if (offhandSpeed) then + text = speed .. " | " .. offhandSpeed + else + text = speed + end + + BCS_AddDamageTooltip(damageText, statFrame, speed, offhandSpeed) + + label:SetText(TEXT(SPEED) .. ":") + damageText:SetText(text) +end + +function BCS:SetAttackPower(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + local tooltipText = HIGHLIGHT_FONT_COLOR_CODE .. MELEE_ATTACK_POWER .. " " + local base, posBuff, negBuff = UnitAttackPower("player") + local effectiveStat = base + posBuff + negBuff + + if ((posBuff == 0) and (negBuff == 0)) then + text:SetText(effectiveStat) + statFrame.tooltip = tooltipText .. base .. FONT_COLOR_CODE_CLOSE + else + tooltipText = tooltipText .. effectiveStat + if (posBuff > 0 or negBuff < 0) then + tooltipText = tooltipText .. " (" .. (base - posBuff - negBuff) .. FONT_COLOR_CODE_CLOSE + end + if (posBuff > 0) then + tooltipText = tooltipText .. FONT_COLOR_CODE_CLOSE .. GREEN_FONT_COLOR_CODE .. "+" .. posBuff .. FONT_COLOR_CODE_CLOSE + end + if (negBuff < 0) then + tooltipText = tooltipText .. RED_FONT_COLOR_CODE .. " " .. negBuff .. FONT_COLOR_CODE_CLOSE + end + if (posBuff > 0 or negBuff < 0) then + tooltipText = tooltipText .. HIGHLIGHT_FONT_COLOR_CODE .. ")" .. FONT_COLOR_CODE_CLOSE + end + statFrame.tooltip = tooltipText + + if (negBuff < 0) then + text:SetText(RED_FONT_COLOR_CODE .. effectiveStat .. FONT_COLOR_CODE_CLOSE) + else + text:SetText(GREEN_FONT_COLOR_CODE .. effectiveStat .. FONT_COLOR_CODE_CLOSE) + end + end + + label:SetText(TEXT(ATTACK_POWER_COLON)) + PaperDollFormatStat(MELEE_ATTACK_POWER, base, posBuff, negBuff, statFrame, text) + statFrame.tooltipSubtext = format(MELEE_ATTACK_POWER_TOOLTIP, max((base + posBuff + negBuff), 0) / ATTACK_POWER_MAGIC_NUMBER) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetSpellPower(statFrame, school) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + local green = "|cff20ff20" + + if school then + local base, _, _, dmgOnly = BCS:GetSpellPower() + local fromSchool = BCS:GetSpellPower(school) + base = base + dmgOnly + local output = base + fromSchool + + if fromSchool > 0 then + output = green .. output .. "|r" + end + + label:SetText(L["SPELL_SCHOOL_" .. strupper(school)]) + text:SetText(output) + + if fromSchool > 0 then + statFrame.tooltip = format(L.SPELL_SCHOOL_SECONDARY_TOOLTIP , school, base + fromSchool, base, fromSchool) + else + statFrame.tooltip = format(L.SPELL_SCHOOL_TOOLTIP , school, base) + end + statFrame.tooltipSubtext = format(L.SPELL_SCHOOL_TOOLTIP_SUB, strlower(school)) + else + local damageAndHealing, secondaryPower, secondaryName, damageOnly = BCS:GetSpellPower() + local total = damageAndHealing + damageOnly + + label:SetText(L.SPELL_POWER_COLON) + if secondaryPower > 0 then + text:SetText(green..total + secondaryPower) + else + text:SetText(total + secondaryPower) + end + + if secondaryPower ~= 0 then + statFrame.tooltip = format(L.SPELL_POWER_SECONDARY_TOOLTIP, (total + secondaryPower), total, secondaryPower, secondaryName) + statFrame.tooltipSubtext = format(L.SPELL_POWER_SECONDARY_TOOLTIP_SUB) + else + statFrame.tooltip = format(L.SPELL_POWER_TOOLTIP, total) + statFrame.tooltipSubtext = format(L.SPELL_POWER_TOOLTIP_SUB) + end + end + + BCS_AddTooltip(statFrame) +end + +function BCS:SetHitRating(statFrame, ratingType) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + local _, class = UnitClass("player") + label:SetText(L.MELEE_HIT_RATING_COLON) + + if ratingType == "MELEE" then + local rating = BCS:GetHitRating() + rating = rating .. "%" + text:SetText(rating) + + statFrame.tooltip = (L.MELEE_HIT_TOOLTIP) + statFrame.tooltipSubtext = format(L.MELEE_HIT_TOOLTIP_SUB) + + elseif ratingType == "RANGED" then + -- If no ranged attack then set to n/a + if UnitHasRelicSlot("player") or not (GetInventoryItemLink("player",18)) then + text:SetText(NOT_APPLICABLE) + return + end + + local rating = BCS:GetRangedHitRating() + rating = rating .. "%" + text:SetText(rating) + + statFrame.tooltip = (L.RANGED_HIT_TOOLTIP) + statFrame.tooltipSubtext = format(L.RANGED_HIT_TOOLTIP_SUB) + + elseif ratingType == "SPELL" then + local spell_hit, spell_hit_fire, spell_hit_frost, spell_hit_arcane, spell_hit_shadow, spell_hit_holy = BCS:GetSpellHitRating() + + text:SetText(spell_hit .. "%") + + statFrame.tooltip = format(L.SPELL_HIT_TOOLTIP) + statFrame.tooltipSubtext = format(L.SPELL_HIT_TOOLTIP_SUB) + + if statFrame.tooltip then + statFrame:SetScript("OnEnter", function() + GameTooltip:SetOwner(this, "ANCHOR_RIGHT") + GameTooltip:SetText(this.tooltip) + GameTooltip:AddLine(this.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) + + if spell_hit_fire > 0 then + GameTooltip:AddLine(format(L.SPELL_SCHOOL_FIRE.." spells: %.f%%", spell_hit + spell_hit_fire)) + end + if spell_hit_frost > 0 then + GameTooltip:AddLine(format(L.SPELL_SCHOOL_FROST.." spells: %.f%%", spell_hit + spell_hit_frost)) + end + if spell_hit_arcane > 0 then + GameTooltip:AddLine(format(L.SPELL_SCHOOL_ARCANE.." spells: %.f%%", spell_hit + spell_hit_arcane)) + end + if spell_hit_shadow > 0 then + if class == "WARLOCK" then + GameTooltip:AddLine(format("Affliction spells: %.f%%", spell_hit + spell_hit_shadow)) + else + GameTooltip:AddLine(format(L.SPELL_SCHOOL_SHADOW.." spells: %.f%%", spell_hit + spell_hit_shadow)) + end + end + if spell_hit_holy > 0 then + GameTooltip:AddLine(format(L.SPELL_SCHOOL_HOLY.." and Discipline spells: %.f%%", spell_hit + spell_hit_holy)) + end + + GameTooltip:Show() + end) + + statFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + end + end + + if ratingType ~= "SPELL" then + BCS_AddTooltip(statFrame) + end +end + +function BCS:SetMeleeCritChance(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + label:SetText(L.MELEE_CRIT_COLON) + text:SetText(format("%.2f%%", BCS:GetCritChance())) + + statFrame.tooltip = (L.MELEE_CRIT_TOOLTIP) + statFrame.tooltipSubtext = (L.MELEE_CRIT_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetWeaponSkill(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + label:SetText(L.WEAPON_SKILL_COLON) + + if OffhandHasWeapon() == 1 then + text:SetText(format("%d |%d", BCS:GetMHWeaponSkill(), BCS:GetOHWeaponSkill())) + else + text:SetText(format("%d", BCS:GetMHWeaponSkill())) + end + + statFrame.tooltip = format(L.MELEE_WEAPON_SKILL_TOOLTIP) + statFrame.tooltipSubtext = format(L.MELEE_WEAPON_SKILL_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetRangedWeaponSkill(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + label:SetText(L.WEAPON_SKILL_COLON) + + -- If no ranged attack then set to n/a + if UnitHasRelicSlot("player") or not (GetInventoryItemLink("player",18)) then + text:SetText(NOT_APPLICABLE) + return + end + + text:SetText(format("%d", BCS:GetRangedWeaponSkill())) + + statFrame.tooltip = format(L.RANGED_WEAPON_SKILL_TOOLTIP) + statFrame.tooltipSubtext = format(L.RANGED_WEAPON_SKILL_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetSpellCritChance(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + local _, class = UnitClass("player") + + label:SetText(L.SPELL_CRIT_COLON) + + local generic = BCS:GetSpellCritChance() + local spell1, spell2, spell3, spell4, spell5, spell6 = BCS:GetSpellCritFromClass(class) + local total1 = generic + spell1 + local total2 = generic + spell2 + local total3 = generic + spell3 + local total4 = generic + spell4 + local total5 = generic + spell5 + local total6 = generic + spell6 + + if total1 > 100 then total1 = 100 end + if total2 > 100 then total2 = 100 end + if total3 > 100 then total3 = 100 end + if total4 > 100 then total4 = 100 end + if total5 > 100 then total5 = 100 end + if total6 > 100 then total6 = 100 end + + text:SetText(format("%.2f%%", generic)) + + -- warlock spells that can crit are all destruction so just add this to generic + if class == "WARLOCK" and spell1 > 0 then + text:SetText(format("%.2f%%", generic + spell1)) + + -- if priest have both talents add lowest to generic cos there will be no more spells left that can crit + elseif class == "PRIEST" and spell3 > 0 and spell2 > 0 then + if spell2 < spell3 then + text:SetText(format("%.2f%%", generic + spell2)) + elseif spell2 >= spell3 then + text:SetText(format("%.2f%%", generic + spell3)) + end + end + + statFrame.tooltip = format(L.SPELL_CRIT_TOOLTIP) + statFrame.tooltipSubtext = format(L.SPELL_CRIT_TOOLTIP_SUB) + + statFrame:SetScript("OnEnter", function() + GameTooltip:SetOwner(this, "ANCHOR_RIGHT") + GameTooltip:SetText(this.tooltip) + GameTooltip:AddLine(this.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) + + if class == "DRUID" then + if spell1 > 0 then + GameTooltip:AddLine(format("Moonfire: %.2f%%", total1)) + end + if spell2 > 0 then + GameTooltip:AddLine(format("Regrowth: %.2f%%", total2)) + end + + elseif class == "PALADIN" then + if spell1 > 0 then + GameTooltip:AddLine(format("Holy Light: %.2f%%", total1)) + end + if spell2 > 0 then + GameTooltip:AddLine(format("Flash of Light: %.2f%%", total2)) + end + if spell3 > 0 then + GameTooltip:AddLine(format("Holy Shock: %.2f%%", total3)) + end + + elseif class == "WARLOCK" then + if spell2 > 0 and spell2 ~= spell1 then + GameTooltip:AddLine(format("Searing Pain: %.2f%%", total2)) + end + + elseif class == "PRIEST" then -- all healing spells are holy, change tooltip if player have both talents + if spell1 > 0 then + if spell3 > 0 then + GameTooltip:AddLine(format("Healing spells: %.2f%%", total1)) + end + GameTooltip:AddLine(format("Holy spells: %.2f%%", total1 + spell3)) + end + if spell2 > 0 then + GameTooltip:AddLine(format("Discipline spells: %.2f%%", total2 + spell3)) + end + if spell3 > 0 then + if spell2 > 0 then + GameTooltip:AddLine(format("Shadow spells: %.2f%%", total3)) + else + GameTooltip:AddLine(format("Offensive spells: %.2f%%", total3)) + end + end + if spell4 > 0 then + GameTooltip:AddLine(format("Prayer of Healing: %.2f%%", total4 + spell1)) + end + + elseif class == "MAGE" then -- dont show specific spells if they have same chance as fire spells + if spell1 > 0 then + GameTooltip:AddLine(format("Arcane spells: %.2f%%", total1)) + end + if spell2 > 0 then + GameTooltip:AddLine(format("Fire spells: %.2f%%", total2)) + end + if spell3 > 0 and spell3 ~= spell2 then + GameTooltip:AddLine(format("Fire Blast: %.2f%%", total3)) + end + if spell4 > 0 and spell4 ~= spell2 then + GameTooltip:AddLine(format("Scorch: %.2f%%", total4)) + end + if spell5 > 0 and spell5 ~= spell2 then + GameTooltip:AddLine(format("Flamestrike: %.2f%%", total5)) + end + if spell6 > 0 then + GameTooltip:AddLine(format("Frozen targets: %.2f%%", total6)) + end + + elseif class == "SHAMAN" then + if spell1 > 0 then + GameTooltip:AddLine(format("Lightning Bolt: %.2f%%", total1)) + end + if spell2 > 0 then + GameTooltip:AddLine(format("Chain Lightning: %.2f%%", total2)) + end + if spell3 > 0 then + GameTooltip:AddLine(format("Lightning Shield: %.2f%%", total3)) + end + if spell4 > 0 then + GameTooltip:AddLine(format("Fire and Frost spells: %.2f%%", total4)) + end + if spell5 > 0 then + GameTooltip:AddLine(format("Healing spells: %.2f%%", total5)) + end + end + + GameTooltip:Show() + end) + + statFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + end) +end + +function BCS:SetRangedCritChance(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + label:SetText(L.RANGED_CRIT_COLON) + + -- If no ranged attack then set to n/a + if UnitHasRelicSlot("player") or not (GetInventoryItemLink("player",18)) then + text:SetText(NOT_APPLICABLE) + return + end + + local crit = BCS:GetRangedCritChance() + -- apply skill difference modifier + local skill = BCS:GetRangedWeaponSkill() + local level = UnitLevel("player") + local skillDiff = skill - (level*5) + + if (skill >= (level*5)) then + crit = crit + (skillDiff * 0.04) + else + crit = crit + (skillDiff * 0.2) + end + + if crit < 0 then + crit = 0 + end + + text:SetText(format("%.2f%%", crit)) + + statFrame.tooltip = (L.RANGED_CRIT_TOOLTIP) + statFrame.tooltipSubtext = (L.RANGED_CRIT_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetHealing(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + local damageAndHealing = BCS:GetSpellPower() + local healingOnly, treebonus, ironclad = BCS:GetHealingPower() + local total = damageAndHealing + healingOnly + local tooltipExtra + + if ironclad > 0 then + tooltipExtra = format("Healing power from Ironclad: %d", ironclad) + end + + if treebonus and aura <= treebonus then + total = total + treebonus + elseif (not treebonus and aura > 0) or (treebonus and aura > treebonus) then + total = total + aura + end + + label:SetText(L.HEAL_POWER_COLON) + text:SetText(format("%d",total)) + + if healingOnly ~= 0 then + statFrame.tooltip = format(L.SPELL_HEALING_POWER_SECONDARY_TOOLTIP, (total), damageAndHealing, healingOnly) + else + statFrame.tooltip = format(L.SPELL_HEALING_POWER_TOOLTIP, (total)) + end + statFrame.tooltipSubtext = format(L.SPELL_HEALING_POWER_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame, tooltipExtra) +end + +function BCS:SetManaRegen(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + label:SetText(L.MANA_REGEN_COLON) + + -- if not a mana user and not a druid set to N/A + local _,class = UnitClass("player") + if (UnitPowerType("player") ~= 0 and not(class=="DRUID"))then + text:SetText(NOT_APPLICABLE) + statFrame.tooltip = nil + return + end + + local base, casting, mp5 = BCS:GetManaRegen() + local mp2 = mp5 * 0.4 + local totalRegen = base + mp2 + local totalRegenWhileCasting = (casting / 100) * base + mp2 + + text:SetText(format("%d (%d)", totalRegen, totalRegenWhileCasting)) + + statFrame.tooltip = format(L.SPELL_MANA_REGEN_TOOLTIP, totalRegen, totalRegenWhileCasting) + statFrame.tooltipSubtext = format(L.SPELL_MANA_REGEN_TOOLTIP_SUB, base, casting, mp5, mp2) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetDodge(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + label:SetText(L.DODGE_COLON) + text:SetText(format("%.2f%%", GetDodgeChance())) + + statFrame.tooltip = format(L.PLAYER_DODGE_TOOLTIP) + statFrame.tooltipSubtext = format(L.PLAYER_DODGE_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetParry(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + label:SetText(L.PARRY_COLON) + text:SetText(format("%.2f%%", GetParryChance())) + + statFrame.tooltip = format(L.PLAYER_PARRY_TOOLTIP) + statFrame.tooltipSubtext = format(L.PLAYER_PARRY_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetBlock(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + local blockChance = GetBlockChance() + local tooltipExtra + + if blockChance > 0 then + tooltipExtra = "Block Value: "..BCS:GetBlockValue() + end + + label:SetText(L.BLOCK_COLON) + text:SetText(format("%.2f%%", blockChance )) + + statFrame.tooltip = format(L.PLAYER_BLOCK_TOOLTIP) + statFrame.tooltipSubtext = format(L.PLAYER_BLOCK_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame, tooltipExtra) +end + +function BCS:SetTotalAvoidance(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + -- apply skill modifier + local base, mod = UnitDefense("player") + local skillDiff = base + mod - UnitLevel("player") * 5 + local missChance = 5 + skillDiff * 0.04 + local total = missChance + GetBlockChance() + GetParryChance() + GetDodgeChance() + + if total < 0 then + total = 0 + end + + label:SetText(L.TOTAL_COLON) + text:SetText(format("%.2f%%", total)) + + statFrame.tooltip = format(L.TOTAL_AVOIDANCE_TOOLTIP) + statFrame.tooltipSubtext = format(L.TOTAL_AVOIDANCE_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetDefense(statFrame) + local base, modifier = UnitDefense("player") + local label = getglobal(statFrame:GetName() .. "Label") + local text = getglobal(statFrame:GetName() .. "StatText") + local posBuff = 0 + local negBuff = 0 + + label:SetText(TEXT(DEFENSE_COLON)) + + if (modifier > 0) then + posBuff = modifier + elseif (modifier < 0) then + negBuff = modifier + end + + PaperDollFormatStat(DEFENSE_COLON, base, posBuff, negBuff, statFrame, text) + statFrame.tooltip = format(L.DEFENSE_TOOLTIP) + statFrame.tooltipSubtext = format(L.DEFENSE_TOOLTIP_SUB) + + BCS_AddTooltip(statFrame) +end + +function BCS:SetRangedDamage(statFrame) + local label = getglobal(statFrame:GetName() .. "Label") + local damageText = getglobal(statFrame:GetName() .. "StatText") + + label:SetText(TEXT(DAMAGE_COLON)) + + -- If no ranged attack then set to n/a + if UnitHasRelicSlot("player") or not (GetInventoryItemLink("player",18)) then + damageText:SetText(NOT_APPLICABLE) + statFrame.damage = nil + return + end + + BCS_AddDamageTooltip(damageText, statFrame, nil, nil, true) +end + +function BCS:SetRangedAttackSpeed(statFrame) + local label = getglobal(statFrame:GetName() .. "Label") + local damageText = getglobal(statFrame:GetName() .. "StatText") + + label:SetText(TEXT(SPEED) .. ":") + + -- If no ranged attack then set to n/a + if UnitHasRelicSlot("player") or not (GetInventoryItemLink("player",18)) then + damageText:SetText(NOT_APPLICABLE) + statFrame.damage = nil + return + end + + BCS_AddDamageTooltip(damageText, statFrame, nil, nil, true) + + damageText:SetText(format("%.2f",UnitRangedDamage("player"))) +end + +function BCS:SetRangedAttackPower(statFrame) + local text = getglobal(statFrame:GetName() .. "StatText") + local label = getglobal(statFrame:GetName() .. "Label") + + label:SetText(TEXT(ATTACK_POWER_COLON)) + + -- If no ranged attack then set to n/a + if UnitHasRelicSlot("player") or not (GetInventoryItemLink("player",18)) then + text:SetText(NOT_APPLICABLE) + statFrame.tooltip = nil + return + end + + if ( HasWandEquipped() ) then + text:SetText("--"); + statFrame.tooltip = nil; + return; + end + + local base, posBuff, negBuff = UnitRangedAttackPower("player") + local tooltipText = HIGHLIGHT_FONT_COLOR_CODE .. RANGED_ATTACK_POWER .. " " + local effectiveStat = base + posBuff + negBuff + + PaperDollFormatStat(RANGED_ATTACK_POWER, base, posBuff, negBuff, statFrame, text) + statFrame.tooltipSubtext = format(RANGED_ATTACK_POWER_TOOLTIP, base / ATTACK_POWER_MAGIC_NUMBER) + + if ((posBuff == 0) and (negBuff == 0)) then + text:SetText(effectiveStat) + statFrame.tooltip = tooltipText .. base .. FONT_COLOR_CODE_CLOSE + else + tooltipText = tooltipText .. effectiveStat + if (posBuff > 0 or negBuff < 0) then + tooltipText = tooltipText .. " (" .. (base - posBuff - negBuff) .. FONT_COLOR_CODE_CLOSE + end + if (posBuff > 0) then + tooltipText = tooltipText .. FONT_COLOR_CODE_CLOSE .. GREEN_FONT_COLOR_CODE .. "+" .. posBuff .. FONT_COLOR_CODE_CLOSE + end + if (negBuff < 0) then + tooltipText = tooltipText .. RED_FONT_COLOR_CODE .. " " .. negBuff .. FONT_COLOR_CODE_CLOSE + end + if (posBuff > 0 or negBuff < 0) then + tooltipText = tooltipText .. HIGHLIGHT_FONT_COLOR_CODE .. ")" .. FONT_COLOR_CODE_CLOSE + end + statFrame.tooltip = tooltipText + + if (negBuff < 0) then + text:SetText(RED_FONT_COLOR_CODE .. effectiveStat .. FONT_COLOR_CODE_CLOSE) + else + text:SetText(GREEN_FONT_COLOR_CODE .. effectiveStat .. FONT_COLOR_CODE_CLOSE) + end + end + + label:SetText(TEXT(ATTACK_POWER_COLON)) + + PaperDollFormatStat(RANGED_ATTACK_POWER, base, posBuff, negBuff, statFrame, text) + statFrame.tooltipSubtext = format(RANGED_ATTACK_POWER_TOOLTIP, max((base + posBuff + negBuff), 0) / ATTACK_POWER_MAGIC_NUMBER) + + BCS_AddTooltip(statFrame) +end + +function BCS:UpdatePaperdollStats(prefix, index) + local stat1 = getglobal(prefix .. 1) + local stat2 = getglobal(prefix .. 2) + local stat3 = getglobal(prefix .. 3) + local stat4 = getglobal(prefix .. 4) + local stat5 = getglobal(prefix .. 5) + local stat6 = getglobal(prefix .. 6) + + stat1:SetScript("OnEnter", nil) + stat2:SetScript("OnEnter", nil) + stat3:SetScript("OnEnter", nil) + stat4:SetScript("OnEnter", nil) + stat4:SetScript("OnEnter", nil) + stat5:SetScript("OnEnter", nil) + stat6:SetScript("OnEnter", nil) + + stat1.tooltip = nil + stat2.tooltip = nil + stat3.tooltip = nil + stat4.tooltip = nil + stat4.tooltip = nil + stat5.tooltip = nil + stat6.tooltip = nil + + stat4:Show() + stat5:Show() + stat6:Show() + + if (index == "PLAYERSTAT_BASE_STATS") then + BCS:SetStat(stat1, 1) + BCS:SetStat(stat2, 2) + BCS:SetStat(stat3, 3) + BCS:SetStat(stat4, 4) + BCS:SetStat(stat5, 5) + BCS:SetArmor(stat6) + elseif (index == "PLAYERSTAT_MELEE_COMBAT") then + BCS:SetWeaponSkill(stat1) + BCS:SetDamage(stat2) + BCS:SetAttackSpeed(stat3) + BCS:SetAttackPower(stat4) + BCS:SetHitRating(stat5, "MELEE") + BCS:SetMeleeCritChance(stat6) + elseif (index == "PLAYERSTAT_RANGED_COMBAT") then + BCS:SetRangedWeaponSkill(stat1) + BCS:SetRangedDamage(stat2) + BCS:SetRangedAttackSpeed(stat3) + BCS:SetRangedAttackPower(stat4) + BCS:SetHitRating(stat5, "RANGED") + BCS:SetRangedCritChance(stat6) + elseif (index == "PLAYERSTAT_SPELL_COMBAT") then + BCS:SetSpellPower(stat1) + BCS:SetHitRating(stat2, "SPELL") + BCS:SetSpellCritChance(stat3) + BCS:SetHealing(stat4) + BCS:SetManaRegen(stat5) + stat6:Hide() + elseif (index == "PLAYERSTAT_SPELL_SCHOOLS") then + BCS:SetSpellPower(stat1, "Arcane") + BCS:SetSpellPower(stat2, "Fire") + BCS:SetSpellPower(stat3, "Frost") + BCS:SetSpellPower(stat4, "Holy") + BCS:SetSpellPower(stat5, "Nature") + BCS:SetSpellPower(stat6, "Shadow") + elseif (index == "PLAYERSTAT_DEFENSES") then + BCS:SetArmor(stat1) + BCS:SetDefense(stat2) + BCS:SetDodge(stat3) + BCS:SetParry(stat4) + BCS:SetBlock(stat5) + BCS:SetTotalAvoidance(stat6) + end +end + +local function PlayerStatFrameLeftDropDown_OnClick() + BCS.needScanGear = true + BCS.needScanTalents = true + BCS.needScanAuras = true + BCS.needScanSkills = true + + UIDropDownMenu_SetSelectedValue(getglobal(this.owner), this.value) + IndexLeft = this.value + BCSConfig["DropdownLeft"] = IndexLeft + BCS:UpdatePaperdollStats("PlayerStatFrameLeft", this.value) + + BCS.needScanGear = false + BCS.needScanTalents = false + BCS.needScanAuras = false + BCS.needScanSkills = false +end + +local function PlayerStatFrameRightDropDown_OnClick() + BCS.needScanGear = true + BCS.needScanTalents = true + BCS.needScanAuras = true + BCS.needScanSkills = true + + UIDropDownMenu_SetSelectedValue(getglobal(this.owner), this.value) + IndexRight = this.value + BCSConfig["DropdownRight"] = IndexRight + BCS:UpdatePaperdollStats("PlayerStatFrameRight", this.value) + + BCS.needScanGear = false + BCS.needScanTalents = false + BCS.needScanAuras = false + BCS.needScanSkills = false +end + +local function PlayerStatFrameLeftDropDown_Initialize() + local info = {} + local checked = nil + for i = 1, getn(BCS.PLAYERSTAT_DROPDOWN_OPTIONS) do + info.text = BCS.L[BCS.PLAYERSTAT_DROPDOWN_OPTIONS[i]] + info.func = PlayerStatFrameLeftDropDown_OnClick + info.value = BCS.PLAYERSTAT_DROPDOWN_OPTIONS[i] + info.checked = checked + info.owner = UIDROPDOWNMENU_OPEN_MENU + if not (UnitHasRelicSlot("player") and info.value == "PLAYERSTAT_RANGED_COMBAT") then + UIDropDownMenu_AddButton(info) + end + end +end + +local function PlayerStatFrameRightDropDown_Initialize() + local info = {} + local checked = nil + for i = 1, getn(BCS.PLAYERSTAT_DROPDOWN_OPTIONS) do + info.text = BCS.L[BCS.PLAYERSTAT_DROPDOWN_OPTIONS[i]] + info.func = PlayerStatFrameRightDropDown_OnClick + info.value = BCS.PLAYERSTAT_DROPDOWN_OPTIONS[i] + info.checked = checked + info.owner = UIDROPDOWNMENU_OPEN_MENU + if not (UnitHasRelicSlot("player") and info.value == "PLAYERSTAT_RANGED_COMBAT") then + UIDropDownMenu_AddButton(info) + end + end +end + +function PlayerStatFrameLeftDropDown_OnLoad() + RaiseFrameLevel(this) + RaiseFrameLevel(getglobal(this:GetName() .. "Button")) + UIDropDownMenu_Initialize(this, PlayerStatFrameLeftDropDown_Initialize) + UIDropDownMenu_SetWidth(99, this) + UIDropDownMenu_JustifyText("LEFT") +end + +function PlayerStatFrameRightDropDown_OnLoad() + RaiseFrameLevel(this) + RaiseFrameLevel(getglobal(this:GetName() .. "Button")) + UIDropDownMenu_Initialize(this, PlayerStatFrameRightDropDown_Initialize) + UIDropDownMenu_SetWidth(99, this) + UIDropDownMenu_JustifyText("LEFT") +end diff --git a/BetterCharacterStats.toc b/BetterCharacterStats.toc index 8eaba5f..42e4641 100644 --- a/BetterCharacterStats.toc +++ b/BetterCharacterStats.toc @@ -1,7 +1,7 @@ ## Interface: 11200 ## Title: BetterCharacterStats -## Author: moh, Bennylava, |cffbe5effLexie|r -## Version: 1.12.5 -## SavedVariablesPerCharacter: BCSConfig bcsupdateavailable +## Author: moh, Bennylava, |cffbe5effLexie|r, Spit, Pepopo +## Version: 1.12.7 +## SavedVariablesPerCharacter: BCSConfig BCScache BetterCharacterStats.xml \ No newline at end of file diff --git a/Localization.lua b/Localization.lua index 115faf7..bafa9c0 100644 --- a/Localization.lua +++ b/Localization.lua @@ -1,172 +1,222 @@ -BCS = BCS or {} - -BCS["L"] = { - - ["([%d.]+)%% chance to crit"] = "([%d.]+)%% chance to crit", - - ["^Set: Improves your chance to hit by (%d)%%."] = "^Set: Improves your chance to hit by (%d)%%.", - ["^Set: Improves your chance to get a critical strike with spells by (%d)%%."] = "^Set: Improves your chance to get a critical strike with spells by (%d)%%.", - ["^Set: Improves your chance to hit with spells by (%d)%%."] = "^Set: Improves your chance to hit with spells by (%d)%%.", - ["^Set: Increases damage and healing done by magical spells and effects by up to (%d+)%."] = "^Set: Increases damage and healing done by magical spells and effects by up to (%d+)%.", - ["^Set: Increases healing done by spells and effects by up to (%d+)%."] = "^Set: Increases healing done by spells and effects by up to (%d+)%.", - ["^Set: Allows (%d+)%% of your Mana regeneration to continue while casting."] = "^Set: Allows (%d+)%% of your Mana regeneration to continue while casting.", - - ["Equip: Improves your chance to hit by (%d)%%."] = "Equip: Improves your chance to hit by (%d)%%.", - ["Equip: Improves your chance to get a critical strike with spells by (%d)%%."] = "Equip: Improves your chance to get a critical strike with spells by (%d)%%.", - ["Equip: Improves your chance to hit with spells by (%d)%%."] = "Equip: Improves your chance to hit with spells by (%d)%%.", - - ["Increases your chance to hit with melee weapons by (%d)%%."] = "Increases your chance to hit with melee weapons by (%d)%%.", - ["Increases your critical strike chance with ranged weapons by (%d)%%."] = "Increases your critical strike chance with ranged weapons by (%d)%%.", - ["Increases hit chance by (%d)%% and increases the chance movement impairing effects will be resisted by an additional %d+%%."] = "Increases hit chance by (%d)%% and increases the chance movement impairing effects will be resisted by an additional %d+%%.", - ["Increases your critical strike chance with all attacks by (%d)%%."] = "Increases your critical strike chance with all attacks by (%d)%%.", - ["Increases spell damage and healing by up to (%d+)%% of your total Spirit."] = "Increases spell damage and healing by up to (%d+)%% of your total Spirit.", - ["Allows (%d+)%% of your Mana regeneration to continue while casting."] = "Allows (%d+)%% of your Mana regeneration to continue while casting.", - ["Reduces the chance that the opponent can resist your Frost and Fire spells by (%d)%%."] = "Reduces the chance that the opponent can resist your Frost and Fire spells by (%d)%%.", - ["Reduces the chance that the opponent can resist your Arcane spells by (%d+)%%."] = "Reduces the chance that the opponent can resist your Arcane spells by (%d+)%%.", - ["Reduces your target's chance to resist your Shadow spells by (%d+)%%."] = "Reduces your target's chance to resist your Shadow spells by (%d+)%%.", - - ["Equip: Increases damage done by Arcane spells and effects by up to (%d+)."] = "Equip: Increases damage done by Arcane spells and effects by up to (%d+).", - ["Equip: Increases damage done by Fire spells and effects by up to (%d+)."] = "Equip: Increases damage done by Fire spells and effects by up to (%d+).", - ["Equip: Increases damage done by Frost spells and effects by up to (%d+)."] = "Equip: Increases damage done by Frost spells and effects by up to (%d+).", - ["Equip: Increases damage done by Holy spells and effects by up to (%d+)."] = "Equip: Increases damage done by Holy spells and effects by up to (%d+).", - ["Equip: Increases damage done by Nature spells and effects by up to (%d+)."] = "Equip: Increases damage done by Nature spells and effects by up to (%d+).", - ["Equip: Increases damage done by Shadow spells and effects by up to (%d+)."] = "Equip: Increases damage done by Shadow spells and effects by up to (%d+).", - - ["Shadow Damage %+(%d+)"] = "Shadow Damage %+(%d+)", - ["Spell Damage %+(%d+)"] = "Spell Damage %+(%d+)", - ["Fire Damage %+(%d+)"] = "Fire Damage %+(%d+)", - ["Frost Damage %+(%d+)"] = "Frost Damage %+(%d+)", - ["Healing Spells %+(%d+)"] = "Healing Spells %+(%d+)", - ["^Healing %+(%d+) and %d+ mana per 5 sec."] = "^Healing %+(%d+) and %d+ mana per 5 sec.", - - ["Equip: Restores (%d+) mana per 5 sec."] = "Equip: Restores (%d+) mana per 5 sec.", - ["+(%d)%% Hit"] = "+(%d)%% Hit", - - -- Random Bonuses // https://wow.gamepedia.com/index.php?title=SuffixId&oldid=204406 - ["^%+(%d+) Damage and Healing Spells"] = "^%+(%d+) Damage and Healing Spells", - ["^%+(%d+) Arcane Spell Damage"] = "^%+(%d+) Arcane Spell Damage", - ["^%+(%d+) Fire Spell Damage"] = "^%+(%d+) Fire Spell Damage", - ["^%+(%d+) Frost Spell Damage"] = "^%+(%d+) Frost Spell Damage", - ["^%+(%d+) Holy Spell Damage"] = "^%+(%d+) Holy Spell Damage", - ["^%+(%d+) Nature Spell Damage"] = "^%+(%d+) Nature Spell Damage", - ["^%+(%d+) Shadow Spell Damage"] = "^%+(%d+) Shadow Spell Damage", - ["^%+(%d+) mana every 5 sec."] = "^%+(%d+) mana every 5 sec.", - ["Restores (%d+) mana every 1 sec."] = "Restores (%d+) mana every 1 sec.", - ["(%d+)%% of your Mana regeneration continuing while casting."] = "(%d+)%% of your Mana regeneration continuing while casting.", - - - -- Mana Oils - ["^Brilliant Mana Oil %((%d+) min%"] = "^Brilliant Mana Oil %((%d+) min%", - ["^Lesser Mana Oil ((%d+) min)"] = "^Lesser Mana Oil ((%d+) min)", - ["^Minor Mana Oil ((%d+) min)"] = "^Minor Mana Oil ((%d+) min)", - - -- snowflakes ZG enchants - ["/Hit %+(%d+)"] = "/Hit %+(%d+)", - ["/Spell Hit %+(%d+)"] = "/Spell Hit %+(%d+)", - ["^Mana Regen %+(%d+)"] = "^Mana Regen %+(%d+)", - ["^Healing %+%d+ and (%d+) mana per 5 sec."] = "^Healing %+%d+ and (%d+) mana per 5 sec.", - ["^%+(%d+) Healing Spells"] = "^%+(%d+) Healing Spells", - ["^%+(%d+) Spell Damage and Healing"] = "^%+(%d+) Spell Damage and Healing", - - -- Mana Oils - ["^Brilliant Mana Oil %((%d+) min%"] = "^Brilliant Mana Oil %((%d+) min%", - - ["Equip: Increases damage and healing done by magical spells and effects by up to (%d+)."] = "Equip: Increases damage and healing done by magical spells and effects by up to (%d+).", - ["Equip: Increases healing done by spells and effects by up to (%d+)."] = "Equip: Increases healing done by spells and effects by up to (%d+).", - - -- auras - ["Chance to hit increased by (%d)%%."] = "Chance to hit increased by (%d)%%.", - ["Magical damage dealt is increased by up to (%d+)."] = "Magical damage dealt is increased by up to (%d+).", - ["Healing done by magical spells is increased by up to (%d+)."] = "Healing done by magical spells is increased by up to (%d+).", - ["Increases healing done by magical spells by up to (%d+) for 3600 sec."] = "Increases healing done by magical spells by up to (%d+) for 3600 sec.", - ["Healing increased by up to (%d+)."] = "Healing increased by up to (%d+).", - ["Healing spells increased by up to (%d+)."] = "Healing spells increased by up to (%d+).", - ["Chance to hit reduced by (%d+)%%."] = "Chance to hit reduced by (%d+)%%.", - ["Chance to hit decreased by (%d+)%% and %d+ Nature damage every %d+ sec."] = "Chance to hit decreased by (%d+)%% and %d+ Nature damage every %d+ sec.", - ["Lowered chance to hit."] = "Lowered chance to hit.", -- 5917 Fumble (25%) - ["Increases hitpoints by 300. 15%% haste to melee attacks. (%d+) mana regen every 5 seconds."] = "Increases hitpoints by 300. 15%% haste to melee attacks. (%d+) mana regen every 5 seconds.", - ["Restores (%d+) mana per 5 sec."] = "Restores (%d+) mana per 5 sec.", - ["Regenerating (%d+) Mana every 5 seconds."] = "Regenerating (%d+) Mana every 5 seconds.", - ["Regenerate (%d+) mana per 5 sec."] = "Regenerate (%d+) mana per 5 sec.", - ["Mana Regeneration increased by (%d+) every 5 seconds."] = "Mana Regeneration increased by (%d+) every 5 seconds.", - ["Improves your chance to hit by (%d+)%%."] = "Improves your chance to hit by (%d+)%%.", - ["Chance for a critical hit with a spell increased by (%d+)%%."] = "Chance for a critical hit with a spell increased by (%d+)%%.", - ["While active, target's critical hit chance with spells and attacks increases by 10%%."] = "While active, target's critical hit chance with spells and attacks increases by 10%%.", - ["Increases attack power by %d+ and chance to hit by (%d+)%%."] = "Increases attack power by %d+ and chance to hit by (%d+)%%.", - ["Holy spell critical hit chance increased by (%d+)%%."] = "Holy spell critical hit chance increased by (%d+)%%.", - ["Destruction spell critical hit chance increased by (%d+)%%."] = "Destruction spell critical hit chance increased by (%d+)%%.", - ["Arcane spell critical hit chance increased by (%d+)%%.\r\nArcane spell critical hit damage increased by (%d+)%%."] = "Arcane spell critical hit chance increased by (%d+)%%.\r\nArcane spell critical hit damage increased by (%d+)%%.", - ["Spell hit chance increased by (%d+)%%."] = "Spell hit chance increased by (%d+)%%.", - - ["Increases chance for a melee, ranged, or spell critical by (%d+)%% and all attributes by %d+."] = "Increases chance for a melee, ranged, or spell critical by (%d+)%% and all attributes by %d+.", - ["Melee critical-hit chance reduced by (%d+)%%.\r\nSpell critical-hit chance reduced by (%d+)%%."] = "Melee critical-hit chance reduced by (%d+)%%.\r\nSpell critical-hit chance reduced by (%d+)%%.", - ["Increases critical chance of spells by 10%%, melee and ranged by 5%% and grants 140 attack power. 120 minute duration."] = "Increases critical chance of spells by 10%%, melee and ranged by 5%% and grants 140 attack power. 120 minute duration.", - ["Holy spell critical hit chance increased by (%d+)%%."] = "Holy spell critical hit chance increased by (%d+)%%.", - ["Destruction spell critical hit chance increased by (%d+)%%."] = "Destruction spell critical hit chance increased by (%d+)%%.", - ["Critical strike chance with spells and melee attacks increased by (%d+)%%."] = "Critical strike chance with spells and melee attacks increased by (%d+)%%.", - - - ["MELEE_HIT_TOOLTIP"] = [[|cffffffffHit|r - Result of an attack made with - melee or ranged weapons.]], - - ["SPELL_HIT_TOOLTIP"] = [[|cffffffffHit|r - Result of an attack made with - spells.]], - - ["SPELL_HIT_SECONDARY_TOOLTIP"] = [[|cffffffffHit %d%% (%d%%|cff20ff20+%d%% %s|r|cffffffff)|r - Result of an attack made with - spells.]], - - ["SPELL_POWER_TOOLTIP"] = [[|cffffffffSpell Power %d|r - Increases damage done by spells and effects.]], - - ["SPELL_POWER_SECONDARY_TOOLTIP"] = [[|cffffffffSpell Power %d (%d|cff20ff20+%d %s|r|cffffffff)|r - Increases damage done by spells and effects.]], - - ["SPELL_HEALING_POWER_TOOLTIP"] = [[|cffffffffHealing Power %d (%d|cff20ff20+%d|r|cffffffff)|r - Increases healing done by spells and effects.]], - - ["SPELL_MANA_REGEN_TOOLTIP"] = [[|cffffffffMana regen: %d |cffBF40BF(%d)|r - Mana regen when not casting and |cffBF40BF(while casting)|r. - Mana regenerates every 2 seconds and the amount - is dependent on your total spirit and MP5. - Spirit Regen: |cff7DF9FF%d|r - %%Regen while casting: |cffBF40BF%d%%|r - MP5 Regen: |cff20ff20%d|r - MP5 Regen (2s): |cff20ff20%d|r]], - - ["ROGUE_MELEE_HIT_TOOLTIP"] = [[ -+5% hit to always hit enemy players. -+8% hit to always hit with your special abilities against a raid boss. -+24.6% hit to always hit a raid boss.]], - - PLAYERSTAT_BASE_STATS = "Base Stats", - PLAYERSTAT_DEFENSES = "Defenses", - PLAYERSTAT_MELEE_COMBAT = "Melee", - PLAYERSTAT_RANGED_COMBAT = "Ranged", - PLAYERSTAT_SPELL_COMBAT = "Spell", - PLAYERSTAT_SPELL_SCHOOLS = "Schools", - - MELEE_HIT_RATING_COLON = "Hit Rating:", - RANGED_HIT_RATING_COLON = "Hit Rating:", - SPELL_HIT_RATING_COLON = "Hit Rating:", - MELEE_CRIT_COLON = "Crit Chance:", - RANGED_CRIT_COLON = "Crit Chance:", - SPELL_CRIT_COLON = "Crit Chance:", - MANA_REGEN_COLON = "Mana regen:", - HEAL_POWER_COLON = "Healing:", - DODGE_COLON = DODGE .. ":", - PARRY_COLON = PARRY .. ":", - BLOCK_COLON = BLOCK .. ":", - - SPELL_POWER_COLON = "Power:", - - SPELL_SCHOOL_ARCANE = "Arcane", - SPELL_SCHOOL_FIRE = "Fire", - SPELL_SCHOOL_FROST = "Frost", - SPELL_SCHOOL_HOLY = "Holy", - SPELL_SCHOOL_NATURE = "Nature", - SPELL_SCHOOL_SHADOW = "Shadow", - -} \ No newline at end of file +BCS = BCS or {} + +BCS["L"] = { + ["%+(%d+)%% Critical Strike"] = "%+(%d+)%% Critical Strike", + ["([%d.]+)%% chance to crit"] = "([%d.]+)%% chance to crit", + + ["^Set: Improves your chance to hit by (%d)%%."] = "^Set: Improves your chance to hit by (%d)%%.", + ["^Set: Improves your chance to get a critical strike with spells by (%d)%%."] = "^Set: Improves your chance to get a critical strike with spells by (%d)%%.", + ["^Set: Improves your chance to hit with spells by (%d)%%."] = "^Set: Improves your chance to hit with spells by (%d)%%.", + ["^Set: Increases damage and healing done by magical spells and effects by up to (%d+)%."] = "^Set: Increases damage and healing done by magical spells and effects by up to (%d+)%.", + ["^Set: Increases healing done by spells and effects by up to (%d+)%."] = "^Set: Increases healing done by spells and effects by up to (%d+)%.", + ["^Set: Allows (%d+)%% of your Mana regeneration to continue while casting."] = "^Set: Allows (%d+)%% of your Mana regeneration to continue while casting.", + ["^Set: Improves your chance to get a critical strike by (%d)%%."] = "^Set: Improves your chance to get a critical strike by (%d)%%.", + + ["Equip: Improves your chance to hit by (%d)%%."] = "Equip: Improves your chance to hit by (%d)%%.", + ["Equip: Improves your chance to get a critical strike with spells by (%d)%%."] = "Equip: Improves your chance to get a critical strike with spells by (%d)%%.", + ["Equip: Improves your chance to hit with spells by (%d)%%."] = "Equip: Improves your chance to hit with spells by (%d)%%.", + ["Equip: Improves your chance to get a critical strike by (%d)%%."] = "Equip: Improves your chance to get a critical strike by (%d)%%.", + ["Increases your chance to hit with melee weapons by (%d)%%."] = "Increases your chance to hit with melee weapons by (%d)%%.", + ["Increases your critical strike chance with ranged weapons by (%d)%%."] = "Increases your critical strike chance with ranged weapons by (%d)%%.", + ["Increases hit chance by (%d)%% and increases the chance movement impairing effects will be resisted by an additional %d+%%."] = "Increases hit chance by (%d)%% and increases the chance movement impairing effects will be resisted by an additional %d+%%.", + ["Increases your critical strike chance with all attacks by (%d)%%."] = "Increases your critical strike chance with all attacks by (%d)%%.", + ["Increases spell damage and healing by up to (%d+)%% of your total Spirit."] = "Increases spell damage and healing by up to (%d+)%% of your total Spirit.", + ["Allows (%d+)%% of your Mana regeneration to continue while casting."] = "Allows (%d+)%% of your Mana regeneration to continue while casting.", + ["Reduces the chance that the opponent can resist your Frost and Fire spells by (%d)%%."] = "Reduces the chance that the opponent can resist your Frost and Fire spells by (%d)%%.", + ["Reduces the chance that the opponent can resist your Arcane spells by (%d+)%%."] = "Reduces the chance that the opponent can resist your Arcane spells by (%d+)%%.", + ["Reduces your target's chance to resist your Shadow spells by (%d+)%%."] = "Reduces your target's chance to resist your Shadow spells by (%d+)%%.", + + ["Equip: Increases damage done by Arcane spells and effects by up to (%d+)."] = "Equip: Increases damage done by Arcane spells and effects by up to (%d+).", + ["Equip: Increases damage done by Fire spells and effects by up to (%d+)."] = "Equip: Increases damage done by Fire spells and effects by up to (%d+).", + ["Equip: Increases damage done by Frost spells and effects by up to (%d+)."] = "Equip: Increases damage done by Frost spells and effects by up to (%d+).", + ["Equip: Increases damage done by Holy spells and effects by up to (%d+)."] = "Equip: Increases damage done by Holy spells and effects by up to (%d+).", + ["Equip: Increases damage done by Nature spells and effects by up to (%d+)."] = "Equip: Increases damage done by Nature spells and effects by up to (%d+).", + ["Equip: Increases damage done by Shadow spells and effects by up to (%d+)."] = "Equip: Increases damage done by Shadow spells and effects by up to (%d+).", + + ["Shadow Damage %+(%d+)"] = "Shadow Damage %+(%d+)", + ["Spell Damage %+(%d+)"] = "Spell Damage %+(%d+)", + ["Fire Damage %+(%d+)"] = "Fire Damage %+(%d+)", + ["Frost Damage %+(%d+)"] = "Frost Damage %+(%d+)", + ["Healing Spells %+(%d+)"] = "Healing Spells %+(%d+)", + ["^Healing %+(%d+) and %d+ mana per 5 sec."] = "^Healing %+(%d+) and %d+ mana per 5 sec.", + + ["Equip: Restores (%d+) mana per 5 sec."] = "Equip: Restores (%d+) mana per 5 sec.", + ["+(%d)%% Ranged Hit"] = "+(%d)%% Ranged Hit", + + -- Random Bonuses // https://wow.gamepedia.com/index.php?title=SuffixId&oldid=204406 + ["^%+(%d+) Damage and Healing Spells"] = "^%+(%d+) Damage and Healing Spells", + ["^%+(%d+) Arcane Spell Damage"] = "^%+(%d+) Arcane Spell Damage", + ["^%+(%d+) Fire Spell Damage"] = "^%+(%d+) Fire Spell Damage", + ["^%+(%d+) Frost Spell Damage"] = "^%+(%d+) Frost Spell Damage", + ["^%+(%d+) Holy Spell Damage"] = "^%+(%d+) Holy Spell Damage", + ["^%+(%d+) Nature Spell Damage"] = "^%+(%d+) Nature Spell Damage", + ["^%+(%d+) Shadow Spell Damage"] = "^%+(%d+) Shadow Spell Damage", + ["^%+(%d+) mana every 5 sec."] = "^%+(%d+) mana every 5 sec.", + ["Restores (%d+) mana every 1 sec."] = "Restores (%d+) mana every 1 sec.", + ["(%d+)%% of your Mana regeneration continuing while casting."] = "(%d+)%% of your Mana regeneration continuing while casting.", + ["(%d+)%% of your mana regeneration to continue while casting."] = "(%d+)%% of your mana regeneration to continue while casting.", + + -- Mana Oils + ["^Brilliant Mana Oil %((%d+) min%"] = "^Brilliant Mana Oil %((%d+) min%", + ["^Lesser Mana Oil ((%d+) min)"] = "^Lesser Mana Oil ((%d+) min)", + ["^Minor Mana Oil ((%d+) min)"] = "^Minor Mana Oil ((%d+) min)", + + -- snowflakes ZG enchants + ["/Hit %+(%d+)"] = "/Hit %+(%d+)", + ["/Spell Hit %+(%d+)"] = "/Spell Hit %+(%d+)", + ["^Mana Regen %+(%d+)"] = "^Mana Regen %+(%d+)", + ["^Healing %+%d+ and (%d+) mana per 5 sec."] = "^Healing %+%d+ and (%d+) mana per 5 sec.", + ["^%+(%d+) Healing Spells"] = "^%+(%d+) Healing Spells", + ["^%+(%d+) Spell Damage and Healing"] = "^%+(%d+) Spell Damage and Healing", + + ["Equip: Increases damage and healing done by magical spells and effects by up to (%d+)."] = "Equip: Increases damage and healing done by magical spells and effects by up to (%d+).", + ["Equip: Increases healing done by spells and effects by up to (%d+)."] = "Equip: Increases healing done by spells and effects by up to (%d+).", + + -- auras + ["Chance to hit increased by (%d)%%."] = "Chance to hit increased by (%d)%%.", + ["Magical damage dealt is increased by up to (%d+)."] = "Magical damage dealt is increased by up to (%d+).", + ["Healing done by magical spells is increased by up to (%d+)."] = "Healing done by magical spells is increased by up to (%d+).", + ["Increases healing done by magical spells by up to (%d+) for 3600 sec."] = "Increases healing done by magical spells by up to (%d+) for 3600 sec.", + ["Healing increased by up to (%d+)."] = "Healing increased by up to (%d+).", + ["Healing spells increased by up to (%d+)."] = "Healing spells increased by up to (%d+).", + ["Chance to hit reduced by (%d+)%%."] = "Chance to hit reduced by (%d+)%%.", + ["Chance to hit decreased by (%d+)%% and %d+ Nature damage every %d+ sec."] = "Chance to hit decreased by (%d+)%% and %d+ Nature damage every %d+ sec.", + ["Lowered chance to hit."] = "Lowered chance to hit.", -- 5917 Fumble (25%) + ["Increases hitpoints by 300. 15%% haste to melee attacks. (%d+) mana regen every 5 seconds."] = "Increases hitpoints by 300. 15%% haste to melee attacks. (%d+) mana regen every 5 seconds.", + ["Restores (%d+) mana per 5 sec."] = "Restores (%d+) mana per 5 sec.", + ["Regenerating (%d+) Mana every 5 seconds."] = "Regenerating (%d+) Mana every 5 seconds.", + ["Regenerate (%d+) mana per 5 sec."] = "Regenerate (%d+) mana per 5 sec.", + ["Mana Regeneration increased by (%d+) every 5 seconds."] = "Mana Regeneration increased by (%d+) every 5 seconds.", + ["Improves your chance to hit by (%d+)%%."] = "Improves your chance to hit by (%d+)%%.", + ["Chance for a critical hit with a spell increased by (%d+)%%."] = "Chance for a critical hit with a spell increased by (%d+)%%.", + ["While active, target's critical hit chance with spells and attacks increases by 10%%."] = "While active, target's critical hit chance with spells and attacks increases by 10%%.",--?? + ["Increases attack power by %d+ and chance to hit by (%d+)%%."] = "Increases attack power by %d+ and chance to hit by (%d+)%%.", + ["Holy spell critical hit chance increased by (%d+)%%."] = "Holy spell critical hit chance increased by (%d+)%%.", + ["Destruction spell critical hit chance increased by (%d+)%%."] = "Destruction spell critical hit chance increased by (%d+)%%.", + ["Arcane spell critical hit chance increased by (%d+)%%.\r\nArcane spell critical hit damage increased by (%d+)%%."] = "Arcane spell critical hit chance increased by (%d+)%%.\r\nArcane spell critical hit damage increased by (%d+)%%.", + ["Spell hit chance increased by (%d+)%%."] = "Spell hit chance increased by (%d+)%%.", + ["Agility increased by 25, Critical hit chance increases by (%d)%%."] = "Agility increased by 25, Critical hit chance increases by (%d)%%.", + ["Increases chance for a melee, ranged, or spell critical by (%d+)%% and all attributes by %d+."] = "Increases chance for a melee, ranged, or spell critical by (%d+)%% and all attributes by %d+.", + ["Melee critical-hit chance reduced by (%d+)%%.\r\nSpell critical-hit chance reduced by (%d+)%%."] = "Melee critical-hit chance reduced by (%d+)%%.\r\nSpell critical-hit chance reduced by (%d+)%%.", + ["Increases critical chance of spells by 10%%, melee and ranged by 5%% and grants 140 attack power. 120 minute duration."] = "Increases critical chance of spells by 10%%, melee and ranged by 5%% and grants 140 attack power. 120 minute duration.", + ["Critical strike chance with spells and melee attacks increased by (%d+)%%."] = "Critical strike chance with spells and melee attacks increased by (%d+)%%.", + ["Increases ranged and melee critical chance by (%d+)%%."] = "Increases ranged and melee critical chance by (%d+)%%.", + ["Equip: Increases the critical chance provided by Leader of the Pack and Moonkin Aura by (%d)%%."] = "Equip: Increases the critical chance provided by Leader of the Pack and Moonkin Aura by (%d)%%.", + -- druid + ["Increases the damage and critical strike chance of your Moonfire spell by (%d+)%%."] = "Increases the damage and critical strike chance of your Moonfire spell by (%d+)%%.", + ["Increases the critical effect chance of your Regrowth spell by (%d+)%%."] = "Increases the critical effect chance of your Regrowth spell by (%d+)%%.", + -- paladin + ["Increases your healing power by (%d+)%% of your Armor."] = "Increases your healing power by (%d+)%% of your Armor.", + ["Increases the critical effect chance of your Holy Light and Flash of Light by (%d+)%%."] = "Increases the critical effect chance of your Holy Light and Flash of Light by (%d+)%%.", + ["Improves your chance to get a critical strike with Holy Shock by (%d+)%%."] = "Improves your chance to get a critical strike with Holy Shock by (%d+)%%.", + -- shaman + ["Increases the critical strike chance of your Lightning Bolt and Chain Lightning spells by an additional (%d+)%%."] = "Increases the critical strike chance of your Lightning Bolt and Chain Lightning spells by an additional (%d+)%%.", + ["Increases the critical effect chance of your healing and lightning spells by (%d+)%%."] = "Increases the critical effect chance of your healing and lightning spells by (%d+)%%.", + -- warlock + ["Increases the critical strike chance of your Destruction spells by (%d+)%%."] = "Increases the critical strike chance of your Destruction spells by (%d+)%%.", + ["Increases the critical strike chance of your Searing Pain spell by (%d+)%%."] = "Increases the critical strike chance of your Searing Pain spell by (%d+)%%.", + ["Reduces the chance for enemies to resist your Affliction spells by (%d+)%%."] = "Reduces the chance for enemies to resist your Affliction spells by (%d+)%%.", + -- mage + ["Increases the critical strike chance of your Arcane Explosion and Arcane Missiles spells by an additional (%d+)%%."] = "Increases the critical strike chance of your Arcane Explosion and Arcane Missiles spells by an additional (%d+)%%.", + ["Increases the critical strike chance of your Fire Blast and Scorch spells by (%d+)%%."] = "Increases the critical strike chance of your Fire Blast and Scorch spells by (%d+)%%.", + ["Increases the critical strike chance of your Flamestrike spell by (%d+)%%."] = "Increases the critical strike chance of your Flamestrike spell by (%d+)%%.", + ["Increases the critical strike chance of your Fire spells by (%d+)%%."] = "Increases the critical strike chance of your Fire spells by (%d+)%%.", + ["Increases the critical strike chance of all your spells against frozen targets by (%d+)%%."] = "Increases the critical strike chance of all your spells against frozen targets by (%d+)%%.", + ["Increases your spell damage and critical srike chance by (%d+)%%."] = "Increases your spell damage and critical srike chance by (%d+)%%.", + ["Increases critical strike chance from Fire damage spells by (%d+)%%."] = "Increases critical strike chance from Fire damage spells by (%d+)%%.", + -- priest + ["Reduces the chance for enemies to resist your Holy and Discipline spells by (%d+)%%."] = "Reduces the chance for enemies to resist your Holy and Discipline spells by (%d+)%%.", + ["Increases the critical effect chance of your Holy and Discipline spells by (%d+)%%."] = "Increases the critical effect chance of your Holy and Discipline spells by (%d+)%%.", + ["Increases your spell damage by %d+%% and the critical strike chance of your offensive spells by (%d)%%"] = "Increases your spell damage by %d+%% and the critical strike chance of your offensive spells by (%d)%%", + ["^Set: Improves your chance to get a critical strike with Holy spells by (%d)%%."] = "^Set: Improves your chance to get a critical strike with Holy spells by (%d)%%.", + ["^Set: Increases your chance of a critical hit with Prayer of Healing by (%d+)%%."] = "^Set: Increases your chance of a critical hit with Prayer of Healing by (%d+)%%.", + --defense + ["DEFENSE_TOOLTIP"] = [[|cffffffffDefense Skill|r]], + ["DEFENSE_TOOLTIP_SUB"] = [[Higher defense makes you harder to hit and makes monsters less likely to land a crushing blow.]], + + ["PLAYER_DODGE_TOOLTIP"] = [[|cffffffffDodge|r]], + ["PLAYER_DODGE_TOOLTIP_SUB"] = [[Your chance to dodge enemy melee attacks. + Players can not dodge attacks from behind.]], + + ["PLAYER_PARRY_TOOLTIP"] = [[|cffffffffParry|r]], + ["PLAYER_PARRY_TOOLTIP_SUB"] = [[Your chance to parry enemy melee attacks. + Players and monsters can not parry attacks from behind.]], + + ["PLAYER_BLOCK_TOOLTIP"] = [[|cffffffffBlock|r]], + ["PLAYER_BLOCK_TOOLTIP_SUB"] = [[Your chance to block enemy physical attacks with a shield. + Players and monsters can not block attacks from behind.]], + + ["TOTAL_AVOIDANCE_TOOLTIP"] = [[|cffffffffAvoidance|r]], + ["TOTAL_AVOIDANCE_TOOLTIP_SUB"] = [[Your total chance to avoid enemy physical attacks.]], + + --melee + ["MELEE_HIT_TOOLTIP"] = [[|cffffffffMelee Hit|r]], + ["MELEE_HIT_TOOLTIP_SUB"] = [[Increases chance to hit with melee attacks.]], + ["MELEE_CRIT_TOOLTIP"] = [[|cffffffffMelee Crit|r]], + ["MELEE_CRIT_TOOLTIP_SUB"] = [[Your chance to land a critical strike with melee attacks.]], + ["MELEE_WEAPON_SKILL_TOOLTIP"] = [[|cffffffffMelee Weapon Skill|r]], + ["MELEE_WEAPON_SKILL_TOOLTIP_SUB"] = [[Higher weapon skill reduces your chance to miss and increases damage of your glancing blows, while using melee weapons.]], + --ranged + ["RANGED_WEAPON_SKILL_TOOLTIP"] = [[|cffffffffRanged Weapon Skill|r]], + ["RANGED_WEAPON_SKILL_TOOLTIP_SUB"] = [[Higher weapon skill reduces your chance to miss with a ranged weapon.]], + ["RANGED_CRIT_TOOLTIP"] = [[|cffffffffRanged Crit|r]], + ["RANGED_CRIT_TOOLTIP_SUB"] = [[Your chance to land a critical strike with ranged weapons.]], + ["RANGED_HIT_TOOLTIP"] = [[|cffffffffRanged Hit|r]], + ["RANGED_HIT_TOOLTIP_SUB"] = [[Increases chance to hit with ranged weapons.]], + + --spells + ["SPELL_HIT_TOOLTIP"] = [[|cffffffffSpell Hit|r]], + ["SPELL_HIT_SECONDARY_TOOLTIP"] = [[|cffffffffSpell Hit (%d%%|cff20ff20+%d%% %s|r|cffffffff)|r]], + ["SPELL_HIT_TOOLTIP_SUB"] = [[Increases chance to land a harmful spell.]], + + ["SPELL_CRIT_TOOLTIP"] = [[|cffffffffSpell Crit|r]], + ["SPELL_CRIT_TOOLTIP_SUB"] = [[Your chance to land a critical strike with spells.]], + + ["SPELL_POWER_TOOLTIP"] = [[|cffffffffSpell Power %d|r]], + ["SPELL_POWER_TOOLTIP_SUB"] = [[Increases damage done by spells and effects.]], + ["SPELL_POWER_SECONDARY_TOOLTIP"] = [[|cffffffffSpell Power %d (%d|cff20ff20+%d %s|r|cffffffff)|r]], + ["SPELL_POWER_SECONDARY_TOOLTIP_SUB"] = [[Increases damage done by spells and effects.]], + + ["SPELL_SCHOOL_TOOLTIP"] = [[|cffffffff%s Spell Power %s|r]], + ["SPELL_SCHOOL_SECONDARY_TOOLTIP"] = [[|cffffffff%s Spell Power %d (%d|cff20ff20+%d|r|cffffffff)|r]], + ["SPELL_SCHOOL_TOOLTIP_SUB"] = [[Increases damage done by %s spells and effects.]], + + ["SPELL_HEALING_POWER_TOOLTIP"] = [[|cffffffffHealing Power %d|r]], + ["SPELL_HEALING_POWER_SECONDARY_TOOLTIP"] = [[|cffffffffHealing Power %d (%d|cff20ff20+%d|r|cffffffff)|r]], + ["SPELL_HEALING_POWER_TOOLTIP_SUB"] = [[Increases healing done by spells and effects.]], + + ["SPELL_MANA_REGEN_TOOLTIP"] = [[|cffffffffMana regen: %d |cffffffff(%d)|r]], + ["SPELL_MANA_REGEN_TOOLTIP_SUB"] = [[Mana regen when not casting and (while casting). + Mana regenerates every 2 seconds and the amount is dependent on your total spirit and MP5. + Spirit Regen: %d + Regen while casting: %d%% + MP5 Regen: %d + MP5 Regen (2s): %d]], + + PLAYERSTAT_BASE_STATS = "Base Stats", + PLAYERSTAT_DEFENSES = "Defenses", + PLAYERSTAT_MELEE_COMBAT = "Melee", + PLAYERSTAT_RANGED_COMBAT = "Ranged", + PLAYERSTAT_SPELL_COMBAT = "Spell", + PLAYERSTAT_SPELL_SCHOOLS = "Schools", + WEAPON_SKILL_COLON = "Skill:", + MELEE_HIT_RATING_COLON = "Hit Rating:", + RANGED_HIT_RATING_COLON = "Hit Rating:", + SPELL_HIT_RATING_COLON = "Hit Rating:", + MELEE_CRIT_COLON = "Crit Chance:", + RANGED_CRIT_COLON = "Crit Chance:", + SPELL_CRIT_COLON = "Crit Chance:", + MANA_REGEN_COLON = "Mana regen:", + HEAL_POWER_COLON = "Healing:", + DODGE_COLON = DODGE .. ":", + PARRY_COLON = PARRY .. ":", + BLOCK_COLON = BLOCK .. ":", + TOTAL_COLON = "Total:", + SPELL_POWER_COLON = "Power:", + SPELL_SCHOOL_ARCANE = "Arcane", + SPELL_SCHOOL_FIRE = "Fire", + SPELL_SCHOOL_FROST = "Frost", + SPELL_SCHOOL_HOLY = "Holy", + SPELL_SCHOOL_NATURE = "Nature", + SPELL_SCHOOL_SHADOW = "Shadow", +} diff --git a/README.md b/README.md index 8e36f63..ebcce4e 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,20 @@ -BetterCharacterStats - a World of Warcraft (1.12.1) AddOn -=================================================== - -![preview](https://raw.githubusercontent.com/yutsuku/BetterCharacterStats/gh-pages/images/BetterCharacterStats.png) - -Installation: - -Put "BetterCharacterStats" folder into ".../World of Warcraft/Interface/AddOns/". -Create AddOns folder if necessary - -After Installation directory tree should look like the following - - World of Warcraft - `- Interface - `- AddOns - `- BetterCharacterStats - |- README.md - |- BetterCharacterStats.lua - |- BetterCharacterStats.toc - |- BetterCharacterStats.xml - |- helper.lua - `- Localization.lua - -Features: -- Displays character statistics in one place (just like the character tab in Burning Crusade). - -Known Issues: -- May be lacking things related to spell hit/spell crit. - -Thanks to: -- All people who keeps reporting to me that some things are missing or are broken. \ No newline at end of file +# BetterCharacterStats for Turtle WoW +This addon shows your character stats that are not present in default UI.
+This version is designed specifically for TurtleWoW and its custom changes. +## Features + - Base stats: strength, agility, stamina, intellect, spirit, armor + - Melee/Ranged: weapon skill, damage, attack speed, attack power, hit, crit + - Spells: spell power, spell hit, crit, healing power, mana regeneration + - Schools: your spell power for each school of magic + - Defenses: armor, defense skill, dodge, parry, block, avoidance +## Preview +![preview1](https://github.com/user-attachments/assets/d342aed0-812c-40f9-a4d4-9b33eb48caa3) + +## Installation +1. Click Code -> Download ZIP +2. Extract ZIP file into your Interface/AddOnns folder, remove ``-main`` +3. Restart the game +## Feedback +If you find any bugs, inaccuracies, typos or just want to suggest something, open an [issue](https://github.com/Otari98/BetterCharacterStats/issues) on GitHub +## Thanks to original author and all contributors +Moh, Bennylava, Lexie, Spit, Pepopo diff --git a/helper.lua b/helper.lua index 2bb87c0..b3d0e9b 100644 --- a/helper.lua +++ b/helper.lua @@ -21,6 +21,65 @@ local function tContains(table, item) return nil end +BCScache = BCScache or { + ["gear"] = { + damage_and_healing = 0, + arcane = 0, + fire = 0, + frost = 0, + holy = 0, + nature = 0, + shadow = 0, + healing = 0, + mp5 = 0, + casting = 0, + spell_hit = 0, + spell_crit = 0, + hit = 0, + ranged_hit = 0, + ranged_crit = 0 + }, + ["talents"] = { + damage_and_healing = 0, + healing = 0, + spell_hit = 0, + spell_hit_fire = 0, + spell_hit_frost = 0, + spell_hit_arcane = 0, + spell_hit_shadow = 0, + spell_hit_holy = 0, + spell_crit = 0, + casting = 0, + mp5 = 0, + hit = 0, + ranged_hit = 0, + ranged_crit = 0 + }, + ["auras"] = { + damage_and_healing = 0, + only_damage = 0, -- +dmg to all schools, needed to calculate healing + arcane = 0, + fire = 0, + frost = 0, + holy = 0, + nature = 0, + shadow = 0, + healing = 0, + mp5 = 0, + casting = 0, + spell_hit = 0, + spell_crit = 0, + hit = 0, + ranged_hit = 0, + ranged_crit = 0, + hit_debuff = 0 + }, + ["skills"] = { + mh = 0, + oh = 0, + ranged = 0 + } +} function BCS:GetPlayerAura(searchText, auraType) if not auraType then -- buffs @@ -30,9 +89,7 @@ function BCS:GetPlayerAura(searchText, auraType) local index = GetPlayerBuff(i, 'HELPFUL') if index > -1 then BCS_Tooltip:SetPlayerBuff(index) - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do + for line=1, BCS_Tooltip:NumLines() do local left = getglobal(BCS_Prefix .. "TextLeft" .. line) if left:GetText() then if left:GetText() == "Power of the Guardian" and searchText == "Power of the Guardian Crit" then @@ -52,9 +109,7 @@ function BCS:GetPlayerAura(searchText, auraType) local index = GetPlayerBuff(i, auraType) if index > -1 then BCS_Tooltip:SetPlayerBuff(index) - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do + for line=1, BCS_Tooltip:NumLines() do local left = getglobal(BCS_Prefix .. "TextLeft" .. line) if left:GetText() then local value = {strfind(left:GetText(), searchText)} @@ -68,174 +123,128 @@ function BCS:GetPlayerAura(searchText, auraType) end end -local Cache_GetHitRating_Tab, Cache_GetHitRating_Talent -local hit_debuff = 0 function BCS:GetHitRating(hitOnly) local Hit_Set_Bonus = {} - local hit = 0; - local MAX_INVENTORY_SLOTS = 19; - hit_debuff = 0; - - for slot=0, MAX_INVENTORY_SLOTS do - local hasItem = BCS_Tooltip:SetInventoryItem("player", slot) - if hasItem then - local MAX_LINES = BCS_Tooltip:NumLines() - local SET_NAME = nil - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Equip: Improves your chance to hit by (%d)%%."]) - if value then - hit = hit + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["/Hit %+(%d+)"]) - if value then - hit = hit + tonumber(value) - end - _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") - if value then - SET_NAME = value - end - _,_, value = strfind(left:GetText(), L["^Set: Improves your chance to hit by (%d)%%."]) - if value and SET_NAME and not tContains(Hit_Set_Bonus, SET_NAME) then - tinsert(Hit_Set_Bonus, SET_NAME) - hit = hit + tonumber(value) - line = MAX_LINES + local hit = 0 + + if BCS.needScanGear then + BCScache["gear"].hit = 0 + --scan gear + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + local SET_NAME = nil + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), L["Equip: Improves your chance to hit by (%d)%%."]) + if value then + BCScache["gear"].hit = BCScache["gear"].hit + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["/Hit %+(%d+)"]) + if value then + BCScache["gear"].hit = BCScache["gear"].hit + tonumber(value) + end + + _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + if value then + SET_NAME = value + end + _,_, value = strfind(left:GetText(), L["^Set: Improves your chance to hit by (%d)%%."]) + if value and SET_NAME and not tContains(Hit_Set_Bonus, SET_NAME) then + tinsert(Hit_Set_Bonus, SET_NAME) + BCScache["gear"].hit = BCScache["gear"].hit + tonumber(value) + break + end end end end - end end - -- buffs - local _, _, hitFromAura = BCS:GetPlayerAura(L["Chance to hit increased by (%d)%%."]) - if hitFromAura then - hit = hit + tonumber(hitFromAura) - end - _, _, hitFromAura = BCS:GetPlayerAura(L["Improves your chance to hit by (%d+)%%."]) - if hitFromAura then - hit = hit + tonumber(hitFromAura) - end - _, _, hitFromAura = BCS:GetPlayerAura(L["Increases attack power by %d+ and chance to hit by (%d+)%%."]) - if hitFromAura then - hit = hit + tonumber(hitFromAura) - end - -- debuffs - _, _, hitFromAura = BCS:GetPlayerAura(L["Chance to hit reduced by (%d+)%%."], 'HARMFUL') - if hitFromAura then - hit_debuff = hit_debuff + tonumber(hitFromAura) - end - _, _, hitFromAura = BCS:GetPlayerAura(L["Chance to hit decreased by (%d+)%% and %d+ Nature damage every %d+ sec."], 'HARMFUL') - if hitFromAura then - hit_debuff = hit_debuff + tonumber(hitFromAura) - end - hitFromAura = BCS:GetPlayerAura(L["Lowered chance to hit."], 'HARMFUL') - if hitFromAura then - hit_debuff = hit_debuff + 25 - end - - local MAX_TABS = GetNumTalentTabs() - -- speedup - if Cache_GetHitRating_Tab and Cache_GetHitRating_Talent then - BCS_Tooltip:SetTalent(Cache_GetHitRating_Tab, Cache_GetHitRating_Talent) - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - -- rogues - local _,_, value = strfind(left:GetText(), L["Increases your chance to hit with melee weapons by (%d)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(Cache_GetHitRating_Tab, Cache_GetHitRating_Talent) - if value and rank > 0 then - hit = hit + tonumber(value) - line = MAX_LINES - end - - -- hunters - _,_, value = strfind(left:GetText(), L["Increases hit chance by (%d)%% and increases the chance movement impairing effects will be resisted by an additional %d+%%."]) - name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(Cache_GetHitRating_Tab, Cache_GetHitRating_Talent) - if value and rank > 0 then - hit = hit + tonumber(value) - line = MAX_LINES - end - end + if BCS.needScanAuras then + BCScache["auras"].hit = 0 + BCScache["auras"].hit_debuff = 0 + -- buffs + local _, _, hitFromAura = BCS:GetPlayerAura(L["Chance to hit increased by (%d)%%."]) + if hitFromAura then + BCScache["auras"].hit = BCScache["auras"].hit + tonumber(hitFromAura) end - - if not hitOnly then - hit = hit - hit_debuff - if hit < 0 then hit = 0 end - return hit - else - return hit + _, _, hitFromAura = BCS:GetPlayerAura(L["Improves your chance to hit by (%d+)%%."]) + if hitFromAura then + BCScache["auras"].hit = BCScache["auras"].hit + tonumber(hitFromAura) + end + _, _, hitFromAura = BCS:GetPlayerAura(L["Increases attack power by %d+ and chance to hit by (%d+)%%."]) + if hitFromAura then + BCScache["auras"].hit = BCScache["auras"].hit + tonumber(hitFromAura) + end + -- debuffs + _, _, hitFromAura = BCS:GetPlayerAura(L["Chance to hit reduced by (%d+)%%."], 'HARMFUL') + if hitFromAura then + BCScache["auras"].hit_debuff = BCScache["auras"].hit_debuff + tonumber(hitFromAura) + end + _, _, hitFromAura = BCS:GetPlayerAura(L["Chance to hit decreased by (%d+)%% and %d+ Nature damage every %d+ sec."], 'HARMFUL') + if hitFromAura then + BCScache["auras"].hit_debuff = BCScache["auras"].hit_debuff + tonumber(hitFromAura) + end + hitFromAura = BCS:GetPlayerAura(L["Lowered chance to hit."], 'HARMFUL') + if hitFromAura then + BCScache["auras"].hit_debuff = BCScache["auras"].hit_debuff + 25 end end - - for tab=1, MAX_TABS do - local MAX_TALENTS = GetNumTalents(tab) - - for talent=1, MAX_TALENTS do - BCS_Tooltip:SetTalent(tab, talent); - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - -- rogues - local _,_, value = strfind(left:GetText(), L["Increases your chance to hit with melee weapons by (%d)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit = hit + tonumber(value) - - Cache_GetHitRating_Tab = tab - Cache_GetHitRating_Talent = talent - - line = MAX_LINES - talent = MAX_TALENTS - tab = MAX_TABS - end - - -- hunters - _,_, value = strfind(left:GetText(), L["Increases hit chance by (%d)%% and increases the chance movement impairing effects will be resisted by an additional %d+%%."]) - name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit = hit + tonumber(value) - - Cache_GetHitRating_Tab = tab - Cache_GetHitRating_Talent = talent - - line = MAX_LINES - talent = MAX_TALENTS - tab = MAX_TABS - end - - -- Druid - -- Natural Weapons - _,_, value = strfind(left:GetText(), "Also increases chance to hit with melee attacks and spells by (%d+)%%.") - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit = hit + tonumber(value) - line = MAX_LINES - end - - -- Paladin & Shaman - -- Precision & Nature's Guidance - _,_, value = strfind(left:GetText(), "Increases your chance to hit with melee attacks and spells by (%d+)%%.") - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit = hit + tonumber(value) - line = MAX_LINES + + if BCS.needScanTalents then + BCScache["talents"].hit = 0 + --scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Rogue + local _,_, value = strfind(left:GetText(), L["Increases your chance to hit with melee weapons by (%d)%%."]) + if value and rank > 0 then + BCScache["talents"].hit = BCScache["talents"].hit + tonumber(value) + break + end + -- Hunter + _,_, value = strfind(left:GetText(), L["Increases hit chance by (%d)%% and increases the chance movement impairing effects will be resisted by an additional %d+%%."]) + if value and rank > 0 then + BCScache["talents"].hit = BCScache["talents"].hit + tonumber(value) + break + end + -- Druid + -- Natural Weapons + _,_, value = strfind(left:GetText(), "Also increases chance to hit with melee attacks and spells by (%d+)%%.") + if value and rank > 0 then + BCScache["talents"].hit = BCScache["talents"].hit + tonumber(value) + break + end + -- Paladin + -- Precision + _,_, value = strfind(left:GetText(), "Increases your chance to hit with melee attacks and spells by (%d+)%%.") + if value and rank > 0 then + BCScache["talents"].hit = BCScache["talents"].hit + tonumber(value) + break + end + -- Shaman + -- Elemental Devastation + _,_, value = strfind(left:GetText(), "Increases your chance to hit with spells and melee attacks by (%d+)%%") + if value and rank > 0 then + BCScache["talents"].hit = BCScache["talents"].hit + tonumber(value) + break + end end - - end + end end - end end - + hit = BCScache["talents"].hit + BCScache["gear"].hit + BCScache["auras"].hit if not hitOnly then - hit = hit - hit_debuff + hit = hit - BCScache["auras"].hit_debuff if hit < 0 then hit = 0 end -- Dust Cloud OP return hit else @@ -244,26 +253,22 @@ function BCS:GetHitRating(hitOnly) end function BCS:GetRangedHitRating() - local melee_hit = BCS:GetHitRating(true) - local ranged_hit = melee_hit - local debuff = hit_debuff - - local hasItem = BCS_Tooltip:SetInventoryItem("player", 18) -- ranged enchant - if hasItem then - local MAX_LINES = BCS_Tooltip:NumLines() - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["+(%d)%% Hit"]) - if value then - ranged_hit = ranged_hit + tonumber(value) - line = MAX_LINES + if BCS.needScanGear then + BCScache["gear"].ranged_hit = 0 + if BCS_Tooltip:SetInventoryItem("player", 18) then + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), L["+(%d)%% Ranged Hit"]) + if value then + BCScache["gear"].ranged_hit = BCScache["gear"].ranged_hit + tonumber(value) + break + end end end end end - - ranged_hit = ranged_hit - debuff + local ranged_hit = BCS:GetHitRating(true) + BCScache["gear"].ranged_hit - BCScache["auras"].hit_debuff if ranged_hit < 0 then ranged_hit = 0 end return ranged_hit end @@ -274,885 +279,1672 @@ function BCS:GetSpellHitRating() local hit_frost = 0 local hit_arcane = 0 local hit_shadow = 0 + local hit_holy = 0 local hit_Set_Bonus = {} - - -- scan gear - local MAX_INVENTORY_SLOTS = 19 - for slot=0, MAX_INVENTORY_SLOTS do - local hasItem = BCS_Tooltip:SetInventoryItem("player", slot) - - if hasItem then - local SET_NAME - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Equip: Improves your chance to hit with spells by (%d)%%."]) - if value then - hit = hit + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["/Spell Hit %+(%d+)"]) - if value then - hit = hit + tonumber(value) - end - - _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") - if value then - SET_NAME = value - end - _, _, value = strfind(left:GetText(), L["^Set: Improves your chance to hit with spells by (%d)%%."]) - if value and SET_NAME and not tContains(hit_Set_Bonus, SET_NAME) then - tinsert(hit_Set_Bonus, SET_NAME) - hit = hit + tonumber(value) + if BCS.needScanGear then + BCScache["gear"].spell_hit = 0 + -- scan gear + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + local SET_NAME + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), L["Equip: Improves your chance to hit with spells by (%d)%%."]) + if value then + BCScache["gear"].spell_hit = BCScache["gear"].spell_hit + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["/Spell Hit %+(%d+)"]) + if value then + BCScache["gear"].spell_hit = BCScache["gear"].spell_hit + tonumber(value) + end + + _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + if value then + SET_NAME = value + end + _, _, value = strfind(left:GetText(), L["^Set: Improves your chance to hit with spells by (%d)%%."]) + if value and SET_NAME and not tContains(hit_Set_Bonus, SET_NAME) then + tinsert(hit_Set_Bonus, SET_NAME) + BCScache["gear"].spell_hit = BCScache["gear"].spell_hit + tonumber(value) + end end end end - end end - - -- scan talents - local MAX_TABS = GetNumTalentTabs() - - for tab=1, MAX_TABS do - local MAX_TALENTS = GetNumTalents(tab) - - for talent=1, MAX_TALENTS do - BCS_Tooltip:SetTalent(tab, talent) - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - -- Mage - -- Elemental Precision - local _,_, value = strfind(left:GetText(), L["Reduces the chance that the opponent can resist your Frost and Fire spells by (%d)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit_fire = hit_fire + tonumber(value) - hit_frost = hit_frost + tonumber(value) - line = MAX_LINES - end - - -- Arcane Focus - _,_, value = strfind(left:GetText(), L["Reduces the chance that the opponent can resist your Arcane spells by (%d+)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit_arcane = hit_arcane + tonumber(value) - line = MAX_LINES - end - - -- Priest - -- Shadow Focus - _,_, value = strfind(left:GetText(), L["Reduces your target's chance to resist your Shadow spells by (%d+)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit_shadow = hit_shadow + tonumber(value) - line = MAX_LINES - end - - -- Druid - -- Natural Weapons - _,_, value = strfind(left:GetText(), "Also increases chance to hit with melee attacks and spells by (%d+)%%.") - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit = hit + tonumber(value) - line = MAX_LINES - end - - -- Paladin & Shaman - -- Precision & Nature's Guidance - _,_, value = strfind(left:GetText(), "Increases your chance to hit with melee attacks and spells by (%d+)%%.") - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - hit = hit + tonumber(value) - line = MAX_LINES + if BCS.needScanTalents then + BCScache["talents"].spell_hit = 0 + BCScache["talents"].spell_hit_fire = 0 + BCScache["talents"].spell_hit_frost = 0 + BCScache["talents"].spell_hit_arcane = 0 + BCScache["talents"].spell_hit_shadow = 0 + BCScache["talents"].spell_hit_holy = 0 + -- scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Mage + -- Elemental Precision + local _,_, value = strfind(left:GetText(), L["Reduces the chance that the opponent can resist your Frost and Fire spells by (%d)%%."]) + if value and rank > 0 then + BCScache["talents"].spell_hit_fire = BCScache["talents"].spell_hit_fire + tonumber(value) + BCScache["talents"].spell_hit_frost = BCScache["talents"].spell_hit_frost + tonumber(value) + break + end + -- Arcane Focus + _,_, value = strfind(left:GetText(), L["Reduces the chance that the opponent can resist your Arcane spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].spell_hit_arcane = BCScache["talents"].spell_hit_arcane + tonumber(value) + break + end + -- Priest + -- Piercing Light + _,_, value = strfind(left:GetText(), L["Reduces the chance for enemies to resist your Holy and Discipline spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].spell_hit_holy = BCScache["talents"].spell_hit_holy + tonumber(value) + break + end + -- Shadow Focus + _,_, value = strfind(left:GetText(), L["Reduces your target's chance to resist your Shadow spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].spell_hit_shadow = BCScache["talents"].spell_hit_shadow + tonumber(value) + break + end + -- Druid + -- Natural Weapons + _,_, value = strfind(left:GetText(), "Also increases chance to hit with melee attacks and spells by (%d+)%%.") + if value and rank > 0 then + BCScache["talents"].spell_hit = BCScache["talents"].spell_hit + tonumber(value) + break + end + -- Paladin + -- Precision + _,_, value = strfind(left:GetText(), "Increases your chance to hit with melee attacks and spells by (%d+)%%.") + if value and rank > 0 then + BCScache["talents"].spell_hit = BCScache["talents"].spell_hit + tonumber(value) + break + end + -- Shaman + -- Elemental Devastation + _,_, value = strfind(left:GetText(), "Increases your chance to hit with spells and melee attacks by (%d+)%%") + if value and rank > 0 then + BCScache["talents"].spell_hit = BCScache["talents"].spell_hit + tonumber(value) + break + end + -- Warlock + -- Suppression + _,_, value = strfind(left:GetText(), L["Reduces the chance for enemies to resist your Affliction spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].spell_hit_shadow = BCScache["talents"].spell_hit_shadow + tonumber(value) + break + end end - end + end end - end end - -- buffs - local _, _, hitFromAura = BCS:GetPlayerAura(L["Spell hit chance increased by (%d+)%%."]) - if hitFromAura then - hit = hit + tonumber(hitFromAura) + if BCS.needScanAuras then + BCScache["auras"].spell_hit = 0 + local _, _, hitFromAura = BCS:GetPlayerAura(L["Spell hit chance increased by (%d+)%%."]) + if hitFromAura then + BCScache["auras"].spell_hit = BCScache["auras"].spell_hit + tonumber(hitFromAura) + end + -- Elemental Devastation + _, _, hitFromAura = BCS:GetPlayerAura("Increases your chance to hit with spells by (%d+)%%") + if hitFromAura then + BCScache["auras"].spell_hit = BCScache["auras"].spell_hit + tonumber(hitFromAura) + end end - - return hit, hit_fire, hit_frost, hit_arcane, hit_shadow + hit = BCScache["gear"].spell_hit + BCScache["talents"].spell_hit + BCScache["auras"].spell_hit + hit_fire = BCScache["talents"].spell_hit_fire + hit_frost = BCScache["talents"].spell_hit_frost + hit_arcane = BCScache["talents"].spell_hit_arcane + hit_shadow = BCScache["talents"].spell_hit_shadow + hit_holy = BCScache["talents"].spell_hit_holy + return hit, hit_fire, hit_frost, hit_arcane, hit_shadow, hit_holy end -local Cache_GetCritChance_SpellID, Cache_GetCritChance_BookType, Cache_GetCritChance_Line -local Cache_GetCritChance_Tab, Cache_GetCritChance_Talent function BCS:GetCritChance() local crit = 0 - local _, class = UnitClass('player') - - if class == 'HUNTER' then - - local MAX_TABS = GetNumTalentTabs() - -- speedup - if Cache_GetCritChance_Tab and Cache_GetCritChance_Talent then - BCS_Tooltip:SetTalent(Cache_GetCritChance_Tab, Cache_GetCritChance_Talent) - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Increases your critical strike chance with all attacks by (%d)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(Cache_GetCritChance_Tab, Cache_GetCritChance_Talent) - if value and rank > 0 then - crit = crit + tonumber(value) - line = MAX_LINES - end - end - end - else - for tab=1, MAX_TABS do - local MAX_TALENTS = GetNumTalents(tab) - for talent=1, MAX_TALENTS do - BCS_Tooltip:SetTalent(tab, talent); - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Increases your critical strike chance with all attacks by (%d)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - crit = crit + tonumber(value) - - Cache_GetCritChance_Tab = tab - Cache_GetCritChance_Talent = talent - - line = MAX_LINES - talent = MAX_TALENTS - tab = MAX_TABS - end - end - end - - end - end - end - - end - - -- speedup - if Cache_GetCritChance_SpellID and Cache_GetCritChance_BookType and Cache_GetCritChance_Line then - - BCS_Tooltip:SetSpell(Cache_GetCritChance_SpellID, Cache_GetCritChance_BookType) - local left = getglobal(BCS_Prefix .. "TextLeft" .. Cache_GetCritChance_Line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["([%d.]+)%% chance to crit"]) - if value then - crit = crit + tonumber(value) - end - end - - return crit - end - - local MAX_TABS = GetNumSpellTabs() - - for tab=1, MAX_TABS do - local name, texture, offset, numSpells = GetSpellTabInfo(tab) - + --scan spellbook + for tab=1, GetNumSpellTabs() do + local _, _, offset, numSpells = GetSpellTabInfo(tab) for spell=1, numSpells do local currentPage = ceil(spell/SPELLS_PER_PAGE) local SpellID = spell + offset + ( SPELLS_PER_PAGE * (currentPage - 1)) - BCS_Tooltip:SetSpell(SpellID, BOOKTYPE_SPELL) - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do + for line=1, BCS_Tooltip:NumLines() do local left = getglobal(BCS_Prefix .. "TextLeft" .. line) if left:GetText() then local _,_, value = strfind(left:GetText(), L["([%d.]+)%% chance to crit"]) if value then crit = crit + tonumber(value) - - Cache_GetCritChance_SpellID = SpellID - Cache_GetCritChance_BookType = BOOKTYPE_SPELL - Cache_GetCritChance_Line = line - - line = MAX_LINES - spell = numSpells - tab = MAX_TABS + break end end end - end end - + return crit end -local Cache_GetRangedCritChance_Tab, Cache_GetRangedCritChance_Talent, Cache_GetRangedCritChance_Line function BCS:GetRangedCritChance() - local crit = BCS:GetCritChance() - - if Cache_GetRangedCritChance_Tab and Cache_GetRangedCritChance_Talent and Cache_GetRangedCritChance_Line then - BCS_Tooltip:SetTalent(Cache_GetRangedCritChance_Tab, Cache_GetRangedCritChance_Talent) - local left = getglobal(BCS_Prefix .. "TextLeft" .. Cache_GetRangedCritChance_Line) - - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Increases your critical strike chance with ranged weapons by (%d)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(Cache_GetRangedCritChance_Tab, Cache_GetRangedCritChance_Talent) - if value and rank > 0 then - crit = crit + tonumber(value) + -- values from vmangos core + local crit = 0 + local _, class = UnitClass("player") + local _, agility = UnitStat("player", 2) + local vallvl1 = 0 + local vallvl60 = 0 + local classrate = 0 + + if class == "MAGE" then + vallvl1 = 12.9 + vallvl60 = 20 + elseif class == "ROGUE" then + vallvl1 = 2.2 + vallvl60 = 29 + elseif class == "HUNTER" then + vallvl1 = 3.5 + vallvl60 = 53 + elseif class == "PRIEST" then + vallvl1 = 11 + vallvl60 = 20 + elseif class == "WARLOCK" then + vallvl1 = 8.4 + vallvl60 = 20 + elseif class == "WARRIOR" then + vallvl1 = 3.9 + vallvl60 = 20 + else + return crit + end + + classrate = vallvl1 * (60 - UnitLevel("player")) / 59 + vallvl60 * (UnitLevel("player") - 1) / 59 + crit = agility / classrate + + if BCS.needScanTalents then + BCScache["talents"].ranged_crit = 0 + --scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + local _,_, value = strfind(left:GetText(), L["Increases your critical strike chance with ranged weapons by (%d)%%."]) + if value and rank > 0 then + BCScache["talents"].ranged_crit = BCScache["talents"].ranged_crit + tonumber(value) + break + end + _,_, value = strfind(left:GetText(), L["Increases your critical strike chance with all attacks by (%d)%%."]) + if value and rank > 0 then + BCScache["talents"].ranged_crit = BCScache["talents"].ranged_crit + tonumber(value) + break + end + end + end end end - - return crit end - - local MAX_TABS = GetNumTalentTabs() - - for tab=1, MAX_TABS do - local MAX_TALENTS = GetNumTalents(tab) - - for talent=1, MAX_TALENTS do - BCS_Tooltip:SetTalent(tab, talent); - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Increases your critical strike chance with ranged weapons by (%d)%%."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - crit = crit + tonumber(value) - - line = MAX_LINES - talent = MAX_TALENTS - tab = MAX_TABS + + if BCS.needScanGear then + BCScache["gear"].ranged_crit = 0 + --scan gear + local Crit_Set_Bonus = {} + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + local SET_NAME + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), L["Equip: Improves your chance to get a critical strike by (%d)%%."]) + if value then + BCScache["gear"].ranged_crit = BCScache["gear"].ranged_crit + tonumber(value) + end + _,_, value = strfind(left:GetText(), "Equip: Improves your chance to get a critical strike with missile weapons by (%d)%%.") + if value then + BCScache["gear"].ranged_crit = BCScache["gear"].ranged_crit + tonumber(value) + end + -- Might of the Scourge (shoulder enchant) + _,_, value = strfind(left:GetText(), L["%+(%d+)%% Critical Strike"]) + if value then + BCScache["gear"].ranged_crit = BCScache["gear"].ranged_crit + tonumber(value) + end + + _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + if value then + SET_NAME = value + end + _, _, value = strfind(left:GetText(), L["^Set: Improves your chance to get a critical strike by (%d)%%."]) + if value and SET_NAME and not tContains(Crit_Set_Bonus, SET_NAME) then + tinsert(Crit_Set_Bonus, SET_NAME) + BCScache["gear"].ranged_crit = BCScache["gear"].ranged_crit + tonumber(value) + end end end end - end end - + if BCS.needScanAuras then + BCScache["auras"].ranged_crit = 0 + --buffs + --ony head + local critFromAura = BCS:GetPlayerAura(L["Increases critical chance of spells by 10%%, melee and ranged by 5%% and grants 140 attack power. 120 minute duration."]) + if critFromAura then + BCScache["auras"].ranged_crit = BCScache["auras"].ranged_crit + 5 + end + --mongoose + _, _, critFromAura = BCS:GetPlayerAura(L["Agility increased by 25, Critical hit chance increases by (%d)%%."]) + if critFromAura then + BCScache["auras"].ranged_crit = BCScache["auras"].ranged_crit + tonumber(critFromAura) + end + --songflower + _, _, critFromAura = BCS:GetPlayerAura(L["Increases chance for a melee, ranged, or spell critical by (%d+)%% and all attributes by %d+."]) + if critFromAura then + BCScache["auras"].ranged_crit = BCScache["auras"].ranged_crit + tonumber(critFromAura) + end + --leader of the pack + _, _, critFromAura = BCS:GetPlayerAura(L["Increases ranged and melee critical chance by (%d+)%%."]) + if critFromAura then + BCScache["auras"].ranged_crit = BCScache["auras"].ranged_crit + tonumber(critFromAura) + --check if druid is shapeshifted and have Idol of the Moonfang equipped + for i=1, GetNumPartyMembers() do + local _, partyClass = UnitClass("party"..i) + if partyClass == "DRUID" then + if BCS_Tooltip:SetInventoryItem("party"..i, 18) and UnitCreatureType("party"..i) == "Beast" then + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + _, _, critFromAura = strfind(left:GetText(), L["Equip: Increases the critical chance provided by Leader of the Pack and Moonkin Aura by (%d)%%."]) + if critFromAura then + BCScache["auras"].ranged_crit = BCScache["auras"].ranged_crit + tonumber(critFromAura) + break + end + end + end + end + end + end + end + end + + if class == "MAGE" then + crit = crit + 3.2 + elseif class == "PRIEST" then + crit = crit + 3 + elseif class == "WARLOCK" then + crit = crit + 2 + end + + crit = crit + BCScache["gear"].ranged_crit + BCScache["talents"].ranged_crit + BCScache["auras"].ranged_crit + return crit end function BCS:GetSpellCritChance() - -- school crit: most likely never local Crit_Set_Bonus = {} local spellCrit = 0; - local _, intelect = UnitStat("player", 4) + local _, intellect = UnitStat("player", 4) local _, class = UnitClass("player") - -- values from theorycraft / http://wow.allakhazam.com/forum.html?forum=21&mid=1157230638252681707 + -- values from vmangos core + local playerLevel = UnitLevel("player") if class == "MAGE" then - spellCrit = 0.2 + (intelect / 59.5) + spellCrit = 3.7 + intellect / (14.77 + .65 * playerLevel) elseif class == "WARLOCK" then - spellCrit = 1.7 + (intelect / 60.6) + spellCrit = 3.18 + intellect / (11.30 + .82 * playerLevel) elseif class == "PRIEST" then - spellCrit = 0.8 + (intelect / 59.56) + spellCrit = 2.97 + intellect / (10.03 + .82 * playerLevel) elseif class == "DRUID" then - spellCrit = 1.8 + (intelect / 60) + spellCrit = 3.33 + intellect / (12.41 + .79 * playerLevel) elseif class == "SHAMAN" then - spellCrit = 1.8 + (intelect / 59.2) + spellCrit = 3.54 + intellect / (11.51 + .8 * playerLevel) elseif class == "PALADIN" then - spellCrit = intelect / 29.5 + spellCrit = 3.7 + intellect / (14.77 + .65 * playerLevel) end - - local MAX_INVENTORY_SLOTS = 19 - - for slot=0, MAX_INVENTORY_SLOTS do - local hasItem = BCS_Tooltip:SetInventoryItem("player", slot) - - if hasItem then - local SET_NAME = nil - - for line=1, BCS_Tooltip:NumLines() do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Equip: Improves your chance to get a critical strike with spells by (%d)%%."]) - if value then - spellCrit = spellCrit + tonumber(value) - end - - _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") - if value then - SET_NAME = value - end + if BCS.needScanGear then + BCScache["gear"].spell_crit = 0 + --scan gear + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + local SET_NAME = nil + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), L["Equip: Improves your chance to get a critical strike with spells by (%d)%%."]) + if value then + BCScache["gear"].spell_crit = BCScache["gear"].spell_crit + tonumber(value) + end - _, _, value = strfind(left:GetText(), L["^Set: Improves your chance to get a critical strike with spells by (%d)%%."]) - if value and SET_NAME and not tContains(Crit_Set_Bonus, SET_NAME) then - tinsert(Crit_Set_Bonus, SET_NAME) - spellCrit = spellCrit + tonumber(value) + _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + if value then + SET_NAME = value + end + _, _, value = strfind(left:GetText(), L["^Set: Improves your chance to get a critical strike with spells by (%d)%%."]) + if value and SET_NAME and not tContains(Crit_Set_Bonus, SET_NAME) then + tinsert(Crit_Set_Bonus, SET_NAME) + BCScache["gear"].spell_crit = BCScache["gear"].spell_crit + tonumber(value) + end + _,_, value = strfind(left:GetText(), "(%d)%% Spell Critical Strike") + if value then + BCScache["gear"].spell_crit = BCScache["gear"].spell_crit + tonumber(value) + end end - - local _,_, value = strfind(left:GetText(), "(%d)%% Spell Critical Strike") - if value then - spellCrit = spellCrit + tonumber(value) + end + end + end + if BCS_Tooltip:SetInventoryItem("player", 16) then + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local found = strfind(left:GetText(), "Brilliant Wizard Oil") + if found then + BCScache["gear"].spell_crit = BCScache["gear"].spell_crit + 1 end - end end end - - end - - -- buffs - local _, _, critFromAura = BCS:GetPlayerAura(L["Chance for a critical hit with a spell increased by (%d+)%%."]) - if critFromAura then - spellCrit = spellCrit + tonumber(critFromAura) - end - _, _, critFromAura = BCS:GetPlayerAura("(Moonkin Aura)") - if critFromAura then - spellCrit = spellCrit + 3 - end - _, _, critFromAura = BCS:GetPlayerAura("Power of the Guardian Crit") - if critFromAura then - spellCrit = spellCrit + tonumber(critFromAura) end - _, _, critFromAura = BCS:GetPlayerAura("Chance to get a critical strike with spells is increased by (%d+)%%") - if critFromAura then - spellCrit = spellCrit + tonumber(critFromAura) - end - _, _, critFromAura = BCS:GetPlayerAura(L["While active, target's critical hit chance with spells and attacks increases by 10%%."]) - if critFromAura then - spellCrit = spellCrit + 10 - end - _, _, critFromAura = BCS:GetPlayerAura(L["Increases chance for a melee, ranged, or spell critical by (%d+)%% and all attributes by %d+."]) - if critFromAura then - spellCrit = spellCrit + tonumber(critFromAura) - end - critFromAura = BCS:GetPlayerAura(L["Increases critical chance of spells by 10%%, melee and ranged by 5%% and grants 140 attack power. 120 minute duration."]) - if critFromAura then - spellCrit = spellCrit + 10 - end - _, _, critFromAura = BCS:GetPlayerAura(L["Critical strike chance with spells and melee attacks increased by (%d+)%%."]) - if critFromAura then - spellCrit = spellCrit + tonumber(critFromAura) - end - -- debuffs - _, _, _, critFromAura = BCS:GetPlayerAura(L["Melee critical-hit chance reduced by (%d+)%%.\r\nSpell critical-hit chance reduced by (%d+)%%."], 'HARMFUL') - if critFromAura then - spellCrit = spellCrit - tonumber(critFromAura) - end - - return spellCrit -end -function BCS:GetSpellPower(school) - if school then - if not L["Equip: Increases damage done by "..school.." spells and effects by up to (%d+)."] then return -1 end - local spellPower = 0; - local MAX_INVENTORY_SLOTS = 19 - - for slot=0, MAX_INVENTORY_SLOTS do - local hasItem = BCS_Tooltip:SetInventoryItem("player", slot) - - if hasItem then + if BCS.needScanAuras then + BCScache["auras"].spell_crit = 0 + -- buffs + local _, _, critFromAura = BCS:GetPlayerAura(L["Chance for a critical hit with a spell increased by (%d+)%%."]) + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + tonumber(critFromAura) + end + _, _, critFromAura = BCS:GetPlayerAura("(Moonkin Aura)") + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + 3 + if BCS:GetPlayerAura("Moonkin Form") and BCS_Tooltip:SetInventoryItem("player", 18) then for line=1, BCS_Tooltip:NumLines() do local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by "..school.." spells and effects by up to (%d+)."]) - if value then - spellPower = spellPower + tonumber(value) - end - if L[school.." Damage %+(%d+)"] then - _,_, value = strfind(left:GetText(), L[school.." Damage %+(%d+)"]) - if value then - spellPower = spellPower + tonumber(value) - end + _, _, critFromAura = strfind(left:GetText(), L["Equip: Increases the critical chance provided by Leader of the Pack and Moonkin Aura by (%d)%%."]) + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + tonumber(critFromAura) end - if L["^%+(%d+) "..school.." Spell Damage"] then - _,_, value = strfind(left:GetText(), L["^%+(%d+) "..school.." Spell Damage"]) - if value then - spellPower = spellPower + tonumber(value) + end + end + else + --check if druid is shapeshifted and have Idol of the Moonfang equipped + for i=1, GetNumPartyMembers() do + local _, partyClass = UnitClass("party"..i) + if partyClass == "DRUID" then + if BCS_Tooltip:SetInventoryItem("party"..i, 18) then + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + _, _, critFromAura = strfind(left:GetText(), L["Equip: Increases the critical chance provided by Leader of the Pack and Moonkin Aura by (%d)%%."]) + if critFromAura then + for buff = 1, 32 do + if UnitBuff("party"..i, buff) and UnitBuff("party"..i, buff) == "Interface\\Icons\\Spell_Nature_ForceOfNature" then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + tonumber(critFromAura) + break + end + end + end + end end end end end end - end - - return spellPower - else - local spellPower = 0; - local arcanePower = 0; - local firePower = 0; - local frostPower = 0; - local holyPower = 0; - local naturePower = 0; - local shadowPower = 0; - local damagePower = 0; - local MAX_INVENTORY_SLOTS = 19 - - local SpellPower_Set_Bonus = {} - - -- scan gear - for slot=0, MAX_INVENTORY_SLOTS do - local hasItem = BCS_Tooltip:SetInventoryItem("player", slot) - - if hasItem then - local SET_NAME - + critFromAura = BCS:GetPlayerAura("Inner Focus") + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + 25 + end + _, _, critFromAura = BCS:GetPlayerAura("Power of the Guardian Crit") + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + tonumber(critFromAura) + end + _, _, critFromAura = BCS:GetPlayerAura("Chance to get a critical strike with spells is increased by (%d+)%%") + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + tonumber(critFromAura) + end + _, _, critFromAura = BCS:GetPlayerAura(L["While active, target's critical hit chance with spells and attacks increases by 10%%."])--SoD spell? 23964 + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + 10 + end + _, _, critFromAura = BCS:GetPlayerAura(L["Increases chance for a melee, ranged, or spell critical by (%d+)%% and all attributes by %d+."]) + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + tonumber(critFromAura) + end + critFromAura = BCS:GetPlayerAura(L["Increases critical chance of spells by 10%%, melee and ranged by 5%% and grants 140 attack power. 120 minute duration."]) + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + 10 + end + _, _, critFromAura = BCS:GetPlayerAura(L["Critical strike chance with spells and melee attacks increased by (%d+)%%."]) + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit + tonumber(critFromAura) + end + -- debuffs + _, _, _, critFromAura = BCS:GetPlayerAura(L["Melee critical-hit chance reduced by (%d+)%%.\r\nSpell critical-hit chance reduced by (%d+)%%."], 'HARMFUL') + if critFromAura then + BCScache["auras"].spell_crit = BCScache["auras"].spell_crit - tonumber(critFromAura) + end + end + + -- scan talents + if BCS.needScanTalents then + BCScache["talents"].spell_crit = 0 + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) for line=1, BCS_Tooltip:NumLines() do local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Equip: Increases damage and healing done by magical spells and effects by up to (%d+)."]) - if value then - spellPower = spellPower + tonumber(value) - end - _,_, value = strfind(left:GetText(), "Equip: Increases your spell damage by up to (%d+)") - if value then - spellPower = spellPower + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["Spell Damage %+(%d+)"]) - if value then - spellPower = spellPower + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Spell Damage and Healing"]) - if value then - spellPower = spellPower + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Damage and Healing Spells"]) - if value then - spellPower = spellPower + tonumber(value) - end - - _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Arcane spells and effects by up to (%d+)."]) - if value then - arcanePower = arcanePower + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Arcane Spell Damage"]) - if value then - arcanePower = arcanePower + tonumber(value) - end - - _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Fire spells and effects by up to (%d+)."]) - if value then - firePower = firePower + tonumber(value) + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Arcane Instability + local _,_, value = strfind(left:GetText(), L["Increases your spell damage and critical srike chance by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].spell_crit = BCScache["talents"].spell_crit + tonumber(value) + break end - _,_, value = strfind(left:GetText(), L["Fire Damage %+(%d+)"]) - if value then - firePower = firePower + tonumber(value) + end + end + end + end + end + + spellCrit = spellCrit + BCScache["talents"].spell_crit + BCScache["gear"].spell_crit + BCScache["auras"].spell_crit + + return spellCrit +end + +function BCS:GetSpellCritFromClass(class) + if not class then + return 0, 0, 0, 0, 0, 0 + end + + if class == "PALADIN" then + --scan talents + if BCS.needScanTalents or BCS.needScanAuras then + BCScache["talents"].paladin_holy_light = 0 + BCScache["talents"].paladin_flash = 0 + BCScache["talents"].paladin_shock = 0 + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Holy Power + local _,_, value = strfind(left:GetText(), L["Increases the critical effect chance of your Holy Light and Flash of Light by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].paladin_holy_light = BCScache["talents"].paladin_holy_light + tonumber(value) + BCScache["talents"].paladin_flash = BCScache["talents"].paladin_flash + tonumber(value) + break + end + -- Divine Favor + _,_, value = strfind(left:GetText(), L["Improves your chance to get a critical strike with Holy Shock by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].paladin_shock = BCScache["talents"].paladin_shock + tonumber(value) + break + end end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Fire Spell Damage"]) - if value then - firePower = firePower + tonumber(value) + end + end + end + end + + return BCScache["talents"].paladin_holy_light, + BCScache["talents"].paladin_flash, + BCScache["talents"].paladin_shock, 0, 0, 0 + + elseif class == "DRUID" then + --scan talents + if BCS.needScanTalents then + BCScache["talents"].druid_moonfire = 0 + BCScache["talents"].druid_regrowth = 0 + -- scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Improved Moonfire + local _,_, value = strfind(left:GetText(), L["Increases the damage and critical strike chance of your Moonfire spell by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].druid_moonfire = BCScache["talents"].druid_moonfire + tonumber(value) + break + end + -- Improved Regrowth + _,_, value = strfind(left:GetText(), L["Increases the critical effect chance of your Regrowth spell by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].druid_regrowth = BCScache["talents"].druid_regrowth + tonumber(value) + break + end end - - _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Frost spells and effects by up to (%d+)."]) - if value then - frostPower = frostPower + tonumber(value) + end + end + end + end + + return BCScache["talents"].druid_moonfire, + BCScache["talents"].druid_regrowth, 0, 0, 0, 0 + + elseif class == "WARLOCK" then + --scan talents + if BCS.needScanTalents then + BCScache["talents"].warlock_destruction_spells = 0 + BCScache["talents"].warlock_searing_pain = 0 + -- scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Devastation + local _,_, value = strfind(left:GetText(), L["Increases the critical strike chance of your Destruction spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].warlock_destruction_spells = BCScache["talents"].warlock_destruction_spells + tonumber(value) + BCScache["talents"].warlock_searing_pain = BCScache["talents"].warlock_searing_pain + tonumber(value) + break + end + -- Improved Searing Pain + _,_, value = strfind(left:GetText(), L["Increases the critical strike chance of your Searing Pain spell by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].warlock_searing_pain = BCScache["talents"].warlock_searing_pain + tonumber(value) + break + end end - _,_, value = strfind(left:GetText(), L["Frost Damage %+(%d+)"]) - if value then - frostPower = frostPower + tonumber(value) + end + end + end + end + + return BCScache["talents"].warlock_destruction_spells, + BCScache["talents"].warlock_searing_pain, 0, 0, 0, 0 + + elseif class == "MAGE" then + --scan talents + if BCS.needScanTalents or BCS.needScanAuras then + BCScache["talents"].mage_arcane_spells = 0 + BCScache["talents"].mage_fire_spells = 0 + BCScache["talents"].mage_fireblast = 0 + BCScache["talents"].mage_scorch = 0 + BCScache["talents"].mage_flamestrike = 0 + BCScache["talents"].mage_shatter = 0 + -- scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Arcane Impact + local _,_, value = strfind(left:GetText(), L["Increases the critical strike chance of your Arcane Explosion and Arcane Missiles spells by an additional (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].mage_arcane_spells = BCScache["talents"].mage_arcane_spells + tonumber(value) + break + end + -- Incinerate + _,_, value = strfind(left:GetText(), L["Increases the critical strike chance of your Fire Blast and Scorch spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].mage_fireblast = BCScache["talents"].mage_fireblast + tonumber(value) + BCScache["talents"].mage_scorch = BCScache["talents"].mage_scorch + tonumber(value) + break + end + -- Improved Flamestrike + _,_, value = strfind(left:GetText(), L["Increases the critical strike chance of your Flamestrike spell by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].mage_flamestrike = BCScache["talents"].mage_flamestrike + tonumber(value) + break + end + -- Critical Mass + _,_, value = strfind(left:GetText(), L["Increases the critical strike chance of your Fire spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].mage_fire_spells = BCScache["talents"].mage_fire_spells + tonumber(value) + BCScache["talents"].mage_fireblast = BCScache["talents"].mage_fireblast + tonumber(value) + BCScache["talents"].mage_flamestrike = BCScache["talents"].mage_flamestrike + tonumber(value) + BCScache["talents"].mage_scorch = BCScache["talents"].mage_scorch + tonumber(value) + break + end + -- Shatter + _,_, value = strfind(left:GetText(), L["Increases the critical strike chance of all your spells against frozen targets by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].mage_shatter = BCScache["talents"].mage_shatter + tonumber(value) + break + end end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Frost Spell Damage"]) - if value then - frostPower = frostPower + tonumber(value) + end + end + end + -- Buffs + local _, _, value = BCS:GetPlayerAura(L["Increases critical strike chance from Fire damage spells by (%d+)%%."]) + -- Combustion + if value then + BCScache["talents"].mage_fire_spells = BCScache["talents"].mage_fire_spells + tonumber(value) + BCScache["talents"].mage_fireblast = BCScache["talents"].mage_fireblast + tonumber(value) + BCScache["talents"].mage_flamestrike = BCScache["talents"].mage_flamestrike + tonumber(value) + BCScache["talents"].mage_scorch = BCScache["talents"].mage_scorch + tonumber(value) + end + end + + return BCScache["talents"].mage_arcane_spells, + BCScache["talents"].mage_fire_spells, + BCScache["talents"].mage_fireblast, + BCScache["talents"].mage_scorch, + BCScache["talents"].mage_flamestrike, + BCScache["talents"].mage_shatter + + elseif class == "PRIEST" then + if BCS.needScanTalents then + BCScache["talents"].priest_holy_spells = 0 + BCScache["talents"].priest_discipline_spells = 0 + BCScache["talents"].priest_offensive_spells = 0 + -- scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Divinity + local _,_, value = strfind(left:GetText(), L["Increases the critical effect chance of your Holy and Discipline spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].priest_holy_spells = BCScache["talents"].priest_holy_spells + tonumber(value) + BCScache["talents"].priest_discipline_spells = BCScache["talents"].priest_discipline_spells + tonumber(value) + break + end + -- Force of Will + _,_, value = strfind(left:GetText(), "Increases your spell damage and the critical strike chance of your offensive spells by (%d+)%%") + if value and rank > 0 then + BCScache["talents"].priest_offensive_spells = BCScache["talents"].priest_offensive_spells + tonumber(value) + break + end end - - _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Holy spells and effects by up to (%d+)."]) - if value then - holyPower = holyPower + tonumber(value) + end + end + end + end + -- scan gear + if BCS.needScanGear then + -- t1 set gives + 2% crit to holy and 25% to prayer of healing + BCScache["gear"].priest_holy_spells = 0 + BCScache["gear"].priest_prayer = 0 + local Crit_Set_Bonus = {} + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + local SET_NAME = nil + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + if value then + SET_NAME = value + end + _, _, value = strfind(left:GetText(), L["^Set: Improves your chance to get a critical strike with Holy spells by (%d)%%."]) + if value and SET_NAME and not tContains(Crit_Set_Bonus, SET_NAME) then + tinsert(Crit_Set_Bonus, SET_NAME) + BCScache["gear"].priest_holy_spells = BCScache["gear"].priest_holy_spells + tonumber(value) + end + _, _, value = strfind(left:GetText(), L["^Set: Increases your chance of a critical hit with Prayer of Healing by (%d+)%%."]) + if value and SET_NAME and not tContains(Crit_Set_Bonus, SET_NAME) then + tinsert(Crit_Set_Bonus, SET_NAME) + BCScache["gear"].priest_prayer = BCScache["gear"].priest_prayer + tonumber(value) + end end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Holy Spell Damage"]) - if value then - holyPower = holyPower + tonumber(value) + end + end + end + end + + local holySpells = BCScache["talents"].priest_holy_spells + BCScache["gear"].priest_holy_spells + + return holySpells, + BCScache["talents"].priest_discipline_spells, + BCScache["talents"].priest_offensive_spells, + BCScache["gear"].priest_prayer, 0, 0 + + elseif class == "SHAMAN" then + if BCS.needScanTalents then + BCScache["talents"].shaman_lightning_bolt = 0 + BCScache["talents"].shaman_chain_lightning = 0 + BCScache["talents"].shaman_lightning_shield = 0 + BCScache["talents"].shaman_firefrost_spells = 0 + BCScache["talents"].shaman_healing_spells = 0 + -- scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Call of Thunder + local _,_, value = strfind(left:GetText(), L["Increases the critical strike chance of your Lightning Bolt and Chain Lightning spells by an additional (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].shaman_lightning_bolt = BCScache["talents"].shaman_lightning_bolt + tonumber(value) + BCScache["talents"].shaman_chain_lightning = BCScache["talents"].shaman_chain_lightning + tonumber(value) + break + end + -- Tidal Mastery + _,_, value = strfind(left:GetText(), L["Increases the critical effect chance of your healing and lightning spells by (%d+)%%."]) + if value and rank > 0 then + BCScache["talents"].shaman_lightning_bolt = BCScache["talents"].shaman_lightning_bolt + tonumber(value) + BCScache["talents"].shaman_chain_lightning = BCScache["talents"].shaman_chain_lightning + tonumber(value) + BCScache["talents"].shaman_lightning_shield = BCScache["talents"].shaman_lightning_shield + tonumber(value) + BCScache["talents"].shaman_healing_spells = BCScache["talents"].shaman_healing_spells + tonumber(value) + break + end end - - _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Nature spells and effects by up to (%d+)."]) - if value then - naturePower = naturePower + tonumber(value) + end + end + end + end + -- buffs + if BCS.needScanAuras then + BCScache["auras"].shaman_lightning_bolt = 0 + BCScache["auras"].shaman_chain_lightning = 0 + BCScache["auras"].shaman_firefrost_spells = 0 + local hasAura = BCS:GetPlayerAura("Elemental Mastery") + if hasAura then + BCScache["auras"].shaman_lightning_bolt = 100 + BCScache["auras"].shaman_chain_lightning = 100 + BCScache["auras"].shaman_firefrost_spells = 100 + end + end + + local lightningBolt = BCScache["auras"].shaman_lightning_bolt + BCScache["talents"].shaman_lightning_bolt + local chainLightning = BCScache["auras"].shaman_chain_lightning + BCScache["talents"].shaman_chain_lightning + + return lightningBolt, chainLightning, + BCScache["talents"].shaman_lightning_shield, + BCScache["auras"].shaman_firefrost_spells, + BCScache["talents"].shaman_healing_spells, 0 + + else + return 0, 0, 0, 0, 0, 0 + end +end + +local impInnerFire = nil +local spiritualGuidance = nil +function BCS:GetSpellPower(school) + if school then + local spellPower = 0; + --scan gear + if BCS.needScanGear then + if school == "Arcane" then BCScache["gear"].arcane = 0 + elseif school == "Fire" then BCScache["gear"].fire = 0 + elseif school == "Frost" then BCScache["gear"].frost = 0 + elseif school == "Holy" then BCScache["gear"].holy = 0 + elseif school == "Nature" then BCScache["gear"].nature = 0 + elseif school == "Shadow" then BCScache["gear"].shadow = 0 + end + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem("player", slot) then + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by "..school.." spells and effects by up to (%d+)."]) + if value then + spellPower = spellPower + tonumber(value) + end + _,_, value = strfind(left:GetText(), school.." Damage %+(%d+)") + if value then + spellPower = spellPower + tonumber(value) + end + _,_, value = strfind(left:GetText(), "^%+(%d+) "..school.." Spell Damage") + if value then + spellPower = spellPower + tonumber(value) + end end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Nature Spell Damage"]) - if value then - naturePower = naturePower + tonumber(value) + end + end + end + if school == "Arcane" then BCScache["gear"].arcane = spellPower + elseif school == "Fire" then BCScache["gear"].fire = spellPower + elseif school == "Frost" then BCScache["gear"].frost = spellPower + elseif school == "Holy" then BCScache["gear"].holy = spellPower + elseif school == "Nature" then BCScache["gear"].nature = spellPower + elseif school == "Shadow" then BCScache["gear"].shadow = spellPower + end + else + if school == "Arcane" then spellPower = BCScache["gear"].arcane + elseif school == "Fire" then spellPower = BCScache["gear"].fire + elseif school == "Frost" then spellPower = BCScache["gear"].frost + elseif school == "Holy" then spellPower = BCScache["gear"].holy + elseif school == "Nature" then spellPower = BCScache["gear"].nature + elseif school == "Shadow" then spellPower = BCScache["gear"].shadow + end + end + + return spellPower + else + local damageAndHealing = 0 + local damageOnly = 0 + local SpellPower_Set_Bonus = {} + if BCS.needScanGear then + BCScache["gear"].damage_and_healing = 0 + BCScache["gear"].only_damage = 0 + BCScache["gear"].arcane = 0 + BCScache["gear"].fire = 0 + BCScache["gear"].frost = 0 + BCScache["gear"].holy = 0 + BCScache["gear"].nature = 0 + BCScache["gear"].shadow = 0 + -- scan gear + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + local SET_NAME + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + -- generic bonus on most gear + local _,_, value = strfind(left:GetText(), L["Equip: Increases damage and healing done by magical spells and effects by up to (%d+)."]) + if value then + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + tonumber(value) + end + -- Spell Power (weapon/bracer enchant) apparently gives healing too + -- Arcanum of Focus (Head/Legs enchant) + -- Power of the Scourge (Shoulder enchant) + _,_, value = strfind(left:GetText(), "Spell Damage %+(%d+)") + if value then + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + tonumber(value) + end + -- Atiesh (druid/priest) + _,_, value = strfind(left:GetText(), "Equip: Increases your spell damage by up to (%d+) and your healing by up to %d+.") + if value then + BCScache["gear"].only_damage = BCScache["gear"].only_damage + tonumber(value) + end + -- Zandalar Signet of Mojo (Shoulder enchant) + _,_, value = strfind(left:GetText(), L["^%+(%d+) Spell Damage and Healing"]) + if value then + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + tonumber(value) + end + -- Enchanted Armor Kit (Leatherworking) + _,_, value = strfind(left:GetText(), L["^%+(%d+) Damage and Healing Spells"]) + if value then + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Arcane spells and effects by up to (%d+)."]) + if value then + BCScache["gear"].arcane = BCScache["gear"].arcane + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["^%+(%d+) Arcane Spell Damage"]) + if value then + BCScache["gear"].arcane = BCScache["gear"].arcane + tonumber(value) + end + + _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Fire spells and effects by up to (%d+)."]) + if value then + BCScache["gear"].fire = BCScache["gear"].fire + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["Fire Damage %+(%d+)"]) + if value then + BCScache["gear"].fire = BCScache["gear"].fire + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["^%+(%d+) Fire Spell Damage"]) + if value then + BCScache["gear"].fire = BCScache["gear"].fire + tonumber(value) + end + + _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Frost spells and effects by up to (%d+)."]) + if value then + BCScache["gear"].frost = BCScache["gear"].frost + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["Frost Damage %+(%d+)"]) + if value then + BCScache["gear"].frost = BCScache["gear"].frost + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["^%+(%d+) Frost Spell Damage"]) + if value then + BCScache["gear"].frost = BCScache["gear"].frost + tonumber(value) + end + + _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Holy spells and effects by up to (%d+)."]) + if value then + BCScache["gear"].holy = BCScache["gear"].holy + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["^%+(%d+) Holy Spell Damage"]) + if value then + BCScache["gear"].holy = BCScache["gear"].holy + tonumber(value) + end + + _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Nature spells and effects by up to (%d+)."]) + if value then + BCScache["gear"].nature = BCScache["gear"].nature + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["^%+(%d+) Nature Spell Damage"]) + if value then + BCScache["gear"].nature = BCScache["gear"].nature + tonumber(value) + end + _,_, value = strfind(left:GetText(), "Nature Damage %+(%d+)") + if value then + BCScache["gear"].nature = BCScache["gear"].nature + tonumber(value) + end + + _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Shadow spells and effects by up to (%d+)."]) + if value then + BCScache["gear"].shadow = BCScache["gear"].shadow + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["Shadow Damage %+(%d+)"]) + if value then + BCScache["gear"].shadow = BCScache["gear"].shadow + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["^%+(%d+) Shadow Spell Damage"]) + if value then + BCScache["gear"].shadow = BCScache["gear"].shadow + tonumber(value) + end + + _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + if value then + SET_NAME = value + end + + _, _, value = strfind(left:GetText(), L["^Set: Increases damage and healing done by magical spells and effects by up to (%d+)%."]) + if value and SET_NAME and not tContains(SpellPower_Set_Bonus, SET_NAME) then + tinsert(SpellPower_Set_Bonus, SET_NAME) + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + tonumber(value) + end end - - _,_, value = strfind(left:GetText(), L["Equip: Increases damage done by Shadow spells and effects by up to (%d+)."]) - if value then - shadowPower = shadowPower + tonumber(value) + end + end + end + -- SetHyperLink doesnt show temporary enhancements, have to use SetInventoryItem + if BCS_Tooltip:SetInventoryItem("player", 16) then + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + -- apparently gives healing too + local found = strfind(left:GetText(), "Brilliant Wizard Oil") + if found then + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + 36 + break end - _,_, value = strfind(left:GetText(), L["Shadow Damage %+(%d+)"]) - if value then - shadowPower = shadowPower + tonumber(value) + found = strfind(left:GetText(), "Lesser Wizard Oil") + if found then + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + 16 + break end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Shadow Spell Damage"]) - if value then - shadowPower = shadowPower + tonumber(value) + found = strfind(left:GetText(), "Minor Wizard Oil") + if found then + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + 8 + break end - - _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") - if value then - SET_NAME = value + found = strfind(left:GetText(), "Wizard Oil") + if found then + BCScache["gear"].damage_and_healing = BCScache["gear"].damage_and_healing + 24 + break end + end + end + end + end - _, _, value = strfind(left:GetText(), L["^Set: Increases damage and healing done by magical spells and effects by up to (%d+)%."]) - if value and SET_NAME and not tContains(SpellPower_Set_Bonus, SET_NAME) then - tinsert(SpellPower_Set_Bonus, SET_NAME) - spellPower = spellPower + tonumber(value) + if BCS.needScanTalents then + impInnerFire = nil + spiritualGuidance = nil + -- scan talents + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Priest + -- Spiritual Guidance + local _,_, value = strfind(left:GetText(), L["Increases spell damage and healing by up to (%d+)%% of your total Spirit."]) + if value and rank > 0 then + spiritualGuidance = tonumber(value) + break + end + -- Improved Inner Fire + _,_, value = strfind(left:GetText(), "Increases the effects of your Inner Fire spell by (%d+)%%.") + if value and rank > 0 then + impInnerFire = tonumber(value) + break + end end - end end end - end - - -- scan talents - local MAX_TABS = GetNumTalentTabs() - - for tab=1, MAX_TABS do - local MAX_TALENTS = GetNumTalents(tab) - - for talent=1, MAX_TALENTS do - BCS_Tooltip:SetTalent(tab, talent) - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do - local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - -- Priest - -- Spiritual Guidance - local _,_, value = strfind(left:GetText(), L["Increases spell damage and healing by up to (%d+)%% of your total Spirit."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) - if value and rank > 0 then - local stat, effectiveStat = UnitStat("player", 5) - spellPower = spellPower + floor(((tonumber(value) / 100) * effectiveStat)) - - -- nothing more is currenlty supported, break out of the loops - line = MAX_LINES - talent = MAX_TALENTS - tab = MAX_TABS - end - end + if BCS.needScanAuras then + BCScache["auras"].damage_and_healing = 0 + BCScache["auras"].only_damage = 0 + -- buffs + local _, _, spellPowerFromAura = BCS:GetPlayerAura(L["Magical damage dealt is increased by up to (%d+)."]) + if spellPowerFromAura then + BCScache["auras"].only_damage = BCScache["auras"].only_damage + tonumber(spellPowerFromAura) + end + _, _, spellPowerFromAura = BCS:GetPlayerAura("Increases damage and healing done by magical spells and effects by up to (%d+).") + if spellPowerFromAura then + BCScache["auras"].damage_and_healing = BCScache["auras"].damage_and_healing + tonumber(spellPowerFromAura) + end + -- Dreamtonic/Arcane Elixir + _, _, spellPowerFromAura = BCS:GetPlayerAura("Magical damage dealt by spells and abilities is increased by up to (%d+)") + if spellPowerFromAura then + BCScache["auras"].only_damage = BCScache["auras"].only_damage + tonumber(spellPowerFromAura) + end + -- Dreamshard Elixir + _, _, spellPowerFromAura = BCS:GetPlayerAura("Spell damage is increased by up to (%d+)") + if spellPowerFromAura then + BCScache["auras"].only_damage = BCScache["auras"].only_damage + tonumber(spellPowerFromAura) + end + -- Flask of Supreme Power + _, _, spellPowerFromAura = BCS:GetPlayerAura("Spell damage increased by up to (%d+)") + if spellPowerFromAura then + BCScache["auras"].only_damage = BCScache["auras"].only_damage + tonumber(spellPowerFromAura) + end + -- Danonzo's Tel'Abim Delight + _, _, spellPowerFromAura = BCS:GetPlayerAura("Spell Damage increased by (%d+)") + if spellPowerFromAura then + BCScache["auras"].only_damage = BCScache["auras"].only_damage + tonumber(spellPowerFromAura) + end + --Inner Fire + _, _, spellPowerFromAura = BCS:GetPlayerAura("Increased damage done by magical spells and effects by (%d+).") + if spellPowerFromAura then + spellPowerFromAura = tonumber(spellPowerFromAura) + if impInnerFire then + spellPowerFromAura = floor((spellPowerFromAura * (impInnerFire/100)) + (spellPowerFromAura)) end - + BCScache["auras"].only_damage = BCScache["auras"].only_damage + spellPowerFromAura end end - - -- buffs - local _, _, spellPowerFromAura = BCS:GetPlayerAura(L["Magical damage dealt is increased by up to (%d+)."]) - if spellPowerFromAura then - spellPower = spellPower + tonumber(spellPowerFromAura) - damagePower = damagePower + tonumber(spellPowerFromAura) - end - - _, _, spellPowerFromAura = BCS:GetPlayerAura("Increases damage and healing done by magical spells and effects by up to (%d+).") - if spellPowerFromAura then - spellPower = spellPower + tonumber(spellPowerFromAura) - damagePower = damagePower + tonumber(spellPowerFromAura) - end - - _, _, spellPowerFromAura = BCS:GetPlayerAura("Magical damage dealt by spells and abilities is increased by up to (%d+)") - if spellPowerFromAura then - spellPower = spellPower + tonumber(spellPowerFromAura) - damagePower = damagePower + tonumber(spellPowerFromAura) - end - - _, _, spellPowerFromAura = BCS:GetPlayerAura("Spell damage is increased by up to (%d+)") - if spellPowerFromAura then - spellPower = spellPower + tonumber(spellPowerFromAura) - damagePower = damagePower + tonumber(spellPowerFromAura) - end - local secondaryPower = 0 local secondaryPowerName = "" - - if arcanePower > secondaryPower then - secondaryPower = arcanePower + + if BCScache["gear"].arcane > secondaryPower then + secondaryPower = BCScache["gear"].arcane secondaryPowerName = L.SPELL_SCHOOL_ARCANE end - if firePower > secondaryPower then - secondaryPower = firePower + if BCScache["gear"].fire > secondaryPower then + secondaryPower = BCScache["gear"].fire secondaryPowerName = L.SPELL_SCHOOL_FIRE end - if frostPower > secondaryPower then - secondaryPower = frostPower + if BCScache["gear"].frost > secondaryPower then + secondaryPower = BCScache["gear"].frost secondaryPowerName = L.SPELL_SCHOOL_FROST end - if holyPower > secondaryPower then - secondaryPower = holyPower + if BCScache["gear"].holy > secondaryPower then + secondaryPower = BCScache["gear"].holy secondaryPowerName = L.SPELL_SCHOOL_HOLY end - if naturePower > secondaryPower then - secondaryPower = naturePower + if BCScache["gear"].nature > secondaryPower then + secondaryPower = BCScache["gear"].nature secondaryPowerName = L.SPELL_SCHOOL_NATURE end - if shadowPower > secondaryPower then - secondaryPower = shadowPower + if BCScache["gear"].shadow > secondaryPower then + secondaryPower = BCScache["gear"].shadow secondaryPowerName = L.SPELL_SCHOOL_SHADOW end - - return spellPower, secondaryPower, secondaryPowerName, damagePower + + if spiritualGuidance ~= nil then + BCScache["talents"].damage_and_healing = 0 + local _, spirit = UnitStat("player", 5) + BCScache["talents"].damage_and_healing = BCScache["talents"].damage_and_healing + floor(((spiritualGuidance / 100) * spirit)) + end + + damageAndHealing = BCScache["gear"].damage_and_healing + BCScache["talents"].damage_and_healing + BCScache["auras"].damage_and_healing + damageOnly = BCScache["auras"].only_damage + BCScache["gear"].only_damage + + return damageAndHealing, secondaryPower, secondaryPowerName, damageOnly end end +local ironClad = nil +--this is stuff that gives ONLY healing, we count stuff that gives both damage and healing in GetSpellPower function BCS:GetHealingPower() local healPower = 0; local healPower_Set_Bonus = {} - local MAX_INVENTORY_SLOTS = 19 - - for slot=0, MAX_INVENTORY_SLOTS do - local hasItem = BCS_Tooltip:SetInventoryItem("player", slot) - - if hasItem then - local SET_NAME - + --talents + if BCS.needScanTalents then + ironClad = nil + BCScache["talents"].healing = 0 + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Paladin + -- Ironclad + local _,_, value = strfind(left:GetText(), L["Increases your healing power by (%d+)%% of your Armor."]) + if value and rank > 0 then + ironClad = tonumber(value) + break + end + end + end + end + end + end + if BCS.needScanGear then + BCScache["gear"].healing = 0 + --scan gear + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + local SET_NAME + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), L["Equip: Increases healing done by spells and effects by up to (%d+)."]) + if value then + BCScache["gear"].healing = BCScache["gear"].healing + tonumber(value) + end + -- Atiesh (druid/priest) + _,_, value = strfind(left:GetText(), "Equip: Increases your spell damage by up to %d+ and your healing by up to (%d+).") + if value then + BCScache["gear"].healing = BCScache["gear"].healing + tonumber(value) + end + -- Enchant Weapon/Gloves/Bracers - Healing Power + _,_, value = strfind(left:GetText(), L["Healing Spells %+(%d+)"]) + if value then + BCScache["gear"].healing = BCScache["gear"].healing + tonumber(value) + end + -- Zandalar Signet of Serenity (Shoulder enchant) + _,_, value = strfind(left:GetText(), L["^%+(%d+) Healing Spells"]) + if value then + BCScache["gear"].healing = BCScache["gear"].healing + tonumber(value) + end + -- Beautiful Diamond Gemstone (Jewelcrafting) + -- Resilience of the Scourge (Shoulder enchant) + _,_, value = strfind(left:GetText(), "Healing %+(%d+)") + if value then + BCScache["gear"].healing = BCScache["gear"].healing + tonumber(value) + end + -- Enchanted Armor Kit (Leatherwotking) + -- Arcanum of Focus (Head/Legs enchant) + -- already included in GetSpellPower + + _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + if value then + SET_NAME = value + end + _, _, value = strfind(left:GetText(), L["^Set: Increases healing done by spells and effects by up to (%d+)%."]) + if value and SET_NAME and not tContains(healPower_Set_Bonus, SET_NAME) then + tinsert(healPower_Set_Bonus, SET_NAME) + BCScache["gear"].healing = BCScache["gear"].healing + tonumber(value) + end + end + end + end + end + -- SetHyperLink doesnt show temporary enhancements, have to use SetInventoryItem + if BCS_Tooltip:SetInventoryItem("player", 16) then for line=1, BCS_Tooltip:NumLines() do local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["Equip: Increases healing done by spells and effects by up to (%d+)."]) - if value then - healPower = healPower + tonumber(value) - end - _,_, value = strfind(left:GetText(), "Equip: Increases your spell damage by up to 120 and your healing by up to (300).") - if value then - healPower = healPower + tonumber(value) - 120 - end - _,_, value = strfind(left:GetText(), L["Healing Spells %+(%d+)"]) - if value then - healPower = healPower + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["^Healing %+(%d+) and %d+ mana per 5 sec."]) - if value then - healPower = healPower + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["^%+(%d+) Healing Spells"]) - if value then - healPower = healPower + tonumber(value) - end - _,_, value = strfind(left:GetText(), "^Brilliant Mana Oil %((%d+) min%)") - if value then - healPower = healPower + 25 - end - - _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") - if value then - SET_NAME = value - end - _, _, value = strfind(left:GetText(), L["^Set: Increases healing done by spells and effects by up to (%d+)%."]) - if value and SET_NAME and not tContains(healPower_Set_Bonus, SET_NAME) then - tinsert(healPower_Set_Bonus, SET_NAME) - healPower = healPower + tonumber(value) + local found = strfind(left:GetText(), "Brilliant Mana Oil") + if found then + BCScache["gear"].healing = BCScache["gear"].healing + 25 end end end end - end - -- buffs - local _, _, healPowerFromAura = BCS:GetPlayerAura(L["Healing done by magical spells is increased by up to (%d+)."]) - if healPowerFromAura then - healPower = healPower + tonumber(healPowerFromAura) - end - --Sweet Surprise - _, _, healPowerFromAura = BCS:GetPlayerAura(L["Increases healing done by magical spells by up to (%d+) for 3600 sec."]) - if healPowerFromAura then - healPower = healPower + tonumber(healPowerFromAura) - end - --Unstable Power - _, _, healPowerFromAura = BCS:GetPlayerAura(L["Healing increased by up to (%d+)."]) - if healPowerFromAura then - healPower = healPower + tonumber(healPowerFromAura) - end - --The Eye of the Dead - _, _, healPowerFromAura = BCS:GetPlayerAura(L["Healing spells increased by up to (%d+)."]) - if healPowerFromAura then - healPower = healPower + tonumber(healPowerFromAura) - end - --Power of the Guardian - _, _, healPowerFromAura = BCS:GetPlayerAura("Increases healing done by magical spells and effects by up to (%d+).") - if healPowerFromAura then - healPower = healPower + tonumber(healPowerFromAura) - end - _, _, healPowerFromAura = BCS:GetPlayerAura("Increases damage and healing done by magical spells and effects by up to (%d+).") - if healPowerFromAura then - healPower = healPower + tonumber(healPowerFromAura) + local treebonus = nil + if BCS.needScanAuras then + BCScache["auras"].healing = 0 + local _, _, healPowerFromAura = BCS:GetPlayerAura(L["Healing done by magical spells is increased by up to (%d+)."]) + if healPowerFromAura then + BCScache["auras"].healing = BCScache["auras"].healing + tonumber(healPowerFromAura) + end + --Tree of Life (own) + local found = BCS:GetPlayerAura("Tree of Life Form") and BCS:GetPlayerAura("Tree of Life Aura") + local _, spirit = UnitStat("player", 5) + if found then + treebonus = spirit * 0.2 + end + --Sweet Surprise + _, _, healPowerFromAura = BCS:GetPlayerAura(L["Increases healing done by magical spells by up to (%d+) for 3600 sec."]) + if healPowerFromAura then + BCScache["auras"].healing = BCScache["auras"].healing + tonumber(healPowerFromAura) + end + --Unstable Power + _, _, healPowerFromAura = BCS:GetPlayerAura(L["Healing increased by up to (%d+)."]) + if healPowerFromAura then + BCScache["auras"].healing = BCScache["auras"].healing + tonumber(healPowerFromAura) + end + --The Eye of the Dead + _, _, healPowerFromAura = BCS:GetPlayerAura(L["Healing spells increased by up to (%d+)."]) + if healPowerFromAura then + BCScache["auras"].healing = BCScache["auras"].healing + tonumber(healPowerFromAura) + end + --Power of the Guardian + _, _, healPowerFromAura = BCS:GetPlayerAura("Increases healing done by magical spells and effects by up to (%d+).") + if healPowerFromAura then + BCScache["auras"].healing = BCScache["auras"].healing + tonumber(healPowerFromAura) + end + --Dreamshard Elixir + _, _, healPowerFromAura = BCS:GetPlayerAura("Healing done is increased by up to (%d+)") + if healPowerFromAura then + BCScache["auras"].healing = BCScache["auras"].healing + tonumber(healPowerFromAura) + end end - --Dreamshard Elixir - _, _, healPowerFromAura = BCS:GetPlayerAura("Healing done is increased by up to (%d+)") - if healPowerFromAura then - healPower = healPower + tonumber(healPowerFromAura) + if ironClad ~= nil then + BCScache["talents"].healing = 0 + local base = UnitArmor("player") + local _, agility = UnitStat("player", 2) + local armorFromGear = base - (agility * 2) + BCScache["talents"].healing = floor(((ironClad / 100) * armorFromGear)) end - - return healPower + healPower = BCScache["gear"].healing + BCScache["auras"].healing + BCScache["talents"].healing + + return healPower, treebonus, BCScache["talents"].healing end local function GetRegenMPPerSpirit() local addvalue = 0 - - local stat, Spirit, posBuff, negBuff = UnitStat("player", 5) - local lClass, class = UnitClass("player") - + local _, spirit = UnitStat("player", 5) + local _, class = UnitClass("player") + if class == "DRUID" then - addvalue = (Spirit / 5 + 15) + addvalue = (spirit / 5 + 15) elseif class == "HUNTER" then - addvalue = (Spirit / 5 + 15) + addvalue = (spirit / 5 + 15) elseif class == "MAGE" then - addvalue = (Spirit / 4 + 12.5) + addvalue = (spirit / 4 + 12.5) elseif class == "PALADIN" then - addvalue = (Spirit / 5 + 15) + addvalue = (spirit / 5 + 15) elseif class == "PRIEST" then - addvalue = (Spirit / 4 + 12.5) + addvalue = (spirit / 4 + 12.5) elseif class == "SHAMAN" then - addvalue = (Spirit / 5 + 17) + addvalue = (spirit / 5 + 17) elseif class == "WARLOCK" then - addvalue = (Spirit / 5 + 15) - else - return addvalue + addvalue = (spirit / 5 + 15) end + return addvalue end +local waterShield = nil function BCS:GetManaRegen() local base = GetRegenMPPerSpirit() local casting = 0 local mp5 = 0 local mp5_Set_Bonus = {} - local MAX_INVENTORY_SLOTS = 19 - - for slot=0, MAX_INVENTORY_SLOTS do - local hasItem = BCS_Tooltip:SetInventoryItem("player", slot) - - if hasItem then - local SET_NAME + -- scan talents + if BCS.needScanTalents then + waterShield = nil + BCScache["talents"].casting = 0 + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do + BCS_Tooltip:SetTalent(tab, talent) + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _, _, _, _, rank = GetTalentInfo(tab, talent) + -- Priest (Meditation) / Druid (Reflection) / Mage (Arcane Meditation) / Shaman (Improved Water Shield) + local _,_, value = strfind(left:GetText(), L["Allows (%d+)%% of your Mana regeneration to continue while casting."]) + if value and rank > 0 then + BCScache["talents"].casting = BCScache["talents"].casting + tonumber(value) + waterShield = rank + break + end + end + end + end + end + end + + if BCS.needScanGear then + BCScache["gear"].mp5 = 0 + BCScache["gear"].casting = 0 + --scan gear + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + local SET_NAME + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), L["^Mana Regen %+(%d+)"]) + if value then + BCScache["gear"].mp5 = BCScache["gear"].mp5 + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["Equip: Restores (%d+) mana per 5 sec."]) + if value and not strfind(left:GetText(), "to all party members") then + BCScache["gear"].mp5 = BCScache["gear"].mp5 + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["^Healing %+%d+ and (%d+) mana per 5 sec."]) + if value then + BCScache["gear"].mp5 = BCScache["gear"].mp5 + tonumber(value) + end + _,_, value = strfind(left:GetText(), L["^%+(%d+) mana every 5 sec."]) + if value then + BCScache["gear"].mp5 = BCScache["gear"].mp5 + tonumber(value) + end + _,_, value = strfind(left:GetText(), "^Equip: Allows (%d+)%% of your Mana regeneration to continue while casting.") + if value then + BCScache["gear"].casting = BCScache["gear"].casting + tonumber(value) + end + + _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + if value then + SET_NAME = value + end + _,_, value = strfind(left:GetText(), L["^Set: Allows (%d+)%% of your Mana regeneration to continue while casting."]) + if value and SET_NAME and not tContains(mp5_Set_Bonus, SET_NAME) then + tinsert(mp5_Set_Bonus, SET_NAME) + BCScache["gear"].casting = BCScache["gear"].casting + tonumber(value) + end + _,_, value = strfind(left:GetText(), "^Set: Restores (%d+) mana per 5 sec.") + if value and SET_NAME and not tContains(mp5_Set_Bonus, SET_NAME) then + tinsert(mp5_Set_Bonus, SET_NAME) + BCScache["gear"].mp5 = BCScache["gear"].mp5 + tonumber(value) + end + end + end + end + end + -- SetHyperLink doesnt show temporary enhancements, have to use SetInventoryItem + if BCS_Tooltip:SetInventoryItem("player", 16) then for line=1, BCS_Tooltip:NumLines() do local left = getglobal(BCS_Prefix .. "TextLeft" .. line) - if left:GetText() then - local _,_, value = strfind(left:GetText(), L["^Mana Regen %+(%d+)"]) - if value then - mp5 = mp5 + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["Equip: Restores (%d+) mana per 5 sec."]) - if value and not strfind(left:GetText(), "to all party members") then - mp5 = mp5 + tonumber(value) - end - _,_, value = strfind(left:GetText(), L["^Healing %+%d+ and (%d+) mana per 5 sec."]) - if value then - mp5 = mp5 + tonumber(value) + local found = strfind(left:GetText(), "Brilliant Mana Oil") + if found then + BCScache["gear"].mp5 = BCScache["gear"].mp5 + 12 end - _,_, value = strfind(left:GetText(), L["^%+(%d+) mana every 5 sec."]) - if value then - mp5 = mp5 + tonumber(value) - end - _,_, value = strfind(left:GetText(), "^Brilliant Mana Oil %((%d+) min%)") - if value then - mp5 = mp5 + 12 + found = strfind(left:GetText(), "Lesser Mana Oil") + if found then + BCScache["gear"].mp5 = BCScache["gear"].mp5 + 8 end - _,_, value = strfind(left:GetText(), "^Lesser Mana Oil %((%d+) min%)") - if value then - mp5 = mp5 + 8 + found = strfind(left:GetText(), "Minor Mana Oil") + if found then + BCScache["gear"].mp5 = BCScache["gear"].mp5 + 4 end - _,_, value = strfind(left:GetText(), "^Minor Mana Oil %((%d+) min%)") + end + end + end + end + + -- buffs + if BCS.needScanAuras then + BCScache["auras"].casting = 0 + BCScache["auras"].mp5 = 0 + -- improved Shadowform + for tab=1, GetNumSpellTabs() do + local _, _, offset, numSpells = GetSpellTabInfo(tab); + for s = offset + 1, offset + numSpells do + local spell = GetSpellName(s, BOOKTYPE_SPELL); + if spell == "Improved Shadowform" and BCS:GetPlayerAura("Shadowform") then + BCScache["auras"].casting = BCScache["auras"].casting + 15 + end + end + end + -- Warchief's Blessing + local _, _, mp5FromAura = BCS:GetPlayerAura(L["Increases hitpoints by 300. 15%% haste to melee attacks. (%d+) mana regen every 5 seconds."]) + if mp5FromAura then + BCScache["auras"].mp5 = BCScache["auras"].mp5 + 10 + end + --Epiphany + _, _, mp5FromAura = BCS:GetPlayerAura(L["Restores (%d+) mana per 5 sec."]) + if mp5FromAura then + BCScache["auras"].mp5 = BCScache["auras"].mp5 + tonumber(mp5FromAura) + end + --Nightfin Soup + _, _, mp5FromAura = BCS:GetPlayerAura(L["Regenerating (%d+) Mana every 5 seconds."]) + if mp5FromAura then + BCScache["auras"].mp5 = BCScache["auras"].mp5 + tonumber(mp5FromAura)*2.5 -- had to double the mp5FromAura because the item is a true mp5 tick + end + --Mageblood Potion + _, _, mp5FromAura = BCS:GetPlayerAura(L["Regenerate (%d+) mana per 5 sec."]) + if mp5FromAura then + BCScache["auras"].mp5 = BCScache["auras"].mp5 + tonumber(mp5FromAura) + end + --Fizzy Energy Drink and Sagefin + _, _, mp5FromAura = BCS:GetPlayerAura(L["Mana Regeneration increased by (%d+) every 5 seconds."]) + if mp5FromAura then + BCScache["auras"].mp5 = BCScache["auras"].mp5 + tonumber(mp5FromAura)*2.5 + end + --Second Wind + _, _, mp5FromAura = BCS:GetPlayerAura(L["Restores (%d+) mana every 1 sec."]) + if mp5FromAura then + BCScache["auras"].mp5 = BCScache["auras"].mp5 + tonumber(mp5FromAura)*5 -- had to multiply by 5 the mp5FromAura because the item is a sec per tick + end + --Power of the Guardian + _, _, mp5FromAura = BCS:GetPlayerAura("Restores (%d+) mana per 5 seconds.") + if mp5FromAura then + BCScache["auras"].mp5 = BCScache["auras"].mp5 + tonumber(mp5FromAura) + end + --Aura of the blue dragon + local _, _, castingFromAura = BCS:GetPlayerAura(L["(%d+)%% of your Mana regeneration continuing while casting."]) + if castingFromAura then + BCScache["auras"].casting = BCScache["auras"].casting + tonumber(castingFromAura) + end + --Mage Armor + _, _, castingFromAura = BCS:GetPlayerAura(L["(%d+)%% of your mana regeneration to continue while casting."]) + if castingFromAura then + BCScache["auras"].casting = BCScache["auras"].casting + tonumber(castingFromAura) + end + --Sylvan Blessing + _, _, castingFromAura = BCS:GetPlayerAura("Allows (%d+)%% of mana regeneration while casting.") + if castingFromAura then + BCScache["auras"].casting = BCScache["auras"].casting + tonumber(castingFromAura) + end + --Improved Water Shield + if waterShield ~= nil then + for i = 1, 32 do + local icon, stacks = UnitBuff("player", i) + if icon and stacks and icon == "Interface\\Icons\\Ability_Shaman_WaterShield" then + BCScache["auras"].casting = BCScache["auras"].casting + (tonumber(stacks) * waterShield) + end + end + end + end + + casting = BCScache["auras"].casting + BCScache["talents"].casting + BCScache["gear"].casting + mp5 = BCScache["auras"].mp5 + BCScache["gear"].mp5 + + if casting > 100 then + casting = 100 + end + + return base, casting, mp5 +end + +--Weapon Skill code adapted from https://github.com/pepopo978/BetterCharacterStats +function BCS:GetWeaponSkill(skillName) + -- loop through skills + local skillIndex = 1 + while true do + local name, _, _, skillRank, _, skillModifier = GetSkillLineInfo(skillIndex) + if not name then + return 0 + end + + if name == skillName then + return skillRank + skillModifier + end + + skillIndex = skillIndex + 1 + end +end + +function BCS:GetWeaponSkillForWeaponType(weaponType) + if weaponType == "Daggers" then + return BCS:GetWeaponSkill("Daggers") + elseif weaponType == "One-Handed Swords" then + return BCS:GetWeaponSkill("Swords") + elseif weaponType == "Two-Handed Swords" then + return BCS:GetWeaponSkill("Two-Handed Swords") + elseif weaponType == "One-Handed Axes" then + return BCS:GetWeaponSkill("Axes") + elseif weaponType == "Two-Handed Axes" then + return BCS:GetWeaponSkill("Two-Handed Axes") + elseif weaponType == "One-Handed Maces" then + return BCS:GetWeaponSkill("Maces") + elseif weaponType == "Two-Handed Maces" then + return BCS:GetWeaponSkill("Two-Handed Maces") + elseif weaponType == "Staves" then + return BCS:GetWeaponSkill("Staves") + elseif weaponType == "Polearms" then + return BCS:GetWeaponSkill("Polearms") + elseif weaponType == "Fist Weapons" then + return BCS:GetWeaponSkill("Unarmed") + elseif weaponType == "Bows" then + return BCS:GetWeaponSkill("Bows") + elseif weaponType == "Crossbows" then + return BCS:GetWeaponSkill("Crossbows") + elseif weaponType == "Guns" then + return BCS:GetWeaponSkill("Guns") + elseif weaponType == "Thrown" then + return BCS:GetWeaponSkill("Thrown") + elseif weaponType == "Wands" then + return BCS:GetWeaponSkill("Wands") + end + -- no weapon equipped + return BCS:GetWeaponSkill("Unarmed") +end + +function BCS:GetItemTypeForSlot(slot) + local _, _, id = string.find(GetInventoryItemLink("player", GetInventorySlotInfo(slot)) or "", "(item:%d+:%d+:%d+:%d+)"); + if not id then + return + end + + local _, _, _, _, _, itemType = GetItemInfo(id); + + return itemType +end + +function BCS:GetMHWeaponSkill() + if not BCS.needScanSkills then + return BCScache["skills"].mh + end + local itemType = BCS:GetItemTypeForSlot("MainHandSlot") + BCScache["skills"].mh = BCS:GetWeaponSkillForWeaponType(itemType) + + return BCScache["skills"].mh +end + +function BCS:GetOHWeaponSkill() + if not BCS.needScanSkills then + return BCScache["skills"].oh + end + + local itemType = BCS:GetItemTypeForSlot("SecondaryHandSlot") + BCScache["skills"].oh = BCS:GetWeaponSkillForWeaponType(itemType) + + return BCScache["skills"].oh +end + +function BCS:GetRangedWeaponSkill() + if not BCS.needScanSkills then + return BCScache["skills"].ranged + end + + local itemType = BCS:GetItemTypeForSlot("RangedSlot") + BCScache["skills"].ranged = BCS:GetWeaponSkillForWeaponType(itemType) + + return BCScache["skills"].ranged +end + +--https://us.forums.blizzard.com/en/wow/t/block-value-formula/283718/18 +local enhancingTotems = nil +function BCS:GetBlockValue() + local blockValue = 0 + local _, strength = UnitStat("player", 1) + local mod = 0 + -- scan gear + for slot=1, 19 do + if BCS_Tooltip:SetInventoryItem('player', slot) then + local _, _, eqItemLink = strfind(GetInventoryItemLink('player', slot), "(item:%d+:%d+:%d+:%d+)") + if eqItemLink then BCS_Tooltip:ClearLines() BCS_Tooltip:SetHyperlink(eqItemLink) end + for line=1, BCS_Tooltip:NumLines() do + local left = getglobal(BCS_Prefix .. "TextLeft" .. line) + if left:GetText() then + local _,_, value = strfind(left:GetText(), "(%d+) Block") if value then - mp5 = mp5 + 4 + blockValue = blockValue + tonumber(value) end - _,_, value = strfind(left:GetText(), "^Equip: Allows (%d+)%% of your Mana regeneration to continue while casting.") + _,_, value = strfind(left:GetText(), "Equip: Increases the block value of your shield by (%d+).") if value then - casting = casting + tonumber(value) + blockValue = blockValue + tonumber(value) end - _,_, value = strfind(left:GetText(), "(.+) %(%d/%d%)") + _,_, value = strfind(left:GetText(), "Block Value %+(%d+)") if value then - SET_NAME = value - end - _,_, value = strfind(left:GetText(), L["^Set: Allows (%d+)%% of your Mana regeneration to continue while casting."]) - if value and SET_NAME and not tContains(mp5_Set_Bonus, SET_NAME) then - tinsert(mp5_Set_Bonus, SET_NAME) - casting = casting + tonumber(value) - end - _,_, value = strfind(left:GetText(), "^Set: Restores (%d+) mana per 5 sec.") - if value and SET_NAME and not tContains(mp5_Set_Bonus, SET_NAME) then - tinsert(mp5_Set_Bonus, SET_NAME) - mp5 = mp5 + tonumber(value) + blockValue = blockValue + tonumber(value) end end end end end - -- scan talents - local MAX_TABS = GetNumTalentTabs() - - for tab=1, MAX_TABS do - local MAX_TALENTS = GetNumTalents(tab) - - for talent=1, MAX_TALENTS do + for tab=1, GetNumTalentTabs() do + for talent=1, GetNumTalents(tab) do BCS_Tooltip:SetTalent(tab, talent) - local MAX_LINES = BCS_Tooltip:NumLines() - - for line=1, MAX_LINES do + for line=1, BCS_Tooltip:NumLines() do local left = getglobal(BCS_Prefix .. "TextLeft" .. line) if left:GetText() then - -- Priest (Meditation) / Druid (Reflection) - local _,_, value = strfind(left:GetText(), L["Allows (%d+)%% of your Mana regeneration to continue while casting."]) - local name, iconTexture, tier, column, rank, maxRank, isExceptional, meetsPrereq = GetTalentInfo(tab, talent) + local _, _, _, _, rank = GetTalentInfo(tab, talent) + --warrior/paladin + local _,_, value = strfind(left:GetText(), "amount of damage absorbed by your shield by (%d+)%%") + if value and rank > 0 then + mod = mod + tonumber(value) + break + end + --shaman + --shield specialization + _,_, value = strfind(left:GetText(), "increases the amount blocked by (%d+)%%") if value and rank > 0 then - casting = casting + tonumber(value) + mod = mod + tonumber(value) + break end - end + --enhancing totems + _,_, value = strfind(left:GetText(), "increases block amount by (%d+)%%") + if value and rank > 0 then + enhancingTotems = tonumber(value) + break + end + end end - end end - -- buffs - -- Warchief's Blessing - local _, _, mp5FromAura = BCS:GetPlayerAura(L["Increases hitpoints by 300. 15%% haste to melee attacks. (%d+) mana regen every 5 seconds."]) - if mp5FromAura then - mp5 = mp5 + 10 - end - --Epiphany - _, _, mp5FromAura = BCS:GetPlayerAura(L["Restores (%d+) mana per 5 sec."]) - if mp5FromAura then - mp5 = mp5 + tonumber(mp5FromAura) - end - --Nightfin Soup - _, _, mp5FromAura = BCS:GetPlayerAura(L["Regenerating (%d+) Mana every 5 seconds."]) - if mp5FromAura then - mp5 = mp5 + tonumber(mp5FromAura)*2.5 -- had to double the mp5FromAura because the item is a true mp5 tick - end - --Mageblood Potion - _, _, mp5FromAura = BCS:GetPlayerAura(L["Regenerate (%d+) mana per 5 sec."]) - if mp5FromAura then - mp5 = mp5 + tonumber(mp5FromAura) - end - --Fizzy Energy Drink and Sagefin - _, _, mp5FromAura = BCS:GetPlayerAura(L["Mana Regeneration increased by (%d+) every 5 seconds."]) - if mp5FromAura then - mp5 = mp5 + tonumber(mp5FromAura)*2.5 - end - --Second Wind - _, _, mp5FromAura = BCS:GetPlayerAura(L["Restores (%d+) mana every 1 sec."]) - if mp5FromAura then - mp5 = mp5 + tonumber(mp5FromAura)*5 -- had to multiply by 5 the mp5FromAura because the item is a sec per tick + --Glyph of Deflection + local _, _, value = BCS:GetPlayerAura("Block value increased by (%d+).") + if value then + blockValue = blockValue + tonumber(value) end - --Aura of the blue dragon - _, _, castingFromAura = BCS:GetPlayerAura(L["(%d+)%% of your Mana regeneration continuing while casting."]) - if mp5FromAura then - casting = casting + tonumber(castingFromAura) + if enhancingTotems and BCS:GetPlayerAura("^Stoneskin") then + mod = mod + enhancingTotems end - --Power of the Guardian - _, _, castingFromAura = BCS:GetPlayerAura("Restores (%d+) mana per 5 seconds.") - if mp5FromAura then - mp5 = mp5 + tonumber(mp5FromAura) - end - if casting > 100 then - casting = 100 - end - return base, casting, mp5 + + mod = mod/100 + blockValue = blockValue + (strength/20 - 1) + blockValue = floor(blockValue + blockValue * mod) + + if blockValue < 0 then blockValue = 0 end + + return blockValue end \ No newline at end of file