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.
 
 
 

197 lines
4.8 KiB

  1. let animations = require('../config/animations');
  2. let itemGenerator = require('../items/generator');
  3. //const track = {};
  4. module.exports = {
  5. build: function (mob, blueprint, type, zoneName) {
  6. mob.instance.eventEmitter.emit('onBeforeBuildMob', zoneName, mob.name.toLowerCase(), blueprint);
  7. let typeDefinition = blueprint[type] || blueprint;
  8. if (blueprint.nonSelectable)
  9. mob.nonSelectable = true;
  10. mob.addComponent('effects');
  11. if (type && type !== 'regular') {
  12. mob.effects.addEffect({
  13. type: type
  14. });
  15. mob['is' + type[0].toUpperCase() + type.substr(1)] = true;
  16. mob.baseName = mob.name;
  17. mob.name = typeDefinition.name || mob.baseName;
  18. }
  19. if (typeDefinition.sheetName)
  20. mob.sheetName = typeDefinition.sheetName;
  21. if (typeDefinition.has('cell'))
  22. mob.cell = typeDefinition.cell;
  23. mob.addComponent('stats', {
  24. values: {
  25. level: blueprint.level
  26. }
  27. });
  28. let cpnMob = mob.addComponent('mob');
  29. extend(cpnMob, {
  30. walkDistance: blueprint.walkDistance,
  31. hpMult: blueprint.hpMult || typeDefinition.hpMult,
  32. dmgMult: blueprint.dmgMult || typeDefinition.dmgMult,
  33. grantRep: blueprint.grantRep,
  34. deathRep: blueprint.deathRep
  35. });
  36. if (blueprint.patrol)
  37. cpnMob.patrol = blueprint.patrol;
  38. if (cpnMob.patrol)
  39. cpnMob.walkDistance = 1;
  40. let spells = extend([], blueprint.spells);
  41. spells.forEach(s => {
  42. if (!s.animation && mob.sheetName === 'mobs' && animations.mobs[mob.cell])
  43. s.animation = 'basic';
  44. });
  45. mob.addComponent('spellbook', {
  46. spells: spells,
  47. dmgMult: typeDefinition.dmgMult
  48. });
  49. if (!blueprint.has('attackable') || blueprint.attackable === true) {
  50. mob.addComponent('aggro', {
  51. faction: blueprint.faction
  52. });
  53. mob.aggro.calcThreatCeiling(type);
  54. }
  55. mob.addComponent('equipment');
  56. mob.addComponent('inventory', typeDefinition.drops);
  57. mob.inventory.inventorySize = -1;
  58. mob.inventory.dailyDrops = blueprint.dailyDrops;
  59. if (this.zone) {
  60. let chats = this.zone.chats;
  61. if (chats && chats[mob.name.toLowerCase()]) {
  62. mob.addComponent('chatter', {
  63. chats: chats[mob.name.toLowerCase()]
  64. });
  65. }
  66. let dialogues = this.zone.dialogues;
  67. if (dialogues && dialogues[mob.name.toLowerCase()]) {
  68. mob.addComponent('dialogue', {
  69. config: dialogues[mob.name.toLowerCase()]
  70. });
  71. }
  72. }
  73. if (blueprint.properties && blueprint.properties.cpnTrade)
  74. mob.addComponent('trade', blueprint.properties.cpnTrade);
  75. this.scale(mob, blueprint.level);
  76. },
  77. scale: function (mob, level) {
  78. let drops = mob.inventory.blueprint || {};
  79. let statValues = mob.stats.values;
  80. let preferStat = ['str', 'dex', 'int'][~~(Math.random() * 3)];
  81. mob.equipment.unequipAll();
  82. mob.inventory.clear();
  83. let hp = level * 40;
  84. statValues.hpMax = hp;
  85. statValues.level = level;
  86. if ((!drops.blueprints) || (drops.alsoRandom)) {
  87. [
  88. 'head',
  89. 'chest',
  90. 'neck',
  91. 'hands',
  92. 'waist',
  93. 'legs',
  94. 'feet',
  95. 'finger',
  96. 'trinket',
  97. 'twoHanded'
  98. ].forEach(slot => {
  99. let item = itemGenerator.generate({
  100. noSpell: true,
  101. level: level,
  102. slot: slot,
  103. quality: 4,
  104. forceStats: [preferStat]
  105. });
  106. delete item.spell;
  107. mob.inventory.getItem(item);
  108. mob.equipment.autoEquip(item.id);
  109. });
  110. } else {
  111. //TODO: Don't give the mob these items: he'll drop them anyway
  112. drops.blueprints.forEach(d => {
  113. if (d.type === 'key')
  114. return;
  115. let drop = extend({}, d);
  116. drop.level = level;
  117. mob.inventory.getItem(itemGenerator.generate(drop));
  118. });
  119. }
  120. let spellCount = (mob.isRare ? 1 : 0) + (mob.isChampion ? 2 : 0);
  121. for (let i = 0; i < spellCount; i++) {
  122. let rune = itemGenerator.generate({
  123. spell: true
  124. });
  125. rune.eq = true;
  126. mob.inventory.getItem(rune);
  127. }
  128. let dmgMult = 4.5 * mob.mob.dmgMult;
  129. let hpMult = 1 * mob.mob.hpMult;
  130. dmgMult *= [0.25, 0.4, 0.575, 0.8, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5][level - 1];
  131. statValues.hpMax = ~~(statValues.hpMax * [0.1, 0.2, 0.4, 0.7, 0.78, 0.91, 1.16, 1.19, 1.65, 2.36, 3.07, 3.55, 4.1, 4.85, 5.6, 5.9, 6.5, 7.1, 7.9, 12][level - 1]);
  132. statValues.hpMax *= hpMult;
  133. statValues.hp = statValues.hpMax;
  134. statValues.mana = statValues.manaMax;
  135. mob.spellbook.spells.forEach(s => {
  136. s.dmgMult = s.name ? dmgMult / 3 : dmgMult;
  137. s.statType = preferStat;
  138. s.manaCost = 0;
  139. /*if (mob.name.toLowerCase().includes('stinktooth')) {
  140. mob.stats.values.critChance = 0;
  141. mob.stats.values.attackCritChance = 0;
  142. mob.stats.values.spellCritChance = 0;
  143. const n = mob.name + '-' + s.type;
  144. if (!track[n])
  145. track[n] = [];
  146. track[n].push(~~s.getDamage(mob, true).amount);
  147. track[n].sort((a, b) => a - b);
  148. console.log(track);
  149. console.log('');
  150. }*/
  151. });
  152. ['hp', 'hpMax', 'mana', 'manaMax', 'level'].forEach(s => mob.syncer.setObject(false, 'stats', 'values', s, statValues[s]));
  153. }
  154. };