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.

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