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.
 
 
 

421 lines
9.5 KiB

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