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.
 
 
 

219 lines
4.6 KiB

  1. let herbs = require('../config/herbs');
  2. const eventEmitter = require('../misc/events');
  3. const defaultGatherChance = {
  4. herb: 100,
  5. fish: 40
  6. };
  7. module.exports = {
  8. nodes: [],
  9. objects: null,
  10. syncer: null,
  11. zoneConfig: null,
  12. physics: null,
  13. map: null,
  14. cdMax: 171,
  15. init: function (instance) {
  16. Object.assign(this, {
  17. objects: instance.objects,
  18. syncer: instance.syncer,
  19. physics: instance.physics,
  20. map: instance.map,
  21. zoneConfig: instance.zoneConfig
  22. });
  23. },
  24. register: function (name, blueprint) {
  25. const exists = this.nodes.find(n => (n.blueprint.name === name));
  26. if (exists) {
  27. if (!exists.blueprint.positions) {
  28. exists.blueprint.positions = [{
  29. x: exists.blueprint.x,
  30. y: exists.blueprint.y,
  31. width: exists.blueprint.width,
  32. height: exists.blueprint.height
  33. }];
  34. }
  35. exists.blueprint.positions.push({
  36. x: blueprint.x,
  37. y: blueprint.y,
  38. width: blueprint.width,
  39. height: blueprint.height
  40. });
  41. return;
  42. }
  43. blueprint = extend({}, blueprint, herbs[name], {
  44. name: name
  45. });
  46. const max = blueprint.max;
  47. delete blueprint.max;
  48. const chance = blueprint.chance;
  49. delete blueprint.chance;
  50. const cdMax = blueprint.cdMax;
  51. delete blueprint.cdMax;
  52. blueprint.gatherChance = blueprint.gatherChance ?? defaultGatherChance[blueprint.type];
  53. this.nodes.push({
  54. cd: 0,
  55. max,
  56. chance,
  57. cdMax,
  58. blueprint,
  59. spawns: []
  60. });
  61. },
  62. getRandomSpawnPosition: function (node, blueprint) {
  63. //Get an accessible position
  64. let w = this.physics.width;
  65. let h = this.physics.height;
  66. let x = blueprint.x;
  67. let y = blueprint.y;
  68. let position = null;
  69. if (blueprint.type === 'herb' && !blueprint.positions) {
  70. x = ~~(Math.random() * w);
  71. y = ~~(Math.random() * h);
  72. if (this.physics.isTileBlocking(x, y))
  73. return false;
  74. let spawn = this.map.spawn[0];
  75. let path = this.physics.getPath(spawn, {
  76. x: x,
  77. y: y
  78. });
  79. let endTile = path[path.length - 1];
  80. if (!endTile)
  81. return false;
  82. else if ((endTile.x !== x) || (endTile.y !== y))
  83. return false;
  84. //Don't spawn in rooms or on objects/other resources
  85. let cell = this.physics.getCell(x, y);
  86. if (cell.length > 0)
  87. return false;
  88. position = { x, y };
  89. } else if (blueprint.positions) {
  90. //Find all possible positions in which a node hasn't spawned yet
  91. position = blueprint.positions.filter(f => !node.spawns.some(s => ((s.x === f.x) && (s.y === f.y))));
  92. if (position.length === 0)
  93. return false;
  94. position = position[~~(Math.random() * position.length)];
  95. }
  96. return position;
  97. },
  98. spawn: function (node) {
  99. const blueprint = node.blueprint;
  100. const eBeforeSpawnResource = {
  101. node,
  102. position: undefined,
  103. allowRandomPosition: true
  104. };
  105. eventEmitter.emit('beforeSpawnResource', eBeforeSpawnResource);
  106. if (eBeforeSpawnResource.allowRandomPosition && !eBeforeSpawnResource.position)
  107. eBeforeSpawnResource.position = this.getRandomSpawnPosition(node, blueprint);
  108. const { position } = eBeforeSpawnResource;
  109. if (!position)
  110. return false;
  111. let quantity = 1;
  112. if (blueprint.quantity)
  113. quantity = blueprint.quantity[0] + ~~(Math.random() * (blueprint.quantity[1] - blueprint.quantity[0]));
  114. const nodeXp = this.zoneConfig.level[0] * 2;
  115. let objBlueprint = extend({}, blueprint, position);
  116. objBlueprint.properties = {
  117. cpnResourceNode: {
  118. nodeType: blueprint.type,
  119. ttl: blueprint.ttl,
  120. xp: nodeXp,
  121. blueprint: extend({}, blueprint),
  122. quantity: quantity
  123. }
  124. };
  125. let obj = this.objects.buildObjects([objBlueprint]);
  126. delete obj.ttl;
  127. if (blueprint.type === 'herb') {
  128. this.syncer.queue('onGetObject', {
  129. x: obj.x,
  130. y: obj.y,
  131. components: [{
  132. type: 'attackAnimation',
  133. row: 0,
  134. col: 4
  135. }]
  136. }, -1);
  137. }
  138. let inventory = obj.addComponent('inventory');
  139. obj.layerName = 'objects';
  140. node.spawns.push(obj);
  141. let item = {
  142. material: true,
  143. type: node.type || null,
  144. sprite: node.blueprint.itemSprite,
  145. name: node.blueprint.name,
  146. quantity: (blueprint.type !== 'fish') ? 1 : null,
  147. quality: 0
  148. };
  149. if (blueprint.itemSheet)
  150. item.spritesheet = blueprint.itemSheet;
  151. if (blueprint.type === 'fish')
  152. item.noStack = true;
  153. inventory.getItem(item);
  154. return true;
  155. },
  156. update: function () {
  157. let nodes = this.nodes;
  158. let nLen = nodes.length;
  159. for (let i = 0; i < nLen; i++) {
  160. let node = nodes[i];
  161. let spawns = node.spawns;
  162. spawns.spliceWhere(f => f.destroyed);
  163. if (spawns.length < node.max) {
  164. if (node.cd > 0)
  165. node.cd--;
  166. else if ((!node.chance || Math.random() < node.chance) && this.spawn(node))
  167. node.cd = node.cdMax || this.cdMax;
  168. }
  169. }
  170. }
  171. };