No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

486 líneas
12 KiB

  1. define([
  2. 'js/system/events',
  3. 'js/system/client',
  4. 'html!ui/templates/equipment/template',
  5. 'css!ui/templates/equipment/styles',
  6. 'js/input',
  7. 'ui/shared/renderItem'
  8. ], function (
  9. events,
  10. client,
  11. template,
  12. styles,
  13. input,
  14. renderItem
  15. ) {
  16. return {
  17. tpl: template,
  18. centered: true,
  19. modal: true,
  20. hasClose: true,
  21. stats: null,
  22. equipment: null,
  23. hoverItem: null,
  24. hoverEl: null,
  25. hoverCompare: null,
  26. isInspecting: false,
  27. postRender: function () {
  28. this.onEvent('onGetStats', this.onGetStats.bind(this));
  29. this.onEvent('onGetItems', this.onGetItems.bind(this));
  30. this.onEvent('onInspectTarget', this.onInspectTarget.bind(this));
  31. this.onEvent('onShowEquipment', this.toggle.bind(this));
  32. this.find('.tab').on('click', this.onTabClick.bind(this));
  33. this.onEvent('onKeyDown', this.onKeyDown.bind(this));
  34. this.onEvent('onKeyUp', this.onKeyUp.bind(this));
  35. },
  36. beforeHide: function () {
  37. this.isInspecting = false;
  38. delete this.result;
  39. },
  40. toggle: function (show) {
  41. this.shown = !this.el.is(':visible');
  42. this.isInspecting = false;
  43. delete this.result;
  44. this.find('.itemList').hide();
  45. if (this.shown) {
  46. this.show();
  47. this.onGetStats();
  48. this.onGetItems();
  49. } else
  50. this.hide();
  51. this.onHoverItem(null, null, null);
  52. },
  53. onKeyDown: function (key) {
  54. if (key === 'j')
  55. this.toggle();
  56. else if (key === 'shift' && this.hoverItem)
  57. this.onHoverItem(this.hoverEl, this.hoverItem, this.hoverCompare);
  58. },
  59. onKeyUp: function (key) {
  60. if (key === 'shift' && this.hoverItem)
  61. this.onHoverItem(this.hoverEl, this.hoverItem, null);
  62. },
  63. onTabClick: function (e) {
  64. this.find('.tab.selected').removeClass('selected');
  65. $(e.target).addClass('selected');
  66. let stats = this.isInspecting ? this.result.stats : this.stats;
  67. this.onGetStats(stats);
  68. },
  69. onGetItems: function (items) {
  70. items = items || this.items;
  71. if (!this.isInspecting)
  72. this.items = items;
  73. if (!this.shown)
  74. return;
  75. this.find('.slot').addClass('empty');
  76. this.find('[slot]')
  77. .removeData('item')
  78. .addClass('empty show-default-icon')
  79. .find('.info')
  80. .html('')
  81. .parent()
  82. .find('.icon')
  83. .off()
  84. .css('background-image', '')
  85. .css('background-position', '')
  86. .on('click', this.buildSlot.bind(this));
  87. this.find('[slot]').toArray().forEach(el => {
  88. el = $(el);
  89. let slot = el.attr('slot');
  90. let newItems = window.player.inventory.items.some(i => {
  91. if (slot.indexOf('finger') === 0)
  92. slot = 'finger';
  93. else if (slot === 'oneHanded')
  94. return (['oneHanded', 'twoHanded'].includes(i.slot) && i.isNew);
  95. return (i.slot === slot && i.isNew);
  96. });
  97. if (newItems)
  98. el.find('.info').html('new');
  99. });
  100. items
  101. .filter(item => item.has('quickSlot') || (item.eq && (item.slot || item.has('runeSlot'))))
  102. .forEach(item => {
  103. let slot = item.slot;
  104. if (item.has('runeSlot')) {
  105. let runeSlot = item.runeSlot;
  106. slot = 'rune-' + runeSlot;
  107. } else if (item.has('quickSlot'))
  108. slot = 'quick-' + item.quickSlot;
  109. slot = item.equipSlot || slot;
  110. const elSlot = this.find('[slot="' + slot + '"]')
  111. .removeClass('empty show-default-icon');
  112. const itemEl = renderItem(null, item, elSlot);
  113. itemEl
  114. .data('item', item)
  115. .removeClass('empty show-default-icon')
  116. .find('.icon')
  117. .off()
  118. .on('contextmenu', this.showContext.bind(this, item))
  119. .on('mousedown', this.buildSlot.bind(this, elSlot))
  120. .on('mousemove', this.onHoverItem.bind(this, elSlot, item, null))
  121. .on('mouseleave', this.onHoverItem.bind(this, null, null));
  122. });
  123. },
  124. showContext: function (item, e) {
  125. let menuItems = {
  126. unequip: {
  127. text: 'unequip',
  128. callback: this.unequipItem.bind(this, item)
  129. }
  130. };
  131. let config = [];
  132. config.push(menuItems.unequip);
  133. events.emit('onContextMenu', config, e);
  134. e.preventDefault();
  135. return false;
  136. },
  137. unequipItem: function (item) {
  138. const isQuickslot = item.has('quickSlot');
  139. const method = isQuickslot ? 'setQuickSlot' : 'unequip';
  140. const data = isQuickslot ? { slot: item.quickSlot } : item.id;
  141. client.request({
  142. cpn: 'player',
  143. method: 'performAction',
  144. data: {
  145. cpn: 'equipment',
  146. method,
  147. data
  148. }
  149. });
  150. },
  151. onInspectTarget: function (result) {
  152. this.isInspecting = true;
  153. this.show();
  154. this.result = result;
  155. this.onGetStats(result.stats);
  156. this.onGetItems(result.equipment);
  157. },
  158. buildSlot: function (el, e) {
  159. if (e && e.button !== 0)
  160. return;
  161. if (this.isInspecting)
  162. return;
  163. if (el.target)
  164. el = $(el.target).parent();
  165. let slot = el.attr('slot');
  166. let isRune = (slot.indexOf('rune') === 0);
  167. const isConsumable = (slot.indexOf('quick') === 0);
  168. let container = this.find('.itemList')
  169. .empty()
  170. .show();
  171. let hoverCompare = this.hoverCompare = el.data('item');
  172. let items = this.items
  173. .filter(item => {
  174. if (isRune)
  175. return (!item.slot && item.spell && !item.eq);
  176. else if (isConsumable)
  177. return (item.type === 'consumable' && !item.has('quickSlot'));
  178. let checkSlot = (slot.indexOf('finger') === 0) ? 'finger' : slot;
  179. if (slot === 'oneHanded')
  180. return (!item.eq && (item.slot === 'oneHanded' || item.slot === 'twoHanded'));
  181. return (item.slot === checkSlot && !item.eq);
  182. });
  183. if (isConsumable)
  184. items = items.filter((item, i) => items.findIndex(f => f.name === item.name) === i);
  185. items.splice(0, 0, {
  186. name: 'None',
  187. slot: hoverCompare ? hoverCompare.slot : null,
  188. id: (hoverCompare && !isConsumable) ? hoverCompare.id : null,
  189. type: isConsumable ? 'consumable' : null,
  190. empty: true
  191. });
  192. if (hoverCompare)
  193. items.splice(1, 0, hoverCompare);
  194. items
  195. .forEach(function (item, i) {
  196. let sprite = item.sprite || [7, 0];
  197. let spriteSheet = item.empty ? '../../../images/uiIcons.png' : item.spritesheet || '../../../images/items.png';
  198. if (i > 0 && item.type === 'consumable')
  199. spriteSheet = '../../../images/consumables.png';
  200. let imgX = -sprite[0] * 64;
  201. let imgY = -sprite[1] * 64;
  202. let itemEl = $('<div class="slot"><div class="icon"></div></div>')
  203. .appendTo(container);
  204. itemEl
  205. .find('.icon')
  206. .css('background', 'url("' + spriteSheet + '") ' + imgX + 'px ' + imgY + 'px')
  207. .on('mousedown', this.equipItem.bind(this, item, slot))
  208. .on('mousemove', this.onHoverItem.bind(this, itemEl, item, null))
  209. .on('mouseleave', this.onHoverItem.bind(this, null, null));
  210. if (item === hoverCompare)
  211. itemEl.find('.icon').addClass('eq');
  212. else if (item.isNew)
  213. el.find('.icon').addClass('new');
  214. }, this);
  215. if (!items.length)
  216. container.hide();
  217. if (e) {
  218. e.preventDefault();
  219. return false;
  220. }
  221. },
  222. equipItem: function (item, slot, e) {
  223. let isNew = window.player.inventory.items.some(f => (f.equipSlot === slot && f.isNew));
  224. if (!isNew)
  225. this.find('[slot="' + slot + '"] .info').html('');
  226. if (item === this.hoverCompare) {
  227. this.find('.itemList').hide();
  228. return;
  229. }
  230. let cpn = 'equipment';
  231. let method = 'equip';
  232. let data = item.id;
  233. if (item.empty)
  234. method = 'unequip';
  235. if (item.type === 'consumable') {
  236. cpn = 'equipment';
  237. method = 'setQuickSlot';
  238. data = {
  239. itemId: item.id,
  240. slot: ~~slot.replace('quick-', '')
  241. };
  242. } else if (!item.slot) {
  243. cpn = 'inventory';
  244. method = 'learnAbility';
  245. data = {
  246. itemId: item.id,
  247. slot: ~~slot.replace('rune-', '')
  248. };
  249. if (item.empty) {
  250. if (!this.hoverCompare) {
  251. this.find('.itemList').hide();
  252. return;
  253. }
  254. method = 'unlearnAbility';
  255. data.itemId = this.hoverCompare.id;
  256. }
  257. } else if (item.slot === 'finger') {
  258. data = {
  259. itemId: item.id,
  260. slot: slot
  261. };
  262. }
  263. client.request({
  264. cpn: 'player',
  265. method: 'performAction',
  266. data: {
  267. cpn: cpn,
  268. method: method,
  269. data: data
  270. }
  271. });
  272. this.find('.itemList').hide();
  273. e.preventDefault();
  274. return false;
  275. },
  276. onHoverItem: function (el, item, compare, e) {
  277. if (el) {
  278. this.hoverItem = item;
  279. this.hoverEl = el;
  280. if ((item.isNew) && (!item.eq)) {
  281. delete item.isNew;
  282. el.find('.icon').removeClass('new');
  283. }
  284. let ttPos = null;
  285. if (e) {
  286. ttPos = {
  287. x: ~~(e.clientX + 32),
  288. y: ~~(e.clientY)
  289. };
  290. }
  291. events.emit('onShowItemTooltip', item, ttPos, this.hoverCompare);
  292. } else {
  293. events.emit('onHideItemTooltip', this.hoverItem);
  294. this.hoverItem = null;
  295. }
  296. },
  297. onGetStats: function (stats ) {
  298. if (stats && !this.isInspecting)
  299. this.stats = stats;
  300. stats = stats || this.stats;
  301. if (!this.shown)
  302. return;
  303. let container = this.el.find('.stats');
  304. container
  305. .children('*:not(.tabs)')
  306. .remove();
  307. let xpRemaining = (stats.xpMax - stats.xp).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  308. let newStats = {
  309. basic: {
  310. level: stats.level,
  311. 'next level': xpRemaining + 'xp',
  312. gap1: '',
  313. gold: window.player.trade.gold,
  314. gap2: '',
  315. hp: ~~stats.hp + '/' + ~~stats.hpMax,
  316. mana: ~~stats.mana + '/' + ~~stats.manaMax,
  317. 'hp regen': stats.regenHp,
  318. 'mana regen': ~~stats.regenMana + '%',
  319. gap3: '',
  320. str: stats.str,
  321. int: stats.int,
  322. dex: stats.dex,
  323. vit: stats.vit
  324. },
  325. offense: {
  326. 'global crit chance': (~~(stats.critChance * 10) / 10) + '%',
  327. 'global crit multiplier': (~~(stats.critMultiplier * 10) / 10) + '%',
  328. 'attack crit chance': (~~((stats.critChance + stats.attackCritChance) * 10) / 10) + '%',
  329. 'attack crit multiplier': (~~((stats.critMultiplier + stats.attackCritMultiplier) * 10) / 10) + '%',
  330. 'spell crit chance': (~~((stats.critChance + stats.spellCritChance) * 10) / 10) + '%',
  331. 'spell crit multiplier': (~~((stats.critMultiplier + stats.spellCritMultiplier) * 10) / 10) + '%',
  332. gap1: '',
  333. 'arcane increase': stats.elementArcanePercent + '%',
  334. 'fire increase': stats.elementFirePercent + '%',
  335. 'frost increase': stats.elementFrostPercent + '%',
  336. 'holy increase': stats.elementHolyPercent + '%',
  337. 'poison increase': stats.elementPoisonPercent + '%',
  338. 'physical increase': stats.physicalPercent + '%',
  339. gap2: '',
  340. 'spell increase': stats.spellPercent + '%',
  341. gap3: '',
  342. 'attack speed': (100 + stats.attackSpeed) + '%',
  343. 'cast speed': (100 + stats.castSpeed) + '%'
  344. },
  345. defense: {
  346. armor: stats.armor,
  347. 'chance to block attacks': stats.blockAttackChance + '%',
  348. 'chance to block spells': stats.blockSpellChance + '%',
  349. gap1: '',
  350. 'chance to dodge attacks': (~~(stats.dodgeAttackChance * 10) / 10) + '%',
  351. 'chance to dodge spells': (~~(stats.dodgeSpellChance * 10) / 10) + '%',
  352. gap2: '',
  353. 'arcane resist': stats.elementArcaneResist,
  354. 'fire resist': stats.elementFireResist,
  355. 'frost resist': stats.elementFrostResist,
  356. 'holy resist': stats.elementHolyResist,
  357. 'poison resist': stats.elementPoisonResist,
  358. gap3: '',
  359. 'all resist': stats.elementAllResist,
  360. gap4: '',
  361. 'life gained on hit': stats.lifeOnHit
  362. },
  363. misc: {
  364. 'item quality': stats.magicFind + '%',
  365. 'item quantity': stats.itemQuantity + '%',
  366. gap1: '',
  367. 'sprint chance': ((~~(stats.sprintChance * 100) / 100) || 0) + '%',
  368. gap2: '',
  369. 'xp increase': stats.xpIncrease + '%',
  370. gap3: '',
  371. 'chance to catch a fish': stats.catchChance + '%',
  372. 'fishing speed': stats.catchSpeed + '%',
  373. 'increased fish rarity': stats.fishRarity + '%',
  374. 'increased fish weight': stats.fishWeight + '%',
  375. 'chance to fish items': stats.fishItems + '%'
  376. }
  377. }[this.find('.tab.selected').html()];
  378. for (let s in newStats) {
  379. let label = s + ': ';
  380. let value = newStats[s];
  381. let isGap = false;
  382. if (label.indexOf('gap') === 0) {
  383. isGap = true;
  384. label = '';
  385. value = '';
  386. }
  387. let row = $('<div class="stat"><font class="q0">' + label + '</font><font color="#999">' + value + '</font></div>')
  388. .appendTo(container);
  389. if (s === 'gold')
  390. row.addClass('gold');
  391. else if ((s === 'level') || (s === 'next level'))
  392. row.addClass('blueText');
  393. if (isGap)
  394. row.addClass('empty');
  395. }
  396. }
  397. };
  398. });