spell.lua 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. local Spell = class()
  2. function Spell:mirrorOwner()
  3. self.x, self.y, self.angle = self.owner.x, self.owner.y, self.owner.angle
  4. end
  5. function Spell:move(length, options)
  6. options = options or {}
  7. local x, y, angle = options.x or self.x, options.y or self.y, options.angle or self.angle
  8. self.x, self.y = x + math.dx(length, angle), y + math.dy(length, angle)
  9. end
  10. function Spell:movePlayerTo(player, x, y)
  11. player.x, player.y = x, y
  12. if player.inputs then
  13. table.insert(player.inputs, {
  14. tick = tick + 1,
  15. reposition = {
  16. x = player.x,
  17. y = player.y
  18. }
  19. })
  20. end
  21. end
  22. function Spell:movePlayer(player, length, options)
  23. options = options or {}
  24. local angle = options.angle or self.angle
  25. return Spell.movePlayerTo(self, player, player.x + math.dx(length, angle), player.y + math.dy(length, angle))
  26. end
  27. function Spell:moveOwnerTo(x, y)
  28. return Spell.movePlayerTo(self, self.owner, x, y)
  29. end
  30. function Spell:moveOwner(length, options)
  31. return Spell.movePlayer(self, self.owner, length, options)
  32. end
  33. function Spell:distanceTo(object, options)
  34. options = options or {}
  35. local x, y = options.x or self.x, options.y or self.y
  36. return math.distance(x, y, object.x, object.y)
  37. end
  38. function Spell:wallDistance(range)
  39. local x2, y2 = self.x + math.dx(range, self.angle), self.y + math.dy(range, self.angle)
  40. local wall, distance = ctx.collision:lineTest(self.x, self.y, x2, y2, {tag = 'wall', first = true})
  41. return wall and distance or range
  42. end
  43. function Spell:resolveCircle(x, y, r, options)
  44. options = options or {}
  45. local ox, oy = x, y
  46. local angle = options.angle or self.angle
  47. local sign = 1
  48. local distance = 0
  49. local function move() x, y = ox + math.dx(distance * sign, angle), oy + math.dy(distance * sign, angle) end
  50. while ctx.collision:circleTest(x, y, self.owner.radius, {tag = 'wall'}) or not math.inside(x, y, 0, 0, ctx.map.width, ctx.map.height) do
  51. sign = -sign
  52. if sign == 1 then distance = distance + 10 end
  53. move()
  54. end
  55. if distance > 0 or sign == -1 then
  56. repeat
  57. distance = distance - 1
  58. move()
  59. until ctx.collision:circleTest(x, y, self.owner.radius, {tag = 'wall'})
  60. distance = distance + 1
  61. move()
  62. end
  63. return x, y
  64. end
  65. function Spell:rot(fn)
  66. self.timer = self.timer - tickRate
  67. if self.timer <= 0 then
  68. f.exe(fn)
  69. ctx.spells:deactivate(self)
  70. return true
  71. end
  72. end
  73. function Spell:die()
  74. return ctx.spells:deactivate(self)
  75. end
  76. function Spell:enemiesInRadius(options)
  77. options = options or {}
  78. local x, y, r = options.x or self.x, options.y or self.y, options.radius or self.radius
  79. local function isEnemy(p) return p.team ~= self.owner.team end
  80. return ctx.collision:circleTest(x, y, r, {tag = 'player', fn = isEnemy, all = true})
  81. end
  82. function Spell:enemiesInLine(distance, options)
  83. options = options or {}
  84. local x, y, angle, all = options.x or self.x, options.y or self.y, options.angle or self.angle, options.all or false
  85. local x2, y2 = self.x + math.dx(distance, self.angle), self.y + math.dy(distance, self.angle)
  86. local function isEnemy(p) return p.team ~= self.owner.team end
  87. return select(1, ctx.collision:lineTest(x, y, x2, y2, {tag = 'player', fn = isEnemy, first = not all, all = all}))
  88. end
  89. function Spell:damage(enemies, amount)
  90. if not enemies then return end
  91. if enemies.id then enemies = {enemies} end
  92. amount = f.val(amount)
  93. table.each(enemies, function(enemy)
  94. ctx.net:emit(app.net.events.damage, {id = enemy.id, from = self.owner.id, amount = amount(enemy), tick = tick})
  95. end)
  96. end
  97. function Spell:damageInLine(distance, amount, options)
  98. Spell.damage(self, Spell.enemiesInLine(self, distance, options), amount)
  99. end
  100. function Spell:damageInRadius(amount, options)
  101. Spell.damage(self, Spell.enemiesInRadius(self, options), amount)
  102. end
  103. function Spell:lerpInit(vars)
  104. self._prev = {}
  105. if not vars then vars = {'x', 'y'} end
  106. for i = 1, #vars do self._prev[vars[i]] = 0 end
  107. end
  108. function Spell:lerpUpdate()
  109. table.each(self._prev, function(_, k) self._prev[k] = self[k] end)
  110. end
  111. function Spell:lerpGet(...)
  112. local res = {}
  113. local args = {...}
  114. if #args == 0 then args = {'x', 'y'} end
  115. table.each(args, function(x)
  116. table.insert(res, math.lerp(self._prev[x], self[x], tickDelta / tickRate))
  117. end)
  118. return unpack(res)
  119. end
  120. function Spell:drawCircle(how, options)
  121. options = options or {}
  122. love.graphics.circle(how, options.x or self.x, options.y or self.y, options.radius or self.radius)
  123. end
  124. function Spell:drawImage(options)
  125. options = options or {}
  126. local image = self.image or options.image
  127. local x, y, a, s = self.x or options.x, self.y or options.y, self.angle or options.angle, self.scale or options.scale
  128. local ax, ay = self.anchorx or options.anchorx, self.anchory or options.anchory
  129. love.graphics.draw(image, x, y, a, s, s, ax, ay)
  130. end
  131. function Spell:playSound(sound, options)
  132. options = options or {}
  133. options.x = options.x or self.x
  134. options.y = options.y or self.y
  135. ctx.event:emit('sound.play', table.merge({sound = sound}, options))
  136. end
  137. return Spell