local ____lualib = require("lualib_bundle") local __TS__Class = ____lualib.__TS__Class local __TS__ClassExtends = ____lualib.__TS__ClassExtends local __TS__Decorate = ____lualib.__TS__Decorate local ____exports = {} local modifier_boss_nevermore_hub_crossburst_lock local ____dota_ts_adapter = require("lib.dota_ts_adapter") local BaseAbility = ____dota_ts_adapter.BaseAbility local BaseModifier = ____dota_ts_adapter.BaseModifier local registerAbility = ____dota_ts_adapter.registerAbility local registerModifier = ____dota_ts_adapter.registerModifier local ____modifier_boss_nevermore_coil_debuff = require("abilities.creep.modifier_boss_nevermore_coil_debuff") local modifier_boss_nevermore_coil_debuff = ____modifier_boss_nevermore_coil_debuff.modifier_boss_nevermore_coil_debuff --- Случайная точка-хаб: от неё волны взрывов по 4 лучам (плюс или крест). ____exports.boss_nevermore_hub_crossburst = __TS__Class() local boss_nevermore_hub_crossburst = ____exports.boss_nevermore_hub_crossburst boss_nevermore_hub_crossburst.name = "boss_nevermore_hub_crossburst" boss_nevermore_hub_crossburst.____file_path = "scripts/vscripts/abilities/creep/boss_nevermore_hub_crossburst.lua" __TS__ClassExtends(boss_nevermore_hub_crossburst, BaseAbility) function boss_nevermore_hub_crossburst.prototype.Precache(self, context) PrecacheResource("particle", "particles/units/heroes/hero_nevermore/nevermore_shadowraze.vpcf", context) PrecacheResource("particle", "particles/darkmoon_creep_warning.vpcf", context) PrecacheResource("particle", "particles/econ/events/darkmoon_2017/darkmoon_generic_aoe.vpcf", context) PrecacheResource("soundfile", "sounds/units/heroes/nevermore/shadowraze.vsnd", context) end function boss_nevermore_hub_crossburst.prototype.GetAOERadius(self) local pick = self:getSpecialOrDefault("spawn_pick_radius", ____exports.boss_nevermore_hub_crossburst.DEFAULT_PICK_RADIUS) local start = self:getSpecialOrDefault("ring_start_dist", ____exports.boss_nevermore_hub_crossburst.DEFAULT_RING_START) local step = self:getSpecialOrDefault("ring_step", ____exports.boss_nevermore_hub_crossburst.DEFAULT_RING_STEP) local n = self:getRingCountForPhase(self:getBossPhase()) local reach = start + (n - 1) * step + self:GetSpecialValueFor("radius") return pick + reach end function boss_nevermore_hub_crossburst.prototype.getSpecialOrDefault(self, name, fallback) local v = self:GetSpecialValueFor(name) if not v or v <= 0 then return fallback end return v end function boss_nevermore_hub_crossburst.prototype.getBossPhase(self) local c = self:GetCaster() if not c or c:IsNull() then return 1 end local hp = c:GetHealthPercent() if hp <= 25 then return 4 end if hp <= 50 then return 3 end if hp <= 75 then return 2 end return 1 end function boss_nevermore_hub_crossburst.prototype.getRingCountForPhase(self, phase) local base = math.floor(self:getSpecialOrDefault("ring_count", ____exports.boss_nevermore_hub_crossburst.DEFAULT_RING_COUNT)) local perPhase = math.floor(self:getSpecialOrDefault("ring_count_phase_bonus", ____exports.boss_nevermore_hub_crossburst.DEFAULT_RING_COUNT_PHASE_BONUS)) return math.max(1, base + (phase - 1) * perPhase) end function boss_nevermore_hub_crossburst.prototype.pickRandomHub(self, groundOrigin) local maxR = self:getSpecialOrDefault("spawn_pick_radius", ____exports.boss_nevermore_hub_crossburst.DEFAULT_PICK_RADIUS) local ang = RandomFloat(0, 360) local dist = maxR * math.sqrt(RandomFloat(0.001, 1)) local rad = ang * math.pi / 180 local dx = math.cos(rad) * dist local dy = math.sin(rad) * dist return GetGroundPosition( groundOrigin + Vector(dx, dy, 0), nil ) end function boss_nevermore_hub_crossburst.prototype.getDirections(self, pattern) if pattern == "plus" then return { Vector(1, 0, 0), Vector(-1, 0, 0), Vector(0, 1, 0), Vector(0, -1, 0) } end local s = 1 / math.sqrt(2) return { Vector(s, s, 0), Vector(s, -s, 0), Vector(-s, s, 0), Vector(-s, -s, 0) } end function boss_nevermore_hub_crossburst.prototype.OnSpellStart(self) if not IsServer() then return end local caster = self:GetCaster() if not caster or caster:IsNull() or not caster:IsAlive() then return end local bossGround = GetGroundPosition( caster:GetAbsOrigin(), nil ) local hub = self:pickRandomHub(bossGround) local pattern = RandomInt(0, 1) == 0 and "plus" or "cross" local radius = self:GetSpecialValueFor("radius") local rEff = radius > 0 and radius or ____exports.boss_nevermore_hub_crossburst.DEFAULT_RADIUS local phaseNow = self:getBossPhase() local ringCount = self:getRingCountForPhase(phaseNow) local ringStep = self:getSpecialOrDefault("ring_step", ____exports.boss_nevermore_hub_crossburst.DEFAULT_RING_STEP) local ringStart = self:getSpecialOrDefault("ring_start_dist", ____exports.boss_nevermore_hub_crossburst.DEFAULT_RING_START) local baseInterval = self:getSpecialOrDefault("ring_interval", ____exports.boss_nevermore_hub_crossburst.DEFAULT_RING_INTERVAL) --- Ниже фаза — чуть быстрее волны (до ~−12% на фазе 4). local ringInterval = baseInterval * math.max(0.72, 1 - (phaseNow - 1) * 0.06) local firstDelay = self:getSpecialOrDefault("first_ring_delay", ____exports.boss_nevermore_hub_crossburst.DEFAULT_FIRST_DELAY) local warningTime = self:getSpecialOrDefault("precast_warning_time", ____exports.boss_nevermore_hub_crossburst.DEFAULT_WARNING_TIME) local dirs = self:getDirections(pattern) local function ringPositionsForIndex(____, ringIdx) local along = ringStart + ringIdx * ringStep local out = {} for ____, d in ipairs(dirs) do local scaled = Vector(d.x * along, d.y * along, 0) out[#out + 1] = GetGroundPosition(hub + scaled, nil) end return out end local lastHitTime = firstDelay + (ringCount - 1) * ringInterval caster:AddNewModifier(caster, self, modifier_boss_nevermore_hub_crossburst_lock.name, {duration = lastHitTime + 0.5}) do local r = 0 while r < ringCount do local hitTime = firstDelay + r * ringInterval local warnT = math.max(0, hitTime - warningTime) local positions = ringPositionsForIndex(nil, r) local isRedWave = r % 2 == 0 Timers:CreateTimer( warnT, function() if not caster or caster:IsNull() or not caster:IsAlive() then return nil end local ____pairs = {} for ____, p in ipairs(positions) do ____pairs[#____pairs + 1] = self:createWarningPair(p, rEff, isRedWave) end Timers:CreateTimer( hitTime - warnT, function() if not caster or caster:IsNull() or not caster:IsAlive() then return nil end for ____, pair in ipairs(____pairs) do do if not pair then goto __continue28 end ParticleManager:DestroyParticle(pair[1], true) ParticleManager:ReleaseParticleIndex(pair[1]) ParticleManager:DestroyParticle(pair[2], true) ParticleManager:ReleaseParticleIndex(pair[2]) end ::__continue28:: end for ____, p in ipairs(positions) do self:applyRingDamage(p, rEff) end return nil end ) return nil end ) r = r + 1 end end end function boss_nevermore_hub_crossburst.prototype.createWarningPair(self, pos, rad, firstStyle) local caster = self:GetCaster() local warningParticle = ParticleManager:CreateParticle("particles/darkmoon_creep_warning.vpcf", PATTACH_CUSTOMORIGIN, caster) local aoeParticle = ParticleManager:CreateParticle("particles/econ/events/darkmoon_2017/darkmoon_generic_aoe.vpcf", PATTACH_CUSTOMORIGIN, caster) ParticleManager:SetParticleControl(warningParticle, 0, pos) ParticleManager:SetParticleControl( warningParticle, 1, Vector(rad, 100, 100) ) ParticleManager:SetParticleControl(aoeParticle, 0, pos) ParticleManager:SetParticleControl( aoeParticle, 1, Vector(rad, 0, 0) ) ParticleManager:SetParticleControl( aoeParticle, 2, Vector(6, 0, 1) ) local rgb = firstStyle and Vector(230, 80, 40) or Vector(180, 80, 230) ParticleManager:SetParticleControl(aoeParticle, 3, rgb) ParticleManager:SetParticleControl(aoeParticle, 4, pos) return {warningParticle, aoeParticle} end function boss_nevermore_hub_crossburst.prototype.applyRingDamage(self, pulsePoint, rad) local caster = self:GetCaster() if not caster or caster:IsNull() or not caster:IsAlive() then return end local phase = self:getBossPhase() local baseDamage = caster:GetAttackDamage() local bonusDamagePerStack = self:GetSpecialValueFor("coil_stack_bonus_damage") local damageMultiplier = 1 + (phase - 1) * 0.3 local enemies = FindUnitsInRadius( caster:GetTeamNumber(), pulsePoint, nil, rad, DOTA_UNIT_TARGET_TEAM_ENEMY, bit.bor(DOTA_UNIT_TARGET_HERO, DOTA_UNIT_TARGET_BASIC), DOTA_UNIT_TARGET_FLAG_NONE, FIND_ANY_ORDER, false ) for ____, enemy in ipairs(enemies) do local coilDebuff = enemy:FindModifierByName(modifier_boss_nevermore_coil_debuff.name) local stacks = coilDebuff and coilDebuff:GetStackCount() or 0 local damage = (baseDamage + stacks * bonusDamagePerStack) * damageMultiplier * 0.85 ApplyDamage({ victim = enemy, attacker = caster, damage = damage, damage_type = DAMAGE_TYPE_MAGICAL, ability = self }) local updatedDebuff = enemy:AddNewModifier(caster, self, modifier_boss_nevermore_coil_debuff.name, {}) if updatedDebuff ~= nil then updatedDebuff:SetStackCount(stacks > 0 and stacks + 1 or 1) end end EmitSoundOnLocationWithCaster(pulsePoint, "Hero_Nevermore.Shadowraze", caster) local hitParticle = ParticleManager:CreateParticle("particles/units/heroes/hero_nevermore/nevermore_shadowraze.vpcf", PATTACH_WORLDORIGIN, nil) ParticleManager:SetParticleControl(hitParticle, 0, pulsePoint) ParticleManager:SetParticleControl( hitParticle, 1, Vector(rad, 1, 1) ) ParticleManager:ReleaseParticleIndex(hitParticle) end boss_nevermore_hub_crossburst.DEFAULT_PICK_RADIUS = 1500 boss_nevermore_hub_crossburst.DEFAULT_RADIUS = 165 boss_nevermore_hub_crossburst.DEFAULT_RING_COUNT = 7 boss_nevermore_hub_crossburst.DEFAULT_RING_COUNT_PHASE_BONUS = 1 boss_nevermore_hub_crossburst.DEFAULT_RING_STEP = 190 boss_nevermore_hub_crossburst.DEFAULT_RING_START = 90 boss_nevermore_hub_crossburst.DEFAULT_RING_INTERVAL = 0.52 boss_nevermore_hub_crossburst.DEFAULT_FIRST_DELAY = 0.55 boss_nevermore_hub_crossburst.DEFAULT_WARNING_TIME = 0.82 boss_nevermore_hub_crossburst = __TS__Decorate( boss_nevermore_hub_crossburst, boss_nevermore_hub_crossburst, {registerAbility(nil)}, {kind = "class", name = "boss_nevermore_hub_crossburst"} ) ____exports.boss_nevermore_hub_crossburst = boss_nevermore_hub_crossburst modifier_boss_nevermore_hub_crossburst_lock = __TS__Class() modifier_boss_nevermore_hub_crossburst_lock.name = "modifier_boss_nevermore_hub_crossburst_lock" modifier_boss_nevermore_hub_crossburst_lock.____file_path = "scripts/vscripts/abilities/creep/boss_nevermore_hub_crossburst.lua" __TS__ClassExtends(modifier_boss_nevermore_hub_crossburst_lock, BaseModifier) function modifier_boss_nevermore_hub_crossburst_lock.prototype.IsHidden(self) return true end function modifier_boss_nevermore_hub_crossburst_lock.prototype.IsPurgable(self) return false end function modifier_boss_nevermore_hub_crossburst_lock.prototype.CheckState(self) return {[MODIFIER_STATE_DISARMED] = true} end modifier_boss_nevermore_hub_crossburst_lock = __TS__Decorate( modifier_boss_nevermore_hub_crossburst_lock, modifier_boss_nevermore_hub_crossburst_lock, {registerModifier(nil)}, {kind = "class", name = "modifier_boss_nevermore_hub_crossburst_lock"} ) return ____exports