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.
 
 
 

349 lines
8.0 KiB

  1. let qualityGenerator = require('../items/generators/quality');
  2. module.exports = {
  3. type: 'gatherer',
  4. nodes: [],
  5. gathering: null,
  6. gatheringTtl: 0,
  7. gatheringTtlMax: 7,
  8. defaultTtlMax: 7,
  9. simplify: function () {
  10. return {
  11. type: 'gatherer'
  12. };
  13. },
  14. gather: function () {
  15. const { gathering, nodes, defaultTtlMax, obj } = this;
  16. const { equipment, stats, instance: { eventEmitter } } = obj;
  17. if (gathering)
  18. return;
  19. else if (!nodes.length)
  20. return;
  21. const [ node ] = nodes;
  22. if (!this.hasSpace(node)) {
  23. this.sendAnnouncement('Your bags are too full to gather any more resources.');
  24. return;
  25. }
  26. const eGather = {
  27. node,
  28. obj: this
  29. };
  30. eventEmitter.emit('beforeGatherResource', eGather);
  31. obj.fireEvent('beforeGatherResource', eGather);
  32. this.gathering = node;
  33. let ttlMax = node.resourceNode.ttl || defaultTtlMax;
  34. if (node.resourceNode.nodeType === 'fish') {
  35. if (equipment.isSlotEmpty('tool')) {
  36. this.sendAnnouncement('You need a fishing rod to fish');
  37. this.gathering = null;
  38. return;
  39. }
  40. let statCatchSpeed = Math.min(150, stats.values.catchSpeed);
  41. ttlMax *= (1 - (statCatchSpeed / 200));
  42. }
  43. this.gatheringTtlMax = ttlMax;
  44. this.gatheringTtl = ttlMax;
  45. },
  46. update: function () {
  47. let gathering = this.gathering;
  48. if (!gathering)
  49. return;
  50. let isFish = (gathering.resourceNode.nodeType === 'fish');
  51. let hasSpace = this.hasSpace(this.gathering);
  52. if (gathering.destroyed || !hasSpace) {
  53. this.gathering = null;
  54. this.gatheringTtl = 0;
  55. this.obj.syncer.set(false, 'gatherer', 'progress', 100);
  56. this.obj.syncer.set(true, 'gatherer', 'progress', 100);
  57. if (isFish)
  58. this.obj.syncer.set(true, 'gatherer', 'action', 'Fishing');
  59. if (!hasSpace)
  60. this.sendAnnouncement('Your bags are too full to gather any more resources.');
  61. return;
  62. }
  63. if (this.gatheringTtl > 0) {
  64. if (this.gatheringTtl === this.gatheringTtlMax && gathering.width > 1) {
  65. ['x', 'y', 'width', 'height'].forEach(p => {
  66. this.obj.syncer.set(false, 'gatherer', p, gathering[p]);
  67. });
  68. }
  69. this.gatheringTtl--;
  70. let progress = 100 - ~~((this.gatheringTtl / this.gatheringTtlMax) * 100);
  71. this.obj.syncer.set(true, 'gatherer', 'progress', progress);
  72. if (isFish)
  73. this.obj.syncer.set(true, 'gatherer', 'action', 'Fishing');
  74. return;
  75. }
  76. this.completeGathering(gathering, isFish);
  77. },
  78. completeGathering: function (gathering, isFish) {
  79. let resourceNode = gathering.resourceNode;
  80. let gatherResult = extend({
  81. obj: gathering,
  82. source: this.obj
  83. }, {
  84. nodeType: resourceNode.nodeType,
  85. blueprint: resourceNode.blueprint,
  86. xp: resourceNode.xp,
  87. items: gathering.inventory.items
  88. });
  89. this.obj.instance.eventEmitter.emit('beforeGatherResourceComplete', gatherResult);
  90. this.obj.fireEvent('beforeGatherResourceComplete', gatherResult);
  91. this.obj.syncer.set(false, 'gatherer', 'progress', 100);
  92. if (isFish) {
  93. const catchChance = gatherResult.blueprint.gatherChance + this.obj.stats.values.catchChance;
  94. if (~~(Math.random() * 100) >= catchChance) {
  95. this.sendAnnouncement('The fish got away');
  96. this.gathering = null;
  97. return;
  98. }
  99. gatherResult.items.forEach(g => {
  100. if (g.slot)
  101. return;
  102. delete g.quantity;
  103. qualityGenerator.generate(g, {
  104. //100 x 2.86 = 2000 (chance for a common)
  105. bonusMagicFind: this.obj.stats.values.fishRarity * 2.82
  106. });
  107. g.name = {
  108. 0: '',
  109. 1: 'Big ',
  110. 2: 'Giant ',
  111. 3: 'Trophy ',
  112. 4: 'Fabled '
  113. }[g.quality] + g.name;
  114. let statFishWeight = 1 + (this.obj.stats.values.fishWeight / 100);
  115. let weight = ~~((gatherResult.blueprint.baseWeight + g.quality + (Math.random() * statFishWeight)) * 100) / 100;
  116. g.stats = {
  117. weight: weight
  118. };
  119. g.worth = ~~(weight * 10);
  120. });
  121. } else {
  122. gatherResult.items.forEach(g => {
  123. if (g.worth === undefined)
  124. g.worth = 1;
  125. });
  126. }
  127. if (isFish) {
  128. let itemChance = 1 + this.obj.stats.values.fishItems;
  129. if (~~(Math.random() * 500) < itemChance) {
  130. gatherResult.items = [{
  131. name: 'Cerulean Pearl',
  132. material: true,
  133. quantity: 1,
  134. quality: 3,
  135. sprite: [11, 9]
  136. }];
  137. }
  138. }
  139. let blueprint = gatherResult.blueprint;
  140. gatherResult.items.forEach((item, i) => {
  141. delete item.pos;
  142. if (i === 0) {
  143. if (blueprint.itemName)
  144. item.name = blueprint.itemName;
  145. if (blueprint.itemAmount)
  146. item.quantity = ~~(Math.random() * blueprint.itemAmount[1]) + blueprint.itemAmount[0];
  147. }
  148. this.obj.inventory.getItem(item, false, false, true);
  149. if (item.material)
  150. this.obj.fireEvent('afterGatherResource', gatherResult);
  151. });
  152. if (!gatherResult.noChangeAmount)
  153. resourceNode.gather();
  154. this.obj.stats.getXp(gatherResult.xp, this.obj, gatherResult.obj);
  155. if (gathering.destroyed) {
  156. if (isFish)
  157. this.sendAnnouncement('The school has been depleted');
  158. this.nodes.spliceWhere(n => (n === gathering));
  159. this.updateServerActions(false);
  160. }
  161. this.gathering = null;
  162. },
  163. hasSpace: function (node) {
  164. // By default, the player is allowed to gather "nothing"
  165. if (!node.inventory || !node.inventory.items)
  166. return true;
  167. return this.obj.inventory.hasSpaceList(node.inventory.items);
  168. },
  169. enter: function (node) {
  170. const { obj } = this;
  171. let gatherResult = extend({
  172. nodeName: node.name
  173. });
  174. obj.instance.eventEmitter.emit('beforeEnterPool', gatherResult, obj);
  175. let nodeType = node.resourceNode.nodeType;
  176. if (nodeType === 'fish') {
  177. if (!obj.equipment.eq.has('tool')) {
  178. this.sendAnnouncement('You need a fishing rod to fish');
  179. return;
  180. }
  181. }
  182. this.updateServerActions(true);
  183. let action = null;
  184. if (nodeType === 'fish')
  185. action = 'fish for';
  186. else if (nodeType === 'herb')
  187. action = 'gather the';
  188. const actionString = `${action} ${gatherResult.nodeName}`;
  189. this.sendAnnouncement(`Press U to ${actionString}`);
  190. this.nodes.spliceWhere(n => (n === node));
  191. this.nodes.push(node);
  192. },
  193. exit: function (node) {
  194. if (!this.nodes.includes(node))
  195. return;
  196. this.updateServerActions(false);
  197. this.nodes.spliceWhere(n => (n === node));
  198. },
  199. sendAnnouncement: function (msg) {
  200. process.send({
  201. method: 'events',
  202. data: {
  203. onGetAnnouncement: [{
  204. obj: {
  205. msg: msg
  206. },
  207. to: [this.obj.serverId]
  208. }]
  209. }
  210. });
  211. },
  212. updateServerActions: function (isAdd) {
  213. const { obj } = this;
  214. const action = isAdd ? 'addActions' : 'removeActions';
  215. obj.syncer.setArray(true, 'serverActions', action, {
  216. key: 'u',
  217. action: {
  218. cpn: 'gatherer',
  219. method: 'gather',
  220. data: {
  221. targetId: obj.id
  222. }
  223. }
  224. });
  225. },
  226. events: {
  227. beforeRezone: function () {
  228. this.events.beforeMove.call(this);
  229. },
  230. beforeMove: function () {
  231. if (!this.gathering)
  232. return;
  233. ['x', 'y', 'width', 'height'].forEach(p => {
  234. this.obj.syncer.delete(false, 'gatherer', p);
  235. });
  236. this.obj.syncer.set(true, 'gatherer', 'progress', 100);
  237. this.obj.syncer.set(false, 'gatherer', 'progress', 100);
  238. if (this.gathering.resourceNode.nodeType === 'fish')
  239. this.obj.syncer.set(true, 'gatherer', 'action', 'Fishing');
  240. this.gathering = null;
  241. },
  242. beforeCastSpell: function () {
  243. this.events.beforeMove.call(this);
  244. },
  245. beforeTakeDamage: function (damageEvent) {
  246. this.events.beforeMove.call(this);
  247. },
  248. afterEquipItem: function (item) {
  249. let nodes = this.nodes;
  250. let nLen = nodes.length;
  251. for (let i = 0; i < nLen; i++) {
  252. let node = nodes[i];
  253. if (item.slot !== 'tool')
  254. continue;
  255. if (node.resourceNode.nodeType === 'fish') {
  256. if (!this.obj.equipment.eq.has('tool')) {
  257. this.sendAnnouncement('You need a fishing rod to fish');
  258. if (this.gathering === node) {
  259. if (this.gathering.resourceNode.nodeType === 'fish')
  260. this.obj.syncer.set(true, 'gatherer', 'action', 'Fishing');
  261. this.gathering = null;
  262. this.obj.syncer.set(true, 'gatherer', 'progress', 100);
  263. this.obj.syncer.set(false, 'gatherer', 'progress', 100);
  264. }
  265. }
  266. }
  267. }
  268. },
  269. afterUnequipItem: function (item) {
  270. this.events.afterEquipItem.call(this, item);
  271. }
  272. }
  273. };