local ____lualib = require("lualib_bundle") local __TS__NumberIsFinite = ____lualib.__TS__NumberIsFinite local __TS__ArraySort = ____lualib.__TS__ArraySort local Map = ____lualib.Map local __TS__New = ____lualib.__TS__New local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter local __TS__Class = ____lualib.__TS__Class local __TS__ClassExtends = ____lualib.__TS__ClassExtends local __TS__Decorate = ____lualib.__TS__Decorate local ____exports = {} local clampToxinPoolRadius, toxinIsValidUnit, isToxinPoolThinker, toxinIsValidAbility, toxinPoolsOverlap, getToxinPoolRadiusForThinker, getToxinPoolMergeStackForThinker, getToxinDamagePerTickForThinker, getToxinPoolRemainingDuration, toxinDistSqHoriz, buildToxinOverlapCluster, computeMergedPoolStats, toxinSortDedupeEntIndices, toxinEnqueuePoolMergeForThinker, toxinDrainToxinMergeQueueFrame, toxinTryResolvePoolMergeForThinkerIndex, TOXIN_POOL_MODIFIER_NAME, TOXIN_MERGE_SCAN_RADIUS, TOXIN_MERGE_OVERLAP_EPSILON, TOXIN_THINKER_CLASS, TOXIN_POOL_MAX_RADIUS, TOXIN_MAX_MERGE_SCAN_THINKERS, toxinMergeQueue, toxinMergeDrainScheduled, toxinIsDrainingMerge local ____difficulty_manager = require("difficulty_manager") local Difficulty = ____difficulty_manager.Difficulty 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 ____creep_render_color = require("utils.creep_render_color") local trySetIntrinsicCreepRenderColor = ____creep_render_color.trySetIntrinsicCreepRenderColor local ____entity_radius = require("utils.entity_radius") local findAllByClassnameInRadius = ____entity_radius.findAllByClassnameInRadius function clampToxinPoolRadius(self, r) return math.max( 1, math.min(r, TOXIN_POOL_MAX_RADIUS) ) end function toxinIsValidUnit(self, unit) return unit ~= nil and unit ~= nil and not unit:IsNull() and IsValidEntity(unit) end function isToxinPoolThinker(self, unit) return toxinIsValidUnit(nil, unit) and unit:GetClassname() == TOXIN_THINKER_CLASS end function toxinIsValidAbility(self, ab) return ab ~= nil and ab ~= nil and not ab:IsNull() and IsValidEntity(ab) end function toxinPoolsOverlap(self, centerA, radiusA, centerB, radiusB) local dx = centerA.x - centerB.x local dy = centerA.y - centerB.y local dist = math.sqrt(dx * dx + dy * dy) return dist <= radiusA + radiusB + TOXIN_MERGE_OVERLAP_EPSILON end function getToxinPoolRadiusForThinker(self, thinker, poolMod, ability) if not toxinIsValidAbility(nil, ability) then return 0 end local raw if poolMod and poolMod.effectiveRadius > 0 then raw = poolMod.effectiveRadius else raw = ability:GetSpecialValueFor("radius") end return clampToxinPoolRadius(nil, raw) end function getToxinPoolMergeStackForThinker(self, poolMod, _ability) if poolMod ~= nil and poolMod.poolMergeStackCount > 0 then return math.floor(poolMod.poolMergeStackCount) end return 1 end function getToxinDamagePerTickForThinker(self, poolMod, ability) if not toxinIsValidAbility(nil, ability) then return 0 end if poolMod and poolMod.damagePerTick > 0 then return poolMod.damagePerTick end return ability:GetSpecialValueFor("damage") * 0.33 end function getToxinPoolRemainingDuration(self, poolMod, fallbackDuration) local getter = poolMod.GetRemainingTime if getter ~= nil then local v = getter(poolMod) if type(v) == "number" and __TS__NumberIsFinite(v) then return math.max(0, v) end end return math.max(0, fallbackDuration) end function toxinDistSqHoriz(self, ax, bx) local dx = ax.x - bx.x local dy = ax.y - bx.y return dx * dx + dy * dy end function buildToxinOverlapCluster(self, seed, ability) if not toxinIsValidUnit(nil, seed) or not toxinIsValidAbility(nil, ability) then return {} end local seedTeam = seed:GetTeamNumber() local origin = seed:GetAbsOrigin() local raw = findAllByClassnameInRadius("npc_dota_thinker", origin, TOXIN_MERGE_SCAN_RADIUS) local toxinThinkers = {} for ____, ent in ipairs(raw) do do local npc = ent if not toxinIsValidUnit(nil, npc) then goto __continue22 end if npc:GetTeamNumber() ~= seedTeam then goto __continue22 end if not npc:FindModifierByName(TOXIN_POOL_MODIFIER_NAME) then goto __continue22 end toxinThinkers[#toxinThinkers + 1] = npc end ::__continue22:: end if #toxinThinkers > TOXIN_MAX_MERGE_SCAN_THINKERS then __TS__ArraySort( toxinThinkers, function(____, a, b) return toxinDistSqHoriz( nil, a:GetAbsOrigin(), origin ) - toxinDistSqHoriz( nil, b:GetAbsOrigin(), origin ) end ) while #toxinThinkers > TOXIN_MAX_MERGE_SCAN_THINKERS do table.remove(toxinThinkers) end end local cluster = {} local visited = __TS__New(Map) local queue = {seed} while #queue > 0 do do local cur = table.remove(queue) if not toxinIsValidUnit(nil, cur) then goto __continue30 end local idx = cur:GetEntityIndex() if visited:get(idx) then goto __continue30 end visited:set(idx, true) cluster[#cluster + 1] = cur local curMod = cur:FindModifierByName(TOXIN_POOL_MODIFIER_NAME) local rCur = getToxinPoolRadiusForThinker(nil, cur, curMod, ability) local pCur = cur:GetAbsOrigin() for ____, other in ipairs(toxinThinkers) do do if not toxinIsValidUnit(nil, other) then goto __continue33 end local oIdx = other:GetEntityIndex() if visited:get(oIdx) then goto __continue33 end local oMod = other:FindModifierByName(TOXIN_POOL_MODIFIER_NAME) local rO = getToxinPoolRadiusForThinker(nil, other, oMod, ability) if toxinPoolsOverlap( nil, pCur, rCur, other:GetAbsOrigin(), rO ) then queue[#queue + 1] = other end end ::__continue33:: end end ::__continue30:: end return cluster end function computeMergedPoolStats(self, cluster, ability) if not toxinIsValidAbility(nil, ability) then return { centroid = Vector(0, 0, 0), damagePerTick = 0, radius = 1, duration = 0.05, mergeStackCount = 1 } end local valid = __TS__ArrayFilter( cluster, function(____, t) return toxinIsValidUnit(nil, t) end ) local n = #valid if n <= 0 then local baseRadius = ability:GetSpecialValueFor("radius") local baseDur = ability:GetSpecialValueFor("duration") return { centroid = Vector(0, 0, 0), damagePerTick = ability:GetSpecialValueFor("damage") * 0.33, radius = clampToxinPoolRadius(nil, baseRadius), duration = math.max(0.05, baseDur), mergeStackCount = 1 } end local baseDuration = ability:GetSpecialValueFor("duration") local radiusBonusPerMerge = math.max( 0, ability:GetSpecialValueFor("merge_radius_bonus") ) local durationBonusPerMerge = math.max( 0, ability:GetSpecialValueFor("merge_duration_bonus") ) local sumR2 = 0 local sumDmg = 0 local sumStacks = 0 local maxRem = 0 local sx = 0 local sy = 0 local sz = 0 for ____, t in ipairs(valid) do local mod = t:FindModifierByName(TOXIN_POOL_MODIFIER_NAME) local r = getToxinPoolRadiusForThinker(nil, t, mod, ability) sumR2 = sumR2 + r * r sumDmg = sumDmg + getToxinDamagePerTickForThinker(nil, mod, ability) sumStacks = sumStacks + getToxinPoolMergeStackForThinker(nil, mod, ability) local p = t:GetAbsOrigin() sx = sx + p.x sy = sy + p.y sz = sz + p.z if mod then maxRem = math.max( maxRem, getToxinPoolRemainingDuration(nil, mod, baseDuration) ) else maxRem = math.max(maxRem, baseDuration) end end local mergedRadiusUncapped = math.max( 1, math.sqrt(sumR2) + math.max(0, n - 1) * radiusBonusPerMerge ) local mergedRadius = clampToxinPoolRadius(nil, mergedRadiusUncapped) local mergedDuration = math.max( 0.05, maxRem + math.max(0, n - 1) * durationBonusPerMerge ) return { centroid = Vector(sx / n, sy / n, sz / n), damagePerTick = sumDmg, radius = mergedRadius, duration = mergedDuration, mergeStackCount = math.max(1, sumStacks) } end function toxinSortDedupeEntIndices(self, arr) if #arr <= 1 then return arr end local sorted = {unpack(arr)} __TS__ArraySort( sorted, function(____, a, b) return a - b end ) local out = {} local prev = -2147483648 for ____, x in ipairs(sorted) do local n = x if n ~= prev then out[#out + 1] = x prev = n end end return out end function toxinEnqueuePoolMergeForThinker(self, entIndex) if not IsServer() then return end toxinMergeQueue[#toxinMergeQueue + 1] = entIndex if toxinMergeDrainScheduled or toxinIsDrainingMerge then return end toxinMergeDrainScheduled = true Timers:CreateTimer(0, toxinDrainToxinMergeQueueFrame) end function toxinDrainToxinMergeQueueFrame(self) if not IsServer() then return end toxinIsDrainingMerge = true toxinMergeDrainScheduled = false local batch = toxinMergeQueue toxinMergeQueue = {} local uniq = toxinSortDedupeEntIndices(nil, batch) for ____, idx in ipairs(uniq) do toxinTryResolvePoolMergeForThinkerIndex(nil, idx) end toxinIsDrainingMerge = false if #toxinMergeQueue > 0 then toxinMergeDrainScheduled = true Timers:CreateTimer(0, toxinDrainToxinMergeQueueFrame) end end function toxinTryResolvePoolMergeForThinkerIndex(self, entIndex) if not IsServer() then return end local npc = EntIndexToHScript(entIndex) if not isToxinPoolThinker(nil, npc) then return end local buff = npc:FindModifierByName(TOXIN_POOL_MODIFIER_NAME) if not buff then return end local poolMod = buff local abilityRaw = buff:GetAbility() if not toxinIsValidAbility(nil, abilityRaw) then return end local ability = abilityRaw local caster = buff:GetCaster() if not toxinIsValidUnit(nil, caster) then return end local cluster = buildToxinOverlapCluster(nil, npc, ability) if #cluster < 2 then poolMod:initializeSinglePoolFromAbility() return end local mergeLeader local minIdx = 2147483647 for ____, t in ipairs(cluster) do do if not toxinIsValidUnit(nil, t) then goto __continue141 end local ei = t:GetEntityIndex() if ei < minIdx then minIdx = ei mergeLeader = t end end ::__continue141:: end if not mergeLeader or not toxinIsValidUnit(nil, mergeLeader) then return end if npc:GetEntityIndex() ~= mergeLeader:GetEntityIndex() then toxinEnqueuePoolMergeForThinker( nil, mergeLeader:GetEntityIndex() ) return end local merged = computeMergedPoolStats(nil, cluster, ability) local spawnParams = {duration = merged.duration, merged_damage_per_tick = merged.damagePerTick, merged_radius = merged.radius, merged_stack_count = merged.mergeStackCount} for ____, t in ipairs(cluster) do if toxinIsValidUnit(nil, t) then UTIL_Remove(t) end end if not toxinIsValidAbility(nil, ability) or not toxinIsValidUnit(nil, caster) then return end CreateModifierThinker( caster, ability, TOXIN_POOL_MODIFIER_NAME, spawnParams, merged.centroid, caster:GetTeamNumber(), false ) end TOXIN_POOL_MODIFIER_NAME = "modifier_spider_nethertoxin_lua" TOXIN_MERGE_SCAN_RADIUS = 2400 TOXIN_MERGE_OVERLAP_EPSILON = 12 TOXIN_THINKER_CLASS = "npc_dota_thinker" TOXIN_POOL_MAX_RADIUS = 900 TOXIN_MAX_MERGE_SCAN_THINKERS = 220 toxinMergeQueue = {} toxinMergeDrainScheduled = false toxinIsDrainingMerge = false ____exports.toxin = __TS__Class() local toxin = ____exports.toxin toxin.name = "toxin" toxin.____file_path = "scripts/vscripts/abilities/creep/toxin.lua" __TS__ClassExtends(toxin, BaseAbility) function toxin.prototype.Precache(self, context) PrecacheResource("particle", "particles/units/heroes/hero_alchemist/alchemist_acid_spray.vpcf", context) PrecacheResource("particle", "particles/units/heroes/hero_viper/viper_nethertoxin.vpcf", context) PrecacheResource("particle", "particles/units/heroes/hero_viper/viper_nethertoxin_debuff.vpcf", context) PrecacheResource("soundfile", "soundevents/game_sounds_heroes/game_sounds_broodmother.vsndevts", context) PrecacheResource("soundfile", "soundevents/game_sounds_heroes/game_sounds_viper.vsndevts", context) end function toxin.prototype.GetIntrinsicModifierName(self) return "modifier_spider_toxin_death_listener" end toxin = __TS__Decorate( toxin, toxin, {registerAbility(nil)}, {kind = "class", name = "toxin"} ) ____exports.toxin = toxin ____exports.modifier_spider_toxin_death_listener = __TS__Class() local modifier_spider_toxin_death_listener = ____exports.modifier_spider_toxin_death_listener modifier_spider_toxin_death_listener.name = "modifier_spider_toxin_death_listener" modifier_spider_toxin_death_listener.____file_path = "scripts/vscripts/abilities/creep/toxin.lua" __TS__ClassExtends(modifier_spider_toxin_death_listener, BaseModifier) function modifier_spider_toxin_death_listener.prototype.IsHidden(self) return true end function modifier_spider_toxin_death_listener.prototype.IsPurgable(self) return false end function modifier_spider_toxin_death_listener.prototype.OnCreated(self, _params) if not IsServer() then return end local parent = self:GetParent() if not toxinIsValidUnit(nil, parent) then return end trySetIntrinsicCreepRenderColor( nil, parent, 51, 102, 0 ) end function modifier_spider_toxin_death_listener.prototype.DeclareFunctions(self) return {MODIFIER_EVENT_ON_DEATH} end function modifier_spider_toxin_death_listener.prototype.OnDeath(self, event) if not IsServer() then return end if event.unit ~= self:GetParent() then return end local ability = self:GetAbility() if not toxinIsValidAbility(nil, ability) then return end local caster = self:GetCaster() if not toxinIsValidUnit(nil, caster) then return end local parent = self:GetParent() local spawnOrigin = parent:GetAbsOrigin() local duration = ability:GetSpecialValueFor("duration") local radius = clampToxinPoolRadius( nil, ability:GetSpecialValueFor("radius") ) local splashPfx = ParticleManager:CreateParticle("particles/units/heroes/hero_alchemist/alchemist_acid_spray.vpcf", PATTACH_WORLDORIGIN, nil) ParticleManager:SetParticleControl(splashPfx, 0, spawnOrigin) ParticleManager:SetParticleControl( splashPfx, 1, Vector(radius, 1, 1) ) ParticleManager:SetParticleControl( splashPfx, 15, Vector(255, 153, 102) ) ParticleManager:SetParticleControl( splashPfx, 16, Vector(1, 0, 0) ) Timers:CreateTimer( 4, function() if not IsServer() then return end ParticleManager:DestroyParticle(splashPfx, false) ParticleManager:ReleaseParticleIndex(splashPfx) end ) EmitSoundOn("Hero_Broodmother.SpawnSpiderlings", parent) CreateModifierThinker( caster, ability, TOXIN_POOL_MODIFIER_NAME, {duration = duration}, spawnOrigin, caster:GetTeamNumber(), false ) end modifier_spider_toxin_death_listener = __TS__Decorate( modifier_spider_toxin_death_listener, modifier_spider_toxin_death_listener, {registerModifier(nil)}, {kind = "class", name = "modifier_spider_toxin_death_listener"} ) ____exports.modifier_spider_toxin_death_listener = modifier_spider_toxin_death_listener ____exports.modifier_spider_nethertoxin_lua = __TS__Class() local modifier_spider_nethertoxin_lua = ____exports.modifier_spider_nethertoxin_lua modifier_spider_nethertoxin_lua.name = "modifier_spider_nethertoxin_lua" modifier_spider_nethertoxin_lua.____file_path = "scripts/vscripts/abilities/creep/toxin.lua" __TS__ClassExtends(modifier_spider_nethertoxin_lua, BaseModifier) function modifier_spider_nethertoxin_lua.prototype.____constructor(self, ...) BaseModifier.prototype.____constructor(self, ...) self.effectiveRadius = 0 self.damagePerTick = 0 self.poolMergeStackCount = 0 self.auraPenaltyStack = 1 self.damageTable = {} end function modifier_spider_nethertoxin_lua.prototype.GetTexture(self) return "viper_nethertoxin" end function modifier_spider_nethertoxin_lua.prototype.IsHidden(self) return false end function modifier_spider_nethertoxin_lua.prototype.IsDebuff(self) return true end function modifier_spider_nethertoxin_lua.prototype.IsStunDebuff(self) return false end function modifier_spider_nethertoxin_lua.prototype.IsPurgable(self) return false end function modifier_spider_nethertoxin_lua.prototype.initializeAuraVictimDebuff(self) local ability = self:GetAbility() if toxinIsValidAbility(nil, ability) then self:SetDuration( math.max( 0.05, self:GetAuraDuration() ), true ) end self.effectiveRadius = 0 self.damagePerTick = 0 self.poolMergeStackCount = 0 if IsServer() then self:syncAuraPenaltyFromCasterThinker() self:SetStackCount(math.max( 1, math.floor(self.auraPenaltyStack) )) end end function modifier_spider_nethertoxin_lua.prototype.syncAuraPenaltyFromCasterThinker(self) local parent = self:GetParent() if isToxinPoolThinker(nil, parent) then return end local source = self:GetCaster() if not toxinIsValidUnit(nil, source) then return end local srcMod = source:FindModifierByName(TOXIN_POOL_MODIFIER_NAME) if srcMod ~= nil and srcMod.poolMergeStackCount > 0 then self.auraPenaltyStack = math.floor(srcMod.poolMergeStackCount) else self.auraPenaltyStack = math.max(1, self.auraPenaltyStack) end end function modifier_spider_nethertoxin_lua.prototype.initializeSinglePoolFromAbility(self) local ability = self:GetAbility() local caster = self:GetCaster() local parent = self:GetParent() if not toxinIsValidAbility(nil, ability) or not toxinIsValidUnit(nil, caster) or not toxinIsValidUnit(nil, parent) then return end local baseDamage = ability:GetSpecialValueFor("damage") local baseRadius = ability:GetSpecialValueFor("radius") local baseDuration = ability:GetSpecialValueFor("duration") self.damagePerTick = (baseDamage + self:GetCaster():GetAttackDamage() * 0.15) * 0.33 local totaldamage = self:GetParent():IsRangedAttacker() and self.damagePerTick or self.damagePerTick * 0.25 self.effectiveRadius = clampToxinPoolRadius(nil, baseRadius) self.poolMergeStackCount = 1 self:SetDuration( math.max(0.05, baseDuration), true ) self.damageTable = { victim = caster, attacker = caster, damage = totaldamage, damage_type = ability:GetAbilityDamageType(), ability = ability } self:StartIntervalThink(0.33) self:PlayEffects() end function modifier_spider_nethertoxin_lua.prototype.initializeMergedPoolFromParams(self, params) local ability = self:GetAbility() local caster = self:GetCaster() local parent = self:GetParent() if not toxinIsValidAbility(nil, ability) or not toxinIsValidUnit(nil, caster) or not toxinIsValidUnit(nil, parent) then return end self.damagePerTick = params.merged_damage_per_tick self.effectiveRadius = clampToxinPoolRadius(nil, params.merged_radius) self.poolMergeStackCount = math.max( 1, math.floor(params.merged_stack_count or 1) ) self:SetDuration( math.max(0.05, params.duration), true ) self.damageTable = { victim = caster, attacker = caster, damage = self.damagePerTick, damage_type = ability:GetAbilityDamageType(), ability = ability } self:StartIntervalThink(0.33) self:PlayEffects() end function modifier_spider_nethertoxin_lua.prototype.OnCreated(self, params) if not IsServer() then return end local parent = self:GetParent() if not isToxinPoolThinker(nil, parent) then self:initializeAuraVictimDebuff() return end local p = params if p.merged_damage_per_tick ~= nil and p.merged_radius ~= nil and p.duration ~= nil then self:initializeMergedPoolFromParams(p) return end toxinEnqueuePoolMergeForThinker( nil, parent:GetEntityIndex() ) end function modifier_spider_nethertoxin_lua.prototype.OnRefresh(self, _params) if not IsServer() then return end local ability = self:GetAbility() if not toxinIsValidAbility(nil, ability) then return end if not isToxinPoolThinker( nil, self:GetParent() ) then self:syncAuraPenaltyFromCasterThinker() self:SetStackCount(math.max( 1, math.floor(self.auraPenaltyStack) )) return end self.damageTable.damage = self.damagePerTick self.damageTable.damage_type = ability:GetAbilityDamageType() end function modifier_spider_nethertoxin_lua.prototype.DeclareFunctions(self) return {MODIFIER_PROPERTY_PHYSICAL_ARMOR_BONUS, MODIFIER_PROPERTY_MAGICAL_RESISTANCE_BONUS} end function modifier_spider_nethertoxin_lua.prototype.GetModifierPhysicalArmorBonus(self) local parent = self:GetParent() if isToxinPoolThinker(nil, parent) then return 0 end local ability = self:GetAbility() if not toxinIsValidAbility(nil, ability) then return 0 end local per = math.max( 0, ability:GetSpecialValueFor("armor_magic_reduce_per_stack") ) local scale = Difficulty:getNpcStatScale() return -per * math.max( 1, math.floor(self.auraPenaltyStack) ) * scale end function modifier_spider_nethertoxin_lua.prototype.GetModifierMagicalResistanceBonus(self) local parent = self:GetParent() if isToxinPoolThinker(nil, parent) then return 0 end local ability = self:GetAbility() if not toxinIsValidAbility(nil, ability) then return 0 end local per = math.max( 0, ability:GetSpecialValueFor("armor_magic_reduce_per_stack") ) local scale = Difficulty:getNpcStatScale() return -per * math.max( 1, math.floor(self.auraPenaltyStack) ) * scale end function modifier_spider_nethertoxin_lua.prototype.OnDestroy(self) if not IsServer() then return end local parent = self:GetParent() if not isToxinPoolThinker(nil, parent) then return end local entIndex = parent:GetEntityIndex() Timers:CreateTimer( 0, function() if not IsServer() then return end local npc = EntIndexToHScript(entIndex) if not toxinIsValidUnit(nil, npc) then return end if npc:GetClassname() ~= TOXIN_THINKER_CLASS then return end UTIL_Remove(npc) end ) end function modifier_spider_nethertoxin_lua.prototype.CheckState(self) return {[MODIFIER_STATE_PASSIVES_DISABLED] = true} end function modifier_spider_nethertoxin_lua.prototype.OnIntervalThink(self) local parent = self:GetParent() if not isToxinPoolThinker(nil, parent) then return end local caster = self:GetCaster() local ability = self:GetAbility() if not toxinIsValidUnit(nil, caster) or not toxinIsValidAbility(nil, ability) then return end local units = FindUnitsInRadius( caster:GetTeamNumber(), parent:GetAbsOrigin(), nil, self.effectiveRadius, self:GetAuraSearchTeam(), self:GetAuraSearchType(), DOTA_UNIT_TARGET_FLAG_NONE, FIND_ANY_ORDER, false ) self.damageTable.attacker = caster self.damageTable.ability = ability self.damageTable.damage_type = ability:GetAbilityDamageType() local damagedAny = false for ____, unit in ipairs(units) do do if not toxinIsValidUnit(nil, unit) or not unit:IsAlive() then goto __continue104 end self.damageTable.victim = unit ApplyDamage(self.damageTable) damagedAny = true end ::__continue104:: end if damagedAny then EmitSoundOn("Hero_Viper.NetherToxin.Damage", parent) end end function modifier_spider_nethertoxin_lua.prototype.IsAura(self) return isToxinPoolThinker( nil, self:GetParent() ) end function modifier_spider_nethertoxin_lua.prototype.GetModifierAura(self) return TOXIN_POOL_MODIFIER_NAME end function modifier_spider_nethertoxin_lua.prototype.GetAuraRadius(self) local ability = self:GetAbility() if self.effectiveRadius > 0 then return self.effectiveRadius end if toxinIsValidAbility(nil, ability) then return clampToxinPoolRadius( nil, ability:GetSpecialValueFor("radius") ) end return 0 end function modifier_spider_nethertoxin_lua.prototype.GetAuraDuration(self) return 0.25 end function modifier_spider_nethertoxin_lua.prototype.GetAuraSearchTeam(self) return DOTA_UNIT_TARGET_TEAM_ENEMY end function modifier_spider_nethertoxin_lua.prototype.GetAuraSearchType(self) return DOTA_UNIT_TARGET_HERO + DOTA_UNIT_TARGET_BASIC end function modifier_spider_nethertoxin_lua.prototype.GetEffectName(self) return "particles/units/heroes/hero_viper/viper_nethertoxin_debuff.vpcf" end function modifier_spider_nethertoxin_lua.prototype.GetEffectAttachType(self) return PATTACH_ABSORIGIN_FOLLOW end function modifier_spider_nethertoxin_lua.prototype.PlayEffects(self) local parent = self:GetParent() if not toxinIsValidUnit(nil, parent) then return end local particle_cast = "particles/units/heroes/hero_viper/viper_nethertoxin.vpcf" local sound_cast = "Hero_Viper.NetherToxin" local effect_cast = ParticleManager:CreateParticle(particle_cast, PATTACH_WORLDORIGIN, nil) ParticleManager:SetParticleControl( effect_cast, 0, parent:GetOrigin() ) ParticleManager:SetParticleControl( effect_cast, 1, Vector(self.effectiveRadius, 1, 1) ) self:AddParticle( effect_cast, false, false, -1, false, false ) EmitSoundOn(sound_cast, parent) end modifier_spider_nethertoxin_lua = __TS__Decorate( modifier_spider_nethertoxin_lua, modifier_spider_nethertoxin_lua, {registerModifier(nil)}, {kind = "class", name = "modifier_spider_nethertoxin_lua"} ) ____exports.modifier_spider_nethertoxin_lua = modifier_spider_nethertoxin_lua return ____exports