選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

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