PaperDollFrame.lua

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