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.
 
 
 

132 lines
3.5 KiB

  1. /* eslint-disable-next-line max-lines-per-function */
  2. const cast = (cpnSpellbook, action, isAuto) => {
  3. const { obj, physics, spells } = cpnSpellbook;
  4. //Stop casting
  5. if (!action.has('spell')) {
  6. const wasCasting = cpnSpellbook.isCasting();
  7. cpnSpellbook.stopCasting();
  8. //Consume a tick if we were casting
  9. return wasCasting;
  10. }
  11. const spell = spells.find(s => (s.id === action.spell));
  12. if (!spell)
  13. return false;
  14. action.target = cpnSpellbook.getTarget(spell, action);
  15. action.auto = spell.auto;
  16. //If a target has become nonSelectable, we need to stop attacks that are queued/auto
  17. if (!action.target || action.target.nonSelectable)
  18. return false;
  19. let success = true;
  20. if (spell.cd > 0) {
  21. if (!isAuto) {
  22. const type = (spell.auto) ? 'Weapon' : 'Spell';
  23. cpnSpellbook.sendAnnouncement(`${type} is on cooldown`);
  24. }
  25. success = false;
  26. } else if (spell.manaCost > obj.stats.values.mana) {
  27. if (!isAuto)
  28. cpnSpellbook.sendAnnouncement('Insufficient mana to cast spell');
  29. success = false;
  30. } else if (spell.has('range')) {
  31. const distance = Math.max(Math.abs(action.target.x - obj.x), Math.abs(action.target.y - obj.y));
  32. let range = spell.range;
  33. if ((spell.useWeaponRange) && (obj.player)) {
  34. const weapon = obj.inventory.findItem(obj.equipment.eq.oneHanded) || obj.inventory.findItem(obj.equipment.eq.twoHanded);
  35. if (weapon)
  36. range = weapon.range || 1;
  37. }
  38. if (distance > range) {
  39. if (!isAuto)
  40. cpnSpellbook.sendAnnouncement('Target out of range');
  41. success = false;
  42. }
  43. }
  44. //LoS check
  45. //Null means we don't have LoS and as such, we should move
  46. if (spell.needLos && success) {
  47. if (!physics.hasLos(~~obj.x, ~~obj.y, ~~action.target.x, ~~action.target.y)) {
  48. if (!isAuto)
  49. cpnSpellbook.sendAnnouncement('Target not in line of sight');
  50. action.auto = false;
  51. success = null;
  52. }
  53. }
  54. if (!success) {
  55. cpnSpellbook.queueAuto(action, spell);
  56. return success;
  57. } else if (!cpnSpellbook.queueAuto(action, spell))
  58. return false;
  59. const eventBeforeCastSpell = {
  60. success: true,
  61. action
  62. };
  63. obj.fireEvent('beforeCastSpell', eventBeforeCastSpell);
  64. if (!eventBeforeCastSpell.success)
  65. return false;
  66. if (spell.manaReserve) {
  67. const reserve = spell.manaReserve;
  68. if (reserve.percentage) {
  69. const reserveEvent = {
  70. spell: spell.name,
  71. reservePercent: reserve.percentage
  72. };
  73. obj.fireEvent('onBeforeReserveMana', reserveEvent);
  74. if (!spell.active) {
  75. if (1 - obj.stats.values.manaReservePercent < reserve.percentage) {
  76. cpnSpellbook.sendAnnouncement('Insufficient mana to cast spell');
  77. return;
  78. } obj.stats.addStat('manaReservePercent', reserveEvent.reservePercent);
  79. } else
  80. obj.stats.addStat('manaReservePercent', -reserveEvent.reservePercent);
  81. }
  82. }
  83. if (spell.targetFurthest)
  84. spell.target = obj.aggro.getFurthest();
  85. else if (spell.targetRandom)
  86. spell.target = obj.aggro.getRandom();
  87. if (!!eventBeforeCastSpell.action.target?.effects) {
  88. const eventBeforeIsSpellTarget = {
  89. source: obj,
  90. spell,
  91. target: eventBeforeCastSpell.action.target
  92. };
  93. eventBeforeIsSpellTarget.target.fireEvent('beforeIsSpellTarget', eventBeforeIsSpellTarget);
  94. eventBeforeCastSpell.action.target = eventBeforeIsSpellTarget.target;
  95. }
  96. success = spell.castBase(eventBeforeCastSpell.action);
  97. cpnSpellbook.stopCasting(spell, true);
  98. if (success) {
  99. spell.consumeMana();
  100. spell.setCd();
  101. }
  102. obj.fireEvent('afterCastSpell', {
  103. castSuccess: success,
  104. spell,
  105. action: eventBeforeCastSpell.action
  106. });
  107. //Null means we didn't fail but are initiating casting
  108. return (success === null || success === true);
  109. };
  110. module.exports = cast;