EQUIPPED_FIRST = 1; EQUIPPED_LAST = 19; NUM_RESISTANCE_TYPES = 5; NUM_STATS = 5; NUM_SHOPPING_TOOLTIPS = 2; MAX_SPELL_SCHOOLS = 7; CR_WEAPON_SKILL = 1; CR_DEFENSE_SKILL = 2; CR_DODGE = 3; CR_PARRY = 4; CR_BLOCK = 5; CR_HIT_MELEE = 6; CR_HIT_RANGED = 7; CR_HIT_SPELL = 8; CR_CRIT_MELEE = 9; CR_CRIT_RANGED = 10; CR_CRIT_SPELL = 11; CR_HIT_TAKEN_MELEE = 12; CR_HIT_TAKEN_RANGED = 13; CR_HIT_TAKEN_SPELL = 14; CR_CRIT_TAKEN_MELEE = 15; CR_CRIT_TAKEN_RANGED = 16; CR_CRIT_TAKEN_SPELL = 17; CR_HASTE_MELEE = 18; CR_HASTE_RANGED = 19; CR_HASTE_SPELL = 20; CR_WEAPON_SKILL_MAINHAND = 21; CR_WEAPON_SKILL_OFFHAND = 22; CR_WEAPON_SKILL_RANGED = 23; CR_EXPERTISE = 24; CR_ARMOR_PENETRATION = 25; ATTACK_POWER_MAGIC_NUMBER = 14; BLOCK_PER_STRENGTH = 0.5; HEALTH_PER_STAMINA = 10; ARMOR_PER_AGILITY = 2; MANA_PER_INTELLECT = 15; MANA_REGEN_PER_SPIRIT = 0.2; DODGE_PARRY_BLOCK_PERCENT_PER_DEFENSE = 0.04; RESILIENCE_CRIT_CHANCE_TO_DAMAGE_REDUCTION_MULTIPLIER = 2.2; RESILIENCE_CRIT_CHANCE_TO_CONSTANT_DAMAGE_REDUCTION_MULTIPLIER = 2.0; --Pet scaling: HUNTER_PET_BONUS = {}; HUNTER_PET_BONUS["PET_BONUS_RAP_TO_AP"] = 0.22; HUNTER_PET_BONUS["PET_BONUS_RAP_TO_SPELLDMG"] = 0.1287; HUNTER_PET_BONUS["PET_BONUS_STAM"] = 0.3; HUNTER_PET_BONUS["PET_BONUS_RES"] = 0.4; HUNTER_PET_BONUS["PET_BONUS_ARMOR"] = 0.35; HUNTER_PET_BONUS["PET_BONUS_SPELLDMG_TO_SPELLDMG"] = 0.0; HUNTER_PET_BONUS["PET_BONUS_SPELLDMG_TO_AP"] = 0.0; HUNTER_PET_BONUS["PET_BONUS_INT"] = 0.0; WARLOCK_PET_BONUS = {}; WARLOCK_PET_BONUS["PET_BONUS_RAP_TO_AP"] = 0.0; WARLOCK_PET_BONUS["PET_BONUS_RAP_TO_SPELLDMG"] = 0.0; WARLOCK_PET_BONUS["PET_BONUS_STAM"] = 0.3; WARLOCK_PET_BONUS["PET_BONUS_RES"] = 0.4; WARLOCK_PET_BONUS["PET_BONUS_ARMOR"] = 0.35; WARLOCK_PET_BONUS["PET_BONUS_SPELLDMG_TO_SPELLDMG"] = 0.15; WARLOCK_PET_BONUS["PET_BONUS_SPELLDMG_TO_AP"] = 0.57; WARLOCK_PET_BONUS["PET_BONUS_INT"] = 0.3; PLAYERSTAT_DROPDOWN_OPTIONS = { "PLAYERSTAT_BASE_STATS", "PLAYERSTAT_MELEE_COMBAT", "PLAYERSTAT_RANGED_COMBAT", "PLAYERSTAT_SPELL_COMBAT", "PLAYERSTAT_DEFENSES", }; PDFITEMFLYOUT_MAXITEMS = 23; PDFITEMFLYOUT_ONESLOT_LEFT_COORDS = { 0, 0.09765625, 0.5546875, 0.77734375 } PDFITEMFLYOUT_ONESLOT_RIGHT_COORDS = { 0.41796875, 0.51171875, 0.5546875, 0.77734375 } PDFITEMFLYOUT_ONESLOT_LEFTWIDTH = 25; PDFITEMFLYOUT_ONESLOT_RIGHTWIDTH = 24; PDFITEMFLYOUT_ONESLOT_WIDTH = 49; PDFITEMFLYOUT_ONESLOT_HEIGHT = 54; PDFITEMFLYOUT_ONEROW_LEFT_COORDS = { 0, 0.16796875, 0.5546875, 0.77734375 } PDFITEMFLYOUT_ONEROW_CENTER_COORDS = { 0.16796875, 0.328125, 0.5546875, 0.77734375 } PDFITEMFLYOUT_ONEROW_RIGHT_COORDS = { 0.328125, 0.51171875, 0.5546875, 0.77734375 } PDFITEMFLYOUT_MULTIROW_TOP_COORDS = { 0, 0.8359375, 0, 0.19140625 } PDFITEMFLYOUT_MULTIROW_MIDDLE_COORDS = { 0, 0.8359375, 0.19140625, 0.35546875 } PDFITEMFLYOUT_MULTIROW_BOTTOM_COORDS = { 0, 0.8359375, 0.35546875, 0.546875 } PDFITEMFLYOUT_ONEROW_HEIGHT = 54; PDFITEMFLYOUT_ONEROW_LEFT_WIDTH = 43; PDFITEMFLYOUT_ONEROW_CENTER_WIDTH = 41; PDFITEMFLYOUT_ONEROW_RIGHT_WIDTH = 47; PDFITEMFLYOUT_MULTIROW_WIDTH = 214; PDFITEMFLYOUT_MULTIROW_TOP_HEIGHT = 49; PDFITEMFLYOUT_MULTIROW_MIDDLE_HEIGHT = 42; PDFITEMFLYOUT_MULTIROW_BOTTOM_HEIGHT = 49; PDFITEMFLYOUT_PLACEINBAGS_LOCATION = 0xFFFFFFFF; PDFITEMFLYOUT_IGNORESLOT_LOCATION = 0xFFFFFFFE; PDFITEMFLYOUT_UNIGNORESLOT_LOCATION = 0xFFFFFFFD; PDFITEMFLYOUT_FIRST_SPECIAL_LOCATION = PDFITEMFLYOUT_UNIGNORESLOT_LOCATION PLAYER_DISPLAYED_TITLES = 6; PLAYER_TITLE_HEIGHT = 16; local VERTICAL_FLYOUTS = { [16] = true, [17] = true, [18] = true } local itemSlotButtons = {}; function PaperDollFrame_OnLoad (self) self:RegisterEvent("PLAYER_ENTERING_WORLD"); self:RegisterEvent("CHARACTER_POINTS_CHANGED"); self:RegisterEvent("UNIT_MODEL_CHANGED"); self:RegisterEvent("UNIT_LEVEL"); self:RegisterEvent("UNIT_RESISTANCES"); self:RegisterEvent("UNIT_STATS"); self:RegisterEvent("UNIT_DAMAGE"); self:RegisterEvent("UNIT_RANGEDDAMAGE"); self:RegisterEvent("PLAYER_DAMAGE_DONE_MODS"); self:RegisterEvent("UNIT_ATTACK_SPEED"); self:RegisterEvent("UNIT_ATTACK_POWER"); self:RegisterEvent("UNIT_RANGED_ATTACK_POWER"); self:RegisterEvent("UNIT_ATTACK"); self:RegisterEvent("PLAYER_GUILD_UPDATE"); self:RegisterEvent("SKILL_LINES_CHANGED"); self:RegisterEvent("VARIABLES_LOADED"); self:RegisterEvent("COMBAT_RATING_UPDATE"); self:RegisterEvent("KNOWN_TITLES_UPDATE"); self:RegisterEvent("UNIT_NAME_UPDATE"); end function PaperDoll_IsEquippedSlot (slot) if ( slot ) then slot = tonumber(slot); if ( slot ) then return slot >= EQUIPPED_FIRST and slot <= EQUIPPED_LAST; end end return false; end function CharacterModelFrame_OnMouseUp (self, button) if ( button == "LeftButton" ) then AutoEquipCursorItem(); end end function PaperDollFrame_OnEvent (self, event, ...) local unit = ...; if ( event == "PLAYER_ENTERING_WORLD" or event == "UNIT_MODEL_CHANGED" and unit == "player" ) then CharacterModelFrame:SetUnit("player"); return; elseif ( event == "VARIABLES_LOADED" ) then -- Set defaults if no settings for the dropdowns if ( GetCVar("playerStatLeftDropdown") == "" or GetCVar("playerStatRightDropdown") == "" ) then local temp, classFileName = UnitClass("player"); classFileName = strupper(classFileName); SetCVar("playerStatLeftDropdown", "PLAYERSTAT_BASE_STATS"); if ( classFileName == "MAGE" or classFileName == "PRIEST" or classFileName == "WARLOCK" or classFileName == "DRUID" ) then SetCVar("playerStatRightDropdown", "PLAYERSTAT_SPELL_COMBAT"); elseif ( classFileName == "HUNTER" ) then SetCVar("playerStatRightDropdown", "PLAYERSTAT_RANGED_COMBAT"); else SetCVar("playerStatRightDropdown", "PLAYERSTAT_MELEE_COMBAT"); end end PaperDollFrame_UpdateStats(self); elseif ( event == "KNOWN_TITLES_UPDATE" or (event == "UNIT_NAME_UPDATE" and unit == "player")) then PlayerTitleFrame_UpdateTitles(); end if ( not self:IsVisible() ) then return; end if ( unit == "player" ) then if ( event == "UNIT_LEVEL" ) then PaperDollFrame_SetLevel(); elseif ( event == "UNIT_DAMAGE" or event == "PLAYER_DAMAGE_DONE_MODS" or event == "UNIT_ATTACK_SPEED" or event == "UNIT_RANGEDDAMAGE" or event == "UNIT_ATTACK" or event == "UNIT_STATS" or event == "UNIT_RANGED_ATTACK_POWER" ) then PaperDollFrame_UpdateStats(); elseif ( event == "UNIT_RESISTANCES" ) then PaperDollFrame_SetResistances(); PaperDollFrame_UpdateStats(); elseif ( event == "UNIT_RANGED_ATTACK_POWER" ) then PaperDollFrame_SetRangedAttack(); end end if ( event == "COMBAT_RATING_UPDATE" ) then PaperDollFrame_UpdateStats(); end end function PaperDollFrame_SetLevel() CharacterLevelText:SetFormattedText(PLAYER_LEVEL, UnitLevel("player"), UnitRace("player"), UnitClass("player")); -- Set it for the honor frame while we at it HonorLevelText:SetFormattedText(PLAYER_LEVEL, UnitLevel("player"), UnitRace("player"), UnitClass("player")); end function PaperDollFrame_SetGuild() local guildName; local title; local rank; guildName, title, rank = GetGuildInfo("player"); if ( guildName ) then CharacterGuildText:Show(); CharacterGuildText:SetFormattedText(GUILD_TITLE_TEMPLATE, title, guildName); -- Set it for the honor frame while we're at it HonorGuildText:Show(); HonorGuildText:SetFormattedText(GUILD_TITLE_TEMPLATE, title, guildName); else CharacterGuildText:Hide(); HonorGuildText:Hide(); end end function PaperDollFrame_SetStat(statFrame, statIndex) local label = _G[statFrame:GetName().."Label"]; local text = _G[statFrame:GetName().."StatText"]; local stat; local effectiveStat; local posBuff; local negBuff; stat, effectiveStat, posBuff, negBuff = UnitStat("player", statIndex); local statName = _G["SPELL_STAT"..statIndex.."_NAME"]; label:SetText(format(STAT_FORMAT, statName)); -- Set the tooltip text local tooltipText = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, statName).." "; 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 statFrame.tooltip2 = _G["DEFAULT_STAT"..statIndex.."_TOOLTIP"]; local _, unitClass = UnitClass("player"); unitClass = strupper(unitClass); if ( statIndex == 1 ) then local attackPower = GetAttackPowerForStat(statIndex,effectiveStat); statFrame.tooltip2 = format(statFrame.tooltip2, attackPower); if ( unitClass == "WARRIOR" or unitClass == "SHAMAN" or unitClass == "PALADIN" ) then statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format( STAT_BLOCK_TOOLTIP, max(0, effectiveStat*BLOCK_PER_STRENGTH-10) ); end elseif ( statIndex == 3 ) then local baseStam = min(20, effectiveStat); local moreStam = effectiveStat - baseStam; statFrame.tooltip2 = format(statFrame.tooltip2, (baseStam + (moreStam*HEALTH_PER_STAMINA))*GetUnitMaxHealthModifier("player")); local petStam = ComputePetBonus("PET_BONUS_STAM", effectiveStat ); if( petStam > 0 ) then statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_STAMINA,petStam); end elseif ( statIndex == 2 ) then local attackPower = GetAttackPowerForStat(statIndex,effectiveStat); if ( attackPower > 0 ) then statFrame.tooltip2 = format(STAT_ATTACK_POWER, attackPower) .. format(statFrame.tooltip2, GetCritChanceFromAgility("player"), effectiveStat*ARMOR_PER_AGILITY); else statFrame.tooltip2 = format(statFrame.tooltip2, GetCritChanceFromAgility("player"), effectiveStat*ARMOR_PER_AGILITY); end elseif ( statIndex == 4 ) then local baseInt = min(20, effectiveStat); local moreInt = effectiveStat - baseInt if ( UnitHasMana("player") ) then statFrame.tooltip2 = format(statFrame.tooltip2, baseInt + moreInt*MANA_PER_INTELLECT, GetSpellCritChanceFromIntellect("player")); else statFrame.tooltip2 = nil; end local petInt = ComputePetBonus("PET_BONUS_INT", effectiveStat ); if( petInt > 0 ) then if ( not statFrame.tooltip2 ) then statFrame.tooltip2 = ""; end statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_INTELLECT,petInt); end elseif ( statIndex == 5 ) then -- All mana regen stats are displayed as mana/5 sec. statFrame.tooltip2 = format(statFrame.tooltip2, GetUnitHealthRegenRateFromSpirit("player")); if ( UnitHasMana("player") ) then local regen = GetUnitManaRegenRateFromSpirit("player"); regen = floor( regen * 5.0 ); statFrame.tooltip2 = statFrame.tooltip2.."\n"..format(MANA_REGEN_FROM_SPIRIT, regen); end end statFrame:Show(); end function PaperDollFrame_SetRating(statFrame, ratingIndex) local label = _G[statFrame:GetName().."Label"]; local text = _G[statFrame:GetName().."StatText"]; local statName = _G["COMBAT_RATING_NAME"..ratingIndex]; label:SetText(format(STAT_FORMAT, statName)); local rating = GetCombatRating(ratingIndex); local ratingBonus = GetCombatRatingBonus(ratingIndex); text:SetText(rating); -- Set the tooltip text statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, statName).." "..rating..FONT_COLOR_CODE_CLOSE; -- Can probably axe this if else tree if all rating tooltips follow the same format if ( ratingIndex == CR_HIT_MELEE ) then statFrame.tooltip2 = format(CR_HIT_MELEE_TOOLTIP, UnitLevel("player"), ratingBonus, GetCombatRating(CR_ARMOR_PENETRATION), GetArmorPenetration()); elseif ( ratingIndex == CR_HIT_RANGED ) then statFrame.tooltip2 = format(CR_HIT_RANGED_TOOLTIP, UnitLevel("player"), ratingBonus, GetCombatRating(CR_ARMOR_PENETRATION), GetArmorPenetration()); elseif ( ratingIndex == CR_DODGE ) then statFrame.tooltip2 = format(CR_DODGE_TOOLTIP, ratingBonus); elseif ( ratingIndex == CR_PARRY ) then statFrame.tooltip2 = format(CR_PARRY_TOOLTIP, ratingBonus); elseif ( ratingIndex == CR_BLOCK ) then statFrame.tooltip2 = format(CR_PARRY_TOOLTIP, ratingBonus); elseif ( ratingIndex == CR_HIT_SPELL ) then local spellPenetration = GetSpellPenetration(); statFrame.tooltip2 = format(CR_HIT_SPELL_TOOLTIP, UnitLevel("player"), ratingBonus, spellPenetration, spellPenetration); elseif ( ratingIndex == CR_CRIT_SPELL ) then local holySchool = 2; local minCrit = GetSpellCritChance(holySchool); statFrame.spellCrit = {}; statFrame.spellCrit[holySchool] = minCrit; local spellCrit; for i=(holySchool+1), MAX_SPELL_SCHOOLS do spellCrit = GetSpellCritChance(i); minCrit = min(minCrit, spellCrit); statFrame.spellCrit[i] = spellCrit; end minCrit = format("%.2f%%", minCrit); statFrame.minCrit = minCrit; elseif ( ratingIndex == CR_EXPERTISE ) then statFrame.tooltip2 = format(CR_EXPERTISE_TOOLTIP, ratingBonus); else statFrame.tooltip2 = HIGHLIGHT_FONT_COLOR_CODE.._G["COMBAT_RATING_NAME"..ratingIndex].." "..rating; end statFrame:Show(); end function PaperDollFrame_SetResistances() for i=1, NUM_RESISTANCE_TYPES, 1 do local resistance; local positive; local negative; local resistanceLevel local base; local text = _G["MagicResText"..i]; local frame = _G["MagicResFrame"..i]; base, resistance, positive, negative = UnitResistance("player", frame:GetID()); local petBonus = ComputePetBonus( "PET_BONUS_RES", resistance ); local resistanceName = _G["RESISTANCE"..(frame:GetID()).."_NAME"]; frame.tooltip = format(PAPERDOLLFRAME_TOOLTIP_FORMAT, resistanceName).." "..resistance; -- resistances can now be negative. Show Red if negative, Green if positive, white otherwise if( abs(negative) > positive ) then text:SetText(RED_FONT_COLOR_CODE..resistance..FONT_COLOR_CODE_CLOSE); elseif( abs(negative) == positive ) then text:SetText(resistance); else text:SetText(GREEN_FONT_COLOR_CODE..resistance..FONT_COLOR_CODE_CLOSE); end if ( positive ~= 0 or negative ~= 0 ) then -- Otherwise build up the formula frame.tooltip = frame.tooltip.. " ( "..HIGHLIGHT_FONT_COLOR_CODE..base; if( positive > 0 ) then frame.tooltip = frame.tooltip..GREEN_FONT_COLOR_CODE.." +"..positive; end if( negative < 0 ) then frame.tooltip = frame.tooltip.." "..RED_FONT_COLOR_CODE..negative; end frame.tooltip = frame.tooltip..FONT_COLOR_CODE_CLOSE.." )"; end local unitLevel = UnitLevel("player"); unitLevel = max(unitLevel, 20); local magicResistanceNumber = resistance/unitLevel; if ( magicResistanceNumber > 5 ) then resistanceLevel = RESISTANCE_EXCELLENT; elseif ( magicResistanceNumber > 3.75 ) then resistanceLevel = RESISTANCE_VERYGOOD; elseif ( magicResistanceNumber > 2.5 ) then resistanceLevel = RESISTANCE_GOOD; elseif ( magicResistanceNumber > 1.25 ) then resistanceLevel = RESISTANCE_FAIR; elseif ( magicResistanceNumber > 0 ) then resistanceLevel = RESISTANCE_POOR; else resistanceLevel = RESISTANCE_NONE; end frame.tooltipSubtext = format(RESISTANCE_TOOLTIP_SUBTEXT, _G["RESISTANCE_TYPE"..frame:GetID()], unitLevel, resistanceLevel); if( petBonus > 0 ) then frame.tooltipSubtext = frame.tooltipSubtext .. "\n" .. format(PET_BONUS_TOOLTIP_RESISTANCE, petBonus); end end end function PaperDollFrame_SetArmor(statFrame, unit) if ( not unit ) then unit = "player"; end local base, effectiveArmor, armor, posBuff, negBuff = UnitArmor(unit); _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, ARMOR)); local text = _G[statFrame:GetName().."StatText"]; PaperDollFormatStat(ARMOR, base, posBuff, negBuff, statFrame, text); local armorReduction = PaperDollFrame_GetArmorReduction(effectiveArmor, UnitLevel(unit)); statFrame.tooltip2 = format(DEFAULT_STATARMOR_TOOLTIP, armorReduction); if ( unit == "player" ) then local petBonus = ComputePetBonus("PET_BONUS_ARMOR", effectiveArmor ); if( petBonus > 0 ) then statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_ARMOR, petBonus); end end statFrame:Show(); end function PaperDollFrame_SetDefense(statFrame, unit) if ( not unit ) then unit = "player"; end local base, modifier = UnitDefense(unit); local posBuff = 0; local negBuff = 0; if ( modifier > 0 ) then posBuff = modifier; elseif ( modifier < 0 ) then negBuff = modifier; end _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, DEFENSE)); local text = _G[statFrame:GetName().."StatText"]; PaperDollFormatStat(DEFENSE, base, posBuff, negBuff, statFrame, text); local defensePercent = GetDodgeBlockParryChanceFromDefense(); statFrame.tooltip2 = format(DEFAULT_STATDEFENSE_TOOLTIP, GetCombatRating(CR_DEFENSE_SKILL), GetCombatRatingBonus(CR_DEFENSE_SKILL), defensePercent, defensePercent); statFrame:Show(); end function PaperDollFrame_SetDodge(statFrame) local chance = GetDodgeChance(); PaperDollFrame_SetLabelAndText(statFrame, STAT_DODGE, chance, 1); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, DODGE_CHANCE).." "..string.format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = format(CR_DODGE_TOOLTIP, GetCombatRating(CR_DODGE), GetCombatRatingBonus(CR_DODGE)); statFrame:Show(); end function PaperDollFrame_SetBlock(statFrame) local chance = GetBlockChance(); PaperDollFrame_SetLabelAndText(statFrame, STAT_BLOCK, chance, 1); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, BLOCK_CHANCE).." "..string.format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = format(CR_BLOCK_TOOLTIP, GetCombatRating(CR_BLOCK), GetCombatRatingBonus(CR_BLOCK), GetShieldBlock()); statFrame:Show(); end function PaperDollFrame_SetParry(statFrame) local chance = GetParryChance(); PaperDollFrame_SetLabelAndText(statFrame, STAT_PARRY, chance, 1); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, PARRY_CHANCE).." "..string.format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = format(CR_PARRY_TOOLTIP, GetCombatRating(CR_PARRY), GetCombatRatingBonus(CR_PARRY)); statFrame:Show(); end function GetDodgeBlockParryChanceFromDefense() local base, modifier = UnitDefense("player"); --local defensePercent = DODGE_PARRY_BLOCK_PERCENT_PER_DEFENSE * modifier; local defensePercent = DODGE_PARRY_BLOCK_PERCENT_PER_DEFENSE * ((base + modifier) - (UnitLevel("player")*5)); defensePercent = max(defensePercent, 0); return defensePercent; end function PaperDollFrame_SetResilience(statFrame) local melee = GetCombatRating(CR_CRIT_TAKEN_MELEE); local ranged = GetCombatRating(CR_CRIT_TAKEN_RANGED); local spell = GetCombatRating(CR_CRIT_TAKEN_SPELL); local minResilience = min(melee, ranged); minResilience = min(minResilience, spell); local lowestRating = CR_CRIT_TAKEN_MELEE; if ( melee == minResilience ) then lowestRating = CR_CRIT_TAKEN_MELEE; elseif ( ranged == minResilience ) then lowestRating = CR_CRIT_TAKEN_RANGED; else lowestRating = CR_CRIT_TAKEN_SPELL; end local maxRatingBonus = GetMaxCombatRatingBonus(lowestRating); local lowestRatingBonus = GetCombatRatingBonus(lowestRating); PaperDollFrame_SetLabelAndText(statFrame, STAT_RESILIENCE, minResilience); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_RESILIENCE).." "..minResilience..FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = format(RESILIENCE_TOOLTIP, lowestRatingBonus, min(lowestRatingBonus * RESILIENCE_CRIT_CHANCE_TO_DAMAGE_REDUCTION_MULTIPLIER, maxRatingBonus), lowestRatingBonus * RESILIENCE_CRIT_CHANCE_TO_CONSTANT_DAMAGE_REDUCTION_MULTIPLIER); statFrame:Show(); end function PaperDollFrame_SetDamage(statFrame, unit) if ( not unit ) then unit = "player"; end _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, DAMAGE)); local text = _G[statFrame:GetName().."StatText"]; local speed, offhandSpeed = UnitAttackSpeed(unit); local minDamage; local maxDamage; local minOffHandDamage; local maxOffHandDamage; local physicalBonusPos; local physicalBonusNeg; local percent; minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent = UnitDamage(unit); 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"; -- epsilon check if ( totalBonus < 0.1 and totalBonus > -0.1 ) then totalBonus = 0.0; end if ( totalBonus == 0 ) then if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then text:SetText(displayMin.." - "..displayMax); else text:SetText(displayMin.."-"..displayMax); end else local color; if ( totalBonus > 0 ) then color = colorPos; else color = colorNeg; end if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then text:SetText(color..displayMin.." - "..displayMax.."|r"); else text: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 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..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 statFrame.offhandDamage = offhandDamageTooltip; statFrame.offhandAttackSpeed = offhandSpeed; statFrame.offhandDps = offhandDamagePerSecond; else statFrame.offhandAttackSpeed = nil; end statFrame:Show(); end function PaperDollFrame_SetAttackSpeed(statFrame, unit) if ( not unit ) then unit = "player"; end local speed, offhandSpeed = UnitAttackSpeed(unit); speed = format("%.2f", speed); if ( offhandSpeed ) then offhandSpeed = format("%.2f", offhandSpeed); end local text; if ( offhandSpeed ) then text = speed.." / "..offhandSpeed; else text = speed; end PaperDollFrame_SetLabelAndText(statFrame, WEAPON_SPEED, 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 PaperDollFrame_SetAttackPower(statFrame, unit) if ( not unit ) then unit = "player"; end _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, ATTACK_POWER)); local text = _G[statFrame:GetName().."StatText"]; local base, posBuff, negBuff = UnitAttackPower(unit); PaperDollFormatStat(MELEE_ATTACK_POWER, base, posBuff, negBuff, statFrame, text); statFrame.tooltip2 = format(MELEE_ATTACK_POWER_TOOLTIP, max((base+posBuff+negBuff), 0)/ATTACK_POWER_MAGIC_NUMBER); statFrame:Show(); end function PaperDollFrame_SetAttackBothHands(statFrame, unit) if ( not unit ) then unit = "player"; end local mainHandAttackBase, mainHandAttackMod, offHandAttackBase, offHandAttackMod = UnitAttackBothHands(unit); _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, COMBAT_RATING_NAME1)); local text = _G[statFrame:GetName().."StatText"]; if( mainHandAttackMod == 0 ) then text:SetText(mainHandAttackBase); else local color = RED_FONT_COLOR_CODE; if( mainHandAttackMod > 0 ) then color = GREEN_FONT_COLOR_CODE; end text:SetText(color..(mainHandAttackBase + mainHandAttackMod)..FONT_COLOR_CODE_CLOSE); end if( mainHandAttackMod == 0 ) then statFrame.weaponSkill = COMBAT_RATING_NAME1.." "..mainHandAttackBase; else local color = RED_FONT_COLOR_CODE; statFrame.weaponSkill = COMBAT_RATING_NAME1.." "..(mainHandAttackBase + mainHandAttackMod).." ("..mainHandAttackBase..color.." "..mainHandAttackMod..")"; if( mainHandAttackMod > 0 ) then color = GREEN_FONT_COLOR_CODE; statFrame.weaponSkill = COMBAT_RATING_NAME1.." "..(mainHandAttackBase + mainHandAttackMod).." ("..mainHandAttackBase..color.." +"..mainHandAttackMod..FONT_COLOR_CODE_CLOSE..")"; end end local total = GetCombatRating(CR_WEAPON_SKILL) + GetCombatRating(CR_WEAPON_SKILL_MAINHAND); statFrame.weaponRating = format(WEAPON_SKILL_RATING, total); if ( total > 0 ) then statFrame.weaponRating = statFrame.weaponRating..format(WEAPON_SKILL_RATING_BONUS, GetCombatRatingBonus(CR_WEAPON_SKILL) + GetCombatRatingBonus(CR_WEAPON_SKILL_MAINHAND)); end local speed, offhandSpeed = UnitAttackSpeed(unit); if ( offhandSpeed ) then if( offHandAttackMod == 0 ) then statFrame.offhandSkill = COMBAT_RATING_NAME1.." "..offHandAttackBase; else local color = RED_FONT_COLOR_CODE; statFrame.offhandSkill = COMBAT_RATING_NAME1.." "..(offHandAttackBase + offHandAttackMod).." ("..offHandAttackBase..color.." "..offHandAttackMod..")"; if( offHandAttackMod > 0 ) then color = GREEN_FONT_COLOR_CODE; statFrame.offhandSkill = COMBAT_RATING_NAME1.." "..(offHandAttackBase + offHandAttackMod).." ("..offHandAttackBase..color.." +"..offHandAttackMod..FONT_COLOR_CODE_CLOSE..")"; end end total = GetCombatRating(CR_WEAPON_SKILL) + GetCombatRating(CR_WEAPON_SKILL_OFFHAND); statFrame.offhandRating = format(WEAPON_SKILL_RATING, total); if ( total > 0 ) then statFrame.offhandRating = statFrame.offhandRating..format(WEAPON_SKILL_RATING_BONUS, GetCombatRatingBonus(CR_WEAPON_SKILL) + GetCombatRatingBonus(CR_WEAPON_SKILL_OFFHAND)); end else statFrame.offhandSkill = nil; end statFrame:Show(); end function PaperDollFrame_SetRangedAttack(statFrame, unit) if ( not unit ) then unit = "player"; elseif ( unit == "pet" ) then return; end local hasRelic = UnitHasRelicSlot(unit); local rangedAttackBase, rangedAttackMod = UnitRangedAttack(unit); _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, COMBAT_RATING_NAME1)); local text = _G[statFrame:GetName().."StatText"]; -- If no ranged texture then set stats to n/a local rangedTexture = GetInventoryItemTexture("player", 18); if ( rangedTexture and not hasRelic ) then PaperDollFrame.noRanged = nil; else text:SetText(NOT_APPLICABLE); PaperDollFrame.noRanged = 1; statFrame.tooltip = nil; end if ( not rangedTexture or hasRelic ) then return; end if( rangedAttackMod == 0 ) then text:SetText(rangedAttackBase); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, COMBAT_RATING_NAME1).." "..rangedAttackBase..FONT_COLOR_CODE_CLOSE; else local color = RED_FONT_COLOR_CODE; if( rangedAttackMod > 0 ) then color = GREEN_FONT_COLOR_CODE; statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, COMBAT_RATING_NAME1).." "..(rangedAttackBase + rangedAttackMod).." ("..rangedAttackBase..color.." +"..rangedAttackMod..FONT_COLOR_CODE_CLOSE..HIGHLIGHT_FONT_COLOR_CODE..")"; else statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, COMBAT_RATING_NAME1).." "..(rangedAttackBase + rangedAttackMod).." ("..rangedAttackBase..color.." "..rangedAttackMod..FONT_COLOR_CODE_CLOSE..HIGHLIGHT_FONT_COLOR_CODE..")"; end text:SetText(color..(rangedAttackBase + rangedAttackMod)..FONT_COLOR_CODE_CLOSE); end local total = GetCombatRating(CR_WEAPON_SKILL) + GetCombatRating(CR_WEAPON_SKILL_RANGED); statFrame.tooltip2 = format(WEAPON_SKILL_RATING, total); if ( total > 0 ) then statFrame.tooltip2 = statFrame.tooltip2..format(WEAPON_SKILL_RATING_BONUS, GetCombatRatingBonus(CR_WEAPON_SKILL) + GetCombatRatingBonus(CR_WEAPON_SKILL_RANGED)); end statFrame:Show(); end function PaperDollFrame_SetRangedDamage(statFrame, unit) if ( not unit ) then unit = "player"; elseif ( unit == "pet" ) then return; end _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, DAMAGE)); local text = _G[statFrame:GetName().."StatText"]; -- If no ranged attack then set to n/a local hasRelic = UnitHasRelicSlot(unit); local rangedTexture = GetInventoryItemTexture("player", 18); if ( rangedTexture and not hasRelic ) then PaperDollFrame.noRanged = nil; else text:SetText(NOT_APPLICABLE); PaperDollFrame.noRanged = 1; statFrame.damage = nil; return; end local rangedAttackSpeed, minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent = UnitRangedDamage(unit); -- Round to the third decimal place (i.e. 99.9 percent) percent = math.floor(percent * 10^3 + 0.5) / 10^3 local displayMin = max(floor(minDamage),1); local displayMax = max(ceil(maxDamage),1); local baseDamage; local fullDamage; local totalBonus; local damagePerSecond; local tooltip; if ( HasWandEquipped() ) then baseDamage = (minDamage + maxDamage) * 0.5; fullDamage = baseDamage * percent; totalBonus = 0; if( rangedAttackSpeed == 0 ) then damagePerSecond = 0; else damagePerSecond = (max(fullDamage,1) / rangedAttackSpeed); end tooltip = max(floor(minDamage),1).." - "..max(ceil(maxDamage),1); else minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg; maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg; baseDamage = (minDamage + maxDamage) * 0.5; fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent; totalBonus = (fullDamage - baseDamage); if( rangedAttackSpeed == 0 ) then damagePerSecond = 0; else damagePerSecond = (max(fullDamage,1) / rangedAttackSpeed); end tooltip = max(floor(minDamage),1).." - "..max(ceil(maxDamage),1); end if ( totalBonus == 0 ) then if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then text:SetText(displayMin.." - "..displayMax); else text: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 text:SetText(color..displayMin.." - "..displayMax.."|r"); else text: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 statFrame.tooltip = tooltip.." "..format(DPS_TEMPLATE, damagePerSecond); end statFrame.attackSpeed = rangedAttackSpeed; statFrame.damage = tooltip; statFrame.dps = damagePerSecond; statFrame:Show(); end function PaperDollFrame_SetRangedAttackSpeed(statFrame, unit) if ( not unit ) then unit = "player"; elseif ( unit == "pet" ) then return; end local text; -- If no ranged attack then set to n/a if ( PaperDollFrame.noRanged ) then text = NOT_APPLICABLE; statFrame.tooltip = nil; else text = UnitRangedDamage(unit); text = format("%.2f", text); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ATTACK_SPEED).." "..text..FONT_COLOR_CODE_CLOSE; end PaperDollFrame_SetLabelAndText(statFrame, WEAPON_SPEED, text); statFrame.tooltip2 = format(CR_HASTE_RATING_TOOLTIP, GetCombatRating(CR_HASTE_RANGED), GetCombatRatingBonus(CR_HASTE_RANGED)); statFrame:Show(); end function PaperDollFrame_SetRangedAttackPower(statFrame, unit) if ( not unit ) then unit = "player"; end _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, ATTACK_POWER)); local text = _G[statFrame:GetName().."StatText"]; local base, posBuff, negBuff = UnitRangedAttackPower(unit); PaperDollFormatStat(RANGED_ATTACK_POWER, base, posBuff, negBuff, statFrame, text); local totalAP = base+posBuff+negBuff; statFrame.tooltip2 = format(RANGED_ATTACK_POWER_TOOLTIP, max((totalAP), 0)/ATTACK_POWER_MAGIC_NUMBER); local petAPBonus = ComputePetBonus( "PET_BONUS_RAP_TO_AP", totalAP ); if( petAPBonus > 0 ) then statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_RANGED_ATTACK_POWER, petAPBonus); end local petSpellDmgBonus = ComputePetBonus( "PET_BONUS_RAP_TO_SPELLDMG", totalAP ); if( petSpellDmgBonus > 0 ) then statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_SPELLDAMAGE, petSpellDmgBonus); end statFrame:Show(); end function PaperDollFrame_SetSpellBonusDamage(statFrame) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, BONUS_DAMAGE)); local text = _G[statFrame:GetName().."StatText"]; local holySchool = 2; -- Start at 2 to skip physical damage local minModifier = GetSpellBonusDamage(holySchool); statFrame.bonusDamage = {}; statFrame.bonusDamage[holySchool] = minModifier; local bonusDamage; for i=(holySchool+1), MAX_SPELL_SCHOOLS do bonusDamage = GetSpellBonusDamage(i); minModifier = min(minModifier, bonusDamage); statFrame.bonusDamage[i] = bonusDamage; end text:SetText(minModifier); statFrame.minModifier = minModifier; statFrame:Show(); end function PaperDollFrame_SetSpellCritChance(statFrame) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, SPELL_CRIT_CHANCE)); local text = _G[statFrame:GetName().."StatText"]; local holySchool = 2; -- Start at 2 to skip physical damage local minCrit = GetSpellCritChance(holySchool); statFrame.spellCrit = {}; statFrame.spellCrit[holySchool] = minCrit; local spellCrit; for i=(holySchool+1), MAX_SPELL_SCHOOLS do spellCrit = GetSpellCritChance(i); minCrit = min(minCrit, spellCrit); statFrame.spellCrit[i] = spellCrit; end -- Add agility contribution --minCrit = minCrit + GetSpellCritChanceFromIntellect(); minCrit = format("%.2f%%", minCrit); text:SetText(minCrit); statFrame.minCrit = minCrit; statFrame:Show(); end function PaperDollFrame_SetMeleeCritChance(statFrame) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, MELEE_CRIT_CHANCE)); local text = _G[statFrame:GetName().."StatText"]; local critChance = GetCritChance();-- + GetCritChanceFromAgility(); critChance = format("%.2f%%", critChance); text:SetText(critChance); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, MELEE_CRIT_CHANCE).." "..critChance..FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = format(CR_CRIT_MELEE_TOOLTIP, GetCombatRating(CR_CRIT_MELEE), GetCombatRatingBonus(CR_CRIT_MELEE)); end function PaperDollFrame_SetRangedCritChance(statFrame) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, RANGED_CRIT_CHANCE)); local text = _G[statFrame:GetName().."StatText"]; local critChance = GetRangedCritChance();-- + GetCritChanceFromAgility(); critChance = format("%.2f%%", critChance); text:SetText(critChance); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, RANGED_CRIT_CHANCE).." "..critChance..FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = format(CR_CRIT_RANGED_TOOLTIP, GetCombatRating(CR_CRIT_RANGED), GetCombatRatingBonus(CR_CRIT_RANGED)); end function PaperDollFrame_SetSpellBonusHealing(statFrame) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, BONUS_HEALING)); local text = _G[statFrame:GetName().."StatText"]; local bonusHealing = GetSpellBonusHealing(); text:SetText(bonusHealing); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. BONUS_HEALING .. FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 =format(BONUS_HEALING_TOOLTIP, bonusHealing); statFrame:Show(); end function PaperDollFrame_SetSpellPenetration(statFrame) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, SPELL_PENETRATION)); local text = _G[statFrame:GetName().."StatText"]; text:SetText(GetSpellPenetration()); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE ..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, SPELL_PENETRATION).. FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = SPELL_PENETRATION_TOOLTIP; statFrame:Show(); end function PaperDollFrame_SetSpellHaste(statFrame) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, SPELL_HASTE)); local text = _G[statFrame:GetName().."StatText"]; text:SetText(GetCombatRating(CR_HASTE_SPELL)); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. SPELL_HASTE .. FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = format(SPELL_HASTE_TOOLTIP, GetCombatRatingBonus(CR_HASTE_SPELL)); statFrame:Show(); end function PaperDollFrame_SetManaRegen(statFrame) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, MANA_REGEN)); local text = _G[statFrame:GetName().."StatText"]; if ( not UnitHasMana("player") ) then text:SetText(NOT_APPLICABLE); statFrame.tooltip = nil; return; end local base, casting = GetManaRegen(); -- All mana regen stats are displayed as mana/5 sec. base = floor( base * 5.0 ); casting = floor( casting * 5.0 ); text:SetText(base); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. MANA_REGEN .. FONT_COLOR_CODE_CLOSE; statFrame.tooltip2 = format(MANA_REGEN_TOOLTIP, base, casting); statFrame:Show(); end function PaperDollFrame_SetExpertise(statFrame, unit) if ( not unit ) then unit = "player"; end local expertise, offhandExpertise = GetExpertise(); local speed, offhandSpeed = UnitAttackSpeed(unit); local text; if( offhandSpeed ) then text = expertise.." / "..offhandExpertise; else text = expertise; end PaperDollFrame_SetLabelAndText(statFrame, STAT_EXPERTISE, text); statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, _G["COMBAT_RATING_NAME"..CR_EXPERTISE]).." "..text..FONT_COLOR_CODE_CLOSE; local expertisePercent, offhandExpertisePercent = GetExpertisePercent(); expertisePercent = format("%.2f", expertisePercent); if( offhandSpeed ) then offhandExpertisePercent = format("%.2f", offhandExpertisePercent); text = expertisePercent.."% / "..offhandExpertisePercent.."%"; else text = expertisePercent.."%"; end statFrame.tooltip2 = format(CR_EXPERTISE_TOOLTIP, text, GetCombatRating(CR_EXPERTISE), GetCombatRatingBonus(CR_EXPERTISE)); statFrame:Show(); end function CharacterSpellBonusDamage_OnEnter (self) GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, BONUS_DAMAGE).." "..self.minModifier..FONT_COLOR_CODE_CLOSE); for i=2, MAX_SPELL_SCHOOLS do GameTooltip:AddDoubleLine(_G["DAMAGE_SCHOOL"..i], self.bonusDamage[i], NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:AddTexture("Interface\\PaperDollInfoFrame\\SpellSchoolIcon"..i); end local petStr, damage; if( self.bonusDamage[6] > self.bonusDamage[3] ) then petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_SHADOW; damage = self.bonusDamage[6]; else petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_FIRE; damage = self.bonusDamage[3]; end local petBonusAP = ComputePetBonus("PET_BONUS_SPELLDMG_TO_AP", damage ); local petBonusDmg = ComputePetBonus("PET_BONUS_SPELLDMG_TO_SPELLDMG", damage ); if( petBonusAP > 0 or petBonusDmg > 0 ) then GameTooltip:AddLine("\n" .. format(petStr, petBonusAP, petBonusDmg), nil, nil, nil, 1 ); end GameTooltip:Show(); end function CharacterSpellCritChance_OnEnter (self) GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, COMBAT_RATING_NAME11).." "..GetCombatRating(11)..FONT_COLOR_CODE_CLOSE); local spellCrit; for i=2, MAX_SPELL_SCHOOLS do spellCrit = format("%.2f", self.spellCrit[i]); spellCrit = spellCrit.."%"; GameTooltip:AddDoubleLine(_G["DAMAGE_SCHOOL"..i], spellCrit, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:AddTexture("Interface\\PaperDollInfoFrame\\SpellSchoolIcon"..i); end GameTooltip:Show(); end function PaperDollFrame_OnShow (self) --PaperDollFrame_SetGuild(); PaperDollFrame_SetLevel(); PaperDollFrame_SetResistances(); PaperDollFrame_UpdateStats(); if ( UnitHasRelicSlot("player") ) then CharacterAmmoSlot:Hide(); else CharacterAmmoSlot:Show(); end if ( not PlayerTitlePickerScrollFrame.titles ) then PlayerTitleFrame_UpdateTitles(); end end function PaperDollFrame_OnHide (self) PlayerTitlePickerFrame:Hide(); GearManagerDialog:Hide(); end function PaperDollFrame_ClearIgnoredSlots () EquipmentManagerClearIgnoredSlotsForSave(); for k, button in next, itemSlotButtons do if ( button.ignored ) then button.ignored = nil; PaperDollItemSlotButton_Update(button); end end end function PaperDollFrame_IgnoreSlotsForSet (setName) local set = GetEquipmentSetItemIDs(setName); for slot, item in ipairs(set) do if ( item == EQUIPMENT_SET_IGNORED_SLOT ) then EquipmentManagerIgnoreSlotForSave(slot); itemSlotButtons[slot].ignored = true; PaperDollItemSlotButton_Update(itemSlotButtons[slot]); end end end function PaperDollItemSlotButton_OnLoad (self) self:RegisterForDrag("LeftButton"); self:RegisterForClicks("LeftButtonUp", "RightButtonUp"); local slotName = self:GetName(); local id, textureName, checkRelic = GetInventorySlotInfo(strsub(slotName,10)); self:SetID(id); local texture = _G[slotName.."IconTexture"]; texture:SetTexture(textureName); self.backgroundTextureName = textureName; self.checkRelic = checkRelic; self.UpdateTooltip = PaperDollItemSlotButton_OnEnter; itemSlotButtons[id] = self; self.verticalFlyout = VERTICAL_FLYOUTS[id]; local popoutButton = self.popoutButton; if ( popoutButton ) then if ( self.verticalFlyout ) then popoutButton:SetHeight(16); popoutButton:SetWidth(38); popoutButton:GetNormalTexture():SetTexCoord(0.15625, 0.84375, 0.5, 0); popoutButton:GetHighlightTexture():SetTexCoord(0.15625, 0.84375, 1, 0.5); popoutButton:ClearAllPoints(); popoutButton:SetPoint("TOP", self, "BOTTOM", 0, 4); else popoutButton:SetHeight(38); popoutButton:SetWidth(16); popoutButton:GetNormalTexture():SetTexCoord(0.15625, 0.5, 0.84375, 0.5, 0.15625, 0, 0.84375, 0); popoutButton:GetHighlightTexture():SetTexCoord(0.15625, 1, 0.84375, 1, 0.15625, 0.5, 0.84375, 0.5); popoutButton:ClearAllPoints(); popoutButton:SetPoint("LEFT", self, "RIGHT", -8, 0); end end end function PaperDollItemSlotButton_OnShow (self) self:RegisterEvent("UNIT_INVENTORY_CHANGED"); self:RegisterEvent("MERCHANT_UPDATE"); self:RegisterEvent("PLAYERBANKSLOTS_CHANGED"); self:RegisterEvent("ITEM_LOCK_CHANGED"); self:RegisterEvent("CURSOR_UPDATE"); self:RegisterEvent("BAG_UPDATE_COOLDOWN"); self:RegisterEvent("SHOW_COMPARE_TOOLTIP"); self:RegisterEvent("UPDATE_INVENTORY_ALERTS"); PaperDollItemSlotButton_Update(self); end function PaperDollItemSlotButton_OnHide (self) self:UnregisterEvent("UNIT_INVENTORY_CHANGED"); self:UnregisterEvent("MERCHANT_UPDATE"); self:UnregisterEvent("PLAYERBANKSLOTS_CHANGED"); self:UnregisterEvent("ITEM_LOCK_CHANGED"); self:UnregisterEvent("CURSOR_UPDATE"); self:UnregisterEvent("BAG_UPDATE_COOLDOWN"); self:UnregisterEvent("SHOW_COMPARE_TOOLTIP"); self:UnregisterEvent("UPDATE_INVENTORY_ALERTS"); end function PaperDollItemSlotButton_OnEvent (self, event, ...) local arg1, arg2 = ...; if ( event == "UNIT_INVENTORY_CHANGED" ) then if ( arg1 == "player" ) then PaperDollItemSlotButton_Update(self); end elseif ( event == "ITEM_LOCK_CHANGED" ) then if ( not arg2 and arg1 == self:GetID() ) then PaperDollItemSlotButton_UpdateLock(self); end elseif ( event == "BAG_UPDATE_COOLDOWN" ) then PaperDollItemSlotButton_Update(self); elseif ( event == "CURSOR_UPDATE" ) then if ( CursorCanGoInSlot(self:GetID()) ) then self:LockHighlight(); else self:UnlockHighlight(); end elseif ( event == "SHOW_COMPARE_TOOLTIP" ) then if ( (arg1 ~= self:GetID()) or (arg2 > NUM_SHOPPING_TOOLTIPS) ) then return; end local tooltip = _G["ShoppingTooltip"..arg2]; local anchor = "ANCHOR_RIGHT"; if ( arg2 > 1 ) then anchor = "ANCHOR_BOTTOMRIGHT"; end tooltip:SetOwner(self, anchor); local hasItem, hasCooldown = tooltip:SetInventoryItem("player", self:GetID()); if ( not hasItem ) then tooltip:Hide(); end elseif ( event == "UPDATE_INVENTORY_ALERTS" ) then PaperDollItemSlotButton_Update(self); elseif ( event == "MODIFIER_STATE_CHANGED" ) then if ( IsModifiedClick("SHOWITEMFLYOUT") and self:IsMouseOver() ) then PaperDollItemSlotButton_OnEnter(self); end end end function PaperDollItemSlotButton_OnClick (self, button) MerchantFrame_ResetRefundItem(); if ( button == "LeftButton" ) then local type = GetCursorInfo(); if ( type == "merchant" and MerchantFrame.extendedCost ) then MerchantFrame_ConfirmExtendedItemCost(MerchantFrame.extendedCost); else PickupInventoryItem(self:GetID()); if ( CursorHasItem() ) then MerchantFrame_SetRefundItem(self, 1); end end else UseInventoryItem(self:GetID()); end end function PaperDollItemSlotButton_OnModifiedClick (self, button) if ( HandleModifiedItemClick(GetInventoryItemLink("player", self:GetID())) ) then return; end if ( IsModifiedClick("SOCKETITEM") ) then SocketInventoryItem(self:GetID()); end end function PaperDollItemSlotButton_Update (self) local textureName = GetInventoryItemTexture("player", self:GetID()); local cooldown = _G[self:GetName().."Cooldown"]; if ( textureName ) then SetItemButtonTexture(self, textureName); SetItemButtonCount(self, GetInventoryItemCount("player", self:GetID())); if ( GetInventoryItemBroken("player", self:GetID()) ) then SetItemButtonTextureVertexColor(self, 0.9, 0, 0); SetItemButtonNormalTextureVertexColor(self, 0.9, 0, 0); else SetItemButtonTextureVertexColor(self, 1.0, 1.0, 1.0); SetItemButtonNormalTextureVertexColor(self, 1.0, 1.0, 1.0); end if ( cooldown ) then local start, duration, enable = GetInventoryItemCooldown("player", self:GetID()); CooldownFrame_SetTimer(cooldown, start, duration, enable); end self.hasItem = 1; else local textureName = self.backgroundTextureName; if ( self.checkRelic and UnitHasRelicSlot("player") ) then textureName = "Interface\\Paperdoll\\UI-PaperDoll-Slot-Relic.blp"; end SetItemButtonTexture(self, textureName); SetItemButtonCount(self, 0); SetItemButtonTextureVertexColor(self, 1.0, 1.0, 1.0); SetItemButtonNormalTextureVertexColor(self, 1.0, 1.0, 1.0); if ( cooldown ) then cooldown:Hide(); end self.hasItem = nil; end if ( not GearManagerDialog:IsShown() ) then self.ignored = nil; end if ( self.ignored and self.ignoreTexture ) then self.ignoreTexture:Show(); elseif ( self.ignoreTexture ) then self.ignoreTexture:Hide(); end PaperDollItemSlotButton_UpdateLock(self); -- Update repair all button status MerchantFrame_UpdateGuildBankRepair(); MerchantFrame_UpdateCanRepairAll(); end function PaperDollItemSlotButton_UpdateLock (self) if ( IsInventoryItemLocked(self:GetID()) ) then --this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot"); SetItemButtonDesaturated(self, 1, 0.5, 0.5, 0.5); else --this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2"); SetItemButtonDesaturated(self, nil); end end function PaperDollItemSlotButton_UpdateFlyout (self) if ( self:GetID() ~= INVSLOT_AMMO ) then if ( (IsModifiedClick("SHOWITEMFLYOUT") and not (PaperDollFrameItemFlyout:IsVisible() and PaperDollFrameItemFlyout.button == self)) or self.popoutButton.flyoutLocked) then PaperDollFrameItemFlyout_Show(self); elseif ( (PaperDollFrameItemFlyout:IsVisible() and PaperDollFrameItemFlyout.button == self) and not self.popoutButton.flyoutLocked and not IsModifiedClick("SHOWITEMFLYOUT") ) then PaperDollFrameItemFlyout_Hide(); end end end function PaperDollItemSlotButton_OnEnter (self) self:RegisterEvent("MODIFIER_STATE_CHANGED"); PaperDollItemSlotButton_UpdateFlyout(self); if ( PaperDollFrameItemFlyout:IsShown() ) then GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6); else GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); end local hasItem, hasCooldown, repairCost = GameTooltip:SetInventoryItem("player", self:GetID()); if ( not hasItem ) then local text = _G[strupper(strsub(self:GetName(), 10))]; if ( self.checkRelic and UnitHasRelicSlot("player") ) then text = RELICSLOT; end GameTooltip:SetText(text); end if ( InRepairMode() and repairCost and (repairCost > 0) ) then GameTooltip:AddLine(REPAIR_COST, "", 1, 1, 1); SetTooltipMoney(GameTooltip, repairCost); GameTooltip:Show(); else CursorUpdate(self); end end function PaperDollItemSlotButton_OnLeave (self) self:UnregisterEvent("MODIFIER_STATE_CHANGED"); GameTooltip:Hide(); ResetCursor(); end function PaperDollStatTooltip (self, unit) if ( not self.tooltip ) then return; end if ( not unit ) then unit = "player"; end GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); GameTooltip:SetText(self.tooltip); if ( self.tooltip2 ) then GameTooltip:AddLine(self.tooltip2, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1); end GameTooltip:Show(); end function FormatPaperDollTooltipStat(name, base, posBuff, negBuff) local effective = max(0,base + posBuff + negBuff); local text = HIGHLIGHT_FONT_COLOR_CODE..name.." "..effective; if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then text = text..FONT_COLOR_CODE_CLOSE; else if ( posBuff > 0 or negBuff < 0 ) then text = text.." ("..base..FONT_COLOR_CODE_CLOSE; end if ( posBuff > 0 ) then text = text..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE; end if ( negBuff < 0 ) then text = text..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE; end if ( posBuff > 0 or negBuff < 0 ) then text = text..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE; end end return text; end function ColorPaperDollStat(base, posBuff, negBuff) local stat; local effective = max(0,base + posBuff + negBuff); if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then stat = effective; else -- if there is a negative buff then show the main number in red, even if there are -- positive buffs. Otherwise show the number in green if ( negBuff < 0 ) then stat = RED_FONT_COLOR_CODE..effective..FONT_COLOR_CODE_CLOSE; else stat = GREEN_FONT_COLOR_CODE..effective..FONT_COLOR_CODE_CLOSE; end end return stat; end function PaperDollFormatStat(name, base, posBuff, negBuff, frame, textString) local effective = max(0,base + posBuff + negBuff); local text = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT,name).." "..effective; if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then text = text..FONT_COLOR_CODE_CLOSE; textString:SetText(effective); else if ( posBuff > 0 or negBuff < 0 ) then text = text.." ("..base..FONT_COLOR_CODE_CLOSE; end if ( posBuff > 0 ) then text = text..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE; end if ( negBuff < 0 ) then text = text..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE; end if ( posBuff > 0 or negBuff < 0 ) then text = text..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE; end -- if there is a negative buff then show the main number in red, even if there are -- positive buffs. Otherwise show the number in green if ( negBuff < 0 ) then textString:SetText(RED_FONT_COLOR_CODE..effective..FONT_COLOR_CODE_CLOSE); else textString:SetText(GREEN_FONT_COLOR_CODE..effective..FONT_COLOR_CODE_CLOSE); end end frame.tooltip = text; end function CharacterAttackFrame_OnEnter (self) -- Main hand weapon GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); GameTooltip:AddLine(self.weaponSkill); GameTooltip:AddLine(self.weaponRating); -- Check for offhand weapon if ( self.offhandSkill ) then GameTooltip:AddLine("\n"); GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); GameTooltip:AddLine(self.offhandSkill); GameTooltip:AddLine(self.offhandRating); end GameTooltip:Show(); end function CharacterDamageFrame_OnEnter (self) -- Main hand weapon GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); if ( self == PetDamageFrame ) then GameTooltip:SetText(INVTYPE_WEAPONMAINHAND_PET, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); else GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); end GameTooltip:AddDoubleLine(format(STAT_FORMAT, ATTACK_SPEED_SECONDS), format("%.2f", self.attackSpeed), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE), self.damage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE_PER_SECOND), format("%.1f", self.dps), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); -- Check for offhand weapon if ( self.offhandAttackSpeed ) then GameTooltip:AddLine("\n"); GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); GameTooltip:AddDoubleLine(format(STAT_FORMAT, ATTACK_SPEED_SECONDS), format("%.2f", self.offhandAttackSpeed), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE), self.offhandDamage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE_PER_SECOND), format("%.1f", self.offhandDps), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); end GameTooltip:Show(); end function CharacterRangedDamageFrame_OnEnter (self) if ( not self.damage ) then return; end GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); GameTooltip:SetText(INVTYPE_RANGED, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); GameTooltip:AddDoubleLine(format(STAT_FORMAT, ATTACK_SPEED_SECONDS), format("%.2f", self.attackSpeed), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE), self.damage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE_PER_SECOND), format("%.1f", self.dps), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); GameTooltip:Show(); end function PaperDollFrame_GetArmorReduction(armor, attackerLevel) local levelModifier = attackerLevel; if ( levelModifier > 59 ) then levelModifier = levelModifier + (4.5 * (levelModifier-59)); end local temp = 0.1*armor/(8.5*levelModifier + 40); temp = temp/(1+temp); if ( temp > 0.75 ) then return 75; end if ( temp < 0 ) then return 0; end return temp*100; end -- Paperdoll stat selection functions function PlayerStatFrameLeftDropDown_OnLoad (self) RaiseFrameLevel(self); UIDropDownMenu_Initialize(self, PlayerStatFrameLeftDropDown_Initialize); UIDropDownMenu_SetSelectedValue(self, GetCVar("playerStatLeftDropdown")); UIDropDownMenu_SetWidth(self, 99); UIDropDownMenu_JustifyText(self, "LEFT"); end function PlayerStatFrameLeftDropDown_OnShow (self) UIDropDownMenu_Initialize(self, PlayerStatFrameLeftDropDown_Initialize); UIDropDownMenu_SetSelectedValue(self, GetCVar("playerStatLeftDropdown")); end function PlayerStatFrameLeftDropDown_Initialize (self) -- Setup buttons local info = UIDropDownMenu_CreateInfo(); local checked; for i=1, getn(PLAYERSTAT_DROPDOWN_OPTIONS) do if ( PLAYERSTAT_DROPDOWN_OPTIONS[i] == GetCVar("playerStatLeftDropdown") ) then checked = 1; else checked = nil; end info.text = _G[PLAYERSTAT_DROPDOWN_OPTIONS[i]]; info.func = PlayerStatFrameLeftDropDown_OnClick; info.value = PLAYERSTAT_DROPDOWN_OPTIONS[i]; info.checked = checked; info.owner = UIDROPDOWNMENU_OPEN_MENU; UIDropDownMenu_AddButton(info); end end function PlayerStatFrameLeftDropDown_OnClick (self) UIDropDownMenu_SetSelectedValue(self.owner, self.value); SetCVar("playerStatLeftDropdown", self.value); UpdatePaperdollStats("PlayerStatFrameLeft", self.value); end function PlayerStatFrameRightDropDown_OnLoad (self) UIDropDownMenu_Initialize(self, PlayerStatFrameRightDropDown_Initialize); UIDropDownMenu_SetSelectedValue(self, GetCVar("playerStatRightDropdown")); UIDropDownMenu_SetWidth(self, 99); UIDropDownMenu_JustifyText(self, "LEFT"); end function PlayerStatFrameRightDropDown_OnShow (self) UIDropDownMenu_Initialize(self, PlayerStatFrameRightDropDown_Initialize); UIDropDownMenu_SetSelectedValue(self, GetCVar("playerStatRightDropdown")); end function PlayerStatFrameRightDropDown_Initialize (self) -- Setup buttons local info = UIDropDownMenu_CreateInfo(); local checked; for i=1, getn(PLAYERSTAT_DROPDOWN_OPTIONS) do if ( PLAYERSTAT_DROPDOWN_OPTIONS[i] == GetCVar("playerStatRightDropdown") ) then checked = 1; else checked = nil; end info.text = _G[PLAYERSTAT_DROPDOWN_OPTIONS[i]]; info.func = PlayerStatFrameRightDropDown_OnClick; info.value = PLAYERSTAT_DROPDOWN_OPTIONS[i]; info.checked = checked; info.owner = UIDROPDOWNMENU_OPEN_MENU; UIDropDownMenu_AddButton(info); end end function PlayerStatFrameRightDropDown_OnClick (self) UIDropDownMenu_SetSelectedValue(self.owner, self.value); SetCVar("playerStatRightDropdown", self.value); UpdatePaperdollStats("PlayerStatFrameRight", self.value); end function PaperDollFrame_UpdateStats() UpdatePaperdollStats("PlayerStatFrameLeft", GetCVar("playerStatLeftDropdown")); UpdatePaperdollStats("PlayerStatFrameRight", GetCVar("playerStatRightDropdown")); end function PaperDollFrame_SetLabelAndText(statFrame, label, text, isPercentage) _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, label)); if ( isPercentage ) then text = format("%.2f%%", text); end _G[statFrame:GetName().."StatText"]:SetText(text); end function UpdatePaperdollStats(prefix, index) local stat1 = _G[prefix..1]; local stat2 = _G[prefix..2]; local stat3 = _G[prefix..3]; local stat4 = _G[prefix..4]; local stat5 = _G[prefix..5]; local stat6 = _G[prefix..6]; -- reset any OnEnter scripts that may have been changed stat1:SetScript("OnEnter", PaperDollStatTooltip); stat2:SetScript("OnEnter", PaperDollStatTooltip); stat4:SetScript("OnEnter", PaperDollStatTooltip); stat6:Show(); if ( index == "PLAYERSTAT_BASE_STATS" ) then PaperDollFrame_SetStat(stat1, 1); PaperDollFrame_SetStat(stat2, 2); PaperDollFrame_SetStat(stat3, 3); PaperDollFrame_SetStat(stat4, 4); PaperDollFrame_SetStat(stat5, 5); PaperDollFrame_SetArmor(stat6); elseif ( index == "PLAYERSTAT_MELEE_COMBAT" ) then PaperDollFrame_SetDamage(stat1); stat1:SetScript("OnEnter", CharacterDamageFrame_OnEnter); PaperDollFrame_SetAttackSpeed(stat2); PaperDollFrame_SetAttackPower(stat3); PaperDollFrame_SetRating(stat4, CR_HIT_MELEE); PaperDollFrame_SetMeleeCritChance(stat5); PaperDollFrame_SetExpertise(stat6); elseif ( index == "PLAYERSTAT_RANGED_COMBAT" ) then PaperDollFrame_SetRangedDamage(stat1); stat1:SetScript("OnEnter", CharacterRangedDamageFrame_OnEnter); PaperDollFrame_SetRangedAttackSpeed(stat2); PaperDollFrame_SetRangedAttackPower(stat3); PaperDollFrame_SetRating(stat4, CR_HIT_RANGED); PaperDollFrame_SetRangedCritChance(stat5); stat6:Hide(); elseif ( index == "PLAYERSTAT_SPELL_COMBAT" ) then PaperDollFrame_SetSpellBonusDamage(stat1); stat1:SetScript("OnEnter", CharacterSpellBonusDamage_OnEnter); PaperDollFrame_SetSpellBonusHealing(stat2); PaperDollFrame_SetRating(stat3, CR_HIT_SPELL); PaperDollFrame_SetSpellCritChance(stat4); stat4:SetScript("OnEnter", CharacterSpellCritChance_OnEnter); PaperDollFrame_SetSpellHaste(stat5); PaperDollFrame_SetManaRegen(stat6); elseif ( index == "PLAYERSTAT_DEFENSES" ) then PaperDollFrame_SetArmor(stat1); PaperDollFrame_SetDefense(stat2); PaperDollFrame_SetDodge(stat3); PaperDollFrame_SetParry(stat4); PaperDollFrame_SetBlock(stat5); PaperDollFrame_SetResilience(stat6); end end function ComputePetBonus(stat, value) local temp, unitClass = UnitClass("player"); unitClass = strupper(unitClass); if( unitClass == "WARLOCK" ) then if( WARLOCK_PET_BONUS[stat] ) then return value * WARLOCK_PET_BONUS[stat]; else return 0; end elseif( unitClass == "HUNTER" ) then if( HUNTER_PET_BONUS[stat] ) then return value * HUNTER_PET_BONUS[stat]; else return 0; end end return 0; end PDFITEMFLYOUT_ITEMS_PER_ROW = 5; PDFITEMFLYOUT_BORDERWIDTH = 3; PDFITEMFLYOUT_WIDTH = 43; PDFITEMFLYOUT_HEIGHT = 43; PDFITEM_WIDTH = 37; PDFITEM_HEIGHT = 37; PDFITEM_XOFFSET = 4; PDFITEM_YOFFSET = -5; local itemTable = {}; -- Used for items and locations local itemDisplayTable = {} -- Used for ordering items by location function PaperDollFrameItemFlyout_CreateButton () local buttons = PaperDollFrameItemFlyout.buttons; local buttonAnchor = PaperDollFrameItemFlyoutButtons; local numButtons = #buttons; local button = CreateFrame("BUTTON", "PaperDollFrameItemFlyoutButtons" .. numButtons + 1, buttonAnchor, "PaperDollFrameItemFlyoutButtonTemplate"); local pos = numButtons/PDFITEMFLYOUT_ITEMS_PER_ROW; if ( math.floor(pos) == pos ) then -- This is the first button in a row. button:SetPoint("TOPLEFT", buttonAnchor, "TOPLEFT", PDFITEMFLYOUT_BORDERWIDTH, -PDFITEMFLYOUT_BORDERWIDTH - (PDFITEM_HEIGHT - PDFITEM_YOFFSET)* pos); else button:SetPoint("TOPLEFT", buttons[numButtons], "TOPRIGHT", PDFITEM_XOFFSET, 0); end tinsert(buttons, button); return button end function PaperDollFrameItemFlyout_Hide () PaperDollFrameItemFlyout:Hide(); end function PaperDollFrameItemFlyout_OnUpdate (self, elapsed) if ( not IsModifiedClick("SHOWITEMFLYOUT") ) then local button = self.button; if ( button and button.popoutButton.flyoutLocked ) then PaperDollItemSlotButton_UpdateFlyout(button); elseif ( button and button:IsMouseOver() ) then PaperDollItemSlotButton_OnEnter(button); else PaperDollFrameItemFlyout_Hide(); end end end function PaperDollFrameItemFlyout_OnShow (self) self:RegisterEvent("BAG_UPDATE"); self:RegisterEvent("UNIT_INVENTORY_CHANGED"); end function PaperDollFrameItemFlyout_OnHide (self) if ( self.button ) then local popoutButton = self.button.popoutButton; popoutButton.flyoutLocked = false; PaperDollFrameItemPopoutButton_SetReversed(popoutButton, false); end self.button = nil; self:UnregisterEvent("BAG_UPDATE"); self:UnregisterEvent("UNIT_INVENTORY_CHANGED"); end function PaperDollFrameItemFlyout_OnEvent (self, event, ...) if ( event == "BAG_UPDATE" ) then -- This spams a lot, four times when we equip an item, but we need to use it. PaperDollFrameItemFlyout_Show needs to stay fast for this reason. PaperDollFrameItemFlyout_Show(self.button); elseif ( event == "UNIT_INVENTORY_CHANGED" ) then local arg1 = ...; if ( arg1 == "player" ) then PaperDollFrameItemFlyout_Show(self.button); end end end local function _createFlyoutBG (buttonAnchor) local numBGs = buttonAnchor["numBGs"]; numBGs = numBGs + 1; local texture = buttonAnchor:CreateTexture(nil, nil, "PaperDollFrameFlyoutTexture"); buttonAnchor["bg" .. numBGs] = texture; buttonAnchor["numBGs"] = numBGs; return texture; end function PaperDollFrameItemFlyout_Show (paperDollItemSlot) local id = paperDollItemSlot:GetID(); local flyout = PaperDollFrameItemFlyout; local buttons = flyout.buttons; local buttonAnchor = flyout.buttonFrame; if ( flyout.button and flyout.button ~= paperDollItemSlot ) then local popoutButton = flyout.button.popoutButton; if ( popoutButton.flyoutLocked ) then popoutButton.flyoutLocked = false; PaperDollFrameItemPopoutButton_SetReversed(popoutButton, false); end end for k in next, itemDisplayTable do itemDisplayTable[k] = nil; end for k in next, itemTable do itemTable[k] = nil; end GetInventoryItemsForSlot(id, itemTable); for location, itemID in next, itemTable do if ( location - id == ITEM_INVENTORY_LOCATION_PLAYER ) then -- Remove the currently equipped item from the list itemTable[location] = nil; else tinsert(itemDisplayTable, location); end end table.sort(itemDisplayTable); -- Sort by location. This ends up as: inventory, backpack, bags, bank, and bank bags. local numItems = #itemDisplayTable; for i = PDFITEMFLYOUT_MAXITEMS + 1, numItems do itemDisplayTable[i] = nil; end numItems = min(numItems, PDFITEMFLYOUT_MAXITEMS); if ( GearManagerDialog:IsShown() ) then if ( not paperDollItemSlot.ignored ) then tinsert(itemDisplayTable, 1, PDFITEMFLYOUT_IGNORESLOT_LOCATION); else tinsert(itemDisplayTable, 1, PDFITEMFLYOUT_UNIGNORESLOT_LOCATION); end numItems = numItems + 1; end if ( paperDollItemSlot.hasItem ) then tinsert(itemDisplayTable, 1, PDFITEMFLYOUT_PLACEINBAGS_LOCATION); numItems = numItems + 1; end while #buttons < numItems do -- Create any buttons we need. PaperDollFrameItemFlyout_CreateButton(); end if ( numItems == 0 ) then flyout:Hide(); return; end for i, button in ipairs(buttons) do if ( i <= numItems ) then button.id = id; button.location = itemDisplayTable[i]; button:Show(); PaperDollFrameItemFlyout_DisplayButton(button, paperDollItemSlot); else button:Hide(); end end flyout:ClearAllPoints(); flyout:SetFrameLevel(paperDollItemSlot:GetFrameLevel() - 1); flyout.button = paperDollItemSlot; flyout:SetPoint("TOPLEFT", paperDollItemSlot, "TOPLEFT", -PDFITEMFLYOUT_BORDERWIDTH, PDFITEMFLYOUT_BORDERWIDTH); local horizontalItems = min(numItems, PDFITEMFLYOUT_ITEMS_PER_ROW); if ( paperDollItemSlot.verticalFlyout ) then buttonAnchor:SetPoint("TOPLEFT", paperDollItemSlot.popoutButton, "BOTTOMLEFT", 0, -PDFITEMFLYOUT_BORDERWIDTH); else buttonAnchor:SetPoint("TOPLEFT", paperDollItemSlot.popoutButton, "TOPRIGHT", 0, 0); end buttonAnchor:SetWidth((horizontalItems * PDFITEM_WIDTH) + ((horizontalItems - 1) * PDFITEM_XOFFSET) + PDFITEMFLYOUT_BORDERWIDTH); buttonAnchor:SetHeight(PDFITEMFLYOUT_HEIGHT + (math.floor((numItems - 1)/PDFITEMFLYOUT_ITEMS_PER_ROW) * (PDFITEM_HEIGHT - PDFITEM_YOFFSET))); if ( flyout.numItems ~= numItems ) then local texturesUsed = 0; if ( numItems == 1 ) then local bgTex, lastBGTex; bgTex = buttonAnchor.bg1; bgTex:ClearAllPoints(); bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONESLOT_LEFT_COORDS)); bgTex:SetWidth(PDFITEMFLYOUT_ONESLOT_LEFTWIDTH); bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT); bgTex:SetPoint("TOPLEFT", -5, 4); bgTex:Show(); texturesUsed = texturesUsed + 1; lastBGTex = bgTex; bgTex = buttonAnchor.bg2 or _createFlyoutBG(buttonAnchor); bgTex:ClearAllPoints(); bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONESLOT_RIGHT_COORDS)); bgTex:SetWidth(PDFITEMFLYOUT_ONESLOT_RIGHTWIDTH); bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT); bgTex:SetPoint("TOPLEFT", lastBGTex, "TOPRIGHT"); bgTex:Show(); texturesUsed = texturesUsed + 1; lastBGTex = bgTex; elseif ( numItems <= PDFITEMFLYOUT_ITEMS_PER_ROW ) then local bgTex, lastBGTex; bgTex = buttonAnchor.bg1; bgTex:ClearAllPoints(); bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONEROW_LEFT_COORDS)); bgTex:SetWidth(PDFITEMFLYOUT_ONEROW_LEFT_WIDTH); bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT); bgTex:SetPoint("TOPLEFT", -5, 4); bgTex:Show(); texturesUsed = texturesUsed + 1; lastBGTex = bgTex; for i = texturesUsed + 1, numItems - 1 do bgTex = buttonAnchor["bg"..i] or _createFlyoutBG(buttonAnchor); bgTex:ClearAllPoints(); bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONEROW_CENTER_COORDS)); bgTex:SetWidth(PDFITEMFLYOUT_ONEROW_CENTER_WIDTH); bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT); bgTex:SetPoint("TOPLEFT", lastBGTex, "TOPRIGHT"); bgTex:Show(); texturesUsed = texturesUsed + 1; lastBGTex = bgTex; end bgTex = buttonAnchor["bg"..numItems] or _createFlyoutBG(buttonAnchor); bgTex:ClearAllPoints(); bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONEROW_RIGHT_COORDS)); bgTex:SetWidth(PDFITEMFLYOUT_ONEROW_RIGHT_WIDTH); bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT); bgTex:SetPoint("TOPLEFT", lastBGTex, "TOPRIGHT"); bgTex:Show(); texturesUsed = texturesUsed + 1; elseif ( numItems > PDFITEMFLYOUT_ITEMS_PER_ROW ) then local numRows = math.ceil(numItems/PDFITEMFLYOUT_ITEMS_PER_ROW); local bgTex, lastBGTex; bgTex = buttonAnchor.bg1; bgTex:ClearAllPoints(); bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_MULTIROW_TOP_COORDS)); bgTex:SetWidth(PDFITEMFLYOUT_MULTIROW_WIDTH); bgTex:SetHeight(PDFITEMFLYOUT_MULTIROW_TOP_HEIGHT); bgTex:SetPoint("TOPLEFT", -5, 4); bgTex:Show(); texturesUsed = texturesUsed + 1; lastBGTex = bgTex; for i = 2, numRows - 1 do -- Middle rows bgTex = buttonAnchor["bg"..i] or _createFlyoutBG(buttonAnchor); bgTex:ClearAllPoints(); bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_MULTIROW_MIDDLE_COORDS)); bgTex:SetWidth(PDFITEMFLYOUT_MULTIROW_WIDTH); bgTex:SetHeight(PDFITEMFLYOUT_MULTIROW_MIDDLE_HEIGHT); bgTex:SetPoint("TOPLEFT", lastBGTex, "BOTTOMLEFT"); bgTex:Show(); texturesUsed = texturesUsed + 1; lastBGTex = bgTex; end bgTex = buttonAnchor["bg"..numRows] or _createFlyoutBG(buttonAnchor); bgTex:ClearAllPoints(); bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_MULTIROW_BOTTOM_COORDS)); bgTex:SetWidth(PDFITEMFLYOUT_MULTIROW_WIDTH); bgTex:SetHeight(PDFITEMFLYOUT_MULTIROW_BOTTOM_HEIGHT); bgTex:SetPoint("TOPLEFT", lastBGTex, "BOTTOMLEFT"); bgTex:Show(); texturesUsed = texturesUsed + 1; lastBGTex = bgTex; end for i = texturesUsed + 1, buttonAnchor["numBGs"] do buttonAnchor["bg" .. i]:Hide(); end flyout.numItems = numItems; end flyout:Show(); end function PaperDollFrameItemFlyout_DisplayButton (button, paperDollItemSlot) local location = button.location; if ( not location ) then return; end if ( location >= PDFITEMFLYOUT_FIRST_SPECIAL_LOCATION ) then PaperDollFrameItemFlyout_DisplaySpecialButton(button, paperDollItemSlot); return; end local id, name, textureName, count, durability, maxDurability, invType, locked, start, duration, enable, setTooltip = EquipmentManager_GetItemInfoByLocation(location); local broken = ( maxDurability and durability == 0 ); if ( textureName ) then SetItemButtonTexture(button, textureName); SetItemButtonCount(button, count); if ( broken ) then SetItemButtonTextureVertexColor(button, 0.9, 0, 0); SetItemButtonNormalTextureVertexColor(button, 0.9, 0, 0); else SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0); SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0); end CooldownFrame_SetTimer(button.cooldown, start, duration, enable); button.UpdateTooltip = function () GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6); setTooltip(); end; if ( button:IsMouseOver() ) then button.UpdateTooltip(); end else textureName = paperDollItemSlot.backgroundTextureName; if ( paperDollItemSlot.checkRelic and UnitHasRelicSlot("player") ) then textureName = "Interface\\Paperdoll\\UI-PaperDoll-Slot-Relic.blp"; end SetItemButtonTexture(button, textureName); SetItemButtonCount(button, 0); SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0); SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0); button.cooldown:Hide(); button.UpdateTooltip = nil; end end function PaperDollFrameItemFlyout_DisplaySpecialButton (button, paperDollItemSlot) local location = button.location; if ( location == PDFITEMFLYOUT_IGNORESLOT_LOCATION ) then SetItemButtonTexture(button, "Interface\\PaperDollInfoFrame\\UI-GearManager-LeaveItem-Opaque"); SetItemButtonCount(button, nil); button.UpdateTooltip = function () GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6); GameTooltip:SetText(EQUIPMENT_MANAGER_IGNORE_SLOT, 1.0, 1.0, 1.0); if ( SHOW_NEWBIE_TIPS == "1" ) then GameTooltip:AddLine(NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_IGNORE_SLOT, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1); end GameTooltip:Show(); end; SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0); SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0); elseif ( location == PDFITEMFLYOUT_UNIGNORESLOT_LOCATION ) then SetItemButtonTexture(button, "Interface\\PaperDollInfoFrame\\UI-GearManager-Undo"); SetItemButtonCount(button, nil); button.UpdateTooltip = function () GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6); GameTooltip:SetText(EQUIPMENT_MANAGER_UNIGNORE_SLOT, 1.0, 1.0, 1.0); if ( SHOW_NEWBIE_TIPS == "1" ) then GameTooltip:AddLine(NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_UNIGNORE_SLOT, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1); end GameTooltip:Show(); end; SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0); SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0); elseif ( location == PDFITEMFLYOUT_PLACEINBAGS_LOCATION ) then SetItemButtonTexture(button, "Interface\\PaperDollInfoFrame\\UI-GearManager-ItemIntoBag"); SetItemButtonCount(button, nil); button.UpdateTooltip = function () GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6); GameTooltip:SetText(EQUIPMENT_MANAGER_PLACE_IN_BAGS, 1.0, 1.0, 1.0); if ( SHOW_NEWBIE_TIPS == "1" ) then GameTooltip:AddLine(NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_PLACE_IN_BAGS, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1); end GameTooltip:Show(); end; SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0); SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0); end if ( button:IsMouseOver() and button.UpdateTooltip ) then button.UpdateTooltip(); end end function PaperDollFrameItemFlyoutButton_OnEnter (self) if ( self.UpdateTooltip ) then self.UpdateTooltip(); -- This shows the tooltip, and gets called repeatedly thereafter by GameTooltip. end end function PaperDollFrameItemFlyoutButton_OnClick (self) if ( self.location == PDFITEMFLYOUT_IGNORESLOT_LOCATION ) then local slot = PaperDollFrameItemFlyout.button; EquipmentManagerIgnoreSlotForSave(slot:GetID()); slot.ignored = true; PaperDollItemSlotButton_Update(slot); PaperDollFrameItemFlyout_Show(slot); elseif ( self.location == PDFITEMFLYOUT_UNIGNORESLOT_LOCATION ) then local slot = PaperDollFrameItemFlyout.button; EquipmentManagerUnignoreSlotForSave(slot:GetID()); slot.ignored = nil; PaperDollItemSlotButton_Update(slot); PaperDollFrameItemFlyout_Show(slot); elseif ( self.location == PDFITEMFLYOUT_PLACEINBAGS_LOCATION ) then if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[PaperDollFrameItemFlyout.button:GetID()] ) then UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0); return; end local action = EquipmentManager_UnequipItemInSlot(PaperDollFrameItemFlyout.button:GetID()); EquipmentManager_RunAction(action); elseif ( self.location ) then if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[PaperDollFrameItemFlyout.button:GetID()] ) then UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0); return; end local action = EquipmentManager_EquipItemByLocation(self.location, self.id); EquipmentManager_RunAction(action); end if ( PaperDollFrameItemFlyout.button.popoutButton.flyoutLocked ) then PaperDollFrameItemFlyout_Hide(); end end local popoutButtons = {} function PaperDollFrameItemPopoutButton_OnLoad(self) tinsert(popoutButtons, self); end function PaperDollFrameItemPopoutButton_HideAll() if ( PaperDollFrameItemFlyout.button and PaperDollFrameItemFlyout.button.popoutButton.flyoutLocked ) then PaperDollFrameItemFlyout_Hide(); end for _, button in pairs(popoutButtons) do if ( button.flyoutLocked ) then button.flyoutLocked = false; PaperDollFrameItemFlyout_Hide(); PaperDollFrameItemPopoutButton_SetReversed(button, false); end button:Hide(); end end function PaperDollFrameItemPopoutButton_ShowAll() for _, button in pairs(popoutButtons) do button:Show(); end end function PaperDollFrameItemPopoutButton_OnClick(self) if ( self.flyoutLocked ) then self.flyoutLocked = false; PaperDollFrameItemFlyout_Hide(); PaperDollFrameItemPopoutButton_SetReversed(self, false); else self.flyoutLocked = true; PaperDollFrameItemFlyout_Show(self:GetParent()); PaperDollFrameItemPopoutButton_SetReversed(self, true); end end function PaperDollFrameItemPopoutButton_SetReversed(self, isReversed) if ( self:GetParent().verticalFlyout ) then if ( isReversed ) then self:GetNormalTexture():SetTexCoord(0.15625, 0.84375, 0, 0.5); self:GetHighlightTexture():SetTexCoord(0.15625, 0.84375, 0.5, 1); else self:GetNormalTexture():SetTexCoord(0.15625, 0.84375, 0.5, 0); self:GetHighlightTexture():SetTexCoord(0.15625, 0.84375, 1, 0.5); end else if ( isReversed ) then self:GetNormalTexture():SetTexCoord(0.15625, 0, 0.84375, 0, 0.15625, 0.5, 0.84375, 0.5); self:GetHighlightTexture():SetTexCoord(0.15625, 0.5, 0.84375, 0.5, 0.15625, 1, 0.84375, 1); else self:GetNormalTexture():SetTexCoord(0.15625, 0.5, 0.84375, 0.5, 0.15625, 0, 0.84375, 0); self:GetHighlightTexture():SetTexCoord(0.15625, 1, 0.84375, 1, 0.15625, 0.5, 0.84375, 0.5); end end end NUM_GEARSETS_PER_ROW = 5; function GearManagerDialog_OnLoad (self) self.title:SetText(EQUIPMENT_MANAGER); self.buttons = {}; local name = self:GetName(); local button; for i = 1, MAX_EQUIPMENT_SETS_PER_PLAYER do button = CreateFrame("CheckButton", "GearSetButton" .. i, self, "GearSetButtonTemplate"); if ( i == 1 ) then button:SetPoint("TOPLEFT", self, "TOPLEFT", 16, -32); elseif ( mod(i, NUM_GEARSETS_PER_ROW) == 1 ) then button:SetPoint("TOP", "GearSetButton"..(i-NUM_GEARSETS_PER_ROW), "BOTTOM", 0, -10); else button:SetPoint("LEFT", "GearSetButton"..(i-1), "RIGHT", 13, 0); end button.icon = _G["GearSetButton" .. i .. "Icon"]; button.text = _G["GearSetButton" .. i .. "Name"]; tinsert(self.buttons, button); end self:RegisterEvent("VARIABLES_LOADED"); self:RegisterEvent("EQUIPMENT_SWAP_FINISHED"); end function GearManagerDialog_OnShow (self) CharacterFrame:SetAttribute("UIPanelLayout-defined", nil); GearManagerToggleButton:SetButtonState("PUSHED", 1); GearManagerDialog_Update(); self:RegisterEvent("EQUIPMENT_SETS_CHANGED"); EquipmentManagerClearIgnoredSlotsForSave(); PlaySound("igBackPackOpen"); PaperDollFrameItemPopoutButton_ShowAll(); UpdateUIPanelPositions(CharacterFrame); GearManagerDialog:Raise(); end function GearManagerDialog_OnHide (self) CharacterFrame:SetAttribute("UIPanelLayout-defined", nil); GearManagerDialogPopup:Hide(); GearManagerToggleButton:SetButtonState("NORMAL"); self:UnregisterEvent("EQUIPMENT_SETS_CHANGED"); PlaySound("igBackPackClose"); PaperDollFrame_ClearIgnoredSlots(); PaperDollFrameItemPopoutButton_HideAll(); UpdateUIPanelPositions(); end function GearManagerDialog_OnEvent (self, event, ...) if ( event == "EQUIPMENT_SETS_CHANGED" ) then GearManagerDialog_Update(); elseif ( event == "VARIABLES_LOADED" ) then if ( GetCVarBool("equipmentManager") ) then GearManagerToggleButton:Show(); end elseif ( event == "EQUIPMENT_SWAP_FINISHED" ) then local completed, setName = ...; if ( completed ) then self.selectedSetName = setName; GearManagerDialog_Update(); if ( self:IsShown() ) then PaperDollFrame_ClearIgnoredSlots(); PaperDollFrame_IgnoreSlotsForSet(setName); end end end end function GearManagerDialog_Update () local numSets = GetNumEquipmentSets(); local dialog = GearManagerDialog; local buttons = dialog.buttons; local selectedName = dialog.selectedSetName; local name, texture, button; dialog.selectedSet = nil; for i = 1, numSets do name, texture = GetEquipmentSetInfo(i); button = buttons[i]; button:Enable(); button.name = name; button.text:SetText(name); if (texture) then button.icon:SetTexture(texture); else button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark"); end if (selectedName and button.name == selectedName) then button:SetChecked(true); dialog.selectedSet = button; else button:SetChecked(false); end end if ( dialog.selectedSet ) then GearManagerDialogDeleteSet:Enable(); GearManagerDialogEquipSet:Enable(); else GearManagerDialogDeleteSet:Disable(); GearManagerDialogEquipSet:Disable(); end for i = numSets + 1, MAX_EQUIPMENT_SETS_PER_PLAYER do button = buttons[i]; button:Disable(); button:SetChecked(false); button.name = nil; button.text:SetText(""); button.icon:SetTexture(""); end if(GearManagerDialogPopup:IsShown()) then RecalculateGearManagerDialogPopup(); --Scroll so that the texture appears and Save is enabled end end function GearManagerDialogDeleteSet_OnClick (self) local selectedSet = GearManagerDialog.selectedSet; if ( selectedSet ) then local dialog = StaticPopup_Show("CONFIRM_DELETE_EQUIPMENT_SET", selectedSet.name); if ( dialog ) then dialog.data = selectedSet.name; else UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0); end end end function GearManagerDialogSaveSet_OnClick (self) local popup = GearManagerDialogPopup; local wasShown = popup:IsShown(); popup:Show(); if ( wasShown ) then --If the dialog was already shown, the OnShow script will not run and the icon will not be updated (Bug 169523) GearManagerDialogPopup_Update(); end end function GearManagerDialogEquipSet_OnClick (self) local selectedSet = GearManagerDialog.selectedSet; if ( selectedSet ) then local name = selectedSet.name; if ( name and name ~= "" ) then PlaySound("igCharacterInfoTab"); -- inappropriately named, but a good sound. EquipmentManager_EquipSet(name); end end end function GearSetButton_OnClick (self) --[[ Select the new gear set ]] if ( self.name and self.name ~= "" ) then PlaySound("igMainMenuOptionCheckBoxOn"); -- inappropriately named, but a good sound. local dialog = GearManagerDialog; dialog.selectedSetName = self.name; GearManagerDialog_Update(); --change selection, enable one equip button, disable rest. else self:SetChecked(false); end end function GearSetButton_OnEnter (self) if ( self.name and self.name ~= "" ) then GameTooltip_SetDefaultAnchor(GameTooltip, self); GameTooltip:SetEquipmentSet(self.name); end end NUM_GEARSET_ICONS_SHOWN = 15; NUM_GEARSET_ICONS_PER_ROW = 5; NUM_GEARSET_ICON_ROWS = 3; GEARSET_ICON_ROW_HEIGHT = 36; function GearManagerDialogPopup_OnLoad (self) self.buttons = {}; local rows = 0; local button = CreateFrame("CheckButton", "GearManagerDialogPopupButton1", GearManagerDialogPopup, "GearSetPopupButtonTemplate"); button:SetPoint("TOPLEFT", 24, -85); button:SetID(1); tinsert(self.buttons, button); local lastPos; for i = 2, NUM_GEARSET_ICONS_SHOWN do button = CreateFrame("CheckButton", "GearManagerDialogPopupButton" .. i, GearManagerDialogPopup, "GearSetPopupButtonTemplate"); button:SetID(i); lastPos = (i - 1) / NUM_GEARSET_ICONS_PER_ROW; if ( lastPos == math.floor(lastPos) ) then button:SetPoint("TOPLEFT", self.buttons[i-NUM_GEARSET_ICONS_PER_ROW], "BOTTOMLEFT", 0, -8); else button:SetPoint("TOPLEFT", self.buttons[i-1], "TOPRIGHT", 10, 0); end tinsert(self.buttons, button); end self.SetSelection = function(self, fTexture, Value) if(fTexture) then self.selectedTexture = Value; self.selectedIcon = nil; else self.selectedTexture = nil; self.selectedIcon = Value; end end end local _equippedItems = {}; local _numItems; local _specialIcon; local _TotalItems; function GearManagerDialogPopup_OnShow (self) PlaySound("igCharacterInfoOpen"); RecalculateGearManagerDialogPopup(); GearManagerDialogSaveSet:Disable(); end function GearManagerDialogPopup_OnHide (self) local popup = GearManagerDialogPopup; popup.name = nil; popup:SetSelection(true, nil); GearManagerDialogPopupEditBox:SetText(""); GearManagerDialogSaveSet:Enable(); end function RecalculateGearManagerDialogPopup() local popup = GearManagerDialogPopup; local selectedSet = GearManagerDialog.selectedSet; if ( selectedSet ) then popup:SetSelection(true, selectedSet.icon:GetTexture()); local editBox = GearManagerDialogPopupEditBox; editBox:SetText(selectedSet.name); editBox:HighlightText(0); end --[[ Scroll and ensure that any selected equipment shows up in the list. When we first press "save", we want to make sure any selected equipment set shows up in the list, so that the user can just make his changes and press Okay to overwrite. To do this, we need to find the current set (by icon) and move the offset of the GearManagerDialogPopup to display it. Issue ID: 171220 ]] RefreshEquipmentSetIconInfo(); _TotalItems = GetNumMacroIcons() + _numItems; _specialIcon = nil; local texture; if(popup.selectedTexture) then local index = 1; local foundIndex = nil; for index=1, _TotalItems do texture, _ = GetEquipmentSetIconInfo(index); if ( texture == popup.selectedTexture ) then foundIndex = index; break; end end if (foundIndex == nil) then _specialIcon = popup.selectedTexture; _TotalItems = _TotalItems + 1; foundIndex = _TotalItems; else _specialIcon = nil; end -- now make it so we always display at least NUM_GEARSET_ICON_ROWS of data local offsetnumIcons = floor((_TotalItems-1)/NUM_GEARSET_ICONS_PER_ROW); local offset = floor((foundIndex-1) / NUM_GEARSET_ICONS_PER_ROW); offset = offset + min((NUM_GEARSET_ICON_ROWS-1), offsetnumIcons-offset) - (NUM_GEARSET_ICON_ROWS-1); if(foundIndex<=NUM_GEARSET_ICONS_SHOWN) then offset = 0; --Equipment all shows at the same place. end FauxScrollFrame_OnVerticalScroll(GearManagerDialogPopupScrollFrame, offset*GEARSET_ICON_ROW_HEIGHT, GEARSET_ICON_ROW_HEIGHT, nil); end GearManagerDialogPopup_Update(); end --[[ RefreshEquipmentSetIconInfo() counts how many uniquely textured inventory items the player has equipped. ]] function RefreshEquipmentSetIconInfo () _numItems = 0; for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do _equippedItems[i] = GetInventoryItemTexture("player", i); if(_equippedItems[i]) then _numItems = _numItems + 1; --[[ Currently checks all for duplicates, even though only rings, trinkets, and weapons may be duplicated. This version is clean and maintainable. ]] for j=INVSLOT_FIRST_EQUIPPED, (i-1) do if(_equippedItems[i] == _equippedItems[j]) then _equippedItems[i] = nil; _numItems = _numItems - 1; break; end end end end end --[[ GetEquipmentSetIconInfo(index) determines the texture and real index of a regular index Input: index = index into a list of equipped items follows by the macro items. Only tricky part is the equipped items list keeps changing. Output: the associated texture for the item, and a index relative to the join point between the lists, i.e. negative for the equipped items and positive from the equipped items for the macro items// ]] function GetEquipmentSetIconInfo(index) for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do if (_equippedItems[i]) then index = index - 1; if ( index == 0 ) then return _equippedItems[i], -i; end end end if(index>GetNumMacroIcons()) then return _specialIcon, index; end return GetMacroIconInfo(index), index; end function GearManagerDialogPopup_Update () RefreshEquipmentSetIconInfo(); local popup = GearManagerDialogPopup; local buttons = popup.buttons; local offset = FauxScrollFrame_GetOffset(GearManagerDialogPopupScrollFrame) or 0; local button; -- Icon list local texture, index, button, realIndex; for i=1, NUM_GEARSET_ICONS_SHOWN do local button = buttons[i]; index = (offset * NUM_GEARSET_ICONS_PER_ROW) + i; if ( index <= _TotalItems ) then texture, _ = GetEquipmentSetIconInfo(index); -- button.name:SetText(index); --dcw button.icon:SetTexture(texture); button:Show(); if ( index == popup.selectedIcon ) then button:SetChecked(1); elseif ( texture == popup.selectedTexture ) then button:SetChecked(1); popup:SetSelection(false, index); else button:SetChecked(nil); end else button.icon:SetTexture(""); button:Hide(); end end -- Scrollbar stuff FauxScrollFrame_Update(GearManagerDialogPopupScrollFrame, ceil(_TotalItems / NUM_GEARSET_ICONS_PER_ROW) , NUM_GEARSET_ICON_ROWS, GEARSET_ICON_ROW_HEIGHT ); end function GearManagerDialogPopupOkay_Update () local popup = GearManagerDialogPopup; local button = GearManagerDialogPopupOkay; if ( popup.selectedIcon and popup.name ) then button:Enable(); else button:Disable(); end end function GearManagerDialogPopupOkay_OnClick (self, button, pushed) local popup = GearManagerDialogPopup; local _, iconIndex = GetEquipmentSetIconInfo(popup.selectedIcon); if ( GetEquipmentSetInfoByName(popup.name) ) then local dialog = StaticPopup_Show("CONFIRM_OVERWRITE_EQUIPMENT_SET", popup.name); if ( dialog ) then dialog.data = popup.name; dialog.selectedIcon = iconIndex; else UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0); end return; elseif ( GetNumEquipmentSets() >= MAX_EQUIPMENT_SETS_PER_PLAYER ) then UIErrorsFrame:AddMessage(EQUIPMENT_SETS_TOO_MANY, 1.0, 0.1, 0.1, 1.0); return end SaveEquipmentSet(popup.name, iconIndex); GearManagerDialogPopup:Hide(); end function GearManagerDialogPopupCancel_OnClick () GearManagerDialogPopup:Hide(); end function GearSetPopupButton_OnClick (self, button) local popup = GearManagerDialogPopup; local offset = FauxScrollFrame_GetOffset(GearManagerDialogPopupScrollFrame) or 0; popup.selectedIcon = (offset * NUM_GEARSET_ICONS_PER_ROW) + self:GetID(); popup.selectedTexture = nil; GearManagerDialogPopup_Update(); GearManagerDialogPopupOkay_Update(); end function PlayerTitlePickerScrollFrame_OnLoad(self) PlayerTitlePickerFrame:SetFrameLevel(self:GetParent():GetFrameLevel() + 2); PlayerTitlePickerScrollFrame:SetHeight(PLAYER_DISPLAYED_TITLES * PLAYER_TITLE_HEIGHT); HybridScrollFrame_OnLoad(self); self.update = PlayerTitlePickerScrollFrame_Update; HybridScrollFrame_CreateButtons(self, "PlayerTitleButtonTemplate"); end function PlayerTitlePickerScrollFrame_Update() local buttons = PlayerTitlePickerScrollFrame.buttons; local playerTitles = PlayerTitleFrame.titles; local numButtons = #buttons; local scrollOffset = HybridScrollFrame_GetOffset(PlayerTitlePickerScrollFrame); local playerTitle; for i = 1, numButtons do playerTitle = playerTitles[i + scrollOffset]; if ( playerTitle ) then buttons[i].text:SetText(playerTitle.name); buttons[i].titleId = playerTitle.id; if ( PlayerTitleFrame.selected == playerTitle.id ) then buttons[i].check:Show(); else buttons[i].check:Hide(); end end end end local function PlayerTitleSort(a, b) return a.name < b.name; end function PlayerTitleFrame_UpdateTitles() local playerTitles = { }; local currentTitle = GetCurrentTitle(); local titleCount = 1; local buttons = PlayerTitlePickerScrollFrame.buttons; local fontstringText = buttons[1].text; local fontstringWidth; local maxWidth = 0; PlayerTitleFrame.selected = -1; playerTitles[1] = { }; -- reserving space for None so it doesn't get sorted out of the top position playerTitles[1].name = " "; playerTitles[1].id = -1; for i = 1, GetNumTitles() do if ( IsTitleKnown(i) ~= 0 ) then titleCount = titleCount + 1; playerTitles[titleCount] = playerTitles[titleCount] or { }; playerTitles[titleCount].name = strtrim(GetTitleName(i)); playerTitles[titleCount].id = i; if ( i == currentTitle ) then PlayerTitleFrame.selected = i; end fontstringText:SetText(playerTitles[titleCount].name); fontstringWidth = fontstringText:GetWidth(); if ( fontstringWidth > maxWidth ) then maxWidth = fontstringWidth; end end end if ( titleCount < 2 ) then PlayerTitleFrame:Hide(); PlayerTitlePickerFrame:Hide(); else PlayerTitleFrame:Show() if ( currentTitle == 0 ) then PlayerTitleFrameText:SetText(PAPERDOLL_SELECT_TITLE); elseif ( currentTitle == -1 ) then PlayerTitleFrameText:SetText(NONE); else PlayerTitleFrameText:SetText(GetTitleName(currentTitle)); end table.sort(playerTitles, PlayerTitleSort); playerTitles[1].name = NONE; PlayerTitleFrame.titles = playerTitles; maxWidth = maxWidth + 10; for i = 1, #buttons do buttons[i]:SetWidth(maxWidth); end PlayerTitlePickerScrollFrame:SetWidth(maxWidth + 34); PlayerTitlePickerScrollFrameScrollChild:SetWidth(maxWidth + 34); if ( titleCount <= PLAYER_DISPLAYED_TITLES ) then PlayerTitlePickerFrame:SetWidth(maxWidth + 56); PlayerTitlePickerFrame:SetHeight(titleCount * PLAYER_TITLE_HEIGHT + 26); -- adding 1 due to possible rounding errors in HybridScrollFrame PlayerTitlePickerScrollFrame:SetHeight(titleCount * PLAYER_TITLE_HEIGHT + 1); else PlayerTitlePickerFrame:SetWidth(maxWidth + 76); PlayerTitlePickerFrame:SetHeight(PLAYER_TITLE_HEIGHT * PLAYER_DISPLAYED_TITLES + 26); -- adding 1 due to possible rounding errors in HybridScrollFrame PlayerTitlePickerScrollFrame:SetHeight(PLAYER_TITLE_HEIGHT * PLAYER_DISPLAYED_TITLES + 1); end HybridScrollFrame_CreateButtons(PlayerTitlePickerScrollFrame, "PlayerTitleButtonTemplate"); HybridScrollFrame_Update(PlayerTitlePickerScrollFrame, titleCount * PLAYER_TITLE_HEIGHT, PlayerTitlePickerScrollFrame:GetHeight()); PlayerTitlePickerScrollFrame_Update(); end end function PlayerTitlePickerFrame_Toggle() if ( PlayerTitlePickerFrame:IsShown() ) then PlaySound("igMainMenuOptionCheckBoxOff"); PlayerTitlePickerFrame:Hide(); else PlaySound("igMainMenuOptionCheckBoxOn"); PlayerTitlePickerFrame:Show(); PlayerTitlePickerScrollFrame_Update(); end end function PlayerTitleButton_OnClick(self) PlaySound("igMainMenuOptionCheckBoxOff"); PlayerTitleFrame.selected = self.titleId; SetCurrentTitle(self.titleId); PlayerTitleFrameText:SetText(self.text:GetText()); PlayerTitlePickerFrame:Hide(); end function SetTitleByName(name) name = strlower(name); for i = 1, GetNumTitles() do if ( IsTitleKnown(i) ~= 0 ) then local title = strlower(strtrim(GetTitleName(i))); if(title:find(name) == 1) then SetCurrentTitle(i); return true; end end end return false; end