PaperDollFrame.lua

PaperDollFrame.lua (8.3.7.35284; unchanged since 8.3.0.33062)
  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 = 90;
  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 = format(FEATURE_BECOMES_AVAILABLE_AT_LEVEL, SHOW_LFD_LEVEL);
  95. IsActive = function()
  96. return C_EquipmentSet.GetNumEquipmentSets() > 0 or UnitLevel("player") >= SHOW_LFD_LEVEL;
  97. end
  98. },
  99. };
  100. PAPERDOLL_STATINFO = {
  101. -- General
  102. ["HEALTH"] = {
  103. updateFunc = function(statFrame, unit) PaperDollFrame_SetHealth(statFrame, unit); end
  104. },
  105. ["POWER"] = {
  106. updateFunc = function(statFrame, unit) PaperDollFrame_SetPower(statFrame, unit); end
  107. },
  108. ["ALTERNATEMANA"] = {
  109. -- Only appears for Druids when in shapeshift form
  110. updateFunc = function(statFrame, unit) PaperDollFrame_SetAlternateMana(statFrame, unit); end
  111. },
  112. ["ITEMLEVEL"] = {
  113. updateFunc = function(statFrame, unit) PaperDollFrame_SetItemLevel(statFrame, unit); end
  114. },
  115. ["MOVESPEED"] = {
  116. updateFunc = function(statFrame, unit) PaperDollFrame_SetMovementSpeed(statFrame, unit); end
  117. },
  118. -- Base stats
  119. ["STRENGTH"] = {
  120. updateFunc = function(statFrame, unit) PaperDollFrame_SetStat(statFrame, unit, LE_UNIT_STAT_STRENGTH); end
  121. },
  122. ["AGILITY"] = {
  123. updateFunc = function(statFrame, unit) PaperDollFrame_SetStat(statFrame, unit, LE_UNIT_STAT_AGILITY); end
  124. },
  125. ["INTELLECT"] = {
  126. updateFunc = function(statFrame, unit) PaperDollFrame_SetStat(statFrame, unit, LE_UNIT_STAT_INTELLECT); end
  127. },
  128. ["STAMINA"] = {
  129. updateFunc = function(statFrame, unit) PaperDollFrame_SetStat(statFrame, unit, LE_UNIT_STAT_STAMINA); end
  130. },
  131. -- Enhancements
  132. ["CRITCHANCE"] = {
  133. updateFunc = function(statFrame, unit) PaperDollFrame_SetCritChance(statFrame, unit); end
  134. },
  135. ["HASTE"] = {
  136. updateFunc = function(statFrame, unit) PaperDollFrame_SetHaste(statFrame, unit); end
  137. },
  138. ["MASTERY"] = {
  139. updateFunc = function(statFrame, unit) PaperDollFrame_SetMastery(statFrame, unit); end
  140. },
  141. ["VERSATILITY"] = {
  142. updateFunc = function(statFrame, unit) PaperDollFrame_SetVersatility(statFrame, unit); end
  143. },
  144. ["LIFESTEAL"] = {
  145. updateFunc = function(statFrame, unit) PaperDollFrame_SetLifesteal(statFrame, unit); end
  146. },
  147. ["AVOIDANCE"] = {
  148. updateFunc = function(statFrame, unit) PaperDollFrame_SetAvoidance(statFrame, unit); end
  149. },
  150. ["SPEED"] = {
  151. updateFunc = function(statFrame, unit) PaperDollFrame_SetSpeed(statFrame, unit); end
  152. },
  153. -- Attack
  154. ["ATTACK_DAMAGE"] = {
  155. updateFunc = function(statFrame, unit) PaperDollFrame_SetDamage(statFrame, unit); end
  156. },
  157. ["ATTACK_AP"] = {
  158. updateFunc = function(statFrame, unit) PaperDollFrame_SetAttackPower(statFrame, unit); end
  159. },
  160. ["ATTACK_ATTACKSPEED"] = {
  161. updateFunc = function(statFrame, unit) PaperDollFrame_SetAttackSpeed(statFrame, unit); end
  162. },
  163. ["ENERGY_REGEN"] = {
  164. updateFunc = function(statFrame, unit) PaperDollFrame_SetEnergyRegen(statFrame, unit); end
  165. },
  166. ["RUNE_REGEN"] = {
  167. updateFunc = function(statFrame, unit) PaperDollFrame_SetRuneRegen(statFrame, unit); end
  168. },
  169. ["FOCUS_REGEN"] = {
  170. updateFunc = function(statFrame, unit) PaperDollFrame_SetFocusRegen(statFrame, unit); end
  171. },
  172. -- Spell
  173. ["SPELLPOWER"] = {
  174. updateFunc = function(statFrame, unit) PaperDollFrame_SetSpellPower(statFrame, unit); end
  175. },
  176. ["MANAREGEN"] = {
  177. updateFunc = function(statFrame, unit) PaperDollFrame_SetManaRegen(statFrame, unit); end
  178. },
  179. -- Defense
  180. ["ARMOR"] = {
  181. updateFunc = function(statFrame, unit) PaperDollFrame_SetArmor(statFrame, unit); end
  182. },
  183. ["DODGE"] = {
  184. updateFunc = function(statFrame, unit) PaperDollFrame_SetDodge(statFrame, unit); end
  185. },
  186. ["PARRY"] = {
  187. updateFunc = function(statFrame, unit) PaperDollFrame_SetParry(statFrame, unit); end
  188. },
  189. ["BLOCK"] = {
  190. updateFunc = function(statFrame, unit) PaperDollFrame_SetBlock(statFrame, unit); end
  191. },
  192. ["STAGGER"] = {
  193. updateFunc = function(statFrame, unit) PaperDollFrame_SetStagger(statFrame, unit); end
  194. },
  195. };
  196. -- primary: only show the 1 for the player's current spec
  197. -- roles: only show if the player's current spec is one of the roles
  198. -- hideAt: only show if it's not this value
  199. -- showFunc: only show if this function returns true (Note: make sure whatever your function is dependent on also triggers an update when it changes)
  200. PAPERDOLL_STATCATEGORIES= {
  201. [1] = {
  202. categoryFrame = "AttributesCategory",
  203. stats = {
  204. [1] = { stat = "STRENGTH", primary = LE_UNIT_STAT_STRENGTH },
  205. [2] = { stat = "AGILITY", primary = LE_UNIT_STAT_AGILITY },
  206. [3] = { stat = "INTELLECT", primary = LE_UNIT_STAT_INTELLECT },
  207. [4] = { stat = "STAMINA" },
  208. [5] = { stat = "ARMOR" },
  209. [6] = { stat = "STAGGER", hideAt = 0, roles = { "TANK" }},
  210. [7] = { stat = "MANAREGEN", roles = { "HEALER" } },
  211. },
  212. },
  213. [2] = {
  214. categoryFrame = "EnhancementsCategory",
  215. stats = {
  216. { stat = "CRITCHANCE", hideAt = 0 },
  217. { stat = "HASTE", hideAt = 0 },
  218. { stat = "MASTERY", hideAt = 0 },
  219. { stat = "VERSATILITY", hideAt = 0 },
  220. { stat = "LIFESTEAL", hideAt = 0 },
  221. { stat = "AVOIDANCE", hideAt = 0 },
  222. { stat = "SPEED", hideAt = 0 },
  223. { stat = "DODGE", roles = { "TANK" } },
  224. { stat = "PARRY", hideAt = 0, roles = { "TANK" } },
  225. { stat = "BLOCK", hideAt = 0, showFunc = C_PaperDollInfo.OffhandHasShield },
  226. },
  227. },
  228. };
  229. -- Task 67449: Hit and Expertise are being removed from items, so all players receive a 7.5% reduced miss chance,
  230. -- a 15% reduced spell miss chance, a 7.5% reduced enemy dodge chance, and a 4.5% reduced enemy parry chance
  231. BASE_MISS_CHANCE_PHYSICAL = {
  232. [0] = -4.5;
  233. [1] = -3.0;
  234. [2] = -1.5;
  235. [3] = 0.0;
  236. };
  237. BASE_MISS_CHANCE_SPELL = {
  238. [0] = -9.0;
  239. [1] = -6.0;
  240. [2] = -3.0;
  241. [3] = 0.0;
  242. };
  243. BASE_ENEMY_DODGE_CHANCE = {
  244. [0] = -4.5;
  245. [1] = -3.0;
  246. [2] = -1.5;
  247. [3] = 0.0;
  248. };
  249. BASE_ENEMY_PARRY_CHANCE = {
  250. [0] = -1.5;
  251. [1] = 0.0;
  252. [2] = 1.5;
  253. [3] = 3.0;
  254. };
  255. DUAL_WIELD_HIT_PENALTY = 19.0;
  256. function PaperDollFrame_OnLoad(self)
  257. self:RegisterEvent("PLAYER_ENTERING_WORLD");
  258. self:RegisterEvent("CHARACTER_POINTS_CHANGED");
  259. self:RegisterEvent("UNIT_MODEL_CHANGED");
  260. self:RegisterEvent("UNIT_LEVEL");
  261. self:RegisterEvent("UNIT_STATS");
  262. self:RegisterEvent("UNIT_RANGEDDAMAGE");
  263. self:RegisterEvent("UNIT_ATTACK_POWER");
  264. self:RegisterEvent("UNIT_RANGED_ATTACK_POWER");
  265. self:RegisterEvent("UNIT_ATTACK");
  266. self:RegisterEvent("UNIT_SPELL_HASTE");
  267. self:RegisterEvent("UNIT_RESISTANCES");
  268. self:RegisterEvent("PLAYER_GUILD_UPDATE");
  269. self:RegisterEvent("SKILL_LINES_CHANGED");
  270. self:RegisterEvent("COMBAT_RATING_UPDATE");
  271. self:RegisterEvent("MASTERY_UPDATE");
  272. self:RegisterEvent("SPEED_UPDATE");
  273. self:RegisterEvent("LIFESTEAL_UPDATE");
  274. self:RegisterEvent("AVOIDANCE_UPDATE");
  275. self:RegisterEvent("KNOWN_TITLES_UPDATE");
  276. self:RegisterEvent("UNIT_NAME_UPDATE");
  277. self:RegisterEvent("PLAYER_TALENT_UPDATE");
  278. self:RegisterEvent("BAG_UPDATE");
  279. self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED");
  280. self:RegisterEvent("PLAYER_AVG_ITEM_LEVEL_UPDATE");
  281. self:RegisterEvent("PLAYER_DAMAGE_DONE_MODS");
  282. self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED");
  283. self:RegisterUnitEvent("UNIT_DAMAGE", "player");
  284. self:RegisterUnitEvent("UNIT_ATTACK_SPEED", "player");
  285. self:RegisterUnitEvent("UNIT_MAXHEALTH", "player");
  286. self:RegisterUnitEvent("UNIT_AURA", "player");
  287. self:RegisterEvent("SPELL_POWER_CHANGED");
  288. self:RegisterEvent("CHARACTER_ITEM_FIXUP_NOTIFICATION");
  289. self:RegisterEvent("TRIAL_STATUS_UPDATE");
  290. self:RegisterEvent("PLAYER_TARGET_CHANGED");
  291. -- flyout settings
  292. PaperDollItemsFrame.flyoutSettings = {
  293. onClickFunc = PaperDollFrameItemFlyoutButton_OnClick,
  294. getItemsFunc = PaperDollFrameItemFlyout_GetItems,
  295. postGetItemsFunc = PaperDollFrameItemFlyout_PostGetItems,
  296. hasPopouts = true,
  297. parent = PaperDollFrame,
  298. anchorX = 0,
  299. anchorY = -3,
  300. verticalAnchorX = 0,
  301. verticalAnchorY = 0,
  302. };
  303. -- trial edition
  304. local width = CharacterTrialLevelErrorText:GetWidth();
  305. if ( width > 190 ) then
  306. CharacterTrialLevelErrorText:SetPoint("TOP", CharacterLevelText, "BOTTOM", -((width-190)/2), 2);
  307. end
  308. if( GameLimitedMode_IsActive() ) then
  309. CharacterTrialLevelErrorText:SetText(CAPPED_LEVEL_TRIAL);
  310. end
  311. end
  312. function PaperDoll_IsEquippedSlot(slot)
  313. if ( slot ) then
  314. slot = tonumber(slot);
  315. if ( slot ) then
  316. return slot >= EQUIPPED_FIRST and slot <= EQUIPPED_LAST;
  317. end
  318. end
  319. return false;
  320. end
  321. -- This makes sure the update only happens once at the end of the frame
  322. function PaperDollFrame_QueuedUpdate(self)
  323. self:SetScript("OnUpdate", nil);
  324. PaperDollFrame_UpdateStats();
  325. end
  326. function PaperDollFrame_OnEvent(self, event, ...)
  327. local unit = ...;
  328. if ( event == "PLAYER_ENTERING_WORLD" or
  329. event == "UNIT_MODEL_CHANGED" and unit == "player" ) then
  330. CharacterModelFrame:SetUnit("player", false);
  331. PaperDollFrame_UpdateInventoryFixupComplete(self);
  332. return;
  333. elseif ( event == "KNOWN_TITLES_UPDATE" or (event == "UNIT_NAME_UPDATE" and unit == "player")) then
  334. if (PaperDollTitlesPane:IsShown()) then
  335. PaperDollTitlesPane_Update();
  336. end
  337. elseif ( event == "CHARACTER_ITEM_FIXUP_NOTIFICATION" ) then
  338. local fixupVersion = ...
  339. PaperDollFrame_UpdateInventoryFixupComplete(self, fixupVersion);
  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;
  568. spec = GetSpecialization();
  569. local role = GetSpecializationRole(spec);
  570. if (spec) then
  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. if (UnitLevel("player") < SHOW_MASTERY_LEVEL) then
  1064. statFrame.numericValue = 0;
  1065. statFrame:Hide();
  1066. return;
  1067. end
  1068. local mastery = GetMasteryEffect();
  1069. PaperDollFrame_SetLabelAndText(statFrame, STAT_MASTERY, mastery, true, mastery);
  1070. statFrame.onEnterFunc = Mastery_OnEnter;
  1071. statFrame:Show();
  1072. end
  1073. -- Task 68016: Speed increases run speed
  1074. function PaperDollFrame_SetSpeed(statFrame, unit)
  1075. if ( unit ~= "player" ) then
  1076. statFrame:Hide();
  1077. return;
  1078. end
  1079. local speed = GetSpeed();
  1080. PaperDollFrame_SetLabelAndText(statFrame, STAT_SPEED, speed, true, speed);
  1081. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_SPEED) .. " " .. format("%.2F%%", speed) .. FONT_COLOR_CODE_CLOSE;
  1082. statFrame.tooltip2 = format(CR_SPEED_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_SPEED)), GetCombatRatingBonus(CR_SPEED));
  1083. statFrame:Show();
  1084. end
  1085. -- Task 68016: Lifesteal returns a portion of all damage done as health
  1086. function PaperDollFrame_SetLifesteal(statFrame, unit)
  1087. if ( unit ~= "player" ) then
  1088. statFrame:Hide();
  1089. return;
  1090. end
  1091. local lifesteal = GetLifesteal();
  1092. PaperDollFrame_SetLabelAndText(statFrame, STAT_LIFESTEAL, lifesteal, true, lifesteal);
  1093. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_LIFESTEAL) .. " " .. format("%.2F%%", lifesteal) .. FONT_COLOR_CODE_CLOSE;
  1094. statFrame.tooltip2 = format(CR_LIFESTEAL_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_LIFESTEAL)), GetCombatRatingBonus(CR_LIFESTEAL));
  1095. statFrame:Show();
  1096. end
  1097. -- Task 68016: Avoidance reduces AoE damage taken
  1098. function PaperDollFrame_SetAvoidance(statFrame, unit)
  1099. if ( unit ~= "player" ) then
  1100. statFrame:Hide();
  1101. return;
  1102. end
  1103. local avoidance = GetAvoidance();
  1104. PaperDollFrame_SetLabelAndText(statFrame, STAT_AVOIDANCE, avoidance, true, avoidance);
  1105. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_AVOIDANCE) .. " " .. format("%.2F%%", avoidance) .. FONT_COLOR_CODE_CLOSE;
  1106. statFrame.tooltip2 = format(CR_AVOIDANCE_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_AVOIDANCE)), GetCombatRatingBonus(CR_AVOIDANCE));
  1107. statFrame:Show();
  1108. end
  1109. function PaperDollFrame_SetVersatility(statFrame, unit)
  1110. if ( unit ~= "player" ) then
  1111. statFrame:Hide();
  1112. return;
  1113. end
  1114. local versatility = GetCombatRating(CR_VERSATILITY_DAMAGE_DONE);
  1115. local versatilityDamageBonus = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_DONE) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_DONE);
  1116. local versatilityDamageTakenReduction = GetCombatRatingBonus(CR_VERSATILITY_DAMAGE_TAKEN) + GetVersatilityBonus(CR_VERSATILITY_DAMAGE_TAKEN);
  1117. PaperDollFrame_SetLabelAndText(statFrame, STAT_VERSATILITY, versatilityDamageBonus, true, versatilityDamageBonus);
  1118. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_VERSATILITY)..FONT_COLOR_CODE_CLOSE;
  1119. statFrame.tooltip2 = format(CR_VERSATILITY_TOOLTIP, versatilityDamageBonus, versatilityDamageTakenReduction, BreakUpLargeNumbers(versatility), versatilityDamageBonus, versatilityDamageTakenReduction);
  1120. statFrame:Show();
  1121. end
  1122. function PaperDollFrame_SetItemLevel(statFrame, unit)
  1123. if ( unit ~= "player" ) then
  1124. statFrame:Hide();
  1125. return;
  1126. end
  1127. local avgItemLevel, avgItemLevelEquipped = GetAverageItemLevel();
  1128. local minItemLevel = C_PaperDollInfo.GetMinItemLevel();
  1129. local displayItemLevel = math.max(minItemLevel or 0, avgItemLevelEquipped);
  1130. displayItemLevel = floor(displayItemLevel);
  1131. avgItemLevel = floor(avgItemLevel);
  1132. PaperDollFrame_SetLabelAndText(statFrame, STAT_AVERAGE_ITEM_LEVEL, displayItemLevel, false, displayItemLevel);
  1133. statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_AVERAGE_ITEM_LEVEL).." "..avgItemLevel;
  1134. if ( displayItemLevel ~= avgItemLevel ) then
  1135. statFrame.tooltip = statFrame.tooltip .. " " .. format(STAT_AVERAGE_ITEM_LEVEL_EQUIPPED, avgItemLevelEquipped);
  1136. end
  1137. statFrame.tooltip = statFrame.tooltip .. FONT_COLOR_CODE_CLOSE;
  1138. statFrame.tooltip2 = STAT_AVERAGE_ITEM_LEVEL_TOOLTIP;
  1139. end
  1140. function MovementSpeed_OnEnter(statFrame)
  1141. GameTooltip:SetOwner(statFrame, "ANCHOR_RIGHT");
  1142. GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_MOVEMENT_SPEED).." "..format("%d%%", statFrame.speed+0.5)..FONT_COLOR_CODE_CLOSE);
  1143. GameTooltip:AddLine(format(STAT_MOVEMENT_GROUND_TOOLTIP, statFrame.runSpeed+0.5));
  1144. if (statFrame.unit ~= "pet") then
  1145. GameTooltip:AddLine(format(STAT_MOVEMENT_FLIGHT_TOOLTIP, statFrame.flightSpeed+0.5));
  1146. end
  1147. GameTooltip:AddLine(format(STAT_MOVEMENT_SWIM_TOOLTIP, statFrame.swimSpeed+0.5));
  1148. GameTooltip:AddLine(" ");
  1149. GameTooltip:AddLine(format(CR_SPEED_TOOLTIP, BreakUpLargeNumbers(GetCombatRating(CR_SPEED)), GetCombatRatingBonus(CR_SPEED)));
  1150. GameTooltip:Show();
  1151. statFrame.UpdateTooltip = MovementSpeed_OnEnter;
  1152. end
  1153. function MovementSpeed_OnUpdate(statFrame, elapsedTime)
  1154. local unit = statFrame.unit;
  1155. local _, runSpeed, flightSpeed, swimSpeed = GetUnitSpeed(unit);
  1156. runSpeed = runSpeed/BASE_MOVEMENT_SPEED*100;
  1157. flightSpeed = flightSpeed/BASE_MOVEMENT_SPEED*100;
  1158. swimSpeed = swimSpeed/BASE_MOVEMENT_SPEED*100;
  1159. -- Pets seem to always actually use run speed
  1160. if (unit == "pet") then
  1161. swimSpeed = runSpeed;
  1162. end
  1163. -- Determine whether to display running, flying, or swimming speed
  1164. local speed = runSpeed;
  1165. local swimming = IsSwimming(unit);
  1166. if (swimming) then
  1167. speed = swimSpeed;
  1168. elseif (IsFlying(unit)) then
  1169. speed = flightSpeed;
  1170. end
  1171. -- Hack so that your speed doesn't appear to change when jumping out of the water
  1172. if (IsFalling(unit)) then
  1173. if (statFrame.wasSwimming) then
  1174. speed = swimSpeed;
  1175. end
  1176. else
  1177. statFrame.wasSwimming = swimming;
  1178. end
  1179. local valueText = format("%d%%", speed+0.5);
  1180. PaperDollFrame_SetLabelAndText(statFrame, STAT_MOVEMENT_SPEED, valueText, false, speed);
  1181. statFrame.speed = speed;
  1182. statFrame.runSpeed = runSpeed;
  1183. statFrame.flightSpeed = flightSpeed;
  1184. statFrame.swimSpeed = swimSpeed;
  1185. end
  1186. function PaperDollFrame_SetMovementSpeed(statFrame, unit)
  1187. if ( unit ~= "player" ) then
  1188. statFrame:Hide();
  1189. return;
  1190. end
  1191. statFrame.wasSwimming = nil;
  1192. statFrame.unit = unit;
  1193. statFrame:Show();
  1194. MovementSpeed_OnUpdate(statFrame);
  1195. statFrame.onEnterFunc = MovementSpeed_OnEnter;
  1196. end
  1197. function CharacterSpellBonusDamage_OnEnter(self)
  1198. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1199. GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, self.tooltip).." "..BreakUpLargeNumbers(self.minModifier)..FONT_COLOR_CODE_CLOSE);
  1200. for i=2, MAX_SPELL_SCHOOLS do
  1201. if (self.bonusDamage and self.bonusDamage[i] ~= self.minModifier) then
  1202. GameTooltip:AddLine(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, _G["DAMAGE_SCHOOL"..i]).." "..self.bonusDamage[i]..FONT_COLOR_CODE_CLOSE);
  1203. GameTooltip:AddTexture("Interface\\PaperDollInfoFrame\\SpellSchoolIcon"..i);
  1204. end
  1205. end
  1206. GameTooltip:AddLine(self.tooltip2);
  1207. if (self.bonusDamage and self.unit == "player") then
  1208. local petStr, damage;
  1209. if (self.bonusDamage[6] == self.minModifier and self.bonusDamage[3] == self.minModifier) then
  1210. petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG;
  1211. damage = self.minModifier;
  1212. elseif( self.bonusDamage[6] > self.bonusDamage[3] ) then
  1213. petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_SHADOW;
  1214. damage = self.bonusDamage[6];
  1215. else
  1216. petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_FIRE;
  1217. damage = self.bonusDamage[3];
  1218. end
  1219. local petBonusAP = ComputePetBonus("PET_BONUS_SPELLDMG_TO_AP", damage );
  1220. local petBonusDmg = ComputePetBonus("PET_BONUS_SPELLDMG_TO_SPELLDMG", damage );
  1221. if( petBonusAP > 0 or petBonusDmg > 0 ) then
  1222. GameTooltip:AddLine(format(petStr, petBonusAP, petBonusDmg), nil, nil, nil, true );
  1223. end
  1224. end
  1225. GameTooltip:Show();
  1226. end
  1227. local function ShouldShowExaltedPlusHelpTip()
  1228. if (GetCVarBitfield("closedInfoFrames", LE_FRAME_TUTORIAL_REPUTATION_EXALTED_PLUS)) then
  1229. return false;
  1230. end
  1231. local numFactions = GetNumFactions();
  1232. for i=1, numFactions do
  1233. local name, description, standingID, barMin, barMax, barValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild, factionID, hasBonusRepGain, canBeLFGBonus = GetFactionInfo(i);
  1234. if (factionID and C_Reputation.IsFactionParagon(factionID) ) then
  1235. return true;
  1236. end
  1237. end
  1238. return false;
  1239. end
  1240. function PaperDollFrame_OnShow(self)
  1241. CharacterStatsPane.initialOffsetY = 0;
  1242. CharacterFrame:SetTitle(UnitPVPName("player"));
  1243. PaperDollFrame_SetLevel();
  1244. PaperDollFrame_UpdateStats();
  1245. CharacterFrame_Expand();
  1246. SetPaperDollBackground(CharacterModelFrame, "player");
  1247. PaperDollBgDesaturate(true);
  1248. PaperDollSidebarTabs:Show();
  1249. PaperDollFrame_UpdateInventoryFixupComplete(self);
  1250. self:GetParent().ReputationTabHelpBox:SetShown(ShouldShowExaltedPlusHelpTip());
  1251. end
  1252. function PaperDollFrame_OnHide(self)
  1253. CharacterStatsPane.initialOffsetY = 0;
  1254. CharacterFrame_Collapse();
  1255. PaperDollSidebarTabs:Hide();
  1256. PaperDollFrame_HideInventoryFixupComplete(self);
  1257. end
  1258. function PaperDollFrame_ClearIgnoredSlots()
  1259. C_EquipmentSet.ClearIgnoredSlotsForSave();
  1260. for k, button in next, itemSlotButtons do
  1261. if ( button.ignored ) then
  1262. button.ignored = nil;
  1263. PaperDollItemSlotButton_Update(button);
  1264. end
  1265. end
  1266. end
  1267. function PaperDollFrame_IgnoreSlotsForSet(setID)
  1268. local set = C_EquipmentSet.GetIgnoredSlots(setID);
  1269. for slot, ignored in pairs(set) do
  1270. if ( ignored ) then
  1271. C_EquipmentSet.IgnoreSlotForSave(slot);
  1272. itemSlotButtons[slot].ignored = true;
  1273. else
  1274. C_EquipmentSet.UnignoreSlotForSave(slot);
  1275. itemSlotButtons[slot].ignored = false;
  1276. end
  1277. PaperDollItemSlotButton_Update(itemSlotButtons[slot]);
  1278. end
  1279. end
  1280. function PaperDollFrame_IgnoreSlot(slot)
  1281. C_EquipmentSet.IgnoreSlotForSave(slot);
  1282. itemSlotButtons[slot].ignored = true;
  1283. PaperDollItemSlotButton_Update(itemSlotButtons[slot]);
  1284. end
  1285. function PaperDollFrame_UpdateCorruptedItemGlows(glow)
  1286. for _, button in next, itemSlotButtons do
  1287. if button.HasPaperDollAzeriteItemOverlay then
  1288. button:UpdateCorruptedGlow(ItemLocation:CreateFromEquipmentSlot(button:GetID()), glow);
  1289. end
  1290. end
  1291. end
  1292. function PaperDollItemSlotButton_OnLoad(self)
  1293. self:RegisterForDrag("LeftButton");
  1294. self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
  1295. local slotName = self:GetName();
  1296. local id, textureName, checkRelic = GetInventorySlotInfo(strsub(slotName,10));
  1297. self:SetID(id);
  1298. local texture = _G[slotName.."IconTexture"];
  1299. texture:SetTexture(textureName);
  1300. self.backgroundTextureName = textureName;
  1301. self.checkRelic = checkRelic;
  1302. self.UpdateTooltip = PaperDollItemSlotButton_OnEnter;
  1303. itemSlotButtons[id] = self;
  1304. self.verticalFlyout = VERTICAL_FLYOUTS[id];
  1305. local popoutButton = self.popoutButton;
  1306. if ( popoutButton ) then
  1307. if ( self.verticalFlyout ) then
  1308. popoutButton:SetHeight(16);
  1309. popoutButton:SetWidth(38);
  1310. popoutButton:GetNormalTexture():SetTexCoord(0.15625, 0.84375, 0.5, 0);
  1311. popoutButton:GetHighlightTexture():SetTexCoord(0.15625, 0.84375, 1, 0.5);
  1312. popoutButton:ClearAllPoints();
  1313. popoutButton:SetPoint("TOP", self, "BOTTOM", 0, 4);
  1314. else
  1315. popoutButton:SetHeight(38);
  1316. popoutButton:SetWidth(16);
  1317. popoutButton:GetNormalTexture():SetTexCoord(0.15625, 0.5, 0.84375, 0.5, 0.15625, 0, 0.84375, 0);
  1318. popoutButton:GetHighlightTexture():SetTexCoord(0.15625, 1, 0.84375, 1, 0.15625, 0.5, 0.84375, 0.5);
  1319. popoutButton:ClearAllPoints();
  1320. popoutButton:SetPoint("LEFT", self, "RIGHT", -8, 0);
  1321. end
  1322. end
  1323. end
  1324. local PAPERDOLL_FRAME_EVENTS = {
  1325. "PLAYER_EQUIPMENT_CHANGED",
  1326. "MERCHANT_UPDATE",
  1327. "PLAYERBANKSLOTS_CHANGED",
  1328. "ITEM_LOCK_CHANGED",
  1329. "CURSOR_UPDATE",
  1330. "UPDATE_INVENTORY_ALERTS",
  1331. "AZERITE_ITEM_POWER_LEVEL_CHANGED",
  1332. "AZERITE_EMPOWERED_ITEM_SELECTION_UPDATED",
  1333. };
  1334. function PaperDollItemSlotButton_OnShow(self, isBag)
  1335. FrameUtil.RegisterFrameForEvents(self, PAPERDOLL_FRAME_EVENTS);
  1336. if ( not isBag ) then
  1337. self:RegisterEvent("BAG_UPDATE_COOLDOWN");
  1338. end
  1339. PaperDollItemSlotButton_Update(self);
  1340. end
  1341. function PaperDollItemSlotButton_OnHide(self)
  1342. FrameUtil.UnregisterFrameForEvents(self, PAPERDOLL_FRAME_EVENTS);
  1343. self:UnregisterEvent("BAG_UPDATE_COOLDOWN");
  1344. end
  1345. function PaperDollItemSlotButton_OnEvent(self, event, ...)
  1346. if ( event == "PLAYER_EQUIPMENT_CHANGED" ) then
  1347. local equipmentSlot, hasCurrent = ...;
  1348. if ( self:GetID() == equipmentSlot ) then
  1349. PaperDollItemSlotButton_Update(self);
  1350. end
  1351. elseif ( event == "ITEM_LOCK_CHANGED" ) then
  1352. local bagOrSlotIndex, slotIndex = ...;
  1353. if ( not slotIndex and bagOrSlotIndex == self:GetID() ) then
  1354. PaperDollItemSlotButton_UpdateLock(self);
  1355. end
  1356. elseif ( event == "BAG_UPDATE_COOLDOWN" ) then
  1357. PaperDollItemSlotButton_Update(self);
  1358. elseif ( event == "CURSOR_UPDATE" ) then
  1359. if ( CursorCanGoInSlot(self:GetID()) ) then
  1360. self:LockHighlight();
  1361. else
  1362. self:UnlockHighlight();
  1363. end
  1364. elseif ( event == "UPDATE_INVENTORY_ALERTS" ) then
  1365. PaperDollItemSlotButton_Update(self);
  1366. elseif ( event == "MODIFIER_STATE_CHANGED" ) then
  1367. if ( IsModifiedClick("SHOWITEMFLYOUT") and self:IsMouseOver() ) then
  1368. PaperDollItemSlotButton_OnEnter(self);
  1369. end
  1370. elseif event == "AZERITE_ITEM_POWER_LEVEL_CHANGED" then
  1371. local azeriteItemLocation, oldPowerLevel, newPowerLevel = ...;
  1372. if azeriteItemLocation:IsEqualToEquipmentSlot(self:GetID()) then
  1373. PaperDollItemSlotButton_Update(self);
  1374. end
  1375. elseif event == "AZERITE_EMPOWERED_ITEM_SELECTION_UPDATED" then
  1376. local item = ...;
  1377. PaperDollItemSlotButton_Update(self);
  1378. end
  1379. end
  1380. function PaperDollItemSlotButton_OnClick(self, button)
  1381. MerchantFrame_ResetRefundItem();
  1382. if ( button == "LeftButton" ) then
  1383. local type = GetCursorInfo();
  1384. if ( type == "merchant" and MerchantFrame.extendedCost ) then
  1385. MerchantFrame_ConfirmExtendedItemCost(MerchantFrame.extendedCost);
  1386. else
  1387. PickupInventoryItem(self:GetID());
  1388. if ( CursorHasItem() ) then
  1389. MerchantFrame_SetRefundItem(self, 1);
  1390. end
  1391. end
  1392. else
  1393. UseInventoryItem(self:GetID());
  1394. end
  1395. end
  1396. function PaperDollItemSlotButton_OnModifiedClick(self, button)
  1397. if ( IsModifiedClick("EXPANDITEM") ) then
  1398. local itemLocation = ItemLocation:CreateFromEquipmentSlot(self:GetID());
  1399. if C_Item.DoesItemExist(itemLocation) then
  1400. if C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(itemLocation) then
  1401. if C_Item.CanViewItemPowers(itemLocation) then
  1402. OpenAzeriteEmpoweredItemUIFromItemLocation(itemLocation);
  1403. else
  1404. UIErrorsFrame:AddExternalErrorMessage(AZERITE_PREVIEW_UNAVAILABLE_FOR_CLASS);
  1405. end
  1406. return;
  1407. end
  1408. local heartItemLocation = C_AzeriteItem.FindActiveAzeriteItem();
  1409. if heartItemLocation and heartItemLocation:IsEqualTo(itemLocation) then
  1410. OpenAzeriteEssenceUIFromItemLocation(itemLocation);
  1411. return;
  1412. end
  1413. SocketInventoryItem(self:GetID());
  1414. end
  1415. return;
  1416. end
  1417. if ( HandleModifiedItemClick(GetInventoryItemLink("player", self:GetID())) ) then
  1418. return;
  1419. end
  1420. end
  1421. function PaperDollItemSlotButton_Update(self)
  1422. local textureName = GetInventoryItemTexture("player", self:GetID());
  1423. local cooldown = _G[self:GetName().."Cooldown"];
  1424. local hasItem = textureName ~= nil;
  1425. if ( hasItem ) then
  1426. SetItemButtonTexture(self, textureName);
  1427. SetItemButtonCount(self, GetInventoryItemCount("player", self:GetID()));
  1428. if ( GetInventoryItemBroken("player", self:GetID())
  1429. or GetInventoryItemEquippedUnusable("player", self:GetID()) ) then
  1430. SetItemButtonTextureVertexColor(self, 0.9, 0, 0);
  1431. SetItemButtonNormalTextureVertexColor(self, 0.9, 0, 0);
  1432. else
  1433. SetItemButtonTextureVertexColor(self, 1.0, 1.0, 1.0);
  1434. SetItemButtonNormalTextureVertexColor(self, 1.0, 1.0, 1.0);
  1435. end
  1436. if ( cooldown ) then
  1437. local start, duration, enable = GetInventoryItemCooldown("player", self:GetID());
  1438. CooldownFrame_Set(cooldown, start, duration, enable);
  1439. end
  1440. else
  1441. local textureName = self.backgroundTextureName;
  1442. if ( self.checkRelic and UnitHasRelicSlot("player") ) then
  1443. textureName = "Interface\\Paperdoll\\UI-PaperDoll-Slot-Relic.blp";
  1444. end
  1445. SetItemButtonTexture(self, textureName);
  1446. SetItemButtonCount(self, 0);
  1447. SetItemButtonTextureVertexColor(self, 1.0, 1.0, 1.0);
  1448. SetItemButtonNormalTextureVertexColor(self, 1.0, 1.0, 1.0);
  1449. if ( cooldown ) then
  1450. cooldown:Hide();
  1451. end
  1452. end
  1453. local quality = GetInventoryItemQuality("player", self:GetID());
  1454. local suppressOverlays = self.HasPaperDollAzeriteItemOverlay;
  1455. SetItemButtonQuality(self, quality, GetInventoryItemID("player", self:GetID()), suppressOverlays);
  1456. if (not PaperDollEquipmentManagerPane:IsShown()) then
  1457. self.ignored = nil;
  1458. end
  1459. if self.ignoreTexture then
  1460. self.ignoreTexture:SetShown(self.ignored);
  1461. end
  1462. if self.HasPaperDollAzeriteItemOverlay then
  1463. self:SetAzeriteItem(hasItem and ItemLocation:CreateFromEquipmentSlot(self:GetID()) or nil);
  1464. end
  1465. PaperDollItemSlotButton_UpdateLock(self);
  1466. -- Update repair all button status
  1467. MerchantFrame_UpdateGuildBankRepair();
  1468. MerchantFrame_UpdateCanRepairAll();
  1469. end
  1470. function PaperDollItemSlotButton_UpdateLock(self)
  1471. SetItemButtonDesaturated(self, IsInventoryItemLocked(self:GetID()));
  1472. end
  1473. function PaperDollItemSlotButton_OnEnter(self)
  1474. self:RegisterEvent("MODIFIER_STATE_CHANGED");
  1475. EquipmentFlyout_UpdateFlyout(self);
  1476. if ( not EquipmentFlyout_SetTooltipAnchor(self) ) then
  1477. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1478. end
  1479. local hasItem, hasCooldown, repairCost = GameTooltip:SetInventoryItem("player", self:GetID(), nil, true);
  1480. if ( not hasItem ) then
  1481. local text = _G[strupper(strsub(self:GetName(), 10))];
  1482. if ( self.checkRelic and UnitHasRelicSlot("player") ) then
  1483. text = RELICSLOT;
  1484. end
  1485. GameTooltip:SetText(text);
  1486. end
  1487. if ( InRepairMode() and repairCost and (repairCost > 0) ) then
  1488. GameTooltip:AddLine(REPAIR_COST, nil, nil, nil, true);
  1489. SetTooltipMoney(GameTooltip, repairCost);
  1490. GameTooltip:Show();
  1491. else
  1492. CursorUpdate(self);
  1493. end
  1494. end
  1495. function PaperDollItemSlotButton_OnLeave(self)
  1496. self:UnregisterEvent("MODIFIER_STATE_CHANGED");
  1497. GameTooltip:Hide();
  1498. ResetCursor();
  1499. end
  1500. function PaperDollStatTooltip(self)
  1501. if ( not self.tooltip ) then
  1502. return;
  1503. end
  1504. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1505. GameTooltip:SetText(self.tooltip);
  1506. if ( self.tooltip2 ) then
  1507. GameTooltip:AddLine(self.tooltip2, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true);
  1508. end
  1509. if ( self.tooltip3 ) then
  1510. GameTooltip:AddLine(self.tooltip3, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true);
  1511. end
  1512. GameTooltip:Show();
  1513. end
  1514. function FormatPaperDollTooltipStat(name, base, posBuff, negBuff)
  1515. local effective = BreakUpLargeNumbers(max(0,base + posBuff + negBuff));
  1516. local text = HIGHLIGHT_FONT_COLOR_CODE..name.." "..effective;
  1517. if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
  1518. text = text..FONT_COLOR_CODE_CLOSE;
  1519. else
  1520. if ( posBuff > 0 or negBuff < 0 ) then
  1521. text = text.." ("..base..FONT_COLOR_CODE_CLOSE;
  1522. end
  1523. if ( posBuff > 0 ) then
  1524. text = text..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE;
  1525. end
  1526. if ( negBuff < 0 ) then
  1527. text = text..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE;
  1528. end
  1529. if ( posBuff > 0 or negBuff < 0 ) then
  1530. text = text..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
  1531. end
  1532. end
  1533. return text;
  1534. end
  1535. function PaperDollFormatStat(name, base, posBuff, negBuff)
  1536. local effectiveText = BreakUpLargeNumbers(max(0,base + posBuff + negBuff));
  1537. local text = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT,name).." "..effectiveText;
  1538. if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
  1539. text = text..FONT_COLOR_CODE_CLOSE;
  1540. else
  1541. if ( posBuff > 0 or negBuff < 0 ) then
  1542. text = text.." ("..base..FONT_COLOR_CODE_CLOSE;
  1543. end
  1544. if ( posBuff > 0 ) then
  1545. text = text..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE;
  1546. end
  1547. if ( negBuff < 0 ) then
  1548. text = text..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE;
  1549. end
  1550. if ( posBuff > 0 or negBuff < 0 ) then
  1551. text = text..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
  1552. end
  1553. -- if there is a negative buff then show the main number in red, even if there are
  1554. -- positive buffs. Otherwise show the number in green
  1555. if ( negBuff < 0 and not GetPVPGearStatRules() ) then
  1556. effectiveText = RED_FONT_COLOR_CODE..effectiveText..FONT_COLOR_CODE_CLOSE;
  1557. end
  1558. end
  1559. return effectiveText, text;
  1560. end
  1561. function CharacterAttackFrame_OnEnter(self)
  1562. -- Main hand weapon
  1563. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1564. GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1565. GameTooltip:AddLine(self.weaponSkill);
  1566. GameTooltip:AddLine(self.weaponRating);
  1567. -- Check for offhand weapon
  1568. if ( self.offhandSkill ) then
  1569. GameTooltip:AddLine("\n");
  1570. GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1571. GameTooltip:AddLine(self.offhandSkill);
  1572. GameTooltip:AddLine(self.offhandRating);
  1573. end
  1574. GameTooltip:Show();
  1575. end
  1576. function CharacterDamageFrame_OnEnter(self)
  1577. -- Main hand weapon
  1578. GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
  1579. if ( self.unit == "pet" ) then
  1580. GameTooltip:SetText(INVTYPE_WEAPONMAINHAND_PET, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1581. else
  1582. GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1583. end
  1584. 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);
  1585. 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);
  1586. -- Check for offhand weapon
  1587. if ( self.offhandAttackSpeed ) then
  1588. GameTooltip:AddLine("\n");
  1589. GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
  1590. 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);
  1591. 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);
  1592. end
  1593. GameTooltip:Show();
  1594. end
  1595. function PaperDollFrame_GetArmorReduction(armor, attackerLevel)
  1596. return C_PaperDollInfo.GetArmorEffectiveness(armor, attackerLevel) * 100;
  1597. end
  1598. function PaperDollFrame_GetArmorReductionAgainstTarget(armor)
  1599. local armorEffectiveness = C_PaperDollInfo.GetArmorEffectivenessAgainstTarget(armor);
  1600. if ( armorEffectiveness ) then
  1601. return armorEffectiveness * 100;
  1602. end
  1603. end
  1604. function PaperDollFrame_UpdateStats()
  1605. local level = UnitLevel("player");
  1606. local categoryYOffset = 0;
  1607. local statYOffset = 0;
  1608. if ( level >= MIN_PLAYER_LEVEL_FOR_ITEM_LEVEL_DISPLAY ) then
  1609. PaperDollFrame_SetItemLevel(CharacterStatsPane.ItemLevelFrame, "player");
  1610. CharacterStatsPane.ItemLevelFrame.Value:SetTextColor(GetItemLevelColor());
  1611. CharacterStatsPane.ItemLevelCategory:Show();
  1612. CharacterStatsPane.ItemLevelFrame:Show();
  1613. CharacterStatsPane.AttributesCategory:ClearAllPoints();
  1614. CharacterStatsPane.AttributesCategory:SetPoint("TOP", CharacterStatsPane.ItemLevelFrame, "BOTTOM", 0, 0);
  1615. else
  1616. CharacterStatsPane.ItemLevelCategory:Hide();
  1617. CharacterStatsPane.ItemLevelFrame:Hide();
  1618. CharacterStatsPane.AttributesCategory:ClearAllPoints();
  1619. CharacterStatsPane.AttributesCategory:SetPoint("TOP", CharacterStatsPane, "TOP", 0, -2);
  1620. categoryYOffset = -11;
  1621. statYOffset = -5;
  1622. end
  1623. local spec = GetSpecialization();
  1624. local role = GetSpecializationRole(spec);
  1625. CharacterStatsPane.statsFramePool:ReleaseAll();
  1626. -- we need a stat frame to first do the math to know if we need to show the stat frame
  1627. -- so effectively we'll always pre-allocate
  1628. local statFrame = CharacterStatsPane.statsFramePool:Acquire();
  1629. local lastAnchor;
  1630. for catIndex = 1, #PAPERDOLL_STATCATEGORIES do
  1631. local catFrame = CharacterStatsPane[PAPERDOLL_STATCATEGORIES[catIndex].categoryFrame];
  1632. local numStatInCat = 0;
  1633. for statIndex = 1, #PAPERDOLL_STATCATEGORIES[catIndex].stats do
  1634. local stat = PAPERDOLL_STATCATEGORIES[catIndex].stats[statIndex];
  1635. local showStat = true;
  1636. if ( showStat and stat.primary ) then
  1637. local primaryStat = select(6, GetSpecializationInfo(spec, nil, nil, nil, UnitSex("player")));
  1638. if ( stat.primary ~= primaryStat ) then
  1639. showStat = false;
  1640. end
  1641. end
  1642. if ( showStat and stat.roles ) then
  1643. local foundRole = false;
  1644. for _, statRole in pairs(stat.roles) do
  1645. if ( role == statRole ) then
  1646. foundRole = true;
  1647. break;
  1648. end
  1649. end
  1650. showStat = foundRole;
  1651. end
  1652. if ( showStat and stat.showFunc ) then
  1653. showStat = stat.showFunc();
  1654. end
  1655. if ( showStat ) then
  1656. statFrame.onEnterFunc = nil;
  1657. statFrame.UpdateTooltip = nil;
  1658. PAPERDOLL_STATINFO[stat.stat].updateFunc(statFrame, "player");
  1659. if ( not stat.hideAt or stat.hideAt ~= statFrame.numericValue ) then
  1660. if ( numStatInCat == 0 ) then
  1661. if ( lastAnchor ) then
  1662. catFrame:SetPoint("TOP", lastAnchor, "BOTTOM", 0, categoryYOffset);
  1663. end
  1664. lastAnchor = catFrame;
  1665. statFrame:SetPoint("TOP", catFrame, "BOTTOM", 0, -2);
  1666. else
  1667. statFrame:SetPoint("TOP", lastAnchor, "BOTTOM", 0, statYOffset);
  1668. end
  1669. numStatInCat = numStatInCat + 1;
  1670. statFrame.Background:SetShown((numStatInCat % 2) == 0);
  1671. lastAnchor = statFrame;
  1672. -- done with this stat frame, get the next one
  1673. statFrame = CharacterStatsPane.statsFramePool:Acquire();
  1674. end
  1675. end
  1676. end
  1677. catFrame:SetShown(numStatInCat > 0);
  1678. end
  1679. -- release the current stat frame
  1680. CharacterStatsPane.statsFramePool:Release(statFrame);
  1681. end
  1682. function PaperDollFrame_SetLabelAndText(statFrame, label, text, isPercentage, numericValue)
  1683. if ( statFrame.Label ) then
  1684. statFrame.Label:SetText(format(STAT_FORMAT, label));
  1685. end
  1686. if ( isPercentage ) then
  1687. text = format("%d%%", numericValue + 0.5);
  1688. end
  1689. statFrame.Value:SetText(text);
  1690. statFrame.numericValue = numericValue;
  1691. end
  1692. function ComputePetBonus(stat, value)
  1693. local temp, unitClass = UnitClass("player");
  1694. unitClass = strupper(unitClass);
  1695. if( unitClass == "WARLOCK" ) then
  1696. if( WARLOCK_PET_BONUS[stat] ) then
  1697. return value * WARLOCK_PET_BONUS[stat];
  1698. else
  1699. return 0;
  1700. end
  1701. elseif( unitClass == "HUNTER" ) then
  1702. if( HUNTER_PET_BONUS[stat] ) then
  1703. return value * HUNTER_PET_BONUS[stat];
  1704. else
  1705. return 0;
  1706. end
  1707. end
  1708. return 0;
  1709. end
  1710. function PaperDollFrameItemFlyoutButton_OnClick(self)
  1711. if ( self.location == EQUIPMENTFLYOUT_IGNORESLOT_LOCATION ) then
  1712. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
  1713. local slot = EquipmentFlyoutFrame.button;
  1714. C_EquipmentSet.IgnoreSlotForSave(slot:GetID());
  1715. slot.ignored = true;
  1716. PaperDollItemSlotButton_Update(slot);
  1717. EquipmentFlyout_Show(slot);
  1718. PaperDollEquipmentManagerPaneSaveSet:Enable();
  1719. elseif ( self.location == EQUIPMENTFLYOUT_UNIGNORESLOT_LOCATION ) then
  1720. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
  1721. local slot = EquipmentFlyoutFrame.button;
  1722. C_EquipmentSet.UnignoreSlotForSave(slot:GetID());
  1723. slot.ignored = nil;
  1724. PaperDollItemSlotButton_Update(slot);
  1725. EquipmentFlyout_Show(slot);
  1726. PaperDollEquipmentManagerPaneSaveSet:Enable();
  1727. elseif ( self.location == EQUIPMENTFLYOUT_PLACEINBAGS_LOCATION ) then
  1728. if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[EquipmentFlyoutFrame.button:GetID()] ) then
  1729. UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
  1730. return;
  1731. end
  1732. local action = EquipmentManager_UnequipItemInSlot(EquipmentFlyoutFrame.button:GetID());
  1733. EquipmentManager_RunAction(action);
  1734. elseif ( self.location ) then
  1735. if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[EquipmentFlyoutFrame.button:GetID()] ) then
  1736. UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
  1737. return;
  1738. end
  1739. local action = EquipmentManager_EquipItemByLocation(self.location, self.id);
  1740. EquipmentManager_RunAction(action);
  1741. end
  1742. end
  1743. function PaperDollFrameItemFlyout_GetItems(paperDollItemSlot, itemTable)
  1744. GetInventoryItemsForSlot(paperDollItemSlot, itemTable);
  1745. end
  1746. function PaperDollFrameItemFlyout_PostGetItems(itemSlotButton, itemDisplayTable, numItems)
  1747. if (PaperDollEquipmentManagerPane:IsShown() and (PaperDollEquipmentManagerPane.selectedSetID or GearManagerDialogPopup:IsShown())) then
  1748. if ( not itemSlotButton.ignored ) then
  1749. tinsert(itemDisplayTable, 1, EQUIPMENTFLYOUT_IGNORESLOT_LOCATION);
  1750. else
  1751. tinsert(itemDisplayTable, 1, EQUIPMENTFLYOUT_UNIGNORESLOT_LOCATION);
  1752. end
  1753. numItems = numItems + 1;
  1754. end
  1755. if ( GetInventoryItemTexture("player", itemSlotButton:GetID()) ~= nil ) then
  1756. tinsert(itemDisplayTable, 1, EQUIPMENTFLYOUT_PLACEINBAGS_LOCATION);
  1757. numItems = numItems + 1;
  1758. end
  1759. return numItems;
  1760. end
  1761. function GearSetEditButton_OnLoad(self)
  1762. self.Dropdown = GearSetEditButtonDropDown;
  1763. UIDropDownMenu_Initialize(self.Dropdown, nil, "MENU");
  1764. UIDropDownMenu_SetInitializeFunction(self.Dropdown, GearSetEditButtonDropDown_Initialize);
  1765. end
  1766. function GearSetEditButton_OnMouseDown(self, button)
  1767. self.texture:SetPoint("TOPLEFT", 1, -1);
  1768. GearSetButton_OnClick(self:GetParent(), button);
  1769. if ( self.Dropdown.gearSetButton ~= self:GetParent() ) then
  1770. HideDropDownMenu(1);
  1771. self.Dropdown.gearSetButton = self:GetParent();
  1772. end
  1773. ToggleDropDownMenu(1, nil, self.Dropdown, self, 0, 0);
  1774. end
  1775. function GearSetEditButtonDropDown_Initialize(dropdownFrame, level, menuList)
  1776. local gearSetButton = dropdownFrame.gearSetButton;
  1777. local info = UIDropDownMenu_CreateInfo();
  1778. info.text = EQUIPMENT_SET_EDIT;
  1779. info.notCheckable = true;
  1780. info.func = function() GearSetButton_OpenPopup(gearSetButton); end;
  1781. UIDropDownMenu_AddButton(info, UIDROPDOWN_MENU_LEVEL);
  1782. info = UIDropDownMenu_CreateInfo();
  1783. info.text = EQUIPMENT_SET_ASSIGN_TO_SPEC;
  1784. info.isTitle = true;
  1785. info.notCheckable = true;
  1786. UIDropDownMenu_AddButton(info, UIDROPDOWN_MENU_LEVEL);
  1787. local equipmentSetID = gearSetButton.setID;
  1788. for i = 1, GetNumSpecializations() do
  1789. info = UIDropDownMenu_CreateInfo();
  1790. info.checked = function()
  1791. return C_EquipmentSet.GetEquipmentSetAssignedSpec(equipmentSetID) == i;
  1792. end;
  1793. info.func = function()
  1794. local currentSpecIndex = C_EquipmentSet.GetEquipmentSetAssignedSpec(equipmentSetID);
  1795. if ( currentSpecIndex ~= i ) then
  1796. C_EquipmentSet.AssignSpecToEquipmentSet(equipmentSetID, i);
  1797. else
  1798. C_EquipmentSet.UnassignEquipmentSetSpec(equipmentSetID);
  1799. end
  1800. GearSetButton_UpdateSpecInfo(gearSetButton);
  1801. PaperDollEquipmentManagerPane_Update(true);
  1802. end;
  1803. local specID = GetSpecializationInfo(i);
  1804. info.text = select(2, GetSpecializationInfoByID(specID));
  1805. UIDropDownMenu_AddButton(info, UIDROPDOWN_MENU_LEVEL);
  1806. end
  1807. end
  1808. function GearSetButton_OpenPopup(self)
  1809. GearManagerDialogPopup:Show();
  1810. GearManagerDialogPopup.isEdit = true;
  1811. GearManagerDialogPopup.setID = self.setID;
  1812. GearManagerDialogPopup.origName = self.text:GetText();
  1813. RecalculateGearManagerDialogPopup(self.text:GetText(), self.icon:GetTexture());
  1814. end
  1815. function GearSetButton_SetSpecInfo(self, specID)
  1816. if ( specID and specID > 0 ) then
  1817. self.specID = specID;
  1818. local id, name, description, texture, role, class = GetSpecializationInfoByID(specID);
  1819. SetPortraitToTexture(self.SpecIcon, texture);
  1820. self.SpecIcon:Show();
  1821. self.SpecRing:Show();
  1822. else
  1823. self.specID = nil;
  1824. self.SpecIcon:Hide();
  1825. self.SpecRing:Hide();
  1826. end
  1827. end
  1828. function GearSetButton_UpdateSpecInfo(self)
  1829. if ( not self.setID ) then
  1830. GearSetButton_SetSpecInfo(self, nil);
  1831. return;
  1832. end
  1833. local specIndex = C_EquipmentSet.GetEquipmentSetAssignedSpec(self.setID);
  1834. if ( not specIndex ) then
  1835. GearSetButton_SetSpecInfo(self, nil);
  1836. return;
  1837. end
  1838. local specID = GetSpecializationInfo(specIndex);
  1839. GearSetButton_SetSpecInfo(self, specID);
  1840. end
  1841. function GearSetButton_OnClick(self, button, down)
  1842. if ( self.setID ) then
  1843. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON); -- inappropriately named, but a good sound.
  1844. PaperDollEquipmentManagerPane.selectedSetID = self.setID;
  1845. -- mark the ignored slots
  1846. PaperDollFrame_ClearIgnoredSlots();
  1847. PaperDollFrame_IgnoreSlotsForSet(self.setID);
  1848. PaperDollEquipmentManagerPane_Update();
  1849. GearManagerDialogPopup:Hide();
  1850. else
  1851. -- This is the "New Set" button
  1852. GearManagerDialogPopup:Show();
  1853. PaperDollEquipmentManagerPane.selectedSetID = nil;
  1854. PaperDollFrame_ClearIgnoredSlots();
  1855. PaperDollEquipmentManagerPane_Update();
  1856. -- Ignore shirt and tabard by default
  1857. PaperDollFrame_IgnoreSlot(4);
  1858. PaperDollFrame_IgnoreSlot(19);
  1859. end
  1860. StaticPopup_Hide("CONFIRM_SAVE_EQUIPMENT_SET");
  1861. StaticPopup_Hide("CONFIRM_OVERWRITE_EQUIPMENT_SET");
  1862. end
  1863. function GearSetButton_OnEnter(self)
  1864. if ( self.setID ) then
  1865. GameTooltip_SetDefaultAnchor(GameTooltip, self);
  1866. GameTooltip:SetEquipmentSet(self.setID);
  1867. end
  1868. end
  1869. NUM_GEARSET_ICONS_PER_ROW = 10;
  1870. NUM_GEARSET_ICON_ROWS = 9;
  1871. NUM_GEARSET_ICONS_SHOWN = NUM_GEARSET_ICONS_PER_ROW * NUM_GEARSET_ICON_ROWS;
  1872. GEARSET_ICON_ROW_HEIGHT = 36;
  1873. local EM_ICON_FILENAMES = {};
  1874. function OnGearManagerDialogPopupButtonCreated(self, newButton)
  1875. tinsert(self.buttons, newButton);
  1876. end
  1877. function GearManagerDialogPopup_OnLoad(self)
  1878. self.buttons = {};
  1879. BuildIconArray(GearManagerDialogPopup, "GearManagerDialogPopupButton", "GearSetPopupButtonTemplate", NUM_GEARSET_ICONS_PER_ROW, NUM_GEARSET_ICON_ROWS, OnGearManagerDialogPopupButtonCreated);
  1880. self.SetSelection = function(self, fTexture, Value)
  1881. if(fTexture) then
  1882. self.selectedTexture = Value;
  1883. self.selectedIcon = nil;
  1884. else
  1885. self.selectedTexture = nil;
  1886. self.selectedIcon = Value;
  1887. end
  1888. end
  1889. GearManagerDialogPopupScrollFrame.ScrollBar.scrollStep = 8 * GEARSET_ICON_ROW_HEIGHT;
  1890. end
  1891. local GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING = 40;
  1892. function GearManagerDialogPopup_AdjustAnchors(self)
  1893. local rightSpace = GetScreenWidth() - PaperDollFrame:GetRight();
  1894. self.parentLeft = PaperDollFrame:GetLeft();
  1895. local leftSpace = self.parentLeft;
  1896. self:ClearAllPoints();
  1897. if ( leftSpace >= rightSpace ) then
  1898. if ( leftSpace < self:GetWidth() + GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING ) then
  1899. self:SetPoint("RIGHT", PaperDollFrame, "LEFT", self:GetWidth() + GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING - leftSpace, 0);
  1900. else
  1901. self:SetPoint("RIGHT", PaperDollFrame, "LEFT", -5, 0);
  1902. end
  1903. else
  1904. if ( rightSpace < self:GetWidth() + GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING ) then
  1905. self:SetPoint("LEFT", PaperDollFrame, "RIGHT", rightSpace - (self:GetWidth() + GEAR_MANAGER_POPUP_FRAME_MINIMUM_PADDING), 0);
  1906. else
  1907. self:SetPoint("LEFT", PaperDollFrame, "RIGHT", 0, 0);
  1908. end
  1909. end
  1910. end
  1911. function GearManagerDialogPopup_OnShow(self)
  1912. GearManagerDialogPopup_AdjustAnchors(self);
  1913. PlaySound(SOUNDKIT.IG_CHARACTER_INFO_OPEN);
  1914. self.setID = nil;
  1915. self.isEdit = false;
  1916. RecalculateGearManagerDialogPopup();
  1917. RefreshEquipmentSetIconInfo();
  1918. end
  1919. function GearManagerDialogPopup_OnUpdate(self)
  1920. if ( PaperDollFrame:GetLeft() ~= self.parentLeft ) then
  1921. GearManagerDialogPopup_AdjustAnchors(self);
  1922. end
  1923. end
  1924. function GearManagerDialogPopup_OnHide(self)
  1925. GearManagerDialogPopup.setID = nil;
  1926. GearManagerDialogPopup:SetSelection(true, nil);
  1927. GearManagerDialogPopupEditBox:SetText("");
  1928. if (not PaperDollEquipmentManagerPane.selectedSetID) then
  1929. PaperDollFrame_ClearIgnoredSlots();
  1930. end
  1931. EM_ICON_FILENAMES = nil;
  1932. collectgarbage();
  1933. end
  1934. function RecalculateGearManagerDialogPopup(setName, iconTexture)
  1935. local popup = GearManagerDialogPopup;
  1936. if ( setName and setName ~= "") then
  1937. GearManagerDialogPopupEditBox:SetText(setName);
  1938. GearManagerDialogPopupEditBox:HighlightText(0);
  1939. else
  1940. GearManagerDialogPopupEditBox:SetText("");
  1941. end
  1942. if (iconTexture) then
  1943. popup:SetSelection(true, iconTexture);
  1944. else
  1945. popup:SetSelection(false, 1);
  1946. end
  1947. --[[
  1948. Scroll and ensure that any selected equipment shows up in the list.
  1949. When we first press "save", we want to make sure any selected equipment set shows up in the list, so that
  1950. the user can just make his changes and press Okay to overwrite.
  1951. To do this, we need to find the current set (by icon) and move the offset of the GearManagerDialogPopup
  1952. to display it. Issue ID: 171220
  1953. ]]
  1954. RefreshEquipmentSetIconInfo();
  1955. local totalItems = #EM_ICON_FILENAMES;
  1956. local texture, _;
  1957. if(popup.selectedTexture) then
  1958. local foundIndex = nil;
  1959. for index=1, totalItems do
  1960. texture = GetEquipmentSetIconInfo(index);
  1961. if ( texture == popup.selectedTexture ) then
  1962. foundIndex = index;
  1963. break;
  1964. end
  1965. end
  1966. if (foundIndex == nil) then
  1967. foundIndex = 1;
  1968. end
  1969. -- now make it so we always display at least NUM_GEARSET_ICON_ROWS of data
  1970. local offsetnumIcons = floor((totalItems-1)/NUM_GEARSET_ICONS_PER_ROW);
  1971. local offset = floor((foundIndex-1) / NUM_GEARSET_ICONS_PER_ROW);
  1972. offset = offset + min((NUM_GEARSET_ICON_ROWS-1), offsetnumIcons-offset) - (NUM_GEARSET_ICON_ROWS-1);
  1973. if(foundIndex<=NUM_GEARSET_ICONS_SHOWN) then
  1974. offset = 0; --Equipment all shows at the same place.
  1975. end
  1976. FauxScrollFrame_OnVerticalScroll(GearManagerDialogPopupScrollFrame, offset*GEARSET_ICON_ROW_HEIGHT, GEARSET_ICON_ROW_HEIGHT, nil);
  1977. else
  1978. FauxScrollFrame_OnVerticalScroll(GearManagerDialogPopupScrollFrame, 0, GEARSET_ICON_ROW_HEIGHT, nil);
  1979. end
  1980. GearManagerDialogPopup_Update();
  1981. end
  1982. --[[
  1983. RefreshEquipmentSetIconInfo() counts how many uniquely textured inventory items the player has equipped.
  1984. ]]
  1985. function RefreshEquipmentSetIconInfo()
  1986. EM_ICON_FILENAMES = {};
  1987. EM_ICON_FILENAMES[1] = "INV_MISC_QUESTIONMARK";
  1988. local index = 2;
  1989. for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
  1990. local itemTexture = GetInventoryItemTexture("player", i);
  1991. if ( itemTexture ) then
  1992. EM_ICON_FILENAMES[index] = itemTexture;
  1993. if(EM_ICON_FILENAMES[index]) then
  1994. index = index + 1;
  1995. --[[
  1996. Currently checks all for duplicates, even though only rings, trinkets, and weapons may be duplicated.
  1997. This version is clean and maintainable.
  1998. ]]
  1999. for j=INVSLOT_FIRST_EQUIPPED, (index-1) do
  2000. if(EM_ICON_FILENAMES[index] == EM_ICON_FILENAMES[j]) then
  2001. EM_ICON_FILENAMES[index] = nil;
  2002. index = index - 1;
  2003. break;
  2004. end
  2005. end
  2006. end
  2007. end
  2008. end
  2009. GetLooseMacroItemIcons(EM_ICON_FILENAMES);
  2010. GetLooseMacroIcons(EM_ICON_FILENAMES);
  2011. GetMacroItemIcons(EM_ICON_FILENAMES);
  2012. GetMacroIcons(EM_ICON_FILENAMES);
  2013. end
  2014. --[[
  2015. GetEquipmentSetIconInfo(index) determines the texture and real index of a regular index
  2016. Input: index = index into a list of equipped items followed by the macro items. Only tricky part is the equipped items list keeps changing.
  2017. 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
  2018. and positive for the macro items//
  2019. ]]
  2020. function GetEquipmentSetIconInfo(index)
  2021. return EM_ICON_FILENAMES[index];
  2022. end
  2023. function GearManagerDialogPopup_Update()
  2024. local popup = GearManagerDialogPopup;
  2025. local buttons = popup.buttons;
  2026. local offset = FauxScrollFrame_GetOffset(GearManagerDialogPopupScrollFrame) or 0;
  2027. local button;
  2028. -- Icon list
  2029. local texture, index, button, realIndex, _;
  2030. for i=1, NUM_GEARSET_ICONS_SHOWN do
  2031. local button = buttons[i];
  2032. index = (offset * NUM_GEARSET_ICONS_PER_ROW) + i;
  2033. if ( index <= #EM_ICON_FILENAMES ) then
  2034. texture = GetEquipmentSetIconInfo(index);
  2035. -- button.name:SetText(index); --dcw
  2036. if(type(texture) == "number") then
  2037. button.icon:SetTexture(texture);
  2038. else
  2039. button.icon:SetTexture("INTERFACE\\ICONS\\"..texture);
  2040. end
  2041. button:Show();
  2042. if ( index == popup.selectedIcon ) then
  2043. button:SetChecked(true);
  2044. elseif ( texture == popup.selectedTexture ) then
  2045. button:SetChecked(true);
  2046. popup:SetSelection(false, index);
  2047. else
  2048. button:SetChecked(false);
  2049. end
  2050. else
  2051. button.icon:SetTexture("");
  2052. button:Hide();
  2053. end
  2054. end
  2055. -- Scrollbar stuff
  2056. FauxScrollFrame_Update(GearManagerDialogPopupScrollFrame, ceil(#EM_ICON_FILENAMES / NUM_GEARSET_ICONS_PER_ROW) + 1, NUM_GEARSET_ICON_ROWS, GEARSET_ICON_ROW_HEIGHT );
  2057. end
  2058. function GearManagerDialogPopupOkay_Update()
  2059. local popup = GearManagerDialogPopup;
  2060. local button = GearManagerDialogPopupOkay;
  2061. if ( (popup.selectedIcon or popup.isEdit) and popup.name ) then
  2062. button:Enable();
  2063. else
  2064. button:Disable();
  2065. end
  2066. end
  2067. function GearManagerDialogPopupOkay_OnClick(self, button, pushed)
  2068. local popup = GearManagerDialogPopup;
  2069. local iconTexture = GetEquipmentSetIconInfo(popup.selectedIcon);
  2070. if ( C_EquipmentSet.GetEquipmentSetID(popup.name) ) then
  2071. if (popup.isEdit and popup.name ~= popup.origName) then
  2072. -- Not allowed to overwrite an existing set by doing a rename
  2073. UIErrorsFrame:AddMessage(EQUIPMENT_SETS_CANT_RENAME, 1.0, 0.1, 0.1, 1.0);
  2074. return;
  2075. elseif (not popup.isEdit) then
  2076. local dialog = StaticPopup_Show("CONFIRM_OVERWRITE_EQUIPMENT_SET", popup.name);
  2077. if ( dialog ) then
  2078. dialog.data = C_EquipmentSet.GetEquipmentSetID(popup.name);
  2079. dialog.selectedIcon = iconTexture;
  2080. else
  2081. UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
  2082. end
  2083. return;
  2084. end
  2085. elseif ( C_EquipmentSet.GetNumEquipmentSets() >= MAX_EQUIPMENT_SETS_PER_PLAYER and not popup.isEdit) then
  2086. UIErrorsFrame:AddMessage(EQUIPMENT_SETS_TOO_MANY, 1.0, 0.1, 0.1, 1.0);
  2087. return;
  2088. end
  2089. if (popup.isEdit) then
  2090. PaperDollEquipmentManagerPane.selectedSetID = popup.setID;
  2091. C_EquipmentSet.ModifyEquipmentSet(popup.setID, popup.name, iconTexture);
  2092. else
  2093. C_EquipmentSet.CreateEquipmentSet(popup.name, iconTexture);
  2094. end
  2095. popup:Hide();
  2096. end
  2097. function GearManagerDialogPopupCancel_OnClick()
  2098. GearManagerDialogPopup:Hide();
  2099. end
  2100. function GearSetPopupButton_OnClick(self, button)
  2101. local popup = GearManagerDialogPopup;
  2102. local offset = FauxScrollFrame_GetOffset(GearManagerDialogPopupScrollFrame) or 0;
  2103. popup.selectedIcon = (offset * NUM_GEARSET_ICONS_PER_ROW) + self:GetID();
  2104. popup.selectedTexture = nil;
  2105. GearManagerDialogPopup_Update();
  2106. GearManagerDialogPopupOkay_Update();
  2107. end
  2108. function PaperDollEquipmentManagerPane_OnLoad(self)
  2109. HybridScrollFrame_OnLoad(self);
  2110. self.update = PaperDollEquipmentManagerPane_Update;
  2111. HybridScrollFrame_CreateButtons(self, "GearSetButtonTemplate", 2, -(self.EquipSet:GetHeight()+4));
  2112. self:RegisterEvent("EQUIPMENT_SWAP_FINISHED");
  2113. self:RegisterEvent("EQUIPMENT_SETS_CHANGED");
  2114. self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED");
  2115. self:RegisterEvent("BAG_UPDATE");
  2116. end
  2117. function PaperDollEquipmentManagerPane_OnUpdate(self)
  2118. for i = 1, #self.buttons do
  2119. local button = self.buttons[i];
  2120. if (button:IsMouseOver()) then
  2121. if (button.setID) then
  2122. button.DeleteButton:Show();
  2123. button.EditButton:Show();
  2124. else
  2125. button.DeleteButton:Hide();
  2126. button.EditButton:Hide();
  2127. end
  2128. button.HighlightBar:Show();
  2129. else
  2130. button.DeleteButton:Hide();
  2131. button.EditButton:Hide();
  2132. button.HighlightBar:Hide();
  2133. end
  2134. end
  2135. if (self.queuedUpdate) then
  2136. PaperDollEquipmentManagerPane_Update();
  2137. self.queuedUpdate = false;
  2138. end
  2139. end
  2140. function PaperDollEquipmentManagerPane_OnShow(self)
  2141. PaperDollEquipmentManagerPane_Update(true);
  2142. EquipmentFlyoutPopoutButton_ShowAll();
  2143. end
  2144. function PaperDollEquipmentManagerPane_OnEvent(self, event, ...)
  2145. if ( event == "EQUIPMENT_SWAP_FINISHED" ) then
  2146. local completed, setID = ...;
  2147. if ( completed ) then
  2148. PlaySound(SOUNDKIT.PUT_DOWN_SMALL_CHAIN); -- plays the equip sound for plate mail
  2149. if (self:IsShown()) then
  2150. self.selectedSetID = setID;
  2151. PaperDollEquipmentManagerPane_Update();
  2152. end
  2153. end
  2154. end
  2155. if (self:IsShown()) then
  2156. if ( event == "EQUIPMENT_SETS_CHANGED" ) then
  2157. PaperDollEquipmentManagerPane_Update(true);
  2158. elseif ( event == "PLAYER_EQUIPMENT_CHANGED" or event == "BAG_UPDATE" ) then
  2159. -- This queues the update to only happen once at the end of the frame
  2160. self.queuedUpdate = true;
  2161. end
  2162. end
  2163. end
  2164. function PaperDollEquipmentManagerPane_OnHide(self)
  2165. EquipmentFlyoutPopoutButton_HideAll();
  2166. PaperDollFrame_ClearIgnoredSlots();
  2167. GearManagerDialogPopup:Hide();
  2168. StaticPopup_Hide("CONFIRM_SAVE_EQUIPMENT_SET");
  2169. StaticPopup_Hide("CONFIRM_OVERWRITE_EQUIPMENT_SET");
  2170. end
  2171. function SortEquipmentSetIDs(equipmentSetIDs)
  2172. local sortedIDs = {};
  2173. -- Add all the spec-assigned sets first because they should appear first.
  2174. for i, equipmentSetID in ipairs(equipmentSetIDs) do
  2175. if C_EquipmentSet.GetEquipmentSetAssignedSpec(equipmentSetID) then
  2176. sortedIDs[#sortedIDs + 1] = equipmentSetID;
  2177. end
  2178. end
  2179. for i, equipmentSetID in ipairs(equipmentSetIDs) do
  2180. if not C_EquipmentSet.GetEquipmentSetAssignedSpec(equipmentSetID) then
  2181. sortedIDs[#sortedIDs + 1] = equipmentSetID;
  2182. end
  2183. end
  2184. return sortedIDs;
  2185. end
  2186. function PaperDollEquipmentManagerPane_Update(equipmentSetsDirty)
  2187. local _, setID, isEquipped;
  2188. if (PaperDollEquipmentManagerPane.selectedSetID) then
  2189. _, _, setID, isEquipped = C_EquipmentSet.GetEquipmentSetInfo(PaperDollEquipmentManagerPane.selectedSetID);
  2190. end
  2191. if (setID) then
  2192. if (isEquipped) then
  2193. PaperDollEquipmentManagerPaneSaveSet:Disable();
  2194. PaperDollEquipmentManagerPaneEquipSet:Disable();
  2195. else
  2196. PaperDollEquipmentManagerPaneSaveSet:Enable();
  2197. PaperDollEquipmentManagerPaneEquipSet:Enable();
  2198. end
  2199. PaperDollFrame_IgnoreSlotsForSet(setID);
  2200. else
  2201. PaperDollEquipmentManagerPaneSaveSet:Disable();
  2202. PaperDollEquipmentManagerPaneEquipSet:Disable();
  2203. -- Clear selected equipment set if it doesn't exist
  2204. if (PaperDollEquipmentManagerPane.selectedSetID) then
  2205. PaperDollEquipmentManagerPane.selectedSetID = nil;
  2206. PaperDollFrame_ClearIgnoredSlots();
  2207. end
  2208. end
  2209. if ( equipmentSetsDirty ) then
  2210. PaperDollEquipmentManagerPane.equipmentSetIDs = SortEquipmentSetIDs(C_EquipmentSet.GetEquipmentSetIDs());
  2211. end
  2212. local numSets = #PaperDollEquipmentManagerPane.equipmentSetIDs;
  2213. local numRows = numSets;
  2214. if (numSets < MAX_EQUIPMENT_SETS_PER_PLAYER) then
  2215. numRows = numRows + 1; -- "Add New Set" button
  2216. end
  2217. HybridScrollFrame_Update(PaperDollEquipmentManagerPane, numRows * EQUIPMENTSET_BUTTON_HEIGHT + PaperDollEquipmentManagerPaneEquipSet:GetHeight() + 20 , PaperDollEquipmentManagerPane:GetHeight());
  2218. local scrollOffset = HybridScrollFrame_GetOffset(PaperDollEquipmentManagerPane);
  2219. local buttons = PaperDollEquipmentManagerPane.buttons;
  2220. local selectedSetID = PaperDollEquipmentManagerPane.selectedSetID;
  2221. local name, texture, button, numLost;
  2222. for i = 1, #buttons do
  2223. if (i+scrollOffset <= numRows) then
  2224. button = buttons[i];
  2225. buttons[i]:Show();
  2226. button:Enable();
  2227. if (i+scrollOffset <= numSets) then
  2228. -- Normal equipment set button
  2229. name, texture, setID, isEquipped, _, _, _, numLost = C_EquipmentSet.GetEquipmentSetInfo(PaperDollEquipmentManagerPane.equipmentSetIDs[i+scrollOffset]);
  2230. button.setID = setID;
  2231. button.text:SetText(name);
  2232. if (numLost > 0) then
  2233. button.text:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
  2234. else
  2235. button.text:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
  2236. end
  2237. if (texture) then
  2238. button.icon:SetTexture(texture);
  2239. else
  2240. button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark");
  2241. end
  2242. if (selectedSetID and button.setID == selectedSetID) then
  2243. button.SelectedBar:Show();
  2244. else
  2245. button.SelectedBar:Hide();
  2246. end
  2247. if (isEquipped) then
  2248. button.Check:Show();
  2249. else
  2250. button.Check:Hide();
  2251. end
  2252. button.icon:SetSize(36, 36);
  2253. button.icon:SetPoint("LEFT", 4, 0);
  2254. else
  2255. -- This is the Add New button
  2256. button.setID = nil;
  2257. button.text:SetText(PAPERDOLL_NEWEQUIPMENTSET);
  2258. button.text:SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b);
  2259. button.icon:SetTexture("Interface\\PaperDollInfoFrame\\Character-Plus");
  2260. button.icon:SetSize(30, 30);
  2261. button.icon:SetPoint("LEFT", 7, 0);
  2262. button.Check:Hide();
  2263. button.SelectedBar:Hide();
  2264. end
  2265. if ((i+scrollOffset) == 1) then
  2266. buttons[i].BgTop:Show();
  2267. buttons[i].BgMiddle:SetPoint("TOP", buttons[i].BgTop, "BOTTOM");
  2268. else
  2269. buttons[i].BgTop:Hide();
  2270. buttons[i].BgMiddle:SetPoint("TOP");
  2271. end
  2272. if ((i+scrollOffset) == numRows) then
  2273. buttons[i].BgBottom:Show();
  2274. buttons[i].BgMiddle:SetPoint("BOTTOM", buttons[i].BgBottom, "TOP");
  2275. else
  2276. buttons[i].BgBottom:Hide();
  2277. buttons[i].BgMiddle:SetPoint("BOTTOM");
  2278. end
  2279. if ((i+scrollOffset)%2 == 0) then
  2280. buttons[i].Stripe:SetColorTexture(STRIPE_COLOR.r, STRIPE_COLOR.g, STRIPE_COLOR.b);
  2281. buttons[i].Stripe:SetAlpha(0.1);
  2282. buttons[i].Stripe:Show();
  2283. else
  2284. buttons[i].Stripe:Hide();
  2285. end
  2286. GearSetButton_UpdateSpecInfo(buttons[i]);
  2287. else
  2288. buttons[i]:Hide();
  2289. end
  2290. end
  2291. end
  2292. function PaperDollEquipmentManagerPaneSaveSet_OnClick(self)
  2293. local selectedSetID = PaperDollEquipmentManagerPane.selectedSetID
  2294. if (selectedSetID) then
  2295. local selectedSetName = C_EquipmentSet.GetEquipmentSetInfo(selectedSetID);
  2296. local dialog = StaticPopup_Show("CONFIRM_SAVE_EQUIPMENT_SET", selectedSetName);
  2297. if ( dialog ) then
  2298. dialog.data = selectedSetID;
  2299. else
  2300. UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
  2301. end
  2302. end
  2303. end
  2304. function PaperDollEquipmentManagerPaneEquipSet_OnClick(self)
  2305. local selectedSetID = PaperDollEquipmentManagerPane.selectedSetID;
  2306. if ( selectedSetID) then
  2307. PlaySound(SOUNDKIT.IG_CHARACTER_INFO_TAB); -- inappropriately named, but a good sound.
  2308. EquipmentManager_EquipSet(selectedSetID);
  2309. end
  2310. end
  2311. function PaperDollTitlesPane_OnLoad(self)
  2312. HybridScrollFrame_OnLoad(self);
  2313. self.update = PaperDollTitlesPane_UpdateScrollFrame;
  2314. HybridScrollFrame_CreateButtons(self, "PlayerTitleButtonTemplate", 2, -4);
  2315. end
  2316. function PaperDollTitlesPane_UpdateScrollFrame()
  2317. local buttons = PaperDollTitlesPane.buttons;
  2318. local playerTitles = PaperDollTitlesPane.titles;
  2319. local numButtons = #buttons;
  2320. local scrollOffset = HybridScrollFrame_GetOffset(PaperDollTitlesPane);
  2321. local playerTitle;
  2322. for i = 1, numButtons do
  2323. playerTitle = playerTitles[i + scrollOffset];
  2324. if ( playerTitle ) then
  2325. buttons[i]:Show();
  2326. buttons[i].text:SetText(playerTitle.name);
  2327. buttons[i].titleId = playerTitle.id;
  2328. if ( PaperDollTitlesPane.selected == playerTitle.id ) then
  2329. buttons[i].Check:Show();
  2330. buttons[i].SelectedBar:Show();
  2331. else
  2332. buttons[i].Check:Hide();
  2333. buttons[i].SelectedBar:Hide();
  2334. end
  2335. if ((i+scrollOffset) == 1) then
  2336. buttons[i].BgTop:Show();
  2337. buttons[i].BgMiddle:SetPoint("TOP", buttons[i].BgTop, "BOTTOM");
  2338. else
  2339. buttons[i].BgTop:Hide();
  2340. buttons[i].BgMiddle:SetPoint("TOP");
  2341. end
  2342. if ((i+scrollOffset) == #playerTitles) then
  2343. buttons[i].BgBottom:Show();
  2344. buttons[i].BgMiddle:SetPoint("BOTTOM", buttons[i].BgBottom, "TOP");
  2345. else
  2346. buttons[i].BgBottom:Hide();
  2347. buttons[i].BgMiddle:SetPoint("BOTTOM");
  2348. end
  2349. if ((i+scrollOffset)%2 == 0) then
  2350. buttons[i].Stripe:SetColorTexture(STRIPE_COLOR.r, STRIPE_COLOR.g, STRIPE_COLOR.b);
  2351. buttons[i].Stripe:SetAlpha(0.1);
  2352. buttons[i].Stripe:Show();
  2353. else
  2354. buttons[i].Stripe:Hide();
  2355. end
  2356. else
  2357. buttons[i]:Hide();
  2358. end
  2359. end
  2360. end
  2361. local function PlayerTitleSort(a, b) return a.name < b.name; end
  2362. function GetKnownTitles()
  2363. local playerTitles = { };
  2364. local titleCount = 1;
  2365. local playerTitle = false;
  2366. local tempName = 0;
  2367. local selectedTitle = -1;
  2368. playerTitles[1] = { };
  2369. -- reserving space for None so it doesn't get sorted out of the top position
  2370. playerTitles[1].name = " ";
  2371. playerTitles[1].id = -1;
  2372. for i = 1, GetNumTitles() do
  2373. if ( IsTitleKnown(i) ) then
  2374. tempName, playerTitle = GetTitleName(i);
  2375. if ( tempName and playerTitle ) then
  2376. titleCount = titleCount + 1;
  2377. playerTitles[titleCount] = playerTitles[titleCount] or { };
  2378. playerTitles[titleCount].name = strtrim(tempName);
  2379. playerTitles[titleCount].id = i;
  2380. end
  2381. end
  2382. end
  2383. return playerTitles, selectedTitle;
  2384. end
  2385. function PaperDollTitlesPane_Update()
  2386. local currentTitle = GetCurrentTitle();
  2387. local buttons = PaperDollTitlesPane.buttons;
  2388. local playerTitles = GetKnownTitles();
  2389. if ( currentTitle > 0 and currentTitle <= GetNumTitles() and IsTitleKnown(currentTitle) ) then
  2390. PaperDollTitlesPane.selected = currentTitle;
  2391. else
  2392. PaperDollTitlesPane.selected = -1;
  2393. end
  2394. table.sort(playerTitles, PlayerTitleSort);
  2395. playerTitles[1].name = PLAYER_TITLE_NONE;
  2396. PaperDollTitlesPane.titles = playerTitles;
  2397. HybridScrollFrame_Update(PaperDollTitlesPane, #playerTitles * PLAYER_TITLE_HEIGHT + 20 , PaperDollTitlesPane:GetHeight());
  2398. PaperDollTitlesPane_UpdateScrollFrame();
  2399. end
  2400. function PlayerTitleButton_OnClick(self)
  2401. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF);
  2402. SetCurrentTitle(self.titleId);
  2403. end
  2404. function SetTitleByName(name)
  2405. name = strlower(name);
  2406. for i = 1, GetNumTitles() do
  2407. if ( IsTitleKnown(i) ) then
  2408. local title = GetTitleName(i);
  2409. title = strlower(strtrim(title));
  2410. if(title:find(name) == 1) then
  2411. SetCurrentTitle(i);
  2412. return true;
  2413. end
  2414. end
  2415. end
  2416. return false;
  2417. end
  2418. function SetPaperDollBackground(model, unit)
  2419. local race, fileName = UnitRace(unit);
  2420. local texture = DressUpTexturePath(fileName);
  2421. model.BackgroundTopLeft:SetTexture(texture..1);
  2422. model.BackgroundTopRight:SetTexture(texture..2);
  2423. model.BackgroundBotLeft:SetTexture(texture..3);
  2424. model.BackgroundBotRight:SetTexture(texture..4);
  2425. -- HACK - Adjust background brightness for different races
  2426. if ( strupper(fileName) == "BLOODELF") then
  2427. model.BackgroundOverlay:SetAlpha(0.8);
  2428. elseif (strupper(fileName) == "NIGHTELF") then
  2429. model.BackgroundOverlay:SetAlpha(0.6);
  2430. elseif ( strupper(fileName) == "SCOURGE") then
  2431. model.BackgroundOverlay:SetAlpha(0.3);
  2432. elseif ( strupper(fileName) == "TROLL" or strupper(fileName) == "ORC") then
  2433. model.BackgroundOverlay:SetAlpha(0.6);
  2434. elseif ( strupper(fileName) == "WORGEN" ) then
  2435. model.BackgroundOverlay:SetAlpha(0.5);
  2436. elseif ( strupper(fileName) == "GOBLIN" ) then
  2437. model.BackgroundOverlay:SetAlpha(0.6);
  2438. else
  2439. model.BackgroundOverlay:SetAlpha(0.7);
  2440. end
  2441. end
  2442. function PaperDollBgDesaturate(on)
  2443. CharacterModelFrameBackgroundTopLeft:SetDesaturated(on);
  2444. CharacterModelFrameBackgroundTopRight:SetDesaturated(on);
  2445. CharacterModelFrameBackgroundBotLeft:SetDesaturated(on);
  2446. CharacterModelFrameBackgroundBotRight:SetDesaturated(on);
  2447. end
  2448. function PaperDollFrame_UpdateSidebarTabs()
  2449. for i = 1, #PAPERDOLL_SIDEBARS do
  2450. local tab = _G["PaperDollSidebarTab"..i];
  2451. if (tab) then
  2452. if (_G[PAPERDOLL_SIDEBARS[i].frame]:IsShown()) then
  2453. tab.Hider:Hide();
  2454. tab.Highlight:Hide();
  2455. tab.TabBg:SetTexCoord(0.01562500, 0.79687500, 0.78906250, 0.95703125);
  2456. else
  2457. tab.Hider:Show();
  2458. tab.Highlight:Show();
  2459. tab.TabBg:SetTexCoord(0.01562500, 0.79687500, 0.61328125, 0.78125000);
  2460. if ( PAPERDOLL_SIDEBARS[i].IsActive() ) then
  2461. tab:Enable();
  2462. else
  2463. tab:Disable();
  2464. end
  2465. end
  2466. end
  2467. end
  2468. end
  2469. function PaperDollFrame_SetSidebar(self, index)
  2470. if (not _G[PAPERDOLL_SIDEBARS[index].frame]:IsShown()) then
  2471. for i = 1, #PAPERDOLL_SIDEBARS do
  2472. _G[PAPERDOLL_SIDEBARS[i].frame]:Hide();
  2473. end
  2474. _G[PAPERDOLL_SIDEBARS[index].frame]:Show();
  2475. PaperDollFrame.currentSideBar = _G[PAPERDOLL_SIDEBARS[index].frame];
  2476. PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF);
  2477. PaperDollFrame_UpdateSidebarTabs();
  2478. end
  2479. end
  2480. local inventoryFixupVersionToTutorialIndex =
  2481. {
  2482. {
  2483. seenIndex = LE_FRAME_TUTORIAL_INVENTORY_FIXUP_EXPANSION_LEGION,
  2484. checkIndex = LE_FRAME_TUTORIAL_INVENTORY_FIXUP_CHECK_EXPANSION_LEGION,
  2485. },
  2486. };
  2487. local function CheckFixupStates(fixupVersion)
  2488. local tutorialIndices = fixupVersion and inventoryFixupVersionToTutorialIndex[fixupVersion];
  2489. -- Set the appropriate index to check, this is how the client knows the user's
  2490. -- inventory was fixed up at some point in the past, but hasn't seen the tutorial yet.
  2491. if tutorialIndices and tutorialIndices.checkIndex then
  2492. SetCVarBitfield("closedInfoFrames", tutorialIndices.checkIndex, true);
  2493. end
  2494. -- Return the any matching tutorial that the user hasn't seen
  2495. for expansionID, tutorialIndices in pairs(inventoryFixupVersionToTutorialIndex) do
  2496. local doCheck = GetCVarBitfield("closedInfoFrames", tutorialIndices.checkIndex);
  2497. local seenTutorial = GetCVarBitfield("closedInfoFrames", tutorialIndices.seenIndex);
  2498. if doCheck and not seenTutorial then
  2499. return tutorialIndices.seenIndex;
  2500. end
  2501. end
  2502. end
  2503. function PaperDollFrame_UpdateInventoryFixupComplete(self, fixupVersion)
  2504. local tutorialIndexToShow = CheckFixupStates(fixupVersion);
  2505. if tutorialIndexToShow then
  2506. if self:IsVisible() then
  2507. if not self.fixupNotificationFrame then
  2508. self.fixupNotificationFrame = MicroButtonAlert_CreateAlert(self, tutorialIndexToShow, PAPERDOLL_INVENTORY_FIXUP_COMPLETE, "BOTTOM", CharacterMainHandSlot, "TOPRIGHT", 2, 30);
  2509. end
  2510. self.fixupNotificationFrame:Show();
  2511. SetCVarBitfield( "closedInfoFrames", tutorialIndexToShow, true );
  2512. else
  2513. MicroButtonPulse(CharacterMicroButton, 60);
  2514. end
  2515. end
  2516. end
  2517. function PaperDollFrame_HideInventoryFixupComplete(self)
  2518. if self.fixupNotificationFrame then
  2519. self.fixupNotificationFrame:Hide();
  2520. end
  2521. MicroButtonPulseStop(CharacterMicroButton);
  2522. end
  2523. PaperDollItemsMixin = {};
  2524. do
  2525. local helpFlags = {
  2526. AzeriteEmpoweredItemTipClosed = 0x0001,
  2527. AzeriteEmpoweredItemUIShown = 0x0002,
  2528. AzeriteEssenceUnlockTipClosed = 0x0004,
  2529. AzeriteEssenceSlotTipClosed = 0x0008,
  2530. AzeriteEssenceUIShown = 0x0010,
  2531. AzeriteEssenceSwapTipClosed = 0x0020,
  2532. };
  2533. function PaperDollItemsMixin:OnLoad()
  2534. self.isDirty = false;
  2535. self.onAzeriteEmpoweredItemUIShownCallback = function() self:OnAzeriteEmpoweredItemUIShown() end;
  2536. self.onAzeriteEssenceUIShownCallback = function() self:OnAzeriteEssenceUIShown() end;
  2537. self.helpFlags = CreateFromMixins(FlagsMixin);
  2538. self.helpFlags:OnLoad();
  2539. self.helpFlags:AddNamedFlagsFromTable(helpFlags);
  2540. self.clearableFlags = Flags_CreateMaskFromTable(helpFlags) - self.helpFlags.AzeriteEssenceUnlockTipClosed - self.helpFlags.AzeriteEssenceSwapTipClosed;
  2541. end
  2542. end
  2543. function PaperDollItemsMixin:MarkDirty()
  2544. self.isDirty = true;
  2545. end
  2546. function PaperDollItemsMixin:OnUpdate()
  2547. if self.isDirty then
  2548. self.isDirty = false;
  2549. self:EvaluateHelpTip();
  2550. end
  2551. end
  2552. local PAPERDOLL_ITEMS_FRAME_EVENTS = {
  2553. "PLAYER_EQUIPMENT_CHANGED",
  2554. "AZERITE_ITEM_POWER_LEVEL_CHANGED",
  2555. "AZERITE_EMPOWERED_ITEM_SELECTION_UPDATED",
  2556. };
  2557. function PaperDollItemsMixin:OnShow()
  2558. self:MarkDirty();
  2559. FrameUtil.RegisterFrameForEvents(self, PAPERDOLL_ITEMS_FRAME_EVENTS);
  2560. if AzeriteEmpoweredItemUI then
  2561. AzeriteEmpoweredItemUI:RegisterCallback(AzeriteEmpoweredItemUIMixin.Event.OnShow, self.onAzeriteEmpoweredItemUIShownCallback);
  2562. else
  2563. self:RegisterEvent("ADDON_LOADED");
  2564. end
  2565. end
  2566. function PaperDollItemsMixin:OnHide()
  2567. self:ResetHelpTipFlags();
  2568. FrameUtil.UnregisterFrameForEvents(self, PAPERDOLL_ITEMS_FRAME_EVENTS);
  2569. if AzeriteEmpoweredItemUI then
  2570. AzeriteEmpoweredItemUI:UnregisterCallback(AzeriteEmpoweredItemUIMixin.Event.OnShow, self.onAzeriteEmpoweredItemUIShownCallback);
  2571. end
  2572. self:UnregisterEvent("ADDON_LOADED");
  2573. end
  2574. function PaperDollItemsMixin:OnEvent(event, ...)
  2575. if event == "AZERITE_ITEM_POWER_LEVEL_CHANGED" then
  2576. local azeriteItemLocation, oldPowerLevel, newPowerLevel = ...;
  2577. self:MarkDirty();
  2578. elseif event == "AZERITE_EMPOWERED_ITEM_SELECTION_UPDATED" then
  2579. local item = ...;
  2580. self:MarkDirty();
  2581. elseif event == "PLAYER_EQUIPMENT_CHANGED" then
  2582. local equipmentSlot, hasCurrent = ...;
  2583. self:ResetHelpTipFlags();
  2584. self:MarkDirty();
  2585. elseif event == "ADDON_LOADED" then
  2586. local addOnName = ...;
  2587. if addOnName == "Blizzard_AzeriteUI" then
  2588. self.helpFlags:Set(self.helpFlags.AzeriteEmpoweredItemUIShown);
  2589. self:MarkDirty();
  2590. AzeriteEmpoweredItemUI:RegisterCallback(AzeriteEmpoweredItemUIMixin.Event.OnShow, self.onAzeriteEmpoweredItemUIShownCallback);
  2591. elseif addOnName == "Blizzard_AzeriteEssenceUI" then
  2592. self.helpFlags:Set(self.helpFlags.AzeriteEssenceUIShown);
  2593. self:MarkDirty();
  2594. AzeriteEssenceUI:RegisterCallback(AzeriteEssenceUIMixin.Event.OnShow, self.onAzeriteEssenceUIShownCallback);
  2595. end
  2596. end
  2597. end
  2598. function PaperDollItemsMixin:OnAzeriteEmpoweredItemUIShown()
  2599. self.helpFlags:Set(self.helpFlags.AzeriteEmpoweredItemUIShown);
  2600. self:MarkDirty();
  2601. end
  2602. function PaperDollItemsMixin:OnAzeriteEssenceUIShown()
  2603. self.helpFlags:Set(self.helpFlags.AzeriteEssenceUIShown);
  2604. self:MarkDirty();
  2605. end
  2606. function PaperDollItemsMixin:ResetHelpTipFlags()
  2607. self.helpFlags:Clear(self.clearableFlags);
  2608. end
  2609. function PaperDollItemsMixin:ShouldShowAzeriteEmpoweredItemHelpTip()
  2610. if self.helpFlags:IsSet(self.helpFlags.AzeriteEmpoweredItemTipClosed) then
  2611. return false;
  2612. end
  2613. if self.helpFlags:IsSet(self.helpFlags.AzeriteEmpoweredItemUIShown) then
  2614. return false;
  2615. end
  2616. if AzeriteEmpoweredItemUI and AzeriteEmpoweredItemUI:IsShown() then
  2617. return false;
  2618. end
  2619. return true;
  2620. end
  2621. function PaperDollItemsMixin:ShouldShowAzeriteEssenceUnlockHelpTip()
  2622. if self.helpFlags:IsSet(self.helpFlags.AzeriteEssenceUnlockTipClosed) then
  2623. return false;
  2624. end
  2625. if self.helpFlags:IsSet(self.helpFlags.AzeriteEssenceUIShown) then
  2626. return false;
  2627. end
  2628. if AzeriteEssenceUI and AzeriteEssenceUI:IsShown() then
  2629. return false;
  2630. end
  2631. return true;
  2632. end
  2633. function PaperDollItemsMixin:ShouldShowAzeriteEssenceSlotHelpTip()
  2634. if self.helpFlags:IsSet(self.helpFlags.AzeriteEssenceSlotTipClosed) then
  2635. return false;
  2636. end
  2637. if self.helpFlags:IsSet(self.helpFlags.AzeriteEssenceUIShown) then
  2638. return false;
  2639. end
  2640. if AzeriteEssenceUI and AzeriteEssenceUI:IsShown() then
  2641. return false;
  2642. end
  2643. return true;
  2644. end
  2645. function PaperDollItemsMixin:ShouldShowAzeriteEssenceSwapHelpTip()
  2646. if self.helpFlags:IsSet(self.helpFlags.AzeriteEssenceSwapTipClosed) then
  2647. return false;
  2648. end
  2649. if self.helpFlags:IsSet(self.helpFlags.AzeriteEssenceUIShown) then
  2650. return false;
  2651. end
  2652. return AzeriteEssenceUtil.ShouldShowEssenceSwapTutorial();
  2653. end
  2654. function PaperDollItemsMixin:OnHelpTipManuallyClosed(closeFlag)
  2655. self.helpFlags:Set(closeFlag);
  2656. self:MarkDirty();
  2657. end
  2658. function PaperDollItemsMixin:EvaluateHelpTip()
  2659. local bestHelpTipButton, helpTipText;
  2660. local helpCloseFlag = 0;
  2661. if not bestHelpTipButton and self:ShouldShowAzeriteEssenceUnlockHelpTip() then
  2662. local hasUnlockable, firstUnlockableIsSlot = AzeriteEssenceUtil.HasAnyUnlockableMilestones();
  2663. if hasUnlockable then
  2664. bestHelpTipButton = self:FindActiveAzeriteItemButton();
  2665. helpTipText = firstUnlockableIsSlot and AZERITE_ESSENCE_HELPTIP_UNLOCKED_SLOT or AZERITE_ESSENCE_HELPTIP_UNLOCKED_POWER;
  2666. helpCloseFlag = self.helpFlags.AzeriteEssenceUnlockTipClosed;
  2667. end
  2668. end
  2669. if not bestHelpTipButton and self:ShouldShowAzeriteEssenceSlotHelpTip() then
  2670. if AzeriteEssenceUtil.ShouldShowEmptySlotHelptip() then
  2671. bestHelpTipButton = self:FindActiveAzeriteItemButton();
  2672. helpTipText = AZERITE_ESSENCE_HELPTIP_AVAILABLE_SLOT;
  2673. helpCloseFlag = self.helpFlags.AzeriteEssenceSlotTipClosed;
  2674. end
  2675. end
  2676. if not bestHelpTipButton and self:ShouldShowAzeriteEssenceSwapHelpTip() then
  2677. bestHelpTipButton = self:FindActiveAzeriteItemButton();
  2678. if bestHelpTipButton then
  2679. helpTipText = CHARACTER_SHEET_MICRO_BUTTON_AZERITE_ESSENCE_CHANGE_ESSENCES;
  2680. helpCloseFlag = self.helpFlags.AzeriteEssenceSwapTipClosed;
  2681. AzeriteEssenceUtil.SetEssenceSwapTutorialSeen();
  2682. end
  2683. end
  2684. if not bestHelpTipButton and self:ShouldShowAzeriteEmpoweredItemHelpTip() then
  2685. bestHelpTipButton = self:FindBestAzeriteEmpoweredItemUIHelpTipButton();
  2686. helpTipText = AZERITE_EMPOWERED_UNSELECTED_TRAITS_HELPTIP;
  2687. helpCloseFlag = self.helpFlags.AzeriteEmpoweredItemTipClosed;
  2688. end
  2689. HelpTip:HideAll(self);
  2690. if bestHelpTipButton then
  2691. local helpTipInfo = {
  2692. onHideCallback = function(acknowledged, closeFlag)
  2693. if acknowledged then
  2694. PaperDollItemsFrame:OnHelpTipManuallyClosed(closeFlag);
  2695. end
  2696. end,
  2697. callbackArg = helpCloseFlag;
  2698. buttonStyle = HelpTip.ButtonStyle.Close,
  2699. text = helpTipText
  2700. };
  2701. if bestHelpTipButton.IsLeftSide then
  2702. helpTipInfo.targetPoint = HelpTip.Point.RightEdgeCenter;
  2703. helpTipInfo.offsetX = 10;
  2704. else
  2705. helpTipInfo.targetPoint = HelpTip.Point.LeftEdgeCenter;
  2706. helpTipInfo.offsetX = -10;
  2707. end
  2708. HelpTip:Show(self, helpTipInfo, bestHelpTipButton);
  2709. end
  2710. end
  2711. function PaperDollItemsMixin:FindBestAzeriteEmpoweredItemUIHelpTipButton()
  2712. for equipSlotIndex, itemLocation in AzeriteUtil.EnumerateEquipedAzeriteEmpoweredItems() do
  2713. if C_AzeriteEmpoweredItem.HasAnyUnselectedPowers(itemLocation) then
  2714. -- Right now we're just going to try pointing at the lowest slot index
  2715. return self.EquipmentSlots[equipSlotIndex];
  2716. end
  2717. end
  2718. return nil;
  2719. end
  2720. function PaperDollItemsMixin:FindActiveAzeriteItemButton()
  2721. local itemLocation = C_AzeriteItem.FindActiveAzeriteItem();
  2722. if itemLocation then
  2723. return self.EquipmentSlots[itemLocation.equipmentSlotIndex];
  2724. end
  2725. return nil;
  2726. end