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.
 
 
 

244 line
5.2 KiB

  1. let combat = require('../../combat/combat');
  2. module.exports = {
  3. cd: 0,
  4. cdMax: 0,
  5. manaCost: 1,
  6. threatMult: 1,
  7. casting: false,
  8. castTime: 0,
  9. castTimeMax: 0,
  10. needLos: false,
  11. currentAction: null,
  12. pendingAttacks: [],
  13. canCast: function (target) {
  14. if (this.cd > 0)
  15. return false;
  16. else if (this.manaCost > this.obj.stats.values.mana)
  17. return false;
  18. else if (!target)
  19. return true;
  20. let inRange = true;
  21. if (this.has('range')) {
  22. let obj = this.obj;
  23. let distance = Math.max(Math.abs(target.x - obj.x), Math.abs(target.y - obj.y));
  24. inRange = (distance <= this.range);
  25. }
  26. return inRange;
  27. },
  28. castBase: function (action) {
  29. if (this.castTimeMax > 0) {
  30. if ((!this.currentAction) || (this.currentAction.target != action.target)) {
  31. this.currentAction = action;
  32. this.castTime = this.castTimeMax;
  33. this.obj.syncer.set(false, null, 'casting', 0);
  34. }
  35. return false;
  36. }
  37. return this.cast(action);
  38. },
  39. updateBase: function () {
  40. if (this.castTime > 0) {
  41. this.castTime--;
  42. this.obj.syncer.set(false, null, 'casting', (this.castTimeMax - this.castTime) / this.castTimeMax);
  43. if (!this.castTime) {
  44. if (this.cast(this.currentAction)) {
  45. this.consumeMana();
  46. this.setCd();
  47. this.currentAction = null;
  48. }
  49. } else
  50. this.sendBump(null, 0, -1);
  51. return;
  52. }
  53. if (this.cd > 0)
  54. this.cd--;
  55. },
  56. consumeMana: function () {
  57. let stats = this.obj.stats.values;
  58. stats.mana -= this.manaCost;
  59. if (this.obj.player)
  60. this.obj.syncer.setObject(true, 'stats', 'values', 'mana', stats.mana);
  61. },
  62. setCd: function () {
  63. let cd = {
  64. cd: this.cdMax
  65. };
  66. let isAttack = (this.type == 'melee');
  67. if ((Math.random() * 100) < this.obj.stats.values[isAttack ? 'attackSpeed' : 'castSpeed'])
  68. cd.cd = 1;
  69. this.obj.fireEvent('beforeSetSpellCooldown', cd);
  70. this.cd = cd.cd;
  71. if (this.obj.player) {
  72. this.obj.instance.syncer.queue('onGetSpellCooldowns', {
  73. id: this.obj.id,
  74. spell: this.id,
  75. cd: (this.cd * 350)
  76. }, [this.obj.serverId]);
  77. }
  78. },
  79. calcDps: function (target, noSync) {
  80. if ((!this.values) || (this.spellType == 'buff'))
  81. return;
  82. if ((!this.damage) && (!this.healing))
  83. delete this.values.dps;
  84. else {
  85. let noMitigate = !target;
  86. let dmg = combat.getDamage({
  87. source: this.obj,
  88. target: (target || {
  89. stats: {
  90. values: {}
  91. }
  92. }),
  93. damage: (this.damage || this.healing) * (this.dmgMult || 1),
  94. cd: this.cdMax,
  95. element: this.element,
  96. statType: this.statType,
  97. statMult: this.statMult,
  98. noMitigate: noMitigate,
  99. noCrit: true
  100. }).amount;
  101. let isAttack = (this.type == 'melee');
  102. let statValues = this.obj.stats.values;
  103. let critChance = isAttack ? statValues.attackCritChance : statValues.spellCritChance;
  104. let critMultiplier = isAttack ? statValues.attackCritMultiplier : statValues.spellCritMultiplier;
  105. let attackSpeed = (statValues.attackSpeed / 100);
  106. attackSpeed += 1;
  107. dmg = (((dmg / 100) * (100 - critChance)) + (((dmg / 100) * critChance) * (critMultiplier / 100))) * attackSpeed;
  108. let duration = this.values.duration;
  109. if (duration)
  110. dmg *= duration;
  111. dmg /= this.cdMax;
  112. if (this.damage)
  113. this.values.dmg = ~~(dmg * 100) / 100 + '/tick';
  114. else
  115. this.values.heal = ~~(dmg * 100) / 100 + '/tick';
  116. if (!noSync)
  117. this.obj.syncer.setArray(true, 'spellbook', 'getSpells', this.simplify());
  118. }
  119. },
  120. sendAnimation: function (blueprint) {
  121. this.obj.instance.syncer.queue('onGetObject', blueprint);
  122. },
  123. sendBump: function (target, deltaX, deltaY) {
  124. if (target) {
  125. let x = this.obj.x;
  126. let y = this.obj.y;
  127. let tx = target.x;
  128. let ty = target.y;
  129. if (tx < x)
  130. deltaX = -1;
  131. else if (tx > x)
  132. deltaX = 1;
  133. if (ty < y)
  134. deltaY = -1;
  135. else if (ty > y)
  136. deltaY = 1;
  137. }
  138. let components = [{
  139. type: 'bumpAnimation',
  140. deltaX: deltaX,
  141. deltaY: deltaY
  142. }];
  143. //During casting we only bump
  144. if ((target) && (this.animation)) {
  145. components.push({
  146. type: 'animation',
  147. template: this.animation
  148. });
  149. }
  150. this.obj.instance.syncer.queue('onGetObject', {
  151. id: this.obj.id,
  152. components: components
  153. });
  154. },
  155. simplify: function (self) {
  156. let values = {};
  157. for (let p in this) {
  158. let value = this[p];
  159. if ((typeof (value) === 'function') || (p === 'obj'))
  160. continue;
  161. values[p] = value;
  162. }
  163. if (this.animation)
  164. values.animation = this.animation.name;
  165. if (this.values)
  166. values.values = this.values;
  167. if (this.onAfterSimplify)
  168. this.onAfterSimplify(values);
  169. return values;
  170. },
  171. getDamage: function (target, noMitigate) {
  172. let config = {
  173. source: this.obj,
  174. target: target,
  175. damage: (this.damage || this.healing) * (this.dmgMult || 1),
  176. cd: this.cdMax,
  177. element: this.element,
  178. statType: this.statType,
  179. statMult: this.statMult,
  180. isAttack: (this.type === 'melee'),
  181. noMitigate: noMitigate
  182. };
  183. this.obj.fireEvent('onBeforeCalculateDamage', config);
  184. let damage = combat.getDamage(config);
  185. return damage;
  186. },
  187. queueCallback: function (callback, delay, destroyCallback, target, destroyOnRezone) {
  188. return this.obj.spellbook.registerCallback(this.obj.id, callback, delay, destroyCallback, target ? target.id : null, destroyOnRezone);
  189. },
  190. die: function () {
  191. this.obj.spellbook.unregisterCallback(this.obj.id);
  192. }
  193. };