| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- local abilities = lib.object.create()
- local function isLeft(x, y, b)
- return b == 1
- end
- local function hasTouch(id)
- return util.find(love.touch.getTouches(), id) or (id == 'm' and love.mouse.isDown(1))
- end
- function abilities:isCasting()
- return self.casting
- end
- function abilities:init()
- self.selected = nil
- self.casts = {}
- -- TODO group these eventually once UI is decided
- self.list = {
- app.abilities.summon:new(),
- app.abilities.heal:new(),
- app.abilities.burst:new()
- }
- end
- function abilities:bind()
- local abilityCast, autoCast = love.touchpressed
- :map(function(id, x, y)
- return id, lib.target.objectAtPosition(app.context.view:worldPoint(x, y))
- end)
- :filter(function(id, owner)
- return owner and (owner.isMinion or owner == app.context.objects.muju)
- end)
- :partition(function()
- return self.selected
- end)
- return {
- abilityCast
- :filter(function(id, owner)
- return owner:canCast(self.selected)
- end)
- :tap(function(id, owner)
- local ox, oy = app.context.view:worldPoint(love.touch.getPosition(id))
- self.casts[id] = {
- id = id,
- ability = self.selected,
- owner = owner,
- ox = ox,
- oy = oy,
- active = true,
- factor = 0,
- tick = lib.tick.index
- }
- lib.flux.to(self.casts[id], .3, { factor = 1 }):ease('backinout')
- end)
- :flatMap(function(id, owner)
- return love.touchreleased
- :filter(f.eq(id))
- :take(1)
- end)
- :subscribe(function(id, x, y)
- local mx, my = app.context.view:worldPoint(x, y)
- local cast = self.casts[id]
- if not cast then return end
- cast.active = false
- cast.x = mx
- cast.y = my
- cast.ability:cast(cast.owner, mx, my)
- lib.flux.to(cast, .35, { factor = 0 })
- :ease('cubicout')
- :oncomplete(function()
- if not hasTouch(id) then
- self.casts[id] = nil
- end
- end)
- self.selected = nil
- end),
- love.touchreleased
- :filter(function(id)
- local casting = util.match(self.casts, function(cast) return cast.active and cast.id == id end)
- return self.selected and not casting
- end)
- :subscribe(function()
- self.selected = nil
- end),
- autoCast
- :filter(function(id, owner)
- return owner.isMinion or owner:canCast(self.list[1])
- end)
- :tap(function(id, owner)
- local ox, oy = app.context.view:worldPoint(love.touch.getPosition(id))
- self.casts[id] = {
- id = id,
- ability = nil,
- owner = owner,
- ox = ox,
- oy = oy,
- active = true,
- factor = 0,
- tick = lib.tick.index
- }
- lib.flux.to(self.casts[id], .3, { factor = 1 }):ease('backinout')
- end)
- :flatMap(function(id)
- return love.touchreleased
- :filter(f.eq(id))
- :take(1)
- end)
- :subscribe(function(id, x, y)
- local mx, my = app.context.view:worldPoint(x, y)
- local cast = self.casts[id]
- cast.active = false
- cast.x = mx
- cast.y = my
- if cast.owner.isMinion then
- cast.owner:command(mx, my)
- else
- cast.owner:cast(self.list[1], mx, my)
- end
- lib.flux.to(cast, .35, { factor = 0 })
- :ease('cubicout')
- :oncomplete(function()
- if not hasTouch(id) then
- self.casts[id] = nil
- end
- end)
- end),
- app.context.view.draw:subscribe(self:wrap(self.draw))
- }
- end
- function abilities:draw()
- util.each(self.casts, function(cast)
- if cast.factor > 0 and cast.owner then
- local ox, oy = cast.owner.position.x, cast.owner.position.y
- local points = {}
- local radius = 35
- local tx, ty
- if cast.active and (util.find(love.touch.getTouches(), cast.id) or cast.id == 'm') then
- tx, ty = app.context.view:worldPoint(love.touch.getPosition(cast.id))
- else
- radius = radius + 20 * (1 - cast.factor)
- tx = cast.x
- ty = cast.y
- end
- if not tx or not ty then return end
- local entity = lib.target.objectAtPosition(tx, ty)
- if entity and (entity.isEnemy or entity.isShruju) then
- tx = util.lerp(tx, entity.position.x, .5)
- ty = util.lerp(ty, entity.position.y, .5)
- radius = radius + 10
- end
- local dir = util.angle(ox, oy, tx, ty)
- local pointCount = 80
- for i = 1, 80 do
- local x = tx + util.dx(radius, dir + (2 * math.pi * (i / 80)))
- local y = ty + util.dy(radius, dir + (2 * math.pi * (i / 80)))
- local mouseDir = util.angle(x, y, tx, ty)
- if util.distance(ox, oy, tx, ty) >= radius then
- local max = math.pi / 2 + (math.pi / 2) * util.distance(ox, oy, tx, ty) / 500 -- how bulbous it is
- local dif = (max - util.clamp(math.abs(util.anglediff(mouseDir, dir)), 0, max)) / max
- if cast.active then
- x = util.lerp(ox, x, cast.factor ^ 2)
- y = util.lerp(oy, y, cast.factor ^ 2)
- end
- x = util.lerp(x, ox, dif ^ 5)
- y = util.lerp(y, oy, dif ^ 5)
- end
- if util.distance(x, y, ox, oy) < 1 then
- table.insert(points, x)
- table.insert(points, y)
- else
- if util.distance(ox, oy, tx, ty) >= radius then
- local sign = util.sign(util.anglediff(mouseDir, dir))
- x = x + 2 * math.cos(dir + (math.pi / 2) * sign)
- y = y + 2 * math.sin(dir + (math.pi / 2) * sign)
- end
- table.insert(points, x)
- table.insert(points, y)
- end
- end
- if #points >= 3 then
- g.white(40 * cast.factor)
- g.setLineWidth(3)
- g.polygon('fill', points)
- g.setLineWidth(1)
- end
- local image, color, angle
- if self.selected then
- image = app.art.icons[self.selected.tag]
- color = { 255, 255, 255 }
- angle = 0
- else
- if cast.owner.isMinion then
- image = app.art.icons.command
- color = (entity and entity.isEnemy) and { 255, 140, 140 } or { 140, 255, 140 }
- angle = dir - math.pi / 4
- else
- image = app.art.icons.summon
- color = { 255, 255, 255 }
- angle = 0
- end
- end
- local w, h = image:getDimensions()
- local size = .75 * 2 * radius * cast.factor
- local scale = size / ((w > h) and w or h)
- g.setColor(g.alpha(color, 255 * cast.factor ^ 3))
- g.draw(image, tx, ty, angle, scale, scale, w / 2, h / 2)
- end
- end)
- return -1000
- end
- function abilities:isValidCastTarget(entity)
- --[[util.match(self.casts, function(cast)
- print(cast.ability)
- return cast.ability and cast.ability:canCast(entity)
- end)]]
- return self.selected and self.selected:canCast(entity)
- end
- return abilities
|