Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

452 linhas
11 KiB

  1. define([
  2. 'js/system/events',
  3. 'css!ui/templates/tooltipItem/styles',
  4. 'html!ui/templates/tooltipItem/template',
  5. 'html!ui/templates/tooltipItem/templateTooltip',
  6. 'js/misc/statTranslations',
  7. 'js/input'
  8. ], function (
  9. events,
  10. styles,
  11. template,
  12. tplTooltip,
  13. statTranslations,
  14. input
  15. ) {
  16. let percentageStats = [
  17. 'addCritChance',
  18. 'addCritMultiplier',
  19. 'addAttackCritChance',
  20. 'addAttackCritMultiplier',
  21. 'addSpellCritChance',
  22. 'addSpellCritMultiplier',
  23. 'sprintChance',
  24. 'xpIncrease',
  25. 'blockAttackChance',
  26. 'blockSpellChance',
  27. 'dodgeAttackChance',
  28. 'dodgeSpellChance',
  29. 'attackSpeed',
  30. 'castSpeed',
  31. 'itemQuantity',
  32. 'magicFind',
  33. 'catchChance',
  34. 'catchSpeed',
  35. 'fishRarity',
  36. 'fishWeight',
  37. 'fishItems'
  38. ];
  39. return {
  40. tpl: template,
  41. type: 'tooltipItem',
  42. tooltip: null,
  43. item: null,
  44. postRender: function () {
  45. this.tooltip = this.el.find('.tooltip');
  46. this.onEvent('onShowItemTooltip', this.onShowItemTooltip.bind(this));
  47. this.onEvent('onHideItemTooltip', this.onHideItemTooltip.bind(this));
  48. },
  49. getCompareItem: function (msg) {
  50. const shiftDown = input.isKeyDown('shift', true);
  51. let item = msg.item;
  52. let items = window.player.inventory.items;
  53. let compare = null;
  54. if (item.slot) {
  55. compare = items.find(i => i.eq && i.slot === item.slot);
  56. // check special cases for mismatched weapon/offhand scenarios (only valid when comparing)
  57. if (!compare) {
  58. let equippedTwoHanded = items.find(i => i.eq && i.slot === 'twoHanded');
  59. let equippedOneHanded = items.find(i => i.eq && i.slot === 'oneHanded');
  60. let equippedOffhand = items.find(i => i.eq && i.slot === 'offHand');
  61. if (item.slot === 'twoHanded') {
  62. if (!equippedOneHanded)
  63. compare = equippedOffhand;
  64. else if (!equippedOffhand)
  65. compare = equippedOneHanded;
  66. else {
  67. // compare against oneHanded and offHand combined by creating a virtual item that is the sum of the two
  68. compare = $.extend(true, {}, equippedOneHanded);
  69. compare.refItem = equippedOneHanded;
  70. for (let s in equippedOffhand.stats) {
  71. if (!compare.stats[s])
  72. compare.stats[s] = 0;
  73. compare.stats[s] += equippedOffhand.stats[s];
  74. }
  75. }
  76. }
  77. if (item.slot === 'oneHanded')
  78. compare = equippedTwoHanded;
  79. // this case is kind of ugly, but we don't want to go in when comparing an offHand to (oneHanded + empty offHand) - that should just use the normal compare which is offHand to empty
  80. if (item.slot === 'offHand' && equippedTwoHanded && shiftDown) {
  81. // since we're comparing an offhand to an equipped Twohander, we need to clone the 'spell' values over (setting damage to zero) so that we can properly display how much damage
  82. // the player would lose by switching to the offhand (which would remove the twoHander)
  83. // keep a reference to the original item for use in onHideToolTip
  84. let spellClone = $.extend(true, {}, equippedTwoHanded.spell);
  85. spellClone.name = '';
  86. spellClone.values.damage = 0;
  87. let clone = $.extend(true, {}, item, {
  88. spell: spellClone
  89. });
  90. clone.refItem = item;
  91. msg.item = clone;
  92. compare = equippedTwoHanded;
  93. }
  94. }
  95. }
  96. msg.compare = compare;
  97. },
  98. onHideItemTooltip: function (item) {
  99. if (
  100. (!this.item) ||
  101. (
  102. (this.item !== item) &&
  103. (this.item.refItem) &&
  104. (this.item.refItem !== item)
  105. )
  106. )
  107. return;
  108. this.item = null;
  109. this.tooltip.hide();
  110. },
  111. onShowItemTooltip: function (item, pos, canCompare, bottomAlign) {
  112. const shiftDown = input.isKeyDown('shift', true);
  113. let msg = {
  114. item: item,
  115. compare: null
  116. };
  117. this.getCompareItem(msg);
  118. this.item = item = msg.item;
  119. let compare = canCompare ? msg.compare : null;
  120. let tempStats = $.extend(true, {}, item.stats);
  121. let enchantedStats = item.enchantedStats || {};
  122. if (compare && shiftDown) {
  123. if (!item.eq) {
  124. let compareStats = compare.stats;
  125. for (let s in tempStats) {
  126. if (compareStats[s]) {
  127. let delta = tempStats[s] - compareStats[s];
  128. if (delta > 0)
  129. tempStats[s] = '+' + delta;
  130. else if (delta < 0)
  131. tempStats[s] = delta;
  132. } else
  133. tempStats[s] = '+' + tempStats[s];
  134. }
  135. for (let s in compareStats) {
  136. if (!tempStats[s])
  137. tempStats[s] = -compareStats[s];
  138. }
  139. }
  140. } else {
  141. Object.keys(tempStats).forEach(function (s) {
  142. if (enchantedStats[s]) {
  143. tempStats[s] -= enchantedStats[s];
  144. if (tempStats[s] <= 0)
  145. delete tempStats[s];
  146. tempStats['_' + s] = enchantedStats[s];
  147. }
  148. });
  149. }
  150. let stats = Object.keys(tempStats)
  151. .map(s => {
  152. let isEnchanted = (s[0] === '_');
  153. let statName = s;
  154. if (isEnchanted)
  155. statName = statName.substr(1);
  156. let value = this.getStatValue(statName, tempStats[s]);
  157. statName = statTranslations.translate(statName);
  158. let row = value + ' ' + statName;
  159. let rowClass = '';
  160. if (compare) {
  161. if (row.indexOf('-') > -1)
  162. rowClass = 'loseStat';
  163. else if (row.indexOf('+') > -1)
  164. rowClass = 'gainStat';
  165. }
  166. if (isEnchanted)
  167. rowClass += ' enchanted';
  168. row = '<div class="' + rowClass + '">' + row + '</div>';
  169. return row;
  170. })
  171. .sort(function (a, b) {
  172. return (a.replace(' enchanted', '').length - b.replace(' enchanted', '').length);
  173. })
  174. .sort(function (a, b) {
  175. if ((a.indexOf('enchanted') > -1) && (b.indexOf('enchanted') === -1))
  176. return 1;
  177. else if ((a.indexOf('enchanted') === -1) && (b.indexOf('enchanted') > -1))
  178. return -1;
  179. return 0;
  180. })
  181. .join('');
  182. let implicitStats = (item.implicitStats || []).map(s => {
  183. let stat = s.stat;
  184. let value = this.getStatValue(stat, s.value);
  185. let statName = statTranslations.translate(stat);
  186. let row = value + ' ' + statName;
  187. let rowClass = '';
  188. row = '<div class="' + rowClass + '">' + row + '</div>';
  189. return row;
  190. }).join('');
  191. let itemName = item.name;
  192. if (item.quantity > 1)
  193. itemName += ' x' + item.quantity;
  194. let level = null;
  195. if (item.level)
  196. level = item.level.push ? item.level[0] + ' - ' + item.level[1] : item.level;
  197. let html = tplTooltip
  198. .replace('$NAME$', itemName)
  199. .replace('$QUALITY$', item.quality)
  200. .replace('$TYPE$', item.type)
  201. .replace('$SLOT$', item.slot)
  202. .replace('$IMPLICITSTATS$', implicitStats)
  203. .replace('$STATS$', stats)
  204. .replace('$LEVEL$', level);
  205. if (item.requires && item.requires[0]) {
  206. html = html
  207. .replace('$ATTRIBUTE$', item.requires[0].stat)
  208. .replace('$ATTRIBUTEVALUE$', item.requires[0].value);
  209. }
  210. if (item.power)
  211. html = html.replace('$POWER$', ' ' + (new Array(item.power + 1)).join('+'));
  212. if ((item.spell) && (item.spell.values)) {
  213. let abilityValues = '';
  214. for (let p in item.spell.values) {
  215. if ((compare) && (shiftDown)) {
  216. let delta = item.spell.values[p] - compare.spell.values[p];
  217. // adjust by EPSILON to handle float point imprecision, otherwise 3.15 - 2 = 1.14 or 2 - 3.15 = -1.14
  218. // have to move away from zero by EPSILON, not a simple add
  219. if (delta >= 0)
  220. delta += Number.EPSILON;
  221. else
  222. delta -= Number.EPSILON;
  223. delta = ~~((delta) * 100) / 100;
  224. let rowClass = '';
  225. if (delta > 0) {
  226. rowClass = 'gainDamage';
  227. delta = '+' + delta;
  228. } else if (delta < 0)
  229. rowClass = 'loseDamage';
  230. abilityValues += '<div class="' + rowClass + '">' + p + ': ' + delta + '</div>';
  231. } else
  232. abilityValues += p + ': ' + item.spell.values[p] + '<br/>';
  233. }
  234. if (!item.ability)
  235. abilityValues = abilityValues;
  236. html = html.replace('$DAMAGE$', abilityValues);
  237. }
  238. let tooltip = this.tooltip;
  239. tooltip.html(html);
  240. if (!item.level)
  241. tooltip.find('.level').hide();
  242. else
  243. tooltip.find('.level').show();
  244. if (!item.implicitStats)
  245. tooltip.find('.implicitStats').hide();
  246. else
  247. tooltip.find('.implicitStats').show();
  248. if (!item.requires) {
  249. if (!item.level)
  250. tooltip.find('.requires').hide();
  251. else
  252. tooltip.find('.requires .stats').hide();
  253. } else
  254. tooltip.find('.requires .stats').show();
  255. if (!stats.length)
  256. tooltip.children('.stats').hide();
  257. if ((!item.type) || (item.type === item.name))
  258. tooltip.find('.type').hide();
  259. else {
  260. tooltip.find('.type')
  261. .html(item.type)
  262. .show();
  263. }
  264. if (item.power)
  265. tooltip.find('.power').show();
  266. let equipErrors = window.player.inventory.equipItemErrors(item);
  267. equipErrors.forEach(function (e) {
  268. tooltip.find('.requires').addClass('high-level');
  269. tooltip.find('.requires .' + e).addClass('high-level');
  270. }, this);
  271. if ((item.material) || (item.quest)) {
  272. tooltip.find('.level').hide();
  273. tooltip.find('.info').hide();
  274. if (item.material)
  275. tooltip.find('.material').show();
  276. else if (item.quest)
  277. tooltip.find('.quest').show();
  278. } else if (item.eq)
  279. tooltip.find('.info').hide();
  280. if (!item.ability)
  281. tooltip.find('.damage').hide();
  282. else
  283. tooltip.find('.info').hide();
  284. if (item.spell) {
  285. tooltip.find('.spellName')
  286. .html(item.spell.name)
  287. .addClass('q' + item.spell.quality)
  288. .show();
  289. tooltip.find('.damage')
  290. .show();
  291. if (item.spell.manaCost) {
  292. tooltip.find('.spellCost')
  293. .html(item.spell.manaCost + ' mana')
  294. .show();
  295. }
  296. if (item.ability)
  297. tooltip.find('.spellName').hide();
  298. } else {
  299. tooltip.find('.spellName').hide();
  300. tooltip.find('.spellCost').hide();
  301. }
  302. tooltip.find('.worth').html(item.worthText ? ('<br />value: ' + item.worthText) : '');
  303. if (item.effects && item.effects[0].text && item.type !== 'mtx') {
  304. let htmlEffects = '';
  305. item.effects.forEach(function (e, i) {
  306. htmlEffects += e.text;
  307. if (i < item.effects.length - 1)
  308. htmlEffects += '<br />';
  309. });
  310. this.find('.effects')
  311. .html(htmlEffects)
  312. .show();
  313. } else if (item.description) {
  314. this.find('.effects')
  315. .html(item.description)
  316. .show();
  317. } else
  318. this.find('.effects').hide();
  319. if (item.type === 'Reward Card') {
  320. this.find('.spellName')
  321. .html('Set Size: ' + item.setSize)
  322. .show();
  323. }
  324. if (item.factions) {
  325. let htmlFactions = '';
  326. item.factions.forEach(function (f, i) {
  327. let htmlF = f.name + ': ' + f.tierName;
  328. if (f.noEquip)
  329. htmlF = '<font class="color-red">' + htmlF + '</font>';
  330. htmlFactions += htmlF;
  331. if (i < item.factions.length - 1)
  332. htmlFactions += '<br />';
  333. });
  334. this.find('.faction')
  335. .html(htmlFactions)
  336. .show();
  337. } else
  338. this.find('.faction').hide();
  339. if (shiftDown || !compare)
  340. tooltip.find('.info').hide();
  341. if (item.cd) {
  342. tooltip.find('.info')
  343. .html('cooldown: ' + item.cd)
  344. .show();
  345. } else if (item.uses) {
  346. tooltip.find('.info')
  347. .html('uses: ' + item.uses)
  348. .show();
  349. }
  350. this.tooltip
  351. .show();
  352. if (pos) {
  353. if (bottomAlign)
  354. pos.y -= this.tooltip.height();
  355. this.tooltip.css({
  356. left: pos.x,
  357. top: pos.y
  358. });
  359. }
  360. events.emit('onBuiltItemTooltip', this.tooltip);
  361. },
  362. getStatValue: function (statName, statValue) {
  363. let res = statValue;
  364. if (statName.indexOf('CritChance') > -1)
  365. res = res / 20;
  366. if (percentageStats.includes(statName) || (statName.indexOf('element') === 0 && statName.indexOf('Resist') === -1))
  367. res += '%';
  368. return res;
  369. },
  370. showWorth: function (canAfford) {
  371. this.tooltip.find('.worth').show();
  372. if (!canAfford)
  373. this.tooltip.find('.worth').addClass('no-afford');
  374. }
  375. };
  376. });