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.
 
 
 

218 lines
4.4 KiB

  1. const getTargetPos = (physics, obj, m, pushback) => {
  2. let targetPos = {
  3. x: m.x,
  4. y: m.y
  5. };
  6. let dx = m.x - obj.x;
  7. let dy = m.y - obj.y;
  8. while ((dx === 0) && (dy === 0)) {
  9. dx = ~~(Math.random() * 2) - 1;
  10. dy = ~~(Math.random() * 2) - 1;
  11. }
  12. dx = ~~(dx / Math.abs(dx));
  13. dy = ~~(dy / Math.abs(dy));
  14. for (let l = 0; l < pushback; l++) {
  15. if (physics.isTileBlocking(targetPos.x + dx, targetPos.y + dy)) {
  16. if (physics.isTileBlocking(targetPos.x + dx, targetPos.y)) {
  17. if (physics.isTileBlocking(targetPos.x, targetPos.y + dy))
  18. break;
  19. else {
  20. dx = 0;
  21. targetPos.y += dy;
  22. }
  23. } else {
  24. dy = 0;
  25. targetPos.x += dx;
  26. }
  27. } else {
  28. targetPos.x += dx;
  29. targetPos.y += dy;
  30. }
  31. }
  32. return targetPos;
  33. };
  34. module.exports = {
  35. type: 'fireblast',
  36. targetGround: true,
  37. targetPlayerPos: true,
  38. radius: 2,
  39. pushback: 4,
  40. damage: 1,
  41. cast: function (action) {
  42. const { obj, targetPlayerPos } = this;
  43. let { x, y, instance: { physics, syncer } } = obj;
  44. if (!targetPlayerPos) {
  45. x = action.target.x;
  46. y = action.target.y;
  47. }
  48. let radius = this.radius;
  49. const particleEvent = {
  50. source: this,
  51. particleConfig: extend({}, this.particles)
  52. };
  53. obj.fireEvent('beforeSpawnParticles', particleEvent);
  54. for (let i = x - radius; i <= x + radius; i++) {
  55. for (let j = y - radius; j <= y + radius; j++) {
  56. if (!physics.hasLos(~~x, ~~y, ~~i, ~~j))
  57. continue;
  58. let effect = {
  59. x: i,
  60. y: j,
  61. components: [{
  62. type: 'particles',
  63. ttl: 10,
  64. blueprint: particleEvent.particleConfig
  65. }]
  66. };
  67. if ((i !== x) || (j !== y))
  68. syncer.queue('onGetObject', effect, -1);
  69. let mobs = physics.getCell(i, j);
  70. let mLen = mobs.length;
  71. for (let k = 0; k < mLen; k++) {
  72. let m = mobs[k];
  73. //Maybe we killed something?
  74. if (!m) {
  75. mLen--;
  76. continue;
  77. } else if (!m.aggro || !m.effects)
  78. continue;
  79. else if (!obj.aggro.canAttack(m))
  80. continue;
  81. const targetPos = getTargetPos(physics, obj, m, this.pushback);
  82. let distance = Math.max(Math.abs(m.x - targetPos.x), Math.abs(m.y - targetPos.y));
  83. let ttl = distance * 125;
  84. m.clearQueue();
  85. let damage = this.getDamage(m);
  86. m.stats.takeDamage({
  87. damage,
  88. threatMult: 1,
  89. source: this.obj,
  90. target: m,
  91. spellName: 'fireblast',
  92. noEvents: this.noEvents
  93. });
  94. if (m.destroyed)
  95. continue;
  96. const eventMsg = {
  97. success: true,
  98. targetPos
  99. };
  100. m.fireEvent('beforePositionChange', eventMsg);
  101. if (!eventMsg.success)
  102. continue;
  103. const targetEffect = m.effects.addEffect({
  104. type: 'stunned',
  105. silent: true
  106. });
  107. //If targetEffect is undefined, it means that the target has become resistant
  108. if (!targetEffect)
  109. continue;
  110. this.sendAnimation({
  111. id: m.id,
  112. components: [{
  113. type: 'moveAnimation',
  114. targetX: targetPos.x,
  115. targetY: targetPos.y,
  116. ttl: ttl
  117. }]
  118. });
  119. this.queueCallback(
  120. this.endEffect.bind(this, m, targetPos, targetEffect),
  121. ttl,
  122. null,
  123. m
  124. );
  125. //To be called when the object is destroyed
  126. this.obj.spellbook.registerDestroyCallback(this.destroyEffectOnTarget.bind(this, m, targetEffect));
  127. }
  128. }
  129. }
  130. this.sendBump({
  131. x: x,
  132. y: y - 1
  133. });
  134. return true;
  135. },
  136. endEffect: function (target, targetPos, targetEffect) {
  137. const { instance: { physics }, syncer, effects } = target;
  138. const { x: xNew, y: yNew } = targetPos;
  139. const xOld = target.x;
  140. const yOld = target.y;
  141. effects.removeEffect(targetEffect.id);
  142. target.x = xNew;
  143. target.y = yNew;
  144. if (physics.addObject(target, xNew, yNew, xOld, yOld))
  145. physics.removeObject(target, xOld, yOld, xNew, yNew);
  146. else {
  147. target.x = xOld;
  148. target.y = yOld;
  149. return false;
  150. }
  151. //We can't use xNew and yNew because addObject could have changed the position (like entering a building interior with stairs)
  152. const { x: xFinal, y: yFinal } = target;
  153. syncer.o.x = xFinal;
  154. syncer.o.y = yFinal;
  155. const moveEvent = {
  156. oldPos: {
  157. x: xOld,
  158. y: yOld
  159. },
  160. newPos: {
  161. x: xFinal,
  162. y: yFinal
  163. },
  164. source: this.obj,
  165. target,
  166. spellName: 'fireblast',
  167. spell: this
  168. };
  169. target.fireEvent('afterPositionChange', moveEvent);
  170. },
  171. destroyEffectOnTarget: function (target, targetEffect) {
  172. if (targetEffect)
  173. target.effects.removeEffect(targetEffect.id);
  174. }
  175. };