| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- UnitBuffs = class()
- function UnitBuffs:init(unit)
- self.unit = unit
- self.list = {}
- table.merge(table.only(self.unit.class, Unit.classStats), self.unit)
- self:applyRunes('health')
- self:applyRunes('damage')
- self:applyRunes('spirit')
- self:applyRunes('haste')
- end
- function UnitBuffs:update()
- table.with(self.list, 'rot')
- table.with(self.list, 'update')
- self.unit.speed = self:getBaseSpeed()
- local speed = self.unit.speed
- -- Apply Hastes
- local hastes = self:buffsWithTag('haste')
- table.each(hastes, function(haste)
- speed = speed + (self.unit.class.speed * haste.haste)
- end)
- -- Apply Slows
- self.unit.speed = speed * self:slowAmount()
- -- Apply Roots and Stuns
- if self:rooted() or self:stunned() then self.unit.speed = 0 end
- -- Apply Attack Speed Increases
- local attackSpeed = self:getBaseAttackSpeed()
- local frenzies = self:buffsWithTag('frenzy')
- table.each(frenzies, function(frenzy)
- attackSpeed = attackSpeed * (1 - frenzy.frenzy)
- end)
- -- Apply Attack Speed Decreases
- local exhausts = self:buffsWithTag('exhaust')
- table.each(exhausts, function(exhaust)
- attackSpeed = attackSpeed + attackSpeed * (1 - exhaust.exhaust)
- end)
- self.unit.attackSpeed = math.max(attackSpeed, .4)
- -- Apply DoTs
- local dots = self:buffsWithTag('dot')
- table.each(dots, function(dot)
- self.unit:hurt(dot.dot * ls.tickrate, nil, {'dot'})
- end)
- -- Apply Knockups
- self.unit.prev.knockup = self.unit.knockup
- self.unit.knockup = 0
- local knockups = self:buffsWithTag('knockup')
- table.each(knockups, function(knockup)
- self.unit.knockup = self.unit.knockup + knockup.knockup
- end)
- end
- function UnitBuffs:add(code, vars)
- if not self:shouldApply(code) then return end
- if self:isCrowdControl(code) and self:ccImmunity() == 1 then return end
- if self:get(code) then return self:reapply(code, vars) end
- local buff = data.buff[code]()
- buff.unit = self.unit
- self.list[buff] = buff
- table.merge(vars, buff, true)
- if buff.stack then buff.stacks = 1 end
- f.exe(buff.activate, buff)
- if buff.timer and self:isCrowdControl(code) then
- local ccimmunity = self:ccImmunity()
- buff.timer = buff.timer * (1 - ccimmunity)
- end
- return buff
- end
- function UnitBuffs:remove(buff)
- if type(buff) == 'string' then
- buff = self:get(buff)
- end
- if buff then
- f.exe(buff and buff.deactivate, buff, self.unit)
- self.list[buff] = nil
- end
- end
- function UnitBuffs:get(code)
- return next(table.filter(self.list, function(buff) return buff.code == code end))
- end
- function UnitBuffs:reapply(code, vars)
- if self:isCrowdControl(code) and self:ccImmunity() == 1 then return end
- local buff = self:get(code)
- if buff then
- table.merge(vars, buff, true)
- if buff.stacks then
- buff.stacks = math.min((buff.stacks or 1) + 1, buff.maxStacks or 1)
- end
- return buff
- else
- return self:add(code, vars)
- end
- end
- function UnitBuffs:buffsWithTag(tag)
- return table.filter(self.list, function(buff) return table.has(buff.tags, tag) end)
- end
- function UnitBuffs:isCrowdControl(buff)
- if type(buff) == 'string' then buff = data.buff[buff] end
- local tags = buff.tags
- local function t(s) return table.has(tags, s) end
- return t('slow') or t('root') or t('stun') or t('silence') or t('knockback') or t('taunt') or t('fear')
- end
- function UnitBuffs:shouldApply(code)
- for buff in pairs(self.list) do
- if buff.shouldApplyBuff and buff:shouldApplyBuff(code) == false then
- return false
- end
- end
- return true
- end
- function UnitBuffs:applyRunes(stat)
- if not self.unit.player or not self.unit:hasRunes() then return end
- local runes = self.unit.player.deck[self.unit.class.code].runes
- table.each(runes, function(rune)
- if rune.stats and rune.stats[stat] then
- self.unit[stat] = self.unit[stat] + rune.stats[stat]
- end
- end)
- end
- function UnitBuffs:getBaseSpeed()
- --local speed = math.max(self.unit.class.speed * (self.unit.health / self.unit.maxHealth) ^ .25, 20)
- local speed = self.unit.class.speed
- if not self.unit.player then return speed end
- local agilityLevel = self.unit.class.attributes.agility
- speed = speed + agilityLevel * config.attributes.agility.speed
- local runes = self.unit.player.deck[self.unit.class.code].runes
- table.each(runes, function(rune)
- if rune.stats and rune.stats.speed then
- speed = speed + rune.stats.speed
- end
- end)
- return speed
- end
- function UnitBuffs:getBaseAttackSpeed()
- local baseSpeed = self.unit.class.attackSpeed
- local speed = baseSpeed
- if not self.unit.player then return speed end
- local agilityLevel = self.unit.class.attributes.agility
- speed = speed - (agilityLevel * config.attributes.agility.attackSpeed) * baseSpeed
- local runes = self.unit.player.deck[self.unit.class.code].runes
- table.each(runes, function(rune)
- if rune.stats and rune.stats.attackSpeed then
- speed = speed - (rune.stats.attackSpeed * baseSpeed)
- end
- end)
- return math.max(speed, .4)
- end
- function UnitBuffs:prehurt(amount, source, kind)
- table.each(self.list, function(buff)
- if buff.prehurt then
- amount = buff:prehurt(amount, source, kind) or amount
- end
- end)
- if kind and table.has(kind, 'attack') then
- local armors = self:buffsWithTag('armor')
- local armor = 0
- table.each(armors, function(buff)
- armor = armor + (1 - armor) * math.clamp(buff.armor * (buff.armorRangedMultiplier or 1), 0, .9)
- end)
- amount = amount * (1 - armor)
- end
- return amount
- end
- function UnitBuffs:posthurt(amount, source, kind)
- table.with(self.list, 'posthurt', amount, source, kind)
- return amount
- end
- function UnitBuffs:preattack(target, damage)
- table.each(self.list, function(buff)
- if buff.preattack then
- damage = buff:preattack(target, damage) or damage
- end
- end)
- return damage
- end
- function UnitBuffs:postattack(target, damage)
- table.with(self.list, 'postattack', target, damage)
- end
- function UnitBuffs:die()
- table.with(self.list, 'die')
- table.with(self.list, 'deactivate')
- end
- function UnitBuffs:emitParticles()
- -- Frenzy particles
- local frenzy = self:frenzied()
- if frenzy and frenzy.frenzy > 0 then
- for _, bone in pairs({'region_lefthand', 'region_righthand'}) do
- bone = self.unit.animation.spine.skeleton:findBone(bone)
- if bone then
- local x, y = self.unit.animation.spine.skeleton.x + bone.worldX, self.unit.animation.spine.skeleton.y - bone.worldY
- ctx.particles:emit('frenzy', x, y, 1)
- end
- end
- end
- -- Haste Particles
- local haste = self:hasted()
- if haste and haste.haste > 0 and love.math.random() < .3 then
- ctx.particles:emit('haste', self.unit.x, ctx.map.height - ctx.map.groundHeight, 1, {direction = self.unit.animation.flipped and 0 or math.pi})
- end
- -- Slow Particles
- if self:slowAmount() < 1 and love.math.random() < .3 then
- ctx.particles:emit('slow', self.unit.x, ctx.map.height - ctx.map.groundHeight, 1, {direction = self.unit.animation.flipped and 0 or math.pi})
- end
- end
- function UnitBuffs:slowed()
- return next(self:buffsWithTag('slow'))
- end
- function UnitBuffs:slowAmount()
- local multiplier = 1
- local slows = self:buffsWithTag('slow')
- table.each(slows, function(slow)
- multiplier = multiplier * (1 - slow.slow)
- end)
- if self:feared() then multiplier = multiplier / 2 end
- return multiplier
- end
- function UnitBuffs:hasted()
- return next(self:buffsWithTag('haste'))
- end
- function UnitBuffs:taunted()
- local taunt = next(self:buffsWithTag('taunt'))
- return taunt and taunt.target
- end
- function UnitBuffs:stunned()
- return next(self:buffsWithTag('stun'))
- end
- function UnitBuffs:rooted()
- return next(self:buffsWithTag('root'))
- end
- function UnitBuffs:silenced()
- return next(self:buffsWithTag('silence'))
- end
- function UnitBuffs:ccImmunity()
- local vulnerability = 1
- table.each(self:buffsWithTag('ccimmune'), function(buff)
- vulnerability = vulnerability * (1 - buff.ccimmunity)
- end)
- return 1 - vulnerability
- end
- function UnitBuffs:feared()
- return next(self:buffsWithTag('fear'))
- end
- function UnitBuffs:potency()
- local ratio = 1
- table.each(self:buffsWithTag('potency'), function(potency)
- ratio = ratio * potency.potency
- end)
- return ratio
- end
- function UnitBuffs:frenzied()
- return next(self:buffsWithTag('frenzy'))
- end
|