25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

436 satır
9.3 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. const eventMsg = {
  105. items: itemList,
  106. markup,
  107. action: msg.action
  108. };
  109. events.emit('onBeforeGetTradeList', eventMsg);
  110. this.obj.syncer.set(true, 'trade', 'buyList', {
  111. markup,
  112. items: itemList,
  113. buyback: (msg.action === 'buyback')
  114. });
  115. },
  116. buySell: function (msg) {
  117. if (msg.action === 'buy')
  118. this.buy(msg);
  119. else if (msg.action === 'sell')
  120. this.sell(msg);
  121. else if (msg.action === 'buyback')
  122. this.buyback(msg);
  123. },
  124. buy: function (msg) {
  125. let target = this.target;
  126. if (!target)
  127. return;
  128. let item = null;
  129. let targetTrade = target.trade;
  130. let markup = targetTrade.markup.sell;
  131. if (msg.action === 'buyback') {
  132. item = targetTrade.findBuyback(msg.itemId, this.obj.name);
  133. markup = targetTrade.markup.buy;
  134. } else
  135. item = targetTrade.findItem(msg.itemId, this.obj.name);
  136. if (!item) {
  137. this.resolveCallback(msg);
  138. return;
  139. }
  140. let canAfford = false;
  141. if (item.worth.currency) {
  142. let currencyItem = this.obj.inventory.items.find(i => (i.name === item.worth.currency));
  143. canAfford = ((currencyItem) && (currencyItem.quantity >= item.worth.amount));
  144. } else
  145. canAfford = this.gold >= ~~(item.worth * markup);
  146. if (!canAfford) {
  147. sendMessage(this.obj, 'color-redA', 'You can\'t afford that item.');
  148. this.resolveCallback(msg);
  149. return;
  150. }
  151. if (!targetTrade.canBuy(msg.itemId, this.obj, msg.action)) {
  152. this.resolveCallback(msg);
  153. return;
  154. }
  155. if (item.type === 'skin') {
  156. let haveSkin = this.obj.auth.doesOwnSkin(item.skinId);
  157. if (haveSkin) {
  158. sendMessage(this.obj, 'color-redA', 'You have already unlocked that skin.');
  159. this.resolveCallback(msg);
  160. return;
  161. }
  162. }
  163. if (msg.action === 'buyback')
  164. targetTrade.removeBuyback(msg.itemId, this.obj.name);
  165. else if ((item.type !== 'skin') && (!item.infinite)) {
  166. targetTrade.removeItem(msg.itemId, this.obj.name);
  167. targetTrade.genLeft++;
  168. }
  169. if (item.type !== 'skin') {
  170. let clonedItem = extend({}, item);
  171. if (item.worth.currency)
  172. clonedItem.worth = 0;
  173. if ((item.stats) && (item.stats.stats)) {
  174. delete clonedItem.stats;
  175. statGenerator.generate(clonedItem, {});
  176. }
  177. delete clonedItem.infinite;
  178. if (clonedItem.generate) {
  179. clonedItem = generator.generate(clonedItem);
  180. delete clonedItem.generate;
  181. if (item.factions)
  182. clonedItem.factions = item.factions;
  183. }
  184. if (!this.obj.inventory.getItem(clonedItem)) {
  185. this.resolveCallback(msg);
  186. return;
  187. }
  188. if (!item.infinite)
  189. this.obj.syncer.setArray(true, 'trade', 'removeItems', item.id);
  190. } else {
  191. this.obj.auth.saveSkin(item.skinId);
  192. sendMessage(this.obj, 'color-greenB', `Unlocked skin: ${item.name}.`);
  193. }
  194. const eventMsg = {
  195. item,
  196. worth: ~~(item.worth * targetTrade.markup.buy),
  197. action: msg.action
  198. };
  199. events.emit('onBeforeTradeItem', eventMsg);
  200. let { worth } = eventMsg;
  201. if (typeof(worth) === 'number') {
  202. targetTrade.gold += ~~(worth * markup);
  203. this.gold -= ~~(worth * markup);
  204. this.obj.syncer.set(true, 'trade', 'gold', this.gold);
  205. } else {
  206. if (!worth.push)
  207. worth = [worth];
  208. worth.forEach(w => {
  209. let currencyItem = this.obj.inventory.items.find(i => (i.name === w.name));
  210. this.obj.inventory.destroyItem(currencyItem.id, w.quantity, true);
  211. });
  212. }
  213. //Hack to always redraw the UI (to give items the red overlay if they can't be afforded)
  214. this.obj.syncer.setArray(true, 'trade', 'redraw', true);
  215. this.resolveCallback(msg);
  216. },
  217. buyback: function (msg) {
  218. msg.action = 'buyback';
  219. this.buy(msg);
  220. },
  221. sell: function (msg) {
  222. let target = this.target;
  223. if (!target)
  224. return;
  225. const { obj: { inventory, syncer } } = this;
  226. let targetTrade = target.trade;
  227. const item = inventory.findItem(msg.itemId);
  228. if (!item)
  229. return;
  230. const oldQuantity = item.quantity;
  231. inventory.destroyItem(msg.itemId);
  232. if (oldQuantity)
  233. item.quantity = oldQuantity;
  234. const eventMsg = {
  235. item,
  236. worth: ~~(item.worth * targetTrade.markup.buy),
  237. action: 'sell'
  238. };
  239. events.emit('onBeforeTradeItem', eventMsg);
  240. let { worth } = eventMsg;
  241. if (typeof(worth) === 'number') {
  242. this.gold += worth;
  243. syncer.set(true, 'trade', 'gold', this.gold);
  244. } else {
  245. if (!worth.push)
  246. worth = [worth];
  247. worth.forEach(w => inventory.getItem(w, false, false, false, true));
  248. }
  249. syncer.setArray(true, 'trade', 'removeItems', item.id);
  250. let buybackList = targetTrade.buybackList;
  251. let name = this.obj.name;
  252. if (!buybackList[name])
  253. buybackList[name] = [];
  254. buybackList[name].push(item);
  255. if (buybackList[name].length > this.maxBuyback)
  256. buybackList[name].splice(0, 1);
  257. },
  258. startSell: function (msg) {
  259. let target = msg.target;
  260. let targetName = (msg.targetName || '').toLowerCase();
  261. if (!target && !targetName)
  262. return false;
  263. if (target && !target.id)
  264. target = this.obj.instance.objects.objects.find(o => o.id === target);
  265. else if (targetName)
  266. target = this.obj.instance.objects.objects.find(o => ((o.name) && (o.name.toLowerCase() === targetName)));
  267. this.target = null;
  268. if ((!target) || (!target.trade))
  269. return false;
  270. this.target = target;
  271. const itemList = extend([], this.obj.inventory.items.filter(i => i.worth && !i.eq));
  272. const eventMsg = {
  273. items: itemList,
  274. markup: target.trade.markup.sell,
  275. action: 'sell'
  276. };
  277. events.emit('onBeforeGetTradeList', eventMsg);
  278. this.obj.syncer.set(true, 'trade', 'sellList', eventMsg);
  279. },
  280. startBuyback: function (msg) {
  281. msg.action = 'buyback';
  282. this.startBuy(msg);
  283. },
  284. removeItem: function (itemId) {
  285. return this.items.spliceFirstWhere(i => i.id === itemId);
  286. },
  287. removeBuyback: function (itemId, name) {
  288. return (this.buybackList[name] || []).spliceFirstWhere(i => i.id === itemId);
  289. },
  290. getItems: function (requestedBy) {
  291. let items = this.items.map(i => requestedBy.inventory.simplifyItem(i));
  292. return items;
  293. },
  294. canBuy: function (itemId, requestedBy, action) {
  295. return true;
  296. },
  297. findItem: function (itemId, sourceName) {
  298. return this.items.find(i => i.id === itemId);
  299. },
  300. findBuyback: function (itemId, sourceName) {
  301. return (this.buybackList[sourceName] || []).find(i => i.id === itemId);
  302. },
  303. resolveCallback: function (msg, result) {
  304. let callbackId = msg.has('callbackId') ? msg.callbackId : msg;
  305. result = result || [];
  306. if (!callbackId)
  307. return;
  308. process.send({
  309. module: 'atlas',
  310. method: 'resolveCallback',
  311. msg: {
  312. id: callbackId,
  313. result: result
  314. }
  315. });
  316. },
  317. simplify: function (self) {
  318. let result = {
  319. type: 'trade'
  320. };
  321. if (self)
  322. result.gold = this.gold;
  323. return result;
  324. },
  325. events: {
  326. beforeMove: function () {
  327. if (!this.target)
  328. return;
  329. this.obj.syncer.set(true, 'trade', 'closeTrade', true);
  330. this.target = null;
  331. }
  332. }
  333. };