Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 

408 righe
8.9 KiB

  1. let generator = require('../items/generator');
  2. let statGenerator = require('../items/generators/stats');
  3. let skins = require('../config/skins');
  4. const events = require('../misc/events');
  5. const sendMessage = ({ instance, id, serverId }, color, message) => {
  6. instance.syncer.queue('onGetMessages', {
  7. id: id,
  8. messages: [{
  9. class: color,
  10. message,
  11. type: 'info'
  12. }]
  13. }, [serverId]);
  14. };
  15. module.exports = {
  16. type: 'trade',
  17. items: [],
  18. buybackList: {},
  19. maxBuyback: 10,
  20. blueprint: null,
  21. gold: 0,
  22. target: null,
  23. regenCd: 0,
  24. regenCdMax: 1710,
  25. genLeft: 0,
  26. markup: {
  27. buy: 1,
  28. sell: 1
  29. },
  30. init: function (blueprint) {
  31. this.blueprint = blueprint;
  32. this.gold = blueprint.gold;
  33. this.items = [];
  34. this.regenCd = this.regenCdMax;
  35. (blueprint.forceItems || []).forEach(function (f, i) {
  36. let item = extend({}, f);
  37. let id = 0;
  38. this.items.forEach(function (checkItem) {
  39. if (checkItem.id >= id)
  40. id = checkItem.id + 1;
  41. });
  42. if (item.type === 'skin') {
  43. let skinBlueprint = skins.getBlueprint(item.skinId);
  44. item.name = skinBlueprint.name;
  45. item.sprite = skinBlueprint.sprite;
  46. item.spritesheet = skinBlueprint.spritesheet;
  47. item.skinId = item.skinId;
  48. }
  49. item.id = id;
  50. this.items.push(item);
  51. }, this);
  52. if (!blueprint.items)
  53. return;
  54. this.markup = blueprint.markup;
  55. if (blueprint.faction) {
  56. this.obj.extendComponent('trade', 'factionVendor', blueprint);
  57. return;
  58. }
  59. this.genLeft = blueprint.items.max;
  60. },
  61. update: function () {
  62. if (this.regenCd > 0) {
  63. this.regenCd--;
  64. return;
  65. }
  66. this.regenCd = this.regenCdMax;
  67. if (!this.genLeft)
  68. return;
  69. this.genLeft--;
  70. let blueprint = this.blueprint;
  71. let level = 1;
  72. if (blueprint.level)
  73. level = blueprint.level.min + ~~(Math.random() * (blueprint.level.max - blueprint.level.min));
  74. let item = generator.generate({
  75. noSpell: true,
  76. level: level
  77. });
  78. let id = 0;
  79. this.items.forEach(function (checkItem) {
  80. if (checkItem.id >= id)
  81. id = checkItem.id + 1;
  82. });
  83. item.id = id;
  84. this.items.push(item);
  85. },
  86. startBuy: function (msg) {
  87. if (!msg.has('target') && !msg.targetName)
  88. return false;
  89. let target = msg.target;
  90. if (target && !target.id)
  91. target = this.obj.instance.objects.objects.find(o => o.id === target);
  92. else if (msg.targetName)
  93. target = this.obj.instance.objects.objects.find(o => ((o.name) && (o.name.toLowerCase() === msg.targetName.toLowerCase())));
  94. this.target = null;
  95. if ((!target) || (!target.trade))
  96. return false;
  97. this.target = target;
  98. let itemList = target.trade.getItems(this.obj);
  99. let markup = target.trade.markup.sell;
  100. if (msg.action === 'buyback') {
  101. itemList = target.trade.buybackList[this.obj.name] || [];
  102. markup = target.trade.markup.buy;
  103. }
  104. this.obj.syncer.set(true, 'trade', 'buyList', {
  105. markup: markup,
  106. items: itemList,
  107. buyback: (msg.action === 'buyback')
  108. });
  109. },
  110. buySell: function (msg) {
  111. if (msg.action === 'buy')
  112. this.buy(msg);
  113. else if (msg.action === 'sell')
  114. this.sell(msg);
  115. else if (msg.action === 'buyback')
  116. this.buyback(msg);
  117. },
  118. buy: function (msg) {
  119. let target = this.target;
  120. if (!target)
  121. return;
  122. let item = null;
  123. let targetTrade = target.trade;
  124. let markup = targetTrade.markup.sell;
  125. if (msg.action === 'buyback') {
  126. item = targetTrade.findBuyback(msg.itemId, this.obj.name);
  127. markup = targetTrade.markup.buy;
  128. } else
  129. item = targetTrade.findItem(msg.itemId, this.obj.name);
  130. if (!item) {
  131. this.resolveCallback(msg);
  132. return;
  133. }
  134. let canAfford = false;
  135. if (item.worth.currency) {
  136. let currencyItem = this.obj.inventory.items.find(i => (i.name === item.worth.currency));
  137. canAfford = ((currencyItem) && (currencyItem.quantity >= item.worth.amount));
  138. } else
  139. canAfford = this.gold >= ~~(item.worth * markup);
  140. if (!canAfford) {
  141. sendMessage(this.obj, 'color-redA', 'You can\'t afford that item.');
  142. this.resolveCallback(msg);
  143. return;
  144. }
  145. if (!targetTrade.canBuy(msg.itemId, this.obj, msg.action)) {
  146. this.resolveCallback(msg);
  147. return;
  148. }
  149. if (item.type === 'skin') {
  150. let haveSkin = this.obj.auth.doesOwnSkin(item.skinId);
  151. if (haveSkin) {
  152. sendMessage(this.obj, 'color-redA', 'You have already unlocked that skin.');
  153. this.resolveCallback(msg);
  154. return;
  155. }
  156. }
  157. if (msg.action === 'buyback')
  158. targetTrade.removeBuyback(msg.itemId, this.obj.name);
  159. else if ((item.type !== 'skin') && (!item.infinite)) {
  160. targetTrade.removeItem(msg.itemId, this.obj.name);
  161. targetTrade.genLeft++;
  162. }
  163. if (item.type !== 'skin') {
  164. let clonedItem = extend({}, item);
  165. if (item.worth.currency)
  166. clonedItem.worth = 0;
  167. if ((item.stats) && (item.stats.stats)) {
  168. delete clonedItem.stats;
  169. statGenerator.generate(clonedItem, {});
  170. }
  171. delete clonedItem.infinite;
  172. if (clonedItem.generate) {
  173. clonedItem = generator.generate(clonedItem);
  174. delete clonedItem.generate;
  175. if (item.factions)
  176. clonedItem.factions = item.factions;
  177. }
  178. if (!this.obj.inventory.getItem(clonedItem)) {
  179. this.resolveCallback(msg);
  180. return;
  181. }
  182. if (!item.infinite)
  183. this.obj.syncer.setArray(true, 'trade', 'removeItems', item.id);
  184. } else {
  185. this.obj.auth.saveSkin(item.skinId);
  186. sendMessage(this.obj, 'color-greenB', `Unlocked skin: ${item.name}.`);
  187. }
  188. if (item.worth.currency) {
  189. let currencyItem = this.obj.inventory.items.find(i => (i.name === item.worth.currency));
  190. this.obj.inventory.destroyItem(currencyItem.id, item.worth.amount, true);
  191. } else {
  192. targetTrade.gold += ~~(item.worth * markup);
  193. this.gold -= ~~(item.worth * markup);
  194. this.obj.syncer.set(true, 'trade', 'gold', this.gold);
  195. }
  196. //Hack to always redraw the UI (to give items the red overlay if they can't be afforded)
  197. this.obj.syncer.setArray(true, 'trade', 'redraw', true);
  198. this.resolveCallback(msg);
  199. },
  200. buyback: function (msg) {
  201. msg.action = 'buyback';
  202. this.buy(msg);
  203. },
  204. sell: function (msg) {
  205. let target = this.target;
  206. if (!target)
  207. return;
  208. const { obj: { inventory, syncer } } = this;
  209. let targetTrade = target.trade;
  210. const item = inventory.findItem(msg.itemId);
  211. if (!item)
  212. return;
  213. const oldQuantity = item.quantity;
  214. inventory.destroyItem(msg.itemId);
  215. if (oldQuantity)
  216. item.quantity = oldQuantity;
  217. const sellEventMsg = {
  218. item,
  219. worth: ~~(item.worth * targetTrade.markup.buy)
  220. };
  221. events.emit('onBeforeSellItem', sellEventMsg);
  222. const { worth } = sellEventMsg;
  223. if (typeof(worth) !== 'object') {
  224. this.gold += worth;
  225. syncer.set(true, 'trade', 'gold', this.gold);
  226. } else
  227. inventory.getItem(worth, false, false, false, true);
  228. syncer.setArray(true, 'trade', 'removeItems', item.id);
  229. let buybackList = targetTrade.buybackList;
  230. let name = this.obj.name;
  231. if (!buybackList[name])
  232. buybackList[name] = [];
  233. buybackList[name].push(item);
  234. if (buybackList[name].length > this.maxBuyback)
  235. buybackList[name].splice(0, 1);
  236. },
  237. startSell: function (msg) {
  238. let target = msg.target;
  239. let targetName = (msg.targetName || '').toLowerCase();
  240. if (!target && !targetName)
  241. return false;
  242. if (target && !target.id)
  243. target = this.obj.instance.objects.objects.find(o => o.id === target);
  244. else if (targetName)
  245. target = this.obj.instance.objects.objects.find(o => ((o.name) && (o.name.toLowerCase() === targetName)));
  246. this.target = null;
  247. if ((!target) || (!target.trade))
  248. return false;
  249. this.target = target;
  250. const itemList = extend([], this.obj.inventory.items.filter(i => i.worth && !i.eq));
  251. const sellEventMsg = {
  252. items: itemList,
  253. markup: target.trade.markup.buy
  254. };
  255. events.emit('onBeforeGetSellList', sellEventMsg);
  256. this.obj.syncer.set(true, 'trade', 'sellList', sellEventMsg);
  257. },
  258. startBuyback: function (msg) {
  259. msg.action = 'buyback';
  260. this.startBuy(msg);
  261. },
  262. removeItem: function (itemId) {
  263. return this.items.spliceFirstWhere(i => i.id === itemId);
  264. },
  265. removeBuyback: function (itemId, name) {
  266. return (this.buybackList[name] || []).spliceFirstWhere(i => i.id === itemId);
  267. },
  268. getItems: function (requestedBy) {
  269. let items = this.items.map(i => requestedBy.inventory.simplifyItem(i));
  270. return items;
  271. },
  272. canBuy: function (itemId, requestedBy, action) {
  273. return true;
  274. },
  275. findItem: function (itemId, sourceName) {
  276. return this.items.find(i => i.id === itemId);
  277. },
  278. findBuyback: function (itemId, sourceName) {
  279. return (this.buybackList[sourceName] || []).find(i => i.id === itemId);
  280. },
  281. resolveCallback: function (msg, result) {
  282. let callbackId = msg.has('callbackId') ? msg.callbackId : msg;
  283. result = result || [];
  284. if (!callbackId)
  285. return;
  286. process.send({
  287. module: 'atlas',
  288. method: 'resolveCallback',
  289. msg: {
  290. id: callbackId,
  291. result: result
  292. }
  293. });
  294. },
  295. simplify: function (self) {
  296. let result = {
  297. type: 'trade'
  298. };
  299. if (self)
  300. result.gold = this.gold;
  301. return result;
  302. },
  303. events: {
  304. beforeMove: function () {
  305. if (!this.target)
  306. return;
  307. this.obj.syncer.set(true, 'trade', 'closeTrade', true);
  308. this.target = null;
  309. }
  310. }
  311. };