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.
 
 
 

583 linhas
14 KiB

  1. define([
  2. 'js/system/events',
  3. 'js/system/client',
  4. 'html!ui/templates/inventory/template',
  5. 'css!ui/templates/inventory/styles',
  6. 'html!ui/templates/inventory/templateItem',
  7. 'js/input',
  8. 'js/config',
  9. 'ui/shared/renderItem'
  10. ], function (
  11. events,
  12. client,
  13. template,
  14. styles,
  15. tplItem,
  16. input,
  17. config,
  18. renderItem
  19. ) {
  20. return {
  21. tpl: template,
  22. centered: true,
  23. items: [],
  24. dragItem: null,
  25. dragEl: null,
  26. hoverCell: null,
  27. modal: true,
  28. hasClose: true,
  29. oldSpellsZIndex: 0,
  30. postRender: function () {
  31. this.onEvent('onGetItems', this.onGetItems.bind(this));
  32. this.onEvent('onDestroyItems', this.onDestroyItems.bind(this));
  33. this.onEvent('onShowInventory', this.toggle.bind(this));
  34. this.onEvent('onToggleQualityIndicators', this.onToggleQualityIndicators.bind(this));
  35. this.onToggleQualityIndicators(config.qualityIndicators);
  36. this.onEvent('onToggleUnusableIndicators', this.onToggleUnusableIndicators.bind(this));
  37. this.onToggleUnusableIndicators(config.unusableIndicators);
  38. this.onEvent('onKeyDown', this.onKeyDown.bind(this));
  39. this.onEvent('onKeyUp', this.onKeyUp.bind(this));
  40. this.find('.grid')
  41. .on('mousemove', this.onMouseMove.bind(this))
  42. .on('mouseleave', this.onMouseDown.bind(this, null, null, false));
  43. this.find('.split-box .amount')
  44. .on('mousewheel', this.onChangeStackAmount.bind(this))
  45. .on('input', this.onEnterStackAmount.bind(this));
  46. this.find('.split-box').on('click', this.splitStackEnd.bind(this, true));
  47. this.find('.split-box .btnSplit').on('click', this.splitStackEnd.bind(this, null));
  48. this.find('.split-box .btnLess').on('click', this.onChangeStackAmount.bind(this, null, -1));
  49. this.find('.split-box .btnMore').on('click', this.onChangeStackAmount.bind(this, null, 1));
  50. this.find('.btnSortInv').on('click', this.onSortInventory.bind(this));
  51. },
  52. build: function () {
  53. let container = this.el.find('.grid')
  54. .empty();
  55. let items = this.items
  56. .filter(function (item) {
  57. return !item.eq;
  58. });
  59. let iLen = Math.max(items.length, 50);
  60. let rendered = [];
  61. for (let i = 0; i < iLen; i++) {
  62. let itemEl = null;
  63. let item = items.find(f => (f.pos !== null && f.pos === i));
  64. if (!item) {
  65. itemEl = renderItem(container, null);
  66. itemEl
  67. .on('mouseup', this.onMouseDown.bind(this, null, null, false))
  68. .on('mousemove', this.onHover.bind(this, itemEl, item))
  69. .on('mouseleave', this.hideTooltip.bind(this, itemEl, item))
  70. .children()
  71. .remove();
  72. continue;
  73. } else
  74. rendered.push(item);
  75. itemEl = renderItem(container, item);
  76. let clickHandler = this.onMouseDown.bind(this, itemEl, item, true);
  77. let moveHandler = this.onHover.bind(this, itemEl, item);
  78. if (isMobile) {
  79. clickHandler = this.onHover.bind(this, itemEl, item);
  80. moveHandler = () => {};
  81. }
  82. itemEl
  83. .data('item', item)
  84. .on('click', this.onClick.bind(this, item, false))
  85. .on('mousedown', clickHandler)
  86. .on('mouseup', this.onMouseDown.bind(this, null, null, false))
  87. .on('mousemove', moveHandler)
  88. .on('mouseleave', this.hideTooltip.bind(this, itemEl, item))
  89. .find('.icon')
  90. .on('contextmenu', this.showContext.bind(this, item));
  91. }
  92. },
  93. onToggleQualityIndicators: function (state) {
  94. const className = `quality-${state.toLowerCase()}`;
  95. $('.ui-container')
  96. .removeClass('quality-off quality-bottom quality-border quality-background')
  97. .addClass(className);
  98. },
  99. onToggleUnusableIndicators: function (state) {
  100. const className = `unusable-${state.toLowerCase()}`;
  101. $('.ui-container')
  102. .removeClass('unusable-off unusable-border unusable-top unusable-background')
  103. .addClass(className);
  104. },
  105. onClick: function (item, forceCtrl) {
  106. let msg = {
  107. item: item,
  108. success: true
  109. };
  110. events.emit('beforeInventoryClickItem', msg);
  111. if (!msg.success)
  112. return;
  113. if (!forceCtrl && !input.isKeyDown('ctrl', true))
  114. return;
  115. client.request({
  116. cpn: 'social',
  117. method: 'chat',
  118. data: {
  119. message: '{' + item.name + '}',
  120. item: item
  121. }
  122. });
  123. },
  124. onMouseDown: function (el, item, down, e) {
  125. if (e.button !== 0)
  126. return;
  127. if (down) {
  128. this.dragEl = el.clone()
  129. .appendTo(this.find('.grid'))
  130. .hide()
  131. .on('mouseup', this.onMouseDown.bind(this, null, null, false))
  132. .addClass('dragging');
  133. this.dragItem = el;
  134. events.emit('onHideItemTooltip', this.hoverItem);
  135. this.hoverItem = null;
  136. } else if (this.dragItem) {
  137. let method = 'moveItem';
  138. if ((this.hoverCell) && (this.hoverCell[0] !== this.dragItem[0])) {
  139. let placeholder = $('<div></div>')
  140. .insertAfter(this.dragItem);
  141. this.dragItem.insertBefore(this.hoverCell);
  142. this.hoverCell.insertBefore(placeholder);
  143. placeholder.remove();
  144. let msgs = [{
  145. id: this.dragItem.data('item').id,
  146. pos: this.dragItem.index()
  147. }];
  148. this.items.find(function (i) {
  149. return (i.id === this.dragItem.data('item').id);
  150. }, this).pos = this.dragItem.index();
  151. let hoverCellItem = this.hoverCell.data('item');
  152. if (hoverCellItem) {
  153. if ((hoverCellItem.name !== this.dragItem.data('item').name) || (!hoverCellItem.quantity)) {
  154. msgs.push({
  155. id: hoverCellItem.id,
  156. pos: this.hoverCell.index()
  157. });
  158. this.items.find(function (i) {
  159. return (i.id === hoverCellItem.id);
  160. }, this).pos = this.hoverCell.index();
  161. } else {
  162. method = 'combineStacks';
  163. msgs = {
  164. fromId: this.dragItem.data('item').id,
  165. toId: hoverCellItem.id
  166. };
  167. }
  168. }
  169. client.request({
  170. cpn: 'player',
  171. method: 'performAction',
  172. data: {
  173. cpn: 'inventory',
  174. method: method,
  175. data: msgs
  176. }
  177. });
  178. this.build();
  179. }
  180. this.dragItem = null;
  181. this.dragEl.remove();
  182. this.dragEl = null;
  183. this.hoverCell = null;
  184. this.find('.hover').removeClass('hover');
  185. }
  186. },
  187. onMouseMove: function (e) {
  188. if (!this.dragEl)
  189. return;
  190. let offset = this.find('.grid').offset();
  191. this.dragEl.css({
  192. left: e.clientX - offset.left - 40,
  193. top: e.clientY - offset.top - 40,
  194. display: 'block'
  195. });
  196. },
  197. onSortInventory: function () {
  198. client.request({
  199. cpn: 'player',
  200. method: 'performAction',
  201. data: {
  202. cpn: 'inventory',
  203. method: 'sortInventory',
  204. data: {}
  205. }
  206. });
  207. },
  208. showContext: function (item, e) {
  209. let menuItems = {
  210. drop: {
  211. text: 'drop',
  212. callback: this.performItemAction.bind(this, item, 'dropItem')
  213. },
  214. destroy: {
  215. text: 'destroy',
  216. callback: this.performItemAction.bind(this, item, 'destroyItem')
  217. },
  218. salvage: {
  219. text: 'salvage',
  220. callback: this.performItemAction.bind(this, item, 'salvageItem'),
  221. hotkey: 'f'
  222. },
  223. stash: {
  224. text: 'stash',
  225. callback: this.performItemAction.bind(this, item, 'stashItem')
  226. },
  227. learn: {
  228. text: 'learn',
  229. callback: this.performItemAction.bind(this, item, 'learnAbility')
  230. },
  231. quickSlot: {
  232. text: 'quickslot',
  233. callback: this.performItemAction.bind(this, item, 'setQuickSlot')
  234. },
  235. activate: {
  236. text: 'activate',
  237. callback: this.performItemAction.bind(this, item, 'activateMtx')
  238. },
  239. use: {
  240. text: 'use',
  241. callback: this.performItemAction.bind(this, item, 'useItem')
  242. },
  243. equip: {
  244. text: 'equip',
  245. callback: this.performItemAction.bind(this, item, 'equip')
  246. },
  247. mail: {
  248. text: 'mail',
  249. callback: this.openMailUi.bind(this, item)
  250. },
  251. split: {
  252. text: 'split stack',
  253. callback: this.splitStackStart.bind(this, item)
  254. },
  255. link: {
  256. text: 'link',
  257. callback: this.onClick.bind(this, item, true)
  258. },
  259. divider: '----------'
  260. };
  261. if (item.eq) {
  262. menuItems.learn.text = 'unlearn';
  263. menuItems.equip.text = 'unequip';
  264. }
  265. if (item.active)
  266. menuItems.activate.text = 'deactivate';
  267. let ctxConfig = [];
  268. if (item.ability)
  269. ctxConfig.push(menuItems.learn);
  270. else if (item.type === 'mtx')
  271. ctxConfig.push(menuItems.activate);
  272. else if (item.type === 'toy' || item.type === 'consumable' || item.useText || item.type === 'recipe') {
  273. if (item.useText)
  274. menuItems.use.text = item.useText;
  275. ctxConfig.push(menuItems.use);
  276. if (!item.has('quickSlot'))
  277. ctxConfig.push(menuItems.quickSlot);
  278. } else if (item.slot) {
  279. ctxConfig.push(menuItems.equip);
  280. if (!item.eq)
  281. ctxConfig.push(menuItems.divider);
  282. }
  283. if ((!item.eq) && (!item.active)) {
  284. if (!item.quest) {
  285. if ((window.player.stash.active) && (!item.noStash))
  286. ctxConfig.push(menuItems.stash);
  287. if (!item.noDrop)
  288. ctxConfig.push(menuItems.drop);
  289. if ((!item.material) && (!item.noSalvage))
  290. ctxConfig.push(menuItems.salvage);
  291. }
  292. }
  293. if (item.quantity > 1 && !item.quest)
  294. ctxConfig.push(menuItems.split);
  295. if ((!item.noDrop) && (!item.quest))
  296. ctxConfig.push(menuItems.mail);
  297. ctxConfig.push(menuItems.link);
  298. if (!item.eq && !item.active && !item.noDestroy) {
  299. ctxConfig.push(menuItems.divider);
  300. ctxConfig.push(menuItems.destroy);
  301. }
  302. if (isMobile)
  303. this.hideTooltip(null, this.hoverItem);
  304. if (ctxConfig.length > 0)
  305. events.emit('onContextMenu', ctxConfig, e);
  306. e.preventDefault();
  307. return false;
  308. },
  309. splitStackStart: function (item) {
  310. let box = this.find('.split-box').show();
  311. box.data('item', item);
  312. box.find('.amount')
  313. .val('1')
  314. .focus();
  315. },
  316. splitStackEnd: function (cancel, e) {
  317. let box = this.find('.split-box');
  318. if ((cancel) || (!e) || (e.target !== box.find('.btnSplit')[0])) {
  319. if ((cancel) && (!$(e.target).hasClass('btn')))
  320. box.hide();
  321. return;
  322. }
  323. box.hide();
  324. client.request({
  325. cpn: 'player',
  326. method: 'performAction',
  327. data: {
  328. cpn: 'inventory',
  329. method: 'splitStack',
  330. data: {
  331. itemId: box.data('item').id,
  332. stackSize: ~~this.find('.split-box .amount').val()
  333. }
  334. }
  335. });
  336. },
  337. onChangeStackAmount: function (e, amount) {
  338. let item = this.find('.split-box').data('item');
  339. let delta = amount;
  340. if (e)
  341. delta = (e.originalEvent.deltaY > 0) ? -1 : 1;
  342. if (input.isKeyDown('shift', true))
  343. delta *= 10;
  344. let elAmount = this.find('.split-box .amount');
  345. elAmount.val(Math.max(1, Math.min(item.quantity - 1, ~~elAmount.val() + delta)));
  346. },
  347. onEnterStackAmount: function (e) {
  348. let el = this.find('.split-box .amount');
  349. let val = el.val();
  350. if (+val !== ~~+val)
  351. el.val('');
  352. else if (val) {
  353. let item = this.find('.split-box').data('item');
  354. if (val < 0)
  355. val = '';
  356. else if (val > item.quantity - 1)
  357. val = item.quantity - 1;
  358. el.val(val);
  359. }
  360. },
  361. hideTooltip: function () {
  362. if (this.dragEl) {
  363. this.hoverCell = null;
  364. return;
  365. }
  366. events.emit('onHideItemTooltip', this.hoverItem);
  367. this.hoverItem = null;
  368. },
  369. onHover: function (el, item, e) {
  370. if (this.dragEl) {
  371. this.hoverCell = el;
  372. this.find('.hover').removeClass('hover');
  373. el.addClass('hover');
  374. return;
  375. }
  376. if (item)
  377. this.hoverItem = item;
  378. else
  379. item = this.hoverItem;
  380. if (!item)
  381. return;
  382. let ttPos = null;
  383. if (el) {
  384. if (el.hasClass('new')) {
  385. el.removeClass('new');
  386. el.find('.quantity').html((item.quantity > 1) ? item.quantity : '');
  387. delete item.isNew;
  388. }
  389. ttPos = {
  390. x: ~~(e.clientX + 32),
  391. y: ~~(e.clientY)
  392. };
  393. }
  394. events.emit('onShowItemTooltip', item, ttPos, true);
  395. },
  396. onGetItems: function (items, rerender) {
  397. this.items = items;
  398. if ((this.shown) && (rerender))
  399. this.build();
  400. },
  401. onDestroyItems: function (itemIds) {
  402. itemIds.forEach(function (id) {
  403. let item = this.items.find(i => i.id === id);
  404. if (item === this.hoverItem)
  405. this.hideTooltip();
  406. this.items.spliceWhere(i => i.id === id);
  407. }, this);
  408. if (this.shown)
  409. this.build();
  410. },
  411. toggle: function (show) {
  412. this.shown = !this.el.is(':visible');
  413. if (this.shown) {
  414. this.find('.split-box').hide();
  415. this.show();
  416. this.build();
  417. } else {
  418. this.hide();
  419. events.emit('onHideInventory');
  420. events.emit('onHideContextMenu');
  421. }
  422. this.hideTooltip();
  423. },
  424. beforeDestroy: function () {
  425. this.el.parent().css('background-color', 'transparent');
  426. this.el.parent().removeClass('blocking');
  427. },
  428. beforeHide: function () {
  429. if (this.oldSpellsZIndex) {
  430. $('.uiSpells').css('z-index', this.oldSpellsZIndex);
  431. this.oldSpellsZIndex = null;
  432. }
  433. },
  434. performItemAction: function (item, action) {
  435. if (!item)
  436. return;
  437. else if ((action === 'equip') && ((item.material) || (item.quest) || (item.type === 'mtx') || (!window.player.inventory.canEquipItem(item))))
  438. return;
  439. else if ((action === 'learnAbility') && (!window.player.inventory.canEquipItem(item)))
  440. return;
  441. else if ((action === 'activateMtx') && (item.type !== 'mtx'))
  442. return;
  443. let data = item.id;
  444. let cpn = 'inventory';
  445. if (['equip', 'setQuickSlot'].includes(action)) {
  446. cpn = 'equipment';
  447. if (action === 'setQuickSlot') {
  448. data = {
  449. itemId: item.id,
  450. slot: 0
  451. };
  452. }
  453. }
  454. if (action === 'useItem')
  455. this.hide();
  456. client.request({
  457. cpn: 'player',
  458. method: 'performAction',
  459. data: {
  460. cpn: cpn,
  461. method: action,
  462. data: data
  463. }
  464. });
  465. },
  466. openMailUi: function (item) {
  467. events.emit('onSetMailItem', {
  468. item: item
  469. });
  470. },
  471. onKeyDown: function (key) {
  472. if (key === 'i')
  473. this.toggle();
  474. else if (key === 'shift' && this.hoverItem)
  475. this.onHover();
  476. },
  477. onKeyUp: function (key) {
  478. if (key === 'shift' && this.hoverItem)
  479. this.onHover();
  480. }
  481. };
  482. });