You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

inventory.js 13 KiB

7 jaren geleden
4 jaren geleden
4 jaren geleden
7 jaren geleden
4 jaren geleden
4 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
4 jaren geleden
7 jaren geleden
7 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
4 jaren geleden
7 jaren geleden
5 jaren geleden
6 jaren geleden
7 jaren geleden
4 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
5 jaren geleden
6 jaren geleden
4 jaren geleden
7 jaren geleden
4 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
7 jaren geleden
5 jaren geleden
6 jaren geleden
5 jaren geleden
2 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
2 jaren geleden
7 jaren geleden
2 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
6 jaren geleden
2 jaren geleden
6 jaren geleden
5 jaren geleden
6 jaren geleden
2 jaren geleden
6 jaren geleden
7 jaren geleden
6 jaren geleden
2 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
5 jaren geleden
7 jaren geleden
4 jaren geleden
7 jaren geleden
5 jaren geleden
5 jaren geleden
5 jaren geleden
6 jaren geleden
7 jaren geleden
6 jaren geleden
4 jaren geleden
7 jaren geleden
6 jaren geleden
7 jaren geleden
4 jaren geleden
5 jaren geleden
5 jaren geleden
5 jaren geleden
7 jaren geleden
7 jaren geleden
2 jaren geleden
7 jaren geleden
2 jaren geleden
7 jaren geleden
2 jaren geleden
7 jaren geleden
4 jaren geleden
6 jaren geleden
4 jaren geleden
4 jaren geleden
4 maanden geleden
4 maanden geleden
7 jaren geleden
7 jaren geleden
6 jaren geleden
5 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
5 jaren geleden
6 jaren geleden
5 jaren geleden
5 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
5 jaren geleden
5 jaren geleden
6 jaren geleden
6 jaren geleden
6 jaren geleden
5 jaren geleden
5 jaren geleden
6 jaren geleden
5 jaren geleden
6 jaren geleden
6 jaren geleden
7 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
6 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
4 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
7 jaren geleden
3 jaren geleden
6 jaren geleden
5 jaren geleden
6 jaren geleden
7 jaren geleden
2 jaren geleden
5 jaren geleden
5 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
5 jaren geleden
5 jaren geleden
7 jaren geleden
2 jaren geleden
7 jaren geleden
2 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
7 jaren geleden
5 jaren geleden
5 jaren geleden
7 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  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. type: 'global'
  122. }
  123. });
  124. },
  125. onMouseDown: function (el, item, down, e) {
  126. if (e.button !== 0)
  127. return;
  128. if (down) {
  129. this.dragEl = el.clone()
  130. .appendTo(this.find('.grid'))
  131. .hide()
  132. .on('mouseup', this.onMouseDown.bind(this, null, null, false))
  133. .addClass('dragging');
  134. this.dragItem = el;
  135. events.emit('onHideItemTooltip', this.hoverItem);
  136. events.emit('onStartMoveItem', this.dragItem.data('item'));
  137. this.hoverItem = null;
  138. } else if (this.dragItem) {
  139. let method = 'moveItem';
  140. if ((this.hoverCell) && (this.hoverCell[0] !== this.dragItem[0])) {
  141. const data = {};
  142. let placeholder = $('<div></div>')
  143. .insertAfter(this.dragItem);
  144. this.dragItem.insertBefore(this.hoverCell);
  145. this.hoverCell.insertBefore(placeholder);
  146. placeholder.remove();
  147. let msgs = [{
  148. itemId: this.dragItem.data('item').id,
  149. targetPos: this.dragItem.index()
  150. }];
  151. data.moveMsgs = msgs;
  152. this.items.find(function (i) {
  153. return (i.id === this.dragItem.data('item').id);
  154. }, this).pos = this.dragItem.index();
  155. let hoverCellItem = this.hoverCell.data('item');
  156. if (hoverCellItem) {
  157. if ((hoverCellItem.name !== this.dragItem.data('item').name) || (!hoverCellItem.quantity)) {
  158. msgs.push({
  159. itemId: hoverCellItem.id,
  160. targetPos: this.hoverCell.index()
  161. });
  162. this.items.find(function (i) {
  163. return (i.id === hoverCellItem.id);
  164. }, this).pos = this.hoverCell.index();
  165. } else {
  166. delete data.moveMsgs;
  167. data.fromId = this.dragItem.data('item').id;
  168. data.toId = hoverCellItem.id;
  169. method = 'combineStacks';
  170. }
  171. }
  172. client.request({
  173. cpn: 'player',
  174. method: 'performAction',
  175. data: {
  176. cpn: 'inventory',
  177. method: method,
  178. data
  179. }
  180. });
  181. events.emit('onStopMoveItem', this.dragItem.data('item'));
  182. this.build();
  183. }
  184. this.dragItem = null;
  185. this.dragEl.remove();
  186. this.dragEl = null;
  187. this.hoverCell = null;
  188. this.find('.hover').removeClass('hover');
  189. }
  190. },
  191. onMouseMove: function (e) {
  192. if (!this.dragEl)
  193. return;
  194. let offset = this.find('.grid').offset();
  195. this.dragEl.css({
  196. left: e.clientX - offset.left - 40,
  197. top: e.clientY - offset.top - 40,
  198. display: 'block'
  199. });
  200. },
  201. onSortInventory: function () {
  202. client.request({
  203. cpn: 'player',
  204. method: 'performAction',
  205. data: {
  206. cpn: 'inventory',
  207. method: 'sortInventory',
  208. data: {}
  209. }
  210. });
  211. },
  212. showContext: function (item, e) {
  213. let menuItems = {
  214. drop: {
  215. text: 'drop',
  216. callback: this.performItemAction.bind(this, item, 'dropItem')
  217. },
  218. destroy: {
  219. text: 'destroy',
  220. callback: this.performItemAction.bind(this, item, 'destroyItem')
  221. },
  222. salvage: {
  223. text: 'salvage',
  224. callback: this.performItemAction.bind(this, item, 'salvageItem'),
  225. hotkey: 'f'
  226. },
  227. stash: {
  228. text: 'stash',
  229. callback: this.performItemAction.bind(this, item, 'stashItem')
  230. },
  231. learn: {
  232. text: 'learn',
  233. callback: this.performItemAction.bind(this, item, 'learnAbility')
  234. },
  235. quickSlot: {
  236. text: 'quickslot',
  237. callback: this.performItemAction.bind(this, item, 'setQuickSlot')
  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. split: {
  248. text: 'split stack',
  249. callback: this.splitStackStart.bind(this, item)
  250. },
  251. link: {
  252. text: 'link',
  253. callback: this.onClick.bind(this, item, true)
  254. },
  255. divider: '----------'
  256. };
  257. if (item.eq) {
  258. menuItems.learn.text = 'unlearn';
  259. menuItems.equip.text = 'unequip';
  260. }
  261. if (item.active)
  262. menuItems.activate.text = 'deactivate';
  263. let ctxConfig = [];
  264. if (item.ability)
  265. ctxConfig.push(menuItems.learn);
  266. else if (item.type === 'toy' || item.type === 'consumable' || item.useText || item.type === 'recipe') {
  267. if (item.useText)
  268. menuItems.use.text = item.useText;
  269. ctxConfig.push(menuItems.use);
  270. if (!item.has('quickSlot'))
  271. ctxConfig.push(menuItems.quickSlot);
  272. } else if (item.slot) {
  273. ctxConfig.push(menuItems.equip);
  274. if (!item.eq)
  275. ctxConfig.push(menuItems.divider);
  276. }
  277. if (!item.eq && !item.active && !item.quest) {
  278. const isAtStash = window.player.serverActions.hasAction('openStash');
  279. if (isAtStash && !item.noStash)
  280. ctxConfig.push(menuItems.stash);
  281. if (!item.noDrop)
  282. ctxConfig.push(menuItems.drop);
  283. if (!item.material && !item.noSalvage)
  284. ctxConfig.push(menuItems.salvage);
  285. }
  286. if (item.quantity > 1 && !item.quest)
  287. ctxConfig.push(menuItems.split);
  288. ctxConfig.push(menuItems.link);
  289. if (!item.eq && !item.active && !item.noDestroy) {
  290. ctxConfig.push(menuItems.divider);
  291. ctxConfig.push(menuItems.destroy);
  292. }
  293. if (isMobile)
  294. this.hideTooltip(null, this.hoverItem);
  295. const eBeforeShowItemContextMenu = {
  296. sourceUi: 'inventory',
  297. item: this.hoverItem,
  298. ctxConfig
  299. };
  300. events.emit('beforeShowItemContextMenu', eBeforeShowItemContextMenu);
  301. if (ctxConfig.length > 0)
  302. events.emit('onContextMenu', eBeforeShowItemContextMenu.ctxConfig, e);
  303. e.preventDefault();
  304. return false;
  305. },
  306. splitStackStart: function (item) {
  307. let box = this.find('.split-box').show();
  308. box.data('item', item);
  309. box.find('.amount')
  310. .val('1')
  311. .focus();
  312. },
  313. splitStackEnd: function (cancel, e) {
  314. let box = this.find('.split-box');
  315. if ((cancel) || (!e) || (e.target !== box.find('.btnSplit')[0])) {
  316. if ((cancel) && (!$(e.target).hasClass('btn')))
  317. box.hide();
  318. return;
  319. }
  320. box.hide();
  321. client.request({
  322. cpn: 'player',
  323. method: 'performAction',
  324. data: {
  325. cpn: 'inventory',
  326. method: 'splitStack',
  327. data: {
  328. itemId: box.data('item').id,
  329. stackSize: ~~this.find('.split-box .amount').val()
  330. }
  331. }
  332. });
  333. },
  334. onChangeStackAmount: function (e, amount) {
  335. let item = this.find('.split-box').data('item');
  336. let delta = amount;
  337. if (e)
  338. delta = (e.originalEvent.deltaY > 0) ? -1 : 1;
  339. if (input.isKeyDown('shift', true))
  340. delta *= 10;
  341. let elAmount = this.find('.split-box .amount');
  342. elAmount.val(Math.max(1, Math.min(item.quantity - 1, ~~elAmount.val() + delta)));
  343. },
  344. onEnterStackAmount: function (e) {
  345. let el = this.find('.split-box .amount');
  346. let val = el.val();
  347. if (+val !== ~~+val)
  348. el.val('');
  349. else if (val) {
  350. let item = this.find('.split-box').data('item');
  351. if (val < 0)
  352. val = '';
  353. else if (val > item.quantity - 1)
  354. val = item.quantity - 1;
  355. el.val(val);
  356. }
  357. },
  358. hideTooltip: function () {
  359. if (this.dragEl) {
  360. this.hoverCell = null;
  361. return;
  362. }
  363. events.emit('onHideItemTooltip', this.hoverItem);
  364. this.hoverItem = null;
  365. },
  366. onHover: function (el, item, e) {
  367. if (this.dragEl) {
  368. this.hoverCell = el;
  369. this.find('.hover').removeClass('hover');
  370. el.addClass('hover');
  371. return;
  372. }
  373. if (item)
  374. this.hoverItem = item;
  375. else
  376. item = this.hoverItem;
  377. if (!item)
  378. return;
  379. let ttPos = null;
  380. if (el) {
  381. if (el.hasClass('new')) {
  382. el.removeClass('new');
  383. el.find('.quantity').html((item.quantity > 1) ? item.quantity : '');
  384. delete item.isNew;
  385. }
  386. ttPos = {
  387. x: ~~(e.clientX + 32),
  388. y: ~~(e.clientY)
  389. };
  390. }
  391. events.emit('onShowItemTooltip', item, ttPos, true);
  392. },
  393. onGetItems: function (items, rerender) {
  394. this.items = items;
  395. if ((this.shown) && (rerender))
  396. this.build();
  397. },
  398. onDestroyItems: function (itemIds) {
  399. itemIds.forEach(function (id) {
  400. let item = this.items.find(i => i.id === id);
  401. if (item === this.hoverItem)
  402. this.hideTooltip();
  403. this.items.spliceWhere(i => i.id === id);
  404. }, this);
  405. if (this.shown)
  406. this.build();
  407. },
  408. onAfterShow: function () {
  409. this.find('.split-box').hide();
  410. this.build();
  411. this.hideTooltip();
  412. },
  413. beforeDestroy: function () {
  414. this.el.parent().css('background-color', 'transparent');
  415. this.el.parent().removeClass('blocking');
  416. },
  417. beforeHide: function () {
  418. if (this.oldSpellsZIndex) {
  419. $('.uiSpells').css('z-index', this.oldSpellsZIndex);
  420. this.oldSpellsZIndex = null;
  421. }
  422. events.emit('onHideInventory');
  423. events.emit('onHideContextMenu');
  424. this.hideTooltip();
  425. },
  426. performItemAction: function (item, action) {
  427. if (!item)
  428. return;
  429. else if ((action === 'equip') && ((item.material) || (item.quest) || (!window.player.inventory.canEquipItem(item))))
  430. return;
  431. else if ((action === 'learnAbility') && (!window.player.inventory.canEquipItem(item)))
  432. return;
  433. let data = {
  434. itemId: item.id
  435. };
  436. let cpn = 'inventory';
  437. if (['equip', 'setQuickSlot'].includes(action)) {
  438. cpn = 'equipment';
  439. if (action === 'setQuickSlot') {
  440. data = {
  441. itemId: item.id,
  442. slot: 0
  443. };
  444. }
  445. }
  446. if (action === 'useItem')
  447. this.hide();
  448. client.request({
  449. cpn: 'player',
  450. method: 'performAction',
  451. data: {
  452. cpn,
  453. method: action,
  454. data
  455. }
  456. });
  457. },
  458. onKeyDown: function (key) {
  459. if (key === 'i')
  460. this.toggle();
  461. else if (key === 'shift' && this.hoverItem)
  462. this.onHover();
  463. },
  464. onKeyUp: function (key) {
  465. if (key === 'shift' && this.hoverItem)
  466. this.onHover();
  467. }
  468. };
  469. });