PaperDollFrame.lua

PaperDollFrame.lua (9.0.2.37474; unchanged since 9.0.1.36230)
  1. EQUIPPED_FIRST = 1;
  2. EQUIPPED_LAST = 19;
  3. NUM_STATS = 5;
  4. NUM_SHOPPING_TOOLTIPS = 2;
  5. MAX_SPELL_SCHOOLS = 7;
  6. CR_UNUSED_1 = 1;
  7. CR_DEFENSE_SKILL = 2;
  8. CR_DODGE = 3;
  9. CR_PARRY = 4;
  10. CR_BLOCK = 5;
  11. CR_HIT_MELEE = 6;
  12. CR_HIT_RANGED = 7;
  13. CR_HIT_SPELL = 8;
  14. CR_CRIT_MELEE = 9;
  15. CR_CRIT_RANGED = 10;
  16. CR_CRIT_SPELL = 11;
  17. CR_CORRUPTION = 12;
  18. CR_CORRUPTION_RESISTANCE = 13;
  19. CR_SPEED = 14;
  20. COMBAT_RATING_RESILIENCE_CRIT_TAKEN = 15;
  21. COMBAT_RATING_RESILIENCE_PLAYER_DAMAGE_TAKEN = 16;
  22. CR_LIFESTEAL = 17;
  23. CR_HASTE_MELEE = 18;
  24. CR_HASTE_RANGED = 19;
  25. CR_HASTE_SPELL = 20;
  26. CR_AVOIDANCE = 21;
  27. CR_UNUSED_2 = 22;
  28. CR_WEAPON_SKILL_RANGED = 23;
  29. CR_EXPERTISE = 24;
  30. CR_ARMOR_PENETRATION = 25;
  31. CR_MASTERY = 26;
  32. CR_UNUSED_3 = 27;
  33. CR_UNUSED_4 = 28;
  34. CR_VERSATILITY_DAMAGE_DONE = 29;
  35. CR_VERSATILITY_DAMAGE_TAKEN = 31;
  36. ATTACK_POWER_MAGIC_NUMBER = 3.5;
  37. BLOCK_PER_STRENGTH = 0.5;
  38. MANA_PER_INTELLECT = 15;
  39. BASE_MOVEMENT_SPEED = 7;
  40. CREATURE_HP_PER_STA = 10;
  41. local BreakUpLargeNumbers = BreakUpLargeNumbers;
  42. --Pet scaling:
  43. HUNTER_PET_BONUS = {};
  44. HUNTER_PET_BONUS["PET_BONUS_RAP_TO_AP"] = 0.22;
  45. HUNTER_PET_BONUS["PET_BONUS_RAP_TO_SPELLDMG"] = 0.1287;
  46. HUNTER_PET_BONUS["PET_BONUS_STAM"] = 0.3;
  47. HUNTER_PET_BONUS["PET_BONUS_RES"] = 0.4;
  48. HUNTER_PET_BONUS["PET_BONUS_ARMOR"] = 0.7;
  49. HUNTER_PET_BONUS["PET_BONUS_SPELLDMG_TO_SPELLDMG"] = 0.0;
  50. HUNTER_PET_BONUS["PET_BONUS_SPELLDMG_TO_AP"] = 0.0;
  51. HUNTER_PET_BONUS["PET_BONUS_INT"] = 0.0;
  52. WARLOCK_PET_BONUS = {};
  53. WARLOCK_PET_BONUS["PET_BONUS_RAP_TO_AP"] = 0.0;
  54. WARLOCK_PET_BONUS["PET_BONUS_RAP_TO_SPELLDMG"] = 0.0;
  55. WARLOCK_PET_BONUS["PET_BONUS_STAM"] = 0.3;
  56. WARLOCK_PET_BONUS["PET_BONUS_RES"] = 0.4;
  57. WARLOCK_PET_BONUS["PET_BONUS_ARMOR"] = 1.00;
  58. WARLOCK_PET_BONUS["PET_BONUS_SPELLDMG_TO_SPELLDMG"] = 0.15;
  59. WARLOCK_PET_BONUS["PET_BONUS_SPELLDMG_TO_AP"] = 0.57;
  60. WARLOCK_PET_BONUS["PET_BONUS_INT"] = 0.3;
  61. PLAYER_DISPLAYED_TITLES = 6;
  62. PLAYER_TITLE_HEIGHT = 22;
  63. EQUIPMENTSET_BUTTON_HEIGHT = 44;
  64. local itemSlotButtons = {};
  65. MOVING_STAT_CATEGORY = nil;
  66. local StatCategoryFrames = {};
  67. local STRIPE_COLOR = {r=0.9, g=0.9, b=1};
  68. MIN_PLAYER_LEVEL_FOR_ITEM_LEVEL_DISPLAY = 10;
  69. PAPERDOLL_SIDEBARS = {
  70. {
  71. name=PAPERDOLL_SIDEBAR_STATS;
  72. frame="CharacterStatsPane";
  73. icon = nil; -- Uses the character portrait
  74. texCoords = {0.109375, 0.890625, 0.09375, 0.90625};
  75. disabledTooltip = nil;
  76. IsActive = function() return true; end
  77. },
  78. {
  79. name=PAPERDOLL_SIDEBAR_TITLES;
  80. frame="PaperDollTitlesPane";
  81. icon = "Interface\\PaperDollInfoFrame\\PaperDollSidebarTabs";
  82. texCoords = {0.01562500, 0.53125000, 0.32421875, 0.46093750};
  83. disabledTooltip = NO_TITLES_TOOLTIP;
  84. IsActive = function()
  85. -- You always have the "No Title" title so you need to have more than one to have an option.
  86. return #GetKnownTitles() > 1;
  87. end
  88. },
  89. {
  90. name=PAPERDOLL_EQUIPMENTMANAGER;
  91. frame="PaperDollEquipmentManagerPane";
  92. icon = "Interface\\PaperDollInfoFrame\\PaperDollSidebarTabs";
  93. texCoords = {0.01562500, 0.53125000, 0.46875000, 0.60546875};
  94. disabledTooltip = function()
  95. local _, failureReason = C_LFGInfo.CanPlayerUseLFD();
  96. return failureReason;
  97. end;
  98. IsActive = function()
  99. return C_EquipmentSet.GetNumEquipmentSets() > 0 or C_LFGInfo.CanPlayerUseLFD();
  100. end
  101. },
  102. };
  103. PAPERDOLL_STATINFO = {
  104. -- General
  105. ["HEALTH"] = {
  106. updateFunc = function(statFrame, unit) PaperDollFrame_SetHealth(statFrame, unit); end
  107. },
  108. ["POWER"] = {
  109. updateFunc = function(statFrame, unit) PaperDollFrame_SetPower(statFrame, unit); end
  110. },
  111. ["ALTERNATEMANA"] = {
  112. -- Only appears for Druids when in shapeshift form
  113. updateFunc = function(statFrame, unit) PaperDollFrame_SetAlternateMana(statFrame, unit); end
  114. },
  115. ["ITEMLEVEL"] = {
  116. updateFunc = function(statFrame, unit) PaperDollFrame_SetItemLevel(statFrame, unit); end
  117. },
  118. ["MOVESPEED"] = {
  119. updateFunc = function(statFrame, unit) PaperDollFrame_SetMovementSpeed(statFrame, unit); end
  120. },
  121. -- Base stats
  122. ["STRENGTH"] = {
  123. updateFunc = function(statFrame, unit) PaperDollFrame_SetStat(statFrame, unit, LE_UNIT_STAT_STRENGTH); end
  124. },
  125. ["AGILITY"] = {
  126. updateFunc = function(statFrame, unit) PaperDollFrame_SetStat(statFrame, unit, LE_UNIT_STAT_AGILITY); end
  127. },
  128. ["INTELLECT"] = {
  129. updateFunc = function(statFrame, unit) PaperDollFrame_SetStat(statFrame, unit, LE_UNIT_STAT_INTELLECT); end
  130. },
  131. ["STAMINA"] = {
  132. updateFunc = function(statFrame, unit) PaperDollFrame_SetStat(statFrame, unit, LE_UNIT_STAT_STAMINA); end
  133. },
  134. -- Enhancements
  135. ["CRITCHANCE"] = {
  136. updateFunc = function(statFrame, unit) PaperDollFrame_SetCritChance(statFrame, unit); end
  137. },
  138. ["HASTE"] = {
  139. updateFunc = function(statFrame, unit) PaperDollFrame_SetHaste(statFrame, unit); end
  140. },
  141. ["MASTERY"] = {
  142. updateFunc = function(statFrame, unit) PaperDollFrame_SetMastery(statFrame, unit); end
  143. },
  144. ["VERSATILITY"] = {
  145. updateFunc = function(statFrame, unit) PaperDollFrame_SetVersatility(statFrame, unit); end
  146. },
  147. ["LIFESTEAL"] = {
  148. updateFunc = function(statFrame, unit) PaperDollFrame_SetLifesteal(statFrame, unit); end
  149. },
  150. ["AVOIDANCE"] = {
  151. updateFunc = function(statFrame, unit) PaperDollFrame_SetAvoidance(statFrame, unit); end
  152. },
  153. ["SPEED"] = {
  154. updateFunc = function(statFrame, unit) PaperDollFrame_SetSpeed(statFrame, unit); end
  155. },
  156. -- Attack
  157. ["ATTACK_DAMAGE"] = {
  158. updateFunc = function(statFrame, unit) PaperDollFrame_SetDamage(statFrame, unit); end
  159. },
  160. ["ATTACK_AP"] = {
  161. updateFunc = function(statFrame, unit) PaperDollFrame_SetAttackPower(statFrame, unit); end
  162. },
  163. ["ATTACK_ATTACKSPEED"] = {
  164. updateFunc = function(statFrame, unit) PaperDollFrame_SetAttackSpeed(statFrame, unit); end
  165. },
  166. ["ENERGY_REGEN"] = {
  167. updateFunc = function(statFrame, unit) PaperDollFrame_SetEnergyRegen(statFrame, unit); end
  168. },
  169. ["RUNE_REGEN"] = {
  170. updateFunc = function(statFrame, unit) PaperDollFrame_SetRuneRegen(statFrame, unit); end
  171. },
  172. ["FOCUS_REGEN"] = {
  173. updateFunc = function(statFrame, unit) PaperDollFrame_SetFocusRegen(statFrame, unit); end
  174. },
  175. -- Spell
  176. ["SPELLPOWER"] = {
  177. updateFunc = function(statFrame, unit) PaperDollFrame_SetSpellPower(statFrame, unit); end
  178. },
  179. ["MANAREGEN"] = {
  180. updateFunc = function(statFrame, unit) PaperDollFrame_SetManaRegen(statFrame, unit); end
  181. },
  182. -- Defense
  183. ["ARMOR"] = {
  184. updateFunc = function(statFrame, unit) PaperDollFrame_SetArmor(statFrame, unit); end
  185. },
  186. ["DODGE"] = {
  187. updateFunc = function(statFrame, unit) PaperDollFrame_SetDodge(statFrame, unit); end
  188. },
  189. ["PARRY"] = {
  190. updateFunc = function(statFrame, unit) PaperDollFrame_SetParry(statFrame, unit); end
  191. },
  192. ["BLOCK"] = {
  193. updateFunc = function(statFrame, unit) PaperDollFrame_SetBlock(statFrame, unit); end
  194. },
  195. ["STAGGER"] = {
  196. updateFunc = function(statFrame, unit) PaperDollFrame_SetStagger(statFrame, unit); end
  197. },
  198. };
  199. -- primary: only show the 1 for the player's current spec
  200. -- roles: only show if the player's current spec is one of the roles
  201. -- hideAt: only show if it's not this value
  202. -- showFunc: only show if this function returns true (Note: make sure whatever your function is dependent on also triggers an update when it changes)
  203. PAPERDOLL_STATCATEGORIES= {
  204. [1] = {
  205. categoryFrame = "AttributesCategory",
  206. stats = {
  207. [1] = { stat = "STRENGTH", primary = LE_UNIT_STAT_STRENGTH },
  208. [2] = { stat = "AGILITY", primary = LE_UNIT_STAT_AGILITY },
  209. [3] = { stat = "INTELLECT", primary = LE_UNIT_STAT_INTELLECT },
  210. [4] = { stat = "STAMINA" },
  211. [5] = { stat = "ARMOR" },
  212. [6] = { stat = "STAGGER", hideAt = 0, roles = { "TANK" }},
  213. [7] = { stat = "MANAREGEN", roles = { "HEALER" } },
  214. },
  215. },
  216. [2] = {
  217. categoryFrame = "EnhancementsCategory",
  218. stats = {
  219. { stat = "CRITCHANCE", hideAt = 0 },
  220. { stat = "HASTE", hideAt = 0 },
  221. { stat = "MASTERY", hideAt = 0 },
  222. { stat = "VERSATILITY", hideAt = 0 },
  223. { stat = "LIFESTEAL", hideAt = 0 },
  224. { stat = "AVOIDANCE", hideAt = 0 },
  225. { stat = "SPEED", hideAt = 0 },
  226. { stat = "DODGE", roles = { "TANK" } },
  227. { stat = "PARRY", hideAt = 0, roles = { "TANK" } },
  228. { stat = "BLOCK", hideAt = 0, showFunc = C_PaperDollInfo.OffhandHasShield },
  229. },
  230. },
  231. };
  232. -- Task 67449: Hit and Expertise are being removed from items, so all players receive a 7.5% reduced miss chance,
  233. -- a 15% reduced spell miss chance, a 7.5% reduced enemy dodge chance, and a 4.5% reduced enemy parry chance
  234. BASE_MISS_CHANCE_PHYSICAL = {
  235. [0] = -4.5;
  236. [1] = -3.0;
  237. [2] = -1.5;
  238. [3] = 0.0;
  239. };
  240. BASE_MISS_CHANCE_SPELL = {
  241. [0] = -9.0;
  242. [1] = -6.0;
  243. [2] = -3.0;
  244. [3] = 0.0;
  245. };
  246. BASE_ENEMY_DODGE_CHANCE = {
  247. [0] = -4.5;
  248. [1] = -3.0;
  249. [2] = -1.5;
  250. [3] = 0.0;
  251. };
  252. BASE_ENEMY_PARRY_CHANCE = {
  253. [0] = -1.5;
  254. [1] = 0.0;
  255. [2] = 1.5;
  256. [3] = 3.0;
  257. };
  258. DUAL_WIELD_HIT_PENALTY = 19.0;
  259. function PaperDollFrame_OnLoad(self)
  260. self:RegisterEvent("PLAYER_ENTERING_WORLD");
  261. self:RegisterEvent("CHARACTER_POINTS_CHANGED");
  262. self:RegisterEvent("UNIT_MODEL_CHANGED");
  263. self:RegisterEvent("UNIT_LEVEL");
  264. self:RegisterEvent("UNIT_STATS");
  265. self:RegisterEvent("UNIT_RANGEDDAMAGE");
  266. self:RegisterEvent("UNIT_ATTACK_POWER");
  267. self:RegisterEvent("UNIT_RANGED_ATTACK_POWER");
  268. self:RegisterEvent("UNIT_ATTACK");
  269. self:RegisterEvent("UNIT_SPELL_HASTE");
  270. self:RegisterEvent("UNIT_RESISTANCES");
  271. self:RegisterEvent("PLAYER_GUILD_UPDATE");
  272. self:RegisterEvent("SKILL_LINES_CHANGED");
  273. self:RegisterEvent("COMBAT_RATING_UPDATE");
  274. self:RegisterEvent("MASTERY_UPDATE");
  275. self:RegisterEvent("SPEED_UPDATE");
  276. self:RegisterEvent("LIFESTEAL_UPDATE");
  277. self:RegisterEvent("AVOIDANCE_UPDATE");
  278. self:RegisterEvent("KNOWN_TITLES_UPDATE");
  279. self:RegisterEvent("UNIT_NAME_UPDATE");
  280. self:RegisterEvent("PLAYER_TALENT_UPDATE");
  281. self:RegisterEvent("BAG_UPDATE");
  282. self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED");
  283. self:RegisterEvent("PLAYER_AVG_ITEM_LEVEL_UPDATE");
  284. self:RegisterEvent("PLAYER_DAMAGE_DONE_MODS");
  285. self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED");
  286. self:RegisterUnitEvent("UNIT_DAMAGE", "player");
  287. self:RegisterUnitEvent("UNIT_ATTACK_SPEED", "player");
  288. self:RegisterUnitEvent("UNIT_MAXHEALTH", "player");
  289. self:RegisterUnitEvent("UNIT_AURA", "player");
  290. self:RegisterEvent("SPELL_POWER_CHANGED");
  291. self:RegisterEvent("CHARACTER_ITEM_FIXUP_NOTIFICATION");
  292. self:RegisterEvent("TRIAL_STATUS_UPDATE");
  293. self:RegisterEvent("PLAYER_TARGET_CHANGED");
  294. self:RegisterEvent("GX_RESTARTED");
  295. -- flyout settings
  296. PaperDollItemsFrame.flyoutSettings = {
  297. onClickFunc = PaperDollFrameItemFlyoutButton_OnClick,
  298. getItemsFunc = PaperDollFrameItemFlyout_GetItems,
  299. postGetItemsFunc = PaperDollFrameItemFlyout_PostGetItems,
  300. hasPopouts = true,
  301. parent = PaperDollFrame,
  302. anchorX = 0,
  303. anchorY = -3,
  304. verticalAnchorX = 0,
  305. verticalAnchorY = 0,
  306. };
  307. -- trial edition
  308. local width = CharacterTrialLevelErrorText:GetWidth();
  309. if ( width > 190 ) then
  310. CharacterTrialLevelErrorText:SetPoint("TOP", CharacterLevelText, "BOTTOM", -((width-190)/2), 2);
  311. end
  312. if( GameLimitedMode_IsActive() ) then
  313. CharacterTrialLevelErrorText:SetText(CAPPED_LEVEL_TRIAL);
  314. end
  315. end
  316. function PaperDoll_IsEquippedSlot(slot)
  317. if ( slot ) then
  318. slot = tonumber(slot);
  319. if ( slot ) then
  320. return slot >= EQUIPPED_FIRST and slot <= EQUIPPED_LAST;
  321. end
  322. end
  323. return false;
  324. end
  325. -- This makes sure the update only happens once at the end of the frame
  326. function PaperDollFrame_QueuedUpdate(self)
  327. self:SetScript("OnUpdate", nil);
  328. PaperDollFrame_UpdateStats();
  329. end
  330. function PaperDollFrame_OnEvent(self, event, ...)
  331. local unit = ...;
  332. if ( event == "PLAYER_ENTERING_WORLD" or event == "GX_RESTARTED" or
  333. event == "UNIT_MODEL_CHANGED" and unit == "player" ) then
  334. CharacterModelFrame:SetUnit("player", false);
  335. return;
  336. elseif ( event == "KNOWN_TITLES_UPDATE" or (event == "UNIT_NAME_UPDATE" and unit == "player")) then
  337. if (PaperDollTitlesPane:IsShown()) then
  338. PaperDollTitlesPane_Update();
  339. end
  340. end
  341. if ( not self:IsVisible() ) then
  342. return;
  343. end
  344. if ( unit == "player" ) then
  345. if ( event == "UNIT_LEVEL" ) then
  346. PaperDollFrame_SetLevel();
  347. elseif ( event == "UNIT_DAMAGE" or
  348. event == "UNIT_ATTACK_SPEED" or
  349. event == "UNIT_RANGEDDAMAGE" or
  350. event == "UNIT_ATTACK" or
  351. event == "UNIT_STATS" or
  352. event == "UNIT_RANGED_ATTACK_POWER" or
  353. event == "UNIT_SPELL_HASTE" or
  354. event == "UNIT_MAXHEALTH" or
  355. event == "UNIT_AURA" or
  356. event == "UNIT_RESISTANCES") then
  357. self:SetScript("OnUpdate", PaperDollFrame_QueuedUpdate);
  358. end
  359. end
  360. if ( event == "COMBAT_RATING_UPDATE" or
  361. event == "MASTERY_UPDATE" or
  362. event == "SPEED_UPDATE" or
  363. event == "LIFESTEAL_UPDATE" or
  364. event == "AVOIDANCE_UPDATE" or
  365. event == "BAG_UPDATE" or
  366. event == "PLAYER_EQUIPMENT_CHANGED" or
  367. event == "PLAYER_AVG_ITEM_LEVEL_UPDATE" or
  368. event == "PLAYER_DAMAGE_DONE_MODS" or
  369. event == "PLAYER_TARGET_CHANGED") then
  370. self:SetScript("OnUpdate", PaperDollFrame_QueuedUpdate);
  371. elseif (event == "PLAYER_TALENT_UPDATE") then
  372. PaperDollFrame_SetLevel();
  373. self:SetScript("OnUpdate", PaperDollFrame_QueuedUpdate);
  374. elseif (event == "ACTIVE_TALENT_GROUP_CHANGED") then
  375. PaperDollFrame_UpdateStats();
  376. elseif ( event == "SPELL_POWER_CHANGED" ) then
  377. self:SetScript("OnUpdate", PaperDollFrame_QueuedUpdate);
  378. elseif ( event == "TRIAL_STATUS_UPDATE" ) then
  379. PaperDollFrame_SetLevel();
  380. end
  381. end
  382. function PaperDollFrame_SetLevel()
  383. local primaryTalentTree = GetSpecialization();
  384. local classDisplayName, class = UnitClass("player");
  385. local classColorString = RAID_CLASS_COLORS[class].colorStr;
  386. local specName, _;
  387. if (primaryTalentTree) then
  388. _, specName = GetSpecializationInfo(primaryTalentTree, nil, nil, nil, UnitSex("player"));
  389. end
  390. local level = UnitLevel("player");
  391. local effectiveLevel = UnitEffectiveLevel("player");
  392. if ( effectiveLevel ~= level ) then
  393. level = EFFECTIVE_LEVEL_FORMAT:format(effectiveLevel, level);
  394. end
  395. if (specName and specName ~= "") then
  396. CharacterLevelText:SetFormattedText(PLAYER_LEVEL, level, classColorString, specName, classDisplayName);
  397. else
  398. CharacterLevelText:SetFormattedText(PLAYER_LEVEL_NO_SPEC, level, classColorString, classDisplayName);
  399. end
  400. local showTrialCap = false;
  401. if (GameLimitedMode_IsActive()) then
  402. local rLevel = GetRestrictedAccountData();
  403. if (UnitLevel("player") >= rLevel) then
  404. showTrialCap = true;
  405. end
  406. end
  407. CharacterTrialLevelErrorText:SetShown(showTrialCap);
  408. if (showTrialCap) then
  409. CharacterLevelText:SetPoint("CENTER", PaperDollFrame, "TOP", 0, -36);
  410. else
  411. CharacterLevelText:SetPoint("CENTER", PaperDollFrame, "TOP", 0, -42);
  412. end
  413. end
  414. function GetEnemyDodgeChance(levelOffset)
  415. if (levelOffset < 0 or levelOffset > 3) then
  416. return 0;
  417. end
  418. local chance = BASE_ENEMY_DODGE_CHANCE[levelOffset];
  419. local offhandChance = BASE_ENEMY_DODGE_CHANCE[levelOffset];
  420. local rangedChance = BASE_ENEMY_DODGE_CHANCE[levelOffset];
  421. local expertisePct, offhandExpertisePct, rangedExpertisePct = GetExpertise();
  422. chance = chance - expertisePct;
  423. offhandChance = offhandChance - offhandExpertisePct;
  424. rangedChance = rangedChance - rangedExpertisePct;
  425. if (chance < 0) then
  426. chance = 0;
  427. elseif (chance > 100) then
  428. chance = 100;
  429. end
  430. if (offhandChance < 0) then
  431. offhandChance = 0;
  432. elseif (offhandChance > 100) then
  433. offhandChance = 100;
  434. end
  435. if (rangedChance < 0) then
  436. rangedChance = 0;
  437. elseif (rangedChance > 100) then
  438. rangedChance = 100;
  439. end
  440. return chance, offhandChance, rangedChance;
  441. end
  442. function GetEnemyParryChance(levelOffset)
  443. if (levelOffset < 0 or levelOffset > 3) then
  444. return 0;
  445. end
  446. local chance = BASE_ENEMY_PARRY_CHANCE[levelOffset];
  447. local offhandChance = BASE_ENEMY_PARRY_CHANCE[levelOffset];
  448. local expertisePct, offhandExpertisePct = GetExpertise();
  449. local mainhandDodge = BASE_ENEMY_DODGE_CHANCE[levelOffset];
  450. local offhandDodge = BASE_ENEMY_DODGE_CHANCE[levelOffset];
  451. expertisePct = expertisePct - mainhandDodge;
  452. if ( expertisePct < 0 ) then
  453. expertisePct = 0;
  454. end
  455. chance = chance - expertisePct;
  456. if (chance < 0) then
  457. chance = 0;
  458. elseif (chance > 100) then
  459. chance = 100;
  460. end
  461. offhandExpertisePct = offhandExpertisePct - offhandDodge;
  462. if ( offhandExpertisePct < 0 ) then
  463. offhandExpertisePct = 0;
  464. end
  465. offhandChance = offhandChance - offhandExpertisePct;
  466. if (offhandChance < 0) then
  467. offhandChance = 0;
  468. elseif (offhandChance > 100) then
  469. offhandChance = 100;
  470. end
  471. return chance, offhandChance;
  472. end
  473. function PaperDollFrame_SetHealth(statFrame, unit)
  474. if (not unit) then
  475. unit = "player";
  476. end
  477. local health = UnitHealthMax(unit);
  478. local healthText = BreakUpLargeNumbers(health);
  479. PaperDollFrame_SetLabelAndText(statFrame, HEALTH, healthText, false, health);
  480. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, HEALTH).." "..healthText..FONT_COLOR_CODE_CLOSE;
  481. if (unit == "player") then
  482. statFrame.tooltip2 = STAT_HEALTH_TOOLTIP;
  483. elseif (unit == "pet") then
  484. statFrame.tooltip2 = STAT_HEALTH_PET_TOOLTIP;
  485. end
  486. statFrame:Show();
  487. end
  488. function PaperDollFrame_SetPower(statFrame, unit)
  489. if (not unit) then
  490. unit = "player";
  491. end
  492. local powerType, powerToken = UnitPowerType(unit);
  493. local power = UnitPowerMax(unit) or 0;
  494. local powerText = BreakUpLargeNumbers(power);
  495. if (powerToken and _G[powerToken]) then
  496. PaperDollFrame_SetLabelAndText(statFrame, _G[powerToken], powerText, false, power);
  497. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, _G[powerToken]).." "..powerText..FONT_COLOR_CODE_CLOSE;
  498. statFrame.tooltip2 = _G["STAT_"..powerToken.."_TOOLTIP"];
  499. statFrame:Show();
  500. else
  501. statFrame:Hide();
  502. end
  503. end
  504. function PaperDollFrame_SetAlternateMana(statFrame, unit)
  505. if (not unit) then
  506. unit = "player";
  507. end
  508. local _, class = UnitClass(unit);
  509. if (class ~= "DRUID" and (class ~= "MONK" or GetSpecialization() ~= SPEC_MONK_MISTWEAVER)) then
  510. statFrame:Hide();
  511. return;
  512. end
  513. local powerType, powerToken = UnitPowerType(unit);
  514. if (powerToken == "MANA") then
  515. statFrame:Hide();
  516. return;
  517. end
  518. local power = UnitPowerMax(unit, 0);
  519. local powerText = BreakUpLargeNumbers(power);
  520. PaperDollFrame_SetLabelAndText(statFrame, MANA, powerText, false, power);
  521. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, MANA).." "..powerText..FONT_COLOR_CODE_CLOSE;
  522. statFrame.tooltip2 = _G["STAT_MANA_TOOLTIP"];
  523. statFrame:Show();
  524. end
  525. function PaperDollFrame_SetStat(statFrame, unit, statIndex)
  526. if (unit ~= "player") then
  527. statFrame:Hide();
  528. return;
  529. end
  530. local stat;
  531. local effectiveStat;
  532. local posBuff;
  533. local negBuff;
  534. stat, effectiveStat, posBuff, negBuff = UnitStat(unit, statIndex);
  535. local effectiveStatDisplay = BreakUpLargeNumbers(effectiveStat);
  536. -- Set the tooltip text
  537. local statName = _G["SPELL_STAT"..statIndex.."_NAME"];
  538. local tooltipText = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, statName).." ";
  539. if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
  540. statFrame.tooltip = tooltipText..effectiveStatDisplay..FONT_COLOR_CODE_CLOSE;
  541. else
  542. tooltipText = tooltipText..effectiveStatDisplay;
  543. if ( posBuff > 0 or negBuff < 0 ) then
  544. tooltipText = tooltipText.." ("..BreakUpLargeNumbers(stat - posBuff - negBuff)..FONT_COLOR_CODE_CLOSE;
  545. end
  546. if ( posBuff > 0 ) then
  547. tooltipText = tooltipText..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..BreakUpLargeNumbers(posBuff)..FONT_COLOR_CODE_CLOSE;
  548. end
  549. if ( negBuff < 0 ) then
  550. tooltipText = tooltipText..RED_FONT_COLOR_CODE.." "..BreakUpLargeNumbers(negBuff)..FONT_COLOR_CODE_CLOSE;
  551. end
  552. if ( posBuff > 0 or negBuff < 0 ) then
  553. tooltipText = tooltipText..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
  554. end
  555. statFrame.tooltip = tooltipText;
  556. -- If there are any negative buffs then show the main number in red even if there are
  557. -- positive buffs. Otherwise show in green.
  558. if ( negBuff < 0 and not GetPVPGearStatRules() ) then
  559. effectiveStatDisplay = RED_FONT_COLOR_CODE..effectiveStatDisplay..FONT_COLOR_CODE_CLOSE;
  560. end
  561. end
  562. PaperDollFrame_SetLabelAndText(statFrame, statName, effectiveStatDisplay, false, effectiveStat);
  563. statFrame.tooltip2 = _G["DEFAULT_STAT"..statIndex.."_TOOLTIP"];
  564. if (unit == "player") then
  565. local _, unitClass = UnitClass("player");
  566. unitClass = strupper(unitClass);
  567. local primaryStat, spec, role;
  568. spec = GetSpecialization();
  569. if (spec) then
  570. role = GetSpecializationRole(spec);
  571. primaryStat = select(6, GetSpecializationInfo(spec, nil, nil, nil, UnitSex("player")));
  572. end
  573. -- Strength
  574. if ( statIndex == LE_UNIT_STAT_STRENGTH ) then
  575. local attackPower = GetAttackPowerForStat(statIndex,effectiveStat);
  576. if (HasAPEffectsSpellPower()) then
  577. statFrame.tooltip2 = STAT_TOOLTIP_BONUS_AP_SP;
  578. end
  579. if (not primaryStat or primaryStat == LE_UNIT_STAT_STRENGTH) then
  580. statFrame.tooltip2 = format(statFrame.tooltip2, BreakUpLargeNumbers(attackPower));
  581. if ( role == "TANK" ) then
  582. local increasedParryChance = GetParryChanceFromAttribute();
  583. if ( increasedParryChance > 0 ) then
  584. statFrame.tooltip2 = statFrame.tooltip2.."|n|n"..format(CR_PARRY_BASE_STAT_TOOLTIP, increasedParryChance);
  585. end
  586. end
  587. else
  588. statFrame.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
  589. end
  590. -- Agility
  591. elseif ( statIndex == LE_UNIT_STAT_AGILITY ) then
  592. local attackPower = GetAttackPowerForStat(statIndex,effectiveStat);
  593. local tooltip = STAT_TOOLTIP_BONUS_AP;
  594. if (HasAPEffectsSpellPower()) then
  595. tooltip = STAT_TOOLTIP_BONUS_AP_SP;
  596. end
  597. if (not primaryStat or primaryStat == LE_UNIT_STAT_AGILITY) then
  598. statFrame.tooltip2 = format(tooltip, BreakUpLargeNumbers(attackPower));
  599. if ( role == "TANK" ) then
  600. local increasedDodgeChance = GetDodgeChanceFromAttribute();
  601. if ( increasedDodgeChance > 0 ) then
  602. statFrame.tooltip2 = statFrame.tooltip2.."|n|n"..format(CR_DODGE_BASE_STAT_TOOLTIP, increasedDodgeChance);
  603. end
  604. end
  605. else
  606. statFrame.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
  607. end
  608. -- Stamina
  609. elseif ( statIndex == LE_UNIT_STAT_STAMINA ) then
  610. statFrame.tooltip2 = format(statFrame.tooltip2, BreakUpLargeNumbers(((effectiveStat*UnitHPPerStamina("player")))*GetUnitMaxHealthModifier("player")));
  611. -- Intellect
  612. elseif ( statIndex == LE_UNIT_STAT_INTELLECT ) then
  613. if ( UnitHasMana("player") ) then
  614. if (HasAPEffectsSpellPower()) then
  615. statFrame.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
  616. else
  617. local result, druid = HasSPEffectsAttackPower();
  618. if (result and druid) then
  619. statFrame.tooltip2 = format(STAT_TOOLTIP_SP_AP_DRUID, max(0, effectiveStat), max(0, effectiveStat));
  620. elseif (result) then
  621. statFrame.tooltip2 = format(STAT_TOOLTIP_BONUS_AP_SP, max(0, effectiveStat));
  622. elseif (not primaryStat or primaryStat == LE_UNIT_STAT_INTELLECT) then
  623. statFrame.tooltip2 = format(statFrame.tooltip2, max(0, effectiveStat));
  624. else
  625. statFrame.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
  626. end
  627. end
  628. else
  629. statFrame.tooltip2 = STAT_NO_BENEFIT_TOOLTIP;
  630. end
  631. end
  632. end
  633. statFrame:Show();
  634. end
  635. function PaperDollFrame_SetArmor(statFrame, unit)
  636. local baselineArmor, effectiveArmor, armor, bonusArmor = UnitArmor(unit);
  637. PaperDollFrame_SetLabelAndText(statFrame, STAT_ARMOR, BreakUpLargeNumbers(effectiveArmor), false, effectiveArmor);
  638. local armorReduction = PaperDollFrame_GetArmorReduction(effectiveArmor, UnitEffectiveLevel(unit));
  639. local armorReductionAgainstTarget = PaperDollFrame_GetArmorReductionAgainstTarget(effectiveArmor);
  640. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ARMOR).." "..BreakUpLargeNumbers(effectiveArmor)..FONT_COLOR_CODE_CLOSE;
  641. statFrame.tooltip2 = format(STAT_ARMOR_TOOLTIP, armorReduction);
  642. if (armorReductionAgainstTarget) then
  643. statFrame.tooltip3 = format(STAT_ARMOR_TARGET_TOOLTIP, armorReductionAgainstTarget);
  644. else
  645. statFrame.tooltip3 = nil;
  646. end
  647. statFrame:Show();
  648. end
  649. function PaperDollFrame_SetStagger(statFrame, unit)
  650. local stagger, staggerAgainstTarget = C_PaperDollInfo.GetStaggerPercentage(unit);
  651. PaperDollFrame_SetLabelAndText(statFrame, STAT_STAGGER, BreakUpLargeNumbers(stagger), true, stagger);
  652. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAGGER).." "..string.format("%.2F%%",stagger)..FONT_COLOR_CODE_CLOSE;
  653. statFrame.tooltip2 = format(STAT_STAGGER_TOOLTIP, stagger);
  654. if (staggerAgainstTarget) then
  655. statFrame.tooltip3 = format(STAT_STAGGER_TARGET_TOOLTIP, staggerAgainstTarget);
  656. else
  657. statFrame.tooltip3 = nil;
  658. end
  659. statFrame:Show();
  660. end
  661. function PaperDollFrame_SetDodge(statFrame, unit)
  662. if (unit ~= "player") then
  663. statFrame:Hide();
  664. return;
  665. end
  666. local chance = GetDodgeChance();
  667. PaperDollFrame_SetLabelAndText(statFrame, STAT_DODGE, chance, true, chance);
  668. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, DODGE_CHANCE).." "..string.format("%.2F", chance).."%"..FONT_COLOR_CODE_CLOSE;
  669. statFrame.tooltip2 = format(CR_DODGE_TOOLTIP, GetCombatRating(CR_DODGE), GetCombatRatingBonus(CR_DODGE));
  670. statFrame:Show();
  671. end
  672. function PaperDollFrame_SetBlock(statFrame, unit)
  673. if (unit ~= "player") then
  674. statFrame:Hide();
  675. return;
  676. end
  677. local chance = GetBlockChance();
  678. PaperDollFrame_SetLabelAndText(statFrame, STAT_BLOCK, chance, true, chance);
  679. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, BLOCK_CHANCE).." "..string.format("%.2F", chance).."%"..FONT_COLOR_CODE_CLOSE;
  680. local shieldBlockArmor = GetShieldBlock();
  681. local blockArmorReduction = PaperDollFrame_GetArmorReduction(shieldBlockArmor, UnitEffectiveLevel(unit));
  682. local blockArmorReductionAgainstTarget = PaperDollFrame_GetArmorReductionAgainstTarget(shieldBlockArmor);
  683. statFrame.tooltip2 = CR_BLOCK_TOOLTIP:format(blockArmorReduction);
  684. if (blockArmorReductionAgainstTarget) then
  685. statFrame.tooltip3 = format(STAT_BLOCK_TARGET_TOOLTIP, blockArmorReductionAgainstTarget);
  686. else
  687. statFrame.tooltip3 = nil;
  688. end
  689. statFrame:Show();
  690. end
  691. function PaperDollFrame_SetParry(statFrame, unit)
  692. if (unit ~= "player") then
  693. statFrame:Hide();
  694. return;
  695. end
  696. local chance = GetParryChance();
  697. PaperDollFrame_SetLabelAndText(statFrame, STAT_PARRY, chance, true, chance);
  698. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, PARRY_CHANCE).." "..string.format("%.2F", chance).."%"..FONT_COLOR_CODE_CLOSE;
  699. statFrame.tooltip2 = format(CR_PARRY_TOOLTIP, GetCombatRating(CR_PARRY), GetCombatRatingBonus(CR_PARRY));
  700. statFrame:Show();
  701. end
  702. function PaperDollFrame_SetResilience(statFrame, unit)
  703. if (unit ~= "player") then
  704. statFrame:Hide();
  705. return;
  706. end
  707. local resilienceRating = BreakUpLargeNumbers(GetCombatRating(COMBAT_RATING_RESILIENCE_PLAYER_DAMAGE_TAKEN));
  708. local ratingBonus = GetCombatRatingBonus(COMBAT_RATING_RESILIENCE_PLAYER_DAMAGE_TAKEN);
  709. local damageReduction = ratingBonus + GetModResilienceDamageReduction();
  710. PaperDollFrame_SetLabelAndText(statFrame, STAT_RESILIENCE, damageReduction, true, damageReduction);
  711. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_RESILIENCE).." "..format("%.2F%%", damageReduction)..FONT_COLOR_CODE_CLOSE;
  712. statFrame.tooltip2 = RESILIENCE_TOOLTIP .. format(STAT_RESILIENCE_BASE_TOOLTIP, resilienceRating,
  713. ratingBonus);
  714. statFrame:Show();
  715. end
  716. local function GetAppropriateDamage(unit)
  717. if IsRangedWeapon() then
  718. local attackTime, minDamage, maxDamage, bonusPos, bonusNeg, percent = UnitRangedDamage(unit);
  719. return minDamage, maxDamage, nil, nil, 0, 0, percent;
  720. else
  721. return UnitDamage(unit);
  722. end
  723. end
  724. function PaperDollFrame_SetDamage(statFrame, unit)
  725. local speed, offhandSpeed = UnitAttackSpeed(unit);
  726. local minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent = GetAppropriateDamage(unit);
  727. -- remove decimal points for display values
  728. local displayMin = max(floor(minDamage),1);
  729. local displayMinLarge = BreakUpLargeNumbers(displayMin);
  730. local displayMax = max(ceil(maxDamage),1);
  731. local displayMaxLarge = BreakUpLargeNumbers(displayMax);
  732. -- calculate base damage
  733. minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg;
  734. maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg;
  735. local baseDamage = (minDamage + maxDamage) * 0.5;
  736. local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent;
  737. local totalBonus = (fullDamage - baseDamage);
  738. -- set tooltip text with base damage
  739. local damageTooltip = BreakUpLargeNumbers(max(floor(minDamage),1)).." - "..BreakUpLargeNumbers(max(ceil(maxDamage),1));
  740. local colorPos = "|cff20ff20";
  741. local colorNeg = "|cffff2020";
  742. -- epsilon check
  743. if ( totalBonus < 0.1 and totalBonus > -0.1 ) then
  744. totalBonus = 0.0;
  745. end
  746. local value;
  747. if ( totalBonus == 0 ) then
  748. if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then
  749. value = displayMinLarge.." - "..displayMaxLarge;
  750. else
  751. value = displayMinLarge.."-"..displayMaxLarge;
  752. end
  753. else
  754. -- set bonus color and display
  755. local color;
  756. if ( totalBonus > 0 ) then
  757. color = colorPos;
  758. else
  759. color = colorNeg;
  760. end
  761. if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then
  762. value = color..displayMinLarge.." - "..displayMaxLarge.."|r";
  763. else
  764. value = color..displayMinLarge.."-"..displayMaxLarge.."|r";
  765. end
  766. if ( physicalBonusPos > 0 ) then
  767. damageTooltip = damageTooltip..colorPos.." +"..physicalBonusPos.."|r";
  768. end
  769. if ( physicalBonusNeg < 0 ) then
  770. damageTooltip = damageTooltip..colorNeg.." "..physicalBonusNeg.."|r";
  771. end
  772. if ( percent > 1 ) then
  773. damageTooltip = damageTooltip..colorPos.." x"..floor(percent*100+0.5).."%|r";
  774. elseif ( percent < 1 ) then
  775. damageTooltip = damageTooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r";
  776. end
  777. end
  778. PaperDollFrame_SetLabelAndText(statFrame, DAMAGE, value, false, displayMax);
  779. statFrame.damage = damageTooltip;
  780. statFrame.attackSpeed = speed;
  781. statFrame.unit = unit;
  782. -- If there's an offhand speed then add the offhand info to the tooltip
  783. if ( offhandSpeed and minOffHandDamage and maxOffHandDamage ) then
  784. minOffHandDamage = (minOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg;
  785. maxOffHandDamage = (maxOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg;
  786. local offhandBaseDamage = (minOffHandDamage + maxOffHandDamage) * 0.5;
  787. local offhandFullDamage = (offhandBaseDamage + physicalBonusPos + physicalBonusNeg) * percent;
  788. local offhandDamageTooltip = BreakUpLargeNumbers(max(floor(minOffHandDamage),1)).." - "..BreakUpLargeNumbers(max(ceil(maxOffHandDamage),1));
  789. if ( physicalBonusPos > 0 ) then
  790. offhandDamageTooltip = offhandDamageTooltip..colorPos.." +"..physicalBonusPos.."|r";
  791. end
  792. if ( physicalBonusNeg < 0 ) then
  793. offhandDamageTooltip = offhandDamageTooltip..colorNeg.." "..physicalBonusNeg.."|r";
  794. end
  795. if ( percent > 1 ) then
  796. offhandDamageTooltip = offhandDamageTooltip..colorPos.." x"..floor(percent*100+0.5).."%|r";
  797. elseif ( percent < 1 ) then
  798. offhandDamageTooltip = offhandDamageTooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r";
  799. end
  800. statFrame.offhandDamage = offhandDamageTooltip;
  801. statFrame.offhandAttackSpeed = offhandSpeed;
  802. else
  803. statFrame.offhandAttackSpeed = nil;
  804. end
  805. statFrame.onEnterFunc = CharacterDamageFrame_OnEnter;
  806. statFrame:Show();
  807. end
  808. function PaperDollFrame_SetAttackSpeed(statFrame, unit)
  809. local meleeHaste = GetMeleeHaste();
  810. local speed, offhandSpeed = UnitAttackSpeed(unit);
  811. local displaySpeed = format("%.2F", speed);
  812. if ( offhandSpeed ) then
  813. offhandSpeed = format("%.2F", offhandSpeed);
  814. end
  815. if ( offhandSpeed ) then
  816. displaySpeed = BreakUpLargeNumbers(displaySpeed).." / ".. offhandSpeed;
  817. else
  818. displaySpeed = BreakUpLargeNumbers(displaySpeed);
  819. end
  820. PaperDollFrame_SetLabelAndText(statFrame, WEAPON_SPEED, displaySpeed, false, speed);
  821. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ATTACK_SPEED).." "..displaySpeed..FONT_COLOR_CODE_CLOSE;
  822. statFrame.tooltip2 = format(STAT_ATTACK_SPEED_BASE_TOOLTIP, BreakUpLargeNumbers(meleeHaste));
  823. statFrame:Show();
  824. end
  825. function PaperDollFrame_SetAttackPower(statFrame, unit)
  826. local base, posBuff, negBuff;
  827. local rangedWeapon = IsRangedWeapon();
  828. local tag, tooltip;
  829. if ( rangedWeapon ) then
  830. base, posBuff, negBuff = UnitRangedAttackPower(unit);
  831. tag, tooltip = RANGED_ATTACK_POWER, RANGED_ATTACK_POWER_TOOLTIP;
  832. else
  833. base, posBuff, negBuff = UnitAttackPower(unit);
  834. tag, tooltip = MELEE_ATTACK_POWER, MELEE_ATTACK_POWER_TOOLTIP;
  835. end
  836. local damageBonus = BreakUpLargeNumbers(max((base+posBuff+negBuff), 0)/ATTACK_POWER_MAGIC_NUMBER);
  837. local spellPower = 0;
  838. local value, valueText, tooltipText;
  839. if (GetOverrideAPBySpellPower() ~= nil) then
  840. local holySchool = 2;
  841. -- Start at 2 to skip physical damage
  842. spellPower = GetSpellBonusDamage(holySchool);
  843. for i=(holySchool+1), MAX_SPELL_SCHOOLS do
  844. spellPower = min(spellPower, GetSpellBonusDamage(i));
  845. end
  846. spellPower = min(spellPower, GetSpellBonusHealing()) * GetOverrideAPBySpellPower();
  847. value = spellPower;
  848. valueText, tooltipText = PaperDollFormatStat(tag, spellPower, 0, 0);
  849. damageBonus = BreakUpLargeNumbers(spellPower / ATTACK_POWER_MAGIC_NUMBER);
  850. else
  851. value = base;
  852. valueText, tooltipText = PaperDollFormatStat(tag, base, posBuff, negBuff);
  853. end
  854. PaperDollFrame_SetLabelAndText(statFrame, STAT_ATTACK_POWER, valueText, false, value);
  855. statFrame.tooltip = tooltipText;
  856. local effectiveAP = max(0,base + posBuff + negBuff);
  857. if (GetOverrideSpellPowerByAP() ~= nil) then
  858. statFrame.tooltip2 = format(MELEE_ATTACK_POWER_SPELL_POWER_TOOLTIP, damageBonus, BreakUpLargeNumbers(effectiveAP * GetOverrideSpellPowerByAP() + 0.5));
  859. else
  860. statFrame.tooltip2 = format(tooltip, damageBonus);
  861. end
  862. statFrame:Show();
  863. end
  864. function PaperDollFrame_SetSpellPower(statFrame, unit)
  865. local minModifier = 0;
  866. if (unit == "player") then
  867. local holySchool = 2;
  868. -- Start at 2 to skip physical damage
  869. minModifier = GetSpellBonusDamage(holySchool);
  870. if (statFrame.bonusDamage) then
  871. table.wipe(statFrame.bonusDamage);
  872. else
  873. statFrame.bonusDamage = {};
  874. end
  875. statFrame.bonusDamage[holySchool] = minModifier;
  876. for i=(holySchool+1), MAX_SPELL_SCHOOLS do
  877. local bonusDamage = GetSpellBonusDamage(i);
  878. minModifier = min(minModifier, bonusDamage);
  879. statFrame.bonusDamage[i] = bonusDamage;
  880. end
  881. elseif (unit == "pet") then
  882. minModifier = GetPetSpellBonusDamage();
  883. statFrame.bonusDamage = nil;
  884. end
  885. PaperDollFrame_SetLabelAndText(statFrame, STAT_SPELLPOWER, BreakUpLargeNumbers(minModifier), false, minModifier);
  886. statFrame.tooltip = STAT_SPELLPOWER;
  887. statFrame.tooltip2 = STAT_SPELLPOWER_TOOLTIP;
  888. statFrame.minModifier = minModifier;
  889. statFrame.unit = unit;
  890. statFrame.onEnterFunc = CharacterSpellBonusDamage_OnEnter;
  891. statFrame:Show();
  892. end
  893. function PaperDollFrame_SetCritChance(statFrame, unit)
  894. if ( unit ~= "player" ) then
  895. statFrame:Hide();
  896. return;
  897. end
  898. local rating;
  899. local spellCrit, rangedCrit, meleeCrit;
  900. local critChance;
  901. -- Start at 2 to skip physical damage
  902. local holySchool = 2;
  903. local minCrit = GetSpellCritChance(holySchool);
  904. statFrame.spellCrit = {};
  905. statFrame.spellCrit[holySchool] = minCrit;
  906. local spellCrit;
  907. for i=(holySchool+1), MAX_SPELL_SCHOOLS do
  908. spellCrit = GetSpellCritChance(i);
  909. minCrit = min(minCrit, spellCrit);
  910. statFrame.spellCrit[i] = spellCrit;
  911. end
  912. spellCrit = minCrit
  913. rangedCrit = GetRangedCritChance();
  914. meleeCrit = GetCritChance();
  915. if (spellCrit >= rangedCrit and spellCrit >= meleeCrit) then
  916. critChance = spellCrit;
  917. rating = CR_CRIT_SPELL;
  918. elseif (rangedCrit >= meleeCrit) then
  919. critChance = rangedCrit;
  920. rating = CR_CRIT_RANGED;
  921. else
  922. critChance = meleeCrit;
  923. rating = CR_CRIT_MELEE;
  924. end
  925. PaperDollFrame_SetLabelAndText(statFrame, STAT_CRITICAL_STRIKE, critChance, true, critChance);
  926. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_CRITICAL_STRIKE)..FONT_COLOR_CODE_CLOSE;
  927. local extraCritChance = GetCombatRatingBonus(rating);
  928. local extraCritRating = GetCombatRating(rating);
  929. if (GetCritChanceProvidesParryEffect()) then
  930. statFrame.tooltip2 = format(CR_CRIT_PARRY_RATING_TOOLTIP, BreakUpLargeNumbers(extraCritRating), extraCritChance, GetCombatRatingBonusForCombatRatingValue(CR_PARRY, extraCritRating));
  931. else
  932. statFrame.tooltip2 = format(CR_CRIT_TOOLTIP, BreakUpLargeNumbers(extraCritRating), extraCritChance);
  933. end
  934. statFrame:Show();
  935. end
  936. function PaperDollFrame_SetEnergyRegen(statFrame, unit)
  937. if ( unit ~= "player" ) then
  938. statFrame:Hide();
  939. return;
  940. end
  941. local powerType, powerToken = UnitPowerType(unit);
  942. if (powerToken ~= "ENERGY") then
  943. statFrame:Hide();
  944. return;
  945. end
  946. local regenRate = GetPowerRegen();
  947. local regenRateText = BreakUpLargeNumbers(regenRate);
  948. PaperDollFrame_SetLabelAndText(statFrame, STAT_ENERGY_REGEN, regenRateText, false, regenRate);
  949. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_ENERGY_REGEN).." "..regenRateText..FONT_COLOR_CODE_CLOSE;
  950. statFrame.tooltip2 = STAT_ENERGY_REGEN_TOOLTIP;
  951. statFrame:Show();
  952. end
  953. function PaperDollFrame_SetFocusRegen(statFrame, unit)
  954. if ( unit ~= "player" ) then
  955. statFrame:Hide();
  956. return;
  957. end
  958. local powerType, powerToken = UnitPowerType(unit);
  959. if (powerToken ~= "FOCUS") then
  960. statFrame:Hide();
  961. return;
  962. end
  963. local regenRate = GetPowerRegen();
  964. local regenRateText = BreakUpLargeNumbers(regenRate);
  965. PaperDollFrame_SetLabelAndText(statFrame, STAT_FOCUS_REGEN, regenRateText, false, regenRate);
  966. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_FOCUS_REGEN).." "..regenRateText..FONT_COLOR_CODE_CLOSE;
  967. statFrame.tooltip2 = STAT_FOCUS_REGEN_TOOLTIP;
  968. statFrame:Show();
  969. end
  970. function PaperDollFrame_SetRuneRegen(statFrame, unit)
  971. if ( unit ~= "player" ) then
  972. statFrame:Hide();
  973. return;
  974. end
  975. local _, class = UnitClass(unit);
  976. if (class ~= "DEATHKNIGHT") then
  977. statFrame:Hide();
  978. return;
  979. end
  980. local _, regenRate = GetRuneCooldown(1); -- Assuming they are all the same for now
  981. local regenRateText = (format(STAT_RUNE_REGEN_FORMAT, regenRate));
  982. PaperDollFrame_SetLabelAndText(statFrame, STAT_RUNE_REGEN, regenRateText, false, regenRate);
  983. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_RUNE_REGEN).." "..regenRateText..FONT_COLOR_CODE_CLOSE;
  984. statFrame.tooltip2 = STAT_RUNE_REGEN_TOOLTIP;
  985. statFrame:Show();
  986. end
  987. function PaperDollFrame_SetHaste(statFrame, unit)
  988. if ( unit ~= "player" ) then
  989. statFrame:Hide();
  990. return;
  991. end
  992. local haste = GetHaste();
  993. local rating = CR_HASTE_MELEE;
  994. local hasteFormatString;
  995. if (haste < 0 and not GetPVPGearStatRules()) then
  996. hasteFormatString = RED_FONT_COLOR_CODE.."%s"..FONT_COLOR_CODE_CLOSE;
  997. else
  998. hasteFormatString = "%s";
  999. end
  1000. PaperDollFrame_SetLabelAndText(statFrame, STAT_HASTE, format(hasteFormatString, format("%d%%", haste + 0.5)), false, haste);
  1001. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_HASTE)..FONT_COLOR_CODE_CLOSE;
  1002. local _, class = UnitClass(unit);
  1003. statFrame.tooltip2 = _G["STAT_HASTE_"..class.."_TOOLTIP"];
  1004. if (not statFrame.tooltip2) then
  1005. statFrame.tooltip2 = STAT_HASTE_TOOLTIP;
  1006. end
  1007. statFrame.tooltip2 = statFrame.tooltip2 .. format(STAT_HASTE_BASE_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(rating)), GetCombatRatingBonus(rating));
  1008. statFrame:Show();
  1009. end
  1010. function PaperDollFrame_SetManaRegen(statFrame, unit)
  1011. if ( unit ~= "player" ) then
  1012. statFrame:Hide();
  1013. return;
  1014. end
  1015. if ( not UnitHasMana("player") ) then
  1016. PaperDollFrame_SetLabelAndText(statFrame, MANA_REGEN, NOT_APPLICABLE, false, 0);
  1017. statFrame.tooltip = nil;
  1018. return;
  1019. end
  1020. local base, combat = GetManaRegen();
  1021. -- All mana regen stats are displayed as mana/5 sec.
  1022. base = floor(base * 5.0);
  1023. combat = floor(combat * 5.0);
  1024. local baseText = BreakUpLargeNumbers(base);
  1025. local combatText = BreakUpLargeNumbers(combat);
  1026. -- Combat mana regen is most important to the player, so we display it as the main value
  1027. PaperDollFrame_SetLabelAndText(statFrame, MANA_REGEN, combatText, false, combat);
  1028. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. format(PAPERDOLLFRAME_TOOLTIP_FORMAT, MANA_REGEN) .. " " .. combatText .. FONT_COLOR_CODE_CLOSE;
  1029. -- Base (out of combat) regen is displayed only in the subtext of the tooltip
  1030. statFrame.tooltip2 = format(MANA_REGEN_TOOLTIP, baseText);
  1031. statFrame:Show();
  1032. end
  1033. function Mastery_OnEnter(statFrame)
  1034. GameTooltip:SetOwner(statFrame, "ANCHOR_RIGHT");
  1035. local _, class = UnitClass("player");
  1036. local mastery, bonusCoeff = GetMasteryEffect();
  1037. local masteryBonus = GetCombatRatingBonus(CR_MASTERY) * bonusCoeff;
  1038. local primaryTalentTree = GetSpecialization();
  1039. if (primaryTalentTree) then
  1040. local masterySpell, masterySpell2 = GetSpecializationMasterySpells(primaryTalentTree);
  1041. if (masterySpell) then
  1042. GameTooltip:AddSpellByID(masterySpell);
  1043. end
  1044. if (masterySpell2) then
  1045. GameTooltip:AddLine(" ");
  1046. GameTooltip:AddSpellByID(masterySpell2);
  1047. end
  1048. GameTooltip:AddLine(" ");
  1049. GameTooltip:AddLine(format(STAT_MASTERY_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_MASTERY)), masteryBonus), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true);
  1050. else
  1051. GameTooltip:AddLine(format(STAT_MASTERY_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_MASTERY)), masteryBonus), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true);
  1052. GameTooltip:AddLine(" ");
  1053. GameTooltip:AddLine(STAT_MASTERY_TOOLTIP_NO_TALENT_SPEC, GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b, true);
  1054. end
  1055. statFrame.UpdateTooltip = statFrame.onEnterFunc;
  1056. GameTooltip:Show();
  1057. end
  1058. function PaperDollFrame_SetMastery(statFrame, unit)
  1059. if ( unit ~= "player" ) then
  1060. statFrame:Hide();
  1061. return;
  1062. end
  1063. local mastery = GetMasteryEffect();
  1064. PaperDollFrame_SetLabelAndText(statFrame, STAT_MASTERY, mastery, true, mastery);
  1065. statFrame.onEnterFunc = Mastery_OnEnter;
  1066. statFrame:Show();
  1067. end
  1068. -- Task 68016: Speed increases run speed
  1069. function PaperDollFrame_SetSpeed(statFrame, unit)
  1070. if ( unit ~= "player" ) then
  1071. statFrame:Hide();
  1072. return;
  1073. end
  1074. local speed = GetSpeed();
  1075. PaperDollFrame_SetLabelAndText(statFrame, STAT_SPEED, speed, true, speed);
  1076. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_SPEED) .. " " .. format("%.2F%%", speed) .. FONT_COLOR_CODE_CLOSE;
  1077. statFrame.tooltip2 = format(CR_SPEED_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_SPEED)), GetCombatRatingBonus(CR_SPEED));
  1078. statFrame:Show();
  1079. end
  1080. -- Task 68016: Lifesteal returns a portion of all damage done as health
  1081. function PaperDollFrame_SetLifesteal(statFrame, unit)
  1082. if ( unit ~= "player" ) then
  1083. statFrame:Hide();
  1084. return;
  1085. end
  1086. local lifesteal = GetLifesteal();
  1087. PaperDollFrame_SetLabelAndText(statFrame, STAT_LIFESTEAL, lifesteal, true, lifesteal);
  1088. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_LIFESTEAL) .. " " .. format("%.2F%%", lifesteal) .. FONT_COLOR_CODE_CLOSE;
  1089. statFrame.tooltip2 = format(CR_LIFESTEAL_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_LIFESTEAL)), GetCombatRatingBonus(CR_LIFESTEAL));
  1090. statFrame:Show();
  1091. end
  1092. -- Task 68016: Avoidance reduces AoE damage taken
  1093. function PaperDollFrame_SetAvoidance(statFrame, unit)
  1094. if ( unit ~= "player" ) then
  1095. statFrame:Hide();
  1096. return;
  1097. end
  1098. local avoidance = GetAvoidance();
  1099. PaperDollFrame_SetLabelAndText(statFrame, STAT_AVOIDANCE, avoidance, true, avoidance);
  1100. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_AVOIDANCE) .. " " .. format("%.2F%%", avoidance) .. FONT_COLOR_CODE_CLOSE;
  1101. statFrame.tooltip2 = format(CR_AVOIDANCE_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_AVOIDANCE)), GetCombatRatingBonus(CR_AVOIDANCE));
  1102. statFrame:Show();
  1103. end
  1104. function PaperDollFrame_SetVersatility(statFrame, unit)
  1105. if ( unit ~= "player" ) then
  1106. statFrame:Hide();
  1107. return;
  1108. end
  1109. local versatility = GetCombatRating(CR_VERSATILITY_DAMAGE_DONE);
  1110. local versatilityDamageBonus = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_DONE);
  1111. local versatilityDamageTakenReduction = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_TAKEN) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_TAKEN);
  1112. PaperDollFrame_SetLabelAndText(statFrame, STAT_VERSATILITY, versatilityDamageBonus, true, versatilityDamageBonus);
  1113. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_VERSATILITY)..FONT_COLOR_CODE_CLOSE;
  1114. statFrame.tooltip2 = format(CR_VERSATILITY_TOOLTIP, versatilityDamageBonus, versatilityDamageTakenReduction, BreakUpLargeNumbers(versatility), versatilityDamageBonus, versatilityDamageTakenReduction);
  1115. statFrame:Show();
  1116. end
  1117. function PaperDollFrame_SetItemLevel(statFrame, unit)
  1118. if ( unit ~= "player" ) then
  1119. statFrame:Hide();
  1120. return;
  1121. end
  1122. local avgItemLevel, avgItemLevelEquipped = GetAverageItemLevel();
  1123. local minItemLevel = C_PaperDollInfo.GetMinItemLevel();
  1124. local displayItemLevel = math.max(minItemLevel or 0, avgItemLevelEquipped);
  1125. displayItemLevel = floor(displayItemLevel);
  1126. avgItemLevel = floor(avgItemLevel);
  1127. PaperDollFrame_SetLabelAndText(statFrame, STAT_AVERAGE_ITEM_LEVEL, displayItemLevel, false, displayItemLevel);
  1128. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_AVERAGE_ITEM_LEVEL).." "..avgItemLevel;
  1129. if ( displayItemLevel ~= avgItemLevel ) then
  1130. statFrame.tooltip = statFrame.tooltip .. " " .. format(STAT_AVERAGE_ITEM_LEVEL_EQUIPPED, avgItemLevelEquipped);
  1131. end
  1132. statFrame.tooltip = statFrame.tooltip .. FONT_COLOR_CODE_CLOSE;
  1133. statFrame.tooltip2 = STAT_AVERAGE_ITEM_LEVEL_TOOLTIP;
  1134. end
  1135. function MovementSpeed_OnEnter(statFrame)
  1136. GameTooltip:SetOwner(statFrame, "ANCHOR_RIGHT");
  1137. GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_MOVEMENT_SPEED).." "..format("%d%%", statFrame.speed+0.5)..FONT_COLOR_CODE_CLOSE);
  1138. GameTooltip:AddLine(format(STAT_MOVEMENT_GROUND_TOOLTIP, statFrame.runSpeed+0.5));
  1139. if (statFrame.unit ~= "pet") then
  1140. GameTooltip:AddLine(format(STAT_MOVEMENT_FLIGHT_TOOLTIP, statFrame.flightSpeed+0.5));
  1141. end
  1142. GameTooltip:AddLine(format(STAT_MOVEMENT_SWIM_TOOLTIP, statFrame.swimSpeed+0.5));
  1143. GameTooltip:AddLine(" ");
  1144. GameTooltip:AddLine(format(CR_SPEED_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_SPEED)), GetCombatRatingBonus(CR_SPEED)));
  1145. GameTooltip:Show();
  1146. statFrame.UpdateTooltip = MovementSpeed_OnEnter;
  1147. end
  1148. function MovementSpeed_OnUpdate(statFrame, elapsedTime)
  1149. local unit = statFrame.unit;
  1150. local _, runSpeed, flightSpeed, swimSpeed = GetUnitSpeed(unit);
  1151. runSpeed = runSpeed/BASE_MOVEMENT_SPEED*100;
  1152. flightSpeed = flightSpeed/BASE_MOVEMENT_SPEED*100;
  1153. swimSpeed = swimSpeed/BASE_MOVEMENT_SPEED*100;
  1154. -- Pets seem to always actually use run speed
  1155. if (unit == "pet") then
  1156. swimSpeed = runSpeed;
  1157. end
  1158. -- Determine whether to display running, flying, or swimming speed
  1159. local speed = runSpeed;
  1160. local swimming = IsSwimming(unit);
  1161. if (swimming) then
  1162. speed = swimSpeed;
  1163. elseif (IsFlying(unit)) then
  1164. speed = flightSpeed;
  1165. end
  1166. -- Hack so that your speed doesn't appear to change when jumping out of the water
  1167. if (IsFalling(unit)) then
  1168. if (statFrame.wasSwimming) then
  1169. speed = swimSpeed;
  1170. end
  1171. else
  1172. statFrame.wasSwimming = swimming;
  1173. end
  1174. local valueText = format("%d%%", speed+0.5);
  1175. PaperDollFrame_SetLabelAndText(statFrame, STAT_MOVEMENT_SPEED, valueText, false, speed);
  1176. statFrame.speed = speed;
  1177. statFrame.runSpeed = runSpeed;
  1178. statFrame.flightSpeed = flightSpeed;
  1179. statFrame.swimSpeed = swimSpeed;
  1180. end
  1181. function PaperDollFrame_SetMovementSpeed(statFrame, unit)
  1182. if ( unit ~= "player" ) then
  1183. statFrame:Hide();
  1184. return;
  1185. end
  1186. statFrame.wasSwimming = nil;
  1187. statFrame.unit = unit;
  1188. statFrame:Show();
  1189. MovementSpeed_OnUpdate(statFrame);
  1190. statFrame.onEnterFunc = MovementSpeed_OnEnter;
  1191. end
  1192. function CharacterSpellBonusDamage_OnEnter(self)
  1193. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1194. GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, self.tooltip).." "..BreakUpLargeNumbers(self.minModifier)..FONT_COLOR_CODE_CLOSE);
  1195. for i=2, MAX_SPELL_SCHOOLS do
  1196. if (self.bonusDamage and self.bonusDamage[i] ~= self.minModifier) then
  1197. GameTooltip:AddLine(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, _G["DAMAGE_SCHOOL"..i]).." "..self.bonusDamage[i]..FONT_COLOR_CODE_CLOSE);
  1198. GameTooltip:AddTexture("Interface\\PaperDollInfoFrame\\SpellSchoolIcon"..i);
  1199. end
  1200. end
  1201. GameTooltip:AddLine(self.tooltip2);
  1202. if (self.bonusDamage and self.unit == "player") then
  1203. local petStr, damage;
  1204. if (self.bonusDamage[6] == self.minModifier and self.bonusDamage[3] == self.minModifier) then
  1205. petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG;
  1206. damage = self.minModifier;
  1207. elseif( self.bonusDamage[6] > self.bonusDamage[3] ) then
  1208. petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_SHADOW;
  1209. damage = self.bonusDamage[6];
  1210. else
  1211. petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_FIRE;
  1212. damage = self.bonusDamage[3];
  1213. end
  1214. local petBonusAP = ComputePetBonus("PET_BONUS_SPELLDMG_TO_AP", damage );
  1215. local petBonusDmg = ComputePetBonus("PET_BONUS_SPELLDMG_TO_SPELLDMG", damage );
  1216. if( petBonusAP > 0 or petBonusDmg > 0 ) then
  1217. GameTooltip:AddLine(format(petStr, petBonusAP, petBonusDmg), nil, nil, nil, true );
  1218. end
  1219. end
  1220. GameTooltip:Show();
  1221. end
  1222. function PaperDollFrame_OnShow(self)
  1223. CharacterStatsPane.initialOffsetY = 0;
  1224. CharacterFrame:SetTitle(UnitPVPName("player"));
  1225. PaperDollFrame_SetLevel();
  1226. PaperDollFrame_UpdateStats();
  1227. CharacterFrame_Expand();
  1228. SetPaperDollBackground(CharacterModelFrame, "player");
  1229. PaperDollBgDesaturate(true);
  1230. PaperDollSidebarTabs:Show();
  1231. end
  1232. function PaperDollFrame_OnHide(self)
  1233. CharacterStatsPane.initialOffsetY = 0;
  1234. CharacterFrame_Collapse();
  1235. PaperDollSidebarTabs:Hide();
  1236. PaperDollFrame_HideInventoryFixupComplete(self);
  1237. end
  1238. function PaperDollFrame_ClearIgnoredSlots()
  1239. C_EquipmentSet.ClearIgnoredSlotsForSave();
  1240. for k, button in next, itemSlotButtons do
  1241. if ( button.ignored ) then
  1242. button.ignored = nil;
  1243. PaperDollItemSlotButton_Update(button);
  1244. end
  1245. end
  1246. end
  1247. function PaperDollFrame_IgnoreSlotsForSet(setID)
  1248. local set = C_EquipmentSet.GetIgnoredSlots(setID);
  1249. for slot, ignored in pairs(set) do
  1250. if ( ignored ) then
  1251. C_EquipmentSet.IgnoreSlotForSave(slot);
  1252. itemSlotButtons[slot].ignored = true;
  1253. else
  1254. C_EquipmentSet.UnignoreSlotForSave(slot);
  1255. itemSlotButtons[slot].ignored = false;
  1256. end
  1257. PaperDollItemSlotButton_Update(itemSlotButtons[slot]);
  1258. end
  1259. end
  1260. function PaperDollFrame_IgnoreSlot(slot)
  1261. C_EquipmentSet.IgnoreSlotForSave(slot);
  1262. itemSlotButtons[slot].ignored = true;
  1263. PaperDollItemSlotButton_Update(itemSlotButtons[slot]);
  1264. end
  1265. function PaperDollFrame_UpdateCorruptedItemGlows(glow)
  1266. for _, button in next, itemSlotButtons do
  1267. if button.HasPaperDollAzeriteItemOverlay then
  1268. button:UpdateCorruptedGlow(ItemLocation:CreateFromEquipmentSlot(button:GetID()), glow);
  1269. end
  1270. end
  1271. end
  1272. function PaperDollItemSlotButton_OnLoad(self)
  1273. self:RegisterForDrag("LeftButton");
  1274. self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
  1275. local slotName = self:GetName();
  1276. local id, textureName, checkRelic = GetInventorySlotInfo(strsub(slotName,10));
  1277. self:SetID(id);
  1278. local texture = _G[slotName.."IconTexture"];
  1279. texture:SetTexture(textureName);
  1280. self.backgroundTextureName = textureName;
  1281. self.checkRelic = checkRelic;
  1282. self.UpdateTooltip = PaperDollItemSlotButton_OnEnter;
  1283. itemSlotButtons[id] = self;
  1284. self.verticalFlyout = VERTICAL_FLYOUTS[id];
  1285. local popoutButton = self.popoutButton;
  1286. if ( popoutButton ) then
  1287. if ( self.verticalFlyout ) then
  1288. popoutButton:SetHeight(16);
  1289. popoutButton:SetWidth(38);
  1290. popoutButton:GetNormalTexture():SetTexCoord(0.15625, 0.84375, 0.5, 0);
  1291. popoutButton:GetHighlightTexture():SetTexCoord(0.15625, 0.84375, 1, 0.5);
  1292. popoutButton:ClearAllPoints();
  1293. popoutButton:SetPoint("TOP", self, "BOTTOM", 0, 4);
  1294. else
  1295. popoutButton:SetHeight(38);
  1296. popoutButton:SetWidth(16);
  1297. popoutButton:GetNormalTexture():SetTexCoord(0.15625, 0.5, 0.84375, 0.5, 0.15625, 0, 0.84375, 0);
  1298. popoutButton:GetHighlightTexture():SetTexCoord(0.15625, 1, 0.84375, 1, 0.15625, 0.5, 0.84375, 0.5);
  1299. popoutButton:ClearAllPoints();
  1300. popoutButton:SetPoint("LEFT", self, "RIGHT", -8, 0);
  1301. end
  1302. end
  1303. end
  1304. local PAPERDOLL_FRAME_EVENTS = {
  1305. "PLAYER_EQUIPMENT_CHANGED",
  1306. "MERCHANT_UPDATE",
  1307. "PLAYERBANKSLOTS_CHANGED",
  1308. "ITEM_LOCK_CHANGED",
  1309. "CURSOR_UPDATE",
  1310. "UPDATE_INVENTORY_ALERTS",
  1311. "AZERITE_ITEM_POWER_LEVEL_CHANGED",
  1312. "AZERITE_EMPOWERED_ITEM_SELECTION_UPDATED",
  1313. };
  1314. function PaperDollItemSlotButton_OnShow(self, isBag)
  1315. FrameUtil.RegisterFrameForEvents(self, PAPERDOLL_FRAME_EVENTS);
  1316. if ( not isBag ) then
  1317. self:RegisterEvent("BAG_UPDATE_COOLDOWN");
  1318. end
  1319. PaperDollItemSlotButton_Update(self);
  1320. end
  1321. function PaperDollItemSlotButton_OnHide(self)
  1322. FrameUtil.UnregisterFrameForEvents(self, PAPERDOLL_FRAME_EVENTS);
  1323. self:UnregisterEvent("BAG_UPDATE_COOLDOWN");
  1324. end
  1325. function PaperDollItemSlotButton_OnEvent(self, event, ...)
  1326. if ( event == "PLAYER_EQUIPMENT_CHANGED" ) then
  1327. local equipmentSlot, hasCurrent = ...;
  1328. if ( self:GetID() == equipmentSlot ) then
  1329. PaperDollItemSlotButton_Update(self);
  1330. end
  1331. elseif ( event == "ITEM_LOCK_CHANGED" ) then
  1332. local bagOrSlotIndex, slotIndex = ...;
  1333. if ( not slotIndex and bagOrSlotIndex == self:GetID() ) then
  1334. PaperDollItemSlotButton_UpdateLock(self);
  1335. end
  1336. elseif ( event == "BAG_UPDATE_COOLDOWN" ) then
  1337. PaperDollItemSlotButton_Update(self);
  1338. elseif ( event == "CURSOR_UPDATE" ) then
  1339. if ( CursorCanGoInSlot(self:GetID()) ) then
  1340. self:LockHighlight();
  1341. else
  1342. self:UnlockHighlight();
  1343. end
  1344. elseif ( event == "UPDATE_INVENTORY_ALERTS" ) then
  1345. PaperDollItemSlotButton_Update(self);
  1346. elseif ( event == "MODIFIER_STATE_CHANGED" ) then
  1347. if ( IsModifiedClick("SHOWITEMFLYOUT") and self:IsMouseOver() ) then
  1348. PaperDollItemSlotButton_OnEnter(self);
  1349. end
  1350. elseif event == "AZERITE_ITEM_POWER_LEVEL_CHANGED" then
  1351. local azeriteItemLocation, oldPowerLevel, newPowerLevel = ...;
  1352. if azeriteItemLocation:IsEqualToEquipmentSlot(self:GetID()) then
  1353. PaperDollItemSlotButton_Update(self);
  1354. end
  1355. elseif event == "AZERITE_EMPOWERED_ITEM_SELECTION_UPDATED" then
  1356. local item = ...;
  1357. PaperDollItemSlotButton_Update(self);
  1358. end
  1359. end
  1360. function PaperDollItemSlotButton_OnClick(self, button)
  1361. MerchantFrame_ResetRefundItem();
  1362. if ( button == "LeftButton" ) then
  1363. local type = GetCursorInfo();
  1364. if ( type == "merchant" and MerchantFrame.extendedCost ) then
  1365. MerchantFrame_ConfirmExtendedItemCost(MerchantFrame.extendedCost);
  1366. else
  1367. PickupInventoryItem(self:GetID());
  1368. if ( CursorHasItem() ) then
  1369. MerchantFrame_SetRefundItem(self, 1);
  1370. end
  1371. end
  1372. else
  1373. UseInventoryItem(self:GetID());
  1374. end
  1375. end
  1376. function PaperDollItemSlotButton_OnModifiedClick(self, button)
  1377. if ( IsModifiedClick("EXPANDITEM") ) then
  1378. local itemLocation = ItemLocation:CreateFromEquipmentSlot(self:GetID());
  1379. if C_Item.DoesItemExist(itemLocation) then
  1380. if C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(itemLocation) then
  1381. if C_Item.CanViewItemPowers(itemLocation) then
  1382. OpenAzeriteEmpoweredItemUIFromItemLocation(itemLocation);
  1383. else
  1384. UIErrorsFrame:AddExternalErrorMessage(AZERITE_PREVIEW_UNAVAILABLE_FOR_CLASS);
  1385. end
  1386. return;
  1387. end
  1388. local heartItemLocation = C_AzeriteItem.FindActiveAzeriteItem();
  1389. if heartItemLocation and heartItemLocation:IsEqualTo(itemLocation) then
  1390. OpenAzeriteEssenceUIFromItemLocation(itemLocation);
  1391. return;
  1392. end
  1393. SocketInventoryItem(self:GetID());
  1394. end
  1395. return;
  1396. end
  1397. if ( HandleModifiedItemClick(GetInventoryItemLink("player", self:GetID())) ) then
  1398. return;
  1399. end
  1400. end
  1401. function PaperDollItemSlotButton_Update(self)
  1402. local textureName = GetInventoryItemTexture("player", self:GetID());
  1403. local cooldown = _G[self:GetName().."Cooldown"];
  1404. local hasItem = textureName ~= nil;
  1405. if ( hasItem ) then
  1406. SetItemButtonTexture(self, textureName);
  1407. SetItemButtonCount(self, GetInventoryItemCount("player", self:GetID()));
  1408. if ( GetInventoryItemBroken("player", self:GetID())
  1409. or GetInventoryItemEquippedUnusable("player", self:GetID()) ) then
  1410. SetItemButtonTextureVertexColor(self, 0.9, 0, 0);
  1411. SetItemButtonNormalTextureVertexColor(self, 0.9, 0, 0);
  1412. else
  1413. SetItemButtonTextureVertexColor(self, 1.0, 1.0, 1.0);
  1414. SetItemButtonNormalTextureVertexColor(self, 1.0, 1.0, 1.0);
  1415. end
  1416. if ( cooldown ) then
  1417. local start, duration, enable = GetInventoryItemCooldown("player", self:GetID());
  1418. CooldownFrame_Set(cooldown, start, duration, enable);
  1419. end
  1420. else
  1421. local textureName = self.backgroundTextureName;
  1422. if ( self.checkRelic and UnitHasRelicSlot("player") ) then
  1423. textureName = "Interface\\Paperdoll\\UI-PaperDoll-Slot-Relic.blp";
  1424. end
  1425. SetItemButtonTexture(self, textureName);
  1426. SetItemButtonCount(self, 0);
  1427. SetItemButtonTextureVertexColor(self, 1.0, 1.0, 1.0);
  1428. SetItemButtonNormalTextureVertexColor(self, 1.0, 1.0, 1.0);
  1429. if ( cooldown ) then
  1430. cooldown:Hide();
  1431. end
  1432. end
  1433. local quality = GetInventoryItemQuality("player", self:GetID());
  1434. local suppressOverlays = self.HasPaperDollAzeriteItemOverlay;
  1435. SetItemButtonQuality(self, quality, GetInventoryItemID("player", self:GetID()), suppressOverlays);
  1436. if (not PaperDollEquipmentManagerPane:IsShown()) then
  1437. self.ignored = nil;
  1438. end
  1439. if self.ignoreTexture then
  1440. self.ignoreTexture:SetShown(self.ignored);
  1441. end
  1442. if self.HasPaperDollAzeriteItemOverlay then
  1443. self:SetAzeriteItem(hasItem and ItemLocation:CreateFromEquipmentSlot(self:GetID()) or nil);
  1444. end
  1445. PaperDollItemSlotButton_UpdateLock(self);
  1446. -- Update repair all button status
  1447. MerchantFrame_UpdateGuildBankRepair();
  1448. MerchantFrame_UpdateCanRepairAll();
  1449. end
  1450. function PaperDollItemSlotButton_UpdateLock(self)
  1451. SetItemButtonDesaturated(self, IsInventoryItemLocked(self:GetID()));
  1452. end
  1453. function PaperDollItemSlotButton_OnEnter(self)
  1454. self:RegisterEvent("MODIFIER_STATE_CHANGED");
  1455. EquipmentFlyout_UpdateFlyout(self);
  1456. if ( not EquipmentFlyout_SetTooltipAnchor(self) ) then
  1457. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1458. end
  1459. local hasItem, hasCooldown, repairCost = GameTooltip:SetInventoryItem("player", self:GetID(), nil, true);
  1460. if ( not hasItem ) then
  1461. local text = _G[strupper(strsub(self:GetName(), 10))];
  1462. if ( self.checkRelic and UnitHasRelicSlot("player") ) then
  1463. text = RELICSLOT;
  1464. end
  1465. GameTooltip:SetText(text);
  1466. end
  1467. if ( InRepairMode() and repairCost and (repairCost > 0) ) then
  1468. GameTooltip:AddLine(REPAIR_COST, nil, nil, nil, true);
  1469. SetTooltipMoney(GameTooltip, repairCost);
  1470. GameTooltip:Show();
  1471. else
  1472. CursorUpdate(self);
  1473. end
  1474. end
  1475. function PaperDollItemSlotButton_OnLeave(self)
  1476. self:UnregisterEvent("MODIFIER_STATE_CHANGED");
  1477. GameTooltip:Hide();
  1478. ResetCursor();
  1479. end
  1480. function PaperDollStatTooltip(self)
  1481. if ( not self.tooltip ) then
  1482. return;
  1483. end
  1484. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1485. GameTooltip:SetText(self.tooltip);
  1486. if ( self.tooltip2 ) then
  1487. GameTooltip:AddLine(self.tooltip2, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true);
  1488. end
  1489. if ( self.tooltip3 ) then
  1490. GameTooltip:AddLine(self.tooltip3, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true);
  1491. end
  1492. GameTooltip:Show();
  1493. end
  1494. function FormatPaperDollTooltipStat(name, base, posBuff, negBuff)
  1495. local effective = BreakUpLargeNumbers(max(0,base + posBuff + negBuff));
  1496. local text = HIGHLIGHT_FONT_COLOR_CODE..name.." "..effective;
  1497. if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
  1498. text = text..FONT_COLOR_CODE_CLOSE;
  1499. else
  1500. if ( posBuff > 0 or negBuff < 0 ) then
  1501. text = text.." ("..base..FONT_COLOR_CODE_CLOSE;
  1502. end
  1503. if ( posBuff > 0 ) then
  1504. text = text..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE;
  1505. end
  1506. if ( negBuff < 0 ) then
  1507. text = text..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE;
  1508. end
  1509. if ( posBuff > 0 or negBuff < 0 ) then
  1510. text = text..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
  1511. end
  1512. end
  1513. return text;
  1514. end
  1515. function PaperDollFormatStat(name, base, posBuff, negBuff)
  1516. local effectiveText = BreakUpLargeNumbers(max(0,base + posBuff + negBuff));
  1517. local text = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT,name).." "..effectiveText;
  1518. if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
  1519. text = text..FONT_COLOR_CODE_CLOSE;
  1520. else
  1521. if ( posBuff > 0 or negBuff < 0 ) then
  1522. text = text.." ("..base..FONT_COLOR_CODE_CLOSE;
  1523. end
  1524. if ( posBuff > 0 ) then
  1525. text = text..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE;
  1526. end
  1527. if ( negBuff < 0 ) then
  1528. text = text..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE;
  1529. end
  1530. if ( posBuff > 0 or negBuff < 0 ) then
  1531. text = text..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
  1532. end
  1533. -- if there is a negative buff then show the main number in red, even if there are
  1534. -- positive buffs. Otherwise show the number in green
  1535. if ( negBuff < 0 and not GetPVPGearStatRules() ) then
  1536. effectiveText = RED_FONT_COLOR_CODE..effectiveText..FONT_COLOR_CODE_CLOSE;
  1537. end
  1538. end
  1539. return effectiveText, text;
  1540. end
  1541. function CharacterAttackFrame_OnEnter(self)
  1542. -- Main hand weapon
  1543. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1544. GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1545. GameTooltip:AddLine(self.weaponSkill);
  1546. GameTooltip:AddLine(self.weaponRating);
  1547. -- Check for offhand weapon
  1548. if ( self.offhandSkill ) then
  1549. GameTooltip:AddLine("\n");
  1550. GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1551. GameTooltip:AddLine(self.offhandSkill);
  1552. GameTooltip:AddLine(self.offhandRating);
  1553. end
  1554. GameTooltip:Show();
  1555. end
  1556. function CharacterDamageFrame_OnEnter(self)
  1557. -- Main hand weapon
  1558. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1559. if ( self.unit == "pet" ) then
  1560. GameTooltip:SetText(INVTYPE_WEAPONMAINHAND_PET, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1561. else
  1562. GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1563. end
  1564. 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);
  1565. 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);
  1566. -- Check for offhand weapon
  1567. if ( self.offhandAttackSpeed ) then
  1568. GameTooltip:AddLine("\n");
  1569. GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1570. 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);
  1571. 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);
  1572. end
  1573. GameTooltip:Show();
  1574. end
  1575. function PaperDollFrame_GetArmorReduction(armor, attackerLevel)
  1576. return C_PaperDollInfo.GetArmorEffectiveness(armor, attackerLevel) * 100;
  1577. end
  1578. function PaperDollFrame_GetArmorReductionAgainstTarget(armor)
  1579. local armorEffectiveness = C_PaperDollInfo.GetArmorEffectivenessAgainstTarget(armor);
  1580. if ( armorEffectiveness ) then
  1581. return armorEffectiveness * 100;
  1582. end
  1583. end
  1584. function PaperDollFrame_UpdateStats()
  1585. local level = UnitLevel("player");
  1586. local categoryYOffset = 0;
  1587. local statYOffset = 0;
  1588. if ( level >= MIN_PLAYER_LEVEL_FOR_ITEM_LEVEL_DISPLAY ) then
  1589. PaperDollFrame_SetItemLevel(CharacterStatsPane.ItemLevelFrame, "player");
  1590. CharacterStatsPane.ItemLevelFrame.Value:SetTextColor(GetItemLevelColor());
  1591. CharacterStatsPane.ItemLevelCategory:Show();
  1592. CharacterStatsPane.ItemLevelFrame:Show();
  1593. CharacterStatsPane.AttributesCategory:ClearAllPoints();
  1594. CharacterStatsPane.AttributesCategory:SetPoint("TOP", CharacterStatsPane.ItemLevelFrame, "BOTTOM", 0, 0);
  1595. else
  1596. CharacterStatsPane.ItemLevelCategory:Hide();
  1597. CharacterStatsPane.ItemLevelFrame:Hide();
  1598. CharacterStatsPane.AttributesCategory:ClearAllPoints();
  1599. CharacterStatsPane.AttributesCategory:SetPoint("TOP", CharacterStatsPane, "TOP", 0, -2);
  1600. categoryYOffset = -11;
  1601. statYOffset = -5;
  1602. end
  1603. local spec, role;
  1604. spec = GetSpecialization();
  1605. if spec then
  1606. role = GetSpecializationRole(spec);
  1607. end
  1608. CharacterStatsPane.statsFramePool:ReleaseAll();
  1609. -- we need a stat frame to first do the math to know if we need to show the stat frame
  1610. -- so effectively we'll always pre-allocate
  1611. local statFrame = CharacterStatsPane.statsFramePool:Acquire();
  1612. local lastAnchor;
  1613. for catIndex = 1, #PAPERDOLL_STATCATEGORIES do
  1614. local catFrame = CharacterStatsPane[PAPERDOLL_STATCATEGORIES[catIndex].categoryFrame];
  1615. local numStatInCat = 0;
  1616. for statIndex = 1, #PAPERDOLL_STATCATEGORIES[catIndex].stats do
  1617. local stat = PAPERDOLL_STATCATEGORIES[catIndex].stats[statIndex];
  1618. local showStat = true;
  1619. if ( showStat and stat.primary and spec ) then
  1620. local primaryStat = select(6, GetSpecializationInfo(spec, nil, nil, nil, UnitSex("player")));
  1621. if ( stat.primary ~= primaryStat ) then
  1622. showStat = false;
  1623. end
  1624. end
  1625. if ( showStat and stat.roles ) then
  1626. local foundRole = false;
  1627. for _, statRole in pairs(stat.roles) do
  1628. if ( role == statRole ) then
  1629. foundRole = true;
  1630. break;
  1631. end
  1632. end
  1633. showStat = foundRole;
  1634. end
  1635. if ( showStat and stat.showFunc ) then
  1636. showStat = stat.showFunc();
  1637. end
  1638. if ( showStat ) then
  1639. statFrame.onEnterFunc = nil;
  1640. statFrame.UpdateTooltip = nil;
  1641. PAPERDOLL_STATINFO[stat.stat].updateFunc(statFrame, "player");
  1642. if ( not stat.hideAt or stat.hideAt ~= statFrame.numericValue ) then
  1643. if ( numStatInCat == 0 ) then
  1644. if ( lastAnchor ) then
  1645. catFrame:SetPoint("TOP", lastAnchor, "BOTTOM", 0, categoryYOffset);
  1646. end
  1647. lastAnchor = catFrame;
  1648. statFrame:SetPoint("TOP", catFrame, "BOTTOM", 0, -2);
  1649. else
  1650. statFrame:SetPoint("TOP", lastAnchor, "BOTTOM", 0, statYOffset);
  1651. end
  1652. numStatInCat = numStatInCat + 1;
  1653. statFrame.Background:SetShown((numStatInCat % 2) == 0);
  1654. lastAnchor = statFrame;
  1655. -- done with this stat frame, get the next one
  1656. statFrame = CharacterStatsPane.statsFramePool:Acquire();
  1657. end
  1658. end
  1659. end
  1660. catFrame:SetShown(numStatInCat > 0);
  1661. end
  1662. -- release the current stat frame
  1663. CharacterStatsPane.statsFramePool:Release(statFrame);
  1664. end
  1665. function PaperDollFrame_SetLabelAndText(statFrame, label, text, isPercentage, numericValue)
  1666. if ( statFrame.Label ) then
  1667. statFrame.Label:SetText(format(STAT_FORMAT, label));
  1668. end
  1669. if ( isPercentage ) then
  1670. text = format("%d%%", numericValue + 0.5);
  1671. end
  1672. statFrame.Value:SetText(text);
  1673. statFrame.numericValue = numericValue;
  1674. end
  1675. function ComputePetBonus(stat, value)
  1676. local temp, unitClass = UnitClass("player");
  1677. unitClass = strupper(unitClass);
  1678. if( unitClass == "WARLOCK" ) then
  1679. if( WARLOCK_PET_BONUS[stat] ) then
  1680. return value * WARLOCK_PET_BONUS[stat];
  1681. else
  1682. return 0;
  1683. end
  1684. elseif( unitClass == "HUNTER" ) then
  1685. if( HUNTER_PET_BONUS[stat] ) then
  1686. return value * HUNTER_PET_BONUS[stat];
  1687. else
  1688. return 0;
  1689. end
  1690. end
  1691. return 0;
  1692. end
  1693. function PaperDollFrameItemFlyoutButton_OnClick(self)
  1694. if ( self.location == EQUIPMENTFLYOUT_IGNORESLOT_LOCATION ) then
  1695. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
  1696. local slot = EquipmentFlyoutFrame.button;
  1697. C_EquipmentSet.IgnoreSlotForSave(slot:GetID());
  1698. slot.ignored = true;
  1699. PaperDollItemSlotButton_Update(slot);
  1700. EquipmentFlyout_Show(slot);
  1701. PaperDollEquipmentManagerPaneSaveSet:Enable();
  1702. elseif ( self.location == EQUIPMENTFLYOUT_UNIGNORESLOT_LOCATION ) then
  1703. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
  1704. local slot = EquipmentFlyoutFrame.button;
  1705. C_EquipmentSet.UnignoreSlotForSave(slot:GetID());
  1706. slot.ignored = nil;
  1707. PaperDollItemSlotButton_Update(slot);
  1708. EquipmentFlyout_Show(slot);
  1709. PaperDollEquipmentManagerPaneSaveSet:Enable();
  1710. elseif ( self.location == EQUIPMENTFLYOUT_PLACEINBAGS_LOCATION ) then
  1711. if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[EquipmentFlyoutFrame.button:GetID()] ) then
  1712. UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
  1713. return;
  1714. end
  1715. local action = EquipmentManager_UnequipItemInSlot(EquipmentFlyoutFrame.button:GetID());
  1716. EquipmentManager_RunAction(action);
  1717. elseif ( self.location ) then
  1718. if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[EquipmentFlyoutFrame.button:GetID()] ) then
  1719. UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
  1720. return;
  1721. end
  1722. local action = EquipmentManager_EquipItemByLocation(self.location, self.id);
  1723. EquipmentManager_RunAction(action);
  1724. end
  1725. end
  1726. function PaperDollFrameItemFlyout_GetItems(paperDollItemSlot, itemTable)
  1727. GetInventoryItemsForSlot(paperDollItemSlot, itemTable);
  1728. end
  1729. function PaperDollFrameItemFlyout_PostGetItems(itemSlotButton, itemDisplayTable, numItems)
  1730. if (PaperDollEquipmentManagerPane:IsShown() and (PaperDollEquipmentManagerPane.selectedSetID or GearManagerDialogPopup:IsShown())) then
  1731. if ( not itemSlotButton.ignored ) then
  1732. tinsert(itemDisplayTable, 1, EQUIPMENTFLYOUT_IGNORESLOT_LOCATION);
  1733. else
  1734. tinsert(itemDisplayTable, 1, EQUIPMENTFLYOUT_UNIGNORESLOT_LOCATION);
  1735. end
  1736. numItems = numItems + 1;
  1737. end
  1738. if ( GetInventoryItemTexture("player", itemSlotButton:GetID()) ~= nil ) then
  1739. tinsert(itemDisplayTable, 1, EQUIPMENTFLYOUT_PLACEINBAGS_LOCATION);
  1740. numItems = numItems + 1;
  1741. end
  1742. return numItems;
  1743. end
  1744. function GearSetEditButton_OnLoad(self)
  1745. self.Dropdown = GearSetEditButtonDropDown;
  1746. UIDropDownMenu_Initialize(self.Dropdown, nil, "MENU");
  1747. UIDropDownMenu_SetInitializeFunction(self.Dropdown, GearSetEditButtonDropDown_Initialize);
  1748. end
  1749. function GearSetEditButton_OnMouseDown(self, button)
  1750. self.texture:SetPoint("TOPLEFT", 1, -1);
  1751. GearSetButton_OnClick(self:GetParent(), button);
  1752. if ( self.Dropdown.gearSetButton ~= self:GetParent() ) then
  1753. HideDropDownMenu(1);
  1754. self.Dropdown.gearSetButton = self:GetParent();
  1755. end
  1756. ToggleDropDownMenu(1, nil, self.Dropdown, self, 0, 0);
  1757. end
  1758. function GearSetEditButtonDropDown_Initialize(dropdownFrame, level, menuList)
  1759. local gearSetButton = dropdownFrame.gearSetButton;
  1760. local info = UIDropDownMenu_CreateInfo();
  1761. info.text = EQUIPMENT_SET_EDIT;
  1762. info.notCheckable = true;
  1763. info.func = function() GearSetButton_OpenPopup(gearSetButton); end;
  1764. UIDropDownMenu_AddButton(info, UIDROPDOWN_MENU_LEVEL);
  1765. info = UIDropDownMenu_CreateInfo();
  1766. info.text = EQUIPMENT_SET_ASSIGN_TO_SPEC;
  1767. info.isTitle = true;
  1768. info.notCheckable = true;
  1769. UIDropDownMenu_AddButton(info, UIDROPDOWN_MENU_LEVEL);
  1770. local equipmentSetID = gearSetButton.setID;
  1771. for i = 1, GetNumSpecializations() do
  1772. info = UIDropDownMenu_CreateInfo();
  1773. info.checked = function()
  1774. return C_EquipmentSet.GetEquipmentSetAssignedSpec(equipmentSetID) == i;
  1775. end;
  1776. info.func = function()
  1777. local currentSpecIndex = C_EquipmentSet.GetEquipmentSetAssignedSpec(equipmentSetID);
  1778. if ( currentSpecIndex ~= i ) then
  1779. C_EquipmentSet.AssignSpecToEquipmentSet(equipmentSetID, i);
  1780. else
  1781. C_EquipmentSet.UnassignEquipmentSetSpec(equipmentSetID);
  1782. end
  1783. GearSetButton_UpdateSpecInfo(gearSetButton);
  1784. PaperDollEquipmentManagerPane_Update(true);
  1785. end;
  1786. local specID = GetSpecializationInfo(i);
  1787. info.text = select(2, GetSpecializationInfoByID(specID));
  1788. UIDropDownMenu_AddButton(info, UIDROPDOWN_MENU_LEVEL);
  1789. end
  1790. end
  1791. function GearSetButton_OpenPopup(self)
  1792. GearManagerDialogPopup:Show();
  1793. GearManagerDialogPopup.isEdit = true;
  1794. GearManagerDialogPopup.setID = self.setID;
  1795. GearManagerDialogPopup.origName = self.text:GetText();
  1796. RecalculateGearManagerDialogPopup(self.text:GetText(), self.icon:GetTexture());
  1797. end
  1798. function GearSetButton_SetSpecInfo(self, specID)
  1799. if ( specID and specID > 0 ) then
  1800. self.specID = specID;
  1801. local id, name, description, texture, role, class = GetSpecializationInfoByID(specID);
  1802. SetPortraitToTexture(self.SpecIcon, texture);
  1803. self.SpecIcon:Show();
  1804. self.SpecRing:Show();
  1805. else
  1806. self.specID = nil;
  1807. self.SpecIcon:Hide();
  1808. self.SpecRing:Hide();
  1809. end
  1810. end
  1811. function GearSetButton_UpdateSpecInfo(self)
  1812. if ( not self.setID ) then
  1813. GearSetButton_SetSpecInfo(self, nil);
  1814. return;
  1815. end
  1816. local specIndex = C_EquipmentSet.GetEquipmentSetAssignedSpec(self.setID);
  1817. if ( not specIndex ) then
  1818. GearSetButton_SetSpecInfo(self, nil);
  1819. return;
  1820. end
  1821. local specID = GetSpecializationInfo(specIndex);
  1822. GearSetButton_SetSpecInfo(self, specID);
  1823. end
  1824. function GearSetButton_OnClick(self, button, down)
  1825. if ( self.setID ) then
  1826. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON); -- inappropriately named, but a good sound.
  1827. PaperDollEquipmentManagerPane.selectedSetID = self.setID;
  1828. -- mark the ignored slots
  1829. PaperDollFrame_ClearIgnoredSlots();
  1830. PaperDollFrame_IgnoreSlotsForSet(self.setID);
  1831. PaperDollEquipmentManagerPane_Update();
  1832. GearManagerDialogPopup:Hide();
  1833. else
  1834. -- This is the "New Set" button
  1835. GearManagerDialogPopup:Show();
  1836. PaperDollEquipmentManagerPane.selectedSetID = nil;
  1837. PaperDollFrame_ClearIgnoredSlots();
  1838. PaperDollEquipmentManagerPane_Update();
  1839. -- Ignore shirt and tabard by default
  1840. PaperDollFrame_IgnoreSlot(4);
  1841. PaperDollFrame_IgnoreSlot(19);
  1842. end
  1843. StaticPopup_Hide("CONFIRM_SAVE_EQUIPMENT_SET");
  1844. StaticPopup_Hide("CONFIRM_OVERWRITE_EQUIPMENT_SET");
  1845. end
  1846. function GearSetButton_OnEnter(self)
  1847. if ( self.setID ) then
  1848. GameTooltip_SetDefaultAnchor(GameTooltip, self);
  1849. GameTooltip:SetEquipmentSet(self.setID);
  1850. end
  1851. end
  1852. NUM_GEARSET_ICONS_PER_ROW = 10;
  1853. NUM_GEARSET_ICON_ROWS = 9;
  1854. NUM_GEARSET_ICONS_SHOWN = NUM_GEARSET_ICONS_PER_ROW * NUM_GEARSET_ICON_ROWS;
  1855. GEARSET_ICON_ROW_HEIGHT = 36;
  1856. local EM_ICON_FILENAMES = {};
  1857. function OnGearManagerDialogPopupButtonCreated(self, newButton)
  1858. tinsert(self.buttons, newButton);
  1859. end
  1860. function GearManagerDialogPopup_OnLoad(self)
  1861. self.buttons = {};
  1862. BuildIconArray(GearManagerDialogPopup, "GearManagerDialogPopupButton", "GearSetPopupButtonTemplate", NUM_GEARSET_ICONS_PER_ROW, NUM_GEARSET_ICON_ROWS, OnGearManagerDialogPopupButtonCreated);
  1863. self.SetSelection = function(self, fTexture, Value)
  1864. if(fTexture) then
  1865. self.selectedTexture = Value;
  1866. self.selectedIcon = nil;
  1867. else
  1868. self.selectedTexture = nil;
  1869. self.selectedIcon = Value;
  1870. end
  1871. end
  1872. GearManagerDialogPopupScrollFrame.ScrollBar.scrollStep = 8 * GEARSET_ICON_ROW_HEIGHT;
  1873. end
  1874. local GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING = 40;
  1875. function GearManagerDialogPopup_AdjustAnchors(self)
  1876. local rightSpace = GetScreenWidth() - PaperDollFrame:GetRight();
  1877. self.parentLeft = PaperDollFrame:GetLeft();
  1878. local leftSpace = self.parentLeft;
  1879. self:ClearAllPoints();
  1880. if ( leftSpace >= rightSpace ) then
  1881. if ( leftSpace < self:GetWidth() + GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING ) then
  1882. self:SetPoint("RIGHT", PaperDollFrame, "LEFT", self:GetWidth() + GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING - leftSpace, 0);
  1883. else
  1884. self:SetPoint("RIGHT", PaperDollFrame, "LEFT", -5, 0);
  1885. end
  1886. else
  1887. if ( rightSpace < self:GetWidth() + GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING ) then
  1888. self:SetPoint("LEFT", PaperDollFrame, "RIGHT", rightSpace - (self:GetWidth() + GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING), 0);
  1889. else
  1890. self:SetPoint("LEFT", PaperDollFrame, "RIGHT", 0, 0);
  1891. end
  1892. end
  1893. end
  1894. function GearManagerDialogPopup_OnShow(self)
  1895. GearManagerDialogPopup_AdjustAnchors(self);
  1896. PlaySound(SOUNDKIT.IG_CHARACTER_INFO_OPEN);
  1897. self.setID = nil;
  1898. self.isEdit = false;
  1899. RecalculateGearManagerDialogPopup();
  1900. RefreshEquipmentSetIconInfo();
  1901. end
  1902. function GearManagerDialogPopup_OnUpdate(self)
  1903. if ( PaperDollFrame:GetLeft() ~= self.parentLeft ) then
  1904. GearManagerDialogPopup_AdjustAnchors(self);
  1905. end
  1906. end
  1907. function GearManagerDialogPopup_OnHide(self)
  1908. GearManagerDialogPopup.setID = nil;
  1909. GearManagerDialogPopup:SetSelection(true, nil);
  1910. GearManagerDialogPopupEditBox:SetText("");
  1911. if (not PaperDollEquipmentManagerPane.selectedSetID) then
  1912. PaperDollFrame_ClearIgnoredSlots();
  1913. end
  1914. EM_ICON_FILENAMES = nil;
  1915. collectgarbage();
  1916. end
  1917. function RecalculateGearManagerDialogPopup(setName, iconTexture)
  1918. local popup = GearManagerDialogPopup;
  1919. if ( setName and setName ~= "") then
  1920. GearManagerDialogPopupEditBox:SetText(setName);
  1921. GearManagerDialogPopupEditBox:HighlightText(0);
  1922. else
  1923. GearManagerDialogPopupEditBox:SetText("");
  1924. end
  1925. if (iconTexture) then
  1926. popup:SetSelection(true, iconTexture);
  1927. else
  1928. popup:SetSelection(false, 1);
  1929. end
  1930. --[[
  1931. Scroll and ensure that any selected equipment shows up in the list.
  1932. When we first press "save", we want to make sure any selected equipment set shows up in the list, so that
  1933. the user can just make his changes and press Okay to overwrite.
  1934. To do this, we need to find the current set (by icon) and move the offset of the GearManagerDialogPopup
  1935. to display it. Issue ID: 171220
  1936. ]]
  1937. RefreshEquipmentSetIconInfo();
  1938. local totalItems = #EM_ICON_FILENAMES;
  1939. local texture, _;
  1940. if(popup.selectedTexture) then
  1941. local foundIndex = nil;
  1942. for index=1, totalItems do
  1943. texture = GetEquipmentSetIconInfo(index);
  1944. if ( texture == popup.selectedTexture ) then
  1945. foundIndex = index;
  1946. break;
  1947. end
  1948. end
  1949. if (foundIndex == nil) then
  1950. foundIndex = 1;
  1951. end
  1952. -- now make it so we always display at least NUM_GEARSET_ICON_ROWS of data
  1953. local offsetnumIcons = floor((totalItems-1)/NUM_GEARSET_ICONS_PER_ROW);
  1954. local offset = floor((foundIndex-1) / NUM_GEARSET_ICONS_PER_ROW);
  1955. offset = offset + min((NUM_GEARSET_ICON_ROWS-1), offsetnumIcons-offset) - (NUM_GEARSET_ICON_ROWS-1);
  1956. if(foundIndex<=NUM_GEARSET_ICONS_SHOWN) then
  1957. offset = 0; --Equipment all shows at the same place.
  1958. end
  1959. FauxScrollFrame_OnVerticalScroll(GearManagerDialogPopupScrollFrame, offset*GEARSET_ICON_ROW_HEIGHT, GEARSET_ICON_ROW_HEIGHT, nil);
  1960. else
  1961. FauxScrollFrame_OnVerticalScroll(GearManagerDialogPopupScrollFrame, 0, GEARSET_ICON_ROW_HEIGHT, nil);
  1962. end
  1963. GearManagerDialogPopup_Update();
  1964. end
  1965. --[[
  1966. RefreshEquipmentSetIconInfo() counts how many uniquely textured inventory items the player has equipped.
  1967. ]]
  1968. function RefreshEquipmentSetIconInfo()
  1969. EM_ICON_FILENAMES = {};
  1970. EM_ICON_FILENAMES[1] = "INV_MISC_QUESTIONMARK";
  1971. local index = 2;
  1972. for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
  1973. local itemTexture = GetInventoryItemTexture("player", i);
  1974. if ( itemTexture ) then
  1975. EM_ICON_FILENAMES[index] = itemTexture;
  1976. if(EM_ICON_FILENAMES[index]) then
  1977. index = index + 1;
  1978. --[[
  1979. Currently checks all for duplicates, even though only rings, trinkets, and weapons may be duplicated.
  1980. This version is clean and maintainable.
  1981. ]]
  1982. for j=INVSLOT_FIRST_EQUIPPED, (index-1) do
  1983. if(EM_ICON_FILENAMES[index] == EM_ICON_FILENAMES[j]) then
  1984. EM_ICON_FILENAMES[index] = nil;
  1985. index = index - 1;
  1986. break;
  1987. end
  1988. end
  1989. end
  1990. end
  1991. end
  1992. GetLooseMacroItemIcons(EM_ICON_FILENAMES);
  1993. GetLooseMacroIcons(EM_ICON_FILENAMES);
  1994. GetMacroItemIcons(EM_ICON_FILENAMES);
  1995. GetMacroIcons(EM_ICON_FILENAMES);
  1996. end
  1997. --[[
  1998. GetEquipmentSetIconInfo(index) determines the texture and real index of a regular index
  1999. Input: index = index into a list of equipped items followed by the macro items. Only tricky part is the equipped items list keeps changing.
  2000. 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
  2001. and positive for the macro items//
  2002. ]]
  2003. function GetEquipmentSetIconInfo(index)
  2004. return EM_ICON_FILENAMES[index];
  2005. end
  2006. function GearManagerDialogPopup_Update()
  2007. local popup = GearManagerDialogPopup;
  2008. local buttons = popup.buttons;
  2009. local offset = FauxScrollFrame_GetOffset(GearManagerDialogPopupScrollFrame) or 0;
  2010. local button;
  2011. -- Icon list
  2012. local texture, index, button, realIndex, _;
  2013. for i=1, NUM_GEARSET_ICONS_SHOWN do
  2014. local button = buttons[i];
  2015. index = (offset * NUM_GEARSET_ICONS_PER_ROW) + i;
  2016. if ( index <= #EM_ICON_FILENAMES ) then
  2017. texture = GetEquipmentSetIconInfo(index);
  2018. -- button.name:SetText(index); --dcw
  2019. if(type(texture) == "number") then
  2020. button.icon:SetTexture(texture);
  2021. else
  2022. button.icon:SetTexture("INTERFACE\\ICONS\\"..texture);
  2023. end
  2024. button:Show();
  2025. if ( index == popup.selectedIcon ) then
  2026. button:SetChecked(true);
  2027. elseif ( texture == popup.selectedTexture ) then
  2028. button:SetChecked(true);
  2029. popup:SetSelection(false, index);
  2030. else
  2031. button:SetChecked(false);
  2032. end
  2033. else
  2034. button.icon:SetTexture("");
  2035. button:Hide();
  2036. end
  2037. end
  2038. -- Scrollbar stuff
  2039. FauxScrollFrame_Update(GearManagerDialogPopupScrollFrame, ceil(#EM_ICON_FILENAMES / NUM_GEARSET_ICONS_PER_ROW) + 1, NUM_GEARSET_ICON_ROWS, GEARSET_ICON_ROW_HEIGHT );
  2040. end
  2041. function GearManagerDialogPopupOkay_Update()
  2042. local popup = GearManagerDialogPopup;
  2043. local button = GearManagerDialogPopupOkay;
  2044. if ( (popup.selectedIcon or popup.isEdit) and popup.name ) then
  2045. button:Enable();
  2046. else
  2047. button:Disable();
  2048. end
  2049. end
  2050. function GearManagerDialogPopupOkay_OnClick(self, button, pushed)
  2051. local popup = GearManagerDialogPopup;
  2052. local iconTexture = GetEquipmentSetIconInfo(popup.selectedIcon);
  2053. if ( C_EquipmentSet.GetEquipmentSetID(popup.name) ) then
  2054. if (popup.isEdit and popup.name ~= popup.origName) then
  2055. -- Not allowed to overwrite an existing set by doing a rename
  2056. UIErrorsFrame:AddMessage(EQUIPMENT_SETS_CANT_RENAME, 1.0, 0.1, 0.1, 1.0);
  2057. return;
  2058. elseif (not popup.isEdit) then
  2059. local dialog = StaticPopup_Show("CONFIRM_OVERWRITE_EQUIPMENT_SET", popup.name);
  2060. if ( dialog ) then
  2061. dialog.data = C_EquipmentSet.GetEquipmentSetID(popup.name);
  2062. dialog.selectedIcon = iconTexture;
  2063. else
  2064. UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
  2065. end
  2066. return;
  2067. end
  2068. elseif ( C_EquipmentSet.GetNumEquipmentSets() >= MAX_EQUIPMENT_SETS_PER_PLAYER and not popup.isEdit) then
  2069. UIErrorsFrame:AddMessage(EQUIPMENT_SETS_TOO_MANY, 1.0, 0.1, 0.1, 1.0);
  2070. return;
  2071. end
  2072. if (popup.isEdit) then
  2073. PaperDollEquipmentManagerPane.selectedSetID = popup.setID;
  2074. C_EquipmentSet.ModifyEquipmentSet(popup.setID, popup.name, iconTexture);
  2075. else
  2076. C_EquipmentSet.CreateEquipmentSet(popup.name, iconTexture);
  2077. end
  2078. popup:Hide();
  2079. end
  2080. function GearManagerDialogPopupCancel_OnClick()
  2081. GearManagerDialogPopup:Hide();
  2082. end
  2083. function GearSetPopupButton_OnClick(self, button)
  2084. local popup = GearManagerDialogPopup;
  2085. local offset = FauxScrollFrame_GetOffset(GearManagerDialogPopupScrollFrame) or 0;
  2086. popup.selectedIcon = (offset * NUM_GEARSET_ICONS_PER_ROW) + self:GetID();
  2087. popup.selectedTexture = nil;
  2088. GearManagerDialogPopup_Update();
  2089. GearManagerDialogPopupOkay_Update();
  2090. end
  2091. function PaperDollEquipmentManagerPane_OnLoad(self)
  2092. HybridScrollFrame_OnLoad(self);
  2093. self.update = PaperDollEquipmentManagerPane_Update;
  2094. HybridScrollFrame_CreateButtons(self, "GearSetButtonTemplate", 2, -(self.EquipSet:GetHeight()+4));
  2095. self:RegisterEvent("EQUIPMENT_SWAP_FINISHED");
  2096. self:RegisterEvent("EQUIPMENT_SETS_CHANGED");
  2097. self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED");
  2098. self:RegisterEvent("BAG_UPDATE");
  2099. end
  2100. function PaperDollEquipmentManagerPane_OnUpdate(self)
  2101. for i = 1, #self.buttons do
  2102. local button = self.buttons[i];
  2103. if (button:IsMouseOver()) then
  2104. if (button.setID) then
  2105. button.DeleteButton:Show();
  2106. button.EditButton:Show();
  2107. else
  2108. button.DeleteButton:Hide();
  2109. button.EditButton:Hide();
  2110. end
  2111. button.HighlightBar:Show();
  2112. else
  2113. button.DeleteButton:Hide();
  2114. button.EditButton:Hide();
  2115. button.HighlightBar:Hide();
  2116. end
  2117. end
  2118. if (self.queuedUpdate) then
  2119. PaperDollEquipmentManagerPane_Update();
  2120. self.queuedUpdate = false;
  2121. end
  2122. end
  2123. function PaperDollEquipmentManagerPane_OnShow(self)
  2124. PaperDollEquipmentManagerPane_Update(true);
  2125. EquipmentFlyoutPopoutButton_ShowAll();
  2126. end
  2127. function PaperDollEquipmentManagerPane_OnEvent(self, event, ...)
  2128. if ( event == "EQUIPMENT_SWAP_FINISHED" ) then
  2129. local completed, setID = ...;
  2130. if ( completed ) then
  2131. PlaySound(SOUNDKIT.PUT_DOWN_SMALL_CHAIN); -- plays the equip sound for plate mail
  2132. if (self:IsShown()) then
  2133. self.selectedSetID = setID;
  2134. PaperDollEquipmentManagerPane_Update();
  2135. end
  2136. end
  2137. end
  2138. if (self:IsShown()) then
  2139. if ( event == "EQUIPMENT_SETS_CHANGED" ) then
  2140. PaperDollEquipmentManagerPane_Update(true);
  2141. elseif ( event == "PLAYER_EQUIPMENT_CHANGED" or event == "BAG_UPDATE" ) then
  2142. -- This queues the update to only happen once at the end of the frame
  2143. self.queuedUpdate = true;
  2144. end
  2145. end
  2146. end
  2147. function PaperDollEquipmentManagerPane_OnHide(self)
  2148. EquipmentFlyoutPopoutButton_HideAll();
  2149. PaperDollFrame_ClearIgnoredSlots();
  2150. GearManagerDialogPopup:Hide();
  2151. StaticPopup_Hide("CONFIRM_SAVE_EQUIPMENT_SET");
  2152. StaticPopup_Hide("CONFIRM_OVERWRITE_EQUIPMENT_SET");
  2153. end
  2154. function SortEquipmentSetIDs(equipmentSetIDs)
  2155. local sortedIDs = {};
  2156. -- Add all the spec-assigned sets first because they should appear first.
  2157. for i, equipmentSetID in ipairs(equipmentSetIDs) do
  2158. if C_EquipmentSet.GetEquipmentSetAssignedSpec(equipmentSetID) then
  2159. sortedIDs[#sortedIDs + 1] = equipmentSetID;
  2160. end
  2161. end
  2162. for i, equipmentSetID in ipairs(equipmentSetIDs) do
  2163. if not C_EquipmentSet.GetEquipmentSetAssignedSpec(equipmentSetID) then
  2164. sortedIDs[#sortedIDs + 1] = equipmentSetID;
  2165. end
  2166. end
  2167. return sortedIDs;
  2168. end
  2169. function PaperDollEquipmentManagerPane_Update(equipmentSetsDirty)
  2170. local _, setID, isEquipped;
  2171. if (PaperDollEquipmentManagerPane.selectedSetID) then
  2172. _, _, setID, isEquipped = C_EquipmentSet.GetEquipmentSetInfo(PaperDollEquipmentManagerPane.selectedSetID);
  2173. end
  2174. if (setID) then
  2175. if (isEquipped) then
  2176. PaperDollEquipmentManagerPaneSaveSet:Disable();
  2177. PaperDollEquipmentManagerPaneEquipSet:Disable();
  2178. else
  2179. PaperDollEquipmentManagerPaneSaveSet:Enable();
  2180. PaperDollEquipmentManagerPaneEquipSet:Enable();
  2181. end
  2182. PaperDollFrame_IgnoreSlotsForSet(setID);
  2183. else
  2184. PaperDollEquipmentManagerPaneSaveSet:Disable();
  2185. PaperDollEquipmentManagerPaneEquipSet:Disable();
  2186. -- Clear selected equipment set if it doesn't exist
  2187. if (PaperDollEquipmentManagerPane.selectedSetID) then
  2188. PaperDollEquipmentManagerPane.selectedSetID = nil;
  2189. PaperDollFrame_ClearIgnoredSlots();
  2190. end
  2191. end
  2192. if ( equipmentSetsDirty ) then
  2193. PaperDollEquipmentManagerPane.equipmentSetIDs = SortEquipmentSetIDs(C_EquipmentSet.GetEquipmentSetIDs());
  2194. end
  2195. local numSets = #PaperDollEquipmentManagerPane.equipmentSetIDs;
  2196. local numRows = numSets;
  2197. if (numSets < MAX_EQUIPMENT_SETS_PER_PLAYER) then
  2198. numRows = numRows + 1; -- "Add New Set" button
  2199. end
  2200. HybridScrollFrame_Update(PaperDollEquipmentManagerPane, numRows * EQUIPMENTSET_BUTTON_HEIGHT + PaperDollEquipmentManagerPaneEquipSet:GetHeight() + 20 , PaperDollEquipmentManagerPane:GetHeight());
  2201. local scrollOffset = HybridScrollFrame_GetOffset(PaperDollEquipmentManagerPane);
  2202. local buttons = PaperDollEquipmentManagerPane.buttons;
  2203. local selectedSetID = PaperDollEquipmentManagerPane.selectedSetID;
  2204. local name, texture, button, numLost;
  2205. for i = 1, #buttons do
  2206. if (i+scrollOffset <= numRows) then
  2207. button = buttons[i];
  2208. buttons[i]:Show();
  2209. button:Enable();
  2210. if (i+scrollOffset <= numSets) then
  2211. -- Normal equipment set button
  2212. name, texture, setID, isEquipped, _, _, _, numLost = C_EquipmentSet.GetEquipmentSetInfo(PaperDollEquipmentManagerPane.equipmentSetIDs[i+scrollOffset]);
  2213. button.setID = setID;
  2214. button.text:SetText(name);
  2215. if (numLost > 0) then
  2216. button.text:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
  2217. else
  2218. button.text:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
  2219. end
  2220. if (texture) then
  2221. button.icon:SetTexture(texture);
  2222. else
  2223. button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark");
  2224. end
  2225. if (selectedSetID and button.setID == selectedSetID) then
  2226. button.SelectedBar:Show();
  2227. else
  2228. button.SelectedBar:Hide();
  2229. end
  2230. if (isEquipped) then
  2231. button.Check:Show();
  2232. else
  2233. button.Check:Hide();
  2234. end
  2235. button.icon:SetSize(36, 36);
  2236. button.icon:SetPoint("LEFT", 4, 0);
  2237. else
  2238. -- This is the Add New button
  2239. button.setID = nil;
  2240. button.text:SetText(PAPERDOLL_NEWEQUIPMENTSET);
  2241. button.text:SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b);
  2242. button.icon:SetTexture("Interface\\PaperDollInfoFrame\\Character-Plus");
  2243. button.icon:SetSize(30, 30);
  2244. button.icon:SetPoint("LEFT", 7, 0);
  2245. button.Check:Hide();
  2246. button.SelectedBar:Hide();
  2247. end
  2248. if ((i+scrollOffset) == 1) then
  2249. buttons[i].BgTop:Show();
  2250. buttons[i].BgMiddle:SetPoint("TOP", buttons[i].BgTop, "BOTTOM");
  2251. else
  2252. buttons[i].BgTop:Hide();
  2253. buttons[i].BgMiddle:SetPoint("TOP");
  2254. end
  2255. if ((i+scrollOffset) == numRows) then
  2256. buttons[i].BgBottom:Show();
  2257. buttons[i].BgMiddle:SetPoint("BOTTOM", buttons[i].BgBottom, "TOP");
  2258. else
  2259. buttons[i].BgBottom:Hide();
  2260. buttons[i].BgMiddle:SetPoint("BOTTOM");
  2261. end
  2262. if ((i+scrollOffset)%2 == 0) then
  2263. buttons[i].Stripe:SetColorTexture(STRIPE_COLOR.r, STRIPE_COLOR.g, STRIPE_COLOR.b);
  2264. buttons[i].Stripe:SetAlpha(0.1);
  2265. buttons[i].Stripe:Show();
  2266. else
  2267. buttons[i].Stripe:Hide();
  2268. end
  2269. GearSetButton_UpdateSpecInfo(buttons[i]);
  2270. else
  2271. buttons[i]:Hide();
  2272. end
  2273. end
  2274. end
  2275. function PaperDollEquipmentManagerPaneSaveSet_OnClick(self)
  2276. local selectedSetID = PaperDollEquipmentManagerPane.selectedSetID
  2277. if (selectedSetID) then
  2278. local selectedSetName = C_EquipmentSet.GetEquipmentSetInfo(selectedSetID);
  2279. local dialog = StaticPopup_Show("CONFIRM_SAVE_EQUIPMENT_SET", selectedSetName);
  2280. if ( dialog ) then
  2281. dialog.data = selectedSetID;
  2282. else
  2283. UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
  2284. end
  2285. end
  2286. end
  2287. function PaperDollEquipmentManagerPaneEquipSet_OnClick(self)
  2288. local selectedSetID = PaperDollEquipmentManagerPane.selectedSetID;
  2289. if ( selectedSetID) then
  2290. PlaySound(SOUNDKIT.IG_CHARACTER_INFO_TAB); -- inappropriately named, but a good sound.
  2291. EquipmentManager_EquipSet(selectedSetID);
  2292. end
  2293. end
  2294. function PaperDollTitlesPane_OnLoad(self)
  2295. HybridScrollFrame_OnLoad(self);
  2296. self.update = PaperDollTitlesPane_UpdateScrollFrame;
  2297. HybridScrollFrame_CreateButtons(self, "PlayerTitleButtonTemplate", 2, -4);
  2298. end
  2299. function PaperDollTitlesPane_UpdateScrollFrame()
  2300. local buttons = PaperDollTitlesPane.buttons;
  2301. local playerTitles = PaperDollTitlesPane.titles;
  2302. local numButtons = #buttons;
  2303. local scrollOffset = HybridScrollFrame_GetOffset(PaperDollTitlesPane);
  2304. local playerTitle;
  2305. for i = 1, numButtons do
  2306. playerTitle = playerTitles[i + scrollOffset];
  2307. if ( playerTitle ) then
  2308. buttons[i]:Show();
  2309. buttons[i].text:SetText(playerTitle.name);
  2310. buttons[i].titleId = playerTitle.id;
  2311. if ( PaperDollTitlesPane.selected == playerTitle.id ) then
  2312. buttons[i].Check:Show();
  2313. buttons[i].SelectedBar:Show();
  2314. else
  2315. buttons[i].Check:Hide();
  2316. buttons[i].SelectedBar:Hide();
  2317. end
  2318. if ((i+scrollOffset) == 1) then
  2319. buttons[i].BgTop:Show();
  2320. buttons[i].BgMiddle:SetPoint("TOP", buttons[i].BgTop, "BOTTOM");
  2321. else
  2322. buttons[i].BgTop:Hide();
  2323. buttons[i].BgMiddle:SetPoint("TOP");
  2324. end
  2325. if ((i+scrollOffset) == #playerTitles) then
  2326. buttons[i].BgBottom:Show();
  2327. buttons[i].BgMiddle:SetPoint("BOTTOM", buttons[i].BgBottom, "TOP");
  2328. else
  2329. buttons[i].BgBottom:Hide();
  2330. buttons[i].BgMiddle:SetPoint("BOTTOM");
  2331. end
  2332. if ((i+scrollOffset)%2 == 0) then
  2333. buttons[i].Stripe:SetColorTexture(STRIPE_COLOR.r, STRIPE_COLOR.g, STRIPE_COLOR.b);
  2334. buttons[i].Stripe:SetAlpha(0.1);
  2335. buttons[i].Stripe:Show();
  2336. else
  2337. buttons[i].Stripe:Hide();
  2338. end
  2339. else
  2340. buttons[i]:Hide();
  2341. end
  2342. end
  2343. end
  2344. local function PlayerTitleSort(a, b) return a.name < b.name; end
  2345. function GetKnownTitles()
  2346. local playerTitles = { };
  2347. local titleCount = 1;
  2348. local playerTitle = false;
  2349. local tempName = 0;
  2350. local selectedTitle = -1;
  2351. playerTitles[1] = { };
  2352. -- reserving space for None so it doesn't get sorted out of the top position
  2353. playerTitles[1].name = " ";
  2354. playerTitles[1].id = -1;
  2355. for i = 1, GetNumTitles() do
  2356. if ( IsTitleKnown(i) ) then
  2357. tempName, playerTitle = GetTitleName(i);
  2358. if ( tempName and playerTitle ) then
  2359. titleCount = titleCount + 1;
  2360. playerTitles[titleCount] = playerTitles[titleCount] or { };
  2361. playerTitles[titleCount].name = strtrim(tempName);
  2362. playerTitles[titleCount].id = i;
  2363. end
  2364. end
  2365. end
  2366. return playerTitles, selectedTitle;
  2367. end
  2368. function PaperDollTitlesPane_Update()
  2369. local currentTitle = GetCurrentTitle();
  2370. local buttons = PaperDollTitlesPane.buttons;
  2371. local playerTitles = GetKnownTitles();
  2372. if ( currentTitle > 0 and currentTitle <= GetNumTitles() and IsTitleKnown(currentTitle) ) then
  2373. PaperDollTitlesPane.selected = currentTitle;
  2374. else
  2375. PaperDollTitlesPane.selected = -1;
  2376. end
  2377. table.sort(playerTitles, PlayerTitleSort);
  2378. playerTitles[1].name = PLAYER_TITLE_NONE;
  2379. PaperDollTitlesPane.titles = playerTitles;
  2380. HybridScrollFrame_Update(PaperDollTitlesPane, #playerTitles * PLAYER_TITLE_HEIGHT + 20 , PaperDollTitlesPane:GetHeight());
  2381. PaperDollTitlesPane_UpdateScrollFrame();
  2382. end
  2383. function PlayerTitleButton_OnClick(self)
  2384. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF);
  2385. SetCurrentTitle(self.titleId);
  2386. end
  2387. function SetTitleByName(name)
  2388. name = strlower(name);
  2389. for i = 1, GetNumTitles() do
  2390. if ( IsTitleKnown(i) ) then
  2391. local title = GetTitleName(i);
  2392. title = strlower(strtrim(title));
  2393. if(title:find(name) == 1) then
  2394. SetCurrentTitle(i);
  2395. return true;
  2396. end
  2397. end
  2398. end
  2399. return false;
  2400. end
  2401. function SetPaperDollBackground(model, unit)
  2402. local race, fileName = UnitRace(unit);
  2403. local texture = DressUpTexturePath(fileName);
  2404. model.BackgroundTopLeft:SetTexture(texture..1);
  2405. model.BackgroundTopRight:SetTexture(texture..2);
  2406. model.BackgroundBotLeft:SetTexture(texture..3);
  2407. model.BackgroundBotRight:SetTexture(texture..4);
  2408. -- HACK - Adjust background brightness for different races
  2409. if ( strupper(fileName) == "BLOODELF") then
  2410. model.BackgroundOverlay:SetAlpha(0.8);
  2411. elseif (strupper(fileName) == "NIGHTELF") then
  2412. model.BackgroundOverlay:SetAlpha(0.6);
  2413. elseif ( strupper(fileName) == "SCOURGE") then
  2414. model.BackgroundOverlay:SetAlpha(0.3);
  2415. elseif ( strupper(fileName) == "TROLL" or strupper(fileName) == "ORC") then
  2416. model.BackgroundOverlay:SetAlpha(0.6);
  2417. elseif ( strupper(fileName) == "WORGEN" ) then
  2418. model.BackgroundOverlay:SetAlpha(0.5);
  2419. elseif ( strupper(fileName) == "GOBLIN" ) then
  2420. model.BackgroundOverlay:SetAlpha(0.6);
  2421. else
  2422. model.BackgroundOverlay:SetAlpha(0.7);
  2423. end
  2424. end
  2425. function PaperDollBgDesaturate(on)
  2426. CharacterModelFrameBackgroundTopLeft:SetDesaturated(on);
  2427. CharacterModelFrameBackgroundTopRight:SetDesaturated(on);
  2428. CharacterModelFrameBackgroundBotLeft:SetDesaturated(on);
  2429. CharacterModelFrameBackgroundBotRight:SetDesaturated(on);
  2430. end
  2431. function PaperDollFrame_UpdateSidebarTabs()
  2432. for i = 1, #PAPERDOLL_SIDEBARS do
  2433. local tab = _G["PaperDollSidebarTab"..i];
  2434. if (tab) then
  2435. if (_G[PAPERDOLL_SIDEBARS[i].frame]:IsShown()) then
  2436. tab.Hider:Hide();
  2437. tab.Highlight:Hide();
  2438. tab.TabBg:SetTexCoord(0.01562500, 0.79687500, 0.78906250, 0.95703125);
  2439. else
  2440. tab.Hider:Show();
  2441. tab.Highlight:Show();
  2442. tab.TabBg:SetTexCoord(0.01562500, 0.79687500, 0.61328125, 0.78125000);
  2443. if ( PAPERDOLL_SIDEBARS[i].IsActive() ) then
  2444. tab:Enable();
  2445. else
  2446. tab:Disable();
  2447. end
  2448. end
  2449. end
  2450. end
  2451. end
  2452. function PaperDollFrame_SetSidebar(self, index)
  2453. if (not _G[PAPERDOLL_SIDEBARS[index].frame]:IsShown()) then
  2454. for i = 1, #PAPERDOLL_SIDEBARS do
  2455. _G[PAPERDOLL_SIDEBARS[i].frame]:Hide();
  2456. end
  2457. _G[PAPERDOLL_SIDEBARS[index].frame]:Show();
  2458. PaperDollFrame.currentSideBar = _G[PAPERDOLL_SIDEBARS[index].frame];
  2459. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF);
  2460. PaperDollFrame_UpdateSidebarTabs();
  2461. end
  2462. end
  2463. function PaperDollFrame_SidebarTab_OnEnter(self)
  2464. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  2465. GameTooltip_SetTitle(GameTooltip, PAPERDOLL_SIDEBARS[self:GetID()].name);
  2466. if not self:IsEnabled() and self.disabledTooltip then
  2467. local disabledTooltipText = GetValueOrCallFunction(self, "disabledTooltip");
  2468. GameTooltip_AddErrorLine(GameTooltip, disabledTooltipText, true);
  2469. end
  2470. GameTooltip:Show();
  2471. end
  2472. local inventoryFixupVersionToTutorialIndex =
  2473. {
  2474. {
  2475. seenIndex = LE_FRAME_TUTORIAL_INVENTORY_FIXUP_EXPANSION_LEGION,
  2476. checkIndex = LE_FRAME_TUTORIAL_INVENTORY_FIXUP_CHECK_EXPANSION_LEGION,
  2477. },
  2478. };
  2479. local function CheckFixupStates(fixupVersion)
  2480. local tutorialIndices = fixupVersion and inventoryFixupVersionToTutorialIndex[fixupVersion];
  2481. -- Set the appropriate index to check, this is how the client knows the user's
  2482. -- inventory was fixed up at some point in the past, but hasn't seen the tutorial yet.
  2483. if tutorialIndices and tutorialIndices.checkIndex then
  2484. SetCVarBitfield("closedInfoFrames", tutorialIndices.checkIndex, true);
  2485. end
  2486. -- Return the any matching tutorial that the user hasn't seen
  2487. for expansionID, tutorialIndices in pairs(inventoryFixupVersionToTutorialIndex) do
  2488. local doCheck = GetCVarBitfield("closedInfoFrames", tutorialIndices.checkIndex);
  2489. local seenTutorial = GetCVarBitfield("closedInfoFrames", tutorialIndices.seenIndex);
  2490. if doCheck and not seenTutorial then
  2491. return tutorialIndices.seenIndex;
  2492. end
  2493. end
  2494. end
  2495. function PaperDollFrame_HideInventoryFixupComplete(self)
  2496. HelpTip:Hide(self, PAPERDOLL_INVENTORY_FIXUP_COMPLETE);
  2497. MicroButtonPulseStop(CharacterMicroButton);
  2498. end