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.
 
 
 

204 lines
4.0 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. });
  93. if (m.destroyed)
  94. continue;
  95. const eventMsg = {
  96. success: true,
  97. targetPos
  98. };
  99. m.fireEvent('beforePositionChange', eventMsg);
  100. if (!eventMsg.success)
  101. continue;
  102. const targetEffect = m.effects.addEffect({
  103. type: 'stunned',
  104. silent: true
  105. });
  106. //If targetEffect is undefined, it means that the target has become resistant
  107. if (!targetEffect)
  108. continue;
  109. this.sendAnimation({
  110. id: m.id,
  111. components: [{
  112. type: 'moveAnimation',
  113. targetX: targetPos.x,
  114. targetY: targetPos.y,
  115. ttl: ttl
  116. }]
  117. });
  118. this.queueCallback(this.endEffect.bind(this, m, targetPos, targetEffect), ttl, null, m);
  119. }
  120. }
  121. }
  122. this.sendBump({
  123. x: x,
  124. y: y - 1
  125. });
  126. return true;
  127. },
  128. endEffect: function (target, targetPos, targetEffect) {
  129. const { instance: { physics }, syncer, effects } = target;
  130. const { x: xNew, y: yNew } = targetPos;
  131. const xOld = target.x;
  132. const yOld = target.y;
  133. effects.removeEffect(targetEffect.id);
  134. target.x = xNew;
  135. target.y = yNew;
  136. if (physics.addObject(target, xNew, yNew, xOld, yOld))
  137. physics.removeObject(target, xOld, yOld, xNew, yNew);
  138. else {
  139. target.x = xOld;
  140. target.y = yOld;
  141. return false;
  142. }
  143. //We can't use xNew and yNew because addObject could have changed the position (like entering a building interior with stairs)
  144. const { x: xFinal, y: yFinal } = target;
  145. syncer.o.x = xFinal;
  146. syncer.o.y = yFinal;
  147. const moveEvent = {
  148. oldPos: {
  149. x: xOld,
  150. y: yOld
  151. },
  152. newPos: {
  153. x: xFinal,
  154. y: yFinal
  155. },
  156. source: this.obj,
  157. target,
  158. spellName: 'fireblast',
  159. spell: this
  160. };
  161. target.fireEvent('afterPositionChange', moveEvent);
  162. }
  163. };