UnitFrame.lua

UnitFrame.lua (8.2.5.32144; unchanged since 8.2.5.31960)
  1. PowerBarColor = {};
  2. PowerBarColor["MANA"] = { r = 0.00, g = 0.00, b = 1.00 };
  3. PowerBarColor["RAGE"] = { r = 1.00, g = 0.00, b = 0.00, fullPowerAnim=true };
  4. PowerBarColor["FOCUS"] = { r = 1.00, g = 0.50, b = 0.25, fullPowerAnim=true };
  5. PowerBarColor["ENERGY"] = { r = 1.00, g = 1.00, b = 0.00, fullPowerAnim=true };
  6. PowerBarColor["COMBO_POINTS"] = { r = 1.00, g = 0.96, b = 0.41 };
  7. PowerBarColor["RUNES"] = { r = 0.50, g = 0.50, b = 0.50 };
  8. PowerBarColor["RUNIC_POWER"] = { r = 0.00, g = 0.82, b = 1.00 };
  9. PowerBarColor["SOUL_SHARDS"] = { r = 0.50, g = 0.32, b = 0.55 };
  10. PowerBarColor["LUNAR_POWER"] = { r = 0.30, g = 0.52, b = 0.90, atlas="_Druid-LunarBar" };
  11. PowerBarColor["HOLY_POWER"] = { r = 0.95, g = 0.90, b = 0.60 };
  12. PowerBarColor["MAELSTROM"] = { r = 0.00, g = 0.50, b = 1.00, atlas = "_Shaman-MaelstromBar", fullPowerAnim=true };
  13. PowerBarColor["INSANITY"] = { r = 0.40, g = 0, b = 0.80, atlas = "_Priest-InsanityBar"};
  14. PowerBarColor["CHI"] = { r = 0.71, g = 1.0, b = 0.92 };
  15. PowerBarColor["ARCANE_CHARGES"] = { r = 0.1, g = 0.1, b = 0.98 };
  16. PowerBarColor["FURY"] = { r = 0.788, g = 0.259, b = 0.992, atlas = "_DemonHunter-DemonicFuryBar", fullPowerAnim=true };
  17. PowerBarColor["PAIN"] = { r = 255/255, g = 156/255, b = 0, atlas = "_DemonHunter-DemonicPainBar", fullPowerAnim=true };
  18. -- vehicle colors
  19. PowerBarColor["AMMOSLOT"] = { r = 0.80, g = 0.60, b = 0.00 };
  20. PowerBarColor["FUEL"] = { r = 0.0, g = 0.55, b = 0.5 };
  21. PowerBarColor["STAGGER"] = { {r = 0.52, g = 1.0, b = 0.52}, {r = 1.0, g = 0.98, b = 0.72}, {r = 1.0, g = 0.42, b = 0.42},};
  22. -- these are mostly needed for a fallback case (in case the code tries to index a power token that is missing from the table,
  23. -- it will try to index by power type instead)
  24. PowerBarColor[0] = PowerBarColor["MANA"];
  25. PowerBarColor[1] = PowerBarColor["RAGE"];
  26. PowerBarColor[2] = PowerBarColor["FOCUS"];
  27. PowerBarColor[3] = PowerBarColor["ENERGY"];
  28. PowerBarColor[4] = PowerBarColor["CHI"];
  29. PowerBarColor[5] = PowerBarColor["RUNES"];
  30. PowerBarColor[6] = PowerBarColor["RUNIC_POWER"];
  31. PowerBarColor[7] = PowerBarColor["SOUL_SHARDS"];
  32. PowerBarColor[8] = PowerBarColor["LUNAR_POWER"];
  33. PowerBarColor[9] = PowerBarColor["HOLY_POWER"];
  34. PowerBarColor[11] = PowerBarColor["MAELSTROM"];
  35. PowerBarColor[13] = PowerBarColor["INSANITY"];
  36. PowerBarColor[17] = PowerBarColor["FURY"];
  37. PowerBarColor[18] = PowerBarColor["PAIN"];
  38. --[[
  39. This system uses "update" functions as OnUpdate, and OnEvent handlers.
  40. This "Initialize" function registers the events to handle.
  41. The "update" function is set as the OnEvent handler (although they do not parse the event),
  42. as well as run from the parent's update handler.
  43. TT: I had to make the spellbar system differ from the norm.
  44. I needed a seperate OnUpdate and OnEvent handlers. And needed to parse the event.
  45. ]]--
  46. function UnitFrame_Initialize (self, unit, name, portrait, healthbar, healthtext, manabar, manatext, threatIndicator, threatFeedbackUnit, threatNumericIndicator,
  47. myHealPredictionBar, otherHealPredictionBar, totalAbsorbBar, totalAbsorbBarOverlay, overAbsorbGlow, overHealAbsorbGlow, healAbsorbBar, healAbsorbBarLeftShadow,
  48. healAbsorbBarRightShadow, myManaCostPredictionBar)
  49. self.unit = unit;
  50. self.name = name;
  51. self.portrait = portrait;
  52. self.healthbar = healthbar;
  53. self.manabar = manabar;
  54. self.threatIndicator = threatIndicator;
  55. self.threatNumericIndicator = threatNumericIndicator;
  56. self.myHealPredictionBar = myHealPredictionBar;
  57. self.otherHealPredictionBar = otherHealPredictionBar
  58. self.totalAbsorbBar = totalAbsorbBar;
  59. self.totalAbsorbBarOverlay = totalAbsorbBarOverlay;
  60. self.overAbsorbGlow = overAbsorbGlow;
  61. self.overHealAbsorbGlow = overHealAbsorbGlow;
  62. self.healAbsorbBar = healAbsorbBar;
  63. self.healAbsorbBarLeftShadow = healAbsorbBarLeftShadow;
  64. self.healAbsorbBarRightShadow = healAbsorbBarRightShadow;
  65. self.myManaCostPredictionBar = myManaCostPredictionBar;
  66. if ( self.myHealPredictionBar ) then
  67. self.myHealPredictionBar:ClearAllPoints();
  68. end
  69. if ( self.otherHealPredictionBar ) then
  70. self.otherHealPredictionBar:ClearAllPoints();
  71. end
  72. if ( self.totalAbsorbBar ) then
  73. self.totalAbsorbBar:ClearAllPoints();
  74. end
  75. if ( self.myManaCostPredictionBar ) then
  76. self.myManaCostPredictionBar:ClearAllPoints();
  77. end
  78. if ( self.totalAbsorbBarOverlay ) then
  79. self.totalAbsorbBar.overlay = self.totalAbsorbBarOverlay;
  80. self.totalAbsorbBarOverlay:SetAllPoints(self.totalAbsorbBar);
  81. self.totalAbsorbBarOverlay.tileSize = 32;
  82. end
  83. if ( self.overAbsorbGlow ) then
  84. self.overAbsorbGlow:ClearAllPoints();
  85. self.overAbsorbGlow:SetPoint("TOPLEFT", self.healthbar, "TOPRIGHT", -7, 0);
  86. self.overAbsorbGlow:SetPoint("BOTTOMLEFT", self.healthbar, "BOTTOMRIGHT", -7, 0);
  87. end
  88. if ( self.healAbsorbBar ) then
  89. self.healAbsorbBar:ClearAllPoints();
  90. self.healAbsorbBar:SetTexture("Interface\\RaidFrame\\Absorb-Fill", true, true);
  91. end
  92. if ( self.overHealAbsorbGlow ) then
  93. self.overHealAbsorbGlow:ClearAllPoints();
  94. self.overHealAbsorbGlow:SetPoint("BOTTOMRIGHT", self.healthbar, "BOTTOMLEFT", 7, 0);
  95. self.overHealAbsorbGlow:SetPoint("TOPRIGHT", self.healthbar, "TOPLEFT", 7, 0);
  96. end
  97. if ( healAbsorbBarLeftShadow ) then
  98. self.healAbsorbBarLeftShadow:ClearAllPoints();
  99. end
  100. if ( healAbsorbBarRightShadow ) then
  101. self.healAbsorbBarRightShadow:ClearAllPoints();
  102. end
  103. if (self.healthbar) then
  104. self.healthbar.capNumericDisplay = true;
  105. end
  106. if (self.manabar) then
  107. self.manabar.capNumericDisplay = true;
  108. end
  109. UnitFrameHealthBar_Initialize(unit, healthbar, healthtext, true);
  110. UnitFrameManaBar_Initialize(unit, manabar, manatext, (unit == "player" or unit == "pet" or unit == "vehicle" or unit == "target" or unit == "focus"));
  111. UnitFrameThreatIndicator_Initialize(unit, self, threatFeedbackUnit);
  112. UnitFrame_Update(self);
  113. self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
  114. self:RegisterEvent("UNIT_NAME_UPDATE");
  115. self:RegisterEvent("UNIT_DISPLAYPOWER");
  116. self:RegisterEvent("UNIT_PORTRAIT_UPDATE")
  117. self:RegisterEvent("PORTRAITS_UPDATED");
  118. if ( self.healAbsorbBar ) then
  119. self:RegisterUnitEvent("UNIT_HEAL_ABSORB_AMOUNT_CHANGED", unit);
  120. end
  121. if ( self.myHealPredictionBar ) then
  122. self:RegisterUnitEvent("UNIT_MAXHEALTH", unit);
  123. self:RegisterUnitEvent("UNIT_HEAL_PREDICTION", unit);
  124. end
  125. if ( self.totalAbsorbBar ) then
  126. self:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", unit);
  127. end
  128. if ( self.myManaCostPredictionBar ) then
  129. self:RegisterUnitEvent("UNIT_SPELLCAST_START", unit);
  130. self:RegisterUnitEvent("UNIT_SPELLCAST_STOP", unit);
  131. self:RegisterUnitEvent("UNIT_SPELLCAST_FAILED", unit);
  132. self:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", unit);
  133. end
  134. end
  135. function UnitFrame_SetUnit (self, unit, healthbar, manabar)
  136. -- update unit events if unit changes
  137. if ( self.unit ~= unit ) then
  138. if ( self.myHealPredictionBar ) then
  139. self:RegisterUnitEvent("UNIT_MAXHEALTH", unit);
  140. self:RegisterUnitEvent("UNIT_HEAL_PREDICTION", unit);
  141. end
  142. if ( self.totalAbsorbBar ) then
  143. self:RegisterUnitEvent("UNIT_ABSORB_AMOUNT_CHANGED", unit);
  144. end
  145. if ( not healthbar.frequentUpdates ) then
  146. healthbar:RegisterUnitEvent("UNIT_HEALTH", unit);
  147. end
  148. if ( manabar and not manabar.frequentUpdates ) then
  149. UnitFrameManaBar_RegisterDefaultEvents(manabar);
  150. end
  151. healthbar:RegisterUnitEvent("UNIT_MAXHEALTH", unit);
  152. if ( self.PlayerFrameHealthBarAnimatedLoss ) then
  153. self.PlayerFrameHealthBarAnimatedLoss:SetUnitHealthBar(unit, healthbar);
  154. end
  155. end
  156. self.unit = unit;
  157. healthbar.unit = unit;
  158. if ( manabar ) then --Party Pet frames don't have a mana bar.
  159. manabar.unit = unit;
  160. end
  161. self:SetAttribute("unit", unit);
  162. securecall("UnitFrame_Update", self);
  163. end
  164. function UnitFrame_Update (self, isParty)
  165. if (self.name) then
  166. local name;
  167. if ( self.overrideName ) then
  168. name = self.overrideName;
  169. else
  170. name = self.unit;
  171. end
  172. if (isParty) then
  173. self.name:SetText(GetUnitName(name, true));
  174. else
  175. self.name:SetText(GetUnitName(name));
  176. end
  177. end
  178. UnitFramePortrait_Update(self);
  179. UnitFrameHealthBar_Update(self.healthbar, self.unit);
  180. UnitFrameManaBar_Update(self.manabar, self.unit);
  181. UnitFrame_UpdateThreatIndicator(self.threatIndicator, self.threatNumericIndicator);
  182. UnitFrameHealPredictionBars_UpdateMax(self);
  183. UnitFrameHealPredictionBars_Update(self);
  184. UnitFrameManaCostPredictionBars_Update(self);
  185. end
  186. function UnitFramePortrait_Update (self)
  187. if ( self.portrait ) then
  188. SetPortraitTexture(self.portrait, self.unit);
  189. end
  190. end
  191. function UnitFrame_OnEvent(self, event, ...)
  192. local eventUnit = ...
  193. local unit = self.unit;
  194. if ( eventUnit == unit ) then
  195. if ( event == "UNIT_NAME_UPDATE" ) then
  196. self.name:SetText(GetUnitName(unit));
  197. elseif ( event == "UNIT_PORTRAIT_UPDATE" ) then
  198. UnitFramePortrait_Update(self);
  199. elseif ( event == "UNIT_DISPLAYPOWER" ) then
  200. if ( self.manabar ) then
  201. UnitFrameManaBar_UpdateType(self.manabar);
  202. end
  203. elseif ( event == "UNIT_MAXHEALTH" ) then
  204. UnitFrameHealPredictionBars_UpdateMax(self);
  205. UnitFrameHealPredictionBars_Update(self);
  206. elseif ( event == "UNIT_HEAL_PREDICTION" ) then
  207. UnitFrameHealPredictionBars_Update(self);
  208. elseif ( event == "UNIT_ABSORB_AMOUNT_CHANGED" ) then
  209. UnitFrameHealPredictionBars_Update(self);
  210. elseif ( event == "UNIT_HEAL_ABSORB_AMOUNT_CHANGED" ) then
  211. UnitFrameHealPredictionBars_Update(self);
  212. elseif ( event == "UNIT_SPELLCAST_START" or event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_SUCCEEDED" ) then
  213. local name, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible, spellID = UnitCastingInfo(unit);
  214. UnitFrameManaCostPredictionBars_Update(self, event == "UNIT_SPELLCAST_START", startTime, endTime, spellID);
  215. end
  216. elseif ( event == "PORTRAITS_UPDATED" ) then
  217. UnitFramePortrait_Update(self);
  218. end
  219. end
  220. function UnitFrameHealPredictionBars_UpdateMax(self)
  221. if ( not self.myHealPredictionBar ) then
  222. return;
  223. end
  224. UnitFrameHealPredictionBars_Update(self);
  225. end
  226. function UnitFrameHealPredictionBars_UpdateSize(self)
  227. if ( not self.myHealPredictionBar or not self.otherHealPredictionBar ) then
  228. return;
  229. end
  230. UnitFrameHealPredictionBars_Update(self);
  231. end
  232. --WARNING: This function is very similar to the function CompactUnitFrame_UpdateHealPrediction in CompactUnitFrame.lua.
  233. --If you are making changes here, it is possible you may want to make changes there as well.
  234. local MAX_INCOMING_HEAL_OVERFLOW = 1.0;
  235. function UnitFrameHealPredictionBars_Update(frame)
  236. if ( not frame.myHealPredictionBar ) then
  237. return;
  238. end
  239. local _, maxHealth = frame.healthbar:GetMinMaxValues();
  240. local health = frame.healthbar:GetValue();
  241. if ( maxHealth <= 0 ) then
  242. return;
  243. end
  244. local myIncomingHeal = UnitGetIncomingHeals(frame.unit, "player") or 0;
  245. local allIncomingHeal = UnitGetIncomingHeals(frame.unit) or 0;
  246. local totalAbsorb = UnitGetTotalAbsorbs(frame.unit) or 0;
  247. local myCurrentHealAbsorb = 0;
  248. if ( frame.healAbsorbBar ) then
  249. myCurrentHealAbsorb = UnitGetTotalHealAbsorbs(frame.unit) or 0;
  250. --We don't fill outside the health bar with healAbsorbs. Instead, an overHealAbsorbGlow is shown.
  251. if ( health < myCurrentHealAbsorb ) then
  252. frame.overHealAbsorbGlow:Show();
  253. myCurrentHealAbsorb = health;
  254. else
  255. frame.overHealAbsorbGlow:Hide();
  256. end
  257. end
  258. --See how far we're going over the health bar and make sure we don't go too far out of the frame.
  259. if ( health - myCurrentHealAbsorb + allIncomingHeal > maxHealth * MAX_INCOMING_HEAL_OVERFLOW ) then
  260. allIncomingHeal = maxHealth * MAX_INCOMING_HEAL_OVERFLOW - health + myCurrentHealAbsorb;
  261. end
  262. local otherIncomingHeal = 0;
  263. --Split up incoming heals.
  264. if ( allIncomingHeal >= myIncomingHeal ) then
  265. otherIncomingHeal = allIncomingHeal - myIncomingHeal;
  266. else
  267. myIncomingHeal = allIncomingHeal;
  268. end
  269. --We don't fill outside the the health bar with absorbs. Instead, an overAbsorbGlow is shown.
  270. local overAbsorb = false;
  271. if ( health - myCurrentHealAbsorb + allIncomingHeal + totalAbsorb >= maxHealth or health + totalAbsorb >= maxHealth ) then
  272. if ( totalAbsorb > 0 ) then
  273. overAbsorb = true;
  274. end
  275. if ( allIncomingHeal > myCurrentHealAbsorb ) then
  276. totalAbsorb = max(0,maxHealth - (health - myCurrentHealAbsorb + allIncomingHeal));
  277. else
  278. totalAbsorb = max(0,maxHealth - health);
  279. end
  280. end
  281. if ( overAbsorb ) then
  282. frame.overAbsorbGlow:Show();
  283. else
  284. frame.overAbsorbGlow:Hide();
  285. end
  286. local healthTexture = frame.healthbar:GetStatusBarTexture();
  287. local myCurrentHealAbsorbPercent = 0;
  288. local healAbsorbTexture = nil;
  289. if ( frame.healAbsorbBar ) then
  290. myCurrentHealAbsorbPercent = myCurrentHealAbsorb / maxHealth;
  291. --If allIncomingHeal is greater than myCurrentHealAbsorb, then the current
  292. --heal absorb will be completely overlayed by the incoming heals so we don't show it.
  293. if ( myCurrentHealAbsorb > allIncomingHeal ) then
  294. local shownHealAbsorb = myCurrentHealAbsorb - allIncomingHeal;
  295. local shownHealAbsorbPercent = shownHealAbsorb / maxHealth;
  296. healAbsorbTexture = UnitFrameUtil_UpdateFillBar(frame, healthTexture, frame.healAbsorbBar, shownHealAbsorb, -shownHealAbsorbPercent);
  297. --If there are incoming heals the left shadow would be overlayed by the incoming heals
  298. --so it isn't shown.
  299. if ( allIncomingHeal > 0 ) then
  300. frame.healAbsorbBarLeftShadow:Hide();
  301. else
  302. frame.healAbsorbBarLeftShadow:SetPoint("TOPLEFT", healAbsorbTexture, "TOPLEFT", 0, 0);
  303. frame.healAbsorbBarLeftShadow:SetPoint("BOTTOMLEFT", healAbsorbTexture, "BOTTOMLEFT", 0, 0);
  304. frame.healAbsorbBarLeftShadow:Show();
  305. end
  306. -- The right shadow is only shown if there are absorbs on the health bar.
  307. if ( totalAbsorb > 0 ) then
  308. frame.healAbsorbBarRightShadow:SetPoint("TOPLEFT", healAbsorbTexture, "TOPRIGHT", -8, 0);
  309. frame.healAbsorbBarRightShadow:SetPoint("BOTTOMLEFT", healAbsorbTexture, "BOTTOMRIGHT", -8, 0);
  310. frame.healAbsorbBarRightShadow:Show();
  311. else
  312. frame.healAbsorbBarRightShadow:Hide();
  313. end
  314. else
  315. frame.healAbsorbBar:Hide();
  316. frame.healAbsorbBarLeftShadow:Hide();
  317. frame.healAbsorbBarRightShadow:Hide();
  318. end
  319. end
  320. --Show myIncomingHeal on the health bar.
  321. local incomingHealTexture = UnitFrameUtil_UpdateFillBar(frame, healthTexture, frame.myHealPredictionBar, myIncomingHeal, -myCurrentHealAbsorbPercent);
  322. --Append otherIncomingHeal on the health bar
  323. if (myIncomingHeal > 0) then
  324. incomingHealTexture = UnitFrameUtil_UpdateFillBar(frame, incomingHealTexture, frame.otherHealPredictionBar, otherIncomingHeal);
  325. else
  326. incomingHealTexture = UnitFrameUtil_UpdateFillBar(frame, healthTexture, frame.otherHealPredictionBar, otherIncomingHeal, -myCurrentHealAbsorbPercent);
  327. end
  328. --Append absorbs to the correct section of the health bar.
  329. local appendTexture = nil;
  330. if ( healAbsorbTexture ) then
  331. --If there is a healAbsorb part shown, append the absorb to the end of that.
  332. appendTexture = healAbsorbTexture;
  333. else
  334. --Otherwise, append the absorb to the end of the the incomingHeals part;
  335. appendTexture = incomingHealTexture;
  336. end
  337. UnitFrameUtil_UpdateFillBar(frame, appendTexture, frame.totalAbsorbBar, totalAbsorb)
  338. end
  339. function UnitFrameManaCostPredictionBars_Update(frame, isStarting, startTime, endTime, spellID)
  340. if (not frame.manabar or not frame.myManaCostPredictionBar) then
  341. return;
  342. end
  343. local cost = 0;
  344. if (not isStarting or startTime == endTime) then
  345. local currentSpellID = select(9, UnitCastingInfo(frame.unit));
  346. if(currentSpellID and frame.predictedPowerCost) then --if we're currently casting something with a power cost, then whatever cast
  347. cost = frame.predictedPowerCost; --just finished was allowed while casting, don't reset the original cast
  348. else
  349. frame.predictedPowerCost = nil;
  350. end
  351. else
  352. local costTable = GetSpellPowerCost(spellID);
  353. for _, costInfo in pairs(costTable) do
  354. if (costInfo.type == frame.manabar.powerType) then
  355. cost = costInfo.cost;
  356. break;
  357. end
  358. end
  359. frame.predictedPowerCost = cost;
  360. end
  361. local manaBarTexture = frame.manabar:GetStatusBarTexture();
  362. UnitFrameManaBar_Update(frame.manabar, frame.unit);
  363. UnitFrameUtil_UpdateManaFillBar(frame, manaBarTexture, frame.myManaCostPredictionBar, cost);
  364. end
  365. --WARNING: This function is very similar to the function CompactUnitFrameUtil_UpdateFillBar in CompactUnitFrame.lua.
  366. --If you are making changes here, it is possible you may want to make changes there as well.
  367. function UnitFrameUtil_UpdateFillBarBase(frame, realbar, previousTexture, bar, amount, barOffsetXPercent)
  368. if ( amount == 0 ) then
  369. bar:Hide();
  370. if ( bar.overlay ) then
  371. bar.overlay:Hide();
  372. end
  373. return previousTexture;
  374. end
  375. local barOffsetX = 0;
  376. if ( barOffsetXPercent ) then
  377. local realbarSizeX = realbar:GetWidth();
  378. barOffsetX = realbarSizeX * barOffsetXPercent;
  379. end
  380. bar:SetPoint("TOPLEFT", previousTexture, "TOPRIGHT", barOffsetX, 0);
  381. bar:SetPoint("BOTTOMLEFT", previousTexture, "BOTTOMRIGHT", barOffsetX, 0);
  382. local totalWidth, totalHeight = realbar:GetSize();
  383. local _, totalMax = realbar:GetMinMaxValues();
  384. local barSize = (amount / totalMax) * totalWidth;
  385. bar:SetWidth(barSize);
  386. bar:Show();
  387. if ( bar.overlay ) then
  388. bar.overlay:SetTexCoord(0, barSize / bar.overlay.tileSize, 0, totalHeight / bar.overlay.tileSize);
  389. bar.overlay:Show();
  390. end
  391. return bar;
  392. end
  393. function UnitFrameUtil_UpdateFillBar(frame, previousTexture, bar, amount, barOffsetXPercent)
  394. return UnitFrameUtil_UpdateFillBarBase(frame, frame.healthbar, previousTexture, bar, amount, barOffsetXPercent);
  395. end
  396. function UnitFrameUtil_UpdateManaFillBar(frame, previousTexture, bar, amount, barOffsetXPercent)
  397. return UnitFrameUtil_UpdateFillBarBase(frame, frame.manabar, previousTexture, bar, amount, barOffsetXPercent);
  398. end
  399. function UnitFrame_OnEnter (self)
  400. UnitFrame_UpdateTooltip(self);
  401. end
  402. function UnitFrame_OnLeave (self)
  403. self.UpdateTooltip = nil;
  404. GameTooltip:FadeOut();
  405. end
  406. function UnitFrame_UpdateTooltip (self)
  407. GameTooltip_SetDefaultAnchor(GameTooltip, self);
  408. if ( GameTooltip:SetUnit(self.unit, self.hideStatusOnTooltip) ) then
  409. self.UpdateTooltip = UnitFrame_UpdateTooltip;
  410. else
  411. self.UpdateTooltip = nil;
  412. end
  413. local r, g, b = GameTooltip_UnitColor(self.unit);
  414. GameTooltipTextLeft1:SetTextColor(r, g, b);
  415. end
  416. function UnitFrameManaBar_UpdateType (manaBar)
  417. if ( not manaBar ) then
  418. return;
  419. end
  420. local unitFrame = manaBar:GetParent();
  421. local powerType, powerToken, altR, altG, altB = UnitPowerType(manaBar.unit);
  422. local prefix = _G[powerToken];
  423. local info = PowerBarColor[powerToken];
  424. if ( info ) then
  425. if ( not manaBar.lockColor ) then
  426. local playerDeadOrGhost = (manaBar.unit == "player" and (UnitIsDead("player") or UnitIsGhost("player")));
  427. if ( info.atlas ) then
  428. manaBar:SetStatusBarAtlas(info.atlas);
  429. manaBar:SetStatusBarColor(1, 1, 1);
  430. manaBar:GetStatusBarTexture():SetDesaturated(playerDeadOrGhost);
  431. manaBar:GetStatusBarTexture():SetAlpha(playerDeadOrGhost and 0.5 or 1);
  432. else
  433. manaBar:SetStatusBarTexture("Interface\\TargetingFrame\\UI-StatusBar");
  434. if ( playerDeadOrGhost ) then
  435. manaBar:SetStatusBarColor(0.6, 0.6, 0.6, 0.5);
  436. else
  437. manaBar:SetStatusBarColor(info.r, info.g, info.b);
  438. end
  439. end
  440. if ( manaBar.FeedbackFrame ) then
  441. manaBar.FeedbackFrame:Initialize(info, manaBar.unit, powerType);
  442. end
  443. if ( manaBar.FullPowerFrame ) then
  444. manaBar.FullPowerFrame:Initialize(info.fullPowerAnim);
  445. end
  446. end
  447. else
  448. if ( not altR) then
  449. -- couldn't find a power token entry...default to indexing by power type or just mana if we don't have that either
  450. info = PowerBarColor[powerType] or PowerBarColor["MANA"];
  451. else
  452. if ( not manaBar.lockColor ) then
  453. manaBar:SetStatusBarColor(altR, altG, altB);
  454. end
  455. end
  456. end
  457. if ( manaBar.powerType ~= powerType or manaBar.powerType ~= powerType ) then
  458. manaBar.powerType = powerType;
  459. manaBar.powerToken = powerToken;
  460. if ( manaBar.FullPowerFrame ) then
  461. manaBar.FullPowerFrame:RemoveAnims();
  462. end
  463. if manaBar.FeedbackFrame then
  464. manaBar.FeedbackFrame:StopFeedbackAnim();
  465. end
  466. manaBar.currValue = UnitPower("player", powerType);
  467. if unitFrame.myManaCostPredictionBar then
  468. unitFrame.myManaCostPredictionBar:Hide();
  469. end
  470. unitFrame.predictedPowerCost = 0;
  471. end
  472. -- Update the manabar text
  473. if ( not unitFrame.noTextPrefix ) then
  474. SetTextStatusBarTextPrefix(manaBar, prefix);
  475. end
  476. TextStatusBar_UpdateTextString(manaBar);
  477. -- Setup newbie tooltip
  478. if ( manaBar.unit ~= "pet") then
  479. if ( unitFrame:GetName() == "PlayerFrame" ) then
  480. manaBar.tooltipTitle = prefix;
  481. manaBar.tooltipText = _G["NEWBIE_TOOLTIP_MANABAR_"..powerType];
  482. else
  483. manaBar.tooltipTitle = nil;
  484. manaBar.tooltipText = nil;
  485. end
  486. end
  487. end
  488. function UnitFrameHealthBar_Initialize (unit, statusbar, statustext, frequentUpdates)
  489. if ( not statusbar ) then
  490. return;
  491. end
  492. statusbar.unit = unit;
  493. SetTextStatusBarText(statusbar, statustext);
  494. statusbar.frequentUpdates = frequentUpdates;
  495. if ( frequentUpdates ) then
  496. statusbar:RegisterEvent("VARIABLES_LOADED");
  497. end
  498. if ( GetCVarBool("predictedHealth") and frequentUpdates ) then
  499. statusbar:SetScript("OnUpdate", UnitFrameHealthBar_OnUpdate);
  500. else
  501. statusbar:RegisterUnitEvent("UNIT_HEALTH", unit);
  502. end
  503. statusbar:RegisterUnitEvent("UNIT_MAXHEALTH", unit);
  504. statusbar:SetScript("OnEvent", UnitFrameHealthBar_OnEvent);
  505. -- Setup newbie tooltip
  506. if ( statusbar and (statusbar:GetParent() == PlayerFrame) ) then
  507. statusbar.tooltipTitle = HEALTH;
  508. statusbar.tooltipText = NEWBIE_TOOLTIP_HEALTHBAR;
  509. else
  510. statusbar.tooltipTitle = nil;
  511. statusbar.tooltipText = nil;
  512. end
  513. end
  514. function UnitFrameHealthBar_OnEvent(self, event, ...)
  515. if ( event == "CVAR_UPDATE" ) then
  516. TextStatusBar_OnEvent(self, event, ...);
  517. elseif ( event == "VARIABLES_LOADED" ) then
  518. self:UnregisterEvent("VARIABLES_LOADED");
  519. if ( GetCVarBool("predictedHealth") and self.frequentUpdates ) then
  520. self:SetScript("OnUpdate", UnitFrameHealthBar_OnUpdate);
  521. self:UnregisterEvent("UNIT_HEALTH");
  522. else
  523. self:RegisterUnitEvent("UNIT_HEALTH", self.unit);
  524. self:SetScript("OnUpdate", nil);
  525. end
  526. else
  527. if ( not self.ignoreNoUnit or UnitGUID(self.unit) ) then
  528. UnitFrameHealthBar_Update(self, ...);
  529. end
  530. end
  531. end
  532. AnimatedHealthLossMixin = {};
  533. function AnimatedHealthLossMixin:OnLoad()
  534. self:SetStatusBarColor(1, 0, 0, 1);
  535. self:SetDuration(.25);
  536. self:SetStartDelay(.1);
  537. self:SetPauseDelay(.05);
  538. self:SetPostponeDelay(.05);
  539. end
  540. function AnimatedHealthLossMixin:SetDuration(duration)
  541. self.animationDuration = duration or 0;
  542. end
  543. function AnimatedHealthLossMixin:SetStartDelay(delay)
  544. self.animationStartDelay = delay or 0;
  545. end
  546. function AnimatedHealthLossMixin:SetPauseDelay(delay)
  547. self.animationPauseDelay = delay or 0;
  548. end
  549. function AnimatedHealthLossMixin:SetPostponeDelay(delay)
  550. self.animationPostponeDelay = delay or 0;
  551. end
  552. function AnimatedHealthLossMixin:SetUnitHealthBar(unit, healthBar)
  553. if self.unit ~= unit then
  554. healthBar.AnimatedLossBar = self;
  555. self.unit = unit;
  556. self:SetAllPoints(healthBar);
  557. self:UpdateHealthMinMax();
  558. end
  559. end
  560. function AnimatedHealthLossMixin:UpdateHealthMinMax()
  561. local maxValue = UnitHealthMax(self.unit);
  562. self:SetMinMaxValues(0, maxValue);
  563. end
  564. function AnimatedHealthLossMixin:GetHealthLossAnimationData(currentHealth, previousHealth)
  565. if self.animationStartTime then
  566. local totalElapsedTime = GetTime() - self.animationStartTime;
  567. if totalElapsedTime > 0 then
  568. local animCompletePercent = totalElapsedTime / self.animationDuration;
  569. if animCompletePercent < 1 and previousHealth > currentHealth then
  570. local healthDelta = previousHealth - currentHealth;
  571. local animatedLossAmount = previousHealth - (animCompletePercent * healthDelta);
  572. return animatedLossAmount, animCompletePercent;
  573. end
  574. else
  575. return previousHealth, 0;
  576. end
  577. end
  578. return 0, 1; -- Animated loss amount is 0, and the animation is fully complete.
  579. end
  580. function AnimatedHealthLossMixin:CancelAnimation()
  581. self:Hide();
  582. self.animationStartTime = nil;
  583. self.animationCompletePercent = nil;
  584. end
  585. function AnimatedHealthLossMixin:BeginAnimation(value)
  586. self.animationStartValue = value;
  587. self.animationStartTime = GetTime() + self.animationStartDelay;
  588. self.animationCompletePercent = 0;
  589. self:Show();
  590. self:SetValue(self.animationStartValue);
  591. end
  592. function AnimatedHealthLossMixin:PostponeStartTime()
  593. self.animationStartTime = self.animationStartTime + self.animationPostponeDelay;
  594. end
  595. function AnimatedHealthLossMixin:UpdateHealth(currentHealth, previousHealth)
  596. local delta = currentHealth - previousHealth;
  597. local hasLoss = delta < 0;
  598. local hasBegun = self.animationStartTime ~= nil;
  599. local isAnimating = hasBegun and self.animationCompletePercent > 0;
  600. if hasLoss and not hasBegun then
  601. self:BeginAnimation(previousHealth);
  602. elseif hasLoss and hasBegun and not isAnimating then
  603. self:PostponeStartTime();
  604. elseif hasLoss and isAnimating then
  605. -- Reset the starting value of the health to what the animated loss bar was when the new incoming damage happened
  606. -- and pause briefly when new damage occurs.
  607. self.animationStartValue = self:GetHealthLossAnimationData(previousHealth, self.animationStartValue);
  608. self.animationStartTime = GetTime() + self.animationPauseDelay;
  609. elseif not hasLoss and hasBegun and currentHealth >= self.animationStartValue then
  610. self:CancelAnimation();
  611. end
  612. end
  613. function AnimatedHealthLossMixin:UpdateLossAnimation(currentHealth)
  614. local totalAbsorb = UnitGetTotalAbsorbs(self.unit) or 0;
  615. if totalAbsorb > 0 then
  616. self:CancelAnimation();
  617. end
  618. if self.animationStartTime then
  619. local animationValue, animationCompletePercent = self:GetHealthLossAnimationData(currentHealth, self.animationStartValue);
  620. self.animationCompletePercent = animationCompletePercent;
  621. if animationCompletePercent >= 1 then
  622. self:CancelAnimation();
  623. else
  624. self:SetValue(animationValue);
  625. end
  626. end
  627. end
  628. function UnitFrameHealthBar_OnUpdate(self)
  629. if ( not self.disconnected and not self.lockValues) then
  630. local currValue = UnitHealth(self.unit);
  631. local animatedLossBar = self.AnimatedLossBar;
  632. if ( currValue ~= self.currValue ) then
  633. if ( not self.ignoreNoUnit or UnitGUID(self.unit) ) then
  634. if animatedLossBar then
  635. animatedLossBar:UpdateHealth(currValue, self.currValue);
  636. end
  637. self:SetValue(currValue);
  638. self.currValue = currValue;
  639. TextStatusBar_UpdateTextString(self);
  640. UnitFrameHealPredictionBars_Update(self:GetParent());
  641. end
  642. end
  643. if animatedLossBar then
  644. animatedLossBar:UpdateLossAnimation(currValue);
  645. end
  646. end
  647. end
  648. function UnitFrameHealthBar_Update(statusbar, unit)
  649. if ( not statusbar or statusbar.lockValues ) then
  650. return;
  651. end
  652. if ( unit == statusbar.unit ) then
  653. local maxValue = UnitHealthMax(unit);
  654. -- Safety check to make sure we never get an empty bar.
  655. statusbar.forceHideText = false;
  656. if ( maxValue == 0 ) then
  657. maxValue = 1;
  658. statusbar.forceHideText = true;
  659. end
  660. statusbar:SetMinMaxValues(0, maxValue);
  661. if statusbar.AnimatedLossBar then
  662. statusbar.AnimatedLossBar:UpdateHealthMinMax();
  663. end
  664. statusbar.disconnected = not UnitIsConnected(unit);
  665. if ( statusbar.disconnected ) then
  666. if ( not statusbar.lockColor ) then
  667. statusbar:SetStatusBarColor(0.5, 0.5, 0.5);
  668. end
  669. statusbar:SetValue(maxValue);
  670. statusbar.currValue = maxValue;
  671. else
  672. local currValue = UnitHealth(unit);
  673. if ( not statusbar.lockColor ) then
  674. statusbar:SetStatusBarColor(0.0, 1.0, 0.0);
  675. end
  676. statusbar:SetValue(currValue);
  677. statusbar.currValue = currValue;
  678. end
  679. end
  680. TextStatusBar_UpdateTextString(statusbar);
  681. UnitFrameHealPredictionBars_Update(statusbar:GetParent());
  682. end
  683. function UnitFrameHealthBar_OnValueChanged(self, value)
  684. TextStatusBar_OnValueChanged(self, value);
  685. HealthBar_OnValueChanged(self, value);
  686. end
  687. function UnitFrameManaBar_UnregisterDefaultEvents(self)
  688. self:UnregisterEvent("UNIT_POWER_UPDATE");
  689. end
  690. function UnitFrameManaBar_RegisterDefaultEvents(self)
  691. self:RegisterUnitEvent("UNIT_POWER_UPDATE", self.unit);
  692. end
  693. function UnitFrameManaBar_Initialize (unit, statusbar, statustext, frequentUpdates)
  694. if ( not statusbar ) then
  695. return;
  696. end
  697. statusbar.unit = unit;
  698. statusbar.texture = statusbar:GetStatusBarTexture();
  699. SetTextStatusBarText(statusbar, statustext);
  700. statusbar.frequentUpdates = frequentUpdates;
  701. if ( frequentUpdates ) then
  702. statusbar:RegisterEvent("VARIABLES_LOADED");
  703. end
  704. if ( frequentUpdates ) then
  705. statusbar:SetScript("OnUpdate", UnitFrameManaBar_OnUpdate);
  706. else
  707. UnitFrameManaBar_RegisterDefaultEvents(statusbar);
  708. end
  709. statusbar:RegisterEvent("UNIT_DISPLAYPOWER");
  710. statusbar:RegisterUnitEvent("UNIT_MAXPOWER", unit);
  711. if ( statusbar.unit == "player" ) then
  712. statusbar:RegisterEvent("PLAYER_DEAD");
  713. statusbar:RegisterEvent("PLAYER_ALIVE");
  714. statusbar:RegisterEvent("PLAYER_UNGHOST");
  715. end
  716. statusbar:SetScript("OnEvent", UnitFrameManaBar_OnEvent);
  717. end
  718. function UnitFrameManaBar_OnEvent(self, event, ...)
  719. if ( event == "CVAR_UPDATE" ) then
  720. TextStatusBar_OnEvent(self, event, ...);
  721. elseif ( event == "VARIABLES_LOADED" ) then
  722. self:UnregisterEvent("VARIABLES_LOADED");
  723. if ( self.frequentUpdates ) then
  724. self:SetScript("OnUpdate", UnitFrameManaBar_OnUpdate);
  725. UnitFrameManaBar_UnregisterDefaultEvents(self);
  726. else
  727. UnitFrameManaBar_RegisterDefaultEvents(self);
  728. self:SetScript("OnUpdate", nil);
  729. end
  730. elseif ( event == "PLAYER_ALIVE" or event == "PLAYER_DEAD" or event == "PLAYER_UNGHOST" ) then
  731. UnitFrameManaBar_UpdateType(self);
  732. else
  733. if ( not self.ignoreNoUnit or UnitGUID(self.unit) ) then
  734. UnitFrameManaBar_Update(self, ...);
  735. end
  736. end
  737. end
  738. function UnitFrameManaBar_OnUpdate(self)
  739. if ( not self.disconnected and not self.lockValues ) then
  740. local predictedCost = self:GetParent().predictedPowerCost;
  741. local currValue = UnitPower(self.unit, self.powerType);
  742. if (predictedCost) then
  743. currValue = currValue - predictedCost;
  744. end
  745. if ( currValue ~= self.currValue or self.forceUpdate ) then
  746. self.forceUpdate = nil;
  747. if ( not self.ignoreNoUnit or UnitGUID(self.unit) ) then
  748. if ( self.FeedbackFrame ) then
  749. -- Only show anim if change is more than 10%
  750. local oldValue = self.currValue or 0;
  751. if ( self.FeedbackFrame.maxValue ~= 0 and math.abs(currValue - oldValue) / self.FeedbackFrame.maxValue > 0.1 ) then
  752. self.FeedbackFrame:StartFeedbackAnim(oldValue, currValue);
  753. end
  754. end
  755. if ( self.FullPowerFrame and self.FullPowerFrame.active ) then
  756. self.FullPowerFrame:StartAnimIfFull(self.currValue or 0, currValue);
  757. end
  758. self:SetValue(currValue);
  759. self.currValue = currValue;
  760. TextStatusBar_UpdateTextString(self);
  761. end
  762. end
  763. end
  764. end
  765. function UnitFrameManaBar_Update(statusbar, unit)
  766. if ( not statusbar or statusbar.lockValues ) then
  767. return;
  768. end
  769. if ( unit == statusbar.unit ) then
  770. -- be sure to update the power type before grabbing the max power!
  771. UnitFrameManaBar_UpdateType(statusbar);
  772. local maxValue = UnitPowerMax(unit, statusbar.powerType);
  773. statusbar:SetMinMaxValues(0, maxValue);
  774. statusbar.disconnected = not UnitIsConnected(unit);
  775. if ( statusbar.disconnected ) then
  776. statusbar:SetValue(maxValue);
  777. statusbar.currValue = maxValue;
  778. if ( not statusbar.lockColor ) then
  779. statusbar:SetStatusBarColor(0.5, 0.5, 0.5);
  780. end
  781. else
  782. local predictedCost = statusbar:GetParent().predictedPowerCost;
  783. local currValue = UnitPower(unit, statusbar.powerType);
  784. if (predictedCost) then
  785. currValue = currValue - predictedCost;
  786. end
  787. if ( statusbar.FullPowerFrame ) then
  788. statusbar.FullPowerFrame:SetMaxValue(maxValue);
  789. end
  790. statusbar:SetValue(currValue);
  791. statusbar.forceUpdate = true;
  792. end
  793. end
  794. TextStatusBar_UpdateTextString(statusbar);
  795. end
  796. function UnitFrameThreatIndicator_Initialize(unit, unitFrame, feedbackUnit)
  797. local indicator = unitFrame.threatIndicator;
  798. if ( not indicator ) then
  799. return;
  800. end
  801. indicator.unit = unit;
  802. indicator.feedbackUnit = feedbackUnit or unit;
  803. unitFrame:RegisterEvent("UNIT_THREAT_SITUATION_UPDATE");
  804. if ( unitFrame.OnEvent == nil ) then
  805. unitFrame.OnEvent = unitFrame:GetScript("OnEvent") or false;
  806. end
  807. unitFrame:SetScript("OnEvent", UnitFrameThreatIndicator_OnEvent);
  808. end
  809. function UnitFrameThreatIndicator_OnEvent(self, event, ...)
  810. if ( self.OnEvent ) then
  811. self.OnEvent(self, event, ...);
  812. end
  813. if ( event == "UNIT_THREAT_SITUATION_UPDATE" ) then
  814. UnitFrame_UpdateThreatIndicator(self.threatIndicator, self.threatNumericIndicator,...);
  815. end
  816. end
  817. function UnitFrame_UpdateThreatIndicator(indicator, numericIndicator, unit)
  818. if ( not indicator ) then
  819. return;
  820. end
  821. if ( not unit or unit == indicator.feedbackUnit ) then
  822. local status;
  823. if ( indicator.feedbackUnit ~= indicator.unit ) then
  824. status = UnitThreatSituation(indicator.feedbackUnit, indicator.unit);
  825. else
  826. status = UnitThreatSituation(indicator.feedbackUnit);
  827. end
  828. if ( IsThreatWarningEnabled() ) then
  829. if (status and status > 0) then
  830. indicator:SetVertexColor(GetThreatStatusColor(status));
  831. indicator:Show();
  832. else
  833. indicator:Hide();
  834. end
  835. if ( numericIndicator ) then
  836. if ( ShowNumericThreat() and not (UnitClassification(indicator.unit) == "minus") ) then
  837. local isTanking, status, percentage, rawPercentage = UnitDetailedThreatSituation(indicator.feedbackUnit, indicator.unit);
  838. local display = rawPercentage;
  839. if ( isTanking ) then
  840. display = UnitThreatPercentageOfLead(indicator.feedbackUnit, indicator.unit);
  841. end
  842. if ( display and display ~= 0 ) then
  843. numericIndicator.text:SetText(format("%1.0f", display).."%");
  844. numericIndicator.bg:SetVertexColor(GetThreatStatusColor(status));
  845. numericIndicator:Show();
  846. else
  847. numericIndicator:Hide();
  848. end
  849. else
  850. numericIndicator:Hide();
  851. end
  852. end
  853. else
  854. indicator:Hide();
  855. if ( numericIndicator ) then
  856. numericIndicator:Hide();
  857. end
  858. end
  859. end
  860. end
  861. function GetUnitName(unit, showServerName)
  862. local name, server = UnitName(unit);
  863. local relationship = UnitRealmRelationship(unit);
  864. if ( server and server ~= "" ) then
  865. if ( showServerName ) then
  866. return name.."-"..server;
  867. else
  868. if (relationship == LE_REALM_RELATION_VIRTUAL) then
  869. return name;
  870. else
  871. return name..FOREIGN_SERVER_LABEL;
  872. end
  873. end
  874. else
  875. return name;
  876. end
  877. end
  878. function ShowNumericThreat()
  879. if ( GetCVar("threatShowNumeric") == "1" ) then
  880. return true;
  881. else
  882. return false;
  883. end
  884. end